attrib.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,911 行 · 第 1/5 页
C
1,911 行
*/ if (right) __ntfs_rl_merge(src + ssize - 1, dst + loc + 1); if (left) __ntfs_rl_merge(dst + loc - 1, src); /* FIXME: What does this mean? (AIA) */ magic = loc + ssize - left; /* Move the tail of @dst out of the way, then copy in @src. */ ntfs_rl_mm(dst, magic, loc + right + 1, dsize - loc - right - 1); ntfs_rl_mc(dst, loc, src, left, ssize - left); /* We may have changed the length of the file, so fix the end marker */ if (dst[magic].lcn == LCN_ENOENT) dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length; return dst;}/** * ntfs_rl_split - insert a runlist into the centre of a hole * @dst: original runlist to be worked on * @dsize: number of elements in @dst (including end marker) * @src: new runlist to be inserted * @ssize: number of elements in @src (excluding end marker) * @loc: index in runlist @dst at which to split and insert @src * * Split the runlist @dst at @loc into two and insert @new in between the two * fragments. No merging of runlists is necessary. Adjust the size of the * holes either side. * * It is up to the caller to serialize access to the runlists @dst and @src. * * On success, return a pointer to the new, combined, runlist. Note, both * runlists @dst and @src are deallocated before returning so you cannot use * the pointers for anything any more. (Strictly speaking the returned runlist * may be the same as @dst but this is irrelevant.) * * On error, return -errno. Both runlists are left unmodified. The following * error codes are defined: * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. */static inline runlist_element *ntfs_rl_split(runlist_element *dst, int dsize, runlist_element *src, int ssize, int loc){ BUG_ON(!dst); BUG_ON(!src); /* Space required: @dst size + @src size + one new hole. */ dst = ntfs_rl_realloc(dst, dsize, dsize + ssize + 1); if (IS_ERR(dst)) return dst; /* * We are guaranteed to succeed from here so can start modifying the * original runlists. */ /* Move the tail of @dst out of the way, then copy in @src. */ ntfs_rl_mm(dst, loc + 1 + ssize, loc, dsize - loc); ntfs_rl_mc(dst, loc + 1, src, 0, ssize); /* Adjust the size of the holes either size of @src. */ dst[loc].length = dst[loc+1].vcn - dst[loc].vcn; dst[loc+ssize+1].vcn = dst[loc+ssize].vcn + dst[loc+ssize].length; dst[loc+ssize+1].length = dst[loc+ssize+2].vcn - dst[loc+ssize+1].vcn; return dst;}/** * ntfs_merge_runlists - merge two runlists into one * @drl: original runlist to be worked on * @srl: new runlist to be merged into @drl * * First we sanity check the two runlists @srl and @drl to make sure that they * are sensible and can be merged. The runlist @srl must be either after the * runlist @drl or completely within a hole (or unmapped region) in @drl. * * It is up to the caller to serialize access to the runlists @drl and @srl. * * Merging of runlists is necessary in two cases: * 1. When attribute lists are used and a further extent is being mapped. * 2. When new clusters are allocated to fill a hole or extend a file. * * There are four possible ways @srl can be merged. It can: * - be inserted at the beginning of a hole, * - split the hole in two and be inserted between the two fragments, * - be appended at the end of a hole, or it can * - replace the whole hole. * It can also be appended to the end of the runlist, which is just a variant * of the insert case. * * On success, return a pointer to the new, combined, runlist. Note, both * runlists @drl and @srl are deallocated before returning so you cannot use * the pointers for anything any more. (Strictly speaking the returned runlist * may be the same as @dst but this is irrelevant.) * * On error, return -errno. Both runlists are left unmodified. The following * error codes are defined: * -ENOMEM - Not enough memory to allocate runlist array. * -EINVAL - Invalid parameters were passed in. * -ERANGE - The runlists overlap and cannot be merged. */runlist_element *ntfs_merge_runlists(runlist_element *drl, runlist_element *srl){ int di, si; /* Current index into @[ds]rl. */ int sstart; /* First index with lcn > LCN_RL_NOT_MAPPED. */ int dins; /* Index into @drl at which to insert @srl. */ int dend, send; /* Last index into @[ds]rl. */ int dfinal, sfinal; /* The last index into @[ds]rl with lcn >= LCN_HOLE. */ int marker = 0; VCN marker_vcn = 0;#ifdef DEBUG ntfs_debug("dst:"); ntfs_debug_dump_runlist(drl); ntfs_debug("src:"); ntfs_debug_dump_runlist(srl);#endif /* Check for silly calling... */ if (unlikely(!srl)) return drl; if (IS_ERR(srl) || IS_ERR(drl)) return ERR_PTR(-EINVAL); /* Check for the case where the first mapping is being done now. */ if (unlikely(!drl)) { drl = srl; /* Complete the source runlist if necessary. */ if (unlikely(drl[0].vcn)) { /* Scan to the end of the source runlist. */ for (dend = 0; likely(drl[dend].length); dend++) ; drl = ntfs_rl_realloc(drl, dend, dend + 1); if (IS_ERR(drl)) return drl; /* Insert start element at the front of the runlist. */ ntfs_rl_mm(drl, 1, 0, dend); drl[0].vcn = 0; drl[0].lcn = LCN_RL_NOT_MAPPED; drl[0].length = drl[1].vcn; } goto finished; } si = di = 0; /* Skip any unmapped start element(s) in the source runlist. */ while (srl[si].length && srl[si].lcn < (LCN)LCN_HOLE) si++; /* Can't have an entirely unmapped source runlist. */ BUG_ON(!srl[si].length); /* Record the starting points. */ sstart = si; /* * Skip forward in @drl until we reach the position where @srl needs to * be inserted. If we reach the end of @drl, @srl just needs to be * appended to @drl. */ for (; drl[di].length; di++) { if (drl[di].vcn + drl[di].length > srl[sstart].vcn) break; } dins = di; /* Sanity check for illegal overlaps. */ if ((drl[di].vcn == srl[si].vcn) && (drl[di].lcn >= 0) && (srl[si].lcn >= 0)) { ntfs_error(NULL, "Run lists overlap. Cannot merge!"); return ERR_PTR(-ERANGE); } /* Scan to the end of both runlists in order to know their sizes. */ for (send = si; srl[send].length; send++) ; for (dend = di; drl[dend].length; dend++) ; if (srl[send].lcn == (LCN)LCN_ENOENT) marker_vcn = srl[marker = send].vcn; /* Scan to the last element with lcn >= LCN_HOLE. */ for (sfinal = send; sfinal >= 0 && srl[sfinal].lcn < LCN_HOLE; sfinal--) ; for (dfinal = dend; dfinal >= 0 && drl[dfinal].lcn < LCN_HOLE; dfinal--) ; { BOOL start; BOOL finish; int ds = dend + 1; /* Number of elements in drl & srl */ int ss = sfinal - sstart + 1; start = ((drl[dins].lcn < LCN_RL_NOT_MAPPED) || /* End of file */ (drl[dins].vcn == srl[sstart].vcn)); /* Start of hole */ finish = ((drl[dins].lcn >= LCN_RL_NOT_MAPPED) && /* End of file */ ((drl[dins].vcn + drl[dins].length) <= /* End of hole */ (srl[send - 1].vcn + srl[send - 1].length))); /* Or we'll lose an end marker */ if (start && finish && (drl[dins].length == 0)) ss++; if (marker && (drl[dins].vcn + drl[dins].length > srl[send - 1].vcn)) finish = FALSE;#if 0 ntfs_debug("dfinal = %i, dend = %i", dfinal, dend); ntfs_debug("sstart = %i, sfinal = %i, send = %i", sstart, sfinal, send); ntfs_debug("start = %i, finish = %i", start, finish); ntfs_debug("ds = %i, ss = %i, dins = %i", ds, ss, dins);#endif if (start) { if (finish) drl = ntfs_rl_replace(drl, ds, srl + sstart, ss, dins); else drl = ntfs_rl_insert(drl, ds, srl + sstart, ss, dins); } else { if (finish) drl = ntfs_rl_append(drl, ds, srl + sstart, ss, dins); else drl = ntfs_rl_split(drl, ds, srl + sstart, ss, dins); } if (IS_ERR(drl)) { ntfs_error(NULL, "Merge failed."); return drl; } ntfs_free(srl); if (marker) { ntfs_debug("Triggering marker code."); for (ds = dend; drl[ds].length; ds++) ; /* We only need to care if @srl ended after @drl. */ if (drl[ds].vcn <= marker_vcn) { int slots = 0; if (drl[ds].vcn == marker_vcn) { ntfs_debug("Old marker = 0x%llx, replacing " "with LCN_ENOENT.", (unsigned long long) drl[ds].lcn); drl[ds].lcn = (LCN)LCN_ENOENT; goto finished; } /* * We need to create an unmapped runlist element in * @drl or extend an existing one before adding the * ENOENT terminator. */ if (drl[ds].lcn == (LCN)LCN_ENOENT) { ds--; slots = 1; } if (drl[ds].lcn != (LCN)LCN_RL_NOT_MAPPED) { /* Add an unmapped runlist element. */ if (!slots) { /* FIXME/TODO: We need to have the * extra memory already! (AIA) */ drl = ntfs_rl_realloc(drl, ds, ds + 2); if (!drl) goto critical_error; slots = 2; } ds++; /* Need to set vcn if it isn't set already. */ if (slots != 1) drl[ds].vcn = drl[ds - 1].vcn + drl[ds - 1].length; drl[ds].lcn = (LCN)LCN_RL_NOT_MAPPED; /* We now used up a slot. */ slots--; } drl[ds].length = marker_vcn - drl[ds].vcn; /* Finally add the ENOENT terminator. */ ds++; if (!slots) { /* FIXME/TODO: We need to have the extra * memory already! (AIA) */ drl = ntfs_rl_realloc(drl, ds, ds + 1); if (!drl) goto critical_error; } drl[ds].vcn = marker_vcn; drl[ds].lcn = (LCN)LCN_ENOENT; drl[ds].length = (s64)0; } } }finished: /* The merge was completed successfully. */ ntfs_debug("Merged runlist:"); ntfs_debug_dump_runlist(drl); return drl;critical_error: /* Critical error! We cannot afford to fail here. */ ntfs_error(NULL, "Critical error! Not enough memory."); panic("NTFS: Cannot continue.");}/** * decompress_mapping_pairs - convert mapping pairs array to runlist * @vol: ntfs volume on which the attribute resides * @attr: attribute record whose mapping pairs array to decompress * @old_rl: optional runlist in which to insert @attr's runlist * * It is up to the caller to serialize access to the runlist @old_rl. * * Decompress the attribute @attr's mapping pairs array into a runlist. On * success, return the decompressed runlist. * * If @old_rl is not NULL, decompressed runlist is inserted into the * appropriate place in @old_rl and the resultant, combined runlist is * returned. The original @old_rl is deallocated. * * On error, return -errno. @old_rl is left unmodified in that case. * * The following error codes are defined: * -ENOMEM - Not enough memory to allocate runlist array. * -EIO - Corrupt runlist. * -EINVAL - Invalid parameters were passed in. * -ERANGE - The two runlists overlap. * * FIXME: For now we take the conceptionally simplest approach of creating the * new runlist disregarding the already existing one and then splicing the * two into one, if that is possible (we check for overlap and discard the new * runlist if overlap present before returning ERR_PTR(-ERANGE)). */runlist_element *decompress_mapping_pairs(const ntfs_volume *vol, const ATTR_RECORD *attr, runlist_element *old_rl){ VCN vcn; /* Current vcn. */ LCN lcn; /* Current lcn. */ s64 deltaxcn; /* Change in [vl]cn. */ runlist_element *rl; /* The output runlist. */ u8 *buf; /* Current position in mapping pairs array. */ u8 *attr_end; /* End of attribute. */ int rlsize; /* Size of runlist buffer. */ u16 rlpos; /* Current runlist position in units of runlist_elements. */ u8 b; /* Current byte offset in buf. */#ifdef DEBUG /* Make sure attr exists and is non-resident. */ if (!attr || !attr->non_resident || sle64_to_cpu( attr->data.non_resident.lowest_vcn) < (VCN)0) { ntfs_error(vol->sb, "Invalid arguments."); return ERR_PTR(-EINVAL); }#endif /* Start at vcn = lowest_vcn and lcn 0. */ vcn = sle64_to_cpu(attr->data.non_resident.lowest_vcn); lcn = 0; /* Get start of the mapping pairs array. */ buf = (u8*)attr + le16_to_cpu( attr->data.non_resident.mapping_pairs_offset); attr_end = (u8*)attr + le32_to_cpu(attr->length); if (unlikely(buf < (u8*)attr || buf > attr_end)) { ntfs_error(vol->sb, "Corrupt attribute."); return ERR_PTR(-EIO); } /* Current position in runlist array. */ rlpos = 0; /* Allocate first page and set current runlist size to one page. */ rl = ntfs_malloc_nofs(rlsize = PAGE_SIZE); if (unlikely(!rl)) return ERR_PTR(-ENOMEM); /* Insert unmapped starting element if necessary. */ if (vcn) { rl->vcn = (VCN)0; rl->lcn = (LCN)LCN_RL_NOT_MAPPED; rl->length = vcn; rlpos++; } while (buf < attr_end && *buf) { /* * Allocate more memory if needed, including space for the
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?