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 + -
显示快捷键?