Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *  linux/fs/hfsplus/inode.c
0004  *
0005  * Copyright (C) 2001
0006  * Brad Boyer (flar@allandria.com)
0007  * (C) 2003 Ardis Technologies <roman@ardistech.com>
0008  *
0009  * Inode handling routines
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      * In case of error extending write may have instantiated a few
0139      * blocks outside i_size. Trim these off again.
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      * Sync inode metadata into the catalog and extent trees.
0320      */
0321     sync_inode_metadata(inode, 1);
0322 
0323     /*
0324      * And explicitly write out the btrees.
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         /* panic? */
0582         return -EIO;
0583 
0584     if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
0585         /* panic? */
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         /* simple node checks? */
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     /* don't silently ignore unsupported ext2 flags */
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 }