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