11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/hfsplus/inode.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 2001 51da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com) 61da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * Inode handling routines 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 1134a2d313SChristoph Hellwig #include <linux/blkdev.h> 121da177e4SLinus Torvalds #include <linux/mm.h> 131da177e4SLinus Torvalds #include <linux/fs.h> 141da177e4SLinus Torvalds #include <linux/pagemap.h> 151da177e4SLinus Torvalds #include <linux/mpage.h> 16e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 17e2e40f2cSChristoph Hellwig #include <linux/uio.h> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include "hfsplus_fs.h" 201da177e4SLinus Torvalds #include "hfsplus_raw.h" 21324ef39aSVyacheslav Dubeyko #include "xattr.h" 22b4c1107cSVyacheslav Dubeyko #include "acl.h" 231da177e4SLinus Torvalds 241da177e4SLinus Torvalds static int hfsplus_readpage(struct file *file, struct page *page) 251da177e4SLinus Torvalds { 261da177e4SLinus Torvalds return block_read_full_page(page, hfsplus_get_block); 271da177e4SLinus Torvalds } 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds static int hfsplus_writepage(struct page *page, struct writeback_control *wbc) 301da177e4SLinus Torvalds { 311da177e4SLinus Torvalds return block_write_full_page(page, hfsplus_get_block, wbc); 321da177e4SLinus Torvalds } 331da177e4SLinus Torvalds 34d5068485SMarco Stornelli static void hfsplus_write_failed(struct address_space *mapping, loff_t to) 35d5068485SMarco Stornelli { 36d5068485SMarco Stornelli struct inode *inode = mapping->host; 37d5068485SMarco Stornelli 38d5068485SMarco Stornelli if (to > inode->i_size) { 397caef267SKirill A. Shutemov truncate_pagecache(inode, inode->i_size); 40d5068485SMarco Stornelli hfsplus_file_truncate(inode); 41d5068485SMarco Stornelli } 42d5068485SMarco Stornelli } 43d5068485SMarco Stornelli 447c0efc62SNick Piggin static int hfsplus_write_begin(struct file *file, struct address_space *mapping, 457c0efc62SNick Piggin loff_t pos, unsigned len, unsigned flags, 467c0efc62SNick Piggin struct page **pagep, void **fsdata) 471da177e4SLinus Torvalds { 48282dc178SChristoph Hellwig int ret; 49282dc178SChristoph Hellwig 507c0efc62SNick Piggin *pagep = NULL; 51282dc178SChristoph Hellwig ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 527c0efc62SNick Piggin hfsplus_get_block, 536af502deSChristoph Hellwig &HFSPLUS_I(mapping->host)->phys_size); 54d5068485SMarco Stornelli if (unlikely(ret)) 55d5068485SMarco Stornelli hfsplus_write_failed(mapping, pos + len); 56282dc178SChristoph Hellwig 57282dc178SChristoph Hellwig return ret; 581da177e4SLinus Torvalds } 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) 611da177e4SLinus Torvalds { 621da177e4SLinus Torvalds return generic_block_bmap(mapping, block, hfsplus_get_block); 631da177e4SLinus Torvalds } 641da177e4SLinus Torvalds 6527496a8cSAl Viro static int hfsplus_releasepage(struct page *page, gfp_t mask) 661da177e4SLinus Torvalds { 671da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 681da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 691da177e4SLinus Torvalds struct hfs_btree *tree; 701da177e4SLinus Torvalds struct hfs_bnode *node; 711da177e4SLinus Torvalds u32 nidx; 721da177e4SLinus Torvalds int i, res = 1; 731da177e4SLinus Torvalds 741da177e4SLinus Torvalds switch (inode->i_ino) { 751da177e4SLinus Torvalds case HFSPLUS_EXT_CNID: 76dd73a01aSChristoph Hellwig tree = HFSPLUS_SB(sb)->ext_tree; 771da177e4SLinus Torvalds break; 781da177e4SLinus Torvalds case HFSPLUS_CAT_CNID: 79dd73a01aSChristoph Hellwig tree = HFSPLUS_SB(sb)->cat_tree; 801da177e4SLinus Torvalds break; 811da177e4SLinus Torvalds case HFSPLUS_ATTR_CNID: 82dd73a01aSChristoph Hellwig tree = HFSPLUS_SB(sb)->attr_tree; 831da177e4SLinus Torvalds break; 841da177e4SLinus Torvalds default: 851da177e4SLinus Torvalds BUG(); 861da177e4SLinus Torvalds return 0; 871da177e4SLinus Torvalds } 8870632249SEric Sesterhenn if (!tree) 8970632249SEric Sesterhenn return 0; 901da177e4SLinus Torvalds if (tree->node_size >= PAGE_CACHE_SIZE) { 912753cc28SAnton Salikhmetov nidx = page->index >> 922753cc28SAnton Salikhmetov (tree->node_size_shift - PAGE_CACHE_SHIFT); 931da177e4SLinus Torvalds spin_lock(&tree->hash_lock); 941da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, nidx); 951da177e4SLinus Torvalds if (!node) 961da177e4SLinus Torvalds ; 971da177e4SLinus Torvalds else if (atomic_read(&node->refcnt)) 981da177e4SLinus Torvalds res = 0; 991da177e4SLinus Torvalds if (res && node) { 1001da177e4SLinus Torvalds hfs_bnode_unhash(node); 1011da177e4SLinus Torvalds hfs_bnode_free(node); 1021da177e4SLinus Torvalds } 1031da177e4SLinus Torvalds spin_unlock(&tree->hash_lock); 1041da177e4SLinus Torvalds } else { 1052753cc28SAnton Salikhmetov nidx = page->index << 1062753cc28SAnton Salikhmetov (PAGE_CACHE_SHIFT - tree->node_size_shift); 1071da177e4SLinus Torvalds i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift); 1081da177e4SLinus Torvalds spin_lock(&tree->hash_lock); 1091da177e4SLinus Torvalds do { 1101da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, nidx++); 1111da177e4SLinus Torvalds if (!node) 1121da177e4SLinus Torvalds continue; 1131da177e4SLinus Torvalds if (atomic_read(&node->refcnt)) { 1141da177e4SLinus Torvalds res = 0; 1151da177e4SLinus Torvalds break; 1161da177e4SLinus Torvalds } 1171da177e4SLinus Torvalds hfs_bnode_unhash(node); 1181da177e4SLinus Torvalds hfs_bnode_free(node); 1191da177e4SLinus Torvalds } while (--i && nidx < tree->node_count); 1201da177e4SLinus Torvalds spin_unlock(&tree->hash_lock); 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds return res ? try_to_free_buffers(page) : 0; 1231da177e4SLinus Torvalds } 1241da177e4SLinus Torvalds 12522c6186eSOmar Sandoval static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter, 12622c6186eSOmar Sandoval loff_t offset) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds struct file *file = iocb->ki_filp; 129d5068485SMarco Stornelli struct address_space *mapping = file->f_mapping; 130496ad9aaSAl Viro struct inode *inode = file_inode(file)->i_mapping->host; 131a6cbcd4aSAl Viro size_t count = iov_iter_count(iter); 132eafdc7d1SChristoph Hellwig ssize_t ret; 1331da177e4SLinus Torvalds 13417f8c842SOmar Sandoval ret = blockdev_direct_IO(iocb, inode, iter, offset, hfsplus_get_block); 135eafdc7d1SChristoph Hellwig 136eafdc7d1SChristoph Hellwig /* 137eafdc7d1SChristoph Hellwig * In case of error extending write may have instantiated a few 138eafdc7d1SChristoph Hellwig * blocks outside i_size. Trim these off again. 139eafdc7d1SChristoph Hellwig */ 1406f673763SOmar Sandoval if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { 141eafdc7d1SChristoph Hellwig loff_t isize = i_size_read(inode); 142a6cbcd4aSAl Viro loff_t end = offset + count; 143eafdc7d1SChristoph Hellwig 144eafdc7d1SChristoph Hellwig if (end > isize) 145d5068485SMarco Stornelli hfsplus_write_failed(mapping, end); 146eafdc7d1SChristoph Hellwig } 147eafdc7d1SChristoph Hellwig 148eafdc7d1SChristoph Hellwig return ret; 1491da177e4SLinus Torvalds } 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds static int hfsplus_writepages(struct address_space *mapping, 1521da177e4SLinus Torvalds struct writeback_control *wbc) 1531da177e4SLinus Torvalds { 1541da177e4SLinus Torvalds return mpage_writepages(mapping, wbc, hfsplus_get_block); 1551da177e4SLinus Torvalds } 1561da177e4SLinus Torvalds 157f5e54d6eSChristoph Hellwig const struct address_space_operations hfsplus_btree_aops = { 1581da177e4SLinus Torvalds .readpage = hfsplus_readpage, 1591da177e4SLinus Torvalds .writepage = hfsplus_writepage, 1607c0efc62SNick Piggin .write_begin = hfsplus_write_begin, 1617c0efc62SNick Piggin .write_end = generic_write_end, 1621da177e4SLinus Torvalds .bmap = hfsplus_bmap, 1631da177e4SLinus Torvalds .releasepage = hfsplus_releasepage, 1641da177e4SLinus Torvalds }; 1651da177e4SLinus Torvalds 166f5e54d6eSChristoph Hellwig const struct address_space_operations hfsplus_aops = { 1671da177e4SLinus Torvalds .readpage = hfsplus_readpage, 1681da177e4SLinus Torvalds .writepage = hfsplus_writepage, 1697c0efc62SNick Piggin .write_begin = hfsplus_write_begin, 1707c0efc62SNick Piggin .write_end = generic_write_end, 1711da177e4SLinus Torvalds .bmap = hfsplus_bmap, 1721da177e4SLinus Torvalds .direct_IO = hfsplus_direct_IO, 1731da177e4SLinus Torvalds .writepages = hfsplus_writepages, 1741da177e4SLinus Torvalds }; 1751da177e4SLinus Torvalds 176e16404edSAl Viro const struct dentry_operations hfsplus_dentry_operations = { 177d45bce8fSDuane Griffin .d_hash = hfsplus_hash_dentry, 178d45bce8fSDuane Griffin .d_compare = hfsplus_compare_dentry, 179d45bce8fSDuane Griffin }; 180d45bce8fSDuane Griffin 1812753cc28SAnton Salikhmetov static void hfsplus_get_perms(struct inode *inode, 1822753cc28SAnton Salikhmetov struct hfsplus_perm *perms, int dir) 1831da177e4SLinus Torvalds { 184dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 1851da177e4SLinus Torvalds u16 mode; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds mode = be16_to_cpu(perms->mode); 1881da177e4SLinus Torvalds 18916525e3fSEric W. Biederman i_uid_write(inode, be32_to_cpu(perms->owner)); 19016525e3fSEric W. Biederman if (!i_uid_read(inode) && !mode) 191dd73a01aSChristoph Hellwig inode->i_uid = sbi->uid; 1921da177e4SLinus Torvalds 19316525e3fSEric W. Biederman i_gid_write(inode, be32_to_cpu(perms->group)); 19416525e3fSEric W. Biederman if (!i_gid_read(inode) && !mode) 195dd73a01aSChristoph Hellwig inode->i_gid = sbi->gid; 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds if (dir) { 198dd73a01aSChristoph Hellwig mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask)); 1991da177e4SLinus Torvalds mode |= S_IFDIR; 2001da177e4SLinus Torvalds } else if (!mode) 201dd73a01aSChristoph Hellwig mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask)); 2021da177e4SLinus Torvalds inode->i_mode = mode; 2031da177e4SLinus Torvalds 2046af502deSChristoph Hellwig HFSPLUS_I(inode)->userflags = perms->userflags; 2051da177e4SLinus Torvalds if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE) 2061da177e4SLinus Torvalds inode->i_flags |= S_IMMUTABLE; 2071da177e4SLinus Torvalds else 2081da177e4SLinus Torvalds inode->i_flags &= ~S_IMMUTABLE; 2091da177e4SLinus Torvalds if (perms->rootflags & HFSPLUS_FLG_APPEND) 2101da177e4SLinus Torvalds inode->i_flags |= S_APPEND; 2111da177e4SLinus Torvalds else 2121da177e4SLinus Torvalds inode->i_flags &= ~S_APPEND; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds static int hfsplus_file_open(struct inode *inode, struct file *file) 2161da177e4SLinus Torvalds { 2171da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 2186af502deSChristoph Hellwig inode = HFSPLUS_I(inode)->rsrc_inode; 2196e715294SAlan Cox if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS) 2206e715294SAlan Cox return -EOVERFLOW; 2216af502deSChristoph Hellwig atomic_inc(&HFSPLUS_I(inode)->opencnt); 2221da177e4SLinus Torvalds return 0; 2231da177e4SLinus Torvalds } 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds static int hfsplus_file_release(struct inode *inode, struct file *file) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 2306af502deSChristoph Hellwig inode = HFSPLUS_I(inode)->rsrc_inode; 2316af502deSChristoph Hellwig if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) { 2321b1dcc1bSJes Sorensen mutex_lock(&inode->i_mutex); 2331da177e4SLinus Torvalds hfsplus_file_truncate(inode); 2341da177e4SLinus Torvalds if (inode->i_flags & S_DEAD) { 235dd73a01aSChristoph Hellwig hfsplus_delete_cat(inode->i_ino, 236dd73a01aSChristoph Hellwig HFSPLUS_SB(sb)->hidden_dir, NULL); 2371da177e4SLinus Torvalds hfsplus_delete_inode(inode); 2381da177e4SLinus Torvalds } 2391b1dcc1bSJes Sorensen mutex_unlock(&inode->i_mutex); 2401da177e4SLinus Torvalds } 2411da177e4SLinus Torvalds return 0; 2421da177e4SLinus Torvalds } 2431da177e4SLinus Torvalds 244d39aae9eSChristoph Hellwig static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) 245d39aae9eSChristoph Hellwig { 2462b0143b5SDavid Howells struct inode *inode = d_inode(dentry); 247d39aae9eSChristoph Hellwig int error; 248d39aae9eSChristoph Hellwig 249d39aae9eSChristoph Hellwig error = inode_change_ok(inode, attr); 250d39aae9eSChristoph Hellwig if (error) 251d39aae9eSChristoph Hellwig return error; 2521025774cSChristoph Hellwig 2531025774cSChristoph Hellwig if ((attr->ia_valid & ATTR_SIZE) && 2541025774cSChristoph Hellwig attr->ia_size != i_size_read(inode)) { 255562c72aaSChristoph Hellwig inode_dio_wait(inode); 256*059a704cSSergei Antonov if (attr->ia_size > inode->i_size) { 257*059a704cSSergei Antonov error = generic_cont_expand_simple(inode, 258*059a704cSSergei Antonov attr->ia_size); 259*059a704cSSergei Antonov if (error) 260*059a704cSSergei Antonov return error; 261*059a704cSSergei Antonov } 262d5068485SMarco Stornelli truncate_setsize(inode, attr->ia_size); 263d5068485SMarco Stornelli hfsplus_file_truncate(inode); 2641025774cSChristoph Hellwig } 2651025774cSChristoph Hellwig 2661025774cSChristoph Hellwig setattr_copy(inode, attr); 2671025774cSChristoph Hellwig mark_inode_dirty(inode); 268b4c1107cSVyacheslav Dubeyko 269b4c1107cSVyacheslav Dubeyko if (attr->ia_valid & ATTR_MODE) { 270b0a7ab57SChristoph Hellwig error = posix_acl_chmod(inode, inode->i_mode); 271b4c1107cSVyacheslav Dubeyko if (unlikely(error)) 272b4c1107cSVyacheslav Dubeyko return error; 273b4c1107cSVyacheslav Dubeyko } 274b4c1107cSVyacheslav Dubeyko 2751025774cSChristoph Hellwig return 0; 276d39aae9eSChristoph Hellwig } 277d39aae9eSChristoph Hellwig 27802c24a82SJosef Bacik int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end, 27902c24a82SJosef Bacik int datasync) 280b5fc510cSAl Viro { 28128146976SChristoph Hellwig struct inode *inode = file->f_mapping->host; 282e3494705SChristoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 28328146976SChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb); 284e3494705SChristoph Hellwig int error = 0, error2; 285b5fc510cSAl Viro 28602c24a82SJosef Bacik error = filemap_write_and_wait_range(inode->i_mapping, start, end); 28702c24a82SJosef Bacik if (error) 28802c24a82SJosef Bacik return error; 28902c24a82SJosef Bacik mutex_lock(&inode->i_mutex); 29002c24a82SJosef Bacik 29128146976SChristoph Hellwig /* 29228146976SChristoph Hellwig * Sync inode metadata into the catalog and extent trees. 29328146976SChristoph Hellwig */ 29428146976SChristoph Hellwig sync_inode_metadata(inode, 1); 295b5fc510cSAl Viro 29628146976SChristoph Hellwig /* 29728146976SChristoph Hellwig * And explicitly write out the btrees. 29828146976SChristoph Hellwig */ 299e3494705SChristoph Hellwig if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags)) 30028146976SChristoph Hellwig error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping); 301e3494705SChristoph Hellwig 302e3494705SChristoph Hellwig if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) { 3032753cc28SAnton Salikhmetov error2 = 3042753cc28SAnton Salikhmetov filemap_write_and_wait(sbi->ext_tree->inode->i_mapping); 30528146976SChristoph Hellwig if (!error) 30628146976SChristoph Hellwig error = error2; 307e3494705SChristoph Hellwig } 308e3494705SChristoph Hellwig 309324ef39aSVyacheslav Dubeyko if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) { 310324ef39aSVyacheslav Dubeyko if (sbi->attr_tree) { 311324ef39aSVyacheslav Dubeyko error2 = 312324ef39aSVyacheslav Dubeyko filemap_write_and_wait( 313324ef39aSVyacheslav Dubeyko sbi->attr_tree->inode->i_mapping); 314324ef39aSVyacheslav Dubeyko if (!error) 315324ef39aSVyacheslav Dubeyko error = error2; 316324ef39aSVyacheslav Dubeyko } else { 317d6142673SJoe Perches pr_err("sync non-existent attributes tree\n"); 318324ef39aSVyacheslav Dubeyko } 319324ef39aSVyacheslav Dubeyko } 320324ef39aSVyacheslav Dubeyko 321e3494705SChristoph Hellwig if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) { 32228146976SChristoph Hellwig error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping); 32328146976SChristoph Hellwig if (!error) 32428146976SChristoph Hellwig error = error2; 325e3494705SChristoph Hellwig } 326e3494705SChristoph Hellwig 32734a2d313SChristoph Hellwig if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags)) 32834a2d313SChristoph Hellwig blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); 32934a2d313SChristoph Hellwig 33002c24a82SJosef Bacik mutex_unlock(&inode->i_mutex); 33102c24a82SJosef Bacik 33228146976SChristoph Hellwig return error; 333b5fc510cSAl Viro } 334b5fc510cSAl Viro 33592e1d5beSArjan van de Ven static const struct inode_operations hfsplus_file_inode_operations = { 336d39aae9eSChristoph Hellwig .setattr = hfsplus_setattr, 337324ef39aSVyacheslav Dubeyko .setxattr = generic_setxattr, 338324ef39aSVyacheslav Dubeyko .getxattr = generic_getxattr, 3391da177e4SLinus Torvalds .listxattr = hfsplus_listxattr, 340b168fff7SChristoph Hellwig .removexattr = generic_removexattr, 341b4c1107cSVyacheslav Dubeyko #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 342b4c1107cSVyacheslav Dubeyko .get_acl = hfsplus_get_posix_acl, 343b0a7ab57SChristoph Hellwig .set_acl = hfsplus_set_posix_acl, 344b4c1107cSVyacheslav Dubeyko #endif 3451da177e4SLinus Torvalds }; 3461da177e4SLinus Torvalds 3474b6f5d20SArjan van de Ven static const struct file_operations hfsplus_file_operations = { 3481da177e4SLinus Torvalds .llseek = generic_file_llseek, 349aad4f8bbSAl Viro .read_iter = generic_file_read_iter, 3508174202bSAl Viro .write_iter = generic_file_write_iter, 3511da177e4SLinus Torvalds .mmap = generic_file_mmap, 3525ffc4ef4SJens Axboe .splice_read = generic_file_splice_read, 353b5fc510cSAl Viro .fsync = hfsplus_file_fsync, 3541da177e4SLinus Torvalds .open = hfsplus_file_open, 3551da177e4SLinus Torvalds .release = hfsplus_file_release, 3567cc4bcc6SArnd Bergmann .unlocked_ioctl = hfsplus_ioctl, 3571da177e4SLinus Torvalds }; 3581da177e4SLinus Torvalds 359c47da798SAl Viro struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode) 3601da177e4SLinus Torvalds { 361dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 3621da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 3636af502deSChristoph Hellwig struct hfsplus_inode_info *hip; 364dd73a01aSChristoph Hellwig 3651da177e4SLinus Torvalds if (!inode) 3661da177e4SLinus Torvalds return NULL; 3671da177e4SLinus Torvalds 368dd73a01aSChristoph Hellwig inode->i_ino = sbi->next_cnid++; 3691da177e4SLinus Torvalds inode->i_mode = mode; 3704ac8489aSDavid Howells inode->i_uid = current_fsuid(); 3714ac8489aSDavid Howells inode->i_gid = current_fsgid(); 372bfe86848SMiklos Szeredi set_nlink(inode, 1); 3731da177e4SLinus Torvalds inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; 3746af502deSChristoph Hellwig 3756af502deSChristoph Hellwig hip = HFSPLUS_I(inode); 3766af502deSChristoph Hellwig INIT_LIST_HEAD(&hip->open_dir_list); 3776af502deSChristoph Hellwig mutex_init(&hip->extents_lock); 3786af502deSChristoph Hellwig atomic_set(&hip->opencnt, 0); 379b33b7921SChristoph Hellwig hip->extent_state = 0; 3806af502deSChristoph Hellwig hip->flags = 0; 381f3922382SMatthew Garrett hip->userflags = 0; 382d7d673a5SSergei Antonov hip->subfolders = 0; 3836af502deSChristoph Hellwig memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec)); 3846af502deSChristoph Hellwig memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 3856af502deSChristoph Hellwig hip->alloc_blocks = 0; 3866af502deSChristoph Hellwig hip->first_blocks = 0; 3876af502deSChristoph Hellwig hip->cached_start = 0; 3886af502deSChristoph Hellwig hip->cached_blocks = 0; 3896af502deSChristoph Hellwig hip->phys_size = 0; 3906af502deSChristoph Hellwig hip->fs_blocks = 0; 3916af502deSChristoph Hellwig hip->rsrc_inode = NULL; 3921da177e4SLinus Torvalds if (S_ISDIR(inode->i_mode)) { 3931da177e4SLinus Torvalds inode->i_size = 2; 394dd73a01aSChristoph Hellwig sbi->folder_count++; 3951da177e4SLinus Torvalds inode->i_op = &hfsplus_dir_inode_operations; 3961da177e4SLinus Torvalds inode->i_fop = &hfsplus_dir_operations; 3971da177e4SLinus Torvalds } else if (S_ISREG(inode->i_mode)) { 398dd73a01aSChristoph Hellwig sbi->file_count++; 3991da177e4SLinus Torvalds inode->i_op = &hfsplus_file_inode_operations; 4001da177e4SLinus Torvalds inode->i_fop = &hfsplus_file_operations; 4011da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 4026af502deSChristoph Hellwig hip->clump_blocks = sbi->data_clump_blocks; 4031da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 404dd73a01aSChristoph Hellwig sbi->file_count++; 4051da177e4SLinus Torvalds inode->i_op = &page_symlink_inode_operations; 4061da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 4076af502deSChristoph Hellwig hip->clump_blocks = 1; 4081da177e4SLinus Torvalds } else 409dd73a01aSChristoph Hellwig sbi->file_count++; 4101da177e4SLinus Torvalds insert_inode_hash(inode); 4111da177e4SLinus Torvalds mark_inode_dirty(inode); 4129e6c5829SArtem Bityutskiy hfsplus_mark_mdb_dirty(sb); 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds return inode; 4151da177e4SLinus Torvalds } 4161da177e4SLinus Torvalds 4171da177e4SLinus Torvalds void hfsplus_delete_inode(struct inode *inode) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 4201da177e4SLinus Torvalds 4211da177e4SLinus Torvalds if (S_ISDIR(inode->i_mode)) { 422dd73a01aSChristoph Hellwig HFSPLUS_SB(sb)->folder_count--; 4239e6c5829SArtem Bityutskiy hfsplus_mark_mdb_dirty(sb); 4241da177e4SLinus Torvalds return; 4251da177e4SLinus Torvalds } 426dd73a01aSChristoph Hellwig HFSPLUS_SB(sb)->file_count--; 4271da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) { 4281da177e4SLinus Torvalds if (!inode->i_nlink) { 4291da177e4SLinus Torvalds inode->i_size = 0; 4301da177e4SLinus Torvalds hfsplus_file_truncate(inode); 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 4331da177e4SLinus Torvalds inode->i_size = 0; 4341da177e4SLinus Torvalds hfsplus_file_truncate(inode); 4351da177e4SLinus Torvalds } 4369e6c5829SArtem Bityutskiy hfsplus_mark_mdb_dirty(sb); 4371da177e4SLinus Torvalds } 4381da177e4SLinus Torvalds 4391da177e4SLinus Torvalds void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork) 4401da177e4SLinus Torvalds { 4411da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 442dd73a01aSChristoph Hellwig struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 4436af502deSChristoph Hellwig struct hfsplus_inode_info *hip = HFSPLUS_I(inode); 4441da177e4SLinus Torvalds u32 count; 4451da177e4SLinus Torvalds int i; 4461da177e4SLinus Torvalds 4476af502deSChristoph Hellwig memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec)); 4481da177e4SLinus Torvalds for (count = 0, i = 0; i < 8; i++) 4491da177e4SLinus Torvalds count += be32_to_cpu(fork->extents[i].block_count); 4506af502deSChristoph Hellwig hip->first_blocks = count; 4516af502deSChristoph Hellwig memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec)); 4526af502deSChristoph Hellwig hip->cached_start = 0; 4536af502deSChristoph Hellwig hip->cached_blocks = 0; 4541da177e4SLinus Torvalds 4556af502deSChristoph Hellwig hip->alloc_blocks = be32_to_cpu(fork->total_blocks); 4566af502deSChristoph Hellwig hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size); 4576af502deSChristoph Hellwig hip->fs_blocks = 4586af502deSChristoph Hellwig (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 4596af502deSChristoph Hellwig inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits); 4606af502deSChristoph Hellwig hip->clump_blocks = 461dd73a01aSChristoph Hellwig be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift; 4626af502deSChristoph Hellwig if (!hip->clump_blocks) { 4636af502deSChristoph Hellwig hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ? 464dd73a01aSChristoph Hellwig sbi->rsrc_clump_blocks : 465dd73a01aSChristoph Hellwig sbi->data_clump_blocks; 466dd73a01aSChristoph Hellwig } 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 4692753cc28SAnton Salikhmetov void hfsplus_inode_write_fork(struct inode *inode, 4702753cc28SAnton Salikhmetov struct hfsplus_fork_raw *fork) 4711da177e4SLinus Torvalds { 4726af502deSChristoph Hellwig memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents, 4731da177e4SLinus Torvalds sizeof(hfsplus_extent_rec)); 4741da177e4SLinus Torvalds fork->total_size = cpu_to_be64(inode->i_size); 4756af502deSChristoph Hellwig fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks); 4761da177e4SLinus Torvalds } 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds hfsplus_cat_entry entry; 4811da177e4SLinus Torvalds int res = 0; 4821da177e4SLinus Torvalds u16 type; 4831da177e4SLinus Torvalds 4841da177e4SLinus Torvalds type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset); 4851da177e4SLinus Torvalds 486f6089ff8SChristoph Hellwig HFSPLUS_I(inode)->linkid = 0; 4871da177e4SLinus Torvalds if (type == HFSPLUS_FOLDER) { 4881da177e4SLinus Torvalds struct hfsplus_cat_folder *folder = &entry.folder; 4891da177e4SLinus Torvalds 4901da177e4SLinus Torvalds if (fd->entrylength < sizeof(struct hfsplus_cat_folder)) 4911da177e4SLinus Torvalds /* panic? */; 4921da177e4SLinus Torvalds hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 4931da177e4SLinus Torvalds sizeof(struct hfsplus_cat_folder)); 4941da177e4SLinus Torvalds hfsplus_get_perms(inode, &folder->permissions, 1); 495bfe86848SMiklos Szeredi set_nlink(inode, 1); 4961da177e4SLinus Torvalds inode->i_size = 2 + be32_to_cpu(folder->valence); 4971da177e4SLinus Torvalds inode->i_atime = hfsp_mt2ut(folder->access_date); 4981da177e4SLinus Torvalds inode->i_mtime = hfsp_mt2ut(folder->content_mod_date); 4999a4cad95SRoman Zippel inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date); 5006af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = folder->create_date; 5016af502deSChristoph Hellwig HFSPLUS_I(inode)->fs_blocks = 0; 502d7d673a5SSergei Antonov if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) { 503d7d673a5SSergei Antonov HFSPLUS_I(inode)->subfolders = 504d7d673a5SSergei Antonov be32_to_cpu(folder->subfolders); 505d7d673a5SSergei Antonov } 5061da177e4SLinus Torvalds inode->i_op = &hfsplus_dir_inode_operations; 5071da177e4SLinus Torvalds inode->i_fop = &hfsplus_dir_operations; 5081da177e4SLinus Torvalds } else if (type == HFSPLUS_FILE) { 5091da177e4SLinus Torvalds struct hfsplus_cat_file *file = &entry.file; 5101da177e4SLinus Torvalds 5111da177e4SLinus Torvalds if (fd->entrylength < sizeof(struct hfsplus_cat_file)) 5121da177e4SLinus Torvalds /* panic? */; 5131da177e4SLinus Torvalds hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, 5141da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 5151da177e4SLinus Torvalds 516b33b7921SChristoph Hellwig hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ? 517b33b7921SChristoph Hellwig &file->rsrc_fork : &file->data_fork); 5181da177e4SLinus Torvalds hfsplus_get_perms(inode, &file->permissions, 0); 519bfe86848SMiklos Szeredi set_nlink(inode, 1); 5201da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) { 5211da177e4SLinus Torvalds if (file->permissions.dev) 522bfe86848SMiklos Szeredi set_nlink(inode, 523bfe86848SMiklos Szeredi be32_to_cpu(file->permissions.dev)); 5241da177e4SLinus Torvalds inode->i_op = &hfsplus_file_inode_operations; 5251da177e4SLinus Torvalds inode->i_fop = &hfsplus_file_operations; 5261da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 5271da177e4SLinus Torvalds } else if (S_ISLNK(inode->i_mode)) { 5281da177e4SLinus Torvalds inode->i_op = &page_symlink_inode_operations; 5291da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfsplus_aops; 5301da177e4SLinus Torvalds } else { 5311da177e4SLinus Torvalds init_special_inode(inode, inode->i_mode, 5321da177e4SLinus Torvalds be32_to_cpu(file->permissions.dev)); 5331da177e4SLinus Torvalds } 5341da177e4SLinus Torvalds inode->i_atime = hfsp_mt2ut(file->access_date); 5351da177e4SLinus Torvalds inode->i_mtime = hfsp_mt2ut(file->content_mod_date); 5369a4cad95SRoman Zippel inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date); 5376af502deSChristoph Hellwig HFSPLUS_I(inode)->create_date = file->create_date; 5381da177e4SLinus Torvalds } else { 539d6142673SJoe Perches pr_err("bad catalog entry used to create inode\n"); 5401da177e4SLinus Torvalds res = -EIO; 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds return res; 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds int hfsplus_cat_write_inode(struct inode *inode) 5461da177e4SLinus Torvalds { 5471da177e4SLinus Torvalds struct inode *main_inode = inode; 5481da177e4SLinus Torvalds struct hfs_find_data fd; 5491da177e4SLinus Torvalds hfsplus_cat_entry entry; 5501da177e4SLinus Torvalds 5511da177e4SLinus Torvalds if (HFSPLUS_IS_RSRC(inode)) 5526af502deSChristoph Hellwig main_inode = HFSPLUS_I(inode)->rsrc_inode; 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds if (!main_inode->i_nlink) 5551da177e4SLinus Torvalds return 0; 5561da177e4SLinus Torvalds 557dd73a01aSChristoph Hellwig if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd)) 5581da177e4SLinus Torvalds /* panic? */ 5591da177e4SLinus Torvalds return -EIO; 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd)) 5621da177e4SLinus Torvalds /* panic? */ 5631da177e4SLinus Torvalds goto out; 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds if (S_ISDIR(main_inode->i_mode)) { 5661da177e4SLinus Torvalds struct hfsplus_cat_folder *folder = &entry.folder; 5671da177e4SLinus Torvalds 5681da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) 5691da177e4SLinus Torvalds /* panic? */; 5701da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 5711da177e4SLinus Torvalds sizeof(struct hfsplus_cat_folder)); 5721da177e4SLinus Torvalds /* simple node checks? */ 57390e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &folder->permissions); 5741da177e4SLinus Torvalds folder->access_date = hfsp_ut2mt(inode->i_atime); 5751da177e4SLinus Torvalds folder->content_mod_date = hfsp_ut2mt(inode->i_mtime); 5761da177e4SLinus Torvalds folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); 5771da177e4SLinus Torvalds folder->valence = cpu_to_be32(inode->i_size - 2); 578d7d673a5SSergei Antonov if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) { 579d7d673a5SSergei Antonov folder->subfolders = 580d7d673a5SSergei Antonov cpu_to_be32(HFSPLUS_I(inode)->subfolders); 581d7d673a5SSergei Antonov } 5821da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 5831da177e4SLinus Torvalds sizeof(struct hfsplus_cat_folder)); 5841da177e4SLinus Torvalds } else if (HFSPLUS_IS_RSRC(inode)) { 5851da177e4SLinus Torvalds struct hfsplus_cat_file *file = &entry.file; 5861da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 5871da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 5881da177e4SLinus Torvalds hfsplus_inode_write_fork(inode, &file->rsrc_fork); 5891da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 5901da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 5911da177e4SLinus Torvalds } else { 5921da177e4SLinus Torvalds struct hfsplus_cat_file *file = &entry.file; 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfsplus_cat_file)) 5951da177e4SLinus Torvalds /* panic? */; 5961da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, 5971da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 5981da177e4SLinus Torvalds hfsplus_inode_write_fork(inode, &file->data_fork); 59990e61690SChristoph Hellwig hfsplus_cat_set_perms(inode, &file->permissions); 6002753cc28SAnton Salikhmetov if (HFSPLUS_FLG_IMMUTABLE & 6012753cc28SAnton Salikhmetov (file->permissions.rootflags | 6022753cc28SAnton Salikhmetov file->permissions.userflags)) 6031da177e4SLinus Torvalds file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED); 6041da177e4SLinus Torvalds else 6051da177e4SLinus Torvalds file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED); 6061da177e4SLinus Torvalds file->access_date = hfsp_ut2mt(inode->i_atime); 6071da177e4SLinus Torvalds file->content_mod_date = hfsp_ut2mt(inode->i_mtime); 6081da177e4SLinus Torvalds file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime); 6091da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &entry, fd.entryoffset, 6101da177e4SLinus Torvalds sizeof(struct hfsplus_cat_file)); 6111da177e4SLinus Torvalds } 612e3494705SChristoph Hellwig 613e3494705SChristoph Hellwig set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags); 6141da177e4SLinus Torvalds out: 6151da177e4SLinus Torvalds hfs_find_exit(&fd); 6161da177e4SLinus Torvalds return 0; 6171da177e4SLinus Torvalds } 618