⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dir.c

📁 上一个上传的有问题,这个是好的。visopsys包括系统内核和GUI的全部SOURCE code ,还包括一些基本的docs文档。里面src子目录对应所有SOURCE code.对于想研究操作系统的朋
💻 C
📖 第 1 页 / 共 4 页
字号:
/** * dir.c - Directory handling code. Part of the Linux-NTFS project. * * Copyright (c) 2002-2005 Anton Altaparmakov * Copyright (c) 2005-2006 Yura Pakhuchiy * Copyright (c) 2004-2005 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 * * Modified 01/2007 by Andy McLaughlin for Visopsys port. */#ifdef HAVE_CONFIG_H#include "config.h"#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef HAVE_ERRNO_H#include <errno.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif#ifdef HAVE_SYS_SYSMACROS_H#include <sys/sysmacros.h>#endif#include "types.h"#include "debug.h"#include "attrib.h"#include "inode.h"#include "dir.h"#include "volume.h"#include "mft.h"#include "index.h"#include "ntfstime.h"#include "lcnalloc.h"#include "logging.h"/* * The little endian Unicode strings "$I30", "$SII", "$SDH", "$O" *  and "$Q" as global constants. */ntfschar NTFS_INDEX_I30[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('I'),		const_cpu_to_le16('3'), const_cpu_to_le16('0'),		const_cpu_to_le16('\0') };ntfschar NTFS_INDEX_SII[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'),		const_cpu_to_le16('I'), const_cpu_to_le16('I'),		const_cpu_to_le16('\0') };ntfschar NTFS_INDEX_SDH[5] = { const_cpu_to_le16('$'), const_cpu_to_le16('S'),		const_cpu_to_le16('D'), const_cpu_to_le16('H'),		const_cpu_to_le16('\0') };ntfschar NTFS_INDEX_O[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('O'),		const_cpu_to_le16('\0') };ntfschar NTFS_INDEX_Q[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('Q'),		const_cpu_to_le16('\0') };ntfschar NTFS_INDEX_R[3] = { const_cpu_to_le16('$'), const_cpu_to_le16('R'),		const_cpu_to_le16('\0') };/** * ntfs_inode_lookup_by_name - find an inode in a directory given its name * @dir_ni:	ntfs inode of the directory in which to search for the name * @uname:	Unicode name for which to search in the directory * @uname_len:	length of the name @uname in Unicode characters * * Look for an inode with name @uname in the directory with inode @dir_ni. * ntfs_inode_lookup_by_name() walks the contents of the directory looking for * the Unicode name. If the name is found in the directory, the corresponding * inode number (>= 0) is returned as a mft reference in cpu format, i.e. it * is a 64-bit number containing the sequence number. * * On error, return -1 with errno set to the error code. If the inode is is not * found errno is ENOENT. * * Note, @uname_len does not include the (optional) terminating NULL character. * * Note, we look for a case sensitive match first but we also look for a case * insensitive match at the same time. If we find a case insensitive match, we * save that for the case that we don't find an exact match, where we return * the mft reference of the case insensitive match. * * If the volume is mounted with the case sensitive flag set, then we only * allow exact matches. */u64 ntfs_inode_lookup_by_name(ntfs_inode *dir_ni, const ntfschar *uname,		const int uname_len){	VCN vcn;	u64 mref = 0;	s64 br;	ntfs_volume *vol = dir_ni->vol;	ntfs_attr_search_ctx *ctx;	INDEX_ROOT *ir;	INDEX_ENTRY *ie;	INDEX_ALLOCATION *ia;	u8 *index_end;	ntfs_attr *ia_na;	int eo, rc;	u32 index_block_size, index_vcn_size;	u8 index_vcn_size_bits;	if (!dir_ni || !dir_ni->mrec || !uname || uname_len <= 0) {		errno = EINVAL;		return -1;	}	ctx = ntfs_attr_get_search_ctx(dir_ni, NULL);	if (!ctx)		return -1;	/* Find the index root attribute in the mft record. */	if (ntfs_attr_lookup(AT_INDEX_ROOT, NTFS_INDEX_I30, 4, CASE_SENSITIVE, 0, NULL,			0, ctx)) {		ntfs_log_perror("Index root attribute missing in directory inode "				"0x%llx", (unsigned long long)dir_ni->mft_no);		goto put_err_out;	}	/* Get to the index root value. */	ir = (INDEX_ROOT*)((u8*)ctx->attr +			le16_to_cpu(ctx->attr->value_offset));	index_block_size = le32_to_cpu(ir->index_block_size);	if (index_block_size < NTFS_BLOCK_SIZE ||			index_block_size & (index_block_size - 1)) {		ntfs_log_debug("Index block size %u is invalid.\n",				(unsigned)index_block_size);		goto put_err_out;	}	index_end = (u8*)&ir->index + le32_to_cpu(ir->index.index_length);	/* The first index entry. */	ie = (INDEX_ENTRY*)((u8*)&ir->index +			le32_to_cpu(ir->index.entries_offset));	/*	 * Loop until we exceed valid memory (corruption case) or until we	 * reach the last entry.	 */	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {		/* Bounds checks. */		if ((u8*)ie < (u8*)ctx->mrec || (u8*)ie +				sizeof(INDEX_ENTRY_HEADER) > index_end ||				(u8*)ie + le16_to_cpu(ie->key_length) >				index_end)			goto put_err_out;		/*		 * The last entry cannot contain a name. It can however contain		 * a pointer to a child node in the B+tree so we just break out.		 */		if (ie->flags & INDEX_ENTRY_END)			break;		/*		 * We perform a case sensitive comparison and if that matches		 * we are done and return the mft reference of the inode (i.e.		 * the inode number together with the sequence number for		 * consistency checking). We convert it to cpu format before		 * returning.		 */		if (ntfs_names_are_equal(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length,				CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {found_it:			/*			 * We have a perfect match, so we don't need to care			 * about having matched imperfectly before.			 */			mref = le64_to_cpu(ie->indexed_file);			ntfs_attr_put_search_ctx(ctx);			return mref;		}		/*		 * For a case insensitive mount, we also perform a case		 * insensitive comparison (provided the file name is not in the		 * POSIX namespace). If the comparison matches, we cache the		 * mft reference in mref.		 */		if (!NVolCaseSensitive(vol) &&				ie->key.file_name.file_name_type &&				ntfs_names_are_equal(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length,				IGNORE_CASE, vol->upcase, vol->upcase_len)) {			/* Only one case insensitive matching name allowed. */			if (mref) {				ntfs_log_error("Found already cached mft "						"reference in phase 1. Please "						"run chkdsk and if that doesn't"						" find any errors please report"						" you saw this message to %s\n",						NTFS_DEV_LIST);				goto put_err_out;			}			mref = le64_to_cpu(ie->indexed_file);		}		/*		 * Not a perfect match, need to do full blown collation so we		 * know which way in the B+tree we have to go.		 */		rc = ntfs_names_collate(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length, 1,				IGNORE_CASE, vol->upcase, vol->upcase_len);		/*		 * If uname collates before the name of the current entry, there		 * is definitely no such name in this index but we might need to		 * descend into the B+tree so we just break out of the loop.		 */		if (rc == -1)			break;		/* The names are not equal, continue the search. */		if (rc)			continue;		/*		 * Names match with case insensitive comparison, now try the		 * case sensitive comparison, which is required for proper		 * collation.		 */		rc = ntfs_names_collate(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length, 1,				CASE_SENSITIVE, vol->upcase, vol->upcase_len);		if (rc == -1)			break;		if (rc)			continue;		/*		 * Perfect match, this will never happen as the		 * ntfs_are_names_equal() call will have gotten a match but we		 * still treat it correctly.		 */		goto found_it;	}	/*	 * We have finished with this index without success. Check for the	 * presence of a child node and if not present return error code	 * ENOENT, unless we have got the mft reference of a matching name	 * cached in mref in which case return mref.	 */	if (!(ie->flags & INDEX_ENTRY_NODE)) {		ntfs_attr_put_search_ctx(ctx);		if (mref)			return mref;		ntfs_log_debug("Entry not found.\n");		errno = ENOENT;		return -1;	} /* Child node present, descend into it. */	/* Open the index allocation attribute. */	ia_na = ntfs_attr_open(dir_ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);	if (!ia_na) {		ntfs_log_perror("Failed to open index allocation attribute. Directory "				"inode 0x%llx is corrupt or driver bug",				(unsigned long long)dir_ni->mft_no);		goto put_err_out;	}	/* Allocate a buffer for the current index block. */	ia = (INDEX_ALLOCATION*)malloc(index_block_size);	if (!ia) {		ntfs_log_perror("Failed to allocate buffer for index block");		ntfs_attr_close(ia_na);		goto put_err_out;	}	/* Determine the size of a vcn in the directory index. */	if (vol->cluster_size <= index_block_size) {		index_vcn_size = vol->cluster_size;		index_vcn_size_bits = vol->cluster_size_bits;	} else {		index_vcn_size = vol->sector_size;		index_vcn_size_bits = vol->sector_size_bits;	}	/* Get the starting vcn of the index_block holding the child node. */	vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);descend_into_child_node:	/* Read the index block starting at vcn. */	br = ntfs_attr_mst_pread(ia_na, vcn << index_vcn_size_bits, 1,			index_block_size, ia);	if (br != 1) {		if (br != -1)			errno = EIO;		ntfs_log_perror("Failed to read vcn 0x%llx", vcn);		goto close_err_out;	}	if (sle64_to_cpu(ia->index_block_vcn) != vcn) {		ntfs_log_debug("Actual VCN (0x%llx) of index buffer is different "				"from expected VCN (0x%llx).\n",				(long long)sle64_to_cpu(ia->index_block_vcn),				(long long)vcn);		errno = EIO;		goto close_err_out;	}	if (le32_to_cpu(ia->index.allocated_size) + 0x18 != index_block_size) {		ntfs_log_debug("Index buffer (VCN 0x%llx) of directory inode 0x%llx "				"has a size (%u) differing from the directory "				"specified size (%u).\n", (long long)vcn,				(unsigned long long)dir_ni->mft_no,				(unsigned) le32_to_cpu(ia->index.allocated_size) + 0x18,				(unsigned)index_block_size);		errno = EIO;		goto close_err_out;	}	index_end = (u8*)&ia->index + le32_to_cpu(ia->index.index_length);	if (index_end > (u8*)ia + index_block_size) {		ntfs_log_debug("Size of index buffer (VCN 0x%llx) of directory inode "				"0x%llx exceeds maximum size.\n",				(long long)vcn, (unsigned long long)dir_ni->mft_no);		errno = EIO;		goto close_err_out;	}	/* The first index entry. */	ie = (INDEX_ENTRY*)((u8*)&ia->index +			le32_to_cpu(ia->index.entries_offset));	/*	 * Iterate similar to above big loop but applied to index buffer, thus	 * loop until we exceed valid memory (corruption case) or until we	 * reach the last entry.	 */	for (;; ie = (INDEX_ENTRY*)((u8*)ie + le16_to_cpu(ie->length))) {		/* Bounds check. */		if ((u8*)ie < (u8*)ia || (u8*)ie +				sizeof(INDEX_ENTRY_HEADER) > index_end ||				(u8*)ie + le16_to_cpu(ie->key_length) >				index_end) {			ntfs_log_debug("Index entry out of bounds in directory "					"inode 0x%llx.\n",					(unsigned long long)dir_ni->mft_no);			errno = EIO;			goto close_err_out;		}		/*		 * The last entry cannot contain a name. It can however contain		 * a pointer to a child node in the B+tree so we just break out.		 */		if (ie->flags & INDEX_ENTRY_END)			break;		/*		 * We perform a case sensitive comparison and if that matches		 * we are done and return the mft reference of the inode (i.e.		 * the inode number together with the sequence number for		 * consistency checking). We convert it to cpu format before		 * returning.		 */		if (ntfs_names_are_equal(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length,				CASE_SENSITIVE, vol->upcase, vol->upcase_len)) {found_it2:			/*			 * We have a perfect match, so we don't need to care			 * about having matched imperfectly before.			 */			mref = le64_to_cpu(ie->indexed_file);			free(ia);			ntfs_attr_close(ia_na);			ntfs_attr_put_search_ctx(ctx);			return mref;		}		/*		 * For a case insensitive mount, we also perform a case		 * insensitive comparison (provided the file name is not in the		 * POSIX namespace). If the comparison matches, we cache the		 * mft reference in mref.		 */		if (!NVolCaseSensitive(vol) &&				ie->key.file_name.file_name_type &&				ntfs_names_are_equal(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length,				IGNORE_CASE, vol->upcase, vol->upcase_len)) {			/* Only one case insensitive matching name allowed. */			if (mref) {				ntfs_log_error("Found already cached mft "						"reference in phase 2. Please "						"run chkdsk and if that doesn't"						" find any errors please report"						" you saw this message to %s\n",						NTFS_DEV_LIST);				goto close_err_out;			}			mref = le64_to_cpu(ie->indexed_file);		}		/*		 * Not a perfect match, need to do full blown collation so we		 * know which way in the B+tree we have to go.		 */		rc = ntfs_names_collate(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length, 1,				IGNORE_CASE, vol->upcase, vol->upcase_len);		/*		 * If uname collates before the name of the current entry, there		 * is definitely no such name in this index but we might need to		 * descend into the B+tree so we just break out of the loop.		 */		if (rc == -1)			break;		/* The names are not equal, continue the search. */		if (rc)			continue;		/*		 * Names match with case insensitive comparison, now try the		 * case sensitive comparison, which is required for proper		 * collation.		 */		rc = ntfs_names_collate(uname, uname_len,				(ntfschar*)&ie->key.file_name.file_name,				ie->key.file_name.file_name_length, 1,				CASE_SENSITIVE, vol->upcase, vol->upcase_len);		if (rc == -1)			break;		if (rc)			continue;		/*		 * Perfect match, this will never happen as the		 * ntfs_are_names_equal() call will have gotten a match but we		 * still treat it correctly.		 */		goto found_it2;	}	/*	 * We have finished with this index buffer without success. Check for	 * the presence of a child node.	 */	if (ie->flags & INDEX_ENTRY_NODE) {		if ((ia->index.flags & NODE_MASK) == LEAF_NODE) {			ntfs_log_debug("Index entry with child node found in a leaf "					"node in directory inode 0x%llx.\n",					(unsigned long long)dir_ni->mft_no);			errno = EIO;			goto close_err_out;		}		/* Child node present, descend into it. */		vcn = sle64_to_cpup((u8*)ie + le16_to_cpu(ie->length) - 8);		if (vcn >= 0)			goto descend_into_child_node;		ntfs_log_debug("Negative child node vcn in directory inode "				"0x%llx.\n", (unsigned long long)dir_ni->mft_no);		errno = EIO;		goto close_err_out;	}	free(ia);	ntfs_attr_close(ia_na);	ntfs_attr_put_search_ctx(ctx);	/*	 * No child node present, return error code ENOENT, unless we have got	 * the mft reference of a matching name cached in mref in which case	 * return mref.	 */	if (mref)		return mref;	ntfs_log_debug("Entry not found.\n");	errno = ENOENT;	return -1;put_err_out:	eo = EIO;	ntfs_log_debug("Corrupt directory. Aborting lookup.\n");eo_put_err_out:	ntfs_attr_put_search_ctx(ctx);	errno = eo;	return -1;close_err_out:	eo = errno;	free(ia);	ntfs_attr_close(ia_na);	goto eo_put_err_out;}#ifndef __VISOPSYS__/** * ntfs_pathname_to_inode - Find the inode which represents the given pathname * @vol:       An ntfs volume obtained from ntfs_mount * @parent:    A directory inode to begin the search (may be NULL) * @pathname:  Pathname to be located * * Take an ASCII pathname and find the inode that represents it.  The function * splits the path and then descends the directory tree.  If @parent is NULL, * then the root directory '.' will be used as the base for the search. * * Return:  inode  Success, the pathname was valid *	    NULL   Error, the pathname was invalid, or some other error occurred */ntfs_inode *ntfs_pathname_to_inode(ntfs_volume *vol, ntfs_inode *parent,		const char *pathname){	u64 inum;	int len, err = 0;	char *p, *q;	ntfs_inode *ni;	ntfs_inode *result = NULL;	ntfschar *unicode = NULL;	char *ascii = NULL;	if (!vol || !pathname) {		errno = EINVAL;		return NULL;	}	if (parent) {		ni = parent;	} else {		ni = ntfs_inode_open(vol, FILE_root);		if (!ni) {			ntfs_log_debug("Couldn't open the inode of the root "					"directory.\n");			err = EIO;			goto close;		}	}	unicode = calloc(1, MAX_PATH);

⌨️ 快捷键说明

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