attrib.c
来自「一个类似windows」· C语言 代码 · 共 1,722 行 · 第 1/4 页
C
1,722 行
/**
* attrib.c - NTFS attribute operations. Part of the Linux-NTFS project.
*
* Copyright (c) 2001-2003 Anton Altaparmakov
* Copyright (c) 2002 Richard Russon
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the Linux-NTFS
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/buffer_head.h>
#include "ntfs.h"
#include "dir.h"
/* Temporary helper functions -- might become macros */
/**
* ntfs_rl_mm - run_list memmove
*
* It is up to the caller to serialize access to the run list @base.
*/
static inline void ntfs_rl_mm(run_list_element *base, int dst, int src,
int size)
{
if (likely((dst != src) && (size > 0)))
memmove(base + dst, base + src, size * sizeof (*base));
}
/**
* ntfs_rl_mc - run_list memory copy
*
* It is up to the caller to serialize access to the run lists @dstbase and
* @srcbase.
*/
static inline void ntfs_rl_mc(run_list_element *dstbase, int dst,
run_list_element *srcbase, int src, int size)
{
if (likely(size > 0))
memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase));
}
/**
* ntfs_rl_realloc - Reallocate memory for run_lists
* @rl: original run list
* @old_size: number of run list elements in the original run list @rl
* @new_size: number of run list elements we need space for
*
* As the run_lists grow, more memory will be required. To prevent the
* kernel having to allocate and reallocate large numbers of small bits of
* memory, this function returns and entire page of memory.
*
* It is up to the caller to serialize access to the run list @rl.
*
* N.B. If the new allocation doesn't require a different number of pages in
* memory, the function will return the original pointer.
*
* On success, return a pointer to the newly allocated, or recycled, memory.
* On error, return -errno. The following error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static inline run_list_element *ntfs_rl_realloc(run_list_element *rl,
int old_size, int new_size)
{
run_list_element *new_rl;
old_size = PAGE_ALIGN(old_size * sizeof(*rl));
new_size = PAGE_ALIGN(new_size * sizeof(*rl));
if (old_size == new_size)
return rl;
new_rl = ntfs_malloc_nofs(new_size);
if (unlikely(!new_rl))
return ERR_PTR(-ENOMEM);
if (likely(rl != NULL)) {
if (unlikely(old_size > new_size))
old_size = new_size;
memcpy(new_rl, rl, old_size);
ntfs_free(rl);
}
return new_rl;
}
/**
* ntfs_are_rl_mergeable - test if two run lists can be joined together
* @dst: original run list
* @src: new run list to test for mergeability with @dst
*
* Test if two run lists can be joined together. For this, their VCNs and LCNs
* must be adjacent.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* Return: TRUE Success, the run lists can be merged.
* FALSE Failure, the run lists cannot be merged.
*/
static inline BOOL ntfs_are_rl_mergeable(run_list_element *dst,
run_list_element *src)
{
BUG_ON(!dst);
BUG_ON(!src);
if ((dst->lcn < 0) || (src->lcn < 0)) /* Are we merging holes? */
return FALSE;
if ((dst->lcn + dst->length) != src->lcn) /* Are the runs contiguous? */
return FALSE;
if ((dst->vcn + dst->length) != src->vcn) /* Are the runs misaligned? */
return FALSE;
return TRUE;
}
/**
* __ntfs_rl_merge - merge two run lists without testing if they can be merged
* @dst: original, destination run list
* @src: new run list to merge with @dst
*
* Merge the two run lists, writing into the destination run list @dst. The
* caller must make sure the run lists can be merged or this will corrupt the
* destination run list.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*/
static inline void __ntfs_rl_merge(run_list_element *dst, run_list_element *src)
{
dst->length += src->length;
}
/**
* ntfs_rl_merge - test if two run lists can be joined together and merge them
* @dst: original, destination run list
* @src: new run list to merge with @dst
*
* Test if two run lists can be joined together. For this, their VCNs and LCNs
* must be adjacent. If they can be merged, perform the merge, writing into
* the destination run list @dst.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* Return: TRUE Success, the run lists have been merged.
* FALSE Failure, the run lists cannot be merged and have not been
* modified.
*/
static inline BOOL ntfs_rl_merge(run_list_element *dst, run_list_element *src)
{
BOOL merge = ntfs_are_rl_mergeable(dst, src);
if (merge)
__ntfs_rl_merge(dst, src);
return merge;
}
/**
* ntfs_rl_append - append a run list after a given element
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: run list to be inserted into @dst
* @ssize: number of elements in @src (excluding end marker)
* @loc: append the new run list @src after this element in @dst
*
* Append the run list @src after element @loc in @dst. Merge the right end of
* the new run list, if necessary. Adjust the size of the hole before the
* appended run list.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static inline run_list_element *ntfs_rl_append(run_list_element *dst,
int dsize, run_list_element *src, int ssize, int loc)
{
BOOL right;
int magic;
BUG_ON(!dst);
BUG_ON(!src);
/* First, check if the right hand end needs merging. */
right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
/* Space required: @dst size + @src size, less one if we merged. */
dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - right);
if (IS_ERR(dst))
return dst;
/*
* We are guaranteed to succeed from here so can start modifying the
* original run lists.
*/
/* First, merge the right hand end, if necessary. */
if (right)
__ntfs_rl_merge(src + ssize - 1, dst + loc + 1);
magic = loc + ssize;
/* Move the tail of @dst out of the way, then copy in @src. */
ntfs_rl_mm(dst, magic + 1, loc + 1 + right, dsize - loc - 1 - right);
ntfs_rl_mc(dst, loc + 1, src, 0, ssize);
/* Adjust the size of the preceding hole. */
dst[loc].length = dst[loc + 1].vcn - dst[loc].vcn;
/* We may have changed the length of the file, so fix the end marker */
if (dst[magic + 1].lcn == LCN_ENOENT)
dst[magic + 1].vcn = dst[magic].vcn + dst[magic].length;
return dst;
}
/**
* ntfs_rl_insert - insert a run list into another
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: new run list to be inserted
* @ssize: number of elements in @src (excluding end marker)
* @loc: insert the new run list @src before this element in @dst
*
* Insert the run list @src before element @loc in the run list @dst. Merge the
* left end of the new run list, if necessary. Adjust the size of the hole
* after the inserted run list.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static inline run_list_element *ntfs_rl_insert(run_list_element *dst,
int dsize, run_list_element *src, int ssize, int loc)
{
BOOL left = FALSE;
BOOL disc = FALSE; /* Discontinuity */
BOOL hole = FALSE; /* Following a hole */
int magic;
BUG_ON(!dst);
BUG_ON(!src);
/* disc => Discontinuity between the end of @dst and the start of @src.
* This means we might need to insert a hole.
* hole => @dst ends with a hole or an unmapped region which we can
* extend to match the discontinuity. */
if (loc == 0)
disc = (src[0].vcn > 0);
else {
s64 merged_length;
left = ntfs_are_rl_mergeable(dst + loc - 1, src);
merged_length = dst[loc - 1].length;
if (left)
merged_length += src->length;
disc = (src[0].vcn > dst[loc - 1].vcn + merged_length);
if (disc)
hole = (dst[loc - 1].lcn == LCN_HOLE);
}
/* Space required: @dst size + @src size, less one if we merged, plus
* one if there was a discontinuity, less one for a trailing hole. */
dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left + disc - hole);
if (IS_ERR(dst))
return dst;
/*
* We are guaranteed to succeed from here so can start modifying the
* original run list.
*/
if (left)
__ntfs_rl_merge(dst + loc - 1, src);
magic = loc + ssize - left + disc - hole;
/* Move the tail of @dst out of the way, then copy in @src. */
ntfs_rl_mm(dst, magic, loc, dsize - loc);
ntfs_rl_mc(dst, loc + disc - hole, src, left, ssize - left);
/* Adjust the VCN of the last run ... */
if (dst[magic].lcn <= LCN_HOLE)
dst[magic].vcn = dst[magic - 1].vcn + dst[magic - 1].length;
/* ... and the length. */
if (dst[magic].lcn == LCN_HOLE || dst[magic].lcn == LCN_RL_NOT_MAPPED)
dst[magic].length = dst[magic + 1].vcn - dst[magic].vcn;
/* Writing beyond the end of the file and there's a discontinuity. */
if (disc) {
if (hole)
dst[loc - 1].length = dst[loc].vcn - dst[loc - 1].vcn;
else {
if (loc > 0) {
dst[loc].vcn = dst[loc - 1].vcn +
dst[loc - 1].length;
dst[loc].length = dst[loc + 1].vcn -
dst[loc].vcn;
} else {
dst[loc].vcn = 0;
dst[loc].length = dst[loc + 1].vcn;
}
dst[loc].lcn = LCN_RL_NOT_MAPPED;
}
magic += hole;
if (dst[magic].lcn == LCN_ENOENT)
dst[magic].vcn = dst[magic - 1].vcn +
dst[magic - 1].length;
}
return dst;
}
/**
* ntfs_rl_replace - overwrite a run_list element with another run list
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: new run list to be inserted
* @ssize: number of elements in @src (excluding end marker)
* @loc: index in run list @dst to overwrite with @src
*
* Replace the run list element @dst at @loc with @src. Merge the left and
* right ends of the inserted run list, if necessary.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static inline run_list_element *ntfs_rl_replace(run_list_element *dst,
int dsize, run_list_element *src, int ssize, int loc)
{
BOOL left = FALSE;
BOOL right;
int magic;
BUG_ON(!dst);
BUG_ON(!src);
/* First, merge the left and right ends, if necessary. */
right = ntfs_are_rl_mergeable(src + ssize - 1, dst + loc + 1);
if (loc > 0)
left = ntfs_are_rl_mergeable(dst + loc - 1, src);
/* Allocate some space. We'll need less if the left, right, or both
* ends were merged. */
dst = ntfs_rl_realloc(dst, dsize, dsize + ssize - left - right);
if (IS_ERR(dst))
return dst;
/*
* We are guaranteed to succeed from here so can start modifying the
* original run lists.
*/
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 run list into the centre of a hole
* @dst: original run list to be worked on
* @dsize: number of elements in @dst (including end marker)
* @src: new run list to be inserted
* @ssize: number of elements in @src (excluding end marker)
* @loc: index in run list @dst at which to split and insert @src
*
* Split the run list @dst at @loc into two and insert @new in between the two
* fragments. No merging of run lists is necessary. Adjust the size of the
* holes either side.
*
* It is up to the caller to serialize access to the run lists @dst and @src.
*
* On success, return a pointer to the new, combined, run list. Note, both
* run lists @dst and @src are deallocated before returning so you cannot use
* the pointers for anything any more. (Strictly speaking the returned run list
* may be the same as @dst but this is irrelevant.)
*
* On error, return -errno. Both run lists are left unmodified. The following
* error codes are defined:
* -ENOMEM - Not enough memory to allocate run list array.
* -EINVAL - Invalid parameters were passed in.
*/
static inline run_list_element *ntfs_rl_split(run_list_element *dst, int dsize,
run_list_element *src, int ssize, int loc)
{
BUG_ON(!dst);
BUG_ON(!src);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?