attrib.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,911 行 · 第 1/5 页
C
1,911 行
* not-mapped and terminator elements. ntfs_malloc_nofs() * operates on whole pages only. */ if (((rlpos + 3) * sizeof(*old_rl)) > rlsize) { runlist_element *rl2; rl2 = ntfs_malloc_nofs(rlsize + (int)PAGE_SIZE); if (unlikely(!rl2)) { ntfs_free(rl); return ERR_PTR(-ENOMEM); } memcpy(rl2, rl, rlsize); ntfs_free(rl); rl = rl2; rlsize += PAGE_SIZE; } /* Enter the current vcn into the current runlist element. */ rl[rlpos].vcn = vcn; /* * Get the change in vcn, i.e. the run length in clusters. * Doing it this way ensures that we signextend negative values. * A negative run length doesn't make any sense, but hey, I * didn't make up the NTFS specs and Windows NT4 treats the run * length as a signed value so that's how it is... */ b = *buf & 0xf; if (b) { if (unlikely(buf + b > attr_end)) goto io_error; for (deltaxcn = (s8)buf[b--]; b; b--) deltaxcn = (deltaxcn << 8) + buf[b]; } else { /* The length entry is compulsory. */ ntfs_error(vol->sb, "Missing length entry in mapping " "pairs array."); deltaxcn = (s64)-1; } /* * Assume a negative length to indicate data corruption and * hence clean-up and return NULL. */ if (unlikely(deltaxcn < 0)) { ntfs_error(vol->sb, "Invalid length in mapping pairs " "array."); goto err_out; } /* * Enter the current run length into the current runlist * element. */ rl[rlpos].length = deltaxcn; /* Increment the current vcn by the current run length. */ vcn += deltaxcn; /* * There might be no lcn change at all, as is the case for * sparse clusters on NTFS 3.0+, in which case we set the lcn * to LCN_HOLE. */ if (!(*buf & 0xf0)) rl[rlpos].lcn = (LCN)LCN_HOLE; else { /* Get the lcn change which really can be negative. */ u8 b2 = *buf & 0xf; b = b2 + ((*buf >> 4) & 0xf); if (buf + b > attr_end) goto io_error; for (deltaxcn = (s8)buf[b--]; b > b2; b--) deltaxcn = (deltaxcn << 8) + buf[b]; /* Change the current lcn to its new value. */ lcn += deltaxcn;#ifdef DEBUG /* * On NTFS 1.2-, apparently can have lcn == -1 to * indicate a hole. But we haven't verified ourselves * whether it is really the lcn or the deltaxcn that is * -1. So if either is found give us a message so we * can investigate it further! */ if (vol->major_ver < 3) { if (unlikely(deltaxcn == (LCN)-1)) ntfs_error(vol->sb, "lcn delta == -1"); if (unlikely(lcn == (LCN)-1)) ntfs_error(vol->sb, "lcn == -1"); }#endif /* Check lcn is not below -1. */ if (unlikely(lcn < (LCN)-1)) { ntfs_error(vol->sb, "Invalid LCN < -1 in " "mapping pairs array."); goto err_out; } /* Enter the current lcn into the runlist element. */ rl[rlpos].lcn = lcn; } /* Get to the next runlist element. */ rlpos++; /* Increment the buffer position to the next mapping pair. */ buf += (*buf & 0xf) + ((*buf >> 4) & 0xf) + 1; } if (unlikely(buf >= attr_end)) goto io_error; /* * If there is a highest_vcn specified, it must be equal to the final * vcn in the runlist - 1, or something has gone badly wrong. */ deltaxcn = sle64_to_cpu(attr->data.non_resident.highest_vcn); if (unlikely(deltaxcn && vcn - 1 != deltaxcn)) {mpa_err: ntfs_error(vol->sb, "Corrupt mapping pairs array in " "non-resident attribute."); goto err_out; } /* Setup not mapped runlist element if this is the base extent. */ if (!attr->data.non_resident.lowest_vcn) { VCN max_cluster; max_cluster = (sle64_to_cpu( attr->data.non_resident.allocated_size) + vol->cluster_size - 1) >> vol->cluster_size_bits; /* * If there is a difference between the highest_vcn and the * highest cluster, the runlist is either corrupt or, more * likely, there are more extents following this one. */ if (deltaxcn < --max_cluster) { ntfs_debug("More extents to follow; deltaxcn = 0x%llx, " "max_cluster = 0x%llx", (unsigned long long)deltaxcn, (unsigned long long)max_cluster); rl[rlpos].vcn = vcn; vcn += rl[rlpos].length = max_cluster - deltaxcn; rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED; rlpos++; } else if (unlikely(deltaxcn > max_cluster)) { ntfs_error(vol->sb, "Corrupt attribute. deltaxcn = " "0x%llx, max_cluster = 0x%llx", (unsigned long long)deltaxcn, (unsigned long long)max_cluster); goto mpa_err; } rl[rlpos].lcn = (LCN)LCN_ENOENT; } else /* Not the base extent. There may be more extents to follow. */ rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED; /* Setup terminating runlist element. */ rl[rlpos].vcn = vcn; rl[rlpos].length = (s64)0; /* If no existing runlist was specified, we are done. */ if (!old_rl) { ntfs_debug("Mapping pairs array successfully decompressed:"); ntfs_debug_dump_runlist(rl); return rl; } /* Now combine the new and old runlists checking for overlaps. */ old_rl = ntfs_merge_runlists(old_rl, rl); if (likely(!IS_ERR(old_rl))) return old_rl; ntfs_free(rl); ntfs_error(vol->sb, "Failed to merge runlists."); return old_rl;io_error: ntfs_error(vol->sb, "Corrupt attribute.");err_out: ntfs_free(rl); return ERR_PTR(-EIO);}/** * ntfs_map_runlist - map (a part of) a runlist of an ntfs inode * @ni: ntfs inode for which to map (part of) a runlist * @vcn: map runlist part containing this vcn * * Map the part of a runlist containing the @vcn of the ntfs inode @ni. * * Return 0 on success and -errno on error. * * Locking: - The runlist must be unlocked on entry and is unlocked on return. * - This function takes the lock for writing and modifies the runlist. */int ntfs_map_runlist(ntfs_inode *ni, VCN vcn){ ntfs_inode *base_ni; ntfs_attr_search_ctx *ctx; MFT_RECORD *mrec; int err = 0; ntfs_debug("Mapping runlist part containing vcn 0x%llx.", (unsigned long long)vcn); if (!NInoAttr(ni)) base_ni = ni; else base_ni = ni->ext.base_ntfs_ino; mrec = map_mft_record(base_ni); if (IS_ERR(mrec)) return PTR_ERR(mrec); ctx = ntfs_attr_get_search_ctx(base_ni, mrec); if (unlikely(!ctx)) { err = -ENOMEM; goto err_out; } err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len, CASE_SENSITIVE, vcn, NULL, 0, ctx); if (unlikely(err)) goto put_err_out; down_write(&ni->runlist.lock); /* Make sure someone else didn't do the work while we were sleeping. */ if (likely(ntfs_vcn_to_lcn(ni->runlist.rl, vcn) <= LCN_RL_NOT_MAPPED)) { runlist_element *rl; rl = decompress_mapping_pairs(ni->vol, ctx->attr, ni->runlist.rl); if (IS_ERR(rl)) err = PTR_ERR(rl); else ni->runlist.rl = rl; } up_write(&ni->runlist.lock);put_err_out: ntfs_attr_put_search_ctx(ctx);err_out: unmap_mft_record(base_ni); return err;}/** * ntfs_vcn_to_lcn - convert a vcn into a lcn given a runlist * @rl: runlist to use for conversion * @vcn: vcn to convert * * Convert the virtual cluster number @vcn of an attribute into a logical * cluster number (lcn) of a device using the runlist @rl to map vcns to their * corresponding lcns. * * It is up to the caller to serialize access to the runlist @rl. * * Since lcns must be >= 0, we use negative return values with special meaning: * * Return value Meaning / Description * ================================================== * -1 = LCN_HOLE Hole / not allocated on disk. * -2 = LCN_RL_NOT_MAPPED This is part of the runlist which has not been * inserted into the runlist yet. * -3 = LCN_ENOENT There is no such vcn in the attribute. * * Locking: - The caller must have locked the runlist (for reading or writing). * - This function does not touch the lock. */LCN ntfs_vcn_to_lcn(const runlist_element *rl, const VCN vcn){ int i; BUG_ON(vcn < 0); /* * If rl is NULL, assume that we have found an unmapped runlist. The * caller can then attempt to map it and fail appropriately if * necessary. */ if (unlikely(!rl)) return (LCN)LCN_RL_NOT_MAPPED; /* Catch out of lower bounds vcn. */ if (unlikely(vcn < rl[0].vcn)) return (LCN)LCN_ENOENT; for (i = 0; likely(rl[i].length); i++) { if (unlikely(vcn < rl[i+1].vcn)) { if (likely(rl[i].lcn >= (LCN)0)) return rl[i].lcn + (vcn - rl[i].vcn); return rl[i].lcn; } } /* * The terminator element is setup to the correct value, i.e. one of * LCN_HOLE, LCN_RL_NOT_MAPPED, or LCN_ENOENT. */ if (likely(rl[i].lcn < (LCN)0)) return rl[i].lcn; /* Just in case... We could replace this with BUG() some day. */ return (LCN)LCN_ENOENT;}/** * ntfs_find_vcn - find a vcn in the runlist described by an ntfs inode * @ni: ntfs inode describing the runlist to search * @vcn: vcn to find * @need_write: if false, lock for reading and if true, lock for writing * * Find the virtual cluster number @vcn in the runlist described by the ntfs * inode @ni and return the address of the runlist element containing the @vcn. * The runlist is left locked and the caller has to unlock it. If @need_write * is true, the runlist is locked for writing and if @need_write is false, the * runlist is locked for reading. In the error case, the runlist is not left * locked. * * Note you need to distinguish between the lcn of the returned runlist element * being >= 0 and LCN_HOLE. In the later case you have to return zeroes on * read and allocate clusters on write. * * Return the runlist element containing the @vcn on success and * ERR_PTR(-errno) on error. You need to test the return value with IS_ERR() * to decide if the return is success or failure and PTR_ERR() to get to the * error code if IS_ERR() is true. * * The possible error return codes are: * -ENOENT - No such vcn in the runlist, i.e. @vcn is out of bounds. * -ENOMEM - Not enough memory to map runlist. * -EIO - Critical error (runlist/file is corrupt, i/o error, etc). * * Locking: - The runlist must be unlocked on entry. * - On failing return, the runlist is unlocked. * - On successful return, the runlist is locked. If @need_write us * true, it is locked for writing. Otherwise is is locked for * reading. */runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn, const BOOL need_write){ runlist_element *rl; int err = 0; BOOL is_retry = FALSE; ntfs_debug("Entering for i_ino 0x%lx, vcn 0x%llx, lock for %sing.", ni->mft_no, (unsigned long long)vcn, !need_write ? "read" : "writ"); BUG_ON(!ni); BUG_ON(!NInoNonResident(ni)); BUG_ON(vcn < 0);lock_retry_remap: if (!need_write) down_read(&ni->runlist.lock); else down_write(&ni->runlist.lock); rl = ni->runlist.rl; if (likely(rl && vcn >= rl[0].vcn)) { while (likely(rl->length)) { if (likely(vcn < rl[1].vcn)) { if (likely(rl->lcn >= (LCN)LCN_HOLE)) { ntfs_debug("Done."); return rl; } break; } rl++; } if (likely(rl->lcn != (LCN)LCN_RL_NOT_MAPPED)) { if (likely(rl->lcn == (LCN)LCN_ENOENT)) err = -ENOENT; else err = -EIO; } } if (!need_write) up_read(&ni->runlist.lock); else up_write(&ni->runlist.lock); if (!err && !is_retry) { /* * The @vcn is in an unmapped region, map the runlist and * retry. */ err = ntfs_map_runlist(ni, vcn); if (likely(!err)) { is_retry = TRUE; goto lock_retry_remap; } /* * -EINVAL and -ENOENT coming from a failed mapping attempt are * equivalent to i/o errors for us as they should not happen in * our code paths. */ if (err == -EINVAL || err == -ENOENT) err = -EIO; } else if (!err) err = -EIO; ntfs_error(ni->vol->sb, "Failed with error code %i.", err); return ERR_PTR(err);}/**
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?