162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2001-2012 Anton Altaparmakov and Tuxera Inc. 662306a36Sopenharmony_ci * Copyright (c) 2002 Richard Russon 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/buffer_head.h> 1062306a36Sopenharmony_ci#include <linux/sched.h> 1162306a36Sopenharmony_ci#include <linux/slab.h> 1262306a36Sopenharmony_ci#include <linux/swap.h> 1362306a36Sopenharmony_ci#include <linux/writeback.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "attrib.h" 1662306a36Sopenharmony_ci#include "debug.h" 1762306a36Sopenharmony_ci#include "layout.h" 1862306a36Sopenharmony_ci#include "lcnalloc.h" 1962306a36Sopenharmony_ci#include "malloc.h" 2062306a36Sopenharmony_ci#include "mft.h" 2162306a36Sopenharmony_ci#include "ntfs.h" 2262306a36Sopenharmony_ci#include "types.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/** 2562306a36Sopenharmony_ci * ntfs_map_runlist_nolock - map (a part of) a runlist of an ntfs inode 2662306a36Sopenharmony_ci * @ni: ntfs inode for which to map (part of) a runlist 2762306a36Sopenharmony_ci * @vcn: map runlist part containing this vcn 2862306a36Sopenharmony_ci * @ctx: active attribute search context if present or NULL if not 2962306a36Sopenharmony_ci * 3062306a36Sopenharmony_ci * Map the part of a runlist containing the @vcn of the ntfs inode @ni. 3162306a36Sopenharmony_ci * 3262306a36Sopenharmony_ci * If @ctx is specified, it is an active search context of @ni and its base mft 3362306a36Sopenharmony_ci * record. This is needed when ntfs_map_runlist_nolock() encounters unmapped 3462306a36Sopenharmony_ci * runlist fragments and allows their mapping. If you do not have the mft 3562306a36Sopenharmony_ci * record mapped, you can specify @ctx as NULL and ntfs_map_runlist_nolock() 3662306a36Sopenharmony_ci * will perform the necessary mapping and unmapping. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * Note, ntfs_map_runlist_nolock() saves the state of @ctx on entry and 3962306a36Sopenharmony_ci * restores it before returning. Thus, @ctx will be left pointing to the same 4062306a36Sopenharmony_ci * attribute on return as on entry. However, the actual pointers in @ctx may 4162306a36Sopenharmony_ci * point to different memory locations on return, so you must remember to reset 4262306a36Sopenharmony_ci * any cached pointers from the @ctx, i.e. after the call to 4362306a36Sopenharmony_ci * ntfs_map_runlist_nolock(), you will probably want to do: 4462306a36Sopenharmony_ci * m = ctx->mrec; 4562306a36Sopenharmony_ci * a = ctx->attr; 4662306a36Sopenharmony_ci * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that 4762306a36Sopenharmony_ci * you cache ctx->mrec in a variable @m of type MFT_RECORD *. 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * Return 0 on success and -errno on error. There is one special error code 5062306a36Sopenharmony_ci * which is not an error as such. This is -ENOENT. It means that @vcn is out 5162306a36Sopenharmony_ci * of bounds of the runlist. 5262306a36Sopenharmony_ci * 5362306a36Sopenharmony_ci * Note the runlist can be NULL after this function returns if @vcn is zero and 5462306a36Sopenharmony_ci * the attribute has zero allocated size, i.e. there simply is no runlist. 5562306a36Sopenharmony_ci * 5662306a36Sopenharmony_ci * WARNING: If @ctx is supplied, regardless of whether success or failure is 5762306a36Sopenharmony_ci * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx 5862306a36Sopenharmony_ci * is no longer valid, i.e. you need to either call 5962306a36Sopenharmony_ci * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. 6062306a36Sopenharmony_ci * In that case PTR_ERR(@ctx->mrec) will give you the error code for 6162306a36Sopenharmony_ci * why the mapping of the old inode failed. 6262306a36Sopenharmony_ci * 6362306a36Sopenharmony_ci * Locking: - The runlist described by @ni must be locked for writing on entry 6462306a36Sopenharmony_ci * and is locked on return. Note the runlist will be modified. 6562306a36Sopenharmony_ci * - If @ctx is NULL, the base mft record of @ni must not be mapped on 6662306a36Sopenharmony_ci * entry and it will be left unmapped on return. 6762306a36Sopenharmony_ci * - If @ctx is not NULL, the base mft record must be mapped on entry 6862306a36Sopenharmony_ci * and it will be left mapped on return. 6962306a36Sopenharmony_ci */ 7062306a36Sopenharmony_ciint ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn, ntfs_attr_search_ctx *ctx) 7162306a36Sopenharmony_ci{ 7262306a36Sopenharmony_ci VCN end_vcn; 7362306a36Sopenharmony_ci unsigned long flags; 7462306a36Sopenharmony_ci ntfs_inode *base_ni; 7562306a36Sopenharmony_ci MFT_RECORD *m; 7662306a36Sopenharmony_ci ATTR_RECORD *a; 7762306a36Sopenharmony_ci runlist_element *rl; 7862306a36Sopenharmony_ci struct page *put_this_page = NULL; 7962306a36Sopenharmony_ci int err = 0; 8062306a36Sopenharmony_ci bool ctx_is_temporary, ctx_needs_reset; 8162306a36Sopenharmony_ci ntfs_attr_search_ctx old_ctx = { NULL, }; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci ntfs_debug("Mapping runlist part containing vcn 0x%llx.", 8462306a36Sopenharmony_ci (unsigned long long)vcn); 8562306a36Sopenharmony_ci if (!NInoAttr(ni)) 8662306a36Sopenharmony_ci base_ni = ni; 8762306a36Sopenharmony_ci else 8862306a36Sopenharmony_ci base_ni = ni->ext.base_ntfs_ino; 8962306a36Sopenharmony_ci if (!ctx) { 9062306a36Sopenharmony_ci ctx_is_temporary = ctx_needs_reset = true; 9162306a36Sopenharmony_ci m = map_mft_record(base_ni); 9262306a36Sopenharmony_ci if (IS_ERR(m)) 9362306a36Sopenharmony_ci return PTR_ERR(m); 9462306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(base_ni, m); 9562306a36Sopenharmony_ci if (unlikely(!ctx)) { 9662306a36Sopenharmony_ci err = -ENOMEM; 9762306a36Sopenharmony_ci goto err_out; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci VCN allocated_size_vcn; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci BUG_ON(IS_ERR(ctx->mrec)); 10362306a36Sopenharmony_ci a = ctx->attr; 10462306a36Sopenharmony_ci BUG_ON(!a->non_resident); 10562306a36Sopenharmony_ci ctx_is_temporary = false; 10662306a36Sopenharmony_ci end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn); 10762306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 10862306a36Sopenharmony_ci allocated_size_vcn = ni->allocated_size >> 10962306a36Sopenharmony_ci ni->vol->cluster_size_bits; 11062306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 11162306a36Sopenharmony_ci if (!a->data.non_resident.lowest_vcn && end_vcn <= 0) 11262306a36Sopenharmony_ci end_vcn = allocated_size_vcn - 1; 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * If we already have the attribute extent containing @vcn in 11562306a36Sopenharmony_ci * @ctx, no need to look it up again. We slightly cheat in 11662306a36Sopenharmony_ci * that if vcn exceeds the allocated size, we will refuse to 11762306a36Sopenharmony_ci * map the runlist below, so there is definitely no need to get 11862306a36Sopenharmony_ci * the right attribute extent. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci if (vcn >= allocated_size_vcn || (a->type == ni->type && 12162306a36Sopenharmony_ci a->name_length == ni->name_len && 12262306a36Sopenharmony_ci !memcmp((u8*)a + le16_to_cpu(a->name_offset), 12362306a36Sopenharmony_ci ni->name, ni->name_len) && 12462306a36Sopenharmony_ci sle64_to_cpu(a->data.non_resident.lowest_vcn) 12562306a36Sopenharmony_ci <= vcn && end_vcn >= vcn)) 12662306a36Sopenharmony_ci ctx_needs_reset = false; 12762306a36Sopenharmony_ci else { 12862306a36Sopenharmony_ci /* Save the old search context. */ 12962306a36Sopenharmony_ci old_ctx = *ctx; 13062306a36Sopenharmony_ci /* 13162306a36Sopenharmony_ci * If the currently mapped (extent) inode is not the 13262306a36Sopenharmony_ci * base inode we will unmap it when we reinitialize the 13362306a36Sopenharmony_ci * search context which means we need to get a 13462306a36Sopenharmony_ci * reference to the page containing the mapped mft 13562306a36Sopenharmony_ci * record so we do not accidentally drop changes to the 13662306a36Sopenharmony_ci * mft record when it has not been marked dirty yet. 13762306a36Sopenharmony_ci */ 13862306a36Sopenharmony_ci if (old_ctx.base_ntfs_ino && old_ctx.ntfs_ino != 13962306a36Sopenharmony_ci old_ctx.base_ntfs_ino) { 14062306a36Sopenharmony_ci put_this_page = old_ctx.ntfs_ino->page; 14162306a36Sopenharmony_ci get_page(put_this_page); 14262306a36Sopenharmony_ci } 14362306a36Sopenharmony_ci /* 14462306a36Sopenharmony_ci * Reinitialize the search context so we can lookup the 14562306a36Sopenharmony_ci * needed attribute extent. 14662306a36Sopenharmony_ci */ 14762306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 14862306a36Sopenharmony_ci ctx_needs_reset = true; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci if (ctx_needs_reset) { 15262306a36Sopenharmony_ci err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 15362306a36Sopenharmony_ci CASE_SENSITIVE, vcn, NULL, 0, ctx); 15462306a36Sopenharmony_ci if (unlikely(err)) { 15562306a36Sopenharmony_ci if (err == -ENOENT) 15662306a36Sopenharmony_ci err = -EIO; 15762306a36Sopenharmony_ci goto err_out; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci BUG_ON(!ctx->attr->non_resident); 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci a = ctx->attr; 16262306a36Sopenharmony_ci /* 16362306a36Sopenharmony_ci * Only decompress the mapping pairs if @vcn is inside it. Otherwise 16462306a36Sopenharmony_ci * we get into problems when we try to map an out of bounds vcn because 16562306a36Sopenharmony_ci * we then try to map the already mapped runlist fragment and 16662306a36Sopenharmony_ci * ntfs_mapping_pairs_decompress() fails. 16762306a36Sopenharmony_ci */ 16862306a36Sopenharmony_ci end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1; 16962306a36Sopenharmony_ci if (unlikely(vcn && vcn >= end_vcn)) { 17062306a36Sopenharmony_ci err = -ENOENT; 17162306a36Sopenharmony_ci goto err_out; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl); 17462306a36Sopenharmony_ci if (IS_ERR(rl)) 17562306a36Sopenharmony_ci err = PTR_ERR(rl); 17662306a36Sopenharmony_ci else 17762306a36Sopenharmony_ci ni->runlist.rl = rl; 17862306a36Sopenharmony_cierr_out: 17962306a36Sopenharmony_ci if (ctx_is_temporary) { 18062306a36Sopenharmony_ci if (likely(ctx)) 18162306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 18262306a36Sopenharmony_ci unmap_mft_record(base_ni); 18362306a36Sopenharmony_ci } else if (ctx_needs_reset) { 18462306a36Sopenharmony_ci /* 18562306a36Sopenharmony_ci * If there is no attribute list, restoring the search context 18662306a36Sopenharmony_ci * is accomplished simply by copying the saved context back over 18762306a36Sopenharmony_ci * the caller supplied context. If there is an attribute list, 18862306a36Sopenharmony_ci * things are more complicated as we need to deal with mapping 18962306a36Sopenharmony_ci * of mft records and resulting potential changes in pointers. 19062306a36Sopenharmony_ci */ 19162306a36Sopenharmony_ci if (NInoAttrList(base_ni)) { 19262306a36Sopenharmony_ci /* 19362306a36Sopenharmony_ci * If the currently mapped (extent) inode is not the 19462306a36Sopenharmony_ci * one we had before, we need to unmap it and map the 19562306a36Sopenharmony_ci * old one. 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci if (ctx->ntfs_ino != old_ctx.ntfs_ino) { 19862306a36Sopenharmony_ci /* 19962306a36Sopenharmony_ci * If the currently mapped inode is not the 20062306a36Sopenharmony_ci * base inode, unmap it. 20162306a36Sopenharmony_ci */ 20262306a36Sopenharmony_ci if (ctx->base_ntfs_ino && ctx->ntfs_ino != 20362306a36Sopenharmony_ci ctx->base_ntfs_ino) { 20462306a36Sopenharmony_ci unmap_extent_mft_record(ctx->ntfs_ino); 20562306a36Sopenharmony_ci ctx->mrec = ctx->base_mrec; 20662306a36Sopenharmony_ci BUG_ON(!ctx->mrec); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci /* 20962306a36Sopenharmony_ci * If the old mapped inode is not the base 21062306a36Sopenharmony_ci * inode, map it. 21162306a36Sopenharmony_ci */ 21262306a36Sopenharmony_ci if (old_ctx.base_ntfs_ino && 21362306a36Sopenharmony_ci old_ctx.ntfs_ino != 21462306a36Sopenharmony_ci old_ctx.base_ntfs_ino) { 21562306a36Sopenharmony_ciretry_map: 21662306a36Sopenharmony_ci ctx->mrec = map_mft_record( 21762306a36Sopenharmony_ci old_ctx.ntfs_ino); 21862306a36Sopenharmony_ci /* 21962306a36Sopenharmony_ci * Something bad has happened. If out 22062306a36Sopenharmony_ci * of memory retry till it succeeds. 22162306a36Sopenharmony_ci * Any other errors are fatal and we 22262306a36Sopenharmony_ci * return the error code in ctx->mrec. 22362306a36Sopenharmony_ci * Let the caller deal with it... We 22462306a36Sopenharmony_ci * just need to fudge things so the 22562306a36Sopenharmony_ci * caller can reinit and/or put the 22662306a36Sopenharmony_ci * search context safely. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci if (IS_ERR(ctx->mrec)) { 22962306a36Sopenharmony_ci if (PTR_ERR(ctx->mrec) == 23062306a36Sopenharmony_ci -ENOMEM) { 23162306a36Sopenharmony_ci schedule(); 23262306a36Sopenharmony_ci goto retry_map; 23362306a36Sopenharmony_ci } else 23462306a36Sopenharmony_ci old_ctx.ntfs_ino = 23562306a36Sopenharmony_ci old_ctx. 23662306a36Sopenharmony_ci base_ntfs_ino; 23762306a36Sopenharmony_ci } 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci /* Update the changed pointers in the saved context. */ 24162306a36Sopenharmony_ci if (ctx->mrec != old_ctx.mrec) { 24262306a36Sopenharmony_ci if (!IS_ERR(ctx->mrec)) 24362306a36Sopenharmony_ci old_ctx.attr = (ATTR_RECORD*)( 24462306a36Sopenharmony_ci (u8*)ctx->mrec + 24562306a36Sopenharmony_ci ((u8*)old_ctx.attr - 24662306a36Sopenharmony_ci (u8*)old_ctx.mrec)); 24762306a36Sopenharmony_ci old_ctx.mrec = ctx->mrec; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci /* Restore the search context to the saved one. */ 25162306a36Sopenharmony_ci *ctx = old_ctx; 25262306a36Sopenharmony_ci /* 25362306a36Sopenharmony_ci * We drop the reference on the page we took earlier. In the 25462306a36Sopenharmony_ci * case that IS_ERR(ctx->mrec) is true this means we might lose 25562306a36Sopenharmony_ci * some changes to the mft record that had been made between 25662306a36Sopenharmony_ci * the last time it was marked dirty/written out and now. This 25762306a36Sopenharmony_ci * at this stage is not a problem as the mapping error is fatal 25862306a36Sopenharmony_ci * enough that the mft record cannot be written out anyway and 25962306a36Sopenharmony_ci * the caller is very likely to shutdown the whole inode 26062306a36Sopenharmony_ci * immediately and mark the volume dirty for chkdsk to pick up 26162306a36Sopenharmony_ci * the pieces anyway. 26262306a36Sopenharmony_ci */ 26362306a36Sopenharmony_ci if (put_this_page) 26462306a36Sopenharmony_ci put_page(put_this_page); 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci return err; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/** 27062306a36Sopenharmony_ci * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode 27162306a36Sopenharmony_ci * @ni: ntfs inode for which to map (part of) a runlist 27262306a36Sopenharmony_ci * @vcn: map runlist part containing this vcn 27362306a36Sopenharmony_ci * 27462306a36Sopenharmony_ci * Map the part of a runlist containing the @vcn of the ntfs inode @ni. 27562306a36Sopenharmony_ci * 27662306a36Sopenharmony_ci * Return 0 on success and -errno on error. There is one special error code 27762306a36Sopenharmony_ci * which is not an error as such. This is -ENOENT. It means that @vcn is out 27862306a36Sopenharmony_ci * of bounds of the runlist. 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * Locking: - The runlist must be unlocked on entry and is unlocked on return. 28162306a36Sopenharmony_ci * - This function takes the runlist lock for writing and may modify 28262306a36Sopenharmony_ci * the runlist. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ciint ntfs_map_runlist(ntfs_inode *ni, VCN vcn) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int err = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci down_write(&ni->runlist.lock); 28962306a36Sopenharmony_ci /* Make sure someone else didn't do the work while we were sleeping. */ 29062306a36Sopenharmony_ci if (likely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) <= 29162306a36Sopenharmony_ci LCN_RL_NOT_MAPPED)) 29262306a36Sopenharmony_ci err = ntfs_map_runlist_nolock(ni, vcn, NULL); 29362306a36Sopenharmony_ci up_write(&ni->runlist.lock); 29462306a36Sopenharmony_ci return err; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/** 29862306a36Sopenharmony_ci * ntfs_attr_vcn_to_lcn_nolock - convert a vcn into a lcn given an ntfs inode 29962306a36Sopenharmony_ci * @ni: ntfs inode of the attribute whose runlist to search 30062306a36Sopenharmony_ci * @vcn: vcn to convert 30162306a36Sopenharmony_ci * @write_locked: true if the runlist is locked for writing 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * Find the virtual cluster number @vcn in the runlist of the ntfs attribute 30462306a36Sopenharmony_ci * described by the ntfs inode @ni and return the corresponding logical cluster 30562306a36Sopenharmony_ci * number (lcn). 30662306a36Sopenharmony_ci * 30762306a36Sopenharmony_ci * If the @vcn is not mapped yet, the attempt is made to map the attribute 30862306a36Sopenharmony_ci * extent containing the @vcn and the vcn to lcn conversion is retried. 30962306a36Sopenharmony_ci * 31062306a36Sopenharmony_ci * If @write_locked is true the caller has locked the runlist for writing and 31162306a36Sopenharmony_ci * if false for reading. 31262306a36Sopenharmony_ci * 31362306a36Sopenharmony_ci * Since lcns must be >= 0, we use negative return codes with special meaning: 31462306a36Sopenharmony_ci * 31562306a36Sopenharmony_ci * Return code Meaning / Description 31662306a36Sopenharmony_ci * ========================================== 31762306a36Sopenharmony_ci * LCN_HOLE Hole / not allocated on disk. 31862306a36Sopenharmony_ci * LCN_ENOENT There is no such vcn in the runlist, i.e. @vcn is out of bounds. 31962306a36Sopenharmony_ci * LCN_ENOMEM Not enough memory to map runlist. 32062306a36Sopenharmony_ci * LCN_EIO Critical error (runlist/file is corrupt, i/o error, etc). 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * Locking: - The runlist must be locked on entry and is left locked on return. 32362306a36Sopenharmony_ci * - If @write_locked is 'false', i.e. the runlist is locked for reading, 32462306a36Sopenharmony_ci * the lock may be dropped inside the function so you cannot rely on 32562306a36Sopenharmony_ci * the runlist still being the same when this function returns. 32662306a36Sopenharmony_ci */ 32762306a36Sopenharmony_ciLCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn, 32862306a36Sopenharmony_ci const bool write_locked) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci LCN lcn; 33162306a36Sopenharmony_ci unsigned long flags; 33262306a36Sopenharmony_ci bool is_retry = false; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci BUG_ON(!ni); 33562306a36Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, %s_locked.", 33662306a36Sopenharmony_ci ni->mft_no, (unsigned long long)vcn, 33762306a36Sopenharmony_ci write_locked ? "write" : "read"); 33862306a36Sopenharmony_ci BUG_ON(!NInoNonResident(ni)); 33962306a36Sopenharmony_ci BUG_ON(vcn < 0); 34062306a36Sopenharmony_ci if (!ni->runlist.rl) { 34162306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 34262306a36Sopenharmony_ci if (!ni->allocated_size) { 34362306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 34462306a36Sopenharmony_ci return LCN_ENOENT; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ciretry_remap: 34962306a36Sopenharmony_ci /* Convert vcn to lcn. If that fails map the runlist and retry once. */ 35062306a36Sopenharmony_ci lcn = ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn); 35162306a36Sopenharmony_ci if (likely(lcn >= LCN_HOLE)) { 35262306a36Sopenharmony_ci ntfs_debug("Done, lcn 0x%llx.", (long long)lcn); 35362306a36Sopenharmony_ci return lcn; 35462306a36Sopenharmony_ci } 35562306a36Sopenharmony_ci if (lcn != LCN_RL_NOT_MAPPED) { 35662306a36Sopenharmony_ci if (lcn != LCN_ENOENT) 35762306a36Sopenharmony_ci lcn = LCN_EIO; 35862306a36Sopenharmony_ci } else if (!is_retry) { 35962306a36Sopenharmony_ci int err; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci if (!write_locked) { 36262306a36Sopenharmony_ci up_read(&ni->runlist.lock); 36362306a36Sopenharmony_ci down_write(&ni->runlist.lock); 36462306a36Sopenharmony_ci if (unlikely(ntfs_rl_vcn_to_lcn(ni->runlist.rl, vcn) != 36562306a36Sopenharmony_ci LCN_RL_NOT_MAPPED)) { 36662306a36Sopenharmony_ci up_write(&ni->runlist.lock); 36762306a36Sopenharmony_ci down_read(&ni->runlist.lock); 36862306a36Sopenharmony_ci goto retry_remap; 36962306a36Sopenharmony_ci } 37062306a36Sopenharmony_ci } 37162306a36Sopenharmony_ci err = ntfs_map_runlist_nolock(ni, vcn, NULL); 37262306a36Sopenharmony_ci if (!write_locked) { 37362306a36Sopenharmony_ci up_write(&ni->runlist.lock); 37462306a36Sopenharmony_ci down_read(&ni->runlist.lock); 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci if (likely(!err)) { 37762306a36Sopenharmony_ci is_retry = true; 37862306a36Sopenharmony_ci goto retry_remap; 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci if (err == -ENOENT) 38162306a36Sopenharmony_ci lcn = LCN_ENOENT; 38262306a36Sopenharmony_ci else if (err == -ENOMEM) 38362306a36Sopenharmony_ci lcn = LCN_ENOMEM; 38462306a36Sopenharmony_ci else 38562306a36Sopenharmony_ci lcn = LCN_EIO; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci if (lcn != LCN_ENOENT) 38862306a36Sopenharmony_ci ntfs_error(ni->vol->sb, "Failed with error code %lli.", 38962306a36Sopenharmony_ci (long long)lcn); 39062306a36Sopenharmony_ci return lcn; 39162306a36Sopenharmony_ci} 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci/** 39462306a36Sopenharmony_ci * ntfs_attr_find_vcn_nolock - find a vcn in the runlist of an ntfs inode 39562306a36Sopenharmony_ci * @ni: ntfs inode describing the runlist to search 39662306a36Sopenharmony_ci * @vcn: vcn to find 39762306a36Sopenharmony_ci * @ctx: active attribute search context if present or NULL if not 39862306a36Sopenharmony_ci * 39962306a36Sopenharmony_ci * Find the virtual cluster number @vcn in the runlist described by the ntfs 40062306a36Sopenharmony_ci * inode @ni and return the address of the runlist element containing the @vcn. 40162306a36Sopenharmony_ci * 40262306a36Sopenharmony_ci * If the @vcn is not mapped yet, the attempt is made to map the attribute 40362306a36Sopenharmony_ci * extent containing the @vcn and the vcn to lcn conversion is retried. 40462306a36Sopenharmony_ci * 40562306a36Sopenharmony_ci * If @ctx is specified, it is an active search context of @ni and its base mft 40662306a36Sopenharmony_ci * record. This is needed when ntfs_attr_find_vcn_nolock() encounters unmapped 40762306a36Sopenharmony_ci * runlist fragments and allows their mapping. If you do not have the mft 40862306a36Sopenharmony_ci * record mapped, you can specify @ctx as NULL and ntfs_attr_find_vcn_nolock() 40962306a36Sopenharmony_ci * will perform the necessary mapping and unmapping. 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * Note, ntfs_attr_find_vcn_nolock() saves the state of @ctx on entry and 41262306a36Sopenharmony_ci * restores it before returning. Thus, @ctx will be left pointing to the same 41362306a36Sopenharmony_ci * attribute on return as on entry. However, the actual pointers in @ctx may 41462306a36Sopenharmony_ci * point to different memory locations on return, so you must remember to reset 41562306a36Sopenharmony_ci * any cached pointers from the @ctx, i.e. after the call to 41662306a36Sopenharmony_ci * ntfs_attr_find_vcn_nolock(), you will probably want to do: 41762306a36Sopenharmony_ci * m = ctx->mrec; 41862306a36Sopenharmony_ci * a = ctx->attr; 41962306a36Sopenharmony_ci * Assuming you cache ctx->attr in a variable @a of type ATTR_RECORD * and that 42062306a36Sopenharmony_ci * you cache ctx->mrec in a variable @m of type MFT_RECORD *. 42162306a36Sopenharmony_ci * Note you need to distinguish between the lcn of the returned runlist element 42262306a36Sopenharmony_ci * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on 42362306a36Sopenharmony_ci * read and allocate clusters on write. 42462306a36Sopenharmony_ci * 42562306a36Sopenharmony_ci * Return the runlist element containing the @vcn on success and 42662306a36Sopenharmony_ci * ERR_PTR(-errno) on error. You need to test the return value with IS_ERR() 42762306a36Sopenharmony_ci * to decide if the return is success or failure and PTR_ERR() to get to the 42862306a36Sopenharmony_ci * error code if IS_ERR() is true. 42962306a36Sopenharmony_ci * 43062306a36Sopenharmony_ci * The possible error return codes are: 43162306a36Sopenharmony_ci * -ENOENT - No such vcn in the runlist, i.e. @vcn is out of bounds. 43262306a36Sopenharmony_ci * -ENOMEM - Not enough memory to map runlist. 43362306a36Sopenharmony_ci * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). 43462306a36Sopenharmony_ci * 43562306a36Sopenharmony_ci * WARNING: If @ctx is supplied, regardless of whether success or failure is 43662306a36Sopenharmony_ci * returned, you need to check IS_ERR(@ctx->mrec) and if 'true' the @ctx 43762306a36Sopenharmony_ci * is no longer valid, i.e. you need to either call 43862306a36Sopenharmony_ci * ntfs_attr_reinit_search_ctx() or ntfs_attr_put_search_ctx() on it. 43962306a36Sopenharmony_ci * In that case PTR_ERR(@ctx->mrec) will give you the error code for 44062306a36Sopenharmony_ci * why the mapping of the old inode failed. 44162306a36Sopenharmony_ci * 44262306a36Sopenharmony_ci * Locking: - The runlist described by @ni must be locked for writing on entry 44362306a36Sopenharmony_ci * and is locked on return. Note the runlist may be modified when 44462306a36Sopenharmony_ci * needed runlist fragments need to be mapped. 44562306a36Sopenharmony_ci * - If @ctx is NULL, the base mft record of @ni must not be mapped on 44662306a36Sopenharmony_ci * entry and it will be left unmapped on return. 44762306a36Sopenharmony_ci * - If @ctx is not NULL, the base mft record must be mapped on entry 44862306a36Sopenharmony_ci * and it will be left mapped on return. 44962306a36Sopenharmony_ci */ 45062306a36Sopenharmony_cirunlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni, const VCN vcn, 45162306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci unsigned long flags; 45462306a36Sopenharmony_ci runlist_element *rl; 45562306a36Sopenharmony_ci int err = 0; 45662306a36Sopenharmony_ci bool is_retry = false; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci BUG_ON(!ni); 45962306a36Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, with%s ctx.", 46062306a36Sopenharmony_ci ni->mft_no, (unsigned long long)vcn, ctx ? "" : "out"); 46162306a36Sopenharmony_ci BUG_ON(!NInoNonResident(ni)); 46262306a36Sopenharmony_ci BUG_ON(vcn < 0); 46362306a36Sopenharmony_ci if (!ni->runlist.rl) { 46462306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 46562306a36Sopenharmony_ci if (!ni->allocated_size) { 46662306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 46762306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ciretry_remap: 47262306a36Sopenharmony_ci rl = ni->runlist.rl; 47362306a36Sopenharmony_ci if (likely(rl && vcn >= rl[0].vcn)) { 47462306a36Sopenharmony_ci while (likely(rl->length)) { 47562306a36Sopenharmony_ci if (unlikely(vcn < rl[1].vcn)) { 47662306a36Sopenharmony_ci if (likely(rl->lcn >= LCN_HOLE)) { 47762306a36Sopenharmony_ci ntfs_debug("Done."); 47862306a36Sopenharmony_ci return rl; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci rl++; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci if (likely(rl->lcn != LCN_RL_NOT_MAPPED)) { 48562306a36Sopenharmony_ci if (likely(rl->lcn == LCN_ENOENT)) 48662306a36Sopenharmony_ci err = -ENOENT; 48762306a36Sopenharmony_ci else 48862306a36Sopenharmony_ci err = -EIO; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci if (!err && !is_retry) { 49262306a36Sopenharmony_ci /* 49362306a36Sopenharmony_ci * If the search context is invalid we cannot map the unmapped 49462306a36Sopenharmony_ci * region. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ci if (IS_ERR(ctx->mrec)) 49762306a36Sopenharmony_ci err = PTR_ERR(ctx->mrec); 49862306a36Sopenharmony_ci else { 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * The @vcn is in an unmapped region, map the runlist 50162306a36Sopenharmony_ci * and retry. 50262306a36Sopenharmony_ci */ 50362306a36Sopenharmony_ci err = ntfs_map_runlist_nolock(ni, vcn, ctx); 50462306a36Sopenharmony_ci if (likely(!err)) { 50562306a36Sopenharmony_ci is_retry = true; 50662306a36Sopenharmony_ci goto retry_remap; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci if (err == -EINVAL) 51062306a36Sopenharmony_ci err = -EIO; 51162306a36Sopenharmony_ci } else if (!err) 51262306a36Sopenharmony_ci err = -EIO; 51362306a36Sopenharmony_ci if (err != -ENOENT) 51462306a36Sopenharmony_ci ntfs_error(ni->vol->sb, "Failed with error code %i.", err); 51562306a36Sopenharmony_ci return ERR_PTR(err); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/** 51962306a36Sopenharmony_ci * ntfs_attr_find - find (next) attribute in mft record 52062306a36Sopenharmony_ci * @type: attribute type to find 52162306a36Sopenharmony_ci * @name: attribute name to find (optional, i.e. NULL means don't care) 52262306a36Sopenharmony_ci * @name_len: attribute name length (only needed if @name present) 52362306a36Sopenharmony_ci * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 52462306a36Sopenharmony_ci * @val: attribute value to find (optional, resident attributes only) 52562306a36Sopenharmony_ci * @val_len: attribute value length 52662306a36Sopenharmony_ci * @ctx: search context with mft record and attribute to search from 52762306a36Sopenharmony_ci * 52862306a36Sopenharmony_ci * You should not need to call this function directly. Use ntfs_attr_lookup() 52962306a36Sopenharmony_ci * instead. 53062306a36Sopenharmony_ci * 53162306a36Sopenharmony_ci * ntfs_attr_find() takes a search context @ctx as parameter and searches the 53262306a36Sopenharmony_ci * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an 53362306a36Sopenharmony_ci * attribute of @type, optionally @name and @val. 53462306a36Sopenharmony_ci * 53562306a36Sopenharmony_ci * If the attribute is found, ntfs_attr_find() returns 0 and @ctx->attr will 53662306a36Sopenharmony_ci * point to the found attribute. 53762306a36Sopenharmony_ci * 53862306a36Sopenharmony_ci * If the attribute is not found, ntfs_attr_find() returns -ENOENT and 53962306a36Sopenharmony_ci * @ctx->attr will point to the attribute before which the attribute being 54062306a36Sopenharmony_ci * searched for would need to be inserted if such an action were to be desired. 54162306a36Sopenharmony_ci * 54262306a36Sopenharmony_ci * On actual error, ntfs_attr_find() returns -EIO. In this case @ctx->attr is 54362306a36Sopenharmony_ci * undefined and in particular do not rely on it not changing. 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * If @ctx->is_first is 'true', the search begins with @ctx->attr itself. If it 54662306a36Sopenharmony_ci * is 'false', the search begins after @ctx->attr. 54762306a36Sopenharmony_ci * 54862306a36Sopenharmony_ci * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and 54962306a36Sopenharmony_ci * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record 55062306a36Sopenharmony_ci * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at 55162306a36Sopenharmony_ci * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case 55262306a36Sopenharmony_ci * sensitive. When @name is present, @name_len is the @name length in Unicode 55362306a36Sopenharmony_ci * characters. 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * If @name is not present (NULL), we assume that the unnamed attribute is 55662306a36Sopenharmony_ci * being searched for. 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci * Finally, the resident attribute value @val is looked for, if present. If 55962306a36Sopenharmony_ci * @val is not present (NULL), @val_len is ignored. 56062306a36Sopenharmony_ci * 56162306a36Sopenharmony_ci * ntfs_attr_find() only searches the specified mft record and it ignores the 56262306a36Sopenharmony_ci * presence of an attribute list attribute (unless it is the one being searched 56362306a36Sopenharmony_ci * for, obviously). If you need to take attribute lists into consideration, 56462306a36Sopenharmony_ci * use ntfs_attr_lookup() instead (see below). This also means that you cannot 56562306a36Sopenharmony_ci * use ntfs_attr_find() to search for extent records of non-resident 56662306a36Sopenharmony_ci * attributes, as extents with lowest_vcn != 0 are usually described by the 56762306a36Sopenharmony_ci * attribute list attribute only. - Note that it is possible that the first 56862306a36Sopenharmony_ci * extent is only in the attribute list while the last extent is in the base 56962306a36Sopenharmony_ci * mft record, so do not rely on being able to find the first extent in the 57062306a36Sopenharmony_ci * base mft record. 57162306a36Sopenharmony_ci * 57262306a36Sopenharmony_ci * Warning: Never use @val when looking for attribute types which can be 57362306a36Sopenharmony_ci * non-resident as this most likely will result in a crash! 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_cistatic int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name, 57662306a36Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 57762306a36Sopenharmony_ci const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci ATTR_RECORD *a; 58062306a36Sopenharmony_ci ntfs_volume *vol = ctx->ntfs_ino->vol; 58162306a36Sopenharmony_ci ntfschar *upcase = vol->upcase; 58262306a36Sopenharmony_ci u32 upcase_len = vol->upcase_len; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* 58562306a36Sopenharmony_ci * Iterate over attributes in mft record starting at @ctx->attr, or the 58662306a36Sopenharmony_ci * attribute following that, if @ctx->is_first is 'true'. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_ci if (ctx->is_first) { 58962306a36Sopenharmony_ci a = ctx->attr; 59062306a36Sopenharmony_ci ctx->is_first = false; 59162306a36Sopenharmony_ci } else 59262306a36Sopenharmony_ci a = (ATTR_RECORD*)((u8*)ctx->attr + 59362306a36Sopenharmony_ci le32_to_cpu(ctx->attr->length)); 59462306a36Sopenharmony_ci for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) { 59562306a36Sopenharmony_ci u8 *mrec_end = (u8 *)ctx->mrec + 59662306a36Sopenharmony_ci le32_to_cpu(ctx->mrec->bytes_allocated); 59762306a36Sopenharmony_ci u8 *name_end; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* check whether ATTR_RECORD wrap */ 60062306a36Sopenharmony_ci if ((u8 *)a < (u8 *)ctx->mrec) 60162306a36Sopenharmony_ci break; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci /* check whether Attribute Record Header is within bounds */ 60462306a36Sopenharmony_ci if ((u8 *)a > mrec_end || 60562306a36Sopenharmony_ci (u8 *)a + sizeof(ATTR_RECORD) > mrec_end) 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* check whether ATTR_RECORD's name is within bounds */ 60962306a36Sopenharmony_ci name_end = (u8 *)a + le16_to_cpu(a->name_offset) + 61062306a36Sopenharmony_ci a->name_length * sizeof(ntfschar); 61162306a36Sopenharmony_ci if (name_end > mrec_end) 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci ctx->attr = a; 61562306a36Sopenharmony_ci if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) || 61662306a36Sopenharmony_ci a->type == AT_END)) 61762306a36Sopenharmony_ci return -ENOENT; 61862306a36Sopenharmony_ci if (unlikely(!a->length)) 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci /* check whether ATTR_RECORD's length wrap */ 62262306a36Sopenharmony_ci if ((u8 *)a + le32_to_cpu(a->length) < (u8 *)a) 62362306a36Sopenharmony_ci break; 62462306a36Sopenharmony_ci /* check whether ATTR_RECORD's length is within bounds */ 62562306a36Sopenharmony_ci if ((u8 *)a + le32_to_cpu(a->length) > mrec_end) 62662306a36Sopenharmony_ci break; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci if (a->type != type) 62962306a36Sopenharmony_ci continue; 63062306a36Sopenharmony_ci /* 63162306a36Sopenharmony_ci * If @name is present, compare the two names. If @name is 63262306a36Sopenharmony_ci * missing, assume we want an unnamed attribute. 63362306a36Sopenharmony_ci */ 63462306a36Sopenharmony_ci if (!name) { 63562306a36Sopenharmony_ci /* The search failed if the found attribute is named. */ 63662306a36Sopenharmony_ci if (a->name_length) 63762306a36Sopenharmony_ci return -ENOENT; 63862306a36Sopenharmony_ci } else if (!ntfs_are_names_equal(name, name_len, 63962306a36Sopenharmony_ci (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)), 64062306a36Sopenharmony_ci a->name_length, ic, upcase, upcase_len)) { 64162306a36Sopenharmony_ci register int rc; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci rc = ntfs_collate_names(name, name_len, 64462306a36Sopenharmony_ci (ntfschar*)((u8*)a + 64562306a36Sopenharmony_ci le16_to_cpu(a->name_offset)), 64662306a36Sopenharmony_ci a->name_length, 1, IGNORE_CASE, 64762306a36Sopenharmony_ci upcase, upcase_len); 64862306a36Sopenharmony_ci /* 64962306a36Sopenharmony_ci * If @name collates before a->name, there is no 65062306a36Sopenharmony_ci * matching attribute. 65162306a36Sopenharmony_ci */ 65262306a36Sopenharmony_ci if (rc == -1) 65362306a36Sopenharmony_ci return -ENOENT; 65462306a36Sopenharmony_ci /* If the strings are not equal, continue search. */ 65562306a36Sopenharmony_ci if (rc) 65662306a36Sopenharmony_ci continue; 65762306a36Sopenharmony_ci rc = ntfs_collate_names(name, name_len, 65862306a36Sopenharmony_ci (ntfschar*)((u8*)a + 65962306a36Sopenharmony_ci le16_to_cpu(a->name_offset)), 66062306a36Sopenharmony_ci a->name_length, 1, CASE_SENSITIVE, 66162306a36Sopenharmony_ci upcase, upcase_len); 66262306a36Sopenharmony_ci if (rc == -1) 66362306a36Sopenharmony_ci return -ENOENT; 66462306a36Sopenharmony_ci if (rc) 66562306a36Sopenharmony_ci continue; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * The names match or @name not present and attribute is 66962306a36Sopenharmony_ci * unnamed. If no @val specified, we have found the attribute 67062306a36Sopenharmony_ci * and are done. 67162306a36Sopenharmony_ci */ 67262306a36Sopenharmony_ci if (!val) 67362306a36Sopenharmony_ci return 0; 67462306a36Sopenharmony_ci /* @val is present; compare values. */ 67562306a36Sopenharmony_ci else { 67662306a36Sopenharmony_ci register int rc; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci rc = memcmp(val, (u8*)a + le16_to_cpu( 67962306a36Sopenharmony_ci a->data.resident.value_offset), 68062306a36Sopenharmony_ci min_t(u32, val_len, le32_to_cpu( 68162306a36Sopenharmony_ci a->data.resident.value_length))); 68262306a36Sopenharmony_ci /* 68362306a36Sopenharmony_ci * If @val collates before the current attribute's 68462306a36Sopenharmony_ci * value, there is no matching attribute. 68562306a36Sopenharmony_ci */ 68662306a36Sopenharmony_ci if (!rc) { 68762306a36Sopenharmony_ci register u32 avl; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci avl = le32_to_cpu( 69062306a36Sopenharmony_ci a->data.resident.value_length); 69162306a36Sopenharmony_ci if (val_len == avl) 69262306a36Sopenharmony_ci return 0; 69362306a36Sopenharmony_ci if (val_len < avl) 69462306a36Sopenharmony_ci return -ENOENT; 69562306a36Sopenharmony_ci } else if (rc < 0) 69662306a36Sopenharmony_ci return -ENOENT; 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci ntfs_error(vol->sb, "Inode is corrupt. Run chkdsk."); 70062306a36Sopenharmony_ci NVolSetErrors(vol); 70162306a36Sopenharmony_ci return -EIO; 70262306a36Sopenharmony_ci} 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci/** 70562306a36Sopenharmony_ci * load_attribute_list - load an attribute list into memory 70662306a36Sopenharmony_ci * @vol: ntfs volume from which to read 70762306a36Sopenharmony_ci * @runlist: runlist of the attribute list 70862306a36Sopenharmony_ci * @al_start: destination buffer 70962306a36Sopenharmony_ci * @size: size of the destination buffer in bytes 71062306a36Sopenharmony_ci * @initialized_size: initialized size of the attribute list 71162306a36Sopenharmony_ci * 71262306a36Sopenharmony_ci * Walk the runlist @runlist and load all clusters from it copying them into 71362306a36Sopenharmony_ci * the linear buffer @al. The maximum number of bytes copied to @al is @size 71462306a36Sopenharmony_ci * bytes. Note, @size does not need to be a multiple of the cluster size. If 71562306a36Sopenharmony_ci * @initialized_size is less than @size, the region in @al between 71662306a36Sopenharmony_ci * @initialized_size and @size will be zeroed and not read from disk. 71762306a36Sopenharmony_ci * 71862306a36Sopenharmony_ci * Return 0 on success or -errno on error. 71962306a36Sopenharmony_ci */ 72062306a36Sopenharmony_ciint load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start, 72162306a36Sopenharmony_ci const s64 size, const s64 initialized_size) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci LCN lcn; 72462306a36Sopenharmony_ci u8 *al = al_start; 72562306a36Sopenharmony_ci u8 *al_end = al + initialized_size; 72662306a36Sopenharmony_ci runlist_element *rl; 72762306a36Sopenharmony_ci struct buffer_head *bh; 72862306a36Sopenharmony_ci struct super_block *sb; 72962306a36Sopenharmony_ci unsigned long block_size; 73062306a36Sopenharmony_ci unsigned long block, max_block; 73162306a36Sopenharmony_ci int err = 0; 73262306a36Sopenharmony_ci unsigned char block_size_bits; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci ntfs_debug("Entering."); 73562306a36Sopenharmony_ci if (!vol || !runlist || !al || size <= 0 || initialized_size < 0 || 73662306a36Sopenharmony_ci initialized_size > size) 73762306a36Sopenharmony_ci return -EINVAL; 73862306a36Sopenharmony_ci if (!initialized_size) { 73962306a36Sopenharmony_ci memset(al, 0, size); 74062306a36Sopenharmony_ci return 0; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci sb = vol->sb; 74362306a36Sopenharmony_ci block_size = sb->s_blocksize; 74462306a36Sopenharmony_ci block_size_bits = sb->s_blocksize_bits; 74562306a36Sopenharmony_ci down_read(&runlist->lock); 74662306a36Sopenharmony_ci rl = runlist->rl; 74762306a36Sopenharmony_ci if (!rl) { 74862306a36Sopenharmony_ci ntfs_error(sb, "Cannot read attribute list since runlist is " 74962306a36Sopenharmony_ci "missing."); 75062306a36Sopenharmony_ci goto err_out; 75162306a36Sopenharmony_ci } 75262306a36Sopenharmony_ci /* Read all clusters specified by the runlist one run at a time. */ 75362306a36Sopenharmony_ci while (rl->length) { 75462306a36Sopenharmony_ci lcn = ntfs_rl_vcn_to_lcn(rl, rl->vcn); 75562306a36Sopenharmony_ci ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.", 75662306a36Sopenharmony_ci (unsigned long long)rl->vcn, 75762306a36Sopenharmony_ci (unsigned long long)lcn); 75862306a36Sopenharmony_ci /* The attribute list cannot be sparse. */ 75962306a36Sopenharmony_ci if (lcn < 0) { 76062306a36Sopenharmony_ci ntfs_error(sb, "ntfs_rl_vcn_to_lcn() failed. Cannot " 76162306a36Sopenharmony_ci "read attribute list."); 76262306a36Sopenharmony_ci goto err_out; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci block = lcn << vol->cluster_size_bits >> block_size_bits; 76562306a36Sopenharmony_ci /* Read the run from device in chunks of block_size bytes. */ 76662306a36Sopenharmony_ci max_block = block + (rl->length << vol->cluster_size_bits >> 76762306a36Sopenharmony_ci block_size_bits); 76862306a36Sopenharmony_ci ntfs_debug("max_block = 0x%lx.", max_block); 76962306a36Sopenharmony_ci do { 77062306a36Sopenharmony_ci ntfs_debug("Reading block = 0x%lx.", block); 77162306a36Sopenharmony_ci bh = sb_bread(sb, block); 77262306a36Sopenharmony_ci if (!bh) { 77362306a36Sopenharmony_ci ntfs_error(sb, "sb_bread() failed. Cannot " 77462306a36Sopenharmony_ci "read attribute list."); 77562306a36Sopenharmony_ci goto err_out; 77662306a36Sopenharmony_ci } 77762306a36Sopenharmony_ci if (al + block_size >= al_end) 77862306a36Sopenharmony_ci goto do_final; 77962306a36Sopenharmony_ci memcpy(al, bh->b_data, block_size); 78062306a36Sopenharmony_ci brelse(bh); 78162306a36Sopenharmony_ci al += block_size; 78262306a36Sopenharmony_ci } while (++block < max_block); 78362306a36Sopenharmony_ci rl++; 78462306a36Sopenharmony_ci } 78562306a36Sopenharmony_ci if (initialized_size < size) { 78662306a36Sopenharmony_ciinitialize: 78762306a36Sopenharmony_ci memset(al_start + initialized_size, 0, size - initialized_size); 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_cidone: 79062306a36Sopenharmony_ci up_read(&runlist->lock); 79162306a36Sopenharmony_ci return err; 79262306a36Sopenharmony_cido_final: 79362306a36Sopenharmony_ci if (al < al_end) { 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * Partial block. 79662306a36Sopenharmony_ci * 79762306a36Sopenharmony_ci * Note: The attribute list can be smaller than its allocation 79862306a36Sopenharmony_ci * by multiple clusters. This has been encountered by at least 79962306a36Sopenharmony_ci * two people running Windows XP, thus we cannot do any 80062306a36Sopenharmony_ci * truncation sanity checking here. (AIA) 80162306a36Sopenharmony_ci */ 80262306a36Sopenharmony_ci memcpy(al, bh->b_data, al_end - al); 80362306a36Sopenharmony_ci brelse(bh); 80462306a36Sopenharmony_ci if (initialized_size < size) 80562306a36Sopenharmony_ci goto initialize; 80662306a36Sopenharmony_ci goto done; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci brelse(bh); 80962306a36Sopenharmony_ci /* Real overflow! */ 81062306a36Sopenharmony_ci ntfs_error(sb, "Attribute list buffer overflow. Read attribute list " 81162306a36Sopenharmony_ci "is truncated."); 81262306a36Sopenharmony_cierr_out: 81362306a36Sopenharmony_ci err = -EIO; 81462306a36Sopenharmony_ci goto done; 81562306a36Sopenharmony_ci} 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci/** 81862306a36Sopenharmony_ci * ntfs_external_attr_find - find an attribute in the attribute list of an inode 81962306a36Sopenharmony_ci * @type: attribute type to find 82062306a36Sopenharmony_ci * @name: attribute name to find (optional, i.e. NULL means don't care) 82162306a36Sopenharmony_ci * @name_len: attribute name length (only needed if @name present) 82262306a36Sopenharmony_ci * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 82362306a36Sopenharmony_ci * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 82462306a36Sopenharmony_ci * @val: attribute value to find (optional, resident attributes only) 82562306a36Sopenharmony_ci * @val_len: attribute value length 82662306a36Sopenharmony_ci * @ctx: search context with mft record and attribute to search from 82762306a36Sopenharmony_ci * 82862306a36Sopenharmony_ci * You should not need to call this function directly. Use ntfs_attr_lookup() 82962306a36Sopenharmony_ci * instead. 83062306a36Sopenharmony_ci * 83162306a36Sopenharmony_ci * Find an attribute by searching the attribute list for the corresponding 83262306a36Sopenharmony_ci * attribute list entry. Having found the entry, map the mft record if the 83362306a36Sopenharmony_ci * attribute is in a different mft record/inode, ntfs_attr_find() the attribute 83462306a36Sopenharmony_ci * in there and return it. 83562306a36Sopenharmony_ci * 83662306a36Sopenharmony_ci * On first search @ctx->ntfs_ino must be the base mft record and @ctx must 83762306a36Sopenharmony_ci * have been obtained from a call to ntfs_attr_get_search_ctx(). On subsequent 83862306a36Sopenharmony_ci * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is 83962306a36Sopenharmony_ci * then the base inode). 84062306a36Sopenharmony_ci * 84162306a36Sopenharmony_ci * After finishing with the attribute/mft record you need to call 84262306a36Sopenharmony_ci * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 84362306a36Sopenharmony_ci * mapped inodes, etc). 84462306a36Sopenharmony_ci * 84562306a36Sopenharmony_ci * If the attribute is found, ntfs_external_attr_find() returns 0 and 84662306a36Sopenharmony_ci * @ctx->attr will point to the found attribute. @ctx->mrec will point to the 84762306a36Sopenharmony_ci * mft record in which @ctx->attr is located and @ctx->al_entry will point to 84862306a36Sopenharmony_ci * the attribute list entry for the attribute. 84962306a36Sopenharmony_ci * 85062306a36Sopenharmony_ci * If the attribute is not found, ntfs_external_attr_find() returns -ENOENT and 85162306a36Sopenharmony_ci * @ctx->attr will point to the attribute in the base mft record before which 85262306a36Sopenharmony_ci * the attribute being searched for would need to be inserted if such an action 85362306a36Sopenharmony_ci * were to be desired. @ctx->mrec will point to the mft record in which 85462306a36Sopenharmony_ci * @ctx->attr is located and @ctx->al_entry will point to the attribute list 85562306a36Sopenharmony_ci * entry of the attribute before which the attribute being searched for would 85662306a36Sopenharmony_ci * need to be inserted if such an action were to be desired. 85762306a36Sopenharmony_ci * 85862306a36Sopenharmony_ci * Thus to insert the not found attribute, one wants to add the attribute to 85962306a36Sopenharmony_ci * @ctx->mrec (the base mft record) and if there is not enough space, the 86062306a36Sopenharmony_ci * attribute should be placed in a newly allocated extent mft record. The 86162306a36Sopenharmony_ci * attribute list entry for the inserted attribute should be inserted in the 86262306a36Sopenharmony_ci * attribute list attribute at @ctx->al_entry. 86362306a36Sopenharmony_ci * 86462306a36Sopenharmony_ci * On actual error, ntfs_external_attr_find() returns -EIO. In this case 86562306a36Sopenharmony_ci * @ctx->attr is undefined and in particular do not rely on it not changing. 86662306a36Sopenharmony_ci */ 86762306a36Sopenharmony_cistatic int ntfs_external_attr_find(const ATTR_TYPE type, 86862306a36Sopenharmony_ci const ntfschar *name, const u32 name_len, 86962306a36Sopenharmony_ci const IGNORE_CASE_BOOL ic, const VCN lowest_vcn, 87062306a36Sopenharmony_ci const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx) 87162306a36Sopenharmony_ci{ 87262306a36Sopenharmony_ci ntfs_inode *base_ni, *ni; 87362306a36Sopenharmony_ci ntfs_volume *vol; 87462306a36Sopenharmony_ci ATTR_LIST_ENTRY *al_entry, *next_al_entry; 87562306a36Sopenharmony_ci u8 *al_start, *al_end; 87662306a36Sopenharmony_ci ATTR_RECORD *a; 87762306a36Sopenharmony_ci ntfschar *al_name; 87862306a36Sopenharmony_ci u32 al_name_len; 87962306a36Sopenharmony_ci int err = 0; 88062306a36Sopenharmony_ci static const char *es = " Unmount and run chkdsk."; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci ni = ctx->ntfs_ino; 88362306a36Sopenharmony_ci base_ni = ctx->base_ntfs_ino; 88462306a36Sopenharmony_ci ntfs_debug("Entering for inode 0x%lx, type 0x%x.", ni->mft_no, type); 88562306a36Sopenharmony_ci if (!base_ni) { 88662306a36Sopenharmony_ci /* First call happens with the base mft record. */ 88762306a36Sopenharmony_ci base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino; 88862306a36Sopenharmony_ci ctx->base_mrec = ctx->mrec; 88962306a36Sopenharmony_ci } 89062306a36Sopenharmony_ci if (ni == base_ni) 89162306a36Sopenharmony_ci ctx->base_attr = ctx->attr; 89262306a36Sopenharmony_ci if (type == AT_END) 89362306a36Sopenharmony_ci goto not_found; 89462306a36Sopenharmony_ci vol = base_ni->vol; 89562306a36Sopenharmony_ci al_start = base_ni->attr_list; 89662306a36Sopenharmony_ci al_end = al_start + base_ni->attr_list_size; 89762306a36Sopenharmony_ci if (!ctx->al_entry) 89862306a36Sopenharmony_ci ctx->al_entry = (ATTR_LIST_ENTRY*)al_start; 89962306a36Sopenharmony_ci /* 90062306a36Sopenharmony_ci * Iterate over entries in attribute list starting at @ctx->al_entry, 90162306a36Sopenharmony_ci * or the entry following that, if @ctx->is_first is 'true'. 90262306a36Sopenharmony_ci */ 90362306a36Sopenharmony_ci if (ctx->is_first) { 90462306a36Sopenharmony_ci al_entry = ctx->al_entry; 90562306a36Sopenharmony_ci ctx->is_first = false; 90662306a36Sopenharmony_ci } else 90762306a36Sopenharmony_ci al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry + 90862306a36Sopenharmony_ci le16_to_cpu(ctx->al_entry->length)); 90962306a36Sopenharmony_ci for (;; al_entry = next_al_entry) { 91062306a36Sopenharmony_ci /* Out of bounds check. */ 91162306a36Sopenharmony_ci if ((u8*)al_entry < base_ni->attr_list || 91262306a36Sopenharmony_ci (u8*)al_entry > al_end) 91362306a36Sopenharmony_ci break; /* Inode is corrupt. */ 91462306a36Sopenharmony_ci ctx->al_entry = al_entry; 91562306a36Sopenharmony_ci /* Catch the end of the attribute list. */ 91662306a36Sopenharmony_ci if ((u8*)al_entry == al_end) 91762306a36Sopenharmony_ci goto not_found; 91862306a36Sopenharmony_ci if (!al_entry->length) 91962306a36Sopenharmony_ci break; 92062306a36Sopenharmony_ci if ((u8*)al_entry + 6 > al_end || (u8*)al_entry + 92162306a36Sopenharmony_ci le16_to_cpu(al_entry->length) > al_end) 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry + 92462306a36Sopenharmony_ci le16_to_cpu(al_entry->length)); 92562306a36Sopenharmony_ci if (le32_to_cpu(al_entry->type) > le32_to_cpu(type)) 92662306a36Sopenharmony_ci goto not_found; 92762306a36Sopenharmony_ci if (type != al_entry->type) 92862306a36Sopenharmony_ci continue; 92962306a36Sopenharmony_ci /* 93062306a36Sopenharmony_ci * If @name is present, compare the two names. If @name is 93162306a36Sopenharmony_ci * missing, assume we want an unnamed attribute. 93262306a36Sopenharmony_ci */ 93362306a36Sopenharmony_ci al_name_len = al_entry->name_length; 93462306a36Sopenharmony_ci al_name = (ntfschar*)((u8*)al_entry + al_entry->name_offset); 93562306a36Sopenharmony_ci if (!name) { 93662306a36Sopenharmony_ci if (al_name_len) 93762306a36Sopenharmony_ci goto not_found; 93862306a36Sopenharmony_ci } else if (!ntfs_are_names_equal(al_name, al_name_len, name, 93962306a36Sopenharmony_ci name_len, ic, vol->upcase, vol->upcase_len)) { 94062306a36Sopenharmony_ci register int rc; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci rc = ntfs_collate_names(name, name_len, al_name, 94362306a36Sopenharmony_ci al_name_len, 1, IGNORE_CASE, 94462306a36Sopenharmony_ci vol->upcase, vol->upcase_len); 94562306a36Sopenharmony_ci /* 94662306a36Sopenharmony_ci * If @name collates before al_name, there is no 94762306a36Sopenharmony_ci * matching attribute. 94862306a36Sopenharmony_ci */ 94962306a36Sopenharmony_ci if (rc == -1) 95062306a36Sopenharmony_ci goto not_found; 95162306a36Sopenharmony_ci /* If the strings are not equal, continue search. */ 95262306a36Sopenharmony_ci if (rc) 95362306a36Sopenharmony_ci continue; 95462306a36Sopenharmony_ci /* 95562306a36Sopenharmony_ci * FIXME: Reverse engineering showed 0, IGNORE_CASE but 95662306a36Sopenharmony_ci * that is inconsistent with ntfs_attr_find(). The 95762306a36Sopenharmony_ci * subsequent rc checks were also different. Perhaps I 95862306a36Sopenharmony_ci * made a mistake in one of the two. Need to recheck 95962306a36Sopenharmony_ci * which is correct or at least see what is going on... 96062306a36Sopenharmony_ci * (AIA) 96162306a36Sopenharmony_ci */ 96262306a36Sopenharmony_ci rc = ntfs_collate_names(name, name_len, al_name, 96362306a36Sopenharmony_ci al_name_len, 1, CASE_SENSITIVE, 96462306a36Sopenharmony_ci vol->upcase, vol->upcase_len); 96562306a36Sopenharmony_ci if (rc == -1) 96662306a36Sopenharmony_ci goto not_found; 96762306a36Sopenharmony_ci if (rc) 96862306a36Sopenharmony_ci continue; 96962306a36Sopenharmony_ci } 97062306a36Sopenharmony_ci /* 97162306a36Sopenharmony_ci * The names match or @name not present and attribute is 97262306a36Sopenharmony_ci * unnamed. Now check @lowest_vcn. Continue search if the 97362306a36Sopenharmony_ci * next attribute list entry still fits @lowest_vcn. Otherwise 97462306a36Sopenharmony_ci * we have reached the right one or the search has failed. 97562306a36Sopenharmony_ci */ 97662306a36Sopenharmony_ci if (lowest_vcn && (u8*)next_al_entry >= al_start && 97762306a36Sopenharmony_ci (u8*)next_al_entry + 6 < al_end && 97862306a36Sopenharmony_ci (u8*)next_al_entry + le16_to_cpu( 97962306a36Sopenharmony_ci next_al_entry->length) <= al_end && 98062306a36Sopenharmony_ci sle64_to_cpu(next_al_entry->lowest_vcn) <= 98162306a36Sopenharmony_ci lowest_vcn && 98262306a36Sopenharmony_ci next_al_entry->type == al_entry->type && 98362306a36Sopenharmony_ci next_al_entry->name_length == al_name_len && 98462306a36Sopenharmony_ci ntfs_are_names_equal((ntfschar*)((u8*) 98562306a36Sopenharmony_ci next_al_entry + 98662306a36Sopenharmony_ci next_al_entry->name_offset), 98762306a36Sopenharmony_ci next_al_entry->name_length, 98862306a36Sopenharmony_ci al_name, al_name_len, CASE_SENSITIVE, 98962306a36Sopenharmony_ci vol->upcase, vol->upcase_len)) 99062306a36Sopenharmony_ci continue; 99162306a36Sopenharmony_ci if (MREF_LE(al_entry->mft_reference) == ni->mft_no) { 99262306a36Sopenharmony_ci if (MSEQNO_LE(al_entry->mft_reference) != ni->seq_no) { 99362306a36Sopenharmony_ci ntfs_error(vol->sb, "Found stale mft " 99462306a36Sopenharmony_ci "reference in attribute list " 99562306a36Sopenharmony_ci "of base inode 0x%lx.%s", 99662306a36Sopenharmony_ci base_ni->mft_no, es); 99762306a36Sopenharmony_ci err = -EIO; 99862306a36Sopenharmony_ci break; 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci } else { /* Mft references do not match. */ 100162306a36Sopenharmony_ci /* If there is a mapped record unmap it first. */ 100262306a36Sopenharmony_ci if (ni != base_ni) 100362306a36Sopenharmony_ci unmap_extent_mft_record(ni); 100462306a36Sopenharmony_ci /* Do we want the base record back? */ 100562306a36Sopenharmony_ci if (MREF_LE(al_entry->mft_reference) == 100662306a36Sopenharmony_ci base_ni->mft_no) { 100762306a36Sopenharmony_ci ni = ctx->ntfs_ino = base_ni; 100862306a36Sopenharmony_ci ctx->mrec = ctx->base_mrec; 100962306a36Sopenharmony_ci } else { 101062306a36Sopenharmony_ci /* We want an extent record. */ 101162306a36Sopenharmony_ci ctx->mrec = map_extent_mft_record(base_ni, 101262306a36Sopenharmony_ci le64_to_cpu( 101362306a36Sopenharmony_ci al_entry->mft_reference), &ni); 101462306a36Sopenharmony_ci if (IS_ERR(ctx->mrec)) { 101562306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to map " 101662306a36Sopenharmony_ci "extent mft record " 101762306a36Sopenharmony_ci "0x%lx of base inode " 101862306a36Sopenharmony_ci "0x%lx.%s", 101962306a36Sopenharmony_ci MREF_LE(al_entry-> 102062306a36Sopenharmony_ci mft_reference), 102162306a36Sopenharmony_ci base_ni->mft_no, es); 102262306a36Sopenharmony_ci err = PTR_ERR(ctx->mrec); 102362306a36Sopenharmony_ci if (err == -ENOENT) 102462306a36Sopenharmony_ci err = -EIO; 102562306a36Sopenharmony_ci /* Cause @ctx to be sanitized below. */ 102662306a36Sopenharmony_ci ni = NULL; 102762306a36Sopenharmony_ci break; 102862306a36Sopenharmony_ci } 102962306a36Sopenharmony_ci ctx->ntfs_ino = ni; 103062306a36Sopenharmony_ci } 103162306a36Sopenharmony_ci ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + 103262306a36Sopenharmony_ci le16_to_cpu(ctx->mrec->attrs_offset)); 103362306a36Sopenharmony_ci } 103462306a36Sopenharmony_ci /* 103562306a36Sopenharmony_ci * ctx->vfs_ino, ctx->mrec, and ctx->attr now point to the 103662306a36Sopenharmony_ci * mft record containing the attribute represented by the 103762306a36Sopenharmony_ci * current al_entry. 103862306a36Sopenharmony_ci */ 103962306a36Sopenharmony_ci /* 104062306a36Sopenharmony_ci * We could call into ntfs_attr_find() to find the right 104162306a36Sopenharmony_ci * attribute in this mft record but this would be less 104262306a36Sopenharmony_ci * efficient and not quite accurate as ntfs_attr_find() ignores 104362306a36Sopenharmony_ci * the attribute instance numbers for example which become 104462306a36Sopenharmony_ci * important when one plays with attribute lists. Also, 104562306a36Sopenharmony_ci * because a proper match has been found in the attribute list 104662306a36Sopenharmony_ci * entry above, the comparison can now be optimized. So it is 104762306a36Sopenharmony_ci * worth re-implementing a simplified ntfs_attr_find() here. 104862306a36Sopenharmony_ci */ 104962306a36Sopenharmony_ci a = ctx->attr; 105062306a36Sopenharmony_ci /* 105162306a36Sopenharmony_ci * Use a manual loop so we can still use break and continue 105262306a36Sopenharmony_ci * with the same meanings as above. 105362306a36Sopenharmony_ci */ 105462306a36Sopenharmony_cido_next_attr_loop: 105562306a36Sopenharmony_ci if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec + 105662306a36Sopenharmony_ci le32_to_cpu(ctx->mrec->bytes_allocated)) 105762306a36Sopenharmony_ci break; 105862306a36Sopenharmony_ci if (a->type == AT_END) 105962306a36Sopenharmony_ci break; 106062306a36Sopenharmony_ci if (!a->length) 106162306a36Sopenharmony_ci break; 106262306a36Sopenharmony_ci if (al_entry->instance != a->instance) 106362306a36Sopenharmony_ci goto do_next_attr; 106462306a36Sopenharmony_ci /* 106562306a36Sopenharmony_ci * If the type and/or the name are mismatched between the 106662306a36Sopenharmony_ci * attribute list entry and the attribute record, there is 106762306a36Sopenharmony_ci * corruption so we break and return error EIO. 106862306a36Sopenharmony_ci */ 106962306a36Sopenharmony_ci if (al_entry->type != a->type) 107062306a36Sopenharmony_ci break; 107162306a36Sopenharmony_ci if (!ntfs_are_names_equal((ntfschar*)((u8*)a + 107262306a36Sopenharmony_ci le16_to_cpu(a->name_offset)), a->name_length, 107362306a36Sopenharmony_ci al_name, al_name_len, CASE_SENSITIVE, 107462306a36Sopenharmony_ci vol->upcase, vol->upcase_len)) 107562306a36Sopenharmony_ci break; 107662306a36Sopenharmony_ci ctx->attr = a; 107762306a36Sopenharmony_ci /* 107862306a36Sopenharmony_ci * If no @val specified or @val specified and it matches, we 107962306a36Sopenharmony_ci * have found it! 108062306a36Sopenharmony_ci */ 108162306a36Sopenharmony_ci if (!val || (!a->non_resident && le32_to_cpu( 108262306a36Sopenharmony_ci a->data.resident.value_length) == val_len && 108362306a36Sopenharmony_ci !memcmp((u8*)a + 108462306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset), 108562306a36Sopenharmony_ci val, val_len))) { 108662306a36Sopenharmony_ci ntfs_debug("Done, found."); 108762306a36Sopenharmony_ci return 0; 108862306a36Sopenharmony_ci } 108962306a36Sopenharmony_cido_next_attr: 109062306a36Sopenharmony_ci /* Proceed to the next attribute in the current mft record. */ 109162306a36Sopenharmony_ci a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length)); 109262306a36Sopenharmony_ci goto do_next_attr_loop; 109362306a36Sopenharmony_ci } 109462306a36Sopenharmony_ci if (!err) { 109562306a36Sopenharmony_ci ntfs_error(vol->sb, "Base inode 0x%lx contains corrupt " 109662306a36Sopenharmony_ci "attribute list attribute.%s", base_ni->mft_no, 109762306a36Sopenharmony_ci es); 109862306a36Sopenharmony_ci err = -EIO; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci if (ni != base_ni) { 110162306a36Sopenharmony_ci if (ni) 110262306a36Sopenharmony_ci unmap_extent_mft_record(ni); 110362306a36Sopenharmony_ci ctx->ntfs_ino = base_ni; 110462306a36Sopenharmony_ci ctx->mrec = ctx->base_mrec; 110562306a36Sopenharmony_ci ctx->attr = ctx->base_attr; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci if (err != -ENOMEM) 110862306a36Sopenharmony_ci NVolSetErrors(vol); 110962306a36Sopenharmony_ci return err; 111062306a36Sopenharmony_cinot_found: 111162306a36Sopenharmony_ci /* 111262306a36Sopenharmony_ci * If we were looking for AT_END, we reset the search context @ctx and 111362306a36Sopenharmony_ci * use ntfs_attr_find() to seek to the end of the base mft record. 111462306a36Sopenharmony_ci */ 111562306a36Sopenharmony_ci if (type == AT_END) { 111662306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 111762306a36Sopenharmony_ci return ntfs_attr_find(AT_END, name, name_len, ic, val, val_len, 111862306a36Sopenharmony_ci ctx); 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci /* 112162306a36Sopenharmony_ci * The attribute was not found. Before we return, we want to ensure 112262306a36Sopenharmony_ci * @ctx->mrec and @ctx->attr indicate the position at which the 112362306a36Sopenharmony_ci * attribute should be inserted in the base mft record. Since we also 112462306a36Sopenharmony_ci * want to preserve @ctx->al_entry we cannot reinitialize the search 112562306a36Sopenharmony_ci * context using ntfs_attr_reinit_search_ctx() as this would set 112662306a36Sopenharmony_ci * @ctx->al_entry to NULL. Thus we do the necessary bits manually (see 112762306a36Sopenharmony_ci * ntfs_attr_init_search_ctx() below). Note, we _only_ preserve 112862306a36Sopenharmony_ci * @ctx->al_entry as the remaining fields (base_*) are identical to 112962306a36Sopenharmony_ci * their non base_ counterparts and we cannot set @ctx->base_attr 113062306a36Sopenharmony_ci * correctly yet as we do not know what @ctx->attr will be set to by 113162306a36Sopenharmony_ci * the call to ntfs_attr_find() below. 113262306a36Sopenharmony_ci */ 113362306a36Sopenharmony_ci if (ni != base_ni) 113462306a36Sopenharmony_ci unmap_extent_mft_record(ni); 113562306a36Sopenharmony_ci ctx->mrec = ctx->base_mrec; 113662306a36Sopenharmony_ci ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + 113762306a36Sopenharmony_ci le16_to_cpu(ctx->mrec->attrs_offset)); 113862306a36Sopenharmony_ci ctx->is_first = true; 113962306a36Sopenharmony_ci ctx->ntfs_ino = base_ni; 114062306a36Sopenharmony_ci ctx->base_ntfs_ino = NULL; 114162306a36Sopenharmony_ci ctx->base_mrec = NULL; 114262306a36Sopenharmony_ci ctx->base_attr = NULL; 114362306a36Sopenharmony_ci /* 114462306a36Sopenharmony_ci * In case there are multiple matches in the base mft record, need to 114562306a36Sopenharmony_ci * keep enumerating until we get an attribute not found response (or 114662306a36Sopenharmony_ci * another error), otherwise we would keep returning the same attribute 114762306a36Sopenharmony_ci * over and over again and all programs using us for enumeration would 114862306a36Sopenharmony_ci * lock up in a tight loop. 114962306a36Sopenharmony_ci */ 115062306a36Sopenharmony_ci do { 115162306a36Sopenharmony_ci err = ntfs_attr_find(type, name, name_len, ic, val, val_len, 115262306a36Sopenharmony_ci ctx); 115362306a36Sopenharmony_ci } while (!err); 115462306a36Sopenharmony_ci ntfs_debug("Done, not found."); 115562306a36Sopenharmony_ci return err; 115662306a36Sopenharmony_ci} 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci/** 115962306a36Sopenharmony_ci * ntfs_attr_lookup - find an attribute in an ntfs inode 116062306a36Sopenharmony_ci * @type: attribute type to find 116162306a36Sopenharmony_ci * @name: attribute name to find (optional, i.e. NULL means don't care) 116262306a36Sopenharmony_ci * @name_len: attribute name length (only needed if @name present) 116362306a36Sopenharmony_ci * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) 116462306a36Sopenharmony_ci * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) 116562306a36Sopenharmony_ci * @val: attribute value to find (optional, resident attributes only) 116662306a36Sopenharmony_ci * @val_len: attribute value length 116762306a36Sopenharmony_ci * @ctx: search context with mft record and attribute to search from 116862306a36Sopenharmony_ci * 116962306a36Sopenharmony_ci * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must 117062306a36Sopenharmony_ci * be the base mft record and @ctx must have been obtained from a call to 117162306a36Sopenharmony_ci * ntfs_attr_get_search_ctx(). 117262306a36Sopenharmony_ci * 117362306a36Sopenharmony_ci * This function transparently handles attribute lists and @ctx is used to 117462306a36Sopenharmony_ci * continue searches where they were left off at. 117562306a36Sopenharmony_ci * 117662306a36Sopenharmony_ci * After finishing with the attribute/mft record you need to call 117762306a36Sopenharmony_ci * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any 117862306a36Sopenharmony_ci * mapped inodes, etc). 117962306a36Sopenharmony_ci * 118062306a36Sopenharmony_ci * Return 0 if the search was successful and -errno if not. 118162306a36Sopenharmony_ci * 118262306a36Sopenharmony_ci * When 0, @ctx->attr is the found attribute and it is in mft record 118362306a36Sopenharmony_ci * @ctx->mrec. If an attribute list attribute is present, @ctx->al_entry is 118462306a36Sopenharmony_ci * the attribute list entry of the found attribute. 118562306a36Sopenharmony_ci * 118662306a36Sopenharmony_ci * When -ENOENT, @ctx->attr is the attribute which collates just after the 118762306a36Sopenharmony_ci * attribute being searched for, i.e. if one wants to add the attribute to the 118862306a36Sopenharmony_ci * mft record this is the correct place to insert it into. If an attribute 118962306a36Sopenharmony_ci * list attribute is present, @ctx->al_entry is the attribute list entry which 119062306a36Sopenharmony_ci * collates just after the attribute list entry of the attribute being searched 119162306a36Sopenharmony_ci * for, i.e. if one wants to add the attribute to the mft record this is the 119262306a36Sopenharmony_ci * correct place to insert its attribute list entry into. 119362306a36Sopenharmony_ci * 119462306a36Sopenharmony_ci * When -errno != -ENOENT, an error occurred during the lookup. @ctx->attr is 119562306a36Sopenharmony_ci * then undefined and in particular you should not rely on it not changing. 119662306a36Sopenharmony_ci */ 119762306a36Sopenharmony_ciint ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, 119862306a36Sopenharmony_ci const u32 name_len, const IGNORE_CASE_BOOL ic, 119962306a36Sopenharmony_ci const VCN lowest_vcn, const u8 *val, const u32 val_len, 120062306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx) 120162306a36Sopenharmony_ci{ 120262306a36Sopenharmony_ci ntfs_inode *base_ni; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci ntfs_debug("Entering."); 120562306a36Sopenharmony_ci BUG_ON(IS_ERR(ctx->mrec)); 120662306a36Sopenharmony_ci if (ctx->base_ntfs_ino) 120762306a36Sopenharmony_ci base_ni = ctx->base_ntfs_ino; 120862306a36Sopenharmony_ci else 120962306a36Sopenharmony_ci base_ni = ctx->ntfs_ino; 121062306a36Sopenharmony_ci /* Sanity check, just for debugging really. */ 121162306a36Sopenharmony_ci BUG_ON(!base_ni); 121262306a36Sopenharmony_ci if (!NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) 121362306a36Sopenharmony_ci return ntfs_attr_find(type, name, name_len, ic, val, val_len, 121462306a36Sopenharmony_ci ctx); 121562306a36Sopenharmony_ci return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn, 121662306a36Sopenharmony_ci val, val_len, ctx); 121762306a36Sopenharmony_ci} 121862306a36Sopenharmony_ci 121962306a36Sopenharmony_ci/** 122062306a36Sopenharmony_ci * ntfs_attr_init_search_ctx - initialize an attribute search context 122162306a36Sopenharmony_ci * @ctx: attribute search context to initialize 122262306a36Sopenharmony_ci * @ni: ntfs inode with which to initialize the search context 122362306a36Sopenharmony_ci * @mrec: mft record with which to initialize the search context 122462306a36Sopenharmony_ci * 122562306a36Sopenharmony_ci * Initialize the attribute search context @ctx with @ni and @mrec. 122662306a36Sopenharmony_ci */ 122762306a36Sopenharmony_cistatic inline void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, 122862306a36Sopenharmony_ci ntfs_inode *ni, MFT_RECORD *mrec) 122962306a36Sopenharmony_ci{ 123062306a36Sopenharmony_ci *ctx = (ntfs_attr_search_ctx) { 123162306a36Sopenharmony_ci .mrec = mrec, 123262306a36Sopenharmony_ci /* Sanity checks are performed elsewhere. */ 123362306a36Sopenharmony_ci .attr = (ATTR_RECORD*)((u8*)mrec + 123462306a36Sopenharmony_ci le16_to_cpu(mrec->attrs_offset)), 123562306a36Sopenharmony_ci .is_first = true, 123662306a36Sopenharmony_ci .ntfs_ino = ni, 123762306a36Sopenharmony_ci }; 123862306a36Sopenharmony_ci} 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci/** 124162306a36Sopenharmony_ci * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context 124262306a36Sopenharmony_ci * @ctx: attribute search context to reinitialize 124362306a36Sopenharmony_ci * 124462306a36Sopenharmony_ci * Reinitialize the attribute search context @ctx, unmapping an associated 124562306a36Sopenharmony_ci * extent mft record if present, and initialize the search context again. 124662306a36Sopenharmony_ci * 124762306a36Sopenharmony_ci * This is used when a search for a new attribute is being started to reset 124862306a36Sopenharmony_ci * the search context to the beginning. 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_civoid ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci if (likely(!ctx->base_ntfs_ino)) { 125362306a36Sopenharmony_ci /* No attribute list. */ 125462306a36Sopenharmony_ci ctx->is_first = true; 125562306a36Sopenharmony_ci /* Sanity checks are performed elsewhere. */ 125662306a36Sopenharmony_ci ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + 125762306a36Sopenharmony_ci le16_to_cpu(ctx->mrec->attrs_offset)); 125862306a36Sopenharmony_ci /* 125962306a36Sopenharmony_ci * This needs resetting due to ntfs_external_attr_find() which 126062306a36Sopenharmony_ci * can leave it set despite having zeroed ctx->base_ntfs_ino. 126162306a36Sopenharmony_ci */ 126262306a36Sopenharmony_ci ctx->al_entry = NULL; 126362306a36Sopenharmony_ci return; 126462306a36Sopenharmony_ci } /* Attribute list. */ 126562306a36Sopenharmony_ci if (ctx->ntfs_ino != ctx->base_ntfs_ino) 126662306a36Sopenharmony_ci unmap_extent_mft_record(ctx->ntfs_ino); 126762306a36Sopenharmony_ci ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec); 126862306a36Sopenharmony_ci return; 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci/** 127262306a36Sopenharmony_ci * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context 127362306a36Sopenharmony_ci * @ni: ntfs inode with which to initialize the search context 127462306a36Sopenharmony_ci * @mrec: mft record with which to initialize the search context 127562306a36Sopenharmony_ci * 127662306a36Sopenharmony_ci * Allocate a new attribute search context, initialize it with @ni and @mrec, 127762306a36Sopenharmony_ci * and return it. Return NULL if allocation failed. 127862306a36Sopenharmony_ci */ 127962306a36Sopenharmony_cintfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, GFP_NOFS); 128462306a36Sopenharmony_ci if (ctx) 128562306a36Sopenharmony_ci ntfs_attr_init_search_ctx(ctx, ni, mrec); 128662306a36Sopenharmony_ci return ctx; 128762306a36Sopenharmony_ci} 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci/** 129062306a36Sopenharmony_ci * ntfs_attr_put_search_ctx - release an attribute search context 129162306a36Sopenharmony_ci * @ctx: attribute search context to free 129262306a36Sopenharmony_ci * 129362306a36Sopenharmony_ci * Release the attribute search context @ctx, unmapping an associated extent 129462306a36Sopenharmony_ci * mft record if present. 129562306a36Sopenharmony_ci */ 129662306a36Sopenharmony_civoid ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino) 129962306a36Sopenharmony_ci unmap_extent_mft_record(ctx->ntfs_ino); 130062306a36Sopenharmony_ci kmem_cache_free(ntfs_attr_ctx_cache, ctx); 130162306a36Sopenharmony_ci return; 130262306a36Sopenharmony_ci} 130362306a36Sopenharmony_ci 130462306a36Sopenharmony_ci#ifdef NTFS_RW 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci/** 130762306a36Sopenharmony_ci * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file 130862306a36Sopenharmony_ci * @vol: ntfs volume to which the attribute belongs 130962306a36Sopenharmony_ci * @type: attribute type which to find 131062306a36Sopenharmony_ci * 131162306a36Sopenharmony_ci * Search for the attribute definition record corresponding to the attribute 131262306a36Sopenharmony_ci * @type in the $AttrDef system file. 131362306a36Sopenharmony_ci * 131462306a36Sopenharmony_ci * Return the attribute type definition record if found and NULL if not found. 131562306a36Sopenharmony_ci */ 131662306a36Sopenharmony_cistatic ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, 131762306a36Sopenharmony_ci const ATTR_TYPE type) 131862306a36Sopenharmony_ci{ 131962306a36Sopenharmony_ci ATTR_DEF *ad; 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci BUG_ON(!vol->attrdef); 132262306a36Sopenharmony_ci BUG_ON(!type); 132362306a36Sopenharmony_ci for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < 132462306a36Sopenharmony_ci vol->attrdef_size && ad->type; ++ad) { 132562306a36Sopenharmony_ci /* We have not found it yet, carry on searching. */ 132662306a36Sopenharmony_ci if (likely(le32_to_cpu(ad->type) < le32_to_cpu(type))) 132762306a36Sopenharmony_ci continue; 132862306a36Sopenharmony_ci /* We found the attribute; return it. */ 132962306a36Sopenharmony_ci if (likely(ad->type == type)) 133062306a36Sopenharmony_ci return ad; 133162306a36Sopenharmony_ci /* We have gone too far already. No point in continuing. */ 133262306a36Sopenharmony_ci break; 133362306a36Sopenharmony_ci } 133462306a36Sopenharmony_ci /* Attribute not found. */ 133562306a36Sopenharmony_ci ntfs_debug("Attribute type 0x%x not found in $AttrDef.", 133662306a36Sopenharmony_ci le32_to_cpu(type)); 133762306a36Sopenharmony_ci return NULL; 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci/** 134162306a36Sopenharmony_ci * ntfs_attr_size_bounds_check - check a size of an attribute type for validity 134262306a36Sopenharmony_ci * @vol: ntfs volume to which the attribute belongs 134362306a36Sopenharmony_ci * @type: attribute type which to check 134462306a36Sopenharmony_ci * @size: size which to check 134562306a36Sopenharmony_ci * 134662306a36Sopenharmony_ci * Check whether the @size in bytes is valid for an attribute of @type on the 134762306a36Sopenharmony_ci * ntfs volume @vol. This information is obtained from $AttrDef system file. 134862306a36Sopenharmony_ci * 134962306a36Sopenharmony_ci * Return 0 if valid, -ERANGE if not valid, or -ENOENT if the attribute is not 135062306a36Sopenharmony_ci * listed in $AttrDef. 135162306a36Sopenharmony_ci */ 135262306a36Sopenharmony_ciint ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPE type, 135362306a36Sopenharmony_ci const s64 size) 135462306a36Sopenharmony_ci{ 135562306a36Sopenharmony_ci ATTR_DEF *ad; 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci BUG_ON(size < 0); 135862306a36Sopenharmony_ci /* 135962306a36Sopenharmony_ci * $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not 136062306a36Sopenharmony_ci * listed in $AttrDef. 136162306a36Sopenharmony_ci */ 136262306a36Sopenharmony_ci if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024)) 136362306a36Sopenharmony_ci return -ERANGE; 136462306a36Sopenharmony_ci /* Get the $AttrDef entry for the attribute @type. */ 136562306a36Sopenharmony_ci ad = ntfs_attr_find_in_attrdef(vol, type); 136662306a36Sopenharmony_ci if (unlikely(!ad)) 136762306a36Sopenharmony_ci return -ENOENT; 136862306a36Sopenharmony_ci /* Do the bounds check. */ 136962306a36Sopenharmony_ci if (((sle64_to_cpu(ad->min_size) > 0) && 137062306a36Sopenharmony_ci size < sle64_to_cpu(ad->min_size)) || 137162306a36Sopenharmony_ci ((sle64_to_cpu(ad->max_size) > 0) && size > 137262306a36Sopenharmony_ci sle64_to_cpu(ad->max_size))) 137362306a36Sopenharmony_ci return -ERANGE; 137462306a36Sopenharmony_ci return 0; 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci/** 137862306a36Sopenharmony_ci * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident 137962306a36Sopenharmony_ci * @vol: ntfs volume to which the attribute belongs 138062306a36Sopenharmony_ci * @type: attribute type which to check 138162306a36Sopenharmony_ci * 138262306a36Sopenharmony_ci * Check whether the attribute of @type on the ntfs volume @vol is allowed to 138362306a36Sopenharmony_ci * be non-resident. This information is obtained from $AttrDef system file. 138462306a36Sopenharmony_ci * 138562306a36Sopenharmony_ci * Return 0 if the attribute is allowed to be non-resident, -EPERM if not, and 138662306a36Sopenharmony_ci * -ENOENT if the attribute is not listed in $AttrDef. 138762306a36Sopenharmony_ci */ 138862306a36Sopenharmony_ciint ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci ATTR_DEF *ad; 139162306a36Sopenharmony_ci 139262306a36Sopenharmony_ci /* Find the attribute definition record in $AttrDef. */ 139362306a36Sopenharmony_ci ad = ntfs_attr_find_in_attrdef(vol, type); 139462306a36Sopenharmony_ci if (unlikely(!ad)) 139562306a36Sopenharmony_ci return -ENOENT; 139662306a36Sopenharmony_ci /* Check the flags and return the result. */ 139762306a36Sopenharmony_ci if (ad->flags & ATTR_DEF_RESIDENT) 139862306a36Sopenharmony_ci return -EPERM; 139962306a36Sopenharmony_ci return 0; 140062306a36Sopenharmony_ci} 140162306a36Sopenharmony_ci 140262306a36Sopenharmony_ci/** 140362306a36Sopenharmony_ci * ntfs_attr_can_be_resident - check if an attribute can be resident 140462306a36Sopenharmony_ci * @vol: ntfs volume to which the attribute belongs 140562306a36Sopenharmony_ci * @type: attribute type which to check 140662306a36Sopenharmony_ci * 140762306a36Sopenharmony_ci * Check whether the attribute of @type on the ntfs volume @vol is allowed to 140862306a36Sopenharmony_ci * be resident. This information is derived from our ntfs knowledge and may 140962306a36Sopenharmony_ci * not be completely accurate, especially when user defined attributes are 141062306a36Sopenharmony_ci * present. Basically we allow everything to be resident except for index 141162306a36Sopenharmony_ci * allocation and $EA attributes. 141262306a36Sopenharmony_ci * 141362306a36Sopenharmony_ci * Return 0 if the attribute is allowed to be non-resident and -EPERM if not. 141462306a36Sopenharmony_ci * 141562306a36Sopenharmony_ci * Warning: In the system file $MFT the attribute $Bitmap must be non-resident 141662306a36Sopenharmony_ci * otherwise windows will not boot (blue screen of death)! We cannot 141762306a36Sopenharmony_ci * check for this here as we do not know which inode's $Bitmap is 141862306a36Sopenharmony_ci * being asked about so the caller needs to special case this. 141962306a36Sopenharmony_ci */ 142062306a36Sopenharmony_ciint ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type) 142162306a36Sopenharmony_ci{ 142262306a36Sopenharmony_ci if (type == AT_INDEX_ALLOCATION) 142362306a36Sopenharmony_ci return -EPERM; 142462306a36Sopenharmony_ci return 0; 142562306a36Sopenharmony_ci} 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci/** 142862306a36Sopenharmony_ci * ntfs_attr_record_resize - resize an attribute record 142962306a36Sopenharmony_ci * @m: mft record containing attribute record 143062306a36Sopenharmony_ci * @a: attribute record to resize 143162306a36Sopenharmony_ci * @new_size: new size in bytes to which to resize the attribute record @a 143262306a36Sopenharmony_ci * 143362306a36Sopenharmony_ci * Resize the attribute record @a, i.e. the resident part of the attribute, in 143462306a36Sopenharmony_ci * the mft record @m to @new_size bytes. 143562306a36Sopenharmony_ci * 143662306a36Sopenharmony_ci * Return 0 on success and -errno on error. The following error codes are 143762306a36Sopenharmony_ci * defined: 143862306a36Sopenharmony_ci * -ENOSPC - Not enough space in the mft record @m to perform the resize. 143962306a36Sopenharmony_ci * 144062306a36Sopenharmony_ci * Note: On error, no modifications have been performed whatsoever. 144162306a36Sopenharmony_ci * 144262306a36Sopenharmony_ci * Warning: If you make a record smaller without having copied all the data you 144362306a36Sopenharmony_ci * are interested in the data may be overwritten. 144462306a36Sopenharmony_ci */ 144562306a36Sopenharmony_ciint ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size) 144662306a36Sopenharmony_ci{ 144762306a36Sopenharmony_ci ntfs_debug("Entering for new_size %u.", new_size); 144862306a36Sopenharmony_ci /* Align to 8 bytes if it is not already done. */ 144962306a36Sopenharmony_ci if (new_size & 7) 145062306a36Sopenharmony_ci new_size = (new_size + 7) & ~7; 145162306a36Sopenharmony_ci /* If the actual attribute length has changed, move things around. */ 145262306a36Sopenharmony_ci if (new_size != le32_to_cpu(a->length)) { 145362306a36Sopenharmony_ci u32 new_muse = le32_to_cpu(m->bytes_in_use) - 145462306a36Sopenharmony_ci le32_to_cpu(a->length) + new_size; 145562306a36Sopenharmony_ci /* Not enough space in this mft record. */ 145662306a36Sopenharmony_ci if (new_muse > le32_to_cpu(m->bytes_allocated)) 145762306a36Sopenharmony_ci return -ENOSPC; 145862306a36Sopenharmony_ci /* Move attributes following @a to their new location. */ 145962306a36Sopenharmony_ci memmove((u8*)a + new_size, (u8*)a + le32_to_cpu(a->length), 146062306a36Sopenharmony_ci le32_to_cpu(m->bytes_in_use) - ((u8*)a - 146162306a36Sopenharmony_ci (u8*)m) - le32_to_cpu(a->length)); 146262306a36Sopenharmony_ci /* Adjust @m to reflect the change in used space. */ 146362306a36Sopenharmony_ci m->bytes_in_use = cpu_to_le32(new_muse); 146462306a36Sopenharmony_ci /* Adjust @a to reflect the new size. */ 146562306a36Sopenharmony_ci if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length)) 146662306a36Sopenharmony_ci a->length = cpu_to_le32(new_size); 146762306a36Sopenharmony_ci } 146862306a36Sopenharmony_ci return 0; 146962306a36Sopenharmony_ci} 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci/** 147262306a36Sopenharmony_ci * ntfs_resident_attr_value_resize - resize the value of a resident attribute 147362306a36Sopenharmony_ci * @m: mft record containing attribute record 147462306a36Sopenharmony_ci * @a: attribute record whose value to resize 147562306a36Sopenharmony_ci * @new_size: new size in bytes to which to resize the attribute value of @a 147662306a36Sopenharmony_ci * 147762306a36Sopenharmony_ci * Resize the value of the attribute @a in the mft record @m to @new_size bytes. 147862306a36Sopenharmony_ci * If the value is made bigger, the newly allocated space is cleared. 147962306a36Sopenharmony_ci * 148062306a36Sopenharmony_ci * Return 0 on success and -errno on error. The following error codes are 148162306a36Sopenharmony_ci * defined: 148262306a36Sopenharmony_ci * -ENOSPC - Not enough space in the mft record @m to perform the resize. 148362306a36Sopenharmony_ci * 148462306a36Sopenharmony_ci * Note: On error, no modifications have been performed whatsoever. 148562306a36Sopenharmony_ci * 148662306a36Sopenharmony_ci * Warning: If you make a record smaller without having copied all the data you 148762306a36Sopenharmony_ci * are interested in the data may be overwritten. 148862306a36Sopenharmony_ci */ 148962306a36Sopenharmony_ciint ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, 149062306a36Sopenharmony_ci const u32 new_size) 149162306a36Sopenharmony_ci{ 149262306a36Sopenharmony_ci u32 old_size; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci /* Resize the resident part of the attribute record. */ 149562306a36Sopenharmony_ci if (ntfs_attr_record_resize(m, a, 149662306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset) + new_size)) 149762306a36Sopenharmony_ci return -ENOSPC; 149862306a36Sopenharmony_ci /* 149962306a36Sopenharmony_ci * The resize succeeded! If we made the attribute value bigger, clear 150062306a36Sopenharmony_ci * the area between the old size and @new_size. 150162306a36Sopenharmony_ci */ 150262306a36Sopenharmony_ci old_size = le32_to_cpu(a->data.resident.value_length); 150362306a36Sopenharmony_ci if (new_size > old_size) 150462306a36Sopenharmony_ci memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) + 150562306a36Sopenharmony_ci old_size, 0, new_size - old_size); 150662306a36Sopenharmony_ci /* Finally update the length of the attribute value. */ 150762306a36Sopenharmony_ci a->data.resident.value_length = cpu_to_le32(new_size); 150862306a36Sopenharmony_ci return 0; 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci/** 151262306a36Sopenharmony_ci * ntfs_attr_make_non_resident - convert a resident to a non-resident attribute 151362306a36Sopenharmony_ci * @ni: ntfs inode describing the attribute to convert 151462306a36Sopenharmony_ci * @data_size: size of the resident data to copy to the non-resident attribute 151562306a36Sopenharmony_ci * 151662306a36Sopenharmony_ci * Convert the resident ntfs attribute described by the ntfs inode @ni to a 151762306a36Sopenharmony_ci * non-resident one. 151862306a36Sopenharmony_ci * 151962306a36Sopenharmony_ci * @data_size must be equal to the attribute value size. This is needed since 152062306a36Sopenharmony_ci * we need to know the size before we can map the mft record and our callers 152162306a36Sopenharmony_ci * always know it. The reason we cannot simply read the size from the vfs 152262306a36Sopenharmony_ci * inode i_size is that this is not necessarily uptodate. This happens when 152362306a36Sopenharmony_ci * ntfs_attr_make_non_resident() is called in the ->truncate call path(s). 152462306a36Sopenharmony_ci * 152562306a36Sopenharmony_ci * Return 0 on success and -errno on error. The following error return codes 152662306a36Sopenharmony_ci * are defined: 152762306a36Sopenharmony_ci * -EPERM - The attribute is not allowed to be non-resident. 152862306a36Sopenharmony_ci * -ENOMEM - Not enough memory. 152962306a36Sopenharmony_ci * -ENOSPC - Not enough disk space. 153062306a36Sopenharmony_ci * -EINVAL - Attribute not defined on the volume. 153162306a36Sopenharmony_ci * -EIO - I/o error or other error. 153262306a36Sopenharmony_ci * Note that -ENOSPC is also returned in the case that there is not enough 153362306a36Sopenharmony_ci * space in the mft record to do the conversion. This can happen when the mft 153462306a36Sopenharmony_ci * record is already very full. The caller is responsible for trying to make 153562306a36Sopenharmony_ci * space in the mft record and trying again. FIXME: Do we need a separate 153662306a36Sopenharmony_ci * error return code for this kind of -ENOSPC or is it always worth trying 153762306a36Sopenharmony_ci * again in case the attribute may then fit in a resident state so no need to 153862306a36Sopenharmony_ci * make it non-resident at all? Ho-hum... (AIA) 153962306a36Sopenharmony_ci * 154062306a36Sopenharmony_ci * NOTE to self: No changes in the attribute list are required to move from 154162306a36Sopenharmony_ci * a resident to a non-resident attribute. 154262306a36Sopenharmony_ci * 154362306a36Sopenharmony_ci * Locking: - The caller must hold i_mutex on the inode. 154462306a36Sopenharmony_ci */ 154562306a36Sopenharmony_ciint ntfs_attr_make_non_resident(ntfs_inode *ni, const u32 data_size) 154662306a36Sopenharmony_ci{ 154762306a36Sopenharmony_ci s64 new_size; 154862306a36Sopenharmony_ci struct inode *vi = VFS_I(ni); 154962306a36Sopenharmony_ci ntfs_volume *vol = ni->vol; 155062306a36Sopenharmony_ci ntfs_inode *base_ni; 155162306a36Sopenharmony_ci MFT_RECORD *m; 155262306a36Sopenharmony_ci ATTR_RECORD *a; 155362306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 155462306a36Sopenharmony_ci struct page *page; 155562306a36Sopenharmony_ci runlist_element *rl; 155662306a36Sopenharmony_ci u8 *kaddr; 155762306a36Sopenharmony_ci unsigned long flags; 155862306a36Sopenharmony_ci int mp_size, mp_ofs, name_ofs, arec_size, err, err2; 155962306a36Sopenharmony_ci u32 attr_size; 156062306a36Sopenharmony_ci u8 old_res_attr_flags; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci /* Check that the attribute is allowed to be non-resident. */ 156362306a36Sopenharmony_ci err = ntfs_attr_can_be_non_resident(vol, ni->type); 156462306a36Sopenharmony_ci if (unlikely(err)) { 156562306a36Sopenharmony_ci if (err == -EPERM) 156662306a36Sopenharmony_ci ntfs_debug("Attribute is not allowed to be " 156762306a36Sopenharmony_ci "non-resident."); 156862306a36Sopenharmony_ci else 156962306a36Sopenharmony_ci ntfs_debug("Attribute not defined on the NTFS " 157062306a36Sopenharmony_ci "volume!"); 157162306a36Sopenharmony_ci return err; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci /* 157462306a36Sopenharmony_ci * FIXME: Compressed and encrypted attributes are not supported when 157562306a36Sopenharmony_ci * writing and we should never have gotten here for them. 157662306a36Sopenharmony_ci */ 157762306a36Sopenharmony_ci BUG_ON(NInoCompressed(ni)); 157862306a36Sopenharmony_ci BUG_ON(NInoEncrypted(ni)); 157962306a36Sopenharmony_ci /* 158062306a36Sopenharmony_ci * The size needs to be aligned to a cluster boundary for allocation 158162306a36Sopenharmony_ci * purposes. 158262306a36Sopenharmony_ci */ 158362306a36Sopenharmony_ci new_size = (data_size + vol->cluster_size - 1) & 158462306a36Sopenharmony_ci ~(vol->cluster_size - 1); 158562306a36Sopenharmony_ci if (new_size > 0) { 158662306a36Sopenharmony_ci /* 158762306a36Sopenharmony_ci * Will need the page later and since the page lock nests 158862306a36Sopenharmony_ci * outside all ntfs locks, we need to get the page now. 158962306a36Sopenharmony_ci */ 159062306a36Sopenharmony_ci page = find_or_create_page(vi->i_mapping, 0, 159162306a36Sopenharmony_ci mapping_gfp_mask(vi->i_mapping)); 159262306a36Sopenharmony_ci if (unlikely(!page)) 159362306a36Sopenharmony_ci return -ENOMEM; 159462306a36Sopenharmony_ci /* Start by allocating clusters to hold the attribute value. */ 159562306a36Sopenharmony_ci rl = ntfs_cluster_alloc(vol, 0, new_size >> 159662306a36Sopenharmony_ci vol->cluster_size_bits, -1, DATA_ZONE, true); 159762306a36Sopenharmony_ci if (IS_ERR(rl)) { 159862306a36Sopenharmony_ci err = PTR_ERR(rl); 159962306a36Sopenharmony_ci ntfs_debug("Failed to allocate cluster%s, error code " 160062306a36Sopenharmony_ci "%i.", (new_size >> 160162306a36Sopenharmony_ci vol->cluster_size_bits) > 1 ? "s" : "", 160262306a36Sopenharmony_ci err); 160362306a36Sopenharmony_ci goto page_err_out; 160462306a36Sopenharmony_ci } 160562306a36Sopenharmony_ci } else { 160662306a36Sopenharmony_ci rl = NULL; 160762306a36Sopenharmony_ci page = NULL; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci /* Determine the size of the mapping pairs array. */ 161062306a36Sopenharmony_ci mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, -1); 161162306a36Sopenharmony_ci if (unlikely(mp_size < 0)) { 161262306a36Sopenharmony_ci err = mp_size; 161362306a36Sopenharmony_ci ntfs_debug("Failed to get size for mapping pairs array, error " 161462306a36Sopenharmony_ci "code %i.", err); 161562306a36Sopenharmony_ci goto rl_err_out; 161662306a36Sopenharmony_ci } 161762306a36Sopenharmony_ci down_write(&ni->runlist.lock); 161862306a36Sopenharmony_ci if (!NInoAttr(ni)) 161962306a36Sopenharmony_ci base_ni = ni; 162062306a36Sopenharmony_ci else 162162306a36Sopenharmony_ci base_ni = ni->ext.base_ntfs_ino; 162262306a36Sopenharmony_ci m = map_mft_record(base_ni); 162362306a36Sopenharmony_ci if (IS_ERR(m)) { 162462306a36Sopenharmony_ci err = PTR_ERR(m); 162562306a36Sopenharmony_ci m = NULL; 162662306a36Sopenharmony_ci ctx = NULL; 162762306a36Sopenharmony_ci goto err_out; 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(base_ni, m); 163062306a36Sopenharmony_ci if (unlikely(!ctx)) { 163162306a36Sopenharmony_ci err = -ENOMEM; 163262306a36Sopenharmony_ci goto err_out; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 163562306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 163662306a36Sopenharmony_ci if (unlikely(err)) { 163762306a36Sopenharmony_ci if (err == -ENOENT) 163862306a36Sopenharmony_ci err = -EIO; 163962306a36Sopenharmony_ci goto err_out; 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci m = ctx->mrec; 164262306a36Sopenharmony_ci a = ctx->attr; 164362306a36Sopenharmony_ci BUG_ON(NInoNonResident(ni)); 164462306a36Sopenharmony_ci BUG_ON(a->non_resident); 164562306a36Sopenharmony_ci /* 164662306a36Sopenharmony_ci * Calculate new offsets for the name and the mapping pairs array. 164762306a36Sopenharmony_ci */ 164862306a36Sopenharmony_ci if (NInoSparse(ni) || NInoCompressed(ni)) 164962306a36Sopenharmony_ci name_ofs = (offsetof(ATTR_REC, 165062306a36Sopenharmony_ci data.non_resident.compressed_size) + 165162306a36Sopenharmony_ci sizeof(a->data.non_resident.compressed_size) + 165262306a36Sopenharmony_ci 7) & ~7; 165362306a36Sopenharmony_ci else 165462306a36Sopenharmony_ci name_ofs = (offsetof(ATTR_REC, 165562306a36Sopenharmony_ci data.non_resident.compressed_size) + 7) & ~7; 165662306a36Sopenharmony_ci mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; 165762306a36Sopenharmony_ci /* 165862306a36Sopenharmony_ci * Determine the size of the resident part of the now non-resident 165962306a36Sopenharmony_ci * attribute record. 166062306a36Sopenharmony_ci */ 166162306a36Sopenharmony_ci arec_size = (mp_ofs + mp_size + 7) & ~7; 166262306a36Sopenharmony_ci /* 166362306a36Sopenharmony_ci * If the page is not uptodate bring it uptodate by copying from the 166462306a36Sopenharmony_ci * attribute value. 166562306a36Sopenharmony_ci */ 166662306a36Sopenharmony_ci attr_size = le32_to_cpu(a->data.resident.value_length); 166762306a36Sopenharmony_ci BUG_ON(attr_size != data_size); 166862306a36Sopenharmony_ci if (page && !PageUptodate(page)) { 166962306a36Sopenharmony_ci kaddr = kmap_atomic(page); 167062306a36Sopenharmony_ci memcpy(kaddr, (u8*)a + 167162306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset), 167262306a36Sopenharmony_ci attr_size); 167362306a36Sopenharmony_ci memset(kaddr + attr_size, 0, PAGE_SIZE - attr_size); 167462306a36Sopenharmony_ci kunmap_atomic(kaddr); 167562306a36Sopenharmony_ci flush_dcache_page(page); 167662306a36Sopenharmony_ci SetPageUptodate(page); 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci /* Backup the attribute flag. */ 167962306a36Sopenharmony_ci old_res_attr_flags = a->data.resident.flags; 168062306a36Sopenharmony_ci /* Resize the resident part of the attribute record. */ 168162306a36Sopenharmony_ci err = ntfs_attr_record_resize(m, a, arec_size); 168262306a36Sopenharmony_ci if (unlikely(err)) 168362306a36Sopenharmony_ci goto err_out; 168462306a36Sopenharmony_ci /* 168562306a36Sopenharmony_ci * Convert the resident part of the attribute record to describe a 168662306a36Sopenharmony_ci * non-resident attribute. 168762306a36Sopenharmony_ci */ 168862306a36Sopenharmony_ci a->non_resident = 1; 168962306a36Sopenharmony_ci /* Move the attribute name if it exists and update the offset. */ 169062306a36Sopenharmony_ci if (a->name_length) 169162306a36Sopenharmony_ci memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), 169262306a36Sopenharmony_ci a->name_length * sizeof(ntfschar)); 169362306a36Sopenharmony_ci a->name_offset = cpu_to_le16(name_ofs); 169462306a36Sopenharmony_ci /* Setup the fields specific to non-resident attributes. */ 169562306a36Sopenharmony_ci a->data.non_resident.lowest_vcn = 0; 169662306a36Sopenharmony_ci a->data.non_resident.highest_vcn = cpu_to_sle64((new_size - 1) >> 169762306a36Sopenharmony_ci vol->cluster_size_bits); 169862306a36Sopenharmony_ci a->data.non_resident.mapping_pairs_offset = cpu_to_le16(mp_ofs); 169962306a36Sopenharmony_ci memset(&a->data.non_resident.reserved, 0, 170062306a36Sopenharmony_ci sizeof(a->data.non_resident.reserved)); 170162306a36Sopenharmony_ci a->data.non_resident.allocated_size = cpu_to_sle64(new_size); 170262306a36Sopenharmony_ci a->data.non_resident.data_size = 170362306a36Sopenharmony_ci a->data.non_resident.initialized_size = 170462306a36Sopenharmony_ci cpu_to_sle64(attr_size); 170562306a36Sopenharmony_ci if (NInoSparse(ni) || NInoCompressed(ni)) { 170662306a36Sopenharmony_ci a->data.non_resident.compression_unit = 0; 170762306a36Sopenharmony_ci if (NInoCompressed(ni) || vol->major_ver < 3) 170862306a36Sopenharmony_ci a->data.non_resident.compression_unit = 4; 170962306a36Sopenharmony_ci a->data.non_resident.compressed_size = 171062306a36Sopenharmony_ci a->data.non_resident.allocated_size; 171162306a36Sopenharmony_ci } else 171262306a36Sopenharmony_ci a->data.non_resident.compression_unit = 0; 171362306a36Sopenharmony_ci /* Generate the mapping pairs array into the attribute record. */ 171462306a36Sopenharmony_ci err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs, 171562306a36Sopenharmony_ci arec_size - mp_ofs, rl, 0, -1, NULL); 171662306a36Sopenharmony_ci if (unlikely(err)) { 171762306a36Sopenharmony_ci ntfs_debug("Failed to build mapping pairs, error code %i.", 171862306a36Sopenharmony_ci err); 171962306a36Sopenharmony_ci goto undo_err_out; 172062306a36Sopenharmony_ci } 172162306a36Sopenharmony_ci /* Setup the in-memory attribute structure to be non-resident. */ 172262306a36Sopenharmony_ci ni->runlist.rl = rl; 172362306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 172462306a36Sopenharmony_ci ni->allocated_size = new_size; 172562306a36Sopenharmony_ci if (NInoSparse(ni) || NInoCompressed(ni)) { 172662306a36Sopenharmony_ci ni->itype.compressed.size = ni->allocated_size; 172762306a36Sopenharmony_ci if (a->data.non_resident.compression_unit) { 172862306a36Sopenharmony_ci ni->itype.compressed.block_size = 1U << (a->data. 172962306a36Sopenharmony_ci non_resident.compression_unit + 173062306a36Sopenharmony_ci vol->cluster_size_bits); 173162306a36Sopenharmony_ci ni->itype.compressed.block_size_bits = 173262306a36Sopenharmony_ci ffs(ni->itype.compressed.block_size) - 173362306a36Sopenharmony_ci 1; 173462306a36Sopenharmony_ci ni->itype.compressed.block_clusters = 1U << 173562306a36Sopenharmony_ci a->data.non_resident.compression_unit; 173662306a36Sopenharmony_ci } else { 173762306a36Sopenharmony_ci ni->itype.compressed.block_size = 0; 173862306a36Sopenharmony_ci ni->itype.compressed.block_size_bits = 0; 173962306a36Sopenharmony_ci ni->itype.compressed.block_clusters = 0; 174062306a36Sopenharmony_ci } 174162306a36Sopenharmony_ci vi->i_blocks = ni->itype.compressed.size >> 9; 174262306a36Sopenharmony_ci } else 174362306a36Sopenharmony_ci vi->i_blocks = ni->allocated_size >> 9; 174462306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 174562306a36Sopenharmony_ci /* 174662306a36Sopenharmony_ci * This needs to be last since the address space operations ->read_folio 174762306a36Sopenharmony_ci * and ->writepage can run concurrently with us as they are not 174862306a36Sopenharmony_ci * serialized on i_mutex. Note, we are not allowed to fail once we flip 174962306a36Sopenharmony_ci * this switch, which is another reason to do this last. 175062306a36Sopenharmony_ci */ 175162306a36Sopenharmony_ci NInoSetNonResident(ni); 175262306a36Sopenharmony_ci /* Mark the mft record dirty, so it gets written back. */ 175362306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 175462306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 175562306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 175662306a36Sopenharmony_ci unmap_mft_record(base_ni); 175762306a36Sopenharmony_ci up_write(&ni->runlist.lock); 175862306a36Sopenharmony_ci if (page) { 175962306a36Sopenharmony_ci set_page_dirty(page); 176062306a36Sopenharmony_ci unlock_page(page); 176162306a36Sopenharmony_ci put_page(page); 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci ntfs_debug("Done."); 176462306a36Sopenharmony_ci return 0; 176562306a36Sopenharmony_ciundo_err_out: 176662306a36Sopenharmony_ci /* Convert the attribute back into a resident attribute. */ 176762306a36Sopenharmony_ci a->non_resident = 0; 176862306a36Sopenharmony_ci /* Move the attribute name if it exists and update the offset. */ 176962306a36Sopenharmony_ci name_ofs = (offsetof(ATTR_RECORD, data.resident.reserved) + 177062306a36Sopenharmony_ci sizeof(a->data.resident.reserved) + 7) & ~7; 177162306a36Sopenharmony_ci if (a->name_length) 177262306a36Sopenharmony_ci memmove((u8*)a + name_ofs, (u8*)a + le16_to_cpu(a->name_offset), 177362306a36Sopenharmony_ci a->name_length * sizeof(ntfschar)); 177462306a36Sopenharmony_ci mp_ofs = (name_ofs + a->name_length * sizeof(ntfschar) + 7) & ~7; 177562306a36Sopenharmony_ci a->name_offset = cpu_to_le16(name_ofs); 177662306a36Sopenharmony_ci arec_size = (mp_ofs + attr_size + 7) & ~7; 177762306a36Sopenharmony_ci /* Resize the resident part of the attribute record. */ 177862306a36Sopenharmony_ci err2 = ntfs_attr_record_resize(m, a, arec_size); 177962306a36Sopenharmony_ci if (unlikely(err2)) { 178062306a36Sopenharmony_ci /* 178162306a36Sopenharmony_ci * This cannot happen (well if memory corruption is at work it 178262306a36Sopenharmony_ci * could happen in theory), but deal with it as well as we can. 178362306a36Sopenharmony_ci * If the old size is too small, truncate the attribute, 178462306a36Sopenharmony_ci * otherwise simply give it a larger allocated size. 178562306a36Sopenharmony_ci * FIXME: Should check whether chkdsk complains when the 178662306a36Sopenharmony_ci * allocated size is much bigger than the resident value size. 178762306a36Sopenharmony_ci */ 178862306a36Sopenharmony_ci arec_size = le32_to_cpu(a->length); 178962306a36Sopenharmony_ci if ((mp_ofs + attr_size) > arec_size) { 179062306a36Sopenharmony_ci err2 = attr_size; 179162306a36Sopenharmony_ci attr_size = arec_size - mp_ofs; 179262306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to undo partial resident " 179362306a36Sopenharmony_ci "to non-resident attribute " 179462306a36Sopenharmony_ci "conversion. Truncating inode 0x%lx, " 179562306a36Sopenharmony_ci "attribute type 0x%x from %i bytes to " 179662306a36Sopenharmony_ci "%i bytes to maintain metadata " 179762306a36Sopenharmony_ci "consistency. THIS MEANS YOU ARE " 179862306a36Sopenharmony_ci "LOSING %i BYTES DATA FROM THIS %s.", 179962306a36Sopenharmony_ci vi->i_ino, 180062306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), 180162306a36Sopenharmony_ci err2, attr_size, err2 - attr_size, 180262306a36Sopenharmony_ci ((ni->type == AT_DATA) && 180362306a36Sopenharmony_ci !ni->name_len) ? "FILE": "ATTRIBUTE"); 180462306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 180562306a36Sopenharmony_ci ni->initialized_size = attr_size; 180662306a36Sopenharmony_ci i_size_write(vi, attr_size); 180762306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci } 181062306a36Sopenharmony_ci /* Setup the fields specific to resident attributes. */ 181162306a36Sopenharmony_ci a->data.resident.value_length = cpu_to_le32(attr_size); 181262306a36Sopenharmony_ci a->data.resident.value_offset = cpu_to_le16(mp_ofs); 181362306a36Sopenharmony_ci a->data.resident.flags = old_res_attr_flags; 181462306a36Sopenharmony_ci memset(&a->data.resident.reserved, 0, 181562306a36Sopenharmony_ci sizeof(a->data.resident.reserved)); 181662306a36Sopenharmony_ci /* Copy the data from the page back to the attribute value. */ 181762306a36Sopenharmony_ci if (page) { 181862306a36Sopenharmony_ci kaddr = kmap_atomic(page); 181962306a36Sopenharmony_ci memcpy((u8*)a + mp_ofs, kaddr, attr_size); 182062306a36Sopenharmony_ci kunmap_atomic(kaddr); 182162306a36Sopenharmony_ci } 182262306a36Sopenharmony_ci /* Setup the allocated size in the ntfs inode in case it changed. */ 182362306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 182462306a36Sopenharmony_ci ni->allocated_size = arec_size - mp_ofs; 182562306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 182662306a36Sopenharmony_ci /* Mark the mft record dirty, so it gets written back. */ 182762306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 182862306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 182962306a36Sopenharmony_cierr_out: 183062306a36Sopenharmony_ci if (ctx) 183162306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 183262306a36Sopenharmony_ci if (m) 183362306a36Sopenharmony_ci unmap_mft_record(base_ni); 183462306a36Sopenharmony_ci ni->runlist.rl = NULL; 183562306a36Sopenharmony_ci up_write(&ni->runlist.lock); 183662306a36Sopenharmony_cirl_err_out: 183762306a36Sopenharmony_ci if (rl) { 183862306a36Sopenharmony_ci if (ntfs_cluster_free_from_rl(vol, rl) < 0) { 183962306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to release allocated " 184062306a36Sopenharmony_ci "cluster(s) in error code path. Run " 184162306a36Sopenharmony_ci "chkdsk to recover the lost " 184262306a36Sopenharmony_ci "cluster(s)."); 184362306a36Sopenharmony_ci NVolSetErrors(vol); 184462306a36Sopenharmony_ci } 184562306a36Sopenharmony_ci ntfs_free(rl); 184662306a36Sopenharmony_cipage_err_out: 184762306a36Sopenharmony_ci unlock_page(page); 184862306a36Sopenharmony_ci put_page(page); 184962306a36Sopenharmony_ci } 185062306a36Sopenharmony_ci if (err == -EINVAL) 185162306a36Sopenharmony_ci err = -EIO; 185262306a36Sopenharmony_ci return err; 185362306a36Sopenharmony_ci} 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_ci/** 185662306a36Sopenharmony_ci * ntfs_attr_extend_allocation - extend the allocated space of an attribute 185762306a36Sopenharmony_ci * @ni: ntfs inode of the attribute whose allocation to extend 185862306a36Sopenharmony_ci * @new_alloc_size: new size in bytes to which to extend the allocation to 185962306a36Sopenharmony_ci * @new_data_size: new size in bytes to which to extend the data to 186062306a36Sopenharmony_ci * @data_start: beginning of region which is required to be non-sparse 186162306a36Sopenharmony_ci * 186262306a36Sopenharmony_ci * Extend the allocated space of an attribute described by the ntfs inode @ni 186362306a36Sopenharmony_ci * to @new_alloc_size bytes. If @data_start is -1, the whole extension may be 186462306a36Sopenharmony_ci * implemented as a hole in the file (as long as both the volume and the ntfs 186562306a36Sopenharmony_ci * inode @ni have sparse support enabled). If @data_start is >= 0, then the 186662306a36Sopenharmony_ci * region between the old allocated size and @data_start - 1 may be made sparse 186762306a36Sopenharmony_ci * but the regions between @data_start and @new_alloc_size must be backed by 186862306a36Sopenharmony_ci * actual clusters. 186962306a36Sopenharmony_ci * 187062306a36Sopenharmony_ci * If @new_data_size is -1, it is ignored. If it is >= 0, then the data size 187162306a36Sopenharmony_ci * of the attribute is extended to @new_data_size. Note that the i_size of the 187262306a36Sopenharmony_ci * vfs inode is not updated. Only the data size in the base attribute record 187362306a36Sopenharmony_ci * is updated. The caller has to update i_size separately if this is required. 187462306a36Sopenharmony_ci * WARNING: It is a BUG() for @new_data_size to be smaller than the old data 187562306a36Sopenharmony_ci * size as well as for @new_data_size to be greater than @new_alloc_size. 187662306a36Sopenharmony_ci * 187762306a36Sopenharmony_ci * For resident attributes this involves resizing the attribute record and if 187862306a36Sopenharmony_ci * necessary moving it and/or other attributes into extent mft records and/or 187962306a36Sopenharmony_ci * converting the attribute to a non-resident attribute which in turn involves 188062306a36Sopenharmony_ci * extending the allocation of a non-resident attribute as described below. 188162306a36Sopenharmony_ci * 188262306a36Sopenharmony_ci * For non-resident attributes this involves allocating clusters in the data 188362306a36Sopenharmony_ci * zone on the volume (except for regions that are being made sparse) and 188462306a36Sopenharmony_ci * extending the run list to describe the allocated clusters as well as 188562306a36Sopenharmony_ci * updating the mapping pairs array of the attribute. This in turn involves 188662306a36Sopenharmony_ci * resizing the attribute record and if necessary moving it and/or other 188762306a36Sopenharmony_ci * attributes into extent mft records and/or splitting the attribute record 188862306a36Sopenharmony_ci * into multiple extent attribute records. 188962306a36Sopenharmony_ci * 189062306a36Sopenharmony_ci * Also, the attribute list attribute is updated if present and in some of the 189162306a36Sopenharmony_ci * above cases (the ones where extent mft records/attributes come into play), 189262306a36Sopenharmony_ci * an attribute list attribute is created if not already present. 189362306a36Sopenharmony_ci * 189462306a36Sopenharmony_ci * Return the new allocated size on success and -errno on error. In the case 189562306a36Sopenharmony_ci * that an error is encountered but a partial extension at least up to 189662306a36Sopenharmony_ci * @data_start (if present) is possible, the allocation is partially extended 189762306a36Sopenharmony_ci * and this is returned. This means the caller must check the returned size to 189862306a36Sopenharmony_ci * determine if the extension was partial. If @data_start is -1 then partial 189962306a36Sopenharmony_ci * allocations are not performed. 190062306a36Sopenharmony_ci * 190162306a36Sopenharmony_ci * WARNING: Do not call ntfs_attr_extend_allocation() for $MFT/$DATA. 190262306a36Sopenharmony_ci * 190362306a36Sopenharmony_ci * Locking: This function takes the runlist lock of @ni for writing as well as 190462306a36Sopenharmony_ci * locking the mft record of the base ntfs inode. These locks are maintained 190562306a36Sopenharmony_ci * throughout execution of the function. These locks are required so that the 190662306a36Sopenharmony_ci * attribute can be resized safely and so that it can for example be converted 190762306a36Sopenharmony_ci * from resident to non-resident safely. 190862306a36Sopenharmony_ci * 190962306a36Sopenharmony_ci * TODO: At present attribute list attribute handling is not implemented. 191062306a36Sopenharmony_ci * 191162306a36Sopenharmony_ci * TODO: At present it is not safe to call this function for anything other 191262306a36Sopenharmony_ci * than the $DATA attribute(s) of an uncompressed and unencrypted file. 191362306a36Sopenharmony_ci */ 191462306a36Sopenharmony_cis64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, 191562306a36Sopenharmony_ci const s64 new_data_size, const s64 data_start) 191662306a36Sopenharmony_ci{ 191762306a36Sopenharmony_ci VCN vcn; 191862306a36Sopenharmony_ci s64 ll, allocated_size, start = data_start; 191962306a36Sopenharmony_ci struct inode *vi = VFS_I(ni); 192062306a36Sopenharmony_ci ntfs_volume *vol = ni->vol; 192162306a36Sopenharmony_ci ntfs_inode *base_ni; 192262306a36Sopenharmony_ci MFT_RECORD *m; 192362306a36Sopenharmony_ci ATTR_RECORD *a; 192462306a36Sopenharmony_ci ntfs_attr_search_ctx *ctx; 192562306a36Sopenharmony_ci runlist_element *rl, *rl2; 192662306a36Sopenharmony_ci unsigned long flags; 192762306a36Sopenharmony_ci int err, mp_size; 192862306a36Sopenharmony_ci u32 attr_len = 0; /* Silence stupid gcc warning. */ 192962306a36Sopenharmony_ci bool mp_rebuilt; 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_ci#ifdef DEBUG 193262306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 193362306a36Sopenharmony_ci allocated_size = ni->allocated_size; 193462306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 193562306a36Sopenharmony_ci ntfs_debug("Entering for i_ino 0x%lx, attribute type 0x%x, " 193662306a36Sopenharmony_ci "old_allocated_size 0x%llx, " 193762306a36Sopenharmony_ci "new_allocated_size 0x%llx, new_data_size 0x%llx, " 193862306a36Sopenharmony_ci "data_start 0x%llx.", vi->i_ino, 193962306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), 194062306a36Sopenharmony_ci (unsigned long long)allocated_size, 194162306a36Sopenharmony_ci (unsigned long long)new_alloc_size, 194262306a36Sopenharmony_ci (unsigned long long)new_data_size, 194362306a36Sopenharmony_ci (unsigned long long)start); 194462306a36Sopenharmony_ci#endif 194562306a36Sopenharmony_ciretry_extend: 194662306a36Sopenharmony_ci /* 194762306a36Sopenharmony_ci * For non-resident attributes, @start and @new_size need to be aligned 194862306a36Sopenharmony_ci * to cluster boundaries for allocation purposes. 194962306a36Sopenharmony_ci */ 195062306a36Sopenharmony_ci if (NInoNonResident(ni)) { 195162306a36Sopenharmony_ci if (start > 0) 195262306a36Sopenharmony_ci start &= ~(s64)vol->cluster_size_mask; 195362306a36Sopenharmony_ci new_alloc_size = (new_alloc_size + vol->cluster_size - 1) & 195462306a36Sopenharmony_ci ~(s64)vol->cluster_size_mask; 195562306a36Sopenharmony_ci } 195662306a36Sopenharmony_ci BUG_ON(new_data_size >= 0 && new_data_size > new_alloc_size); 195762306a36Sopenharmony_ci /* Check if new size is allowed in $AttrDef. */ 195862306a36Sopenharmony_ci err = ntfs_attr_size_bounds_check(vol, ni->type, new_alloc_size); 195962306a36Sopenharmony_ci if (unlikely(err)) { 196062306a36Sopenharmony_ci /* Only emit errors when the write will fail completely. */ 196162306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 196262306a36Sopenharmony_ci allocated_size = ni->allocated_size; 196362306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 196462306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) { 196562306a36Sopenharmony_ci if (err == -ERANGE) { 196662306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation " 196762306a36Sopenharmony_ci "of inode 0x%lx, attribute " 196862306a36Sopenharmony_ci "type 0x%x, because the new " 196962306a36Sopenharmony_ci "allocation would exceed the " 197062306a36Sopenharmony_ci "maximum allowed size for " 197162306a36Sopenharmony_ci "this attribute type.", 197262306a36Sopenharmony_ci vi->i_ino, (unsigned) 197362306a36Sopenharmony_ci le32_to_cpu(ni->type)); 197462306a36Sopenharmony_ci } else { 197562306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation " 197662306a36Sopenharmony_ci "of inode 0x%lx, attribute " 197762306a36Sopenharmony_ci "type 0x%x, because this " 197862306a36Sopenharmony_ci "attribute type is not " 197962306a36Sopenharmony_ci "defined on the NTFS volume. " 198062306a36Sopenharmony_ci "Possible corruption! You " 198162306a36Sopenharmony_ci "should run chkdsk!", 198262306a36Sopenharmony_ci vi->i_ino, (unsigned) 198362306a36Sopenharmony_ci le32_to_cpu(ni->type)); 198462306a36Sopenharmony_ci } 198562306a36Sopenharmony_ci } 198662306a36Sopenharmony_ci /* Translate error code to be POSIX conformant for write(2). */ 198762306a36Sopenharmony_ci if (err == -ERANGE) 198862306a36Sopenharmony_ci err = -EFBIG; 198962306a36Sopenharmony_ci else 199062306a36Sopenharmony_ci err = -EIO; 199162306a36Sopenharmony_ci return err; 199262306a36Sopenharmony_ci } 199362306a36Sopenharmony_ci if (!NInoAttr(ni)) 199462306a36Sopenharmony_ci base_ni = ni; 199562306a36Sopenharmony_ci else 199662306a36Sopenharmony_ci base_ni = ni->ext.base_ntfs_ino; 199762306a36Sopenharmony_ci /* 199862306a36Sopenharmony_ci * We will be modifying both the runlist (if non-resident) and the mft 199962306a36Sopenharmony_ci * record so lock them both down. 200062306a36Sopenharmony_ci */ 200162306a36Sopenharmony_ci down_write(&ni->runlist.lock); 200262306a36Sopenharmony_ci m = map_mft_record(base_ni); 200362306a36Sopenharmony_ci if (IS_ERR(m)) { 200462306a36Sopenharmony_ci err = PTR_ERR(m); 200562306a36Sopenharmony_ci m = NULL; 200662306a36Sopenharmony_ci ctx = NULL; 200762306a36Sopenharmony_ci goto err_out; 200862306a36Sopenharmony_ci } 200962306a36Sopenharmony_ci ctx = ntfs_attr_get_search_ctx(base_ni, m); 201062306a36Sopenharmony_ci if (unlikely(!ctx)) { 201162306a36Sopenharmony_ci err = -ENOMEM; 201262306a36Sopenharmony_ci goto err_out; 201362306a36Sopenharmony_ci } 201462306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 201562306a36Sopenharmony_ci allocated_size = ni->allocated_size; 201662306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 201762306a36Sopenharmony_ci /* 201862306a36Sopenharmony_ci * If non-resident, seek to the last extent. If resident, there is 201962306a36Sopenharmony_ci * only one extent, so seek to that. 202062306a36Sopenharmony_ci */ 202162306a36Sopenharmony_ci vcn = NInoNonResident(ni) ? allocated_size >> vol->cluster_size_bits : 202262306a36Sopenharmony_ci 0; 202362306a36Sopenharmony_ci /* 202462306a36Sopenharmony_ci * Abort if someone did the work whilst we waited for the locks. If we 202562306a36Sopenharmony_ci * just converted the attribute from resident to non-resident it is 202662306a36Sopenharmony_ci * likely that exactly this has happened already. We cannot quite 202762306a36Sopenharmony_ci * abort if we need to update the data size. 202862306a36Sopenharmony_ci */ 202962306a36Sopenharmony_ci if (unlikely(new_alloc_size <= allocated_size)) { 203062306a36Sopenharmony_ci ntfs_debug("Allocated size already exceeds requested size."); 203162306a36Sopenharmony_ci new_alloc_size = allocated_size; 203262306a36Sopenharmony_ci if (new_data_size < 0) 203362306a36Sopenharmony_ci goto done; 203462306a36Sopenharmony_ci /* 203562306a36Sopenharmony_ci * We want the first attribute extent so that we can update the 203662306a36Sopenharmony_ci * data size. 203762306a36Sopenharmony_ci */ 203862306a36Sopenharmony_ci vcn = 0; 203962306a36Sopenharmony_ci } 204062306a36Sopenharmony_ci err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 204162306a36Sopenharmony_ci CASE_SENSITIVE, vcn, NULL, 0, ctx); 204262306a36Sopenharmony_ci if (unlikely(err)) { 204362306a36Sopenharmony_ci if (err == -ENOENT) 204462306a36Sopenharmony_ci err = -EIO; 204562306a36Sopenharmony_ci goto err_out; 204662306a36Sopenharmony_ci } 204762306a36Sopenharmony_ci m = ctx->mrec; 204862306a36Sopenharmony_ci a = ctx->attr; 204962306a36Sopenharmony_ci /* Use goto to reduce indentation. */ 205062306a36Sopenharmony_ci if (a->non_resident) 205162306a36Sopenharmony_ci goto do_non_resident_extend; 205262306a36Sopenharmony_ci BUG_ON(NInoNonResident(ni)); 205362306a36Sopenharmony_ci /* The total length of the attribute value. */ 205462306a36Sopenharmony_ci attr_len = le32_to_cpu(a->data.resident.value_length); 205562306a36Sopenharmony_ci /* 205662306a36Sopenharmony_ci * Extend the attribute record to be able to store the new attribute 205762306a36Sopenharmony_ci * size. ntfs_attr_record_resize() will not do anything if the size is 205862306a36Sopenharmony_ci * not changing. 205962306a36Sopenharmony_ci */ 206062306a36Sopenharmony_ci if (new_alloc_size < vol->mft_record_size && 206162306a36Sopenharmony_ci !ntfs_attr_record_resize(m, a, 206262306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset) + 206362306a36Sopenharmony_ci new_alloc_size)) { 206462306a36Sopenharmony_ci /* The resize succeeded! */ 206562306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 206662306a36Sopenharmony_ci ni->allocated_size = le32_to_cpu(a->length) - 206762306a36Sopenharmony_ci le16_to_cpu(a->data.resident.value_offset); 206862306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 206962306a36Sopenharmony_ci if (new_data_size >= 0) { 207062306a36Sopenharmony_ci BUG_ON(new_data_size < attr_len); 207162306a36Sopenharmony_ci a->data.resident.value_length = 207262306a36Sopenharmony_ci cpu_to_le32((u32)new_data_size); 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci goto flush_done; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci /* 207762306a36Sopenharmony_ci * We have to drop all the locks so we can call 207862306a36Sopenharmony_ci * ntfs_attr_make_non_resident(). This could be optimised by try- 207962306a36Sopenharmony_ci * locking the first page cache page and only if that fails dropping 208062306a36Sopenharmony_ci * the locks, locking the page, and redoing all the locking and 208162306a36Sopenharmony_ci * lookups. While this would be a huge optimisation, it is not worth 208262306a36Sopenharmony_ci * it as this is definitely a slow code path. 208362306a36Sopenharmony_ci */ 208462306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 208562306a36Sopenharmony_ci unmap_mft_record(base_ni); 208662306a36Sopenharmony_ci up_write(&ni->runlist.lock); 208762306a36Sopenharmony_ci /* 208862306a36Sopenharmony_ci * Not enough space in the mft record, try to make the attribute 208962306a36Sopenharmony_ci * non-resident and if successful restart the extension process. 209062306a36Sopenharmony_ci */ 209162306a36Sopenharmony_ci err = ntfs_attr_make_non_resident(ni, attr_len); 209262306a36Sopenharmony_ci if (likely(!err)) 209362306a36Sopenharmony_ci goto retry_extend; 209462306a36Sopenharmony_ci /* 209562306a36Sopenharmony_ci * Could not make non-resident. If this is due to this not being 209662306a36Sopenharmony_ci * permitted for this attribute type or there not being enough space, 209762306a36Sopenharmony_ci * try to make other attributes non-resident. Otherwise fail. 209862306a36Sopenharmony_ci */ 209962306a36Sopenharmony_ci if (unlikely(err != -EPERM && err != -ENOSPC)) { 210062306a36Sopenharmony_ci /* Only emit errors when the write will fail completely. */ 210162306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 210262306a36Sopenharmony_ci allocated_size = ni->allocated_size; 210362306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 210462306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 210562306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation of " 210662306a36Sopenharmony_ci "inode 0x%lx, attribute type 0x%x, " 210762306a36Sopenharmony_ci "because the conversion from resident " 210862306a36Sopenharmony_ci "to non-resident attribute failed " 210962306a36Sopenharmony_ci "with error code %i.", vi->i_ino, 211062306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), err); 211162306a36Sopenharmony_ci if (err != -ENOMEM) 211262306a36Sopenharmony_ci err = -EIO; 211362306a36Sopenharmony_ci goto conv_err_out; 211462306a36Sopenharmony_ci } 211562306a36Sopenharmony_ci /* TODO: Not implemented from here, abort. */ 211662306a36Sopenharmony_ci read_lock_irqsave(&ni->size_lock, flags); 211762306a36Sopenharmony_ci allocated_size = ni->allocated_size; 211862306a36Sopenharmony_ci read_unlock_irqrestore(&ni->size_lock, flags); 211962306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) { 212062306a36Sopenharmony_ci if (err == -ENOSPC) 212162306a36Sopenharmony_ci ntfs_error(vol->sb, "Not enough space in the mft " 212262306a36Sopenharmony_ci "record/on disk for the non-resident " 212362306a36Sopenharmony_ci "attribute value. This case is not " 212462306a36Sopenharmony_ci "implemented yet."); 212562306a36Sopenharmony_ci else /* if (err == -EPERM) */ 212662306a36Sopenharmony_ci ntfs_error(vol->sb, "This attribute type may not be " 212762306a36Sopenharmony_ci "non-resident. This case is not " 212862306a36Sopenharmony_ci "implemented yet."); 212962306a36Sopenharmony_ci } 213062306a36Sopenharmony_ci err = -EOPNOTSUPP; 213162306a36Sopenharmony_ci goto conv_err_out; 213262306a36Sopenharmony_ci#if 0 213362306a36Sopenharmony_ci // TODO: Attempt to make other attributes non-resident. 213462306a36Sopenharmony_ci if (!err) 213562306a36Sopenharmony_ci goto do_resident_extend; 213662306a36Sopenharmony_ci /* 213762306a36Sopenharmony_ci * Both the attribute list attribute and the standard information 213862306a36Sopenharmony_ci * attribute must remain in the base inode. Thus, if this is one of 213962306a36Sopenharmony_ci * these attributes, we have to try to move other attributes out into 214062306a36Sopenharmony_ci * extent mft records instead. 214162306a36Sopenharmony_ci */ 214262306a36Sopenharmony_ci if (ni->type == AT_ATTRIBUTE_LIST || 214362306a36Sopenharmony_ci ni->type == AT_STANDARD_INFORMATION) { 214462306a36Sopenharmony_ci // TODO: Attempt to move other attributes into extent mft 214562306a36Sopenharmony_ci // records. 214662306a36Sopenharmony_ci err = -EOPNOTSUPP; 214762306a36Sopenharmony_ci if (!err) 214862306a36Sopenharmony_ci goto do_resident_extend; 214962306a36Sopenharmony_ci goto err_out; 215062306a36Sopenharmony_ci } 215162306a36Sopenharmony_ci // TODO: Attempt to move this attribute to an extent mft record, but 215262306a36Sopenharmony_ci // only if it is not already the only attribute in an mft record in 215362306a36Sopenharmony_ci // which case there would be nothing to gain. 215462306a36Sopenharmony_ci err = -EOPNOTSUPP; 215562306a36Sopenharmony_ci if (!err) 215662306a36Sopenharmony_ci goto do_resident_extend; 215762306a36Sopenharmony_ci /* There is nothing we can do to make enough space. )-: */ 215862306a36Sopenharmony_ci goto err_out; 215962306a36Sopenharmony_ci#endif 216062306a36Sopenharmony_cido_non_resident_extend: 216162306a36Sopenharmony_ci BUG_ON(!NInoNonResident(ni)); 216262306a36Sopenharmony_ci if (new_alloc_size == allocated_size) { 216362306a36Sopenharmony_ci BUG_ON(vcn); 216462306a36Sopenharmony_ci goto alloc_done; 216562306a36Sopenharmony_ci } 216662306a36Sopenharmony_ci /* 216762306a36Sopenharmony_ci * If the data starts after the end of the old allocation, this is a 216862306a36Sopenharmony_ci * $DATA attribute and sparse attributes are enabled on the volume and 216962306a36Sopenharmony_ci * for this inode, then create a sparse region between the old 217062306a36Sopenharmony_ci * allocated size and the start of the data. Otherwise simply proceed 217162306a36Sopenharmony_ci * with filling the whole space between the old allocated size and the 217262306a36Sopenharmony_ci * new allocated size with clusters. 217362306a36Sopenharmony_ci */ 217462306a36Sopenharmony_ci if ((start >= 0 && start <= allocated_size) || ni->type != AT_DATA || 217562306a36Sopenharmony_ci !NVolSparseEnabled(vol) || NInoSparseDisabled(ni)) 217662306a36Sopenharmony_ci goto skip_sparse; 217762306a36Sopenharmony_ci // TODO: This is not implemented yet. We just fill in with real 217862306a36Sopenharmony_ci // clusters for now... 217962306a36Sopenharmony_ci ntfs_debug("Inserting holes is not-implemented yet. Falling back to " 218062306a36Sopenharmony_ci "allocating real clusters instead."); 218162306a36Sopenharmony_ciskip_sparse: 218262306a36Sopenharmony_ci rl = ni->runlist.rl; 218362306a36Sopenharmony_ci if (likely(rl)) { 218462306a36Sopenharmony_ci /* Seek to the end of the runlist. */ 218562306a36Sopenharmony_ci while (rl->length) 218662306a36Sopenharmony_ci rl++; 218762306a36Sopenharmony_ci } 218862306a36Sopenharmony_ci /* If this attribute extent is not mapped, map it now. */ 218962306a36Sopenharmony_ci if (unlikely(!rl || rl->lcn == LCN_RL_NOT_MAPPED || 219062306a36Sopenharmony_ci (rl->lcn == LCN_ENOENT && rl > ni->runlist.rl && 219162306a36Sopenharmony_ci (rl-1)->lcn == LCN_RL_NOT_MAPPED))) { 219262306a36Sopenharmony_ci if (!rl && !allocated_size) 219362306a36Sopenharmony_ci goto first_alloc; 219462306a36Sopenharmony_ci rl = ntfs_mapping_pairs_decompress(vol, a, ni->runlist.rl); 219562306a36Sopenharmony_ci if (IS_ERR(rl)) { 219662306a36Sopenharmony_ci err = PTR_ERR(rl); 219762306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 219862306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation " 219962306a36Sopenharmony_ci "of inode 0x%lx, attribute " 220062306a36Sopenharmony_ci "type 0x%x, because the " 220162306a36Sopenharmony_ci "mapping of a runlist " 220262306a36Sopenharmony_ci "fragment failed with error " 220362306a36Sopenharmony_ci "code %i.", vi->i_ino, 220462306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), 220562306a36Sopenharmony_ci err); 220662306a36Sopenharmony_ci if (err != -ENOMEM) 220762306a36Sopenharmony_ci err = -EIO; 220862306a36Sopenharmony_ci goto err_out; 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci ni->runlist.rl = rl; 221162306a36Sopenharmony_ci /* Seek to the end of the runlist. */ 221262306a36Sopenharmony_ci while (rl->length) 221362306a36Sopenharmony_ci rl++; 221462306a36Sopenharmony_ci } 221562306a36Sopenharmony_ci /* 221662306a36Sopenharmony_ci * We now know the runlist of the last extent is mapped and @rl is at 221762306a36Sopenharmony_ci * the end of the runlist. We want to begin allocating clusters 221862306a36Sopenharmony_ci * starting at the last allocated cluster to reduce fragmentation. If 221962306a36Sopenharmony_ci * there are no valid LCNs in the attribute we let the cluster 222062306a36Sopenharmony_ci * allocator choose the starting cluster. 222162306a36Sopenharmony_ci */ 222262306a36Sopenharmony_ci /* If the last LCN is a hole or simillar seek back to last real LCN. */ 222362306a36Sopenharmony_ci while (rl->lcn < 0 && rl > ni->runlist.rl) 222462306a36Sopenharmony_ci rl--; 222562306a36Sopenharmony_cifirst_alloc: 222662306a36Sopenharmony_ci // FIXME: Need to implement partial allocations so at least part of the 222762306a36Sopenharmony_ci // write can be performed when start >= 0. (Needed for POSIX write(2) 222862306a36Sopenharmony_ci // conformance.) 222962306a36Sopenharmony_ci rl2 = ntfs_cluster_alloc(vol, allocated_size >> vol->cluster_size_bits, 223062306a36Sopenharmony_ci (new_alloc_size - allocated_size) >> 223162306a36Sopenharmony_ci vol->cluster_size_bits, (rl && (rl->lcn >= 0)) ? 223262306a36Sopenharmony_ci rl->lcn + rl->length : -1, DATA_ZONE, true); 223362306a36Sopenharmony_ci if (IS_ERR(rl2)) { 223462306a36Sopenharmony_ci err = PTR_ERR(rl2); 223562306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 223662306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation of " 223762306a36Sopenharmony_ci "inode 0x%lx, attribute type 0x%x, " 223862306a36Sopenharmony_ci "because the allocation of clusters " 223962306a36Sopenharmony_ci "failed with error code %i.", vi->i_ino, 224062306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), err); 224162306a36Sopenharmony_ci if (err != -ENOMEM && err != -ENOSPC) 224262306a36Sopenharmony_ci err = -EIO; 224362306a36Sopenharmony_ci goto err_out; 224462306a36Sopenharmony_ci } 224562306a36Sopenharmony_ci rl = ntfs_runlists_merge(ni->runlist.rl, rl2); 224662306a36Sopenharmony_ci if (IS_ERR(rl)) { 224762306a36Sopenharmony_ci err = PTR_ERR(rl); 224862306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 224962306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation of " 225062306a36Sopenharmony_ci "inode 0x%lx, attribute type 0x%x, " 225162306a36Sopenharmony_ci "because the runlist merge failed " 225262306a36Sopenharmony_ci "with error code %i.", vi->i_ino, 225362306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), err); 225462306a36Sopenharmony_ci if (err != -ENOMEM) 225562306a36Sopenharmony_ci err = -EIO; 225662306a36Sopenharmony_ci if (ntfs_cluster_free_from_rl(vol, rl2)) { 225762306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to release allocated " 225862306a36Sopenharmony_ci "cluster(s) in error code path. Run " 225962306a36Sopenharmony_ci "chkdsk to recover the lost " 226062306a36Sopenharmony_ci "cluster(s)."); 226162306a36Sopenharmony_ci NVolSetErrors(vol); 226262306a36Sopenharmony_ci } 226362306a36Sopenharmony_ci ntfs_free(rl2); 226462306a36Sopenharmony_ci goto err_out; 226562306a36Sopenharmony_ci } 226662306a36Sopenharmony_ci ni->runlist.rl = rl; 226762306a36Sopenharmony_ci ntfs_debug("Allocated 0x%llx clusters.", (long long)(new_alloc_size - 226862306a36Sopenharmony_ci allocated_size) >> vol->cluster_size_bits); 226962306a36Sopenharmony_ci /* Find the runlist element with which the attribute extent starts. */ 227062306a36Sopenharmony_ci ll = sle64_to_cpu(a->data.non_resident.lowest_vcn); 227162306a36Sopenharmony_ci rl2 = ntfs_rl_find_vcn_nolock(rl, ll); 227262306a36Sopenharmony_ci BUG_ON(!rl2); 227362306a36Sopenharmony_ci BUG_ON(!rl2->length); 227462306a36Sopenharmony_ci BUG_ON(rl2->lcn < LCN_HOLE); 227562306a36Sopenharmony_ci mp_rebuilt = false; 227662306a36Sopenharmony_ci /* Get the size for the new mapping pairs array for this extent. */ 227762306a36Sopenharmony_ci mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1); 227862306a36Sopenharmony_ci if (unlikely(mp_size <= 0)) { 227962306a36Sopenharmony_ci err = mp_size; 228062306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 228162306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation of " 228262306a36Sopenharmony_ci "inode 0x%lx, attribute type 0x%x, " 228362306a36Sopenharmony_ci "because determining the size for the " 228462306a36Sopenharmony_ci "mapping pairs failed with error code " 228562306a36Sopenharmony_ci "%i.", vi->i_ino, 228662306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), err); 228762306a36Sopenharmony_ci err = -EIO; 228862306a36Sopenharmony_ci goto undo_alloc; 228962306a36Sopenharmony_ci } 229062306a36Sopenharmony_ci /* Extend the attribute record to fit the bigger mapping pairs array. */ 229162306a36Sopenharmony_ci attr_len = le32_to_cpu(a->length); 229262306a36Sopenharmony_ci err = ntfs_attr_record_resize(m, a, mp_size + 229362306a36Sopenharmony_ci le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); 229462306a36Sopenharmony_ci if (unlikely(err)) { 229562306a36Sopenharmony_ci BUG_ON(err != -ENOSPC); 229662306a36Sopenharmony_ci // TODO: Deal with this by moving this extent to a new mft 229762306a36Sopenharmony_ci // record or by starting a new extent in a new mft record, 229862306a36Sopenharmony_ci // possibly by extending this extent partially and filling it 229962306a36Sopenharmony_ci // and creating a new extent for the remainder, or by making 230062306a36Sopenharmony_ci // other attributes non-resident and/or by moving other 230162306a36Sopenharmony_ci // attributes out of this mft record. 230262306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 230362306a36Sopenharmony_ci ntfs_error(vol->sb, "Not enough space in the mft " 230462306a36Sopenharmony_ci "record for the extended attribute " 230562306a36Sopenharmony_ci "record. This case is not " 230662306a36Sopenharmony_ci "implemented yet."); 230762306a36Sopenharmony_ci err = -EOPNOTSUPP; 230862306a36Sopenharmony_ci goto undo_alloc; 230962306a36Sopenharmony_ci } 231062306a36Sopenharmony_ci mp_rebuilt = true; 231162306a36Sopenharmony_ci /* Generate the mapping pairs array directly into the attr record. */ 231262306a36Sopenharmony_ci err = ntfs_mapping_pairs_build(vol, (u8*)a + 231362306a36Sopenharmony_ci le16_to_cpu(a->data.non_resident.mapping_pairs_offset), 231462306a36Sopenharmony_ci mp_size, rl2, ll, -1, NULL); 231562306a36Sopenharmony_ci if (unlikely(err)) { 231662306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 231762306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot extend allocation of " 231862306a36Sopenharmony_ci "inode 0x%lx, attribute type 0x%x, " 231962306a36Sopenharmony_ci "because building the mapping pairs " 232062306a36Sopenharmony_ci "failed with error code %i.", vi->i_ino, 232162306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), err); 232262306a36Sopenharmony_ci err = -EIO; 232362306a36Sopenharmony_ci goto undo_alloc; 232462306a36Sopenharmony_ci } 232562306a36Sopenharmony_ci /* Update the highest_vcn. */ 232662306a36Sopenharmony_ci a->data.non_resident.highest_vcn = cpu_to_sle64((new_alloc_size >> 232762306a36Sopenharmony_ci vol->cluster_size_bits) - 1); 232862306a36Sopenharmony_ci /* 232962306a36Sopenharmony_ci * We now have extended the allocated size of the attribute. Reflect 233062306a36Sopenharmony_ci * this in the ntfs_inode structure and the attribute record. 233162306a36Sopenharmony_ci */ 233262306a36Sopenharmony_ci if (a->data.non_resident.lowest_vcn) { 233362306a36Sopenharmony_ci /* 233462306a36Sopenharmony_ci * We are not in the first attribute extent, switch to it, but 233562306a36Sopenharmony_ci * first ensure the changes will make it to disk later. 233662306a36Sopenharmony_ci */ 233762306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 233862306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 233962306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 234062306a36Sopenharmony_ci err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, 234162306a36Sopenharmony_ci CASE_SENSITIVE, 0, NULL, 0, ctx); 234262306a36Sopenharmony_ci if (unlikely(err)) 234362306a36Sopenharmony_ci goto restore_undo_alloc; 234462306a36Sopenharmony_ci /* @m is not used any more so no need to set it. */ 234562306a36Sopenharmony_ci a = ctx->attr; 234662306a36Sopenharmony_ci } 234762306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 234862306a36Sopenharmony_ci ni->allocated_size = new_alloc_size; 234962306a36Sopenharmony_ci a->data.non_resident.allocated_size = cpu_to_sle64(new_alloc_size); 235062306a36Sopenharmony_ci /* 235162306a36Sopenharmony_ci * FIXME: This would fail if @ni is a directory, $MFT, or an index, 235262306a36Sopenharmony_ci * since those can have sparse/compressed set. For example can be 235362306a36Sopenharmony_ci * set compressed even though it is not compressed itself and in that 235462306a36Sopenharmony_ci * case the bit means that files are to be created compressed in the 235562306a36Sopenharmony_ci * directory... At present this is ok as this code is only called for 235662306a36Sopenharmony_ci * regular files, and only for their $DATA attribute(s). 235762306a36Sopenharmony_ci * FIXME: The calculation is wrong if we created a hole above. For now 235862306a36Sopenharmony_ci * it does not matter as we never create holes. 235962306a36Sopenharmony_ci */ 236062306a36Sopenharmony_ci if (NInoSparse(ni) || NInoCompressed(ni)) { 236162306a36Sopenharmony_ci ni->itype.compressed.size += new_alloc_size - allocated_size; 236262306a36Sopenharmony_ci a->data.non_resident.compressed_size = 236362306a36Sopenharmony_ci cpu_to_sle64(ni->itype.compressed.size); 236462306a36Sopenharmony_ci vi->i_blocks = ni->itype.compressed.size >> 9; 236562306a36Sopenharmony_ci } else 236662306a36Sopenharmony_ci vi->i_blocks = new_alloc_size >> 9; 236762306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 236862306a36Sopenharmony_cialloc_done: 236962306a36Sopenharmony_ci if (new_data_size >= 0) { 237062306a36Sopenharmony_ci BUG_ON(new_data_size < 237162306a36Sopenharmony_ci sle64_to_cpu(a->data.non_resident.data_size)); 237262306a36Sopenharmony_ci a->data.non_resident.data_size = cpu_to_sle64(new_data_size); 237362306a36Sopenharmony_ci } 237462306a36Sopenharmony_ciflush_done: 237562306a36Sopenharmony_ci /* Ensure the changes make it to disk. */ 237662306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 237762306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 237862306a36Sopenharmony_cidone: 237962306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 238062306a36Sopenharmony_ci unmap_mft_record(base_ni); 238162306a36Sopenharmony_ci up_write(&ni->runlist.lock); 238262306a36Sopenharmony_ci ntfs_debug("Done, new_allocated_size 0x%llx.", 238362306a36Sopenharmony_ci (unsigned long long)new_alloc_size); 238462306a36Sopenharmony_ci return new_alloc_size; 238562306a36Sopenharmony_cirestore_undo_alloc: 238662306a36Sopenharmony_ci if (start < 0 || start >= allocated_size) 238762306a36Sopenharmony_ci ntfs_error(vol->sb, "Cannot complete extension of allocation " 238862306a36Sopenharmony_ci "of inode 0x%lx, attribute type 0x%x, because " 238962306a36Sopenharmony_ci "lookup of first attribute extent failed with " 239062306a36Sopenharmony_ci "error code %i.", vi->i_ino, 239162306a36Sopenharmony_ci (unsigned)le32_to_cpu(ni->type), err); 239262306a36Sopenharmony_ci if (err == -ENOENT) 239362306a36Sopenharmony_ci err = -EIO; 239462306a36Sopenharmony_ci ntfs_attr_reinit_search_ctx(ctx); 239562306a36Sopenharmony_ci if (ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, 239662306a36Sopenharmony_ci allocated_size >> vol->cluster_size_bits, NULL, 0, 239762306a36Sopenharmony_ci ctx)) { 239862306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to find last attribute extent of " 239962306a36Sopenharmony_ci "attribute in error code path. Run chkdsk to " 240062306a36Sopenharmony_ci "recover."); 240162306a36Sopenharmony_ci write_lock_irqsave(&ni->size_lock, flags); 240262306a36Sopenharmony_ci ni->allocated_size = new_alloc_size; 240362306a36Sopenharmony_ci /* 240462306a36Sopenharmony_ci * FIXME: This would fail if @ni is a directory... See above. 240562306a36Sopenharmony_ci * FIXME: The calculation is wrong if we created a hole above. 240662306a36Sopenharmony_ci * For now it does not matter as we never create holes. 240762306a36Sopenharmony_ci */ 240862306a36Sopenharmony_ci if (NInoSparse(ni) || NInoCompressed(ni)) { 240962306a36Sopenharmony_ci ni->itype.compressed.size += new_alloc_size - 241062306a36Sopenharmony_ci allocated_size; 241162306a36Sopenharmony_ci vi->i_blocks = ni->itype.compressed.size >> 9; 241262306a36Sopenharmony_ci } else 241362306a36Sopenharmony_ci vi->i_blocks = new_alloc_size >> 9; 241462306a36Sopenharmony_ci write_unlock_irqrestore(&ni->size_lock, flags); 241562306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 241662306a36Sopenharmony_ci unmap_mft_record(base_ni); 241762306a36Sopenharmony_ci up_write(&ni->runlist.lock); 241862306a36Sopenharmony_ci /* 241962306a36Sopenharmony_ci * The only thing that is now wrong is the allocated size of the 242062306a36Sopenharmony_ci * base attribute extent which chkdsk should be able to fix. 242162306a36Sopenharmony_ci */ 242262306a36Sopenharmony_ci NVolSetErrors(vol); 242362306a36Sopenharmony_ci return err; 242462306a36Sopenharmony_ci } 242562306a36Sopenharmony_ci ctx->attr->data.non_resident.highest_vcn = cpu_to_sle64( 242662306a36Sopenharmony_ci (allocated_size >> vol->cluster_size_bits) - 1); 242762306a36Sopenharmony_ciundo_alloc: 242862306a36Sopenharmony_ci ll = allocated_size >> vol->cluster_size_bits; 242962306a36Sopenharmony_ci if (ntfs_cluster_free(ni, ll, -1, ctx) < 0) { 243062306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to release allocated cluster(s) " 243162306a36Sopenharmony_ci "in error code path. Run chkdsk to recover " 243262306a36Sopenharmony_ci "the lost cluster(s)."); 243362306a36Sopenharmony_ci NVolSetErrors(vol); 243462306a36Sopenharmony_ci } 243562306a36Sopenharmony_ci m = ctx->mrec; 243662306a36Sopenharmony_ci a = ctx->attr; 243762306a36Sopenharmony_ci /* 243862306a36Sopenharmony_ci * If the runlist truncation fails and/or the search context is no 243962306a36Sopenharmony_ci * longer valid, we cannot resize the attribute record or build the 244062306a36Sopenharmony_ci * mapping pairs array thus we mark the inode bad so that no access to 244162306a36Sopenharmony_ci * the freed clusters can happen. 244262306a36Sopenharmony_ci */ 244362306a36Sopenharmony_ci if (ntfs_rl_truncate_nolock(vol, &ni->runlist, ll) || IS_ERR(m)) { 244462306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to %s in error code path. Run " 244562306a36Sopenharmony_ci "chkdsk to recover.", IS_ERR(m) ? 244662306a36Sopenharmony_ci "restore attribute search context" : 244762306a36Sopenharmony_ci "truncate attribute runlist"); 244862306a36Sopenharmony_ci NVolSetErrors(vol); 244962306a36Sopenharmony_ci } else if (mp_rebuilt) { 245062306a36Sopenharmony_ci if (ntfs_attr_record_resize(m, a, attr_len)) { 245162306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to restore attribute " 245262306a36Sopenharmony_ci "record in error code path. Run " 245362306a36Sopenharmony_ci "chkdsk to recover."); 245462306a36Sopenharmony_ci NVolSetErrors(vol); 245562306a36Sopenharmony_ci } else /* if (success) */ { 245662306a36Sopenharmony_ci if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu( 245762306a36Sopenharmony_ci a->data.non_resident. 245862306a36Sopenharmony_ci mapping_pairs_offset), attr_len - 245962306a36Sopenharmony_ci le16_to_cpu(a->data.non_resident. 246062306a36Sopenharmony_ci mapping_pairs_offset), rl2, ll, -1, 246162306a36Sopenharmony_ci NULL)) { 246262306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to restore " 246362306a36Sopenharmony_ci "mapping pairs array in error " 246462306a36Sopenharmony_ci "code path. Run chkdsk to " 246562306a36Sopenharmony_ci "recover."); 246662306a36Sopenharmony_ci NVolSetErrors(vol); 246762306a36Sopenharmony_ci } 246862306a36Sopenharmony_ci flush_dcache_mft_record_page(ctx->ntfs_ino); 246962306a36Sopenharmony_ci mark_mft_record_dirty(ctx->ntfs_ino); 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci } 247262306a36Sopenharmony_cierr_out: 247362306a36Sopenharmony_ci if (ctx) 247462306a36Sopenharmony_ci ntfs_attr_put_search_ctx(ctx); 247562306a36Sopenharmony_ci if (m) 247662306a36Sopenharmony_ci unmap_mft_record(base_ni); 247762306a36Sopenharmony_ci up_write(&ni->runlist.lock); 247862306a36Sopenharmony_ciconv_err_out: 247962306a36Sopenharmony_ci ntfs_debug("Failed. Returning error code %i.", err); 248062306a36Sopenharmony_ci return err; 248162306a36Sopenharmony_ci} 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci/** 248462306a36Sopenharmony_ci * ntfs_attr_set - fill (a part of) an attribute with a byte 248562306a36Sopenharmony_ci * @ni: ntfs inode describing the attribute to fill 248662306a36Sopenharmony_ci * @ofs: offset inside the attribute at which to start to fill 248762306a36Sopenharmony_ci * @cnt: number of bytes to fill 248862306a36Sopenharmony_ci * @val: the unsigned 8-bit value with which to fill the attribute 248962306a36Sopenharmony_ci * 249062306a36Sopenharmony_ci * Fill @cnt bytes of the attribute described by the ntfs inode @ni starting at 249162306a36Sopenharmony_ci * byte offset @ofs inside the attribute with the constant byte @val. 249262306a36Sopenharmony_ci * 249362306a36Sopenharmony_ci * This function is effectively like memset() applied to an ntfs attribute. 249462306a36Sopenharmony_ci * Note this function actually only operates on the page cache pages belonging 249562306a36Sopenharmony_ci * to the ntfs attribute and it marks them dirty after doing the memset(). 249662306a36Sopenharmony_ci * Thus it relies on the vm dirty page write code paths to cause the modified 249762306a36Sopenharmony_ci * pages to be written to the mft record/disk. 249862306a36Sopenharmony_ci * 249962306a36Sopenharmony_ci * Return 0 on success and -errno on error. An error code of -ESPIPE means 250062306a36Sopenharmony_ci * that @ofs + @cnt were outside the end of the attribute and no write was 250162306a36Sopenharmony_ci * performed. 250262306a36Sopenharmony_ci */ 250362306a36Sopenharmony_ciint ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt, const u8 val) 250462306a36Sopenharmony_ci{ 250562306a36Sopenharmony_ci ntfs_volume *vol = ni->vol; 250662306a36Sopenharmony_ci struct address_space *mapping; 250762306a36Sopenharmony_ci struct page *page; 250862306a36Sopenharmony_ci u8 *kaddr; 250962306a36Sopenharmony_ci pgoff_t idx, end; 251062306a36Sopenharmony_ci unsigned start_ofs, end_ofs, size; 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci ntfs_debug("Entering for ofs 0x%llx, cnt 0x%llx, val 0x%hx.", 251362306a36Sopenharmony_ci (long long)ofs, (long long)cnt, val); 251462306a36Sopenharmony_ci BUG_ON(ofs < 0); 251562306a36Sopenharmony_ci BUG_ON(cnt < 0); 251662306a36Sopenharmony_ci if (!cnt) 251762306a36Sopenharmony_ci goto done; 251862306a36Sopenharmony_ci /* 251962306a36Sopenharmony_ci * FIXME: Compressed and encrypted attributes are not supported when 252062306a36Sopenharmony_ci * writing and we should never have gotten here for them. 252162306a36Sopenharmony_ci */ 252262306a36Sopenharmony_ci BUG_ON(NInoCompressed(ni)); 252362306a36Sopenharmony_ci BUG_ON(NInoEncrypted(ni)); 252462306a36Sopenharmony_ci mapping = VFS_I(ni)->i_mapping; 252562306a36Sopenharmony_ci /* Work out the starting index and page offset. */ 252662306a36Sopenharmony_ci idx = ofs >> PAGE_SHIFT; 252762306a36Sopenharmony_ci start_ofs = ofs & ~PAGE_MASK; 252862306a36Sopenharmony_ci /* Work out the ending index and page offset. */ 252962306a36Sopenharmony_ci end = ofs + cnt; 253062306a36Sopenharmony_ci end_ofs = end & ~PAGE_MASK; 253162306a36Sopenharmony_ci /* If the end is outside the inode size return -ESPIPE. */ 253262306a36Sopenharmony_ci if (unlikely(end > i_size_read(VFS_I(ni)))) { 253362306a36Sopenharmony_ci ntfs_error(vol->sb, "Request exceeds end of attribute."); 253462306a36Sopenharmony_ci return -ESPIPE; 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci end >>= PAGE_SHIFT; 253762306a36Sopenharmony_ci /* If there is a first partial page, need to do it the slow way. */ 253862306a36Sopenharmony_ci if (start_ofs) { 253962306a36Sopenharmony_ci page = read_mapping_page(mapping, idx, NULL); 254062306a36Sopenharmony_ci if (IS_ERR(page)) { 254162306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to read first partial " 254262306a36Sopenharmony_ci "page (error, index 0x%lx).", idx); 254362306a36Sopenharmony_ci return PTR_ERR(page); 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci /* 254662306a36Sopenharmony_ci * If the last page is the same as the first page, need to 254762306a36Sopenharmony_ci * limit the write to the end offset. 254862306a36Sopenharmony_ci */ 254962306a36Sopenharmony_ci size = PAGE_SIZE; 255062306a36Sopenharmony_ci if (idx == end) 255162306a36Sopenharmony_ci size = end_ofs; 255262306a36Sopenharmony_ci kaddr = kmap_atomic(page); 255362306a36Sopenharmony_ci memset(kaddr + start_ofs, val, size - start_ofs); 255462306a36Sopenharmony_ci flush_dcache_page(page); 255562306a36Sopenharmony_ci kunmap_atomic(kaddr); 255662306a36Sopenharmony_ci set_page_dirty(page); 255762306a36Sopenharmony_ci put_page(page); 255862306a36Sopenharmony_ci balance_dirty_pages_ratelimited(mapping); 255962306a36Sopenharmony_ci cond_resched(); 256062306a36Sopenharmony_ci if (idx == end) 256162306a36Sopenharmony_ci goto done; 256262306a36Sopenharmony_ci idx++; 256362306a36Sopenharmony_ci } 256462306a36Sopenharmony_ci /* Do the whole pages the fast way. */ 256562306a36Sopenharmony_ci for (; idx < end; idx++) { 256662306a36Sopenharmony_ci /* Find or create the current page. (The page is locked.) */ 256762306a36Sopenharmony_ci page = grab_cache_page(mapping, idx); 256862306a36Sopenharmony_ci if (unlikely(!page)) { 256962306a36Sopenharmony_ci ntfs_error(vol->sb, "Insufficient memory to grab " 257062306a36Sopenharmony_ci "page (index 0x%lx).", idx); 257162306a36Sopenharmony_ci return -ENOMEM; 257262306a36Sopenharmony_ci } 257362306a36Sopenharmony_ci kaddr = kmap_atomic(page); 257462306a36Sopenharmony_ci memset(kaddr, val, PAGE_SIZE); 257562306a36Sopenharmony_ci flush_dcache_page(page); 257662306a36Sopenharmony_ci kunmap_atomic(kaddr); 257762306a36Sopenharmony_ci /* 257862306a36Sopenharmony_ci * If the page has buffers, mark them uptodate since buffer 257962306a36Sopenharmony_ci * state and not page state is definitive in 2.6 kernels. 258062306a36Sopenharmony_ci */ 258162306a36Sopenharmony_ci if (page_has_buffers(page)) { 258262306a36Sopenharmony_ci struct buffer_head *bh, *head; 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci bh = head = page_buffers(page); 258562306a36Sopenharmony_ci do { 258662306a36Sopenharmony_ci set_buffer_uptodate(bh); 258762306a36Sopenharmony_ci } while ((bh = bh->b_this_page) != head); 258862306a36Sopenharmony_ci } 258962306a36Sopenharmony_ci /* Now that buffers are uptodate, set the page uptodate, too. */ 259062306a36Sopenharmony_ci SetPageUptodate(page); 259162306a36Sopenharmony_ci /* 259262306a36Sopenharmony_ci * Set the page and all its buffers dirty and mark the inode 259362306a36Sopenharmony_ci * dirty, too. The VM will write the page later on. 259462306a36Sopenharmony_ci */ 259562306a36Sopenharmony_ci set_page_dirty(page); 259662306a36Sopenharmony_ci /* Finally unlock and release the page. */ 259762306a36Sopenharmony_ci unlock_page(page); 259862306a36Sopenharmony_ci put_page(page); 259962306a36Sopenharmony_ci balance_dirty_pages_ratelimited(mapping); 260062306a36Sopenharmony_ci cond_resched(); 260162306a36Sopenharmony_ci } 260262306a36Sopenharmony_ci /* If there is a last partial page, need to do it the slow way. */ 260362306a36Sopenharmony_ci if (end_ofs) { 260462306a36Sopenharmony_ci page = read_mapping_page(mapping, idx, NULL); 260562306a36Sopenharmony_ci if (IS_ERR(page)) { 260662306a36Sopenharmony_ci ntfs_error(vol->sb, "Failed to read last partial page " 260762306a36Sopenharmony_ci "(error, index 0x%lx).", idx); 260862306a36Sopenharmony_ci return PTR_ERR(page); 260962306a36Sopenharmony_ci } 261062306a36Sopenharmony_ci kaddr = kmap_atomic(page); 261162306a36Sopenharmony_ci memset(kaddr, val, end_ofs); 261262306a36Sopenharmony_ci flush_dcache_page(page); 261362306a36Sopenharmony_ci kunmap_atomic(kaddr); 261462306a36Sopenharmony_ci set_page_dirty(page); 261562306a36Sopenharmony_ci put_page(page); 261662306a36Sopenharmony_ci balance_dirty_pages_ratelimited(mapping); 261762306a36Sopenharmony_ci cond_resched(); 261862306a36Sopenharmony_ci } 261962306a36Sopenharmony_cidone: 262062306a36Sopenharmony_ci ntfs_debug("Done."); 262162306a36Sopenharmony_ci return 0; 262262306a36Sopenharmony_ci} 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci#endif /* NTFS_RW */ 2625