Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Vyacheslav Dubeyko and committed by
Linus Torvalds
127e5f5a 3e05ca20

+999
+709
fs/hfsplus/xattr.c
··· 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 + };
+60
fs/hfsplus/xattr.h
··· 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
+104
fs/hfsplus/xattr_security.c
··· 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 + };
+63
fs/hfsplus/xattr_trusted.c
··· 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 + };
+63
fs/hfsplus/xattr_user.c
··· 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 + };