18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * linux/fs/hfs/inode.c 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 1995-1997 Paul H. Hargrove 58c2ecf20Sopenharmony_ci * (C) 2003 Ardis Technologies <roman@ardistech.com> 68c2ecf20Sopenharmony_ci * This file may be distributed under the terms of the GNU General Public License. 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * This file contains inode-related functions which do not depend on 98c2ecf20Sopenharmony_ci * which scheme is being used to represent forks. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Based on the minix file system code, (C) 1991, 1992 by Linus Torvalds 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 158c2ecf20Sopenharmony_ci#include <linux/mpage.h> 168c2ecf20Sopenharmony_ci#include <linux/sched.h> 178c2ecf20Sopenharmony_ci#include <linux/cred.h> 188c2ecf20Sopenharmony_ci#include <linux/uio.h> 198c2ecf20Sopenharmony_ci#include <linux/xattr.h> 208c2ecf20Sopenharmony_ci#include <linux/blkdev.h> 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include "hfs_fs.h" 238c2ecf20Sopenharmony_ci#include "btree.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic const struct file_operations hfs_file_operations; 268c2ecf20Sopenharmony_cistatic const struct inode_operations hfs_file_inode_operations; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/*================ Variable-like macros ================*/ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define HFS_VALID_MODE_BITS (S_IFREG | S_IFDIR | S_IRWXUGO) 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistatic int hfs_writepage(struct page *page, struct writeback_control *wbc) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci return block_write_full_page(page, hfs_get_block, wbc); 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int hfs_readpage(struct file *file, struct page *page) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci return block_read_full_page(page, hfs_get_block); 408c2ecf20Sopenharmony_ci} 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic void hfs_write_failed(struct address_space *mapping, loff_t to) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci if (to > inode->i_size) { 478c2ecf20Sopenharmony_ci truncate_pagecache(inode, inode->i_size); 488c2ecf20Sopenharmony_ci hfs_file_truncate(inode); 498c2ecf20Sopenharmony_ci } 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic int hfs_write_begin(struct file *file, struct address_space *mapping, 538c2ecf20Sopenharmony_ci loff_t pos, unsigned len, unsigned flags, 548c2ecf20Sopenharmony_ci struct page **pagep, void **fsdata) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci int ret; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci *pagep = NULL; 598c2ecf20Sopenharmony_ci ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, 608c2ecf20Sopenharmony_ci hfs_get_block, 618c2ecf20Sopenharmony_ci &HFS_I(mapping->host)->phys_size); 628c2ecf20Sopenharmony_ci if (unlikely(ret)) 638c2ecf20Sopenharmony_ci hfs_write_failed(mapping, pos + len); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return ret; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic sector_t hfs_bmap(struct address_space *mapping, sector_t block) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci return generic_block_bmap(mapping, block, hfs_get_block); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int hfs_releasepage(struct page *page, gfp_t mask) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci struct inode *inode = page->mapping->host; 768c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 778c2ecf20Sopenharmony_ci struct hfs_btree *tree; 788c2ecf20Sopenharmony_ci struct hfs_bnode *node; 798c2ecf20Sopenharmony_ci u32 nidx; 808c2ecf20Sopenharmony_ci int i, res = 1; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci switch (inode->i_ino) { 838c2ecf20Sopenharmony_ci case HFS_EXT_CNID: 848c2ecf20Sopenharmony_ci tree = HFS_SB(sb)->ext_tree; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci case HFS_CAT_CNID: 878c2ecf20Sopenharmony_ci tree = HFS_SB(sb)->cat_tree; 888c2ecf20Sopenharmony_ci break; 898c2ecf20Sopenharmony_ci default: 908c2ecf20Sopenharmony_ci BUG(); 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (!tree) 958c2ecf20Sopenharmony_ci return 0; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci if (tree->node_size >= PAGE_SIZE) { 988c2ecf20Sopenharmony_ci nidx = page->index >> (tree->node_size_shift - PAGE_SHIFT); 998c2ecf20Sopenharmony_ci spin_lock(&tree->hash_lock); 1008c2ecf20Sopenharmony_ci node = hfs_bnode_findhash(tree, nidx); 1018c2ecf20Sopenharmony_ci if (!node) 1028c2ecf20Sopenharmony_ci ; 1038c2ecf20Sopenharmony_ci else if (atomic_read(&node->refcnt)) 1048c2ecf20Sopenharmony_ci res = 0; 1058c2ecf20Sopenharmony_ci if (res && node) { 1068c2ecf20Sopenharmony_ci hfs_bnode_unhash(node); 1078c2ecf20Sopenharmony_ci hfs_bnode_free(node); 1088c2ecf20Sopenharmony_ci } 1098c2ecf20Sopenharmony_ci spin_unlock(&tree->hash_lock); 1108c2ecf20Sopenharmony_ci } else { 1118c2ecf20Sopenharmony_ci nidx = page->index << (PAGE_SHIFT - tree->node_size_shift); 1128c2ecf20Sopenharmony_ci i = 1 << (PAGE_SHIFT - tree->node_size_shift); 1138c2ecf20Sopenharmony_ci spin_lock(&tree->hash_lock); 1148c2ecf20Sopenharmony_ci do { 1158c2ecf20Sopenharmony_ci node = hfs_bnode_findhash(tree, nidx++); 1168c2ecf20Sopenharmony_ci if (!node) 1178c2ecf20Sopenharmony_ci continue; 1188c2ecf20Sopenharmony_ci if (atomic_read(&node->refcnt)) { 1198c2ecf20Sopenharmony_ci res = 0; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci hfs_bnode_unhash(node); 1238c2ecf20Sopenharmony_ci hfs_bnode_free(node); 1248c2ecf20Sopenharmony_ci } while (--i && nidx < tree->node_count); 1258c2ecf20Sopenharmony_ci spin_unlock(&tree->hash_lock); 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci return res ? try_to_free_buffers(page) : 0; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_cistatic ssize_t hfs_direct_IO(struct kiocb *iocb, struct iov_iter *iter) 1318c2ecf20Sopenharmony_ci{ 1328c2ecf20Sopenharmony_ci struct file *file = iocb->ki_filp; 1338c2ecf20Sopenharmony_ci struct address_space *mapping = file->f_mapping; 1348c2ecf20Sopenharmony_ci struct inode *inode = mapping->host; 1358c2ecf20Sopenharmony_ci size_t count = iov_iter_count(iter); 1368c2ecf20Sopenharmony_ci ssize_t ret; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ret = blockdev_direct_IO(iocb, inode, iter, hfs_get_block); 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* 1418c2ecf20Sopenharmony_ci * In case of error extending write may have instantiated a few 1428c2ecf20Sopenharmony_ci * blocks outside i_size. Trim these off again. 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) { 1458c2ecf20Sopenharmony_ci loff_t isize = i_size_read(inode); 1468c2ecf20Sopenharmony_ci loff_t end = iocb->ki_pos + count; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci if (end > isize) 1498c2ecf20Sopenharmony_ci hfs_write_failed(mapping, end); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return ret; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int hfs_writepages(struct address_space *mapping, 1568c2ecf20Sopenharmony_ci struct writeback_control *wbc) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci return mpage_writepages(mapping, wbc, hfs_get_block); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ciconst struct address_space_operations hfs_btree_aops = { 1628c2ecf20Sopenharmony_ci .readpage = hfs_readpage, 1638c2ecf20Sopenharmony_ci .writepage = hfs_writepage, 1648c2ecf20Sopenharmony_ci .write_begin = hfs_write_begin, 1658c2ecf20Sopenharmony_ci .write_end = generic_write_end, 1668c2ecf20Sopenharmony_ci .bmap = hfs_bmap, 1678c2ecf20Sopenharmony_ci .releasepage = hfs_releasepage, 1688c2ecf20Sopenharmony_ci}; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ciconst struct address_space_operations hfs_aops = { 1718c2ecf20Sopenharmony_ci .readpage = hfs_readpage, 1728c2ecf20Sopenharmony_ci .writepage = hfs_writepage, 1738c2ecf20Sopenharmony_ci .write_begin = hfs_write_begin, 1748c2ecf20Sopenharmony_ci .write_end = generic_write_end, 1758c2ecf20Sopenharmony_ci .bmap = hfs_bmap, 1768c2ecf20Sopenharmony_ci .direct_IO = hfs_direct_IO, 1778c2ecf20Sopenharmony_ci .writepages = hfs_writepages, 1788c2ecf20Sopenharmony_ci}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci/* 1818c2ecf20Sopenharmony_ci * hfs_new_inode 1828c2ecf20Sopenharmony_ci */ 1838c2ecf20Sopenharmony_cistruct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t mode) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci struct super_block *sb = dir->i_sb; 1868c2ecf20Sopenharmony_ci struct inode *inode = new_inode(sb); 1878c2ecf20Sopenharmony_ci if (!inode) 1888c2ecf20Sopenharmony_ci return NULL; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci mutex_init(&HFS_I(inode)->extents_lock); 1918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); 1928c2ecf20Sopenharmony_ci spin_lock_init(&HFS_I(inode)->open_dir_lock); 1938c2ecf20Sopenharmony_ci hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name); 1948c2ecf20Sopenharmony_ci inode->i_ino = HFS_SB(sb)->next_id++; 1958c2ecf20Sopenharmony_ci inode->i_mode = mode; 1968c2ecf20Sopenharmony_ci inode->i_uid = current_fsuid(); 1978c2ecf20Sopenharmony_ci inode->i_gid = current_fsgid(); 1988c2ecf20Sopenharmony_ci set_nlink(inode, 1); 1998c2ecf20Sopenharmony_ci inode->i_mtime = inode->i_atime = inode->i_ctime = current_time(inode); 2008c2ecf20Sopenharmony_ci HFS_I(inode)->flags = 0; 2018c2ecf20Sopenharmony_ci HFS_I(inode)->rsrc_inode = NULL; 2028c2ecf20Sopenharmony_ci HFS_I(inode)->fs_blocks = 0; 2038c2ecf20Sopenharmony_ci if (S_ISDIR(mode)) { 2048c2ecf20Sopenharmony_ci inode->i_size = 2; 2058c2ecf20Sopenharmony_ci HFS_SB(sb)->folder_count++; 2068c2ecf20Sopenharmony_ci if (dir->i_ino == HFS_ROOT_CNID) 2078c2ecf20Sopenharmony_ci HFS_SB(sb)->root_dirs++; 2088c2ecf20Sopenharmony_ci inode->i_op = &hfs_dir_inode_operations; 2098c2ecf20Sopenharmony_ci inode->i_fop = &hfs_dir_operations; 2108c2ecf20Sopenharmony_ci inode->i_mode |= S_IRWXUGO; 2118c2ecf20Sopenharmony_ci inode->i_mode &= ~HFS_SB(inode->i_sb)->s_dir_umask; 2128c2ecf20Sopenharmony_ci } else if (S_ISREG(mode)) { 2138c2ecf20Sopenharmony_ci HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks; 2148c2ecf20Sopenharmony_ci HFS_SB(sb)->file_count++; 2158c2ecf20Sopenharmony_ci if (dir->i_ino == HFS_ROOT_CNID) 2168c2ecf20Sopenharmony_ci HFS_SB(sb)->root_files++; 2178c2ecf20Sopenharmony_ci inode->i_op = &hfs_file_inode_operations; 2188c2ecf20Sopenharmony_ci inode->i_fop = &hfs_file_operations; 2198c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &hfs_aops; 2208c2ecf20Sopenharmony_ci inode->i_mode |= S_IRUGO|S_IXUGO; 2218c2ecf20Sopenharmony_ci if (mode & S_IWUSR) 2228c2ecf20Sopenharmony_ci inode->i_mode |= S_IWUGO; 2238c2ecf20Sopenharmony_ci inode->i_mode &= ~HFS_SB(inode->i_sb)->s_file_umask; 2248c2ecf20Sopenharmony_ci HFS_I(inode)->phys_size = 0; 2258c2ecf20Sopenharmony_ci HFS_I(inode)->alloc_blocks = 0; 2268c2ecf20Sopenharmony_ci HFS_I(inode)->first_blocks = 0; 2278c2ecf20Sopenharmony_ci HFS_I(inode)->cached_start = 0; 2288c2ecf20Sopenharmony_ci HFS_I(inode)->cached_blocks = 0; 2298c2ecf20Sopenharmony_ci memset(HFS_I(inode)->first_extents, 0, sizeof(hfs_extent_rec)); 2308c2ecf20Sopenharmony_ci memset(HFS_I(inode)->cached_extents, 0, sizeof(hfs_extent_rec)); 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci insert_inode_hash(inode); 2338c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 2348c2ecf20Sopenharmony_ci set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags); 2358c2ecf20Sopenharmony_ci hfs_mark_mdb_dirty(sb); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return inode; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_civoid hfs_delete_inode(struct inode *inode) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci hfs_dbg(INODE, "delete_inode: %lu\n", inode->i_ino); 2458c2ecf20Sopenharmony_ci if (S_ISDIR(inode->i_mode)) { 2468c2ecf20Sopenharmony_ci HFS_SB(sb)->folder_count--; 2478c2ecf20Sopenharmony_ci if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID)) 2488c2ecf20Sopenharmony_ci HFS_SB(sb)->root_dirs--; 2498c2ecf20Sopenharmony_ci set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags); 2508c2ecf20Sopenharmony_ci hfs_mark_mdb_dirty(sb); 2518c2ecf20Sopenharmony_ci return; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci HFS_SB(sb)->file_count--; 2548c2ecf20Sopenharmony_ci if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID)) 2558c2ecf20Sopenharmony_ci HFS_SB(sb)->root_files--; 2568c2ecf20Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 2578c2ecf20Sopenharmony_ci if (!inode->i_nlink) { 2588c2ecf20Sopenharmony_ci inode->i_size = 0; 2598c2ecf20Sopenharmony_ci hfs_file_truncate(inode); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags); 2638c2ecf20Sopenharmony_ci hfs_mark_mdb_dirty(sb); 2648c2ecf20Sopenharmony_ci} 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_civoid hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext, 2678c2ecf20Sopenharmony_ci __be32 __log_size, __be32 phys_size, u32 clump_size) 2688c2ecf20Sopenharmony_ci{ 2698c2ecf20Sopenharmony_ci struct super_block *sb = inode->i_sb; 2708c2ecf20Sopenharmony_ci u32 log_size = be32_to_cpu(__log_size); 2718c2ecf20Sopenharmony_ci u16 count; 2728c2ecf20Sopenharmony_ci int i; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci memcpy(HFS_I(inode)->first_extents, ext, sizeof(hfs_extent_rec)); 2758c2ecf20Sopenharmony_ci for (count = 0, i = 0; i < 3; i++) 2768c2ecf20Sopenharmony_ci count += be16_to_cpu(ext[i].count); 2778c2ecf20Sopenharmony_ci HFS_I(inode)->first_blocks = count; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci inode->i_size = HFS_I(inode)->phys_size = log_size; 2808c2ecf20Sopenharmony_ci HFS_I(inode)->fs_blocks = (log_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits; 2818c2ecf20Sopenharmony_ci inode_set_bytes(inode, HFS_I(inode)->fs_blocks << sb->s_blocksize_bits); 2828c2ecf20Sopenharmony_ci HFS_I(inode)->alloc_blocks = be32_to_cpu(phys_size) / 2838c2ecf20Sopenharmony_ci HFS_SB(sb)->alloc_blksz; 2848c2ecf20Sopenharmony_ci HFS_I(inode)->clump_blocks = clump_size / HFS_SB(sb)->alloc_blksz; 2858c2ecf20Sopenharmony_ci if (!HFS_I(inode)->clump_blocks) 2868c2ecf20Sopenharmony_ci HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistruct hfs_iget_data { 2908c2ecf20Sopenharmony_ci struct hfs_cat_key *key; 2918c2ecf20Sopenharmony_ci hfs_cat_rec *rec; 2928c2ecf20Sopenharmony_ci}; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic int hfs_test_inode(struct inode *inode, void *data) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct hfs_iget_data *idata = data; 2978c2ecf20Sopenharmony_ci hfs_cat_rec *rec; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci rec = idata->rec; 3008c2ecf20Sopenharmony_ci switch (rec->type) { 3018c2ecf20Sopenharmony_ci case HFS_CDR_DIR: 3028c2ecf20Sopenharmony_ci return inode->i_ino == be32_to_cpu(rec->dir.DirID); 3038c2ecf20Sopenharmony_ci case HFS_CDR_FIL: 3048c2ecf20Sopenharmony_ci return inode->i_ino == be32_to_cpu(rec->file.FlNum); 3058c2ecf20Sopenharmony_ci default: 3068c2ecf20Sopenharmony_ci BUG(); 3078c2ecf20Sopenharmony_ci return 1; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci} 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci/* 3128c2ecf20Sopenharmony_ci * hfs_read_inode 3138c2ecf20Sopenharmony_ci */ 3148c2ecf20Sopenharmony_cistatic int hfs_read_inode(struct inode *inode, void *data) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci struct hfs_iget_data *idata = data; 3178c2ecf20Sopenharmony_ci struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); 3188c2ecf20Sopenharmony_ci hfs_cat_rec *rec; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci HFS_I(inode)->flags = 0; 3218c2ecf20Sopenharmony_ci HFS_I(inode)->rsrc_inode = NULL; 3228c2ecf20Sopenharmony_ci mutex_init(&HFS_I(inode)->extents_lock); 3238c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list); 3248c2ecf20Sopenharmony_ci spin_lock_init(&HFS_I(inode)->open_dir_lock); 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Initialize the inode */ 3278c2ecf20Sopenharmony_ci inode->i_uid = hsb->s_uid; 3288c2ecf20Sopenharmony_ci inode->i_gid = hsb->s_gid; 3298c2ecf20Sopenharmony_ci set_nlink(inode, 1); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (idata->key) 3328c2ecf20Sopenharmony_ci HFS_I(inode)->cat_key = *idata->key; 3338c2ecf20Sopenharmony_ci else 3348c2ecf20Sopenharmony_ci HFS_I(inode)->flags |= HFS_FLG_RSRC; 3358c2ecf20Sopenharmony_ci HFS_I(inode)->tz_secondswest = sys_tz.tz_minuteswest * 60; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci rec = idata->rec; 3388c2ecf20Sopenharmony_ci switch (rec->type) { 3398c2ecf20Sopenharmony_ci case HFS_CDR_FIL: 3408c2ecf20Sopenharmony_ci if (!HFS_IS_RSRC(inode)) { 3418c2ecf20Sopenharmony_ci hfs_inode_read_fork(inode, rec->file.ExtRec, rec->file.LgLen, 3428c2ecf20Sopenharmony_ci rec->file.PyLen, be16_to_cpu(rec->file.ClpSize)); 3438c2ecf20Sopenharmony_ci } else { 3448c2ecf20Sopenharmony_ci hfs_inode_read_fork(inode, rec->file.RExtRec, rec->file.RLgLen, 3458c2ecf20Sopenharmony_ci rec->file.RPyLen, be16_to_cpu(rec->file.ClpSize)); 3468c2ecf20Sopenharmony_ci } 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci inode->i_ino = be32_to_cpu(rec->file.FlNum); 3498c2ecf20Sopenharmony_ci inode->i_mode = S_IRUGO | S_IXUGO; 3508c2ecf20Sopenharmony_ci if (!(rec->file.Flags & HFS_FIL_LOCK)) 3518c2ecf20Sopenharmony_ci inode->i_mode |= S_IWUGO; 3528c2ecf20Sopenharmony_ci inode->i_mode &= ~hsb->s_file_umask; 3538c2ecf20Sopenharmony_ci inode->i_mode |= S_IFREG; 3548c2ecf20Sopenharmony_ci inode->i_ctime = inode->i_atime = inode->i_mtime = 3558c2ecf20Sopenharmony_ci hfs_m_to_utime(rec->file.MdDat); 3568c2ecf20Sopenharmony_ci inode->i_op = &hfs_file_inode_operations; 3578c2ecf20Sopenharmony_ci inode->i_fop = &hfs_file_operations; 3588c2ecf20Sopenharmony_ci inode->i_mapping->a_ops = &hfs_aops; 3598c2ecf20Sopenharmony_ci break; 3608c2ecf20Sopenharmony_ci case HFS_CDR_DIR: 3618c2ecf20Sopenharmony_ci inode->i_ino = be32_to_cpu(rec->dir.DirID); 3628c2ecf20Sopenharmony_ci inode->i_size = be16_to_cpu(rec->dir.Val) + 2; 3638c2ecf20Sopenharmony_ci HFS_I(inode)->fs_blocks = 0; 3648c2ecf20Sopenharmony_ci inode->i_mode = S_IFDIR | (S_IRWXUGO & ~hsb->s_dir_umask); 3658c2ecf20Sopenharmony_ci inode->i_ctime = inode->i_atime = inode->i_mtime = 3668c2ecf20Sopenharmony_ci hfs_m_to_utime(rec->dir.MdDat); 3678c2ecf20Sopenharmony_ci inode->i_op = &hfs_dir_inode_operations; 3688c2ecf20Sopenharmony_ci inode->i_fop = &hfs_dir_operations; 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci default: 3718c2ecf20Sopenharmony_ci make_bad_inode(inode); 3728c2ecf20Sopenharmony_ci } 3738c2ecf20Sopenharmony_ci return 0; 3748c2ecf20Sopenharmony_ci} 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci/* 3778c2ecf20Sopenharmony_ci * __hfs_iget() 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * Given the MDB for a HFS filesystem, a 'key' and an 'entry' in 3808c2ecf20Sopenharmony_ci * the catalog B-tree and the 'type' of the desired file return the 3818c2ecf20Sopenharmony_ci * inode for that file/directory or NULL. Note that 'type' indicates 3828c2ecf20Sopenharmony_ci * whether we want the actual file or directory, or the corresponding 3838c2ecf20Sopenharmony_ci * metadata (AppleDouble header file or CAP metadata file). 3848c2ecf20Sopenharmony_ci */ 3858c2ecf20Sopenharmony_cistruct inode *hfs_iget(struct super_block *sb, struct hfs_cat_key *key, hfs_cat_rec *rec) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct hfs_iget_data data = { key, rec }; 3888c2ecf20Sopenharmony_ci struct inode *inode; 3898c2ecf20Sopenharmony_ci u32 cnid; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci switch (rec->type) { 3928c2ecf20Sopenharmony_ci case HFS_CDR_DIR: 3938c2ecf20Sopenharmony_ci cnid = be32_to_cpu(rec->dir.DirID); 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci case HFS_CDR_FIL: 3968c2ecf20Sopenharmony_ci cnid = be32_to_cpu(rec->file.FlNum); 3978c2ecf20Sopenharmony_ci break; 3988c2ecf20Sopenharmony_ci default: 3998c2ecf20Sopenharmony_ci return NULL; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci inode = iget5_locked(sb, cnid, hfs_test_inode, hfs_read_inode, &data); 4028c2ecf20Sopenharmony_ci if (inode && (inode->i_state & I_NEW)) 4038c2ecf20Sopenharmony_ci unlock_new_inode(inode); 4048c2ecf20Sopenharmony_ci return inode; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_civoid hfs_inode_write_fork(struct inode *inode, struct hfs_extent *ext, 4088c2ecf20Sopenharmony_ci __be32 *log_size, __be32 *phys_size) 4098c2ecf20Sopenharmony_ci{ 4108c2ecf20Sopenharmony_ci memcpy(ext, HFS_I(inode)->first_extents, sizeof(hfs_extent_rec)); 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci if (log_size) 4138c2ecf20Sopenharmony_ci *log_size = cpu_to_be32(inode->i_size); 4148c2ecf20Sopenharmony_ci if (phys_size) 4158c2ecf20Sopenharmony_ci *phys_size = cpu_to_be32(HFS_I(inode)->alloc_blocks * 4168c2ecf20Sopenharmony_ci HFS_SB(inode->i_sb)->alloc_blksz); 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ciint hfs_write_inode(struct inode *inode, struct writeback_control *wbc) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct inode *main_inode = inode; 4228c2ecf20Sopenharmony_ci struct hfs_find_data fd; 4238c2ecf20Sopenharmony_ci hfs_cat_rec rec; 4248c2ecf20Sopenharmony_ci int res; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci hfs_dbg(INODE, "hfs_write_inode: %lu\n", inode->i_ino); 4278c2ecf20Sopenharmony_ci res = hfs_ext_write_extent(inode); 4288c2ecf20Sopenharmony_ci if (res) 4298c2ecf20Sopenharmony_ci return res; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (inode->i_ino < HFS_FIRSTUSER_CNID) { 4328c2ecf20Sopenharmony_ci switch (inode->i_ino) { 4338c2ecf20Sopenharmony_ci case HFS_ROOT_CNID: 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci case HFS_EXT_CNID: 4368c2ecf20Sopenharmony_ci hfs_btree_write(HFS_SB(inode->i_sb)->ext_tree); 4378c2ecf20Sopenharmony_ci return 0; 4388c2ecf20Sopenharmony_ci case HFS_CAT_CNID: 4398c2ecf20Sopenharmony_ci hfs_btree_write(HFS_SB(inode->i_sb)->cat_tree); 4408c2ecf20Sopenharmony_ci return 0; 4418c2ecf20Sopenharmony_ci default: 4428c2ecf20Sopenharmony_ci BUG(); 4438c2ecf20Sopenharmony_ci return -EIO; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci if (HFS_IS_RSRC(inode)) 4488c2ecf20Sopenharmony_ci main_inode = HFS_I(inode)->rsrc_inode; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci if (!main_inode->i_nlink) 4518c2ecf20Sopenharmony_ci return 0; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (hfs_find_init(HFS_SB(main_inode->i_sb)->cat_tree, &fd)) 4548c2ecf20Sopenharmony_ci /* panic? */ 4558c2ecf20Sopenharmony_ci return -EIO; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci res = -EIO; 4588c2ecf20Sopenharmony_ci if (HFS_I(main_inode)->cat_key.CName.len > HFS_NAMELEN) 4598c2ecf20Sopenharmony_ci goto out; 4608c2ecf20Sopenharmony_ci fd.search_key->cat = HFS_I(main_inode)->cat_key; 4618c2ecf20Sopenharmony_ci if (hfs_brec_find(&fd)) 4628c2ecf20Sopenharmony_ci goto out; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (S_ISDIR(main_inode->i_mode)) { 4658c2ecf20Sopenharmony_ci if (fd.entrylength < sizeof(struct hfs_cat_dir)) 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, 4688c2ecf20Sopenharmony_ci sizeof(struct hfs_cat_dir)); 4698c2ecf20Sopenharmony_ci if (rec.type != HFS_CDR_DIR || 4708c2ecf20Sopenharmony_ci be32_to_cpu(rec.dir.DirID) != inode->i_ino) { 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci rec.dir.MdDat = hfs_u_to_mtime(inode->i_mtime); 4748c2ecf20Sopenharmony_ci rec.dir.Val = cpu_to_be16(inode->i_size - 2); 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, 4778c2ecf20Sopenharmony_ci sizeof(struct hfs_cat_dir)); 4788c2ecf20Sopenharmony_ci } else if (HFS_IS_RSRC(inode)) { 4798c2ecf20Sopenharmony_ci if (fd.entrylength < sizeof(struct hfs_cat_file)) 4808c2ecf20Sopenharmony_ci goto out; 4818c2ecf20Sopenharmony_ci hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, 4828c2ecf20Sopenharmony_ci sizeof(struct hfs_cat_file)); 4838c2ecf20Sopenharmony_ci hfs_inode_write_fork(inode, rec.file.RExtRec, 4848c2ecf20Sopenharmony_ci &rec.file.RLgLen, &rec.file.RPyLen); 4858c2ecf20Sopenharmony_ci hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, 4868c2ecf20Sopenharmony_ci sizeof(struct hfs_cat_file)); 4878c2ecf20Sopenharmony_ci } else { 4888c2ecf20Sopenharmony_ci if (fd.entrylength < sizeof(struct hfs_cat_file)) 4898c2ecf20Sopenharmony_ci goto out; 4908c2ecf20Sopenharmony_ci hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, 4918c2ecf20Sopenharmony_ci sizeof(struct hfs_cat_file)); 4928c2ecf20Sopenharmony_ci if (rec.type != HFS_CDR_FIL || 4938c2ecf20Sopenharmony_ci be32_to_cpu(rec.file.FlNum) != inode->i_ino) { 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci if (inode->i_mode & S_IWUSR) 4978c2ecf20Sopenharmony_ci rec.file.Flags &= ~HFS_FIL_LOCK; 4988c2ecf20Sopenharmony_ci else 4998c2ecf20Sopenharmony_ci rec.file.Flags |= HFS_FIL_LOCK; 5008c2ecf20Sopenharmony_ci hfs_inode_write_fork(inode, rec.file.ExtRec, &rec.file.LgLen, &rec.file.PyLen); 5018c2ecf20Sopenharmony_ci rec.file.MdDat = hfs_u_to_mtime(inode->i_mtime); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, 5048c2ecf20Sopenharmony_ci sizeof(struct hfs_cat_file)); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci res = 0; 5078c2ecf20Sopenharmony_ciout: 5088c2ecf20Sopenharmony_ci hfs_find_exit(&fd); 5098c2ecf20Sopenharmony_ci return res; 5108c2ecf20Sopenharmony_ci} 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry, 5138c2ecf20Sopenharmony_ci unsigned int flags) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct inode *inode = NULL; 5168c2ecf20Sopenharmony_ci hfs_cat_rec rec; 5178c2ecf20Sopenharmony_ci struct hfs_find_data fd; 5188c2ecf20Sopenharmony_ci int res; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (HFS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc")) 5218c2ecf20Sopenharmony_ci goto out; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci inode = HFS_I(dir)->rsrc_inode; 5248c2ecf20Sopenharmony_ci if (inode) 5258c2ecf20Sopenharmony_ci goto out; 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci inode = new_inode(dir->i_sb); 5288c2ecf20Sopenharmony_ci if (!inode) 5298c2ecf20Sopenharmony_ci return ERR_PTR(-ENOMEM); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci res = hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); 5328c2ecf20Sopenharmony_ci if (res) { 5338c2ecf20Sopenharmony_ci iput(inode); 5348c2ecf20Sopenharmony_ci return ERR_PTR(res); 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci fd.search_key->cat = HFS_I(dir)->cat_key; 5378c2ecf20Sopenharmony_ci res = hfs_brec_read(&fd, &rec, sizeof(rec)); 5388c2ecf20Sopenharmony_ci if (!res) { 5398c2ecf20Sopenharmony_ci struct hfs_iget_data idata = { NULL, &rec }; 5408c2ecf20Sopenharmony_ci hfs_read_inode(inode, &idata); 5418c2ecf20Sopenharmony_ci } 5428c2ecf20Sopenharmony_ci hfs_find_exit(&fd); 5438c2ecf20Sopenharmony_ci if (res) { 5448c2ecf20Sopenharmony_ci iput(inode); 5458c2ecf20Sopenharmony_ci return ERR_PTR(res); 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci HFS_I(inode)->rsrc_inode = dir; 5488c2ecf20Sopenharmony_ci HFS_I(dir)->rsrc_inode = inode; 5498c2ecf20Sopenharmony_ci igrab(dir); 5508c2ecf20Sopenharmony_ci inode_fake_hash(inode); 5518c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 5528c2ecf20Sopenharmony_ci dont_mount(dentry); 5538c2ecf20Sopenharmony_ciout: 5548c2ecf20Sopenharmony_ci return d_splice_alias(inode, dentry); 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_civoid hfs_evict_inode(struct inode *inode) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci truncate_inode_pages_final(&inode->i_data); 5608c2ecf20Sopenharmony_ci clear_inode(inode); 5618c2ecf20Sopenharmony_ci if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) { 5628c2ecf20Sopenharmony_ci HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL; 5638c2ecf20Sopenharmony_ci iput(HFS_I(inode)->rsrc_inode); 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci} 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_cistatic int hfs_file_open(struct inode *inode, struct file *file) 5688c2ecf20Sopenharmony_ci{ 5698c2ecf20Sopenharmony_ci if (HFS_IS_RSRC(inode)) 5708c2ecf20Sopenharmony_ci inode = HFS_I(inode)->rsrc_inode; 5718c2ecf20Sopenharmony_ci atomic_inc(&HFS_I(inode)->opencnt); 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic int hfs_file_release(struct inode *inode, struct file *file) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci //struct super_block *sb = inode->i_sb; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci if (HFS_IS_RSRC(inode)) 5808c2ecf20Sopenharmony_ci inode = HFS_I(inode)->rsrc_inode; 5818c2ecf20Sopenharmony_ci if (atomic_dec_and_test(&HFS_I(inode)->opencnt)) { 5828c2ecf20Sopenharmony_ci inode_lock(inode); 5838c2ecf20Sopenharmony_ci hfs_file_truncate(inode); 5848c2ecf20Sopenharmony_ci //if (inode->i_flags & S_DEAD) { 5858c2ecf20Sopenharmony_ci // hfs_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL); 5868c2ecf20Sopenharmony_ci // hfs_delete_inode(inode); 5878c2ecf20Sopenharmony_ci //} 5888c2ecf20Sopenharmony_ci inode_unlock(inode); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci} 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci/* 5948c2ecf20Sopenharmony_ci * hfs_notify_change() 5958c2ecf20Sopenharmony_ci * 5968c2ecf20Sopenharmony_ci * Based very closely on fs/msdos/inode.c by Werner Almesberger 5978c2ecf20Sopenharmony_ci * 5988c2ecf20Sopenharmony_ci * This is the notify_change() field in the super_operations structure 5998c2ecf20Sopenharmony_ci * for HFS file systems. The purpose is to take that changes made to 6008c2ecf20Sopenharmony_ci * an inode and apply then in a filesystem-dependent manner. In this 6018c2ecf20Sopenharmony_ci * case the process has a few of tasks to do: 6028c2ecf20Sopenharmony_ci * 1) prevent changes to the i_uid and i_gid fields. 6038c2ecf20Sopenharmony_ci * 2) map file permissions to the closest allowable permissions 6048c2ecf20Sopenharmony_ci * 3) Since multiple Linux files can share the same on-disk inode under 6058c2ecf20Sopenharmony_ci * HFS (for instance the data and resource forks of a file) a change 6068c2ecf20Sopenharmony_ci * to permissions must be applied to all other in-core inodes which 6078c2ecf20Sopenharmony_ci * correspond to the same HFS file. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ciint hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci struct inode *inode = d_inode(dentry); 6138c2ecf20Sopenharmony_ci struct hfs_sb_info *hsb = HFS_SB(inode->i_sb); 6148c2ecf20Sopenharmony_ci int error; 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci error = setattr_prepare(dentry, attr); /* basic permission checks */ 6178c2ecf20Sopenharmony_ci if (error) 6188c2ecf20Sopenharmony_ci return error; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* no uig/gid changes and limit which mode bits can be set */ 6218c2ecf20Sopenharmony_ci if (((attr->ia_valid & ATTR_UID) && 6228c2ecf20Sopenharmony_ci (!uid_eq(attr->ia_uid, hsb->s_uid))) || 6238c2ecf20Sopenharmony_ci ((attr->ia_valid & ATTR_GID) && 6248c2ecf20Sopenharmony_ci (!gid_eq(attr->ia_gid, hsb->s_gid))) || 6258c2ecf20Sopenharmony_ci ((attr->ia_valid & ATTR_MODE) && 6268c2ecf20Sopenharmony_ci ((S_ISDIR(inode->i_mode) && 6278c2ecf20Sopenharmony_ci (attr->ia_mode != inode->i_mode)) || 6288c2ecf20Sopenharmony_ci (attr->ia_mode & ~HFS_VALID_MODE_BITS)))) { 6298c2ecf20Sopenharmony_ci return hsb->s_quiet ? 0 : error; 6308c2ecf20Sopenharmony_ci } 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci if (attr->ia_valid & ATTR_MODE) { 6338c2ecf20Sopenharmony_ci /* Only the 'w' bits can ever change and only all together. */ 6348c2ecf20Sopenharmony_ci if (attr->ia_mode & S_IWUSR) 6358c2ecf20Sopenharmony_ci attr->ia_mode = inode->i_mode | S_IWUGO; 6368c2ecf20Sopenharmony_ci else 6378c2ecf20Sopenharmony_ci attr->ia_mode = inode->i_mode & ~S_IWUGO; 6388c2ecf20Sopenharmony_ci attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if ((attr->ia_valid & ATTR_SIZE) && 6428c2ecf20Sopenharmony_ci attr->ia_size != i_size_read(inode)) { 6438c2ecf20Sopenharmony_ci inode_dio_wait(inode); 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci error = inode_newsize_ok(inode, attr->ia_size); 6468c2ecf20Sopenharmony_ci if (error) 6478c2ecf20Sopenharmony_ci return error; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci truncate_setsize(inode, attr->ia_size); 6508c2ecf20Sopenharmony_ci hfs_file_truncate(inode); 6518c2ecf20Sopenharmony_ci inode->i_atime = inode->i_mtime = inode->i_ctime = 6528c2ecf20Sopenharmony_ci current_time(inode); 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci setattr_copy(inode, attr); 6568c2ecf20Sopenharmony_ci mark_inode_dirty(inode); 6578c2ecf20Sopenharmony_ci return 0; 6588c2ecf20Sopenharmony_ci} 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cistatic int hfs_file_fsync(struct file *filp, loff_t start, loff_t end, 6618c2ecf20Sopenharmony_ci int datasync) 6628c2ecf20Sopenharmony_ci{ 6638c2ecf20Sopenharmony_ci struct inode *inode = filp->f_mapping->host; 6648c2ecf20Sopenharmony_ci struct super_block * sb; 6658c2ecf20Sopenharmony_ci int ret, err; 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ci ret = file_write_and_wait_range(filp, start, end); 6688c2ecf20Sopenharmony_ci if (ret) 6698c2ecf20Sopenharmony_ci return ret; 6708c2ecf20Sopenharmony_ci inode_lock(inode); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* sync the inode to buffers */ 6738c2ecf20Sopenharmony_ci ret = write_inode_now(inode, 0); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci /* sync the superblock to buffers */ 6768c2ecf20Sopenharmony_ci sb = inode->i_sb; 6778c2ecf20Sopenharmony_ci flush_delayed_work(&HFS_SB(sb)->mdb_work); 6788c2ecf20Sopenharmony_ci /* .. finally sync the buffers to disk */ 6798c2ecf20Sopenharmony_ci err = sync_blockdev(sb->s_bdev); 6808c2ecf20Sopenharmony_ci if (!ret) 6818c2ecf20Sopenharmony_ci ret = err; 6828c2ecf20Sopenharmony_ci inode_unlock(inode); 6838c2ecf20Sopenharmony_ci return ret; 6848c2ecf20Sopenharmony_ci} 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cistatic const struct file_operations hfs_file_operations = { 6878c2ecf20Sopenharmony_ci .llseek = generic_file_llseek, 6888c2ecf20Sopenharmony_ci .read_iter = generic_file_read_iter, 6898c2ecf20Sopenharmony_ci .write_iter = generic_file_write_iter, 6908c2ecf20Sopenharmony_ci .mmap = generic_file_mmap, 6918c2ecf20Sopenharmony_ci .splice_read = generic_file_splice_read, 6928c2ecf20Sopenharmony_ci .fsync = hfs_file_fsync, 6938c2ecf20Sopenharmony_ci .open = hfs_file_open, 6948c2ecf20Sopenharmony_ci .release = hfs_file_release, 6958c2ecf20Sopenharmony_ci}; 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_cistatic const struct inode_operations hfs_file_inode_operations = { 6988c2ecf20Sopenharmony_ci .lookup = hfs_file_lookup, 6998c2ecf20Sopenharmony_ci .setattr = hfs_inode_setattr, 7008c2ecf20Sopenharmony_ci .listxattr = generic_listxattr, 7018c2ecf20Sopenharmony_ci}; 702