diff options
author | Vyacheslav Dubeyko <slava@dubeyko.com> | 2013-02-27 20:03:03 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-02-27 22:10:10 -0500 |
commit | 127e5f5ae51eff44c9bff673f24e8587caa4e29f (patch) | |
tree | c36b2b22e18241b43a85e8719603ba0e6a897d68 /fs/hfsplus | |
parent | 3e05ca20fb570b456bd9841b5ff489d865e8c563 (diff) |
hfsplus: rework functionality of getting, setting and deleting of extended attributes
Rework functionality of getting, setting and deleting of extended attributes.
Signed-off-by: Vyacheslav Dubeyko <slava@dubeyko.com>
Reported-by: Hin-Tak Leung <htl10@users.sourceforge.net>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Jan Kara <jack@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/hfsplus')
-rw-r--r-- | fs/hfsplus/xattr.c | 709 | ||||
-rw-r--r-- | fs/hfsplus/xattr.h | 60 | ||||
-rw-r--r-- | fs/hfsplus/xattr_security.c | 104 | ||||
-rw-r--r-- | fs/hfsplus/xattr_trusted.c | 63 | ||||
-rw-r--r-- | fs/hfsplus/xattr_user.c | 63 |
5 files changed, 999 insertions, 0 deletions
diff --git a/fs/hfsplus/xattr.c b/fs/hfsplus/xattr.c new file mode 100644 index 000000000000..e8a4b0815c61 --- /dev/null +++ b/fs/hfsplus/xattr.c | |||
@@ -0,0 +1,709 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Logic of processing extended attributes | ||
7 | */ | ||
8 | |||
9 | #include "hfsplus_fs.h" | ||
10 | #include "xattr.h" | ||
11 | |||
12 | const struct xattr_handler *hfsplus_xattr_handlers[] = { | ||
13 | &hfsplus_xattr_osx_handler, | ||
14 | &hfsplus_xattr_user_handler, | ||
15 | &hfsplus_xattr_trusted_handler, | ||
16 | &hfsplus_xattr_security_handler, | ||
17 | NULL | ||
18 | }; | ||
19 | |||
20 | static int strcmp_xattr_finder_info(const char *name) | ||
21 | { | ||
22 | if (name) { | ||
23 | return strncmp(name, HFSPLUS_XATTR_FINDER_INFO_NAME, | ||
24 | sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME)); | ||
25 | } | ||
26 | return -1; | ||
27 | } | ||
28 | |||
29 | static int strcmp_xattr_acl(const char *name) | ||
30 | { | ||
31 | if (name) { | ||
32 | return strncmp(name, HFSPLUS_XATTR_ACL_NAME, | ||
33 | sizeof(HFSPLUS_XATTR_ACL_NAME)); | ||
34 | } | ||
35 | return -1; | ||
36 | } | ||
37 | |||
38 | static inline int is_known_namespace(const char *name) | ||
39 | { | ||
40 | if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && | ||
41 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && | ||
42 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | ||
43 | strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) | ||
44 | return false; | ||
45 | |||
46 | return true; | ||
47 | } | ||
48 | |||
49 | static int can_set_xattr(struct inode *inode, const char *name, | ||
50 | const void *value, size_t value_len) | ||
51 | { | ||
52 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
53 | return -EOPNOTSUPP; /* TODO: implement ACL support */ | ||
54 | |||
55 | if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) { | ||
56 | /* | ||
57 | * This makes sure that we aren't trying to set an | ||
58 | * attribute in a different namespace by prefixing it | ||
59 | * with "osx." | ||
60 | */ | ||
61 | if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN)) | ||
62 | return -EOPNOTSUPP; | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | /* | ||
68 | * Don't allow setting an attribute in an unknown namespace. | ||
69 | */ | ||
70 | if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && | ||
71 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | ||
72 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) | ||
73 | return -EOPNOTSUPP; | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | int __hfsplus_setxattr(struct inode *inode, const char *name, | ||
79 | const void *value, size_t size, int flags) | ||
80 | { | ||
81 | int err = 0; | ||
82 | struct hfs_find_data cat_fd; | ||
83 | hfsplus_cat_entry entry; | ||
84 | u16 cat_entry_flags, cat_entry_type; | ||
85 | u16 folder_finderinfo_len = sizeof(struct DInfo) + | ||
86 | sizeof(struct DXInfo); | ||
87 | u16 file_finderinfo_len = sizeof(struct FInfo) + | ||
88 | sizeof(struct FXInfo); | ||
89 | |||
90 | if ((!S_ISREG(inode->i_mode) && | ||
91 | !S_ISDIR(inode->i_mode)) || | ||
92 | HFSPLUS_IS_RSRC(inode)) | ||
93 | return -EOPNOTSUPP; | ||
94 | |||
95 | err = can_set_xattr(inode, name, value, size); | ||
96 | if (err) | ||
97 | return err; | ||
98 | |||
99 | if (strncmp(name, XATTR_MAC_OSX_PREFIX, | ||
100 | XATTR_MAC_OSX_PREFIX_LEN) == 0) | ||
101 | name += XATTR_MAC_OSX_PREFIX_LEN; | ||
102 | |||
103 | if (value == NULL) { | ||
104 | value = ""; | ||
105 | size = 0; | ||
106 | } | ||
107 | |||
108 | err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); | ||
109 | if (err) { | ||
110 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
111 | return err; | ||
112 | } | ||
113 | |||
114 | err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); | ||
115 | if (err) { | ||
116 | printk(KERN_ERR "hfs: catalog searching failed\n"); | ||
117 | goto end_setxattr; | ||
118 | } | ||
119 | |||
120 | if (!strcmp_xattr_finder_info(name)) { | ||
121 | if (flags & XATTR_CREATE) { | ||
122 | printk(KERN_ERR "hfs: xattr exists yet\n"); | ||
123 | err = -EOPNOTSUPP; | ||
124 | goto end_setxattr; | ||
125 | } | ||
126 | hfs_bnode_read(cat_fd.bnode, &entry, cat_fd.entryoffset, | ||
127 | sizeof(hfsplus_cat_entry)); | ||
128 | if (be16_to_cpu(entry.type) == HFSPLUS_FOLDER) { | ||
129 | if (size == folder_finderinfo_len) { | ||
130 | memcpy(&entry.folder.user_info, value, | ||
131 | folder_finderinfo_len); | ||
132 | hfs_bnode_write(cat_fd.bnode, &entry, | ||
133 | cat_fd.entryoffset, | ||
134 | sizeof(struct hfsplus_cat_folder)); | ||
135 | hfsplus_mark_inode_dirty(inode, | ||
136 | HFSPLUS_I_CAT_DIRTY); | ||
137 | } else { | ||
138 | err = -ERANGE; | ||
139 | goto end_setxattr; | ||
140 | } | ||
141 | } else if (be16_to_cpu(entry.type) == HFSPLUS_FILE) { | ||
142 | if (size == file_finderinfo_len) { | ||
143 | memcpy(&entry.file.user_info, value, | ||
144 | file_finderinfo_len); | ||
145 | hfs_bnode_write(cat_fd.bnode, &entry, | ||
146 | cat_fd.entryoffset, | ||
147 | sizeof(struct hfsplus_cat_file)); | ||
148 | hfsplus_mark_inode_dirty(inode, | ||
149 | HFSPLUS_I_CAT_DIRTY); | ||
150 | } else { | ||
151 | err = -ERANGE; | ||
152 | goto end_setxattr; | ||
153 | } | ||
154 | } else { | ||
155 | err = -EOPNOTSUPP; | ||
156 | goto end_setxattr; | ||
157 | } | ||
158 | goto end_setxattr; | ||
159 | } | ||
160 | |||
161 | if (!HFSPLUS_SB(inode->i_sb)->attr_tree) { | ||
162 | err = -EOPNOTSUPP; | ||
163 | goto end_setxattr; | ||
164 | } | ||
165 | |||
166 | if (hfsplus_attr_exists(inode, name)) { | ||
167 | if (flags & XATTR_CREATE) { | ||
168 | printk(KERN_ERR "hfs: xattr exists yet\n"); | ||
169 | err = -EOPNOTSUPP; | ||
170 | goto end_setxattr; | ||
171 | } | ||
172 | err = hfsplus_delete_attr(inode, name); | ||
173 | if (err) | ||
174 | goto end_setxattr; | ||
175 | err = hfsplus_create_attr(inode, name, value, size); | ||
176 | if (err) | ||
177 | goto end_setxattr; | ||
178 | } else { | ||
179 | if (flags & XATTR_REPLACE) { | ||
180 | printk(KERN_ERR "hfs: cannot replace xattr\n"); | ||
181 | err = -EOPNOTSUPP; | ||
182 | goto end_setxattr; | ||
183 | } | ||
184 | err = hfsplus_create_attr(inode, name, value, size); | ||
185 | if (err) | ||
186 | goto end_setxattr; | ||
187 | } | ||
188 | |||
189 | cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); | ||
190 | if (cat_entry_type == HFSPLUS_FOLDER) { | ||
191 | cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, | ||
192 | cat_fd.entryoffset + | ||
193 | offsetof(struct hfsplus_cat_folder, flags)); | ||
194 | cat_entry_flags |= HFSPLUS_XATTR_EXISTS; | ||
195 | if (!strcmp_xattr_acl(name)) | ||
196 | cat_entry_flags |= HFSPLUS_ACL_EXISTS; | ||
197 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
198 | offsetof(struct hfsplus_cat_folder, flags), | ||
199 | cat_entry_flags); | ||
200 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
201 | } else if (cat_entry_type == HFSPLUS_FILE) { | ||
202 | cat_entry_flags = hfs_bnode_read_u16(cat_fd.bnode, | ||
203 | cat_fd.entryoffset + | ||
204 | offsetof(struct hfsplus_cat_file, flags)); | ||
205 | cat_entry_flags |= HFSPLUS_XATTR_EXISTS; | ||
206 | if (!strcmp_xattr_acl(name)) | ||
207 | cat_entry_flags |= HFSPLUS_ACL_EXISTS; | ||
208 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
209 | offsetof(struct hfsplus_cat_file, flags), | ||
210 | cat_entry_flags); | ||
211 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
212 | } else { | ||
213 | printk(KERN_ERR "hfs: invalid catalog entry type\n"); | ||
214 | err = -EIO; | ||
215 | goto end_setxattr; | ||
216 | } | ||
217 | |||
218 | end_setxattr: | ||
219 | hfs_find_exit(&cat_fd); | ||
220 | return err; | ||
221 | } | ||
222 | |||
223 | static inline int is_osx_xattr(const char *xattr_name) | ||
224 | { | ||
225 | return !is_known_namespace(xattr_name); | ||
226 | } | ||
227 | |||
228 | static int name_len(const char *xattr_name, int xattr_name_len) | ||
229 | { | ||
230 | int len = xattr_name_len + 1; | ||
231 | |||
232 | if (is_osx_xattr(xattr_name)) | ||
233 | len += XATTR_MAC_OSX_PREFIX_LEN; | ||
234 | |||
235 | return len; | ||
236 | } | ||
237 | |||
238 | static int copy_name(char *buffer, const char *xattr_name, int name_len) | ||
239 | { | ||
240 | int len = name_len; | ||
241 | int offset = 0; | ||
242 | |||
243 | if (is_osx_xattr(xattr_name)) { | ||
244 | strncpy(buffer, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN); | ||
245 | offset += XATTR_MAC_OSX_PREFIX_LEN; | ||
246 | len += XATTR_MAC_OSX_PREFIX_LEN; | ||
247 | } | ||
248 | |||
249 | strncpy(buffer + offset, xattr_name, name_len); | ||
250 | memset(buffer + offset + name_len, 0, 1); | ||
251 | len += 1; | ||
252 | |||
253 | return len; | ||
254 | } | ||
255 | |||
256 | static ssize_t hfsplus_getxattr_finder_info(struct dentry *dentry, | ||
257 | void *value, size_t size) | ||
258 | { | ||
259 | ssize_t res = 0; | ||
260 | struct inode *inode = dentry->d_inode; | ||
261 | struct hfs_find_data fd; | ||
262 | u16 entry_type; | ||
263 | u16 folder_rec_len = sizeof(struct DInfo) + sizeof(struct DXInfo); | ||
264 | u16 file_rec_len = sizeof(struct FInfo) + sizeof(struct FXInfo); | ||
265 | u16 record_len = max(folder_rec_len, file_rec_len); | ||
266 | u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; | ||
267 | u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; | ||
268 | |||
269 | if (size >= record_len) { | ||
270 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
271 | if (res) { | ||
272 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
273 | return res; | ||
274 | } | ||
275 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
276 | if (res) | ||
277 | goto end_getxattr_finder_info; | ||
278 | entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); | ||
279 | |||
280 | if (entry_type == HFSPLUS_FOLDER) { | ||
281 | hfs_bnode_read(fd.bnode, folder_finder_info, | ||
282 | fd.entryoffset + | ||
283 | offsetof(struct hfsplus_cat_folder, user_info), | ||
284 | folder_rec_len); | ||
285 | memcpy(value, folder_finder_info, folder_rec_len); | ||
286 | res = folder_rec_len; | ||
287 | } else if (entry_type == HFSPLUS_FILE) { | ||
288 | hfs_bnode_read(fd.bnode, file_finder_info, | ||
289 | fd.entryoffset + | ||
290 | offsetof(struct hfsplus_cat_file, user_info), | ||
291 | file_rec_len); | ||
292 | memcpy(value, file_finder_info, file_rec_len); | ||
293 | res = file_rec_len; | ||
294 | } else { | ||
295 | res = -EOPNOTSUPP; | ||
296 | goto end_getxattr_finder_info; | ||
297 | } | ||
298 | } else | ||
299 | res = size ? -ERANGE : record_len; | ||
300 | |||
301 | end_getxattr_finder_info: | ||
302 | if (size >= record_len) | ||
303 | hfs_find_exit(&fd); | ||
304 | return res; | ||
305 | } | ||
306 | |||
307 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
308 | void *value, size_t size) | ||
309 | { | ||
310 | struct inode *inode = dentry->d_inode; | ||
311 | struct hfs_find_data fd; | ||
312 | hfsplus_attr_entry *entry; | ||
313 | __be32 xattr_record_type; | ||
314 | u32 record_type; | ||
315 | u16 record_length = 0; | ||
316 | ssize_t res = 0; | ||
317 | |||
318 | if ((!S_ISREG(inode->i_mode) && | ||
319 | !S_ISDIR(inode->i_mode)) || | ||
320 | HFSPLUS_IS_RSRC(inode)) | ||
321 | return -EOPNOTSUPP; | ||
322 | |||
323 | if (strncmp(name, XATTR_MAC_OSX_PREFIX, | ||
324 | XATTR_MAC_OSX_PREFIX_LEN) == 0) { | ||
325 | /* skip "osx." prefix */ | ||
326 | name += XATTR_MAC_OSX_PREFIX_LEN; | ||
327 | /* | ||
328 | * Don't allow retrieving properly prefixed attributes | ||
329 | * by prepending them with "osx." | ||
330 | */ | ||
331 | if (is_known_namespace(name)) | ||
332 | return -EOPNOTSUPP; | ||
333 | } | ||
334 | |||
335 | if (!strcmp_xattr_finder_info(name)) | ||
336 | return hfsplus_getxattr_finder_info(dentry, value, size); | ||
337 | |||
338 | if (!HFSPLUS_SB(inode->i_sb)->attr_tree) | ||
339 | return -EOPNOTSUPP; | ||
340 | |||
341 | entry = hfsplus_alloc_attr_entry(); | ||
342 | if (!entry) { | ||
343 | printk(KERN_ERR "hfs: can't allocate xattr entry\n"); | ||
344 | return -ENOMEM; | ||
345 | } | ||
346 | |||
347 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); | ||
348 | if (res) { | ||
349 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
350 | goto failed_getxattr_init; | ||
351 | } | ||
352 | |||
353 | res = hfsplus_find_attr(inode->i_sb, inode->i_ino, name, &fd); | ||
354 | if (res) { | ||
355 | if (res == -ENOENT) | ||
356 | res = -ENODATA; | ||
357 | else | ||
358 | printk(KERN_ERR "hfs: xattr searching failed\n"); | ||
359 | goto out; | ||
360 | } | ||
361 | |||
362 | hfs_bnode_read(fd.bnode, &xattr_record_type, | ||
363 | fd.entryoffset, sizeof(xattr_record_type)); | ||
364 | record_type = be32_to_cpu(xattr_record_type); | ||
365 | if (record_type == HFSPLUS_ATTR_INLINE_DATA) { | ||
366 | record_length = hfs_bnode_read_u16(fd.bnode, | ||
367 | fd.entryoffset + | ||
368 | offsetof(struct hfsplus_attr_inline_data, | ||
369 | length)); | ||
370 | if (record_length > HFSPLUS_MAX_INLINE_DATA_SIZE) { | ||
371 | printk(KERN_ERR "hfs: invalid xattr record size\n"); | ||
372 | res = -EIO; | ||
373 | goto out; | ||
374 | } | ||
375 | } else if (record_type == HFSPLUS_ATTR_FORK_DATA || | ||
376 | record_type == HFSPLUS_ATTR_EXTENTS) { | ||
377 | printk(KERN_ERR "hfs: only inline data xattr are supported\n"); | ||
378 | res = -EOPNOTSUPP; | ||
379 | goto out; | ||
380 | } else { | ||
381 | printk(KERN_ERR "hfs: invalid xattr record\n"); | ||
382 | res = -EIO; | ||
383 | goto out; | ||
384 | } | ||
385 | |||
386 | if (size) { | ||
387 | hfs_bnode_read(fd.bnode, entry, fd.entryoffset, | ||
388 | offsetof(struct hfsplus_attr_inline_data, | ||
389 | raw_bytes) + record_length); | ||
390 | } | ||
391 | |||
392 | if (size >= record_length) { | ||
393 | memcpy(value, entry->inline_data.raw_bytes, record_length); | ||
394 | res = record_length; | ||
395 | } else | ||
396 | res = size ? -ERANGE : record_length; | ||
397 | |||
398 | out: | ||
399 | hfs_find_exit(&fd); | ||
400 | |||
401 | failed_getxattr_init: | ||
402 | hfsplus_destroy_attr_entry(entry); | ||
403 | return res; | ||
404 | } | ||
405 | |||
406 | static inline int can_list(const char *xattr_name) | ||
407 | { | ||
408 | if (!xattr_name) | ||
409 | return 0; | ||
410 | |||
411 | return strncmp(xattr_name, XATTR_TRUSTED_PREFIX, | ||
412 | XATTR_TRUSTED_PREFIX_LEN) || | ||
413 | capable(CAP_SYS_ADMIN); | ||
414 | } | ||
415 | |||
416 | static ssize_t hfsplus_listxattr_finder_info(struct dentry *dentry, | ||
417 | char *buffer, size_t size) | ||
418 | { | ||
419 | ssize_t res = 0; | ||
420 | struct inode *inode = dentry->d_inode; | ||
421 | struct hfs_find_data fd; | ||
422 | u16 entry_type; | ||
423 | u8 folder_finder_info[sizeof(struct DInfo) + sizeof(struct DXInfo)]; | ||
424 | u8 file_finder_info[sizeof(struct FInfo) + sizeof(struct FXInfo)]; | ||
425 | unsigned long len, found_bit; | ||
426 | int xattr_name_len, symbols_count; | ||
427 | |||
428 | res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); | ||
429 | if (res) { | ||
430 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
431 | return res; | ||
432 | } | ||
433 | |||
434 | res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); | ||
435 | if (res) | ||
436 | goto end_listxattr_finder_info; | ||
437 | |||
438 | entry_type = hfs_bnode_read_u16(fd.bnode, fd.entryoffset); | ||
439 | if (entry_type == HFSPLUS_FOLDER) { | ||
440 | len = sizeof(struct DInfo) + sizeof(struct DXInfo); | ||
441 | hfs_bnode_read(fd.bnode, folder_finder_info, | ||
442 | fd.entryoffset + | ||
443 | offsetof(struct hfsplus_cat_folder, user_info), | ||
444 | len); | ||
445 | found_bit = find_first_bit((void *)folder_finder_info, len*8); | ||
446 | } else if (entry_type == HFSPLUS_FILE) { | ||
447 | len = sizeof(struct FInfo) + sizeof(struct FXInfo); | ||
448 | hfs_bnode_read(fd.bnode, file_finder_info, | ||
449 | fd.entryoffset + | ||
450 | offsetof(struct hfsplus_cat_file, user_info), | ||
451 | len); | ||
452 | found_bit = find_first_bit((void *)file_finder_info, len*8); | ||
453 | } else { | ||
454 | res = -EOPNOTSUPP; | ||
455 | goto end_listxattr_finder_info; | ||
456 | } | ||
457 | |||
458 | if (found_bit >= (len*8)) | ||
459 | res = 0; | ||
460 | else { | ||
461 | symbols_count = sizeof(HFSPLUS_XATTR_FINDER_INFO_NAME) - 1; | ||
462 | xattr_name_len = | ||
463 | name_len(HFSPLUS_XATTR_FINDER_INFO_NAME, symbols_count); | ||
464 | if (!buffer || !size) { | ||
465 | if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) | ||
466 | res = xattr_name_len; | ||
467 | } else if (can_list(HFSPLUS_XATTR_FINDER_INFO_NAME)) { | ||
468 | if (size < xattr_name_len) | ||
469 | res = -ERANGE; | ||
470 | else { | ||
471 | res = copy_name(buffer, | ||
472 | HFSPLUS_XATTR_FINDER_INFO_NAME, | ||
473 | symbols_count); | ||
474 | } | ||
475 | } | ||
476 | } | ||
477 | |||
478 | end_listxattr_finder_info: | ||
479 | hfs_find_exit(&fd); | ||
480 | |||
481 | return res; | ||
482 | } | ||
483 | |||
484 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) | ||
485 | { | ||
486 | ssize_t err; | ||
487 | ssize_t res = 0; | ||
488 | struct inode *inode = dentry->d_inode; | ||
489 | struct hfs_find_data fd; | ||
490 | u16 key_len = 0; | ||
491 | struct hfsplus_attr_key attr_key; | ||
492 | char strbuf[HFSPLUS_ATTR_MAX_STRLEN + | ||
493 | XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; | ||
494 | int xattr_name_len; | ||
495 | |||
496 | if ((!S_ISREG(inode->i_mode) && | ||
497 | !S_ISDIR(inode->i_mode)) || | ||
498 | HFSPLUS_IS_RSRC(inode)) | ||
499 | return -EOPNOTSUPP; | ||
500 | |||
501 | res = hfsplus_listxattr_finder_info(dentry, buffer, size); | ||
502 | if (res < 0) | ||
503 | return res; | ||
504 | else if (!HFSPLUS_SB(inode->i_sb)->attr_tree) | ||
505 | return (res == 0) ? -EOPNOTSUPP : res; | ||
506 | |||
507 | err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->attr_tree, &fd); | ||
508 | if (err) { | ||
509 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
510 | return err; | ||
511 | } | ||
512 | |||
513 | err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd); | ||
514 | if (err) { | ||
515 | if (err == -ENOENT) { | ||
516 | if (res == 0) | ||
517 | res = -ENODATA; | ||
518 | goto end_listxattr; | ||
519 | } else { | ||
520 | res = err; | ||
521 | goto end_listxattr; | ||
522 | } | ||
523 | } | ||
524 | |||
525 | for (;;) { | ||
526 | key_len = hfs_bnode_read_u16(fd.bnode, fd.keyoffset); | ||
527 | if (key_len == 0 || key_len > fd.tree->max_key_len) { | ||
528 | printk(KERN_ERR "hfs: invalid xattr key length: %d\n", | ||
529 | key_len); | ||
530 | res = -EIO; | ||
531 | goto end_listxattr; | ||
532 | } | ||
533 | |||
534 | hfs_bnode_read(fd.bnode, &attr_key, | ||
535 | fd.keyoffset, key_len + sizeof(key_len)); | ||
536 | |||
537 | if (be32_to_cpu(attr_key.cnid) != inode->i_ino) | ||
538 | goto end_listxattr; | ||
539 | |||
540 | xattr_name_len = HFSPLUS_ATTR_MAX_STRLEN; | ||
541 | if (hfsplus_uni2asc(inode->i_sb, | ||
542 | (const struct hfsplus_unistr *)&fd.key->attr.key_name, | ||
543 | strbuf, &xattr_name_len)) { | ||
544 | printk(KERN_ERR "hfs: unicode conversion failed\n"); | ||
545 | res = -EIO; | ||
546 | goto end_listxattr; | ||
547 | } | ||
548 | |||
549 | if (!buffer || !size) { | ||
550 | if (can_list(strbuf)) | ||
551 | res += name_len(strbuf, xattr_name_len); | ||
552 | } else if (can_list(strbuf)) { | ||
553 | if (size < (res + name_len(strbuf, xattr_name_len))) { | ||
554 | res = -ERANGE; | ||
555 | goto end_listxattr; | ||
556 | } else | ||
557 | res += copy_name(buffer + res, | ||
558 | strbuf, xattr_name_len); | ||
559 | } | ||
560 | |||
561 | if (hfs_brec_goto(&fd, 1)) | ||
562 | goto end_listxattr; | ||
563 | } | ||
564 | |||
565 | end_listxattr: | ||
566 | hfs_find_exit(&fd); | ||
567 | return res; | ||
568 | } | ||
569 | |||
570 | int hfsplus_removexattr(struct dentry *dentry, const char *name) | ||
571 | { | ||
572 | int err = 0; | ||
573 | struct inode *inode = dentry->d_inode; | ||
574 | struct hfs_find_data cat_fd; | ||
575 | u16 flags; | ||
576 | u16 cat_entry_type; | ||
577 | int is_xattr_acl_deleted = 0; | ||
578 | int is_all_xattrs_deleted = 0; | ||
579 | |||
580 | if ((!S_ISREG(inode->i_mode) && | ||
581 | !S_ISDIR(inode->i_mode)) || | ||
582 | HFSPLUS_IS_RSRC(inode)) | ||
583 | return -EOPNOTSUPP; | ||
584 | |||
585 | if (!HFSPLUS_SB(inode->i_sb)->attr_tree) | ||
586 | return -EOPNOTSUPP; | ||
587 | |||
588 | err = can_set_xattr(inode, name, NULL, 0); | ||
589 | if (err) | ||
590 | return err; | ||
591 | |||
592 | if (strncmp(name, XATTR_MAC_OSX_PREFIX, | ||
593 | XATTR_MAC_OSX_PREFIX_LEN) == 0) | ||
594 | name += XATTR_MAC_OSX_PREFIX_LEN; | ||
595 | |||
596 | if (!strcmp_xattr_finder_info(name)) | ||
597 | return -EOPNOTSUPP; | ||
598 | |||
599 | err = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &cat_fd); | ||
600 | if (err) { | ||
601 | printk(KERN_ERR "hfs: can't init xattr find struct\n"); | ||
602 | return err; | ||
603 | } | ||
604 | |||
605 | err = hfsplus_find_cat(inode->i_sb, inode->i_ino, &cat_fd); | ||
606 | if (err) { | ||
607 | printk(KERN_ERR "hfs: catalog searching failed\n"); | ||
608 | goto end_removexattr; | ||
609 | } | ||
610 | |||
611 | err = hfsplus_delete_attr(inode, name); | ||
612 | if (err) | ||
613 | goto end_removexattr; | ||
614 | |||
615 | is_xattr_acl_deleted = !strcmp_xattr_acl(name); | ||
616 | is_all_xattrs_deleted = !hfsplus_attr_exists(inode, NULL); | ||
617 | |||
618 | if (!is_xattr_acl_deleted && !is_all_xattrs_deleted) | ||
619 | goto end_removexattr; | ||
620 | |||
621 | cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset); | ||
622 | |||
623 | if (cat_entry_type == HFSPLUS_FOLDER) { | ||
624 | flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
625 | offsetof(struct hfsplus_cat_folder, flags)); | ||
626 | if (is_xattr_acl_deleted) | ||
627 | flags &= ~HFSPLUS_ACL_EXISTS; | ||
628 | if (is_all_xattrs_deleted) | ||
629 | flags &= ~HFSPLUS_XATTR_EXISTS; | ||
630 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
631 | offsetof(struct hfsplus_cat_folder, flags), | ||
632 | flags); | ||
633 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
634 | } else if (cat_entry_type == HFSPLUS_FILE) { | ||
635 | flags = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
636 | offsetof(struct hfsplus_cat_file, flags)); | ||
637 | if (is_xattr_acl_deleted) | ||
638 | flags &= ~HFSPLUS_ACL_EXISTS; | ||
639 | if (is_all_xattrs_deleted) | ||
640 | flags &= ~HFSPLUS_XATTR_EXISTS; | ||
641 | hfs_bnode_write_u16(cat_fd.bnode, cat_fd.entryoffset + | ||
642 | offsetof(struct hfsplus_cat_file, flags), | ||
643 | flags); | ||
644 | hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); | ||
645 | } else { | ||
646 | printk(KERN_ERR "hfs: invalid catalog entry type\n"); | ||
647 | err = -EIO; | ||
648 | goto end_removexattr; | ||
649 | } | ||
650 | |||
651 | end_removexattr: | ||
652 | hfs_find_exit(&cat_fd); | ||
653 | return err; | ||
654 | } | ||
655 | |||
656 | static int hfsplus_osx_getxattr(struct dentry *dentry, const char *name, | ||
657 | void *buffer, size_t size, int type) | ||
658 | { | ||
659 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + | ||
660 | XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; | ||
661 | size_t len = strlen(name); | ||
662 | |||
663 | if (!strcmp(name, "")) | ||
664 | return -EINVAL; | ||
665 | |||
666 | if (len > HFSPLUS_ATTR_MAX_STRLEN) | ||
667 | return -EOPNOTSUPP; | ||
668 | |||
669 | strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); | ||
670 | strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); | ||
671 | |||
672 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
673 | } | ||
674 | |||
675 | static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name, | ||
676 | const void *buffer, size_t size, int flags, int type) | ||
677 | { | ||
678 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + | ||
679 | XATTR_MAC_OSX_PREFIX_LEN + 1] = {0}; | ||
680 | size_t len = strlen(name); | ||
681 | |||
682 | if (!strcmp(name, "")) | ||
683 | return -EINVAL; | ||
684 | |||
685 | if (len > HFSPLUS_ATTR_MAX_STRLEN) | ||
686 | return -EOPNOTSUPP; | ||
687 | |||
688 | strcpy(xattr_name, XATTR_MAC_OSX_PREFIX); | ||
689 | strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name); | ||
690 | |||
691 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
692 | } | ||
693 | |||
694 | static size_t hfsplus_osx_listxattr(struct dentry *dentry, char *list, | ||
695 | size_t list_size, const char *name, size_t name_len, int type) | ||
696 | { | ||
697 | /* | ||
698 | * This method is not used. | ||
699 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
700 | */ | ||
701 | return -EOPNOTSUPP; | ||
702 | } | ||
703 | |||
704 | const struct xattr_handler hfsplus_xattr_osx_handler = { | ||
705 | .prefix = XATTR_MAC_OSX_PREFIX, | ||
706 | .list = hfsplus_osx_listxattr, | ||
707 | .get = hfsplus_osx_getxattr, | ||
708 | .set = hfsplus_osx_setxattr, | ||
709 | }; | ||
diff --git a/fs/hfsplus/xattr.h b/fs/hfsplus/xattr.h new file mode 100644 index 000000000000..847b695b984d --- /dev/null +++ b/fs/hfsplus/xattr.h | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr.h | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Logic of processing extended attributes | ||
7 | */ | ||
8 | |||
9 | #ifndef _LINUX_HFSPLUS_XATTR_H | ||
10 | #define _LINUX_HFSPLUS_XATTR_H | ||
11 | |||
12 | #include <linux/xattr.h> | ||
13 | |||
14 | extern const struct xattr_handler hfsplus_xattr_osx_handler; | ||
15 | extern const struct xattr_handler hfsplus_xattr_user_handler; | ||
16 | extern const struct xattr_handler hfsplus_xattr_trusted_handler; | ||
17 | /*extern const struct xattr_handler hfsplus_xattr_acl_access_handler;*/ | ||
18 | /*extern const struct xattr_handler hfsplus_xattr_acl_default_handler;*/ | ||
19 | extern const struct xattr_handler hfsplus_xattr_security_handler; | ||
20 | |||
21 | extern const struct xattr_handler *hfsplus_xattr_handlers[]; | ||
22 | |||
23 | int __hfsplus_setxattr(struct inode *inode, const char *name, | ||
24 | const void *value, size_t size, int flags); | ||
25 | |||
26 | static inline int hfsplus_setxattr(struct dentry *dentry, const char *name, | ||
27 | const void *value, size_t size, int flags) | ||
28 | { | ||
29 | return __hfsplus_setxattr(dentry->d_inode, name, value, size, flags); | ||
30 | } | ||
31 | |||
32 | ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, | ||
33 | void *value, size_t size); | ||
34 | |||
35 | ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); | ||
36 | |||
37 | int hfsplus_removexattr(struct dentry *dentry, const char *name); | ||
38 | |||
39 | int hfsplus_init_security(struct inode *inode, struct inode *dir, | ||
40 | const struct qstr *qstr); | ||
41 | |||
42 | static inline int hfsplus_init_acl(struct inode *inode, struct inode *dir) | ||
43 | { | ||
44 | /*TODO: implement*/ | ||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static inline int hfsplus_init_inode_security(struct inode *inode, | ||
49 | struct inode *dir, | ||
50 | const struct qstr *qstr) | ||
51 | { | ||
52 | int err; | ||
53 | |||
54 | err = hfsplus_init_acl(inode, dir); | ||
55 | if (!err) | ||
56 | err = hfsplus_init_security(inode, dir, qstr); | ||
57 | return err; | ||
58 | } | ||
59 | |||
60 | #endif | ||
diff --git a/fs/hfsplus/xattr_security.c b/fs/hfsplus/xattr_security.c new file mode 100644 index 000000000000..83b842f113c5 --- /dev/null +++ b/fs/hfsplus/xattr_security.c | |||
@@ -0,0 +1,104 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr_trusted.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Handler for storing security labels as extended attributes. | ||
7 | */ | ||
8 | |||
9 | #include <linux/security.h> | ||
10 | #include "hfsplus_fs.h" | ||
11 | #include "xattr.h" | ||
12 | |||
13 | static int hfsplus_security_getxattr(struct dentry *dentry, const char *name, | ||
14 | void *buffer, size_t size, int type) | ||
15 | { | ||
16 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
17 | size_t len = strlen(name); | ||
18 | |||
19 | if (!strcmp(name, "")) | ||
20 | return -EINVAL; | ||
21 | |||
22 | if (len + XATTR_SECURITY_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
23 | return -EOPNOTSUPP; | ||
24 | |||
25 | strcpy(xattr_name, XATTR_SECURITY_PREFIX); | ||
26 | strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); | ||
27 | |||
28 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
29 | } | ||
30 | |||
31 | static int hfsplus_security_setxattr(struct dentry *dentry, const char *name, | ||
32 | const void *buffer, size_t size, int flags, int type) | ||
33 | { | ||
34 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
35 | size_t len = strlen(name); | ||
36 | |||
37 | if (!strcmp(name, "")) | ||
38 | return -EINVAL; | ||
39 | |||
40 | if (len + XATTR_SECURITY_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
41 | return -EOPNOTSUPP; | ||
42 | |||
43 | strcpy(xattr_name, XATTR_SECURITY_PREFIX); | ||
44 | strcpy(xattr_name + XATTR_SECURITY_PREFIX_LEN, name); | ||
45 | |||
46 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
47 | } | ||
48 | |||
49 | static size_t hfsplus_security_listxattr(struct dentry *dentry, char *list, | ||
50 | size_t list_size, const char *name, size_t name_len, int type) | ||
51 | { | ||
52 | /* | ||
53 | * This method is not used. | ||
54 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
55 | */ | ||
56 | return -EOPNOTSUPP; | ||
57 | } | ||
58 | |||
59 | static int hfsplus_initxattrs(struct inode *inode, | ||
60 | const struct xattr *xattr_array, | ||
61 | void *fs_info) | ||
62 | { | ||
63 | const struct xattr *xattr; | ||
64 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
65 | size_t xattr_name_len; | ||
66 | int err = 0; | ||
67 | |||
68 | for (xattr = xattr_array; xattr->name != NULL; xattr++) { | ||
69 | xattr_name_len = strlen(xattr->name); | ||
70 | |||
71 | if (xattr_name_len == 0) | ||
72 | continue; | ||
73 | |||
74 | if (xattr_name_len + XATTR_SECURITY_PREFIX_LEN > | ||
75 | HFSPLUS_ATTR_MAX_STRLEN) | ||
76 | return -EOPNOTSUPP; | ||
77 | |||
78 | strcpy(xattr_name, XATTR_SECURITY_PREFIX); | ||
79 | strcpy(xattr_name + | ||
80 | XATTR_SECURITY_PREFIX_LEN, xattr->name); | ||
81 | memset(xattr_name + | ||
82 | XATTR_SECURITY_PREFIX_LEN + xattr_name_len, 0, 1); | ||
83 | |||
84 | err = __hfsplus_setxattr(inode, xattr_name, | ||
85 | xattr->value, xattr->value_len, 0); | ||
86 | if (err) | ||
87 | break; | ||
88 | } | ||
89 | return err; | ||
90 | } | ||
91 | |||
92 | int hfsplus_init_security(struct inode *inode, struct inode *dir, | ||
93 | const struct qstr *qstr) | ||
94 | { | ||
95 | return security_inode_init_security(inode, dir, qstr, | ||
96 | &hfsplus_initxattrs, NULL); | ||
97 | } | ||
98 | |||
99 | const struct xattr_handler hfsplus_xattr_security_handler = { | ||
100 | .prefix = XATTR_SECURITY_PREFIX, | ||
101 | .list = hfsplus_security_listxattr, | ||
102 | .get = hfsplus_security_getxattr, | ||
103 | .set = hfsplus_security_setxattr, | ||
104 | }; | ||
diff --git a/fs/hfsplus/xattr_trusted.c b/fs/hfsplus/xattr_trusted.c new file mode 100644 index 000000000000..426cee277542 --- /dev/null +++ b/fs/hfsplus/xattr_trusted.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr_trusted.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Handler for trusted extended attributes. | ||
7 | */ | ||
8 | |||
9 | #include "hfsplus_fs.h" | ||
10 | #include "xattr.h" | ||
11 | |||
12 | static int hfsplus_trusted_getxattr(struct dentry *dentry, const char *name, | ||
13 | void *buffer, size_t size, int type) | ||
14 | { | ||
15 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
16 | size_t len = strlen(name); | ||
17 | |||
18 | if (!strcmp(name, "")) | ||
19 | return -EINVAL; | ||
20 | |||
21 | if (len + XATTR_TRUSTED_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
22 | return -EOPNOTSUPP; | ||
23 | |||
24 | strcpy(xattr_name, XATTR_TRUSTED_PREFIX); | ||
25 | strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); | ||
26 | |||
27 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
28 | } | ||
29 | |||
30 | static int hfsplus_trusted_setxattr(struct dentry *dentry, const char *name, | ||
31 | const void *buffer, size_t size, int flags, int type) | ||
32 | { | ||
33 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
34 | size_t len = strlen(name); | ||
35 | |||
36 | if (!strcmp(name, "")) | ||
37 | return -EINVAL; | ||
38 | |||
39 | if (len + XATTR_TRUSTED_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
40 | return -EOPNOTSUPP; | ||
41 | |||
42 | strcpy(xattr_name, XATTR_TRUSTED_PREFIX); | ||
43 | strcpy(xattr_name + XATTR_TRUSTED_PREFIX_LEN, name); | ||
44 | |||
45 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
46 | } | ||
47 | |||
48 | static size_t hfsplus_trusted_listxattr(struct dentry *dentry, char *list, | ||
49 | size_t list_size, const char *name, size_t name_len, int type) | ||
50 | { | ||
51 | /* | ||
52 | * This method is not used. | ||
53 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
54 | */ | ||
55 | return -EOPNOTSUPP; | ||
56 | } | ||
57 | |||
58 | const struct xattr_handler hfsplus_xattr_trusted_handler = { | ||
59 | .prefix = XATTR_TRUSTED_PREFIX, | ||
60 | .list = hfsplus_trusted_listxattr, | ||
61 | .get = hfsplus_trusted_getxattr, | ||
62 | .set = hfsplus_trusted_setxattr, | ||
63 | }; | ||
diff --git a/fs/hfsplus/xattr_user.c b/fs/hfsplus/xattr_user.c new file mode 100644 index 000000000000..e34016561ae0 --- /dev/null +++ b/fs/hfsplus/xattr_user.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * linux/fs/hfsplus/xattr_user.c | ||
3 | * | ||
4 | * Vyacheslav Dubeyko <slava@dubeyko.com> | ||
5 | * | ||
6 | * Handler for user extended attributes. | ||
7 | */ | ||
8 | |||
9 | #include "hfsplus_fs.h" | ||
10 | #include "xattr.h" | ||
11 | |||
12 | static int hfsplus_user_getxattr(struct dentry *dentry, const char *name, | ||
13 | void *buffer, size_t size, int type) | ||
14 | { | ||
15 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
16 | size_t len = strlen(name); | ||
17 | |||
18 | if (!strcmp(name, "")) | ||
19 | return -EINVAL; | ||
20 | |||
21 | if (len + XATTR_USER_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
22 | return -EOPNOTSUPP; | ||
23 | |||
24 | strcpy(xattr_name, XATTR_USER_PREFIX); | ||
25 | strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); | ||
26 | |||
27 | return hfsplus_getxattr(dentry, xattr_name, buffer, size); | ||
28 | } | ||
29 | |||
30 | static int hfsplus_user_setxattr(struct dentry *dentry, const char *name, | ||
31 | const void *buffer, size_t size, int flags, int type) | ||
32 | { | ||
33 | char xattr_name[HFSPLUS_ATTR_MAX_STRLEN + 1] = {0}; | ||
34 | size_t len = strlen(name); | ||
35 | |||
36 | if (!strcmp(name, "")) | ||
37 | return -EINVAL; | ||
38 | |||
39 | if (len + XATTR_USER_PREFIX_LEN > HFSPLUS_ATTR_MAX_STRLEN) | ||
40 | return -EOPNOTSUPP; | ||
41 | |||
42 | strcpy(xattr_name, XATTR_USER_PREFIX); | ||
43 | strcpy(xattr_name + XATTR_USER_PREFIX_LEN, name); | ||
44 | |||
45 | return hfsplus_setxattr(dentry, xattr_name, buffer, size, flags); | ||
46 | } | ||
47 | |||
48 | static size_t hfsplus_user_listxattr(struct dentry *dentry, char *list, | ||
49 | size_t list_size, const char *name, size_t name_len, int type) | ||
50 | { | ||
51 | /* | ||
52 | * This method is not used. | ||
53 | * It is used hfsplus_listxattr() instead of generic_listxattr(). | ||
54 | */ | ||
55 | return -EOPNOTSUPP; | ||
56 | } | ||
57 | |||
58 | const struct xattr_handler hfsplus_xattr_user_handler = { | ||
59 | .prefix = XATTR_USER_PREFIX, | ||
60 | .list = hfsplus_user_listxattr, | ||
61 | .get = hfsplus_user_getxattr, | ||
62 | .set = hfsplus_user_setxattr, | ||
63 | }; | ||