1 /* 2 * linux/fs/hfsplus/inode.c 3 * 4 * Copyright (C) 2001 5 * Brad Boyer (flar@allandria.com) 6 * (C) 2003 Ardis Technologies <roman@ardistech.com> 7 * 8 * Inode handling routines 9 */ 10 11 #include <linux/blkdev.h> 12 #include <linux/mm.h> 13 #include <linux/fs.h> 14 #include <linux/pagemap.h> 15 #include <linux/mpage.h> 16 #include <linux/sched.h> 17 18 #include "hfsplus_fs.h" 19 #include "hfsplus_raw.h" 20 21 static int hfsplus_readpage(struct file *file, struct page *page) 22 { 23 return block_read_full_page(page, hfsplus_get_block); 24 } 25 26 static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) 27 { 28 return block_write_full_page(page, hfsplus_get_block, wbc); 29 } 30 31 static void hfsplus_write_failed(struct address_space *mapping, loff_t to) 32 { 33 struct inode *inode = mapping->host; 34 35 if (to > inode->i_size) { 36 truncate_pagecache(inode, to, inode->i_size); 37 hfsplus_file_truncate(inode); 38 } 39 } 40 41 static int hfsplus_write_begin(struct file *file, struct address_space *mapping, 42 loff_t pos, unsigned len, unsigned flags, 43 struct page **pagep, void **fsdata) 44 { 45 int ret; 46 47 *pagep = NULL; 48 ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 49 hfsplus_get_block, 50 &HFSPLUS_I(mapping->host)->phys_size); 51 if (unlikely(ret)) 52 hfsplus_write_failed(mapping, pos + len); 53 54 return ret; 55 } 56 57 static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) 58 { 59 return generic_block_bmap(mapping, block, hfsplus_get_block); 60 } 61 62 static int hfsplus_releasepage(struct page *page, gfp_t mask) 63 { 64 struct inode *inode = page->mapping->host; 65 struct super_block *sb = inode->i_sb; 66 struct hfs_btree *tree; 67 struct hfs_bnode *node; 68 u32 nidx; 69 int i, res = 1; 70 71 switch (inode->i_ino) { 72 case HFSPLUS_EXT_CNID: 73 tree = HFSPLUS_SB(sb)->ext_tree; 74 break; 75 case HFSPLUS_CAT_CNID: 76 tree = HFSPLUS_SB(sb)->cat_tree; 77 break; 78 case HFSPLUS_ATTR_CNID: 79 tree = HFSPLUS_SB(sb)->attr_tree; 80 break; 81 default: 82 BUG(); 83 return 0; 84 } 85 if (!tree) 86 return 0; 87 if (tree->node_size >= PAGE_CACHE_SIZE) { 88 nidx = page->index >> 89 (tree->node_size_shift - PAGE_CACHE_SHIFT); 90 spin_lock(&tree->hash_lock); 91 node = hfs_bnode_findhash(tree, nidx); 92 if (!node) 93 ; 94 else if (atomic_read(&node->refcnt)) 95 res = 0; 96 if (res && node) { 97 hfs_bnode_unhash(node); 98 hfs_bnode_free(node); 99 } 100 spin_unlock(&tree->hash_lock); 101 } else { 102 nidx = page->index << 103 (PAGE_CACHE_SHIFT - tree->node_size_shift); 104 i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); 105 spin_lock(&tree->hash_lock); 106 do { 107 node = hfs_bnode_findhash(tree, nidx++); 108 if (!node) 109 continue; 110 if (atomic_read(&node->refcnt)) { 111 res = 0; 112 break; 113 } 114 hfs_bnode_unhash(node); 115 hfs_bnode_free(node); 116 } while (--i && nidx < tree->node_count); 117 spin_unlock(&tree->hash_lock); 118 } 119 return res ? try_to_free_buffers(page) : 0; 120 } 121 122 static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, 123 const struct iovec *iov, loff_t offset, unsigned long nr_segs) 124 { 125 struct file *file = iocb->ki_filp; 126 struct address_space *mapping = file->f_mapping; 127 struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; 128 ssize_t ret; 129 130 ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs, 131 hfsplus_get_block); 132 133 /* 134 * In case of error extending write may have instantiated a few 135 * blocks outside i_size. Trim these off again. 136 */ 137 if (unlikely((rw & WRITE) && ret < 0)) { 138 loff_t isize = i_size_read(inode); 139 loff_t end = offset + iov_length(iov, nr_segs); 140 141 if (end > isize) 142 hfsplus_write_failed(mapping, end); 143 } 144 145 return ret; 146 } 147 148 static int hfsplus_writepages(struct address_space *mapping, 149 struct writeback_control *wbc) 150 { 151 return mpage_writepages(mapping, wbc, hfsplus_get_block); 152 } 153 154 const struct address_space_operations hfsplus_btree_aops = { 155 .readpage = hfsplus_readpage, 156 .writepage = hfsplus_writepage, 157 .write_begin = hfsplus_write_begin, 158 .write_end = generic_write_end, 159 .bmap = hfsplus_bmap, 160 .releasepage = hfsplus_releasepage, 161 }; 162 163 const struct address_space_operations hfsplus_aops = { 164 .readpage = hfsplus_readpage, 165 .writepage = hfsplus_writepage, 166 .write_begin = hfsplus_write_begin, 167 .write_end = generic_write_end, 168 .bmap = hfsplus_bmap, 169 .direct_IO = hfsplus_direct_IO, 170 .writepages = hfsplus_writepages, 171 }; 172 173 const struct dentry_operations hfsplus_dentry_operations = { 174 .d_hash = hfsplus_hash_dentry, 175 .d_compare = hfsplus_compare_dentry, 176 }; 177 178 static struct dentry *hfsplus_file_lookup(struct inode *dir, 179 struct dentry *dentry, unsigned int flags) 180 { 181 struct hfs_find_data fd; 182 struct super_block *sb = dir->i_sb; 183 struct inode *inode = NULL; 184 struct hfsplus_inode_info *hip; 185 int err; 186 187 if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc")) 188 goto out; 189 190 inode = HFSPLUS_I(dir)->rsrc_inode; 191 if (inode) 192 goto out; 193 194 inode = new_inode(sb); 195 if (!inode) 196 return ERR_PTR(-ENOMEM); 197 198 hip = HFSPLUS_I(inode); 199 inode->i_ino = dir->i_ino; 200 INIT_LIST_HEAD(&hip->open_dir_list); 201 mutex_init(&hip->extents_lock); 202 hip->extent_state = 0; 203 hip->flags = 0; 204 hip->userflags = 0; 205 set_bit(HFSPLUS_I_RSRC, &hip->flags); 206 207 err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); 208 if (!err) { 209 err = hfsplus_find_cat(sb, dir->i_ino, &fd); 210 if (!err) 211 err = hfsplus_cat_read_inode(inode, &fd); 212 hfs_find_exit(&fd); 213 } 214 if (err) { 215 iput(inode); 216 return ERR_PTR(err); 217 } 218 hip->rsrc_inode = dir; 219 HFSPLUS_I(dir)->rsrc_inode = inode; 220 igrab(dir); 221 222 /* 223 * __mark_inode_dirty expects inodes to be hashed. Since we don't 224 * want resource fork inodes in the regular inode space, we make them 225 * appear hashed, but do not put on any lists. hlist_del() 226 * will work fine and require no locking. 227 */ 228 hlist_add_fake(&inode->i_hash); 229 230 mark_inode_dirty(inode); 231 out: 232 d_add(dentry, inode); 233 return NULL; 234 } 235 236 static void hfsplus_get_perms(struct inode *inode, 237 struct hfsplus_perm *perms, int dir) 238 { 239 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 240 u16 mode; 241 242 mode = be16_to_cpu(perms->mode); 243 244 i_uid_write(inode, be32_to_cpu(perms->owner)); 245 if (!i_uid_read(inode) && !mode) 246 inode->i_uid = sbi->uid; 247 248 i_gid_write(inode, be32_to_cpu(perms->group)); 249 if (!i_gid_read(inode) && !mode) 250 inode->i_gid = sbi->gid; 251 252 if (dir) { 253 mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask)); 254 mode |= S_IFDIR; 255 } else if (!mode) 256 mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask)); 257 inode->i_mode = mode; 258 259 HFSPLUS_I(inode)->userflags = perms->userflags; 260 if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE) 261 inode->i_flags |= S_IMMUTABLE; 262 else 263 inode->i_flags &= ~S_IMMUTABLE; 264 if (perms->rootflags & HFSPLUS_FLG_APPEND) 265 inode->i_flags |= S_APPEND; 266 else 267 inode->i_flags &= ~S_APPEND; 268 } 269 270 static int hfsplus_file_open(struct inode *inode, struct file *file) 271 { 272 if (HFSPLUS_IS_RSRC(inode)) 273 inode = HFSPLUS_I(inode)->rsrc_inode; 274 if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) 275 return -EOVERFLOW; 276 atomic_inc(&HFSPLUS_I(inode)->opencnt); 277 return 0; 278 } 279 280 static int hfsplus_file_release(struct inode *inode, struct file *file) 281 { 282 struct super_block *sb = inode->i_sb; 283 284 if (HFSPLUS_IS_RSRC(inode)) 285 inode = HFSPLUS_I(inode)->rsrc_inode; 286 if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) { 287 mutex_lock(&inode->i_mutex); 288 hfsplus_file_truncate(inode); 289 if (inode->i_flags & S_DEAD) { 290 hfsplus_delete_cat(inode->i_ino, 291 HFSPLUS_SB(sb)->hidden_dir, NULL); 292 hfsplus_delete_inode(inode); 293 } 294 mutex_unlock(&inode->i_mutex); 295 } 296 return 0; 297 } 298 299 static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) 300 { 301 struct inode *inode = dentry->d_inode; 302 int error; 303 304 error = inode_change_ok(inode, attr); 305 if (error) 306 return error; 307 308 if ((attr->ia_valid & ATTR_SIZE) && 309 attr->ia_size != i_size_read(inode)) { 310 inode_dio_wait(inode); 311 truncate_setsize(inode, attr->ia_size); 312 hfsplus_file_truncate(inode); 313 } 314 315 setattr_copy(inode, attr); 316 mark_inode_dirty(inode); 317 return 0; 318 } 319 320 int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, 321 int datasync) 322 { 323 struct inode *inode = file->f_mapping->host; 324 struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 325 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 326 int error = 0, error2; 327 328 error = filemap_write_and_wait_range(inode->i_mapping, start, end); 329 if (error) 330 return error; 331 mutex_lock(&inode->i_mutex); 332 333 /* 334 * Sync inode metadata into the catalog and extent trees. 335 */ 336 sync_inode_metadata(inode, 1); 337 338 /* 339 * And explicitly write out the btrees. 340 */ 341 if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags)) 342 error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); 343 344 if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) { 345 error2 = 346 filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); 347 if (!error) 348 error = error2; 349 } 350 351 if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { 352 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); 353 if (!error) 354 error = error2; 355 } 356 357 if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) 358 blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); 359 360 mutex_unlock(&inode->i_mutex); 361 362 return error; 363 } 364 365 static const struct inode_operations hfsplus_file_inode_operations = { 366 .lookup = hfsplus_file_lookup, 367 .setattr = hfsplus_setattr, 368 .setxattr = hfsplus_setxattr, 369 .getxattr = hfsplus_getxattr, 370 .listxattr = hfsplus_listxattr, 371 }; 372 373 static const struct file_operations hfsplus_file_operations = { 374 .llseek = generic_file_llseek, 375 .read = do_sync_read, 376 .aio_read = generic_file_aio_read, 377 .write = do_sync_write, 378 .aio_write = generic_file_aio_write, 379 .mmap = generic_file_mmap, 380 .splice_read = generic_file_splice_read, 381 .fsync = hfsplus_file_fsync, 382 .open = hfsplus_file_open, 383 .release = hfsplus_file_release, 384 .unlocked_ioctl = hfsplus_ioctl, 385 }; 386 387 struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode) 388 { 389 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 390 struct inode *inode = new_inode(sb); 391 struct hfsplus_inode_info *hip; 392 393 if (!inode) 394 return NULL; 395 396 inode->i_ino = sbi->next_cnid++; 397 inode->i_mode = mode; 398 inode->i_uid = current_fsuid(); 399 inode->i_gid = current_fsgid(); 400 set_nlink(inode, 1); 401 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 402 403 hip = HFSPLUS_I(inode); 404 INIT_LIST_HEAD(&hip->open_dir_list); 405 mutex_init(&hip->extents_lock); 406 atomic_set(&hip->opencnt, 0); 407 hip->extent_state = 0; 408 hip->flags = 0; 409 hip->userflags = 0; 410 memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); 411 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 412 hip->alloc_blocks = 0; 413 hip->first_blocks = 0; 414 hip->cached_start = 0; 415 hip->cached_blocks = 0; 416 hip->phys_size = 0; 417 hip->fs_blocks = 0; 418 hip->rsrc_inode = NULL; 419 if (S_ISDIR(inode->i_mode)) { 420 inode->i_size = 2; 421 sbi->folder_count++; 422 inode->i_op = &hfsplus_dir_inode_operations; 423 inode->i_fop = &hfsplus_dir_operations; 424 } else if (S_ISREG(inode->i_mode)) { 425 sbi->file_count++; 426 inode->i_op = &hfsplus_file_inode_operations; 427 inode->i_fop = &hfsplus_file_operations; 428 inode->i_mapping->a_ops = &hfsplus_aops; 429 hip->clump_blocks = sbi->data_clump_blocks; 430 } else if (S_ISLNK(inode->i_mode)) { 431 sbi->file_count++; 432 inode->i_op = &page_symlink_inode_operations; 433 inode->i_mapping->a_ops = &hfsplus_aops; 434 hip->clump_blocks = 1; 435 } else 436 sbi->file_count++; 437 insert_inode_hash(inode); 438 mark_inode_dirty(inode); 439 hfsplus_mark_mdb_dirty(sb); 440 441 return inode; 442 } 443 444 void hfsplus_delete_inode(struct inode *inode) 445 { 446 struct super_block *sb = inode->i_sb; 447 448 if (S_ISDIR(inode->i_mode)) { 449 HFSPLUS_SB(sb)->folder_count--; 450 hfsplus_mark_mdb_dirty(sb); 451 return; 452 } 453 HFSPLUS_SB(sb)->file_count--; 454 if (S_ISREG(inode->i_mode)) { 455 if (!inode->i_nlink) { 456 inode->i_size = 0; 457 hfsplus_file_truncate(inode); 458 } 459 } else if (S_ISLNK(inode->i_mode)) { 460 inode->i_size = 0; 461 hfsplus_file_truncate(inode); 462 } 463 hfsplus_mark_mdb_dirty(sb); 464 } 465 466 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork) 467 { 468 struct super_block *sb = inode->i_sb; 469 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 470 struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 471 u32 count; 472 int i; 473 474 memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec)); 475 for (count = 0, i = 0; i < 8; i++) 476 count += be32_to_cpu(fork->extents[i].block_count); 477 hip->first_blocks = count; 478 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 479 hip->cached_start = 0; 480 hip->cached_blocks = 0; 481 482 hip->alloc_blocks = be32_to_cpu(fork->total_blocks); 483 hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size); 484 hip->fs_blocks = 485 (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 486 inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); 487 hip->clump_blocks = 488 be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift; 489 if (!hip->clump_blocks) { 490 hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ? 491 sbi->rsrc_clump_blocks : 492 sbi->data_clump_blocks; 493 } 494 } 495 496 void hfsplus_inode_write_fork(struct inode *inode, 497 struct hfsplus_fork_raw *fork) 498 { 499 memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, 500 sizeof(hfsplus_extent_rec)); 501 fork->total_size = cpu_to_be64(inode->i_size); 502 fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks); 503 } 504 505 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) 506 { 507 hfsplus_cat_entry entry; 508 int res = 0; 509 u16 type; 510 511 type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset); 512 513 HFSPLUS_I(inode)->linkid = 0; 514 if (type == HFSPLUS_FOLDER) { 515 struct hfsplus_cat_folder *folder = &entry.folder; 516 517 if (fd->entrylength < sizeof(struct hfsplus_cat_folder)) 518 /* panic? */; 519 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 520 sizeof(struct hfsplus_cat_folder)); 521 hfsplus_get_perms(inode, &folder->permissions, 1); 522 set_nlink(inode, 1); 523 inode->i_size = 2 + be32_to_cpu(folder->valence); 524 inode->i_atime = hfsp_mt2ut(folder->access_date); 525 inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); 526 inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); 527 HFSPLUS_I(inode)->create_date = folder->create_date; 528 HFSPLUS_I(inode)->fs_blocks = 0; 529 inode->i_op = &hfsplus_dir_inode_operations; 530 inode->i_fop = &hfsplus_dir_operations; 531 } else if (type == HFSPLUS_FILE) { 532 struct hfsplus_cat_file *file = &entry.file; 533 534 if (fd->entrylength < sizeof(struct hfsplus_cat_file)) 535 /* panic? */; 536 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 537 sizeof(struct hfsplus_cat_file)); 538 539 hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ? 540 &file->rsrc_fork : &file->data_fork); 541 hfsplus_get_perms(inode, &file->permissions, 0); 542 set_nlink(inode, 1); 543 if (S_ISREG(inode->i_mode)) { 544 if (file->permissions.dev) 545 set_nlink(inode, 546 be32_to_cpu(file->permissions.dev)); 547 inode->i_op = &hfsplus_file_inode_operations; 548 inode->i_fop = &hfsplus_file_operations; 549 inode->i_mapping->a_ops = &hfsplus_aops; 550 } else if (S_ISLNK(inode->i_mode)) { 551 inode->i_op = &page_symlink_inode_operations; 552 inode->i_mapping->a_ops = &hfsplus_aops; 553 } else { 554 init_special_inode(inode, inode->i_mode, 555 be32_to_cpu(file->permissions.dev)); 556 } 557 inode->i_atime = hfsp_mt2ut(file->access_date); 558 inode->i_mtime = hfsp_mt2ut(file->content_mod_date); 559 inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); 560 HFSPLUS_I(inode)->create_date = file->create_date; 561 } else { 562 printk(KERN_ERR "hfs: bad catalog entry used to create inode\n"); 563 res = -EIO; 564 } 565 return res; 566 } 567 568 int hfsplus_cat_write_inode(struct inode *inode) 569 { 570 struct inode *main_inode = inode; 571 struct hfs_find_data fd; 572 hfsplus_cat_entry entry; 573 574 if (HFSPLUS_IS_RSRC(inode)) 575 main_inode = HFSPLUS_I(inode)->rsrc_inode; 576 577 if (!main_inode->i_nlink) 578 return 0; 579 580 if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd)) 581 /* panic? */ 582 return -EIO; 583 584 if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd)) 585 /* panic? */ 586 goto out; 587 588 if (S_ISDIR(main_inode->i_mode)) { 589 struct hfsplus_cat_folder *folder = &entry.folder; 590 591 if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) 592 /* panic? */; 593 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 594 sizeof(struct hfsplus_cat_folder)); 595 /* simple node checks? */ 596 hfsplus_cat_set_perms(inode, &folder->permissions); 597 folder->access_date = hfsp_ut2mt(inode->i_atime); 598 folder->content_mod_date = hfsp_ut2mt(inode->i_mtime); 599 folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); 600 folder->valence = cpu_to_be32(inode->i_size - 2); 601 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 602 sizeof(struct hfsplus_cat_folder)); 603 } else if (HFSPLUS_IS_RSRC(inode)) { 604 struct hfsplus_cat_file *file = &entry.file; 605 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 606 sizeof(struct hfsplus_cat_file)); 607 hfsplus_inode_write_fork(inode, &file->rsrc_fork); 608 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 609 sizeof(struct hfsplus_cat_file)); 610 } else { 611 struct hfsplus_cat_file *file = &entry.file; 612 613 if (fd.entrylength < sizeof(struct hfsplus_cat_file)) 614 /* panic? */; 615 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 616 sizeof(struct hfsplus_cat_file)); 617 hfsplus_inode_write_fork(inode, &file->data_fork); 618 hfsplus_cat_set_perms(inode, &file->permissions); 619 if (HFSPLUS_FLG_IMMUTABLE & 620 (file->permissions.rootflags | 621 file->permissions.userflags)) 622 file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); 623 else 624 file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); 625 file->access_date = hfsp_ut2mt(inode->i_atime); 626 file->content_mod_date = hfsp_ut2mt(inode->i_mtime); 627 file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); 628 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 629 sizeof(struct hfsplus_cat_file)); 630 } 631 632 set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); 633 out: 634 hfs_find_exit(&fd); 635 return 0; 636 } 637