ntfsx.c

来自「磁盘格式解读」· C语言 代码 · 共 698 行 · 第 1/2 页

C
698
字号
/* 
 * AUTHOR
 * N. Nielsen
 *
 * LICENSE
 * This software is in the public domain.
 *
 * The software is provided "as is", without warranty of any kind,
 * express or implied, including but not limited to the warranties
 * of merchantability, fitness for a particular purpose, and
 * noninfringement. In no event shall the author(s) be liable for any
 * claim, damages, or other liability, whether in an action of
 * contract, tort, or otherwise, arising from, out of, or in connection
 * with the software or the use or other dealings in the software.
 * 
 * SUPPORT
 * Send bug reports to: <nielsen@memberwebs.com>
 */

#include "scrounge.h"
#include "memref.h"
#include "ntfs.h"
#include "ntfsx.h"

ntfsx_datarun* ntfsx_datarun_alloc(byte* mem, byte* datarun)
{
  ntfsx_datarun* dr = (ntfsx_datarun*)mallocf(sizeof(ntfsx_datarun));

  ASSERT(datarun);
	dr->_mem = (byte*)refadd(mem);
	dr->_datarun = datarun;
  dr->_curpos = NULL;

  dr->cluster = 0;
  dr->length = 0;
  dr->sparse = false;

  return dr;
}

void ntfsx_datarun_free(ntfsx_datarun* dr)
{
  if(dr->_mem)
  {
    refrelease(dr->_mem);
    dr->_mem = NULL;
  }

  free(dr);
}

bool ntfsx_datarun_first(ntfsx_datarun* dr)
{
	dr->_curpos = dr->_datarun;
	dr->cluster = 0;
  dr->length = 0;
	dr->sparse = false;
	return ntfsx_datarun_next(dr);
}

bool ntfsx_datarun_next(ntfsx_datarun* dr)
{
  byte length;
  byte roffset;
	int64 offset;

	ASSERT(dr->_curpos);

	if(!*(dr->_curpos))
		return false;

	length = *(dr->_curpos) & 0x0F;
	roffset = *(dr->_curpos) >> 4;

	/* ASSUMPTION: length and offset are less 64 bit numbers */
	if(length == 0 || length > 8 || roffset > 8)
		return false;
		
	ASSERT(length <= 8);
	ASSERT(roffset <= 8);

	(dr->_curpos)++;

	memset(&(dr->length), 0, sizeof(uint64));

	memcpy(&(dr->length), (dr->_curpos), length);
	(dr->_curpos) += length;


	/* Note that offset can be negative */
	if(*((dr->_curpos) + (roffset - 1)) & 0x80)
		memset(&offset, ~0, sizeof(int64));
	else
		memset(&offset, 0, sizeof(int64));

	memcpy(&offset, (dr->_curpos), roffset);
	(dr->_curpos) += roffset;

	if(offset == 0)
	{
		dr->sparse = true;
	}
	else
	{
		dr->sparse = false;
		dr->cluster += offset;
	}

	return true;
}






void ntfsx_cluster_reserve(ntfsx_cluster* clus, partitioninfo* info)
{
  ntfsx_cluster_release(clus);
  clus->size = CLUSTER_SIZE(*info);

  ASSERT(clus->size != 0);
  clus->data = (byte*)refalloc(clus->size);
}

bool ntfsx_cluster_read(ntfsx_cluster* clus, partitioninfo* info, uint64 begSector, int dd)
{
  int64 pos;
  size_t sz;

  if(!clus->data)
    ntfsx_cluster_reserve(clus, info);

  pos = SECTOR_TO_BYTES(begSector);
  if(lseek64(dd, pos, SEEK_SET) == -1)
    return false;

  sz = read(dd, clus->data, clus->size);
  if(sz == -1)
    return false;

  if(sz != clus->size)
  {
    errno = ERANGE;
    return false;
  }

	return true;
}

void ntfsx_cluster_release(ntfsx_cluster* clus)
{
  if(clus->data)
    refrelease(clus->data);

  clus->data = NULL;
  clus->size = 0;
}




ntfsx_attribute* ntfsx_attribute_alloc(ntfsx_cluster* clus, ntfs_attribheader* header)
{
  ntfsx_attribute* attr = (ntfsx_attribute*)mallocf(sizeof(ntfsx_attribute));
  attr->_header = header;
  attr->_mem = (byte*)refadd(clus->data);
  attr->_length = clus->size;
  return attr;
}

void ntfsx_attribute_free(ntfsx_attribute* attr)
{
  if(attr->_mem)
  {
    refrelease(attr->_mem);
    attr->_mem = NULL;
  }

  free(attr);
}

ntfs_attribheader* ntfsx_attribute_header(ntfsx_attribute* attr)
{
  return attr->_header;
}

void* ntfsx_attribute_getresidentdata(ntfsx_attribute* attr)
{
	ntfs_attribresident* res = (ntfs_attribresident*)attr->_header;
	ASSERT(!attr->_header->bNonResident);
	return (byte*)(attr->_header) + res->offAttribData;
}

uint32 ntfsx_attribute_getresidentsize(ntfsx_attribute* attr)
{
	ntfs_attribresident* res = (ntfs_attribresident*)attr->_header;
	ASSERT(!attr->_header->bNonResident);
	return res->cbAttribData;
}

ntfsx_datarun* ntfsx_attribute_getdatarun(ntfsx_attribute* attr)
{
	ntfs_attribnonresident* nonres = (ntfs_attribnonresident*)attr->_header;
	ASSERT(attr->_header->bNonResident);
	return ntfsx_datarun_alloc(attr->_mem, (byte*)(attr->_header) + nonres->offDataRuns);
}

bool ntfsx_attribute_next(ntfsx_attribute* attr, uint32 attrType)
{
	ntfs_attribheader* header = ntfs_nextattribute(attr->_header, attrType, 
                                    attr->_mem + attr->_length);	
	if(header)
	{
		attr->_header = header;
		return true;
	}

	return false;
}



#define ATTR_ENUM_LISTPRI     1 << 1
#define ATTR_ENUM_DONEINLINE  1 << 2
#define ATTR_ENUM_DONELIST    1 << 3
#define ATTR_ENUM_FOUNDLIST   1 << 4

ntfsx_attrib_enum* ntfsx_attrib_enum_alloc(uint32 type, bool normal)
{
  ntfsx_attrib_enum* attrenum = (ntfsx_attrib_enum*)mallocf(sizeof(ntfsx_attrib_enum));
  attrenum->type = type;
  attrenum->_attrhead = NULL;
  attrenum->_listrec = NULL;
  attrenum->_flags = normal ? ATTR_ENUM_LISTPRI : 0;
  return attrenum;  
}

ntfsx_attribute* ntfsx_attrib_enum_inline(ntfsx_attrib_enum* attrenum, ntfsx_record* record)
{
  ntfsx_attribute* attr;
  ntfsx_cluster* cluster;
  ntfs_recordheader* rechead;

  /* If we're done */
  if(attrenum->_flags & ATTR_ENUM_DONEINLINE)
    return NULL;

  cluster = ntfsx_record_cluster(record);
  rechead = ntfsx_record_header(record);

  /* If this is the first time */
  if(!attrenum->_attrhead && !attrenum->_listrec)
  {
    attrenum->_attrhead = ntfs_findattribute(rechead, attrenum->type, 
                                              cluster->data + cluster->size);

    if(attrenum->_attrhead)
    {
      attr = ntfsx_attribute_alloc(cluster, attrenum->_attrhead);
      return attr;
    }

    /* Otherwise we fall through to the attr list stuff below */
  }

  /* Look for another attribute in the record */
  if(attrenum->_attrhead && attrenum->_attrhead->type == attrenum->type)
  {
    attrenum->_attrhead = ntfs_nextattribute(attrenum->_attrhead, attrenum->type,
                                          cluster->data + cluster->size);

    if(attrenum->_attrhead)
    {
      attr = ntfsx_attribute_alloc(cluster, attrenum->_attrhead);
      return attr;
    }

    /* Otherwise we're done */
  }

  attrenum->_flags |= ATTR_ENUM_DONEINLINE;
  return NULL;
}

ntfsx_attribute* ntfsx_attrib_enum_list(ntfsx_attrib_enum* attrenum, ntfsx_record* record)
{
  ntfsx_cluster* cluster;
  ntfs_recordheader* rechead;
  ntfs_attribresident* resident;
  ntfs_attribheader* attrhead;
  ntfsx_attribute* attr;
  uint64 mftRecord;
  ntfsx_record* r2;
  ntfsx_cluster* c2;

  ASSERT(record && attrenum);

  /* If we're done */
  if(attrenum->_flags & ATTR_ENUM_DONELIST)
    return NULL;
    
  cluster = ntfsx_record_cluster(record);
  rechead = ntfsx_record_header(record);

  /* Okay first check for attribute lists  */
  if(!attrenum->_listrec && !attrenum->_attrhead)
  {
    attrenum->_attrhead = ntfs_findattribute(rechead, kNTFS_ATTRIBUTE_LIST,
                                             cluster->data + cluster->size);
  
    /* If no attribute list, end of story */
    if(!attrenum->_attrhead)
    {
      attrenum->_flags |= ATTR_ENUM_DONELIST;
      return NULL;
    }

    /* We don't support non-resident attribute lists (which are stupid!) */
    if(attrenum->_attrhead->bNonResident)
    {
      warnx("brain dead, incredibly fragmented file data. skipping");
      attrenum->_flags |= ATTR_ENUM_DONELIST;
      return NULL;
    }

    /* We don't do attribute lists when no MFT loaded */
    if(!record->info->mftmap)
    {
      warnx("extended file attributes, but no MFT loaded. skipping");
      attrenum->_flags |= ATTR_ENUM_DONELIST;
      return NULL;
    }
  }

  /* This has to be set by now */
  ASSERT(attrenum->_attrhead);
  ASSERT(attrenum->_attrhead->type == kNTFS_ATTRIBUTE_LIST);

  resident = (ntfs_attribresident*)attrenum->_attrhead;

  for(;;)
  {
    if(attrenum->_listrec) /* progress to next record */
      attrenum->_listrec = (ntfs_attriblistrecord*)(((byte*)attrenum->_listrec) + attrenum->_listrec->cbRecord);

    else  /* get first record */
      attrenum->_listrec = (ntfs_attriblistrecord*)((byte*)resident + resident->offAttribData);

⌨️ 快捷键说明

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