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