1 /* 2 * linux/fs/hfsplus/ioctl.c 3 * 4 * Copyright (C) 2003 5 * Ethan Benson <erbenson@alaska.net> 6 * partially derived from linux/fs/ext2/ioctl.c 7 * Copyright (C) 1993, 1994, 1995 8 * Remy Card (card@masi.ibp.fr) 9 * Laboratoire MASI - Institut Blaise Pascal 10 * Universite Pierre et Marie Curie (Paris VI) 11 * 12 * hfsplus ioctls 13 */ 14 15 #include <linux/capability.h> 16 #include <linux/fs.h> 17 #include <linux/sched.h> 18 #include <linux/xattr.h> 19 #include <asm/uaccess.h> 20 #include "hfsplus_fs.h" 21 22 int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, 23 unsigned long arg) 24 { 25 unsigned int flags; 26 27 switch (cmd) { 28 case HFSPLUS_IOC_EXT2_GETFLAGS: 29 flags = 0; 30 if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE) 31 flags |= EXT2_FLAG_IMMUTABLE; /* EXT2_IMMUTABLE_FL */ 32 if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND) 33 flags |= EXT2_FLAG_APPEND; /* EXT2_APPEND_FL */ 34 if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP) 35 flags |= EXT2_FLAG_NODUMP; /* EXT2_NODUMP_FL */ 36 return put_user(flags, (int __user *)arg); 37 case HFSPLUS_IOC_EXT2_SETFLAGS: { 38 if (IS_RDONLY(inode)) 39 return -EROFS; 40 41 if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) 42 return -EACCES; 43 44 if (get_user(flags, (int __user *)arg)) 45 return -EFAULT; 46 47 if (flags & (EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND) || 48 HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) { 49 if (!capable(CAP_LINUX_IMMUTABLE)) 50 return -EPERM; 51 } 52 53 /* don't silently ignore unsupported ext2 flags */ 54 if (flags & ~(EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND| 55 EXT2_FLAG_NODUMP)) 56 return -EOPNOTSUPP; 57 58 if (flags & EXT2_FLAG_IMMUTABLE) { /* EXT2_IMMUTABLE_FL */ 59 inode->i_flags |= S_IMMUTABLE; 60 HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE; 61 } else { 62 inode->i_flags &= ~S_IMMUTABLE; 63 HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE; 64 } 65 if (flags & EXT2_FLAG_APPEND) { /* EXT2_APPEND_FL */ 66 inode->i_flags |= S_APPEND; 67 HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND; 68 } else { 69 inode->i_flags &= ~S_APPEND; 70 HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND; 71 } 72 if (flags & EXT2_FLAG_NODUMP) /* EXT2_NODUMP_FL */ 73 HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP; 74 else 75 HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP; 76 77 inode->i_ctime = CURRENT_TIME_SEC; 78 mark_inode_dirty(inode); 79 return 0; 80 } 81 default: 82 return -ENOTTY; 83 } 84 } 85 86 int hfsplus_setxattr(struct dentry *dentry, const char *name, 87 const void *value, size_t size, int flags) 88 { 89 struct inode *inode = dentry->d_inode; 90 struct hfs_find_data fd; 91 hfsplus_cat_entry entry; 92 struct hfsplus_cat_file *file; 93 int res; 94 95 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 96 return -EOPNOTSUPP; 97 98 res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); 99 if (res) 100 return res; 101 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 102 if (res) 103 goto out; 104 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 105 sizeof(struct hfsplus_cat_file)); 106 file = &entry.file; 107 108 if (!strcmp(name, "hfs.type")) { 109 if (size == 4) 110 memcpy(&file->user_info.fdType, value, 4); 111 else 112 res = -ERANGE; 113 } else if (!strcmp(name, "hfs.creator")) { 114 if (size == 4) 115 memcpy(&file->user_info.fdCreator, value, 4); 116 else 117 res = -ERANGE; 118 } else 119 res = -EOPNOTSUPP; 120 if (!res) 121 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 122 sizeof(struct hfsplus_cat_file)); 123 out: 124 hfs_find_exit(&fd); 125 return res; 126 } 127 128 ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, 129 void *value, size_t size) 130 { 131 struct inode *inode = dentry->d_inode; 132 struct hfs_find_data fd; 133 hfsplus_cat_entry entry; 134 struct hfsplus_cat_file *file; 135 ssize_t res = 0; 136 137 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 138 return -EOPNOTSUPP; 139 140 if (size) { 141 res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); 142 if (res) 143 return res; 144 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 145 if (res) 146 goto out; 147 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 148 sizeof(struct hfsplus_cat_file)); 149 } 150 file = &entry.file; 151 152 if (!strcmp(name, "hfs.type")) { 153 if (size >= 4) { 154 memcpy(value, &file->user_info.fdType, 4); 155 res = 4; 156 } else 157 res = size ? -ERANGE : 4; 158 } else if (!strcmp(name, "hfs.creator")) { 159 if (size >= 4) { 160 memcpy(value, &file->user_info.fdCreator, 4); 161 res = 4; 162 } else 163 res = size ? -ERANGE : 4; 164 } else 165 res = -ENODATA; 166 out: 167 if (size) 168 hfs_find_exit(&fd); 169 return res; 170 } 171 172 #define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type")) 173 174 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 175 { 176 struct inode *inode = dentry->d_inode; 177 178 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 179 return -EOPNOTSUPP; 180 181 if (!buffer || !size) 182 return HFSPLUS_ATTRLIST_SIZE; 183 if (size < HFSPLUS_ATTRLIST_SIZE) 184 return -ERANGE; 185 strcpy(buffer, "hfs.type"); 186 strcpy(buffer + sizeof("hfs.type"), "hfs.creator"); 187 188 return HFSPLUS_ATTRLIST_SIZE; 189 } 190