162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * inode.c - NTFS kernel inode handling. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2001-2014 Anton Altaparmakov and Tuxera Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/buffer_head.h> 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/mm.h> 1162306a36Sopenharmony_ci#include <linux/mount.h> 1262306a36Sopenharmony_ci#include <linux/mutex.h> 1362306a36Sopenharmony_ci#include <linux/pagemap.h> 1462306a36Sopenharmony_ci#include <linux/quotaops.h> 1562306a36Sopenharmony_ci#include <linux/slab.h> 1662306a36Sopenharmony_ci#include <linux/log2.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "aops.h" 1962306a36Sopenharmony_ci#include "attrib.h" 2062306a36Sopenharmony_ci#include "bitmap.h" 2162306a36Sopenharmony_ci#include "dir.h" 2262306a36Sopenharmony_ci#include "debug.h" 2362306a36Sopenharmony_ci#include "inode.h" 2462306a36Sopenharmony_ci#include "lcnalloc.h" 2562306a36Sopenharmony_ci#include "malloc.h" 2662306a36Sopenharmony_ci#include "mft.h" 2762306a36Sopenharmony_ci#include "time.h" 2862306a36Sopenharmony_ci#include "ntfs.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/** 3162306a36Sopenharmony_ci * ntfs_test_inode - compare two (possibly fake) inodes for equality 3262306a36Sopenharmony_ci * @vi: vfs inode which to test 3362306a36Sopenharmony_ci * @data: data which is being tested with 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Compare the ntfs attribute embedded in the ntfs specific part of the vfs 3662306a36Sopenharmony_ci * inode @vi for equality with the ntfs attribute @data. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * If searching for the normal file/directory inode, set @na->type to AT_UNUSED. 3962306a36Sopenharmony_ci * @na->name and @na->name_len are then ignored. 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * Return 1 if the attributes match and 0 if not. 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * NOTE: This function runs with the inode_hash_lock spin lock held so it is not 4462306a36Sopenharmony_ci * allowed to sleep. 4562306a36Sopenharmony_ci */ 4662306a36Sopenharmony_ciint ntfs_test_inode(struct inode *vi, void *data) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci ntfs_attr *na = (ntfs_attr *)data; 4962306a36Sopenharmony_ci ntfs_inode *ni; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci if (vi->i_ino != na->mft_no) 5262306a36Sopenharmony_ci return 0; 5362306a36Sopenharmony_ci ni = NTFS_I(vi); 5462306a36Sopenharmony_ci /* If !NInoAttr(ni), @vi is a normal file or directory inode. */ 5562306a36Sopenharmony_ci if (likely(!NInoAttr(ni))) { 5662306a36Sopenharmony_ci /* If not looking for a normal inode this is a mismatch. */ 5762306a36Sopenharmony_ci if (unlikely(na->type != AT_UNUSED)) 5862306a36Sopenharmony_ci return 0; 5962306a36Sopenharmony_ci } else { 6062306a36Sopenharmony_ci /* A fake inode describing an attribute. */ 6162306a36Sopenharmony_ci if (ni->type != na->type) 6262306a36Sopenharmony_ci return 0; 6362306a36Sopenharmony_ci if (ni->name_len != na->name_len) 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci if (na->name_len && memcmp(ni->name, na->name, 6662306a36Sopenharmony_ci na->name_len * sizeof(ntfschar))) 6762306a36Sopenharmony_ci return 0; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci /* Match! */ 7062306a36Sopenharmony_ci return 1; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci/** 7462306a36Sopenharmony_ci * ntfs_init_locked_inode - initialize an inode 7562306a36Sopenharmony_ci * @vi: vfs inode to initialize 7662306a36Sopenharmony_ci * @data: data which to initialize @vi to 7762306a36Sopenharmony_ci * 7862306a36Sopenharmony_ci * Initialize the vfs inode @vi with the values from the ntfs attribute @data in 7962306a36Sopenharmony_ci * order to enable ntfs_test_inode() to do its work. 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * If initializing the normal file/directory inode, set @na->type to AT_UNUSED. 8262306a36Sopenharmony_ci * In that case, @na->name and @na->name_len should be set to NULL and 0, 8362306a36Sopenharmony_ci * respectively. Although that is not strictly necessary as 8462306a36Sopenharmony_ci * ntfs_read_locked_inode() will fill them in later. 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Return 0 on success and -errno on error. 8762306a36Sopenharmony_ci * 8862306a36Sopenharmony_ci * NOTE: This function runs with the inode->i_lock spin lock held so it is not 8962306a36Sopenharmony_ci * allowed to sleep. (Hence the GFP_ATOMIC allocation.) 9062306a36Sopenharmony_ci */ 9162306a36Sopenharmony_cistatic int ntfs_init_locked_inode(struct inode *vi, void *data) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci ntfs_attr *na = (ntfs_attr *)data; 9462306a36Sopenharmony_ci ntfs_inode *ni = NTFS_I(vi); 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci vi->i_ino = na->mft_no; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci ni->type = na->type; 9962306a36Sopenharmony_ci if (na->type == AT_INDEX_ALLOCATION) 10062306a36Sopenharmony_ci NInoSetMstProtected(ni); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci ni->name = na->name; 10362306a36Sopenharmony_ci ni->name_len = na->name_len; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* If initializing a normal inode, we are done. */ 10662306a36Sopenharmony_ci if (likely(na->type == AT_UNUSED)) { 10762306a36Sopenharmony_ci BUG_ON(na->name); 10862306a36Sopenharmony_ci BUG_ON(na->name_len); 10962306a36Sopenharmony_ci return 0; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* It is a fake inode. */ 11362306a36Sopenharmony_ci NInoSetAttr(ni); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * We have I30 global constant as an optimization as it is the name 11762306a36Sopenharmony_ci * in >99.9% of named attributes! The other <0.1% incur a GFP_ATOMIC 11862306a36Sopenharmony_ci * allocation but that is ok. And most attributes are unnamed anyway, 11962306a36Sopenharmony_ci * thus the fraction of named attributes with name != I30 is actually 12062306a36Sopenharmony_ci * absolutely tiny. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_ci if (na->name_len && na->name != I30) { 12362306a36Sopenharmony_ci unsigned int i; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci BUG_ON(!na->name); 12662306a36Sopenharmony_ci i = na->name_len * sizeof(ntfschar); 12762306a36Sopenharmony_ci ni->name = kmalloc(i + sizeof(ntfschar), GFP_ATOMIC); 12862306a36Sopenharmony_ci if (!ni->name) 12962306a36Sopenharmony_ci return -ENOMEM; 13062306a36Sopenharmony_ci memcpy(ni->name, na->name, i); 13162306a36Sopenharmony_ci ni->name[na->name_len] = 0; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_cistatic int ntfs_read_locked_inode(struct inode *vi); 13762306a36Sopenharmony_cistatic int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi); 13862306a36Sopenharmony_cistatic int ntfs_read_locked_index_inode(struct inode *base_vi, 13962306a36Sopenharmony_ci struct inode *vi); 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci/** 14262306a36Sopenharmony_ci * ntfs_iget - obtain a struct inode corresponding to a specific normal inode 14362306a36Sopenharmony_ci * @sb: super block of mounted volume 14462306a36Sopenharmony_ci * @mft_no: mft record number / inode number to obtain 14562306a36Sopenharmony_ci * 14662306a36Sopenharmony_ci * Obtain the struct inode corresponding to a specific normal inode (i.e. a 14762306a36Sopenharmony_ci * file or directory). 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * If the inode is in the cache, it is just returned with an increased 15062306a36Sopenharmony_ci * reference count. Otherwise, a new struct inode is allocated and initialized, 15162306a36Sopenharmony_ci * and finally ntfs_read_locked_inode() is called to read in the inode and 15262306a36Sopenharmony_ci * fill in the remainder of the inode structure. 15362306a36Sopenharmony_ci * 15462306a36Sopenharmony_ci * Return the struct inode on success. Check the return value with IS_ERR() and 15562306a36Sopenharmony_ci * if true, the function failed and the error code is obtained from PTR_ERR(). 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_cistruct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no) 15862306a36Sopenharmony_ci{ 15962306a36Sopenharmony_ci struct inode *vi; 16062306a36Sopenharmony_ci int err; 16162306a36Sopenharmony_ci ntfs_attr na; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci na.mft_no = mft_no; 16462306a36Sopenharmony_ci na.type = AT_UNUSED; 16562306a36Sopenharmony_ci na.name = NULL; 16662306a36Sopenharmony_ci na.name_len = 0; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci vi = iget5_locked(sb, mft_no, ntfs_test_inode, 16962306a36Sopenharmony_ci ntfs_init_locked_inode, &na); 17062306a36Sopenharmony_ci if (unlikely(!vi)) 17162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci err = 0; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci /* If this is a freshly allocated inode, need to read it now. */ 17662306a36Sopenharmony_ci if (vi->i_state & I_NEW) { 17762306a36Sopenharmony_ci err = ntfs_read_locked_inode(vi); 17862306a36Sopenharmony_ci unlock_new_inode(vi); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci /* 18162306a36Sopenharmony_ci * There is no point in keeping bad inodes around if the failure was 18262306a36Sopenharmony_ci * due to ENOMEM. We want to be able to retry again later. 18362306a36Sopenharmony_ci */ 18462306a36Sopenharmony_ci if (unlikely(err == -ENOMEM)) { 18562306a36Sopenharmony_ci iput(vi); 18662306a36Sopenharmony_ci vi = ERR_PTR(err); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci return vi; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci/** 19262306a36Sopenharmony_ci * ntfs_attr_iget - obtain a struct inode corresponding to an attribute 19362306a36Sopenharmony_ci * @base_vi: vfs base inode containing the attribute 19462306a36Sopenharmony_ci * @type: attribute type 19562306a36Sopenharmony_ci * @name: Unicode name of the attribute (NULL if unnamed) 19662306a36Sopenharmony_ci * @name_len: length of @name in Unicode characters (0 if unnamed) 19762306a36Sopenharmony_ci * 19862306a36Sopenharmony_ci * Obtain the (fake) struct inode corresponding to the attribute specified by 19962306a36Sopenharmony_ci * @type, @name, and @name_len, which is present in the base mft record 20062306a36Sopenharmony_ci * specified by the vfs inode @base_vi. 20162306a36Sopenharmony_ci * 20262306a36Sopenharmony_ci * If the attribute inode is in the cache, it is just returned with an 20362306a36Sopenharmony_ci * increased reference count. Otherwise, a new struct inode is allocated and 20462306a36Sopenharmony_ci * initialized, and finally ntfs_read_locked_attr_inode() is called to read the 20562306a36Sopenharmony_ci * attribute and fill in the inode structure. 20662306a36Sopenharmony_ci * 20762306a36Sopenharmony_ci * Note, for index allocation attributes, you need to use ntfs_index_iget() 20862306a36Sopenharmony_ci * instead of ntfs_attr_iget() as working with indices is a lot more complex. 20962306a36Sopenharmony_ci * 21062306a36Sopenharmony_ci * Return the struct inode of the attribute inode on success. Check the return 21162306a36Sopenharmony_ci * value with IS_ERR() and if true, the function failed and the error code is 21262306a36Sopenharmony_ci * obtained from PTR_ERR(). 21362306a36Sopenharmony_ci */ 21462306a36Sopenharmony_cistruct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPE type, 21562306a36Sopenharmony_ci ntfschar *name, u32 name_len) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci struct inode *vi; 21862306a36Sopenharmony_ci int err; 21962306a36Sopenharmony_ci ntfs_attr na; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* Make sure no one calls ntfs_attr_iget() for indices. */ 22262306a36Sopenharmony_ci BUG_ON(type == AT_INDEX_ALLOCATION); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci na.mft_no = base_vi->i_ino; 22562306a36Sopenharmony_ci na.type = type; 22662306a36Sopenharmony_ci na.name = name; 22762306a36Sopenharmony_ci na.name_len = name_len; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci vi = iget5_locked(base_vi->i_sb, na.mft_no, ntfs_test_inode, 23062306a36Sopenharmony_ci ntfs_init_locked_inode, &na); 23162306a36Sopenharmony_ci if (unlikely(!vi)) 23262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci err = 0; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* If this is a freshly allocated inode, need to read it now. */ 23762306a36Sopenharmony_ci if (vi->i_state & I_NEW) { 23862306a36Sopenharmony_ci err = ntfs_read_locked_attr_inode(base_vi, vi); 23962306a36Sopenharmony_ci unlock_new_inode(vi); 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * There is no point in keeping bad attribute inodes around. This also 24362306a36Sopenharmony_ci * simplifies things in that we never need to check for bad attribute 24462306a36Sopenharmony_ci * inodes elsewhere. 24562306a36Sopenharmony_ci */ 24662306a36Sopenharmony_ci if (unlikely(err)) { 24762306a36Sopenharmony_ci iput(vi); 24862306a36Sopenharmony_ci vi = ERR_PTR(err); 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci return vi; 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci/** 25462306a36Sopenharmony_ci * ntfs_index_iget - obtain a struct inode corresponding to an index 25562306a36Sopenharmony_ci * @base_vi: vfs base inode containing the index related attributes 25662306a36Sopenharmony_ci * @name: Unicode name of the index 25762306a36Sopenharmony_ci * @name_len: length of @name in Unicode characters 25862306a36Sopenharmony_ci * 25962306a36Sopenharmony_ci * Obtain the (fake) struct inode corresponding to the index specified by @name 26062306a36Sopenharmony_ci * and @name_len, which is present in the base mft record specified by the vfs 26162306a36Sopenharmony_ci * inode @base_vi. 26262306a36Sopenharmony_ci * 26362306a36Sopenharmony_ci * If the index inode is in the cache, it is just returned with an increased 26462306a36Sopenharmony_ci * reference count. Otherwise, a new struct inode is allocated and 26562306a36Sopenharmony_ci * initialized, and finally ntfs_read_locked_index_inode() is called to read 26662306a36Sopenharmony_ci * the index related attributes and fill in the inode structure. 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * Return the struct inode of the index inode on success. Check the return 26962306a36Sopenharmony_ci * value with IS_ERR() and if true, the function failed and the error code is 27062306a36Sopenharmony_ci * obtained from PTR_ERR(). 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_cistruct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name, 27362306a36Sopenharmony_ci u32 name_len) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci struct inode *vi; 27662306a36Sopenharmony_ci int err; 27762306a36Sopenharmony_ci ntfs_attr na; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci na.mft_no = base_vi->i_ino; 28062306a36Sopenharmony_ci na.type = AT_INDEX_ALLOCATION; 28162306a36Sopenharmony_ci na.name = name; 28262306a36Sopenharmony_ci na.name_len = name_len; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci vi = iget5_locked(base_vi->i_sb, na.mft_no, ntfs_test_inode, 28562306a36Sopenharmony_ci ntfs_init_locked_inode, &na); 28662306a36Sopenharmony_ci if (unlikely(!vi)) 28762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci err = 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* If this is a freshly allocated inode, need to read it now. */ 29262306a36Sopenharmony_ci if (vi->i_state & I_NEW) { 29362306a36Sopenharmony_ci err = ntfs_read_locked_index_inode(base_vi, vi); 29462306a36Sopenharmony_ci unlock_new_inode(vi); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci /* 29762306a36Sopenharmony_ci * There is no point in keeping bad index inodes around. This also 29862306a36Sopenharmony_ci * simplifies things in that we never need to check for bad index 29962306a36Sopenharmony_ci * inodes elsewhere. 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci if (unlikely(err)) { 30262306a36Sopenharmony_ci iput(vi); 30362306a36Sopenharmony_ci vi = ERR_PTR(err); 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci return vi; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistruct inode *ntfs_alloc_big_inode(struct super_block *sb) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci ntfs_inode *ni; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci ntfs_debug("Entering."); 31362306a36Sopenharmony_ci ni = alloc_inode_sb(sb, ntfs_big_inode_cache, GFP_NOFS); 31462306a36Sopenharmony_ci if (likely(ni != NULL)) { 31562306a36Sopenharmony_ci ni->state = 0; 31662306a36Sopenharmony_ci return VFS_I(ni); 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci ntfs_error(sb, "Allocation of NTFS big inode structure failed."); 31962306a36Sopenharmony_ci return NULL; 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_civoid ntfs_free_big_inode(struct inode *inode) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci kmem_cache_free(ntfs_big_inode_cache, NTFS_I(inode)); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic inline ntfs_inode *ntfs_alloc_extent_inode(void) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci ntfs_inode *ni; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci ntfs_debug("Entering."); 33262306a36Sopenharmony_ci ni = kmem_cache_alloc(ntfs_inode_cache, GFP_NOFS); 33362306a36Sopenharmony_ci if (likely(ni != NULL)) { 33462306a36Sopenharmony_ci ni->state = 0; 33562306a36Sopenharmony_ci return ni; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci ntfs_error(NULL, "Allocation of NTFS inode structure failed."); 33862306a36Sopenharmony_ci return NULL; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_cistatic void ntfs_destroy_extent_inode(ntfs_inode *ni) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci ntfs_debug("Entering."); 34462306a36Sopenharmony_ci BUG_ON(ni->page); 34562306a36Sopenharmony_ci if (!atomic_dec_and_test(&ni->count)) 34662306a36Sopenharmony_ci BUG(); 34762306a36Sopenharmony_ci kmem_cache_free(ntfs_inode_cache, ni); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/* 35162306a36Sopenharmony_ci * The attribute runlist lock has separate locking rules from the 35262306a36Sopenharmony_ci * normal runlist lock, so split the two lock-classes: 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_cistatic struct lock_class_key attr_list_rl_lock_class; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/** 35762306a36Sopenharmony_ci * __ntfs_init_inode - initialize ntfs specific part of an inode 35862306a36Sopenharmony_ci * @sb: super block of mounted volume 35962306a36Sopenharmony_ci * @ni: freshly allocated ntfs inode which to initialize 36062306a36Sopenharmony_ci * 36162306a36Sopenharmony_ci * Initialize an ntfs inode to defaults. 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * NOTE: ni->mft_no, ni->state, ni->type, ni->name, and ni->name_len are left 36462306a36Sopenharmony_ci * untouched. Make sure to initialize them elsewhere. 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * Return zero on success and -ENOMEM on error. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_civoid __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci ntfs_debug("Entering."); 37162306a36Sopenharmony_ci rwlock_init(&ni->size_lock); 37262306a36Sopenharmony_ci ni->initialized_size = ni->allocated_size = 0; 37362306a36Sopenharmony_ci ni->seq_no = 0; 37462306a36Sopenharmony_ci atomic_set(&ni->count, 1); 37562306a36Sopenharmony_ci ni->vol = NTFS_SB(sb); 37662306a36Sopenharmony_ci ntfs_init_runlist(&ni->runlist); 37762306a36Sopenharmony_ci mutex_init(&ni->mrec_lock); 37862306a36Sopenharmony_ci ni->page = NULL; 37962306a36Sopenharmony_ci ni->page_ofs = 0; 38062306a36Sopenharmony_ci ni->attr_list_size = 0; 38162306a36Sopenharmony_ci ni->attr_list = NULL; 38262306a36Sopenharmony_ci ntfs_init_runlist(&ni->attr_list_rl); 38362306a36Sopenharmony_ci lockdep_set_class(&ni->attr_list_rl.lock, 38462306a36Sopenharmony_ci &attr_list_rl_lock_class); 38562306a36Sopenharmony_ci ni->itype.index.block_size = 0; 38662306a36Sopenharmony_ci ni->itype.index.vcn_size = 0; 38762306a36Sopenharmony_ci ni->itype.index.collation_rule = 0; 38862306a36Sopenharmony_ci ni->itype.index.block_size_bits = 0; 38962306a36Sopenharmony_ci ni->itype.index.vcn_size_bits = 0; 39062306a36Sopenharmony_ci mutex_init(&ni->extent_lock); 39162306a36Sopenharmony_ci ni->nr_extents = 0; 39262306a36Sopenharmony_ci ni->ext.base_ntfs_ino = NULL; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/* 39662306a36Sopenharmony_ci * Extent inodes get MFT-mapped in a nested way, while the base inode 39762306a36Sopenharmony_ci * is still mapped. Teach this nesting to the lock validator by creating 39862306a36Sopenharmony_ci * a separate class for nested inode's mrec_lock's: 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_cistatic struct lock_class_key extent_inode_mrec_lock_key; 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ciinline ntfs_inode *ntfs_new_extent_inode(struct super_block *sb, 40362306a36Sopenharmony_ci unsigned long mft_no) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci ntfs_inode *ni = ntfs_alloc_extent_inode(); 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_ci ntfs_debug("Entering."); 40862306a36Sopenharmony_ci if (likely(ni != NULL)) { 40962306a36Sopenharmony_ci __ntfs_init_inode(sb, ni); 41062306a36Sopenharmony_ci lockdep_set_class(&ni->mrec_lock, &extent_inode_mrec_lock_key); 41162306a36Sopenharmony_ci ni->mft_no = mft_no; 41262306a36Sopenharmony_ci ni->type = AT_UNUSED; 41362306a36Sopenharmony_ci ni->name = NULL; 41462306a36Sopenharmony_ci ni->name_len = 0; 41562306a36Sopenharmony_ci } 41662306a36Sopenharmony_ci return ni; 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci/** 42062306a36Sopenharmony_ci * ntfs_is_extended_system_file - check if a file is in the $Extend directory 42162306a36Sopenharmony_ci * @ctx: initialized attribute search context 42262306a36Sopenharmony_ci * 42362306a36Sopenharmony_ci * Search all file name attributes in the inode described by the attribute 42462306a36Sopenharmony_ci * search context @ctx and check if any of the names are in the $Extend system 42562306a36Sopenharmony_ci * directory. 42662306a36Sopenharmony_ci * 42762306a36Sopenharmony_ci * Return values: 42862306a36Sopenharmony_ci * 1: file is in $Extend directory 42962306a36Sopenharmony_ci * 0: file is not in $Extend directory 43062306a36Sopenharmony_ci * -errno: failed to determine if the file is in the $Extend directory 43162306a36Sopenharmony_ci */ 43262306a36Sopenharmony_cistatic int ntfs_is_extended_system_file(ntfs_attr_search_ctx *ctx) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci int nr_links, err; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci /* Restart search. */ 43762306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci /* Get number of hard links. */ 44062306a36Sopenharmony_ci nr_links = le16_to_cpu(ctx->mrec->link_count); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* Loop through all hard links. */ 44362306a36Sopenharmony_ci while (!(err = ntfs_attr_lookup(AT_FILE_NAME, NULL, 0, 0, 0, NULL, 0, 44462306a36Sopenharmony_ci ctx))) { 44562306a36Sopenharmony_ci FILE_NAME_ATTR *file_name_attr; 44662306a36Sopenharmony_ci ATTR_RECORD *attr = ctx->attr; 44762306a36Sopenharmony_ci u8 *p, *p2; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci nr_links--; 45062306a36Sopenharmony_ci /* 45162306a36Sopenharmony_ci * Maximum sanity checking as we are called on an inode that 45262306a36Sopenharmony_ci * we suspect might be corrupt. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci p = (u8*)attr + le32_to_cpu(attr->length); 45562306a36Sopenharmony_ci if (p < (u8*)ctx->mrec || (u8*)p > (u8*)ctx->mrec + 45662306a36Sopenharmony_ci le32_to_cpu(ctx->mrec->bytes_in_use)) { 45762306a36Sopenharmony_cierr_corrupt_attr: 45862306a36Sopenharmony_ci ntfs_error(ctx->ntfs_ino->vol->sb, "Corrupt file name " 45962306a36Sopenharmony_ci "attribute. You should run chkdsk."); 46062306a36Sopenharmony_ci return -EIO; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci if (attr->non_resident) { 46362306a36Sopenharmony_ci ntfs_error(ctx->ntfs_ino->vol->sb, "Non-resident file " 46462306a36Sopenharmony_ci "name. You should run chkdsk."); 46562306a36Sopenharmony_ci return -EIO; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci if (attr->flags) { 46862306a36Sopenharmony_ci ntfs_error(ctx->ntfs_ino->vol->sb, "File name with " 46962306a36Sopenharmony_ci "invalid flags. You should run " 47062306a36Sopenharmony_ci "chkdsk."); 47162306a36Sopenharmony_ci return -EIO; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci if (!(attr->data.resident.flags & RESIDENT_ATTR_IS_INDEXED)) { 47462306a36Sopenharmony_ci ntfs_error(ctx->ntfs_ino->vol->sb, "Unindexed file " 47562306a36Sopenharmony_ci "name. You should run chkdsk."); 47662306a36Sopenharmony_ci return -EIO; 47762306a36Sopenharmony_ci } 47862306a36Sopenharmony_ci file_name_attr = (FILE_NAME_ATTR*)((u8*)attr + 47962306a36Sopenharmony_ci le16_to_cpu(attr->data.resident.value_offset)); 48062306a36Sopenharmony_ci p2 = (u8 *)file_name_attr + le32_to_cpu(attr->data.resident.value_length); 48162306a36Sopenharmony_ci if (p2 < (u8*)attr || p2 > p) 48262306a36Sopenharmony_ci goto err_corrupt_attr; 48362306a36Sopenharmony_ci /* This attribute is ok, but is it in the $Extend directory? */ 48462306a36Sopenharmony_ci if (MREF_LE(file_name_attr->parent_directory) == FILE_Extend) 48562306a36Sopenharmony_ci return 1; /* YES, it's an extended system file. */ 48662306a36Sopenharmony_ci } 48762306a36Sopenharmony_ci if (unlikely(err != -ENOENT)) 48862306a36Sopenharmony_ci return err; 48962306a36Sopenharmony_ci if (unlikely(nr_links)) { 49062306a36Sopenharmony_ci ntfs_error(ctx->ntfs_ino->vol->sb, "Inode hard link count " 49162306a36Sopenharmony_ci "doesn't match number of name attributes. You " 49262306a36Sopenharmony_ci "should run chkdsk."); 49362306a36Sopenharmony_ci return -EIO; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci return 0; /* NO, it is not an extended system file. */ 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/** 49962306a36Sopenharmony_ci * ntfs_read_locked_inode - read an inode from its device 50062306a36Sopenharmony_ci * @vi: inode to read 50162306a36Sopenharmony_ci * 50262306a36Sopenharmony_ci * ntfs_read_locked_inode() is called from ntfs_iget() to read the inode 50362306a36Sopenharmony_ci * described by @vi into memory from the device. 50462306a36Sopenharmony_ci * 50562306a36Sopenharmony_ci * The only fields in @vi that we need to/can look at when the function is 50662306a36Sopenharmony_ci * called are i_sb, pointing to the mounted device's super block, and i_ino, 50762306a36Sopenharmony_ci * the number of the inode to load. 50862306a36Sopenharmony_ci * 50962306a36Sopenharmony_ci * ntfs_read_locked_inode() maps, pins and locks the mft record number i_ino 51062306a36Sopenharmony_ci * for reading and sets up the necessary @vi fields as well as initializing 51162306a36Sopenharmony_ci * the ntfs inode. 51262306a36Sopenharmony_ci * 51362306a36Sopenharmony_ci * Q: What locks are held when the function is called? 51462306a36Sopenharmony_ci * A: i_state has I_NEW set, hence the inode is locked, also 51562306a36Sopenharmony_ci * i_count is set to 1, so it is not going to go away 51662306a36Sopenharmony_ci * i_flags is set to 0 and we have no business touching it. Only an ioctl() 51762306a36Sopenharmony_ci * is allowed to write to them. We should of course be honouring them but 51862306a36Sopenharmony_ci * we need to do that using the IS_* macros defined in include/linux/fs.h. 51962306a36Sopenharmony_ci * In any case ntfs_read_locked_inode() has nothing to do with i_flags. 52062306a36Sopenharmony_ci * 52162306a36Sopenharmony_ci * Return 0 on success and -errno on error. In the error case, the inode will 52262306a36Sopenharmony_ci * have had make_bad_inode() executed on it. 52362306a36Sopenharmony_ci */ 52462306a36Sopenharmony_cistatic int ntfs_read_locked_inode(struct inode *vi) 52562306a36Sopenharmony_ci{ 52662306a36Sopenharmony_ci ntfs_volume *vol = NTFS_SB(vi->i_sb); 52762306a36Sopenharmony_ci ntfs_inode *ni; 52862306a36Sopenharmony_ci struct inode *bvi; 52962306a36Sopenharmony_ci MFT_RECORD *m; 53062306a36Sopenharmony_ci ATTR_RECORD *a; 53162306a36Sopenharmony_ci STANDARD_INFORMATION *si; 53262306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 53362306a36Sopenharmony_ci int err = 0; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* Setup the generic vfs inode parts now. */ 53862306a36Sopenharmony_ci vi->i_uid = vol->uid; 53962306a36Sopenharmony_ci vi->i_gid = vol->gid; 54062306a36Sopenharmony_ci vi->i_mode = 0; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* 54362306a36Sopenharmony_ci * Initialize the ntfs specific part of @vi special casing 54462306a36Sopenharmony_ci * FILE_MFT which we need to do at mount time. 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_ci if (vi->i_ino != FILE_MFT) 54762306a36Sopenharmony_ci ntfs_init_big_inode(vi); 54862306a36Sopenharmony_ci ni = NTFS_I(vi); 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci m = map_mft_record(ni); 55162306a36Sopenharmony_ci if (IS_ERR(m)) { 55262306a36Sopenharmony_ci err = PTR_ERR(m); 55362306a36Sopenharmony_ci goto err_out; 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(ni, m); 55662306a36Sopenharmony_ci if (!ctx) { 55762306a36Sopenharmony_ci err = -ENOMEM; 55862306a36Sopenharmony_ci goto unm_err_out; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (!(m->flags & MFT_RECORD_IN_USE)) { 56262306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Inode is not in use!"); 56362306a36Sopenharmony_ci goto unm_err_out; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci if (m->base_mft_record) { 56662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Inode is an extent inode!"); 56762306a36Sopenharmony_ci goto unm_err_out; 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci /* Transfer information from mft record into vfs and ntfs inodes. */ 57162306a36Sopenharmony_ci vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* 57462306a36Sopenharmony_ci * FIXME: Keep in mind that link_count is two for files which have both 57562306a36Sopenharmony_ci * a long file name and a short file name as separate entries, so if 57662306a36Sopenharmony_ci * we are hiding short file names this will be too high. Either we need 57762306a36Sopenharmony_ci * to account for the short file names by subtracting them or we need 57862306a36Sopenharmony_ci * to make sure we delete files even though i_nlink is not zero which 57962306a36Sopenharmony_ci * might be tricky due to vfs interactions. Need to think about this 58062306a36Sopenharmony_ci * some more when implementing the unlink command. 58162306a36Sopenharmony_ci */ 58262306a36Sopenharmony_ci set_nlink(vi, le16_to_cpu(m->link_count)); 58362306a36Sopenharmony_ci /* 58462306a36Sopenharmony_ci * FIXME: Reparse points can have the directory bit set even though 58562306a36Sopenharmony_ci * they would be S_IFLNK. Need to deal with this further below when we 58662306a36Sopenharmony_ci * implement reparse points / symbolic links but it will do for now. 58762306a36Sopenharmony_ci * Also if not a directory, it could be something else, rather than 58862306a36Sopenharmony_ci * a regular file. But again, will do for now. 58962306a36Sopenharmony_ci */ 59062306a36Sopenharmony_ci /* Everyone gets all permissions. */ 59162306a36Sopenharmony_ci vi->i_mode |= S_IRWXUGO; 59262306a36Sopenharmony_ci /* If read-only, no one gets write permissions. */ 59362306a36Sopenharmony_ci if (IS_RDONLY(vi)) 59462306a36Sopenharmony_ci vi->i_mode &= ~S_IWUGO; 59562306a36Sopenharmony_ci if (m->flags & MFT_RECORD_IS_DIRECTORY) { 59662306a36Sopenharmony_ci vi->i_mode |= S_IFDIR; 59762306a36Sopenharmony_ci /* 59862306a36Sopenharmony_ci * Apply the directory permissions mask set in the mount 59962306a36Sopenharmony_ci * options. 60062306a36Sopenharmony_ci */ 60162306a36Sopenharmony_ci vi->i_mode &= ~vol->dmask; 60262306a36Sopenharmony_ci /* Things break without this kludge! */ 60362306a36Sopenharmony_ci if (vi->i_nlink > 1) 60462306a36Sopenharmony_ci set_nlink(vi, 1); 60562306a36Sopenharmony_ci } else { 60662306a36Sopenharmony_ci vi->i_mode |= S_IFREG; 60762306a36Sopenharmony_ci /* Apply the file permissions mask set in the mount options. */ 60862306a36Sopenharmony_ci vi->i_mode &= ~vol->fmask; 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci /* 61162306a36Sopenharmony_ci * Find the standard information attribute in the mft record. At this 61262306a36Sopenharmony_ci * stage we haven't setup the attribute list stuff yet, so this could 61362306a36Sopenharmony_ci * in fact fail if the standard information is in an extent record, but 61462306a36Sopenharmony_ci * I don't think this actually ever happens. 61562306a36Sopenharmony_ci */ 61662306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 0, 0, NULL, 0, 61762306a36Sopenharmony_ci ctx); 61862306a36Sopenharmony_ci if (unlikely(err)) { 61962306a36Sopenharmony_ci if (err == -ENOENT) { 62062306a36Sopenharmony_ci /* 62162306a36Sopenharmony_ci * TODO: We should be performing a hot fix here (if the 62262306a36Sopenharmony_ci * recover mount option is set) by creating a new 62362306a36Sopenharmony_ci * attribute. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$STANDARD_INFORMATION attribute " 62662306a36Sopenharmony_ci "is missing."); 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci goto unm_err_out; 62962306a36Sopenharmony_ci } 63062306a36Sopenharmony_ci a = ctx->attr; 63162306a36Sopenharmony_ci /* Get the standard information attribute value. */ 63262306a36Sopenharmony_ci if ((u8 *)a + le16_to_cpu(a->data.resident.value_offset) 63362306a36Sopenharmony_ci + le32_to_cpu(a->data.resident.value_length) > 63462306a36Sopenharmony_ci (u8 *)ctx->mrec + vol->mft_record_size) { 63562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Corrupt standard information attribute in inode."); 63662306a36Sopenharmony_ci goto unm_err_out; 63762306a36Sopenharmony_ci } 63862306a36Sopenharmony_ci si = (STANDARD_INFORMATION*)((u8*)a + 63962306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset)); 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci /* Transfer information from the standard information into vi. */ 64262306a36Sopenharmony_ci /* 64362306a36Sopenharmony_ci * Note: The i_?times do not quite map perfectly onto the NTFS times, 64462306a36Sopenharmony_ci * but they are close enough, and in the end it doesn't really matter 64562306a36Sopenharmony_ci * that much... 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * mtime is the last change of the data within the file. Not changed 64962306a36Sopenharmony_ci * when only metadata is changed, e.g. a rename doesn't affect mtime. 65062306a36Sopenharmony_ci */ 65162306a36Sopenharmony_ci vi->i_mtime = ntfs2utc(si->last_data_change_time); 65262306a36Sopenharmony_ci /* 65362306a36Sopenharmony_ci * ctime is the last change of the metadata of the file. This obviously 65462306a36Sopenharmony_ci * always changes, when mtime is changed. ctime can be changed on its 65562306a36Sopenharmony_ci * own, mtime is then not changed, e.g. when a file is renamed. 65662306a36Sopenharmony_ci */ 65762306a36Sopenharmony_ci inode_set_ctime_to_ts(vi, ntfs2utc(si->last_mft_change_time)); 65862306a36Sopenharmony_ci /* 65962306a36Sopenharmony_ci * Last access to the data within the file. Not changed during a rename 66062306a36Sopenharmony_ci * for example but changed whenever the file is written to. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_ci vi->i_atime = ntfs2utc(si->last_access_time); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci /* Find the attribute list attribute if present. */ 66562306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 66662306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx); 66762306a36Sopenharmony_ci if (err) { 66862306a36Sopenharmony_ci if (unlikely(err != -ENOENT)) { 66962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to lookup attribute list " 67062306a36Sopenharmony_ci "attribute."); 67162306a36Sopenharmony_ci goto unm_err_out; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci } else /* if (!err) */ { 67462306a36Sopenharmony_ci if (vi->i_ino == FILE_MFT) 67562306a36Sopenharmony_ci goto skip_attr_list_load; 67662306a36Sopenharmony_ci ntfs_debug("Attribute list found in inode 0x%lx.", vi->i_ino); 67762306a36Sopenharmony_ci NInoSetAttrList(ni); 67862306a36Sopenharmony_ci a = ctx->attr; 67962306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) { 68062306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Attribute list attribute is " 68162306a36Sopenharmony_ci "compressed."); 68262306a36Sopenharmony_ci goto unm_err_out; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci if (a->flags & ATTR_IS_ENCRYPTED || 68562306a36Sopenharmony_ci a->flags & ATTR_IS_SPARSE) { 68662306a36Sopenharmony_ci if (a->non_resident) { 68762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Non-resident attribute " 68862306a36Sopenharmony_ci "list attribute is encrypted/" 68962306a36Sopenharmony_ci "sparse."); 69062306a36Sopenharmony_ci goto unm_err_out; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci ntfs_warning(vi->i_sb, "Resident attribute list " 69362306a36Sopenharmony_ci "attribute in inode 0x%lx is marked " 69462306a36Sopenharmony_ci "encrypted/sparse which is not true. " 69562306a36Sopenharmony_ci "However, Windows allows this and " 69662306a36Sopenharmony_ci "chkdsk does not detect or correct it " 69762306a36Sopenharmony_ci "so we will just ignore the invalid " 69862306a36Sopenharmony_ci "flags and pretend they are not set.", 69962306a36Sopenharmony_ci vi->i_ino); 70062306a36Sopenharmony_ci } 70162306a36Sopenharmony_ci /* Now allocate memory for the attribute list. */ 70262306a36Sopenharmony_ci ni->attr_list_size = (u32)ntfs_attr_size(a); 70362306a36Sopenharmony_ci ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); 70462306a36Sopenharmony_ci if (!ni->attr_list) { 70562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Not enough memory to allocate " 70662306a36Sopenharmony_ci "buffer for attribute list."); 70762306a36Sopenharmony_ci err = -ENOMEM; 70862306a36Sopenharmony_ci goto unm_err_out; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci if (a->non_resident) { 71162306a36Sopenharmony_ci NInoSetAttrListNonResident(ni); 71262306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 71362306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Attribute list has non " 71462306a36Sopenharmony_ci "zero lowest_vcn."); 71562306a36Sopenharmony_ci goto unm_err_out; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci /* 71862306a36Sopenharmony_ci * Setup the runlist. No need for locking as we have 71962306a36Sopenharmony_ci * exclusive access to the inode at this time. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol, 72262306a36Sopenharmony_ci a, NULL); 72362306a36Sopenharmony_ci if (IS_ERR(ni->attr_list_rl.rl)) { 72462306a36Sopenharmony_ci err = PTR_ERR(ni->attr_list_rl.rl); 72562306a36Sopenharmony_ci ni->attr_list_rl.rl = NULL; 72662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Mapping pairs " 72762306a36Sopenharmony_ci "decompression failed."); 72862306a36Sopenharmony_ci goto unm_err_out; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci /* Now load the attribute list. */ 73162306a36Sopenharmony_ci if ((err = load_attribute_list(vol, &ni->attr_list_rl, 73262306a36Sopenharmony_ci ni->attr_list, ni->attr_list_size, 73362306a36Sopenharmony_ci sle64_to_cpu(a->data.non_resident. 73462306a36Sopenharmony_ci initialized_size)))) { 73562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to load " 73662306a36Sopenharmony_ci "attribute list attribute."); 73762306a36Sopenharmony_ci goto unm_err_out; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci } else /* if (!a->non_resident) */ { 74062306a36Sopenharmony_ci if ((u8*)a + le16_to_cpu(a->data.resident.value_offset) 74162306a36Sopenharmony_ci + le32_to_cpu( 74262306a36Sopenharmony_ci a->data.resident.value_length) > 74362306a36Sopenharmony_ci (u8*)ctx->mrec + vol->mft_record_size) { 74462306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Corrupt attribute list " 74562306a36Sopenharmony_ci "in inode."); 74662306a36Sopenharmony_ci goto unm_err_out; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci /* Now copy the attribute list. */ 74962306a36Sopenharmony_ci memcpy(ni->attr_list, (u8*)a + le16_to_cpu( 75062306a36Sopenharmony_ci a->data.resident.value_offset), 75162306a36Sopenharmony_ci le32_to_cpu( 75262306a36Sopenharmony_ci a->data.resident.value_length)); 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ciskip_attr_list_load: 75662306a36Sopenharmony_ci /* 75762306a36Sopenharmony_ci * If an attribute list is present we now have the attribute list value 75862306a36Sopenharmony_ci * in ntfs_ino->attr_list and it is ntfs_ino->attr_list_size bytes. 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci if (S_ISDIR(vi->i_mode)) { 76162306a36Sopenharmony_ci loff_t bvi_size; 76262306a36Sopenharmony_ci ntfs_inode *bni; 76362306a36Sopenharmony_ci INDEX_ROOT *ir; 76462306a36Sopenharmony_ci u8 *ir_end, *index_end; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci /* It is a directory, find index root attribute. */ 76762306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 76862306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_INDEX_ROOT, I30, 4, CASE_SENSITIVE, 76962306a36Sopenharmony_ci 0, NULL, 0, ctx); 77062306a36Sopenharmony_ci if (unlikely(err)) { 77162306a36Sopenharmony_ci if (err == -ENOENT) { 77262306a36Sopenharmony_ci // FIXME: File is corrupt! Hot-fix with empty 77362306a36Sopenharmony_ci // index root attribute if recovery option is 77462306a36Sopenharmony_ci // set. 77562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ROOT attribute " 77662306a36Sopenharmony_ci "is missing."); 77762306a36Sopenharmony_ci } 77862306a36Sopenharmony_ci goto unm_err_out; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci a = ctx->attr; 78162306a36Sopenharmony_ci /* Set up the state. */ 78262306a36Sopenharmony_ci if (unlikely(a->non_resident)) { 78362306a36Sopenharmony_ci ntfs_error(vol->sb, "$INDEX_ROOT attribute is not " 78462306a36Sopenharmony_ci "resident."); 78562306a36Sopenharmony_ci goto unm_err_out; 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci /* Ensure the attribute name is placed before the value. */ 78862306a36Sopenharmony_ci if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= 78962306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset)))) { 79062306a36Sopenharmony_ci ntfs_error(vol->sb, "$INDEX_ROOT attribute name is " 79162306a36Sopenharmony_ci "placed after the attribute value."); 79262306a36Sopenharmony_ci goto unm_err_out; 79362306a36Sopenharmony_ci } 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * Compressed/encrypted index root just means that the newly 79662306a36Sopenharmony_ci * created files in that directory should be created compressed/ 79762306a36Sopenharmony_ci * encrypted. However index root cannot be both compressed and 79862306a36Sopenharmony_ci * encrypted. 79962306a36Sopenharmony_ci */ 80062306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) 80162306a36Sopenharmony_ci NInoSetCompressed(ni); 80262306a36Sopenharmony_ci if (a->flags & ATTR_IS_ENCRYPTED) { 80362306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) { 80462306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found encrypted and " 80562306a36Sopenharmony_ci "compressed attribute."); 80662306a36Sopenharmony_ci goto unm_err_out; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci NInoSetEncrypted(ni); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci if (a->flags & ATTR_IS_SPARSE) 81162306a36Sopenharmony_ci NInoSetSparse(ni); 81262306a36Sopenharmony_ci ir = (INDEX_ROOT*)((u8*)a + 81362306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset)); 81462306a36Sopenharmony_ci ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length); 81562306a36Sopenharmony_ci if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) { 81662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is " 81762306a36Sopenharmony_ci "corrupt."); 81862306a36Sopenharmony_ci goto unm_err_out; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci index_end = (u8*)&ir->index + 82162306a36Sopenharmony_ci le32_to_cpu(ir->index.index_length); 82262306a36Sopenharmony_ci if (index_end > ir_end) { 82362306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Directory index is corrupt."); 82462306a36Sopenharmony_ci goto unm_err_out; 82562306a36Sopenharmony_ci } 82662306a36Sopenharmony_ci if (ir->type != AT_FILE_NAME) { 82762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Indexed attribute is not " 82862306a36Sopenharmony_ci "$FILE_NAME."); 82962306a36Sopenharmony_ci goto unm_err_out; 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci if (ir->collation_rule != COLLATION_FILE_NAME) { 83262306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index collation rule is not " 83362306a36Sopenharmony_ci "COLLATION_FILE_NAME."); 83462306a36Sopenharmony_ci goto unm_err_out; 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci ni->itype.index.collation_rule = ir->collation_rule; 83762306a36Sopenharmony_ci ni->itype.index.block_size = le32_to_cpu(ir->index_block_size); 83862306a36Sopenharmony_ci if (ni->itype.index.block_size & 83962306a36Sopenharmony_ci (ni->itype.index.block_size - 1)) { 84062306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index block size (%u) is not a " 84162306a36Sopenharmony_ci "power of two.", 84262306a36Sopenharmony_ci ni->itype.index.block_size); 84362306a36Sopenharmony_ci goto unm_err_out; 84462306a36Sopenharmony_ci } 84562306a36Sopenharmony_ci if (ni->itype.index.block_size > PAGE_SIZE) { 84662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index block size (%u) > " 84762306a36Sopenharmony_ci "PAGE_SIZE (%ld) is not " 84862306a36Sopenharmony_ci "supported. Sorry.", 84962306a36Sopenharmony_ci ni->itype.index.block_size, 85062306a36Sopenharmony_ci PAGE_SIZE); 85162306a36Sopenharmony_ci err = -EOPNOTSUPP; 85262306a36Sopenharmony_ci goto unm_err_out; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) { 85562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index block size (%u) < " 85662306a36Sopenharmony_ci "NTFS_BLOCK_SIZE (%i) is not " 85762306a36Sopenharmony_ci "supported. Sorry.", 85862306a36Sopenharmony_ci ni->itype.index.block_size, 85962306a36Sopenharmony_ci NTFS_BLOCK_SIZE); 86062306a36Sopenharmony_ci err = -EOPNOTSUPP; 86162306a36Sopenharmony_ci goto unm_err_out; 86262306a36Sopenharmony_ci } 86362306a36Sopenharmony_ci ni->itype.index.block_size_bits = 86462306a36Sopenharmony_ci ffs(ni->itype.index.block_size) - 1; 86562306a36Sopenharmony_ci /* Determine the size of a vcn in the directory index. */ 86662306a36Sopenharmony_ci if (vol->cluster_size <= ni->itype.index.block_size) { 86762306a36Sopenharmony_ci ni->itype.index.vcn_size = vol->cluster_size; 86862306a36Sopenharmony_ci ni->itype.index.vcn_size_bits = vol->cluster_size_bits; 86962306a36Sopenharmony_ci } else { 87062306a36Sopenharmony_ci ni->itype.index.vcn_size = vol->sector_size; 87162306a36Sopenharmony_ci ni->itype.index.vcn_size_bits = vol->sector_size_bits; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci /* Setup the index allocation attribute, even if not present. */ 87562306a36Sopenharmony_ci NInoSetMstProtected(ni); 87662306a36Sopenharmony_ci ni->type = AT_INDEX_ALLOCATION; 87762306a36Sopenharmony_ci ni->name = I30; 87862306a36Sopenharmony_ci ni->name_len = 4; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci if (!(ir->index.flags & LARGE_INDEX)) { 88162306a36Sopenharmony_ci /* No index allocation. */ 88262306a36Sopenharmony_ci vi->i_size = ni->initialized_size = 88362306a36Sopenharmony_ci ni->allocated_size = 0; 88462306a36Sopenharmony_ci /* We are done with the mft record, so we release it. */ 88562306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 88662306a36Sopenharmony_ci unmap_mft_record(ni); 88762306a36Sopenharmony_ci m = NULL; 88862306a36Sopenharmony_ci ctx = NULL; 88962306a36Sopenharmony_ci goto skip_large_dir_stuff; 89062306a36Sopenharmony_ci } /* LARGE_INDEX: Index allocation present. Setup state. */ 89162306a36Sopenharmony_ci NInoSetIndexAllocPresent(ni); 89262306a36Sopenharmony_ci /* Find index allocation attribute. */ 89362306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 89462306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, I30, 4, 89562306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 89662306a36Sopenharmony_ci if (unlikely(err)) { 89762306a36Sopenharmony_ci if (err == -ENOENT) 89862306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION " 89962306a36Sopenharmony_ci "attribute is not present but " 90062306a36Sopenharmony_ci "$INDEX_ROOT indicated it is."); 90162306a36Sopenharmony_ci else 90262306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to lookup " 90362306a36Sopenharmony_ci "$INDEX_ALLOCATION " 90462306a36Sopenharmony_ci "attribute."); 90562306a36Sopenharmony_ci goto unm_err_out; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci a = ctx->attr; 90862306a36Sopenharmony_ci if (!a->non_resident) { 90962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " 91062306a36Sopenharmony_ci "is resident."); 91162306a36Sopenharmony_ci goto unm_err_out; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci /* 91462306a36Sopenharmony_ci * Ensure the attribute name is placed before the mapping pairs 91562306a36Sopenharmony_ci * array. 91662306a36Sopenharmony_ci */ 91762306a36Sopenharmony_ci if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= 91862306a36Sopenharmony_ci le16_to_cpu( 91962306a36Sopenharmony_ci a->data.non_resident.mapping_pairs_offset)))) { 92062306a36Sopenharmony_ci ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name " 92162306a36Sopenharmony_ci "is placed after the mapping pairs " 92262306a36Sopenharmony_ci "array."); 92362306a36Sopenharmony_ci goto unm_err_out; 92462306a36Sopenharmony_ci } 92562306a36Sopenharmony_ci if (a->flags & ATTR_IS_ENCRYPTED) { 92662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " 92762306a36Sopenharmony_ci "is encrypted."); 92862306a36Sopenharmony_ci goto unm_err_out; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci if (a->flags & ATTR_IS_SPARSE) { 93162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " 93262306a36Sopenharmony_ci "is sparse."); 93362306a36Sopenharmony_ci goto unm_err_out; 93462306a36Sopenharmony_ci } 93562306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) { 93662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute " 93762306a36Sopenharmony_ci "is compressed."); 93862306a36Sopenharmony_ci goto unm_err_out; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 94162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "First extent of " 94262306a36Sopenharmony_ci "$INDEX_ALLOCATION attribute has non " 94362306a36Sopenharmony_ci "zero lowest_vcn."); 94462306a36Sopenharmony_ci goto unm_err_out; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci vi->i_size = sle64_to_cpu(a->data.non_resident.data_size); 94762306a36Sopenharmony_ci ni->initialized_size = sle64_to_cpu( 94862306a36Sopenharmony_ci a->data.non_resident.initialized_size); 94962306a36Sopenharmony_ci ni->allocated_size = sle64_to_cpu( 95062306a36Sopenharmony_ci a->data.non_resident.allocated_size); 95162306a36Sopenharmony_ci /* 95262306a36Sopenharmony_ci * We are done with the mft record, so we release it. Otherwise 95362306a36Sopenharmony_ci * we would deadlock in ntfs_attr_iget(). 95462306a36Sopenharmony_ci */ 95562306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 95662306a36Sopenharmony_ci unmap_mft_record(ni); 95762306a36Sopenharmony_ci m = NULL; 95862306a36Sopenharmony_ci ctx = NULL; 95962306a36Sopenharmony_ci /* Get the index bitmap attribute inode. */ 96062306a36Sopenharmony_ci bvi = ntfs_attr_iget(vi, AT_BITMAP, I30, 4); 96162306a36Sopenharmony_ci if (IS_ERR(bvi)) { 96262306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to get bitmap attribute."); 96362306a36Sopenharmony_ci err = PTR_ERR(bvi); 96462306a36Sopenharmony_ci goto unm_err_out; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci bni = NTFS_I(bvi); 96762306a36Sopenharmony_ci if (NInoCompressed(bni) || NInoEncrypted(bni) || 96862306a36Sopenharmony_ci NInoSparse(bni)) { 96962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$BITMAP attribute is compressed " 97062306a36Sopenharmony_ci "and/or encrypted and/or sparse."); 97162306a36Sopenharmony_ci goto iput_unm_err_out; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci /* Consistency check bitmap size vs. index allocation size. */ 97462306a36Sopenharmony_ci bvi_size = i_size_read(bvi); 97562306a36Sopenharmony_ci if ((bvi_size << 3) < (vi->i_size >> 97662306a36Sopenharmony_ci ni->itype.index.block_size_bits)) { 97762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) " 97862306a36Sopenharmony_ci "for index allocation (0x%llx).", 97962306a36Sopenharmony_ci bvi_size << 3, vi->i_size); 98062306a36Sopenharmony_ci goto iput_unm_err_out; 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci /* No longer need the bitmap attribute inode. */ 98362306a36Sopenharmony_ci iput(bvi); 98462306a36Sopenharmony_ciskip_large_dir_stuff: 98562306a36Sopenharmony_ci /* Setup the operations for this inode. */ 98662306a36Sopenharmony_ci vi->i_op = &ntfs_dir_inode_ops; 98762306a36Sopenharmony_ci vi->i_fop = &ntfs_dir_ops; 98862306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_mst_aops; 98962306a36Sopenharmony_ci } else { 99062306a36Sopenharmony_ci /* It is a file. */ 99162306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* Setup the data attribute, even if not present. */ 99462306a36Sopenharmony_ci ni->type = AT_DATA; 99562306a36Sopenharmony_ci ni->name = NULL; 99662306a36Sopenharmony_ci ni->name_len = 0; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci /* Find first extent of the unnamed data attribute. */ 99962306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, 0, NULL, 0, ctx); 100062306a36Sopenharmony_ci if (unlikely(err)) { 100162306a36Sopenharmony_ci vi->i_size = ni->initialized_size = 100262306a36Sopenharmony_ci ni->allocated_size = 0; 100362306a36Sopenharmony_ci if (err != -ENOENT) { 100462306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to lookup $DATA " 100562306a36Sopenharmony_ci "attribute."); 100662306a36Sopenharmony_ci goto unm_err_out; 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci /* 100962306a36Sopenharmony_ci * FILE_Secure does not have an unnamed $DATA 101062306a36Sopenharmony_ci * attribute, so we special case it here. 101162306a36Sopenharmony_ci */ 101262306a36Sopenharmony_ci if (vi->i_ino == FILE_Secure) 101362306a36Sopenharmony_ci goto no_data_attr_special_case; 101462306a36Sopenharmony_ci /* 101562306a36Sopenharmony_ci * Most if not all the system files in the $Extend 101662306a36Sopenharmony_ci * system directory do not have unnamed data 101762306a36Sopenharmony_ci * attributes so we need to check if the parent 101862306a36Sopenharmony_ci * directory of the file is FILE_Extend and if it is 101962306a36Sopenharmony_ci * ignore this error. To do this we need to get the 102062306a36Sopenharmony_ci * name of this inode from the mft record as the name 102162306a36Sopenharmony_ci * contains the back reference to the parent directory. 102262306a36Sopenharmony_ci */ 102362306a36Sopenharmony_ci if (ntfs_is_extended_system_file(ctx) > 0) 102462306a36Sopenharmony_ci goto no_data_attr_special_case; 102562306a36Sopenharmony_ci // FIXME: File is corrupt! Hot-fix with empty data 102662306a36Sopenharmony_ci // attribute if recovery option is set. 102762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$DATA attribute is missing."); 102862306a36Sopenharmony_ci goto unm_err_out; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci a = ctx->attr; 103162306a36Sopenharmony_ci /* Setup the state. */ 103262306a36Sopenharmony_ci if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { 103362306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) { 103462306a36Sopenharmony_ci NInoSetCompressed(ni); 103562306a36Sopenharmony_ci if (vol->cluster_size > 4096) { 103662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found " 103762306a36Sopenharmony_ci "compressed data but " 103862306a36Sopenharmony_ci "compression is " 103962306a36Sopenharmony_ci "disabled due to " 104062306a36Sopenharmony_ci "cluster size (%i) > " 104162306a36Sopenharmony_ci "4kiB.", 104262306a36Sopenharmony_ci vol->cluster_size); 104362306a36Sopenharmony_ci goto unm_err_out; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci if ((a->flags & ATTR_COMPRESSION_MASK) 104662306a36Sopenharmony_ci != ATTR_IS_COMPRESSED) { 104762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found unknown " 104862306a36Sopenharmony_ci "compression method " 104962306a36Sopenharmony_ci "or corrupt file."); 105062306a36Sopenharmony_ci goto unm_err_out; 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci if (a->flags & ATTR_IS_SPARSE) 105462306a36Sopenharmony_ci NInoSetSparse(ni); 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci if (a->flags & ATTR_IS_ENCRYPTED) { 105762306a36Sopenharmony_ci if (NInoCompressed(ni)) { 105862306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found encrypted and " 105962306a36Sopenharmony_ci "compressed data."); 106062306a36Sopenharmony_ci goto unm_err_out; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci NInoSetEncrypted(ni); 106362306a36Sopenharmony_ci } 106462306a36Sopenharmony_ci if (a->non_resident) { 106562306a36Sopenharmony_ci NInoSetNonResident(ni); 106662306a36Sopenharmony_ci if (NInoCompressed(ni) || NInoSparse(ni)) { 106762306a36Sopenharmony_ci if (NInoCompressed(ni) && a->data.non_resident. 106862306a36Sopenharmony_ci compression_unit != 4) { 106962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found " 107062306a36Sopenharmony_ci "non-standard " 107162306a36Sopenharmony_ci "compression unit (%u " 107262306a36Sopenharmony_ci "instead of 4). " 107362306a36Sopenharmony_ci "Cannot handle this.", 107462306a36Sopenharmony_ci a->data.non_resident. 107562306a36Sopenharmony_ci compression_unit); 107662306a36Sopenharmony_ci err = -EOPNOTSUPP; 107762306a36Sopenharmony_ci goto unm_err_out; 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ci if (a->data.non_resident.compression_unit) { 108062306a36Sopenharmony_ci ni->itype.compressed.block_size = 1U << 108162306a36Sopenharmony_ci (a->data.non_resident. 108262306a36Sopenharmony_ci compression_unit + 108362306a36Sopenharmony_ci vol->cluster_size_bits); 108462306a36Sopenharmony_ci ni->itype.compressed.block_size_bits = 108562306a36Sopenharmony_ci ffs(ni->itype. 108662306a36Sopenharmony_ci compressed. 108762306a36Sopenharmony_ci block_size) - 1; 108862306a36Sopenharmony_ci ni->itype.compressed.block_clusters = 108962306a36Sopenharmony_ci 1U << a->data. 109062306a36Sopenharmony_ci non_resident. 109162306a36Sopenharmony_ci compression_unit; 109262306a36Sopenharmony_ci } else { 109362306a36Sopenharmony_ci ni->itype.compressed.block_size = 0; 109462306a36Sopenharmony_ci ni->itype.compressed.block_size_bits = 109562306a36Sopenharmony_ci 0; 109662306a36Sopenharmony_ci ni->itype.compressed.block_clusters = 109762306a36Sopenharmony_ci 0; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci ni->itype.compressed.size = sle64_to_cpu( 110062306a36Sopenharmony_ci a->data.non_resident. 110162306a36Sopenharmony_ci compressed_size); 110262306a36Sopenharmony_ci } 110362306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 110462306a36Sopenharmony_ci ntfs_error(vi->i_sb, "First extent of $DATA " 110562306a36Sopenharmony_ci "attribute has non zero " 110662306a36Sopenharmony_ci "lowest_vcn."); 110762306a36Sopenharmony_ci goto unm_err_out; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci vi->i_size = sle64_to_cpu( 111062306a36Sopenharmony_ci a->data.non_resident.data_size); 111162306a36Sopenharmony_ci ni->initialized_size = sle64_to_cpu( 111262306a36Sopenharmony_ci a->data.non_resident.initialized_size); 111362306a36Sopenharmony_ci ni->allocated_size = sle64_to_cpu( 111462306a36Sopenharmony_ci a->data.non_resident.allocated_size); 111562306a36Sopenharmony_ci } else { /* Resident attribute. */ 111662306a36Sopenharmony_ci vi->i_size = ni->initialized_size = le32_to_cpu( 111762306a36Sopenharmony_ci a->data.resident.value_length); 111862306a36Sopenharmony_ci ni->allocated_size = le32_to_cpu(a->length) - 111962306a36Sopenharmony_ci le16_to_cpu( 112062306a36Sopenharmony_ci a->data.resident.value_offset); 112162306a36Sopenharmony_ci if (vi->i_size > ni->allocated_size) { 112262306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Resident data attribute " 112362306a36Sopenharmony_ci "is corrupt (size exceeds " 112462306a36Sopenharmony_ci "allocation)."); 112562306a36Sopenharmony_ci goto unm_err_out; 112662306a36Sopenharmony_ci } 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_cino_data_attr_special_case: 112962306a36Sopenharmony_ci /* We are done with the mft record, so we release it. */ 113062306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 113162306a36Sopenharmony_ci unmap_mft_record(ni); 113262306a36Sopenharmony_ci m = NULL; 113362306a36Sopenharmony_ci ctx = NULL; 113462306a36Sopenharmony_ci /* Setup the operations for this inode. */ 113562306a36Sopenharmony_ci vi->i_op = &ntfs_file_inode_ops; 113662306a36Sopenharmony_ci vi->i_fop = &ntfs_file_ops; 113762306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_normal_aops; 113862306a36Sopenharmony_ci if (NInoMstProtected(ni)) 113962306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_mst_aops; 114062306a36Sopenharmony_ci else if (NInoCompressed(ni)) 114162306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_compressed_aops; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci /* 114462306a36Sopenharmony_ci * The number of 512-byte blocks used on disk (for stat). This is in so 114562306a36Sopenharmony_ci * far inaccurate as it doesn't account for any named streams or other 114662306a36Sopenharmony_ci * special non-resident attributes, but that is how Windows works, too, 114762306a36Sopenharmony_ci * so we are at least consistent with Windows, if not entirely 114862306a36Sopenharmony_ci * consistent with the Linux Way. Doing it the Linux Way would cause a 114962306a36Sopenharmony_ci * significant slowdown as it would involve iterating over all 115062306a36Sopenharmony_ci * attributes in the mft record and adding the allocated/compressed 115162306a36Sopenharmony_ci * sizes of all non-resident attributes present to give us the Linux 115262306a36Sopenharmony_ci * correct size that should go into i_blocks (after division by 512). 115362306a36Sopenharmony_ci */ 115462306a36Sopenharmony_ci if (S_ISREG(vi->i_mode) && (NInoCompressed(ni) || NInoSparse(ni))) 115562306a36Sopenharmony_ci vi->i_blocks = ni->itype.compressed.size >> 9; 115662306a36Sopenharmony_ci else 115762306a36Sopenharmony_ci vi->i_blocks = ni->allocated_size >> 9; 115862306a36Sopenharmony_ci ntfs_debug("Done."); 115962306a36Sopenharmony_ci return 0; 116062306a36Sopenharmony_ciiput_unm_err_out: 116162306a36Sopenharmony_ci iput(bvi); 116262306a36Sopenharmony_ciunm_err_out: 116362306a36Sopenharmony_ci if (!err) 116462306a36Sopenharmony_ci err = -EIO; 116562306a36Sopenharmony_ci if (ctx) 116662306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 116762306a36Sopenharmony_ci if (m) 116862306a36Sopenharmony_ci unmap_mft_record(ni); 116962306a36Sopenharmony_cierr_out: 117062306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed with error code %i. Marking corrupt " 117162306a36Sopenharmony_ci "inode 0x%lx as bad. Run chkdsk.", err, vi->i_ino); 117262306a36Sopenharmony_ci make_bad_inode(vi); 117362306a36Sopenharmony_ci if (err != -EOPNOTSUPP && err != -ENOMEM) 117462306a36Sopenharmony_ci NVolSetErrors(vol); 117562306a36Sopenharmony_ci return err; 117662306a36Sopenharmony_ci} 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci/** 117962306a36Sopenharmony_ci * ntfs_read_locked_attr_inode - read an attribute inode from its base inode 118062306a36Sopenharmony_ci * @base_vi: base inode 118162306a36Sopenharmony_ci * @vi: attribute inode to read 118262306a36Sopenharmony_ci * 118362306a36Sopenharmony_ci * ntfs_read_locked_attr_inode() is called from ntfs_attr_iget() to read the 118462306a36Sopenharmony_ci * attribute inode described by @vi into memory from the base mft record 118562306a36Sopenharmony_ci * described by @base_ni. 118662306a36Sopenharmony_ci * 118762306a36Sopenharmony_ci * ntfs_read_locked_attr_inode() maps, pins and locks the base inode for 118862306a36Sopenharmony_ci * reading and looks up the attribute described by @vi before setting up the 118962306a36Sopenharmony_ci * necessary fields in @vi as well as initializing the ntfs inode. 119062306a36Sopenharmony_ci * 119162306a36Sopenharmony_ci * Q: What locks are held when the function is called? 119262306a36Sopenharmony_ci * A: i_state has I_NEW set, hence the inode is locked, also 119362306a36Sopenharmony_ci * i_count is set to 1, so it is not going to go away 119462306a36Sopenharmony_ci * 119562306a36Sopenharmony_ci * Return 0 on success and -errno on error. In the error case, the inode will 119662306a36Sopenharmony_ci * have had make_bad_inode() executed on it. 119762306a36Sopenharmony_ci * 119862306a36Sopenharmony_ci * Note this cannot be called for AT_INDEX_ALLOCATION. 119962306a36Sopenharmony_ci */ 120062306a36Sopenharmony_cistatic int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci ntfs_volume *vol = NTFS_SB(vi->i_sb); 120362306a36Sopenharmony_ci ntfs_inode *ni, *base_ni; 120462306a36Sopenharmony_ci MFT_RECORD *m; 120562306a36Sopenharmony_ci ATTR_RECORD *a; 120662306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 120762306a36Sopenharmony_ci int err = 0; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino); 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci ntfs_init_big_inode(vi); 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci ni = NTFS_I(vi); 121462306a36Sopenharmony_ci base_ni = NTFS_I(base_vi); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* Just mirror the values from the base inode. */ 121762306a36Sopenharmony_ci vi->i_uid = base_vi->i_uid; 121862306a36Sopenharmony_ci vi->i_gid = base_vi->i_gid; 121962306a36Sopenharmony_ci set_nlink(vi, base_vi->i_nlink); 122062306a36Sopenharmony_ci vi->i_mtime = base_vi->i_mtime; 122162306a36Sopenharmony_ci inode_set_ctime_to_ts(vi, inode_get_ctime(base_vi)); 122262306a36Sopenharmony_ci vi->i_atime = base_vi->i_atime; 122362306a36Sopenharmony_ci vi->i_generation = ni->seq_no = base_ni->seq_no; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci /* Set inode type to zero but preserve permissions. */ 122662306a36Sopenharmony_ci vi->i_mode = base_vi->i_mode & ~S_IFMT; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci m = map_mft_record(base_ni); 122962306a36Sopenharmony_ci if (IS_ERR(m)) { 123062306a36Sopenharmony_ci err = PTR_ERR(m); 123162306a36Sopenharmony_ci goto err_out; 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(base_ni, m); 123462306a36Sopenharmony_ci if (!ctx) { 123562306a36Sopenharmony_ci err = -ENOMEM; 123662306a36Sopenharmony_ci goto unm_err_out; 123762306a36Sopenharmony_ci } 123862306a36Sopenharmony_ci /* Find the attribute. */ 123962306a36Sopenharmony_ci err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 124062306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 124162306a36Sopenharmony_ci if (unlikely(err)) 124262306a36Sopenharmony_ci goto unm_err_out; 124362306a36Sopenharmony_ci a = ctx->attr; 124462306a36Sopenharmony_ci if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_SPARSE)) { 124562306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) { 124662306a36Sopenharmony_ci NInoSetCompressed(ni); 124762306a36Sopenharmony_ci if ((ni->type != AT_DATA) || (ni->type == AT_DATA && 124862306a36Sopenharmony_ci ni->name_len)) { 124962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found compressed " 125062306a36Sopenharmony_ci "non-data or named data " 125162306a36Sopenharmony_ci "attribute. Please report " 125262306a36Sopenharmony_ci "you saw this message to " 125362306a36Sopenharmony_ci "linux-ntfs-dev@lists." 125462306a36Sopenharmony_ci "sourceforge.net"); 125562306a36Sopenharmony_ci goto unm_err_out; 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci if (vol->cluster_size > 4096) { 125862306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found compressed " 125962306a36Sopenharmony_ci "attribute but compression is " 126062306a36Sopenharmony_ci "disabled due to cluster size " 126162306a36Sopenharmony_ci "(%i) > 4kiB.", 126262306a36Sopenharmony_ci vol->cluster_size); 126362306a36Sopenharmony_ci goto unm_err_out; 126462306a36Sopenharmony_ci } 126562306a36Sopenharmony_ci if ((a->flags & ATTR_COMPRESSION_MASK) != 126662306a36Sopenharmony_ci ATTR_IS_COMPRESSED) { 126762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found unknown " 126862306a36Sopenharmony_ci "compression method."); 126962306a36Sopenharmony_ci goto unm_err_out; 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci /* 127362306a36Sopenharmony_ci * The compressed/sparse flag set in an index root just means 127462306a36Sopenharmony_ci * to compress all files. 127562306a36Sopenharmony_ci */ 127662306a36Sopenharmony_ci if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { 127762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found mst protected attribute " 127862306a36Sopenharmony_ci "but the attribute is %s. Please " 127962306a36Sopenharmony_ci "report you saw this message to " 128062306a36Sopenharmony_ci "linux-ntfs-dev@lists.sourceforge.net", 128162306a36Sopenharmony_ci NInoCompressed(ni) ? "compressed" : 128262306a36Sopenharmony_ci "sparse"); 128362306a36Sopenharmony_ci goto unm_err_out; 128462306a36Sopenharmony_ci } 128562306a36Sopenharmony_ci if (a->flags & ATTR_IS_SPARSE) 128662306a36Sopenharmony_ci NInoSetSparse(ni); 128762306a36Sopenharmony_ci } 128862306a36Sopenharmony_ci if (a->flags & ATTR_IS_ENCRYPTED) { 128962306a36Sopenharmony_ci if (NInoCompressed(ni)) { 129062306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found encrypted and compressed " 129162306a36Sopenharmony_ci "data."); 129262306a36Sopenharmony_ci goto unm_err_out; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci /* 129562306a36Sopenharmony_ci * The encryption flag set in an index root just means to 129662306a36Sopenharmony_ci * encrypt all files. 129762306a36Sopenharmony_ci */ 129862306a36Sopenharmony_ci if (NInoMstProtected(ni) && ni->type != AT_INDEX_ROOT) { 129962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found mst protected attribute " 130062306a36Sopenharmony_ci "but the attribute is encrypted. " 130162306a36Sopenharmony_ci "Please report you saw this message " 130262306a36Sopenharmony_ci "to linux-ntfs-dev@lists.sourceforge." 130362306a36Sopenharmony_ci "net"); 130462306a36Sopenharmony_ci goto unm_err_out; 130562306a36Sopenharmony_ci } 130662306a36Sopenharmony_ci if (ni->type != AT_DATA) { 130762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found encrypted non-data " 130862306a36Sopenharmony_ci "attribute."); 130962306a36Sopenharmony_ci goto unm_err_out; 131062306a36Sopenharmony_ci } 131162306a36Sopenharmony_ci NInoSetEncrypted(ni); 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci if (!a->non_resident) { 131462306a36Sopenharmony_ci /* Ensure the attribute name is placed before the value. */ 131562306a36Sopenharmony_ci if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= 131662306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset)))) { 131762306a36Sopenharmony_ci ntfs_error(vol->sb, "Attribute name is placed after " 131862306a36Sopenharmony_ci "the attribute value."); 131962306a36Sopenharmony_ci goto unm_err_out; 132062306a36Sopenharmony_ci } 132162306a36Sopenharmony_ci if (NInoMstProtected(ni)) { 132262306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found mst protected attribute " 132362306a36Sopenharmony_ci "but the attribute is resident. " 132462306a36Sopenharmony_ci "Please report you saw this message to " 132562306a36Sopenharmony_ci "linux-ntfs-dev@lists.sourceforge.net"); 132662306a36Sopenharmony_ci goto unm_err_out; 132762306a36Sopenharmony_ci } 132862306a36Sopenharmony_ci vi->i_size = ni->initialized_size = le32_to_cpu( 132962306a36Sopenharmony_ci a->data.resident.value_length); 133062306a36Sopenharmony_ci ni->allocated_size = le32_to_cpu(a->length) - 133162306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset); 133262306a36Sopenharmony_ci if (vi->i_size > ni->allocated_size) { 133362306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Resident attribute is corrupt " 133462306a36Sopenharmony_ci "(size exceeds allocation)."); 133562306a36Sopenharmony_ci goto unm_err_out; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci } else { 133862306a36Sopenharmony_ci NInoSetNonResident(ni); 133962306a36Sopenharmony_ci /* 134062306a36Sopenharmony_ci * Ensure the attribute name is placed before the mapping pairs 134162306a36Sopenharmony_ci * array. 134262306a36Sopenharmony_ci */ 134362306a36Sopenharmony_ci if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= 134462306a36Sopenharmony_ci le16_to_cpu( 134562306a36Sopenharmony_ci a->data.non_resident.mapping_pairs_offset)))) { 134662306a36Sopenharmony_ci ntfs_error(vol->sb, "Attribute name is placed after " 134762306a36Sopenharmony_ci "the mapping pairs array."); 134862306a36Sopenharmony_ci goto unm_err_out; 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci if (NInoCompressed(ni) || NInoSparse(ni)) { 135162306a36Sopenharmony_ci if (NInoCompressed(ni) && a->data.non_resident. 135262306a36Sopenharmony_ci compression_unit != 4) { 135362306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found non-standard " 135462306a36Sopenharmony_ci "compression unit (%u instead " 135562306a36Sopenharmony_ci "of 4). Cannot handle this.", 135662306a36Sopenharmony_ci a->data.non_resident. 135762306a36Sopenharmony_ci compression_unit); 135862306a36Sopenharmony_ci err = -EOPNOTSUPP; 135962306a36Sopenharmony_ci goto unm_err_out; 136062306a36Sopenharmony_ci } 136162306a36Sopenharmony_ci if (a->data.non_resident.compression_unit) { 136262306a36Sopenharmony_ci ni->itype.compressed.block_size = 1U << 136362306a36Sopenharmony_ci (a->data.non_resident. 136462306a36Sopenharmony_ci compression_unit + 136562306a36Sopenharmony_ci vol->cluster_size_bits); 136662306a36Sopenharmony_ci ni->itype.compressed.block_size_bits = 136762306a36Sopenharmony_ci ffs(ni->itype.compressed. 136862306a36Sopenharmony_ci block_size) - 1; 136962306a36Sopenharmony_ci ni->itype.compressed.block_clusters = 1U << 137062306a36Sopenharmony_ci a->data.non_resident. 137162306a36Sopenharmony_ci compression_unit; 137262306a36Sopenharmony_ci } else { 137362306a36Sopenharmony_ci ni->itype.compressed.block_size = 0; 137462306a36Sopenharmony_ci ni->itype.compressed.block_size_bits = 0; 137562306a36Sopenharmony_ci ni->itype.compressed.block_clusters = 0; 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci ni->itype.compressed.size = sle64_to_cpu( 137862306a36Sopenharmony_ci a->data.non_resident.compressed_size); 137962306a36Sopenharmony_ci } 138062306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 138162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "First extent of attribute has " 138262306a36Sopenharmony_ci "non-zero lowest_vcn."); 138362306a36Sopenharmony_ci goto unm_err_out; 138462306a36Sopenharmony_ci } 138562306a36Sopenharmony_ci vi->i_size = sle64_to_cpu(a->data.non_resident.data_size); 138662306a36Sopenharmony_ci ni->initialized_size = sle64_to_cpu( 138762306a36Sopenharmony_ci a->data.non_resident.initialized_size); 138862306a36Sopenharmony_ci ni->allocated_size = sle64_to_cpu( 138962306a36Sopenharmony_ci a->data.non_resident.allocated_size); 139062306a36Sopenharmony_ci } 139162306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_normal_aops; 139262306a36Sopenharmony_ci if (NInoMstProtected(ni)) 139362306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_mst_aops; 139462306a36Sopenharmony_ci else if (NInoCompressed(ni)) 139562306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_compressed_aops; 139662306a36Sopenharmony_ci if ((NInoCompressed(ni) || NInoSparse(ni)) && ni->type != AT_INDEX_ROOT) 139762306a36Sopenharmony_ci vi->i_blocks = ni->itype.compressed.size >> 9; 139862306a36Sopenharmony_ci else 139962306a36Sopenharmony_ci vi->i_blocks = ni->allocated_size >> 9; 140062306a36Sopenharmony_ci /* 140162306a36Sopenharmony_ci * Make sure the base inode does not go away and attach it to the 140262306a36Sopenharmony_ci * attribute inode. 140362306a36Sopenharmony_ci */ 140462306a36Sopenharmony_ci igrab(base_vi); 140562306a36Sopenharmony_ci ni->ext.base_ntfs_ino = base_ni; 140662306a36Sopenharmony_ci ni->nr_extents = -1; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 140962306a36Sopenharmony_ci unmap_mft_record(base_ni); 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci ntfs_debug("Done."); 141262306a36Sopenharmony_ci return 0; 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ciunm_err_out: 141562306a36Sopenharmony_ci if (!err) 141662306a36Sopenharmony_ci err = -EIO; 141762306a36Sopenharmony_ci if (ctx) 141862306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 141962306a36Sopenharmony_ci unmap_mft_record(base_ni); 142062306a36Sopenharmony_cierr_out: 142162306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed with error code %i while reading attribute " 142262306a36Sopenharmony_ci "inode (mft_no 0x%lx, type 0x%x, name_len %i). " 142362306a36Sopenharmony_ci "Marking corrupt inode and base inode 0x%lx as bad. " 142462306a36Sopenharmony_ci "Run chkdsk.", err, vi->i_ino, ni->type, ni->name_len, 142562306a36Sopenharmony_ci base_vi->i_ino); 142662306a36Sopenharmony_ci make_bad_inode(vi); 142762306a36Sopenharmony_ci if (err != -ENOMEM) 142862306a36Sopenharmony_ci NVolSetErrors(vol); 142962306a36Sopenharmony_ci return err; 143062306a36Sopenharmony_ci} 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci/** 143362306a36Sopenharmony_ci * ntfs_read_locked_index_inode - read an index inode from its base inode 143462306a36Sopenharmony_ci * @base_vi: base inode 143562306a36Sopenharmony_ci * @vi: index inode to read 143662306a36Sopenharmony_ci * 143762306a36Sopenharmony_ci * ntfs_read_locked_index_inode() is called from ntfs_index_iget() to read the 143862306a36Sopenharmony_ci * index inode described by @vi into memory from the base mft record described 143962306a36Sopenharmony_ci * by @base_ni. 144062306a36Sopenharmony_ci * 144162306a36Sopenharmony_ci * ntfs_read_locked_index_inode() maps, pins and locks the base inode for 144262306a36Sopenharmony_ci * reading and looks up the attributes relating to the index described by @vi 144362306a36Sopenharmony_ci * before setting up the necessary fields in @vi as well as initializing the 144462306a36Sopenharmony_ci * ntfs inode. 144562306a36Sopenharmony_ci * 144662306a36Sopenharmony_ci * Note, index inodes are essentially attribute inodes (NInoAttr() is true) 144762306a36Sopenharmony_ci * with the attribute type set to AT_INDEX_ALLOCATION. Apart from that, they 144862306a36Sopenharmony_ci * are setup like directory inodes since directories are a special case of 144962306a36Sopenharmony_ci * indices ao they need to be treated in much the same way. Most importantly, 145062306a36Sopenharmony_ci * for small indices the index allocation attribute might not actually exist. 145162306a36Sopenharmony_ci * However, the index root attribute always exists but this does not need to 145262306a36Sopenharmony_ci * have an inode associated with it and this is why we define a new inode type 145362306a36Sopenharmony_ci * index. Also, like for directories, we need to have an attribute inode for 145462306a36Sopenharmony_ci * the bitmap attribute corresponding to the index allocation attribute and we 145562306a36Sopenharmony_ci * can store this in the appropriate field of the inode, just like we do for 145662306a36Sopenharmony_ci * normal directory inodes. 145762306a36Sopenharmony_ci * 145862306a36Sopenharmony_ci * Q: What locks are held when the function is called? 145962306a36Sopenharmony_ci * A: i_state has I_NEW set, hence the inode is locked, also 146062306a36Sopenharmony_ci * i_count is set to 1, so it is not going to go away 146162306a36Sopenharmony_ci * 146262306a36Sopenharmony_ci * Return 0 on success and -errno on error. In the error case, the inode will 146362306a36Sopenharmony_ci * have had make_bad_inode() executed on it. 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_cistatic int ntfs_read_locked_index_inode(struct inode *base_vi, struct inode *vi) 146662306a36Sopenharmony_ci{ 146762306a36Sopenharmony_ci loff_t bvi_size; 146862306a36Sopenharmony_ci ntfs_volume *vol = NTFS_SB(vi->i_sb); 146962306a36Sopenharmony_ci ntfs_inode *ni, *base_ni, *bni; 147062306a36Sopenharmony_ci struct inode *bvi; 147162306a36Sopenharmony_ci MFT_RECORD *m; 147262306a36Sopenharmony_ci ATTR_RECORD *a; 147362306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 147462306a36Sopenharmony_ci INDEX_ROOT *ir; 147562306a36Sopenharmony_ci u8 *ir_end, *index_end; 147662306a36Sopenharmony_ci int err = 0; 147762306a36Sopenharmony_ci 147862306a36Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx.", vi->i_ino); 147962306a36Sopenharmony_ci ntfs_init_big_inode(vi); 148062306a36Sopenharmony_ci ni = NTFS_I(vi); 148162306a36Sopenharmony_ci base_ni = NTFS_I(base_vi); 148262306a36Sopenharmony_ci /* Just mirror the values from the base inode. */ 148362306a36Sopenharmony_ci vi->i_uid = base_vi->i_uid; 148462306a36Sopenharmony_ci vi->i_gid = base_vi->i_gid; 148562306a36Sopenharmony_ci set_nlink(vi, base_vi->i_nlink); 148662306a36Sopenharmony_ci vi->i_mtime = base_vi->i_mtime; 148762306a36Sopenharmony_ci inode_set_ctime_to_ts(vi, inode_get_ctime(base_vi)); 148862306a36Sopenharmony_ci vi->i_atime = base_vi->i_atime; 148962306a36Sopenharmony_ci vi->i_generation = ni->seq_no = base_ni->seq_no; 149062306a36Sopenharmony_ci /* Set inode type to zero but preserve permissions. */ 149162306a36Sopenharmony_ci vi->i_mode = base_vi->i_mode & ~S_IFMT; 149262306a36Sopenharmony_ci /* Map the mft record for the base inode. */ 149362306a36Sopenharmony_ci m = map_mft_record(base_ni); 149462306a36Sopenharmony_ci if (IS_ERR(m)) { 149562306a36Sopenharmony_ci err = PTR_ERR(m); 149662306a36Sopenharmony_ci goto err_out; 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(base_ni, m); 149962306a36Sopenharmony_ci if (!ctx) { 150062306a36Sopenharmony_ci err = -ENOMEM; 150162306a36Sopenharmony_ci goto unm_err_out; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci /* Find the index root attribute. */ 150462306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_INDEX_ROOT, ni->name, ni->name_len, 150562306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 150662306a36Sopenharmony_ci if (unlikely(err)) { 150762306a36Sopenharmony_ci if (err == -ENOENT) 150862306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is " 150962306a36Sopenharmony_ci "missing."); 151062306a36Sopenharmony_ci goto unm_err_out; 151162306a36Sopenharmony_ci } 151262306a36Sopenharmony_ci a = ctx->attr; 151362306a36Sopenharmony_ci /* Set up the state. */ 151462306a36Sopenharmony_ci if (unlikely(a->non_resident)) { 151562306a36Sopenharmony_ci ntfs_error(vol->sb, "$INDEX_ROOT attribute is not resident."); 151662306a36Sopenharmony_ci goto unm_err_out; 151762306a36Sopenharmony_ci } 151862306a36Sopenharmony_ci /* Ensure the attribute name is placed before the value. */ 151962306a36Sopenharmony_ci if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= 152062306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset)))) { 152162306a36Sopenharmony_ci ntfs_error(vol->sb, "$INDEX_ROOT attribute name is placed " 152262306a36Sopenharmony_ci "after the attribute value."); 152362306a36Sopenharmony_ci goto unm_err_out; 152462306a36Sopenharmony_ci } 152562306a36Sopenharmony_ci /* 152662306a36Sopenharmony_ci * Compressed/encrypted/sparse index root is not allowed, except for 152762306a36Sopenharmony_ci * directories of course but those are not dealt with here. 152862306a36Sopenharmony_ci */ 152962306a36Sopenharmony_ci if (a->flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED | 153062306a36Sopenharmony_ci ATTR_IS_SPARSE)) { 153162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Found compressed/encrypted/sparse index " 153262306a36Sopenharmony_ci "root attribute."); 153362306a36Sopenharmony_ci goto unm_err_out; 153462306a36Sopenharmony_ci } 153562306a36Sopenharmony_ci ir = (INDEX_ROOT*)((u8*)a + le16_to_cpu(a->data.resident.value_offset)); 153662306a36Sopenharmony_ci ir_end = (u8*)ir + le32_to_cpu(a->data.resident.value_length); 153762306a36Sopenharmony_ci if (ir_end > (u8*)ctx->mrec + vol->mft_record_size) { 153862306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ROOT attribute is corrupt."); 153962306a36Sopenharmony_ci goto unm_err_out; 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length); 154262306a36Sopenharmony_ci if (index_end > ir_end) { 154362306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index is corrupt."); 154462306a36Sopenharmony_ci goto unm_err_out; 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci if (ir->type) { 154762306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index type is not 0 (type is 0x%x).", 154862306a36Sopenharmony_ci le32_to_cpu(ir->type)); 154962306a36Sopenharmony_ci goto unm_err_out; 155062306a36Sopenharmony_ci } 155162306a36Sopenharmony_ci ni->itype.index.collation_rule = ir->collation_rule; 155262306a36Sopenharmony_ci ntfs_debug("Index collation rule is 0x%x.", 155362306a36Sopenharmony_ci le32_to_cpu(ir->collation_rule)); 155462306a36Sopenharmony_ci ni->itype.index.block_size = le32_to_cpu(ir->index_block_size); 155562306a36Sopenharmony_ci if (!is_power_of_2(ni->itype.index.block_size)) { 155662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index block size (%u) is not a power of " 155762306a36Sopenharmony_ci "two.", ni->itype.index.block_size); 155862306a36Sopenharmony_ci goto unm_err_out; 155962306a36Sopenharmony_ci } 156062306a36Sopenharmony_ci if (ni->itype.index.block_size > PAGE_SIZE) { 156162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index block size (%u) > PAGE_SIZE " 156262306a36Sopenharmony_ci "(%ld) is not supported. Sorry.", 156362306a36Sopenharmony_ci ni->itype.index.block_size, PAGE_SIZE); 156462306a36Sopenharmony_ci err = -EOPNOTSUPP; 156562306a36Sopenharmony_ci goto unm_err_out; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci if (ni->itype.index.block_size < NTFS_BLOCK_SIZE) { 156862306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index block size (%u) < NTFS_BLOCK_SIZE " 156962306a36Sopenharmony_ci "(%i) is not supported. Sorry.", 157062306a36Sopenharmony_ci ni->itype.index.block_size, NTFS_BLOCK_SIZE); 157162306a36Sopenharmony_ci err = -EOPNOTSUPP; 157262306a36Sopenharmony_ci goto unm_err_out; 157362306a36Sopenharmony_ci } 157462306a36Sopenharmony_ci ni->itype.index.block_size_bits = ffs(ni->itype.index.block_size) - 1; 157562306a36Sopenharmony_ci /* Determine the size of a vcn in the index. */ 157662306a36Sopenharmony_ci if (vol->cluster_size <= ni->itype.index.block_size) { 157762306a36Sopenharmony_ci ni->itype.index.vcn_size = vol->cluster_size; 157862306a36Sopenharmony_ci ni->itype.index.vcn_size_bits = vol->cluster_size_bits; 157962306a36Sopenharmony_ci } else { 158062306a36Sopenharmony_ci ni->itype.index.vcn_size = vol->sector_size; 158162306a36Sopenharmony_ci ni->itype.index.vcn_size_bits = vol->sector_size_bits; 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci /* Check for presence of index allocation attribute. */ 158462306a36Sopenharmony_ci if (!(ir->index.flags & LARGE_INDEX)) { 158562306a36Sopenharmony_ci /* No index allocation. */ 158662306a36Sopenharmony_ci vi->i_size = ni->initialized_size = ni->allocated_size = 0; 158762306a36Sopenharmony_ci /* We are done with the mft record, so we release it. */ 158862306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 158962306a36Sopenharmony_ci unmap_mft_record(base_ni); 159062306a36Sopenharmony_ci m = NULL; 159162306a36Sopenharmony_ci ctx = NULL; 159262306a36Sopenharmony_ci goto skip_large_index_stuff; 159362306a36Sopenharmony_ci } /* LARGE_INDEX: Index allocation present. Setup state. */ 159462306a36Sopenharmony_ci NInoSetIndexAllocPresent(ni); 159562306a36Sopenharmony_ci /* Find index allocation attribute. */ 159662306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 159762306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_INDEX_ALLOCATION, ni->name, ni->name_len, 159862306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 159962306a36Sopenharmony_ci if (unlikely(err)) { 160062306a36Sopenharmony_ci if (err == -ENOENT) 160162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " 160262306a36Sopenharmony_ci "not present but $INDEX_ROOT " 160362306a36Sopenharmony_ci "indicated it is."); 160462306a36Sopenharmony_ci else 160562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to lookup " 160662306a36Sopenharmony_ci "$INDEX_ALLOCATION attribute."); 160762306a36Sopenharmony_ci goto unm_err_out; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci a = ctx->attr; 161062306a36Sopenharmony_ci if (!a->non_resident) { 161162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " 161262306a36Sopenharmony_ci "resident."); 161362306a36Sopenharmony_ci goto unm_err_out; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci /* 161662306a36Sopenharmony_ci * Ensure the attribute name is placed before the mapping pairs array. 161762306a36Sopenharmony_ci */ 161862306a36Sopenharmony_ci if (unlikely(a->name_length && (le16_to_cpu(a->name_offset) >= 161962306a36Sopenharmony_ci le16_to_cpu( 162062306a36Sopenharmony_ci a->data.non_resident.mapping_pairs_offset)))) { 162162306a36Sopenharmony_ci ntfs_error(vol->sb, "$INDEX_ALLOCATION attribute name is " 162262306a36Sopenharmony_ci "placed after the mapping pairs array."); 162362306a36Sopenharmony_ci goto unm_err_out; 162462306a36Sopenharmony_ci } 162562306a36Sopenharmony_ci if (a->flags & ATTR_IS_ENCRYPTED) { 162662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " 162762306a36Sopenharmony_ci "encrypted."); 162862306a36Sopenharmony_ci goto unm_err_out; 162962306a36Sopenharmony_ci } 163062306a36Sopenharmony_ci if (a->flags & ATTR_IS_SPARSE) { 163162306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is sparse."); 163262306a36Sopenharmony_ci goto unm_err_out; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) { 163562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$INDEX_ALLOCATION attribute is " 163662306a36Sopenharmony_ci "compressed."); 163762306a36Sopenharmony_ci goto unm_err_out; 163862306a36Sopenharmony_ci } 163962306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 164062306a36Sopenharmony_ci ntfs_error(vi->i_sb, "First extent of $INDEX_ALLOCATION " 164162306a36Sopenharmony_ci "attribute has non zero lowest_vcn."); 164262306a36Sopenharmony_ci goto unm_err_out; 164362306a36Sopenharmony_ci } 164462306a36Sopenharmony_ci vi->i_size = sle64_to_cpu(a->data.non_resident.data_size); 164562306a36Sopenharmony_ci ni->initialized_size = sle64_to_cpu( 164662306a36Sopenharmony_ci a->data.non_resident.initialized_size); 164762306a36Sopenharmony_ci ni->allocated_size = sle64_to_cpu(a->data.non_resident.allocated_size); 164862306a36Sopenharmony_ci /* 164962306a36Sopenharmony_ci * We are done with the mft record, so we release it. Otherwise 165062306a36Sopenharmony_ci * we would deadlock in ntfs_attr_iget(). 165162306a36Sopenharmony_ci */ 165262306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 165362306a36Sopenharmony_ci unmap_mft_record(base_ni); 165462306a36Sopenharmony_ci m = NULL; 165562306a36Sopenharmony_ci ctx = NULL; 165662306a36Sopenharmony_ci /* Get the index bitmap attribute inode. */ 165762306a36Sopenharmony_ci bvi = ntfs_attr_iget(base_vi, AT_BITMAP, ni->name, ni->name_len); 165862306a36Sopenharmony_ci if (IS_ERR(bvi)) { 165962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to get bitmap attribute."); 166062306a36Sopenharmony_ci err = PTR_ERR(bvi); 166162306a36Sopenharmony_ci goto unm_err_out; 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci bni = NTFS_I(bvi); 166462306a36Sopenharmony_ci if (NInoCompressed(bni) || NInoEncrypted(bni) || 166562306a36Sopenharmony_ci NInoSparse(bni)) { 166662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "$BITMAP attribute is compressed and/or " 166762306a36Sopenharmony_ci "encrypted and/or sparse."); 166862306a36Sopenharmony_ci goto iput_unm_err_out; 166962306a36Sopenharmony_ci } 167062306a36Sopenharmony_ci /* Consistency check bitmap size vs. index allocation size. */ 167162306a36Sopenharmony_ci bvi_size = i_size_read(bvi); 167262306a36Sopenharmony_ci if ((bvi_size << 3) < (vi->i_size >> ni->itype.index.block_size_bits)) { 167362306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Index bitmap too small (0x%llx) for " 167462306a36Sopenharmony_ci "index allocation (0x%llx).", bvi_size << 3, 167562306a36Sopenharmony_ci vi->i_size); 167662306a36Sopenharmony_ci goto iput_unm_err_out; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci iput(bvi); 167962306a36Sopenharmony_ciskip_large_index_stuff: 168062306a36Sopenharmony_ci /* Setup the operations for this index inode. */ 168162306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_mst_aops; 168262306a36Sopenharmony_ci vi->i_blocks = ni->allocated_size >> 9; 168362306a36Sopenharmony_ci /* 168462306a36Sopenharmony_ci * Make sure the base inode doesn't go away and attach it to the 168562306a36Sopenharmony_ci * index inode. 168662306a36Sopenharmony_ci */ 168762306a36Sopenharmony_ci igrab(base_vi); 168862306a36Sopenharmony_ci ni->ext.base_ntfs_ino = base_ni; 168962306a36Sopenharmony_ci ni->nr_extents = -1; 169062306a36Sopenharmony_ci 169162306a36Sopenharmony_ci ntfs_debug("Done."); 169262306a36Sopenharmony_ci return 0; 169362306a36Sopenharmony_ciiput_unm_err_out: 169462306a36Sopenharmony_ci iput(bvi); 169562306a36Sopenharmony_ciunm_err_out: 169662306a36Sopenharmony_ci if (!err) 169762306a36Sopenharmony_ci err = -EIO; 169862306a36Sopenharmony_ci if (ctx) 169962306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 170062306a36Sopenharmony_ci if (m) 170162306a36Sopenharmony_ci unmap_mft_record(base_ni); 170262306a36Sopenharmony_cierr_out: 170362306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed with error code %i while reading index " 170462306a36Sopenharmony_ci "inode (mft_no 0x%lx, name_len %i.", err, vi->i_ino, 170562306a36Sopenharmony_ci ni->name_len); 170662306a36Sopenharmony_ci make_bad_inode(vi); 170762306a36Sopenharmony_ci if (err != -EOPNOTSUPP && err != -ENOMEM) 170862306a36Sopenharmony_ci NVolSetErrors(vol); 170962306a36Sopenharmony_ci return err; 171062306a36Sopenharmony_ci} 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci/* 171362306a36Sopenharmony_ci * The MFT inode has special locking, so teach the lock validator 171462306a36Sopenharmony_ci * about this by splitting off the locking rules of the MFT from 171562306a36Sopenharmony_ci * the locking rules of other inodes. The MFT inode can never be 171662306a36Sopenharmony_ci * accessed from the VFS side (or even internally), only by the 171762306a36Sopenharmony_ci * map_mft functions. 171862306a36Sopenharmony_ci */ 171962306a36Sopenharmony_cistatic struct lock_class_key mft_ni_runlist_lock_key, mft_ni_mrec_lock_key; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_ci/** 172262306a36Sopenharmony_ci * ntfs_read_inode_mount - special read_inode for mount time use only 172362306a36Sopenharmony_ci * @vi: inode to read 172462306a36Sopenharmony_ci * 172562306a36Sopenharmony_ci * Read inode FILE_MFT at mount time, only called with super_block lock 172662306a36Sopenharmony_ci * held from within the read_super() code path. 172762306a36Sopenharmony_ci * 172862306a36Sopenharmony_ci * This function exists because when it is called the page cache for $MFT/$DATA 172962306a36Sopenharmony_ci * is not initialized and hence we cannot get at the contents of mft records 173062306a36Sopenharmony_ci * by calling map_mft_record*(). 173162306a36Sopenharmony_ci * 173262306a36Sopenharmony_ci * Further it needs to cope with the circular references problem, i.e. cannot 173362306a36Sopenharmony_ci * load any attributes other than $ATTRIBUTE_LIST until $DATA is loaded, because 173462306a36Sopenharmony_ci * we do not know where the other extent mft records are yet and again, because 173562306a36Sopenharmony_ci * we cannot call map_mft_record*() yet. Obviously this applies only when an 173662306a36Sopenharmony_ci * attribute list is actually present in $MFT inode. 173762306a36Sopenharmony_ci * 173862306a36Sopenharmony_ci * We solve these problems by starting with the $DATA attribute before anything 173962306a36Sopenharmony_ci * else and iterating using ntfs_attr_lookup($DATA) over all extents. As each 174062306a36Sopenharmony_ci * extent is found, we ntfs_mapping_pairs_decompress() including the implied 174162306a36Sopenharmony_ci * ntfs_runlists_merge(). Each step of the iteration necessarily provides 174262306a36Sopenharmony_ci * sufficient information for the next step to complete. 174362306a36Sopenharmony_ci * 174462306a36Sopenharmony_ci * This should work but there are two possible pit falls (see inline comments 174562306a36Sopenharmony_ci * below), but only time will tell if they are real pits or just smoke... 174662306a36Sopenharmony_ci */ 174762306a36Sopenharmony_ciint ntfs_read_inode_mount(struct inode *vi) 174862306a36Sopenharmony_ci{ 174962306a36Sopenharmony_ci VCN next_vcn, last_vcn, highest_vcn; 175062306a36Sopenharmony_ci s64 block; 175162306a36Sopenharmony_ci struct super_block *sb = vi->i_sb; 175262306a36Sopenharmony_ci ntfs_volume *vol = NTFS_SB(sb); 175362306a36Sopenharmony_ci struct buffer_head *bh; 175462306a36Sopenharmony_ci ntfs_inode *ni; 175562306a36Sopenharmony_ci MFT_RECORD *m = NULL; 175662306a36Sopenharmony_ci ATTR_RECORD *a; 175762306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 175862306a36Sopenharmony_ci unsigned int i, nr_blocks; 175962306a36Sopenharmony_ci int err; 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_ci ntfs_debug("Entering."); 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci /* Initialize the ntfs specific part of @vi. */ 176462306a36Sopenharmony_ci ntfs_init_big_inode(vi); 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci ni = NTFS_I(vi); 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_ci /* Setup the data attribute. It is special as it is mst protected. */ 176962306a36Sopenharmony_ci NInoSetNonResident(ni); 177062306a36Sopenharmony_ci NInoSetMstProtected(ni); 177162306a36Sopenharmony_ci NInoSetSparseDisabled(ni); 177262306a36Sopenharmony_ci ni->type = AT_DATA; 177362306a36Sopenharmony_ci ni->name = NULL; 177462306a36Sopenharmony_ci ni->name_len = 0; 177562306a36Sopenharmony_ci /* 177662306a36Sopenharmony_ci * This sets up our little cheat allowing us to reuse the async read io 177762306a36Sopenharmony_ci * completion handler for directories. 177862306a36Sopenharmony_ci */ 177962306a36Sopenharmony_ci ni->itype.index.block_size = vol->mft_record_size; 178062306a36Sopenharmony_ci ni->itype.index.block_size_bits = vol->mft_record_size_bits; 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci /* Very important! Needed to be able to call map_mft_record*(). */ 178362306a36Sopenharmony_ci vol->mft_ino = vi; 178462306a36Sopenharmony_ci 178562306a36Sopenharmony_ci /* Allocate enough memory to read the first mft record. */ 178662306a36Sopenharmony_ci if (vol->mft_record_size > 64 * 1024) { 178762306a36Sopenharmony_ci ntfs_error(sb, "Unsupported mft record size %i (max 64kiB).", 178862306a36Sopenharmony_ci vol->mft_record_size); 178962306a36Sopenharmony_ci goto err_out; 179062306a36Sopenharmony_ci } 179162306a36Sopenharmony_ci i = vol->mft_record_size; 179262306a36Sopenharmony_ci if (i < sb->s_blocksize) 179362306a36Sopenharmony_ci i = sb->s_blocksize; 179462306a36Sopenharmony_ci m = (MFT_RECORD*)ntfs_malloc_nofs(i); 179562306a36Sopenharmony_ci if (!m) { 179662306a36Sopenharmony_ci ntfs_error(sb, "Failed to allocate buffer for $MFT record 0."); 179762306a36Sopenharmony_ci goto err_out; 179862306a36Sopenharmony_ci } 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci /* Determine the first block of the $MFT/$DATA attribute. */ 180162306a36Sopenharmony_ci block = vol->mft_lcn << vol->cluster_size_bits >> 180262306a36Sopenharmony_ci sb->s_blocksize_bits; 180362306a36Sopenharmony_ci nr_blocks = vol->mft_record_size >> sb->s_blocksize_bits; 180462306a36Sopenharmony_ci if (!nr_blocks) 180562306a36Sopenharmony_ci nr_blocks = 1; 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci /* Load $MFT/$DATA's first mft record. */ 180862306a36Sopenharmony_ci for (i = 0; i < nr_blocks; i++) { 180962306a36Sopenharmony_ci bh = sb_bread(sb, block++); 181062306a36Sopenharmony_ci if (!bh) { 181162306a36Sopenharmony_ci ntfs_error(sb, "Device read failed."); 181262306a36Sopenharmony_ci goto err_out; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci memcpy((char*)m + (i << sb->s_blocksize_bits), bh->b_data, 181562306a36Sopenharmony_ci sb->s_blocksize); 181662306a36Sopenharmony_ci brelse(bh); 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci if (le32_to_cpu(m->bytes_allocated) != vol->mft_record_size) { 182062306a36Sopenharmony_ci ntfs_error(sb, "Incorrect mft record size %u in superblock, should be %u.", 182162306a36Sopenharmony_ci le32_to_cpu(m->bytes_allocated), vol->mft_record_size); 182262306a36Sopenharmony_ci goto err_out; 182362306a36Sopenharmony_ci } 182462306a36Sopenharmony_ci 182562306a36Sopenharmony_ci /* Apply the mst fixups. */ 182662306a36Sopenharmony_ci if (post_read_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size)) { 182762306a36Sopenharmony_ci /* FIXME: Try to use the $MFTMirr now. */ 182862306a36Sopenharmony_ci ntfs_error(sb, "MST fixup failed. $MFT is corrupt."); 182962306a36Sopenharmony_ci goto err_out; 183062306a36Sopenharmony_ci } 183162306a36Sopenharmony_ci 183262306a36Sopenharmony_ci /* Sanity check offset to the first attribute */ 183362306a36Sopenharmony_ci if (le16_to_cpu(m->attrs_offset) >= le32_to_cpu(m->bytes_allocated)) { 183462306a36Sopenharmony_ci ntfs_error(sb, "Incorrect mft offset to the first attribute %u in superblock.", 183562306a36Sopenharmony_ci le16_to_cpu(m->attrs_offset)); 183662306a36Sopenharmony_ci goto err_out; 183762306a36Sopenharmony_ci } 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci /* Need this to sanity check attribute list references to $MFT. */ 184062306a36Sopenharmony_ci vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number); 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci /* Provides read_folio() for map_mft_record(). */ 184362306a36Sopenharmony_ci vi->i_mapping->a_ops = &ntfs_mst_aops; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(ni, m); 184662306a36Sopenharmony_ci if (!ctx) { 184762306a36Sopenharmony_ci err = -ENOMEM; 184862306a36Sopenharmony_ci goto err_out; 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci /* Find the attribute list attribute if present. */ 185262306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx); 185362306a36Sopenharmony_ci if (err) { 185462306a36Sopenharmony_ci if (unlikely(err != -ENOENT)) { 185562306a36Sopenharmony_ci ntfs_error(sb, "Failed to lookup attribute list " 185662306a36Sopenharmony_ci "attribute. You should run chkdsk."); 185762306a36Sopenharmony_ci goto put_err_out; 185862306a36Sopenharmony_ci } 185962306a36Sopenharmony_ci } else /* if (!err) */ { 186062306a36Sopenharmony_ci ATTR_LIST_ENTRY *al_entry, *next_al_entry; 186162306a36Sopenharmony_ci u8 *al_end; 186262306a36Sopenharmony_ci static const char *es = " Not allowed. $MFT is corrupt. " 186362306a36Sopenharmony_ci "You should run chkdsk."; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci ntfs_debug("Attribute list attribute found in $MFT."); 186662306a36Sopenharmony_ci NInoSetAttrList(ni); 186762306a36Sopenharmony_ci a = ctx->attr; 186862306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK) { 186962306a36Sopenharmony_ci ntfs_error(sb, "Attribute list attribute is " 187062306a36Sopenharmony_ci "compressed.%s", es); 187162306a36Sopenharmony_ci goto put_err_out; 187262306a36Sopenharmony_ci } 187362306a36Sopenharmony_ci if (a->flags & ATTR_IS_ENCRYPTED || 187462306a36Sopenharmony_ci a->flags & ATTR_IS_SPARSE) { 187562306a36Sopenharmony_ci if (a->non_resident) { 187662306a36Sopenharmony_ci ntfs_error(sb, "Non-resident attribute list " 187762306a36Sopenharmony_ci "attribute is encrypted/" 187862306a36Sopenharmony_ci "sparse.%s", es); 187962306a36Sopenharmony_ci goto put_err_out; 188062306a36Sopenharmony_ci } 188162306a36Sopenharmony_ci ntfs_warning(sb, "Resident attribute list attribute " 188262306a36Sopenharmony_ci "in $MFT system file is marked " 188362306a36Sopenharmony_ci "encrypted/sparse which is not true. " 188462306a36Sopenharmony_ci "However, Windows allows this and " 188562306a36Sopenharmony_ci "chkdsk does not detect or correct it " 188662306a36Sopenharmony_ci "so we will just ignore the invalid " 188762306a36Sopenharmony_ci "flags and pretend they are not set."); 188862306a36Sopenharmony_ci } 188962306a36Sopenharmony_ci /* Now allocate memory for the attribute list. */ 189062306a36Sopenharmony_ci ni->attr_list_size = (u32)ntfs_attr_size(a); 189162306a36Sopenharmony_ci if (!ni->attr_list_size) { 189262306a36Sopenharmony_ci ntfs_error(sb, "Attr_list_size is zero"); 189362306a36Sopenharmony_ci goto put_err_out; 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size); 189662306a36Sopenharmony_ci if (!ni->attr_list) { 189762306a36Sopenharmony_ci ntfs_error(sb, "Not enough memory to allocate buffer " 189862306a36Sopenharmony_ci "for attribute list."); 189962306a36Sopenharmony_ci goto put_err_out; 190062306a36Sopenharmony_ci } 190162306a36Sopenharmony_ci if (a->non_resident) { 190262306a36Sopenharmony_ci NInoSetAttrListNonResident(ni); 190362306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 190462306a36Sopenharmony_ci ntfs_error(sb, "Attribute list has non zero " 190562306a36Sopenharmony_ci "lowest_vcn. $MFT is corrupt. " 190662306a36Sopenharmony_ci "You should run chkdsk."); 190762306a36Sopenharmony_ci goto put_err_out; 190862306a36Sopenharmony_ci } 190962306a36Sopenharmony_ci /* Setup the runlist. */ 191062306a36Sopenharmony_ci ni->attr_list_rl.rl = ntfs_mapping_pairs_decompress(vol, 191162306a36Sopenharmony_ci a, NULL); 191262306a36Sopenharmony_ci if (IS_ERR(ni->attr_list_rl.rl)) { 191362306a36Sopenharmony_ci err = PTR_ERR(ni->attr_list_rl.rl); 191462306a36Sopenharmony_ci ni->attr_list_rl.rl = NULL; 191562306a36Sopenharmony_ci ntfs_error(sb, "Mapping pairs decompression " 191662306a36Sopenharmony_ci "failed with error code %i.", 191762306a36Sopenharmony_ci -err); 191862306a36Sopenharmony_ci goto put_err_out; 191962306a36Sopenharmony_ci } 192062306a36Sopenharmony_ci /* Now load the attribute list. */ 192162306a36Sopenharmony_ci if ((err = load_attribute_list(vol, &ni->attr_list_rl, 192262306a36Sopenharmony_ci ni->attr_list, ni->attr_list_size, 192362306a36Sopenharmony_ci sle64_to_cpu(a->data. 192462306a36Sopenharmony_ci non_resident.initialized_size)))) { 192562306a36Sopenharmony_ci ntfs_error(sb, "Failed to load attribute list " 192662306a36Sopenharmony_ci "attribute with error code %i.", 192762306a36Sopenharmony_ci -err); 192862306a36Sopenharmony_ci goto put_err_out; 192962306a36Sopenharmony_ci } 193062306a36Sopenharmony_ci } else /* if (!ctx.attr->non_resident) */ { 193162306a36Sopenharmony_ci if ((u8*)a + le16_to_cpu( 193262306a36Sopenharmony_ci a->data.resident.value_offset) + 193362306a36Sopenharmony_ci le32_to_cpu( 193462306a36Sopenharmony_ci a->data.resident.value_length) > 193562306a36Sopenharmony_ci (u8*)ctx->mrec + vol->mft_record_size) { 193662306a36Sopenharmony_ci ntfs_error(sb, "Corrupt attribute list " 193762306a36Sopenharmony_ci "attribute."); 193862306a36Sopenharmony_ci goto put_err_out; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci /* Now copy the attribute list. */ 194162306a36Sopenharmony_ci memcpy(ni->attr_list, (u8*)a + le16_to_cpu( 194262306a36Sopenharmony_ci a->data.resident.value_offset), 194362306a36Sopenharmony_ci le32_to_cpu( 194462306a36Sopenharmony_ci a->data.resident.value_length)); 194562306a36Sopenharmony_ci } 194662306a36Sopenharmony_ci /* The attribute list is now setup in memory. */ 194762306a36Sopenharmony_ci /* 194862306a36Sopenharmony_ci * FIXME: I don't know if this case is actually possible. 194962306a36Sopenharmony_ci * According to logic it is not possible but I have seen too 195062306a36Sopenharmony_ci * many weird things in MS software to rely on logic... Thus we 195162306a36Sopenharmony_ci * perform a manual search and make sure the first $MFT/$DATA 195262306a36Sopenharmony_ci * extent is in the base inode. If it is not we abort with an 195362306a36Sopenharmony_ci * error and if we ever see a report of this error we will need 195462306a36Sopenharmony_ci * to do some magic in order to have the necessary mft record 195562306a36Sopenharmony_ci * loaded and in the right place in the page cache. But 195662306a36Sopenharmony_ci * hopefully logic will prevail and this never happens... 195762306a36Sopenharmony_ci */ 195862306a36Sopenharmony_ci al_entry = (ATTR_LIST_ENTRY*)ni->attr_list; 195962306a36Sopenharmony_ci al_end = (u8*)al_entry + ni->attr_list_size; 196062306a36Sopenharmony_ci for (;; al_entry = next_al_entry) { 196162306a36Sopenharmony_ci /* Out of bounds check. */ 196262306a36Sopenharmony_ci if ((u8*)al_entry < ni->attr_list || 196362306a36Sopenharmony_ci (u8*)al_entry > al_end) 196462306a36Sopenharmony_ci goto em_put_err_out; 196562306a36Sopenharmony_ci /* Catch the end of the attribute list. */ 196662306a36Sopenharmony_ci if ((u8*)al_entry == al_end) 196762306a36Sopenharmony_ci goto em_put_err_out; 196862306a36Sopenharmony_ci if (!al_entry->length) 196962306a36Sopenharmony_ci goto em_put_err_out; 197062306a36Sopenharmony_ci if ((u8*)al_entry + 6 > al_end || (u8*)al_entry + 197162306a36Sopenharmony_ci le16_to_cpu(al_entry->length) > al_end) 197262306a36Sopenharmony_ci goto em_put_err_out; 197362306a36Sopenharmony_ci next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + 197462306a36Sopenharmony_ci le16_to_cpu(al_entry->length)); 197562306a36Sopenharmony_ci if (le32_to_cpu(al_entry->type) > le32_to_cpu(AT_DATA)) 197662306a36Sopenharmony_ci goto em_put_err_out; 197762306a36Sopenharmony_ci if (AT_DATA != al_entry->type) 197862306a36Sopenharmony_ci continue; 197962306a36Sopenharmony_ci /* We want an unnamed attribute. */ 198062306a36Sopenharmony_ci if (al_entry->name_length) 198162306a36Sopenharmony_ci goto em_put_err_out; 198262306a36Sopenharmony_ci /* Want the first entry, i.e. lowest_vcn == 0. */ 198362306a36Sopenharmony_ci if (al_entry->lowest_vcn) 198462306a36Sopenharmony_ci goto em_put_err_out; 198562306a36Sopenharmony_ci /* First entry has to be in the base mft record. */ 198662306a36Sopenharmony_ci if (MREF_LE(al_entry->mft_reference) != vi->i_ino) { 198762306a36Sopenharmony_ci /* MFT references do not match, logic fails. */ 198862306a36Sopenharmony_ci ntfs_error(sb, "BUG: The first $DATA extent " 198962306a36Sopenharmony_ci "of $MFT is not in the base " 199062306a36Sopenharmony_ci "mft record. Please report " 199162306a36Sopenharmony_ci "you saw this message to " 199262306a36Sopenharmony_ci "linux-ntfs-dev@lists." 199362306a36Sopenharmony_ci "sourceforge.net"); 199462306a36Sopenharmony_ci goto put_err_out; 199562306a36Sopenharmony_ci } else { 199662306a36Sopenharmony_ci /* Sequence numbers must match. */ 199762306a36Sopenharmony_ci if (MSEQNO_LE(al_entry->mft_reference) != 199862306a36Sopenharmony_ci ni->seq_no) 199962306a36Sopenharmony_ci goto em_put_err_out; 200062306a36Sopenharmony_ci /* Got it. All is ok. We can stop now. */ 200162306a36Sopenharmony_ci break; 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci } 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 200762306a36Sopenharmony_ci 200862306a36Sopenharmony_ci /* Now load all attribute extents. */ 200962306a36Sopenharmony_ci a = NULL; 201062306a36Sopenharmony_ci next_vcn = last_vcn = highest_vcn = 0; 201162306a36Sopenharmony_ci while (!(err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0, 201262306a36Sopenharmony_ci ctx))) { 201362306a36Sopenharmony_ci runlist_element *nrl; 201462306a36Sopenharmony_ci 201562306a36Sopenharmony_ci /* Cache the current attribute. */ 201662306a36Sopenharmony_ci a = ctx->attr; 201762306a36Sopenharmony_ci /* $MFT must be non-resident. */ 201862306a36Sopenharmony_ci if (!a->non_resident) { 201962306a36Sopenharmony_ci ntfs_error(sb, "$MFT must be non-resident but a " 202062306a36Sopenharmony_ci "resident extent was found. $MFT is " 202162306a36Sopenharmony_ci "corrupt. Run chkdsk."); 202262306a36Sopenharmony_ci goto put_err_out; 202362306a36Sopenharmony_ci } 202462306a36Sopenharmony_ci /* $MFT must be uncompressed and unencrypted. */ 202562306a36Sopenharmony_ci if (a->flags & ATTR_COMPRESSION_MASK || 202662306a36Sopenharmony_ci a->flags & ATTR_IS_ENCRYPTED || 202762306a36Sopenharmony_ci a->flags & ATTR_IS_SPARSE) { 202862306a36Sopenharmony_ci ntfs_error(sb, "$MFT must be uncompressed, " 202962306a36Sopenharmony_ci "non-sparse, and unencrypted but a " 203062306a36Sopenharmony_ci "compressed/sparse/encrypted extent " 203162306a36Sopenharmony_ci "was found. $MFT is corrupt. Run " 203262306a36Sopenharmony_ci "chkdsk."); 203362306a36Sopenharmony_ci goto put_err_out; 203462306a36Sopenharmony_ci } 203562306a36Sopenharmony_ci /* 203662306a36Sopenharmony_ci * Decompress the mapping pairs array of this extent and merge 203762306a36Sopenharmony_ci * the result into the existing runlist. No need for locking 203862306a36Sopenharmony_ci * as we have exclusive access to the inode at this time and we 203962306a36Sopenharmony_ci * are a mount in progress task, too. 204062306a36Sopenharmony_ci */ 204162306a36Sopenharmony_ci nrl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl); 204262306a36Sopenharmony_ci if (IS_ERR(nrl)) { 204362306a36Sopenharmony_ci ntfs_error(sb, "ntfs_mapping_pairs_decompress() " 204462306a36Sopenharmony_ci "failed with error code %ld. $MFT is " 204562306a36Sopenharmony_ci "corrupt.", PTR_ERR(nrl)); 204662306a36Sopenharmony_ci goto put_err_out; 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci ni->runlist.rl = nrl; 204962306a36Sopenharmony_ci 205062306a36Sopenharmony_ci /* Are we in the first extent? */ 205162306a36Sopenharmony_ci if (!next_vcn) { 205262306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 205362306a36Sopenharmony_ci ntfs_error(sb, "First extent of $DATA " 205462306a36Sopenharmony_ci "attribute has non zero " 205562306a36Sopenharmony_ci "lowest_vcn. $MFT is corrupt. " 205662306a36Sopenharmony_ci "You should run chkdsk."); 205762306a36Sopenharmony_ci goto put_err_out; 205862306a36Sopenharmony_ci } 205962306a36Sopenharmony_ci /* Get the last vcn in the $DATA attribute. */ 206062306a36Sopenharmony_ci last_vcn = sle64_to_cpu( 206162306a36Sopenharmony_ci a->data.non_resident.allocated_size) 206262306a36Sopenharmony_ci >> vol->cluster_size_bits; 206362306a36Sopenharmony_ci /* Fill in the inode size. */ 206462306a36Sopenharmony_ci vi->i_size = sle64_to_cpu( 206562306a36Sopenharmony_ci a->data.non_resident.data_size); 206662306a36Sopenharmony_ci ni->initialized_size = sle64_to_cpu( 206762306a36Sopenharmony_ci a->data.non_resident.initialized_size); 206862306a36Sopenharmony_ci ni->allocated_size = sle64_to_cpu( 206962306a36Sopenharmony_ci a->data.non_resident.allocated_size); 207062306a36Sopenharmony_ci /* 207162306a36Sopenharmony_ci * Verify the number of mft records does not exceed 207262306a36Sopenharmony_ci * 2^32 - 1. 207362306a36Sopenharmony_ci */ 207462306a36Sopenharmony_ci if ((vi->i_size >> vol->mft_record_size_bits) >= 207562306a36Sopenharmony_ci (1ULL << 32)) { 207662306a36Sopenharmony_ci ntfs_error(sb, "$MFT is too big! Aborting."); 207762306a36Sopenharmony_ci goto put_err_out; 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci /* 208062306a36Sopenharmony_ci * We have got the first extent of the runlist for 208162306a36Sopenharmony_ci * $MFT which means it is now relatively safe to call 208262306a36Sopenharmony_ci * the normal ntfs_read_inode() function. 208362306a36Sopenharmony_ci * Complete reading the inode, this will actually 208462306a36Sopenharmony_ci * re-read the mft record for $MFT, this time entering 208562306a36Sopenharmony_ci * it into the page cache with which we complete the 208662306a36Sopenharmony_ci * kick start of the volume. It should be safe to do 208762306a36Sopenharmony_ci * this now as the first extent of $MFT/$DATA is 208862306a36Sopenharmony_ci * already known and we would hope that we don't need 208962306a36Sopenharmony_ci * further extents in order to find the other 209062306a36Sopenharmony_ci * attributes belonging to $MFT. Only time will tell if 209162306a36Sopenharmony_ci * this is really the case. If not we will have to play 209262306a36Sopenharmony_ci * magic at this point, possibly duplicating a lot of 209362306a36Sopenharmony_ci * ntfs_read_inode() at this point. We will need to 209462306a36Sopenharmony_ci * ensure we do enough of its work to be able to call 209562306a36Sopenharmony_ci * ntfs_read_inode() on extents of $MFT/$DATA. But lets 209662306a36Sopenharmony_ci * hope this never happens... 209762306a36Sopenharmony_ci */ 209862306a36Sopenharmony_ci ntfs_read_locked_inode(vi); 209962306a36Sopenharmony_ci if (is_bad_inode(vi)) { 210062306a36Sopenharmony_ci ntfs_error(sb, "ntfs_read_inode() of $MFT " 210162306a36Sopenharmony_ci "failed. BUG or corrupt $MFT. " 210262306a36Sopenharmony_ci "Run chkdsk and if no errors " 210362306a36Sopenharmony_ci "are found, please report you " 210462306a36Sopenharmony_ci "saw this message to " 210562306a36Sopenharmony_ci "linux-ntfs-dev@lists." 210662306a36Sopenharmony_ci "sourceforge.net"); 210762306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 210862306a36Sopenharmony_ci /* Revert to the safe super operations. */ 210962306a36Sopenharmony_ci ntfs_free(m); 211062306a36Sopenharmony_ci return -1; 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci /* 211362306a36Sopenharmony_ci * Re-initialize some specifics about $MFT's inode as 211462306a36Sopenharmony_ci * ntfs_read_inode() will have set up the default ones. 211562306a36Sopenharmony_ci */ 211662306a36Sopenharmony_ci /* Set uid and gid to root. */ 211762306a36Sopenharmony_ci vi->i_uid = GLOBAL_ROOT_UID; 211862306a36Sopenharmony_ci vi->i_gid = GLOBAL_ROOT_GID; 211962306a36Sopenharmony_ci /* Regular file. No access for anyone. */ 212062306a36Sopenharmony_ci vi->i_mode = S_IFREG; 212162306a36Sopenharmony_ci /* No VFS initiated operations allowed for $MFT. */ 212262306a36Sopenharmony_ci vi->i_op = &ntfs_empty_inode_ops; 212362306a36Sopenharmony_ci vi->i_fop = &ntfs_empty_file_ops; 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci /* Get the lowest vcn for the next extent. */ 212762306a36Sopenharmony_ci highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); 212862306a36Sopenharmony_ci next_vcn = highest_vcn + 1; 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_ci /* Only one extent or error, which we catch below. */ 213162306a36Sopenharmony_ci if (next_vcn <= 0) 213262306a36Sopenharmony_ci break; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci /* Avoid endless loops due to corruption. */ 213562306a36Sopenharmony_ci if (next_vcn < sle64_to_cpu( 213662306a36Sopenharmony_ci a->data.non_resident.lowest_vcn)) { 213762306a36Sopenharmony_ci ntfs_error(sb, "$MFT has corrupt attribute list " 213862306a36Sopenharmony_ci "attribute. Run chkdsk."); 213962306a36Sopenharmony_ci goto put_err_out; 214062306a36Sopenharmony_ci } 214162306a36Sopenharmony_ci } 214262306a36Sopenharmony_ci if (err != -ENOENT) { 214362306a36Sopenharmony_ci ntfs_error(sb, "Failed to lookup $MFT/$DATA attribute extent. " 214462306a36Sopenharmony_ci "$MFT is corrupt. Run chkdsk."); 214562306a36Sopenharmony_ci goto put_err_out; 214662306a36Sopenharmony_ci } 214762306a36Sopenharmony_ci if (!a) { 214862306a36Sopenharmony_ci ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is " 214962306a36Sopenharmony_ci "corrupt. Run chkdsk."); 215062306a36Sopenharmony_ci goto put_err_out; 215162306a36Sopenharmony_ci } 215262306a36Sopenharmony_ci if (highest_vcn && highest_vcn != last_vcn - 1) { 215362306a36Sopenharmony_ci ntfs_error(sb, "Failed to load the complete runlist for " 215462306a36Sopenharmony_ci "$MFT/$DATA. Driver bug or corrupt $MFT. " 215562306a36Sopenharmony_ci "Run chkdsk."); 215662306a36Sopenharmony_ci ntfs_debug("highest_vcn = 0x%llx, last_vcn - 1 = 0x%llx", 215762306a36Sopenharmony_ci (unsigned long long)highest_vcn, 215862306a36Sopenharmony_ci (unsigned long long)last_vcn - 1); 215962306a36Sopenharmony_ci goto put_err_out; 216062306a36Sopenharmony_ci } 216162306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 216262306a36Sopenharmony_ci ntfs_debug("Done."); 216362306a36Sopenharmony_ci ntfs_free(m); 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci /* 216662306a36Sopenharmony_ci * Split the locking rules of the MFT inode from the 216762306a36Sopenharmony_ci * locking rules of other inodes: 216862306a36Sopenharmony_ci */ 216962306a36Sopenharmony_ci lockdep_set_class(&ni->runlist.lock, &mft_ni_runlist_lock_key); 217062306a36Sopenharmony_ci lockdep_set_class(&ni->mrec_lock, &mft_ni_mrec_lock_key); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci return 0; 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ciem_put_err_out: 217562306a36Sopenharmony_ci ntfs_error(sb, "Couldn't find first extent of $DATA attribute in " 217662306a36Sopenharmony_ci "attribute list. $MFT is corrupt. Run chkdsk."); 217762306a36Sopenharmony_ciput_err_out: 217862306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 217962306a36Sopenharmony_cierr_out: 218062306a36Sopenharmony_ci ntfs_error(sb, "Failed. Marking inode as bad."); 218162306a36Sopenharmony_ci make_bad_inode(vi); 218262306a36Sopenharmony_ci ntfs_free(m); 218362306a36Sopenharmony_ci return -1; 218462306a36Sopenharmony_ci} 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_cistatic void __ntfs_clear_inode(ntfs_inode *ni) 218762306a36Sopenharmony_ci{ 218862306a36Sopenharmony_ci /* Free all alocated memory. */ 218962306a36Sopenharmony_ci down_write(&ni->runlist.lock); 219062306a36Sopenharmony_ci if (ni->runlist.rl) { 219162306a36Sopenharmony_ci ntfs_free(ni->runlist.rl); 219262306a36Sopenharmony_ci ni->runlist.rl = NULL; 219362306a36Sopenharmony_ci } 219462306a36Sopenharmony_ci up_write(&ni->runlist.lock); 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci if (ni->attr_list) { 219762306a36Sopenharmony_ci ntfs_free(ni->attr_list); 219862306a36Sopenharmony_ci ni->attr_list = NULL; 219962306a36Sopenharmony_ci } 220062306a36Sopenharmony_ci 220162306a36Sopenharmony_ci down_write(&ni->attr_list_rl.lock); 220262306a36Sopenharmony_ci if (ni->attr_list_rl.rl) { 220362306a36Sopenharmony_ci ntfs_free(ni->attr_list_rl.rl); 220462306a36Sopenharmony_ci ni->attr_list_rl.rl = NULL; 220562306a36Sopenharmony_ci } 220662306a36Sopenharmony_ci up_write(&ni->attr_list_rl.lock); 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci if (ni->name_len && ni->name != I30) { 220962306a36Sopenharmony_ci /* Catch bugs... */ 221062306a36Sopenharmony_ci BUG_ON(!ni->name); 221162306a36Sopenharmony_ci kfree(ni->name); 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci} 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_civoid ntfs_clear_extent_inode(ntfs_inode *ni) 221662306a36Sopenharmony_ci{ 221762306a36Sopenharmony_ci ntfs_debug("Entering for inode 0x%lx.", ni->mft_no); 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci BUG_ON(NInoAttr(ni)); 222062306a36Sopenharmony_ci BUG_ON(ni->nr_extents != -1); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci#ifdef NTFS_RW 222362306a36Sopenharmony_ci if (NInoDirty(ni)) { 222462306a36Sopenharmony_ci if (!is_bad_inode(VFS_I(ni->ext.base_ntfs_ino))) 222562306a36Sopenharmony_ci ntfs_error(ni->vol->sb, "Clearing dirty extent inode! " 222662306a36Sopenharmony_ci "Losing data! This is a BUG!!!"); 222762306a36Sopenharmony_ci // FIXME: Do something!!! 222862306a36Sopenharmony_ci } 222962306a36Sopenharmony_ci#endif /* NTFS_RW */ 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci __ntfs_clear_inode(ni); 223262306a36Sopenharmony_ci 223362306a36Sopenharmony_ci /* Bye, bye... */ 223462306a36Sopenharmony_ci ntfs_destroy_extent_inode(ni); 223562306a36Sopenharmony_ci} 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci/** 223862306a36Sopenharmony_ci * ntfs_evict_big_inode - clean up the ntfs specific part of an inode 223962306a36Sopenharmony_ci * @vi: vfs inode pending annihilation 224062306a36Sopenharmony_ci * 224162306a36Sopenharmony_ci * When the VFS is going to remove an inode from memory, ntfs_clear_big_inode() 224262306a36Sopenharmony_ci * is called, which deallocates all memory belonging to the NTFS specific part 224362306a36Sopenharmony_ci * of the inode and returns. 224462306a36Sopenharmony_ci * 224562306a36Sopenharmony_ci * If the MFT record is dirty, we commit it before doing anything else. 224662306a36Sopenharmony_ci */ 224762306a36Sopenharmony_civoid ntfs_evict_big_inode(struct inode *vi) 224862306a36Sopenharmony_ci{ 224962306a36Sopenharmony_ci ntfs_inode *ni = NTFS_I(vi); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci truncate_inode_pages_final(&vi->i_data); 225262306a36Sopenharmony_ci clear_inode(vi); 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci#ifdef NTFS_RW 225562306a36Sopenharmony_ci if (NInoDirty(ni)) { 225662306a36Sopenharmony_ci bool was_bad = (is_bad_inode(vi)); 225762306a36Sopenharmony_ci 225862306a36Sopenharmony_ci /* Committing the inode also commits all extent inodes. */ 225962306a36Sopenharmony_ci ntfs_commit_inode(vi); 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_ci if (!was_bad && (is_bad_inode(vi) || NInoDirty(ni))) { 226262306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to commit dirty inode " 226362306a36Sopenharmony_ci "0x%lx. Losing data!", vi->i_ino); 226462306a36Sopenharmony_ci // FIXME: Do something!!! 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci#endif /* NTFS_RW */ 226862306a36Sopenharmony_ci 226962306a36Sopenharmony_ci /* No need to lock at this stage as no one else has a reference. */ 227062306a36Sopenharmony_ci if (ni->nr_extents > 0) { 227162306a36Sopenharmony_ci int i; 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci for (i = 0; i < ni->nr_extents; i++) 227462306a36Sopenharmony_ci ntfs_clear_extent_inode(ni->ext.extent_ntfs_inos[i]); 227562306a36Sopenharmony_ci kfree(ni->ext.extent_ntfs_inos); 227662306a36Sopenharmony_ci } 227762306a36Sopenharmony_ci 227862306a36Sopenharmony_ci __ntfs_clear_inode(ni); 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_ci if (NInoAttr(ni)) { 228162306a36Sopenharmony_ci /* Release the base inode if we are holding it. */ 228262306a36Sopenharmony_ci if (ni->nr_extents == -1) { 228362306a36Sopenharmony_ci iput(VFS_I(ni->ext.base_ntfs_ino)); 228462306a36Sopenharmony_ci ni->nr_extents = 0; 228562306a36Sopenharmony_ci ni->ext.base_ntfs_ino = NULL; 228662306a36Sopenharmony_ci } 228762306a36Sopenharmony_ci } 228862306a36Sopenharmony_ci BUG_ON(ni->page); 228962306a36Sopenharmony_ci if (!atomic_dec_and_test(&ni->count)) 229062306a36Sopenharmony_ci BUG(); 229162306a36Sopenharmony_ci return; 229262306a36Sopenharmony_ci} 229362306a36Sopenharmony_ci 229462306a36Sopenharmony_ci/** 229562306a36Sopenharmony_ci * ntfs_show_options - show mount options in /proc/mounts 229662306a36Sopenharmony_ci * @sf: seq_file in which to write our mount options 229762306a36Sopenharmony_ci * @root: root of the mounted tree whose mount options to display 229862306a36Sopenharmony_ci * 229962306a36Sopenharmony_ci * Called by the VFS once for each mounted ntfs volume when someone reads 230062306a36Sopenharmony_ci * /proc/mounts in order to display the NTFS specific mount options of each 230162306a36Sopenharmony_ci * mount. The mount options of fs specified by @root are written to the seq file 230262306a36Sopenharmony_ci * @sf and success is returned. 230362306a36Sopenharmony_ci */ 230462306a36Sopenharmony_ciint ntfs_show_options(struct seq_file *sf, struct dentry *root) 230562306a36Sopenharmony_ci{ 230662306a36Sopenharmony_ci ntfs_volume *vol = NTFS_SB(root->d_sb); 230762306a36Sopenharmony_ci int i; 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci seq_printf(sf, ",uid=%i", from_kuid_munged(&init_user_ns, vol->uid)); 231062306a36Sopenharmony_ci seq_printf(sf, ",gid=%i", from_kgid_munged(&init_user_ns, vol->gid)); 231162306a36Sopenharmony_ci if (vol->fmask == vol->dmask) 231262306a36Sopenharmony_ci seq_printf(sf, ",umask=0%o", vol->fmask); 231362306a36Sopenharmony_ci else { 231462306a36Sopenharmony_ci seq_printf(sf, ",fmask=0%o", vol->fmask); 231562306a36Sopenharmony_ci seq_printf(sf, ",dmask=0%o", vol->dmask); 231662306a36Sopenharmony_ci } 231762306a36Sopenharmony_ci seq_printf(sf, ",nls=%s", vol->nls_map->charset); 231862306a36Sopenharmony_ci if (NVolCaseSensitive(vol)) 231962306a36Sopenharmony_ci seq_printf(sf, ",case_sensitive"); 232062306a36Sopenharmony_ci if (NVolShowSystemFiles(vol)) 232162306a36Sopenharmony_ci seq_printf(sf, ",show_sys_files"); 232262306a36Sopenharmony_ci if (!NVolSparseEnabled(vol)) 232362306a36Sopenharmony_ci seq_printf(sf, ",disable_sparse"); 232462306a36Sopenharmony_ci for (i = 0; on_errors_arr[i].val; i++) { 232562306a36Sopenharmony_ci if (on_errors_arr[i].val & vol->on_errors) 232662306a36Sopenharmony_ci seq_printf(sf, ",errors=%s", on_errors_arr[i].str); 232762306a36Sopenharmony_ci } 232862306a36Sopenharmony_ci seq_printf(sf, ",mft_zone_multiplier=%i", vol->mft_zone_multiplier); 232962306a36Sopenharmony_ci return 0; 233062306a36Sopenharmony_ci} 233162306a36Sopenharmony_ci 233262306a36Sopenharmony_ci#ifdef NTFS_RW 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_cistatic const char *es = " Leaving inconsistent metadata. Unmount and run " 233562306a36Sopenharmony_ci "chkdsk."; 233662306a36Sopenharmony_ci 233762306a36Sopenharmony_ci/** 233862306a36Sopenharmony_ci * ntfs_truncate - called when the i_size of an ntfs inode is changed 233962306a36Sopenharmony_ci * @vi: inode for which the i_size was changed 234062306a36Sopenharmony_ci * 234162306a36Sopenharmony_ci * We only support i_size changes for normal files at present, i.e. not 234262306a36Sopenharmony_ci * compressed and not encrypted. This is enforced in ntfs_setattr(), see 234362306a36Sopenharmony_ci * below. 234462306a36Sopenharmony_ci * 234562306a36Sopenharmony_ci * The kernel guarantees that @vi is a regular file (S_ISREG() is true) and 234662306a36Sopenharmony_ci * that the change is allowed. 234762306a36Sopenharmony_ci * 234862306a36Sopenharmony_ci * This implies for us that @vi is a file inode rather than a directory, index, 234962306a36Sopenharmony_ci * or attribute inode as well as that @vi is a base inode. 235062306a36Sopenharmony_ci * 235162306a36Sopenharmony_ci * Returns 0 on success or -errno on error. 235262306a36Sopenharmony_ci * 235362306a36Sopenharmony_ci * Called with ->i_mutex held. 235462306a36Sopenharmony_ci */ 235562306a36Sopenharmony_ciint ntfs_truncate(struct inode *vi) 235662306a36Sopenharmony_ci{ 235762306a36Sopenharmony_ci s64 new_size, old_size, nr_freed, new_alloc_size, old_alloc_size; 235862306a36Sopenharmony_ci VCN highest_vcn; 235962306a36Sopenharmony_ci unsigned long flags; 236062306a36Sopenharmony_ci ntfs_inode *base_ni, *ni = NTFS_I(vi); 236162306a36Sopenharmony_ci ntfs_volume *vol = ni->vol; 236262306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 236362306a36Sopenharmony_ci MFT_RECORD *m; 236462306a36Sopenharmony_ci ATTR_RECORD *a; 236562306a36Sopenharmony_ci const char *te = " Leaving file length out of sync with i_size."; 236662306a36Sopenharmony_ci int err, mp_size, size_change, alloc_change; 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci ntfs_debug("Entering for inode 0x%lx.", vi->i_ino); 236962306a36Sopenharmony_ci BUG_ON(NInoAttr(ni)); 237062306a36Sopenharmony_ci BUG_ON(S_ISDIR(vi->i_mode)); 237162306a36Sopenharmony_ci BUG_ON(NInoMstProtected(ni)); 237262306a36Sopenharmony_ci BUG_ON(ni->nr_extents < 0); 237362306a36Sopenharmony_ciretry_truncate: 237462306a36Sopenharmony_ci /* 237562306a36Sopenharmony_ci * Lock the runlist for writing and map the mft record to ensure it is 237662306a36Sopenharmony_ci * safe to mess with the attribute runlist and sizes. 237762306a36Sopenharmony_ci */ 237862306a36Sopenharmony_ci down_write(&ni->runlist.lock); 237962306a36Sopenharmony_ci if (!NInoAttr(ni)) 238062306a36Sopenharmony_ci base_ni = ni; 238162306a36Sopenharmony_ci else 238262306a36Sopenharmony_ci base_ni = ni->ext.base_ntfs_ino; 238362306a36Sopenharmony_ci m = map_mft_record(base_ni); 238462306a36Sopenharmony_ci if (IS_ERR(m)) { 238562306a36Sopenharmony_ci err = PTR_ERR(m); 238662306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to map mft record for inode 0x%lx " 238762306a36Sopenharmony_ci "(error code %d).%s", vi->i_ino, err, te); 238862306a36Sopenharmony_ci ctx = NULL; 238962306a36Sopenharmony_ci m = NULL; 239062306a36Sopenharmony_ci goto old_bad_out; 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(base_ni, m); 239362306a36Sopenharmony_ci if (unlikely(!ctx)) { 239462306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to allocate a search context for " 239562306a36Sopenharmony_ci "inode 0x%lx (not enough memory).%s", 239662306a36Sopenharmony_ci vi->i_ino, te); 239762306a36Sopenharmony_ci err = -ENOMEM; 239862306a36Sopenharmony_ci goto old_bad_out; 239962306a36Sopenharmony_ci } 240062306a36Sopenharmony_ci err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 240162306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 240262306a36Sopenharmony_ci if (unlikely(err)) { 240362306a36Sopenharmony_ci if (err == -ENOENT) { 240462306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Open attribute is missing from " 240562306a36Sopenharmony_ci "mft record. Inode 0x%lx is corrupt. " 240662306a36Sopenharmony_ci "Run chkdsk.%s", vi->i_ino, te); 240762306a36Sopenharmony_ci err = -EIO; 240862306a36Sopenharmony_ci } else 240962306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed to lookup attribute in " 241062306a36Sopenharmony_ci "inode 0x%lx (error code %d).%s", 241162306a36Sopenharmony_ci vi->i_ino, err, te); 241262306a36Sopenharmony_ci goto old_bad_out; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci m = ctx->mrec; 241562306a36Sopenharmony_ci a = ctx->attr; 241662306a36Sopenharmony_ci /* 241762306a36Sopenharmony_ci * The i_size of the vfs inode is the new size for the attribute value. 241862306a36Sopenharmony_ci */ 241962306a36Sopenharmony_ci new_size = i_size_read(vi); 242062306a36Sopenharmony_ci /* The current size of the attribute value is the old size. */ 242162306a36Sopenharmony_ci old_size = ntfs_attr_size(a); 242262306a36Sopenharmony_ci /* Calculate the new allocated size. */ 242362306a36Sopenharmony_ci if (NInoNonResident(ni)) 242462306a36Sopenharmony_ci new_alloc_size = (new_size + vol->cluster_size - 1) & 242562306a36Sopenharmony_ci ~(s64)vol->cluster_size_mask; 242662306a36Sopenharmony_ci else 242762306a36Sopenharmony_ci new_alloc_size = (new_size + 7) & ~7; 242862306a36Sopenharmony_ci /* The current allocated size is the old allocated size. */ 242962306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 243062306a36Sopenharmony_ci old_alloc_size = ni->allocated_size; 243162306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 243262306a36Sopenharmony_ci /* 243362306a36Sopenharmony_ci * The change in the file size. This will be 0 if no change, >0 if the 243462306a36Sopenharmony_ci * size is growing, and <0 if the size is shrinking. 243562306a36Sopenharmony_ci */ 243662306a36Sopenharmony_ci size_change = -1; 243762306a36Sopenharmony_ci if (new_size - old_size >= 0) { 243862306a36Sopenharmony_ci size_change = 1; 243962306a36Sopenharmony_ci if (new_size == old_size) 244062306a36Sopenharmony_ci size_change = 0; 244162306a36Sopenharmony_ci } 244262306a36Sopenharmony_ci /* As above for the allocated size. */ 244362306a36Sopenharmony_ci alloc_change = -1; 244462306a36Sopenharmony_ci if (new_alloc_size - old_alloc_size >= 0) { 244562306a36Sopenharmony_ci alloc_change = 1; 244662306a36Sopenharmony_ci if (new_alloc_size == old_alloc_size) 244762306a36Sopenharmony_ci alloc_change = 0; 244862306a36Sopenharmony_ci } 244962306a36Sopenharmony_ci /* 245062306a36Sopenharmony_ci * If neither the size nor the allocation are being changed there is 245162306a36Sopenharmony_ci * nothing to do. 245262306a36Sopenharmony_ci */ 245362306a36Sopenharmony_ci if (!size_change && !alloc_change) 245462306a36Sopenharmony_ci goto unm_done; 245562306a36Sopenharmony_ci /* If the size is changing, check if new size is allowed in $AttrDef. */ 245662306a36Sopenharmony_ci if (size_change) { 245762306a36Sopenharmony_ci err = ntfs_attr_size_bounds_check(vol, ni->type, new_size); 245862306a36Sopenharmony_ci if (unlikely(err)) { 245962306a36Sopenharmony_ci if (err == -ERANGE) { 246062306a36Sopenharmony_ci ntfs_error(vol->sb, "Truncate would cause the " 246162306a36Sopenharmony_ci "inode 0x%lx to %simum size " 246262306a36Sopenharmony_ci "for its attribute type " 246362306a36Sopenharmony_ci "(0x%x). Aborting truncate.", 246462306a36Sopenharmony_ci vi->i_ino, 246562306a36Sopenharmony_ci new_size > old_size ? "exceed " 246662306a36Sopenharmony_ci "the max" : "go under the min", 246762306a36Sopenharmony_ci le32_to_cpu(ni->type)); 246862306a36Sopenharmony_ci err = -EFBIG; 246962306a36Sopenharmony_ci } else { 247062306a36Sopenharmony_ci ntfs_error(vol->sb, "Inode 0x%lx has unknown " 247162306a36Sopenharmony_ci "attribute type 0x%x. " 247262306a36Sopenharmony_ci "Aborting truncate.", 247362306a36Sopenharmony_ci vi->i_ino, 247462306a36Sopenharmony_ci le32_to_cpu(ni->type)); 247562306a36Sopenharmony_ci err = -EIO; 247662306a36Sopenharmony_ci } 247762306a36Sopenharmony_ci /* Reset the vfs inode size to the old size. */ 247862306a36Sopenharmony_ci i_size_write(vi, old_size); 247962306a36Sopenharmony_ci goto err_out; 248062306a36Sopenharmony_ci } 248162306a36Sopenharmony_ci } 248262306a36Sopenharmony_ci if (NInoCompressed(ni) || NInoEncrypted(ni)) { 248362306a36Sopenharmony_ci ntfs_warning(vi->i_sb, "Changes in inode size are not " 248462306a36Sopenharmony_ci "supported yet for %s files, ignoring.", 248562306a36Sopenharmony_ci NInoCompressed(ni) ? "compressed" : 248662306a36Sopenharmony_ci "encrypted"); 248762306a36Sopenharmony_ci err = -EOPNOTSUPP; 248862306a36Sopenharmony_ci goto bad_out; 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci if (a->non_resident) 249162306a36Sopenharmony_ci goto do_non_resident_truncate; 249262306a36Sopenharmony_ci BUG_ON(NInoNonResident(ni)); 249362306a36Sopenharmony_ci /* Resize the attribute record to best fit the new attribute size. */ 249462306a36Sopenharmony_ci if (new_size < vol->mft_record_size && 249562306a36Sopenharmony_ci !ntfs_resident_attr_value_resize(m, a, new_size)) { 249662306a36Sopenharmony_ci /* The resize succeeded! */ 249762306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 249862306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 249962306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 250062306a36Sopenharmony_ci /* Update the sizes in the ntfs inode and all is done. */ 250162306a36Sopenharmony_ci ni->allocated_size = le32_to_cpu(a->length) - 250262306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset); 250362306a36Sopenharmony_ci /* 250462306a36Sopenharmony_ci * Note ntfs_resident_attr_value_resize() has already done any 250562306a36Sopenharmony_ci * necessary data clearing in the attribute record. When the 250662306a36Sopenharmony_ci * file is being shrunk vmtruncate() will already have cleared 250762306a36Sopenharmony_ci * the top part of the last partial page, i.e. since this is 250862306a36Sopenharmony_ci * the resident case this is the page with index 0. However, 250962306a36Sopenharmony_ci * when the file is being expanded, the page cache page data 251062306a36Sopenharmony_ci * between the old data_size, i.e. old_size, and the new_size 251162306a36Sopenharmony_ci * has not been zeroed. Fortunately, we do not need to zero it 251262306a36Sopenharmony_ci * either since on one hand it will either already be zero due 251362306a36Sopenharmony_ci * to both read_folio and writepage clearing partial page data 251462306a36Sopenharmony_ci * beyond i_size in which case there is nothing to do or in the 251562306a36Sopenharmony_ci * case of the file being mmap()ped at the same time, POSIX 251662306a36Sopenharmony_ci * specifies that the behaviour is unspecified thus we do not 251762306a36Sopenharmony_ci * have to do anything. This means that in our implementation 251862306a36Sopenharmony_ci * in the rare case that the file is mmap()ped and a write 251962306a36Sopenharmony_ci * occurred into the mmap()ped region just beyond the file size 252062306a36Sopenharmony_ci * and writepage has not yet been called to write out the page 252162306a36Sopenharmony_ci * (which would clear the area beyond the file size) and we now 252262306a36Sopenharmony_ci * extend the file size to incorporate this dirty region 252362306a36Sopenharmony_ci * outside the file size, a write of the page would result in 252462306a36Sopenharmony_ci * this data being written to disk instead of being cleared. 252562306a36Sopenharmony_ci * Given both POSIX and the Linux mmap(2) man page specify that 252662306a36Sopenharmony_ci * this corner case is undefined, we choose to leave it like 252762306a36Sopenharmony_ci * that as this is much simpler for us as we cannot lock the 252862306a36Sopenharmony_ci * relevant page now since we are holding too many ntfs locks 252962306a36Sopenharmony_ci * which would result in a lock reversal deadlock. 253062306a36Sopenharmony_ci */ 253162306a36Sopenharmony_ci ni->initialized_size = new_size; 253262306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 253362306a36Sopenharmony_ci goto unm_done; 253462306a36Sopenharmony_ci } 253562306a36Sopenharmony_ci /* If the above resize failed, this must be an attribute extension. */ 253662306a36Sopenharmony_ci BUG_ON(size_change < 0); 253762306a36Sopenharmony_ci /* 253862306a36Sopenharmony_ci * We have to drop all the locks so we can call 253962306a36Sopenharmony_ci * ntfs_attr_make_non_resident(). This could be optimised by try- 254062306a36Sopenharmony_ci * locking the first page cache page and only if that fails dropping 254162306a36Sopenharmony_ci * the locks, locking the page, and redoing all the locking and 254262306a36Sopenharmony_ci * lookups. While this would be a huge optimisation, it is not worth 254362306a36Sopenharmony_ci * it as this is definitely a slow code path as it only ever can happen 254462306a36Sopenharmony_ci * once for any given file. 254562306a36Sopenharmony_ci */ 254662306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 254762306a36Sopenharmony_ci unmap_mft_record(base_ni); 254862306a36Sopenharmony_ci up_write(&ni->runlist.lock); 254962306a36Sopenharmony_ci /* 255062306a36Sopenharmony_ci * Not enough space in the mft record, try to make the attribute 255162306a36Sopenharmony_ci * non-resident and if successful restart the truncation process. 255262306a36Sopenharmony_ci */ 255362306a36Sopenharmony_ci err = ntfs_attr_make_non_resident(ni, old_size); 255462306a36Sopenharmony_ci if (likely(!err)) 255562306a36Sopenharmony_ci goto retry_truncate; 255662306a36Sopenharmony_ci /* 255762306a36Sopenharmony_ci * Could not make non-resident. If this is due to this not being 255862306a36Sopenharmony_ci * permitted for this attribute type or there not being enough space, 255962306a36Sopenharmony_ci * try to make other attributes non-resident. Otherwise fail. 256062306a36Sopenharmony_ci */ 256162306a36Sopenharmony_ci if (unlikely(err != -EPERM && err != -ENOSPC)) { 256262306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, attribute " 256362306a36Sopenharmony_ci "type 0x%x, because the conversion from " 256462306a36Sopenharmony_ci "resident to non-resident attribute failed " 256562306a36Sopenharmony_ci "with error code %i.", vi->i_ino, 256662306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), err); 256762306a36Sopenharmony_ci if (err != -ENOMEM) 256862306a36Sopenharmony_ci err = -EIO; 256962306a36Sopenharmony_ci goto conv_err_out; 257062306a36Sopenharmony_ci } 257162306a36Sopenharmony_ci /* TODO: Not implemented from here, abort. */ 257262306a36Sopenharmony_ci if (err == -ENOSPC) 257362306a36Sopenharmony_ci ntfs_error(vol->sb, "Not enough space in the mft record/on " 257462306a36Sopenharmony_ci "disk for the non-resident attribute value. " 257562306a36Sopenharmony_ci "This case is not implemented yet."); 257662306a36Sopenharmony_ci else /* if (err == -EPERM) */ 257762306a36Sopenharmony_ci ntfs_error(vol->sb, "This attribute type may not be " 257862306a36Sopenharmony_ci "non-resident. This case is not implemented " 257962306a36Sopenharmony_ci "yet."); 258062306a36Sopenharmony_ci err = -EOPNOTSUPP; 258162306a36Sopenharmony_ci goto conv_err_out; 258262306a36Sopenharmony_ci#if 0 258362306a36Sopenharmony_ci // TODO: Attempt to make other attributes non-resident. 258462306a36Sopenharmony_ci if (!err) 258562306a36Sopenharmony_ci goto do_resident_extend; 258662306a36Sopenharmony_ci /* 258762306a36Sopenharmony_ci * Both the attribute list attribute and the standard information 258862306a36Sopenharmony_ci * attribute must remain in the base inode. Thus, if this is one of 258962306a36Sopenharmony_ci * these attributes, we have to try to move other attributes out into 259062306a36Sopenharmony_ci * extent mft records instead. 259162306a36Sopenharmony_ci */ 259262306a36Sopenharmony_ci if (ni->type == AT_ATTRIBUTE_LIST || 259362306a36Sopenharmony_ci ni->type == AT_STANDARD_INFORMATION) { 259462306a36Sopenharmony_ci // TODO: Attempt to move other attributes into extent mft 259562306a36Sopenharmony_ci // records. 259662306a36Sopenharmony_ci err = -EOPNOTSUPP; 259762306a36Sopenharmony_ci if (!err) 259862306a36Sopenharmony_ci goto do_resident_extend; 259962306a36Sopenharmony_ci goto err_out; 260062306a36Sopenharmony_ci } 260162306a36Sopenharmony_ci // TODO: Attempt to move this attribute to an extent mft record, but 260262306a36Sopenharmony_ci // only if it is not already the only attribute in an mft record in 260362306a36Sopenharmony_ci // which case there would be nothing to gain. 260462306a36Sopenharmony_ci err = -EOPNOTSUPP; 260562306a36Sopenharmony_ci if (!err) 260662306a36Sopenharmony_ci goto do_resident_extend; 260762306a36Sopenharmony_ci /* There is nothing we can do to make enough space. )-: */ 260862306a36Sopenharmony_ci goto err_out; 260962306a36Sopenharmony_ci#endif 261062306a36Sopenharmony_cido_non_resident_truncate: 261162306a36Sopenharmony_ci BUG_ON(!NInoNonResident(ni)); 261262306a36Sopenharmony_ci if (alloc_change < 0) { 261362306a36Sopenharmony_ci highest_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); 261462306a36Sopenharmony_ci if (highest_vcn > 0 && 261562306a36Sopenharmony_ci old_alloc_size >> vol->cluster_size_bits > 261662306a36Sopenharmony_ci highest_vcn + 1) { 261762306a36Sopenharmony_ci /* 261862306a36Sopenharmony_ci * This attribute has multiple extents. Not yet 261962306a36Sopenharmony_ci * supported. 262062306a36Sopenharmony_ci */ 262162306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot truncate inode 0x%lx, " 262262306a36Sopenharmony_ci "attribute type 0x%x, because the " 262362306a36Sopenharmony_ci "attribute is highly fragmented (it " 262462306a36Sopenharmony_ci "consists of multiple extents) and " 262562306a36Sopenharmony_ci "this case is not implemented yet.", 262662306a36Sopenharmony_ci vi->i_ino, 262762306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type)); 262862306a36Sopenharmony_ci err = -EOPNOTSUPP; 262962306a36Sopenharmony_ci goto bad_out; 263062306a36Sopenharmony_ci } 263162306a36Sopenharmony_ci } 263262306a36Sopenharmony_ci /* 263362306a36Sopenharmony_ci * If the size is shrinking, need to reduce the initialized_size and 263462306a36Sopenharmony_ci * the data_size before reducing the allocation. 263562306a36Sopenharmony_ci */ 263662306a36Sopenharmony_ci if (size_change < 0) { 263762306a36Sopenharmony_ci /* 263862306a36Sopenharmony_ci * Make the valid size smaller (i_size is already up-to-date). 263962306a36Sopenharmony_ci */ 264062306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 264162306a36Sopenharmony_ci if (new_size < ni->initialized_size) { 264262306a36Sopenharmony_ci ni->initialized_size = new_size; 264362306a36Sopenharmony_ci a->data.non_resident.initialized_size = 264462306a36Sopenharmony_ci cpu_to_sle64(new_size); 264562306a36Sopenharmony_ci } 264662306a36Sopenharmony_ci a->data.non_resident.data_size = cpu_to_sle64(new_size); 264762306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 264862306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 264962306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 265062306a36Sopenharmony_ci /* If the allocated size is not changing, we are done. */ 265162306a36Sopenharmony_ci if (!alloc_change) 265262306a36Sopenharmony_ci goto unm_done; 265362306a36Sopenharmony_ci /* 265462306a36Sopenharmony_ci * If the size is shrinking it makes no sense for the 265562306a36Sopenharmony_ci * allocation to be growing. 265662306a36Sopenharmony_ci */ 265762306a36Sopenharmony_ci BUG_ON(alloc_change > 0); 265862306a36Sopenharmony_ci } else /* if (size_change >= 0) */ { 265962306a36Sopenharmony_ci /* 266062306a36Sopenharmony_ci * The file size is growing or staying the same but the 266162306a36Sopenharmony_ci * allocation can be shrinking, growing or staying the same. 266262306a36Sopenharmony_ci */ 266362306a36Sopenharmony_ci if (alloc_change > 0) { 266462306a36Sopenharmony_ci /* 266562306a36Sopenharmony_ci * We need to extend the allocation and possibly update 266662306a36Sopenharmony_ci * the data size. If we are updating the data size, 266762306a36Sopenharmony_ci * since we are not touching the initialized_size we do 266862306a36Sopenharmony_ci * not need to worry about the actual data on disk. 266962306a36Sopenharmony_ci * And as far as the page cache is concerned, there 267062306a36Sopenharmony_ci * will be no pages beyond the old data size and any 267162306a36Sopenharmony_ci * partial region in the last page between the old and 267262306a36Sopenharmony_ci * new data size (or the end of the page if the new 267362306a36Sopenharmony_ci * data size is outside the page) does not need to be 267462306a36Sopenharmony_ci * modified as explained above for the resident 267562306a36Sopenharmony_ci * attribute truncate case. To do this, we simply drop 267662306a36Sopenharmony_ci * the locks we hold and leave all the work to our 267762306a36Sopenharmony_ci * friendly helper ntfs_attr_extend_allocation(). 267862306a36Sopenharmony_ci */ 267962306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 268062306a36Sopenharmony_ci unmap_mft_record(base_ni); 268162306a36Sopenharmony_ci up_write(&ni->runlist.lock); 268262306a36Sopenharmony_ci err = ntfs_attr_extend_allocation(ni, new_size, 268362306a36Sopenharmony_ci size_change > 0 ? new_size : -1, -1); 268462306a36Sopenharmony_ci /* 268562306a36Sopenharmony_ci * ntfs_attr_extend_allocation() will have done error 268662306a36Sopenharmony_ci * output already. 268762306a36Sopenharmony_ci */ 268862306a36Sopenharmony_ci goto done; 268962306a36Sopenharmony_ci } 269062306a36Sopenharmony_ci if (!alloc_change) 269162306a36Sopenharmony_ci goto alloc_done; 269262306a36Sopenharmony_ci } 269362306a36Sopenharmony_ci /* alloc_change < 0 */ 269462306a36Sopenharmony_ci /* Free the clusters. */ 269562306a36Sopenharmony_ci nr_freed = ntfs_cluster_free(ni, new_alloc_size >> 269662306a36Sopenharmony_ci vol->cluster_size_bits, -1, ctx); 269762306a36Sopenharmony_ci m = ctx->mrec; 269862306a36Sopenharmony_ci a = ctx->attr; 269962306a36Sopenharmony_ci if (unlikely(nr_freed < 0)) { 270062306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to release cluster(s) (error code " 270162306a36Sopenharmony_ci "%lli). Unmount and run chkdsk to recover " 270262306a36Sopenharmony_ci "the lost cluster(s).", (long long)nr_freed); 270362306a36Sopenharmony_ci NVolSetErrors(vol); 270462306a36Sopenharmony_ci nr_freed = 0; 270562306a36Sopenharmony_ci } 270662306a36Sopenharmony_ci /* Truncate the runlist. */ 270762306a36Sopenharmony_ci err = ntfs_rl_truncate_nolock(vol, &ni->runlist, 270862306a36Sopenharmony_ci new_alloc_size >> vol->cluster_size_bits); 270962306a36Sopenharmony_ci /* 271062306a36Sopenharmony_ci * If the runlist truncation failed and/or the search context is no 271162306a36Sopenharmony_ci * longer valid, we cannot resize the attribute record or build the 271262306a36Sopenharmony_ci * mapping pairs array thus we mark the inode bad so that no access to 271362306a36Sopenharmony_ci * the freed clusters can happen. 271462306a36Sopenharmony_ci */ 271562306a36Sopenharmony_ci if (unlikely(err || IS_ERR(m))) { 271662306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to %s (error code %li).%s", 271762306a36Sopenharmony_ci IS_ERR(m) ? 271862306a36Sopenharmony_ci "restore attribute search context" : 271962306a36Sopenharmony_ci "truncate attribute runlist", 272062306a36Sopenharmony_ci IS_ERR(m) ? PTR_ERR(m) : err, es); 272162306a36Sopenharmony_ci err = -EIO; 272262306a36Sopenharmony_ci goto bad_out; 272362306a36Sopenharmony_ci } 272462306a36Sopenharmony_ci /* Get the size for the shrunk mapping pairs array for the runlist. */ 272562306a36Sopenharmony_ci mp_size = ntfs_get_size_for_mapping_pairs(vol, ni->runlist.rl, 0, -1); 272662306a36Sopenharmony_ci if (unlikely(mp_size <= 0)) { 272762306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " 272862306a36Sopenharmony_ci "attribute type 0x%x, because determining the " 272962306a36Sopenharmony_ci "size for the mapping pairs failed with error " 273062306a36Sopenharmony_ci "code %i.%s", vi->i_ino, 273162306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), mp_size, es); 273262306a36Sopenharmony_ci err = -EIO; 273362306a36Sopenharmony_ci goto bad_out; 273462306a36Sopenharmony_ci } 273562306a36Sopenharmony_ci /* 273662306a36Sopenharmony_ci * Shrink the attribute record for the new mapping pairs array. Note, 273762306a36Sopenharmony_ci * this cannot fail since we are making the attribute smaller thus by 273862306a36Sopenharmony_ci * definition there is enough space to do so. 273962306a36Sopenharmony_ci */ 274062306a36Sopenharmony_ci err = ntfs_attr_record_resize(m, a, mp_size + 274162306a36Sopenharmony_ci le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); 274262306a36Sopenharmony_ci BUG_ON(err); 274362306a36Sopenharmony_ci /* 274462306a36Sopenharmony_ci * Generate the mapping pairs array directly into the attribute record. 274562306a36Sopenharmony_ci */ 274662306a36Sopenharmony_ci err = ntfs_mapping_pairs_build(vol, (u8*)a + 274762306a36Sopenharmony_ci le16_to_cpu(a->data.non_resident.mapping_pairs_offset), 274862306a36Sopenharmony_ci mp_size, ni->runlist.rl, 0, -1, NULL); 274962306a36Sopenharmony_ci if (unlikely(err)) { 275062306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot shrink allocation of inode 0x%lx, " 275162306a36Sopenharmony_ci "attribute type 0x%x, because building the " 275262306a36Sopenharmony_ci "mapping pairs failed with error code %i.%s", 275362306a36Sopenharmony_ci vi->i_ino, (unsigned)le32_to_cpu(ni->type), 275462306a36Sopenharmony_ci err, es); 275562306a36Sopenharmony_ci err = -EIO; 275662306a36Sopenharmony_ci goto bad_out; 275762306a36Sopenharmony_ci } 275862306a36Sopenharmony_ci /* Update the allocated/compressed size as well as the highest vcn. */ 275962306a36Sopenharmony_ci a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >> 276062306a36Sopenharmony_ci vol->cluster_size_bits) - 1); 276162306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 276262306a36Sopenharmony_ci ni->allocated_size = new_alloc_size; 276362306a36Sopenharmony_ci a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size); 276462306a36Sopenharmony_ci if (NInoSparse(ni) || NInoCompressed(ni)) { 276562306a36Sopenharmony_ci if (nr_freed) { 276662306a36Sopenharmony_ci ni->itype.compressed.size -= nr_freed << 276762306a36Sopenharmony_ci vol->cluster_size_bits; 276862306a36Sopenharmony_ci BUG_ON(ni->itype.compressed.size < 0); 276962306a36Sopenharmony_ci a->data.non_resident.compressed_size = cpu_to_sle64( 277062306a36Sopenharmony_ci ni->itype.compressed.size); 277162306a36Sopenharmony_ci vi->i_blocks = ni->itype.compressed.size >> 9; 277262306a36Sopenharmony_ci } 277362306a36Sopenharmony_ci } else 277462306a36Sopenharmony_ci vi->i_blocks = new_alloc_size >> 9; 277562306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 277662306a36Sopenharmony_ci /* 277762306a36Sopenharmony_ci * We have shrunk the allocation. If this is a shrinking truncate we 277862306a36Sopenharmony_ci * have already dealt with the initialized_size and the data_size above 277962306a36Sopenharmony_ci * and we are done. If the truncate is only changing the allocation 278062306a36Sopenharmony_ci * and not the data_size, we are also done. If this is an extending 278162306a36Sopenharmony_ci * truncate, need to extend the data_size now which is ensured by the 278262306a36Sopenharmony_ci * fact that @size_change is positive. 278362306a36Sopenharmony_ci */ 278462306a36Sopenharmony_cialloc_done: 278562306a36Sopenharmony_ci /* 278662306a36Sopenharmony_ci * If the size is growing, need to update it now. If it is shrinking, 278762306a36Sopenharmony_ci * we have already updated it above (before the allocation change). 278862306a36Sopenharmony_ci */ 278962306a36Sopenharmony_ci if (size_change > 0) 279062306a36Sopenharmony_ci a->data.non_resident.data_size = cpu_to_sle64(new_size); 279162306a36Sopenharmony_ci /* Ensure the modified mft record is written out. */ 279262306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 279362306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 279462306a36Sopenharmony_ciunm_done: 279562306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 279662306a36Sopenharmony_ci unmap_mft_record(base_ni); 279762306a36Sopenharmony_ci up_write(&ni->runlist.lock); 279862306a36Sopenharmony_cidone: 279962306a36Sopenharmony_ci /* Update the mtime and ctime on the base inode. */ 280062306a36Sopenharmony_ci /* normally ->truncate shouldn't update ctime or mtime, 280162306a36Sopenharmony_ci * but ntfs did before so it got a copy & paste version 280262306a36Sopenharmony_ci * of file_update_time. one day someone should fix this 280362306a36Sopenharmony_ci * for real. 280462306a36Sopenharmony_ci */ 280562306a36Sopenharmony_ci if (!IS_NOCMTIME(VFS_I(base_ni)) && !IS_RDONLY(VFS_I(base_ni))) { 280662306a36Sopenharmony_ci struct timespec64 now = current_time(VFS_I(base_ni)); 280762306a36Sopenharmony_ci struct timespec64 ctime = inode_get_ctime(VFS_I(base_ni)); 280862306a36Sopenharmony_ci int sync_it = 0; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci if (!timespec64_equal(&VFS_I(base_ni)->i_mtime, &now) || 281162306a36Sopenharmony_ci !timespec64_equal(&ctime, &now)) 281262306a36Sopenharmony_ci sync_it = 1; 281362306a36Sopenharmony_ci inode_set_ctime_to_ts(VFS_I(base_ni), now); 281462306a36Sopenharmony_ci VFS_I(base_ni)->i_mtime = now; 281562306a36Sopenharmony_ci 281662306a36Sopenharmony_ci if (sync_it) 281762306a36Sopenharmony_ci mark_inode_dirty_sync(VFS_I(base_ni)); 281862306a36Sopenharmony_ci } 281962306a36Sopenharmony_ci 282062306a36Sopenharmony_ci if (likely(!err)) { 282162306a36Sopenharmony_ci NInoClearTruncateFailed(ni); 282262306a36Sopenharmony_ci ntfs_debug("Done."); 282362306a36Sopenharmony_ci } 282462306a36Sopenharmony_ci return err; 282562306a36Sopenharmony_ciold_bad_out: 282662306a36Sopenharmony_ci old_size = -1; 282762306a36Sopenharmony_cibad_out: 282862306a36Sopenharmony_ci if (err != -ENOMEM && err != -EOPNOTSUPP) 282962306a36Sopenharmony_ci NVolSetErrors(vol); 283062306a36Sopenharmony_ci if (err != -EOPNOTSUPP) 283162306a36Sopenharmony_ci NInoSetTruncateFailed(ni); 283262306a36Sopenharmony_ci else if (old_size >= 0) 283362306a36Sopenharmony_ci i_size_write(vi, old_size); 283462306a36Sopenharmony_cierr_out: 283562306a36Sopenharmony_ci if (ctx) 283662306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 283762306a36Sopenharmony_ci if (m) 283862306a36Sopenharmony_ci unmap_mft_record(base_ni); 283962306a36Sopenharmony_ci up_write(&ni->runlist.lock); 284062306a36Sopenharmony_ciout: 284162306a36Sopenharmony_ci ntfs_debug("Failed. Returning error code %i.", err); 284262306a36Sopenharmony_ci return err; 284362306a36Sopenharmony_ciconv_err_out: 284462306a36Sopenharmony_ci if (err != -ENOMEM && err != -EOPNOTSUPP) 284562306a36Sopenharmony_ci NVolSetErrors(vol); 284662306a36Sopenharmony_ci if (err != -EOPNOTSUPP) 284762306a36Sopenharmony_ci NInoSetTruncateFailed(ni); 284862306a36Sopenharmony_ci else 284962306a36Sopenharmony_ci i_size_write(vi, old_size); 285062306a36Sopenharmony_ci goto out; 285162306a36Sopenharmony_ci} 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci/** 285462306a36Sopenharmony_ci * ntfs_truncate_vfs - wrapper for ntfs_truncate() that has no return value 285562306a36Sopenharmony_ci * @vi: inode for which the i_size was changed 285662306a36Sopenharmony_ci * 285762306a36Sopenharmony_ci * Wrapper for ntfs_truncate() that has no return value. 285862306a36Sopenharmony_ci * 285962306a36Sopenharmony_ci * See ntfs_truncate() description above for details. 286062306a36Sopenharmony_ci */ 286162306a36Sopenharmony_ci#ifdef NTFS_RW 286262306a36Sopenharmony_civoid ntfs_truncate_vfs(struct inode *vi) { 286362306a36Sopenharmony_ci ntfs_truncate(vi); 286462306a36Sopenharmony_ci} 286562306a36Sopenharmony_ci#endif 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci/** 286862306a36Sopenharmony_ci * ntfs_setattr - called from notify_change() when an attribute is being changed 286962306a36Sopenharmony_ci * @idmap: idmap of the mount the inode was found from 287062306a36Sopenharmony_ci * @dentry: dentry whose attributes to change 287162306a36Sopenharmony_ci * @attr: structure describing the attributes and the changes 287262306a36Sopenharmony_ci * 287362306a36Sopenharmony_ci * We have to trap VFS attempts to truncate the file described by @dentry as 287462306a36Sopenharmony_ci * soon as possible, because we do not implement changes in i_size yet. So we 287562306a36Sopenharmony_ci * abort all i_size changes here. 287662306a36Sopenharmony_ci * 287762306a36Sopenharmony_ci * We also abort all changes of user, group, and mode as we do not implement 287862306a36Sopenharmony_ci * the NTFS ACLs yet. 287962306a36Sopenharmony_ci * 288062306a36Sopenharmony_ci * Called with ->i_mutex held. 288162306a36Sopenharmony_ci */ 288262306a36Sopenharmony_ciint ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry, 288362306a36Sopenharmony_ci struct iattr *attr) 288462306a36Sopenharmony_ci{ 288562306a36Sopenharmony_ci struct inode *vi = d_inode(dentry); 288662306a36Sopenharmony_ci int err; 288762306a36Sopenharmony_ci unsigned int ia_valid = attr->ia_valid; 288862306a36Sopenharmony_ci 288962306a36Sopenharmony_ci err = setattr_prepare(&nop_mnt_idmap, dentry, attr); 289062306a36Sopenharmony_ci if (err) 289162306a36Sopenharmony_ci goto out; 289262306a36Sopenharmony_ci /* We do not support NTFS ACLs yet. */ 289362306a36Sopenharmony_ci if (ia_valid & (ATTR_UID | ATTR_GID | ATTR_MODE)) { 289462306a36Sopenharmony_ci ntfs_warning(vi->i_sb, "Changes in user/group/mode are not " 289562306a36Sopenharmony_ci "supported yet, ignoring."); 289662306a36Sopenharmony_ci err = -EOPNOTSUPP; 289762306a36Sopenharmony_ci goto out; 289862306a36Sopenharmony_ci } 289962306a36Sopenharmony_ci if (ia_valid & ATTR_SIZE) { 290062306a36Sopenharmony_ci if (attr->ia_size != i_size_read(vi)) { 290162306a36Sopenharmony_ci ntfs_inode *ni = NTFS_I(vi); 290262306a36Sopenharmony_ci /* 290362306a36Sopenharmony_ci * FIXME: For now we do not support resizing of 290462306a36Sopenharmony_ci * compressed or encrypted files yet. 290562306a36Sopenharmony_ci */ 290662306a36Sopenharmony_ci if (NInoCompressed(ni) || NInoEncrypted(ni)) { 290762306a36Sopenharmony_ci ntfs_warning(vi->i_sb, "Changes in inode size " 290862306a36Sopenharmony_ci "are not supported yet for " 290962306a36Sopenharmony_ci "%s files, ignoring.", 291062306a36Sopenharmony_ci NInoCompressed(ni) ? 291162306a36Sopenharmony_ci "compressed" : "encrypted"); 291262306a36Sopenharmony_ci err = -EOPNOTSUPP; 291362306a36Sopenharmony_ci } else { 291462306a36Sopenharmony_ci truncate_setsize(vi, attr->ia_size); 291562306a36Sopenharmony_ci ntfs_truncate_vfs(vi); 291662306a36Sopenharmony_ci } 291762306a36Sopenharmony_ci if (err || ia_valid == ATTR_SIZE) 291862306a36Sopenharmony_ci goto out; 291962306a36Sopenharmony_ci } else { 292062306a36Sopenharmony_ci /* 292162306a36Sopenharmony_ci * We skipped the truncate but must still update 292262306a36Sopenharmony_ci * timestamps. 292362306a36Sopenharmony_ci */ 292462306a36Sopenharmony_ci ia_valid |= ATTR_MTIME | ATTR_CTIME; 292562306a36Sopenharmony_ci } 292662306a36Sopenharmony_ci } 292762306a36Sopenharmony_ci if (ia_valid & ATTR_ATIME) 292862306a36Sopenharmony_ci vi->i_atime = attr->ia_atime; 292962306a36Sopenharmony_ci if (ia_valid & ATTR_MTIME) 293062306a36Sopenharmony_ci vi->i_mtime = attr->ia_mtime; 293162306a36Sopenharmony_ci if (ia_valid & ATTR_CTIME) 293262306a36Sopenharmony_ci inode_set_ctime_to_ts(vi, attr->ia_ctime); 293362306a36Sopenharmony_ci mark_inode_dirty(vi); 293462306a36Sopenharmony_ciout: 293562306a36Sopenharmony_ci return err; 293662306a36Sopenharmony_ci} 293762306a36Sopenharmony_ci 293862306a36Sopenharmony_ci/** 293962306a36Sopenharmony_ci * __ntfs_write_inode - write out a dirty inode 294062306a36Sopenharmony_ci * @vi: inode to write out 294162306a36Sopenharmony_ci * @sync: if true, write out synchronously 294262306a36Sopenharmony_ci * 294362306a36Sopenharmony_ci * Write out a dirty inode to disk including any extent inodes if present. 294462306a36Sopenharmony_ci * 294562306a36Sopenharmony_ci * If @sync is true, commit the inode to disk and wait for io completion. This 294662306a36Sopenharmony_ci * is done using write_mft_record(). 294762306a36Sopenharmony_ci * 294862306a36Sopenharmony_ci * If @sync is false, just schedule the write to happen but do not wait for i/o 294962306a36Sopenharmony_ci * completion. In 2.6 kernels, scheduling usually happens just by virtue of 295062306a36Sopenharmony_ci * marking the page (and in this case mft record) dirty but we do not implement 295162306a36Sopenharmony_ci * this yet as write_mft_record() largely ignores the @sync parameter and 295262306a36Sopenharmony_ci * always performs synchronous writes. 295362306a36Sopenharmony_ci * 295462306a36Sopenharmony_ci * Return 0 on success and -errno on error. 295562306a36Sopenharmony_ci */ 295662306a36Sopenharmony_ciint __ntfs_write_inode(struct inode *vi, int sync) 295762306a36Sopenharmony_ci{ 295862306a36Sopenharmony_ci sle64 nt; 295962306a36Sopenharmony_ci ntfs_inode *ni = NTFS_I(vi); 296062306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 296162306a36Sopenharmony_ci MFT_RECORD *m; 296262306a36Sopenharmony_ci STANDARD_INFORMATION *si; 296362306a36Sopenharmony_ci int err = 0; 296462306a36Sopenharmony_ci bool modified = false; 296562306a36Sopenharmony_ci 296662306a36Sopenharmony_ci ntfs_debug("Entering for %sinode 0x%lx.", NInoAttr(ni) ? "attr " : "", 296762306a36Sopenharmony_ci vi->i_ino); 296862306a36Sopenharmony_ci /* 296962306a36Sopenharmony_ci * Dirty attribute inodes are written via their real inodes so just 297062306a36Sopenharmony_ci * clean them here. Access time updates are taken care off when the 297162306a36Sopenharmony_ci * real inode is written. 297262306a36Sopenharmony_ci */ 297362306a36Sopenharmony_ci if (NInoAttr(ni)) { 297462306a36Sopenharmony_ci NInoClearDirty(ni); 297562306a36Sopenharmony_ci ntfs_debug("Done."); 297662306a36Sopenharmony_ci return 0; 297762306a36Sopenharmony_ci } 297862306a36Sopenharmony_ci /* Map, pin, and lock the mft record belonging to the inode. */ 297962306a36Sopenharmony_ci m = map_mft_record(ni); 298062306a36Sopenharmony_ci if (IS_ERR(m)) { 298162306a36Sopenharmony_ci err = PTR_ERR(m); 298262306a36Sopenharmony_ci goto err_out; 298362306a36Sopenharmony_ci } 298462306a36Sopenharmony_ci /* Update the access times in the standard information attribute. */ 298562306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(ni, m); 298662306a36Sopenharmony_ci if (unlikely(!ctx)) { 298762306a36Sopenharmony_ci err = -ENOMEM; 298862306a36Sopenharmony_ci goto unm_err_out; 298962306a36Sopenharmony_ci } 299062306a36Sopenharmony_ci err = ntfs_attr_lookup(AT_STANDARD_INFORMATION, NULL, 0, 299162306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 299262306a36Sopenharmony_ci if (unlikely(err)) { 299362306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 299462306a36Sopenharmony_ci goto unm_err_out; 299562306a36Sopenharmony_ci } 299662306a36Sopenharmony_ci si = (STANDARD_INFORMATION*)((u8*)ctx->attr + 299762306a36Sopenharmony_ci le16_to_cpu(ctx->attr->data.resident.value_offset)); 299862306a36Sopenharmony_ci /* Update the access times if they have changed. */ 299962306a36Sopenharmony_ci nt = utc2ntfs(vi->i_mtime); 300062306a36Sopenharmony_ci if (si->last_data_change_time != nt) { 300162306a36Sopenharmony_ci ntfs_debug("Updating mtime for inode 0x%lx: old = 0x%llx, " 300262306a36Sopenharmony_ci "new = 0x%llx", vi->i_ino, (long long) 300362306a36Sopenharmony_ci sle64_to_cpu(si->last_data_change_time), 300462306a36Sopenharmony_ci (long long)sle64_to_cpu(nt)); 300562306a36Sopenharmony_ci si->last_data_change_time = nt; 300662306a36Sopenharmony_ci modified = true; 300762306a36Sopenharmony_ci } 300862306a36Sopenharmony_ci nt = utc2ntfs(inode_get_ctime(vi)); 300962306a36Sopenharmony_ci if (si->last_mft_change_time != nt) { 301062306a36Sopenharmony_ci ntfs_debug("Updating ctime for inode 0x%lx: old = 0x%llx, " 301162306a36Sopenharmony_ci "new = 0x%llx", vi->i_ino, (long long) 301262306a36Sopenharmony_ci sle64_to_cpu(si->last_mft_change_time), 301362306a36Sopenharmony_ci (long long)sle64_to_cpu(nt)); 301462306a36Sopenharmony_ci si->last_mft_change_time = nt; 301562306a36Sopenharmony_ci modified = true; 301662306a36Sopenharmony_ci } 301762306a36Sopenharmony_ci nt = utc2ntfs(vi->i_atime); 301862306a36Sopenharmony_ci if (si->last_access_time != nt) { 301962306a36Sopenharmony_ci ntfs_debug("Updating atime for inode 0x%lx: old = 0x%llx, " 302062306a36Sopenharmony_ci "new = 0x%llx", vi->i_ino, 302162306a36Sopenharmony_ci (long long)sle64_to_cpu(si->last_access_time), 302262306a36Sopenharmony_ci (long long)sle64_to_cpu(nt)); 302362306a36Sopenharmony_ci si->last_access_time = nt; 302462306a36Sopenharmony_ci modified = true; 302562306a36Sopenharmony_ci } 302662306a36Sopenharmony_ci /* 302762306a36Sopenharmony_ci * If we just modified the standard information attribute we need to 302862306a36Sopenharmony_ci * mark the mft record it is in dirty. We do this manually so that 302962306a36Sopenharmony_ci * mark_inode_dirty() is not called which would redirty the inode and 303062306a36Sopenharmony_ci * hence result in an infinite loop of trying to write the inode. 303162306a36Sopenharmony_ci * There is no need to mark the base inode nor the base mft record 303262306a36Sopenharmony_ci * dirty, since we are going to write this mft record below in any case 303362306a36Sopenharmony_ci * and the base mft record may actually not have been modified so it 303462306a36Sopenharmony_ci * might not need to be written out. 303562306a36Sopenharmony_ci * NOTE: It is not a problem when the inode for $MFT itself is being 303662306a36Sopenharmony_ci * written out as mark_ntfs_record_dirty() will only set I_DIRTY_PAGES 303762306a36Sopenharmony_ci * on the $MFT inode and hence __ntfs_write_inode() will not be 303862306a36Sopenharmony_ci * re-invoked because of it which in turn is ok since the dirtied mft 303962306a36Sopenharmony_ci * record will be cleaned and written out to disk below, i.e. before 304062306a36Sopenharmony_ci * this function returns. 304162306a36Sopenharmony_ci */ 304262306a36Sopenharmony_ci if (modified) { 304362306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 304462306a36Sopenharmony_ci if (!NInoTestSetDirty(ctx->ntfs_ino)) 304562306a36Sopenharmony_ci mark_ntfs_record_dirty(ctx->ntfs_ino->page, 304662306a36Sopenharmony_ci ctx->ntfs_ino->page_ofs); 304762306a36Sopenharmony_ci } 304862306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 304962306a36Sopenharmony_ci /* Now the access times are updated, write the base mft record. */ 305062306a36Sopenharmony_ci if (NInoDirty(ni)) 305162306a36Sopenharmony_ci err = write_mft_record(ni, m, sync); 305262306a36Sopenharmony_ci /* Write all attached extent mft records. */ 305362306a36Sopenharmony_ci mutex_lock(&ni->extent_lock); 305462306a36Sopenharmony_ci if (ni->nr_extents > 0) { 305562306a36Sopenharmony_ci ntfs_inode **extent_nis = ni->ext.extent_ntfs_inos; 305662306a36Sopenharmony_ci int i; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci ntfs_debug("Writing %i extent inodes.", ni->nr_extents); 305962306a36Sopenharmony_ci for (i = 0; i < ni->nr_extents; i++) { 306062306a36Sopenharmony_ci ntfs_inode *tni = extent_nis[i]; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci if (NInoDirty(tni)) { 306362306a36Sopenharmony_ci MFT_RECORD *tm = map_mft_record(tni); 306462306a36Sopenharmony_ci int ret; 306562306a36Sopenharmony_ci 306662306a36Sopenharmony_ci if (IS_ERR(tm)) { 306762306a36Sopenharmony_ci if (!err || err == -ENOMEM) 306862306a36Sopenharmony_ci err = PTR_ERR(tm); 306962306a36Sopenharmony_ci continue; 307062306a36Sopenharmony_ci } 307162306a36Sopenharmony_ci ret = write_mft_record(tni, tm, sync); 307262306a36Sopenharmony_ci unmap_mft_record(tni); 307362306a36Sopenharmony_ci if (unlikely(ret)) { 307462306a36Sopenharmony_ci if (!err || err == -ENOMEM) 307562306a36Sopenharmony_ci err = ret; 307662306a36Sopenharmony_ci } 307762306a36Sopenharmony_ci } 307862306a36Sopenharmony_ci } 307962306a36Sopenharmony_ci } 308062306a36Sopenharmony_ci mutex_unlock(&ni->extent_lock); 308162306a36Sopenharmony_ci unmap_mft_record(ni); 308262306a36Sopenharmony_ci if (unlikely(err)) 308362306a36Sopenharmony_ci goto err_out; 308462306a36Sopenharmony_ci ntfs_debug("Done."); 308562306a36Sopenharmony_ci return 0; 308662306a36Sopenharmony_ciunm_err_out: 308762306a36Sopenharmony_ci unmap_mft_record(ni); 308862306a36Sopenharmony_cierr_out: 308962306a36Sopenharmony_ci if (err == -ENOMEM) { 309062306a36Sopenharmony_ci ntfs_warning(vi->i_sb, "Not enough memory to write inode. " 309162306a36Sopenharmony_ci "Marking the inode dirty again, so the VFS " 309262306a36Sopenharmony_ci "retries later."); 309362306a36Sopenharmony_ci mark_inode_dirty(vi); 309462306a36Sopenharmony_ci } else { 309562306a36Sopenharmony_ci ntfs_error(vi->i_sb, "Failed (error %i): Run chkdsk.", -err); 309662306a36Sopenharmony_ci NVolSetErrors(ni->vol); 309762306a36Sopenharmony_ci } 309862306a36Sopenharmony_ci return err; 309962306a36Sopenharmony_ci} 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci#endif /* NTFS_RW */ 3102