11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/fs/hfs/inode.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (C) 1995-1997 Paul H. Hargrove 51da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com> 61da177e4SLinus Torvalds * This file may be distributed under the terms of the GNU General Public License. 71da177e4SLinus Torvalds * 81da177e4SLinus Torvalds * This file contains inode-related functions which do not depend on 91da177e4SLinus Torvalds * which scheme is being used to represent forks. 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds 121da177e4SLinus Torvalds */ 131da177e4SLinus Torvalds 141da177e4SLinus Torvalds #include <linux/pagemap.h> 151da177e4SLinus Torvalds #include <linux/mpage.h> 16e8edc6e0SAlexey Dobriyan #include <linux/sched.h> 175b825c3aSIngo Molnar #include <linux/cred.h> 18e2e40f2cSChristoph Hellwig #include <linux/uio.h> 19b8020effSAndreas Gruenbacher #include <linux/xattr.h> 201da177e4SLinus Torvalds 211da177e4SLinus Torvalds #include "hfs_fs.h" 221da177e4SLinus Torvalds #include "btree.h" 231da177e4SLinus Torvalds 244b6f5d20SArjan van de Ven static const struct file_operations hfs_file_operations; 2592e1d5beSArjan van de Ven static const struct inode_operations hfs_file_inode_operations; 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds /*================ Variable-like macros ================*/ 281da177e4SLinus Torvalds 291da177e4SLinus Torvalds #define HFS_VALID_MODE_BITS (S_IFREG | S_IFDIR | S_IRWXUGO) 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds static int hfs_writepage(struct page *page, struct writeback_control *wbc) 321da177e4SLinus Torvalds { 331da177e4SLinus Torvalds return block_write_full_page(page, hfs_get_block, wbc); 341da177e4SLinus Torvalds } 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds static int hfs_readpage(struct file *file, struct page *page) 371da177e4SLinus Torvalds { 381da177e4SLinus Torvalds return block_read_full_page(page, hfs_get_block); 391da177e4SLinus Torvalds } 401da177e4SLinus Torvalds 41c8cf464bSMarco Stornelli static void hfs_write_failed(struct address_space *mapping, loff_t to) 42c8cf464bSMarco Stornelli { 43c8cf464bSMarco Stornelli struct inode *inode = mapping->host; 44c8cf464bSMarco Stornelli 45c8cf464bSMarco Stornelli if (to > inode->i_size) { 467caef267SKirill A. Shutemov truncate_pagecache(inode, inode->i_size); 47c8cf464bSMarco Stornelli hfs_file_truncate(inode); 48c8cf464bSMarco Stornelli } 49c8cf464bSMarco Stornelli } 50c8cf464bSMarco Stornelli 517903d9eeSNick Piggin static int hfs_write_begin(struct file *file, struct address_space *mapping, 527903d9eeSNick Piggin loff_t pos, unsigned len, unsigned flags, 537903d9eeSNick Piggin struct page **pagep, void **fsdata) 541da177e4SLinus Torvalds { 55282dc178SChristoph Hellwig int ret; 56282dc178SChristoph Hellwig 577903d9eeSNick Piggin *pagep = NULL; 58282dc178SChristoph Hellwig ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 597903d9eeSNick Piggin hfs_get_block, 607903d9eeSNick Piggin &HFS_I(mapping->host)->phys_size); 61c8cf464bSMarco Stornelli if (unlikely(ret)) 62c8cf464bSMarco Stornelli hfs_write_failed(mapping, pos + len); 63282dc178SChristoph Hellwig 64282dc178SChristoph Hellwig return ret; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds static sector_t hfs_bmap(struct address_space *mapping, sector_t block) 681da177e4SLinus Torvalds { 691da177e4SLinus Torvalds return generic_block_bmap(mapping, block, hfs_get_block); 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 7227496a8cSAl Viro static int hfs_releasepage(struct page *page, gfp_t mask) 731da177e4SLinus Torvalds { 741da177e4SLinus Torvalds struct inode *inode = page->mapping->host; 751da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 761da177e4SLinus Torvalds struct hfs_btree *tree; 771da177e4SLinus Torvalds struct hfs_bnode *node; 781da177e4SLinus Torvalds u32 nidx; 791da177e4SLinus Torvalds int i, res = 1; 801da177e4SLinus Torvalds 811da177e4SLinus Torvalds switch (inode->i_ino) { 821da177e4SLinus Torvalds case HFS_EXT_CNID: 831da177e4SLinus Torvalds tree = HFS_SB(sb)->ext_tree; 841da177e4SLinus Torvalds break; 851da177e4SLinus Torvalds case HFS_CAT_CNID: 861da177e4SLinus Torvalds tree = HFS_SB(sb)->cat_tree; 871da177e4SLinus Torvalds break; 881da177e4SLinus Torvalds default: 891da177e4SLinus Torvalds BUG(); 901da177e4SLinus Torvalds return 0; 911da177e4SLinus Torvalds } 92eb2e5f45SDave Anderson 93eb2e5f45SDave Anderson if (!tree) 94eb2e5f45SDave Anderson return 0; 95eb2e5f45SDave Anderson 9609cbfeafSKirill A. Shutemov if (tree->node_size >= PAGE_SIZE) { 9709cbfeafSKirill A. Shutemov nidx = page->index >> (tree->node_size_shift - PAGE_SHIFT); 981da177e4SLinus Torvalds spin_lock(&tree->hash_lock); 991da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, nidx); 1001da177e4SLinus Torvalds if (!node) 1011da177e4SLinus Torvalds ; 1021da177e4SLinus Torvalds else if (atomic_read(&node->refcnt)) 1031da177e4SLinus Torvalds res = 0; 1041da177e4SLinus Torvalds if (res && node) { 1051da177e4SLinus Torvalds hfs_bnode_unhash(node); 1061da177e4SLinus Torvalds hfs_bnode_free(node); 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds spin_unlock(&tree->hash_lock); 1091da177e4SLinus Torvalds } else { 11009cbfeafSKirill A. Shutemov nidx = page->index << (PAGE_SHIFT - tree->node_size_shift); 11109cbfeafSKirill A. Shutemov i = 1 << (PAGE_SHIFT - tree->node_size_shift); 1121da177e4SLinus Torvalds spin_lock(&tree->hash_lock); 1131da177e4SLinus Torvalds do { 1141da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, nidx++); 1151da177e4SLinus Torvalds if (!node) 1161da177e4SLinus Torvalds continue; 1171da177e4SLinus Torvalds if (atomic_read(&node->refcnt)) { 1181da177e4SLinus Torvalds res = 0; 1191da177e4SLinus Torvalds break; 1201da177e4SLinus Torvalds } 1211da177e4SLinus Torvalds hfs_bnode_unhash(node); 1221da177e4SLinus Torvalds hfs_bnode_free(node); 1231da177e4SLinus Torvalds } while (--i && nidx < tree->node_count); 1241da177e4SLinus Torvalds spin_unlock(&tree->hash_lock); 1251da177e4SLinus Torvalds } 1261da177e4SLinus Torvalds return res ? try_to_free_buffers(page) : 0; 1271da177e4SLinus Torvalds } 1281da177e4SLinus Torvalds 129c8b8e32dSChristoph Hellwig static ssize_t hfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) 1301da177e4SLinus Torvalds { 1311da177e4SLinus Torvalds struct file *file = iocb->ki_filp; 132c8cf464bSMarco Stornelli struct address_space *mapping = file->f_mapping; 13393c76a3dSAl Viro struct inode *inode = mapping->host; 134a6cbcd4aSAl Viro size_t count = iov_iter_count(iter); 135eafdc7d1SChristoph Hellwig ssize_t ret; 1361da177e4SLinus Torvalds 137c8b8e32dSChristoph Hellwig ret = blockdev_direct_IO(iocb, inode, iter, hfs_get_block); 138eafdc7d1SChristoph Hellwig 139eafdc7d1SChristoph Hellwig /* 140eafdc7d1SChristoph Hellwig * In case of error extending write may have instantiated a few 141eafdc7d1SChristoph Hellwig * blocks outside i_size. Trim these off again. 142eafdc7d1SChristoph Hellwig */ 1436f673763SOmar Sandoval if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { 144eafdc7d1SChristoph Hellwig loff_t isize = i_size_read(inode); 145c8b8e32dSChristoph Hellwig loff_t end = iocb->ki_pos + count; 146eafdc7d1SChristoph Hellwig 147eafdc7d1SChristoph Hellwig if (end > isize) 148c8cf464bSMarco Stornelli hfs_write_failed(mapping, end); 149eafdc7d1SChristoph Hellwig } 150eafdc7d1SChristoph Hellwig 151eafdc7d1SChristoph Hellwig return ret; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds static int hfs_writepages(struct address_space *mapping, 1551da177e4SLinus Torvalds struct writeback_control *wbc) 1561da177e4SLinus Torvalds { 1571da177e4SLinus Torvalds return mpage_writepages(mapping, wbc, hfs_get_block); 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 160f5e54d6eSChristoph Hellwig const struct address_space_operations hfs_btree_aops = { 1611da177e4SLinus Torvalds .readpage = hfs_readpage, 1621da177e4SLinus Torvalds .writepage = hfs_writepage, 1637903d9eeSNick Piggin .write_begin = hfs_write_begin, 1647903d9eeSNick Piggin .write_end = generic_write_end, 1651da177e4SLinus Torvalds .bmap = hfs_bmap, 1661da177e4SLinus Torvalds .releasepage = hfs_releasepage, 1671da177e4SLinus Torvalds }; 1681da177e4SLinus Torvalds 169f5e54d6eSChristoph Hellwig const struct address_space_operations hfs_aops = { 1701da177e4SLinus Torvalds .readpage = hfs_readpage, 1711da177e4SLinus Torvalds .writepage = hfs_writepage, 1727903d9eeSNick Piggin .write_begin = hfs_write_begin, 1737903d9eeSNick Piggin .write_end = generic_write_end, 1741da177e4SLinus Torvalds .bmap = hfs_bmap, 1751da177e4SLinus Torvalds .direct_IO = hfs_direct_IO, 1761da177e4SLinus Torvalds .writepages = hfs_writepages, 1771da177e4SLinus Torvalds }; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds /* 1801da177e4SLinus Torvalds * hfs_new_inode 1811da177e4SLinus Torvalds */ 18271e93963SAl Viro struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t mode) 1831da177e4SLinus Torvalds { 1841da177e4SLinus Torvalds struct super_block *sb = dir->i_sb; 1851da177e4SLinus Torvalds struct inode *inode = new_inode(sb); 1861da177e4SLinus Torvalds if (!inode) 1871da177e4SLinus Torvalds return NULL; 1881da177e4SLinus Torvalds 18939f8d472SMatthias Kaehlcke mutex_init(&HFS_I(inode)->extents_lock); 1901da177e4SLinus Torvalds INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); 1919717a91bSAl Viro spin_lock_init(&HFS_I(inode)->open_dir_lock); 192328b9227SRoman Zippel hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name); 1931da177e4SLinus Torvalds inode->i_ino = HFS_SB(sb)->next_id++; 1941da177e4SLinus Torvalds inode->i_mode = mode; 19594c9a5eeSDavid Howells inode->i_uid = current_fsuid(); 19694c9a5eeSDavid Howells inode->i_gid = current_fsgid(); 197bfe86848SMiklos Szeredi set_nlink(inode, 1); 19802027d42SDeepa Dinamani inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 1991da177e4SLinus Torvalds HFS_I(inode)->flags = 0; 2001da177e4SLinus Torvalds HFS_I(inode)->rsrc_inode = NULL; 2011da177e4SLinus Torvalds HFS_I(inode)->fs_blocks = 0; 2021da177e4SLinus Torvalds if (S_ISDIR(mode)) { 2031da177e4SLinus Torvalds inode->i_size = 2; 2041da177e4SLinus Torvalds HFS_SB(sb)->folder_count++; 2051da177e4SLinus Torvalds if (dir->i_ino == HFS_ROOT_CNID) 2061da177e4SLinus Torvalds HFS_SB(sb)->root_dirs++; 2071da177e4SLinus Torvalds inode->i_op = &hfs_dir_inode_operations; 2081da177e4SLinus Torvalds inode->i_fop = &hfs_dir_operations; 2091da177e4SLinus Torvalds inode->i_mode |= S_IRWXUGO; 2101da177e4SLinus Torvalds inode->i_mode &= ~HFS_SB(inode->i_sb)->s_dir_umask; 2111da177e4SLinus Torvalds } else if (S_ISREG(mode)) { 2121da177e4SLinus Torvalds HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks; 2131da177e4SLinus Torvalds HFS_SB(sb)->file_count++; 2141da177e4SLinus Torvalds if (dir->i_ino == HFS_ROOT_CNID) 2151da177e4SLinus Torvalds HFS_SB(sb)->root_files++; 2161da177e4SLinus Torvalds inode->i_op = &hfs_file_inode_operations; 2171da177e4SLinus Torvalds inode->i_fop = &hfs_file_operations; 2181da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfs_aops; 2191da177e4SLinus Torvalds inode->i_mode |= S_IRUGO|S_IXUGO; 2201da177e4SLinus Torvalds if (mode & S_IWUSR) 2211da177e4SLinus Torvalds inode->i_mode |= S_IWUGO; 2221da177e4SLinus Torvalds inode->i_mode &= ~HFS_SB(inode->i_sb)->s_file_umask; 2231da177e4SLinus Torvalds HFS_I(inode)->phys_size = 0; 2241da177e4SLinus Torvalds HFS_I(inode)->alloc_blocks = 0; 2251da177e4SLinus Torvalds HFS_I(inode)->first_blocks = 0; 2261da177e4SLinus Torvalds HFS_I(inode)->cached_start = 0; 2271da177e4SLinus Torvalds HFS_I(inode)->cached_blocks = 0; 2281da177e4SLinus Torvalds memset(HFS_I(inode)->first_extents, 0, sizeof(hfs_extent_rec)); 2291da177e4SLinus Torvalds memset(HFS_I(inode)->cached_extents, 0, sizeof(hfs_extent_rec)); 2301da177e4SLinus Torvalds } 2311da177e4SLinus Torvalds insert_inode_hash(inode); 2321da177e4SLinus Torvalds mark_inode_dirty(inode); 2331da177e4SLinus Torvalds set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags); 2345687b578SArtem Bityutskiy hfs_mark_mdb_dirty(sb); 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds return inode; 2371da177e4SLinus Torvalds } 2381da177e4SLinus Torvalds 2391da177e4SLinus Torvalds void hfs_delete_inode(struct inode *inode) 2401da177e4SLinus Torvalds { 2411da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2421da177e4SLinus Torvalds 243c2b3e1f7SJoe Perches hfs_dbg(INODE, "delete_inode: %lu\n", inode->i_ino); 2441da177e4SLinus Torvalds if (S_ISDIR(inode->i_mode)) { 2451da177e4SLinus Torvalds HFS_SB(sb)->folder_count--; 2461da177e4SLinus Torvalds if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID)) 2471da177e4SLinus Torvalds HFS_SB(sb)->root_dirs--; 2481da177e4SLinus Torvalds set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags); 2495687b578SArtem Bityutskiy hfs_mark_mdb_dirty(sb); 2501da177e4SLinus Torvalds return; 2511da177e4SLinus Torvalds } 2521da177e4SLinus Torvalds HFS_SB(sb)->file_count--; 2531da177e4SLinus Torvalds if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID)) 2541da177e4SLinus Torvalds HFS_SB(sb)->root_files--; 2551da177e4SLinus Torvalds if (S_ISREG(inode->i_mode)) { 2561da177e4SLinus Torvalds if (!inode->i_nlink) { 2571da177e4SLinus Torvalds inode->i_size = 0; 2581da177e4SLinus Torvalds hfs_file_truncate(inode); 2591da177e4SLinus Torvalds } 2601da177e4SLinus Torvalds } 2611da177e4SLinus Torvalds set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags); 2625687b578SArtem Bityutskiy hfs_mark_mdb_dirty(sb); 2631da177e4SLinus Torvalds } 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext, 2661da177e4SLinus Torvalds __be32 __log_size, __be32 phys_size, u32 clump_size) 2671da177e4SLinus Torvalds { 2681da177e4SLinus Torvalds struct super_block *sb = inode->i_sb; 2691da177e4SLinus Torvalds u32 log_size = be32_to_cpu(__log_size); 2701da177e4SLinus Torvalds u16 count; 2711da177e4SLinus Torvalds int i; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds memcpy(HFS_I(inode)->first_extents, ext, sizeof(hfs_extent_rec)); 2741da177e4SLinus Torvalds for (count = 0, i = 0; i < 3; i++) 2751da177e4SLinus Torvalds count += be16_to_cpu(ext[i].count); 2761da177e4SLinus Torvalds HFS_I(inode)->first_blocks = count; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds inode->i_size = HFS_I(inode)->phys_size = log_size; 2791da177e4SLinus Torvalds HFS_I(inode)->fs_blocks = (log_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 2801da177e4SLinus Torvalds inode_set_bytes(inode, HFS_I(inode)->fs_blocks << sb->s_blocksize_bits); 2811da177e4SLinus Torvalds HFS_I(inode)->alloc_blocks = be32_to_cpu(phys_size) / 2821da177e4SLinus Torvalds HFS_SB(sb)->alloc_blksz; 2831da177e4SLinus Torvalds HFS_I(inode)->clump_blocks = clump_size / HFS_SB(sb)->alloc_blksz; 2841da177e4SLinus Torvalds if (!HFS_I(inode)->clump_blocks) 2851da177e4SLinus Torvalds HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks; 2861da177e4SLinus Torvalds } 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds struct hfs_iget_data { 2891da177e4SLinus Torvalds struct hfs_cat_key *key; 2901da177e4SLinus Torvalds hfs_cat_rec *rec; 2911da177e4SLinus Torvalds }; 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds static int hfs_test_inode(struct inode *inode, void *data) 2941da177e4SLinus Torvalds { 2951da177e4SLinus Torvalds struct hfs_iget_data *idata = data; 2961da177e4SLinus Torvalds hfs_cat_rec *rec; 2971da177e4SLinus Torvalds 2981da177e4SLinus Torvalds rec = idata->rec; 2991da177e4SLinus Torvalds switch (rec->type) { 3001da177e4SLinus Torvalds case HFS_CDR_DIR: 3011da177e4SLinus Torvalds return inode->i_ino == be32_to_cpu(rec->dir.DirID); 3021da177e4SLinus Torvalds case HFS_CDR_FIL: 3031da177e4SLinus Torvalds return inode->i_ino == be32_to_cpu(rec->file.FlNum); 3041da177e4SLinus Torvalds default: 3051da177e4SLinus Torvalds BUG(); 3061da177e4SLinus Torvalds return 1; 3071da177e4SLinus Torvalds } 3081da177e4SLinus Torvalds } 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds /* 3111da177e4SLinus Torvalds * hfs_read_inode 3121da177e4SLinus Torvalds */ 3131da177e4SLinus Torvalds static int hfs_read_inode(struct inode *inode, void *data) 3141da177e4SLinus Torvalds { 3151da177e4SLinus Torvalds struct hfs_iget_data *idata = data; 3161da177e4SLinus Torvalds struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); 3171da177e4SLinus Torvalds hfs_cat_rec *rec; 3181da177e4SLinus Torvalds 3191da177e4SLinus Torvalds HFS_I(inode)->flags = 0; 3201da177e4SLinus Torvalds HFS_I(inode)->rsrc_inode = NULL; 32139f8d472SMatthias Kaehlcke mutex_init(&HFS_I(inode)->extents_lock); 3221da177e4SLinus Torvalds INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); 3239717a91bSAl Viro spin_lock_init(&HFS_I(inode)->open_dir_lock); 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds /* Initialize the inode */ 3261da177e4SLinus Torvalds inode->i_uid = hsb->s_uid; 3271da177e4SLinus Torvalds inode->i_gid = hsb->s_gid; 328bfe86848SMiklos Szeredi set_nlink(inode, 1); 3291da177e4SLinus Torvalds 3301da177e4SLinus Torvalds if (idata->key) 3311da177e4SLinus Torvalds HFS_I(inode)->cat_key = *idata->key; 3321da177e4SLinus Torvalds else 3331da177e4SLinus Torvalds HFS_I(inode)->flags |= HFS_FLG_RSRC; 3341da177e4SLinus Torvalds HFS_I(inode)->tz_secondswest = sys_tz.tz_minuteswest * 60; 3351da177e4SLinus Torvalds 3361da177e4SLinus Torvalds rec = idata->rec; 3371da177e4SLinus Torvalds switch (rec->type) { 3381da177e4SLinus Torvalds case HFS_CDR_FIL: 3391da177e4SLinus Torvalds if (!HFS_IS_RSRC(inode)) { 3401da177e4SLinus Torvalds hfs_inode_read_fork(inode, rec->file.ExtRec, rec->file.LgLen, 3411da177e4SLinus Torvalds rec->file.PyLen, be16_to_cpu(rec->file.ClpSize)); 3421da177e4SLinus Torvalds } else { 3431da177e4SLinus Torvalds hfs_inode_read_fork(inode, rec->file.RExtRec, rec->file.RLgLen, 3441da177e4SLinus Torvalds rec->file.RPyLen, be16_to_cpu(rec->file.ClpSize)); 3451da177e4SLinus Torvalds } 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds inode->i_ino = be32_to_cpu(rec->file.FlNum); 3481da177e4SLinus Torvalds inode->i_mode = S_IRUGO | S_IXUGO; 3491da177e4SLinus Torvalds if (!(rec->file.Flags & HFS_FIL_LOCK)) 3501da177e4SLinus Torvalds inode->i_mode |= S_IWUGO; 3511da177e4SLinus Torvalds inode->i_mode &= ~hsb->s_file_umask; 3521da177e4SLinus Torvalds inode->i_mode |= S_IFREG; 3531da177e4SLinus Torvalds inode->i_ctime = inode->i_atime = inode->i_mtime = 3541da177e4SLinus Torvalds hfs_m_to_utime(rec->file.MdDat); 3551da177e4SLinus Torvalds inode->i_op = &hfs_file_inode_operations; 3561da177e4SLinus Torvalds inode->i_fop = &hfs_file_operations; 3571da177e4SLinus Torvalds inode->i_mapping->a_ops = &hfs_aops; 3581da177e4SLinus Torvalds break; 3591da177e4SLinus Torvalds case HFS_CDR_DIR: 3601da177e4SLinus Torvalds inode->i_ino = be32_to_cpu(rec->dir.DirID); 3611da177e4SLinus Torvalds inode->i_size = be16_to_cpu(rec->dir.Val) + 2; 3621da177e4SLinus Torvalds HFS_I(inode)->fs_blocks = 0; 3631da177e4SLinus Torvalds inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask); 3641da177e4SLinus Torvalds inode->i_ctime = inode->i_atime = inode->i_mtime = 3651da177e4SLinus Torvalds hfs_m_to_utime(rec->dir.MdDat); 3661da177e4SLinus Torvalds inode->i_op = &hfs_dir_inode_operations; 3671da177e4SLinus Torvalds inode->i_fop = &hfs_dir_operations; 3681da177e4SLinus Torvalds break; 3691da177e4SLinus Torvalds default: 3701da177e4SLinus Torvalds make_bad_inode(inode); 3711da177e4SLinus Torvalds } 3721da177e4SLinus Torvalds return 0; 3731da177e4SLinus Torvalds } 3741da177e4SLinus Torvalds 3751da177e4SLinus Torvalds /* 3761da177e4SLinus Torvalds * __hfs_iget() 3771da177e4SLinus Torvalds * 3781da177e4SLinus Torvalds * Given the MDB for a HFS filesystem, a 'key' and an 'entry' in 3791da177e4SLinus Torvalds * the catalog B-tree and the 'type' of the desired file return the 3801da177e4SLinus Torvalds * inode for that file/directory or NULL. Note that 'type' indicates 3811da177e4SLinus Torvalds * whether we want the actual file or directory, or the corresponding 3821da177e4SLinus Torvalds * metadata (AppleDouble header file or CAP metadata file). 3831da177e4SLinus Torvalds */ 3841da177e4SLinus Torvalds struct inode *hfs_iget(struct super_block *sb, struct hfs_cat_key *key, hfs_cat_rec *rec) 3851da177e4SLinus Torvalds { 3861da177e4SLinus Torvalds struct hfs_iget_data data = { key, rec }; 3871da177e4SLinus Torvalds struct inode *inode; 3881da177e4SLinus Torvalds u32 cnid; 3891da177e4SLinus Torvalds 3901da177e4SLinus Torvalds switch (rec->type) { 3911da177e4SLinus Torvalds case HFS_CDR_DIR: 3921da177e4SLinus Torvalds cnid = be32_to_cpu(rec->dir.DirID); 3931da177e4SLinus Torvalds break; 3941da177e4SLinus Torvalds case HFS_CDR_FIL: 3951da177e4SLinus Torvalds cnid = be32_to_cpu(rec->file.FlNum); 3961da177e4SLinus Torvalds break; 3971da177e4SLinus Torvalds default: 3981da177e4SLinus Torvalds return NULL; 3991da177e4SLinus Torvalds } 4001da177e4SLinus Torvalds inode = iget5_locked(sb, cnid, hfs_test_inode, hfs_read_inode, &data); 4011da177e4SLinus Torvalds if (inode && (inode->i_state & I_NEW)) 4021da177e4SLinus Torvalds unlock_new_inode(inode); 4031da177e4SLinus Torvalds return inode; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 4061da177e4SLinus Torvalds void hfs_inode_write_fork(struct inode *inode, struct hfs_extent *ext, 4071da177e4SLinus Torvalds __be32 *log_size, __be32 *phys_size) 4081da177e4SLinus Torvalds { 4091da177e4SLinus Torvalds memcpy(ext, HFS_I(inode)->first_extents, sizeof(hfs_extent_rec)); 4101da177e4SLinus Torvalds 4111da177e4SLinus Torvalds if (log_size) 4121da177e4SLinus Torvalds *log_size = cpu_to_be32(inode->i_size); 4131da177e4SLinus Torvalds if (phys_size) 4141da177e4SLinus Torvalds *phys_size = cpu_to_be32(HFS_I(inode)->alloc_blocks * 4151da177e4SLinus Torvalds HFS_SB(inode->i_sb)->alloc_blksz); 4161da177e4SLinus Torvalds } 4171da177e4SLinus Torvalds 418a9185b41SChristoph Hellwig int hfs_write_inode(struct inode *inode, struct writeback_control *wbc) 4191da177e4SLinus Torvalds { 4201da177e4SLinus Torvalds struct inode *main_inode = inode; 4211da177e4SLinus Torvalds struct hfs_find_data fd; 4221da177e4SLinus Torvalds hfs_cat_rec rec; 4239509f178SAlexey Khoroshilov int res; 4241da177e4SLinus Torvalds 425c2b3e1f7SJoe Perches hfs_dbg(INODE, "hfs_write_inode: %lu\n", inode->i_ino); 4269509f178SAlexey Khoroshilov res = hfs_ext_write_extent(inode); 4279509f178SAlexey Khoroshilov if (res) 4289509f178SAlexey Khoroshilov return res; 4291da177e4SLinus Torvalds 4301da177e4SLinus Torvalds if (inode->i_ino < HFS_FIRSTUSER_CNID) { 4311da177e4SLinus Torvalds switch (inode->i_ino) { 4321da177e4SLinus Torvalds case HFS_ROOT_CNID: 4331da177e4SLinus Torvalds break; 4341da177e4SLinus Torvalds case HFS_EXT_CNID: 4351da177e4SLinus Torvalds hfs_btree_write(HFS_SB(inode->i_sb)->ext_tree); 4361da177e4SLinus Torvalds return 0; 4371da177e4SLinus Torvalds case HFS_CAT_CNID: 4381da177e4SLinus Torvalds hfs_btree_write(HFS_SB(inode->i_sb)->cat_tree); 4391da177e4SLinus Torvalds return 0; 4401da177e4SLinus Torvalds default: 4411da177e4SLinus Torvalds BUG(); 4421da177e4SLinus Torvalds return -EIO; 4431da177e4SLinus Torvalds } 4441da177e4SLinus Torvalds } 4451da177e4SLinus Torvalds 4461da177e4SLinus Torvalds if (HFS_IS_RSRC(inode)) 4471da177e4SLinus Torvalds main_inode = HFS_I(inode)->rsrc_inode; 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds if (!main_inode->i_nlink) 4501da177e4SLinus Torvalds return 0; 4511da177e4SLinus Torvalds 4521da177e4SLinus Torvalds if (hfs_find_init(HFS_SB(main_inode->i_sb)->cat_tree, &fd)) 4531da177e4SLinus Torvalds /* panic? */ 4541da177e4SLinus Torvalds return -EIO; 4551da177e4SLinus Torvalds 4561da177e4SLinus Torvalds fd.search_key->cat = HFS_I(main_inode)->cat_key; 4571da177e4SLinus Torvalds if (hfs_brec_find(&fd)) 4581da177e4SLinus Torvalds /* panic? */ 4591da177e4SLinus Torvalds goto out; 4601da177e4SLinus Torvalds 4611da177e4SLinus Torvalds if (S_ISDIR(main_inode->i_mode)) { 4621da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfs_cat_dir)) 4631da177e4SLinus Torvalds /* panic? */; 4641da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, 4651da177e4SLinus Torvalds sizeof(struct hfs_cat_dir)); 4661da177e4SLinus Torvalds if (rec.type != HFS_CDR_DIR || 4671da177e4SLinus Torvalds be32_to_cpu(rec.dir.DirID) != inode->i_ino) { 4681da177e4SLinus Torvalds } 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds rec.dir.MdDat = hfs_u_to_mtime(inode->i_mtime); 4711da177e4SLinus Torvalds rec.dir.Val = cpu_to_be16(inode->i_size - 2); 4721da177e4SLinus Torvalds 4731da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, 4741da177e4SLinus Torvalds sizeof(struct hfs_cat_dir)); 4751da177e4SLinus Torvalds } else if (HFS_IS_RSRC(inode)) { 4761da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, 4771da177e4SLinus Torvalds sizeof(struct hfs_cat_file)); 4781da177e4SLinus Torvalds hfs_inode_write_fork(inode, rec.file.RExtRec, 4791da177e4SLinus Torvalds &rec.file.RLgLen, &rec.file.RPyLen); 4801da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, 4811da177e4SLinus Torvalds sizeof(struct hfs_cat_file)); 4821da177e4SLinus Torvalds } else { 4831da177e4SLinus Torvalds if (fd.entrylength < sizeof(struct hfs_cat_file)) 4841da177e4SLinus Torvalds /* panic? */; 4851da177e4SLinus Torvalds hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, 4861da177e4SLinus Torvalds sizeof(struct hfs_cat_file)); 4871da177e4SLinus Torvalds if (rec.type != HFS_CDR_FIL || 4881da177e4SLinus Torvalds be32_to_cpu(rec.file.FlNum) != inode->i_ino) { 4891da177e4SLinus Torvalds } 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds if (inode->i_mode & S_IWUSR) 4921da177e4SLinus Torvalds rec.file.Flags &= ~HFS_FIL_LOCK; 4931da177e4SLinus Torvalds else 4941da177e4SLinus Torvalds rec.file.Flags |= HFS_FIL_LOCK; 4951da177e4SLinus Torvalds hfs_inode_write_fork(inode, rec.file.ExtRec, &rec.file.LgLen, &rec.file.PyLen); 4961da177e4SLinus Torvalds rec.file.MdDat = hfs_u_to_mtime(inode->i_mtime); 4971da177e4SLinus Torvalds 4981da177e4SLinus Torvalds hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, 4991da177e4SLinus Torvalds sizeof(struct hfs_cat_file)); 5001da177e4SLinus Torvalds } 5011da177e4SLinus Torvalds out: 5021da177e4SLinus Torvalds hfs_find_exit(&fd); 5031da177e4SLinus Torvalds return 0; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds 5061da177e4SLinus Torvalds static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry, 50700cd8dd3SAl Viro unsigned int flags) 5081da177e4SLinus Torvalds { 5091da177e4SLinus Torvalds struct inode *inode = NULL; 5101da177e4SLinus Torvalds hfs_cat_rec rec; 5111da177e4SLinus Torvalds struct hfs_find_data fd; 5121da177e4SLinus Torvalds int res; 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds if (HFS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc")) 5151da177e4SLinus Torvalds goto out; 5161da177e4SLinus Torvalds 5171da177e4SLinus Torvalds inode = HFS_I(dir)->rsrc_inode; 5181da177e4SLinus Torvalds if (inode) 5191da177e4SLinus Torvalds goto out; 5201da177e4SLinus Torvalds 5211da177e4SLinus Torvalds inode = new_inode(dir->i_sb); 5221da177e4SLinus Torvalds if (!inode) 5231da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 5241da177e4SLinus Torvalds 5259509f178SAlexey Khoroshilov res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); 5269509f178SAlexey Khoroshilov if (res) { 5279509f178SAlexey Khoroshilov iput(inode); 5289509f178SAlexey Khoroshilov return ERR_PTR(res); 5299509f178SAlexey Khoroshilov } 5301da177e4SLinus Torvalds fd.search_key->cat = HFS_I(dir)->cat_key; 5311da177e4SLinus Torvalds res = hfs_brec_read(&fd, &rec, sizeof(rec)); 5321da177e4SLinus Torvalds if (!res) { 5331da177e4SLinus Torvalds struct hfs_iget_data idata = { NULL, &rec }; 5341da177e4SLinus Torvalds hfs_read_inode(inode, &idata); 5351da177e4SLinus Torvalds } 5361da177e4SLinus Torvalds hfs_find_exit(&fd); 5371da177e4SLinus Torvalds if (res) { 5381da177e4SLinus Torvalds iput(inode); 5391da177e4SLinus Torvalds return ERR_PTR(res); 5401da177e4SLinus Torvalds } 5411da177e4SLinus Torvalds HFS_I(inode)->rsrc_inode = dir; 5421da177e4SLinus Torvalds HFS_I(dir)->rsrc_inode = inode; 5431da177e4SLinus Torvalds igrab(dir); 54489b0fc38SAl Viro hlist_add_fake(&inode->i_hash); 5451da177e4SLinus Torvalds mark_inode_dirty(inode); 546*0e5c56fdSAl Viro dont_mount(dentry); 5471da177e4SLinus Torvalds out: 5486b9cceeaSAl Viro return d_splice_alias(inode, dentry); 5491da177e4SLinus Torvalds } 5501da177e4SLinus Torvalds 551b57922d9SAl Viro void hfs_evict_inode(struct inode *inode) 5521da177e4SLinus Torvalds { 55391b0abe3SJohannes Weiner truncate_inode_pages_final(&inode->i_data); 554dbd5768fSJan Kara clear_inode(inode); 5551da177e4SLinus Torvalds if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) { 5561da177e4SLinus Torvalds HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL; 5571da177e4SLinus Torvalds iput(HFS_I(inode)->rsrc_inode); 5581da177e4SLinus Torvalds } 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds 5611da177e4SLinus Torvalds static int hfs_file_open(struct inode *inode, struct file *file) 5621da177e4SLinus Torvalds { 5631da177e4SLinus Torvalds if (HFS_IS_RSRC(inode)) 5641da177e4SLinus Torvalds inode = HFS_I(inode)->rsrc_inode; 5651da177e4SLinus Torvalds atomic_inc(&HFS_I(inode)->opencnt); 5661da177e4SLinus Torvalds return 0; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds static int hfs_file_release(struct inode *inode, struct file *file) 5701da177e4SLinus Torvalds { 5711da177e4SLinus Torvalds //struct super_block *sb = inode->i_sb; 5721da177e4SLinus Torvalds 5731da177e4SLinus Torvalds if (HFS_IS_RSRC(inode)) 5741da177e4SLinus Torvalds inode = HFS_I(inode)->rsrc_inode; 5751da177e4SLinus Torvalds if (atomic_dec_and_test(&HFS_I(inode)->opencnt)) { 5765955102cSAl Viro inode_lock(inode); 5771da177e4SLinus Torvalds hfs_file_truncate(inode); 5781da177e4SLinus Torvalds //if (inode->i_flags & S_DEAD) { 5791da177e4SLinus Torvalds // hfs_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); 5801da177e4SLinus Torvalds // hfs_delete_inode(inode); 5811da177e4SLinus Torvalds //} 5825955102cSAl Viro inode_unlock(inode); 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds return 0; 5851da177e4SLinus Torvalds } 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds /* 5881da177e4SLinus Torvalds * hfs_notify_change() 5891da177e4SLinus Torvalds * 5901da177e4SLinus Torvalds * Based very closely on fs/msdos/inode.c by Werner Almesberger 5911da177e4SLinus Torvalds * 5921da177e4SLinus Torvalds * This is the notify_change() field in the super_operations structure 5931da177e4SLinus Torvalds * for HFS file systems. The purpose is to take that changes made to 5941da177e4SLinus Torvalds * an inode and apply then in a filesystem-dependent manner. In this 5951da177e4SLinus Torvalds * case the process has a few of tasks to do: 5961da177e4SLinus Torvalds * 1) prevent changes to the i_uid and i_gid fields. 5971da177e4SLinus Torvalds * 2) map file permissions to the closest allowable permissions 5981da177e4SLinus Torvalds * 3) Since multiple Linux files can share the same on-disk inode under 5991da177e4SLinus Torvalds * HFS (for instance the data and resource forks of a file) a change 6001da177e4SLinus Torvalds * to permissions must be applied to all other in-core inodes which 6011da177e4SLinus Torvalds * correspond to the same HFS file. 6021da177e4SLinus Torvalds */ 6031da177e4SLinus Torvalds 6041da177e4SLinus Torvalds int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) 6051da177e4SLinus Torvalds { 6062b0143b5SDavid Howells struct inode *inode = d_inode(dentry); 6071da177e4SLinus Torvalds struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); 6081da177e4SLinus Torvalds int error; 6091da177e4SLinus Torvalds 61031051c85SJan Kara error = setattr_prepare(dentry, attr); /* basic permission checks */ 6111da177e4SLinus Torvalds if (error) 6121da177e4SLinus Torvalds return error; 6131da177e4SLinus Torvalds 6141da177e4SLinus Torvalds /* no uig/gid changes and limit which mode bits can be set */ 6151da177e4SLinus Torvalds if (((attr->ia_valid & ATTR_UID) && 61643b5e4ccSEric W. Biederman (!uid_eq(attr->ia_uid, hsb->s_uid))) || 6171da177e4SLinus Torvalds ((attr->ia_valid & ATTR_GID) && 61843b5e4ccSEric W. Biederman (!gid_eq(attr->ia_gid, hsb->s_gid))) || 6191da177e4SLinus Torvalds ((attr->ia_valid & ATTR_MODE) && 6201da177e4SLinus Torvalds ((S_ISDIR(inode->i_mode) && 6211da177e4SLinus Torvalds (attr->ia_mode != inode->i_mode)) || 6221da177e4SLinus Torvalds (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) { 6231da177e4SLinus Torvalds return hsb->s_quiet ? 0 : error; 6241da177e4SLinus Torvalds } 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds if (attr->ia_valid & ATTR_MODE) { 6271da177e4SLinus Torvalds /* Only the 'w' bits can ever change and only all together. */ 6281da177e4SLinus Torvalds if (attr->ia_mode & S_IWUSR) 6291da177e4SLinus Torvalds attr->ia_mode = inode->i_mode | S_IWUGO; 6301da177e4SLinus Torvalds else 6311da177e4SLinus Torvalds attr->ia_mode = inode->i_mode & ~S_IWUGO; 6321da177e4SLinus Torvalds attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; 6331da177e4SLinus Torvalds } 6341025774cSChristoph Hellwig 6351025774cSChristoph Hellwig if ((attr->ia_valid & ATTR_SIZE) && 6361025774cSChristoph Hellwig attr->ia_size != i_size_read(inode)) { 637562c72aaSChristoph Hellwig inode_dio_wait(inode); 638562c72aaSChristoph Hellwig 639c8cf464bSMarco Stornelli error = inode_newsize_ok(inode, attr->ia_size); 6401da177e4SLinus Torvalds if (error) 6411da177e4SLinus Torvalds return error; 642c8cf464bSMarco Stornelli 643c8cf464bSMarco Stornelli truncate_setsize(inode, attr->ia_size); 644c8cf464bSMarco Stornelli hfs_file_truncate(inode); 6451025774cSChristoph Hellwig } 6461da177e4SLinus Torvalds 6471025774cSChristoph Hellwig setattr_copy(inode, attr); 6481025774cSChristoph Hellwig mark_inode_dirty(inode); 6491da177e4SLinus Torvalds return 0; 6501da177e4SLinus Torvalds } 6511da177e4SLinus Torvalds 65202c24a82SJosef Bacik static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, 65302c24a82SJosef Bacik int datasync) 654b5fc510cSAl Viro { 655b5fc510cSAl Viro struct inode *inode = filp->f_mapping->host; 656b5fc510cSAl Viro struct super_block * sb; 657b5fc510cSAl Viro int ret, err; 658b5fc510cSAl Viro 6593b49c9a1SJeff Layton ret = file_write_and_wait_range(filp, start, end); 66002c24a82SJosef Bacik if (ret) 66102c24a82SJosef Bacik return ret; 6625955102cSAl Viro inode_lock(inode); 66302c24a82SJosef Bacik 664b5fc510cSAl Viro /* sync the inode to buffers */ 665b5fc510cSAl Viro ret = write_inode_now(inode, 0); 666b5fc510cSAl Viro 667b5fc510cSAl Viro /* sync the superblock to buffers */ 668b5fc510cSAl Viro sb = inode->i_sb; 66943829731STejun Heo flush_delayed_work(&HFS_SB(sb)->mdb_work); 670b5fc510cSAl Viro /* .. finally sync the buffers to disk */ 671b5fc510cSAl Viro err = sync_blockdev(sb->s_bdev); 672b5fc510cSAl Viro if (!ret) 673b5fc510cSAl Viro ret = err; 6745955102cSAl Viro inode_unlock(inode); 675b5fc510cSAl Viro return ret; 676b5fc510cSAl Viro } 6771da177e4SLinus Torvalds 6784b6f5d20SArjan van de Ven static const struct file_operations hfs_file_operations = { 6791da177e4SLinus Torvalds .llseek = generic_file_llseek, 680aad4f8bbSAl Viro .read_iter = generic_file_read_iter, 6818174202bSAl Viro .write_iter = generic_file_write_iter, 6821da177e4SLinus Torvalds .mmap = generic_file_mmap, 6835ffc4ef4SJens Axboe .splice_read = generic_file_splice_read, 684b5fc510cSAl Viro .fsync = hfs_file_fsync, 6851da177e4SLinus Torvalds .open = hfs_file_open, 6861da177e4SLinus Torvalds .release = hfs_file_release, 6871da177e4SLinus Torvalds }; 6881da177e4SLinus Torvalds 68992e1d5beSArjan van de Ven static const struct inode_operations hfs_file_inode_operations = { 6901da177e4SLinus Torvalds .lookup = hfs_file_lookup, 6911da177e4SLinus Torvalds .setattr = hfs_inode_setattr, 692b8020effSAndreas Gruenbacher .listxattr = generic_listxattr, 6931da177e4SLinus Torvalds }; 694