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

hfsplus: add support of manipulation by attributes file

Add support of manipulation by attributes file.

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
324ef39a 127e5f5a

+287 -183
+2 -2
fs/hfsplus/Makefile
··· 5 5 obj-$(CONFIG_HFSPLUS_FS) += hfsplus.o 6 6 7 7 hfsplus-objs := super.o options.o inode.o ioctl.o extents.o catalog.o dir.o btree.o \ 8 - bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o 9 - 8 + bnode.o brec.o bfind.o tables.o unicode.o wrapper.o bitmap.o part_tbl.o \ 9 + attributes.o xattr.o xattr_user.o xattr_security.o xattr_trusted.o
+80 -13
fs/hfsplus/bfind.c
··· 24 24 fd->key = ptr + tree->max_key_len + 2; 25 25 dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", 26 26 tree->cnid, __builtin_return_address(0)); 27 - mutex_lock(&tree->tree_lock); 27 + switch (tree->cnid) { 28 + case HFSPLUS_CAT_CNID: 29 + mutex_lock_nested(&tree->tree_lock, CATALOG_BTREE_MUTEX); 30 + break; 31 + case HFSPLUS_EXT_CNID: 32 + mutex_lock_nested(&tree->tree_lock, EXTENTS_BTREE_MUTEX); 33 + break; 34 + case HFSPLUS_ATTR_CNID: 35 + mutex_lock_nested(&tree->tree_lock, ATTR_BTREE_MUTEX); 36 + break; 37 + default: 38 + BUG(); 39 + } 28 40 return 0; 29 41 } 30 42 ··· 50 38 fd->tree = NULL; 51 39 } 52 40 53 - /* Find the record in bnode that best matches key (not greater than...)*/ 54 - int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd) 41 + int hfs_find_1st_rec_by_cnid(struct hfs_bnode *bnode, 42 + struct hfs_find_data *fd, 43 + int *begin, 44 + int *end, 45 + int *cur_rec) 46 + { 47 + __be32 cur_cnid, search_cnid; 48 + 49 + if (bnode->tree->cnid == HFSPLUS_EXT_CNID) { 50 + cur_cnid = fd->key->ext.cnid; 51 + search_cnid = fd->search_key->ext.cnid; 52 + } else if (bnode->tree->cnid == HFSPLUS_CAT_CNID) { 53 + cur_cnid = fd->key->cat.parent; 54 + search_cnid = fd->search_key->cat.parent; 55 + } else if (bnode->tree->cnid == HFSPLUS_ATTR_CNID) { 56 + cur_cnid = fd->key->attr.cnid; 57 + search_cnid = fd->search_key->attr.cnid; 58 + } else 59 + BUG(); 60 + 61 + if (cur_cnid == search_cnid) { 62 + (*end) = (*cur_rec); 63 + if ((*begin) == (*end)) 64 + return 1; 65 + } else { 66 + if (be32_to_cpu(cur_cnid) < be32_to_cpu(search_cnid)) 67 + (*begin) = (*cur_rec) + 1; 68 + else 69 + (*end) = (*cur_rec) - 1; 70 + } 71 + 72 + return 0; 73 + } 74 + 75 + int hfs_find_rec_by_key(struct hfs_bnode *bnode, 76 + struct hfs_find_data *fd, 77 + int *begin, 78 + int *end, 79 + int *cur_rec) 55 80 { 56 81 int cmpval; 82 + 83 + cmpval = bnode->tree->keycmp(fd->key, fd->search_key); 84 + if (!cmpval) { 85 + (*end) = (*cur_rec); 86 + return 1; 87 + } 88 + if (cmpval < 0) 89 + (*begin) = (*cur_rec) + 1; 90 + else 91 + *(end) = (*cur_rec) - 1; 92 + 93 + return 0; 94 + } 95 + 96 + /* Find the record in bnode that best matches key (not greater than...)*/ 97 + int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd, 98 + search_strategy_t rec_found) 99 + { 57 100 u16 off, len, keylen; 58 101 int rec; 59 102 int b, e; 60 103 int res; 104 + 105 + if (!rec_found) 106 + BUG(); 61 107 62 108 b = 0; 63 109 e = bnode->num_recs - 1; ··· 129 59 goto fail; 130 60 } 131 61 hfs_bnode_read(bnode, fd->key, off, keylen); 132 - cmpval = bnode->tree->keycmp(fd->key, fd->search_key); 133 - if (!cmpval) { 134 - e = rec; 62 + if (rec_found(bnode, fd, &b, &e, &rec)) { 135 63 res = 0; 136 64 goto done; 137 65 } 138 - if (cmpval < 0) 139 - b = rec + 1; 140 - else 141 - e = rec - 1; 142 66 } while (b <= e); 67 + 143 68 if (rec != e && e >= 0) { 144 69 len = hfs_brec_lenoff(bnode, e, &off); 145 70 keylen = hfs_brec_keylen(bnode, e); ··· 144 79 } 145 80 hfs_bnode_read(bnode, fd->key, off, keylen); 146 81 } 82 + 147 83 done: 148 84 fd->record = e; 149 85 fd->keyoffset = off; 150 86 fd->keylength = keylen; 151 87 fd->entryoffset = off + keylen; 152 88 fd->entrylength = len - keylen; 89 + 153 90 fail: 154 91 return res; 155 92 } 156 93 157 94 /* Traverse a B*Tree from the root to a leaf finding best fit to key */ 158 95 /* Return allocated copy of node found, set recnum to best record */ 159 - int hfs_brec_find(struct hfs_find_data *fd) 96 + int hfs_brec_find(struct hfs_find_data *fd, search_strategy_t do_key_compare) 160 97 { 161 98 struct hfs_btree *tree; 162 99 struct hfs_bnode *bnode; ··· 189 122 goto invalid; 190 123 bnode->parent = parent; 191 124 192 - res = __hfs_brec_find(bnode, fd); 125 + res = __hfs_brec_find(bnode, fd, do_key_compare); 193 126 if (!height) 194 127 break; 195 128 if (fd->record < 0) ··· 216 149 { 217 150 int res; 218 151 219 - res = hfs_brec_find(fd); 152 + res = hfs_brec_find(fd, hfs_find_rec_by_key); 220 153 if (res) 221 154 return res; 222 155 if (fd->entrylength > rec_len)
+4 -2
fs/hfsplus/bnode.c
··· 62 62 63 63 tree = node->tree; 64 64 if (node->type == HFS_NODE_LEAF || 65 - tree->attributes & HFS_TREE_VARIDXKEYS) 65 + tree->attributes & HFS_TREE_VARIDXKEYS || 66 + node->tree->cnid == HFSPLUS_ATTR_CNID) 66 67 key_len = hfs_bnode_read_u16(node, off) + 2; 67 68 else 68 69 key_len = tree->max_key_len + 2; ··· 315 314 if (i && node->type == HFS_NODE_INDEX) { 316 315 int tmp; 317 316 318 - if (node->tree->attributes & HFS_TREE_VARIDXKEYS) 317 + if (node->tree->attributes & HFS_TREE_VARIDXKEYS || 318 + node->tree->cnid == HFSPLUS_ATTR_CNID) 319 319 tmp = hfs_bnode_read_u16(node, key_off) + 2; 320 320 else 321 321 tmp = node->tree->max_key_len + 2;
+14 -9
fs/hfsplus/brec.c
··· 36 36 return 0; 37 37 38 38 if ((node->type == HFS_NODE_INDEX) && 39 - !(node->tree->attributes & HFS_TREE_VARIDXKEYS)) { 39 + !(node->tree->attributes & HFS_TREE_VARIDXKEYS) && 40 + (node->tree->cnid != HFSPLUS_ATTR_CNID)) { 40 41 retval = node->tree->max_key_len + 2; 41 42 } else { 42 43 recoff = hfs_bnode_read_u16(node, ··· 152 151 153 152 /* get index key */ 154 153 hfs_bnode_read_key(new_node, fd->search_key, 14); 155 - __hfs_brec_find(fd->bnode, fd); 154 + __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); 156 155 157 156 hfs_bnode_put(new_node); 158 157 new_node = NULL; 159 158 160 - if (tree->attributes & HFS_TREE_VARIDXKEYS) 159 + if ((tree->attributes & HFS_TREE_VARIDXKEYS) || 160 + (tree->cnid == HFSPLUS_ATTR_CNID)) 161 161 key_len = be16_to_cpu(fd->search_key->key_len) + 2; 162 162 else { 163 163 fd->search_key->key_len = ··· 203 201 hfs_bnode_put(node); 204 202 node = fd->bnode = parent; 205 203 206 - __hfs_brec_find(node, fd); 204 + __hfs_brec_find(node, fd, hfs_find_rec_by_key); 207 205 goto again; 208 206 } 209 207 hfs_bnode_write_u16(node, ··· 369 367 parent = hfs_bnode_find(tree, node->parent); 370 368 if (IS_ERR(parent)) 371 369 return PTR_ERR(parent); 372 - __hfs_brec_find(parent, fd); 370 + __hfs_brec_find(parent, fd, hfs_find_rec_by_key); 373 371 hfs_bnode_dump(parent); 374 372 rec = fd->record; 375 373 376 374 /* size difference between old and new key */ 377 - if (tree->attributes & HFS_TREE_VARIDXKEYS) 375 + if ((tree->attributes & HFS_TREE_VARIDXKEYS) || 376 + (tree->cnid == HFSPLUS_ATTR_CNID)) 378 377 newkeylen = hfs_bnode_read_u16(node, 14) + 2; 379 378 else 380 379 fd->keylength = newkeylen = tree->max_key_len + 2; ··· 430 427 hfs_bnode_read_key(new_node, fd->search_key, 14); 431 428 cnid = cpu_to_be32(new_node->this); 432 429 433 - __hfs_brec_find(fd->bnode, fd); 430 + __hfs_brec_find(fd->bnode, fd, hfs_find_rec_by_key); 434 431 hfs_brec_insert(fd, &cnid, sizeof(cnid)); 435 432 hfs_bnode_put(fd->bnode); 436 433 hfs_bnode_put(new_node); ··· 498 495 /* insert old root idx into new root */ 499 496 node->parent = tree->root; 500 497 if (node->type == HFS_NODE_LEAF || 501 - tree->attributes & HFS_TREE_VARIDXKEYS) 498 + tree->attributes & HFS_TREE_VARIDXKEYS || 499 + tree->cnid == HFSPLUS_ATTR_CNID) 502 500 key_size = hfs_bnode_read_u16(node, 14) + 2; 503 501 else 504 502 key_size = tree->max_key_len + 2; 505 503 hfs_bnode_copy(new_node, 14, node, 14, key_size); 506 504 507 - if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) { 505 + if (!(tree->attributes & HFS_TREE_VARIDXKEYS) && 506 + (tree->cnid != HFSPLUS_ATTR_CNID)) { 508 507 key_size = tree->max_key_len + 2; 509 508 hfs_bnode_write_u16(new_node, 14, tree->max_key_len); 510 509 }
+8
fs/hfsplus/btree.c
··· 98 98 set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags); 99 99 } 100 100 break; 101 + case HFSPLUS_ATTR_CNID: 102 + if (tree->max_key_len != HFSPLUS_ATTR_KEYLEN - sizeof(u16)) { 103 + printk(KERN_ERR "hfs: invalid attributes max_key_len %d\n", 104 + tree->max_key_len); 105 + goto fail_page; 106 + } 107 + tree->keycmp = hfsplus_attr_bin_cmp_key; 108 + break; 101 109 default: 102 110 printk(KERN_ERR "hfs: unknown B*Tree requested\n"); 103 111 goto fail_page;
+22 -14
fs/hfsplus/catalog.c
··· 45 45 46 46 key->cat.parent = cpu_to_be32(parent); 47 47 if (str) { 48 - hfsplus_asc2uni(sb, &key->cat.name, str->name, str->len); 48 + hfsplus_asc2uni(sb, &key->cat.name, HFSPLUS_MAX_STRLEN, 49 + str->name, str->len); 49 50 len = be16_to_cpu(key->cat.name.length); 50 51 } else { 51 52 key->cat.name.length = 0; ··· 168 167 entry->type = cpu_to_be16(type); 169 168 entry->thread.reserved = 0; 170 169 entry->thread.parentID = cpu_to_be32(parentid); 171 - hfsplus_asc2uni(sb, &entry->thread.nodeName, str->name, str->len); 170 + hfsplus_asc2uni(sb, &entry->thread.nodeName, HFSPLUS_MAX_STRLEN, 171 + str->name, str->len); 172 172 return 10 + be16_to_cpu(entry->thread.nodeName.length) * 2; 173 173 } 174 174 ··· 200 198 hfsplus_cat_build_key_uni(fd->search_key, 201 199 be32_to_cpu(tmp.thread.parentID), 202 200 &tmp.thread.nodeName); 203 - return hfs_brec_find(fd); 201 + return hfs_brec_find(fd, hfs_find_rec_by_key); 204 202 } 205 203 206 204 int hfsplus_create_cat(u32 cnid, struct inode *dir, ··· 223 221 S_ISDIR(inode->i_mode) ? 224 222 HFSPLUS_FOLDER_THREAD : HFSPLUS_FILE_THREAD, 225 223 dir->i_ino, str); 226 - err = hfs_brec_find(&fd); 224 + err = hfs_brec_find(&fd, hfs_find_rec_by_key); 227 225 if (err != -ENOENT) { 228 226 if (!err) 229 227 err = -EEXIST; ··· 235 233 236 234 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 237 235 entry_size = hfsplus_cat_build_record(&entry, cnid, inode); 238 - err = hfs_brec_find(&fd); 236 + err = hfs_brec_find(&fd, hfs_find_rec_by_key); 239 237 if (err != -ENOENT) { 240 238 /* panic? */ 241 239 if (!err) ··· 255 253 256 254 err1: 257 255 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); 258 - if (!hfs_brec_find(&fd)) 256 + if (!hfs_brec_find(&fd, hfs_find_rec_by_key)) 259 257 hfs_brec_remove(&fd); 260 258 err2: 261 259 hfs_find_exit(&fd); ··· 281 279 int len; 282 280 283 281 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); 284 - err = hfs_brec_find(&fd); 282 + err = hfs_brec_find(&fd, hfs_find_rec_by_key); 285 283 if (err) 286 284 goto out; 287 285 ··· 298 296 } else 299 297 hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, str); 300 298 301 - err = hfs_brec_find(&fd); 299 + err = hfs_brec_find(&fd, hfs_find_rec_by_key); 302 300 if (err) 303 301 goto out; 304 302 ··· 328 326 goto out; 329 327 330 328 hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL); 331 - err = hfs_brec_find(&fd); 329 + err = hfs_brec_find(&fd, hfs_find_rec_by_key); 332 330 if (err) 333 331 goto out; 334 332 ··· 339 337 dir->i_size--; 340 338 dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; 341 339 hfsplus_mark_inode_dirty(dir, HFSPLUS_I_CAT_DIRTY); 340 + 341 + if (type == HFSPLUS_FILE || type == HFSPLUS_FOLDER) { 342 + if (HFSPLUS_SB(sb)->attr_tree) 343 + hfsplus_delete_all_attrs(dir, cnid); 344 + } 345 + 342 346 out: 343 347 hfs_find_exit(&fd); 344 348 ··· 371 363 372 364 /* find the old dir entry and read the data */ 373 365 hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); 374 - err = hfs_brec_find(&src_fd); 366 + err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 375 367 if (err) 376 368 goto out; 377 369 if (src_fd.entrylength > sizeof(entry) || src_fd.entrylength < 0) { ··· 384 376 385 377 /* create new dir entry with the data from the old entry */ 386 378 hfsplus_cat_build_key(sb, dst_fd.search_key, dst_dir->i_ino, dst_name); 387 - err = hfs_brec_find(&dst_fd); 379 + err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 388 380 if (err != -ENOENT) { 389 381 if (!err) 390 382 err = -EEXIST; ··· 399 391 400 392 /* finally remove the old entry */ 401 393 hfsplus_cat_build_key(sb, src_fd.search_key, src_dir->i_ino, src_name); 402 - err = hfs_brec_find(&src_fd); 394 + err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 403 395 if (err) 404 396 goto out; 405 397 err = hfs_brec_remove(&src_fd); ··· 410 402 411 403 /* remove old thread entry */ 412 404 hfsplus_cat_build_key(sb, src_fd.search_key, cnid, NULL); 413 - err = hfs_brec_find(&src_fd); 405 + err = hfs_brec_find(&src_fd, hfs_find_rec_by_key); 414 406 if (err) 415 407 goto out; 416 408 type = hfs_bnode_read_u16(src_fd.bnode, src_fd.entryoffset); ··· 422 414 hfsplus_cat_build_key(sb, dst_fd.search_key, cnid, NULL); 423 415 entry_size = hfsplus_fill_cat_thread(sb, &entry, type, 424 416 dst_dir->i_ino, dst_name); 425 - err = hfs_brec_find(&dst_fd); 417 + err = hfs_brec_find(&dst_fd, hfs_find_rec_by_key); 426 418 if (err != -ENOENT) { 427 419 if (!err) 428 420 err = -EEXIST;
+40 -15
fs/hfsplus/dir.c
··· 15 15 16 16 #include "hfsplus_fs.h" 17 17 #include "hfsplus_raw.h" 18 + #include "xattr.h" 18 19 19 20 static inline void hfsplus_instantiate(struct dentry *dentry, 20 21 struct inode *inode, u32 cnid) ··· 139 138 if (err) 140 139 return err; 141 140 hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL); 142 - err = hfs_brec_find(&fd); 141 + err = hfs_brec_find(&fd, hfs_find_rec_by_key); 143 142 if (err) 144 143 goto out; 145 144 ··· 422 421 if (res) 423 422 goto out_err; 424 423 424 + res = hfsplus_init_inode_security(inode, dir, &dentry->d_name); 425 + if (res == -EOPNOTSUPP) 426 + res = 0; /* Operation is not supported. */ 427 + else if (res) { 428 + /* Try to delete anyway without error analysis. */ 429 + hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); 430 + goto out_err; 431 + } 432 + 425 433 hfsplus_instantiate(dentry, inode, inode->i_ino); 426 434 mark_inode_dirty(inode); 427 435 goto out; ··· 460 450 init_special_inode(inode, mode, rdev); 461 451 462 452 res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode); 463 - if (res) { 464 - clear_nlink(inode); 465 - hfsplus_delete_inode(inode); 466 - iput(inode); 467 - goto out; 453 + if (res) 454 + goto failed_mknod; 455 + 456 + res = hfsplus_init_inode_security(inode, dir, &dentry->d_name); 457 + if (res == -EOPNOTSUPP) 458 + res = 0; /* Operation is not supported. */ 459 + else if (res) { 460 + /* Try to delete anyway without error analysis. */ 461 + hfsplus_delete_cat(inode->i_ino, dir, &dentry->d_name); 462 + goto failed_mknod; 468 463 } 469 464 470 465 hfsplus_instantiate(dentry, inode, inode->i_ino); 471 466 mark_inode_dirty(inode); 467 + goto out; 468 + 469 + failed_mknod: 470 + clear_nlink(inode); 471 + hfsplus_delete_inode(inode); 472 + iput(inode); 472 473 out: 473 474 mutex_unlock(&sbi->vh_mutex); 474 475 return res; ··· 520 499 } 521 500 522 501 const struct inode_operations hfsplus_dir_inode_operations = { 523 - .lookup = hfsplus_lookup, 524 - .create = hfsplus_create, 525 - .link = hfsplus_link, 526 - .unlink = hfsplus_unlink, 527 - .mkdir = hfsplus_mkdir, 528 - .rmdir = hfsplus_rmdir, 529 - .symlink = hfsplus_symlink, 530 - .mknod = hfsplus_mknod, 531 - .rename = hfsplus_rename, 502 + .lookup = hfsplus_lookup, 503 + .create = hfsplus_create, 504 + .link = hfsplus_link, 505 + .unlink = hfsplus_unlink, 506 + .mkdir = hfsplus_mkdir, 507 + .rmdir = hfsplus_rmdir, 508 + .symlink = hfsplus_symlink, 509 + .mknod = hfsplus_mknod, 510 + .rename = hfsplus_rename, 511 + .setxattr = generic_setxattr, 512 + .getxattr = generic_getxattr, 513 + .listxattr = hfsplus_listxattr, 514 + .removexattr = hfsplus_removexattr, 532 515 }; 533 516 534 517 const struct file_operations hfsplus_dir_operations = {
+2 -2
fs/hfsplus/extents.c
··· 95 95 HFSPLUS_IS_RSRC(inode) ? 96 96 HFSPLUS_TYPE_RSRC : HFSPLUS_TYPE_DATA); 97 97 98 - res = hfs_brec_find(fd); 98 + res = hfs_brec_find(fd, hfs_find_rec_by_key); 99 99 if (hip->extent_state & HFSPLUS_EXT_NEW) { 100 100 if (res != -ENOENT) 101 101 return; ··· 154 154 155 155 hfsplus_ext_build_key(fd->search_key, cnid, block, type); 156 156 fd->key->ext.cnid = 0; 157 - res = hfs_brec_find(fd); 157 + res = hfs_brec_find(fd, hfs_find_rec_by_key); 158 158 if (res && res != -ENOENT) 159 159 return res; 160 160 if (fd->key->ext.cnid != fd->search_key->ext.cnid ||
+43 -9
fs/hfsplus/hfsplus_fs.h
··· 23 23 #define DBG_SUPER 0x00000010 24 24 #define DBG_EXTENT 0x00000020 25 25 #define DBG_BITMAP 0x00000040 26 + #define DBG_ATTR_MOD 0x00000080 26 27 27 28 #if 0 28 29 #define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD) ··· 46 45 const hfsplus_btree_key *); 47 46 48 47 #define NODE_HASH_SIZE 256 48 + 49 + /* B-tree mutex nested subclasses */ 50 + enum hfsplus_btree_mutex_classes { 51 + CATALOG_BTREE_MUTEX, 52 + EXTENTS_BTREE_MUTEX, 53 + ATTR_BTREE_MUTEX, 54 + }; 49 55 50 56 /* An HFS+ BTree held in memory */ 51 57 struct hfs_btree { ··· 231 223 #define HFSPLUS_I_CAT_DIRTY 1 /* has changes in the catalog tree */ 232 224 #define HFSPLUS_I_EXT_DIRTY 2 /* has changes in the extent tree */ 233 225 #define HFSPLUS_I_ALLOC_DIRTY 3 /* has changes in the allocation file */ 226 + #define HFSPLUS_I_ATTR_DIRTY 4 /* has changes in the attributes tree */ 234 227 235 228 #define HFSPLUS_IS_RSRC(inode) \ 236 229 test_bit(HFSPLUS_I_RSRC, &HFSPLUS_I(inode)->flags) ··· 311 302 #define hfs_brec_remove hfsplus_brec_remove 312 303 #define hfs_find_init hfsplus_find_init 313 304 #define hfs_find_exit hfsplus_find_exit 314 - #define __hfs_brec_find __hplusfs_brec_find 305 + #define __hfs_brec_find __hfsplus_brec_find 315 306 #define hfs_brec_find hfsplus_brec_find 316 307 #define hfs_brec_read hfsplus_brec_read 317 308 #define hfs_brec_goto hfsplus_brec_goto ··· 333 324 */ 334 325 #define HFSPLUS_IOC_BLESS _IO('h', 0x80) 335 326 327 + typedef int (*search_strategy_t)(struct hfs_bnode *, 328 + struct hfs_find_data *, 329 + int *, int *, int *); 330 + 336 331 /* 337 332 * Functions in any *.c used in other files 338 333 */ 334 + 335 + /* attributes.c */ 336 + int hfsplus_create_attr_tree_cache(void); 337 + void hfsplus_destroy_attr_tree_cache(void); 338 + hfsplus_attr_entry *hfsplus_alloc_attr_entry(void); 339 + void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry_p); 340 + int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *, 341 + const hfsplus_btree_key *); 342 + int hfsplus_attr_build_key(struct super_block *, hfsplus_btree_key *, 343 + u32, const char *); 344 + void hfsplus_attr_build_key_uni(hfsplus_btree_key *key, 345 + u32 cnid, 346 + struct hfsplus_attr_unistr *name); 347 + int hfsplus_find_attr(struct super_block *, u32, 348 + const char *, struct hfs_find_data *); 349 + int hfsplus_attr_exists(struct inode *inode, const char *name); 350 + int hfsplus_create_attr(struct inode *, const char *, const void *, size_t); 351 + int hfsplus_delete_attr(struct inode *, const char *); 352 + int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid); 339 353 340 354 /* bitmap.c */ 341 355 int hfsplus_block_allocate(struct super_block *, u32, u32, u32 *); ··· 401 369 /* bfind.c */ 402 370 int hfs_find_init(struct hfs_btree *, struct hfs_find_data *); 403 371 void hfs_find_exit(struct hfs_find_data *); 404 - int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *); 405 - int hfs_brec_find(struct hfs_find_data *); 372 + int hfs_find_1st_rec_by_cnid(struct hfs_bnode *, 373 + struct hfs_find_data *, 374 + int *, int *, int *); 375 + int hfs_find_rec_by_key(struct hfs_bnode *, 376 + struct hfs_find_data *, 377 + int *, int *, int *); 378 + int __hfs_brec_find(struct hfs_bnode *, struct hfs_find_data *, 379 + search_strategy_t); 380 + int hfs_brec_find(struct hfs_find_data *, search_strategy_t); 406 381 int hfs_brec_read(struct hfs_find_data *, void *, int); 407 382 int hfs_brec_goto(struct hfs_find_data *, int); 408 383 ··· 456 417 457 418 /* ioctl.c */ 458 419 long hfsplus_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); 459 - int hfsplus_setxattr(struct dentry *dentry, const char *name, 460 - const void *value, size_t size, int flags); 461 - ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, 462 - void *value, size_t size); 463 - ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size); 464 420 465 421 /* options.c */ 466 422 int hfsplus_parse_options(char *, struct hfsplus_sb_info *); ··· 480 446 int hfsplus_uni2asc(struct super_block *, 481 447 const struct hfsplus_unistr *, char *, int *); 482 448 int hfsplus_asc2uni(struct super_block *, 483 - struct hfsplus_unistr *, const char *, int); 449 + struct hfsplus_unistr *, int, const char *, int); 484 450 int hfsplus_hash_dentry(const struct dentry *dentry, 485 451 const struct inode *inode, struct qstr *str); 486 452 int hfsplus_compare_dentry(const struct dentry *parent,
+16 -2
fs/hfsplus/inode.c
··· 17 17 18 18 #include "hfsplus_fs.h" 19 19 #include "hfsplus_raw.h" 20 + #include "xattr.h" 20 21 21 22 static int hfsplus_readpage(struct file *file, struct page *page) 22 23 { ··· 349 348 error = error2; 350 349 } 351 350 351 + if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) { 352 + if (sbi->attr_tree) { 353 + error2 = 354 + filemap_write_and_wait( 355 + sbi->attr_tree->inode->i_mapping); 356 + if (!error) 357 + error = error2; 358 + } else { 359 + printk(KERN_ERR "hfs: sync non-existent attributes tree\n"); 360 + } 361 + } 362 + 352 363 if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { 353 364 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); 354 365 if (!error) ··· 378 365 static const struct inode_operations hfsplus_file_inode_operations = { 379 366 .lookup = hfsplus_file_lookup, 380 367 .setattr = hfsplus_setattr, 381 - .setxattr = hfsplus_setxattr, 382 - .getxattr = hfsplus_getxattr, 368 + .setxattr = generic_setxattr, 369 + .getxattr = generic_getxattr, 383 370 .listxattr = hfsplus_listxattr, 371 + .removexattr = hfsplus_removexattr, 384 372 }; 385 373 386 374 static const struct file_operations hfsplus_file_operations = {
-108
fs/hfsplus/ioctl.c
··· 16 16 #include <linux/fs.h> 17 17 #include <linux/mount.h> 18 18 #include <linux/sched.h> 19 - #include <linux/xattr.h> 20 19 #include <asm/uaccess.h> 21 20 #include "hfsplus_fs.h" 22 21 ··· 149 150 default: 150 151 return -ENOTTY; 151 152 } 152 - } 153 - 154 - int hfsplus_setxattr(struct dentry *dentry, const char *name, 155 - const void *value, size_t size, int flags) 156 - { 157 - struct inode *inode = dentry->d_inode; 158 - struct hfs_find_data fd; 159 - hfsplus_cat_entry entry; 160 - struct hfsplus_cat_file *file; 161 - int res; 162 - 163 - if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 164 - return -EOPNOTSUPP; 165 - 166 - res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 167 - if (res) 168 - return res; 169 - res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 170 - if (res) 171 - goto out; 172 - hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 173 - sizeof(struct hfsplus_cat_file)); 174 - file = &entry.file; 175 - 176 - if (!strcmp(name, "hfs.type")) { 177 - if (size == 4) 178 - memcpy(&file->user_info.fdType, value, 4); 179 - else 180 - res = -ERANGE; 181 - } else if (!strcmp(name, "hfs.creator")) { 182 - if (size == 4) 183 - memcpy(&file->user_info.fdCreator, value, 4); 184 - else 185 - res = -ERANGE; 186 - } else 187 - res = -EOPNOTSUPP; 188 - if (!res) { 189 - hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 190 - sizeof(struct hfsplus_cat_file)); 191 - hfsplus_mark_inode_dirty(inode, HFSPLUS_I_CAT_DIRTY); 192 - } 193 - out: 194 - hfs_find_exit(&fd); 195 - return res; 196 - } 197 - 198 - ssize_t hfsplus_getxattr(struct dentry *dentry, const char *name, 199 - void *value, size_t size) 200 - { 201 - struct inode *inode = dentry->d_inode; 202 - struct hfs_find_data fd; 203 - hfsplus_cat_entry entry; 204 - struct hfsplus_cat_file *file; 205 - ssize_t res = 0; 206 - 207 - if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 208 - return -EOPNOTSUPP; 209 - 210 - if (size) { 211 - res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->cat_tree, &fd); 212 - if (res) 213 - return res; 214 - res = hfsplus_find_cat(inode->i_sb, inode->i_ino, &fd); 215 - if (res) 216 - goto out; 217 - hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 218 - sizeof(struct hfsplus_cat_file)); 219 - } 220 - file = &entry.file; 221 - 222 - if (!strcmp(name, "hfs.type")) { 223 - if (size >= 4) { 224 - memcpy(value, &file->user_info.fdType, 4); 225 - res = 4; 226 - } else 227 - res = size ? -ERANGE : 4; 228 - } else if (!strcmp(name, "hfs.creator")) { 229 - if (size >= 4) { 230 - memcpy(value, &file->user_info.fdCreator, 4); 231 - res = 4; 232 - } else 233 - res = size ? -ERANGE : 4; 234 - } else 235 - res = -EOPNOTSUPP; 236 - out: 237 - if (size) 238 - hfs_find_exit(&fd); 239 - return res; 240 - } 241 - 242 - #define HFSPLUS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type")) 243 - 244 - ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size) 245 - { 246 - struct inode *inode = dentry->d_inode; 247 - 248 - if (!S_ISREG(inode->i_mode) || HFSPLUS_IS_RSRC(inode)) 249 - return -EOPNOTSUPP; 250 - 251 - if (!buffer || !size) 252 - return HFSPLUS_ATTRLIST_SIZE; 253 - if (size < HFSPLUS_ATTRLIST_SIZE) 254 - return -ERANGE; 255 - strcpy(buffer, "hfs.type"); 256 - strcpy(buffer + sizeof("hfs.type"), "hfs.creator"); 257 - 258 - return HFSPLUS_ATTRLIST_SIZE; 259 153 }
+52 -4
fs/hfsplus/super.c
··· 20 20 static void hfsplus_destroy_inode(struct inode *inode); 21 21 22 22 #include "hfsplus_fs.h" 23 + #include "xattr.h" 23 24 24 25 static int hfsplus_system_read_inode(struct inode *inode) 25 26 { ··· 119 118 case HFSPLUS_ATTR_CNID: 120 119 fork = &vhdr->attr_file; 121 120 tree = sbi->attr_tree; 121 + break; 122 122 default: 123 123 return -EIO; 124 124 } ··· 193 191 error2 = filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); 194 192 if (!error) 195 193 error = error2; 194 + if (sbi->attr_tree) { 195 + error2 = 196 + filemap_write_and_wait(sbi->attr_tree->inode->i_mapping); 197 + if (!error) 198 + error = error2; 199 + } 196 200 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); 197 201 if (!error) 198 202 error = error2; ··· 289 281 hfsplus_sync_fs(sb, 1); 290 282 } 291 283 284 + hfs_btree_close(sbi->attr_tree); 292 285 hfs_btree_close(sbi->cat_tree); 293 286 hfs_btree_close(sbi->ext_tree); 294 287 iput(sbi->alloc_file); ··· 486 477 printk(KERN_ERR "hfs: failed to load catalog file\n"); 487 478 goto out_close_ext_tree; 488 479 } 480 + if (vhdr->attr_file.total_blocks != 0) { 481 + sbi->attr_tree = hfs_btree_open(sb, HFSPLUS_ATTR_CNID); 482 + if (!sbi->attr_tree) { 483 + printk(KERN_ERR "hfs: failed to load attributes file\n"); 484 + goto out_close_cat_tree; 485 + } 486 + } 487 + sb->s_xattr = hfsplus_xattr_handlers; 489 488 490 489 inode = hfsplus_iget(sb, HFSPLUS_ALLOC_CNID); 491 490 if (IS_ERR(inode)) { 492 491 printk(KERN_ERR "hfs: failed to load allocation file\n"); 493 492 err = PTR_ERR(inode); 494 - goto out_close_cat_tree; 493 + goto out_close_attr_tree; 495 494 } 496 495 sbi->alloc_file = inode; 497 496 ··· 559 542 } 560 543 err = hfsplus_create_cat(sbi->hidden_dir->i_ino, root, 561 544 &str, sbi->hidden_dir); 562 - mutex_unlock(&sbi->vh_mutex); 563 - if (err) 545 + if (err) { 546 + mutex_unlock(&sbi->vh_mutex); 564 547 goto out_put_hidden_dir; 548 + } 565 549 550 + err = hfsplus_init_inode_security(sbi->hidden_dir, 551 + root, &str); 552 + if (err == -EOPNOTSUPP) 553 + err = 0; /* Operation is not supported. */ 554 + else if (err) { 555 + /* 556 + * Try to delete anyway without 557 + * error analysis. 558 + */ 559 + hfsplus_delete_cat(sbi->hidden_dir->i_ino, 560 + root, &str); 561 + mutex_unlock(&sbi->vh_mutex); 562 + goto out_put_hidden_dir; 563 + } 564 + 565 + mutex_unlock(&sbi->vh_mutex); 566 566 hfsplus_mark_inode_dirty(sbi->hidden_dir, 567 567 HFSPLUS_I_CAT_DIRTY); 568 568 } ··· 596 562 sb->s_root = NULL; 597 563 out_put_alloc_file: 598 564 iput(sbi->alloc_file); 565 + out_close_attr_tree: 566 + hfs_btree_close(sbi->attr_tree); 599 567 out_close_cat_tree: 600 568 hfs_btree_close(sbi->cat_tree); 601 569 out_close_ext_tree: ··· 671 635 hfsplus_init_once); 672 636 if (!hfsplus_inode_cachep) 673 637 return -ENOMEM; 638 + err = hfsplus_create_attr_tree_cache(); 639 + if (err) 640 + goto destroy_inode_cache; 674 641 err = register_filesystem(&hfsplus_fs_type); 675 642 if (err) 676 - kmem_cache_destroy(hfsplus_inode_cachep); 643 + goto destroy_attr_tree_cache; 644 + return 0; 645 + 646 + destroy_attr_tree_cache: 647 + hfsplus_destroy_attr_tree_cache(); 648 + 649 + destroy_inode_cache: 650 + kmem_cache_destroy(hfsplus_inode_cachep); 651 + 677 652 return err; 678 653 } 679 654 ··· 697 650 * destroy cache. 698 651 */ 699 652 rcu_barrier(); 653 + hfsplus_destroy_attr_tree_cache(); 700 654 kmem_cache_destroy(hfsplus_inode_cachep); 701 655 } 702 656
+4 -3
fs/hfsplus/unicode.c
··· 295 295 return hfsplus_decompose_table + (off / 4); 296 296 } 297 297 298 - int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr, 298 + int hfsplus_asc2uni(struct super_block *sb, 299 + struct hfsplus_unistr *ustr, int max_unistr_len, 299 300 const char *astr, int len) 300 301 { 301 302 int size, dsize, decompose; ··· 304 303 wchar_t c; 305 304 306 305 decompose = !test_bit(HFSPLUS_SB_NODECOMPOSE, &HFSPLUS_SB(sb)->flags); 307 - while (outlen < HFSPLUS_MAX_STRLEN && len > 0) { 306 + while (outlen < max_unistr_len && len > 0) { 308 307 size = asc2unichar(sb, astr, len, &c); 309 308 310 309 if (decompose) ··· 312 311 else 313 312 dstr = NULL; 314 313 if (dstr) { 315 - if (outlen + dsize > HFSPLUS_MAX_STRLEN) 314 + if (outlen + dsize > max_unistr_len) 316 315 break; 317 316 do { 318 317 ustr->unicode[outlen++] = cpu_to_be16(*dstr++);