attrib.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,911 行 · 第 1/5 页

C
1,911
字号
/** * attrib.c - NTFS attribute operations. Part of the Linux-NTFS project. * * Copyright (c) 2001-2004 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 - runlist memmove * * It is up to the caller to serialize access to the runlist @base. */static inline void ntfs_rl_mm(runlist_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 - runlist memory copy * * It is up to the caller to serialize access to the runlists @dstbase and * @srcbase. */static inline void ntfs_rl_mc(runlist_element *dstbase, int dst,		runlist_element *srcbase, int src, int size){	if (likely(size > 0))		memcpy(dstbase + dst, srcbase + src, size * sizeof(*dstbase));}/** * ntfs_rl_realloc - Reallocate memory for runlists * @rl:		original runlist * @old_size:	number of runlist elements in the original runlist @rl * @new_size:	number of runlist elements we need space for * * As the runlists 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 runlist @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 runlist array. *	-EINVAL	- Invalid parameters were passed in. */static inline runlist_element *ntfs_rl_realloc(runlist_element *rl,		int old_size, int new_size){	runlist_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 runlists can be joined together * @dst:	original runlist * @src:	new runlist to test for mergeability with @dst * * Test if two runlists can be joined together. For this, their VCNs and LCNs * must be adjacent. * * It is up to the caller to serialize access to the runlists @dst and @src. * * Return: TRUE   Success, the runlists can be merged. *	   FALSE  Failure, the runlists cannot be merged. */static inline BOOL ntfs_are_rl_mergeable(runlist_element *dst,		runlist_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 runlists without testing if they can be merged * @dst:	original, destination runlist * @src:	new runlist to merge with @dst * * Merge the two runlists, writing into the destination runlist @dst. The * caller must make sure the runlists can be merged or this will corrupt the * destination runlist. * * It is up to the caller to serialize access to the runlists @dst and @src. */static inline void __ntfs_rl_merge(runlist_element *dst, runlist_element *src){	dst->length += src->length;}/** * ntfs_rl_merge - test if two runlists can be joined together and merge them * @dst:	original, destination runlist * @src:	new runlist to merge with @dst * * Test if two runlists 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 runlist @dst. * * It is up to the caller to serialize access to the runlists @dst and @src. * * Return: TRUE   Success, the runlists have been merged. *	   FALSE  Failure, the runlists cannot be merged and have not been *		  modified. */static inline BOOL ntfs_rl_merge(runlist_element *dst, runlist_element *src){	BOOL merge = ntfs_are_rl_mergeable(dst, src);	if (merge)		__ntfs_rl_merge(dst, src);	return merge;}/** * ntfs_rl_append - append a runlist after a given element * @dst:	original runlist to be worked on * @dsize:	number of elements in @dst (including end marker) * @src:	runlist to be inserted into @dst * @ssize:	number of elements in @src (excluding end marker) * @loc:	append the new runlist @src after this element in @dst * * Append the runlist @src after element @loc in @dst.  Merge the right end of * the new runlist, if necessary. Adjust the size of the hole before the * appended runlist. * * 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_append(runlist_element *dst,		int dsize, runlist_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 runlists.	 */	/* 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 runlist into another * @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:	insert the new runlist @src before this element in @dst * * Insert the runlist @src before element @loc in the runlist @dst. Merge the * left end of the new runlist, if necessary. Adjust the size of the hole * after the inserted runlist. * * 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_insert(runlist_element *dst,		int dsize, runlist_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 runlist.	 */	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 runlist element with another runlist * @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 to overwrite with @src * * Replace the runlist element @dst at @loc with @src. Merge the left and * right ends of the inserted runlist, if necessary. * * 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_replace(runlist_element *dst,		int dsize, runlist_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 runlists.

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?