c9ac443d202ab2bdfd2dde6101f4fad446de541a
[deliverable/linux.git] / fs / hfsplus / ioctl.c
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/mount.h>
18 #include <linux/sched.h>
19 #include <linux/xattr.h>
20 #include <asm/uaccess.h>
21 #include "hfsplus_fs.h"
22
23 static int hfsplus_ioctl_getflags(struct file *file, int __user *user_flags)
24 {
25 struct inode *inode = file->f_path.dentry->d_inode;
26 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
27 unsigned int flags = 0;
28
29 if (hip->rootflags & HFSPLUS_FLG_IMMUTABLE)
30 flags |= FS_IMMUTABLE_FL;
31 if (hip->rootflags & HFSPLUS_FLG_APPEND)
32 flags |= FS_APPEND_FL;
33 if (hip->userflags & HFSPLUS_FLG_NODUMP)
34 flags |= FS_NODUMP_FL;
35
36 return put_user(flags, user_flags);
37 }
38
39 static int hfsplus_ioctl_setflags(struct file *file, int __user *user_flags)
40 {
41 struct inode *inode = file->f_path.dentry->d_inode;
42 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
43 unsigned int flags;
44 int err = 0;
45
46 err = mnt_want_write(file->f_path.mnt);
47 if (err)
48 goto out;
49
50 if (!is_owner_or_cap(inode)) {
51 err = -EACCES;
52 goto out_drop_write;
53 }
54
55 if (get_user(flags, user_flags)) {
56 err = -EFAULT;
57 goto out_drop_write;
58 }
59
60 mutex_lock(&inode->i_mutex);
61
62 if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
63 hip->rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) {
64 if (!capable(CAP_LINUX_IMMUTABLE)) {
65 err = -EPERM;
66 goto out_unlock_inode;
67 }
68 }
69
70 /* don't silently ignore unsupported ext2 flags */
71 if (flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL)) {
72 err = -EOPNOTSUPP;
73 goto out_unlock_inode;
74 }
75 if (flags & FS_IMMUTABLE_FL) {
76 inode->i_flags |= S_IMMUTABLE;
77 hip->rootflags |= HFSPLUS_FLG_IMMUTABLE;
78 } else {
79 inode->i_flags &= ~S_IMMUTABLE;
80 hip->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
81 }
82 if (flags & FS_APPEND_FL) {
83 inode->i_flags |= S_APPEND;
84 hip->rootflags |= HFSPLUS_FLG_APPEND;
85 } else {
86 inode->i_flags &= ~S_APPEND;
87 hip->rootflags &= ~HFSPLUS_FLG_APPEND;
88 }
89 if (flags & FS_NODUMP_FL)
90 hip->userflags |= HFSPLUS_FLG_NODUMP;
91 else
92 hip->userflags &= ~HFSPLUS_FLG_NODUMP;
93
94 inode->i_ctime = CURRENT_TIME_SEC;
95 mark_inode_dirty(inode);
96
97 out_unlock_inode:
98 mutex_lock(&inode->i_mutex);
99 out_drop_write:
100 mnt_drop_write(file->f_path.mnt);
101 out:
102 return err;
103 }
104
105 long hfsplus_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
106 {
107 void __user *argp = (void __user *)arg;
108
109 switch (cmd) {
110 case HFSPLUS_IOC_EXT2_GETFLAGS:
111 return hfsplus_ioctl_getflags(file, argp);
112 case HFSPLUS_IOC_EXT2_SETFLAGS:
113 return hfsplus_ioctl_setflags(file, argp);
114 default:
115 return -ENOTTY;
116 }
117 }
118
119 int hfsplus_setxattr(struct dentry *dentry, const char *name,
120 const void *value, size_t size, int flags)
121 {
122 struct inode *inode = dentry->d_inode;
123 struct hfs_find_data fd;
124 hfsplus_cat_entry entry;
125 struct hfsplus_cat_file *file;
126 int res;
127
128 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
129 return -EOPNOTSUPP;
130
131 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
132 if (res)
133 return res;
134 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
135 if (res)
136 goto out;
137 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
138 sizeof(struct hfsplus_cat_file));
139 file = &entry.file;
140
141 if (!strcmp(name, "hfs.type")) {
142 if (size == 4)
143 memcpy(&file->user_info.fdType, value, 4);
144 else
145 res = -ERANGE;
146 } else if (!strcmp(name, "hfs.creator")) {
147 if (size == 4)
148 memcpy(&file->user_info.fdCreator, value, 4);
149 else
150 res = -ERANGE;
151 } else
152 res = -EOPNOTSUPP;
153 if (!res)
154 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
155 sizeof(struct hfsplus_cat_file));
156 out:
157 hfs_find_exit(&fd);
158 return res;
159 }
160
161 ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name,
162 void *value, size_t size)
163 {
164 struct inode *inode = dentry->d_inode;
165 struct hfs_find_data fd;
166 hfsplus_cat_entry entry;
167 struct hfsplus_cat_file *file;
168 ssize_t res = 0;
169
170 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
171 return -EOPNOTSUPP;
172
173 if (size) {
174 res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd);
175 if (res)
176 return res;
177 res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd);
178 if (res)
179 goto out;
180 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
181 sizeof(struct hfsplus_cat_file));
182 }
183 file = &entry.file;
184
185 if (!strcmp(name, "hfs.type")) {
186 if (size >= 4) {
187 memcpy(value, &file->user_info.fdType, 4);
188 res = 4;
189 } else
190 res = size ? -ERANGE : 4;
191 } else if (!strcmp(name, "hfs.creator")) {
192 if (size >= 4) {
193 memcpy(value, &file->user_info.fdCreator, 4);
194 res = 4;
195 } else
196 res = size ? -ERANGE : 4;
197 } else
198 res = -ENODATA;
199 out:
200 if (size)
201 hfs_find_exit(&fd);
202 return res;
203 }
204
205 #define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type"))
206
207 ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
208 {
209 struct inode *inode = dentry->d_inode;
210
211 if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode))
212 return -EOPNOTSUPP;
213
214 if (!buffer || !size)
215 return HFSPLUS_ATTRLIST_SIZE;
216 if (size < HFSPLUS_ATTRLIST_SIZE)
217 return -ERANGE;
218 strcpy(buffer, "hfs.type");
219 strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
220
221 return HFSPLUS_ATTRLIST_SIZE;
222 }
This page took 0.037418 seconds and 4 git commands to generate.