📄 attrib.c
字号:
unmap_extent_mft_record(ni); ctx->mrec = ctx->base_mrec; ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + le16_to_cpu(ctx->mrec->attrs_offset)); ctx->is_first = true; ctx->ntfs_ino = base_ni; ctx->base_ntfs_ino = NULL; ctx->base_mrec = NULL; ctx->base_attr = NULL; /* * In case there are multiple matches in the base mft record, need to * keep enumerating until we get an attribute not found response (or * another error), otherwise we would keep returning the same attribute * over and over again and all programs using us for enumeration would * lock up in a tight loop. */ do { err = ntfs_attr_find(type, name, name_len, ic, val, val_len, ctx); } while (!err); ntfs_debug("Done, not found."); return err;}/** * ntfs_attr_lookup - find an attribute in an ntfs inode * @type: attribute type to find * @name: attribute name to find (optional, i.e. NULL means don't care) * @name_len: attribute name length (only needed if @name present) * @ic: IGNORE_CASE or CASE_SENSITIVE (ignored if @name not present) * @lowest_vcn: lowest vcn to find (optional, non-resident attributes only) * @val: attribute value to find (optional, resident attributes only) * @val_len: attribute value length * @ctx: search context with mft record and attribute to search from * * Find an attribute in an ntfs inode. On first search @ctx->ntfs_ino must * be the base mft record and @ctx must have been obtained from a call to * ntfs_attr_get_search_ctx(). * * This function transparently handles attribute lists and @ctx is used to * continue searches where they were left off at. * * After finishing with the attribute/mft record you need to call * ntfs_attr_put_search_ctx() to cleanup the search context (unmapping any * mapped inodes, etc). * * Return 0 if the search was successful and -errno if not. * * When 0, @ctx->attr is the found attribute and it is in mft record * @ctx->mrec. If an attribute list attribute is present, @ctx->al_entry is * the attribute list entry of the found attribute. * * When -ENOENT, @ctx->attr is the attribute which collates just after the * attribute being searched for, i.e. if one wants to add the attribute to the * mft record this is the correct place to insert it into. If an attribute * list attribute is present, @ctx->al_entry is the attribute list entry which * collates just after the attribute list entry of the attribute being searched * for, i.e. if one wants to add the attribute to the mft record this is the * correct place to insert its attribute list entry into. * * When -errno != -ENOENT, an error occured during the lookup. @ctx->attr is * then undefined and in particular you should not rely on it not changing. */int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name, const u32 name_len, const IGNORE_CASE_BOOL ic, const VCN lowest_vcn, const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx){ ntfs_inode *base_ni; ntfs_debug("Entering."); BUG_ON(IS_ERR(ctx->mrec)); if (ctx->base_ntfs_ino) base_ni = ctx->base_ntfs_ino; else base_ni = ctx->ntfs_ino; /* Sanity check, just for debugging really. */ BUG_ON(!base_ni); if (!NInoAttrList(base_ni) || type == AT_ATTRIBUTE_LIST) return ntfs_attr_find(type, name, name_len, ic, val, val_len, ctx); return ntfs_external_attr_find(type, name, name_len, ic, lowest_vcn, val, val_len, ctx);}/** * ntfs_attr_init_search_ctx - initialize an attribute search context * @ctx: attribute search context to initialize * @ni: ntfs inode with which to initialize the search context * @mrec: mft record with which to initialize the search context * * Initialize the attribute search context @ctx with @ni and @mrec. */static inline void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx, ntfs_inode *ni, MFT_RECORD *mrec){ *ctx = (ntfs_attr_search_ctx) { .mrec = mrec, /* Sanity checks are performed elsewhere. */ .attr = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset)), .is_first = true, .ntfs_ino = ni, };}/** * ntfs_attr_reinit_search_ctx - reinitialize an attribute search context * @ctx: attribute search context to reinitialize * * Reinitialize the attribute search context @ctx, unmapping an associated * extent mft record if present, and initialize the search context again. * * This is used when a search for a new attribute is being started to reset * the search context to the beginning. */void ntfs_attr_reinit_search_ctx(ntfs_attr_search_ctx *ctx){ if (likely(!ctx->base_ntfs_ino)) { /* No attribute list. */ ctx->is_first = true; /* Sanity checks are performed elsewhere. */ ctx->attr = (ATTR_RECORD*)((u8*)ctx->mrec + le16_to_cpu(ctx->mrec->attrs_offset)); /* * This needs resetting due to ntfs_external_attr_find() which * can leave it set despite having zeroed ctx->base_ntfs_ino. */ ctx->al_entry = NULL; return; } /* Attribute list. */ if (ctx->ntfs_ino != ctx->base_ntfs_ino) unmap_extent_mft_record(ctx->ntfs_ino); ntfs_attr_init_search_ctx(ctx, ctx->base_ntfs_ino, ctx->base_mrec); return;}/** * ntfs_attr_get_search_ctx - allocate/initialize a new attribute search context * @ni: ntfs inode with which to initialize the search context * @mrec: mft record with which to initialize the search context * * Allocate a new attribute search context, initialize it with @ni and @mrec, * and return it. Return NULL if allocation failed. */ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni, MFT_RECORD *mrec){ ntfs_attr_search_ctx *ctx; ctx = kmem_cache_alloc(ntfs_attr_ctx_cache, GFP_NOFS); if (ctx) ntfs_attr_init_search_ctx(ctx, ni, mrec); return ctx;}/** * ntfs_attr_put_search_ctx - release an attribute search context * @ctx: attribute search context to free * * Release the attribute search context @ctx, unmapping an associated extent * mft record if present. */void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx){ if (ctx->base_ntfs_ino && ctx->ntfs_ino != ctx->base_ntfs_ino) unmap_extent_mft_record(ctx->ntfs_ino); kmem_cache_free(ntfs_attr_ctx_cache, ctx); return;}#ifdef NTFS_RW/** * ntfs_attr_find_in_attrdef - find an attribute in the $AttrDef system file * @vol: ntfs volume to which the attribute belongs * @type: attribute type which to find * * Search for the attribute definition record corresponding to the attribute * @type in the $AttrDef system file. * * Return the attribute type definition record if found and NULL if not found. */static ATTR_DEF *ntfs_attr_find_in_attrdef(const ntfs_volume *vol, const ATTR_TYPE type){ ATTR_DEF *ad; BUG_ON(!vol->attrdef); BUG_ON(!type); for (ad = vol->attrdef; (u8*)ad - (u8*)vol->attrdef < vol->attrdef_size && ad->type; ++ad) { /* We have not found it yet, carry on searching. */ if (likely(le32_to_cpu(ad->type) < le32_to_cpu(type))) continue; /* We found the attribute; return it. */ if (likely(ad->type == type)) return ad; /* We have gone too far already. No point in continuing. */ break; } /* Attribute not found. */ ntfs_debug("Attribute type 0x%x not found in $AttrDef.", le32_to_cpu(type)); return NULL;}/** * ntfs_attr_size_bounds_check - check a size of an attribute type for validity * @vol: ntfs volume to which the attribute belongs * @type: attribute type which to check * @size: size which to check * * Check whether the @size in bytes is valid for an attribute of @type on the * ntfs volume @vol. This information is obtained from $AttrDef system file. * * Return 0 if valid, -ERANGE if not valid, or -ENOENT if the attribute is not * listed in $AttrDef. */int ntfs_attr_size_bounds_check(const ntfs_volume *vol, const ATTR_TYPE type, const s64 size){ ATTR_DEF *ad; BUG_ON(size < 0); /* * $ATTRIBUTE_LIST has a maximum size of 256kiB, but this is not * listed in $AttrDef. */ if (unlikely(type == AT_ATTRIBUTE_LIST && size > 256 * 1024)) return -ERANGE; /* Get the $AttrDef entry for the attribute @type. */ ad = ntfs_attr_find_in_attrdef(vol, type); if (unlikely(!ad)) return -ENOENT; /* Do the bounds check. */ if (((sle64_to_cpu(ad->min_size) > 0) && size < sle64_to_cpu(ad->min_size)) || ((sle64_to_cpu(ad->max_size) > 0) && size > sle64_to_cpu(ad->max_size))) return -ERANGE; return 0;}/** * ntfs_attr_can_be_non_resident - check if an attribute can be non-resident * @vol: ntfs volume to which the attribute belongs * @type: attribute type which to check * * Check whether the attribute of @type on the ntfs volume @vol is allowed to * be non-resident. This information is obtained from $AttrDef system file. * * Return 0 if the attribute is allowed to be non-resident, -EPERM if not, and * -ENOENT if the attribute is not listed in $AttrDef. */int ntfs_attr_can_be_non_resident(const ntfs_volume *vol, const ATTR_TYPE type){ ATTR_DEF *ad; /* Find the attribute definition record in $AttrDef. */ ad = ntfs_attr_find_in_attrdef(vol, type); if (unlikely(!ad)) return -ENOENT; /* Check the flags and return the result. */ if (ad->flags & ATTR_DEF_RESIDENT) return -EPERM; return 0;}/** * ntfs_attr_can_be_resident - check if an attribute can be resident * @vol: ntfs volume to which the attribute belongs * @type: attribute type which to check * * Check whether the attribute of @type on the ntfs volume @vol is allowed to * be resident. This information is derived from our ntfs knowledge and may * not be completely accurate, especially when user defined attributes are * present. Basically we allow everything to be resident except for index * allocation and $EA attributes. * * Return 0 if the attribute is allowed to be non-resident and -EPERM if not. * * Warning: In the system file $MFT the attribute $Bitmap must be non-resident * otherwise windows will not boot (blue screen of death)! We cannot * check for this here as we do not know which inode's $Bitmap is * being asked about so the caller needs to special case this. */int ntfs_attr_can_be_resident(const ntfs_volume *vol, const ATTR_TYPE type){ if (type == AT_INDEX_ALLOCATION) return -EPERM; return 0;}/** * ntfs_attr_record_resize - resize an attribute record * @m: mft record containing attribute record * @a: attribute record to resize * @new_size: new size in bytes to which to resize the attribute record @a * * Resize the attribute record @a, i.e. the resident part of the attribute, in * the mft record @m to @new_size bytes. * * Return 0 on success and -errno on error. The following error codes are * defined: * -ENOSPC - Not enough space in the mft record @m to perform the resize. * * Note: On error, no modifications have been performed whatsoever. * * Warning: If you make a record smaller without having copied all the data you * are interested in the data may be overwritten. */int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size){ ntfs_debug("Entering for new_size %u.", new_size); /* Align to 8 bytes if it is not already done. */ if (new_size & 7) new_size = (new_size + 7) & ~7; /* If the actual attribute length has changed, move things around. */ if (new_size != le32_to_cpu(a->length)) { u32 new_muse = le32_to_cpu(m->bytes_in_use) - le32_to_cpu(a->length) + new_size; /* Not enough space in this mft record. */ if (new_muse > le32_to_cpu(m->bytes_allocated)) return -ENOSPC; /* Move attributes following @a to their new location. */ memmove((u8*)a + new_size, (u8*)a + le32_to_cpu(a->length), le32_to_cpu(m->bytes_in_use) - ((u8*)a - (u8*)m) - le32_to_cpu(a->length)); /* Adjust @m to reflect the change in used space. */ m->bytes_in_use = cpu_to_le32(new_muse); /* Adjust @a to reflect the new size. */ if (new_size >= offsetof(ATTR_REC, length) + sizeof(a->length)) a->length = cpu_to_le32(new_size); } return 0;}/** * ntfs_resident_attr_value_resize - resize the value of a resident attribute * @m: mft record containing attribute record * @a: attribute record whose value to resize * @new_size: new size in bytes to which to resize the attribute value of @a * * Resize the value of the attribute @a in the mft record @m to @new_size bytes. * If the value is made bigger, the newly allocated space is cleared. * * Return 0 on success and -errno on error. The following error codes are * defined: * -ENOSPC - Not enough space in the mft record @m to perform the resize. * * Note: On error, no modifications have been performed whatsoever. * * Warning: If you make a record smaller without having copied all the data you * are interested in the data may be overwritten. */int ntfs_resident_attr_value_resize(MFT_RECORD *m, ATTR_RECORD *a, const u32 new_size){ u32 old_size; /* Resize the resident part of the attribute record. */ if (ntfs_attr_record_resize(m, a, le16_to_cpu(a->data.resident.value_offset) + new_size)) return -ENOSPC; /* * The resize succeeded! If we made the attribute value bigger, clear * the area between the old size and @new_size. */ old_size = le32_to_cpu(a->data.resident.value_length); if (new_size > old_size) memset((u8*)a + le16_to_cpu(a->data.resident.value_offset) + old_size, 0, new_size - old_size); /* Finally update the length of the attribute value. */ a->data.resident.value_length = cpu_to_le32(new_size);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -