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

📄 inode.c

📁 一个linux下NTFS文件格式源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  inode.c * *  Copyright (C) 1995-1999 Martin von L鰓is *  Copyright (C) 1996 Albert D. Cahalan *  Copyright (C) 1996-1997 R間is Duchesne *  Copyright (C) 1998 Joseph Malicki *  Copyright (C) 1999 Steve Dodd */#include "ntfstypes.h"#include "ntfsendian.h"#include "struct.h"#include "inode.h"#include <errno.h>#ifdef HAVE_STRING_H#include <string.h>#endif#include "macros.h"#include "attr.h"#include "super.h"#include "dir.h"#include "support.h"#include "util.h"typedef struct {	int recno;	unsigned char* record;} ntfs_mft_record;typedef struct {	int size;	int count;	ntfs_mft_record* records;} ntfs_disk_inode;voidntfs_fill_mft_header(ntfs_u8*mft,int record_size,int blocksize,		int sequence_number){	int fixup_count = record_size / blocksize + 1;	int attr_offset = (0x2a + (2 * fixup_count) + 7) & ~7;	int fixup_offset = 0x2a;	NTFS_PUTU32(mft + 0x00, 0x454c4946);	     /* FILE */	NTFS_PUTU16(mft + 0x04, 0x2a);		     /* offset to fixup */	NTFS_PUTU16(mft + 0x06, fixup_count);	     /* Number of fixups */	NTFS_PUTU16(mft + 0x10, sequence_number);	NTFS_PUTU16(mft + 0x12, 1);                  /* hard link count */	NTFS_PUTU16(mft + 0x14, attr_offset);	     /* Offset to attributes */	NTFS_PUTU16(mft + 0x16, 1);                  /*FIXME: flags ?? */	NTFS_PUTU32(mft + 0x18, attr_offset + 0x08);	/* In use */	NTFS_PUTU32(mft + 0x1c, record_size);	     /* Total size */	NTFS_PUTU16(mft + fixup_offset, 1);		/* Fixup word */	NTFS_PUTU32(mft + attr_offset, 0xffffffff);	/* End marker */}/* Search in an inode an attribute by type and name */ntfs_attribute* ntfs_find_attr(ntfs_inode *ino,int type,char *name){	int i;	if(!ino){		ntfs_error("ntfs_find_attr: NO INODE!\n");		return 0;	}	for(i=0;i<ino->attr_count;i++)	{		if(type==ino->attrs[i].type)		{			if(!name && !ino->attrs[i].name)				return ino->attrs+i;			if(name && !ino->attrs[i].name)				return 0;			if(!name && ino->attrs[i].name)				return 0;			if(ntfs_ua_strncmp(ino->attrs[i].name,name,strlen(name))==0)				return ino->attrs+i;		}		if(type<ino->attrs[i].type)			return 0;	}	return 0;}/* FIXME: need better strategy to extend the MFT */static int ntfs_extend_mft(ntfs_volume *vol){	/* Try to allocate at least 0.1% of the remaining disk space	   for inodes. If the disk is almost full, make sure at least one	   inode is requested.	 */	int size,rcount,error,block;	ntfs_attribute* mdata,*bmp;	ntfs_u8 *buf;	ntfs_io io;	mdata=ntfs_find_attr(vol->mft_ino,vol->at_data,0);	/* first check whether there is uninitialized space */	if(mdata->allocated<mdata->size+vol->mft_recordsize){		size=ntfs_get_free_cluster_count(vol->bitmap)*vol->clustersize;		block=vol->mft_recordsize;		size=max(size/1000,mdata->size+vol->mft_recordsize);		size=((size+block-1)/block)*block;		/* require this to be a single chunk */		error=ntfs_extend_attr(vol->mft_ino,mdata,&size,				       ALLOC_REQUIRE_SIZE);		/* Try again, now we have the largest available fragment */		if(error==ENOSPC){			/* round down to multiple of mft record size */			size=(size/vol->mft_recordsize)*vol->mft_recordsize;			if(!size)return ENOSPC;			error=ntfs_extend_attr(vol->mft_ino,mdata,&size,					       ALLOC_REQUIRE_SIZE);		}		if(error)			return error;	}	/* even though we might have allocated more than needed,	   we initialize only one record */	mdata->size+=vol->mft_recordsize;		/* now extend the bitmap if necessary*/	rcount=mdata->size/vol->mft_recordsize;	bmp=ntfs_find_attr(vol->mft_ino,vol->at_bitmap,0);	if(bmp->size*8<rcount){ /* less bits than MFT records */		ntfs_u8 buf[1];		/* extend bitmap by one byte */		error=ntfs_resize_attr(vol->mft_ino,bmp,bmp->size+1);		if(error)return error;		/* write the single byte */		buf[0]=0;		io.fn_put=ntfs_put;		io.fn_get=ntfs_get;		io.param=buf;		io.size=1;		error=ntfs_write_attr(vol->mft_ino,vol->at_bitmap,0,				      bmp->size-1,&io);		if(error)return error;		if(io.size!=1)return EIO;	}	/* now fill in the MFT header for the new block */	buf=ntfs_calloc(vol->mft_recordsize);	if(!buf)return ENOMEM;	ntfs_fill_mft_header(buf,vol->mft_recordsize,vol->blocksize,0);	ntfs_insert_fixups(buf,vol->blocksize);	io.param=buf;	io.size=vol->mft_recordsize;	error=ntfs_write_attr(vol->mft_ino,vol->at_data,0,			      (rcount-1)*vol->mft_recordsize,&io);	if(error)return error;	if(io.size!=vol->mft_recordsize)return EIO;	error=ntfs_update_inode(vol->mft_ino);	if(error)return error;	return 0;}/* Insert all attributes from the record mftno of the MFT in the inode ino */void ntfs_insert_mft_attributes(ntfs_inode* ino,char *mft,int mftno){	int i;	char *it;	int type,len;	/* check for duplicate */	for(i=0;i<ino->record_count;i++)		if(ino->records[i]==mftno)			return;	/* (re-)allocate space if necessary */	if(ino->record_count % 8==0)	{		int *new;		new = ntfs_malloc((ino->record_count+8)*sizeof(int));		if( !new )			return;		if( ino->records ) {			for(i=0;i<ino->record_count;i++)				new[i] = ino->records[i];			ntfs_free( ino->records );		}		ino->records = new;	}	ino->records[ino->record_count]=mftno;	ino->record_count++;	it = mft + NTFS_GETU16(mft + 0x14);	do{		type=NTFS_GETU32(it);		len=NTFS_GETU32(it+4);		if(type!=-1) {			/* FIXME: check ntfs_insert_attribute for failure (e.g. no mem)? */			ntfs_insert_attribute(ino,it);		}		it+=len;	}while(type!=-1); /* attribute list ends with type -1 */}/* Read and insert all the attributes of an 'attribute list' attribute   Return the number of remaining bytes in *plen*/static int parse_attributes(ntfs_inode *ino, ntfs_u8 *alist, int *plen){	char *mft;	int mftno,l,error;	int last_mft=-1;	int len=*plen;	mft=ntfs_malloc(ino->vol->mft_recordsize);	if( !mft )		return ENOMEM;	while(len>8)	{		l=NTFS_GETU16(alist+4);		if(l>len)break;	        /* process an attribute description */		mftno=NTFS_GETU32(alist+0x10); /* BUG: this is u64 */		if(mftno!=last_mft){			last_mft=mftno;			/* FIXME: avoid loading record if it's 			   already processed */			error=ntfs_read_mft_record(ino->vol,mftno,mft);			if(error)return error;			ntfs_insert_mft_attributes(ino,mft,mftno);		}		len-=l;		alist+=l;	}	ntfs_free(mft);	*plen=len;	return 0;}static void ntfs_load_attributes(ntfs_inode* ino){	ntfs_attribute *alist;	int datasize;	int offset,len,delta;	char *buf;	ntfs_volume *vol=ino->vol;	ntfs_debug(DEBUG_FILE2, "load_attributes %x 1\n",ino->i_number);	ntfs_insert_mft_attributes(ino,ino->attr,ino->i_number);	ntfs_debug(DEBUG_FILE2, "load_attributes %x 2\n",ino->i_number);	alist=ntfs_find_attr(ino,vol->at_attribute_list,0);	ntfs_debug(DEBUG_FILE2, "load_attributes %x 3\n",ino->i_number);	if(!alist)		return;	ntfs_debug(DEBUG_FILE2, "load_attributes %x 4\n",ino->i_number);	datasize=alist->size;	if(alist->resident)	{		parse_attributes(ino,alist->d.data,&datasize);		return;	}	buf=ntfs_malloc(1024);	if( !buf )		return;	delta=0;	for(offset=0;datasize;datasize-=len)	{		ntfs_io io;		io.fn_put=ntfs_put;		io.fn_get=0;		io.param=buf+delta;		io.size=len=min(datasize,1024-delta);		if(ntfs_read_attr(ino,vol->at_attribute_list,0,offset,&io)){			ntfs_error("error in load_attributes\n");		}		delta=len;		parse_attributes(ino,buf,&delta);		if(delta)			/* move remaining bytes to buffer start */			ntfs_memmove(buf,buf+len-delta,delta);	}	ntfs_debug(DEBUG_FILE2, "load_attributes %x 5\n",ino->i_number);	ntfs_free(buf);}	int ntfs_init_inode(ntfs_inode *ino,ntfs_volume *vol,int inum){	char *buf;	int error;	ntfs_debug(DEBUG_FILE1, "Initializing inode %x\n",inum);	if(!vol)		ntfs_error("NO VOLUME!\n");	ino->i_number=inum;	ino->vol=vol;	ino->attr=buf=ntfs_malloc(vol->mft_recordsize);	if( !buf )		return ENOMEM;	error=ntfs_read_mft_record(vol,inum,ino->attr);	if(error){		ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum);		return error;	}	ntfs_debug(DEBUG_FILE2, "Init: got mft %x\n",inum);	ino->sequence_number=NTFS_GETU16(buf+0x10);	ino->attr_count=0;	ino->record_count=0;	ino->records=0;	ino->attrs=0;	ntfs_load_attributes(ino);	ntfs_debug(DEBUG_FILE2, "Init: done %x\n",inum);	return 0;}void ntfs_clear_inode(ntfs_inode *ino){	int i;	if(!ino->attr){		ntfs_error("ntfs_clear_inode: double free\n");		return;	}	ntfs_free(ino->attr);	ino->attr=0;	ntfs_free(ino->records);	ino->records=0;	for(i=0;i<ino->attr_count;i++)	{		if(ino->attrs[i].name)			ntfs_free(ino->attrs[i].name);		if(ino->attrs[i].resident)		{			if(ino->attrs[i].d.data)				ntfs_free(ino->attrs[i].d.data);		}else{			if(ino->attrs[i].d.r.runlist)				ntfs_free(ino->attrs[i].d.r.runlist);		}	}	ntfs_free(ino->attrs);	ino->attrs=0;}/* Check and fixup a MFT record */int ntfs_check_mft_record(ntfs_volume *vol,char *record){	return ntfs_fixup_record(vol, record, "FILE", vol->mft_recordsize);}/* Return (in result) the value indicating the next available attribute    chunk number. Works for inodes w/o extension records only */int ntfs_allocate_attr_number(ntfs_inode *ino, int *result){	if(ino->record_count!=1)		return EOPNOTSUPP;	*result=NTFS_GETU16(ino->attr+0x28);	NTFS_PUTU16(ino->attr+0x28, (*result)+1);	return 0;}/* find the location of an attribute in the inode. A name of NULL indicates   unnamed attributes. Return pointer to attribute or NULL if not found */char *ntfs_get_attr(ntfs_inode *ino,int attr,char *name){	/* location of first attribute */	char *it= ino->attr + NTFS_GETU16(ino->attr + 0x14);	int type;	int len;	/* Only check for magic DWORD here, fixup should have happened before */	if(!IS_MFT_RECORD(ino->attr))return 0;	do{		type=NTFS_GETU32(it);		len=NTFS_GETU16(it+4);		/* We found the attribute type. Is the name correct, too? */		if(type==attr)		{			int namelen=NTFS_GETU8(it+9);			char *name_it;			/* match given name and attribute name if present,			   make sure attribute name is Unicode */			for(name_it=it+NTFS_GETU16(it+10);namelen;			    name++,name_it+=2,namelen--)				if(*name_it!=*name || name_it[1])break;			if(!namelen)break;		}		it+=len;	}while(type!=-1); /* attribute list end with type -1 */	if(type==-1)return 0;	return it;}int ntfs_get_attr_size(ntfs_inode*ino,int type,char*name){	ntfs_attribute *attr=ntfs_find_attr(ino,type,name);	if(!attr)return 0;	return attr->size;}	int ntfs_attr_is_resident(ntfs_inode*ino,int type,char*name){	ntfs_attribute *attr=ntfs_find_attr(ino,type,name);	if(!attr)return 0;	return attr->resident;}	/* * A run is coded as a type indicator, an unsigned length, and a signed cluster * offset. * . To save space, length and offset are fields of variable length. The low *   nibble of the type indicates the width of the length :), the high nibble *   the width of the offset. * . The first offset is relative to cluster 0, later offsets are relative to *   the previous cluster. * * This function decodes a run. Length is an output parameter, data and cluster * are in/out parameters. */int ntfs_decompress_run(unsigned char **data, int *length, ntfs_cluster_t *cluster,	int *ctype){	unsigned char type=*(*data)++;	*ctype=0;	switch(type & 0xF)	{	case 1: *length=NTFS_GETU8(*data);break;	case 2: *length=NTFS_GETU16(*data);break;	case 3: *length=NTFS_GETU24(*data);break;        case 4: *length=NTFS_GETU32(*data);break;        	/* Note: cases 5-8 are probably pointless to code,        	   since how many runs > 4GB of length are there?        	   at the most, cases 5 and 6 are probably necessary,        	   and would also require making length 64-bit        	   throughout */	default:		ntfs_error("Can't decode run type field %x\n",type);		return -1;	}	*data+=(type & 0xF);	switch(type & 0xF0)	{	case 0:	   *ctype=2; break;	case 0x10: *cluster += NTFS_GETS8(*data);break;	case 0x20: *cluster += NTFS_GETS16(*data);break;	case 0x30: *cluster += NTFS_GETS24(*data);break;	case 0x40: *cluster += NTFS_GETS32(*data);break;

⌨️ 快捷键说明

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