diff options
Diffstat (limited to 'fs/hfsplus/ioctl.c')
-rw-r--r-- | fs/hfsplus/ioctl.c | 188 |
1 files changed, 188 insertions, 0 deletions
diff --git a/fs/hfsplus/ioctl.c b/fs/hfsplus/ioctl.c new file mode 100644 index 000000000000..e07aa096e07c --- /dev/null +++ b/fs/hfsplus/ioctl.c | |||
@@ -0,0 +1,188 @@ | |||
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/fs.h> | ||
16 | #include <linux/sched.h> | ||
17 | #include <linux/xattr.h> | ||
18 | #include <asm/uaccess.h> | ||
19 | #include "hfsplus_fs.h" | ||
20 | |||
21 | int hfsplus_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
22 | unsigned long arg) | ||
23 | { | ||
24 | unsigned int flags; | ||
25 | |||
26 | switch (cmd) { | ||
27 | case HFSPLUS_IOC_EXT2_GETFLAGS: | ||
28 | flags = 0; | ||
29 | if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_IMMUTABLE) | ||
30 | flags |= EXT2_FLAG_IMMUTABLE; /* EXT2_IMMUTABLE_FL */ | ||
31 | if (HFSPLUS_I(inode).rootflags & HFSPLUS_FLG_APPEND) | ||
32 | flags |= EXT2_FLAG_APPEND; /* EXT2_APPEND_FL */ | ||
33 | if (HFSPLUS_I(inode).userflags & HFSPLUS_FLG_NODUMP) | ||
34 | flags |= EXT2_FLAG_NODUMP; /* EXT2_NODUMP_FL */ | ||
35 | return put_user(flags, (int __user *)arg); | ||
36 | case HFSPLUS_IOC_EXT2_SETFLAGS: { | ||
37 | if (IS_RDONLY(inode)) | ||
38 | return -EROFS; | ||
39 | |||
40 | if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) | ||
41 | return -EACCES; | ||
42 | |||
43 | if (get_user(flags, (int __user *)arg)) | ||
44 | return -EFAULT; | ||
45 | |||
46 | if (flags & (EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND) || | ||
47 | HFSPLUS_I(inode).rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) { | ||
48 | if (!capable(CAP_LINUX_IMMUTABLE)) | ||
49 | return -EPERM; | ||
50 | } | ||
51 | |||
52 | /* don't silently ignore unsupported ext2 flags */ | ||
53 | if (flags & ~(EXT2_FLAG_IMMUTABLE|EXT2_FLAG_APPEND| | ||
54 | EXT2_FLAG_NODUMP)) | ||
55 | return -EOPNOTSUPP; | ||
56 | |||
57 | if (flags & EXT2_FLAG_IMMUTABLE) { /* 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 & EXT2_FLAG_APPEND) { /* 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 & EXT2_FLAG_NODUMP) /* 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 | } | ||