attrib.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,911 行 · 第 1/5 页
C
1,911 行
* ntfs_attr_find - find (next) attribute in mft record * @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) * @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 * * You should not need to call this function directly. Use ntfs_attr_lookup() * instead. * * ntfs_attr_find() takes a search context @ctx as parameter and searches the * mft record specified by @ctx->mrec, beginning at @ctx->attr, for an * attribute of @type, optionally @name and @val. * * If the attribute is found, ntfs_attr_find() returns 0 and @ctx->attr will * point to the found attribute. * * If the attribute is not found, ntfs_attr_find() returns -ENOENT and * @ctx->attr will point to the attribute before which the attribute being * searched for would need to be inserted if such an action were to be desired. * * On actual error, ntfs_attr_find() returns -EIO. In this case @ctx->attr is * undefined and in particular do not rely on it not changing. * * If @ctx->is_first is TRUE, the search begins with @ctx->attr itself. If it * is FALSE, the search begins after @ctx->attr. * * If @ic is IGNORE_CASE, the @name comparisson is not case sensitive and * @ctx->ntfs_ino must be set to the ntfs inode to which the mft record * @ctx->mrec belongs. This is so we can get at the ntfs volume and hence at * the upcase table. If @ic is CASE_SENSITIVE, the comparison is case * sensitive. When @name is present, @name_len is the @name length in Unicode * characters. * * If @name is not present (NULL), we assume that the unnamed attribute is * being searched for. * * Finally, the resident attribute value @val is looked for, if present. If * @val is not present (NULL), @val_len is ignored. * * ntfs_attr_find() only searches the specified mft record and it ignores the * presence of an attribute list attribute (unless it is the one being searched * for, obviously). If you need to take attribute lists into consideration, * use ntfs_attr_lookup() instead (see below). This also means that you cannot * use ntfs_attr_find() to search for extent records of non-resident * attributes, as extents with lowest_vcn != 0 are usually described by the * attribute list attribute only. - Note that it is possible that the first * extent is only in the attribute list while the last extent is in the base * mft record, so do not rely on being able to find the first extent in the * base mft record. * * Warning: Never use @val when looking for attribute types which can be * non-resident as this most likely will result in a crash! */static int ntfs_attr_find(const ATTR_TYPE type, const ntfschar *name, const u32 name_len, const IGNORE_CASE_BOOL ic, const u8 *val, const u32 val_len, ntfs_attr_search_ctx *ctx){ ATTR_RECORD *a; ntfs_volume *vol; ntfschar *upcase; u32 upcase_len; if (ic == IGNORE_CASE) { vol = ctx->ntfs_ino->vol; upcase = vol->upcase; upcase_len = vol->upcase_len; } else { vol = NULL; upcase = NULL; upcase_len = 0; } /* * Iterate over attributes in mft record starting at @ctx->attr, or the * attribute following that, if @ctx->is_first is TRUE. */ if (ctx->is_first) { a = ctx->attr; ctx->is_first = FALSE; } else a = (ATTR_RECORD*)((u8*)ctx->attr + le32_to_cpu(ctx->attr->length)); for (;; a = (ATTR_RECORD*)((u8*)a + le32_to_cpu(a->length))) { if ((u8*)a < (u8*)ctx->mrec || (u8*)a > (u8*)ctx->mrec + le32_to_cpu(ctx->mrec->bytes_allocated)) break; ctx->attr = a; if (unlikely(le32_to_cpu(a->type) > le32_to_cpu(type) || a->type == AT_END)) return -ENOENT; if (unlikely(!a->length)) break; if (a->type != type) continue; /* * If @name is present, compare the two names. If @name is * missing, assume we want an unnamed attribute. */ if (!name) { /* The search failed if the found attribute is named. */ if (a->name_length) return -ENOENT; } else if (!ntfs_are_names_equal(name, name_len, (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)), a->name_length, ic, upcase, upcase_len)) { register int rc; rc = ntfs_collate_names(name, name_len, (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)), a->name_length, 1, IGNORE_CASE, upcase, upcase_len); /* * If @name collates before a->name, there is no * matching attribute. */ if (rc == -1) return -ENOENT; /* If the strings are not equal, continue search. */ if (rc) continue; rc = ntfs_collate_names(name, name_len, (ntfschar*)((u8*)a + le16_to_cpu(a->name_offset)), a->name_length, 1, CASE_SENSITIVE, upcase, upcase_len); if (rc == -1) return -ENOENT; if (rc) continue; } /* * The names match or @name not present and attribute is * unnamed. If no @val specified, we have found the attribute * and are done. */ if (!val) return 0; /* @val is present; compare values. */ else { register int rc; rc = memcmp(val, (u8*)a + le16_to_cpu( a->data.resident.value_offset), min_t(u32, val_len, le32_to_cpu( a->data.resident.value_length))); /* * If @val collates before the current attribute's * value, there is no matching attribute. */ if (!rc) { register u32 avl; avl = le32_to_cpu( a->data.resident.value_length); if (val_len == avl) return 0; if (val_len < avl) return -ENOENT; } else if (rc < 0) return -ENOENT; } } ntfs_error(NULL, "Inode is corrupt. Run chkdsk."); NVolSetErrors(vol); return -EIO;}/** * load_attribute_list - load an attribute list into memory * @vol: ntfs volume from which to read * @runlist: runlist of the attribute list * @al_start: destination buffer * @size: size of the destination buffer in bytes * @initialized_size: initialized size of the attribute list * * Walk the runlist @runlist and load all clusters from it copying them into * the linear buffer @al. The maximum number of bytes copied to @al is @size * bytes. Note, @size does not need to be a multiple of the cluster size. If * @initialized_size is less than @size, the region in @al between * @initialized_size and @size will be zeroed and not read from disk. * * Return 0 on success or -errno on error. */int load_attribute_list(ntfs_volume *vol, runlist *runlist, u8 *al_start, const s64 size, const s64 initialized_size){ LCN lcn; u8 *al = al_start; u8 *al_end = al + initialized_size; runlist_element *rl; struct buffer_head *bh; struct super_block *sb; unsigned long block_size; unsigned long block, max_block; int err = 0; unsigned char block_size_bits; ntfs_debug("Entering."); if (!vol || !runlist || !al || size <= 0 || initialized_size < 0 || initialized_size > size) return -EINVAL; if (!initialized_size) { memset(al, 0, size); return 0; } sb = vol->sb; block_size = sb->s_blocksize; block_size_bits = sb->s_blocksize_bits; down_read(&runlist->lock); rl = runlist->rl; /* Read all clusters specified by the runlist one run at a time. */ while (rl->length) { lcn = ntfs_vcn_to_lcn(rl, rl->vcn); ntfs_debug("Reading vcn = 0x%llx, lcn = 0x%llx.", (unsigned long long)rl->vcn, (unsigned long long)lcn); /* The attribute list cannot be sparse. */ if (lcn < 0) { ntfs_error(sb, "ntfs_vcn_to_lcn() failed. Cannot read " "attribute list."); goto err_out; } block = lcn << vol->cluster_size_bits >> block_size_bits; /* Read the run from device in chunks of block_size bytes. */ max_block = block + (rl->length << vol->cluster_size_bits >> block_size_bits); ntfs_debug("max_block = 0x%lx.", max_block); do { ntfs_debug("Reading block = 0x%lx.", block); bh = sb_bread(sb, block); if (!bh) { ntfs_error(sb, "sb_bread() failed. Cannot " "read attribute list."); goto err_out; } if (al + block_size >= al_end) goto do_final; memcpy(al, bh->b_data, block_size); brelse(bh); al += block_size; } while (++block < max_block); rl++; } if (initialized_size < size) {initialize: memset(al_start + initialized_size, 0, size - initialized_size); }done: up_read(&runlist->lock); return err;do_final: if (al < al_end) { /* * Partial block. * * Note: The attribute list can be smaller than its allocation * by multiple clusters. This has been encountered by at least * two people running Windows XP, thus we cannot do any * truncation sanity checking here. (AIA) */ memcpy(al, bh->b_data, al_end - al); brelse(bh); if (initialized_size < size) goto initialize; goto done; } brelse(bh); /* Real overflow! */ ntfs_error(sb, "Attribute list buffer overflow. Read attribute list " "is truncated.");err_out: err = -EIO; goto done;}/** * ntfs_external_attr_find - find an attribute in the attribute list of an 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 * * You should not need to call this function directly. Use ntfs_attr_lookup() * instead. * * Find an attribute by searching the attribute list for the corresponding * attribute list entry. Having found the entry, map the mft record if the * attribute is in a different mft record/inode, ntfs_attr_find() the attribute * in there and return it. * * 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(). On subsequent * calls @ctx->ntfs_ino can be any extent inode, too (@ctx->base_ntfs_ino is * then the base inode). * * 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). * * If the attribute is found, ntfs_external_attr_find() returns 0 and * @ctx->attr will point to the found attribute. @ctx->mrec will point to the * mft record in which @ctx->attr is located and @ctx->al_entry will point to * the attribute list entry for the attribute. * * If the attribute is not found, ntfs_external_attr_find() returns -ENOENT and * @ctx->attr will point to the attribute in the base mft record before which * the attribute being searched for would need to be inserted if such an action * were to be desired. @ctx->mrec will point to the mft record in which * @ctx->attr is located and @ctx->al_entry will point to the attribute list * entry of the attribute before which the attribute being searched for would * need to be inserted if such an action were to be desired. * * Thus to insert the not found attribute, one wants to add the attribute to * @ctx->mrec (the base mft record) and if there is not enough space, the * attribute should be placed in a newly allocated extent mft record. The * attribute list entry for the inserted attribute should be inserted in the * attribute list attribute at @ctx->al_entry. * * On actual error, ntfs_external_attr_find() returns -EIO. In this case * @ctx->attr is undefined and in particular do not rely on it not changing. */static int ntfs_external_attr_find(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, *ni; ntfs_volume *vol; ATTR_LIST_ENTRY *al_entry, *next_al_entry; u8 *al_start, *al_end; ATTR_RECORD *a; ntfschar *al_name; u32 al_name_len; int err = 0; static const char *es = " Unmount and run chkdsk."; ni = ctx->ntfs_ino; base_ni = ctx->base_ntfs_ino; ntfs_debug("Entering for inode 0x%lx, type 0x%x.", ni->mft_no, type); if (!base_ni) { /* First call happens with the base mft record. */ base_ni = ctx->base_ntfs_ino = ctx->ntfs_ino; ctx->base_mrec = ctx->mrec; } if (ni == base_ni) ctx->base_attr = ctx->attr; if (type == AT_END) goto not_found; vol = base_ni->vol; al_start = base_ni->attr_list; al_end = al_start + base_ni->attr_list_size; if (!ctx->al_entry) ctx->al_entry = (ATTR_LIST_ENTRY*)al_start; /* * Iterate over entries in attribute list starting at @ctx->al_entry, * or the entry following that, if @ctx->is_first is TRUE. */ if (ctx->is_first) { al_entry = ctx->al_entry; ctx->is_first = FALSE; } else al_entry = (ATTR_LIST_ENTRY*)((u8*)ctx->al_entry + le16_to_cpu(ctx->al_entry->length)); for (;; al_entry = next_al_entry) { /* Out of bounds check. */ if ((u8*)al_entry < base_ni->attr_list || (u8*)al_entry > al_end) break; /* Inode is corrupt. */ ctx->al_entry = al_entry; /* Catch the end of the attribute list. */ if ((u8*)al_entry == al_end) goto not_found; if (!al_entry->length) break; if ((u8*)al_entry + 6 > al_end || (u8*)al_entry + le16_to_cpu(al_entry->length) > al_end)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?