0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/blkdev.h>
0013 #include <linux/mm.h>
0014 #include <linux/fs.h>
0015 #include <linux/pagemap.h>
0016 #include <linux/mpage.h>
0017 #include <linux/sched.h>
0018 #include <linux/cred.h>
0019 #include <linux/uio.h>
0020 #include <linux/fileattr.h>
0021
0022 #include "hfsplus_fs.h"
0023 #include "hfsplus_raw.h"
0024 #include "xattr.h"
0025
0026 static int hfsplus_read_folio(struct file *file, struct folio *folio)
0027 {
0028 return block_read_full_folio(folio, hfsplus_get_block);
0029 }
0030
0031 static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
0032 {
0033 return block_write_full_page(page, hfsplus_get_block, wbc);
0034 }
0035
0036 static void hfsplus_write_failed(struct address_space *mapping, loff_t to)
0037 {
0038 struct inode *inode = mapping->host;
0039
0040 if (to > inode->i_size) {
0041 truncate_pagecache(inode, inode->i_size);
0042 hfsplus_file_truncate(inode);
0043 }
0044 }
0045
0046 int hfsplus_write_begin(struct file *file, struct address_space *mapping,
0047 loff_t pos, unsigned len, struct page **pagep, void **fsdata)
0048 {
0049 int ret;
0050
0051 *pagep = NULL;
0052 ret = cont_write_begin(file, mapping, pos, len, pagep, fsdata,
0053 hfsplus_get_block,
0054 &HFSPLUS_I(mapping->host)->phys_size);
0055 if (unlikely(ret))
0056 hfsplus_write_failed(mapping, pos + len);
0057
0058 return ret;
0059 }
0060
0061 static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
0062 {
0063 return generic_block_bmap(mapping, block, hfsplus_get_block);
0064 }
0065
0066 static bool hfsplus_release_folio(struct folio *folio, gfp_t mask)
0067 {
0068 struct inode *inode = folio->mapping->host;
0069 struct super_block *sb = inode->i_sb;
0070 struct hfs_btree *tree;
0071 struct hfs_bnode *node;
0072 u32 nidx;
0073 int i;
0074 bool res = true;
0075
0076 switch (inode->i_ino) {
0077 case HFSPLUS_EXT_CNID:
0078 tree = HFSPLUS_SB(sb)->ext_tree;
0079 break;
0080 case HFSPLUS_CAT_CNID:
0081 tree = HFSPLUS_SB(sb)->cat_tree;
0082 break;
0083 case HFSPLUS_ATTR_CNID:
0084 tree = HFSPLUS_SB(sb)->attr_tree;
0085 break;
0086 default:
0087 BUG();
0088 return false;
0089 }
0090 if (!tree)
0091 return false;
0092 if (tree->node_size >= PAGE_SIZE) {
0093 nidx = folio->index >>
0094 (tree->node_size_shift - PAGE_SHIFT);
0095 spin_lock(&tree->hash_lock);
0096 node = hfs_bnode_findhash(tree, nidx);
0097 if (!node)
0098 ;
0099 else if (atomic_read(&node->refcnt))
0100 res = false;
0101 if (res && node) {
0102 hfs_bnode_unhash(node);
0103 hfs_bnode_free(node);
0104 }
0105 spin_unlock(&tree->hash_lock);
0106 } else {
0107 nidx = folio->index <<
0108 (PAGE_SHIFT - tree->node_size_shift);
0109 i = 1 << (PAGE_SHIFT - tree->node_size_shift);
0110 spin_lock(&tree->hash_lock);
0111 do {
0112 node = hfs_bnode_findhash(tree, nidx++);
0113 if (!node)
0114 continue;
0115 if (atomic_read(&node->refcnt)) {
0116 res = false;
0117 break;
0118 }
0119 hfs_bnode_unhash(node);
0120 hfs_bnode_free(node);
0121 } while (--i && nidx < tree->node_count);
0122 spin_unlock(&tree->hash_lock);
0123 }
0124 return res ? try_to_free_buffers(folio) : false;
0125 }
0126
0127 static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
0128 {
0129 struct file *file = iocb->ki_filp;
0130 struct address_space *mapping = file->f_mapping;
0131 struct inode *inode = mapping->host;
0132 size_t count = iov_iter_count(iter);
0133 ssize_t ret;
0134
0135 ret = blockdev_direct_IO(iocb, inode, iter, hfsplus_get_block);
0136
0137
0138
0139
0140
0141 if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) {
0142 loff_t isize = i_size_read(inode);
0143 loff_t end = iocb->ki_pos + count;
0144
0145 if (end > isize)
0146 hfsplus_write_failed(mapping, end);
0147 }
0148
0149 return ret;
0150 }
0151
0152 static int hfsplus_writepages(struct address_space *mapping,
0153 struct writeback_control *wbc)
0154 {
0155 return mpage_writepages(mapping, wbc, hfsplus_get_block);
0156 }
0157
0158 const struct address_space_operations hfsplus_btree_aops = {
0159 .dirty_folio = block_dirty_folio,
0160 .invalidate_folio = block_invalidate_folio,
0161 .read_folio = hfsplus_read_folio,
0162 .writepage = hfsplus_writepage,
0163 .write_begin = hfsplus_write_begin,
0164 .write_end = generic_write_end,
0165 .bmap = hfsplus_bmap,
0166 .release_folio = hfsplus_release_folio,
0167 };
0168
0169 const struct address_space_operations hfsplus_aops = {
0170 .dirty_folio = block_dirty_folio,
0171 .invalidate_folio = block_invalidate_folio,
0172 .read_folio = hfsplus_read_folio,
0173 .writepage = hfsplus_writepage,
0174 .write_begin = hfsplus_write_begin,
0175 .write_end = generic_write_end,
0176 .bmap = hfsplus_bmap,
0177 .direct_IO = hfsplus_direct_IO,
0178 .writepages = hfsplus_writepages,
0179 };
0180
0181 const struct dentry_operations hfsplus_dentry_operations = {
0182 .d_hash = hfsplus_hash_dentry,
0183 .d_compare = hfsplus_compare_dentry,
0184 };
0185
0186 static void hfsplus_get_perms(struct inode *inode,
0187 struct hfsplus_perm *perms, int dir)
0188 {
0189 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
0190 u16 mode;
0191
0192 mode = be16_to_cpu(perms->mode);
0193
0194 i_uid_write(inode, be32_to_cpu(perms->owner));
0195 if (!i_uid_read(inode) && !mode)
0196 inode->i_uid = sbi->uid;
0197
0198 i_gid_write(inode, be32_to_cpu(perms->group));
0199 if (!i_gid_read(inode) && !mode)
0200 inode->i_gid = sbi->gid;
0201
0202 if (dir) {
0203 mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
0204 mode |= S_IFDIR;
0205 } else if (!mode)
0206 mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
0207 inode->i_mode = mode;
0208
0209 HFSPLUS_I(inode)->userflags = perms->userflags;
0210 if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
0211 inode->i_flags |= S_IMMUTABLE;
0212 else
0213 inode->i_flags &= ~S_IMMUTABLE;
0214 if (perms->rootflags & HFSPLUS_FLG_APPEND)
0215 inode->i_flags |= S_APPEND;
0216 else
0217 inode->i_flags &= ~S_APPEND;
0218 }
0219
0220 static int hfsplus_file_open(struct inode *inode, struct file *file)
0221 {
0222 if (HFSPLUS_IS_RSRC(inode))
0223 inode = HFSPLUS_I(inode)->rsrc_inode;
0224 if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
0225 return -EOVERFLOW;
0226 atomic_inc(&HFSPLUS_I(inode)->opencnt);
0227 return 0;
0228 }
0229
0230 static int hfsplus_file_release(struct inode *inode, struct file *file)
0231 {
0232 struct super_block *sb = inode->i_sb;
0233
0234 if (HFSPLUS_IS_RSRC(inode))
0235 inode = HFSPLUS_I(inode)->rsrc_inode;
0236 if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) {
0237 inode_lock(inode);
0238 hfsplus_file_truncate(inode);
0239 if (inode->i_flags & S_DEAD) {
0240 hfsplus_delete_cat(inode->i_ino,
0241 HFSPLUS_SB(sb)->hidden_dir, NULL);
0242 hfsplus_delete_inode(inode);
0243 }
0244 inode_unlock(inode);
0245 }
0246 return 0;
0247 }
0248
0249 static int hfsplus_setattr(struct user_namespace *mnt_userns,
0250 struct dentry *dentry, struct iattr *attr)
0251 {
0252 struct inode *inode = d_inode(dentry);
0253 int error;
0254
0255 error = setattr_prepare(&init_user_ns, dentry, attr);
0256 if (error)
0257 return error;
0258
0259 if ((attr->ia_valid & ATTR_SIZE) &&
0260 attr->ia_size != i_size_read(inode)) {
0261 inode_dio_wait(inode);
0262 if (attr->ia_size > inode->i_size) {
0263 error = generic_cont_expand_simple(inode,
0264 attr->ia_size);
0265 if (error)
0266 return error;
0267 }
0268 truncate_setsize(inode, attr->ia_size);
0269 hfsplus_file_truncate(inode);
0270 inode->i_mtime = inode->i_ctime = current_time(inode);
0271 }
0272
0273 setattr_copy(&init_user_ns, inode, attr);
0274 mark_inode_dirty(inode);
0275
0276 return 0;
0277 }
0278
0279 int hfsplus_getattr(struct user_namespace *mnt_userns, const struct path *path,
0280 struct kstat *stat, u32 request_mask,
0281 unsigned int query_flags)
0282 {
0283 struct inode *inode = d_inode(path->dentry);
0284 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
0285
0286 if (request_mask & STATX_BTIME) {
0287 stat->result_mask |= STATX_BTIME;
0288 stat->btime = hfsp_mt2ut(hip->create_date);
0289 }
0290
0291 if (inode->i_flags & S_APPEND)
0292 stat->attributes |= STATX_ATTR_APPEND;
0293 if (inode->i_flags & S_IMMUTABLE)
0294 stat->attributes |= STATX_ATTR_IMMUTABLE;
0295 if (hip->userflags & HFSPLUS_FLG_NODUMP)
0296 stat->attributes |= STATX_ATTR_NODUMP;
0297
0298 stat->attributes_mask |= STATX_ATTR_APPEND | STATX_ATTR_IMMUTABLE |
0299 STATX_ATTR_NODUMP;
0300
0301 generic_fillattr(&init_user_ns, inode, stat);
0302 return 0;
0303 }
0304
0305 int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
0306 int datasync)
0307 {
0308 struct inode *inode = file->f_mapping->host;
0309 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
0310 struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
0311 int error = 0, error2;
0312
0313 error = file_write_and_wait_range(file, start, end);
0314 if (error)
0315 return error;
0316 inode_lock(inode);
0317
0318
0319
0320
0321 sync_inode_metadata(inode, 1);
0322
0323
0324
0325
0326 if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
0327 error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
0328
0329 if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
0330 error2 =
0331 filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
0332 if (!error)
0333 error = error2;
0334 }
0335
0336 if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) {
0337 if (sbi->attr_tree) {
0338 error2 =
0339 filemap_write_and_wait(
0340 sbi->attr_tree->inode->i_mapping);
0341 if (!error)
0342 error = error2;
0343 } else {
0344 pr_err("sync non-existent attributes tree\n");
0345 }
0346 }
0347
0348 if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
0349 error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
0350 if (!error)
0351 error = error2;
0352 }
0353
0354 if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
0355 blkdev_issue_flush(inode->i_sb->s_bdev);
0356
0357 inode_unlock(inode);
0358
0359 return error;
0360 }
0361
0362 static const struct inode_operations hfsplus_file_inode_operations = {
0363 .setattr = hfsplus_setattr,
0364 .getattr = hfsplus_getattr,
0365 .listxattr = hfsplus_listxattr,
0366 .fileattr_get = hfsplus_fileattr_get,
0367 .fileattr_set = hfsplus_fileattr_set,
0368 };
0369
0370 static const struct file_operations hfsplus_file_operations = {
0371 .llseek = generic_file_llseek,
0372 .read_iter = generic_file_read_iter,
0373 .write_iter = generic_file_write_iter,
0374 .mmap = generic_file_mmap,
0375 .splice_read = generic_file_splice_read,
0376 .fsync = hfsplus_file_fsync,
0377 .open = hfsplus_file_open,
0378 .release = hfsplus_file_release,
0379 .unlocked_ioctl = hfsplus_ioctl,
0380 };
0381
0382 struct inode *hfsplus_new_inode(struct super_block *sb, struct inode *dir,
0383 umode_t mode)
0384 {
0385 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0386 struct inode *inode = new_inode(sb);
0387 struct hfsplus_inode_info *hip;
0388
0389 if (!inode)
0390 return NULL;
0391
0392 inode->i_ino = sbi->next_cnid++;
0393 inode_init_owner(&init_user_ns, inode, dir, mode);
0394 set_nlink(inode, 1);
0395 inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode);
0396
0397 hip = HFSPLUS_I(inode);
0398 INIT_LIST_HEAD(&hip->open_dir_list);
0399 spin_lock_init(&hip->open_dir_lock);
0400 mutex_init(&hip->extents_lock);
0401 atomic_set(&hip->opencnt, 0);
0402 hip->extent_state = 0;
0403 hip->flags = 0;
0404 hip->userflags = 0;
0405 hip->subfolders = 0;
0406 memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
0407 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
0408 hip->alloc_blocks = 0;
0409 hip->first_blocks = 0;
0410 hip->cached_start = 0;
0411 hip->cached_blocks = 0;
0412 hip->phys_size = 0;
0413 hip->fs_blocks = 0;
0414 hip->rsrc_inode = NULL;
0415 if (S_ISDIR(inode->i_mode)) {
0416 inode->i_size = 2;
0417 sbi->folder_count++;
0418 inode->i_op = &hfsplus_dir_inode_operations;
0419 inode->i_fop = &hfsplus_dir_operations;
0420 } else if (S_ISREG(inode->i_mode)) {
0421 sbi->file_count++;
0422 inode->i_op = &hfsplus_file_inode_operations;
0423 inode->i_fop = &hfsplus_file_operations;
0424 inode->i_mapping->a_ops = &hfsplus_aops;
0425 hip->clump_blocks = sbi->data_clump_blocks;
0426 } else if (S_ISLNK(inode->i_mode)) {
0427 sbi->file_count++;
0428 inode->i_op = &page_symlink_inode_operations;
0429 inode_nohighmem(inode);
0430 inode->i_mapping->a_ops = &hfsplus_aops;
0431 hip->clump_blocks = 1;
0432 } else
0433 sbi->file_count++;
0434 insert_inode_hash(inode);
0435 mark_inode_dirty(inode);
0436 hfsplus_mark_mdb_dirty(sb);
0437
0438 return inode;
0439 }
0440
0441 void hfsplus_delete_inode(struct inode *inode)
0442 {
0443 struct super_block *sb = inode->i_sb;
0444
0445 if (S_ISDIR(inode->i_mode)) {
0446 HFSPLUS_SB(sb)->folder_count--;
0447 hfsplus_mark_mdb_dirty(sb);
0448 return;
0449 }
0450 HFSPLUS_SB(sb)->file_count--;
0451 if (S_ISREG(inode->i_mode)) {
0452 if (!inode->i_nlink) {
0453 inode->i_size = 0;
0454 hfsplus_file_truncate(inode);
0455 }
0456 } else if (S_ISLNK(inode->i_mode)) {
0457 inode->i_size = 0;
0458 hfsplus_file_truncate(inode);
0459 }
0460 hfsplus_mark_mdb_dirty(sb);
0461 }
0462
0463 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
0464 {
0465 struct super_block *sb = inode->i_sb;
0466 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
0467 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
0468 u32 count;
0469 int i;
0470
0471 memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
0472 for (count = 0, i = 0; i < 8; i++)
0473 count += be32_to_cpu(fork->extents[i].block_count);
0474 hip->first_blocks = count;
0475 memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
0476 hip->cached_start = 0;
0477 hip->cached_blocks = 0;
0478
0479 hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
0480 hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
0481 hip->fs_blocks =
0482 (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
0483 inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
0484 hip->clump_blocks =
0485 be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift;
0486 if (!hip->clump_blocks) {
0487 hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
0488 sbi->rsrc_clump_blocks :
0489 sbi->data_clump_blocks;
0490 }
0491 }
0492
0493 void hfsplus_inode_write_fork(struct inode *inode,
0494 struct hfsplus_fork_raw *fork)
0495 {
0496 memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
0497 sizeof(hfsplus_extent_rec));
0498 fork->total_size = cpu_to_be64(inode->i_size);
0499 fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
0500 }
0501
0502 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
0503 {
0504 hfsplus_cat_entry entry;
0505 int res = 0;
0506 u16 type;
0507
0508 type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
0509
0510 HFSPLUS_I(inode)->linkid = 0;
0511 if (type == HFSPLUS_FOLDER) {
0512 struct hfsplus_cat_folder *folder = &entry.folder;
0513
0514 WARN_ON(fd->entrylength < sizeof(struct hfsplus_cat_folder));
0515 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
0516 sizeof(struct hfsplus_cat_folder));
0517 hfsplus_get_perms(inode, &folder->permissions, 1);
0518 set_nlink(inode, 1);
0519 inode->i_size = 2 + be32_to_cpu(folder->valence);
0520 inode->i_atime = hfsp_mt2ut(folder->access_date);
0521 inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
0522 inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
0523 HFSPLUS_I(inode)->create_date = folder->create_date;
0524 HFSPLUS_I(inode)->fs_blocks = 0;
0525 if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
0526 HFSPLUS_I(inode)->subfolders =
0527 be32_to_cpu(folder->subfolders);
0528 }
0529 inode->i_op = &hfsplus_dir_inode_operations;
0530 inode->i_fop = &hfsplus_dir_operations;
0531 } else if (type == HFSPLUS_FILE) {
0532 struct hfsplus_cat_file *file = &entry.file;
0533
0534 WARN_ON(fd->entrylength < sizeof(struct hfsplus_cat_file));
0535 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
0536 sizeof(struct hfsplus_cat_file));
0537
0538 hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
0539 &file->rsrc_fork : &file->data_fork);
0540 hfsplus_get_perms(inode, &file->permissions, 0);
0541 set_nlink(inode, 1);
0542 if (S_ISREG(inode->i_mode)) {
0543 if (file->permissions.dev)
0544 set_nlink(inode,
0545 be32_to_cpu(file->permissions.dev));
0546 inode->i_op = &hfsplus_file_inode_operations;
0547 inode->i_fop = &hfsplus_file_operations;
0548 inode->i_mapping->a_ops = &hfsplus_aops;
0549 } else if (S_ISLNK(inode->i_mode)) {
0550 inode->i_op = &page_symlink_inode_operations;
0551 inode_nohighmem(inode);
0552 inode->i_mapping->a_ops = &hfsplus_aops;
0553 } else {
0554 init_special_inode(inode, inode->i_mode,
0555 be32_to_cpu(file->permissions.dev));
0556 }
0557 inode->i_atime = hfsp_mt2ut(file->access_date);
0558 inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
0559 inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
0560 HFSPLUS_I(inode)->create_date = file->create_date;
0561 } else {
0562 pr_err("bad catalog entry used to create inode\n");
0563 res = -EIO;
0564 }
0565 return res;
0566 }
0567
0568 int hfsplus_cat_write_inode(struct inode *inode)
0569 {
0570 struct inode *main_inode = inode;
0571 struct hfs_find_data fd;
0572 hfsplus_cat_entry entry;
0573
0574 if (HFSPLUS_IS_RSRC(inode))
0575 main_inode = HFSPLUS_I(inode)->rsrc_inode;
0576
0577 if (!main_inode->i_nlink)
0578 return 0;
0579
0580 if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
0581
0582 return -EIO;
0583
0584 if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
0585
0586 goto out;
0587
0588 if (S_ISDIR(main_inode->i_mode)) {
0589 struct hfsplus_cat_folder *folder = &entry.folder;
0590
0591 WARN_ON(fd.entrylength < sizeof(struct hfsplus_cat_folder));
0592 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
0593 sizeof(struct hfsplus_cat_folder));
0594
0595 hfsplus_cat_set_perms(inode, &folder->permissions);
0596 folder->access_date = hfsp_ut2mt(inode->i_atime);
0597 folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
0598 folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
0599 folder->valence = cpu_to_be32(inode->i_size - 2);
0600 if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
0601 folder->subfolders =
0602 cpu_to_be32(HFSPLUS_I(inode)->subfolders);
0603 }
0604 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
0605 sizeof(struct hfsplus_cat_folder));
0606 } else if (HFSPLUS_IS_RSRC(inode)) {
0607 struct hfsplus_cat_file *file = &entry.file;
0608 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
0609 sizeof(struct hfsplus_cat_file));
0610 hfsplus_inode_write_fork(inode, &file->rsrc_fork);
0611 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
0612 sizeof(struct hfsplus_cat_file));
0613 } else {
0614 struct hfsplus_cat_file *file = &entry.file;
0615
0616 WARN_ON(fd.entrylength < sizeof(struct hfsplus_cat_file));
0617 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
0618 sizeof(struct hfsplus_cat_file));
0619 hfsplus_inode_write_fork(inode, &file->data_fork);
0620 hfsplus_cat_set_perms(inode, &file->permissions);
0621 if (HFSPLUS_FLG_IMMUTABLE &
0622 (file->permissions.rootflags |
0623 file->permissions.userflags))
0624 file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
0625 else
0626 file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
0627 file->access_date = hfsp_ut2mt(inode->i_atime);
0628 file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
0629 file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
0630 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
0631 sizeof(struct hfsplus_cat_file));
0632 }
0633
0634 set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
0635 out:
0636 hfs_find_exit(&fd);
0637 return 0;
0638 }
0639
0640 int hfsplus_fileattr_get(struct dentry *dentry, struct fileattr *fa)
0641 {
0642 struct inode *inode = d_inode(dentry);
0643 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
0644 unsigned int flags = 0;
0645
0646 if (inode->i_flags & S_IMMUTABLE)
0647 flags |= FS_IMMUTABLE_FL;
0648 if (inode->i_flags & S_APPEND)
0649 flags |= FS_APPEND_FL;
0650 if (hip->userflags & HFSPLUS_FLG_NODUMP)
0651 flags |= FS_NODUMP_FL;
0652
0653 fileattr_fill_flags(fa, flags);
0654
0655 return 0;
0656 }
0657
0658 int hfsplus_fileattr_set(struct user_namespace *mnt_userns,
0659 struct dentry *dentry, struct fileattr *fa)
0660 {
0661 struct inode *inode = d_inode(dentry);
0662 struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
0663 unsigned int new_fl = 0;
0664
0665 if (fileattr_has_fsx(fa))
0666 return -EOPNOTSUPP;
0667
0668
0669 if (fa->flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL))
0670 return -EOPNOTSUPP;
0671
0672 if (fa->flags & FS_IMMUTABLE_FL)
0673 new_fl |= S_IMMUTABLE;
0674
0675 if (fa->flags & FS_APPEND_FL)
0676 new_fl |= S_APPEND;
0677
0678 inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND);
0679
0680 if (fa->flags & FS_NODUMP_FL)
0681 hip->userflags |= HFSPLUS_FLG_NODUMP;
0682 else
0683 hip->userflags &= ~HFSPLUS_FLG_NODUMP;
0684
0685 inode->i_ctime = current_time(inode);
0686 mark_inode_dirty(inode);
0687
0688 return 0;
0689 }