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 |= FS_IMMUTABLE_FL; /* EXT2_IMMUTABLE_FL */ 32 if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND) 33 flags |= FS_APPEND_FL; /* EXT2_APPEND_FL */ 34 if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP) 35 flags |= FS_NODUMP_FL; /* 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 & (FS_IMMUTABLE_FL|FS_APPEND_FL) || 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 & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) 55 return -EOPNOTSUPP; 56 57 if (flags & FS_IMMUTABLE_FL) { /* EXT2_IMMUTABLE_FL */ 58 inode->i_flags |= S_IMMUTABLE; 59 HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_IMMUTABLE; 60 } else { 61 inode->i_flags &= ~S_IMMUTABLE; 62 HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_IMMUTABLE; 63 } 64 if (flags & FS_APPEND_FL) { /* EXT2_APPEND_FL */ 65 inode->i_flags |= S_APPEND; 66 HFSPLUS_I(inode).rootflags |= HFSPLUS_FLG_APPEND; 67 } else { 68 inode->i_flags &= ~S_APPEND; 69 HFSPLUS_I(inode).rootflags &= ~HFSPLUS_FLG_APPEND; 70 } 71 if (flags & FS_NODUMP_FL) /* EXT2_NODUMP_FL */ 72 HFSPLUS_I(inode).userflags |= HFSPLUS_FLG_NODUMP; 73 else 74 HFSPLUS_I(inode).userflags &= ~HFSPLUS_FLG_NODUMP; 75 76 inode->i_ctime = CURRENT_TIME_SEC; 77 mark_inode_dirty(inode); 78 return 0; 79 } 80 default: 81 return -ENOTTY; 82 } 83 } 84 85 int hfsplus_setxattr(struct dentry *dentry, const char *name, 86 const void *value, size_t size, int flags) 87 { 88 struct inode *inode = dentry->d_inode; 89 struct hfs_find_data fd; 90 hfsplus_cat_entry entry; 91 struct hfsplus_cat_file *file; 92 int res; 93 94 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 95 return -EOPNOTSUPP; 96 97 res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); 98 if (res) 99 return res; 100 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 101 if (res) 102 goto out; 103 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 104 sizeof(struct hfsplus_cat_file)); 105 file = &entry.file; 106 107 if (!strcmp(name, "hfs.type")) { 108 if (size == 4) 109 memcpy(&file->user_info.fdType, value, 4); 110 else 111 res = -ERANGE; 112 } else if (!strcmp(name, "hfs.creator")) { 113 if (size == 4) 114 memcpy(&file->user_info.fdCreator, value, 4); 115 else 116 res = -ERANGE; 117 } else 118 res = -EOPNOTSUPP; 119 if (!res) 120 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 121 sizeof(struct hfsplus_cat_file)); 122 out: 123 hfs_find_exit(&fd); 124 return res; 125 } 126 127 ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, 128 void *value, size_t size) 129 { 130 struct inode *inode = dentry->d_inode; 131 struct hfs_find_data fd; 132 hfsplus_cat_entry entry; 133 struct hfsplus_cat_file *file; 134 ssize_t res = 0; 135 136 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 137 return -EOPNOTSUPP; 138 139 if (size) { 140 res = hfs_find_init(HFSPLUS_SB(inode->i_sb).cat_tree, &fd); 141 if (res) 142 return res; 143 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 144 if (res) 145 goto out; 146 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 147 sizeof(struct hfsplus_cat_file)); 148 } 149 file = &entry.file; 150 151 if (!strcmp(name, "hfs.type")) { 152 if (size >= 4) { 153 memcpy(value, &file->user_info.fdType, 4); 154 res = 4; 155 } else 156 res = size ? -ERANGE : 4; 157 } else if (!strcmp(name, "hfs.creator")) { 158 if (size >= 4) { 159 memcpy(value, &file->user_info.fdCreator, 4); 160 res = 4; 161 } else 162 res = size ? -ERANGE : 4; 163 } else 164 res = -ENODATA; 165 out: 166 if (size) 167 hfs_find_exit(&fd); 168 return res; 169 } 170 171 #define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type")) 172 173 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 174 { 175 struct inode *inode = dentry->d_inode; 176 177 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 178 return -EOPNOTSUPP; 179 180 if (!buffer || !size) 181 return HFSPLUS_ATTRLIST_SIZE; 182 if (size < HFSPLUS_ATTRLIST_SIZE) 183 return -ERANGE; 184 strcpy(buffer, "hfs.type"); 185 strcpy(buffer + sizeof("hfs.type"), "hfs.creator"); 186 187 return HFSPLUS_ATTRLIST_SIZE; 188 } 189