ntfsx.c
来自「磁盘格式解读」· C语言 代码 · 共 698 行 · 第 1/2 页
C
698 行
if(((byte*)attrenum->_listrec) >= ((byte*)attrenum->_attrhead) + attrenum->_attrhead->cbAttribute)
{
attrenum->_listrec = NULL;
attrenum->_flags |= ATTR_ENUM_DONELIST;
return NULL;
}
if(attrenum->_listrec->type == attrenum->type)
{
attr = NULL;
r2 = NULL;
/* Read in appropriate cluster */
mftRecord = ntfsx_mftmap_sectorforindex(record->info->mftmap, attrenum->_listrec->refAttrib & kNTFS_RefMask);
if(mftRecord == kInvalidSector)
{
warnx("invalid sector in mft map. screwed up file. skipping data");
}
else
{
r2 = ntfsx_record_alloc(record->info);
if(ntfsx_record_read(r2, mftRecord, record->info->device))
{
rechead = ntfsx_record_header(r2);
c2 = ntfsx_record_cluster(r2);
attrhead = ntfs_findattribute(rechead, attrenum->type,
c2->data + c2->size);
if(attrhead)
attr = ntfsx_attribute_alloc(c2, attrhead);
}
}
if(r2)
ntfsx_record_free(r2);
if(attr)
return attr;
}
}
/* Not reached */
ASSERT(false);
}
ntfsx_attribute* ntfsx_attrib_enum_all(ntfsx_attrib_enum* attrenum, ntfsx_record* record)
{
ntfsx_attribute* attr = NULL;
ASSERT(record && attrenum);
/*
* When in this mode list attributes completely override
* any inline attributes. This is the normal mode of
* operation
*/
if(attrenum->_flags & ATTR_ENUM_LISTPRI)
{
if(!(attrenum->_flags & ATTR_ENUM_DONELIST))
{
attr = ntfsx_attrib_enum_list(attrenum, record);
if(attr)
attrenum->_flags |= ATTR_ENUM_FOUNDLIST;
}
if(!attr && !(attrenum->_flags & ATTR_ENUM_FOUNDLIST) &&
!(attrenum->_flags & ATTR_ENUM_DONEINLINE))
attr = ntfsx_attrib_enum_inline(attrenum, record);
}
/*
* The other mode of operation is to find everything
* inline first and then stuff in the lists.
*/
else
{
if(!(attrenum->_flags & ATTR_ENUM_DONEINLINE))
attr = ntfsx_attrib_enum_inline(attrenum, record);
if(!attr && !(attrenum->_flags & ATTR_ENUM_DONELIST))
attr = ntfsx_attrib_enum_list(attrenum, record);
}
return attr;
}
void ntfsx_attrib_enum_free(ntfsx_attrib_enum* attrenum)
{
free(attrenum);
}
ntfsx_record* ntfsx_record_alloc(partitioninfo* info)
{
ntfsx_record* rec = (ntfsx_record*)mallocf(sizeof(ntfsx_record));
rec->info = info;
memset(&(rec->_clus), 0, sizeof(ntfsx_cluster));
return rec;
}
void ntfsx_record_free(ntfsx_record* record)
{
ntfsx_cluster_release(&(record->_clus));
free(record);
}
bool ntfsx_record_read(ntfsx_record* record, uint64 begSector, int dd)
{
ntfs_recordheader* rechead;
if(!ntfsx_cluster_read(&(record->_clus), record->info, begSector, dd))
{
warn("couldn't read mft record from drive");
return false;
}
/* Check and validate this record */
rechead = ntfsx_record_header(record);
if(rechead->magic != kNTFS_RecMagic ||
!ntfs_dofixups(record->_clus.data, record->_clus.size))
{
warnx("invalid mft record");
ntfsx_cluster_release(&(record->_clus));
return false;
}
return true;
}
ntfsx_cluster* ntfsx_record_cluster(ntfsx_record* record)
{
return &(record->_clus);
}
ntfs_recordheader* ntfsx_record_header(ntfsx_record* record)
{
return (ntfs_recordheader*)(record->_clus.data);
}
ntfsx_attribute* ntfsx_record_findattribute(ntfsx_record* record, uint32 attrType, int dd)
{
ntfsx_attrib_enum* attrenum = NULL;
ntfsx_attribute* attr = NULL;
attrenum = ntfsx_attrib_enum_alloc(attrType, true);
attr = ntfsx_attrib_enum_all(attrenum, record);
ntfsx_attrib_enum_free(attrenum);
return attr;
}
struct _ntfsx_mftmap_block
{
uint64 firstSector; /* relative to the entire drive */
uint64 length; /* length in MFT records */
};
void ntfsx_mftmap_init(ntfsx_mftmap* map, partitioninfo* info)
{
map->info = info;
map->_blocks = NULL;
map->_count = 0;
}
void ntfsx_mftmap_destroy(ntfsx_mftmap* map)
{
if(map->_blocks)
{
free(map->_blocks);
map->_blocks = NULL;
map->_count = 0;
}
}
static void mftmap_expand(ntfsx_mftmap* map, uint32* allocated){ if(map->_count >= *allocated)
{
(*allocated) += 16;
map->_blocks = (struct _ntfsx_mftmap_block*)reallocf(map->_blocks,
(*allocated) * sizeof(struct _ntfsx_mftmap_block));
}}
bool ntfsx_mftmap_load(ntfsx_mftmap* map, ntfsx_record* record, int dd)
{
bool ret = true;
ntfsx_attribute* attribdata = NULL; /* Data Attribute */
ntfsx_datarun* datarun = NULL; /* Data runs for nonresident data */
ntfsx_attrib_enum* attrenum = NULL;
{
ntfs_attribheader* header;
ntfs_attribnonresident* nonres;
uint64 length;
uint64 firstSector;
uint32 allocated; uint64 total;
bool hasdata = false;
if(map->_blocks)
{
free(map->_blocks);
map->_blocks = NULL;
}
map->_count = 0;
allocated = 0;
total = 0;
attrenum = ntfsx_attrib_enum_alloc(kNTFS_DATA, false);
while((attribdata = ntfsx_attrib_enum_all(attrenum, record)) != NULL)
{
header = ntfsx_attribute_header(attribdata);
if(!header->bNonResident)
{
warnx("invalid mft. data attribute non-resident");
}
else
{
datarun = ntfsx_attribute_getdatarun(attribdata);
if(!datarun)
{
warnx("invalid mft. no data runs in data attribute");
}
else
{
hasdata = true;
nonres = (ntfs_attribnonresident*)header;
/* Check total length against nonres->cbAllocated */
if(map->_count == 0)
total = nonres->cbAllocated;
/* Now loop through the data run */
if(ntfsx_datarun_first(datarun))
{
do
{
if(datarun->sparse)
{
warnx("invalid mft. sparse data runs");
}
else
{
mftmap_expand(map, &allocated);
ASSERT(map->info->cluster != 0);
length = datarun->length * ((map->info->cluster * kSectorSize) / kNTFS_RecordLen);
if(length == 0)
continue;
firstSector = (datarun->cluster * map->info->cluster) + map->info->first;
if(firstSector >= map->info->end)
continue;
/*
* When the same as the last one skip. This occurs in really
* fragmented MFTs where we read the inline DATA attribute first
* and then move on to the ATTRLIST one.
*/
if(map->_count > 0 && map->_blocks[map->_count - 1].length == length &&
map->_blocks[map->_count - 1].firstSector == firstSector)
continue;
map->_blocks[map->_count].length = length;
map->_blocks[map->_count].firstSector = firstSector;
map->_count++; total -= length * kSectorSize;
}
}
while(ntfsx_datarun_next(datarun));
}
ntfsx_datarun_free(datarun);
datarun = NULL;
}
}
ntfsx_attribute_free(attribdata);
attribdata = NULL;
}
if(!hasdata)
RETWARNBX("invalid mft. no data attribute");
ret = true; }
cleanup:
if(attribdata)
ntfsx_attribute_free(attribdata);
if(datarun)
ntfsx_datarun_free(datarun);
if(attrenum)
ntfsx_attrib_enum_free(attrenum);
return ret;
}
uint64 ntfsx_mftmap_length(ntfsx_mftmap* map)
{
uint64 length = 0;
uint32 i;
for(i = 0; i < map->_count; i++)
length += map->_blocks[i].length;
return length;
}
uint64 ntfsx_mftmap_sectorforindex(ntfsx_mftmap* map, uint64 index)
{
uint32 i;
struct _ntfsx_mftmap_block* p;
uint64 sector;
for(i = 0; i < map->_count; i++)
{
p = map->_blocks + i;
if(index >= p->length)
{
index -= p->length;
}
else
{
sector = index * (kNTFS_RecordLen / kSectorSize);
sector += p->firstSector;
if(sector >= map->info->end)
return kInvalidSector;
return sector;
}
}
return kInvalidSector;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?