11e9ea7e0SNamjae Jeon // SPDX-License-Identifier: GPL-2.0-or-later 21e9ea7e0SNamjae Jeon /* 3495e90faSNamjae Jeon * NTFS attribute operations. 41e9ea7e0SNamjae Jeon * 51e9ea7e0SNamjae Jeon * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc. 61e9ea7e0SNamjae Jeon * Copyright (c) 2002 Richard Russon 7495e90faSNamjae Jeon * Copyright (c) 2025 LG Electronics Co., Ltd. 8495e90faSNamjae Jeon * 9495e90faSNamjae Jeon * Part of this file is based on code from the NTFS-3G. 10495e90faSNamjae Jeon * and is copyrighted by the respective authors below: 11495e90faSNamjae Jeon * Copyright (c) 2000-2010 Anton Altaparmakov 12495e90faSNamjae Jeon * Copyright (c) 2002-2005 Richard Russon 13495e90faSNamjae Jeon * Copyright (c) 2002-2008 Szabolcs Szakacsits 14495e90faSNamjae Jeon * Copyright (c) 2004-2007 Yura Pakhuchiy 15495e90faSNamjae Jeon * Copyright (c) 2007-2021 Jean-Pierre Andre 16495e90faSNamjae Jeon * Copyright (c) 2010 Erik Larsson 171e9ea7e0SNamjae Jeon */ 181e9ea7e0SNamjae Jeon 191e9ea7e0SNamjae Jeon #include <linux/writeback.h> 20495e90faSNamjae Jeon #include <linux/iomap.h> 211e9ea7e0SNamjae Jeon 221e9ea7e0SNamjae Jeon #include "attrib.h" 23495e90faSNamjae Jeon #include "attrlist.h" 241e9ea7e0SNamjae Jeon #include "lcnalloc.h" 25495e90faSNamjae Jeon #include "debug.h" 261e9ea7e0SNamjae Jeon #include "mft.h" 271e9ea7e0SNamjae Jeon #include "ntfs.h" 28495e90faSNamjae Jeon #include "iomap.h" 291e9ea7e0SNamjae Jeon 30495e90faSNamjae Jeon __le16 AT_UNNAMED[] = { cpu_to_le16('\0') }; 31495e90faSNamjae Jeon 32495e90faSNamjae Jeon /* 331e9ea7e0SNamjae Jeon * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode 341e9ea7e0SNamjae Jeon * @ni: ntfs inode for which to map (part of) a runlist 351e9ea7e0SNamjae Jeon * @vcn: map runlist part containing this vcn 361e9ea7e0SNamjae Jeon * @ctx: active attribute search context if present or NULL if not 371e9ea7e0SNamjae Jeon * 381e9ea7e0SNamjae Jeon * Map the part of a runlist containing the @vcn of the ntfs inode @ni. 391e9ea7e0SNamjae Jeon * 401e9ea7e0SNamjae Jeon * If @ctx is specified, it is an active search context of @ni and its base mft 411e9ea7e0SNamjae Jeon * record. This is needed when ntfs_map_runlist_nolock() encounters unmapped 421e9ea7e0SNamjae Jeon * runlist fragments and allows their mapping. If you do not have the mft 431e9ea7e0SNamjae Jeon * record mapped, you can specify @ctx as NULL and ntfs_map_runlist_nolock() 441e9ea7e0SNamjae Jeon * will perform the necessary mapping and unmapping. 451e9ea7e0SNamjae Jeon * 461e9ea7e0SNamjae Jeon * Note, ntfs_map_runlist_nolock() saves the state of @ctx on entry and 471e9ea7e0SNamjae Jeon * restores it before returning. Thus, @ctx will be left pointing to the same 481e9ea7e0SNamjae Jeon * attribute on return as on entry. However, the actual pointers in @ctx may 491e9ea7e0SNamjae Jeon * point to different memory locations on return, so you must remember to reset 501e9ea7e0SNamjae Jeon * any cached pointers from the @ctx, i.e. after the call to 511e9ea7e0SNamjae Jeon * ntfs_map_runlist_nolock(), you will probably want to do: 521e9ea7e0SNamjae Jeon * m = ctx->mrec; 531e9ea7e0SNamjae Jeon * a = ctx->attr; 54495e90faSNamjae Jeon * Assuming you cache ctx->attr in a variable @a of type struct attr_record * 55495e90faSNamjae Jeon * and that you cache ctx->mrec in a variable @m of type struct mft_record *. 561e9ea7e0SNamjae Jeon * 571e9ea7e0SNamjae Jeon * Return 0 on success and -errno on error. There is one special error code 581e9ea7e0SNamjae Jeon * which is not an error as such. This is -ENOENT. It means that @vcn is out 591e9ea7e0SNamjae Jeon * of bounds of the runlist. 601e9ea7e0SNamjae Jeon * 611e9ea7e0SNamjae Jeon * Note the runlist can be NULL after this function returns if @vcn is zero and 621e9ea7e0SNamjae Jeon * the attribute has zero allocated size, i.e. there simply is no runlist. 631e9ea7e0SNamjae Jeon * 641e9ea7e0SNamjae Jeon * WARNING: If @ctx is supplied, regardless of whether success or failure is 651e9ea7e0SNamjae Jeon * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx 661e9ea7e0SNamjae Jeon * is no longer valid, i.e. you need to either call 671e9ea7e0SNamjae Jeon * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. 681e9ea7e0SNamjae Jeon * In that case PTR_ERR(@ctx->mrec) will give you the error code for 691e9ea7e0SNamjae Jeon * why the mapping of the old inode failed. 701e9ea7e0SNamjae Jeon * 711e9ea7e0SNamjae Jeon * Locking: - The runlist described by @ni must be locked for writing on entry 721e9ea7e0SNamjae Jeon * and is locked on return. Note the runlist will be modified. 731e9ea7e0SNamjae Jeon * - If @ctx is NULL, the base mft record of @ni must not be mapped on 741e9ea7e0SNamjae Jeon * entry and it will be left unmapped on return. 751e9ea7e0SNamjae Jeon * - If @ctx is not NULL, the base mft record must be mapped on entry 761e9ea7e0SNamjae Jeon * and it will be left mapped on return. 771e9ea7e0SNamjae Jeon */ 78495e90faSNamjae Jeon int ntfs_map_runlist_nolock(struct ntfs_inode *ni, s64 vcn, struct ntfs_attr_search_ctx *ctx) 791e9ea7e0SNamjae Jeon { 80495e90faSNamjae Jeon s64 end_vcn; 811e9ea7e0SNamjae Jeon unsigned long flags; 82495e90faSNamjae Jeon struct ntfs_inode *base_ni; 83495e90faSNamjae Jeon struct mft_record *m; 84495e90faSNamjae Jeon struct attr_record *a; 85495e90faSNamjae Jeon struct runlist_element *rl; 86495e90faSNamjae Jeon struct folio *put_this_folio = NULL; 871e9ea7e0SNamjae Jeon int err = 0; 88495e90faSNamjae Jeon bool ctx_is_temporary = false, ctx_needs_reset; 89495e90faSNamjae Jeon struct ntfs_attr_search_ctx old_ctx = { NULL, }; 90495e90faSNamjae Jeon size_t new_rl_count; 911e9ea7e0SNamjae Jeon 921e9ea7e0SNamjae Jeon ntfs_debug("Mapping runlist part containing vcn 0x%llx.", 931e9ea7e0SNamjae Jeon (unsigned long long)vcn); 941e9ea7e0SNamjae Jeon if (!NInoAttr(ni)) 951e9ea7e0SNamjae Jeon base_ni = ni; 961e9ea7e0SNamjae Jeon else 971e9ea7e0SNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 981e9ea7e0SNamjae Jeon if (!ctx) { 991e9ea7e0SNamjae Jeon ctx_is_temporary = ctx_needs_reset = true; 1001e9ea7e0SNamjae Jeon m = map_mft_record(base_ni); 1011e9ea7e0SNamjae Jeon if (IS_ERR(m)) 1021e9ea7e0SNamjae Jeon return PTR_ERR(m); 1031e9ea7e0SNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, m); 1041e9ea7e0SNamjae Jeon if (unlikely(!ctx)) { 1051e9ea7e0SNamjae Jeon err = -ENOMEM; 1061e9ea7e0SNamjae Jeon goto err_out; 1071e9ea7e0SNamjae Jeon } 1081e9ea7e0SNamjae Jeon } else { 109495e90faSNamjae Jeon s64 allocated_size_vcn; 1101e9ea7e0SNamjae Jeon 111495e90faSNamjae Jeon WARN_ON(IS_ERR(ctx->mrec)); 1121e9ea7e0SNamjae Jeon a = ctx->attr; 113495e90faSNamjae Jeon if (!a->non_resident) { 114495e90faSNamjae Jeon err = -EIO; 115495e90faSNamjae Jeon goto err_out; 116495e90faSNamjae Jeon } 117495e90faSNamjae Jeon end_vcn = le64_to_cpu(a->data.non_resident.highest_vcn); 1181e9ea7e0SNamjae Jeon read_lock_irqsave(&ni->size_lock, flags); 119495e90faSNamjae Jeon allocated_size_vcn = 120495e90faSNamjae Jeon ntfs_bytes_to_cluster(ni->vol, ni->allocated_size); 1211e9ea7e0SNamjae Jeon read_unlock_irqrestore(&ni->size_lock, flags); 1221e9ea7e0SNamjae Jeon if (!a->data.non_resident.lowest_vcn && end_vcn <= 0) 1231e9ea7e0SNamjae Jeon end_vcn = allocated_size_vcn - 1; 1241e9ea7e0SNamjae Jeon /* 1251e9ea7e0SNamjae Jeon * If we already have the attribute extent containing @vcn in 1261e9ea7e0SNamjae Jeon * @ctx, no need to look it up again. We slightly cheat in 1271e9ea7e0SNamjae Jeon * that if vcn exceeds the allocated size, we will refuse to 1281e9ea7e0SNamjae Jeon * map the runlist below, so there is definitely no need to get 1291e9ea7e0SNamjae Jeon * the right attribute extent. 1301e9ea7e0SNamjae Jeon */ 1311e9ea7e0SNamjae Jeon if (vcn >= allocated_size_vcn || (a->type == ni->type && 1321e9ea7e0SNamjae Jeon a->name_length == ni->name_len && 1331e9ea7e0SNamjae Jeon !memcmp((u8 *)a + le16_to_cpu(a->name_offset), 1341e9ea7e0SNamjae Jeon ni->name, ni->name_len) && 135495e90faSNamjae Jeon le64_to_cpu(a->data.non_resident.lowest_vcn) 1361e9ea7e0SNamjae Jeon <= vcn && end_vcn >= vcn)) 1371e9ea7e0SNamjae Jeon ctx_needs_reset = false; 1381e9ea7e0SNamjae Jeon else { 1391e9ea7e0SNamjae Jeon /* Save the old search context. */ 1401e9ea7e0SNamjae Jeon old_ctx = *ctx; 1411e9ea7e0SNamjae Jeon /* 1421e9ea7e0SNamjae Jeon * If the currently mapped (extent) inode is not the 1431e9ea7e0SNamjae Jeon * base inode we will unmap it when we reinitialize the 1441e9ea7e0SNamjae Jeon * search context which means we need to get a 1451e9ea7e0SNamjae Jeon * reference to the page containing the mapped mft 1461e9ea7e0SNamjae Jeon * record so we do not accidentally drop changes to the 1471e9ea7e0SNamjae Jeon * mft record when it has not been marked dirty yet. 1481e9ea7e0SNamjae Jeon */ 1491e9ea7e0SNamjae Jeon if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino != 1501e9ea7e0SNamjae Jeon old_ctx.base_ntfs_ino) { 151495e90faSNamjae Jeon put_this_folio = old_ctx.ntfs_ino->folio; 152495e90faSNamjae Jeon folio_get(put_this_folio); 1531e9ea7e0SNamjae Jeon } 1541e9ea7e0SNamjae Jeon /* 1551e9ea7e0SNamjae Jeon * Reinitialize the search context so we can lookup the 1561e9ea7e0SNamjae Jeon * needed attribute extent. 1571e9ea7e0SNamjae Jeon */ 1581e9ea7e0SNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 1591e9ea7e0SNamjae Jeon ctx_needs_reset = true; 1601e9ea7e0SNamjae Jeon } 1611e9ea7e0SNamjae Jeon } 1621e9ea7e0SNamjae Jeon if (ctx_needs_reset) { 1631e9ea7e0SNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 1641e9ea7e0SNamjae Jeon CASE_SENSITIVE, vcn, NULL, 0, ctx); 1651e9ea7e0SNamjae Jeon if (unlikely(err)) { 1661e9ea7e0SNamjae Jeon if (err == -ENOENT) 1671e9ea7e0SNamjae Jeon err = -EIO; 1681e9ea7e0SNamjae Jeon goto err_out; 1691e9ea7e0SNamjae Jeon } 170495e90faSNamjae Jeon WARN_ON(!ctx->attr->non_resident); 1711e9ea7e0SNamjae Jeon } 1721e9ea7e0SNamjae Jeon a = ctx->attr; 1731e9ea7e0SNamjae Jeon /* 1741e9ea7e0SNamjae Jeon * Only decompress the mapping pairs if @vcn is inside it. Otherwise 1751e9ea7e0SNamjae Jeon * we get into problems when we try to map an out of bounds vcn because 1761e9ea7e0SNamjae Jeon * we then try to map the already mapped runlist fragment and 1771e9ea7e0SNamjae Jeon * ntfs_mapping_pairs_decompress() fails. 1781e9ea7e0SNamjae Jeon */ 179495e90faSNamjae Jeon end_vcn = le64_to_cpu(a->data.non_resident.highest_vcn) + 1; 1801e9ea7e0SNamjae Jeon if (unlikely(vcn && vcn >= end_vcn)) { 1811e9ea7e0SNamjae Jeon err = -ENOENT; 1821e9ea7e0SNamjae Jeon goto err_out; 1831e9ea7e0SNamjae Jeon } 184495e90faSNamjae Jeon rl = ntfs_mapping_pairs_decompress(ni->vol, a, &ni->runlist, &new_rl_count); 1851e9ea7e0SNamjae Jeon if (IS_ERR(rl)) 1861e9ea7e0SNamjae Jeon err = PTR_ERR(rl); 187495e90faSNamjae Jeon else { 1881e9ea7e0SNamjae Jeon ni->runlist.rl = rl; 189495e90faSNamjae Jeon ni->runlist.count = new_rl_count; 190495e90faSNamjae Jeon } 1911e9ea7e0SNamjae Jeon err_out: 1921e9ea7e0SNamjae Jeon if (ctx_is_temporary) { 1931e9ea7e0SNamjae Jeon if (likely(ctx)) 1941e9ea7e0SNamjae Jeon ntfs_attr_put_search_ctx(ctx); 1951e9ea7e0SNamjae Jeon unmap_mft_record(base_ni); 1961e9ea7e0SNamjae Jeon } else if (ctx_needs_reset) { 1971e9ea7e0SNamjae Jeon /* 1981e9ea7e0SNamjae Jeon * If there is no attribute list, restoring the search context 1991e9ea7e0SNamjae Jeon * is accomplished simply by copying the saved context back over 2001e9ea7e0SNamjae Jeon * the caller supplied context. If there is an attribute list, 2011e9ea7e0SNamjae Jeon * things are more complicated as we need to deal with mapping 2021e9ea7e0SNamjae Jeon * of mft records and resulting potential changes in pointers. 2031e9ea7e0SNamjae Jeon */ 2041e9ea7e0SNamjae Jeon if (NInoAttrList(base_ni)) { 2051e9ea7e0SNamjae Jeon /* 2061e9ea7e0SNamjae Jeon * If the currently mapped (extent) inode is not the 2071e9ea7e0SNamjae Jeon * one we had before, we need to unmap it and map the 2081e9ea7e0SNamjae Jeon * old one. 2091e9ea7e0SNamjae Jeon */ 2101e9ea7e0SNamjae Jeon if (ctx->ntfs_ino != old_ctx.ntfs_ino) { 2111e9ea7e0SNamjae Jeon /* 2121e9ea7e0SNamjae Jeon * If the currently mapped inode is not the 2131e9ea7e0SNamjae Jeon * base inode, unmap it. 2141e9ea7e0SNamjae Jeon */ 2151e9ea7e0SNamjae Jeon if (ctx->base_ntfs_ino && ctx->ntfs_ino != 2161e9ea7e0SNamjae Jeon ctx->base_ntfs_ino) { 2171e9ea7e0SNamjae Jeon unmap_extent_mft_record(ctx->ntfs_ino); 2181e9ea7e0SNamjae Jeon ctx->mrec = ctx->base_mrec; 219495e90faSNamjae Jeon WARN_ON(!ctx->mrec); 2201e9ea7e0SNamjae Jeon } 2211e9ea7e0SNamjae Jeon /* 2221e9ea7e0SNamjae Jeon * If the old mapped inode is not the base 2231e9ea7e0SNamjae Jeon * inode, map it. 2241e9ea7e0SNamjae Jeon */ 2251e9ea7e0SNamjae Jeon if (old_ctx.base_ntfs_ino && 226495e90faSNamjae Jeon old_ctx.ntfs_ino != old_ctx.base_ntfs_ino) { 2271e9ea7e0SNamjae Jeon retry_map: 228495e90faSNamjae Jeon ctx->mrec = map_mft_record(old_ctx.ntfs_ino); 2291e9ea7e0SNamjae Jeon /* 2301e9ea7e0SNamjae Jeon * Something bad has happened. If out 2311e9ea7e0SNamjae Jeon * of memory retry till it succeeds. 2321e9ea7e0SNamjae Jeon * Any other errors are fatal and we 2331e9ea7e0SNamjae Jeon * return the error code in ctx->mrec. 2341e9ea7e0SNamjae Jeon * Let the caller deal with it... We 2351e9ea7e0SNamjae Jeon * just need to fudge things so the 2361e9ea7e0SNamjae Jeon * caller can reinit and/or put the 2371e9ea7e0SNamjae Jeon * search context safely. 2381e9ea7e0SNamjae Jeon */ 2391e9ea7e0SNamjae Jeon if (IS_ERR(ctx->mrec)) { 240495e90faSNamjae Jeon if (PTR_ERR(ctx->mrec) == -ENOMEM) { 2411e9ea7e0SNamjae Jeon schedule(); 2421e9ea7e0SNamjae Jeon goto retry_map; 2431e9ea7e0SNamjae Jeon } else 2441e9ea7e0SNamjae Jeon old_ctx.ntfs_ino = 245495e90faSNamjae Jeon old_ctx.base_ntfs_ino; 2461e9ea7e0SNamjae Jeon } 2471e9ea7e0SNamjae Jeon } 2481e9ea7e0SNamjae Jeon } 2491e9ea7e0SNamjae Jeon /* Update the changed pointers in the saved context. */ 2501e9ea7e0SNamjae Jeon if (ctx->mrec != old_ctx.mrec) { 2511e9ea7e0SNamjae Jeon if (!IS_ERR(ctx->mrec)) 252495e90faSNamjae Jeon old_ctx.attr = (struct attr_record *)( 2531e9ea7e0SNamjae Jeon (u8 *)ctx->mrec + 2541e9ea7e0SNamjae Jeon ((u8 *)old_ctx.attr - 2551e9ea7e0SNamjae Jeon (u8 *)old_ctx.mrec)); 2561e9ea7e0SNamjae Jeon old_ctx.mrec = ctx->mrec; 2571e9ea7e0SNamjae Jeon } 2581e9ea7e0SNamjae Jeon } 2591e9ea7e0SNamjae Jeon /* Restore the search context to the saved one. */ 2601e9ea7e0SNamjae Jeon *ctx = old_ctx; 2611e9ea7e0SNamjae Jeon /* 2621e9ea7e0SNamjae Jeon * We drop the reference on the page we took earlier. In the 2631e9ea7e0SNamjae Jeon * case that IS_ERR(ctx->mrec) is true this means we might lose 2641e9ea7e0SNamjae Jeon * some changes to the mft record that had been made between 2651e9ea7e0SNamjae Jeon * the last time it was marked dirty/written out and now. This 2661e9ea7e0SNamjae Jeon * at this stage is not a problem as the mapping error is fatal 2671e9ea7e0SNamjae Jeon * enough that the mft record cannot be written out anyway and 2681e9ea7e0SNamjae Jeon * the caller is very likely to shutdown the whole inode 2691e9ea7e0SNamjae Jeon * immediately and mark the volume dirty for chkdsk to pick up 2701e9ea7e0SNamjae Jeon * the pieces anyway. 2711e9ea7e0SNamjae Jeon */ 272495e90faSNamjae Jeon if (put_this_folio) 273495e90faSNamjae Jeon folio_put(put_this_folio); 2741e9ea7e0SNamjae Jeon } 2751e9ea7e0SNamjae Jeon return err; 2761e9ea7e0SNamjae Jeon } 2771e9ea7e0SNamjae Jeon 278495e90faSNamjae Jeon /* 2791e9ea7e0SNamjae Jeon * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode 2801e9ea7e0SNamjae Jeon * @ni: ntfs inode for which to map (part of) a runlist 2811e9ea7e0SNamjae Jeon * @vcn: map runlist part containing this vcn 2821e9ea7e0SNamjae Jeon * 2831e9ea7e0SNamjae Jeon * Map the part of a runlist containing the @vcn of the ntfs inode @ni. 2841e9ea7e0SNamjae Jeon * 2851e9ea7e0SNamjae Jeon * Return 0 on success and -errno on error. There is one special error code 2861e9ea7e0SNamjae Jeon * which is not an error as such. This is -ENOENT. It means that @vcn is out 2871e9ea7e0SNamjae Jeon * of bounds of the runlist. 2881e9ea7e0SNamjae Jeon * 2891e9ea7e0SNamjae Jeon * Locking: - The runlist must be unlocked on entry and is unlocked on return. 2901e9ea7e0SNamjae Jeon * - This function takes the runlist lock for writing and may modify 2911e9ea7e0SNamjae Jeon * the runlist. 2921e9ea7e0SNamjae Jeon */ 293495e90faSNamjae Jeon int ntfs_map_runlist(struct ntfs_inode *ni, s64 vcn) 2941e9ea7e0SNamjae Jeon { 2951e9ea7e0SNamjae Jeon int err = 0; 2961e9ea7e0SNamjae Jeon 2971e9ea7e0SNamjae Jeon down_write(&ni->runlist.lock); 2981e9ea7e0SNamjae Jeon /* Make sure someone else didn't do the work while we were sleeping. */ 2991e9ea7e0SNamjae Jeon if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= 3001e9ea7e0SNamjae Jeon LCN_RL_NOT_MAPPED)) 3011e9ea7e0SNamjae Jeon err = ntfs_map_runlist_nolock(ni, vcn, NULL); 3021e9ea7e0SNamjae Jeon up_write(&ni->runlist.lock); 3031e9ea7e0SNamjae Jeon return err; 3041e9ea7e0SNamjae Jeon } 3051e9ea7e0SNamjae Jeon 306495e90faSNamjae Jeon struct runlist_element *ntfs_attr_vcn_to_rl(struct ntfs_inode *ni, s64 vcn, s64 *lcn) 307495e90faSNamjae Jeon { 308495e90faSNamjae Jeon struct runlist_element *rl = ni->runlist.rl; 309495e90faSNamjae Jeon int err; 310495e90faSNamjae Jeon bool is_retry = false; 311495e90faSNamjae Jeon 312495e90faSNamjae Jeon if (!rl) { 313495e90faSNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 314495e90faSNamjae Jeon if (err) 315495e90faSNamjae Jeon return ERR_PTR(-ENOENT); 316495e90faSNamjae Jeon rl = ni->runlist.rl; 317495e90faSNamjae Jeon } 318495e90faSNamjae Jeon 319495e90faSNamjae Jeon remap_rl: 320495e90faSNamjae Jeon /* Seek to element containing target vcn. */ 321495e90faSNamjae Jeon while (rl->length && rl[1].vcn <= vcn) 322495e90faSNamjae Jeon rl++; 323495e90faSNamjae Jeon *lcn = ntfs_rl_vcn_to_lcn(rl, vcn); 324495e90faSNamjae Jeon 325495e90faSNamjae Jeon if (*lcn <= LCN_RL_NOT_MAPPED && is_retry == false) { 326495e90faSNamjae Jeon is_retry = true; 327495e90faSNamjae Jeon if (!ntfs_map_runlist_nolock(ni, vcn, NULL)) { 328495e90faSNamjae Jeon rl = ni->runlist.rl; 329495e90faSNamjae Jeon goto remap_rl; 330495e90faSNamjae Jeon } 331495e90faSNamjae Jeon } 332495e90faSNamjae Jeon 333495e90faSNamjae Jeon return rl; 334495e90faSNamjae Jeon } 335495e90faSNamjae Jeon 336495e90faSNamjae Jeon /* 3371e9ea7e0SNamjae Jeon * ntfs_attr_vcn_to_lcn_nolock - convert a vcn into a lcn given an ntfs inode 3381e9ea7e0SNamjae Jeon * @ni: ntfs inode of the attribute whose runlist to search 3391e9ea7e0SNamjae Jeon * @vcn: vcn to convert 3401e9ea7e0SNamjae Jeon * @write_locked: true if the runlist is locked for writing 3411e9ea7e0SNamjae Jeon * 3421e9ea7e0SNamjae Jeon * Find the virtual cluster number @vcn in the runlist of the ntfs attribute 3431e9ea7e0SNamjae Jeon * described by the ntfs inode @ni and return the corresponding logical cluster 3441e9ea7e0SNamjae Jeon * number (lcn). 3451e9ea7e0SNamjae Jeon * 3461e9ea7e0SNamjae Jeon * If the @vcn is not mapped yet, the attempt is made to map the attribute 3471e9ea7e0SNamjae Jeon * extent containing the @vcn and the vcn to lcn conversion is retried. 3481e9ea7e0SNamjae Jeon * 3491e9ea7e0SNamjae Jeon * If @write_locked is true the caller has locked the runlist for writing and 3501e9ea7e0SNamjae Jeon * if false for reading. 3511e9ea7e0SNamjae Jeon * 3521e9ea7e0SNamjae Jeon * Since lcns must be >= 0, we use negative return codes with special meaning: 3531e9ea7e0SNamjae Jeon * 3541e9ea7e0SNamjae Jeon * Return code Meaning / Description 3551e9ea7e0SNamjae Jeon * ========================================== 3561e9ea7e0SNamjae Jeon * LCN_HOLE Hole / not allocated on disk. 3571e9ea7e0SNamjae Jeon * LCN_ENOENT There is no such vcn in the runlist, i.e. @vcn is out of bounds. 3581e9ea7e0SNamjae Jeon * LCN_ENOMEM Not enough memory to map runlist. 3591e9ea7e0SNamjae Jeon * LCN_EIO Critical error (runlist/file is corrupt, i/o error, etc). 3601e9ea7e0SNamjae Jeon * 3611e9ea7e0SNamjae Jeon * Locking: - The runlist must be locked on entry and is left locked on return. 3621e9ea7e0SNamjae Jeon * - If @write_locked is 'false', i.e. the runlist is locked for reading, 3631e9ea7e0SNamjae Jeon * the lock may be dropped inside the function so you cannot rely on 3641e9ea7e0SNamjae Jeon * the runlist still being the same when this function returns. 3651e9ea7e0SNamjae Jeon */ 366495e90faSNamjae Jeon s64 ntfs_attr_vcn_to_lcn_nolock(struct ntfs_inode *ni, const s64 vcn, 3671e9ea7e0SNamjae Jeon const bool write_locked) 3681e9ea7e0SNamjae Jeon { 369495e90faSNamjae Jeon s64 lcn; 3701e9ea7e0SNamjae Jeon unsigned long flags; 3711e9ea7e0SNamjae Jeon bool is_retry = false; 3721e9ea7e0SNamjae Jeon 373d9038d99SNamjae Jeon ntfs_debug("Entering for i_ino 0x%llx, vcn 0x%llx, %s_locked.", 3741e9ea7e0SNamjae Jeon ni->mft_no, (unsigned long long)vcn, 3751e9ea7e0SNamjae Jeon write_locked ? "write" : "read"); 3761e9ea7e0SNamjae Jeon if (!ni->runlist.rl) { 3771e9ea7e0SNamjae Jeon read_lock_irqsave(&ni->size_lock, flags); 3781e9ea7e0SNamjae Jeon if (!ni->allocated_size) { 3791e9ea7e0SNamjae Jeon read_unlock_irqrestore(&ni->size_lock, flags); 3801e9ea7e0SNamjae Jeon return LCN_ENOENT; 3811e9ea7e0SNamjae Jeon } 3821e9ea7e0SNamjae Jeon read_unlock_irqrestore(&ni->size_lock, flags); 3831e9ea7e0SNamjae Jeon } 3841e9ea7e0SNamjae Jeon retry_remap: 3851e9ea7e0SNamjae Jeon /* Convert vcn to lcn. If that fails map the runlist and retry once. */ 3861e9ea7e0SNamjae Jeon lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); 3871e9ea7e0SNamjae Jeon if (likely(lcn >= LCN_HOLE)) { 3881e9ea7e0SNamjae Jeon ntfs_debug("Done, lcn 0x%llx.", (long long)lcn); 3891e9ea7e0SNamjae Jeon return lcn; 3901e9ea7e0SNamjae Jeon } 3911e9ea7e0SNamjae Jeon if (lcn != LCN_RL_NOT_MAPPED) { 3921e9ea7e0SNamjae Jeon if (lcn != LCN_ENOENT) 3931e9ea7e0SNamjae Jeon lcn = LCN_EIO; 3941e9ea7e0SNamjae Jeon } else if (!is_retry) { 3951e9ea7e0SNamjae Jeon int err; 3961e9ea7e0SNamjae Jeon 3971e9ea7e0SNamjae Jeon if (!write_locked) { 3981e9ea7e0SNamjae Jeon up_read(&ni->runlist.lock); 3991e9ea7e0SNamjae Jeon down_write(&ni->runlist.lock); 4001e9ea7e0SNamjae Jeon if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) != 4011e9ea7e0SNamjae Jeon LCN_RL_NOT_MAPPED)) { 4021e9ea7e0SNamjae Jeon up_write(&ni->runlist.lock); 4031e9ea7e0SNamjae Jeon down_read(&ni->runlist.lock); 4041e9ea7e0SNamjae Jeon goto retry_remap; 4051e9ea7e0SNamjae Jeon } 4061e9ea7e0SNamjae Jeon } 4071e9ea7e0SNamjae Jeon err = ntfs_map_runlist_nolock(ni, vcn, NULL); 4081e9ea7e0SNamjae Jeon if (!write_locked) { 4091e9ea7e0SNamjae Jeon up_write(&ni->runlist.lock); 4101e9ea7e0SNamjae Jeon down_read(&ni->runlist.lock); 4111e9ea7e0SNamjae Jeon } 4121e9ea7e0SNamjae Jeon if (likely(!err)) { 4131e9ea7e0SNamjae Jeon is_retry = true; 4141e9ea7e0SNamjae Jeon goto retry_remap; 4151e9ea7e0SNamjae Jeon } 4161e9ea7e0SNamjae Jeon if (err == -ENOENT) 4171e9ea7e0SNamjae Jeon lcn = LCN_ENOENT; 4181e9ea7e0SNamjae Jeon else if (err == -ENOMEM) 4191e9ea7e0SNamjae Jeon lcn = LCN_ENOMEM; 4201e9ea7e0SNamjae Jeon else 4211e9ea7e0SNamjae Jeon lcn = LCN_EIO; 4221e9ea7e0SNamjae Jeon } 4231e9ea7e0SNamjae Jeon if (lcn != LCN_ENOENT) 4241e9ea7e0SNamjae Jeon ntfs_error(ni->vol->sb, "Failed with error code %lli.", 4251e9ea7e0SNamjae Jeon (long long)lcn); 4261e9ea7e0SNamjae Jeon return lcn; 4271e9ea7e0SNamjae Jeon } 4281e9ea7e0SNamjae Jeon 429495e90faSNamjae Jeon struct runlist_element *__ntfs_attr_find_vcn_nolock(struct runlist *runlist, const s64 vcn) 430495e90faSNamjae Jeon { 431495e90faSNamjae Jeon size_t lower_idx, upper_idx, idx; 432495e90faSNamjae Jeon struct runlist_element *run; 433495e90faSNamjae Jeon int rh = runlist->rl_hint; 434495e90faSNamjae Jeon 435495e90faSNamjae Jeon if (runlist->count <= 1) 436495e90faSNamjae Jeon return ERR_PTR(-ENOENT); 437495e90faSNamjae Jeon 438495e90faSNamjae Jeon if (runlist->count - 1 > rh && runlist->rl[rh].vcn <= vcn) { 439495e90faSNamjae Jeon if (vcn < runlist->rl[rh].vcn + runlist->rl[rh].length) 440495e90faSNamjae Jeon return &runlist->rl[rh]; 441495e90faSNamjae Jeon if (runlist->count - 2 == rh) 442495e90faSNamjae Jeon return ERR_PTR(-ENOENT); 443495e90faSNamjae Jeon 444495e90faSNamjae Jeon lower_idx = rh + 1; 445495e90faSNamjae Jeon } else { 446495e90faSNamjae Jeon run = &runlist->rl[0]; 447495e90faSNamjae Jeon if (vcn < run->vcn) 448495e90faSNamjae Jeon return ERR_PTR(-ENOENT); 449495e90faSNamjae Jeon else if (vcn < run->vcn + run->length) { 450495e90faSNamjae Jeon runlist->rl_hint = 0; 451495e90faSNamjae Jeon return run; 452495e90faSNamjae Jeon } 453495e90faSNamjae Jeon 454495e90faSNamjae Jeon lower_idx = 1; 455495e90faSNamjae Jeon } 456495e90faSNamjae Jeon 457495e90faSNamjae Jeon run = &runlist->rl[runlist->count - 2]; 458495e90faSNamjae Jeon if (vcn >= run->vcn && vcn < run->vcn + run->length) { 459495e90faSNamjae Jeon runlist->rl_hint = runlist->count - 2; 460495e90faSNamjae Jeon return run; 461495e90faSNamjae Jeon } 462495e90faSNamjae Jeon if (vcn >= run->vcn + run->length) 463495e90faSNamjae Jeon return ERR_PTR(-ENOENT); 464495e90faSNamjae Jeon 465495e90faSNamjae Jeon upper_idx = runlist->count - 2; 466495e90faSNamjae Jeon 467495e90faSNamjae Jeon while (lower_idx <= upper_idx) { 468495e90faSNamjae Jeon idx = (lower_idx + upper_idx) >> 1; 469495e90faSNamjae Jeon run = &runlist->rl[idx]; 470495e90faSNamjae Jeon 471495e90faSNamjae Jeon if (vcn < run->vcn) 472495e90faSNamjae Jeon upper_idx = idx - 1; 473495e90faSNamjae Jeon else if (vcn >= run->vcn + run->length) 474495e90faSNamjae Jeon lower_idx = idx + 1; 475495e90faSNamjae Jeon else { 476495e90faSNamjae Jeon runlist->rl_hint = idx; 477495e90faSNamjae Jeon return run; 478495e90faSNamjae Jeon } 479495e90faSNamjae Jeon } 480495e90faSNamjae Jeon 481495e90faSNamjae Jeon return ERR_PTR(-ENOENT); 482495e90faSNamjae Jeon } 483495e90faSNamjae Jeon 484495e90faSNamjae Jeon /* 4851e9ea7e0SNamjae Jeon * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode 4861e9ea7e0SNamjae Jeon * @ni: ntfs inode describing the runlist to search 4871e9ea7e0SNamjae Jeon * @vcn: vcn to find 4881e9ea7e0SNamjae Jeon * @ctx: active attribute search context if present or NULL if not 4891e9ea7e0SNamjae Jeon * 4901e9ea7e0SNamjae Jeon * Find the virtual cluster number @vcn in the runlist described by the ntfs 4911e9ea7e0SNamjae Jeon * inode @ni and return the address of the runlist element containing the @vcn. 4921e9ea7e0SNamjae Jeon * 4931e9ea7e0SNamjae Jeon * If the @vcn is not mapped yet, the attempt is made to map the attribute 4941e9ea7e0SNamjae Jeon * extent containing the @vcn and the vcn to lcn conversion is retried. 4951e9ea7e0SNamjae Jeon * 4961e9ea7e0SNamjae Jeon * If @ctx is specified, it is an active search context of @ni and its base mft 4971e9ea7e0SNamjae Jeon * record. This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped 4981e9ea7e0SNamjae Jeon * runlist fragments and allows their mapping. If you do not have the mft 4991e9ea7e0SNamjae Jeon * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock() 5001e9ea7e0SNamjae Jeon * will perform the necessary mapping and unmapping. 5011e9ea7e0SNamjae Jeon * 5021e9ea7e0SNamjae Jeon * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and 5031e9ea7e0SNamjae Jeon * restores it before returning. Thus, @ctx will be left pointing to the same 5041e9ea7e0SNamjae Jeon * attribute on return as on entry. However, the actual pointers in @ctx may 5051e9ea7e0SNamjae Jeon * point to different memory locations on return, so you must remember to reset 5061e9ea7e0SNamjae Jeon * any cached pointers from the @ctx, i.e. after the call to 5071e9ea7e0SNamjae Jeon * ntfs_attr_find_vcn_nolock(), you will probably want to do: 5081e9ea7e0SNamjae Jeon * m = ctx->mrec; 5091e9ea7e0SNamjae Jeon * a = ctx->attr; 510495e90faSNamjae Jeon * Assuming you cache ctx->attr in a variable @a of type attr_record * and that 511495e90faSNamjae Jeon * you cache ctx->mrec in a variable @m of type struct mft_record *. 5121e9ea7e0SNamjae Jeon * Note you need to distinguish between the lcn of the returned runlist element 5131e9ea7e0SNamjae Jeon * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on 5141e9ea7e0SNamjae Jeon * read and allocate clusters on write. 5151e9ea7e0SNamjae Jeon */ 516495e90faSNamjae Jeon struct runlist_element *ntfs_attr_find_vcn_nolock(struct ntfs_inode *ni, const s64 vcn, 517495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx) 5181e9ea7e0SNamjae Jeon { 5191e9ea7e0SNamjae Jeon unsigned long flags; 520495e90faSNamjae Jeon struct runlist_element *rl; 5211e9ea7e0SNamjae Jeon int err = 0; 5221e9ea7e0SNamjae Jeon bool is_retry = false; 5231e9ea7e0SNamjae Jeon 524d9038d99SNamjae Jeon ntfs_debug("Entering for i_ino 0x%llx, vcn 0x%llx, with%s ctx.", 5251e9ea7e0SNamjae Jeon ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out"); 5261e9ea7e0SNamjae Jeon if (!ni->runlist.rl) { 5271e9ea7e0SNamjae Jeon read_lock_irqsave(&ni->size_lock, flags); 5281e9ea7e0SNamjae Jeon if (!ni->allocated_size) { 5291e9ea7e0SNamjae Jeon read_unlock_irqrestore(&ni->size_lock, flags); 5301e9ea7e0SNamjae Jeon return ERR_PTR(-ENOENT); 5311e9ea7e0SNamjae Jeon } 5321e9ea7e0SNamjae Jeon read_unlock_irqrestore(&ni->size_lock, flags); 5331e9ea7e0SNamjae Jeon } 534495e90faSNamjae Jeon 5351e9ea7e0SNamjae Jeon retry_remap: 5361e9ea7e0SNamjae Jeon rl = ni->runlist.rl; 5371e9ea7e0SNamjae Jeon if (likely(rl && vcn >= rl[0].vcn)) { 538495e90faSNamjae Jeon rl = __ntfs_attr_find_vcn_nolock(&ni->runlist, vcn); 539495e90faSNamjae Jeon if (IS_ERR(rl)) 540495e90faSNamjae Jeon err = PTR_ERR(rl); 541495e90faSNamjae Jeon else if (rl->lcn >= LCN_HOLE) 5421e9ea7e0SNamjae Jeon return rl; 543495e90faSNamjae Jeon else if (rl->lcn <= LCN_ENOENT) 5441e9ea7e0SNamjae Jeon err = -EIO; 5451e9ea7e0SNamjae Jeon } 5461e9ea7e0SNamjae Jeon if (!err && !is_retry) { 5471e9ea7e0SNamjae Jeon /* 5481e9ea7e0SNamjae Jeon * If the search context is invalid we cannot map the unmapped 5491e9ea7e0SNamjae Jeon * region. 5501e9ea7e0SNamjae Jeon */ 551495e90faSNamjae Jeon if (ctx && IS_ERR(ctx->mrec)) 5521e9ea7e0SNamjae Jeon err = PTR_ERR(ctx->mrec); 5531e9ea7e0SNamjae Jeon else { 5541e9ea7e0SNamjae Jeon /* 5551e9ea7e0SNamjae Jeon * The @vcn is in an unmapped region, map the runlist 5561e9ea7e0SNamjae Jeon * and retry. 5571e9ea7e0SNamjae Jeon */ 5581e9ea7e0SNamjae Jeon err = ntfs_map_runlist_nolock(ni, vcn, ctx); 5591e9ea7e0SNamjae Jeon if (likely(!err)) { 5601e9ea7e0SNamjae Jeon is_retry = true; 5611e9ea7e0SNamjae Jeon goto retry_remap; 5621e9ea7e0SNamjae Jeon } 5631e9ea7e0SNamjae Jeon } 5641e9ea7e0SNamjae Jeon if (err == -EINVAL) 5651e9ea7e0SNamjae Jeon err = -EIO; 5661e9ea7e0SNamjae Jeon } else if (!err) 5671e9ea7e0SNamjae Jeon err = -EIO; 5681e9ea7e0SNamjae Jeon if (err != -ENOENT) 5691e9ea7e0SNamjae Jeon ntfs_error(ni->vol->sb, "Failed with error code %i.", err); 5701e9ea7e0SNamjae Jeon return ERR_PTR(err); 5711e9ea7e0SNamjae Jeon } 5721e9ea7e0SNamjae Jeon 5736ceb4cc8SHyunchul Lee static u32 ntfs_resident_attr_min_value_length(const __le32 type) 5746ceb4cc8SHyunchul Lee { 5756ceb4cc8SHyunchul Lee switch (type) { 5766ceb4cc8SHyunchul Lee case AT_STANDARD_INFORMATION: 5776ceb4cc8SHyunchul Lee return offsetof(struct standard_information, ver) + 5786ceb4cc8SHyunchul Lee sizeof(((struct standard_information *)0)->ver.v1.reserved12); 5796ceb4cc8SHyunchul Lee case AT_ATTRIBUTE_LIST: 5806ceb4cc8SHyunchul Lee return offsetof(struct attr_list_entry, name); 5816ceb4cc8SHyunchul Lee case AT_FILE_NAME: 5826ceb4cc8SHyunchul Lee return offsetof(struct file_name_attr, file_name); 5836ceb4cc8SHyunchul Lee case AT_OBJECT_ID: 5846ceb4cc8SHyunchul Lee return sizeof(struct guid); 5856ceb4cc8SHyunchul Lee case AT_SECURITY_DESCRIPTOR: 5866ceb4cc8SHyunchul Lee return sizeof(struct security_descriptor_relative); 5876ceb4cc8SHyunchul Lee case AT_VOLUME_INFORMATION: 5886ceb4cc8SHyunchul Lee return sizeof(struct volume_information); 5896ceb4cc8SHyunchul Lee case AT_INDEX_ROOT: 5906ceb4cc8SHyunchul Lee return sizeof(struct index_root); 5916ceb4cc8SHyunchul Lee case AT_REPARSE_POINT: 5926ceb4cc8SHyunchul Lee return offsetof(struct reparse_point, reparse_data); 5936ceb4cc8SHyunchul Lee case AT_EA_INFORMATION: 5946ceb4cc8SHyunchul Lee return sizeof(struct ea_information); 5956ceb4cc8SHyunchul Lee case AT_EA: 5966ceb4cc8SHyunchul Lee return offsetof(struct ea_attr, ea_name) + 1; 5976ceb4cc8SHyunchul Lee default: 5986ceb4cc8SHyunchul Lee return 0; 5996ceb4cc8SHyunchul Lee } 6006ceb4cc8SHyunchul Lee } 6016ceb4cc8SHyunchul Lee 602495e90faSNamjae Jeon /* 6031e9ea7e0SNamjae Jeon * ntfs_attr_find - find (next) attribute in mft record 6041e9ea7e0SNamjae Jeon * @type: attribute type to find 6051e9ea7e0SNamjae Jeon * @name: attribute name to find (optional, i.e. NULL means don't care) 6061e9ea7e0SNamjae Jeon * @name_len: attribute name length (only needed if @name present) 6071e9ea7e0SNamjae Jeon * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 6081e9ea7e0SNamjae Jeon * @val: attribute value to find (optional, resident attributes only) 6091e9ea7e0SNamjae Jeon * @val_len: attribute value length 6101e9ea7e0SNamjae Jeon * @ctx: search context with mft record and attribute to search from 6111e9ea7e0SNamjae Jeon * 6121e9ea7e0SNamjae Jeon * You should not need to call this function directly. Use ntfs_attr_lookup() 6131e9ea7e0SNamjae Jeon * instead. 6141e9ea7e0SNamjae Jeon * 6151e9ea7e0SNamjae Jeon * ntfs_attr_find() takes a search context @ctx as parameter and searches the 6161e9ea7e0SNamjae Jeon * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an 6171e9ea7e0SNamjae Jeon * attribute of @type, optionally @name and @val. 6181e9ea7e0SNamjae Jeon * 6191e9ea7e0SNamjae Jeon * If the attribute is found, ntfs_attr_find() returns 0 and @ctx->attr will 6201e9ea7e0SNamjae Jeon * point to the found attribute. 6211e9ea7e0SNamjae Jeon * 6221e9ea7e0SNamjae Jeon * If the attribute is not found, ntfs_attr_find() returns -ENOENT and 6231e9ea7e0SNamjae Jeon * @ctx->attr will point to the attribute before which the attribute being 6241e9ea7e0SNamjae Jeon * searched for would need to be inserted if such an action were to be desired. 6251e9ea7e0SNamjae Jeon * 6261e9ea7e0SNamjae Jeon * On actual error, ntfs_attr_find() returns -EIO. In this case @ctx->attr is 6271e9ea7e0SNamjae Jeon * undefined and in particular do not rely on it not changing. 6281e9ea7e0SNamjae Jeon * 6291e9ea7e0SNamjae Jeon * If @ctx->is_first is 'true', the search begins with @ctx->attr itself. If it 6301e9ea7e0SNamjae Jeon * is 'false', the search begins after @ctx->attr. 6311e9ea7e0SNamjae Jeon * 6321e9ea7e0SNamjae Jeon * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and 6331e9ea7e0SNamjae Jeon * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record 6341e9ea7e0SNamjae Jeon * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at 6351e9ea7e0SNamjae Jeon * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case 6361e9ea7e0SNamjae Jeon * sensitive. When @name is present, @name_len is the @name length in Unicode 6371e9ea7e0SNamjae Jeon * characters. 6381e9ea7e0SNamjae Jeon * 6391e9ea7e0SNamjae Jeon * If @name is not present (NULL), we assume that the unnamed attribute is 6401e9ea7e0SNamjae Jeon * being searched for. 6411e9ea7e0SNamjae Jeon * 6421e9ea7e0SNamjae Jeon * Finally, the resident attribute value @val is looked for, if present. If 6431e9ea7e0SNamjae Jeon * @val is not present (NULL), @val_len is ignored. 6441e9ea7e0SNamjae Jeon * 6451e9ea7e0SNamjae Jeon * ntfs_attr_find() only searches the specified mft record and it ignores the 6461e9ea7e0SNamjae Jeon * presence of an attribute list attribute (unless it is the one being searched 6471e9ea7e0SNamjae Jeon * for, obviously). If you need to take attribute lists into consideration, 6481e9ea7e0SNamjae Jeon * use ntfs_attr_lookup() instead (see below). This also means that you cannot 6491e9ea7e0SNamjae Jeon * use ntfs_attr_find() to search for extent records of non-resident 6501e9ea7e0SNamjae Jeon * attributes, as extents with lowest_vcn != 0 are usually described by the 6511e9ea7e0SNamjae Jeon * attribute list attribute only. - Note that it is possible that the first 6521e9ea7e0SNamjae Jeon * extent is only in the attribute list while the last extent is in the base 6531e9ea7e0SNamjae Jeon * mft record, so do not rely on being able to find the first extent in the 6541e9ea7e0SNamjae Jeon * base mft record. 6551e9ea7e0SNamjae Jeon * 6561e9ea7e0SNamjae Jeon * Warning: Never use @val when looking for attribute types which can be 6571e9ea7e0SNamjae Jeon * non-resident as this most likely will result in a crash! 6581e9ea7e0SNamjae Jeon */ 659495e90faSNamjae Jeon static int ntfs_attr_find(const __le32 type, const __le16 *name, 660495e90faSNamjae Jeon const u32 name_len, const u32 ic, 661495e90faSNamjae Jeon const u8 *val, const u32 val_len, struct ntfs_attr_search_ctx *ctx) 6621e9ea7e0SNamjae Jeon { 663495e90faSNamjae Jeon struct attr_record *a; 664495e90faSNamjae Jeon struct ntfs_volume *vol = ctx->ntfs_ino->vol; 665495e90faSNamjae Jeon __le16 *upcase = vol->upcase; 6661e9ea7e0SNamjae Jeon u32 upcase_len = vol->upcase_len; 667495e90faSNamjae Jeon unsigned int space; 6681e9ea7e0SNamjae Jeon 6691e9ea7e0SNamjae Jeon /* 6701e9ea7e0SNamjae Jeon * Iterate over attributes in mft record starting at @ctx->attr, or the 6711e9ea7e0SNamjae Jeon * attribute following that, if @ctx->is_first is 'true'. 6721e9ea7e0SNamjae Jeon */ 6731e9ea7e0SNamjae Jeon if (ctx->is_first) { 6741e9ea7e0SNamjae Jeon a = ctx->attr; 6751e9ea7e0SNamjae Jeon ctx->is_first = false; 6761e9ea7e0SNamjae Jeon } else 677495e90faSNamjae Jeon a = (struct attr_record *)((u8 *)ctx->attr + 6781e9ea7e0SNamjae Jeon le32_to_cpu(ctx->attr->length)); 679495e90faSNamjae Jeon for (;; a = (struct attr_record *)((u8 *)a + le32_to_cpu(a->length))) { 680495e90faSNamjae Jeon if ((u8 *)a < (u8 *)ctx->mrec || (u8 *)a > (u8 *)ctx->mrec + 681495e90faSNamjae Jeon le32_to_cpu(ctx->mrec->bytes_allocated)) 6821e9ea7e0SNamjae Jeon break; 6831e9ea7e0SNamjae Jeon 684495e90faSNamjae Jeon space = le32_to_cpu(ctx->mrec->bytes_in_use) - ((u8 *)a - (u8 *)ctx->mrec); 685495e90faSNamjae Jeon if ((space < offsetof(struct attr_record, data.resident.reserved) + 1 || 686495e90faSNamjae Jeon space < le32_to_cpu(a->length)) && (space < 4 || a->type != AT_END)) 6871e9ea7e0SNamjae Jeon break; 6881e9ea7e0SNamjae Jeon 6891e9ea7e0SNamjae Jeon ctx->attr = a; 690495e90faSNamjae Jeon if (((type != AT_UNUSED) && (le32_to_cpu(a->type) > le32_to_cpu(type))) || 691495e90faSNamjae Jeon a->type == AT_END) 6921e9ea7e0SNamjae Jeon return -ENOENT; 6931e9ea7e0SNamjae Jeon if (unlikely(!a->length)) 6941e9ea7e0SNamjae Jeon break; 695495e90faSNamjae Jeon if (type == AT_UNUSED) 696495e90faSNamjae Jeon return 0; 6971e9ea7e0SNamjae Jeon if (a->type != type) 6981e9ea7e0SNamjae Jeon continue; 6991e9ea7e0SNamjae Jeon /* 7001e9ea7e0SNamjae Jeon * If @name is present, compare the two names. If @name is 7011e9ea7e0SNamjae Jeon * missing, assume we want an unnamed attribute. 7021e9ea7e0SNamjae Jeon */ 703495e90faSNamjae Jeon if (!name || name == AT_UNNAMED) { 7041e9ea7e0SNamjae Jeon /* The search failed if the found attribute is named. */ 7051e9ea7e0SNamjae Jeon if (a->name_length) 7061e9ea7e0SNamjae Jeon return -ENOENT; 707495e90faSNamjae Jeon } else { 708495e90faSNamjae Jeon if (a->name_length && ((le16_to_cpu(a->name_offset) + 709495e90faSNamjae Jeon a->name_length * sizeof(__le16)) > 710495e90faSNamjae Jeon le32_to_cpu(a->length))) { 711d9038d99SNamjae Jeon ntfs_error(vol->sb, "Corrupt attribute name in MFT record %llu\n", 712d9038d99SNamjae Jeon ctx->ntfs_ino->mft_no); 713495e90faSNamjae Jeon break; 714495e90faSNamjae Jeon } 715495e90faSNamjae Jeon 716495e90faSNamjae Jeon if (!ntfs_are_names_equal(name, name_len, 717495e90faSNamjae Jeon (__le16 *)((u8 *)a + le16_to_cpu(a->name_offset)), 7181e9ea7e0SNamjae Jeon a->name_length, ic, upcase, upcase_len)) { 7191e9ea7e0SNamjae Jeon register int rc; 7201e9ea7e0SNamjae Jeon 7211e9ea7e0SNamjae Jeon rc = ntfs_collate_names(name, name_len, 722495e90faSNamjae Jeon (__le16 *)((u8 *)a + le16_to_cpu(a->name_offset)), 7231e9ea7e0SNamjae Jeon a->name_length, 1, IGNORE_CASE, 7241e9ea7e0SNamjae Jeon upcase, upcase_len); 7251e9ea7e0SNamjae Jeon /* 7261e9ea7e0SNamjae Jeon * If @name collates before a->name, there is no 7271e9ea7e0SNamjae Jeon * matching attribute. 7281e9ea7e0SNamjae Jeon */ 7291e9ea7e0SNamjae Jeon if (rc == -1) 7301e9ea7e0SNamjae Jeon return -ENOENT; 7311e9ea7e0SNamjae Jeon /* If the strings are not equal, continue search. */ 7321e9ea7e0SNamjae Jeon if (rc) 7331e9ea7e0SNamjae Jeon continue; 7341e9ea7e0SNamjae Jeon rc = ntfs_collate_names(name, name_len, 735495e90faSNamjae Jeon (__le16 *)((u8 *)a + le16_to_cpu(a->name_offset)), 7361e9ea7e0SNamjae Jeon a->name_length, 1, CASE_SENSITIVE, 7371e9ea7e0SNamjae Jeon upcase, upcase_len); 7381e9ea7e0SNamjae Jeon if (rc == -1) 7391e9ea7e0SNamjae Jeon return -ENOENT; 7401e9ea7e0SNamjae Jeon if (rc) 7411e9ea7e0SNamjae Jeon continue; 7421e9ea7e0SNamjae Jeon } 743495e90faSNamjae Jeon } 7446ceb4cc8SHyunchul Lee 7456ceb4cc8SHyunchul Lee /* Validate attribute's value offset/length */ 7466ceb4cc8SHyunchul Lee if (!a->non_resident) { 7476ceb4cc8SHyunchul Lee u32 min_len; 7486ceb4cc8SHyunchul Lee u32 value_length = le32_to_cpu(a->data.resident.value_length); 7496ceb4cc8SHyunchul Lee u16 value_offset = le16_to_cpu(a->data.resident.value_offset); 7506ceb4cc8SHyunchul Lee 7516ceb4cc8SHyunchul Lee if (value_length > le32_to_cpu(a->length) || 7526ceb4cc8SHyunchul Lee value_offset > le32_to_cpu(a->length) - value_length) 7536ceb4cc8SHyunchul Lee break; 7546ceb4cc8SHyunchul Lee 7556ceb4cc8SHyunchul Lee min_len = ntfs_resident_attr_min_value_length(a->type); 7566ceb4cc8SHyunchul Lee if (min_len && value_length < min_len) { 7576ceb4cc8SHyunchul Lee ntfs_error(vol->sb, 7586ceb4cc8SHyunchul Lee "Too small %#x resident attribute value in MFT record %lld\n", 7596ceb4cc8SHyunchul Lee le32_to_cpu(a->type), (long long)ctx->ntfs_ino->mft_no); 7606ceb4cc8SHyunchul Lee break; 7616ceb4cc8SHyunchul Lee } 7626ceb4cc8SHyunchul Lee } else { 7636ceb4cc8SHyunchul Lee u32 min_len; 7646ceb4cc8SHyunchul Lee u16 mp_offset; 7656ceb4cc8SHyunchul Lee 7666ceb4cc8SHyunchul Lee min_len = offsetof(struct attr_record, data.non_resident.initialized_size) + 7676ceb4cc8SHyunchul Lee sizeof(a->data.non_resident.initialized_size); 7686ceb4cc8SHyunchul Lee if (le32_to_cpu(a->length) < min_len) 7696ceb4cc8SHyunchul Lee break; 7706ceb4cc8SHyunchul Lee 7716ceb4cc8SHyunchul Lee mp_offset = le16_to_cpu(a->data.non_resident.mapping_pairs_offset); 7726ceb4cc8SHyunchul Lee if (mp_offset < min_len || 7736ceb4cc8SHyunchul Lee mp_offset > le32_to_cpu(a->length)) 7746ceb4cc8SHyunchul Lee break; 7756ceb4cc8SHyunchul Lee } 7766ceb4cc8SHyunchul Lee 7771e9ea7e0SNamjae Jeon /* 7781e9ea7e0SNamjae Jeon * The names match or @name not present and attribute is 7791e9ea7e0SNamjae Jeon * unnamed. If no @val specified, we have found the attribute 7801e9ea7e0SNamjae Jeon * and are done. 7811e9ea7e0SNamjae Jeon */ 7826ceb4cc8SHyunchul Lee if (!val || a->non_resident) 7831e9ea7e0SNamjae Jeon return 0; 7841e9ea7e0SNamjae Jeon /* @val is present; compare values. */ 7851e9ea7e0SNamjae Jeon else { 7866ceb4cc8SHyunchul Lee u32 value_length = le32_to_cpu(a->data.resident.value_length); 7876ceb4cc8SHyunchul Lee int rc; 7881e9ea7e0SNamjae Jeon 7891e9ea7e0SNamjae Jeon rc = memcmp(val, (u8 *)a + le16_to_cpu( 7901e9ea7e0SNamjae Jeon a->data.resident.value_offset), 7916ceb4cc8SHyunchul Lee min_t(u32, val_len, value_length)); 7921e9ea7e0SNamjae Jeon /* 7931e9ea7e0SNamjae Jeon * If @val collates before the current attribute's 7941e9ea7e0SNamjae Jeon * value, there is no matching attribute. 7951e9ea7e0SNamjae Jeon */ 7961e9ea7e0SNamjae Jeon if (!rc) { 7976ceb4cc8SHyunchul Lee if (val_len == value_length) 7981e9ea7e0SNamjae Jeon return 0; 7996ceb4cc8SHyunchul Lee if (val_len < value_length) 8001e9ea7e0SNamjae Jeon return -ENOENT; 8011e9ea7e0SNamjae Jeon } else if (rc < 0) 8021e9ea7e0SNamjae Jeon return -ENOENT; 8031e9ea7e0SNamjae Jeon } 8041e9ea7e0SNamjae Jeon } 8056ceb4cc8SHyunchul Lee ntfs_error(vol->sb, "mft %#llx, type %#x is corrupt. Run chkdsk.", 8066ceb4cc8SHyunchul Lee (long long)ctx->ntfs_ino->mft_no, le32_to_cpu(type)); 8071e9ea7e0SNamjae Jeon NVolSetErrors(vol); 8081e9ea7e0SNamjae Jeon return -EIO; 8091e9ea7e0SNamjae Jeon } 8101e9ea7e0SNamjae Jeon 811495e90faSNamjae Jeon void ntfs_attr_name_free(unsigned char **name) 8121e9ea7e0SNamjae Jeon { 813495e90faSNamjae Jeon if (*name) { 814495e90faSNamjae Jeon kfree(*name); 815495e90faSNamjae Jeon *name = NULL; 816495e90faSNamjae Jeon } 817495e90faSNamjae Jeon } 8181e9ea7e0SNamjae Jeon 819495e90faSNamjae Jeon char *ntfs_attr_name_get(const struct ntfs_volume *vol, const __le16 *uname, 820495e90faSNamjae Jeon const int uname_len) 821495e90faSNamjae Jeon { 822495e90faSNamjae Jeon unsigned char *name = NULL; 823495e90faSNamjae Jeon int name_len; 824495e90faSNamjae Jeon 825495e90faSNamjae Jeon name_len = ntfs_ucstonls(vol, uname, uname_len, &name, 0); 826495e90faSNamjae Jeon if (name_len < 0) { 827495e90faSNamjae Jeon ntfs_error(vol->sb, "ntfs_ucstonls error"); 828495e90faSNamjae Jeon /* This function when returns -1, memory for name might 829495e90faSNamjae Jeon * be allocated. So lets free this memory. 830495e90faSNamjae Jeon */ 831495e90faSNamjae Jeon ntfs_attr_name_free(&name); 832495e90faSNamjae Jeon return NULL; 833495e90faSNamjae Jeon 834495e90faSNamjae Jeon } else if (name_len > 0) 835495e90faSNamjae Jeon return name; 836495e90faSNamjae Jeon 837495e90faSNamjae Jeon ntfs_attr_name_free(&name); 838495e90faSNamjae Jeon return NULL; 839495e90faSNamjae Jeon } 840495e90faSNamjae Jeon 841495e90faSNamjae Jeon int load_attribute_list(struct ntfs_inode *base_ni, u8 *al_start, const s64 size) 842495e90faSNamjae Jeon { 843495e90faSNamjae Jeon struct inode *attr_vi = NULL; 844495e90faSNamjae Jeon u8 *al; 845495e90faSNamjae Jeon struct attr_list_entry *ale; 846495e90faSNamjae Jeon 847495e90faSNamjae Jeon if (!al_start || size <= 0) 8481e9ea7e0SNamjae Jeon return -EINVAL; 849495e90faSNamjae Jeon 850495e90faSNamjae Jeon attr_vi = ntfs_attr_iget(VFS_I(base_ni), AT_ATTRIBUTE_LIST, AT_UNNAMED, 0); 851495e90faSNamjae Jeon if (IS_ERR(attr_vi)) { 852495e90faSNamjae Jeon ntfs_error(base_ni->vol->sb, 853d9038d99SNamjae Jeon "Failed to open an inode for Attribute list, mft = %llu", 854495e90faSNamjae Jeon base_ni->mft_no); 855495e90faSNamjae Jeon return PTR_ERR(attr_vi); 856495e90faSNamjae Jeon } 857495e90faSNamjae Jeon 858495e90faSNamjae Jeon if (ntfs_inode_attr_pread(attr_vi, 0, size, al_start) != size) { 859495e90faSNamjae Jeon iput(attr_vi); 860495e90faSNamjae Jeon ntfs_error(base_ni->vol->sb, 861d9038d99SNamjae Jeon "Failed to read attribute list, mft = %llu", 862495e90faSNamjae Jeon base_ni->mft_no); 863495e90faSNamjae Jeon return -EIO; 864495e90faSNamjae Jeon } 865495e90faSNamjae Jeon iput(attr_vi); 866495e90faSNamjae Jeon 867495e90faSNamjae Jeon for (al = al_start; al < al_start + size; al += le16_to_cpu(ale->length)) { 868495e90faSNamjae Jeon ale = (struct attr_list_entry *)al; 869495e90faSNamjae Jeon if (ale->name_offset != sizeof(struct attr_list_entry)) 870495e90faSNamjae Jeon break; 871495e90faSNamjae Jeon if (le16_to_cpu(ale->length) <= ale->name_offset + ale->name_length || 872495e90faSNamjae Jeon al + le16_to_cpu(ale->length) > al_start + size) 873495e90faSNamjae Jeon break; 874495e90faSNamjae Jeon if (ale->type == AT_UNUSED) 875495e90faSNamjae Jeon break; 876495e90faSNamjae Jeon if (MSEQNO_LE(ale->mft_reference) == 0) 877495e90faSNamjae Jeon break; 878495e90faSNamjae Jeon } 879495e90faSNamjae Jeon if (al != al_start + size) { 880d9038d99SNamjae Jeon ntfs_error(base_ni->vol->sb, "Corrupt attribute list, mft = %llu", 881495e90faSNamjae Jeon base_ni->mft_no); 882495e90faSNamjae Jeon return -EIO; 883495e90faSNamjae Jeon } 8841e9ea7e0SNamjae Jeon return 0; 8851e9ea7e0SNamjae Jeon } 8861e9ea7e0SNamjae Jeon 887495e90faSNamjae Jeon /* 8881e9ea7e0SNamjae Jeon * ntfs_external_attr_find - find an attribute in the attribute list of an inode 8891e9ea7e0SNamjae Jeon * @type: attribute type to find 8901e9ea7e0SNamjae Jeon * @name: attribute name to find (optional, i.e. NULL means don't care) 8911e9ea7e0SNamjae Jeon * @name_len: attribute name length (only needed if @name present) 8921e9ea7e0SNamjae Jeon * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 8931e9ea7e0SNamjae Jeon * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 8941e9ea7e0SNamjae Jeon * @val: attribute value to find (optional, resident attributes only) 8951e9ea7e0SNamjae Jeon * @val_len: attribute value length 8961e9ea7e0SNamjae Jeon * @ctx: search context with mft record and attribute to search from 8971e9ea7e0SNamjae Jeon * 8981e9ea7e0SNamjae Jeon * You should not need to call this function directly. Use ntfs_attr_lookup() 8991e9ea7e0SNamjae Jeon * instead. 9001e9ea7e0SNamjae Jeon * 9011e9ea7e0SNamjae Jeon * Find an attribute by searching the attribute list for the corresponding 9021e9ea7e0SNamjae Jeon * attribute list entry. Having found the entry, map the mft record if the 9031e9ea7e0SNamjae Jeon * attribute is in a different mft record/inode, ntfs_attr_find() the attribute 9041e9ea7e0SNamjae Jeon * in there and return it. 9051e9ea7e0SNamjae Jeon * 9061e9ea7e0SNamjae Jeon * On first search @ctx->ntfs_ino must be the base mft record and @ctx must 9071e9ea7e0SNamjae Jeon * have been obtained from a call to ntfs_attr_get_search_ctx(). On subsequent 9081e9ea7e0SNamjae Jeon * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is 9091e9ea7e0SNamjae Jeon * then the base inode). 9101e9ea7e0SNamjae Jeon * 9111e9ea7e0SNamjae Jeon * After finishing with the attribute/mft record you need to call 9121e9ea7e0SNamjae Jeon * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 9131e9ea7e0SNamjae Jeon * mapped inodes, etc). 9141e9ea7e0SNamjae Jeon * 9151e9ea7e0SNamjae Jeon * If the attribute is found, ntfs_external_attr_find() returns 0 and 9161e9ea7e0SNamjae Jeon * @ctx->attr will point to the found attribute. @ctx->mrec will point to the 9171e9ea7e0SNamjae Jeon * mft record in which @ctx->attr is located and @ctx->al_entry will point to 9181e9ea7e0SNamjae Jeon * the attribute list entry for the attribute. 9191e9ea7e0SNamjae Jeon * 9201e9ea7e0SNamjae Jeon * If the attribute is not found, ntfs_external_attr_find() returns -ENOENT and 9211e9ea7e0SNamjae Jeon * @ctx->attr will point to the attribute in the base mft record before which 9221e9ea7e0SNamjae Jeon * the attribute being searched for would need to be inserted if such an action 9231e9ea7e0SNamjae Jeon * were to be desired. @ctx->mrec will point to the mft record in which 9241e9ea7e0SNamjae Jeon * @ctx->attr is located and @ctx->al_entry will point to the attribute list 9251e9ea7e0SNamjae Jeon * entry of the attribute before which the attribute being searched for would 9261e9ea7e0SNamjae Jeon * need to be inserted if such an action were to be desired. 9271e9ea7e0SNamjae Jeon * 9281e9ea7e0SNamjae Jeon * Thus to insert the not found attribute, one wants to add the attribute to 9291e9ea7e0SNamjae Jeon * @ctx->mrec (the base mft record) and if there is not enough space, the 9301e9ea7e0SNamjae Jeon * attribute should be placed in a newly allocated extent mft record. The 9311e9ea7e0SNamjae Jeon * attribute list entry for the inserted attribute should be inserted in the 9321e9ea7e0SNamjae Jeon * attribute list attribute at @ctx->al_entry. 9331e9ea7e0SNamjae Jeon * 9341e9ea7e0SNamjae Jeon * On actual error, ntfs_external_attr_find() returns -EIO. In this case 9351e9ea7e0SNamjae Jeon * @ctx->attr is undefined and in particular do not rely on it not changing. 9361e9ea7e0SNamjae Jeon */ 937495e90faSNamjae Jeon static int ntfs_external_attr_find(const __le32 type, 938495e90faSNamjae Jeon const __le16 *name, const u32 name_len, 939495e90faSNamjae Jeon const u32 ic, const s64 lowest_vcn, 940495e90faSNamjae Jeon const u8 *val, const u32 val_len, struct ntfs_attr_search_ctx *ctx) 9411e9ea7e0SNamjae Jeon { 942495e90faSNamjae Jeon struct ntfs_inode *base_ni = ctx->base_ntfs_ino, *ni = ctx->ntfs_ino; 943495e90faSNamjae Jeon struct ntfs_volume *vol; 944495e90faSNamjae Jeon struct attr_list_entry *al_entry, *next_al_entry; 9451e9ea7e0SNamjae Jeon u8 *al_start, *al_end; 946495e90faSNamjae Jeon struct attr_record *a; 947495e90faSNamjae Jeon __le16 *al_name; 9481e9ea7e0SNamjae Jeon u32 al_name_len; 949*a198a0c4SHyunchul Lee u32 attr_len, mft_free_len; 950495e90faSNamjae Jeon bool is_first_search = false; 9511e9ea7e0SNamjae Jeon int err = 0; 9521e9ea7e0SNamjae Jeon static const char *es = " Unmount and run chkdsk."; 9531e9ea7e0SNamjae Jeon 954d9038d99SNamjae Jeon ntfs_debug("Entering for inode 0x%llx, type 0x%x.", ni->mft_no, type); 9551e9ea7e0SNamjae Jeon if (!base_ni) { 9561e9ea7e0SNamjae Jeon /* First call happens with the base mft record. */ 9571e9ea7e0SNamjae Jeon base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino; 9581e9ea7e0SNamjae Jeon ctx->base_mrec = ctx->mrec; 959495e90faSNamjae Jeon ctx->mapped_base_mrec = ctx->mapped_mrec; 9601e9ea7e0SNamjae Jeon } 9611e9ea7e0SNamjae Jeon if (ni == base_ni) 9621e9ea7e0SNamjae Jeon ctx->base_attr = ctx->attr; 9631e9ea7e0SNamjae Jeon if (type == AT_END) 9641e9ea7e0SNamjae Jeon goto not_found; 9651e9ea7e0SNamjae Jeon vol = base_ni->vol; 9661e9ea7e0SNamjae Jeon al_start = base_ni->attr_list; 9671e9ea7e0SNamjae Jeon al_end = al_start + base_ni->attr_list_size; 968495e90faSNamjae Jeon if (!ctx->al_entry) { 969495e90faSNamjae Jeon ctx->al_entry = (struct attr_list_entry *)al_start; 970495e90faSNamjae Jeon is_first_search = true; 971495e90faSNamjae Jeon } 9721e9ea7e0SNamjae Jeon /* 9731e9ea7e0SNamjae Jeon * Iterate over entries in attribute list starting at @ctx->al_entry, 9741e9ea7e0SNamjae Jeon * or the entry following that, if @ctx->is_first is 'true'. 9751e9ea7e0SNamjae Jeon */ 9761e9ea7e0SNamjae Jeon if (ctx->is_first) { 9771e9ea7e0SNamjae Jeon al_entry = ctx->al_entry; 9781e9ea7e0SNamjae Jeon ctx->is_first = false; 979495e90faSNamjae Jeon /* 980495e90faSNamjae Jeon * If an enumeration and the first attribute is higher than 981495e90faSNamjae Jeon * the attribute list itself, need to return the attribute list 982495e90faSNamjae Jeon * attribute. 983495e90faSNamjae Jeon */ 984495e90faSNamjae Jeon if ((type == AT_UNUSED) && is_first_search && 985495e90faSNamjae Jeon le32_to_cpu(al_entry->type) > 986495e90faSNamjae Jeon le32_to_cpu(AT_ATTRIBUTE_LIST)) 987495e90faSNamjae Jeon goto find_attr_list_attr; 988495e90faSNamjae Jeon } else { 989495e90faSNamjae Jeon /* Check for small entry */ 990495e90faSNamjae Jeon if (((al_end - (u8 *)ctx->al_entry) < 991495e90faSNamjae Jeon (long)offsetof(struct attr_list_entry, name)) || 992495e90faSNamjae Jeon (le16_to_cpu(ctx->al_entry->length) & 7) || 993495e90faSNamjae Jeon (le16_to_cpu(ctx->al_entry->length) < offsetof(struct attr_list_entry, name))) 994495e90faSNamjae Jeon goto corrupt; 995495e90faSNamjae Jeon 996495e90faSNamjae Jeon al_entry = (struct attr_list_entry *)((u8 *)ctx->al_entry + 9971e9ea7e0SNamjae Jeon le16_to_cpu(ctx->al_entry->length)); 998495e90faSNamjae Jeon 999495e90faSNamjae Jeon if ((u8 *)al_entry == al_end) 1000495e90faSNamjae Jeon goto not_found; 1001495e90faSNamjae Jeon 1002495e90faSNamjae Jeon /* Preliminary check for small entry */ 1003495e90faSNamjae Jeon if ((al_end - (u8 *)al_entry) < 1004495e90faSNamjae Jeon (long)offsetof(struct attr_list_entry, name)) 1005495e90faSNamjae Jeon goto corrupt; 1006495e90faSNamjae Jeon 1007495e90faSNamjae Jeon /* 1008495e90faSNamjae Jeon * If this is an enumeration and the attribute list attribute 1009495e90faSNamjae Jeon * is the next one in the enumeration sequence, just return the 1010495e90faSNamjae Jeon * attribute list attribute from the base mft record as it is 1011495e90faSNamjae Jeon * not listed in the attribute list itself. 1012495e90faSNamjae Jeon */ 1013495e90faSNamjae Jeon if ((type == AT_UNUSED) && le32_to_cpu(ctx->al_entry->type) < 1014495e90faSNamjae Jeon le32_to_cpu(AT_ATTRIBUTE_LIST) && 1015495e90faSNamjae Jeon le32_to_cpu(al_entry->type) > 1016495e90faSNamjae Jeon le32_to_cpu(AT_ATTRIBUTE_LIST)) { 1017495e90faSNamjae Jeon find_attr_list_attr: 1018495e90faSNamjae Jeon 1019495e90faSNamjae Jeon /* Check for bogus calls. */ 1020495e90faSNamjae Jeon if (name || name_len || val || val_len || lowest_vcn) 1021495e90faSNamjae Jeon return -EINVAL; 1022495e90faSNamjae Jeon 1023495e90faSNamjae Jeon /* We want the base record. */ 1024495e90faSNamjae Jeon if (ctx->ntfs_ino != base_ni) 1025495e90faSNamjae Jeon unmap_mft_record(ctx->ntfs_ino); 1026495e90faSNamjae Jeon ctx->ntfs_ino = base_ni; 1027495e90faSNamjae Jeon ctx->mapped_mrec = ctx->mapped_base_mrec; 1028495e90faSNamjae Jeon ctx->mrec = ctx->base_mrec; 1029495e90faSNamjae Jeon ctx->is_first = true; 1030495e90faSNamjae Jeon 1031495e90faSNamjae Jeon /* Sanity checks are performed elsewhere. */ 1032495e90faSNamjae Jeon ctx->attr = (struct attr_record *)((u8 *)ctx->mrec + 1033495e90faSNamjae Jeon le16_to_cpu(ctx->mrec->attrs_offset)); 1034495e90faSNamjae Jeon 1035495e90faSNamjae Jeon /* Find the attribute list attribute. */ 1036495e90faSNamjae Jeon err = ntfs_attr_find(AT_ATTRIBUTE_LIST, NULL, 0, 1037495e90faSNamjae Jeon IGNORE_CASE, NULL, 0, ctx); 1038495e90faSNamjae Jeon 1039495e90faSNamjae Jeon /* 1040495e90faSNamjae Jeon * Setup the search context so the correct 1041495e90faSNamjae Jeon * attribute is returned next time round. 1042495e90faSNamjae Jeon */ 1043495e90faSNamjae Jeon ctx->al_entry = al_entry; 1044495e90faSNamjae Jeon ctx->is_first = true; 1045495e90faSNamjae Jeon 1046495e90faSNamjae Jeon /* Got it. Done. */ 1047495e90faSNamjae Jeon if (!err) 1048495e90faSNamjae Jeon return 0; 1049495e90faSNamjae Jeon 1050495e90faSNamjae Jeon /* Error! If other than not found return it. */ 1051495e90faSNamjae Jeon if (err != -ENOENT) 1052495e90faSNamjae Jeon return err; 1053495e90faSNamjae Jeon 1054495e90faSNamjae Jeon /* Not found?!? Absurd! */ 1055495e90faSNamjae Jeon ntfs_error(ctx->ntfs_ino->vol->sb, "Attribute list wasn't found"); 1056495e90faSNamjae Jeon return -EIO; 1057495e90faSNamjae Jeon } 1058495e90faSNamjae Jeon } 10591e9ea7e0SNamjae Jeon for (;; al_entry = next_al_entry) { 10601e9ea7e0SNamjae Jeon /* Out of bounds check. */ 10611e9ea7e0SNamjae Jeon if ((u8 *)al_entry < base_ni->attr_list || 10621e9ea7e0SNamjae Jeon (u8 *)al_entry > al_end) 10631e9ea7e0SNamjae Jeon break; /* Inode is corrupt. */ 10641e9ea7e0SNamjae Jeon ctx->al_entry = al_entry; 10651e9ea7e0SNamjae Jeon /* Catch the end of the attribute list. */ 10661e9ea7e0SNamjae Jeon if ((u8 *)al_entry == al_end) 10671e9ea7e0SNamjae Jeon goto not_found; 1068495e90faSNamjae Jeon 1069495e90faSNamjae Jeon if ((((u8 *)al_entry + offsetof(struct attr_list_entry, name)) > al_end) || 1070495e90faSNamjae Jeon ((u8 *)al_entry + le16_to_cpu(al_entry->length) > al_end) || 1071495e90faSNamjae Jeon (le16_to_cpu(al_entry->length) & 7) || 1072495e90faSNamjae Jeon (le16_to_cpu(al_entry->length) < 1073495e90faSNamjae Jeon offsetof(struct attr_list_entry, name_length)) || 1074495e90faSNamjae Jeon (al_entry->name_length && ((u8 *)al_entry + al_entry->name_offset + 1075495e90faSNamjae Jeon al_entry->name_length * sizeof(__le16)) > al_end)) 1076495e90faSNamjae Jeon break; /* corrupt */ 1077495e90faSNamjae Jeon 1078495e90faSNamjae Jeon next_al_entry = (struct attr_list_entry *)((u8 *)al_entry + 10791e9ea7e0SNamjae Jeon le16_to_cpu(al_entry->length)); 1080495e90faSNamjae Jeon if (type != AT_UNUSED) { 10811e9ea7e0SNamjae Jeon if (le32_to_cpu(al_entry->type) > le32_to_cpu(type)) 10821e9ea7e0SNamjae Jeon goto not_found; 10831e9ea7e0SNamjae Jeon if (type != al_entry->type) 10841e9ea7e0SNamjae Jeon continue; 1085495e90faSNamjae Jeon } 10861e9ea7e0SNamjae Jeon /* 10871e9ea7e0SNamjae Jeon * If @name is present, compare the two names. If @name is 10881e9ea7e0SNamjae Jeon * missing, assume we want an unnamed attribute. 10891e9ea7e0SNamjae Jeon */ 10901e9ea7e0SNamjae Jeon al_name_len = al_entry->name_length; 1091495e90faSNamjae Jeon al_name = (__le16 *)((u8 *)al_entry + al_entry->name_offset); 1092495e90faSNamjae Jeon 1093495e90faSNamjae Jeon /* 1094495e90faSNamjae Jeon * If !@type we want the attribute represented by this 1095495e90faSNamjae Jeon * attribute list entry. 1096495e90faSNamjae Jeon */ 1097495e90faSNamjae Jeon if (type == AT_UNUSED) 1098495e90faSNamjae Jeon goto is_enumeration; 1099495e90faSNamjae Jeon 1100495e90faSNamjae Jeon if (!name || name == AT_UNNAMED) { 11011e9ea7e0SNamjae Jeon if (al_name_len) 11021e9ea7e0SNamjae Jeon goto not_found; 11031e9ea7e0SNamjae Jeon } else if (!ntfs_are_names_equal(al_name, al_name_len, name, 11041e9ea7e0SNamjae Jeon name_len, ic, vol->upcase, vol->upcase_len)) { 11051e9ea7e0SNamjae Jeon register int rc; 11061e9ea7e0SNamjae Jeon 11071e9ea7e0SNamjae Jeon rc = ntfs_collate_names(name, name_len, al_name, 11081e9ea7e0SNamjae Jeon al_name_len, 1, IGNORE_CASE, 11091e9ea7e0SNamjae Jeon vol->upcase, vol->upcase_len); 11101e9ea7e0SNamjae Jeon /* 11111e9ea7e0SNamjae Jeon * If @name collates before al_name, there is no 11121e9ea7e0SNamjae Jeon * matching attribute. 11131e9ea7e0SNamjae Jeon */ 11141e9ea7e0SNamjae Jeon if (rc == -1) 11151e9ea7e0SNamjae Jeon goto not_found; 11161e9ea7e0SNamjae Jeon /* If the strings are not equal, continue search. */ 11171e9ea7e0SNamjae Jeon if (rc) 11181e9ea7e0SNamjae Jeon continue; 1119495e90faSNamjae Jeon 11201e9ea7e0SNamjae Jeon rc = ntfs_collate_names(name, name_len, al_name, 11211e9ea7e0SNamjae Jeon al_name_len, 1, CASE_SENSITIVE, 11221e9ea7e0SNamjae Jeon vol->upcase, vol->upcase_len); 11231e9ea7e0SNamjae Jeon if (rc == -1) 11241e9ea7e0SNamjae Jeon goto not_found; 11251e9ea7e0SNamjae Jeon if (rc) 11261e9ea7e0SNamjae Jeon continue; 11271e9ea7e0SNamjae Jeon } 11281e9ea7e0SNamjae Jeon /* 11291e9ea7e0SNamjae Jeon * The names match or @name not present and attribute is 11301e9ea7e0SNamjae Jeon * unnamed. Now check @lowest_vcn. Continue search if the 11311e9ea7e0SNamjae Jeon * next attribute list entry still fits @lowest_vcn. Otherwise 11321e9ea7e0SNamjae Jeon * we have reached the right one or the search has failed. 11331e9ea7e0SNamjae Jeon */ 11341e9ea7e0SNamjae Jeon if (lowest_vcn && (u8 *)next_al_entry >= al_start && 11351e9ea7e0SNamjae Jeon (u8 *)next_al_entry + 6 < al_end && 11361e9ea7e0SNamjae Jeon (u8 *)next_al_entry + le16_to_cpu( 11371e9ea7e0SNamjae Jeon next_al_entry->length) <= al_end && 1138495e90faSNamjae Jeon le64_to_cpu(next_al_entry->lowest_vcn) <= 11391e9ea7e0SNamjae Jeon lowest_vcn && 11401e9ea7e0SNamjae Jeon next_al_entry->type == al_entry->type && 11411e9ea7e0SNamjae Jeon next_al_entry->name_length == al_name_len && 1142495e90faSNamjae Jeon ntfs_are_names_equal((__le16 *)((u8 *) 11431e9ea7e0SNamjae Jeon next_al_entry + 11441e9ea7e0SNamjae Jeon next_al_entry->name_offset), 11451e9ea7e0SNamjae Jeon next_al_entry->name_length, 11461e9ea7e0SNamjae Jeon al_name, al_name_len, CASE_SENSITIVE, 11471e9ea7e0SNamjae Jeon vol->upcase, vol->upcase_len)) 11481e9ea7e0SNamjae Jeon continue; 1149495e90faSNamjae Jeon 1150495e90faSNamjae Jeon is_enumeration: 11511e9ea7e0SNamjae Jeon if (MREF_LE(al_entry->mft_reference) == ni->mft_no) { 11521e9ea7e0SNamjae Jeon if (MSEQNO_LE(al_entry->mft_reference) != ni->seq_no) { 1153495e90faSNamjae Jeon ntfs_error(vol->sb, 1154d9038d99SNamjae Jeon "Found stale mft reference in attribute list of base inode 0x%llx.%s", 11551e9ea7e0SNamjae Jeon base_ni->mft_no, es); 11561e9ea7e0SNamjae Jeon err = -EIO; 11571e9ea7e0SNamjae Jeon break; 11581e9ea7e0SNamjae Jeon } 11591e9ea7e0SNamjae Jeon } else { /* Mft references do not match. */ 11601e9ea7e0SNamjae Jeon /* If there is a mapped record unmap it first. */ 11611e9ea7e0SNamjae Jeon if (ni != base_ni) 11621e9ea7e0SNamjae Jeon unmap_extent_mft_record(ni); 11631e9ea7e0SNamjae Jeon /* Do we want the base record back? */ 11641e9ea7e0SNamjae Jeon if (MREF_LE(al_entry->mft_reference) == 11651e9ea7e0SNamjae Jeon base_ni->mft_no) { 11661e9ea7e0SNamjae Jeon ni = ctx->ntfs_ino = base_ni; 11671e9ea7e0SNamjae Jeon ctx->mrec = ctx->base_mrec; 1168495e90faSNamjae Jeon ctx->mapped_mrec = ctx->mapped_base_mrec; 11691e9ea7e0SNamjae Jeon } else { 11701e9ea7e0SNamjae Jeon /* We want an extent record. */ 11711e9ea7e0SNamjae Jeon ctx->mrec = map_extent_mft_record(base_ni, 11721e9ea7e0SNamjae Jeon le64_to_cpu( 11731e9ea7e0SNamjae Jeon al_entry->mft_reference), &ni); 11741e9ea7e0SNamjae Jeon if (IS_ERR(ctx->mrec)) { 1175495e90faSNamjae Jeon ntfs_error(vol->sb, 1176d9038d99SNamjae Jeon "Failed to map extent mft record 0x%lx of base inode 0x%llx.%s", 1177495e90faSNamjae Jeon MREF_LE(al_entry->mft_reference), 11781e9ea7e0SNamjae Jeon base_ni->mft_no, es); 11791e9ea7e0SNamjae Jeon err = PTR_ERR(ctx->mrec); 11801e9ea7e0SNamjae Jeon if (err == -ENOENT) 11811e9ea7e0SNamjae Jeon err = -EIO; 11821e9ea7e0SNamjae Jeon /* Cause @ctx to be sanitized below. */ 11831e9ea7e0SNamjae Jeon ni = NULL; 11841e9ea7e0SNamjae Jeon break; 11851e9ea7e0SNamjae Jeon } 11861e9ea7e0SNamjae Jeon ctx->ntfs_ino = ni; 1187495e90faSNamjae Jeon ctx->mapped_mrec = true; 1188495e90faSNamjae Jeon 11891e9ea7e0SNamjae Jeon } 1190495e90faSNamjae Jeon } 1191495e90faSNamjae Jeon a = ctx->attr = (struct attr_record *)((u8 *)ctx->mrec + 11921e9ea7e0SNamjae Jeon le16_to_cpu(ctx->mrec->attrs_offset)); 11931e9ea7e0SNamjae Jeon /* 11941e9ea7e0SNamjae Jeon * ctx->vfs_ino, ctx->mrec, and ctx->attr now point to the 11951e9ea7e0SNamjae Jeon * mft record containing the attribute represented by the 11961e9ea7e0SNamjae Jeon * current al_entry. 11971e9ea7e0SNamjae Jeon */ 11981e9ea7e0SNamjae Jeon /* 11991e9ea7e0SNamjae Jeon * We could call into ntfs_attr_find() to find the right 12001e9ea7e0SNamjae Jeon * attribute in this mft record but this would be less 12011e9ea7e0SNamjae Jeon * efficient and not quite accurate as ntfs_attr_find() ignores 12021e9ea7e0SNamjae Jeon * the attribute instance numbers for example which become 12031e9ea7e0SNamjae Jeon * important when one plays with attribute lists. Also, 12041e9ea7e0SNamjae Jeon * because a proper match has been found in the attribute list 12051e9ea7e0SNamjae Jeon * entry above, the comparison can now be optimized. So it is 12061e9ea7e0SNamjae Jeon * worth re-implementing a simplified ntfs_attr_find() here. 12071e9ea7e0SNamjae Jeon */ 12081e9ea7e0SNamjae Jeon /* 12091e9ea7e0SNamjae Jeon * Use a manual loop so we can still use break and continue 12101e9ea7e0SNamjae Jeon * with the same meanings as above. 12111e9ea7e0SNamjae Jeon */ 12121e9ea7e0SNamjae Jeon do_next_attr_loop: 1213*a198a0c4SHyunchul Lee if ((u8 *)a < (u8 *)ctx->mrec || 1214*a198a0c4SHyunchul Lee (u8 *)a >= (u8 *)ctx->mrec + le32_to_cpu(ctx->mrec->bytes_allocated) || 1215*a198a0c4SHyunchul Lee (u8 *)a >= (u8 *)ctx->mrec + le32_to_cpu(ctx->mrec->bytes_in_use)) 12161e9ea7e0SNamjae Jeon break; 1217*a198a0c4SHyunchul Lee 1218*a198a0c4SHyunchul Lee mft_free_len = le32_to_cpu(ctx->mrec->bytes_in_use) - 1219*a198a0c4SHyunchul Lee ((u8 *)a - (u8 *)ctx->mrec); 1220*a198a0c4SHyunchul Lee if (mft_free_len >= sizeof(a->type) && a->type == AT_END) 1221495e90faSNamjae Jeon continue; 1222*a198a0c4SHyunchul Lee 1223*a198a0c4SHyunchul Lee attr_len = le32_to_cpu(a->length); 1224*a198a0c4SHyunchul Lee if (!attr_len || 1225*a198a0c4SHyunchul Lee attr_len < offsetof(struct attr_record, data.resident.reserved) + 1226*a198a0c4SHyunchul Lee sizeof(a->data.resident.reserved) || 1227*a198a0c4SHyunchul Lee attr_len > mft_free_len) 12281e9ea7e0SNamjae Jeon break; 1229*a198a0c4SHyunchul Lee 12301e9ea7e0SNamjae Jeon if (al_entry->instance != a->instance) 12311e9ea7e0SNamjae Jeon goto do_next_attr; 12321e9ea7e0SNamjae Jeon /* 12331e9ea7e0SNamjae Jeon * If the type and/or the name are mismatched between the 12341e9ea7e0SNamjae Jeon * attribute list entry and the attribute record, there is 12351e9ea7e0SNamjae Jeon * corruption so we break and return error EIO. 12361e9ea7e0SNamjae Jeon */ 12371e9ea7e0SNamjae Jeon if (al_entry->type != a->type) 12381e9ea7e0SNamjae Jeon break; 1239*a198a0c4SHyunchul Lee if (a->name_length && ((le16_to_cpu(a->name_offset) + 1240*a198a0c4SHyunchul Lee a->name_length * sizeof(__le16)) > attr_len)) 1241*a198a0c4SHyunchul Lee break; 1242495e90faSNamjae Jeon if (!ntfs_are_names_equal((__le16 *)((u8 *)a + 12431e9ea7e0SNamjae Jeon le16_to_cpu(a->name_offset)), a->name_length, 12441e9ea7e0SNamjae Jeon al_name, al_name_len, CASE_SENSITIVE, 12451e9ea7e0SNamjae Jeon vol->upcase, vol->upcase_len)) 12461e9ea7e0SNamjae Jeon break; 1247*a198a0c4SHyunchul Lee 12481e9ea7e0SNamjae Jeon ctx->attr = a; 1249*a198a0c4SHyunchul Lee 1250*a198a0c4SHyunchul Lee if (a->non_resident) { 1251*a198a0c4SHyunchul Lee u32 min_len; 1252*a198a0c4SHyunchul Lee u16 mp_offset; 1253*a198a0c4SHyunchul Lee 1254*a198a0c4SHyunchul Lee min_len = offsetof(struct attr_record, 1255*a198a0c4SHyunchul Lee data.non_resident.initialized_size) + 1256*a198a0c4SHyunchul Lee sizeof(a->data.non_resident.initialized_size); 1257*a198a0c4SHyunchul Lee 1258*a198a0c4SHyunchul Lee if (le32_to_cpu(a->length) < min_len) 1259*a198a0c4SHyunchul Lee break; 1260*a198a0c4SHyunchul Lee 1261*a198a0c4SHyunchul Lee mp_offset = 1262*a198a0c4SHyunchul Lee le16_to_cpu(a->data.non_resident.mapping_pairs_offset); 1263*a198a0c4SHyunchul Lee if (mp_offset < min_len || mp_offset > attr_len) 1264*a198a0c4SHyunchul Lee break; 1265*a198a0c4SHyunchul Lee } 1266*a198a0c4SHyunchul Lee 12671e9ea7e0SNamjae Jeon /* 12681e9ea7e0SNamjae Jeon * If no @val specified or @val specified and it matches, we 12691e9ea7e0SNamjae Jeon * have found it! 12701e9ea7e0SNamjae Jeon */ 1271*a198a0c4SHyunchul Lee if ((type == AT_UNUSED) || !val) 1272*a198a0c4SHyunchul Lee goto attr_found; 1273*a198a0c4SHyunchul Lee if (!a->non_resident) { 1274*a198a0c4SHyunchul Lee u32 value_length = le32_to_cpu(a->data.resident.value_length); 1275*a198a0c4SHyunchul Lee u16 value_offset = le16_to_cpu(a->data.resident.value_offset); 1276*a198a0c4SHyunchul Lee 1277*a198a0c4SHyunchul Lee if (attr_len < offsetof(struct attr_record, data.resident.reserved) + 1278*a198a0c4SHyunchul Lee sizeof(a->data.resident.reserved)) 1279*a198a0c4SHyunchul Lee break; 1280*a198a0c4SHyunchul Lee if (value_length > attr_len || value_offset > attr_len - value_length) 1281*a198a0c4SHyunchul Lee break; 1282*a198a0c4SHyunchul Lee 1283*a198a0c4SHyunchul Lee value_length = ntfs_resident_attr_min_value_length(a->type); 1284*a198a0c4SHyunchul Lee if (value_length && le32_to_cpu(a->data.resident.value_length) < 1285*a198a0c4SHyunchul Lee value_length) { 1286*a198a0c4SHyunchul Lee pr_err("Too small resident attribute value in MFT record %lld, type %#x\n", 1287*a198a0c4SHyunchul Lee (long long)ctx->ntfs_ino->mft_no, a->type); 1288*a198a0c4SHyunchul Lee break; 1289*a198a0c4SHyunchul Lee } 1290*a198a0c4SHyunchul Lee if (value_length == val_len && 1291*a198a0c4SHyunchul Lee !memcmp((u8 *)a + value_offset, val, val_len)) { 1292*a198a0c4SHyunchul Lee attr_found: 12931e9ea7e0SNamjae Jeon ntfs_debug("Done, found."); 12941e9ea7e0SNamjae Jeon return 0; 12951e9ea7e0SNamjae Jeon } 1296*a198a0c4SHyunchul Lee } 12971e9ea7e0SNamjae Jeon do_next_attr: 12981e9ea7e0SNamjae Jeon /* Proceed to the next attribute in the current mft record. */ 1299*a198a0c4SHyunchul Lee a = (struct attr_record *)((u8 *)a + attr_len); 13001e9ea7e0SNamjae Jeon goto do_next_attr_loop; 13011e9ea7e0SNamjae Jeon } 1302495e90faSNamjae Jeon 1303495e90faSNamjae Jeon corrupt: 13041e9ea7e0SNamjae Jeon if (ni != base_ni) { 13051e9ea7e0SNamjae Jeon if (ni) 13061e9ea7e0SNamjae Jeon unmap_extent_mft_record(ni); 13071e9ea7e0SNamjae Jeon ctx->ntfs_ino = base_ni; 13081e9ea7e0SNamjae Jeon ctx->mrec = ctx->base_mrec; 13091e9ea7e0SNamjae Jeon ctx->attr = ctx->base_attr; 1310495e90faSNamjae Jeon ctx->mapped_mrec = ctx->mapped_base_mrec; 13111e9ea7e0SNamjae Jeon } 1312495e90faSNamjae Jeon 1313495e90faSNamjae Jeon if (!err) { 1314*a198a0c4SHyunchul Lee u64 mft_no = ctx->al_entry ? MREF_LE(ctx->al_entry->mft_reference) : 0; 1315*a198a0c4SHyunchul Lee u32 type = ctx->al_entry ? le32_to_cpu(ctx->al_entry->type) : 0; 1316*a198a0c4SHyunchul Lee 1317495e90faSNamjae Jeon ntfs_error(vol->sb, 1318*a198a0c4SHyunchul Lee "Base inode 0x%llx contains corrupt attribute, mft %#llx, type %#x. %s", 1319*a198a0c4SHyunchul Lee (long long)base_ni->mft_no, (long long)mft_no, type, 1320*a198a0c4SHyunchul Lee "Unmount and run chkdsk."); 1321495e90faSNamjae Jeon err = -EIO; 1322495e90faSNamjae Jeon } 1323495e90faSNamjae Jeon 13241e9ea7e0SNamjae Jeon if (err != -ENOMEM) 13251e9ea7e0SNamjae Jeon NVolSetErrors(vol); 13261e9ea7e0SNamjae Jeon return err; 13271e9ea7e0SNamjae Jeon not_found: 13281e9ea7e0SNamjae Jeon /* 13291e9ea7e0SNamjae Jeon * If we were looking for AT_END, we reset the search context @ctx and 13301e9ea7e0SNamjae Jeon * use ntfs_attr_find() to seek to the end of the base mft record. 13311e9ea7e0SNamjae Jeon */ 1332495e90faSNamjae Jeon if (type == AT_UNUSED || type == AT_END) { 13331e9ea7e0SNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 13341e9ea7e0SNamjae Jeon return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len, 13351e9ea7e0SNamjae Jeon ctx); 13361e9ea7e0SNamjae Jeon } 13371e9ea7e0SNamjae Jeon /* 13381e9ea7e0SNamjae Jeon * The attribute was not found. Before we return, we want to ensure 13391e9ea7e0SNamjae Jeon * @ctx->mrec and @ctx->attr indicate the position at which the 13401e9ea7e0SNamjae Jeon * attribute should be inserted in the base mft record. Since we also 13411e9ea7e0SNamjae Jeon * want to preserve @ctx->al_entry we cannot reinitialize the search 13421e9ea7e0SNamjae Jeon * context using ntfs_attr_reinit_search_ctx() as this would set 13431e9ea7e0SNamjae Jeon * @ctx->al_entry to NULL. Thus we do the necessary bits manually (see 13441e9ea7e0SNamjae Jeon * ntfs_attr_init_search_ctx() below). Note, we _only_ preserve 13451e9ea7e0SNamjae Jeon * @ctx->al_entry as the remaining fields (base_*) are identical to 13461e9ea7e0SNamjae Jeon * their non base_ counterparts and we cannot set @ctx->base_attr 13471e9ea7e0SNamjae Jeon * correctly yet as we do not know what @ctx->attr will be set to by 13481e9ea7e0SNamjae Jeon * the call to ntfs_attr_find() below. 13491e9ea7e0SNamjae Jeon */ 13501e9ea7e0SNamjae Jeon if (ni != base_ni) 13511e9ea7e0SNamjae Jeon unmap_extent_mft_record(ni); 13521e9ea7e0SNamjae Jeon ctx->mrec = ctx->base_mrec; 1353495e90faSNamjae Jeon ctx->attr = (struct attr_record *)((u8 *)ctx->mrec + 13541e9ea7e0SNamjae Jeon le16_to_cpu(ctx->mrec->attrs_offset)); 13551e9ea7e0SNamjae Jeon ctx->is_first = true; 13561e9ea7e0SNamjae Jeon ctx->ntfs_ino = base_ni; 13571e9ea7e0SNamjae Jeon ctx->base_ntfs_ino = NULL; 13581e9ea7e0SNamjae Jeon ctx->base_mrec = NULL; 13591e9ea7e0SNamjae Jeon ctx->base_attr = NULL; 1360495e90faSNamjae Jeon ctx->mapped_mrec = ctx->mapped_base_mrec; 13611e9ea7e0SNamjae Jeon /* 13621e9ea7e0SNamjae Jeon * In case there are multiple matches in the base mft record, need to 13631e9ea7e0SNamjae Jeon * keep enumerating until we get an attribute not found response (or 13641e9ea7e0SNamjae Jeon * another error), otherwise we would keep returning the same attribute 13651e9ea7e0SNamjae Jeon * over and over again and all programs using us for enumeration would 13661e9ea7e0SNamjae Jeon * lock up in a tight loop. 13671e9ea7e0SNamjae Jeon */ 13681e9ea7e0SNamjae Jeon do { 13691e9ea7e0SNamjae Jeon err = ntfs_attr_find(type, name, name_len, ic, val, val_len, 13701e9ea7e0SNamjae Jeon ctx); 13711e9ea7e0SNamjae Jeon } while (!err); 13721e9ea7e0SNamjae Jeon ntfs_debug("Done, not found."); 13731e9ea7e0SNamjae Jeon return err; 13741e9ea7e0SNamjae Jeon } 13751e9ea7e0SNamjae Jeon 1376495e90faSNamjae Jeon /* 13771e9ea7e0SNamjae Jeon * ntfs_attr_lookup - find an attribute in an ntfs inode 13781e9ea7e0SNamjae Jeon * @type: attribute type to find 13791e9ea7e0SNamjae Jeon * @name: attribute name to find (optional, i.e. NULL means don't care) 13801e9ea7e0SNamjae Jeon * @name_len: attribute name length (only needed if @name present) 13811e9ea7e0SNamjae Jeon * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 13821e9ea7e0SNamjae Jeon * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 13831e9ea7e0SNamjae Jeon * @val: attribute value to find (optional, resident attributes only) 13841e9ea7e0SNamjae Jeon * @val_len: attribute value length 13851e9ea7e0SNamjae Jeon * @ctx: search context with mft record and attribute to search from 13861e9ea7e0SNamjae Jeon * 13871e9ea7e0SNamjae Jeon * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must 13881e9ea7e0SNamjae Jeon * be the base mft record and @ctx must have been obtained from a call to 13891e9ea7e0SNamjae Jeon * ntfs_attr_get_search_ctx(). 13901e9ea7e0SNamjae Jeon * 13911e9ea7e0SNamjae Jeon * This function transparently handles attribute lists and @ctx is used to 13921e9ea7e0SNamjae Jeon * continue searches where they were left off at. 13931e9ea7e0SNamjae Jeon * 13941e9ea7e0SNamjae Jeon * After finishing with the attribute/mft record you need to call 13951e9ea7e0SNamjae Jeon * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 13961e9ea7e0SNamjae Jeon * mapped inodes, etc). 13971e9ea7e0SNamjae Jeon * 13981e9ea7e0SNamjae Jeon * Return 0 if the search was successful and -errno if not. 13991e9ea7e0SNamjae Jeon * 14001e9ea7e0SNamjae Jeon * When 0, @ctx->attr is the found attribute and it is in mft record 14011e9ea7e0SNamjae Jeon * @ctx->mrec. If an attribute list attribute is present, @ctx->al_entry is 14021e9ea7e0SNamjae Jeon * the attribute list entry of the found attribute. 14031e9ea7e0SNamjae Jeon * 14041e9ea7e0SNamjae Jeon * When -ENOENT, @ctx->attr is the attribute which collates just after the 14051e9ea7e0SNamjae Jeon * attribute being searched for, i.e. if one wants to add the attribute to the 14061e9ea7e0SNamjae Jeon * mft record this is the correct place to insert it into. If an attribute 14071e9ea7e0SNamjae Jeon * list attribute is present, @ctx->al_entry is the attribute list entry which 14081e9ea7e0SNamjae Jeon * collates just after the attribute list entry of the attribute being searched 14091e9ea7e0SNamjae Jeon * for, i.e. if one wants to add the attribute to the mft record this is the 14101e9ea7e0SNamjae Jeon * correct place to insert its attribute list entry into. 14111e9ea7e0SNamjae Jeon */ 1412495e90faSNamjae Jeon int ntfs_attr_lookup(const __le32 type, const __le16 *name, 1413495e90faSNamjae Jeon const u32 name_len, const u32 ic, 1414495e90faSNamjae Jeon const s64 lowest_vcn, const u8 *val, const u32 val_len, 1415495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx) 14161e9ea7e0SNamjae Jeon { 1417495e90faSNamjae Jeon struct ntfs_inode *base_ni; 14181e9ea7e0SNamjae Jeon 14191e9ea7e0SNamjae Jeon ntfs_debug("Entering."); 14201e9ea7e0SNamjae Jeon if (ctx->base_ntfs_ino) 14211e9ea7e0SNamjae Jeon base_ni = ctx->base_ntfs_ino; 14221e9ea7e0SNamjae Jeon else 14231e9ea7e0SNamjae Jeon base_ni = ctx->ntfs_ino; 14241e9ea7e0SNamjae Jeon /* Sanity check, just for debugging really. */ 1425495e90faSNamjae Jeon if (!base_ni || !NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) 14261e9ea7e0SNamjae Jeon return ntfs_attr_find(type, name, name_len, ic, val, val_len, 14271e9ea7e0SNamjae Jeon ctx); 14281e9ea7e0SNamjae Jeon return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn, 14291e9ea7e0SNamjae Jeon val, val_len, ctx); 14301e9ea7e0SNamjae Jeon } 14311e9ea7e0SNamjae Jeon 14321e9ea7e0SNamjae Jeon /** 14331e9ea7e0SNamjae Jeon * ntfs_attr_init_search_ctx - initialize an attribute search context 14341e9ea7e0SNamjae Jeon * @ctx: attribute search context to initialize 14351e9ea7e0SNamjae Jeon * @ni: ntfs inode with which to initialize the search context 14361e9ea7e0SNamjae Jeon * @mrec: mft record with which to initialize the search context 14371e9ea7e0SNamjae Jeon * 14381e9ea7e0SNamjae Jeon * Initialize the attribute search context @ctx with @ni and @mrec. 14391e9ea7e0SNamjae Jeon */ 1440495e90faSNamjae Jeon static bool ntfs_attr_init_search_ctx(struct ntfs_attr_search_ctx *ctx, 1441495e90faSNamjae Jeon struct ntfs_inode *ni, struct mft_record *mrec) 14421e9ea7e0SNamjae Jeon { 1443495e90faSNamjae Jeon if (!mrec) { 1444495e90faSNamjae Jeon mrec = map_mft_record(ni); 1445495e90faSNamjae Jeon if (IS_ERR(mrec)) 1446495e90faSNamjae Jeon return false; 1447495e90faSNamjae Jeon ctx->mapped_mrec = true; 1448495e90faSNamjae Jeon } else { 1449495e90faSNamjae Jeon ctx->mapped_mrec = false; 14501e9ea7e0SNamjae Jeon } 14511e9ea7e0SNamjae Jeon 1452495e90faSNamjae Jeon ctx->mrec = mrec; 1453495e90faSNamjae Jeon /* Sanity checks are performed elsewhere. */ 1454495e90faSNamjae Jeon ctx->attr = (struct attr_record *)((u8 *)mrec + le16_to_cpu(mrec->attrs_offset)); 1455495e90faSNamjae Jeon ctx->is_first = true; 1456495e90faSNamjae Jeon ctx->ntfs_ino = ni; 1457495e90faSNamjae Jeon ctx->al_entry = NULL; 1458495e90faSNamjae Jeon ctx->base_ntfs_ino = NULL; 1459495e90faSNamjae Jeon ctx->base_mrec = NULL; 1460495e90faSNamjae Jeon ctx->base_attr = NULL; 1461495e90faSNamjae Jeon ctx->mapped_base_mrec = false; 1462495e90faSNamjae Jeon return true; 1463495e90faSNamjae Jeon } 1464495e90faSNamjae Jeon 1465495e90faSNamjae Jeon /* 14661e9ea7e0SNamjae Jeon * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context 14671e9ea7e0SNamjae Jeon * @ctx: attribute search context to reinitialize 14681e9ea7e0SNamjae Jeon * 14691e9ea7e0SNamjae Jeon * Reinitialize the attribute search context @ctx, unmapping an associated 14701e9ea7e0SNamjae Jeon * extent mft record if present, and initialize the search context again. 14711e9ea7e0SNamjae Jeon * 14721e9ea7e0SNamjae Jeon * This is used when a search for a new attribute is being started to reset 14731e9ea7e0SNamjae Jeon * the search context to the beginning. 14741e9ea7e0SNamjae Jeon */ 1475495e90faSNamjae Jeon void ntfs_attr_reinit_search_ctx(struct ntfs_attr_search_ctx *ctx) 14761e9ea7e0SNamjae Jeon { 1477495e90faSNamjae Jeon bool mapped_mrec; 1478495e90faSNamjae Jeon 14791e9ea7e0SNamjae Jeon if (likely(!ctx->base_ntfs_ino)) { 14801e9ea7e0SNamjae Jeon /* No attribute list. */ 14811e9ea7e0SNamjae Jeon ctx->is_first = true; 14821e9ea7e0SNamjae Jeon /* Sanity checks are performed elsewhere. */ 1483495e90faSNamjae Jeon ctx->attr = (struct attr_record *)((u8 *)ctx->mrec + 14841e9ea7e0SNamjae Jeon le16_to_cpu(ctx->mrec->attrs_offset)); 14851e9ea7e0SNamjae Jeon /* 14861e9ea7e0SNamjae Jeon * This needs resetting due to ntfs_external_attr_find() which 14871e9ea7e0SNamjae Jeon * can leave it set despite having zeroed ctx->base_ntfs_ino. 14881e9ea7e0SNamjae Jeon */ 14891e9ea7e0SNamjae Jeon ctx->al_entry = NULL; 14901e9ea7e0SNamjae Jeon return; 14911e9ea7e0SNamjae Jeon } /* Attribute list. */ 1492495e90faSNamjae Jeon if (ctx->ntfs_ino != ctx->base_ntfs_ino && ctx->ntfs_ino) 14931e9ea7e0SNamjae Jeon unmap_extent_mft_record(ctx->ntfs_ino); 1494495e90faSNamjae Jeon 1495495e90faSNamjae Jeon mapped_mrec = ctx->mapped_base_mrec; 14961e9ea7e0SNamjae Jeon ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec); 1497495e90faSNamjae Jeon ctx->mapped_mrec = mapped_mrec; 14981e9ea7e0SNamjae Jeon } 14991e9ea7e0SNamjae Jeon 1500495e90faSNamjae Jeon /* 15011e9ea7e0SNamjae Jeon * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context 15021e9ea7e0SNamjae Jeon * @ni: ntfs inode with which to initialize the search context 15031e9ea7e0SNamjae Jeon * @mrec: mft record with which to initialize the search context 15041e9ea7e0SNamjae Jeon * 15051e9ea7e0SNamjae Jeon * Allocate a new attribute search context, initialize it with @ni and @mrec, 15061e9ea7e0SNamjae Jeon * and return it. Return NULL if allocation failed. 15071e9ea7e0SNamjae Jeon */ 1508495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(struct ntfs_inode *ni, 1509495e90faSNamjae Jeon struct mft_record *mrec) 15101e9ea7e0SNamjae Jeon { 1511495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 1512495e90faSNamjae Jeon bool init; 15131e9ea7e0SNamjae Jeon 15141e9ea7e0SNamjae Jeon ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, GFP_NOFS); 1515495e90faSNamjae Jeon if (ctx) { 1516495e90faSNamjae Jeon init = ntfs_attr_init_search_ctx(ctx, ni, mrec); 1517495e90faSNamjae Jeon if (init == false) { 1518495e90faSNamjae Jeon kmem_cache_free(ntfs_attr_ctx_cache, ctx); 1519495e90faSNamjae Jeon ctx = NULL; 1520495e90faSNamjae Jeon } 1521495e90faSNamjae Jeon } 1522495e90faSNamjae Jeon 15231e9ea7e0SNamjae Jeon return ctx; 15241e9ea7e0SNamjae Jeon } 15251e9ea7e0SNamjae Jeon 1526495e90faSNamjae Jeon /* 15271e9ea7e0SNamjae Jeon * ntfs_attr_put_search_ctx - release an attribute search context 15281e9ea7e0SNamjae Jeon * @ctx: attribute search context to free 15291e9ea7e0SNamjae Jeon * 15301e9ea7e0SNamjae Jeon * Release the attribute search context @ctx, unmapping an associated extent 15311e9ea7e0SNamjae Jeon * mft record if present. 15321e9ea7e0SNamjae Jeon */ 1533495e90faSNamjae Jeon void ntfs_attr_put_search_ctx(struct ntfs_attr_search_ctx *ctx) 15341e9ea7e0SNamjae Jeon { 1535495e90faSNamjae Jeon if (ctx->mapped_mrec) 1536495e90faSNamjae Jeon unmap_mft_record(ctx->ntfs_ino); 1537495e90faSNamjae Jeon 1538495e90faSNamjae Jeon if (ctx->mapped_base_mrec && ctx->base_ntfs_ino && 1539495e90faSNamjae Jeon ctx->ntfs_ino != ctx->base_ntfs_ino) 1540495e90faSNamjae Jeon unmap_extent_mft_record(ctx->base_ntfs_ino); 15411e9ea7e0SNamjae Jeon kmem_cache_free(ntfs_attr_ctx_cache, ctx); 15421e9ea7e0SNamjae Jeon } 15431e9ea7e0SNamjae Jeon 1544495e90faSNamjae Jeon /* 15451e9ea7e0SNamjae Jeon * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file 15461e9ea7e0SNamjae Jeon * @vol: ntfs volume to which the attribute belongs 15471e9ea7e0SNamjae Jeon * @type: attribute type which to find 15481e9ea7e0SNamjae Jeon * 15491e9ea7e0SNamjae Jeon * Search for the attribute definition record corresponding to the attribute 15501e9ea7e0SNamjae Jeon * @type in the $AttrDef system file. 15511e9ea7e0SNamjae Jeon * 15521e9ea7e0SNamjae Jeon * Return the attribute type definition record if found and NULL if not found. 15531e9ea7e0SNamjae Jeon */ 1554495e90faSNamjae Jeon static struct attr_def *ntfs_attr_find_in_attrdef(const struct ntfs_volume *vol, 1555495e90faSNamjae Jeon const __le32 type) 15561e9ea7e0SNamjae Jeon { 1557495e90faSNamjae Jeon struct attr_def *ad; 15581e9ea7e0SNamjae Jeon 1559495e90faSNamjae Jeon WARN_ON(!type); 15601e9ea7e0SNamjae Jeon for (ad = vol->attrdef; (u8 *)ad - (u8 *)vol->attrdef < 15611e9ea7e0SNamjae Jeon vol->attrdef_size && ad->type; ++ad) { 15621e9ea7e0SNamjae Jeon /* We have not found it yet, carry on searching. */ 15631e9ea7e0SNamjae Jeon if (likely(le32_to_cpu(ad->type) < le32_to_cpu(type))) 15641e9ea7e0SNamjae Jeon continue; 15651e9ea7e0SNamjae Jeon /* We found the attribute; return it. */ 15661e9ea7e0SNamjae Jeon if (likely(ad->type == type)) 15671e9ea7e0SNamjae Jeon return ad; 15681e9ea7e0SNamjae Jeon /* We have gone too far already. No point in continuing. */ 15691e9ea7e0SNamjae Jeon break; 15701e9ea7e0SNamjae Jeon } 15711e9ea7e0SNamjae Jeon /* Attribute not found. */ 15721e9ea7e0SNamjae Jeon ntfs_debug("Attribute type 0x%x not found in $AttrDef.", 15731e9ea7e0SNamjae Jeon le32_to_cpu(type)); 15741e9ea7e0SNamjae Jeon return NULL; 15751e9ea7e0SNamjae Jeon } 15761e9ea7e0SNamjae Jeon 1577495e90faSNamjae Jeon /* 15781e9ea7e0SNamjae Jeon * ntfs_attr_size_bounds_check - check a size of an attribute type for validity 15791e9ea7e0SNamjae Jeon * @vol: ntfs volume to which the attribute belongs 15801e9ea7e0SNamjae Jeon * @type: attribute type which to check 15811e9ea7e0SNamjae Jeon * @size: size which to check 15821e9ea7e0SNamjae Jeon * 15831e9ea7e0SNamjae Jeon * Check whether the @size in bytes is valid for an attribute of @type on the 15841e9ea7e0SNamjae Jeon * ntfs volume @vol. This information is obtained from $AttrDef system file. 15851e9ea7e0SNamjae Jeon */ 1586495e90faSNamjae Jeon int ntfs_attr_size_bounds_check(const struct ntfs_volume *vol, const __le32 type, 15871e9ea7e0SNamjae Jeon const s64 size) 15881e9ea7e0SNamjae Jeon { 1589495e90faSNamjae Jeon struct attr_def *ad; 15901e9ea7e0SNamjae Jeon 1591495e90faSNamjae Jeon if (size < 0) 1592495e90faSNamjae Jeon return -EINVAL; 1593495e90faSNamjae Jeon 15941e9ea7e0SNamjae Jeon /* 15951e9ea7e0SNamjae Jeon * $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not 15961e9ea7e0SNamjae Jeon * listed in $AttrDef. 15971e9ea7e0SNamjae Jeon */ 15981e9ea7e0SNamjae Jeon if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024)) 15991e9ea7e0SNamjae Jeon return -ERANGE; 16001e9ea7e0SNamjae Jeon /* Get the $AttrDef entry for the attribute @type. */ 16011e9ea7e0SNamjae Jeon ad = ntfs_attr_find_in_attrdef(vol, type); 16021e9ea7e0SNamjae Jeon if (unlikely(!ad)) 16031e9ea7e0SNamjae Jeon return -ENOENT; 16041e9ea7e0SNamjae Jeon /* Do the bounds check. */ 1605495e90faSNamjae Jeon if (((le64_to_cpu(ad->min_size) > 0) && 1606495e90faSNamjae Jeon size < le64_to_cpu(ad->min_size)) || 1607495e90faSNamjae Jeon ((le64_to_cpu(ad->max_size) > 0) && size > 1608495e90faSNamjae Jeon le64_to_cpu(ad->max_size))) 16091e9ea7e0SNamjae Jeon return -ERANGE; 16101e9ea7e0SNamjae Jeon return 0; 16111e9ea7e0SNamjae Jeon } 16121e9ea7e0SNamjae Jeon 1613495e90faSNamjae Jeon /* 16141e9ea7e0SNamjae Jeon * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident 16151e9ea7e0SNamjae Jeon * @vol: ntfs volume to which the attribute belongs 16161e9ea7e0SNamjae Jeon * @type: attribute type which to check 16171e9ea7e0SNamjae Jeon * 16181e9ea7e0SNamjae Jeon * Check whether the attribute of @type on the ntfs volume @vol is allowed to 16191e9ea7e0SNamjae Jeon * be non-resident. This information is obtained from $AttrDef system file. 16201e9ea7e0SNamjae Jeon */ 1621495e90faSNamjae Jeon static int ntfs_attr_can_be_non_resident(const struct ntfs_volume *vol, 1622495e90faSNamjae Jeon const __le32 type) 16231e9ea7e0SNamjae Jeon { 1624495e90faSNamjae Jeon struct attr_def *ad; 16251e9ea7e0SNamjae Jeon 16261e9ea7e0SNamjae Jeon /* Find the attribute definition record in $AttrDef. */ 16271e9ea7e0SNamjae Jeon ad = ntfs_attr_find_in_attrdef(vol, type); 16281e9ea7e0SNamjae Jeon if (unlikely(!ad)) 16291e9ea7e0SNamjae Jeon return -ENOENT; 16301e9ea7e0SNamjae Jeon /* Check the flags and return the result. */ 16311e9ea7e0SNamjae Jeon if (ad->flags & ATTR_DEF_RESIDENT) 16321e9ea7e0SNamjae Jeon return -EPERM; 16331e9ea7e0SNamjae Jeon return 0; 16341e9ea7e0SNamjae Jeon } 16351e9ea7e0SNamjae Jeon 1636495e90faSNamjae Jeon /* 16371e9ea7e0SNamjae Jeon * ntfs_attr_can_be_resident - check if an attribute can be resident 16381e9ea7e0SNamjae Jeon * @vol: ntfs volume to which the attribute belongs 16391e9ea7e0SNamjae Jeon * @type: attribute type which to check 16401e9ea7e0SNamjae Jeon * 16411e9ea7e0SNamjae Jeon * Check whether the attribute of @type on the ntfs volume @vol is allowed to 16421e9ea7e0SNamjae Jeon * be resident. This information is derived from our ntfs knowledge and may 16431e9ea7e0SNamjae Jeon * not be completely accurate, especially when user defined attributes are 16441e9ea7e0SNamjae Jeon * present. Basically we allow everything to be resident except for index 16451e9ea7e0SNamjae Jeon * allocation and $EA attributes. 16461e9ea7e0SNamjae Jeon * 16471e9ea7e0SNamjae Jeon * Return 0 if the attribute is allowed to be non-resident and -EPERM if not. 16481e9ea7e0SNamjae Jeon * 16491e9ea7e0SNamjae Jeon * Warning: In the system file $MFT the attribute $Bitmap must be non-resident 16501e9ea7e0SNamjae Jeon * otherwise windows will not boot (blue screen of death)! We cannot 16511e9ea7e0SNamjae Jeon * check for this here as we do not know which inode's $Bitmap is 16521e9ea7e0SNamjae Jeon * being asked about so the caller needs to special case this. 16531e9ea7e0SNamjae Jeon */ 1654495e90faSNamjae Jeon int ntfs_attr_can_be_resident(const struct ntfs_volume *vol, const __le32 type) 16551e9ea7e0SNamjae Jeon { 16561e9ea7e0SNamjae Jeon if (type == AT_INDEX_ALLOCATION) 16571e9ea7e0SNamjae Jeon return -EPERM; 16581e9ea7e0SNamjae Jeon return 0; 16591e9ea7e0SNamjae Jeon } 16601e9ea7e0SNamjae Jeon 1661495e90faSNamjae Jeon /* 16621e9ea7e0SNamjae Jeon * ntfs_attr_record_resize - resize an attribute record 16631e9ea7e0SNamjae Jeon * @m: mft record containing attribute record 16641e9ea7e0SNamjae Jeon * @a: attribute record to resize 16651e9ea7e0SNamjae Jeon * @new_size: new size in bytes to which to resize the attribute record @a 16661e9ea7e0SNamjae Jeon * 16671e9ea7e0SNamjae Jeon * Resize the attribute record @a, i.e. the resident part of the attribute, in 16681e9ea7e0SNamjae Jeon * the mft record @m to @new_size bytes. 16691e9ea7e0SNamjae Jeon */ 1670495e90faSNamjae Jeon int ntfs_attr_record_resize(struct mft_record *m, struct attr_record *a, u32 new_size) 16711e9ea7e0SNamjae Jeon { 1672495e90faSNamjae Jeon u32 old_size, alloc_size, attr_size; 1673495e90faSNamjae Jeon 1674495e90faSNamjae Jeon old_size = le32_to_cpu(m->bytes_in_use); 1675495e90faSNamjae Jeon alloc_size = le32_to_cpu(m->bytes_allocated); 1676495e90faSNamjae Jeon attr_size = le32_to_cpu(a->length); 1677495e90faSNamjae Jeon 1678495e90faSNamjae Jeon ntfs_debug("Sizes: old=%u alloc=%u attr=%u new=%u\n", 1679495e90faSNamjae Jeon (unsigned int)old_size, (unsigned int)alloc_size, 1680495e90faSNamjae Jeon (unsigned int)attr_size, (unsigned int)new_size); 1681495e90faSNamjae Jeon 16821e9ea7e0SNamjae Jeon /* Align to 8 bytes if it is not already done. */ 16831e9ea7e0SNamjae Jeon if (new_size & 7) 16841e9ea7e0SNamjae Jeon new_size = (new_size + 7) & ~7; 16851e9ea7e0SNamjae Jeon /* If the actual attribute length has changed, move things around. */ 1686495e90faSNamjae Jeon if (new_size != attr_size) { 16871e9ea7e0SNamjae Jeon u32 new_muse = le32_to_cpu(m->bytes_in_use) - 1688495e90faSNamjae Jeon attr_size + new_size; 16891e9ea7e0SNamjae Jeon /* Not enough space in this mft record. */ 16901e9ea7e0SNamjae Jeon if (new_muse > le32_to_cpu(m->bytes_allocated)) 16911e9ea7e0SNamjae Jeon return -ENOSPC; 1692495e90faSNamjae Jeon 1693495e90faSNamjae Jeon if (a->type == AT_INDEX_ROOT && new_size > attr_size && 1694495e90faSNamjae Jeon new_muse + 120 > alloc_size && old_size + 120 <= alloc_size) { 1695495e90faSNamjae Jeon ntfs_debug("Too big struct index_root (%u > %u)\n", 1696495e90faSNamjae Jeon new_muse, alloc_size); 1697495e90faSNamjae Jeon return -ENOSPC; 1698495e90faSNamjae Jeon } 1699495e90faSNamjae Jeon 17001e9ea7e0SNamjae Jeon /* Move attributes following @a to their new location. */ 17011e9ea7e0SNamjae Jeon memmove((u8 *)a + new_size, (u8 *)a + le32_to_cpu(a->length), 17021e9ea7e0SNamjae Jeon le32_to_cpu(m->bytes_in_use) - ((u8 *)a - 1703495e90faSNamjae Jeon (u8 *)m) - attr_size); 17041e9ea7e0SNamjae Jeon /* Adjust @m to reflect the change in used space. */ 17051e9ea7e0SNamjae Jeon m->bytes_in_use = cpu_to_le32(new_muse); 17061e9ea7e0SNamjae Jeon /* Adjust @a to reflect the new size. */ 1707495e90faSNamjae Jeon if (new_size >= offsetof(struct attr_record, length) + sizeof(a->length)) 17081e9ea7e0SNamjae Jeon a->length = cpu_to_le32(new_size); 17091e9ea7e0SNamjae Jeon } 17101e9ea7e0SNamjae Jeon return 0; 17111e9ea7e0SNamjae Jeon } 17121e9ea7e0SNamjae Jeon 1713495e90faSNamjae Jeon /* 17141e9ea7e0SNamjae Jeon * ntfs_resident_attr_value_resize - resize the value of a resident attribute 17151e9ea7e0SNamjae Jeon * @m: mft record containing attribute record 17161e9ea7e0SNamjae Jeon * @a: attribute record whose value to resize 17171e9ea7e0SNamjae Jeon * @new_size: new size in bytes to which to resize the attribute value of @a 17181e9ea7e0SNamjae Jeon * 17191e9ea7e0SNamjae Jeon * Resize the value of the attribute @a in the mft record @m to @new_size bytes. 17201e9ea7e0SNamjae Jeon * If the value is made bigger, the newly allocated space is cleared. 17211e9ea7e0SNamjae Jeon */ 1722495e90faSNamjae Jeon int ntfs_resident_attr_value_resize(struct mft_record *m, struct attr_record *a, 17231e9ea7e0SNamjae Jeon const u32 new_size) 17241e9ea7e0SNamjae Jeon { 17251e9ea7e0SNamjae Jeon u32 old_size; 17261e9ea7e0SNamjae Jeon 17271e9ea7e0SNamjae Jeon /* Resize the resident part of the attribute record. */ 17281e9ea7e0SNamjae Jeon if (ntfs_attr_record_resize(m, a, 17291e9ea7e0SNamjae Jeon le16_to_cpu(a->data.resident.value_offset) + new_size)) 17301e9ea7e0SNamjae Jeon return -ENOSPC; 17311e9ea7e0SNamjae Jeon /* 17321e9ea7e0SNamjae Jeon * The resize succeeded! If we made the attribute value bigger, clear 17331e9ea7e0SNamjae Jeon * the area between the old size and @new_size. 17341e9ea7e0SNamjae Jeon */ 17351e9ea7e0SNamjae Jeon old_size = le32_to_cpu(a->data.resident.value_length); 17361e9ea7e0SNamjae Jeon if (new_size > old_size) 17371e9ea7e0SNamjae Jeon memset((u8 *)a + le16_to_cpu(a->data.resident.value_offset) + 17381e9ea7e0SNamjae Jeon old_size, 0, new_size - old_size); 17391e9ea7e0SNamjae Jeon /* Finally update the length of the attribute value. */ 17401e9ea7e0SNamjae Jeon a->data.resident.value_length = cpu_to_le32(new_size); 17411e9ea7e0SNamjae Jeon return 0; 17421e9ea7e0SNamjae Jeon } 17431e9ea7e0SNamjae Jeon 1744495e90faSNamjae Jeon /* 17451e9ea7e0SNamjae Jeon * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute 17461e9ea7e0SNamjae Jeon * @ni: ntfs inode describing the attribute to convert 17471e9ea7e0SNamjae Jeon * @data_size: size of the resident data to copy to the non-resident attribute 17481e9ea7e0SNamjae Jeon * 17491e9ea7e0SNamjae Jeon * Convert the resident ntfs attribute described by the ntfs inode @ni to a 17501e9ea7e0SNamjae Jeon * non-resident one. 17511e9ea7e0SNamjae Jeon * 17521e9ea7e0SNamjae Jeon * @data_size must be equal to the attribute value size. This is needed since 17531e9ea7e0SNamjae Jeon * we need to know the size before we can map the mft record and our callers 17541e9ea7e0SNamjae Jeon * always know it. The reason we cannot simply read the size from the vfs 17551e9ea7e0SNamjae Jeon * inode i_size is that this is not necessarily uptodate. This happens when 17561e9ea7e0SNamjae Jeon * ntfs_attr_make_non_resident() is called in the ->truncate call path(s). 17571e9ea7e0SNamjae Jeon */ 1758495e90faSNamjae Jeon int ntfs_attr_make_non_resident(struct ntfs_inode *ni, const u32 data_size) 17591e9ea7e0SNamjae Jeon { 17601e9ea7e0SNamjae Jeon s64 new_size; 17611e9ea7e0SNamjae Jeon struct inode *vi = VFS_I(ni); 1762495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 1763495e90faSNamjae Jeon struct ntfs_inode *base_ni; 1764495e90faSNamjae Jeon struct mft_record *m; 1765495e90faSNamjae Jeon struct attr_record *a; 1766495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 1767495e90faSNamjae Jeon struct folio *folio; 1768495e90faSNamjae Jeon struct runlist_element *rl; 17691e9ea7e0SNamjae Jeon unsigned long flags; 17701e9ea7e0SNamjae Jeon int mp_size, mp_ofs, name_ofs, arec_size, err, err2; 17711e9ea7e0SNamjae Jeon u32 attr_size; 17721e9ea7e0SNamjae Jeon u8 old_res_attr_flags; 17731e9ea7e0SNamjae Jeon 1774495e90faSNamjae Jeon if (NInoNonResident(ni)) { 1775495e90faSNamjae Jeon ntfs_warning(vol->sb, 1776495e90faSNamjae Jeon "Trying to make non-resident attribute non-resident. Aborting...\n"); 1777495e90faSNamjae Jeon return -EINVAL; 1778495e90faSNamjae Jeon } 1779495e90faSNamjae Jeon 17801e9ea7e0SNamjae Jeon /* Check that the attribute is allowed to be non-resident. */ 17811e9ea7e0SNamjae Jeon err = ntfs_attr_can_be_non_resident(vol, ni->type); 17821e9ea7e0SNamjae Jeon if (unlikely(err)) { 17831e9ea7e0SNamjae Jeon if (err == -EPERM) 1784495e90faSNamjae Jeon ntfs_debug("Attribute is not allowed to be non-resident."); 17851e9ea7e0SNamjae Jeon else 1786495e90faSNamjae Jeon ntfs_debug("Attribute not defined on the NTFS volume!"); 17871e9ea7e0SNamjae Jeon return err; 17881e9ea7e0SNamjae Jeon } 1789495e90faSNamjae Jeon 1790495e90faSNamjae Jeon if (NInoEncrypted(ni)) 1791495e90faSNamjae Jeon return -EIO; 1792495e90faSNamjae Jeon 17931e9ea7e0SNamjae Jeon if (!NInoAttr(ni)) 17941e9ea7e0SNamjae Jeon base_ni = ni; 17951e9ea7e0SNamjae Jeon else 17961e9ea7e0SNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 17971e9ea7e0SNamjae Jeon m = map_mft_record(base_ni); 17981e9ea7e0SNamjae Jeon if (IS_ERR(m)) { 17991e9ea7e0SNamjae Jeon err = PTR_ERR(m); 18001e9ea7e0SNamjae Jeon m = NULL; 18011e9ea7e0SNamjae Jeon ctx = NULL; 18021e9ea7e0SNamjae Jeon goto err_out; 18031e9ea7e0SNamjae Jeon } 18041e9ea7e0SNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, m); 18051e9ea7e0SNamjae Jeon if (unlikely(!ctx)) { 18061e9ea7e0SNamjae Jeon err = -ENOMEM; 18071e9ea7e0SNamjae Jeon goto err_out; 18081e9ea7e0SNamjae Jeon } 18091e9ea7e0SNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 18101e9ea7e0SNamjae Jeon CASE_SENSITIVE, 0, NULL, 0, ctx); 18111e9ea7e0SNamjae Jeon if (unlikely(err)) { 18121e9ea7e0SNamjae Jeon if (err == -ENOENT) 18131e9ea7e0SNamjae Jeon err = -EIO; 18141e9ea7e0SNamjae Jeon goto err_out; 18151e9ea7e0SNamjae Jeon } 18161e9ea7e0SNamjae Jeon m = ctx->mrec; 18171e9ea7e0SNamjae Jeon a = ctx->attr; 1818495e90faSNamjae Jeon 1819495e90faSNamjae Jeon /* 1820495e90faSNamjae Jeon * The size needs to be aligned to a cluster boundary for allocation 1821495e90faSNamjae Jeon * purposes. 1822495e90faSNamjae Jeon */ 1823495e90faSNamjae Jeon new_size = (data_size + vol->cluster_size - 1) & 1824495e90faSNamjae Jeon ~(vol->cluster_size - 1); 1825495e90faSNamjae Jeon if (new_size > 0) { 1826495e90faSNamjae Jeon if ((a->flags & ATTR_COMPRESSION_MASK) == ATTR_IS_COMPRESSED) { 1827495e90faSNamjae Jeon /* must allocate full compression blocks */ 1828495e90faSNamjae Jeon new_size = 1829495e90faSNamjae Jeon ((new_size - 1) | 1830495e90faSNamjae Jeon ((1L << (STANDARD_COMPRESSION_UNIT + 1831495e90faSNamjae Jeon vol->cluster_size_bits)) - 1)) + 1; 1832495e90faSNamjae Jeon } 1833495e90faSNamjae Jeon 1834495e90faSNamjae Jeon /* 1835495e90faSNamjae Jeon * Will need folio later and since folio lock nests 1836495e90faSNamjae Jeon * outside all ntfs locks, we need to get the folio now. 1837495e90faSNamjae Jeon */ 1838495e90faSNamjae Jeon folio = __filemap_get_folio(vi->i_mapping, 0, 1839495e90faSNamjae Jeon FGP_CREAT | FGP_LOCK, 1840495e90faSNamjae Jeon mapping_gfp_mask(vi->i_mapping)); 1841495e90faSNamjae Jeon if (IS_ERR(folio)) { 1842495e90faSNamjae Jeon err = -ENOMEM; 1843495e90faSNamjae Jeon goto err_out; 1844495e90faSNamjae Jeon } 1845495e90faSNamjae Jeon 1846495e90faSNamjae Jeon /* Start by allocating clusters to hold the attribute value. */ 1847495e90faSNamjae Jeon rl = ntfs_cluster_alloc(vol, 0, 1848495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, new_size), 1849495e90faSNamjae Jeon -1, DATA_ZONE, true, false, false); 1850495e90faSNamjae Jeon if (IS_ERR(rl)) { 1851495e90faSNamjae Jeon err = PTR_ERR(rl); 1852495e90faSNamjae Jeon ntfs_debug("Failed to allocate cluster%s, error code %i.", 1853495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, new_size) > 1 ? "s" : "", 1854495e90faSNamjae Jeon err); 1855495e90faSNamjae Jeon goto folio_err_out; 1856495e90faSNamjae Jeon } 1857495e90faSNamjae Jeon } else { 1858495e90faSNamjae Jeon rl = NULL; 1859495e90faSNamjae Jeon folio = NULL; 1860495e90faSNamjae Jeon } 1861495e90faSNamjae Jeon 1862495e90faSNamjae Jeon down_write(&ni->runlist.lock); 1863495e90faSNamjae Jeon /* Determine the size of the mapping pairs array. */ 1864495e90faSNamjae Jeon mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, -1, -1); 1865495e90faSNamjae Jeon if (unlikely(mp_size < 0)) { 1866495e90faSNamjae Jeon err = mp_size; 1867495e90faSNamjae Jeon ntfs_debug("Failed to get size for mapping pairs array, error code %i.\n", err); 1868495e90faSNamjae Jeon goto rl_err_out; 1869495e90faSNamjae Jeon } 1870495e90faSNamjae Jeon 1871495e90faSNamjae Jeon if (NInoNonResident(ni) || a->non_resident) { 1872495e90faSNamjae Jeon err = -EIO; 1873495e90faSNamjae Jeon goto rl_err_out; 1874495e90faSNamjae Jeon } 1875495e90faSNamjae Jeon 18761e9ea7e0SNamjae Jeon /* 18771e9ea7e0SNamjae Jeon * Calculate new offsets for the name and the mapping pairs array. 18781e9ea7e0SNamjae Jeon */ 18791e9ea7e0SNamjae Jeon if (NInoSparse(ni) || NInoCompressed(ni)) 1880495e90faSNamjae Jeon name_ofs = (offsetof(struct attr_record, 18811e9ea7e0SNamjae Jeon data.non_resident.compressed_size) + 18821e9ea7e0SNamjae Jeon sizeof(a->data.non_resident.compressed_size) + 18831e9ea7e0SNamjae Jeon 7) & ~7; 18841e9ea7e0SNamjae Jeon else 1885495e90faSNamjae Jeon name_ofs = (offsetof(struct attr_record, 18861e9ea7e0SNamjae Jeon data.non_resident.compressed_size) + 7) & ~7; 1887495e90faSNamjae Jeon mp_ofs = (name_ofs + a->name_length * sizeof(__le16) + 7) & ~7; 18881e9ea7e0SNamjae Jeon /* 18891e9ea7e0SNamjae Jeon * Determine the size of the resident part of the now non-resident 18901e9ea7e0SNamjae Jeon * attribute record. 18911e9ea7e0SNamjae Jeon */ 18921e9ea7e0SNamjae Jeon arec_size = (mp_ofs + mp_size + 7) & ~7; 18931e9ea7e0SNamjae Jeon /* 1894495e90faSNamjae Jeon * If the folio is not uptodate bring it uptodate by copying from the 18951e9ea7e0SNamjae Jeon * attribute value. 18961e9ea7e0SNamjae Jeon */ 18971e9ea7e0SNamjae Jeon attr_size = le32_to_cpu(a->data.resident.value_length); 1898495e90faSNamjae Jeon WARN_ON(attr_size != data_size); 1899495e90faSNamjae Jeon if (folio && !folio_test_uptodate(folio)) { 1900495e90faSNamjae Jeon folio_fill_tail(folio, 0, (u8 *)a + 19011e9ea7e0SNamjae Jeon le16_to_cpu(a->data.resident.value_offset), 19021e9ea7e0SNamjae Jeon attr_size); 1903495e90faSNamjae Jeon folio_mark_uptodate(folio); 19041e9ea7e0SNamjae Jeon } 1905495e90faSNamjae Jeon 19061e9ea7e0SNamjae Jeon /* Backup the attribute flag. */ 19071e9ea7e0SNamjae Jeon old_res_attr_flags = a->data.resident.flags; 19081e9ea7e0SNamjae Jeon /* Resize the resident part of the attribute record. */ 19091e9ea7e0SNamjae Jeon err = ntfs_attr_record_resize(m, a, arec_size); 19101e9ea7e0SNamjae Jeon if (unlikely(err)) 1911495e90faSNamjae Jeon goto rl_err_out; 1912495e90faSNamjae Jeon 19131e9ea7e0SNamjae Jeon /* 19141e9ea7e0SNamjae Jeon * Convert the resident part of the attribute record to describe a 19151e9ea7e0SNamjae Jeon * non-resident attribute. 19161e9ea7e0SNamjae Jeon */ 19171e9ea7e0SNamjae Jeon a->non_resident = 1; 19181e9ea7e0SNamjae Jeon /* Move the attribute name if it exists and update the offset. */ 19191e9ea7e0SNamjae Jeon if (a->name_length) 19201e9ea7e0SNamjae Jeon memmove((u8 *)a + name_ofs, (u8 *)a + le16_to_cpu(a->name_offset), 1921495e90faSNamjae Jeon a->name_length * sizeof(__le16)); 19221e9ea7e0SNamjae Jeon a->name_offset = cpu_to_le16(name_ofs); 19231e9ea7e0SNamjae Jeon /* Setup the fields specific to non-resident attributes. */ 19241e9ea7e0SNamjae Jeon a->data.non_resident.lowest_vcn = 0; 1925495e90faSNamjae Jeon a->data.non_resident.highest_vcn = 1926495e90faSNamjae Jeon cpu_to_le64(ntfs_bytes_to_cluster(vol, new_size - 1)); 19271e9ea7e0SNamjae Jeon a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs); 19281e9ea7e0SNamjae Jeon memset(&a->data.non_resident.reserved, 0, 19291e9ea7e0SNamjae Jeon sizeof(a->data.non_resident.reserved)); 1930495e90faSNamjae Jeon a->data.non_resident.allocated_size = cpu_to_le64(new_size); 19311e9ea7e0SNamjae Jeon a->data.non_resident.data_size = 19321e9ea7e0SNamjae Jeon a->data.non_resident.initialized_size = 1933495e90faSNamjae Jeon cpu_to_le64(attr_size); 19341e9ea7e0SNamjae Jeon if (NInoSparse(ni) || NInoCompressed(ni)) { 19351e9ea7e0SNamjae Jeon a->data.non_resident.compression_unit = 0; 19361e9ea7e0SNamjae Jeon if (NInoCompressed(ni) || vol->major_ver < 3) 19371e9ea7e0SNamjae Jeon a->data.non_resident.compression_unit = 4; 19381e9ea7e0SNamjae Jeon a->data.non_resident.compressed_size = 19391e9ea7e0SNamjae Jeon a->data.non_resident.allocated_size; 19401e9ea7e0SNamjae Jeon } else 19411e9ea7e0SNamjae Jeon a->data.non_resident.compression_unit = 0; 19421e9ea7e0SNamjae Jeon /* Generate the mapping pairs array into the attribute record. */ 19431e9ea7e0SNamjae Jeon err = ntfs_mapping_pairs_build(vol, (u8 *)a + mp_ofs, 1944495e90faSNamjae Jeon arec_size - mp_ofs, rl, 0, -1, NULL, NULL, NULL); 19451e9ea7e0SNamjae Jeon if (unlikely(err)) { 1946495e90faSNamjae Jeon ntfs_error(vol->sb, "Failed to build mapping pairs, error code %i.", 19471e9ea7e0SNamjae Jeon err); 19481e9ea7e0SNamjae Jeon goto undo_err_out; 19491e9ea7e0SNamjae Jeon } 1950495e90faSNamjae Jeon 19511e9ea7e0SNamjae Jeon /* Setup the in-memory attribute structure to be non-resident. */ 19521e9ea7e0SNamjae Jeon ni->runlist.rl = rl; 1953495e90faSNamjae Jeon if (rl) { 1954495e90faSNamjae Jeon for (ni->runlist.count = 1; rl->length != 0; rl++) 1955495e90faSNamjae Jeon ni->runlist.count++; 1956495e90faSNamjae Jeon } else 1957495e90faSNamjae Jeon ni->runlist.count = 0; 19581e9ea7e0SNamjae Jeon write_lock_irqsave(&ni->size_lock, flags); 19591e9ea7e0SNamjae Jeon ni->allocated_size = new_size; 19601e9ea7e0SNamjae Jeon if (NInoSparse(ni) || NInoCompressed(ni)) { 19611e9ea7e0SNamjae Jeon ni->itype.compressed.size = ni->allocated_size; 19621e9ea7e0SNamjae Jeon if (a->data.non_resident.compression_unit) { 1963495e90faSNamjae Jeon ni->itype.compressed.block_size = 1U << 1964495e90faSNamjae Jeon (a->data.non_resident.compression_unit + 19651e9ea7e0SNamjae Jeon vol->cluster_size_bits); 19661e9ea7e0SNamjae Jeon ni->itype.compressed.block_size_bits = 19671e9ea7e0SNamjae Jeon ffs(ni->itype.compressed.block_size) - 19681e9ea7e0SNamjae Jeon 1; 19691e9ea7e0SNamjae Jeon ni->itype.compressed.block_clusters = 1U << 19701e9ea7e0SNamjae Jeon a->data.non_resident.compression_unit; 19711e9ea7e0SNamjae Jeon } else { 19721e9ea7e0SNamjae Jeon ni->itype.compressed.block_size = 0; 19731e9ea7e0SNamjae Jeon ni->itype.compressed.block_size_bits = 0; 19741e9ea7e0SNamjae Jeon ni->itype.compressed.block_clusters = 0; 19751e9ea7e0SNamjae Jeon } 19761e9ea7e0SNamjae Jeon vi->i_blocks = ni->itype.compressed.size >> 9; 19771e9ea7e0SNamjae Jeon } else 19781e9ea7e0SNamjae Jeon vi->i_blocks = ni->allocated_size >> 9; 19791e9ea7e0SNamjae Jeon write_unlock_irqrestore(&ni->size_lock, flags); 19801e9ea7e0SNamjae Jeon /* 19811e9ea7e0SNamjae Jeon * This needs to be last since the address space operations ->read_folio 19821e9ea7e0SNamjae Jeon * and ->writepage can run concurrently with us as they are not 19831e9ea7e0SNamjae Jeon * serialized on i_mutex. Note, we are not allowed to fail once we flip 19841e9ea7e0SNamjae Jeon * this switch, which is another reason to do this last. 19851e9ea7e0SNamjae Jeon */ 19861e9ea7e0SNamjae Jeon NInoSetNonResident(ni); 1987495e90faSNamjae Jeon NInoSetFullyMapped(ni); 19881e9ea7e0SNamjae Jeon /* Mark the mft record dirty, so it gets written back. */ 19891e9ea7e0SNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 19901e9ea7e0SNamjae Jeon ntfs_attr_put_search_ctx(ctx); 19911e9ea7e0SNamjae Jeon unmap_mft_record(base_ni); 19921e9ea7e0SNamjae Jeon up_write(&ni->runlist.lock); 1993495e90faSNamjae Jeon if (folio) { 1994495e90faSNamjae Jeon iomap_dirty_folio(vi->i_mapping, folio); 1995495e90faSNamjae Jeon folio_unlock(folio); 1996495e90faSNamjae Jeon folio_put(folio); 19971e9ea7e0SNamjae Jeon } 19981e9ea7e0SNamjae Jeon ntfs_debug("Done."); 19991e9ea7e0SNamjae Jeon return 0; 20001e9ea7e0SNamjae Jeon undo_err_out: 20011e9ea7e0SNamjae Jeon /* Convert the attribute back into a resident attribute. */ 20021e9ea7e0SNamjae Jeon a->non_resident = 0; 20031e9ea7e0SNamjae Jeon /* Move the attribute name if it exists and update the offset. */ 2004495e90faSNamjae Jeon name_ofs = (offsetof(struct attr_record, data.resident.reserved) + 20051e9ea7e0SNamjae Jeon sizeof(a->data.resident.reserved) + 7) & ~7; 20061e9ea7e0SNamjae Jeon if (a->name_length) 20071e9ea7e0SNamjae Jeon memmove((u8 *)a + name_ofs, (u8 *)a + le16_to_cpu(a->name_offset), 2008495e90faSNamjae Jeon a->name_length * sizeof(__le16)); 2009495e90faSNamjae Jeon mp_ofs = (name_ofs + a->name_length * sizeof(__le16) + 7) & ~7; 20101e9ea7e0SNamjae Jeon a->name_offset = cpu_to_le16(name_ofs); 20111e9ea7e0SNamjae Jeon arec_size = (mp_ofs + attr_size + 7) & ~7; 20121e9ea7e0SNamjae Jeon /* Resize the resident part of the attribute record. */ 20131e9ea7e0SNamjae Jeon err2 = ntfs_attr_record_resize(m, a, arec_size); 20141e9ea7e0SNamjae Jeon if (unlikely(err2)) { 20151e9ea7e0SNamjae Jeon /* 20161e9ea7e0SNamjae Jeon * This cannot happen (well if memory corruption is at work it 20171e9ea7e0SNamjae Jeon * could happen in theory), but deal with it as well as we can. 20181e9ea7e0SNamjae Jeon * If the old size is too small, truncate the attribute, 20191e9ea7e0SNamjae Jeon * otherwise simply give it a larger allocated size. 20201e9ea7e0SNamjae Jeon */ 20211e9ea7e0SNamjae Jeon arec_size = le32_to_cpu(a->length); 20221e9ea7e0SNamjae Jeon if ((mp_ofs + attr_size) > arec_size) { 20231e9ea7e0SNamjae Jeon err2 = attr_size; 20241e9ea7e0SNamjae Jeon attr_size = arec_size - mp_ofs; 2025495e90faSNamjae Jeon ntfs_error(vol->sb, 2026e7d82353SNamjae Jeon "Failed to undo partial resident to non-resident attribute conversion. Truncating inode 0x%llx, attribute type 0x%x from %i bytes to %i bytes to maintain metadata consistency. THIS MEANS YOU ARE LOSING %i BYTES DATA FROM THIS %s.", 2027e7d82353SNamjae Jeon ni->mft_no, 2028495e90faSNamjae Jeon (unsigned int)le32_to_cpu(ni->type), 20291e9ea7e0SNamjae Jeon err2, attr_size, err2 - attr_size, 20301e9ea7e0SNamjae Jeon ((ni->type == AT_DATA) && 20311e9ea7e0SNamjae Jeon !ni->name_len) ? "FILE" : "ATTRIBUTE"); 20321e9ea7e0SNamjae Jeon write_lock_irqsave(&ni->size_lock, flags); 20331e9ea7e0SNamjae Jeon ni->initialized_size = attr_size; 20341e9ea7e0SNamjae Jeon i_size_write(vi, attr_size); 20351e9ea7e0SNamjae Jeon write_unlock_irqrestore(&ni->size_lock, flags); 20361e9ea7e0SNamjae Jeon } 20371e9ea7e0SNamjae Jeon } 20381e9ea7e0SNamjae Jeon /* Setup the fields specific to resident attributes. */ 20391e9ea7e0SNamjae Jeon a->data.resident.value_length = cpu_to_le32(attr_size); 20401e9ea7e0SNamjae Jeon a->data.resident.value_offset = cpu_to_le16(mp_ofs); 20411e9ea7e0SNamjae Jeon a->data.resident.flags = old_res_attr_flags; 20421e9ea7e0SNamjae Jeon memset(&a->data.resident.reserved, 0, 20431e9ea7e0SNamjae Jeon sizeof(a->data.resident.reserved)); 2044495e90faSNamjae Jeon /* Copy the data from folio back to the attribute value. */ 2045495e90faSNamjae Jeon if (folio) 2046495e90faSNamjae Jeon memcpy_from_folio((u8 *)a + mp_ofs, folio, 0, attr_size); 20471e9ea7e0SNamjae Jeon /* Setup the allocated size in the ntfs inode in case it changed. */ 20481e9ea7e0SNamjae Jeon write_lock_irqsave(&ni->size_lock, flags); 20491e9ea7e0SNamjae Jeon ni->allocated_size = arec_size - mp_ofs; 20501e9ea7e0SNamjae Jeon write_unlock_irqrestore(&ni->size_lock, flags); 20511e9ea7e0SNamjae Jeon /* Mark the mft record dirty, so it gets written back. */ 20521e9ea7e0SNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 2053495e90faSNamjae Jeon rl_err_out: 2054495e90faSNamjae Jeon up_write(&ni->runlist.lock); 2055495e90faSNamjae Jeon if (rl) { 2056495e90faSNamjae Jeon if (ntfs_cluster_free_from_rl(vol, rl) < 0) { 2057495e90faSNamjae Jeon ntfs_error(vol->sb, 2058495e90faSNamjae Jeon "Failed to release allocated cluster(s) in error code path. Run chkdsk to recover the lost cluster(s)."); 2059495e90faSNamjae Jeon NVolSetErrors(vol); 2060495e90faSNamjae Jeon } 2061495e90faSNamjae Jeon kvfree(rl); 2062495e90faSNamjae Jeon folio_err_out: 2063495e90faSNamjae Jeon folio_unlock(folio); 2064495e90faSNamjae Jeon folio_put(folio); 2065495e90faSNamjae Jeon } 20661e9ea7e0SNamjae Jeon err_out: 20671e9ea7e0SNamjae Jeon if (ctx) 20681e9ea7e0SNamjae Jeon ntfs_attr_put_search_ctx(ctx); 20691e9ea7e0SNamjae Jeon if (m) 20701e9ea7e0SNamjae Jeon unmap_mft_record(base_ni); 20711e9ea7e0SNamjae Jeon ni->runlist.rl = NULL; 2072495e90faSNamjae Jeon 20731e9ea7e0SNamjae Jeon if (err == -EINVAL) 20741e9ea7e0SNamjae Jeon err = -EIO; 20751e9ea7e0SNamjae Jeon return err; 20761e9ea7e0SNamjae Jeon } 20771e9ea7e0SNamjae Jeon 20781e9ea7e0SNamjae Jeon /* 20791e9ea7e0SNamjae Jeon * ntfs_attr_set - fill (a part of) an attribute with a byte 20801e9ea7e0SNamjae Jeon * @ni: ntfs inode describing the attribute to fill 20811e9ea7e0SNamjae Jeon * @ofs: offset inside the attribute at which to start to fill 20821e9ea7e0SNamjae Jeon * @cnt: number of bytes to fill 20831e9ea7e0SNamjae Jeon * @val: the unsigned 8-bit value with which to fill the attribute 20841e9ea7e0SNamjae Jeon * 20851e9ea7e0SNamjae Jeon * Fill @cnt bytes of the attribute described by the ntfs inode @ni starting at 20861e9ea7e0SNamjae Jeon * byte offset @ofs inside the attribute with the constant byte @val. 20871e9ea7e0SNamjae Jeon * 20881e9ea7e0SNamjae Jeon * This function is effectively like memset() applied to an ntfs attribute. 2089495e90faSNamjae Jeon * Note thie function actually only operates on the page cache pages belonging 20901e9ea7e0SNamjae Jeon * to the ntfs attribute and it marks them dirty after doing the memset(). 20911e9ea7e0SNamjae Jeon * Thus it relies on the vm dirty page write code paths to cause the modified 20921e9ea7e0SNamjae Jeon * pages to be written to the mft record/disk. 20931e9ea7e0SNamjae Jeon */ 2094495e90faSNamjae Jeon int ntfs_attr_set(struct ntfs_inode *ni, s64 ofs, s64 cnt, const u8 val) 20951e9ea7e0SNamjae Jeon { 2096495e90faSNamjae Jeon struct address_space *mapping = VFS_I(ni)->i_mapping; 2097495e90faSNamjae Jeon struct folio *folio; 2098495e90faSNamjae Jeon pgoff_t index; 2099495e90faSNamjae Jeon u8 *addr; 2100495e90faSNamjae Jeon unsigned long offset; 2101495e90faSNamjae Jeon size_t attr_len; 2102495e90faSNamjae Jeon int ret = 0; 21031e9ea7e0SNamjae Jeon 2104495e90faSNamjae Jeon index = ofs >> PAGE_SHIFT; 2105495e90faSNamjae Jeon while (cnt) { 2106495e90faSNamjae Jeon folio = read_mapping_folio(mapping, index, NULL); 2107495e90faSNamjae Jeon if (IS_ERR(folio)) { 2108495e90faSNamjae Jeon ret = PTR_ERR(folio); 2109495e90faSNamjae Jeon ntfs_error(VFS_I(ni)->i_sb, "Failed to read a page %lu for attr %#x: %ld", 2110495e90faSNamjae Jeon index, ni->type, PTR_ERR(folio)); 2111495e90faSNamjae Jeon break; 21121e9ea7e0SNamjae Jeon } 2113495e90faSNamjae Jeon 2114495e90faSNamjae Jeon offset = offset_in_folio(folio, ofs); 2115495e90faSNamjae Jeon attr_len = min_t(size_t, (size_t)cnt, folio_size(folio) - offset); 2116495e90faSNamjae Jeon 2117495e90faSNamjae Jeon folio_lock(folio); 2118495e90faSNamjae Jeon addr = kmap_local_folio(folio, offset); 2119495e90faSNamjae Jeon memset(addr, val, attr_len); 2120495e90faSNamjae Jeon kunmap_local(addr); 2121495e90faSNamjae Jeon 2122495e90faSNamjae Jeon folio_mark_dirty(folio); 2123495e90faSNamjae Jeon folio_unlock(folio); 2124495e90faSNamjae Jeon folio_put(folio); 2125495e90faSNamjae Jeon 2126495e90faSNamjae Jeon ofs += attr_len; 2127495e90faSNamjae Jeon cnt -= attr_len; 2128495e90faSNamjae Jeon index++; 21291e9ea7e0SNamjae Jeon cond_resched(); 21301e9ea7e0SNamjae Jeon } 2131495e90faSNamjae Jeon 2132495e90faSNamjae Jeon return ret; 2133495e90faSNamjae Jeon } 2134495e90faSNamjae Jeon 2135495e90faSNamjae Jeon int ntfs_attr_set_initialized_size(struct ntfs_inode *ni, loff_t new_size) 2136495e90faSNamjae Jeon { 2137495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 2138495e90faSNamjae Jeon int err = 0; 2139495e90faSNamjae Jeon 2140495e90faSNamjae Jeon if (!NInoNonResident(ni)) 2141495e90faSNamjae Jeon return -EINVAL; 2142495e90faSNamjae Jeon 2143495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 2144495e90faSNamjae Jeon if (!ctx) 21451e9ea7e0SNamjae Jeon return -ENOMEM; 21461e9ea7e0SNamjae Jeon 2147495e90faSNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 2148495e90faSNamjae Jeon CASE_SENSITIVE, 0, NULL, 0, ctx); 2149495e90faSNamjae Jeon if (err) 2150495e90faSNamjae Jeon goto out_ctx; 2151495e90faSNamjae Jeon 2152495e90faSNamjae Jeon ctx->attr->data.non_resident.initialized_size = cpu_to_le64(new_size); 2153495e90faSNamjae Jeon ni->initialized_size = new_size; 2154495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 2155495e90faSNamjae Jeon out_ctx: 2156495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 2157495e90faSNamjae Jeon return err; 21581e9ea7e0SNamjae Jeon } 2159495e90faSNamjae Jeon 21601e9ea7e0SNamjae Jeon /* 2161495e90faSNamjae Jeon * ntfs_make_room_for_attr - make room for an attribute inside an mft record 2162495e90faSNamjae Jeon * @m: mft record 2163495e90faSNamjae Jeon * @pos: position at which to make space 2164495e90faSNamjae Jeon * @size: byte size to make available at this position 2165495e90faSNamjae Jeon * 2166495e90faSNamjae Jeon * @pos points to the attribute in front of which we want to make space. 21671e9ea7e0SNamjae Jeon */ 2168495e90faSNamjae Jeon static int ntfs_make_room_for_attr(struct mft_record *m, u8 *pos, u32 size) 2169495e90faSNamjae Jeon { 2170495e90faSNamjae Jeon u32 biu; 2171495e90faSNamjae Jeon 2172495e90faSNamjae Jeon ntfs_debug("Entering for pos 0x%x, size %u.\n", 2173495e90faSNamjae Jeon (int)(pos - (u8 *)m), (unsigned int) size); 2174495e90faSNamjae Jeon 2175495e90faSNamjae Jeon /* Make size 8-byte alignment. */ 2176495e90faSNamjae Jeon size = (size + 7) & ~7; 2177495e90faSNamjae Jeon 2178495e90faSNamjae Jeon /* Rigorous consistency checks. */ 2179495e90faSNamjae Jeon if (!m || !pos || pos < (u8 *)m) { 2180ea3566a3SWoody Suwalski pr_err("%s: pos=%p m=%p\n", __func__, pos, m); 2181495e90faSNamjae Jeon return -EINVAL; 21821e9ea7e0SNamjae Jeon } 2183495e90faSNamjae Jeon 2184495e90faSNamjae Jeon /* The -8 is for the attribute terminator. */ 2185495e90faSNamjae Jeon if (pos - (u8 *)m > (int)le32_to_cpu(m->bytes_in_use) - 8) 2186495e90faSNamjae Jeon return -EINVAL; 2187495e90faSNamjae Jeon /* Nothing to do. */ 2188495e90faSNamjae Jeon if (!size) 2189495e90faSNamjae Jeon return 0; 2190495e90faSNamjae Jeon 2191495e90faSNamjae Jeon biu = le32_to_cpu(m->bytes_in_use); 2192495e90faSNamjae Jeon /* Do we have enough space? */ 2193495e90faSNamjae Jeon if (biu + size > le32_to_cpu(m->bytes_allocated) || 2194495e90faSNamjae Jeon pos + size > (u8 *)m + le32_to_cpu(m->bytes_allocated)) { 2195495e90faSNamjae Jeon ntfs_debug("No enough space in the MFT record\n"); 2196495e90faSNamjae Jeon return -ENOSPC; 21971e9ea7e0SNamjae Jeon } 2198495e90faSNamjae Jeon /* Move everything after pos to pos + size. */ 2199495e90faSNamjae Jeon memmove(pos + size, pos, biu - (pos - (u8 *)m)); 2200495e90faSNamjae Jeon /* Update mft record. */ 2201495e90faSNamjae Jeon m->bytes_in_use = cpu_to_le32(biu + size); 22021e9ea7e0SNamjae Jeon return 0; 22031e9ea7e0SNamjae Jeon } 22041e9ea7e0SNamjae Jeon 2205495e90faSNamjae Jeon /* 2206495e90faSNamjae Jeon * ntfs_resident_attr_record_add - add resident attribute to inode 2207495e90faSNamjae Jeon * @ni: opened ntfs inode to which MFT record add attribute 2208495e90faSNamjae Jeon * @type: type of the new attribute 2209495e90faSNamjae Jeon * @name: name of the new attribute 2210495e90faSNamjae Jeon * @name_len: name length of the new attribute 2211495e90faSNamjae Jeon * @val: value of the new attribute 2212495e90faSNamjae Jeon * @size: size of new attribute (length of @val, if @val != NULL) 2213495e90faSNamjae Jeon * @flags: flags of the new attribute 2214495e90faSNamjae Jeon */ 2215495e90faSNamjae Jeon int ntfs_resident_attr_record_add(struct ntfs_inode *ni, __le32 type, 2216495e90faSNamjae Jeon __le16 *name, u8 name_len, u8 *val, u32 size, 2217495e90faSNamjae Jeon __le16 flags) 2218495e90faSNamjae Jeon { 2219495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 2220495e90faSNamjae Jeon u32 length; 2221495e90faSNamjae Jeon struct attr_record *a; 2222495e90faSNamjae Jeon struct mft_record *m; 2223495e90faSNamjae Jeon int err, offset; 2224495e90faSNamjae Jeon struct ntfs_inode *base_ni; 2225495e90faSNamjae Jeon 2226c418e967SEthan Tidmore if (!ni || (!name && name_len)) 2227c418e967SEthan Tidmore return -EINVAL; 2228c418e967SEthan Tidmore 2229495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x, flags 0x%x.\n", 2230495e90faSNamjae Jeon (long long) ni->mft_no, (unsigned int) le32_to_cpu(type), 2231495e90faSNamjae Jeon (unsigned int) le16_to_cpu(flags)); 2232495e90faSNamjae Jeon 2233495e90faSNamjae Jeon err = ntfs_attr_can_be_resident(ni->vol, type); 2234495e90faSNamjae Jeon if (err) { 2235495e90faSNamjae Jeon if (err == -EPERM) 2236495e90faSNamjae Jeon ntfs_debug("Attribute can't be resident.\n"); 2237495e90faSNamjae Jeon else 2238495e90faSNamjae Jeon ntfs_debug("ntfs_attr_can_be_resident failed.\n"); 2239495e90faSNamjae Jeon return err; 2240495e90faSNamjae Jeon } 2241495e90faSNamjae Jeon 2242495e90faSNamjae Jeon /* Locate place where record should be. */ 2243495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 2244495e90faSNamjae Jeon if (!ctx) { 2245495e90faSNamjae Jeon ntfs_error(ni->vol->sb, "%s: Failed to get search context", 2246495e90faSNamjae Jeon __func__); 2247495e90faSNamjae Jeon return -ENOMEM; 2248495e90faSNamjae Jeon } 2249495e90faSNamjae Jeon /* 2250495e90faSNamjae Jeon * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for 2251495e90faSNamjae Jeon * attribute in @ni->mrec, not any extent inode in case if @ni is base 2252495e90faSNamjae Jeon * file record. 2253495e90faSNamjae Jeon */ 2254495e90faSNamjae Jeon err = ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, val, size, ctx); 2255495e90faSNamjae Jeon if (!err) { 2256495e90faSNamjae Jeon err = -EEXIST; 2257495e90faSNamjae Jeon ntfs_debug("Attribute already present.\n"); 2258495e90faSNamjae Jeon goto put_err_out; 2259495e90faSNamjae Jeon } 2260495e90faSNamjae Jeon if (err != -ENOENT) { 2261495e90faSNamjae Jeon err = -EIO; 2262495e90faSNamjae Jeon goto put_err_out; 2263495e90faSNamjae Jeon } 2264495e90faSNamjae Jeon a = ctx->attr; 2265495e90faSNamjae Jeon m = ctx->mrec; 2266495e90faSNamjae Jeon 2267495e90faSNamjae Jeon /* Make room for attribute. */ 2268495e90faSNamjae Jeon length = offsetof(struct attr_record, data.resident.reserved) + 2269495e90faSNamjae Jeon sizeof(a->data.resident.reserved) + 2270495e90faSNamjae Jeon ((name_len * sizeof(__le16) + 7) & ~7) + 2271495e90faSNamjae Jeon ((size + 7) & ~7); 2272495e90faSNamjae Jeon err = ntfs_make_room_for_attr(ctx->mrec, (u8 *) ctx->attr, length); 2273495e90faSNamjae Jeon if (err) { 2274495e90faSNamjae Jeon ntfs_debug("Failed to make room for attribute.\n"); 2275495e90faSNamjae Jeon goto put_err_out; 2276495e90faSNamjae Jeon } 2277495e90faSNamjae Jeon 2278495e90faSNamjae Jeon /* Setup record fields. */ 2279495e90faSNamjae Jeon offset = ((u8 *)a - (u8 *)m); 2280495e90faSNamjae Jeon a->type = type; 2281495e90faSNamjae Jeon a->length = cpu_to_le32(length); 2282495e90faSNamjae Jeon a->non_resident = 0; 2283495e90faSNamjae Jeon a->name_length = name_len; 2284495e90faSNamjae Jeon a->name_offset = 2285495e90faSNamjae Jeon name_len ? cpu_to_le16((offsetof(struct attr_record, data.resident.reserved) + 2286495e90faSNamjae Jeon sizeof(a->data.resident.reserved))) : cpu_to_le16(0); 2287495e90faSNamjae Jeon 2288495e90faSNamjae Jeon a->flags = flags; 2289495e90faSNamjae Jeon a->instance = m->next_attr_instance; 2290495e90faSNamjae Jeon a->data.resident.value_length = cpu_to_le32(size); 2291495e90faSNamjae Jeon a->data.resident.value_offset = cpu_to_le16(length - ((size + 7) & ~7)); 2292495e90faSNamjae Jeon if (val) 2293495e90faSNamjae Jeon memcpy((u8 *)a + le16_to_cpu(a->data.resident.value_offset), val, size); 2294495e90faSNamjae Jeon else 2295495e90faSNamjae Jeon memset((u8 *)a + le16_to_cpu(a->data.resident.value_offset), 0, size); 2296495e90faSNamjae Jeon if (type == AT_FILE_NAME) 2297495e90faSNamjae Jeon a->data.resident.flags = RESIDENT_ATTR_IS_INDEXED; 2298495e90faSNamjae Jeon else 2299495e90faSNamjae Jeon a->data.resident.flags = 0; 2300495e90faSNamjae Jeon if (name_len) 2301495e90faSNamjae Jeon memcpy((u8 *)a + le16_to_cpu(a->name_offset), 2302495e90faSNamjae Jeon name, sizeof(__le16) * name_len); 2303495e90faSNamjae Jeon m->next_attr_instance = 2304495e90faSNamjae Jeon cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); 2305495e90faSNamjae Jeon if (ni->nr_extents == -1) 2306495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 2307495e90faSNamjae Jeon else 2308495e90faSNamjae Jeon base_ni = ni; 2309495e90faSNamjae Jeon if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { 2310495e90faSNamjae Jeon err = ntfs_attrlist_entry_add(ni, a); 2311495e90faSNamjae Jeon if (err) { 2312495e90faSNamjae Jeon ntfs_attr_record_resize(m, a, 0); 2313495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 2314495e90faSNamjae Jeon ntfs_debug("Failed add attribute entry to ATTRIBUTE_LIST.\n"); 2315495e90faSNamjae Jeon goto put_err_out; 2316495e90faSNamjae Jeon } 2317495e90faSNamjae Jeon } 2318495e90faSNamjae Jeon mark_mft_record_dirty(ni); 2319495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 2320495e90faSNamjae Jeon return offset; 2321495e90faSNamjae Jeon put_err_out: 2322495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 2323495e90faSNamjae Jeon return -EIO; 2324495e90faSNamjae Jeon } 2325495e90faSNamjae Jeon 2326495e90faSNamjae Jeon /* 2327495e90faSNamjae Jeon * ntfs_non_resident_attr_record_add - add extent of non-resident attribute 2328495e90faSNamjae Jeon * @ni: opened ntfs inode to which MFT record add attribute 2329495e90faSNamjae Jeon * @type: type of the new attribute extent 2330495e90faSNamjae Jeon * @name: name of the new attribute extent 2331495e90faSNamjae Jeon * @name_len: name length of the new attribute extent 2332495e90faSNamjae Jeon * @lowest_vcn: lowest vcn of the new attribute extent 2333495e90faSNamjae Jeon * @dataruns_size: dataruns size of the new attribute extent 2334495e90faSNamjae Jeon * @flags: flags of the new attribute extent 2335495e90faSNamjae Jeon */ 2336495e90faSNamjae Jeon static int ntfs_non_resident_attr_record_add(struct ntfs_inode *ni, __le32 type, 2337495e90faSNamjae Jeon __le16 *name, u8 name_len, s64 lowest_vcn, int dataruns_size, 2338495e90faSNamjae Jeon __le16 flags) 2339495e90faSNamjae Jeon { 2340495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 2341495e90faSNamjae Jeon u32 length; 2342495e90faSNamjae Jeon struct attr_record *a; 2343495e90faSNamjae Jeon struct mft_record *m; 2344495e90faSNamjae Jeon struct ntfs_inode *base_ni; 2345495e90faSNamjae Jeon int err, offset; 2346495e90faSNamjae Jeon 2347c418e967SEthan Tidmore if (!ni || dataruns_size <= 0 || (!name && name_len)) 2348c418e967SEthan Tidmore return -EINVAL; 2349c418e967SEthan Tidmore 2350495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x, lowest_vcn %lld, dataruns_size %d, flags 0x%x.\n", 2351495e90faSNamjae Jeon (long long) ni->mft_no, (unsigned int) le32_to_cpu(type), 2352495e90faSNamjae Jeon (long long) lowest_vcn, dataruns_size, 2353495e90faSNamjae Jeon (unsigned int) le16_to_cpu(flags)); 2354495e90faSNamjae Jeon 2355495e90faSNamjae Jeon err = ntfs_attr_can_be_non_resident(ni->vol, type); 2356495e90faSNamjae Jeon if (err) { 2357495e90faSNamjae Jeon if (err == -EPERM) 2358ea3566a3SWoody Suwalski pr_err("Attribute can't be non resident\n"); 2359495e90faSNamjae Jeon else 2360ea3566a3SWoody Suwalski pr_err("ntfs_attr_can_be_non_resident failed\n"); 2361495e90faSNamjae Jeon return err; 2362495e90faSNamjae Jeon } 2363495e90faSNamjae Jeon 2364495e90faSNamjae Jeon /* Locate place where record should be. */ 2365495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 2366495e90faSNamjae Jeon if (!ctx) { 2367ea3566a3SWoody Suwalski pr_err("%s: Failed to get search context\n", __func__); 2368495e90faSNamjae Jeon return -ENOMEM; 2369495e90faSNamjae Jeon } 2370495e90faSNamjae Jeon /* 2371495e90faSNamjae Jeon * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for 2372495e90faSNamjae Jeon * attribute in @ni->mrec, not any extent inode in case if @ni is base 2373495e90faSNamjae Jeon * file record. 2374495e90faSNamjae Jeon */ 2375495e90faSNamjae Jeon err = ntfs_attr_find(type, name, name_len, CASE_SENSITIVE, NULL, 0, ctx); 2376495e90faSNamjae Jeon if (!err) { 2377495e90faSNamjae Jeon err = -EEXIST; 2378ea3566a3SWoody Suwalski pr_err("Attribute 0x%x already present\n", type); 2379495e90faSNamjae Jeon goto put_err_out; 2380495e90faSNamjae Jeon } 2381495e90faSNamjae Jeon if (err != -ENOENT) { 2382ea3566a3SWoody Suwalski pr_err("ntfs_attr_find failed\n"); 2383495e90faSNamjae Jeon err = -EIO; 2384495e90faSNamjae Jeon goto put_err_out; 2385495e90faSNamjae Jeon } 2386495e90faSNamjae Jeon a = ctx->attr; 2387495e90faSNamjae Jeon m = ctx->mrec; 2388495e90faSNamjae Jeon 2389495e90faSNamjae Jeon /* Make room for attribute. */ 2390495e90faSNamjae Jeon dataruns_size = (dataruns_size + 7) & ~7; 2391495e90faSNamjae Jeon length = offsetof(struct attr_record, data.non_resident.compressed_size) + 2392495e90faSNamjae Jeon ((sizeof(__le16) * name_len + 7) & ~7) + dataruns_size + 2393495e90faSNamjae Jeon ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? 2394495e90faSNamjae Jeon sizeof(a->data.non_resident.compressed_size) : 0); 2395495e90faSNamjae Jeon err = ntfs_make_room_for_attr(ctx->mrec, (u8 *) ctx->attr, length); 2396495e90faSNamjae Jeon if (err) { 2397ea3566a3SWoody Suwalski pr_err("Failed to make room for attribute\n"); 2398495e90faSNamjae Jeon goto put_err_out; 2399495e90faSNamjae Jeon } 2400495e90faSNamjae Jeon 2401495e90faSNamjae Jeon /* Setup record fields. */ 2402495e90faSNamjae Jeon a->type = type; 2403495e90faSNamjae Jeon a->length = cpu_to_le32(length); 2404495e90faSNamjae Jeon a->non_resident = 1; 2405495e90faSNamjae Jeon a->name_length = name_len; 2406495e90faSNamjae Jeon a->name_offset = cpu_to_le16(offsetof(struct attr_record, 2407495e90faSNamjae Jeon data.non_resident.compressed_size) + 2408495e90faSNamjae Jeon ((flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE)) ? 2409495e90faSNamjae Jeon sizeof(a->data.non_resident.compressed_size) : 0)); 2410495e90faSNamjae Jeon a->flags = flags; 2411495e90faSNamjae Jeon a->instance = m->next_attr_instance; 2412495e90faSNamjae Jeon a->data.non_resident.lowest_vcn = cpu_to_le64(lowest_vcn); 2413495e90faSNamjae Jeon a->data.non_resident.mapping_pairs_offset = cpu_to_le16(length - dataruns_size); 2414495e90faSNamjae Jeon a->data.non_resident.compression_unit = 2415495e90faSNamjae Jeon (flags & ATTR_IS_COMPRESSED) ? STANDARD_COMPRESSION_UNIT : 0; 2416495e90faSNamjae Jeon /* If @lowest_vcn == 0, than setup empty attribute. */ 2417495e90faSNamjae Jeon if (!lowest_vcn) { 2418495e90faSNamjae Jeon a->data.non_resident.highest_vcn = cpu_to_le64(-1); 2419495e90faSNamjae Jeon a->data.non_resident.allocated_size = 0; 2420495e90faSNamjae Jeon a->data.non_resident.data_size = 0; 2421495e90faSNamjae Jeon a->data.non_resident.initialized_size = 0; 2422495e90faSNamjae Jeon /* Set empty mapping pairs. */ 2423495e90faSNamjae Jeon *((u8 *)a + le16_to_cpu(a->data.non_resident.mapping_pairs_offset)) = 0; 2424495e90faSNamjae Jeon } 2425495e90faSNamjae Jeon if (name_len) 2426495e90faSNamjae Jeon memcpy((u8 *)a + le16_to_cpu(a->name_offset), 2427495e90faSNamjae Jeon name, sizeof(__le16) * name_len); 2428495e90faSNamjae Jeon m->next_attr_instance = 2429495e90faSNamjae Jeon cpu_to_le16((le16_to_cpu(m->next_attr_instance) + 1) & 0xffff); 2430495e90faSNamjae Jeon if (ni->nr_extents == -1) 2431495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 2432495e90faSNamjae Jeon else 2433495e90faSNamjae Jeon base_ni = ni; 2434495e90faSNamjae Jeon if (type != AT_ATTRIBUTE_LIST && NInoAttrList(base_ni)) { 2435495e90faSNamjae Jeon err = ntfs_attrlist_entry_add(ni, a); 2436495e90faSNamjae Jeon if (err) { 2437ea3566a3SWoody Suwalski pr_err("Failed add attr entry to attrlist\n"); 2438495e90faSNamjae Jeon ntfs_attr_record_resize(m, a, 0); 2439495e90faSNamjae Jeon goto put_err_out; 2440495e90faSNamjae Jeon } 2441495e90faSNamjae Jeon } 2442495e90faSNamjae Jeon mark_mft_record_dirty(ni); 2443495e90faSNamjae Jeon /* 2444495e90faSNamjae Jeon * Locate offset from start of the MFT record where new attribute is 2445495e90faSNamjae Jeon * placed. We need relookup it, because record maybe moved during 2446495e90faSNamjae Jeon * update of attribute list. 2447495e90faSNamjae Jeon */ 2448495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 2449495e90faSNamjae Jeon err = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 2450495e90faSNamjae Jeon lowest_vcn, NULL, 0, ctx); 2451495e90faSNamjae Jeon if (err) { 2452ea3566a3SWoody Suwalski pr_err("%s: attribute lookup failed\n", __func__); 2453495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 2454495e90faSNamjae Jeon return err; 2455495e90faSNamjae Jeon 2456495e90faSNamjae Jeon } 2457495e90faSNamjae Jeon offset = (u8 *)ctx->attr - (u8 *)ctx->mrec; 2458495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 2459495e90faSNamjae Jeon return offset; 2460495e90faSNamjae Jeon put_err_out: 2461495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 2462495e90faSNamjae Jeon return -1; 2463495e90faSNamjae Jeon } 2464495e90faSNamjae Jeon 2465495e90faSNamjae Jeon /* 2466495e90faSNamjae Jeon * ntfs_attr_record_rm - remove attribute extent 2467495e90faSNamjae Jeon * @ctx: search context describing the attribute which should be removed 2468495e90faSNamjae Jeon * 2469495e90faSNamjae Jeon * If this function succeed, user should reinit search context if he/she wants 2470495e90faSNamjae Jeon * use it anymore. 2471495e90faSNamjae Jeon */ 2472495e90faSNamjae Jeon int ntfs_attr_record_rm(struct ntfs_attr_search_ctx *ctx) 2473495e90faSNamjae Jeon { 2474495e90faSNamjae Jeon struct ntfs_inode *base_ni, *ni; 2475495e90faSNamjae Jeon __le32 type; 2476495e90faSNamjae Jeon int err; 2477495e90faSNamjae Jeon 2478495e90faSNamjae Jeon if (!ctx || !ctx->ntfs_ino || !ctx->mrec || !ctx->attr) 2479495e90faSNamjae Jeon return -EINVAL; 2480495e90faSNamjae Jeon 2481495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x.\n", 2482495e90faSNamjae Jeon (long long) ctx->ntfs_ino->mft_no, 2483495e90faSNamjae Jeon (unsigned int) le32_to_cpu(ctx->attr->type)); 2484495e90faSNamjae Jeon type = ctx->attr->type; 2485495e90faSNamjae Jeon ni = ctx->ntfs_ino; 2486495e90faSNamjae Jeon if (ctx->base_ntfs_ino) 2487495e90faSNamjae Jeon base_ni = ctx->base_ntfs_ino; 2488495e90faSNamjae Jeon else 2489495e90faSNamjae Jeon base_ni = ctx->ntfs_ino; 2490495e90faSNamjae Jeon 2491495e90faSNamjae Jeon /* Remove attribute itself. */ 2492495e90faSNamjae Jeon if (ntfs_attr_record_resize(ctx->mrec, ctx->attr, 0)) { 2493495e90faSNamjae Jeon ntfs_debug("Couldn't remove attribute record. Bug or damaged MFT record.\n"); 2494495e90faSNamjae Jeon return -EIO; 2495495e90faSNamjae Jeon } 2496495e90faSNamjae Jeon mark_mft_record_dirty(ni); 2497495e90faSNamjae Jeon 2498495e90faSNamjae Jeon /* 2499495e90faSNamjae Jeon * Remove record from $ATTRIBUTE_LIST if present and we don't want 2500495e90faSNamjae Jeon * delete $ATTRIBUTE_LIST itself. 2501495e90faSNamjae Jeon */ 2502495e90faSNamjae Jeon if (NInoAttrList(base_ni) && type != AT_ATTRIBUTE_LIST) { 2503495e90faSNamjae Jeon err = ntfs_attrlist_entry_rm(ctx); 2504495e90faSNamjae Jeon if (err) { 2505495e90faSNamjae Jeon ntfs_debug("Couldn't delete record from $ATTRIBUTE_LIST.\n"); 2506495e90faSNamjae Jeon return err; 2507495e90faSNamjae Jeon } 2508495e90faSNamjae Jeon } 2509495e90faSNamjae Jeon 2510495e90faSNamjae Jeon /* Post $ATTRIBUTE_LIST delete setup. */ 2511495e90faSNamjae Jeon if (type == AT_ATTRIBUTE_LIST) { 2512495e90faSNamjae Jeon if (NInoAttrList(base_ni) && base_ni->attr_list) 2513495e90faSNamjae Jeon kvfree(base_ni->attr_list); 2514495e90faSNamjae Jeon base_ni->attr_list = NULL; 2515495e90faSNamjae Jeon NInoClearAttrList(base_ni); 2516495e90faSNamjae Jeon } 2517495e90faSNamjae Jeon 2518495e90faSNamjae Jeon /* Free MFT record, if it doesn't contain attributes. */ 2519495e90faSNamjae Jeon if (le32_to_cpu(ctx->mrec->bytes_in_use) - 2520495e90faSNamjae Jeon le16_to_cpu(ctx->mrec->attrs_offset) == 8) { 2521495e90faSNamjae Jeon if (ntfs_mft_record_free(ni->vol, ni)) { 2522495e90faSNamjae Jeon ntfs_debug("Couldn't free MFT record.\n"); 2523495e90faSNamjae Jeon return -EIO; 2524495e90faSNamjae Jeon } 2525495e90faSNamjae Jeon /* Remove done if we freed base inode. */ 2526495e90faSNamjae Jeon if (ni == base_ni) 2527495e90faSNamjae Jeon return 0; 2528495e90faSNamjae Jeon ntfs_inode_close(ni); 2529495e90faSNamjae Jeon ctx->ntfs_ino = ni = NULL; 2530495e90faSNamjae Jeon } 2531495e90faSNamjae Jeon 2532495e90faSNamjae Jeon if (type == AT_ATTRIBUTE_LIST || !NInoAttrList(base_ni)) 2533495e90faSNamjae Jeon return 0; 2534495e90faSNamjae Jeon 2535495e90faSNamjae Jeon /* Remove attribute list if we don't need it any more. */ 2536495e90faSNamjae Jeon if (!ntfs_attrlist_need(base_ni)) { 2537495e90faSNamjae Jeon struct ntfs_attr na; 2538495e90faSNamjae Jeon struct inode *attr_vi; 2539495e90faSNamjae Jeon 2540495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 2541495e90faSNamjae Jeon if (ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, CASE_SENSITIVE, 2542495e90faSNamjae Jeon 0, NULL, 0, ctx)) { 2543495e90faSNamjae Jeon ntfs_debug("Couldn't find attribute list. Succeed anyway.\n"); 2544495e90faSNamjae Jeon return 0; 2545495e90faSNamjae Jeon } 2546495e90faSNamjae Jeon /* Deallocate clusters. */ 2547495e90faSNamjae Jeon if (ctx->attr->non_resident) { 2548495e90faSNamjae Jeon struct runlist_element *al_rl; 2549495e90faSNamjae Jeon size_t new_rl_count; 2550495e90faSNamjae Jeon 2551495e90faSNamjae Jeon al_rl = ntfs_mapping_pairs_decompress(base_ni->vol, 2552495e90faSNamjae Jeon ctx->attr, NULL, &new_rl_count); 2553495e90faSNamjae Jeon if (IS_ERR(al_rl)) { 2554495e90faSNamjae Jeon ntfs_debug("Couldn't decompress attribute list runlist. Succeed anyway.\n"); 2555495e90faSNamjae Jeon return 0; 2556495e90faSNamjae Jeon } 2557495e90faSNamjae Jeon if (ntfs_cluster_free_from_rl(base_ni->vol, al_rl)) 2558495e90faSNamjae Jeon ntfs_debug("Leaking clusters! Run chkdsk. Couldn't free clusters from attribute list runlist.\n"); 2559495e90faSNamjae Jeon kvfree(al_rl); 2560495e90faSNamjae Jeon } 2561495e90faSNamjae Jeon /* Remove attribute record itself. */ 2562495e90faSNamjae Jeon if (ntfs_attr_record_rm(ctx)) { 2563495e90faSNamjae Jeon ntfs_debug("Couldn't remove attribute list. Succeed anyway.\n"); 2564495e90faSNamjae Jeon return 0; 2565495e90faSNamjae Jeon } 2566495e90faSNamjae Jeon 2567495e90faSNamjae Jeon na.mft_no = VFS_I(base_ni)->i_ino; 2568495e90faSNamjae Jeon na.type = AT_ATTRIBUTE_LIST; 2569495e90faSNamjae Jeon na.name = NULL; 2570495e90faSNamjae Jeon na.name_len = 0; 2571495e90faSNamjae Jeon 2572495e90faSNamjae Jeon attr_vi = ilookup5(VFS_I(base_ni)->i_sb, VFS_I(base_ni)->i_ino, 2573495e90faSNamjae Jeon ntfs_test_inode, &na); 2574495e90faSNamjae Jeon if (attr_vi) { 2575495e90faSNamjae Jeon clear_nlink(attr_vi); 2576495e90faSNamjae Jeon iput(attr_vi); 2577495e90faSNamjae Jeon } 2578495e90faSNamjae Jeon 2579495e90faSNamjae Jeon } 2580495e90faSNamjae Jeon return 0; 2581495e90faSNamjae Jeon } 2582495e90faSNamjae Jeon 2583495e90faSNamjae Jeon /* 2584495e90faSNamjae Jeon * ntfs_attr_add - add attribute to inode 2585495e90faSNamjae Jeon * @ni: opened ntfs inode to which add attribute 2586495e90faSNamjae Jeon * @type: type of the new attribute 2587495e90faSNamjae Jeon * @name: name in unicode of the new attribute 2588495e90faSNamjae Jeon * @name_len: name length in unicode characters of the new attribute 2589495e90faSNamjae Jeon * @val: value of new attribute 2590495e90faSNamjae Jeon * @size: size of the new attribute / length of @val (if specified) 2591495e90faSNamjae Jeon * 2592495e90faSNamjae Jeon * @val should always be specified for always resident attributes (eg. FILE_NAME 2593495e90faSNamjae Jeon * attribute), for attributes that can become non-resident @val can be NULL 2594495e90faSNamjae Jeon * (eg. DATA attribute). @size can be specified even if @val is NULL, in this 2595495e90faSNamjae Jeon * case data size will be equal to @size and initialized size will be equal 2596495e90faSNamjae Jeon * to 0. 2597495e90faSNamjae Jeon * 2598495e90faSNamjae Jeon * If inode haven't got enough space to add attribute, add attribute to one of 2599495e90faSNamjae Jeon * it extents, if no extents present or no one of them have enough space, than 2600495e90faSNamjae Jeon * allocate new extent and add attribute to it. 2601495e90faSNamjae Jeon * 2602495e90faSNamjae Jeon * If on one of this steps attribute list is needed but not present, than it is 2603495e90faSNamjae Jeon * added transparently to caller. So, this function should not be called with 2604495e90faSNamjae Jeon * @type == AT_ATTRIBUTE_LIST, if you really need to add attribute list call 2605495e90faSNamjae Jeon * ntfs_inode_add_attrlist instead. 2606495e90faSNamjae Jeon * 2607495e90faSNamjae Jeon * On success return 0. On error return -1 with errno set to the error code. 2608495e90faSNamjae Jeon */ 2609495e90faSNamjae Jeon int ntfs_attr_add(struct ntfs_inode *ni, __le32 type, 2610495e90faSNamjae Jeon __le16 *name, u8 name_len, u8 *val, s64 size) 2611495e90faSNamjae Jeon { 2612495e90faSNamjae Jeon struct super_block *sb; 2613495e90faSNamjae Jeon u32 attr_rec_size; 2614495e90faSNamjae Jeon int err, i, offset; 2615495e90faSNamjae Jeon bool is_resident; 2616495e90faSNamjae Jeon bool can_be_non_resident = false; 2617495e90faSNamjae Jeon struct ntfs_inode *attr_ni; 2618495e90faSNamjae Jeon struct inode *attr_vi; 2619495e90faSNamjae Jeon struct mft_record *ni_mrec; 2620495e90faSNamjae Jeon 2621495e90faSNamjae Jeon if (!ni || size < 0 || type == AT_ATTRIBUTE_LIST) 2622495e90faSNamjae Jeon return -EINVAL; 2623495e90faSNamjae Jeon 2624495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr %x, size %lld.\n", 2625495e90faSNamjae Jeon (long long) ni->mft_no, type, size); 2626495e90faSNamjae Jeon 2627495e90faSNamjae Jeon if (ni->nr_extents == -1) 2628495e90faSNamjae Jeon ni = ni->ext.base_ntfs_ino; 2629495e90faSNamjae Jeon 2630495e90faSNamjae Jeon /* Check the attribute type and the size. */ 2631495e90faSNamjae Jeon err = ntfs_attr_size_bounds_check(ni->vol, type, size); 2632495e90faSNamjae Jeon if (err) { 2633495e90faSNamjae Jeon if (err == -ENOENT) 2634495e90faSNamjae Jeon err = -EIO; 2635495e90faSNamjae Jeon return err; 2636495e90faSNamjae Jeon } 2637495e90faSNamjae Jeon 2638495e90faSNamjae Jeon sb = ni->vol->sb; 2639495e90faSNamjae Jeon /* Sanity checks for always resident attributes. */ 2640495e90faSNamjae Jeon err = ntfs_attr_can_be_non_resident(ni->vol, type); 2641495e90faSNamjae Jeon if (err) { 2642495e90faSNamjae Jeon if (err != -EPERM) { 2643495e90faSNamjae Jeon ntfs_error(sb, "ntfs_attr_can_be_non_resident failed"); 2644495e90faSNamjae Jeon goto err_out; 2645495e90faSNamjae Jeon } 2646495e90faSNamjae Jeon /* @val is mandatory. */ 2647495e90faSNamjae Jeon if (!val) { 2648495e90faSNamjae Jeon ntfs_error(sb, 2649495e90faSNamjae Jeon "val is mandatory for always resident attributes"); 2650495e90faSNamjae Jeon return -EINVAL; 2651495e90faSNamjae Jeon } 2652495e90faSNamjae Jeon if (size > ni->vol->mft_record_size) { 2653495e90faSNamjae Jeon ntfs_error(sb, "Attribute is too big"); 2654495e90faSNamjae Jeon return -ERANGE; 2655495e90faSNamjae Jeon } 2656495e90faSNamjae Jeon } else 2657495e90faSNamjae Jeon can_be_non_resident = true; 2658495e90faSNamjae Jeon 2659495e90faSNamjae Jeon /* 2660495e90faSNamjae Jeon * Determine resident or not will be new attribute. We add 8 to size in 2661495e90faSNamjae Jeon * non resident case for mapping pairs. 2662495e90faSNamjae Jeon */ 2663495e90faSNamjae Jeon err = ntfs_attr_can_be_resident(ni->vol, type); 2664495e90faSNamjae Jeon if (!err) { 2665495e90faSNamjae Jeon is_resident = true; 2666495e90faSNamjae Jeon } else { 2667495e90faSNamjae Jeon if (err != -EPERM) { 2668495e90faSNamjae Jeon ntfs_error(sb, "ntfs_attr_can_be_resident failed"); 2669495e90faSNamjae Jeon goto err_out; 2670495e90faSNamjae Jeon } 2671495e90faSNamjae Jeon is_resident = false; 2672495e90faSNamjae Jeon } 2673495e90faSNamjae Jeon 2674495e90faSNamjae Jeon /* Calculate attribute record size. */ 2675495e90faSNamjae Jeon if (is_resident) 2676495e90faSNamjae Jeon attr_rec_size = offsetof(struct attr_record, data.resident.reserved) + 2677495e90faSNamjae Jeon 1 + 2678495e90faSNamjae Jeon ((name_len * sizeof(__le16) + 7) & ~7) + 2679495e90faSNamjae Jeon ((size + 7) & ~7); 2680495e90faSNamjae Jeon else 2681495e90faSNamjae Jeon attr_rec_size = offsetof(struct attr_record, data.non_resident.compressed_size) + 2682495e90faSNamjae Jeon ((name_len * sizeof(__le16) + 7) & ~7) + 8; 2683495e90faSNamjae Jeon 2684495e90faSNamjae Jeon /* 2685495e90faSNamjae Jeon * If we have enough free space for the new attribute in the base MFT 2686495e90faSNamjae Jeon * record, then add attribute to it. 2687495e90faSNamjae Jeon */ 2688495e90faSNamjae Jeon retry: 2689495e90faSNamjae Jeon ni_mrec = map_mft_record(ni); 2690495e90faSNamjae Jeon if (IS_ERR(ni_mrec)) { 2691495e90faSNamjae Jeon err = -EIO; 2692495e90faSNamjae Jeon goto err_out; 2693495e90faSNamjae Jeon } 2694495e90faSNamjae Jeon 2695495e90faSNamjae Jeon if (le32_to_cpu(ni_mrec->bytes_allocated) - 2696495e90faSNamjae Jeon le32_to_cpu(ni_mrec->bytes_in_use) >= attr_rec_size) { 2697495e90faSNamjae Jeon attr_ni = ni; 2698495e90faSNamjae Jeon unmap_mft_record(ni); 2699495e90faSNamjae Jeon goto add_attr_record; 2700495e90faSNamjae Jeon } 2701495e90faSNamjae Jeon unmap_mft_record(ni); 2702495e90faSNamjae Jeon 2703495e90faSNamjae Jeon /* Try to add to extent inodes. */ 2704495e90faSNamjae Jeon err = ntfs_inode_attach_all_extents(ni); 2705495e90faSNamjae Jeon if (err) { 2706495e90faSNamjae Jeon ntfs_error(sb, "Failed to attach all extents to inode"); 2707495e90faSNamjae Jeon goto err_out; 2708495e90faSNamjae Jeon } 2709495e90faSNamjae Jeon 2710495e90faSNamjae Jeon for (i = 0; i < ni->nr_extents; i++) { 2711495e90faSNamjae Jeon attr_ni = ni->ext.extent_ntfs_inos[i]; 2712495e90faSNamjae Jeon ni_mrec = map_mft_record(attr_ni); 2713495e90faSNamjae Jeon if (IS_ERR(ni_mrec)) { 2714495e90faSNamjae Jeon err = -EIO; 2715495e90faSNamjae Jeon goto err_out; 2716495e90faSNamjae Jeon } 2717495e90faSNamjae Jeon 2718495e90faSNamjae Jeon if (le32_to_cpu(ni_mrec->bytes_allocated) - 2719495e90faSNamjae Jeon le32_to_cpu(ni_mrec->bytes_in_use) >= 2720495e90faSNamjae Jeon attr_rec_size) { 2721495e90faSNamjae Jeon unmap_mft_record(attr_ni); 2722495e90faSNamjae Jeon goto add_attr_record; 2723495e90faSNamjae Jeon } 2724495e90faSNamjae Jeon unmap_mft_record(attr_ni); 2725495e90faSNamjae Jeon } 2726495e90faSNamjae Jeon 2727495e90faSNamjae Jeon /* There is no extent that contain enough space for new attribute. */ 2728495e90faSNamjae Jeon if (!NInoAttrList(ni)) { 2729495e90faSNamjae Jeon /* Add attribute list not present, add it and retry. */ 2730495e90faSNamjae Jeon err = ntfs_inode_add_attrlist(ni); 2731495e90faSNamjae Jeon if (err) { 2732495e90faSNamjae Jeon ntfs_error(sb, "Failed to add attribute list"); 2733495e90faSNamjae Jeon goto err_out; 2734495e90faSNamjae Jeon } 2735495e90faSNamjae Jeon goto retry; 2736495e90faSNamjae Jeon } 2737495e90faSNamjae Jeon 2738495e90faSNamjae Jeon attr_ni = NULL; 2739495e90faSNamjae Jeon /* Allocate new extent. */ 2740495e90faSNamjae Jeon err = ntfs_mft_record_alloc(ni->vol, 0, &attr_ni, ni, NULL); 2741495e90faSNamjae Jeon if (err) { 2742495e90faSNamjae Jeon ntfs_error(sb, "Failed to allocate extent record"); 2743495e90faSNamjae Jeon goto err_out; 2744495e90faSNamjae Jeon } 2745495e90faSNamjae Jeon unmap_mft_record(attr_ni); 2746495e90faSNamjae Jeon 2747495e90faSNamjae Jeon add_attr_record: 2748495e90faSNamjae Jeon if (is_resident) { 2749495e90faSNamjae Jeon /* Add resident attribute. */ 2750495e90faSNamjae Jeon offset = ntfs_resident_attr_record_add(attr_ni, type, name, 2751495e90faSNamjae Jeon name_len, val, size, 0); 2752495e90faSNamjae Jeon if (offset < 0) { 2753495e90faSNamjae Jeon if (offset == -ENOSPC && can_be_non_resident) 2754495e90faSNamjae Jeon goto add_non_resident; 2755495e90faSNamjae Jeon err = offset; 2756495e90faSNamjae Jeon ntfs_error(sb, "Failed to add resident attribute"); 2757495e90faSNamjae Jeon goto free_err_out; 2758495e90faSNamjae Jeon } 2759495e90faSNamjae Jeon return 0; 2760495e90faSNamjae Jeon } 2761495e90faSNamjae Jeon 2762495e90faSNamjae Jeon add_non_resident: 2763495e90faSNamjae Jeon /* Add non resident attribute. */ 2764495e90faSNamjae Jeon offset = ntfs_non_resident_attr_record_add(attr_ni, type, name, 2765495e90faSNamjae Jeon name_len, 0, 8, 0); 2766495e90faSNamjae Jeon if (offset < 0) { 2767495e90faSNamjae Jeon err = offset; 2768495e90faSNamjae Jeon ntfs_error(sb, "Failed to add non resident attribute"); 2769495e90faSNamjae Jeon goto free_err_out; 2770495e90faSNamjae Jeon } 2771495e90faSNamjae Jeon 2772495e90faSNamjae Jeon /* If @size == 0, we are done. */ 2773495e90faSNamjae Jeon if (!size) 2774495e90faSNamjae Jeon return 0; 2775495e90faSNamjae Jeon 2776495e90faSNamjae Jeon /* Open new attribute and resize it. */ 2777495e90faSNamjae Jeon attr_vi = ntfs_attr_iget(VFS_I(ni), type, name, name_len); 2778495e90faSNamjae Jeon if (IS_ERR(attr_vi)) { 27791c85157eSEthan Tidmore err = PTR_ERR(attr_vi); 2780495e90faSNamjae Jeon ntfs_error(sb, "Failed to open just added attribute"); 2781495e90faSNamjae Jeon goto rm_attr_err_out; 2782495e90faSNamjae Jeon } 2783495e90faSNamjae Jeon attr_ni = NTFS_I(attr_vi); 2784495e90faSNamjae Jeon 2785495e90faSNamjae Jeon /* Resize and set attribute value. */ 2786495e90faSNamjae Jeon if (ntfs_attr_truncate(attr_ni, size) || 2787495e90faSNamjae Jeon (val && (ntfs_inode_attr_pwrite(attr_vi, 0, size, val, false) != size))) { 2788495e90faSNamjae Jeon err = -EIO; 2789495e90faSNamjae Jeon ntfs_error(sb, "Failed to initialize just added attribute"); 2790495e90faSNamjae Jeon if (ntfs_attr_rm(attr_ni)) 2791495e90faSNamjae Jeon ntfs_error(sb, "Failed to remove just added attribute"); 2792495e90faSNamjae Jeon iput(attr_vi); 2793495e90faSNamjae Jeon goto err_out; 2794495e90faSNamjae Jeon } 2795495e90faSNamjae Jeon iput(attr_vi); 2796495e90faSNamjae Jeon return 0; 2797495e90faSNamjae Jeon 2798495e90faSNamjae Jeon rm_attr_err_out: 2799495e90faSNamjae Jeon /* Remove just added attribute. */ 2800495e90faSNamjae Jeon ni_mrec = map_mft_record(attr_ni); 2801495e90faSNamjae Jeon if (!IS_ERR(ni_mrec)) { 2802495e90faSNamjae Jeon if (ntfs_attr_record_resize(ni_mrec, 2803495e90faSNamjae Jeon (struct attr_record *)((u8 *)ni_mrec + offset), 0)) 2804495e90faSNamjae Jeon ntfs_error(sb, "Failed to remove just added attribute #2"); 2805495e90faSNamjae Jeon unmap_mft_record(attr_ni); 2806495e90faSNamjae Jeon } else 2807495e90faSNamjae Jeon pr_err("EIO when try to remove new added attr\n"); 2808495e90faSNamjae Jeon 2809495e90faSNamjae Jeon free_err_out: 2810495e90faSNamjae Jeon /* Free MFT record, if it doesn't contain attributes. */ 2811495e90faSNamjae Jeon ni_mrec = map_mft_record(attr_ni); 2812495e90faSNamjae Jeon if (!IS_ERR(ni_mrec)) { 2813495e90faSNamjae Jeon int attr_size; 2814495e90faSNamjae Jeon 2815495e90faSNamjae Jeon attr_size = le32_to_cpu(ni_mrec->bytes_in_use) - 2816495e90faSNamjae Jeon le16_to_cpu(ni_mrec->attrs_offset); 2817495e90faSNamjae Jeon unmap_mft_record(attr_ni); 2818495e90faSNamjae Jeon if (attr_size == 8) { 2819495e90faSNamjae Jeon if (ntfs_mft_record_free(attr_ni->vol, attr_ni)) 2820495e90faSNamjae Jeon ntfs_error(sb, "Failed to free MFT record"); 2821495e90faSNamjae Jeon if (attr_ni->nr_extents < 0) 2822495e90faSNamjae Jeon ntfs_inode_close(attr_ni); 2823495e90faSNamjae Jeon } 2824495e90faSNamjae Jeon } else 2825495e90faSNamjae Jeon pr_err("EIO when testing mft record is free-able\n"); 2826495e90faSNamjae Jeon 2827495e90faSNamjae Jeon err_out: 2828495e90faSNamjae Jeon return err; 2829495e90faSNamjae Jeon } 2830495e90faSNamjae Jeon 2831495e90faSNamjae Jeon /* 2832495e90faSNamjae Jeon * __ntfs_attr_init - primary initialization of an ntfs attribute structure 2833495e90faSNamjae Jeon * @ni: ntfs attribute inode to initialize 2834495e90faSNamjae Jeon * @ni: ntfs inode with which to initialize the ntfs attribute 2835495e90faSNamjae Jeon * @type: attribute type 2836495e90faSNamjae Jeon * @name: attribute name in little endian Unicode or NULL 2837495e90faSNamjae Jeon * @name_len: length of attribute @name in Unicode characters (if @name given) 2838495e90faSNamjae Jeon * 2839495e90faSNamjae Jeon * Initialize the ntfs attribute @na with @ni, @type, @name, and @name_len. 2840495e90faSNamjae Jeon */ 2841495e90faSNamjae Jeon static void __ntfs_attr_init(struct ntfs_inode *ni, 2842495e90faSNamjae Jeon const __le32 type, __le16 *name, const u32 name_len) 2843495e90faSNamjae Jeon { 2844495e90faSNamjae Jeon ni->runlist.rl = NULL; 2845495e90faSNamjae Jeon ni->type = type; 2846495e90faSNamjae Jeon ni->name = name; 2847495e90faSNamjae Jeon if (name) 2848495e90faSNamjae Jeon ni->name_len = name_len; 2849495e90faSNamjae Jeon else 2850495e90faSNamjae Jeon ni->name_len = 0; 2851495e90faSNamjae Jeon } 2852495e90faSNamjae Jeon 2853495e90faSNamjae Jeon /* 2854495e90faSNamjae Jeon * ntfs_attr_init - initialize an ntfs_attr with data sizes and status 2855495e90faSNamjae Jeon * @ni: ntfs inode to initialize 2856495e90faSNamjae Jeon * @non_resident: true if attribute is non-resident 2857495e90faSNamjae Jeon * @compressed: true if attribute is compressed 2858495e90faSNamjae Jeon * @encrypted: true if attribute is encrypted 2859495e90faSNamjae Jeon * @sparse: true if attribute is sparse 2860495e90faSNamjae Jeon * @allocated_size: allocated size of the attribute 2861495e90faSNamjae Jeon * @data_size: actual data size of the attribute 2862495e90faSNamjae Jeon * @initialized_size: initialized size of the attribute 2863495e90faSNamjae Jeon * @compressed_size: compressed size (if compressed or sparse) 2864495e90faSNamjae Jeon * @compression_unit: compression unit size (log2 of clusters) 2865495e90faSNamjae Jeon * 2866495e90faSNamjae Jeon * Final initialization for an ntfs attribute. 2867495e90faSNamjae Jeon */ 2868495e90faSNamjae Jeon static void ntfs_attr_init(struct ntfs_inode *ni, const bool non_resident, 2869495e90faSNamjae Jeon const bool compressed, const bool encrypted, const bool sparse, 2870495e90faSNamjae Jeon const s64 allocated_size, const s64 data_size, 2871495e90faSNamjae Jeon const s64 initialized_size, const s64 compressed_size, 2872495e90faSNamjae Jeon const u8 compression_unit) 2873495e90faSNamjae Jeon { 2874495e90faSNamjae Jeon if (non_resident) 2875495e90faSNamjae Jeon NInoSetNonResident(ni); 2876495e90faSNamjae Jeon if (compressed) { 2877495e90faSNamjae Jeon NInoSetCompressed(ni); 2878495e90faSNamjae Jeon ni->flags |= FILE_ATTR_COMPRESSED; 2879495e90faSNamjae Jeon } 2880495e90faSNamjae Jeon if (encrypted) { 2881495e90faSNamjae Jeon NInoSetEncrypted(ni); 2882495e90faSNamjae Jeon ni->flags |= FILE_ATTR_ENCRYPTED; 2883495e90faSNamjae Jeon } 2884495e90faSNamjae Jeon if (sparse) { 2885495e90faSNamjae Jeon NInoSetSparse(ni); 2886495e90faSNamjae Jeon ni->flags |= FILE_ATTR_SPARSE_FILE; 2887495e90faSNamjae Jeon } 2888495e90faSNamjae Jeon ni->allocated_size = allocated_size; 2889495e90faSNamjae Jeon ni->data_size = data_size; 2890495e90faSNamjae Jeon ni->initialized_size = initialized_size; 2891495e90faSNamjae Jeon if (compressed || sparse) { 2892495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 2893495e90faSNamjae Jeon 2894495e90faSNamjae Jeon ni->itype.compressed.size = compressed_size; 2895495e90faSNamjae Jeon ni->itype.compressed.block_clusters = 1 << compression_unit; 2896495e90faSNamjae Jeon ni->itype.compressed.block_size = 1 << (compression_unit + 2897495e90faSNamjae Jeon vol->cluster_size_bits); 2898495e90faSNamjae Jeon ni->itype.compressed.block_size_bits = ffs( 2899495e90faSNamjae Jeon ni->itype.compressed.block_size) - 1; 2900495e90faSNamjae Jeon } 2901495e90faSNamjae Jeon } 2902495e90faSNamjae Jeon 2903495e90faSNamjae Jeon /* 2904495e90faSNamjae Jeon * ntfs_attr_open - open an ntfs attribute for access 2905495e90faSNamjae Jeon * @ni: open ntfs inode in which the ntfs attribute resides 2906495e90faSNamjae Jeon * @type: attribute type 2907495e90faSNamjae Jeon * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL 2908495e90faSNamjae Jeon * @name_len: length of attribute @name in Unicode characters (if @name given) 2909495e90faSNamjae Jeon */ 2910495e90faSNamjae Jeon int ntfs_attr_open(struct ntfs_inode *ni, const __le32 type, 2911495e90faSNamjae Jeon __le16 *name, u32 name_len) 2912495e90faSNamjae Jeon { 2913495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 2914495e90faSNamjae Jeon __le16 *newname = NULL; 2915495e90faSNamjae Jeon struct attr_record *a; 2916495e90faSNamjae Jeon bool cs; 2917495e90faSNamjae Jeon struct ntfs_inode *base_ni; 2918495e90faSNamjae Jeon int err; 2919495e90faSNamjae Jeon 2920495e90faSNamjae Jeon ntfs_debug("Entering for inode %lld, attr 0x%x.\n", 2921495e90faSNamjae Jeon (unsigned long long)ni->mft_no, type); 2922495e90faSNamjae Jeon 2923495e90faSNamjae Jeon if (!ni || !ni->vol) 2924495e90faSNamjae Jeon return -EINVAL; 2925495e90faSNamjae Jeon 2926495e90faSNamjae Jeon if (NInoAttr(ni)) 2927495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 2928495e90faSNamjae Jeon else 2929495e90faSNamjae Jeon base_ni = ni; 2930495e90faSNamjae Jeon 2931495e90faSNamjae Jeon if (name && name != AT_UNNAMED && name != I30) { 2932495e90faSNamjae Jeon name = ntfs_ucsndup(name, name_len); 2933495e90faSNamjae Jeon if (!name) { 2934495e90faSNamjae Jeon err = -ENOMEM; 2935495e90faSNamjae Jeon goto err_out; 2936495e90faSNamjae Jeon } 2937495e90faSNamjae Jeon newname = name; 2938495e90faSNamjae Jeon } 2939495e90faSNamjae Jeon 2940495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, NULL); 2941495e90faSNamjae Jeon if (!ctx) { 2942495e90faSNamjae Jeon err = -ENOMEM; 2943ea3566a3SWoody Suwalski pr_err("%s: Failed to get search context\n", __func__); 2944495e90faSNamjae Jeon goto err_out; 2945495e90faSNamjae Jeon } 2946495e90faSNamjae Jeon 2947495e90faSNamjae Jeon err = ntfs_attr_lookup(type, name, name_len, 0, 0, NULL, 0, ctx); 2948495e90faSNamjae Jeon if (err) 2949495e90faSNamjae Jeon goto put_err_out; 2950495e90faSNamjae Jeon 2951495e90faSNamjae Jeon a = ctx->attr; 2952495e90faSNamjae Jeon 2953495e90faSNamjae Jeon if (!name) { 2954495e90faSNamjae Jeon if (a->name_length) { 2955495e90faSNamjae Jeon name = ntfs_ucsndup((__le16 *)((u8 *)a + le16_to_cpu(a->name_offset)), 2956495e90faSNamjae Jeon a->name_length); 2957495e90faSNamjae Jeon if (!name) 2958495e90faSNamjae Jeon goto put_err_out; 2959495e90faSNamjae Jeon newname = name; 2960495e90faSNamjae Jeon name_len = a->name_length; 2961495e90faSNamjae Jeon } else { 2962495e90faSNamjae Jeon name = AT_UNNAMED; 2963495e90faSNamjae Jeon name_len = 0; 2964495e90faSNamjae Jeon } 2965495e90faSNamjae Jeon } 2966495e90faSNamjae Jeon 2967495e90faSNamjae Jeon __ntfs_attr_init(ni, type, name, name_len); 2968495e90faSNamjae Jeon 2969495e90faSNamjae Jeon /* 2970495e90faSNamjae Jeon * Wipe the flags in case they are not zero for an attribute list 2971495e90faSNamjae Jeon * attribute. Windows does not complain about invalid flags and chkdsk 2972495e90faSNamjae Jeon * does not detect or fix them so we need to cope with it, too. 2973495e90faSNamjae Jeon */ 2974495e90faSNamjae Jeon if (type == AT_ATTRIBUTE_LIST) 2975495e90faSNamjae Jeon a->flags = 0; 2976495e90faSNamjae Jeon 2977495e90faSNamjae Jeon if ((type == AT_DATA) && 2978495e90faSNamjae Jeon (a->non_resident ? !a->data.non_resident.initialized_size : 2979495e90faSNamjae Jeon !a->data.resident.value_length)) { 2980495e90faSNamjae Jeon /* 2981495e90faSNamjae Jeon * Define/redefine the compression state if stream is 2982495e90faSNamjae Jeon * empty, based on the compression mark on parent 2983495e90faSNamjae Jeon * directory (for unnamed data streams) or on current 2984495e90faSNamjae Jeon * inode (for named data streams). The compression mark 2985495e90faSNamjae Jeon * may change any time, the compression state can only 2986495e90faSNamjae Jeon * change when stream is wiped out. 2987495e90faSNamjae Jeon * 2988495e90faSNamjae Jeon * Also prevent compression on NTFS version < 3.0 2989495e90faSNamjae Jeon * or cluster size > 4K or compression is disabled 2990495e90faSNamjae Jeon */ 2991495e90faSNamjae Jeon a->flags &= ~ATTR_COMPRESSION_MASK; 2992495e90faSNamjae Jeon if (NInoCompressed(ni) 2993495e90faSNamjae Jeon && (ni->vol->major_ver >= 3) 2994495e90faSNamjae Jeon && NVolCompression(ni->vol) 2995495e90faSNamjae Jeon && (ni->vol->cluster_size <= MAX_COMPRESSION_CLUSTER_SIZE)) 2996495e90faSNamjae Jeon a->flags |= ATTR_IS_COMPRESSED; 2997495e90faSNamjae Jeon } 2998495e90faSNamjae Jeon 2999495e90faSNamjae Jeon cs = a->flags & (ATTR_IS_COMPRESSED | ATTR_IS_SPARSE); 3000495e90faSNamjae Jeon 3001495e90faSNamjae Jeon if (ni->type == AT_DATA && ni->name == AT_UNNAMED && 3002495e90faSNamjae Jeon ((!(a->flags & ATTR_IS_COMPRESSED) != !NInoCompressed(ni)) || 3003495e90faSNamjae Jeon (!(a->flags & ATTR_IS_SPARSE) != !NInoSparse(ni)) || 3004495e90faSNamjae Jeon (!(a->flags & ATTR_IS_ENCRYPTED) != !NInoEncrypted(ni)))) { 3005495e90faSNamjae Jeon err = -EIO; 3006495e90faSNamjae Jeon pr_err("Inode %lld has corrupt attribute flags (0x%x <> 0x%x)\n", 3007495e90faSNamjae Jeon (unsigned long long)ni->mft_no, 3008495e90faSNamjae Jeon a->flags, ni->flags); 3009495e90faSNamjae Jeon goto put_err_out; 3010495e90faSNamjae Jeon } 3011495e90faSNamjae Jeon 3012495e90faSNamjae Jeon if (a->non_resident) { 3013495e90faSNamjae Jeon if (((a->flags & ATTR_COMPRESSION_MASK) || a->data.non_resident.compression_unit) && 3014495e90faSNamjae Jeon (ni->vol->major_ver < 3)) { 3015495e90faSNamjae Jeon err = -EIO; 3016495e90faSNamjae Jeon pr_err("Compressed inode %lld not allowed on NTFS %d.%d\n", 3017495e90faSNamjae Jeon (unsigned long long)ni->mft_no, 3018495e90faSNamjae Jeon ni->vol->major_ver, 3019495e90faSNamjae Jeon ni->vol->major_ver); 3020495e90faSNamjae Jeon goto put_err_out; 3021495e90faSNamjae Jeon } 3022495e90faSNamjae Jeon 3023495e90faSNamjae Jeon if ((a->flags & ATTR_IS_COMPRESSED) && !a->data.non_resident.compression_unit) { 3024495e90faSNamjae Jeon err = -EIO; 3025495e90faSNamjae Jeon pr_err("Compressed inode %lld attr 0x%x has no compression unit\n", 3026495e90faSNamjae Jeon (unsigned long long)ni->mft_no, type); 3027495e90faSNamjae Jeon goto put_err_out; 3028495e90faSNamjae Jeon } 3029495e90faSNamjae Jeon if ((a->flags & ATTR_COMPRESSION_MASK) && 3030495e90faSNamjae Jeon (a->data.non_resident.compression_unit != STANDARD_COMPRESSION_UNIT)) { 3031495e90faSNamjae Jeon err = -EIO; 3032495e90faSNamjae Jeon pr_err("Compressed inode %lld attr 0x%lx has an unsupported compression unit %d\n", 3033495e90faSNamjae Jeon (unsigned long long)ni->mft_no, 3034495e90faSNamjae Jeon (long)le32_to_cpu(type), 3035495e90faSNamjae Jeon (int)a->data.non_resident.compression_unit); 3036495e90faSNamjae Jeon goto put_err_out; 3037495e90faSNamjae Jeon } 3038495e90faSNamjae Jeon ntfs_attr_init(ni, true, a->flags & ATTR_IS_COMPRESSED, 3039495e90faSNamjae Jeon a->flags & ATTR_IS_ENCRYPTED, 3040495e90faSNamjae Jeon a->flags & ATTR_IS_SPARSE, 3041495e90faSNamjae Jeon le64_to_cpu(a->data.non_resident.allocated_size), 3042495e90faSNamjae Jeon le64_to_cpu(a->data.non_resident.data_size), 3043495e90faSNamjae Jeon le64_to_cpu(a->data.non_resident.initialized_size), 3044495e90faSNamjae Jeon cs ? le64_to_cpu(a->data.non_resident.compressed_size) : 0, 3045495e90faSNamjae Jeon cs ? a->data.non_resident.compression_unit : 0); 3046495e90faSNamjae Jeon } else { 3047495e90faSNamjae Jeon s64 l = le32_to_cpu(a->data.resident.value_length); 3048495e90faSNamjae Jeon 3049495e90faSNamjae Jeon ntfs_attr_init(ni, false, a->flags & ATTR_IS_COMPRESSED, 3050495e90faSNamjae Jeon a->flags & ATTR_IS_ENCRYPTED, 3051495e90faSNamjae Jeon a->flags & ATTR_IS_SPARSE, (l + 7) & ~7, l, l, 3052495e90faSNamjae Jeon cs ? (l + 7) & ~7 : 0, 0); 3053495e90faSNamjae Jeon } 3054495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3055495e90faSNamjae Jeon out: 3056495e90faSNamjae Jeon ntfs_debug("\n"); 3057495e90faSNamjae Jeon return err; 3058495e90faSNamjae Jeon 3059495e90faSNamjae Jeon put_err_out: 3060495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3061495e90faSNamjae Jeon err_out: 3062495e90faSNamjae Jeon kfree(newname); 3063495e90faSNamjae Jeon goto out; 3064495e90faSNamjae Jeon } 3065495e90faSNamjae Jeon 3066495e90faSNamjae Jeon /* 3067495e90faSNamjae Jeon * ntfs_attr_close - free an ntfs attribute structure 3068495e90faSNamjae Jeon * @ni: ntfs inode to free 3069495e90faSNamjae Jeon * 3070495e90faSNamjae Jeon * Release all memory associated with the ntfs attribute @na and then release 3071495e90faSNamjae Jeon * @na itself. 3072495e90faSNamjae Jeon */ 3073495e90faSNamjae Jeon void ntfs_attr_close(struct ntfs_inode *ni) 3074495e90faSNamjae Jeon { 3075495e90faSNamjae Jeon if (NInoNonResident(ni) && ni->runlist.rl) 3076495e90faSNamjae Jeon kvfree(ni->runlist.rl); 3077495e90faSNamjae Jeon /* Don't release if using an internal constant. */ 3078495e90faSNamjae Jeon if (ni->name != AT_UNNAMED && ni->name != I30) 3079495e90faSNamjae Jeon kfree(ni->name); 3080495e90faSNamjae Jeon } 3081495e90faSNamjae Jeon 3082495e90faSNamjae Jeon /* 3083495e90faSNamjae Jeon * ntfs_attr_map_whole_runlist - map the whole runlist of an ntfs attribute 3084495e90faSNamjae Jeon * @ni: ntfs inode for which to map the runlist 3085495e90faSNamjae Jeon * 3086495e90faSNamjae Jeon * Map the whole runlist of the ntfs attribute @na. For an attribute made up 3087495e90faSNamjae Jeon * of only one attribute extent this is the same as calling 3088495e90faSNamjae Jeon * ntfs_map_runlist(ni, 0) but for an attribute with multiple extents this 3089495e90faSNamjae Jeon * will map the runlist fragments from each of the extents thus giving access 3090495e90faSNamjae Jeon * to the entirety of the disk allocation of an attribute. 3091495e90faSNamjae Jeon */ 3092495e90faSNamjae Jeon int ntfs_attr_map_whole_runlist(struct ntfs_inode *ni) 3093495e90faSNamjae Jeon { 3094495e90faSNamjae Jeon s64 next_vcn, last_vcn, highest_vcn; 3095495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 3096495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 3097495e90faSNamjae Jeon struct super_block *sb = vol->sb; 3098495e90faSNamjae Jeon struct attr_record *a; 3099495e90faSNamjae Jeon int err; 3100495e90faSNamjae Jeon struct ntfs_inode *base_ni; 3101495e90faSNamjae Jeon int not_mapped; 3102495e90faSNamjae Jeon size_t new_rl_count; 3103495e90faSNamjae Jeon 3104495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x.\n", 3105495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type); 3106495e90faSNamjae Jeon 3107495e90faSNamjae Jeon if (NInoFullyMapped(ni) && ni->runlist.rl) 3108495e90faSNamjae Jeon return 0; 3109495e90faSNamjae Jeon 3110495e90faSNamjae Jeon if (NInoAttr(ni)) 3111495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 3112495e90faSNamjae Jeon else 3113495e90faSNamjae Jeon base_ni = ni; 3114495e90faSNamjae Jeon 3115495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, NULL); 3116495e90faSNamjae Jeon if (!ctx) { 3117495e90faSNamjae Jeon ntfs_error(sb, "%s: Failed to get search context", __func__); 3118495e90faSNamjae Jeon return -ENOMEM; 3119495e90faSNamjae Jeon } 3120495e90faSNamjae Jeon 3121495e90faSNamjae Jeon /* Map all attribute extents one by one. */ 3122495e90faSNamjae Jeon next_vcn = last_vcn = highest_vcn = 0; 3123495e90faSNamjae Jeon a = NULL; 3124495e90faSNamjae Jeon while (1) { 3125495e90faSNamjae Jeon struct runlist_element *rl; 3126495e90faSNamjae Jeon 3127495e90faSNamjae Jeon not_mapped = 0; 3128495e90faSNamjae Jeon if (ntfs_rl_vcn_to_lcn(ni->runlist.rl, next_vcn) == LCN_RL_NOT_MAPPED) 3129495e90faSNamjae Jeon not_mapped = 1; 3130495e90faSNamjae Jeon 3131495e90faSNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 3132495e90faSNamjae Jeon CASE_SENSITIVE, next_vcn, NULL, 0, ctx); 3133495e90faSNamjae Jeon if (err) 3134495e90faSNamjae Jeon break; 3135495e90faSNamjae Jeon 3136495e90faSNamjae Jeon a = ctx->attr; 3137495e90faSNamjae Jeon 3138495e90faSNamjae Jeon if (not_mapped) { 3139495e90faSNamjae Jeon /* Decode the runlist. */ 3140495e90faSNamjae Jeon rl = ntfs_mapping_pairs_decompress(ni->vol, a, &ni->runlist, 3141495e90faSNamjae Jeon &new_rl_count); 3142495e90faSNamjae Jeon if (IS_ERR(rl)) { 3143495e90faSNamjae Jeon err = PTR_ERR(rl); 3144495e90faSNamjae Jeon goto err_out; 3145495e90faSNamjae Jeon } 3146495e90faSNamjae Jeon ni->runlist.rl = rl; 3147495e90faSNamjae Jeon ni->runlist.count = new_rl_count; 3148495e90faSNamjae Jeon } 3149495e90faSNamjae Jeon 3150495e90faSNamjae Jeon /* Are we in the first extent? */ 3151495e90faSNamjae Jeon if (!next_vcn) { 3152495e90faSNamjae Jeon if (a->data.non_resident.lowest_vcn) { 3153495e90faSNamjae Jeon err = -EIO; 3154495e90faSNamjae Jeon ntfs_error(sb, 3155495e90faSNamjae Jeon "First extent of inode %llu attribute has non-zero lowest_vcn", 3156495e90faSNamjae Jeon (unsigned long long)ni->mft_no); 3157495e90faSNamjae Jeon goto err_out; 3158495e90faSNamjae Jeon } 3159495e90faSNamjae Jeon /* Get the last vcn in the attribute. */ 3160495e90faSNamjae Jeon last_vcn = ntfs_bytes_to_cluster(vol, 3161495e90faSNamjae Jeon le64_to_cpu(a->data.non_resident.allocated_size)); 3162495e90faSNamjae Jeon } 3163495e90faSNamjae Jeon 3164495e90faSNamjae Jeon /* Get the lowest vcn for the next extent. */ 3165495e90faSNamjae Jeon highest_vcn = le64_to_cpu(a->data.non_resident.highest_vcn); 3166495e90faSNamjae Jeon next_vcn = highest_vcn + 1; 3167495e90faSNamjae Jeon 3168495e90faSNamjae Jeon /* Only one extent or error, which we catch below. */ 3169495e90faSNamjae Jeon if (next_vcn <= 0) { 3170495e90faSNamjae Jeon err = -ENOENT; 3171495e90faSNamjae Jeon break; 3172495e90faSNamjae Jeon } 3173495e90faSNamjae Jeon 3174495e90faSNamjae Jeon /* Avoid endless loops due to corruption. */ 3175495e90faSNamjae Jeon if (next_vcn < le64_to_cpu(a->data.non_resident.lowest_vcn)) { 3176495e90faSNamjae Jeon err = -EIO; 3177495e90faSNamjae Jeon ntfs_error(sb, "Inode %llu has corrupt attribute list", 3178495e90faSNamjae Jeon (unsigned long long)ni->mft_no); 3179495e90faSNamjae Jeon goto err_out; 3180495e90faSNamjae Jeon } 3181495e90faSNamjae Jeon } 3182495e90faSNamjae Jeon if (!a) { 3183495e90faSNamjae Jeon ntfs_error(sb, "Couldn't find attribute for runlist mapping"); 3184495e90faSNamjae Jeon goto err_out; 3185495e90faSNamjae Jeon } 3186495e90faSNamjae Jeon if (not_mapped && highest_vcn && highest_vcn != last_vcn - 1) { 3187495e90faSNamjae Jeon err = -EIO; 3188495e90faSNamjae Jeon ntfs_error(sb, 3189495e90faSNamjae Jeon "Failed to load full runlist: inode: %llu highest_vcn: 0x%llx last_vcn: 0x%llx", 3190495e90faSNamjae Jeon (unsigned long long)ni->mft_no, 3191495e90faSNamjae Jeon (long long)highest_vcn, (long long)last_vcn); 3192495e90faSNamjae Jeon goto err_out; 3193495e90faSNamjae Jeon } 3194495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3195495e90faSNamjae Jeon if (err == -ENOENT) { 3196495e90faSNamjae Jeon NInoSetFullyMapped(ni); 3197495e90faSNamjae Jeon return 0; 3198495e90faSNamjae Jeon } 3199495e90faSNamjae Jeon 3200495e90faSNamjae Jeon return err; 3201495e90faSNamjae Jeon 3202495e90faSNamjae Jeon err_out: 3203495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3204495e90faSNamjae Jeon return err; 3205495e90faSNamjae Jeon } 3206495e90faSNamjae Jeon 3207495e90faSNamjae Jeon /* 3208495e90faSNamjae Jeon * ntfs_attr_record_move_to - move attribute record to target inode 3209495e90faSNamjae Jeon * @ctx: attribute search context describing the attribute record 3210495e90faSNamjae Jeon * @ni: opened ntfs inode to which move attribute record 3211495e90faSNamjae Jeon */ 3212495e90faSNamjae Jeon int ntfs_attr_record_move_to(struct ntfs_attr_search_ctx *ctx, struct ntfs_inode *ni) 3213495e90faSNamjae Jeon { 3214495e90faSNamjae Jeon struct ntfs_attr_search_ctx *nctx; 3215495e90faSNamjae Jeon struct attr_record *a; 3216495e90faSNamjae Jeon int err; 3217495e90faSNamjae Jeon struct mft_record *ni_mrec; 3218495e90faSNamjae Jeon struct super_block *sb; 3219495e90faSNamjae Jeon 3220495e90faSNamjae Jeon if (!ctx || !ctx->attr || !ctx->ntfs_ino || !ni) { 3221495e90faSNamjae Jeon ntfs_debug("Invalid arguments passed.\n"); 3222495e90faSNamjae Jeon return -EINVAL; 3223495e90faSNamjae Jeon } 3224495e90faSNamjae Jeon 3225495e90faSNamjae Jeon sb = ni->vol->sb; 3226495e90faSNamjae Jeon ntfs_debug("Entering for ctx->attr->type 0x%x, ctx->ntfs_ino->mft_no 0x%llx, ni->mft_no 0x%llx.\n", 3227495e90faSNamjae Jeon (unsigned int) le32_to_cpu(ctx->attr->type), 3228495e90faSNamjae Jeon (long long) ctx->ntfs_ino->mft_no, 3229495e90faSNamjae Jeon (long long) ni->mft_no); 3230495e90faSNamjae Jeon 3231495e90faSNamjae Jeon if (ctx->ntfs_ino == ni) 3232495e90faSNamjae Jeon return 0; 3233495e90faSNamjae Jeon 3234495e90faSNamjae Jeon if (!ctx->al_entry) { 3235495e90faSNamjae Jeon ntfs_debug("Inode should contain attribute list to use this function.\n"); 3236495e90faSNamjae Jeon return -EINVAL; 3237495e90faSNamjae Jeon } 3238495e90faSNamjae Jeon 3239495e90faSNamjae Jeon /* Find place in MFT record where attribute will be moved. */ 3240495e90faSNamjae Jeon a = ctx->attr; 3241495e90faSNamjae Jeon nctx = ntfs_attr_get_search_ctx(ni, NULL); 3242495e90faSNamjae Jeon if (!nctx) { 3243495e90faSNamjae Jeon ntfs_error(sb, "%s: Failed to get search context", __func__); 3244495e90faSNamjae Jeon return -ENOMEM; 3245495e90faSNamjae Jeon } 3246495e90faSNamjae Jeon 3247495e90faSNamjae Jeon /* 3248495e90faSNamjae Jeon * Use ntfs_attr_find instead of ntfs_attr_lookup to find place for 3249495e90faSNamjae Jeon * attribute in @ni->mrec, not any extent inode in case if @ni is base 3250495e90faSNamjae Jeon * file record. 3251495e90faSNamjae Jeon */ 3252495e90faSNamjae Jeon err = ntfs_attr_find(a->type, (__le16 *)((u8 *)a + le16_to_cpu(a->name_offset)), 3253495e90faSNamjae Jeon a->name_length, CASE_SENSITIVE, NULL, 3254495e90faSNamjae Jeon 0, nctx); 3255495e90faSNamjae Jeon if (!err) { 3256495e90faSNamjae Jeon ntfs_debug("Attribute of such type, with same name already present in this MFT record.\n"); 3257495e90faSNamjae Jeon err = -EEXIST; 3258495e90faSNamjae Jeon goto put_err_out; 3259495e90faSNamjae Jeon } 3260495e90faSNamjae Jeon if (err != -ENOENT) { 3261495e90faSNamjae Jeon ntfs_debug("Attribute lookup failed.\n"); 3262495e90faSNamjae Jeon goto put_err_out; 3263495e90faSNamjae Jeon } 3264495e90faSNamjae Jeon 3265495e90faSNamjae Jeon /* Make space and move attribute. */ 3266495e90faSNamjae Jeon ni_mrec = map_mft_record(ni); 3267495e90faSNamjae Jeon if (IS_ERR(ni_mrec)) { 3268495e90faSNamjae Jeon err = -EIO; 3269495e90faSNamjae Jeon goto put_err_out; 3270495e90faSNamjae Jeon } 3271495e90faSNamjae Jeon 3272495e90faSNamjae Jeon err = ntfs_make_room_for_attr(ni_mrec, (u8 *) nctx->attr, 3273495e90faSNamjae Jeon le32_to_cpu(a->length)); 3274495e90faSNamjae Jeon if (err) { 3275495e90faSNamjae Jeon ntfs_debug("Couldn't make space for attribute.\n"); 3276495e90faSNamjae Jeon unmap_mft_record(ni); 3277495e90faSNamjae Jeon goto put_err_out; 3278495e90faSNamjae Jeon } 3279495e90faSNamjae Jeon memcpy(nctx->attr, a, le32_to_cpu(a->length)); 3280495e90faSNamjae Jeon nctx->attr->instance = nctx->mrec->next_attr_instance; 3281495e90faSNamjae Jeon nctx->mrec->next_attr_instance = 3282495e90faSNamjae Jeon cpu_to_le16((le16_to_cpu(nctx->mrec->next_attr_instance) + 1) & 0xffff); 3283495e90faSNamjae Jeon ntfs_attr_record_resize(ctx->mrec, a, 0); 3284495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 3285495e90faSNamjae Jeon mark_mft_record_dirty(ni); 3286495e90faSNamjae Jeon 3287495e90faSNamjae Jeon /* Update attribute list. */ 3288495e90faSNamjae Jeon ctx->al_entry->mft_reference = 3289495e90faSNamjae Jeon MK_LE_MREF(ni->mft_no, le16_to_cpu(ni_mrec->sequence_number)); 3290495e90faSNamjae Jeon ctx->al_entry->instance = nctx->attr->instance; 3291495e90faSNamjae Jeon unmap_mft_record(ni); 3292495e90faSNamjae Jeon put_err_out: 3293495e90faSNamjae Jeon ntfs_attr_put_search_ctx(nctx); 3294495e90faSNamjae Jeon return err; 3295495e90faSNamjae Jeon } 3296495e90faSNamjae Jeon 3297495e90faSNamjae Jeon /* 3298495e90faSNamjae Jeon * ntfs_attr_record_move_away - move away attribute record from it's mft record 3299495e90faSNamjae Jeon * @ctx: attribute search context describing the attribute record 3300495e90faSNamjae Jeon * @extra: minimum amount of free space in the new holder of record 3301495e90faSNamjae Jeon */ 3302495e90faSNamjae Jeon int ntfs_attr_record_move_away(struct ntfs_attr_search_ctx *ctx, int extra) 3303495e90faSNamjae Jeon { 3304495e90faSNamjae Jeon struct ntfs_inode *base_ni, *ni = NULL; 3305495e90faSNamjae Jeon struct mft_record *m; 3306495e90faSNamjae Jeon int i, err; 3307495e90faSNamjae Jeon struct super_block *sb; 3308495e90faSNamjae Jeon 3309495e90faSNamjae Jeon if (!ctx || !ctx->attr || !ctx->ntfs_ino || extra < 0) 3310495e90faSNamjae Jeon return -EINVAL; 3311495e90faSNamjae Jeon 3312495e90faSNamjae Jeon ntfs_debug("Entering for attr 0x%x, inode %llu\n", 3313495e90faSNamjae Jeon (unsigned int) le32_to_cpu(ctx->attr->type), 3314495e90faSNamjae Jeon (unsigned long long)ctx->ntfs_ino->mft_no); 3315495e90faSNamjae Jeon 3316495e90faSNamjae Jeon if (ctx->ntfs_ino->nr_extents == -1) 3317495e90faSNamjae Jeon base_ni = ctx->base_ntfs_ino; 3318495e90faSNamjae Jeon else 3319495e90faSNamjae Jeon base_ni = ctx->ntfs_ino; 3320495e90faSNamjae Jeon 3321495e90faSNamjae Jeon sb = ctx->ntfs_ino->vol->sb; 3322495e90faSNamjae Jeon if (!NInoAttrList(base_ni)) { 3323495e90faSNamjae Jeon ntfs_error(sb, "Inode %llu has no attrlist", 3324495e90faSNamjae Jeon (unsigned long long)base_ni->mft_no); 3325495e90faSNamjae Jeon return -EINVAL; 3326495e90faSNamjae Jeon } 3327495e90faSNamjae Jeon 3328495e90faSNamjae Jeon err = ntfs_inode_attach_all_extents(ctx->ntfs_ino); 3329495e90faSNamjae Jeon if (err) { 3330495e90faSNamjae Jeon ntfs_error(sb, "Couldn't attach extents, inode=%llu", 3331495e90faSNamjae Jeon (unsigned long long)base_ni->mft_no); 3332495e90faSNamjae Jeon return err; 3333495e90faSNamjae Jeon } 3334495e90faSNamjae Jeon 3335495e90faSNamjae Jeon mutex_lock(&base_ni->extent_lock); 3336495e90faSNamjae Jeon /* Walk through all extents and try to move attribute to them. */ 3337495e90faSNamjae Jeon for (i = 0; i < base_ni->nr_extents; i++) { 3338495e90faSNamjae Jeon ni = base_ni->ext.extent_ntfs_inos[i]; 3339495e90faSNamjae Jeon 3340495e90faSNamjae Jeon if (ctx->ntfs_ino->mft_no == ni->mft_no) 3341495e90faSNamjae Jeon continue; 3342495e90faSNamjae Jeon m = map_mft_record(ni); 3343495e90faSNamjae Jeon if (IS_ERR(m)) { 3344495e90faSNamjae Jeon ntfs_error(sb, "Can not map mft record for mft_no %lld", 3345495e90faSNamjae Jeon (unsigned long long)ni->mft_no); 3346495e90faSNamjae Jeon mutex_unlock(&base_ni->extent_lock); 3347495e90faSNamjae Jeon return -EIO; 3348495e90faSNamjae Jeon } 3349495e90faSNamjae Jeon if (le32_to_cpu(m->bytes_allocated) - 3350495e90faSNamjae Jeon le32_to_cpu(m->bytes_in_use) < le32_to_cpu(ctx->attr->length) + extra) { 3351495e90faSNamjae Jeon unmap_mft_record(ni); 3352495e90faSNamjae Jeon continue; 3353495e90faSNamjae Jeon } 3354495e90faSNamjae Jeon unmap_mft_record(ni); 3355495e90faSNamjae Jeon 3356495e90faSNamjae Jeon /* 3357495e90faSNamjae Jeon * ntfs_attr_record_move_to can fail if extent with other lowest 3358495e90faSNamjae Jeon * s64 already present in inode we trying move record to. So, 3359495e90faSNamjae Jeon * do not return error. 3360495e90faSNamjae Jeon */ 3361495e90faSNamjae Jeon if (!ntfs_attr_record_move_to(ctx, ni)) { 3362495e90faSNamjae Jeon mutex_unlock(&base_ni->extent_lock); 3363495e90faSNamjae Jeon return 0; 3364495e90faSNamjae Jeon } 3365495e90faSNamjae Jeon } 3366495e90faSNamjae Jeon mutex_unlock(&base_ni->extent_lock); 3367495e90faSNamjae Jeon 3368495e90faSNamjae Jeon /* 3369495e90faSNamjae Jeon * Failed to move attribute to one of the current extents, so allocate 3370495e90faSNamjae Jeon * new extent and move attribute to it. 3371495e90faSNamjae Jeon */ 3372495e90faSNamjae Jeon ni = NULL; 3373495e90faSNamjae Jeon err = ntfs_mft_record_alloc(base_ni->vol, 0, &ni, base_ni, NULL); 3374495e90faSNamjae Jeon if (err) { 3375495e90faSNamjae Jeon ntfs_error(sb, "Couldn't allocate MFT record, err : %d", err); 3376495e90faSNamjae Jeon return err; 3377495e90faSNamjae Jeon } 3378495e90faSNamjae Jeon unmap_mft_record(ni); 3379495e90faSNamjae Jeon 3380495e90faSNamjae Jeon err = ntfs_attr_record_move_to(ctx, ni); 3381495e90faSNamjae Jeon if (err) 3382495e90faSNamjae Jeon ntfs_error(sb, "Couldn't move attribute to MFT record"); 3383495e90faSNamjae Jeon 3384495e90faSNamjae Jeon return err; 3385495e90faSNamjae Jeon } 3386495e90faSNamjae Jeon 3387495e90faSNamjae Jeon /* 3388495e90faSNamjae Jeon * If we are in the first extent, then set/clean sparse bit, 3389495e90faSNamjae Jeon * update allocated and compressed size. 3390495e90faSNamjae Jeon */ 3391495e90faSNamjae Jeon static int ntfs_attr_update_meta(struct attr_record *a, struct ntfs_inode *ni, 3392495e90faSNamjae Jeon struct mft_record *m, struct ntfs_attr_search_ctx *ctx) 3393495e90faSNamjae Jeon { 3394495e90faSNamjae Jeon int sparse, err = 0; 3395495e90faSNamjae Jeon struct ntfs_inode *base_ni; 3396495e90faSNamjae Jeon struct super_block *sb = ni->vol->sb; 3397495e90faSNamjae Jeon 3398495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x\n", 3399495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type); 3400495e90faSNamjae Jeon 3401495e90faSNamjae Jeon if (NInoAttr(ni)) 3402495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 3403495e90faSNamjae Jeon else 3404495e90faSNamjae Jeon base_ni = ni; 3405495e90faSNamjae Jeon 3406495e90faSNamjae Jeon if (a->data.non_resident.lowest_vcn) 3407495e90faSNamjae Jeon goto out; 3408495e90faSNamjae Jeon 3409495e90faSNamjae Jeon a->data.non_resident.allocated_size = cpu_to_le64(ni->allocated_size); 3410495e90faSNamjae Jeon 3411495e90faSNamjae Jeon sparse = ntfs_rl_sparse(ni->runlist.rl); 3412495e90faSNamjae Jeon if (sparse < 0) { 3413495e90faSNamjae Jeon err = -EIO; 3414495e90faSNamjae Jeon goto out; 3415495e90faSNamjae Jeon } 3416495e90faSNamjae Jeon 3417495e90faSNamjae Jeon /* Attribute become sparse. */ 3418495e90faSNamjae Jeon if (sparse && !(a->flags & (ATTR_IS_SPARSE | ATTR_IS_COMPRESSED))) { 3419495e90faSNamjae Jeon /* 3420495e90faSNamjae Jeon * Move attribute to another mft record, if attribute is too 3421495e90faSNamjae Jeon * small to add compressed_size field to it and we have no 3422495e90faSNamjae Jeon * free space in the current mft record. 3423495e90faSNamjae Jeon */ 3424495e90faSNamjae Jeon if ((le32_to_cpu(a->length) - 3425495e90faSNamjae Jeon le16_to_cpu(a->data.non_resident.mapping_pairs_offset) == 8) && 3426495e90faSNamjae Jeon !(le32_to_cpu(m->bytes_allocated) - le32_to_cpu(m->bytes_in_use))) { 3427495e90faSNamjae Jeon 3428495e90faSNamjae Jeon if (!NInoAttrList(base_ni)) { 3429495e90faSNamjae Jeon err = ntfs_inode_add_attrlist(base_ni); 3430495e90faSNamjae Jeon if (err) 3431495e90faSNamjae Jeon goto out; 3432495e90faSNamjae Jeon err = -EAGAIN; 3433495e90faSNamjae Jeon goto out; 3434495e90faSNamjae Jeon } 3435495e90faSNamjae Jeon err = ntfs_attr_record_move_away(ctx, 8); 3436495e90faSNamjae Jeon if (err) { 3437495e90faSNamjae Jeon ntfs_error(sb, "Failed to move attribute"); 3438495e90faSNamjae Jeon goto out; 3439495e90faSNamjae Jeon } 3440495e90faSNamjae Jeon 3441495e90faSNamjae Jeon err = ntfs_attrlist_update(base_ni); 3442495e90faSNamjae Jeon if (err) 3443495e90faSNamjae Jeon goto out; 3444495e90faSNamjae Jeon err = -EAGAIN; 3445495e90faSNamjae Jeon goto out; 3446495e90faSNamjae Jeon } 3447495e90faSNamjae Jeon if (!(le32_to_cpu(a->length) - 3448495e90faSNamjae Jeon le16_to_cpu(a->data.non_resident.mapping_pairs_offset))) { 3449495e90faSNamjae Jeon err = -EIO; 3450495e90faSNamjae Jeon ntfs_error(sb, "Mapping pairs space is 0"); 3451495e90faSNamjae Jeon goto out; 3452495e90faSNamjae Jeon } 3453495e90faSNamjae Jeon 3454495e90faSNamjae Jeon NInoSetSparse(ni); 3455495e90faSNamjae Jeon ni->flags |= FILE_ATTR_SPARSE_FILE; 3456495e90faSNamjae Jeon a->flags |= ATTR_IS_SPARSE; 3457495e90faSNamjae Jeon a->data.non_resident.compression_unit = 0; 3458495e90faSNamjae Jeon 3459495e90faSNamjae Jeon memmove((u8 *)a + le16_to_cpu(a->name_offset) + 8, 3460495e90faSNamjae Jeon (u8 *)a + le16_to_cpu(a->name_offset), 3461495e90faSNamjae Jeon a->name_length * sizeof(__le16)); 3462495e90faSNamjae Jeon 3463495e90faSNamjae Jeon a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) + 8); 3464495e90faSNamjae Jeon 3465495e90faSNamjae Jeon a->data.non_resident.mapping_pairs_offset = 3466495e90faSNamjae Jeon cpu_to_le16(le16_to_cpu(a->data.non_resident.mapping_pairs_offset) + 8); 3467495e90faSNamjae Jeon } 3468495e90faSNamjae Jeon 3469495e90faSNamjae Jeon /* Attribute no longer sparse. */ 3470495e90faSNamjae Jeon if (!sparse && (a->flags & ATTR_IS_SPARSE) && 3471495e90faSNamjae Jeon !(a->flags & ATTR_IS_COMPRESSED)) { 3472495e90faSNamjae Jeon NInoClearSparse(ni); 3473495e90faSNamjae Jeon ni->flags &= ~FILE_ATTR_SPARSE_FILE; 3474495e90faSNamjae Jeon a->flags &= ~ATTR_IS_SPARSE; 3475495e90faSNamjae Jeon a->data.non_resident.compression_unit = 0; 3476495e90faSNamjae Jeon 3477495e90faSNamjae Jeon memmove((u8 *)a + le16_to_cpu(a->name_offset) - 8, 3478495e90faSNamjae Jeon (u8 *)a + le16_to_cpu(a->name_offset), 3479495e90faSNamjae Jeon a->name_length * sizeof(__le16)); 3480495e90faSNamjae Jeon 3481495e90faSNamjae Jeon if (le16_to_cpu(a->name_offset) >= 8) 3482495e90faSNamjae Jeon a->name_offset = cpu_to_le16(le16_to_cpu(a->name_offset) - 8); 3483495e90faSNamjae Jeon 3484495e90faSNamjae Jeon a->data.non_resident.mapping_pairs_offset = 3485495e90faSNamjae Jeon cpu_to_le16(le16_to_cpu(a->data.non_resident.mapping_pairs_offset) - 8); 3486495e90faSNamjae Jeon } 3487495e90faSNamjae Jeon 3488495e90faSNamjae Jeon /* Update compressed size if required. */ 3489495e90faSNamjae Jeon if (NInoFullyMapped(ni) && (sparse || NInoCompressed(ni))) { 3490495e90faSNamjae Jeon s64 new_compr_size; 3491495e90faSNamjae Jeon 3492495e90faSNamjae Jeon new_compr_size = ntfs_rl_get_compressed_size(ni->vol, ni->runlist.rl); 3493495e90faSNamjae Jeon if (new_compr_size < 0) { 3494495e90faSNamjae Jeon err = new_compr_size; 3495495e90faSNamjae Jeon goto out; 3496495e90faSNamjae Jeon } 3497495e90faSNamjae Jeon 3498495e90faSNamjae Jeon ni->itype.compressed.size = new_compr_size; 3499495e90faSNamjae Jeon a->data.non_resident.compressed_size = cpu_to_le64(new_compr_size); 3500495e90faSNamjae Jeon } 3501495e90faSNamjae Jeon 3502495e90faSNamjae Jeon if (NInoSparse(ni) || NInoCompressed(ni)) 3503495e90faSNamjae Jeon VFS_I(base_ni)->i_blocks = ni->itype.compressed.size >> 9; 3504495e90faSNamjae Jeon else 3505495e90faSNamjae Jeon VFS_I(base_ni)->i_blocks = ni->allocated_size >> 9; 3506495e90faSNamjae Jeon /* 3507495e90faSNamjae Jeon * Set FILE_NAME dirty flag, to update sparse bit and 3508495e90faSNamjae Jeon * allocated size in the index. 3509495e90faSNamjae Jeon */ 3510495e90faSNamjae Jeon if (ni->type == AT_DATA && ni->name == AT_UNNAMED) 3511495e90faSNamjae Jeon NInoSetFileNameDirty(ni); 3512495e90faSNamjae Jeon out: 3513495e90faSNamjae Jeon return err; 3514495e90faSNamjae Jeon } 3515495e90faSNamjae Jeon 3516495e90faSNamjae Jeon #define NTFS_VCN_DELETE_MARK -2 3517495e90faSNamjae Jeon /* 3518495e90faSNamjae Jeon * ntfs_attr_update_mapping_pairs - update mapping pairs for ntfs attribute 3519495e90faSNamjae Jeon * @ni: non-resident ntfs inode for which we need update 3520495e90faSNamjae Jeon * @from_vcn: update runlist starting this VCN 3521495e90faSNamjae Jeon * 3522495e90faSNamjae Jeon * Build mapping pairs from @na->rl and write them to the disk. Also, this 3523495e90faSNamjae Jeon * function updates sparse bit, allocated and compressed size (allocates/frees 3524495e90faSNamjae Jeon * space for this field if required). 3525495e90faSNamjae Jeon * 3526495e90faSNamjae Jeon * @na->allocated_size should be set to correct value for the new runlist before 3527495e90faSNamjae Jeon * call to this function. Vice-versa @na->compressed_size will be calculated and 3528495e90faSNamjae Jeon * set to correct value during this function. 3529495e90faSNamjae Jeon */ 3530495e90faSNamjae Jeon int ntfs_attr_update_mapping_pairs(struct ntfs_inode *ni, s64 from_vcn) 3531495e90faSNamjae Jeon { 3532495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 3533495e90faSNamjae Jeon struct ntfs_inode *base_ni; 3534495e90faSNamjae Jeon struct mft_record *m; 3535495e90faSNamjae Jeon struct attr_record *a; 3536495e90faSNamjae Jeon s64 stop_vcn; 3537495e90faSNamjae Jeon int err = 0, mp_size, cur_max_mp_size, exp_max_mp_size; 3538495e90faSNamjae Jeon bool finished_build; 3539495e90faSNamjae Jeon bool first_updated = false; 3540495e90faSNamjae Jeon struct super_block *sb; 3541495e90faSNamjae Jeon struct runlist_element *start_rl; 3542495e90faSNamjae Jeon unsigned int de_cluster_count = 0; 3543495e90faSNamjae Jeon 3544495e90faSNamjae Jeon retry: 3545495e90faSNamjae Jeon if (!ni || !ni->runlist.rl) 3546495e90faSNamjae Jeon return -EINVAL; 3547495e90faSNamjae Jeon 3548495e90faSNamjae Jeon ntfs_debug("Entering for inode %llu, attr 0x%x\n", 3549495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type); 3550495e90faSNamjae Jeon 3551495e90faSNamjae Jeon sb = ni->vol->sb; 3552495e90faSNamjae Jeon if (!NInoNonResident(ni)) { 3553495e90faSNamjae Jeon ntfs_error(sb, "%s: resident attribute", __func__); 3554495e90faSNamjae Jeon return -EINVAL; 3555495e90faSNamjae Jeon } 3556495e90faSNamjae Jeon 3557495e90faSNamjae Jeon if (ni->nr_extents == -1) 3558495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 3559495e90faSNamjae Jeon else 3560495e90faSNamjae Jeon base_ni = ni; 3561495e90faSNamjae Jeon 3562495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, NULL); 3563495e90faSNamjae Jeon if (!ctx) { 3564495e90faSNamjae Jeon ntfs_error(sb, "%s: Failed to get search context", __func__); 3565495e90faSNamjae Jeon return -ENOMEM; 3566495e90faSNamjae Jeon } 3567495e90faSNamjae Jeon 3568495e90faSNamjae Jeon /* Fill attribute records with new mapping pairs. */ 3569495e90faSNamjae Jeon stop_vcn = 0; 3570495e90faSNamjae Jeon finished_build = false; 3571495e90faSNamjae Jeon start_rl = ni->runlist.rl; 3572495e90faSNamjae Jeon while (!(err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 3573495e90faSNamjae Jeon CASE_SENSITIVE, from_vcn, NULL, 0, ctx))) { 3574495e90faSNamjae Jeon unsigned int de_cnt = 0; 3575495e90faSNamjae Jeon 3576495e90faSNamjae Jeon a = ctx->attr; 3577495e90faSNamjae Jeon m = ctx->mrec; 3578495e90faSNamjae Jeon if (!a->data.non_resident.lowest_vcn) 3579495e90faSNamjae Jeon first_updated = true; 3580495e90faSNamjae Jeon 3581495e90faSNamjae Jeon /* 3582495e90faSNamjae Jeon * If runlist is updating not from the beginning, then set 3583495e90faSNamjae Jeon * @stop_vcn properly, i.e. to the lowest vcn of record that 3584495e90faSNamjae Jeon * contain @from_vcn. Also we do not need @from_vcn anymore, 3585495e90faSNamjae Jeon * set it to 0 to make ntfs_attr_lookup enumerate attributes. 3586495e90faSNamjae Jeon */ 3587495e90faSNamjae Jeon if (from_vcn) { 3588495e90faSNamjae Jeon s64 first_lcn; 3589495e90faSNamjae Jeon 3590495e90faSNamjae Jeon stop_vcn = le64_to_cpu(a->data.non_resident.lowest_vcn); 3591495e90faSNamjae Jeon from_vcn = 0; 3592495e90faSNamjae Jeon /* 3593495e90faSNamjae Jeon * Check whether the first run we need to update is 3594495e90faSNamjae Jeon * the last run in runlist, if so, then deallocate 3595495e90faSNamjae Jeon * all attrubute extents starting this one. 3596495e90faSNamjae Jeon */ 3597495e90faSNamjae Jeon first_lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, stop_vcn); 3598495e90faSNamjae Jeon if (first_lcn == LCN_EINVAL) { 3599495e90faSNamjae Jeon err = -EIO; 3600495e90faSNamjae Jeon ntfs_error(sb, "Bad runlist"); 3601495e90faSNamjae Jeon goto put_err_out; 3602495e90faSNamjae Jeon } 3603495e90faSNamjae Jeon if (first_lcn == LCN_ENOENT || 3604495e90faSNamjae Jeon first_lcn == LCN_RL_NOT_MAPPED) 3605495e90faSNamjae Jeon finished_build = true; 3606495e90faSNamjae Jeon } 3607495e90faSNamjae Jeon 3608495e90faSNamjae Jeon /* 3609495e90faSNamjae Jeon * Check whether we finished mapping pairs build, if so mark 3610495e90faSNamjae Jeon * extent as need to delete (by setting highest vcn to 3611495e90faSNamjae Jeon * NTFS_VCN_DELETE_MARK (-2), we shall check it later and 3612495e90faSNamjae Jeon * delete extent) and continue search. 3613495e90faSNamjae Jeon */ 3614495e90faSNamjae Jeon if (finished_build) { 3615d9038d99SNamjae Jeon ntfs_debug("Mark attr 0x%x for delete in inode 0x%llx.\n", 3616495e90faSNamjae Jeon (unsigned int)le32_to_cpu(a->type), ctx->ntfs_ino->mft_no); 3617495e90faSNamjae Jeon a->data.non_resident.highest_vcn = cpu_to_le64(NTFS_VCN_DELETE_MARK); 3618495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 3619495e90faSNamjae Jeon continue; 3620495e90faSNamjae Jeon } 3621495e90faSNamjae Jeon 3622495e90faSNamjae Jeon err = ntfs_attr_update_meta(a, ni, m, ctx); 3623495e90faSNamjae Jeon if (err < 0) { 3624495e90faSNamjae Jeon if (err == -EAGAIN) { 3625495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3626495e90faSNamjae Jeon goto retry; 3627495e90faSNamjae Jeon } 3628495e90faSNamjae Jeon goto put_err_out; 3629495e90faSNamjae Jeon } 3630495e90faSNamjae Jeon 3631495e90faSNamjae Jeon /* 3632495e90faSNamjae Jeon * Determine maximum possible length of mapping pairs, 3633495e90faSNamjae Jeon * if we shall *not* expand space for mapping pairs. 3634495e90faSNamjae Jeon */ 3635495e90faSNamjae Jeon cur_max_mp_size = le32_to_cpu(a->length) - 3636495e90faSNamjae Jeon le16_to_cpu(a->data.non_resident.mapping_pairs_offset); 3637495e90faSNamjae Jeon /* 3638495e90faSNamjae Jeon * Determine maximum possible length of mapping pairs in the 3639495e90faSNamjae Jeon * current mft record, if we shall expand space for mapping 3640495e90faSNamjae Jeon * pairs. 3641495e90faSNamjae Jeon */ 3642495e90faSNamjae Jeon exp_max_mp_size = le32_to_cpu(m->bytes_allocated) - 3643495e90faSNamjae Jeon le32_to_cpu(m->bytes_in_use) + cur_max_mp_size; 3644495e90faSNamjae Jeon 3645495e90faSNamjae Jeon /* Get the size for the rest of mapping pairs array. */ 3646495e90faSNamjae Jeon mp_size = ntfs_get_size_for_mapping_pairs(ni->vol, start_rl, 3647495e90faSNamjae Jeon stop_vcn, -1, exp_max_mp_size); 3648495e90faSNamjae Jeon if (mp_size <= 0) { 3649495e90faSNamjae Jeon err = mp_size; 3650495e90faSNamjae Jeon ntfs_error(sb, "%s: get MP size failed", __func__); 3651495e90faSNamjae Jeon goto put_err_out; 3652495e90faSNamjae Jeon } 3653495e90faSNamjae Jeon /* Test mapping pairs for fitting in the current mft record. */ 3654495e90faSNamjae Jeon if (mp_size > exp_max_mp_size) { 3655495e90faSNamjae Jeon /* 3656495e90faSNamjae Jeon * Mapping pairs of $ATTRIBUTE_LIST attribute must fit 3657495e90faSNamjae Jeon * in the base mft record. Try to move out other 3658495e90faSNamjae Jeon * attributes and try again. 3659495e90faSNamjae Jeon */ 3660495e90faSNamjae Jeon if (ni->type == AT_ATTRIBUTE_LIST) { 3661495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3662495e90faSNamjae Jeon if (ntfs_inode_free_space(base_ni, mp_size - 3663495e90faSNamjae Jeon cur_max_mp_size)) { 3664495e90faSNamjae Jeon ntfs_debug("Attribute list is too big. Defragment the volume\n"); 3665495e90faSNamjae Jeon return -ENOSPC; 3666495e90faSNamjae Jeon } 3667495e90faSNamjae Jeon if (ntfs_attrlist_update(base_ni)) 3668495e90faSNamjae Jeon return -EIO; 3669495e90faSNamjae Jeon goto retry; 3670495e90faSNamjae Jeon } 3671495e90faSNamjae Jeon 3672495e90faSNamjae Jeon /* Add attribute list if it isn't present, and retry. */ 3673495e90faSNamjae Jeon if (!NInoAttrList(base_ni)) { 3674495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3675495e90faSNamjae Jeon if (ntfs_inode_add_attrlist(base_ni)) { 3676495e90faSNamjae Jeon ntfs_error(sb, "Can not add attrlist"); 3677495e90faSNamjae Jeon return -EIO; 3678495e90faSNamjae Jeon } 3679495e90faSNamjae Jeon goto retry; 3680495e90faSNamjae Jeon } 3681495e90faSNamjae Jeon 3682495e90faSNamjae Jeon /* 3683495e90faSNamjae Jeon * Set mapping pairs size to maximum possible for this 3684495e90faSNamjae Jeon * mft record. We shall write the rest of mapping pairs 3685495e90faSNamjae Jeon * to another MFT records. 3686495e90faSNamjae Jeon */ 3687495e90faSNamjae Jeon mp_size = exp_max_mp_size; 3688495e90faSNamjae Jeon } 3689495e90faSNamjae Jeon 3690495e90faSNamjae Jeon /* Change space for mapping pairs if we need it. */ 3691495e90faSNamjae Jeon if (((mp_size + 7) & ~7) != cur_max_mp_size) { 3692495e90faSNamjae Jeon if (ntfs_attr_record_resize(m, a, 3693495e90faSNamjae Jeon le16_to_cpu(a->data.non_resident.mapping_pairs_offset) + 3694495e90faSNamjae Jeon mp_size)) { 3695495e90faSNamjae Jeon err = -EIO; 3696495e90faSNamjae Jeon ntfs_error(sb, "Failed to resize attribute"); 3697495e90faSNamjae Jeon goto put_err_out; 3698495e90faSNamjae Jeon } 3699495e90faSNamjae Jeon } 3700495e90faSNamjae Jeon 3701495e90faSNamjae Jeon /* Update lowest vcn. */ 3702495e90faSNamjae Jeon a->data.non_resident.lowest_vcn = cpu_to_le64(stop_vcn); 3703495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 3704495e90faSNamjae Jeon if ((ctx->ntfs_ino->nr_extents == -1 || NInoAttrList(ctx->ntfs_ino)) && 3705495e90faSNamjae Jeon ctx->attr->type != AT_ATTRIBUTE_LIST) { 3706495e90faSNamjae Jeon ctx->al_entry->lowest_vcn = cpu_to_le64(stop_vcn); 3707495e90faSNamjae Jeon err = ntfs_attrlist_update(base_ni); 3708495e90faSNamjae Jeon if (err) 3709495e90faSNamjae Jeon goto put_err_out; 3710495e90faSNamjae Jeon } 3711495e90faSNamjae Jeon 3712495e90faSNamjae Jeon /* 3713495e90faSNamjae Jeon * Generate the new mapping pairs array directly into the 3714495e90faSNamjae Jeon * correct destination, i.e. the attribute record itself. 3715495e90faSNamjae Jeon */ 3716495e90faSNamjae Jeon err = ntfs_mapping_pairs_build(ni->vol, 3717495e90faSNamjae Jeon (u8 *)a + le16_to_cpu(a->data.non_resident.mapping_pairs_offset), 3718495e90faSNamjae Jeon mp_size, start_rl, stop_vcn, -1, &stop_vcn, &start_rl, &de_cnt); 3719495e90faSNamjae Jeon if (!err) 3720495e90faSNamjae Jeon finished_build = true; 3721495e90faSNamjae Jeon if (!finished_build && err != -ENOSPC) { 3722495e90faSNamjae Jeon ntfs_error(sb, "Failed to build mapping pairs"); 3723495e90faSNamjae Jeon goto put_err_out; 3724495e90faSNamjae Jeon } 3725495e90faSNamjae Jeon a->data.non_resident.highest_vcn = cpu_to_le64(stop_vcn - 1); 3726495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 3727495e90faSNamjae Jeon de_cluster_count += de_cnt; 3728495e90faSNamjae Jeon } 3729495e90faSNamjae Jeon 3730495e90faSNamjae Jeon /* Check whether error occurred. */ 3731495e90faSNamjae Jeon if (err && err != -ENOENT) { 3732495e90faSNamjae Jeon ntfs_error(sb, "%s: Attribute lookup failed", __func__); 3733495e90faSNamjae Jeon goto put_err_out; 3734495e90faSNamjae Jeon } 3735495e90faSNamjae Jeon 3736495e90faSNamjae Jeon /* 3737495e90faSNamjae Jeon * If the base extent was skipped in the above process, 3738495e90faSNamjae Jeon * we still may have to update the sizes. 3739495e90faSNamjae Jeon */ 3740495e90faSNamjae Jeon if (!first_updated) { 3741495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 3742495e90faSNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 3743495e90faSNamjae Jeon CASE_SENSITIVE, 0, NULL, 0, ctx); 3744495e90faSNamjae Jeon if (!err) { 3745495e90faSNamjae Jeon a = ctx->attr; 3746495e90faSNamjae Jeon a->data.non_resident.allocated_size = cpu_to_le64(ni->allocated_size); 3747495e90faSNamjae Jeon if (NInoCompressed(ni) || NInoSparse(ni)) 3748495e90faSNamjae Jeon a->data.non_resident.compressed_size = 3749495e90faSNamjae Jeon cpu_to_le64(ni->itype.compressed.size); 3750495e90faSNamjae Jeon /* Updating sizes taints the extent holding the attr */ 3751495e90faSNamjae Jeon if (ni->type == AT_DATA && ni->name == AT_UNNAMED) 3752495e90faSNamjae Jeon NInoSetFileNameDirty(ni); 3753495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 3754495e90faSNamjae Jeon } else { 3755495e90faSNamjae Jeon ntfs_error(sb, "Failed to update sizes in base extent\n"); 3756495e90faSNamjae Jeon goto put_err_out; 3757495e90faSNamjae Jeon } 3758495e90faSNamjae Jeon } 3759495e90faSNamjae Jeon 3760495e90faSNamjae Jeon /* Deallocate not used attribute extents and return with success. */ 3761495e90faSNamjae Jeon if (finished_build) { 3762495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 3763495e90faSNamjae Jeon ntfs_debug("Deallocate marked extents.\n"); 3764495e90faSNamjae Jeon while (!(err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 3765495e90faSNamjae Jeon CASE_SENSITIVE, 0, NULL, 0, ctx))) { 3766495e90faSNamjae Jeon if (le64_to_cpu(ctx->attr->data.non_resident.highest_vcn) != 3767495e90faSNamjae Jeon NTFS_VCN_DELETE_MARK) 3768495e90faSNamjae Jeon continue; 3769495e90faSNamjae Jeon /* Remove unused attribute record. */ 3770495e90faSNamjae Jeon err = ntfs_attr_record_rm(ctx); 3771495e90faSNamjae Jeon if (err) { 3772495e90faSNamjae Jeon ntfs_error(sb, "Could not remove unused attr"); 3773495e90faSNamjae Jeon goto put_err_out; 3774495e90faSNamjae Jeon } 3775495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 3776495e90faSNamjae Jeon } 3777495e90faSNamjae Jeon if (err && err != -ENOENT) { 3778495e90faSNamjae Jeon ntfs_error(sb, "%s: Attr lookup failed", __func__); 3779495e90faSNamjae Jeon goto put_err_out; 3780495e90faSNamjae Jeon } 3781495e90faSNamjae Jeon ntfs_debug("Deallocate done.\n"); 3782495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3783495e90faSNamjae Jeon goto out; 3784495e90faSNamjae Jeon } 3785495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3786495e90faSNamjae Jeon ctx = NULL; 3787495e90faSNamjae Jeon 3788495e90faSNamjae Jeon /* Allocate new MFT records for the rest of mapping pairs. */ 3789495e90faSNamjae Jeon while (1) { 3790495e90faSNamjae Jeon struct ntfs_inode *ext_ni = NULL; 3791495e90faSNamjae Jeon unsigned int de_cnt = 0; 3792495e90faSNamjae Jeon 3793495e90faSNamjae Jeon /* Allocate new mft record. */ 3794495e90faSNamjae Jeon err = ntfs_mft_record_alloc(ni->vol, 0, &ext_ni, base_ni, NULL); 3795495e90faSNamjae Jeon if (err) { 3796495e90faSNamjae Jeon ntfs_error(sb, "Failed to allocate extent record"); 3797495e90faSNamjae Jeon goto put_err_out; 3798495e90faSNamjae Jeon } 3799495e90faSNamjae Jeon unmap_mft_record(ext_ni); 3800495e90faSNamjae Jeon 3801495e90faSNamjae Jeon m = map_mft_record(ext_ni); 3802495e90faSNamjae Jeon if (IS_ERR(m)) { 3803495e90faSNamjae Jeon ntfs_error(sb, "Could not map new MFT record"); 3804495e90faSNamjae Jeon if (ntfs_mft_record_free(ni->vol, ext_ni)) 3805495e90faSNamjae Jeon ntfs_error(sb, "Could not free MFT record"); 3806495e90faSNamjae Jeon ntfs_inode_close(ext_ni); 3807495e90faSNamjae Jeon err = -ENOMEM; 3808495e90faSNamjae Jeon ext_ni = NULL; 3809495e90faSNamjae Jeon goto put_err_out; 3810495e90faSNamjae Jeon } 3811495e90faSNamjae Jeon /* 3812495e90faSNamjae Jeon * If mapping size exceed available space, set them to 3813495e90faSNamjae Jeon * possible maximum. 3814495e90faSNamjae Jeon */ 3815495e90faSNamjae Jeon cur_max_mp_size = le32_to_cpu(m->bytes_allocated) - 3816495e90faSNamjae Jeon le32_to_cpu(m->bytes_in_use) - 3817495e90faSNamjae Jeon (sizeof(struct attr_record) + 3818495e90faSNamjae Jeon ((NInoCompressed(ni) || NInoSparse(ni)) ? 3819495e90faSNamjae Jeon sizeof(a->data.non_resident.compressed_size) : 0)) - 3820495e90faSNamjae Jeon ((sizeof(__le16) * ni->name_len + 7) & ~7); 3821495e90faSNamjae Jeon 3822495e90faSNamjae Jeon /* Calculate size of rest mapping pairs. */ 3823495e90faSNamjae Jeon mp_size = ntfs_get_size_for_mapping_pairs(ni->vol, 3824495e90faSNamjae Jeon start_rl, stop_vcn, -1, cur_max_mp_size); 3825495e90faSNamjae Jeon if (mp_size <= 0) { 3826495e90faSNamjae Jeon unmap_mft_record(ext_ni); 3827495e90faSNamjae Jeon ntfs_inode_close(ext_ni); 3828495e90faSNamjae Jeon err = mp_size; 3829495e90faSNamjae Jeon ntfs_error(sb, "%s: get mp size failed", __func__); 3830495e90faSNamjae Jeon goto put_err_out; 3831495e90faSNamjae Jeon } 3832495e90faSNamjae Jeon 3833495e90faSNamjae Jeon if (mp_size > cur_max_mp_size) 3834495e90faSNamjae Jeon mp_size = cur_max_mp_size; 3835495e90faSNamjae Jeon /* Add attribute extent to new record. */ 3836495e90faSNamjae Jeon err = ntfs_non_resident_attr_record_add(ext_ni, ni->type, 3837495e90faSNamjae Jeon ni->name, ni->name_len, stop_vcn, mp_size, 0); 3838495e90faSNamjae Jeon if (err < 0) { 3839495e90faSNamjae Jeon ntfs_error(sb, "Could not add attribute extent"); 3840495e90faSNamjae Jeon unmap_mft_record(ext_ni); 3841495e90faSNamjae Jeon if (ntfs_mft_record_free(ni->vol, ext_ni)) 3842495e90faSNamjae Jeon ntfs_error(sb, "Could not free MFT record"); 3843495e90faSNamjae Jeon ntfs_inode_close(ext_ni); 3844495e90faSNamjae Jeon goto put_err_out; 3845495e90faSNamjae Jeon } 3846495e90faSNamjae Jeon a = (struct attr_record *)((u8 *)m + err); 3847495e90faSNamjae Jeon 3848495e90faSNamjae Jeon err = ntfs_mapping_pairs_build(ni->vol, (u8 *)a + 3849495e90faSNamjae Jeon le16_to_cpu(a->data.non_resident.mapping_pairs_offset), 3850495e90faSNamjae Jeon mp_size, start_rl, stop_vcn, -1, &stop_vcn, &start_rl, 3851495e90faSNamjae Jeon &de_cnt); 3852495e90faSNamjae Jeon if (err < 0 && err != -ENOSPC) { 3853495e90faSNamjae Jeon ntfs_error(sb, "Failed to build MP"); 3854495e90faSNamjae Jeon unmap_mft_record(ext_ni); 3855495e90faSNamjae Jeon if (ntfs_mft_record_free(ni->vol, ext_ni)) 3856495e90faSNamjae Jeon ntfs_error(sb, "Couldn't free MFT record"); 3857495e90faSNamjae Jeon goto put_err_out; 3858495e90faSNamjae Jeon } 3859495e90faSNamjae Jeon a->data.non_resident.highest_vcn = cpu_to_le64(stop_vcn - 1); 3860495e90faSNamjae Jeon mark_mft_record_dirty(ext_ni); 3861495e90faSNamjae Jeon unmap_mft_record(ext_ni); 3862495e90faSNamjae Jeon 3863495e90faSNamjae Jeon de_cluster_count += de_cnt; 3864495e90faSNamjae Jeon /* All mapping pairs has been written. */ 3865495e90faSNamjae Jeon if (!err) 3866495e90faSNamjae Jeon break; 3867495e90faSNamjae Jeon } 3868495e90faSNamjae Jeon out: 3869495e90faSNamjae Jeon if (from_vcn == 0) 3870495e90faSNamjae Jeon ni->i_dealloc_clusters = de_cluster_count; 3871495e90faSNamjae Jeon return 0; 3872495e90faSNamjae Jeon 3873495e90faSNamjae Jeon put_err_out: 3874495e90faSNamjae Jeon if (ctx) 3875495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 3876495e90faSNamjae Jeon return err; 3877495e90faSNamjae Jeon } 3878495e90faSNamjae Jeon 3879495e90faSNamjae Jeon /* 3880495e90faSNamjae Jeon * ntfs_attr_make_resident - convert a non-resident to a resident attribute 3881495e90faSNamjae Jeon * @ni: open ntfs attribute to make resident 3882495e90faSNamjae Jeon * @ctx: ntfs search context describing the attribute 3883495e90faSNamjae Jeon * 3884495e90faSNamjae Jeon * Convert a non-resident ntfs attribute to a resident one. 3885495e90faSNamjae Jeon */ 3886495e90faSNamjae Jeon static int ntfs_attr_make_resident(struct ntfs_inode *ni, struct ntfs_attr_search_ctx *ctx) 3887495e90faSNamjae Jeon { 3888495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 3889495e90faSNamjae Jeon struct super_block *sb = vol->sb; 3890495e90faSNamjae Jeon struct attr_record *a = ctx->attr; 3891495e90faSNamjae Jeon int name_ofs, val_ofs, err; 3892495e90faSNamjae Jeon s64 arec_size; 3893495e90faSNamjae Jeon 3894495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x.\n", 3895495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type); 3896495e90faSNamjae Jeon 3897495e90faSNamjae Jeon /* Should be called for the first extent of the attribute. */ 3898495e90faSNamjae Jeon if (le64_to_cpu(a->data.non_resident.lowest_vcn)) { 3899495e90faSNamjae Jeon ntfs_debug("Eeek! Should be called for the first extent of the attribute. Aborting...\n"); 3900495e90faSNamjae Jeon return -EINVAL; 3901495e90faSNamjae Jeon } 3902495e90faSNamjae Jeon 3903495e90faSNamjae Jeon /* Some preliminary sanity checking. */ 3904495e90faSNamjae Jeon if (!NInoNonResident(ni)) { 3905495e90faSNamjae Jeon ntfs_debug("Eeek! Trying to make resident attribute resident. Aborting...\n"); 3906495e90faSNamjae Jeon return -EINVAL; 3907495e90faSNamjae Jeon } 3908495e90faSNamjae Jeon 3909495e90faSNamjae Jeon /* Make sure this is not $MFT/$BITMAP or Windows will not boot! */ 3910495e90faSNamjae Jeon if (ni->type == AT_BITMAP && ni->mft_no == FILE_MFT) 3911495e90faSNamjae Jeon return -EPERM; 3912495e90faSNamjae Jeon 3913495e90faSNamjae Jeon /* Check that the attribute is allowed to be resident. */ 3914495e90faSNamjae Jeon err = ntfs_attr_can_be_resident(vol, ni->type); 3915495e90faSNamjae Jeon if (err) 3916495e90faSNamjae Jeon return err; 3917495e90faSNamjae Jeon 3918495e90faSNamjae Jeon if (NInoCompressed(ni) || NInoEncrypted(ni)) { 3919495e90faSNamjae Jeon ntfs_debug("Making compressed or encrypted files resident is not implemented yet.\n"); 3920495e90faSNamjae Jeon return -EOPNOTSUPP; 3921495e90faSNamjae Jeon } 3922495e90faSNamjae Jeon 3923495e90faSNamjae Jeon /* Work out offsets into and size of the resident attribute. */ 3924495e90faSNamjae Jeon name_ofs = 24; /* = sizeof(resident_struct attr_record); */ 3925495e90faSNamjae Jeon val_ofs = (name_ofs + a->name_length * sizeof(__le16) + 7) & ~7; 3926495e90faSNamjae Jeon arec_size = (val_ofs + ni->data_size + 7) & ~7; 3927495e90faSNamjae Jeon 3928495e90faSNamjae Jeon /* Sanity check the size before we start modifying the attribute. */ 3929495e90faSNamjae Jeon if (le32_to_cpu(ctx->mrec->bytes_in_use) - le32_to_cpu(a->length) + 3930495e90faSNamjae Jeon arec_size > le32_to_cpu(ctx->mrec->bytes_allocated)) { 3931495e90faSNamjae Jeon ntfs_debug("Not enough space to make attribute resident\n"); 3932495e90faSNamjae Jeon return -ENOSPC; 3933495e90faSNamjae Jeon } 3934495e90faSNamjae Jeon 3935495e90faSNamjae Jeon /* Read and cache the whole runlist if not already done. */ 3936495e90faSNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 3937495e90faSNamjae Jeon if (err) 3938495e90faSNamjae Jeon return err; 3939495e90faSNamjae Jeon 3940495e90faSNamjae Jeon /* Move the attribute name if it exists and update the offset. */ 3941495e90faSNamjae Jeon if (a->name_length) { 3942495e90faSNamjae Jeon memmove((u8 *)a + name_ofs, (u8 *)a + le16_to_cpu(a->name_offset), 3943495e90faSNamjae Jeon a->name_length * sizeof(__le16)); 3944495e90faSNamjae Jeon } 3945495e90faSNamjae Jeon a->name_offset = cpu_to_le16(name_ofs); 3946495e90faSNamjae Jeon 3947495e90faSNamjae Jeon /* Resize the resident part of the attribute record. */ 3948495e90faSNamjae Jeon if (ntfs_attr_record_resize(ctx->mrec, a, arec_size) < 0) { 3949495e90faSNamjae Jeon /* 3950495e90faSNamjae Jeon * Bug, because ntfs_attr_record_resize should not fail (we 3951495e90faSNamjae Jeon * already checked that attribute fits MFT record). 3952495e90faSNamjae Jeon */ 3953495e90faSNamjae Jeon ntfs_error(ctx->ntfs_ino->vol->sb, "BUG! Failed to resize attribute record. "); 3954495e90faSNamjae Jeon return -EIO; 3955495e90faSNamjae Jeon } 3956495e90faSNamjae Jeon 3957495e90faSNamjae Jeon /* Convert the attribute record to describe a resident attribute. */ 3958495e90faSNamjae Jeon a->non_resident = 0; 3959495e90faSNamjae Jeon a->flags = 0; 3960495e90faSNamjae Jeon a->data.resident.value_length = cpu_to_le32(ni->data_size); 3961495e90faSNamjae Jeon a->data.resident.value_offset = cpu_to_le16(val_ofs); 3962495e90faSNamjae Jeon /* 3963495e90faSNamjae Jeon * File names cannot be non-resident so we would never see this here 3964495e90faSNamjae Jeon * but at least it serves as a reminder that there may be attributes 3965495e90faSNamjae Jeon * for which we do need to set this flag. (AIA) 3966495e90faSNamjae Jeon */ 3967495e90faSNamjae Jeon if (a->type == AT_FILE_NAME) 3968495e90faSNamjae Jeon a->data.resident.flags = RESIDENT_ATTR_IS_INDEXED; 3969495e90faSNamjae Jeon else 3970495e90faSNamjae Jeon a->data.resident.flags = 0; 3971495e90faSNamjae Jeon a->data.resident.reserved = 0; 3972495e90faSNamjae Jeon 3973495e90faSNamjae Jeon /* 3974495e90faSNamjae Jeon * Deallocate clusters from the runlist. 3975495e90faSNamjae Jeon * 3976495e90faSNamjae Jeon * NOTE: We can use ntfs_cluster_free() because we have already mapped 3977495e90faSNamjae Jeon * the whole run list and thus it doesn't matter that the attribute 3978495e90faSNamjae Jeon * record is in a transiently corrupted state at this moment in time. 3979495e90faSNamjae Jeon */ 3980495e90faSNamjae Jeon err = ntfs_cluster_free(ni, 0, -1, ctx); 3981495e90faSNamjae Jeon if (err) { 3982495e90faSNamjae Jeon ntfs_error(sb, "Eeek! Failed to release allocated clusters"); 3983495e90faSNamjae Jeon ntfs_debug("Ignoring error and leaving behind wasted clusters.\n"); 3984495e90faSNamjae Jeon } 3985495e90faSNamjae Jeon 3986495e90faSNamjae Jeon /* Throw away the now unused runlist. */ 3987495e90faSNamjae Jeon kvfree(ni->runlist.rl); 3988495e90faSNamjae Jeon ni->runlist.rl = NULL; 3989495e90faSNamjae Jeon ni->runlist.count = 0; 3990495e90faSNamjae Jeon /* Update in-memory struct ntfs_attr. */ 3991495e90faSNamjae Jeon NInoClearNonResident(ni); 3992495e90faSNamjae Jeon NInoClearCompressed(ni); 3993495e90faSNamjae Jeon ni->flags &= ~FILE_ATTR_COMPRESSED; 3994495e90faSNamjae Jeon NInoClearSparse(ni); 3995495e90faSNamjae Jeon ni->flags &= ~FILE_ATTR_SPARSE_FILE; 3996495e90faSNamjae Jeon NInoClearEncrypted(ni); 3997495e90faSNamjae Jeon ni->flags &= ~FILE_ATTR_ENCRYPTED; 3998495e90faSNamjae Jeon ni->initialized_size = ni->data_size; 3999495e90faSNamjae Jeon ni->allocated_size = ni->itype.compressed.size = (ni->data_size + 7) & ~7; 4000495e90faSNamjae Jeon ni->itype.compressed.block_size = 0; 4001495e90faSNamjae Jeon ni->itype.compressed.block_size_bits = ni->itype.compressed.block_clusters = 0; 4002495e90faSNamjae Jeon return 0; 4003495e90faSNamjae Jeon } 4004495e90faSNamjae Jeon 4005495e90faSNamjae Jeon /* 4006495e90faSNamjae Jeon * ntfs_non_resident_attr_shrink - shrink a non-resident, open ntfs attribute 4007495e90faSNamjae Jeon * @ni: non-resident ntfs attribute to shrink 4008495e90faSNamjae Jeon * @newsize: new size (in bytes) to which to shrink the attribute 4009495e90faSNamjae Jeon * 4010495e90faSNamjae Jeon * Reduce the size of a non-resident, open ntfs attribute @na to @newsize bytes. 4011495e90faSNamjae Jeon */ 4012495e90faSNamjae Jeon static int ntfs_non_resident_attr_shrink(struct ntfs_inode *ni, const s64 newsize) 4013495e90faSNamjae Jeon { 4014495e90faSNamjae Jeon struct ntfs_volume *vol; 4015495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 4016495e90faSNamjae Jeon s64 first_free_vcn; 4017495e90faSNamjae Jeon s64 nr_freed_clusters; 4018495e90faSNamjae Jeon int err; 4019495e90faSNamjae Jeon struct ntfs_inode *base_ni; 4020495e90faSNamjae Jeon 4021495e90faSNamjae Jeon ntfs_debug("Inode 0x%llx attr 0x%x new size %lld\n", 4022495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type, (long long)newsize); 4023495e90faSNamjae Jeon 4024495e90faSNamjae Jeon vol = ni->vol; 4025495e90faSNamjae Jeon 4026495e90faSNamjae Jeon if (NInoAttr(ni)) 4027495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 4028495e90faSNamjae Jeon else 4029495e90faSNamjae Jeon base_ni = ni; 4030495e90faSNamjae Jeon 4031495e90faSNamjae Jeon /* 4032495e90faSNamjae Jeon * Check the attribute type and the corresponding minimum size 4033495e90faSNamjae Jeon * against @newsize and fail if @newsize is too small. 4034495e90faSNamjae Jeon */ 4035495e90faSNamjae Jeon err = ntfs_attr_size_bounds_check(vol, ni->type, newsize); 4036495e90faSNamjae Jeon if (err) { 4037495e90faSNamjae Jeon if (err == -ERANGE) 4038495e90faSNamjae Jeon ntfs_debug("Eeek! Size bounds check failed. Aborting...\n"); 4039495e90faSNamjae Jeon else if (err == -ENOENT) 4040495e90faSNamjae Jeon err = -EIO; 4041495e90faSNamjae Jeon return err; 4042495e90faSNamjae Jeon } 4043495e90faSNamjae Jeon 4044495e90faSNamjae Jeon /* The first cluster outside the new allocation. */ 4045495e90faSNamjae Jeon if (NInoCompressed(ni)) 4046495e90faSNamjae Jeon /* 4047495e90faSNamjae Jeon * For compressed files we must keep full compressions blocks, 4048495e90faSNamjae Jeon * but currently we do not decompress/recompress the last 4049495e90faSNamjae Jeon * block to truncate the data, so we may leave more allocated 4050495e90faSNamjae Jeon * clusters than really needed. 4051495e90faSNamjae Jeon */ 4052495e90faSNamjae Jeon first_free_vcn = ntfs_bytes_to_cluster(vol, 4053495e90faSNamjae Jeon ((newsize - 1) | (ni->itype.compressed.block_size - 1)) + 1); 4054495e90faSNamjae Jeon else 4055495e90faSNamjae Jeon first_free_vcn = 4056495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, newsize + vol->cluster_size - 1); 4057495e90faSNamjae Jeon 4058495e90faSNamjae Jeon if (first_free_vcn < 0) 4059495e90faSNamjae Jeon return -EINVAL; 4060495e90faSNamjae Jeon /* 4061495e90faSNamjae Jeon * Compare the new allocation with the old one and only deallocate 4062495e90faSNamjae Jeon * clusters if there is a change. 4063495e90faSNamjae Jeon */ 4064495e90faSNamjae Jeon if (ntfs_bytes_to_cluster(vol, ni->allocated_size) != first_free_vcn) { 4065495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 4066495e90faSNamjae Jeon 4067495e90faSNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 4068495e90faSNamjae Jeon if (err) { 4069495e90faSNamjae Jeon ntfs_debug("Eeek! ntfs_attr_map_whole_runlist failed.\n"); 4070495e90faSNamjae Jeon return err; 4071495e90faSNamjae Jeon } 4072495e90faSNamjae Jeon 4073495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 4074495e90faSNamjae Jeon if (!ctx) { 4075495e90faSNamjae Jeon ntfs_error(vol->sb, "%s: Failed to get search context", __func__); 4076495e90faSNamjae Jeon return -ENOMEM; 4077495e90faSNamjae Jeon } 4078495e90faSNamjae Jeon 4079495e90faSNamjae Jeon /* Deallocate all clusters starting with the first free one. */ 4080495e90faSNamjae Jeon nr_freed_clusters = ntfs_cluster_free(ni, first_free_vcn, -1, ctx); 4081495e90faSNamjae Jeon if (nr_freed_clusters < 0) { 4082495e90faSNamjae Jeon ntfs_debug("Eeek! Freeing of clusters failed. Aborting...\n"); 4083495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4084495e90faSNamjae Jeon return (int)nr_freed_clusters; 4085495e90faSNamjae Jeon } 4086495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4087495e90faSNamjae Jeon 4088495e90faSNamjae Jeon /* Truncate the runlist itself. */ 4089495e90faSNamjae Jeon if (ntfs_rl_truncate_nolock(vol, &ni->runlist, first_free_vcn)) { 4090495e90faSNamjae Jeon /* 4091495e90faSNamjae Jeon * Failed to truncate the runlist, so just throw it 4092495e90faSNamjae Jeon * away, it will be mapped afresh on next use. 4093495e90faSNamjae Jeon */ 4094495e90faSNamjae Jeon kvfree(ni->runlist.rl); 4095495e90faSNamjae Jeon ni->runlist.rl = NULL; 4096495e90faSNamjae Jeon ntfs_error(vol->sb, "Eeek! Run list truncation failed.\n"); 4097495e90faSNamjae Jeon return -EIO; 4098495e90faSNamjae Jeon } 4099495e90faSNamjae Jeon 4100495e90faSNamjae Jeon /* Prepare to mapping pairs update. */ 4101495e90faSNamjae Jeon ni->allocated_size = ntfs_cluster_to_bytes(vol, first_free_vcn); 4102495e90faSNamjae Jeon 4103495e90faSNamjae Jeon if (NInoSparse(ni) || NInoCompressed(ni)) { 4104495e90faSNamjae Jeon if (nr_freed_clusters) { 4105495e90faSNamjae Jeon ni->itype.compressed.size -= 4106495e90faSNamjae Jeon ntfs_cluster_to_bytes(vol, nr_freed_clusters); 4107495e90faSNamjae Jeon VFS_I(base_ni)->i_blocks = ni->itype.compressed.size >> 9; 4108495e90faSNamjae Jeon } 4109495e90faSNamjae Jeon } else 4110495e90faSNamjae Jeon VFS_I(base_ni)->i_blocks = ni->allocated_size >> 9; 4111495e90faSNamjae Jeon 4112495e90faSNamjae Jeon /* Write mapping pairs for new runlist. */ 4113495e90faSNamjae Jeon err = ntfs_attr_update_mapping_pairs(ni, 0 /*first_free_vcn*/); 4114495e90faSNamjae Jeon if (err) { 4115495e90faSNamjae Jeon ntfs_debug("Eeek! Mapping pairs update failed. Leaving inconstant metadata. Run chkdsk.\n"); 4116495e90faSNamjae Jeon return err; 4117495e90faSNamjae Jeon } 4118495e90faSNamjae Jeon } 4119495e90faSNamjae Jeon 4120495e90faSNamjae Jeon /* Get the first attribute record. */ 4121495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, NULL); 4122495e90faSNamjae Jeon if (!ctx) { 4123495e90faSNamjae Jeon ntfs_error(vol->sb, "%s: Failed to get search context", __func__); 4124495e90faSNamjae Jeon return -ENOMEM; 4125495e90faSNamjae Jeon } 4126495e90faSNamjae Jeon 4127495e90faSNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 4128495e90faSNamjae Jeon 0, NULL, 0, ctx); 4129495e90faSNamjae Jeon if (err) { 4130495e90faSNamjae Jeon if (err == -ENOENT) 4131495e90faSNamjae Jeon err = -EIO; 4132495e90faSNamjae Jeon ntfs_debug("Eeek! Lookup of first attribute extent failed. Leaving inconstant metadata.\n"); 4133495e90faSNamjae Jeon goto put_err_out; 4134495e90faSNamjae Jeon } 4135495e90faSNamjae Jeon 4136495e90faSNamjae Jeon /* Update data and initialized size. */ 4137495e90faSNamjae Jeon ni->data_size = newsize; 4138495e90faSNamjae Jeon ctx->attr->data.non_resident.data_size = cpu_to_le64(newsize); 4139495e90faSNamjae Jeon if (newsize < ni->initialized_size) { 4140495e90faSNamjae Jeon ni->initialized_size = newsize; 4141495e90faSNamjae Jeon ctx->attr->data.non_resident.initialized_size = cpu_to_le64(newsize); 4142495e90faSNamjae Jeon } 4143495e90faSNamjae Jeon /* Update data size in the index. */ 4144495e90faSNamjae Jeon if (ni->type == AT_DATA && ni->name == AT_UNNAMED) 4145495e90faSNamjae Jeon NInoSetFileNameDirty(ni); 4146495e90faSNamjae Jeon 4147495e90faSNamjae Jeon /* If the attribute now has zero size, make it resident. */ 4148495e90faSNamjae Jeon if (!newsize && !NInoEncrypted(ni) && !NInoCompressed(ni)) { 4149495e90faSNamjae Jeon err = ntfs_attr_make_resident(ni, ctx); 4150495e90faSNamjae Jeon if (err) { 4151495e90faSNamjae Jeon /* If couldn't make resident, just continue. */ 4152495e90faSNamjae Jeon if (err != -EPERM) 4153495e90faSNamjae Jeon ntfs_error(ni->vol->sb, 4154495e90faSNamjae Jeon "Failed to make attribute resident. Leaving as is...\n"); 4155495e90faSNamjae Jeon } 4156495e90faSNamjae Jeon } 4157495e90faSNamjae Jeon 4158495e90faSNamjae Jeon /* Set the inode dirty so it is written out later. */ 4159495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 4160495e90faSNamjae Jeon /* Done! */ 4161495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4162495e90faSNamjae Jeon return 0; 4163495e90faSNamjae Jeon put_err_out: 4164495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4165495e90faSNamjae Jeon return err; 4166495e90faSNamjae Jeon } 4167495e90faSNamjae Jeon 4168495e90faSNamjae Jeon /* 4169495e90faSNamjae Jeon * ntfs_non_resident_attr_expand - expand a non-resident, open ntfs attribute 4170495e90faSNamjae Jeon * @ni: non-resident ntfs attribute to expand 4171495e90faSNamjae Jeon * @prealloc_size: preallocation size (in bytes) to which to expand the attribute 4172495e90faSNamjae Jeon * @newsize: new size (in bytes) to which to expand the attribute 4173495e90faSNamjae Jeon * @holes: how to create a hole if expanding 4174495e90faSNamjae Jeon * @need_lock: whether mrec lock is needed or not 4175495e90faSNamjae Jeon * 4176495e90faSNamjae Jeon * Expand the size of a non-resident, open ntfs attribute @na to @newsize bytes, 4177495e90faSNamjae Jeon * by allocating new clusters. 4178495e90faSNamjae Jeon */ 4179495e90faSNamjae Jeon static int ntfs_non_resident_attr_expand(struct ntfs_inode *ni, const s64 newsize, 4180495e90faSNamjae Jeon const s64 prealloc_size, unsigned int holes, bool need_lock) 4181495e90faSNamjae Jeon { 4182495e90faSNamjae Jeon s64 lcn_seek_from; 4183495e90faSNamjae Jeon s64 first_free_vcn; 4184495e90faSNamjae Jeon struct ntfs_volume *vol; 4185495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx = NULL; 4186495e90faSNamjae Jeon struct runlist_element *rl, *rln; 4187495e90faSNamjae Jeon s64 org_alloc_size, org_compressed_size; 4188495e90faSNamjae Jeon int err, err2; 4189495e90faSNamjae Jeon struct ntfs_inode *base_ni; 4190495e90faSNamjae Jeon struct super_block *sb = ni->vol->sb; 4191495e90faSNamjae Jeon size_t new_rl_count; 4192495e90faSNamjae Jeon 4193495e90faSNamjae Jeon ntfs_debug("Inode 0x%llx, attr 0x%x, new size %lld old size %lld\n", 4194495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type, 4195495e90faSNamjae Jeon (long long)newsize, (long long)ni->data_size); 4196495e90faSNamjae Jeon 4197495e90faSNamjae Jeon vol = ni->vol; 4198495e90faSNamjae Jeon 4199495e90faSNamjae Jeon if (NInoAttr(ni)) 4200495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 4201495e90faSNamjae Jeon else 4202495e90faSNamjae Jeon base_ni = ni; 4203495e90faSNamjae Jeon 4204495e90faSNamjae Jeon /* 4205495e90faSNamjae Jeon * Check the attribute type and the corresponding maximum size 4206495e90faSNamjae Jeon * against @newsize and fail if @newsize is too big. 4207495e90faSNamjae Jeon */ 4208495e90faSNamjae Jeon err = ntfs_attr_size_bounds_check(vol, ni->type, newsize); 4209495e90faSNamjae Jeon if (err < 0) { 4210495e90faSNamjae Jeon ntfs_error(sb, "%s: bounds check failed", __func__); 4211495e90faSNamjae Jeon return err; 4212495e90faSNamjae Jeon } 4213495e90faSNamjae Jeon 4214495e90faSNamjae Jeon /* Save for future use. */ 4215495e90faSNamjae Jeon org_alloc_size = ni->allocated_size; 4216495e90faSNamjae Jeon org_compressed_size = ni->itype.compressed.size; 4217495e90faSNamjae Jeon 4218495e90faSNamjae Jeon /* The first cluster outside the new allocation. */ 4219495e90faSNamjae Jeon if (prealloc_size) 4220495e90faSNamjae Jeon first_free_vcn = 4221495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, prealloc_size + vol->cluster_size - 1); 4222495e90faSNamjae Jeon else 4223495e90faSNamjae Jeon first_free_vcn = 4224495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, newsize + vol->cluster_size - 1); 4225495e90faSNamjae Jeon if (first_free_vcn < 0) 4226495e90faSNamjae Jeon return -EFBIG; 4227495e90faSNamjae Jeon 4228495e90faSNamjae Jeon /* 4229495e90faSNamjae Jeon * Compare the new allocation with the old one and only allocate 4230495e90faSNamjae Jeon * clusters if there is a change. 4231495e90faSNamjae Jeon */ 4232495e90faSNamjae Jeon if (ntfs_bytes_to_cluster(vol, ni->allocated_size) < first_free_vcn) { 4233495e90faSNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 4234495e90faSNamjae Jeon if (err) { 4235495e90faSNamjae Jeon ntfs_error(sb, "ntfs_attr_map_whole_runlist failed"); 4236495e90faSNamjae Jeon return err; 4237495e90faSNamjae Jeon } 4238495e90faSNamjae Jeon 4239495e90faSNamjae Jeon /* 4240495e90faSNamjae Jeon * If we extend $DATA attribute on NTFS 3+ volume, we can add 4241495e90faSNamjae Jeon * sparse runs instead of real allocation of clusters. 4242495e90faSNamjae Jeon */ 4243495e90faSNamjae Jeon if ((ni->type == AT_DATA && (vol->major_ver >= 3 || !NInoSparseDisabled(ni))) && 4244495e90faSNamjae Jeon (holes != HOLES_NO)) { 4245495e90faSNamjae Jeon if (NInoCompressed(ni)) { 4246495e90faSNamjae Jeon int last = 0, i = 0; 4247495e90faSNamjae Jeon s64 alloc_size; 4248495e90faSNamjae Jeon u64 more_entries = round_up(first_free_vcn - 4249495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, ni->allocated_size), 4250495e90faSNamjae Jeon ni->itype.compressed.block_clusters); 4251495e90faSNamjae Jeon 4252495e90faSNamjae Jeon do_div(more_entries, ni->itype.compressed.block_clusters); 4253495e90faSNamjae Jeon 4254495e90faSNamjae Jeon while (ni->runlist.rl[last].length) 4255495e90faSNamjae Jeon last++; 4256495e90faSNamjae Jeon 4257495e90faSNamjae Jeon rl = ntfs_rl_realloc(ni->runlist.rl, last + 1, 4258495e90faSNamjae Jeon last + more_entries + 1); 4259495e90faSNamjae Jeon if (IS_ERR(rl)) { 4260495e90faSNamjae Jeon err = -ENOMEM; 4261495e90faSNamjae Jeon goto put_err_out; 4262495e90faSNamjae Jeon } 4263495e90faSNamjae Jeon 4264495e90faSNamjae Jeon alloc_size = ni->allocated_size; 4265495e90faSNamjae Jeon while (i++ < more_entries) { 4266495e90faSNamjae Jeon rl[last].vcn = ntfs_bytes_to_cluster(vol, 4267495e90faSNamjae Jeon round_up(alloc_size, vol->cluster_size)); 4268495e90faSNamjae Jeon rl[last].length = ni->itype.compressed.block_clusters - 4269495e90faSNamjae Jeon (rl[last].vcn & 4270495e90faSNamjae Jeon (ni->itype.compressed.block_clusters - 1)); 4271495e90faSNamjae Jeon rl[last].lcn = LCN_HOLE; 4272495e90faSNamjae Jeon last++; 4273495e90faSNamjae Jeon alloc_size += ni->itype.compressed.block_size; 4274495e90faSNamjae Jeon } 4275495e90faSNamjae Jeon 4276495e90faSNamjae Jeon rl[last].vcn = first_free_vcn; 4277495e90faSNamjae Jeon rl[last].lcn = LCN_ENOENT; 4278495e90faSNamjae Jeon rl[last].length = 0; 4279495e90faSNamjae Jeon 4280495e90faSNamjae Jeon ni->runlist.rl = rl; 4281495e90faSNamjae Jeon ni->runlist.count += more_entries; 4282495e90faSNamjae Jeon } else { 4283495e90faSNamjae Jeon rl = kmalloc(sizeof(struct runlist_element) * 2, GFP_NOFS); 4284495e90faSNamjae Jeon if (!rl) { 4285495e90faSNamjae Jeon err = -ENOMEM; 4286495e90faSNamjae Jeon goto put_err_out; 4287495e90faSNamjae Jeon } 4288495e90faSNamjae Jeon 4289495e90faSNamjae Jeon rl[0].vcn = ntfs_bytes_to_cluster(vol, ni->allocated_size); 4290495e90faSNamjae Jeon rl[0].lcn = LCN_HOLE; 4291495e90faSNamjae Jeon rl[0].length = first_free_vcn - 4292495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, ni->allocated_size); 4293495e90faSNamjae Jeon rl[1].vcn = first_free_vcn; 4294495e90faSNamjae Jeon rl[1].lcn = LCN_ENOENT; 4295495e90faSNamjae Jeon rl[1].length = 0; 4296495e90faSNamjae Jeon } 4297495e90faSNamjae Jeon } else { 4298495e90faSNamjae Jeon /* 4299495e90faSNamjae Jeon * Determine first after last LCN of attribute. 4300495e90faSNamjae Jeon * We will start seek clusters from this LCN to avoid 4301495e90faSNamjae Jeon * fragmentation. If there are no valid LCNs in the 4302495e90faSNamjae Jeon * attribute let the cluster allocator choose the 4303495e90faSNamjae Jeon * starting LCN. 4304495e90faSNamjae Jeon */ 4305495e90faSNamjae Jeon lcn_seek_from = -1; 4306495e90faSNamjae Jeon if (ni->runlist.rl->length) { 4307495e90faSNamjae Jeon /* Seek to the last run list element. */ 4308495e90faSNamjae Jeon for (rl = ni->runlist.rl; (rl + 1)->length; rl++) 4309495e90faSNamjae Jeon ; 4310495e90faSNamjae Jeon /* 4311495e90faSNamjae Jeon * If the last LCN is a hole or similar seek 4312495e90faSNamjae Jeon * back to last valid LCN. 4313495e90faSNamjae Jeon */ 4314495e90faSNamjae Jeon while (rl->lcn < 0 && rl != ni->runlist.rl) 4315495e90faSNamjae Jeon rl--; 4316495e90faSNamjae Jeon /* 4317495e90faSNamjae Jeon * Only set lcn_seek_from it the LCN is valid. 4318495e90faSNamjae Jeon */ 4319495e90faSNamjae Jeon if (rl->lcn >= 0) 4320495e90faSNamjae Jeon lcn_seek_from = rl->lcn + rl->length; 4321495e90faSNamjae Jeon } 4322495e90faSNamjae Jeon 4323495e90faSNamjae Jeon rl = ntfs_cluster_alloc(vol, 4324495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, ni->allocated_size), 4325495e90faSNamjae Jeon first_free_vcn - 4326495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, ni->allocated_size), 4327495e90faSNamjae Jeon lcn_seek_from, DATA_ZONE, false, false, false); 4328495e90faSNamjae Jeon if (IS_ERR(rl)) { 4329495e90faSNamjae Jeon ntfs_debug("Cluster allocation failed (%lld)", 4330495e90faSNamjae Jeon (long long)first_free_vcn - 4331495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, ni->allocated_size)); 4332495e90faSNamjae Jeon return PTR_ERR(rl); 4333495e90faSNamjae Jeon } 4334495e90faSNamjae Jeon } 4335495e90faSNamjae Jeon 4336495e90faSNamjae Jeon if (!NInoCompressed(ni)) { 4337495e90faSNamjae Jeon /* Append new clusters to attribute runlist. */ 4338495e90faSNamjae Jeon rln = ntfs_runlists_merge(&ni->runlist, rl, 0, &new_rl_count); 4339495e90faSNamjae Jeon if (IS_ERR(rln)) { 4340495e90faSNamjae Jeon /* Failed, free just allocated clusters. */ 4341495e90faSNamjae Jeon ntfs_error(sb, "Run list merge failed"); 4342495e90faSNamjae Jeon ntfs_cluster_free_from_rl(vol, rl); 4343495e90faSNamjae Jeon kvfree(rl); 4344495e90faSNamjae Jeon return -EIO; 4345495e90faSNamjae Jeon } 4346495e90faSNamjae Jeon ni->runlist.rl = rln; 4347495e90faSNamjae Jeon ni->runlist.count = new_rl_count; 4348495e90faSNamjae Jeon } 4349495e90faSNamjae Jeon 4350495e90faSNamjae Jeon /* Prepare to mapping pairs update. */ 4351495e90faSNamjae Jeon ni->allocated_size = ntfs_cluster_to_bytes(vol, first_free_vcn); 4352495e90faSNamjae Jeon err = ntfs_attr_update_mapping_pairs(ni, 0); 4353495e90faSNamjae Jeon if (err) { 4354495e90faSNamjae Jeon ntfs_debug("Mapping pairs update failed"); 4355495e90faSNamjae Jeon goto rollback; 4356495e90faSNamjae Jeon } 4357495e90faSNamjae Jeon } 4358495e90faSNamjae Jeon 4359495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, NULL); 4360495e90faSNamjae Jeon if (!ctx) { 4361495e90faSNamjae Jeon err = -ENOMEM; 4362495e90faSNamjae Jeon if (ni->allocated_size == org_alloc_size) 4363495e90faSNamjae Jeon return err; 4364495e90faSNamjae Jeon goto rollback; 4365495e90faSNamjae Jeon } 4366495e90faSNamjae Jeon 4367495e90faSNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 4368495e90faSNamjae Jeon 0, NULL, 0, ctx); 4369495e90faSNamjae Jeon if (err) { 4370495e90faSNamjae Jeon if (err == -ENOENT) 4371495e90faSNamjae Jeon err = -EIO; 4372495e90faSNamjae Jeon if (ni->allocated_size != org_alloc_size) 4373495e90faSNamjae Jeon goto rollback; 4374495e90faSNamjae Jeon goto put_err_out; 4375495e90faSNamjae Jeon } 4376495e90faSNamjae Jeon 4377495e90faSNamjae Jeon /* Update data size. */ 4378495e90faSNamjae Jeon ni->data_size = newsize; 4379495e90faSNamjae Jeon ctx->attr->data.non_resident.data_size = cpu_to_le64(newsize); 4380495e90faSNamjae Jeon /* Update data size in the index. */ 4381495e90faSNamjae Jeon if (ni->type == AT_DATA && ni->name == AT_UNNAMED) 4382495e90faSNamjae Jeon NInoSetFileNameDirty(ni); 4383495e90faSNamjae Jeon /* Set the inode dirty so it is written out later. */ 4384495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 4385495e90faSNamjae Jeon /* Done! */ 4386495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4387495e90faSNamjae Jeon return 0; 4388495e90faSNamjae Jeon rollback: 4389495e90faSNamjae Jeon /* Free allocated clusters. */ 4390495e90faSNamjae Jeon err2 = ntfs_cluster_free(ni, ntfs_bytes_to_cluster(vol, org_alloc_size), 4391495e90faSNamjae Jeon -1, ctx); 4392495e90faSNamjae Jeon if (err2) 4393495e90faSNamjae Jeon ntfs_debug("Leaking clusters"); 4394495e90faSNamjae Jeon 4395495e90faSNamjae Jeon /* Now, truncate the runlist itself. */ 4396495e90faSNamjae Jeon if (need_lock) 4397495e90faSNamjae Jeon down_write(&ni->runlist.lock); 4398495e90faSNamjae Jeon err2 = ntfs_rl_truncate_nolock(vol, &ni->runlist, 4399495e90faSNamjae Jeon ntfs_bytes_to_cluster(vol, org_alloc_size)); 4400495e90faSNamjae Jeon if (need_lock) 4401495e90faSNamjae Jeon up_write(&ni->runlist.lock); 4402495e90faSNamjae Jeon if (err2) { 4403495e90faSNamjae Jeon /* 4404495e90faSNamjae Jeon * Failed to truncate the runlist, so just throw it away, it 4405495e90faSNamjae Jeon * will be mapped afresh on next use. 4406495e90faSNamjae Jeon */ 4407495e90faSNamjae Jeon kvfree(ni->runlist.rl); 4408495e90faSNamjae Jeon ni->runlist.rl = NULL; 4409495e90faSNamjae Jeon ntfs_error(sb, "Couldn't truncate runlist. Rollback failed"); 4410495e90faSNamjae Jeon } else { 4411495e90faSNamjae Jeon /* Prepare to mapping pairs update. */ 4412495e90faSNamjae Jeon ni->allocated_size = org_alloc_size; 4413495e90faSNamjae Jeon /* Restore mapping pairs. */ 4414495e90faSNamjae Jeon if (need_lock) 4415495e90faSNamjae Jeon down_read(&ni->runlist.lock); 4416495e90faSNamjae Jeon if (ntfs_attr_update_mapping_pairs(ni, 0)) 4417495e90faSNamjae Jeon ntfs_error(sb, "Failed to restore old mapping pairs"); 4418495e90faSNamjae Jeon if (need_lock) 4419495e90faSNamjae Jeon up_read(&ni->runlist.lock); 4420495e90faSNamjae Jeon 4421495e90faSNamjae Jeon if (NInoSparse(ni) || NInoCompressed(ni)) { 4422495e90faSNamjae Jeon ni->itype.compressed.size = org_compressed_size; 4423495e90faSNamjae Jeon VFS_I(base_ni)->i_blocks = ni->itype.compressed.size >> 9; 4424495e90faSNamjae Jeon } else 4425495e90faSNamjae Jeon VFS_I(base_ni)->i_blocks = ni->allocated_size >> 9; 4426495e90faSNamjae Jeon } 4427495e90faSNamjae Jeon if (ctx) 4428495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4429495e90faSNamjae Jeon return err; 4430495e90faSNamjae Jeon put_err_out: 4431495e90faSNamjae Jeon if (ctx) 4432495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4433495e90faSNamjae Jeon return err; 4434495e90faSNamjae Jeon } 4435495e90faSNamjae Jeon 4436495e90faSNamjae Jeon /* 4437495e90faSNamjae Jeon * ntfs_resident_attr_resize - resize a resident, open ntfs attribute 4438495e90faSNamjae Jeon * @attr_ni: resident ntfs inode to resize 4439495e90faSNamjae Jeon * @newsize: new size (in bytes) to which to resize the attribute 4440495e90faSNamjae Jeon * @prealloc_size: preallocation size (in bytes) to which to resize the attribute 4441495e90faSNamjae Jeon * @holes: flags indicating how to handle holes 4442495e90faSNamjae Jeon * 4443495e90faSNamjae Jeon * Change the size of a resident, open ntfs attribute @na to @newsize bytes. 4444495e90faSNamjae Jeon */ 4445495e90faSNamjae Jeon static int ntfs_resident_attr_resize(struct ntfs_inode *attr_ni, const s64 newsize, 4446495e90faSNamjae Jeon const s64 prealloc_size, unsigned int holes) 4447495e90faSNamjae Jeon { 4448495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 4449495e90faSNamjae Jeon struct ntfs_volume *vol = attr_ni->vol; 4450495e90faSNamjae Jeon struct super_block *sb = vol->sb; 4451495e90faSNamjae Jeon int err = -EIO; 4452495e90faSNamjae Jeon struct ntfs_inode *base_ni, *ext_ni = NULL; 4453495e90faSNamjae Jeon 4454495e90faSNamjae Jeon attr_resize_again: 4455495e90faSNamjae Jeon ntfs_debug("Inode 0x%llx attr 0x%x new size %lld\n", 4456495e90faSNamjae Jeon (unsigned long long)attr_ni->mft_no, attr_ni->type, 4457495e90faSNamjae Jeon (long long)newsize); 4458495e90faSNamjae Jeon 4459495e90faSNamjae Jeon if (NInoAttr(attr_ni)) 4460495e90faSNamjae Jeon base_ni = attr_ni->ext.base_ntfs_ino; 4461495e90faSNamjae Jeon else 4462495e90faSNamjae Jeon base_ni = attr_ni; 4463495e90faSNamjae Jeon 4464495e90faSNamjae Jeon /* Get the attribute record that needs modification. */ 4465495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, NULL); 4466495e90faSNamjae Jeon if (!ctx) { 4467495e90faSNamjae Jeon ntfs_error(sb, "%s: Failed to get search context", __func__); 4468495e90faSNamjae Jeon return -ENOMEM; 4469495e90faSNamjae Jeon } 4470495e90faSNamjae Jeon 4471495e90faSNamjae Jeon err = ntfs_attr_lookup(attr_ni->type, attr_ni->name, attr_ni->name_len, 4472495e90faSNamjae Jeon 0, 0, NULL, 0, ctx); 4473495e90faSNamjae Jeon if (err) { 4474495e90faSNamjae Jeon ntfs_error(sb, "ntfs_attr_lookup failed"); 4475495e90faSNamjae Jeon goto put_err_out; 4476495e90faSNamjae Jeon } 4477495e90faSNamjae Jeon 4478495e90faSNamjae Jeon /* 4479495e90faSNamjae Jeon * Check the attribute type and the corresponding minimum and maximum 4480495e90faSNamjae Jeon * sizes against @newsize and fail if @newsize is out of bounds. 4481495e90faSNamjae Jeon */ 4482495e90faSNamjae Jeon err = ntfs_attr_size_bounds_check(vol, attr_ni->type, newsize); 4483495e90faSNamjae Jeon if (err) { 4484495e90faSNamjae Jeon if (err == -ENOENT) 4485495e90faSNamjae Jeon err = -EIO; 4486495e90faSNamjae Jeon ntfs_debug("%s: bounds check failed", __func__); 4487495e90faSNamjae Jeon goto put_err_out; 4488495e90faSNamjae Jeon } 4489495e90faSNamjae Jeon /* 4490495e90faSNamjae Jeon * If @newsize is bigger than the mft record we need to make the 4491495e90faSNamjae Jeon * attribute non-resident if the attribute type supports it. If it is 4492495e90faSNamjae Jeon * smaller we can go ahead and attempt the resize. 4493495e90faSNamjae Jeon */ 4494495e90faSNamjae Jeon if (newsize < vol->mft_record_size) { 4495495e90faSNamjae Jeon /* Perform the resize of the attribute record. */ 4496495e90faSNamjae Jeon err = ntfs_resident_attr_value_resize(ctx->mrec, ctx->attr, 4497495e90faSNamjae Jeon newsize); 4498495e90faSNamjae Jeon if (!err) { 4499495e90faSNamjae Jeon /* Update attribute size everywhere. */ 4500495e90faSNamjae Jeon attr_ni->data_size = attr_ni->initialized_size = newsize; 4501495e90faSNamjae Jeon attr_ni->allocated_size = (newsize + 7) & ~7; 4502495e90faSNamjae Jeon if (NInoCompressed(attr_ni) || NInoSparse(attr_ni)) 4503495e90faSNamjae Jeon attr_ni->itype.compressed.size = attr_ni->allocated_size; 4504495e90faSNamjae Jeon if (attr_ni->type == AT_DATA && attr_ni->name == AT_UNNAMED) 4505495e90faSNamjae Jeon NInoSetFileNameDirty(attr_ni); 4506495e90faSNamjae Jeon goto resize_done; 4507495e90faSNamjae Jeon } 4508495e90faSNamjae Jeon 4509495e90faSNamjae Jeon /* Prefer AT_INDEX_ALLOCATION instead of AT_ATTRIBUTE_LIST */ 4510495e90faSNamjae Jeon if (err == -ENOSPC && ctx->attr->type == AT_INDEX_ROOT) 4511495e90faSNamjae Jeon goto put_err_out; 4512495e90faSNamjae Jeon 4513495e90faSNamjae Jeon } 4514495e90faSNamjae Jeon /* There is not enough space in the mft record to perform the resize. */ 4515495e90faSNamjae Jeon 4516495e90faSNamjae Jeon /* Make the attribute non-resident if possible. */ 4517495e90faSNamjae Jeon err = ntfs_attr_make_non_resident(attr_ni, 4518495e90faSNamjae Jeon le32_to_cpu(ctx->attr->data.resident.value_length)); 4519495e90faSNamjae Jeon if (!err) { 4520495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 4521495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4522495e90faSNamjae Jeon /* Resize non-resident attribute */ 4523495e90faSNamjae Jeon return ntfs_non_resident_attr_expand(attr_ni, newsize, prealloc_size, holes, true); 4524495e90faSNamjae Jeon } else if (err != -ENOSPC && err != -EPERM) { 4525495e90faSNamjae Jeon ntfs_error(sb, "Failed to make attribute non-resident"); 4526495e90faSNamjae Jeon goto put_err_out; 4527495e90faSNamjae Jeon } 4528495e90faSNamjae Jeon 4529495e90faSNamjae Jeon /* Try to make other attributes non-resident and retry each time. */ 4530495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 4531495e90faSNamjae Jeon while (!(err = ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx))) { 4532495e90faSNamjae Jeon struct inode *tvi; 4533495e90faSNamjae Jeon struct attr_record *a; 4534495e90faSNamjae Jeon 4535495e90faSNamjae Jeon a = ctx->attr; 4536495e90faSNamjae Jeon if (a->non_resident || a->type == AT_ATTRIBUTE_LIST) 4537495e90faSNamjae Jeon continue; 4538495e90faSNamjae Jeon 4539495e90faSNamjae Jeon if (ntfs_attr_can_be_non_resident(vol, a->type)) 4540495e90faSNamjae Jeon continue; 4541495e90faSNamjae Jeon 4542495e90faSNamjae Jeon /* 4543495e90faSNamjae Jeon * Check out whether convert is reasonable. Assume that mapping 4544495e90faSNamjae Jeon * pairs will take 8 bytes. 4545495e90faSNamjae Jeon */ 4546495e90faSNamjae Jeon if (le32_to_cpu(a->length) <= (sizeof(struct attr_record) - sizeof(s64)) + 4547495e90faSNamjae Jeon ((a->name_length * sizeof(__le16) + 7) & ~7) + 8) 4548495e90faSNamjae Jeon continue; 4549495e90faSNamjae Jeon 4550495e90faSNamjae Jeon if (a->type == AT_DATA) 4551495e90faSNamjae Jeon tvi = ntfs_iget(sb, base_ni->mft_no); 4552495e90faSNamjae Jeon else 4553495e90faSNamjae Jeon tvi = ntfs_attr_iget(VFS_I(base_ni), a->type, 4554495e90faSNamjae Jeon (__le16 *)((u8 *)a + le16_to_cpu(a->name_offset)), 4555495e90faSNamjae Jeon a->name_length); 4556495e90faSNamjae Jeon if (IS_ERR(tvi)) { 4557495e90faSNamjae Jeon ntfs_error(sb, "Couldn't open attribute"); 4558495e90faSNamjae Jeon continue; 4559495e90faSNamjae Jeon } 4560495e90faSNamjae Jeon 4561495e90faSNamjae Jeon if (ntfs_attr_make_non_resident(NTFS_I(tvi), 4562495e90faSNamjae Jeon le32_to_cpu(ctx->attr->data.resident.value_length))) { 4563495e90faSNamjae Jeon iput(tvi); 4564495e90faSNamjae Jeon continue; 4565495e90faSNamjae Jeon } 4566495e90faSNamjae Jeon 4567495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 4568495e90faSNamjae Jeon iput(tvi); 4569495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4570495e90faSNamjae Jeon goto attr_resize_again; 4571495e90faSNamjae Jeon } 4572495e90faSNamjae Jeon 4573495e90faSNamjae Jeon /* Check whether error occurred. */ 4574495e90faSNamjae Jeon if (err != -ENOENT) { 4575495e90faSNamjae Jeon ntfs_error(sb, "%s: Attribute lookup failed 1", __func__); 4576495e90faSNamjae Jeon goto put_err_out; 4577495e90faSNamjae Jeon } 4578495e90faSNamjae Jeon 4579495e90faSNamjae Jeon /* 4580495e90faSNamjae Jeon * The standard information and attribute list attributes can't be 4581495e90faSNamjae Jeon * moved out from the base MFT record, so try to move out others. 4582495e90faSNamjae Jeon */ 4583495e90faSNamjae Jeon if (attr_ni->type == AT_STANDARD_INFORMATION || 4584495e90faSNamjae Jeon attr_ni->type == AT_ATTRIBUTE_LIST) { 4585495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4586495e90faSNamjae Jeon 4587495e90faSNamjae Jeon if (!NInoAttrList(base_ni)) { 4588495e90faSNamjae Jeon err = ntfs_inode_add_attrlist(base_ni); 4589495e90faSNamjae Jeon if (err) 4590495e90faSNamjae Jeon return err; 4591495e90faSNamjae Jeon } 4592495e90faSNamjae Jeon 4593495e90faSNamjae Jeon err = ntfs_inode_free_space(base_ni, sizeof(struct attr_record)); 4594495e90faSNamjae Jeon if (err) { 4595495e90faSNamjae Jeon err = -ENOSPC; 4596495e90faSNamjae Jeon ntfs_error(sb, 4597495e90faSNamjae Jeon "Couldn't free space in the MFT record to make attribute list non resident"); 4598495e90faSNamjae Jeon return err; 4599495e90faSNamjae Jeon } 4600495e90faSNamjae Jeon err = ntfs_attrlist_update(base_ni); 4601495e90faSNamjae Jeon if (err) 4602495e90faSNamjae Jeon return err; 4603495e90faSNamjae Jeon goto attr_resize_again; 4604495e90faSNamjae Jeon } 4605495e90faSNamjae Jeon 4606495e90faSNamjae Jeon /* 4607495e90faSNamjae Jeon * Move the attribute to a new mft record, creating an attribute list 4608495e90faSNamjae Jeon * attribute or modifying it if it is already present. 4609495e90faSNamjae Jeon */ 4610495e90faSNamjae Jeon 4611495e90faSNamjae Jeon /* Point search context back to attribute which we need resize. */ 4612495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 4613495e90faSNamjae Jeon err = ntfs_attr_lookup(attr_ni->type, attr_ni->name, attr_ni->name_len, 4614495e90faSNamjae Jeon CASE_SENSITIVE, 0, NULL, 0, ctx); 4615495e90faSNamjae Jeon if (err) { 4616495e90faSNamjae Jeon ntfs_error(sb, "%s: Attribute lookup failed 2", __func__); 4617495e90faSNamjae Jeon goto put_err_out; 4618495e90faSNamjae Jeon } 4619495e90faSNamjae Jeon 4620495e90faSNamjae Jeon /* 4621495e90faSNamjae Jeon * Check whether attribute is already single in this MFT record. 4622495e90faSNamjae Jeon * 8 added for the attribute terminator. 4623495e90faSNamjae Jeon */ 4624495e90faSNamjae Jeon if (le32_to_cpu(ctx->mrec->bytes_in_use) == 4625495e90faSNamjae Jeon le16_to_cpu(ctx->mrec->attrs_offset) + le32_to_cpu(ctx->attr->length) + 8) { 4626495e90faSNamjae Jeon err = -ENOSPC; 4627495e90faSNamjae Jeon ntfs_debug("MFT record is filled with one attribute\n"); 4628495e90faSNamjae Jeon goto put_err_out; 4629495e90faSNamjae Jeon } 4630495e90faSNamjae Jeon 4631495e90faSNamjae Jeon /* Add attribute list if not present. */ 4632495e90faSNamjae Jeon if (!NInoAttrList(base_ni)) { 4633495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4634495e90faSNamjae Jeon err = ntfs_inode_add_attrlist(base_ni); 4635495e90faSNamjae Jeon if (err) 4636495e90faSNamjae Jeon return err; 4637495e90faSNamjae Jeon goto attr_resize_again; 4638495e90faSNamjae Jeon } 4639495e90faSNamjae Jeon 4640495e90faSNamjae Jeon /* Allocate new mft record. */ 4641495e90faSNamjae Jeon err = ntfs_mft_record_alloc(base_ni->vol, 0, &ext_ni, base_ni, NULL); 4642495e90faSNamjae Jeon if (err) { 4643495e90faSNamjae Jeon ntfs_error(sb, "Couldn't allocate MFT record"); 4644495e90faSNamjae Jeon goto put_err_out; 4645495e90faSNamjae Jeon } 4646495e90faSNamjae Jeon unmap_mft_record(ext_ni); 4647495e90faSNamjae Jeon 4648495e90faSNamjae Jeon /* Move attribute to it. */ 4649495e90faSNamjae Jeon err = ntfs_attr_record_move_to(ctx, ext_ni); 4650495e90faSNamjae Jeon if (err) { 4651495e90faSNamjae Jeon ntfs_error(sb, "Couldn't move attribute to new MFT record"); 4652495e90faSNamjae Jeon err = -ENOMEM; 4653495e90faSNamjae Jeon goto put_err_out; 4654495e90faSNamjae Jeon } 4655495e90faSNamjae Jeon 4656495e90faSNamjae Jeon err = ntfs_attrlist_update(base_ni); 4657495e90faSNamjae Jeon if (err < 0) 4658495e90faSNamjae Jeon goto put_err_out; 4659495e90faSNamjae Jeon 4660495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4661495e90faSNamjae Jeon /* Try to perform resize once again. */ 4662495e90faSNamjae Jeon goto attr_resize_again; 4663495e90faSNamjae Jeon 4664495e90faSNamjae Jeon resize_done: 4665495e90faSNamjae Jeon /* 4666495e90faSNamjae Jeon * Set the inode (and its base inode if it exists) dirty so it is 4667495e90faSNamjae Jeon * written out later. 4668495e90faSNamjae Jeon */ 4669495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 4670495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4671495e90faSNamjae Jeon return 0; 4672495e90faSNamjae Jeon 4673495e90faSNamjae Jeon put_err_out: 4674495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4675495e90faSNamjae Jeon return err; 4676495e90faSNamjae Jeon } 4677495e90faSNamjae Jeon 4678495e90faSNamjae Jeon int __ntfs_attr_truncate_vfs(struct ntfs_inode *ni, const s64 newsize, 4679495e90faSNamjae Jeon const s64 i_size) 4680495e90faSNamjae Jeon { 4681495e90faSNamjae Jeon int err = 0; 4682495e90faSNamjae Jeon 4683495e90faSNamjae Jeon if (newsize < 0 || 4684495e90faSNamjae Jeon (ni->mft_no == FILE_MFT && ni->type == AT_DATA)) { 4685495e90faSNamjae Jeon ntfs_debug("Invalid arguments passed.\n"); 4686495e90faSNamjae Jeon return -EINVAL; 4687495e90faSNamjae Jeon } 4688495e90faSNamjae Jeon 4689495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x, size %lld\n", 4690495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type, newsize); 4691495e90faSNamjae Jeon 4692495e90faSNamjae Jeon if (NInoNonResident(ni)) { 4693495e90faSNamjae Jeon if (newsize > i_size) { 4694495e90faSNamjae Jeon down_write(&ni->runlist.lock); 4695495e90faSNamjae Jeon err = ntfs_non_resident_attr_expand(ni, newsize, 0, 4696495e90faSNamjae Jeon NVolDisableSparse(ni->vol) ? 4697495e90faSNamjae Jeon HOLES_NO : HOLES_OK, 4698495e90faSNamjae Jeon false); 4699495e90faSNamjae Jeon up_write(&ni->runlist.lock); 4700495e90faSNamjae Jeon } else 4701495e90faSNamjae Jeon err = ntfs_non_resident_attr_shrink(ni, newsize); 4702495e90faSNamjae Jeon } else 4703495e90faSNamjae Jeon err = ntfs_resident_attr_resize(ni, newsize, 0, 4704495e90faSNamjae Jeon NVolDisableSparse(ni->vol) ? 4705495e90faSNamjae Jeon HOLES_NO : HOLES_OK); 4706495e90faSNamjae Jeon ntfs_debug("Return status %d\n", err); 4707495e90faSNamjae Jeon return err; 4708495e90faSNamjae Jeon } 4709495e90faSNamjae Jeon 4710495e90faSNamjae Jeon int ntfs_attr_expand(struct ntfs_inode *ni, const s64 newsize, const s64 prealloc_size) 4711495e90faSNamjae Jeon { 4712495e90faSNamjae Jeon int err = 0; 4713495e90faSNamjae Jeon 4714495e90faSNamjae Jeon if (newsize < 0 || 4715495e90faSNamjae Jeon (ni->mft_no == FILE_MFT && ni->type == AT_DATA)) { 4716495e90faSNamjae Jeon ntfs_debug("Invalid arguments passed.\n"); 4717495e90faSNamjae Jeon return -EINVAL; 4718495e90faSNamjae Jeon } 4719495e90faSNamjae Jeon 4720495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x, size %lld\n", 4721495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type, newsize); 4722495e90faSNamjae Jeon 4723495e90faSNamjae Jeon if (ni->data_size == newsize) { 4724495e90faSNamjae Jeon ntfs_debug("Size is already ok\n"); 4725495e90faSNamjae Jeon return 0; 4726495e90faSNamjae Jeon } 4727495e90faSNamjae Jeon 4728495e90faSNamjae Jeon /* 4729495e90faSNamjae Jeon * Encrypted attributes are not supported. We return access denied, 4730495e90faSNamjae Jeon * which is what Windows NT4 does, too. 4731495e90faSNamjae Jeon */ 4732495e90faSNamjae Jeon if (NInoEncrypted(ni)) { 4733ea3566a3SWoody Suwalski pr_err("Failed to truncate encrypted attribute\n"); 4734495e90faSNamjae Jeon return -EACCES; 4735495e90faSNamjae Jeon } 4736495e90faSNamjae Jeon 4737495e90faSNamjae Jeon if (NInoNonResident(ni)) { 4738495e90faSNamjae Jeon if (newsize > ni->data_size) 4739495e90faSNamjae Jeon err = ntfs_non_resident_attr_expand(ni, newsize, prealloc_size, 4740495e90faSNamjae Jeon NVolDisableSparse(ni->vol) ? 4741495e90faSNamjae Jeon HOLES_NO : HOLES_OK, true); 4742495e90faSNamjae Jeon } else 4743495e90faSNamjae Jeon err = ntfs_resident_attr_resize(ni, newsize, prealloc_size, 4744495e90faSNamjae Jeon NVolDisableSparse(ni->vol) ? 4745495e90faSNamjae Jeon HOLES_NO : HOLES_OK); 4746495e90faSNamjae Jeon if (!err) 4747495e90faSNamjae Jeon i_size_write(VFS_I(ni), newsize); 4748495e90faSNamjae Jeon ntfs_debug("Return status %d\n", err); 4749495e90faSNamjae Jeon return err; 4750495e90faSNamjae Jeon } 4751495e90faSNamjae Jeon 4752495e90faSNamjae Jeon /* 4753495e90faSNamjae Jeon * ntfs_attr_truncate_i - resize an ntfs attribute 4754495e90faSNamjae Jeon * @ni: open ntfs inode to resize 4755495e90faSNamjae Jeon * @newsize: new size (in bytes) to which to resize the attribute 4756495e90faSNamjae Jeon * @holes: how to create a hole if expanding 4757495e90faSNamjae Jeon * 4758495e90faSNamjae Jeon * Change the size of an open ntfs attribute @na to @newsize bytes. If the 4759495e90faSNamjae Jeon * attribute is made bigger and the attribute is resident the newly 4760495e90faSNamjae Jeon * "allocated" space is cleared and if the attribute is non-resident the 4761495e90faSNamjae Jeon * newly allocated space is marked as not initialised and no real allocation 4762495e90faSNamjae Jeon * on disk is performed. 4763495e90faSNamjae Jeon */ 4764495e90faSNamjae Jeon int ntfs_attr_truncate_i(struct ntfs_inode *ni, const s64 newsize, unsigned int holes) 4765495e90faSNamjae Jeon { 4766495e90faSNamjae Jeon int err; 4767495e90faSNamjae Jeon 4768495e90faSNamjae Jeon if (newsize < 0 || 4769495e90faSNamjae Jeon (ni->mft_no == FILE_MFT && ni->type == AT_DATA)) { 4770495e90faSNamjae Jeon ntfs_debug("Invalid arguments passed.\n"); 4771495e90faSNamjae Jeon return -EINVAL; 4772495e90faSNamjae Jeon } 4773495e90faSNamjae Jeon 4774495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x, size %lld\n", 4775495e90faSNamjae Jeon (unsigned long long)ni->mft_no, ni->type, newsize); 4776495e90faSNamjae Jeon 4777495e90faSNamjae Jeon if (ni->data_size == newsize) { 4778495e90faSNamjae Jeon ntfs_debug("Size is already ok\n"); 4779495e90faSNamjae Jeon return 0; 4780495e90faSNamjae Jeon } 4781495e90faSNamjae Jeon 4782495e90faSNamjae Jeon /* 4783495e90faSNamjae Jeon * Encrypted attributes are not supported. We return access denied, 4784495e90faSNamjae Jeon * which is what Windows NT4 does, too. 4785495e90faSNamjae Jeon */ 4786495e90faSNamjae Jeon if (NInoEncrypted(ni)) { 4787ea3566a3SWoody Suwalski pr_err("Failed to truncate encrypted attribute\n"); 4788495e90faSNamjae Jeon return -EACCES; 4789495e90faSNamjae Jeon } 4790495e90faSNamjae Jeon 4791495e90faSNamjae Jeon if (NInoCompressed(ni)) { 4792ea3566a3SWoody Suwalski pr_err("Failed to truncate compressed attribute\n"); 4793495e90faSNamjae Jeon return -EOPNOTSUPP; 4794495e90faSNamjae Jeon } 4795495e90faSNamjae Jeon 4796495e90faSNamjae Jeon if (NInoNonResident(ni)) { 4797495e90faSNamjae Jeon if (newsize > ni->data_size) 4798495e90faSNamjae Jeon err = ntfs_non_resident_attr_expand(ni, newsize, 0, holes, true); 4799495e90faSNamjae Jeon else 4800495e90faSNamjae Jeon err = ntfs_non_resident_attr_shrink(ni, newsize); 4801495e90faSNamjae Jeon } else 4802495e90faSNamjae Jeon err = ntfs_resident_attr_resize(ni, newsize, 0, holes); 4803495e90faSNamjae Jeon ntfs_debug("Return status %d\n", err); 4804495e90faSNamjae Jeon return err; 4805495e90faSNamjae Jeon } 4806495e90faSNamjae Jeon 4807495e90faSNamjae Jeon /* 4808495e90faSNamjae Jeon * Resize an attribute, creating a hole if relevant 4809495e90faSNamjae Jeon */ 4810495e90faSNamjae Jeon int ntfs_attr_truncate(struct ntfs_inode *ni, const s64 newsize) 4811495e90faSNamjae Jeon { 4812495e90faSNamjae Jeon return ntfs_attr_truncate_i(ni, newsize, 4813495e90faSNamjae Jeon NVolDisableSparse(ni->vol) ? 4814495e90faSNamjae Jeon HOLES_NO : HOLES_OK); 4815495e90faSNamjae Jeon } 4816495e90faSNamjae Jeon 4817495e90faSNamjae Jeon int ntfs_attr_map_cluster(struct ntfs_inode *ni, s64 vcn_start, s64 *lcn_start, 4818495e90faSNamjae Jeon s64 *lcn_count, s64 max_clu_count, bool *balloc, bool update_mp, 4819495e90faSNamjae Jeon bool skip_holes) 4820495e90faSNamjae Jeon { 4821495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 4822495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 4823495e90faSNamjae Jeon struct runlist_element *rl, *rlc; 4824495e90faSNamjae Jeon s64 vcn = vcn_start, lcn, clu_count; 4825495e90faSNamjae Jeon s64 lcn_seek_from = -1; 4826495e90faSNamjae Jeon int err = 0; 4827495e90faSNamjae Jeon size_t new_rl_count; 4828495e90faSNamjae Jeon 4829495e90faSNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 4830495e90faSNamjae Jeon if (err) 4831495e90faSNamjae Jeon return err; 4832495e90faSNamjae Jeon 4833495e90faSNamjae Jeon if (NInoAttr(ni)) 4834495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni->ext.base_ntfs_ino, NULL); 4835495e90faSNamjae Jeon else 4836495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 4837495e90faSNamjae Jeon if (!ctx) { 4838495e90faSNamjae Jeon ntfs_error(vol->sb, "%s: Failed to get search context", __func__); 4839495e90faSNamjae Jeon return -ENOMEM; 4840495e90faSNamjae Jeon } 4841495e90faSNamjae Jeon 4842495e90faSNamjae Jeon err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 4843495e90faSNamjae Jeon CASE_SENSITIVE, vcn, NULL, 0, ctx); 4844495e90faSNamjae Jeon if (err) { 4845495e90faSNamjae Jeon ntfs_error(vol->sb, 4846d9038d99SNamjae Jeon "ntfs_attr_lookup failed, ntfs inode(mft_no : %llu) type : 0x%x, err : %d", 4847495e90faSNamjae Jeon ni->mft_no, ni->type, err); 4848495e90faSNamjae Jeon goto out; 4849495e90faSNamjae Jeon } 4850495e90faSNamjae Jeon 4851495e90faSNamjae Jeon rl = ntfs_attr_find_vcn_nolock(ni, vcn, ctx); 4852495e90faSNamjae Jeon if (IS_ERR(rl)) { 4853495e90faSNamjae Jeon ntfs_error(vol->sb, "Failed to find run after mapping runlist."); 4854495e90faSNamjae Jeon err = PTR_ERR(rl); 4855495e90faSNamjae Jeon goto out; 4856495e90faSNamjae Jeon } 4857495e90faSNamjae Jeon 4858495e90faSNamjae Jeon lcn = ntfs_rl_vcn_to_lcn(rl, vcn); 4859495e90faSNamjae Jeon clu_count = min(max_clu_count, rl->length - (vcn - rl->vcn)); 4860495e90faSNamjae Jeon if (lcn >= LCN_HOLE) { 4861495e90faSNamjae Jeon if (lcn > LCN_DELALLOC || 4862495e90faSNamjae Jeon (lcn == LCN_HOLE && skip_holes)) { 4863495e90faSNamjae Jeon *lcn_start = lcn; 4864495e90faSNamjae Jeon *lcn_count = clu_count; 4865495e90faSNamjae Jeon *balloc = false; 4866495e90faSNamjae Jeon goto out; 4867495e90faSNamjae Jeon } 4868495e90faSNamjae Jeon } else { 4869495e90faSNamjae Jeon WARN_ON(lcn == LCN_RL_NOT_MAPPED); 4870495e90faSNamjae Jeon if (lcn == LCN_ENOENT) 4871495e90faSNamjae Jeon err = -ENOENT; 4872495e90faSNamjae Jeon else 4873495e90faSNamjae Jeon err = -EIO; 4874495e90faSNamjae Jeon goto out; 4875495e90faSNamjae Jeon } 4876495e90faSNamjae Jeon 4877495e90faSNamjae Jeon /* Search backwards to find the best lcn to start seek from. */ 4878495e90faSNamjae Jeon rlc = rl; 4879495e90faSNamjae Jeon while (rlc->vcn) { 4880495e90faSNamjae Jeon rlc--; 4881495e90faSNamjae Jeon if (rlc->lcn >= 0) { 4882495e90faSNamjae Jeon /* 4883495e90faSNamjae Jeon * avoid fragmenting a compressed file 4884495e90faSNamjae Jeon * Windows does not do that, and that may 4885495e90faSNamjae Jeon * not be desirable for files which can 4886495e90faSNamjae Jeon * be updated 4887495e90faSNamjae Jeon */ 4888495e90faSNamjae Jeon if (NInoCompressed(ni)) 4889495e90faSNamjae Jeon lcn_seek_from = rlc->lcn + rlc->length; 4890495e90faSNamjae Jeon else 4891495e90faSNamjae Jeon lcn_seek_from = rlc->lcn + (vcn - rlc->vcn); 4892495e90faSNamjae Jeon break; 4893495e90faSNamjae Jeon } 4894495e90faSNamjae Jeon } 4895495e90faSNamjae Jeon 4896495e90faSNamjae Jeon if (lcn_seek_from == -1) { 4897495e90faSNamjae Jeon /* Backwards search failed, search forwards. */ 4898495e90faSNamjae Jeon rlc = rl; 4899495e90faSNamjae Jeon while (rlc->length) { 4900495e90faSNamjae Jeon rlc++; 4901495e90faSNamjae Jeon if (rlc->lcn >= 0) { 4902495e90faSNamjae Jeon lcn_seek_from = rlc->lcn - (rlc->vcn - vcn); 4903495e90faSNamjae Jeon if (lcn_seek_from < -1) 4904495e90faSNamjae Jeon lcn_seek_from = -1; 4905495e90faSNamjae Jeon break; 4906495e90faSNamjae Jeon } 4907495e90faSNamjae Jeon } 4908495e90faSNamjae Jeon } 4909495e90faSNamjae Jeon 4910495e90faSNamjae Jeon rlc = ntfs_cluster_alloc(vol, vcn, clu_count, lcn_seek_from, DATA_ZONE, 4911495e90faSNamjae Jeon false, true, true); 4912495e90faSNamjae Jeon if (IS_ERR(rlc)) { 4913495e90faSNamjae Jeon err = PTR_ERR(rlc); 4914495e90faSNamjae Jeon goto out; 4915495e90faSNamjae Jeon } 4916495e90faSNamjae Jeon 4917495e90faSNamjae Jeon WARN_ON(rlc->vcn != vcn); 4918495e90faSNamjae Jeon lcn = rlc->lcn; 4919495e90faSNamjae Jeon clu_count = rlc->length; 4920495e90faSNamjae Jeon 4921495e90faSNamjae Jeon rl = ntfs_runlists_merge(&ni->runlist, rlc, 0, &new_rl_count); 4922495e90faSNamjae Jeon if (IS_ERR(rl)) { 4923495e90faSNamjae Jeon ntfs_error(vol->sb, "Failed to merge runlists"); 4924495e90faSNamjae Jeon err = PTR_ERR(rl); 4925495e90faSNamjae Jeon if (ntfs_cluster_free_from_rl(vol, rlc)) 4926495e90faSNamjae Jeon ntfs_error(vol->sb, "Failed to free hot clusters."); 4927495e90faSNamjae Jeon kvfree(rlc); 4928495e90faSNamjae Jeon goto out; 4929495e90faSNamjae Jeon } 4930495e90faSNamjae Jeon ni->runlist.rl = rl; 4931495e90faSNamjae Jeon ni->runlist.count = new_rl_count; 4932495e90faSNamjae Jeon 4933495e90faSNamjae Jeon if (!update_mp) { 4934495e90faSNamjae Jeon u64 free = atomic64_read(&vol->free_clusters) * 100; 4935495e90faSNamjae Jeon 4936495e90faSNamjae Jeon do_div(free, vol->nr_clusters); 4937495e90faSNamjae Jeon if (free <= 5) 4938495e90faSNamjae Jeon update_mp = true; 4939495e90faSNamjae Jeon } 4940495e90faSNamjae Jeon 4941495e90faSNamjae Jeon if (update_mp) { 4942495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 4943495e90faSNamjae Jeon err = ntfs_attr_update_mapping_pairs(ni, 0); 4944495e90faSNamjae Jeon if (err) { 4945495e90faSNamjae Jeon int err2; 4946495e90faSNamjae Jeon 4947495e90faSNamjae Jeon err2 = ntfs_cluster_free(ni, vcn, clu_count, ctx); 4948495e90faSNamjae Jeon if (err2 < 0) 4949495e90faSNamjae Jeon ntfs_error(vol->sb, 4950495e90faSNamjae Jeon "Failed to free cluster allocation. Leaving inconstant metadata.\n"); 4951495e90faSNamjae Jeon goto out; 4952495e90faSNamjae Jeon } 4953495e90faSNamjae Jeon } else { 4954495e90faSNamjae Jeon VFS_I(ni)->i_blocks += clu_count << (vol->cluster_size_bits - 9); 4955495e90faSNamjae Jeon NInoSetRunlistDirty(ni); 4956495e90faSNamjae Jeon mark_mft_record_dirty(ni); 4957495e90faSNamjae Jeon } 4958495e90faSNamjae Jeon 4959495e90faSNamjae Jeon *lcn_start = lcn; 4960495e90faSNamjae Jeon *lcn_count = clu_count; 4961495e90faSNamjae Jeon *balloc = true; 4962495e90faSNamjae Jeon out: 4963495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 4964495e90faSNamjae Jeon return err; 4965495e90faSNamjae Jeon } 4966495e90faSNamjae Jeon 4967495e90faSNamjae Jeon /* 4968495e90faSNamjae Jeon * ntfs_attr_rm - remove attribute from ntfs inode 4969495e90faSNamjae Jeon * @ni: opened ntfs attribute to delete 4970495e90faSNamjae Jeon * 4971495e90faSNamjae Jeon * Remove attribute and all it's extents from ntfs inode. If attribute was non 4972495e90faSNamjae Jeon * resident also free all clusters allocated by attribute. 4973495e90faSNamjae Jeon */ 4974495e90faSNamjae Jeon int ntfs_attr_rm(struct ntfs_inode *ni) 4975495e90faSNamjae Jeon { 4976495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 4977495e90faSNamjae Jeon int err = 0, ret = 0; 4978495e90faSNamjae Jeon struct ntfs_inode *base_ni; 4979495e90faSNamjae Jeon struct super_block *sb = ni->vol->sb; 4980495e90faSNamjae Jeon 4981495e90faSNamjae Jeon if (NInoAttr(ni)) 4982495e90faSNamjae Jeon base_ni = ni->ext.base_ntfs_ino; 4983495e90faSNamjae Jeon else 4984495e90faSNamjae Jeon base_ni = ni; 4985495e90faSNamjae Jeon 4986495e90faSNamjae Jeon ntfs_debug("Entering for inode 0x%llx, attr 0x%x.\n", 4987495e90faSNamjae Jeon (long long) ni->mft_no, ni->type); 4988495e90faSNamjae Jeon 4989495e90faSNamjae Jeon /* Free cluster allocation. */ 4990495e90faSNamjae Jeon if (NInoNonResident(ni)) { 4991495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 4992495e90faSNamjae Jeon 4993495e90faSNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 4994495e90faSNamjae Jeon if (err) 4995495e90faSNamjae Jeon return err; 4996495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 4997495e90faSNamjae Jeon if (!ctx) { 4998495e90faSNamjae Jeon ntfs_error(sb, "%s: Failed to get search context", __func__); 4999495e90faSNamjae Jeon return -ENOMEM; 5000495e90faSNamjae Jeon } 5001495e90faSNamjae Jeon 5002495e90faSNamjae Jeon ret = ntfs_cluster_free(ni, 0, -1, ctx); 5003495e90faSNamjae Jeon if (ret < 0) 5004495e90faSNamjae Jeon ntfs_error(sb, 5005495e90faSNamjae Jeon "Failed to free cluster allocation. Leaving inconstant metadata.\n"); 5006495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5007495e90faSNamjae Jeon } 5008495e90faSNamjae Jeon 5009495e90faSNamjae Jeon /* Search for attribute extents and remove them all. */ 5010495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(base_ni, NULL); 5011495e90faSNamjae Jeon if (!ctx) { 5012495e90faSNamjae Jeon ntfs_error(sb, "%s: Failed to get search context", __func__); 5013495e90faSNamjae Jeon return -ENOMEM; 5014495e90faSNamjae Jeon } 5015495e90faSNamjae Jeon while (!(err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 5016495e90faSNamjae Jeon CASE_SENSITIVE, 0, NULL, 0, ctx))) { 5017495e90faSNamjae Jeon err = ntfs_attr_record_rm(ctx); 5018495e90faSNamjae Jeon if (err) { 5019495e90faSNamjae Jeon ntfs_error(sb, 5020495e90faSNamjae Jeon "Failed to remove attribute extent. Leaving inconstant metadata.\n"); 5021495e90faSNamjae Jeon ret = err; 5022495e90faSNamjae Jeon } 5023495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 5024495e90faSNamjae Jeon } 5025495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5026495e90faSNamjae Jeon if (err != -ENOENT) { 5027495e90faSNamjae Jeon ntfs_error(sb, "Attribute lookup failed. Probably leaving inconstant metadata.\n"); 5028495e90faSNamjae Jeon ret = err; 5029495e90faSNamjae Jeon } 5030495e90faSNamjae Jeon 5031495e90faSNamjae Jeon return ret; 5032495e90faSNamjae Jeon } 5033495e90faSNamjae Jeon 5034495e90faSNamjae Jeon int ntfs_attr_exist(struct ntfs_inode *ni, const __le32 type, __le16 *name, 5035495e90faSNamjae Jeon u32 name_len) 5036495e90faSNamjae Jeon { 5037495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 5038495e90faSNamjae Jeon int ret; 5039495e90faSNamjae Jeon 5040495e90faSNamjae Jeon ntfs_debug("Entering\n"); 5041495e90faSNamjae Jeon 5042495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 5043495e90faSNamjae Jeon if (!ctx) { 5044495e90faSNamjae Jeon ntfs_error(ni->vol->sb, "%s: Failed to get search context", 5045495e90faSNamjae Jeon __func__); 5046495e90faSNamjae Jeon return 0; 5047495e90faSNamjae Jeon } 5048495e90faSNamjae Jeon 5049495e90faSNamjae Jeon ret = ntfs_attr_lookup(type, name, name_len, CASE_SENSITIVE, 5050495e90faSNamjae Jeon 0, NULL, 0, ctx); 5051495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5052495e90faSNamjae Jeon 5053495e90faSNamjae Jeon return !ret; 5054495e90faSNamjae Jeon } 5055495e90faSNamjae Jeon 5056495e90faSNamjae Jeon int ntfs_attr_remove(struct ntfs_inode *ni, const __le32 type, __le16 *name, 5057495e90faSNamjae Jeon u32 name_len) 5058495e90faSNamjae Jeon { 5059495e90faSNamjae Jeon int err; 5060495e90faSNamjae Jeon struct inode *attr_vi; 5061495e90faSNamjae Jeon struct ntfs_inode *attr_ni; 5062495e90faSNamjae Jeon 5063495e90faSNamjae Jeon ntfs_debug("Entering\n"); 5064495e90faSNamjae Jeon 50654e59f8a1SHyunchul Lee if (!ni) 5066495e90faSNamjae Jeon return -EINVAL; 5067495e90faSNamjae Jeon 5068495e90faSNamjae Jeon attr_vi = ntfs_attr_iget(VFS_I(ni), type, name, name_len); 5069495e90faSNamjae Jeon if (IS_ERR(attr_vi)) { 5070495e90faSNamjae Jeon err = PTR_ERR(attr_vi); 50714e59f8a1SHyunchul Lee ntfs_error(ni->vol->sb, "Failed to open attribute 0x%02x of inode 0x%llx", 5072495e90faSNamjae Jeon type, (unsigned long long)ni->mft_no); 5073495e90faSNamjae Jeon return err; 5074495e90faSNamjae Jeon } 5075495e90faSNamjae Jeon attr_ni = NTFS_I(attr_vi); 5076495e90faSNamjae Jeon 5077495e90faSNamjae Jeon err = ntfs_attr_rm(attr_ni); 5078495e90faSNamjae Jeon if (err) 50794e59f8a1SHyunchul Lee ntfs_error(ni->vol->sb, "Failed to remove attribute 0x%02x of inode 0x%llx", 5080495e90faSNamjae Jeon type, (unsigned long long)ni->mft_no); 5081495e90faSNamjae Jeon iput(attr_vi); 5082495e90faSNamjae Jeon return err; 5083495e90faSNamjae Jeon } 5084495e90faSNamjae Jeon 5085495e90faSNamjae Jeon /* 5086495e90faSNamjae Jeon * ntfs_attr_readall - read the entire data from an ntfs attribute 5087495e90faSNamjae Jeon * @ni: open ntfs inode in which the ntfs attribute resides 5088495e90faSNamjae Jeon * @type: attribute type 5089495e90faSNamjae Jeon * @name: attribute name in little endian Unicode or AT_UNNAMED or NULL 5090495e90faSNamjae Jeon * @name_len: length of attribute @name in Unicode characters (if @name given) 5091495e90faSNamjae Jeon * @data_size: if non-NULL then store here the data size 5092495e90faSNamjae Jeon * 5093495e90faSNamjae Jeon * This function will read the entire content of an ntfs attribute. 5094495e90faSNamjae Jeon * If @name is AT_UNNAMED then look specifically for an unnamed attribute. 5095495e90faSNamjae Jeon * If @name is NULL then the attribute could be either named or not. 5096495e90faSNamjae Jeon * In both those cases @name_len is not used at all. 5097495e90faSNamjae Jeon * 5098495e90faSNamjae Jeon * On success a buffer is allocated with the content of the attribute 5099495e90faSNamjae Jeon * and which needs to be freed when it's not needed anymore. If the 5100495e90faSNamjae Jeon * @data_size parameter is non-NULL then the data size is set there. 5101495e90faSNamjae Jeon */ 5102495e90faSNamjae Jeon void *ntfs_attr_readall(struct ntfs_inode *ni, const __le32 type, 5103495e90faSNamjae Jeon __le16 *name, u32 name_len, s64 *data_size) 5104495e90faSNamjae Jeon { 5105495e90faSNamjae Jeon struct ntfs_inode *bmp_ni; 5106495e90faSNamjae Jeon struct inode *bmp_vi; 5107495e90faSNamjae Jeon void *data, *ret = NULL; 5108495e90faSNamjae Jeon s64 size; 5109495e90faSNamjae Jeon struct super_block *sb = ni->vol->sb; 5110495e90faSNamjae Jeon 5111495e90faSNamjae Jeon ntfs_debug("Entering\n"); 5112495e90faSNamjae Jeon 5113495e90faSNamjae Jeon bmp_vi = ntfs_attr_iget(VFS_I(ni), type, name, name_len); 5114495e90faSNamjae Jeon if (IS_ERR(bmp_vi)) { 5115495e90faSNamjae Jeon ntfs_debug("ntfs_attr_iget failed"); 5116495e90faSNamjae Jeon goto err_exit; 5117495e90faSNamjae Jeon } 5118495e90faSNamjae Jeon bmp_ni = NTFS_I(bmp_vi); 5119495e90faSNamjae Jeon 5120495e90faSNamjae Jeon data = kvmalloc(bmp_ni->data_size, GFP_NOFS); 5121495e90faSNamjae Jeon if (!data) 5122495e90faSNamjae Jeon goto out; 5123495e90faSNamjae Jeon 5124495e90faSNamjae Jeon size = ntfs_inode_attr_pread(VFS_I(bmp_ni), 0, bmp_ni->data_size, 5125495e90faSNamjae Jeon (u8 *)data); 5126495e90faSNamjae Jeon if (size != bmp_ni->data_size) { 5127495e90faSNamjae Jeon ntfs_error(sb, "ntfs_attr_pread failed"); 5128495e90faSNamjae Jeon kvfree(data); 5129495e90faSNamjae Jeon goto out; 5130495e90faSNamjae Jeon } 5131495e90faSNamjae Jeon ret = data; 5132495e90faSNamjae Jeon if (data_size) 5133495e90faSNamjae Jeon *data_size = size; 5134495e90faSNamjae Jeon out: 5135495e90faSNamjae Jeon iput(bmp_vi); 5136495e90faSNamjae Jeon err_exit: 5137495e90faSNamjae Jeon ntfs_debug("\n"); 5138495e90faSNamjae Jeon return ret; 5139495e90faSNamjae Jeon } 5140495e90faSNamjae Jeon 5141495e90faSNamjae Jeon int ntfs_non_resident_attr_insert_range(struct ntfs_inode *ni, s64 start_vcn, s64 len) 5142495e90faSNamjae Jeon { 5143495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 5144495e90faSNamjae Jeon struct runlist_element *hole_rl, *rl; 5145495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 5146495e90faSNamjae Jeon int ret; 5147495e90faSNamjae Jeon size_t new_rl_count; 5148495e90faSNamjae Jeon 5149495e90faSNamjae Jeon if (NInoAttr(ni) || ni->type != AT_DATA) 5150495e90faSNamjae Jeon return -EOPNOTSUPP; 5151495e90faSNamjae Jeon if (start_vcn > ntfs_bytes_to_cluster(vol, ni->allocated_size)) 5152495e90faSNamjae Jeon return -EINVAL; 5153495e90faSNamjae Jeon 5154495e90faSNamjae Jeon hole_rl = kmalloc(sizeof(*hole_rl) * 2, GFP_NOFS); 5155495e90faSNamjae Jeon if (!hole_rl) 5156495e90faSNamjae Jeon return -ENOMEM; 5157495e90faSNamjae Jeon hole_rl[0].vcn = start_vcn; 5158495e90faSNamjae Jeon hole_rl[0].lcn = LCN_HOLE; 5159495e90faSNamjae Jeon hole_rl[0].length = len; 5160495e90faSNamjae Jeon hole_rl[1].vcn = start_vcn + len; 5161495e90faSNamjae Jeon hole_rl[1].lcn = LCN_ENOENT; 5162495e90faSNamjae Jeon hole_rl[1].length = 0; 5163495e90faSNamjae Jeon 5164495e90faSNamjae Jeon down_write(&ni->runlist.lock); 5165495e90faSNamjae Jeon ret = ntfs_attr_map_whole_runlist(ni); 5166495e90faSNamjae Jeon if (ret) { 5167495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5168495e90faSNamjae Jeon return ret; 5169495e90faSNamjae Jeon } 5170495e90faSNamjae Jeon 5171495e90faSNamjae Jeon rl = ntfs_rl_find_vcn_nolock(ni->runlist.rl, start_vcn); 5172495e90faSNamjae Jeon if (!rl) { 5173495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5174495e90faSNamjae Jeon kfree(hole_rl); 5175495e90faSNamjae Jeon return -EIO; 5176495e90faSNamjae Jeon } 5177495e90faSNamjae Jeon 5178495e90faSNamjae Jeon rl = ntfs_rl_insert_range(ni->runlist.rl, (int)ni->runlist.count, 5179495e90faSNamjae Jeon hole_rl, 1, &new_rl_count); 5180495e90faSNamjae Jeon if (IS_ERR(rl)) { 5181495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5182495e90faSNamjae Jeon kfree(hole_rl); 5183495e90faSNamjae Jeon return PTR_ERR(rl); 5184495e90faSNamjae Jeon } 5185495e90faSNamjae Jeon ni->runlist.rl = rl; 5186495e90faSNamjae Jeon ni->runlist.count = new_rl_count; 5187495e90faSNamjae Jeon 5188495e90faSNamjae Jeon ni->allocated_size += ntfs_cluster_to_bytes(vol, len); 5189495e90faSNamjae Jeon ni->data_size += ntfs_cluster_to_bytes(vol, len); 5190495e90faSNamjae Jeon if (ntfs_cluster_to_bytes(vol, start_vcn) < ni->initialized_size) 5191495e90faSNamjae Jeon ni->initialized_size += ntfs_cluster_to_bytes(vol, len); 5192495e90faSNamjae Jeon ret = ntfs_attr_update_mapping_pairs(ni, 0); 5193495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5194495e90faSNamjae Jeon if (ret) 5195495e90faSNamjae Jeon return ret; 5196495e90faSNamjae Jeon 5197495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 5198495e90faSNamjae Jeon if (!ctx) { 5199495e90faSNamjae Jeon ret = -ENOMEM; 5200495e90faSNamjae Jeon return ret; 5201495e90faSNamjae Jeon } 5202495e90faSNamjae Jeon 5203495e90faSNamjae Jeon ret = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 5204495e90faSNamjae Jeon 0, NULL, 0, ctx); 5205495e90faSNamjae Jeon if (ret) { 5206495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5207495e90faSNamjae Jeon return ret; 5208495e90faSNamjae Jeon } 5209495e90faSNamjae Jeon 5210495e90faSNamjae Jeon ctx->attr->data.non_resident.data_size = cpu_to_le64(ni->data_size); 5211495e90faSNamjae Jeon ctx->attr->data.non_resident.initialized_size = cpu_to_le64(ni->initialized_size); 5212495e90faSNamjae Jeon if (ni->type == AT_DATA && ni->name == AT_UNNAMED) 5213495e90faSNamjae Jeon NInoSetFileNameDirty(ni); 5214495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 5215495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5216495e90faSNamjae Jeon return ret; 5217495e90faSNamjae Jeon } 5218495e90faSNamjae Jeon 5219495e90faSNamjae Jeon int ntfs_non_resident_attr_collapse_range(struct ntfs_inode *ni, s64 start_vcn, s64 len) 5220495e90faSNamjae Jeon { 5221495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 5222495e90faSNamjae Jeon struct runlist_element *punch_rl, *rl; 5223495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx = NULL; 5224495e90faSNamjae Jeon s64 end_vcn; 5225495e90faSNamjae Jeon int dst_cnt; 5226495e90faSNamjae Jeon int ret; 5227495e90faSNamjae Jeon size_t new_rl_cnt; 5228495e90faSNamjae Jeon 5229495e90faSNamjae Jeon if (NInoAttr(ni) || ni->type != AT_DATA) 5230495e90faSNamjae Jeon return -EOPNOTSUPP; 5231495e90faSNamjae Jeon 5232495e90faSNamjae Jeon end_vcn = ntfs_bytes_to_cluster(vol, ni->allocated_size); 5233495e90faSNamjae Jeon if (start_vcn >= end_vcn) 5234495e90faSNamjae Jeon return -EINVAL; 5235495e90faSNamjae Jeon 5236495e90faSNamjae Jeon down_write(&ni->runlist.lock); 5237495e90faSNamjae Jeon ret = ntfs_attr_map_whole_runlist(ni); 5238ac9ccb6eSEthan Tidmore if (ret) { 5239ac9ccb6eSEthan Tidmore up_write(&ni->runlist.lock); 5240495e90faSNamjae Jeon return ret; 5241ac9ccb6eSEthan Tidmore } 5242495e90faSNamjae Jeon 5243495e90faSNamjae Jeon len = min(len, end_vcn - start_vcn); 5244495e90faSNamjae Jeon for (rl = ni->runlist.rl, dst_cnt = 0; rl && rl->length; rl++) 5245495e90faSNamjae Jeon dst_cnt++; 5246495e90faSNamjae Jeon rl = ntfs_rl_find_vcn_nolock(ni->runlist.rl, start_vcn); 5247495e90faSNamjae Jeon if (!rl) { 5248495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5249495e90faSNamjae Jeon return -EIO; 5250495e90faSNamjae Jeon } 5251495e90faSNamjae Jeon 5252495e90faSNamjae Jeon rl = ntfs_rl_collapse_range(ni->runlist.rl, dst_cnt + 1, 5253495e90faSNamjae Jeon start_vcn, len, &punch_rl, &new_rl_cnt); 5254495e90faSNamjae Jeon if (IS_ERR(rl)) { 5255495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5256495e90faSNamjae Jeon return PTR_ERR(rl); 5257495e90faSNamjae Jeon } 5258495e90faSNamjae Jeon ni->runlist.rl = rl; 5259495e90faSNamjae Jeon ni->runlist.count = new_rl_cnt; 5260495e90faSNamjae Jeon 5261495e90faSNamjae Jeon ni->allocated_size -= ntfs_cluster_to_bytes(vol, len); 5262495e90faSNamjae Jeon if (ni->data_size > ntfs_cluster_to_bytes(vol, start_vcn)) { 5263495e90faSNamjae Jeon if (ni->data_size > ntfs_cluster_to_bytes(vol, (start_vcn + len))) 5264495e90faSNamjae Jeon ni->data_size -= ntfs_cluster_to_bytes(vol, len); 5265495e90faSNamjae Jeon else 5266495e90faSNamjae Jeon ni->data_size = ntfs_cluster_to_bytes(vol, start_vcn); 5267495e90faSNamjae Jeon } 5268495e90faSNamjae Jeon if (ni->initialized_size > ntfs_cluster_to_bytes(vol, start_vcn)) { 5269495e90faSNamjae Jeon if (ni->initialized_size > 5270495e90faSNamjae Jeon ntfs_cluster_to_bytes(vol, start_vcn + len)) 5271495e90faSNamjae Jeon ni->initialized_size -= ntfs_cluster_to_bytes(vol, len); 5272495e90faSNamjae Jeon else 5273495e90faSNamjae Jeon ni->initialized_size = ntfs_cluster_to_bytes(vol, start_vcn); 5274495e90faSNamjae Jeon } 5275495e90faSNamjae Jeon 5276495e90faSNamjae Jeon if (ni->allocated_size > 0) { 5277495e90faSNamjae Jeon ret = ntfs_attr_update_mapping_pairs(ni, 0); 5278495e90faSNamjae Jeon if (ret) { 5279495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5280495e90faSNamjae Jeon goto out_rl; 5281495e90faSNamjae Jeon } 5282495e90faSNamjae Jeon } 5283495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5284495e90faSNamjae Jeon 5285495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, NULL); 5286495e90faSNamjae Jeon if (!ctx) { 5287495e90faSNamjae Jeon ret = -ENOMEM; 5288495e90faSNamjae Jeon goto out_rl; 5289495e90faSNamjae Jeon } 5290495e90faSNamjae Jeon 5291495e90faSNamjae Jeon ret = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 5292495e90faSNamjae Jeon 0, NULL, 0, ctx); 5293495e90faSNamjae Jeon if (ret) 5294495e90faSNamjae Jeon goto out_ctx; 5295495e90faSNamjae Jeon 5296495e90faSNamjae Jeon ctx->attr->data.non_resident.data_size = cpu_to_le64(ni->data_size); 5297495e90faSNamjae Jeon ctx->attr->data.non_resident.initialized_size = cpu_to_le64(ni->initialized_size); 5298495e90faSNamjae Jeon if (ni->allocated_size == 0) 5299495e90faSNamjae Jeon ntfs_attr_make_resident(ni, ctx); 5300495e90faSNamjae Jeon mark_mft_record_dirty(ctx->ntfs_ino); 5301495e90faSNamjae Jeon 5302495e90faSNamjae Jeon ret = ntfs_cluster_free_from_rl(vol, punch_rl); 5303495e90faSNamjae Jeon if (ret) 5304495e90faSNamjae Jeon ntfs_error(vol->sb, "Freeing of clusters failed"); 5305495e90faSNamjae Jeon out_ctx: 5306495e90faSNamjae Jeon if (ctx) 5307495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5308495e90faSNamjae Jeon out_rl: 5309495e90faSNamjae Jeon kvfree(punch_rl); 5310495e90faSNamjae Jeon mark_mft_record_dirty(ni); 5311495e90faSNamjae Jeon return ret; 5312495e90faSNamjae Jeon } 5313495e90faSNamjae Jeon 5314495e90faSNamjae Jeon int ntfs_non_resident_attr_punch_hole(struct ntfs_inode *ni, s64 start_vcn, s64 len) 5315495e90faSNamjae Jeon { 5316495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 5317495e90faSNamjae Jeon struct runlist_element *punch_rl, *rl; 5318495e90faSNamjae Jeon s64 end_vcn; 5319495e90faSNamjae Jeon int dst_cnt; 5320495e90faSNamjae Jeon int ret; 5321495e90faSNamjae Jeon size_t new_rl_count; 5322495e90faSNamjae Jeon 5323495e90faSNamjae Jeon if (NInoAttr(ni) || ni->type != AT_DATA) 5324495e90faSNamjae Jeon return -EOPNOTSUPP; 5325495e90faSNamjae Jeon 5326495e90faSNamjae Jeon end_vcn = ntfs_bytes_to_cluster(vol, ni->allocated_size); 5327495e90faSNamjae Jeon if (start_vcn >= end_vcn) 5328495e90faSNamjae Jeon return -EINVAL; 5329495e90faSNamjae Jeon 5330495e90faSNamjae Jeon down_write(&ni->runlist.lock); 5331495e90faSNamjae Jeon ret = ntfs_attr_map_whole_runlist(ni); 5332495e90faSNamjae Jeon if (ret) { 5333495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5334495e90faSNamjae Jeon return ret; 5335495e90faSNamjae Jeon } 5336495e90faSNamjae Jeon 5337495e90faSNamjae Jeon len = min(len, end_vcn - start_vcn + 1); 5338495e90faSNamjae Jeon for (rl = ni->runlist.rl, dst_cnt = 0; rl && rl->length; rl++) 5339495e90faSNamjae Jeon dst_cnt++; 5340495e90faSNamjae Jeon rl = ntfs_rl_find_vcn_nolock(ni->runlist.rl, start_vcn); 5341495e90faSNamjae Jeon if (!rl) { 5342495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5343495e90faSNamjae Jeon return -EIO; 5344495e90faSNamjae Jeon } 5345495e90faSNamjae Jeon 5346495e90faSNamjae Jeon rl = ntfs_rl_punch_hole(ni->runlist.rl, dst_cnt + 1, 5347495e90faSNamjae Jeon start_vcn, len, &punch_rl, &new_rl_count); 5348495e90faSNamjae Jeon if (IS_ERR(rl)) { 5349495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5350495e90faSNamjae Jeon return PTR_ERR(rl); 5351495e90faSNamjae Jeon } 5352495e90faSNamjae Jeon ni->runlist.rl = rl; 5353495e90faSNamjae Jeon ni->runlist.count = new_rl_count; 5354495e90faSNamjae Jeon 5355495e90faSNamjae Jeon ret = ntfs_attr_update_mapping_pairs(ni, 0); 5356495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5357495e90faSNamjae Jeon if (ret) { 5358495e90faSNamjae Jeon kvfree(punch_rl); 5359495e90faSNamjae Jeon return ret; 5360495e90faSNamjae Jeon } 5361495e90faSNamjae Jeon 5362495e90faSNamjae Jeon ret = ntfs_cluster_free_from_rl(vol, punch_rl); 5363495e90faSNamjae Jeon if (ret) 5364495e90faSNamjae Jeon ntfs_error(vol->sb, "Freeing of clusters failed"); 5365495e90faSNamjae Jeon 5366495e90faSNamjae Jeon kvfree(punch_rl); 5367495e90faSNamjae Jeon mark_mft_record_dirty(ni); 5368495e90faSNamjae Jeon return ret; 5369495e90faSNamjae Jeon } 5370495e90faSNamjae Jeon 5371495e90faSNamjae Jeon int ntfs_attr_fallocate(struct ntfs_inode *ni, loff_t start, loff_t byte_len, bool keep_size) 5372495e90faSNamjae Jeon { 5373495e90faSNamjae Jeon struct ntfs_volume *vol = ni->vol; 5374495e90faSNamjae Jeon struct mft_record *mrec; 5375495e90faSNamjae Jeon struct ntfs_attr_search_ctx *ctx; 5376495e90faSNamjae Jeon s64 old_data_size; 5377495e90faSNamjae Jeon s64 vcn_start, vcn_end, vcn_uninit, vcn, try_alloc_cnt; 5378495e90faSNamjae Jeon s64 lcn, alloc_cnt; 5379495e90faSNamjae Jeon int err = 0; 5380495e90faSNamjae Jeon struct runlist_element *rl; 5381495e90faSNamjae Jeon bool balloc; 5382495e90faSNamjae Jeon 5383495e90faSNamjae Jeon if (NInoAttr(ni) || ni->type != AT_DATA) 5384495e90faSNamjae Jeon return -EINVAL; 5385495e90faSNamjae Jeon 5386495e90faSNamjae Jeon if (NInoNonResident(ni) && !NInoFullyMapped(ni)) { 5387495e90faSNamjae Jeon down_write(&ni->runlist.lock); 5388495e90faSNamjae Jeon err = ntfs_attr_map_whole_runlist(ni); 5389495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5390495e90faSNamjae Jeon if (err) 5391495e90faSNamjae Jeon return err; 5392495e90faSNamjae Jeon } 5393495e90faSNamjae Jeon 5394495e90faSNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 5395495e90faSNamjae Jeon mrec = map_mft_record(ni); 5396495e90faSNamjae Jeon if (IS_ERR(mrec)) { 5397495e90faSNamjae Jeon mutex_unlock(&ni->mrec_lock); 5398495e90faSNamjae Jeon return PTR_ERR(mrec); 5399495e90faSNamjae Jeon } 5400495e90faSNamjae Jeon 5401495e90faSNamjae Jeon ctx = ntfs_attr_get_search_ctx(ni, mrec); 5402495e90faSNamjae Jeon if (!ctx) { 5403495e90faSNamjae Jeon err = -ENOMEM; 5404495e90faSNamjae Jeon goto out_unmap; 5405495e90faSNamjae Jeon } 5406495e90faSNamjae Jeon 5407495e90faSNamjae Jeon err = ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx); 5408495e90faSNamjae Jeon if (err) { 5409495e90faSNamjae Jeon err = -EIO; 5410495e90faSNamjae Jeon goto out_unmap; 5411495e90faSNamjae Jeon } 5412495e90faSNamjae Jeon 5413495e90faSNamjae Jeon old_data_size = ni->data_size; 5414495e90faSNamjae Jeon if (start + byte_len > ni->data_size) { 5415495e90faSNamjae Jeon err = ntfs_attr_truncate(ni, start + byte_len); 5416495e90faSNamjae Jeon if (err) 5417495e90faSNamjae Jeon goto out_unmap; 5418495e90faSNamjae Jeon if (keep_size) { 5419495e90faSNamjae Jeon ntfs_attr_reinit_search_ctx(ctx); 5420495e90faSNamjae Jeon err = ntfs_attr_lookup(AT_DATA, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx); 5421495e90faSNamjae Jeon if (err) { 5422495e90faSNamjae Jeon err = -EIO; 5423495e90faSNamjae Jeon goto out_unmap; 5424495e90faSNamjae Jeon } 5425495e90faSNamjae Jeon ni->data_size = old_data_size; 5426495e90faSNamjae Jeon if (NInoNonResident(ni)) 5427495e90faSNamjae Jeon ctx->attr->data.non_resident.data_size = 5428495e90faSNamjae Jeon cpu_to_le64(old_data_size); 5429495e90faSNamjae Jeon else 5430495e90faSNamjae Jeon ctx->attr->data.resident.value_length = 5431495e90faSNamjae Jeon cpu_to_le32((u32)old_data_size); 5432495e90faSNamjae Jeon mark_mft_record_dirty(ni); 5433495e90faSNamjae Jeon } 5434495e90faSNamjae Jeon } 5435495e90faSNamjae Jeon 5436495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5437495e90faSNamjae Jeon unmap_mft_record(ni); 5438495e90faSNamjae Jeon mutex_unlock(&ni->mrec_lock); 5439495e90faSNamjae Jeon 5440495e90faSNamjae Jeon if (!NInoNonResident(ni)) 5441495e90faSNamjae Jeon goto out; 5442495e90faSNamjae Jeon 5443495e90faSNamjae Jeon vcn_start = (s64)ntfs_bytes_to_cluster(vol, start); 5444495e90faSNamjae Jeon vcn_end = (s64)ntfs_bytes_to_cluster(vol, 5445495e90faSNamjae Jeon round_up(start + byte_len, vol->cluster_size)); 5446495e90faSNamjae Jeon vcn_uninit = (s64)ntfs_bytes_to_cluster(vol, 5447495e90faSNamjae Jeon round_up(ni->initialized_size, vol->cluster_size)); 5448495e90faSNamjae Jeon vcn_uninit = min_t(s64, vcn_uninit, vcn_end); 5449495e90faSNamjae Jeon 5450495e90faSNamjae Jeon /* 5451495e90faSNamjae Jeon * we have to allocate clusters for holes and delayed within initialized_size, 5452495e90faSNamjae Jeon * and zero out the clusters only for the holes. 5453495e90faSNamjae Jeon */ 5454495e90faSNamjae Jeon vcn = vcn_start; 5455495e90faSNamjae Jeon while (vcn < vcn_uninit) { 5456495e90faSNamjae Jeon down_read(&ni->runlist.lock); 5457495e90faSNamjae Jeon rl = ntfs_attr_find_vcn_nolock(ni, vcn, NULL); 5458495e90faSNamjae Jeon up_read(&ni->runlist.lock); 5459495e90faSNamjae Jeon if (IS_ERR(rl)) { 5460495e90faSNamjae Jeon err = PTR_ERR(rl); 5461495e90faSNamjae Jeon goto out; 5462495e90faSNamjae Jeon } 5463495e90faSNamjae Jeon 5464495e90faSNamjae Jeon if (rl->lcn > 0) { 5465495e90faSNamjae Jeon vcn += rl->length - (vcn - rl->vcn); 5466495e90faSNamjae Jeon } else if (rl->lcn == LCN_DELALLOC || rl->lcn == LCN_HOLE) { 5467495e90faSNamjae Jeon try_alloc_cnt = min(rl->length - (vcn - rl->vcn), 5468495e90faSNamjae Jeon vcn_uninit - vcn); 5469495e90faSNamjae Jeon 5470495e90faSNamjae Jeon if (rl->lcn == LCN_DELALLOC) { 5471495e90faSNamjae Jeon vcn += try_alloc_cnt; 5472495e90faSNamjae Jeon continue; 5473495e90faSNamjae Jeon } 5474495e90faSNamjae Jeon 5475495e90faSNamjae Jeon while (try_alloc_cnt > 0) { 5476495e90faSNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 5477495e90faSNamjae Jeon down_write(&ni->runlist.lock); 5478495e90faSNamjae Jeon err = ntfs_attr_map_cluster(ni, vcn, &lcn, &alloc_cnt, 5479495e90faSNamjae Jeon try_alloc_cnt, &balloc, false, false); 5480495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5481495e90faSNamjae Jeon mutex_unlock(&ni->mrec_lock); 5482495e90faSNamjae Jeon if (err) 5483495e90faSNamjae Jeon goto out; 5484495e90faSNamjae Jeon 5485495e90faSNamjae Jeon err = ntfs_dio_zero_range(VFS_I(ni), 5486495e90faSNamjae Jeon lcn << vol->cluster_size_bits, 5487495e90faSNamjae Jeon alloc_cnt << vol->cluster_size_bits); 5488495e90faSNamjae Jeon if (err > 0) 5489495e90faSNamjae Jeon goto out; 5490495e90faSNamjae Jeon 5491495e90faSNamjae Jeon if (signal_pending(current)) 5492495e90faSNamjae Jeon goto out; 5493495e90faSNamjae Jeon 5494495e90faSNamjae Jeon vcn += alloc_cnt; 5495495e90faSNamjae Jeon try_alloc_cnt -= alloc_cnt; 5496495e90faSNamjae Jeon } 5497495e90faSNamjae Jeon } else { 5498495e90faSNamjae Jeon err = -EIO; 5499495e90faSNamjae Jeon goto out; 5500495e90faSNamjae Jeon } 5501495e90faSNamjae Jeon } 5502495e90faSNamjae Jeon 5503495e90faSNamjae Jeon /* allocate clusters outside of initialized_size */ 5504495e90faSNamjae Jeon try_alloc_cnt = vcn_end - vcn; 5505495e90faSNamjae Jeon while (try_alloc_cnt > 0) { 5506495e90faSNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 5507495e90faSNamjae Jeon down_write(&ni->runlist.lock); 5508495e90faSNamjae Jeon err = ntfs_attr_map_cluster(ni, vcn, &lcn, &alloc_cnt, 5509495e90faSNamjae Jeon try_alloc_cnt, &balloc, false, false); 5510495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5511495e90faSNamjae Jeon mutex_unlock(&ni->mrec_lock); 5512495e90faSNamjae Jeon if (err || signal_pending(current)) 5513495e90faSNamjae Jeon goto out; 5514495e90faSNamjae Jeon 5515495e90faSNamjae Jeon vcn += alloc_cnt; 5516495e90faSNamjae Jeon try_alloc_cnt -= alloc_cnt; 5517495e90faSNamjae Jeon cond_resched(); 5518495e90faSNamjae Jeon } 5519495e90faSNamjae Jeon 5520495e90faSNamjae Jeon if (NInoRunlistDirty(ni)) { 5521495e90faSNamjae Jeon mutex_lock_nested(&ni->mrec_lock, NTFS_INODE_MUTEX_NORMAL); 5522495e90faSNamjae Jeon down_write(&ni->runlist.lock); 5523495e90faSNamjae Jeon err = ntfs_attr_update_mapping_pairs(ni, 0); 5524495e90faSNamjae Jeon if (err) 5525495e90faSNamjae Jeon ntfs_error(ni->vol->sb, "Updating mapping pairs failed"); 5526495e90faSNamjae Jeon else 5527495e90faSNamjae Jeon NInoClearRunlistDirty(ni); 5528495e90faSNamjae Jeon up_write(&ni->runlist.lock); 5529495e90faSNamjae Jeon mutex_unlock(&ni->mrec_lock); 5530495e90faSNamjae Jeon } 5531495e90faSNamjae Jeon return err; 5532495e90faSNamjae Jeon out_unmap: 5533495e90faSNamjae Jeon if (ctx) 5534495e90faSNamjae Jeon ntfs_attr_put_search_ctx(ctx); 5535495e90faSNamjae Jeon unmap_mft_record(ni); 5536495e90faSNamjae Jeon mutex_unlock(&ni->mrec_lock); 5537495e90faSNamjae Jeon out: 5538495e90faSNamjae Jeon return err >= 0 ? 0 : err; 5539495e90faSNamjae Jeon } 5540