~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/hfsplus/xattr.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp