Пример #1
0
static void OLE_parse_summary(FILE *file, const uint32_t *fat, const unsigned int fat_entries,
    const struct OLE_HDR *header, const unsigned int ministream_block, const unsigned int ministream_size,
    const unsigned int block, const unsigned int len, const char **ext, char **title, time_t *file_time)
{
  unsigned char *summary=NULL;
  if(len < 48 || len>1024*1024)
    return ;
  if(len < le32(header->miniSectorCutoff))
  {
    if(le32(header->csectMiniFat)!=0 && ministream_size > 0 && ministream_size < 1024*1024)
    {
      const unsigned int mini_fat_entries=(le32(header->csectMiniFat) << le16(header->uSectorShift)) / 4;
      uint32_t *minifat;
      unsigned char *ministream;
      if((minifat=OLE_load_MiniFAT(file, header, fat, fat_entries))==NULL)
	return ;
      ministream=(unsigned char *)OLE_read_stream(file,
	  fat, fat_entries, le16(header->uSectorShift),
	  ministream_block, ministream_size);
      if(ministream != NULL)
      {
	summary=(unsigned char*)OLE_read_ministream(ministream,
	    minifat, mini_fat_entries, le16(header->uMiniSectorShift),
	    block, len, ministream_size);
	free(ministream);
      }
      free(minifat);
    }
  }
  else
    summary=(unsigned char *)OLE_read_stream(file,
	fat, fat_entries, le16(header->uSectorShift),
	block, len);
  if(summary!=NULL)
  {
    OLE_parse_summary_aux(summary, len, ext, title, file_time);
    free(summary);
  }
}
Пример #2
0
static int header_check_qbb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
  const struct qbb_header *hdr0=(const struct qbb_header*)buffer;
  uint64_t data_size=0;
  unsigned int i=0;
  if(buffer[0x0e]!=0x45 || buffer[0x0f]!=0x86)
    return 0;
  while(i+sizeof(struct qbb_header02) < buffer_size)
  {
    const struct qbb_header *hdr=(const struct qbb_header*)&buffer[i];
    if(le16(hdr->magic)!=0x8645)
      break;
    if(le16(hdr->type)==2)
    {
      const struct qbb_header02 *hdr2=(const struct qbb_header02 *)hdr;
      data_size=le32(hdr2->size);
    }
#ifdef DEBUG_QBB
    log_info("i=0x%x size=0x%lx len=0x%x\n", i, sizeof(struct qbb_header), le16(hdr->data_len));
#endif
    i+=sizeof(struct qbb_header)+le16(hdr->data_len);
  }
#ifdef DEBUG_QBB
  log_info("i=0x%x data_size=0x%lx\n", i, (long unsigned)data_size);
#endif
  if(data_size==0)
    return 0;
  reset_file_recovery(file_recovery_new);
  file_recovery_new->calculated_file_size=data_size+i;
  if(le16(hdr0->unk1)==1)
    file_recovery_new->extension="qbmb";
  else
    file_recovery_new->extension=file_hint_qbb.extension;
  file_recovery_new->data_check=&data_check_size;
  file_recovery_new->file_check=&file_check_size;
  file_recovery_new->file_rename=&file_rename_qbb;
  return 1;
}
Пример #3
0
static unsigned int tiff_le_read(const void *val, const unsigned int type)
{
  switch(type)
  {
    case 1:
      return *((const uint8_t*)val);
    case 3:
      return le16(*((const uint16_t*)val));
    case 4:
      return le32(*((const uint32_t*)val));
    default:
      return 0;
  }
}
Пример #4
0
static int header_check_cab(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
  const struct cab_header *cab_hdr=(const struct cab_header*)buffer;
  if(le16(cab_hdr->cab_version)==0x0103 && le32(cab_hdr->filesize) >= sizeof(struct cab_header))
  {
    reset_file_recovery(file_recovery_new);
    file_recovery_new->extension=file_hint_cab.extension;
    file_recovery_new->calculated_file_size=(uint64_t)le32(cab_hdr->filesize);
    file_recovery_new->data_check=&data_check_size;
    file_recovery_new->file_check=&file_check_size;
    return 1;
  }
  return 0;
}
Пример #5
0
static const char *find_tag_from_tiff_header_le_aux(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error, const struct ifd_header *hdr)
{
  const TIFFDirEntry *tmp;
  unsigned int i;
  unsigned int nbr_fields;
  /* Bound checking */
  if((const char*)(hdr) <= (const char*)tiff ||
      (const char*)(hdr+1) > (const char*)tiff+tiff_size)
    return NULL;
  nbr_fields=le16(hdr->nbr_fields);
  for(i=0, tmp=&hdr->ifd;
      i < nbr_fields && (const char*)(tmp+1) <= (const char*)tiff+tiff_size;
      i++, tmp++)
  {
    if(le16(tmp->tdir_type) > 18 && (*potential_error==NULL || *potential_error > (const char*)&tmp->tdir_type+1))
    {
      *potential_error = (const char*)&tmp->tdir_type+1;
    }
    if(le16(tmp->tdir_tag)==tag)
      return (const char*)tiff+le32(tmp->tdir_offset);
  }
  return NULL;
}
Пример #6
0
static int header_check_mft(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
  const struct ntfs_mft_record *mft_rec=(const struct ntfs_mft_record *)buffer;
  const unsigned int usa_ofs = le16(mft_rec->usa_ofs);
  const unsigned int usa_count = le16(mft_rec->usa_count);
  const unsigned int attrs_offset = le16(mft_rec->attrs_offset);
  const unsigned int bytes_in_use = le32(mft_rec->bytes_in_use);
  const unsigned int bytes_allocated = le32(mft_rec->bytes_allocated);
  if(!(memcmp(buffer,"FILE",4)==0 && 
    usa_ofs+usa_count <= attrs_offset &&
    42 <= attrs_offset &&
    attrs_offset%8==0 &&
    attrs_offset < bytes_in_use &&
    bytes_in_use <= bytes_allocated))
    return 0;
  reset_file_recovery(file_recovery_new);
  file_recovery_new->extension=file_hint_mft.extension;
  file_recovery_new->calculated_file_size=bytes_allocated;
  file_recovery_new->data_check=&data_check_size;
  file_recovery_new->file_check=&file_check_size;
  file_recovery_new->file_rename=&file_rename_mft;
  return 1;
}
Пример #7
0
static int test_rfs4(const disk_t *disk_car, const struct reiser4_master_sb *sb, const partition_t *partition, const int verbose)
{
  if (memcmp(sb->magic,REISERFS4_SUPER_MAGIC,sizeof(REISERFS4_SUPER_MAGIC)) != 0)
    return 1;
  if(verbose>0)
    log_info("\nReiserFS Marker at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset));
  /*
   * sanity checks.
   */
  if (le16(sb->blocksize) != 4096)
    return (1);
  /* if a value > 4096 become legal, the code will break while reading the filesystem size (read out of bound) */
  return 0;
}
Пример #8
0
static int set_rfs_info(const struct reiserfs_super_block *sb, partition_t *partition)
{
  partition->fsname[0]='\0';
  partition->blocksize=le16(sb->s_blocksize);
  switch(partition->upart_type)
  {
    case UP_RFS:
      snprintf(partition->info, sizeof(partition->info),
	  "ReiserFS 3.5 with standard journal blocksize=%u", partition->blocksize);
      break;
    case UP_RFS2:
      snprintf(partition->info, sizeof(partition->info),
	  "ReiserFS 3.6 with standard journal blocksize=%u", partition->blocksize);
      set_part_name(partition,(const char*)sb->s_label,16);
      break;
    case UP_RFS3:
      if(le16(sb->sb_version)==1)
	snprintf(partition->info, sizeof(partition->info),
	    "ReiserFS 3.5 with non standard journal blocksize=%u", partition->blocksize);
      else if(le16(sb->sb_version)==2)
	snprintf(partition->info, sizeof(partition->info),
	    "ReiserFS 3.6 with non standard journal blocksize=%u", partition->blocksize);
      else
	snprintf(partition->info, sizeof(partition->info),
	    "ReiserFS 3.? with non standard journal blocksize=%u", partition->blocksize);
      set_part_name(partition,(const char*)sb->s_label,16);
      break;
    default:
      partition->info[0]='\0';
      return 1;
  }
  if (le16(sb->s_state) == REISERFS_ERROR_FS)
  {
    strcat(partition->info,", need recovery");
  }
  return 0;
}
Пример #9
0
static void file_check_xm(file_recovery_t *fr)
{
  uint16_t patterns, instrs;

  fr->file_size = 0;
  fr->offset_error=0;
  fr->offset_ok=0;

  if (fseek(fr->handle, 70, SEEK_SET) == -1)
    return;
  if (fread(&patterns, 2, 1, fr->handle) != 1)
    return;
  if (fread(&instrs, 2, 1, fr->handle) != 1)
    return;
  instrs   = le16(instrs);
  patterns = le16(patterns);

  log_debug("xm: %u patterns, %u instruments\n", patterns, instrs);

  /* Skip flags + tempo + bmp + table */
  if (fseek(fr->handle, 2+2+2+256, SEEK_CUR) == -1)
    return;
  fr->file_size = 336;

  /* Parse patterns and next instruments */
  if (parse_patterns(fr, patterns) < 0 ||
      parse_instruments(fr, instrs) < 0)
  {
    log_debug("xm: lost sync at pos %li\n", ftell(fr->handle));
    fr->offset_error = fr->file_size;
    fr->file_size = 0;
    return;
  }

  /* ModPlug may insert additional data but it is of little relevance */
}
Пример #10
0
static void set_rfs_info(const struct reiserfs_super_block *sb, partition_t *partition)
{
  partition->fsname[0]='\0';
  partition->blocksize=le16(sb->s_blocksize);
  if (memcmp(sb->s_magic,REISERFS_SUPER_MAGIC,sizeof(REISERFS_SUPER_MAGIC)) == 0)
  {
    partition->upart_type = UP_RFS;
    snprintf(partition->info, sizeof(partition->info),
	"ReiserFS 3.5 with standard journal blocksize=%u", partition->blocksize);
  }
  else if(memcmp(sb->s_magic,REISERFS2_SUPER_MAGIC,sizeof(REISERFS2_SUPER_MAGIC)) == 0)
  {
    partition->upart_type = UP_RFS2;
    snprintf(partition->info, sizeof(partition->info),
	"ReiserFS 3.6 with standard journal blocksize=%u", partition->blocksize);
    set_part_name(partition,(const char*)sb->s_label,16);
  }
  else if(memcmp(sb->s_magic,REISERFS3_SUPER_MAGIC,sizeof(REISERFS3_SUPER_MAGIC)) == 0)
  {
    partition->upart_type = UP_RFS3;
    if(le16(sb->sb_version)==1)
      snprintf(partition->info, sizeof(partition->info),
	  "ReiserFS 3.5 with non standard journal blocksize=%u", partition->blocksize);
    else if(le16(sb->sb_version)==2)
      snprintf(partition->info, sizeof(partition->info),
	  "ReiserFS 3.6 with non standard journal blocksize=%u", partition->blocksize);
    else
      snprintf(partition->info, sizeof(partition->info),
	  "ReiserFS 3.? with non standard journal blocksize=%u", partition->blocksize);
    set_part_name(partition,(const char*)sb->s_label,16);
  }
  if(le16(sb->s_state) == REISERFS_ERROR_FS)
  {
    strcat(partition->info,", need recovery");
  }
}
Пример #11
0
static int test_rfs(const disk_t *disk_car, const struct reiserfs_super_block *sb, partition_t *partition, const int verbose)
{
  if (memcmp(sb->s_magic,REISERFS_SUPER_MAGIC,sizeof(REISERFS_SUPER_MAGIC)) == 0)
  {
    partition->upart_type = UP_RFS;
  }
  else
    if(memcmp(sb->s_magic,REISERFS2_SUPER_MAGIC,sizeof(REISERFS2_SUPER_MAGIC)) == 0)
    {
      partition->upart_type = UP_RFS2;
    }
    else
    if(memcmp(sb->s_magic,REISERFS3_SUPER_MAGIC,sizeof(REISERFS3_SUPER_MAGIC)) == 0)
    {
      partition->upart_type = UP_RFS3;
    }
    else
      return 1;
  if(verbose>0)
    log_info("\nReiserFS Marker at %u/%u/%u\n",
	offset2cylinder(disk_car,partition->part_offset),
	offset2head(disk_car,partition->part_offset),
	offset2sector(disk_car,partition->part_offset));
  /*
   * sanity checks.
   */

  if (le32(sb->s_block_count) < le32(sb->s_free_blocks))
    return (1);

  if (le32(sb->s_block_count) < REISERFS_MIN_BLOCK_AMOUNT)
    return (1);

  if ((le16(sb->s_state) != REISERFS_VALID_FS) &&
      (le16(sb->s_state) != REISERFS_ERROR_FS))
    return (1);

  if (le16(sb->s_oid_maxsize) % 2!=0) /* must be even */
    return (1);

  if (le16(sb->s_oid_maxsize) < le16(sb->s_oid_cursize))
    return (1);

  if ((le16(sb->s_blocksize) != 4096) && (le16(sb->s_blocksize) != 8192))
    return (1);

  return 0;
}
Пример #12
0
static void file_rename_ext(file_recovery_t *file_recovery)
{
  unsigned char buffer[512];
  char buffer_cluster[32];
  FILE *file;
  const struct ext2_super_block *sb=(const struct ext2_super_block *)&buffer;
  int buffer_size;
  unsigned long int block_nr;
  if((file=fopen(file_recovery->filename, "rb"))==NULL)
    return;
  buffer_size=fread(buffer, 1, sizeof(buffer), file);
  fclose(file);
  if(buffer_size!=sizeof(buffer))
    return;
  block_nr=(le32(sb->s_first_data_block)+le16(sb->s_block_group_nr)*le32(sb->s_blocks_per_group));
  sprintf(buffer_cluster, "sb_%lu", block_nr);
  file_rename(file_recovery, buffer_cluster, strlen(buffer_cluster), 0, NULL, 1);
}
Пример #13
0
int recover_sun_i386(disk_t *disk_car, const sun_partition_i386 *sunlabel, partition_t *partition,const int verbose, const int dump_ind)
{
  if(test_sun_i386(disk_car, sunlabel, partition, verbose)!=0)
    return 1;
  if(verbose>0 || dump_ind!=0)
  {
    log_info("\nrecover_sun\n");
    if(dump_ind!=0)
    {
      dump_log(sunlabel,sizeof(*sunlabel));
    }
  }
  partition->part_size=(uint64_t)le32(sunlabel->partitions[2].num_sectors) * le16(sunlabel->sector_size);
  set_sun_info_i386(partition);
  partition->part_type_i386 = P_SUN;
  partition->part_type_gpt=GPT_ENT_TYPE_SOLARIS_ROOT;
  return 0;
}
Пример #14
0
static int zip_parse_end_central_dir(file_recovery_t *fr)
{
  struct {
    uint16_t number_disk;             /** Number of this disk */
    uint16_t number_disk2;            /** Number in the central dir */
    uint16_t total_number_disk;       /** Total number of entries in this disk */
    uint16_t total_number_disk2;      /** Total number of entries in the central dir */
    uint32_t size;                    /** Size of the central directory */
    uint32_t offset;                  /** Offset of start of central directory */
    uint16_t comment_length;          /** Comment length */
  } __attribute__ ((__packed__)) dir;

  if (fread(&dir, sizeof(dir), 1, fr->handle) != 1)
  {
#ifdef DEBUG_ZIP
    log_trace("zip: Unexpected EOF reading header of zip_parse_end_central_dir\n");
#endif
    return -1;
  }
  fr->file_size += sizeof(dir);

  if (dir.comment_length)
  {
    const uint16_t len = le16(dir.comment_length);
#ifdef HAVE_FSEEKO
    if (fseeko(fr->handle, len, SEEK_CUR) == -1)
#else
    if (fseek(fr->handle, len, SEEK_CUR) == -1)
#endif
    {
#ifdef DEBUG_ZIP
      log_trace("zip: Unexpected EOF in end_central_dir: expected %u bytes\n", len);
#endif
      return -1;
    }
    fr->file_size += len;
#ifdef DEBUG_ZIP
    log_trace("zip: Comment of length %u\n", len);
#endif
  }
  return 0;
}
Пример #15
0
static int get_geometry_from_nonembr(const unsigned char *buffer, const int verbose, CHSgeometry_t *geometry)
{
  {
    /* Ugly hack to get geometry from FAT and NTFS */
    const struct fat_boot_sector *fat_header=(const struct fat_boot_sector *)buffer;
    if(le16(fat_header->marker)==0xAA55)
    {
      if(le16(fat_header->secs_track)>0 && le16(fat_header->secs_track)<=63 &&
          le16(fat_header->heads)>0 && le16(fat_header->heads)<=255 &&
	  fat_sector_size(fat_header)>0 && fat_sector_size(fat_header)%512==0)
      {
        geometry->sectors_per_head=le16(fat_header->secs_track);
        geometry->heads_per_cylinder=le16(fat_header->heads);
	geometry->bytes_per_sector=fat_sector_size(fat_header);
      }
    }
  }
  return 0;
}
Пример #16
0
static int test_LVM(disk_t *disk_car, const pv_disk_t *pv, const partition_t *partition, const int verbose, const int dump_ind)
{
  if ((memcmp((const char *)pv->id,LVM_ID,sizeof(pv->id)) == 0) && (le16(pv->version) == 1 || le16(pv->version) == 2))
  {
    uint32_t size;
    if(verbose>0 || dump_ind!=0)
    {
      log_info("\nLVM magic value at %u/%u/%u\n", offset2cylinder(disk_car,partition->part_offset),offset2head(disk_car,partition->part_offset),offset2sector(disk_car,partition->part_offset));
    }
    if(dump_ind!=0)
    {
      /* There is a little offset ... */
      dump_log(pv,DEFAULT_SECTOR_SIZE);
    }
    if (le32(pv->pv_size) > LVM_MAX_SIZE)
      return (1);
    if (le32(pv->pv_status) != 0 && le32(pv->pv_status) != PV_ACTIVE)
      return (1);
    if (le32(pv->pv_allocatable) != 0 && le32(pv->pv_allocatable) != PV_ALLOCATABLE)
      return (1);
    if (le32(pv->lv_cur) > MAX_LV)
      return (1);
    if (strlen((const char *)pv->vg_name) > NAME_LEN / 2)
      return (1);
    size = le32(pv->pe_size) / LVM_MIN_PE_SIZE * LVM_MIN_PE_SIZE;
    if ((le32(pv->pe_size) != size) ||
	(le32(pv->pe_size) < LVM_MIN_PE_SIZE) ||
	(le32(pv->pe_size) > LVM_MAX_PE_SIZE))
      return (1);

    if (le32(pv->pe_total) > ( pv->pe_on_disk.size / sizeof ( disk_pe_t)))
      return (1);
    if (le32(pv->pe_allocated) > le32(pv->pe_total))
      return (1);
    return 0;
  }
  return 1;
}
Пример #17
0
const char *find_tag_from_tiff_header_le(const TIFFHeader *tiff, const unsigned int tiff_size, const unsigned int tag, const char**potential_error)
{
  const struct ifd_header *ifd0;
  const struct ifd_header *exififd;
  const uint32_t *tiff_next_diroff;
  if(tiff_size < sizeof(TIFFHeader))
    return NULL;
  if(tiff_size < le32(tiff->tiff_diroff)+sizeof(TIFFDirEntry))
    return NULL;
  ifd0=(const struct ifd_header *)((const char*)tiff + le32(tiff->tiff_diroff));
  /* Bound checking */
  if((const char*)ifd0 < (const char*)tiff ||
      (const char*)(ifd0+1) > (const char*)tiff + tiff_size)
    return NULL;
  {
    const char *tmp=find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, ifd0);
    if(tmp)
      return tmp;
  }
  exififd=(const struct ifd_header *)find_tag_from_tiff_header_le_aux(tiff, tiff_size, TIFFTAG_EXIFIFD, potential_error, ifd0);
  if(exififd!=NULL)
  {
    /* Exif */
    const char *tmp=find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, exififd);
    if(tmp)
      return tmp;
  }
  tiff_next_diroff=(const uint32_t *)(&ifd0->ifd + le16(ifd0->nbr_fields));
  if( (const char *)tiff_next_diroff >= (const char *)tiff &&
      (const char *)(tiff_next_diroff + 1) < (const char*)tiff + tiff_size &&
      le32(*tiff_next_diroff)>0)
  {
    /* IFD1 */
    const struct ifd_header *ifd1=(const struct ifd_header*)((const char *)tiff+le32(*tiff_next_diroff));
    return find_tag_from_tiff_header_le_aux(tiff, tiff_size, tag, potential_error, ifd1);
  }
  return NULL;
}
Пример #18
0
static data_check_t psd_skip_color_mode(const unsigned char *buffer, const unsigned int buffer_size, file_recovery_t *file_recovery)
{
  const struct psd_file_header *psd=(const struct psd_file_header *)&buffer[buffer_size/2];
  psd_image_data_size_max=(uint64_t)le16(psd->channels) * le32(psd->height) * le32(psd->width) * le16(psd->depth) / 8;
#ifdef DEBUG_PSD
  log_info("psd_image_data_size_max %lu\n", (long unsigned)psd_image_data_size_max);
#endif
  while(file_recovery->calculated_file_size + buffer_size/2  >= file_recovery->file_size &&
      file_recovery->calculated_file_size + 16 < file_recovery->file_size + buffer_size/2)
  {
    const unsigned int i=file_recovery->calculated_file_size - file_recovery->file_size + buffer_size/2;
    const unsigned int l=get_be32(buffer, i)+4;
#ifdef DEBUG_PSD
    log_info("Color mode at 0x%lx\n", (long unsigned)(l + file_recovery->calculated_file_size));
#endif
    if(l<4)
      return DC_STOP;
    file_recovery->calculated_file_size+=l;
    file_recovery->data_check=&psd_skip_image_resources;
    return psd_skip_image_resources(buffer, buffer_size, file_recovery);
  }
  return DC_CONTINUE;
}
Пример #19
0
static int header_check_ext2_sb(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
  const struct ext2_super_block *sb=(const struct ext2_super_block *)buffer;
  if(le16(sb->s_magic)!=EXT2_SUPER_MAGIC)
    return 0;
  if (le32(sb->s_free_blocks_count) >= le32(sb->s_blocks_count))
    return 0;
  if (le32(sb->s_free_inodes_count) >= le32(sb->s_inodes_count))
    return 0;
  if (le16(sb->s_errors)!=0 &&
      (le16(sb->s_errors) != EXT2_ERRORS_CONTINUE) &&
      (le16(sb->s_errors) != EXT2_ERRORS_RO) &&
      (le16(sb->s_errors) != EXT2_ERRORS_PANIC))
    return 0;
  if ((le16(sb->s_state) & ~(EXT2_VALID_FS | EXT2_ERROR_FS))!=0)
    return 0;
  if (le32(sb->s_blocks_count) == 0) /* reject empty filesystem */
    return 0;
  if(le32(sb->s_log_block_size)>2)  /* block size max = 4096, can be 8192 on alpha */
    return 0;
  reset_file_recovery(file_recovery_new);
  file_recovery_new->extension=file_hint_ext2_sb.extension;
  return 1;
}
Пример #20
0
static int header_check_fat(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
  const struct fat_boot_sector *fat_header=(const struct fat_boot_sector *)buffer;
  uint64_t start_fat1,start_data,part_size;
  unsigned long int no_of_cluster,fat_length,fat_length_calc;
  if(!(le16(fat_header->marker)==0xAA55
        && (fat_header->ignored[0]==0xeb || fat_header->ignored[0]==0xe9)
        && (fat_header->fats==1 || fat_header->fats==2)))
    return 0;   /* Obviously not a FAT */
  if(!((fat_header->ignored[0]==0xeb && fat_header->ignored[2]==0x90)||fat_header->ignored[0]==0xe9))
    return 0;
  if(fat_sector_size(fat_header)==0 || fat_sector_size(fat_header)%512!=0)
    return 0;
  switch(fat_header->sectors_per_cluster)
  {
    case 1:
    case 2:
    case 4:
    case 8:
    case 16:
    case 32:
    case 64:
    case 128:
      break;
    default:
      return 0;
  }
  if(fat_header->fats!=1 && fat_header->fats!=2)
    return 0;
  if(fat_header->media!=0xF0 && fat_header->media<0xF8)
    return 0;
  fat_length=le16(fat_header->fat_length)>0?le16(fat_header->fat_length):le32(fat_header->fat32_length);
  part_size=(sectors(fat_header)>0?sectors(fat_header):le32(fat_header->total_sect));
  start_fat1=le16(fat_header->reserved);
  start_data=start_fat1+fat_header->fats*fat_length+(get_dir_entries(fat_header)*32+fat_sector_size(fat_header)-1)/fat_sector_size(fat_header);
  no_of_cluster=(part_size-start_data)/fat_header->sectors_per_cluster;
  if(no_of_cluster<4085)
  {
    /* FAT12 */
    if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0))
      return 0;
    if((le16(fat_header->fat_length)>256)||(le16(fat_header->fat_length)==0))
      return 0;
    fat_length_calc=((no_of_cluster+2+fat_sector_size(fat_header)*2/3-1)*3/2/fat_sector_size(fat_header));
  }
  else if(no_of_cluster<65525)
  {
    /* FAT16 */
    if(le16(fat_header->fat_length)==0)
      return 0;
    if((get_dir_entries(fat_header)==0)||(get_dir_entries(fat_header)%16!=0))
      return 0;
    fat_length_calc=((no_of_cluster+2+fat_sector_size(fat_header)/2-1)*2/fat_sector_size(fat_header));
  }
  else
  {
    /* FAT32 */
    if(sectors(fat_header)!=0)
      return 0;
    if(get_dir_entries(fat_header)!=0)
      return 0;
    if((le32(fat_header->root_cluster)<2) ||(le32(fat_header->root_cluster)>=2+no_of_cluster))
      return 0;
    fat_length_calc=((no_of_cluster+2+fat_sector_size(fat_header)/4-1)*4/fat_sector_size(fat_header));
  }
  if(fat_length<fat_length_calc)
    return 0;
  reset_file_recovery(file_recovery_new);
  file_recovery_new->extension=file_hint_fat.extension;
  file_recovery_new->calculated_file_size=(uint64_t)
    (sectors(fat_header)>0?sectors(fat_header):le32(fat_header->total_sect)) *
    fat_sector_size(fat_header);
  file_recovery_new->data_check=&data_check_size;
  file_recovery_new->file_check=&file_check_size;
  return 1;
}
Пример #21
0
Sint16 File::read16le()
{
	return le16(read<Sint16>());
}
Пример #22
0
// Load an ELF file and prepare it for flashing
int flash_load(flash_file_t *ctx, const char *name, int can_write_bl)
{
	FILE *fd = NULL;
	Elf32_Ehdr ehdr;
	Elf32_Phdr *phdrs = NULL;
	int num_phdrs;
	int res;

	fd = fopen(name, "rb");
	if (!fd) {
		fprintf(stderr, "Could not open file '%s': ", name);
		perror(NULL);
		goto fail;
	}

	fprintf(stderr, "Loading ELF file '%s'...\n", name);

	if (fread(&ehdr, sizeof(ehdr), 1, fd) != 1) {
		fprintf(stderr, "Error while reading ELF file header\n");
		goto fail;
	}
	if (memcmp(ehdr.e_ident, elf_ident, sizeof(elf_ident))
		|| le32(ehdr.e_version) != 1)
	{
		fprintf(stderr, "Not an ELF file or wrong ELF type\n");
		goto fail;
	}
	if (le16(ehdr.e_type) != ET_EXEC) {
		fprintf(stderr, "ELF is not executable\n");
		goto fail;
	}
	if (le16(ehdr.e_machine) != EM_ARM) {
		fprintf(stderr, "Wrong ELF architecture\n");
		goto fail;
	}
	if (!ehdr.e_phnum || !ehdr.e_phoff) {
		fprintf(stderr, "ELF has no PHDRs\n");
		goto fail;
	}
	if (le16(ehdr.e_phentsize) != sizeof(Elf32_Phdr)) {
		// could be a structure padding issue...
		fprintf(stderr, "Either the ELF file or this code is made of fail\n");
		goto fail;
	}
	num_phdrs = le16(ehdr.e_phnum);

	phdrs = malloc(le16(ehdr.e_phnum) * sizeof(Elf32_Phdr));
	if (!phdrs) {
		fprintf(stderr, "Out of memory\n");
		goto fail;
	}
	if (fseek(fd, le32(ehdr.e_phoff), SEEK_SET) < 0) {
		fprintf(stderr, "Error while reading ELF PHDRs\n");
		goto fail;
	}
	if (fread(phdrs, sizeof(Elf32_Phdr), num_phdrs, fd) != num_phdrs) {
		fprintf(stderr, "Error while reading ELF PHDRs\n");
		goto fail;
	}

	res = build_segs_from_phdrs(ctx, fd, phdrs, num_phdrs);
	if (res < 0)
		goto fail;
	res = check_segs(ctx, can_write_bl);
	if (res < 0)
		goto fail;

	free(phdrs);
	fclose(fd);
	ctx->filename = name;
	return 0;

fail:
	if (phdrs)
		free(phdrs);
	if (fd)
		fclose(fd);
	flash_free(ctx);
	return -1;
}
Пример #23
0
int main(int argc, char **argv) 
{
	struct FSE_ucode code, *ucode = &code;
	int i, size, reg, val, mask;
	u8 msg[5];
	msg[0] = 0x05;
	msg[1] = 0x46;
	msg[2] = 0x36;
	msg[3] = 0x26;
	msg[4] = 0x16;
	/* create a script */
	FSE_init(ucode);
	FSE_write(ucode, 0x12345678, 0xdeadbeef);
	FSE_write(ucode, 0x12345678, 0xef);
	FSE_wait(ucode, 0x12345678, 0x0f0f0f0f, 0xdeadbeef);
	FSE_mask(ucode, 0x12345678, 0x0f0f0f0f, 0xdeadbeef);
	FSE_delay_ns(ucode, 9999999);
	FSE_send_msg(ucode, 5, msg);
	FSE_fini(ucode);
	
	/* print the generated code */
	printf("encoded program: ucode->len = %i bytes", ucode->len);
	for (i = 0; i < ucode->len; i++) {
		if (i % 16 == 0)
			printf("\n%08x: ", i);
		printf("%01x ", ucode->ptr.u08[i]);
	}
	printf("\n\n");
	
	/* decode */
	printf("decode program:\n");
	i = 0;
	while (i < ucode->len) {
		u8 opcode = le8(ucode->ptr.u08, &i);
		printf("opcode = 0x%02x\n", opcode);
		
		switch (opcode) {
		  
			case 0x00:
				printf("FSE_delay(0x%08x 0x%08x)\n",le32(ucode->ptr.u08, &i), le32(ucode->ptr.u08, &i));
				break;
				
			case 0x01:
				printf("FSE_delay(0x%04x)\n",le16(ucode->ptr.u08, &i));
				break;
				  
			case 0x02:
				printf("FSE_delay_ns(0x%04x)\n",le16(ucode->ptr.u08, &i));
				break;
				
			case 0x10:
				reg = le32(ucode->ptr.u08, &i);
				val = le32(ucode->ptr.u08, &i);
				printf("FSE_write(0x%08x, 0x%08x);\n", reg, val);
				break;
			
			case 0x11:
				reg = le32(ucode->ptr.u08, &i);
				val = le8(ucode->ptr.u08, &i);
				printf("FSE_write(0x%08x, 0x%02x);\n", reg, val);
				break;
			
			case 0x12:
				reg = le32(ucode->ptr.u08, &i);
				mask = le32(ucode->ptr.u08, &i);
				val = le32(ucode->ptr.u08, &i);
				printf("FSE_mask(0x%08x, 0x%08x, 0x%08x);\n",reg, mask, val);
				break;
				
			case 0x13:
				reg = le32(ucode->ptr.u08, &i);
				mask = le32(ucode->ptr.u08, &i);
				val = le32(ucode->ptr.u08, &i);
				printf("FSE_wait(0x%08x, 0x%08x, 0x%08x);\n", reg, mask, val);
				break;
				
			case 0x20:
				size = le16(ucode->ptr.u08, &i);
				printf("FSE_send_msg(%d", size);
				while(size) 
				{
				      printf(",0x%02x", le8(ucode->ptr.u08, &i));      
				      size--;
				}
				printf(")\n");
				break; 
			
			case 0xff:
				printf("exit\n");
				break;
			
			default:
				printf("unknown opcode %1x\n", opcode);
				break;
		}
	}
	
	
	return 0;
}
Пример #24
0
unsigned int fat_get_cluster_from_entry(const struct msdos_dir_entry *entry)
{
  return (((unsigned long int)le16(entry->starthi))<<16) | le16(entry->start);
}
Пример #25
0
int ext2_gfun(disk_desc *d, g_module *m)
{
	struct ext2fs_sb *sb, *sparesb;
	int psize, bsize = 1024;
	s64_t ls, ofs;
	dos_part_entry *pt = &m->m_part;
	byte_t *ubuf, *sbuf;

	m->m_guess = GM_NO;
	sb = (struct ext2fs_sb *)(d->d_sbuf + SUPERBLOCK_OFFSET);
	if (sb->s_magic != le16(EXT2_SUPER_MAGIC))
		return (1);

	/*
	 * first some plausability checks.
	 */

	if (sb->s_free_blocks_count >= sb->s_blocks_count)
		return (1);
	if (sb->s_free_inodes_count >= sb->s_inodes_count)
		return (1);
	if (sb->s_errors && (sb->s_errors != EXT2_ERRORS_CONTINUE) && (sb->s_errors != EXT2_ERRORS_RO) &&
		(sb->s_errors != EXT2_ERRORS_PANIC))
		return (1);
	if (sb->s_state & ~(EXT2_VALID_FS | EXT2_ERROR_FS))
		return (1);

	/*
	 * empty filesystems seem unlikely to me.
	 */

	if (sb->s_blocks_count == 0)
		return (1);

	/*
	 * yet they also shouldn't be too large.
	 */

	if (d->d_nsecs) {
		ls = sb->s_blocks_count;
		ls *= bsize;
		ls /= d->d_ssize;
		ls += d->d_nsb;
		if (ls > d->d_nsecs)
			return (1);
	}

	/*
	 * ext2fs supports 1024, 2048 and 4096b blocks.
	 */

	switch (sb->s_log_block_size) {
	case BSIZE_1024:
		bsize = 1024;
		break;
	case BSIZE_2048:
		bsize = 2048;
		break;
	case BSIZE_4096:
		bsize = 4096;
		break;
	default:
		return (1);
	}

	/*
	 * current mount count shouldn't be greater than max+20
	 * but ext3 usually has s_max_mnt_count==-1
	 */

	if ((sb->s_max_mnt_count != -1) && (sb->s_mnt_count > sb->s_max_mnt_count + 20))
		return (1);

	/*
	 * up to here this looks like a valid ext2 sb, now try to read
	 * the first spare super block to be sure.
	 */

	if ((ls = l64tell(d->d_fd)) == -1)
		pr(FATAL, "ext2: cannot seek: %s", strerror(errno));
	ls /= d->d_ssize;
	ls -= d->d_nsb;
	ls *= d->d_ssize;
	ofs = sb->s_blocks_per_group + sb->s_first_data_block;
	ofs *= bsize;
	if (l64seek(d->d_fd, ofs - ls, SEEK_CUR) == -1)
		pr(FATAL, "ext2: cannot seek: %s", strerror(errno));

	psize = getpagesize();
	ubuf = alloc(SUPERBLOCK_SIZE + psize);
	sbuf = align(ubuf, psize);
	if (read(d->d_fd, sbuf, SUPERBLOCK_SIZE) != SUPERBLOCK_SIZE)
		pr(FATAL, "ext2: cannot read spare super block");
	sparesb = (struct ext2fs_sb *)sbuf;

	/*
	 * test only some values of the spare sb.
	 */

	if (sparesb->s_magic != le16(EXT2_SUPER_MAGIC))
		goto out;
	if (sparesb->s_log_block_size != sb->s_log_block_size)
		goto out;

	/*
	 * seems ok.
	 */

	m->m_guess = GM_YES;
	pt->p_typ = 0x83;
	pt->p_start = d->d_nsb;
	pt->p_size = bsize / d->d_ssize;
	pt->p_size *= sb->s_blocks_count;

out:
	free((void *)ubuf);
	return (1);
}
Пример #26
0
static void file_rename_doc(const char *old_filename)
{
  const char *ext=NULL;
  char *title=NULL;
  FILE *file;
  unsigned char buffer_header[512];
  uint32_t *fat;
  const struct OLE_HDR *header=(const struct OLE_HDR*)&buffer_header;
  time_t file_time=0;
  unsigned int fat_entries;
  if(strstr(old_filename, ".sdd")!=NULL)
    ext="sdd";
  if((file=fopen(old_filename, "rb"))==NULL)
    return;
#ifdef DEBUG_OLE
  log_info("file_rename_doc(%s)\n", old_filename);
#endif
  /*reads first sector including OLE header */
  if(my_fseek(file, 0, SEEK_SET) < 0 ||
      fread(&buffer_header, sizeof(buffer_header), 1, file) != 1)
  {
    fclose(file);
    return ;
  }
  /* Sanity check */
  if(le32(header->num_FAT_blocks)==0 ||
      le32(header->num_extra_FAT_blocks)>50 ||
      le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
  {
    fclose(file);
    return ;
  }
  if((fat=OLE_load_FAT(file, header))==NULL)
  {
    fclose(file);
    return ;
  }
  fat_entries=(le32(header->num_FAT_blocks)==0 ?
      109:
      (le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4);
  {
    unsigned int ministream_block=0;
    unsigned int ministream_size=0;
    unsigned int block;
    unsigned int i;
    /* FFFFFFFE = ENDOFCHAIN
     * Use a loop count i to avoid endless loop */
#ifdef DEBUG_OLE
    log_info("file_rename_doc root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
#endif
    for(block=le32(header->root_start_block), i=0;
	block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
	block=le32(fat[block]), i++)
    {
      struct OLE_DIR *dir_entries;
      if(my_fseek(file, (1+block)<<le16(header->uSectorShift), SEEK_SET)<0)
      {
	free(fat);
	fclose(file);
	free(title);
	return ;
      }
      dir_entries=(struct OLE_DIR *)MALLOC(1<<le16(header->uSectorShift));
      if(fread(dir_entries, 1<<le16(header->uSectorShift), 1, file)!=1)
      {
	free(fat);
	free(dir_entries);
	fclose(file);
	free(title);
	return ;
      }

#ifdef DEBUG_OLE
      log_info("Root Directory block=%u (0x%x)\n", block, block);
#endif
      {
	unsigned int sid;
	const struct OLE_DIR *dir_entry=dir_entries;
	if(i==0)
	{
	  ministream_block=le32(dir_entry->start_block);
	  ministream_size=le32(dir_entry->size);
	}
	for(sid=0, dir_entry=dir_entries;
	    sid<(1<<le16(header->uSectorShift))/sizeof(struct OLE_DIR);
	    sid++,dir_entry++)
	{
	  if(dir_entry->type!=NO_ENTRY)
	  {
	    const char SummaryInformation[40]=
	    {
	      0x05, '\0', 'S', '\0', 'u', '\0', 'm', '\0',
	      'm', '\0', 'a', '\0', 'r', '\0', 'y', '\0',
	      'I', '\0', 'n', '\0', 'f', '\0', 'o', '\0',
	      'r', '\0', 'm', '\0', 'a', '\0', 't', '\0',
	      'i', '\0', 'o', '\0', 'n', '\0', '\0', '\0'
	    };
#ifdef DEBUG_OLE
	    unsigned int j;
	    for(j=0;j<64 && j<le16(dir_entry->namsiz) && dir_entry->name[j]!='\0';j+=2)
	    {
	      log_info("%c",dir_entry->name[j]);
	    }
	    log_info(" type %u", dir_entry->type);
	    log_info(" Flags=%s", (dir_entry->bflags==0?"Red":"Black"));
	    log_info(" sector %u (%u bytes)\n",
		(unsigned int)le32(dir_entry->start_block),
		(unsigned int)le32(dir_entry->size));
#endif
	    switch(le16(dir_entry->namsiz))
	    {
	      case 12:
		/* 3ds max */
		if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0)
		  ext="max";
		/* Licom AlphaCAM */
		else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0)
		  ext="amb";
		break;
	      case 16:
		if(sid==1 && memcmp(dir_entry->name, "d\0o\0c\0.\0d\0e\0t\0\0\0", 16)==0)
		  ext="psmodel";
		/* Windows Sticky Notes */
		else if(sid==1 && memcmp(dir_entry->name, "V\0e\0r\0s\0i\0o\0n\0\0\0", 16)==0)
		  ext="snt";
		break;
	      case 18:
		/* MS Excel
		 * Note: Microsoft Works Spreadsheet contains the same signature */
		if(ext==NULL &&
		    memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0)
		  ext="xls";
		/* Microsoft Works .wps */
		else if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0)
		  ext="wps";
		break;
	      case 20:
		/* Page Maker */
		if(memcmp(&dir_entry->name, "P\0a\0g\0e\0M\0a\0k\0e\0r\0\0\0", 20)==0)
		  ext="p65";
		break;
	      case 22:
		/* SigmaPlot .jnb */
		if(memcmp(dir_entry->name, "J\0N\0B\0V\0e\0r\0s\0i\0o\0n\0\0", 22)==0)
		  ext="jnb";
		break;
	      case 24:
		/* HP Photosmart Photo Printing Album */
		if(memcmp(dir_entry->name,"I\0m\0a\0g\0e\0s\0S\0t\0o\0r\0e\0\0\0",24)==0)
		  ext="albm";
		break;
	      case 28:
		/* Microsoft Works Spreadsheet or Chart */
		if(memcmp(dir_entry->name,"W\0k\0s\0S\0S\0W\0o\0r\0k\0B\0o\0o\0k\0\0\0",28)==0)
		  ext="xlr";
		/* Visio */
		else if(memcmp(dir_entry->name,"V\0i\0s\0i\0o\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",28)==0)
		  ext="vsd";
		/* SolidWorks */
		else if(memcmp(&dir_entry->name, "s\0w\0X\0m\0l\0C\0o\0n\0t\0e\0n\0t\0s\0\0\0", 28)==0)
		{
#ifdef DJGPP
		  ext="sld";
#else
		  ext="sldprt";
#endif
		}
		break;
	      case 32:
		if(memcmp(dir_entry->name, "m\0a\0n\0i\0f\0e\0s\0t\0.\0c\0a\0m\0x\0m\0l\0\0\0",32)==0)
		  ext="camrec";
		break;
	      case 34:
		if(memcmp(dir_entry->name, "S\0t\0a\0r\0C\0a\0l\0c\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",34)==0)
		  ext="sdc";
		break;
	      case 36:
		/* sda=StarDraw, sdd=StarImpress */
		if((ext==NULL || strcmp(ext,"sdd")!=0) &&
		    memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0)
		  ext="sda";
		else if(memcmp(dir_entry->name, "f\0i\0l\0e\0_\0C\0O\0M\0P\0A\0N\0Y\0_\0F\0I\0L\0E\0\0\0", 36)==0)
		    ext="qbb";
		break;
	      case 38:
		/* Quattro Pro spreadsheet */
		if(memcmp(dir_entry->name, "N\0a\0t\0i\0v\0e\0C\0o\0n\0t\0e\0n\0t\0_\0M\0A\0I\0N\0\0\0", 38)==0)
		  ext="qpw";
		else if(memcmp(dir_entry->name, "S\0t\0a\0r\0W\0r\0i\0t\0e\0r\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 38)==0)
		  ext="sdw";
		break;
	      case 40:
		if(memcmp(dir_entry->name, SummaryInformation, 40)==0)
		{
		  OLE_parse_summary(file, fat, fat_entries, header,
		      ministream_block, ministream_size,
		      le32(dir_entry->start_block), le32(dir_entry->size),
		      &ext, &title, &file_time);
		}
		else if(memcmp(dir_entry->name,"P\0o\0w\0e\0r\0P\0o\0i\0n\0t\0 \0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 40)==0)
		  ext="ppt";
		/* Outlook */
		else if(memcmp(dir_entry->name,"_\0_\0n\0a\0m\0e\0i\0d\0_\0v\0e\0r\0s\0i\0o\0n\0001\0.\0000\0\0\0",40)==0)
		  ext="msg";
		break;
	      case 46:
		if(memcmp(dir_entry->name,
		      "I\0S\0o\0l\0i\0d\0W\0o\0r\0k\0s\0I\0n\0f\0o\0r\0m\0a\0t\0i\0o\0n\0\0\0", 46)==0)
		{
#ifdef DJGPP
		  ext="sld";
#else
		  ext="sldprt";
#endif
		}
		break;
	      case 56:
		/* Wilcom ES Software */
		if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0)
		  ext="emb";
		break;
	    }
	    if(sid==1 && le16(dir_entry->namsiz) >=6 &&
		memcmp(dir_entry->name, "D\0g\0n", 6)==0)
	      ext="dgn";
#ifdef DEBUG_OLE
	    if(ext!=NULL)
	      log_info("Found %s %u\n", ext, le16(dir_entry->namsiz));
#endif
	  }
	}
      }
      free(dir_entries);
    }
  }
  free(fat);
  fclose(file);
  if(file_time!=0 && file_time!=(time_t)-1)
    set_date(old_filename, file_time, file_time);
  if(title!=NULL)
  {
    file_rename(old_filename, (const unsigned char*)title, strlen(title), 0, ext, 1);
    free(title);
  }
  else
    file_rename(old_filename, NULL, 0, 0, ext, 1);
}
Пример #27
0
static void file_check_doc(file_recovery_t *file_recovery)
{
  unsigned char buffer_header[512];
  uint64_t doc_file_size;
  uint32_t *fat;
  unsigned long int i;
  unsigned int freesect_count=0;  
  const struct OLE_HDR *header=(const struct OLE_HDR*)&buffer_header;
  const uint64_t doc_file_size_org=file_recovery->file_size;
  file_recovery->file_size=0;
  /*reads first sector including OLE header */
  if(my_fseek(file_recovery->handle, 0, SEEK_SET) < 0 ||
      fread(&buffer_header, sizeof(buffer_header), 1, file_recovery->handle) != 1)
    return ;
#ifdef DEBUG_OLE
  log_info("file_check_doc %s\n", file_recovery->filename);
  log_trace("sector size          %u\n",1<<le16(header->uSectorShift));
  log_trace("num_FAT_blocks       %u\n",le32(header->num_FAT_blocks));
  log_trace("num_extra_FAT_blocks %u\n",le32(header->num_extra_FAT_blocks));
#endif
  /* Sanity check */
  if(le32(header->num_FAT_blocks)==0 ||
      le32(header->num_extra_FAT_blocks)>50 ||
      le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
    return ;
  if((fat=OLE_load_FAT(file_recovery->handle, header))==NULL)
  {
#ifdef DEBUG_OLE
    log_info("OLE_load_FAT failed\n");
#endif
    return ;
  }
  /* Search how many entries are not used at the end of the FAT */
  for(i=(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-1;
      i>0 && le32(fat[i])==0xFFFFFFFF;
      i--)
    freesect_count++;
  doc_file_size=((1+(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4-freesect_count)<<le16(header->uSectorShift));
  if(doc_file_size > doc_file_size_org)
  {
#ifdef DEBUG_OLE
    log_info("doc_file_size=(1+(%u<<%u)/4-%u)<<%u\n",
	le32(header->num_FAT_blocks), le16(header->uSectorShift),
	freesect_count, le16(header->uSectorShift));
    log_info("doc_file_size %llu > doc_file_size_org %llu\n",
    (unsigned long long)doc_file_size, (unsigned long long)doc_file_size_org);
#endif
    free(fat);
    return ;
  }
#ifdef DEBUG_OLE
  log_trace("==> size : %llu\n", (long long unsigned)doc_file_size);
#endif
  {
    unsigned int block;
    const unsigned int fat_entries=(le32(header->num_FAT_blocks)==0 ?
	109:
	(le32(header->num_FAT_blocks)<<le16(header->uSectorShift))/4);
#ifdef DEBUG_OLE
    log_info("root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
#endif
    /* FFFFFFFE = ENDOFCHAIN
     * Use a loop count i to avoid endless loop */
    for(block=le32(header->root_start_block), i=0;
	block!=0xFFFFFFFE && i<fat_entries;
	block=le32(fat[block]), i++)
    {
      struct OLE_DIR *dir_entries;
#ifdef DEBUG_OLE
      log_info("read block %u\n", block);
#endif
      if(!(block < fat_entries))
      {
	free(fat);
	return ;
      }
      if(my_fseek(file_recovery->handle, (1+block)<<le16(header->uSectorShift), SEEK_SET)<0)
      {
#ifdef DEBUG_OLE
	log_info("fseek failed\n");
#endif
	free(fat);
	return ;
      }
      dir_entries=(struct OLE_DIR *)MALLOC(1<<le16(header->uSectorShift));
      if(fread(dir_entries, (1<<le16(header->uSectorShift)), 1, file_recovery->handle)!=1)
      {
#ifdef DEBUG_OLE
	log_info("fread failed\n");
#endif
	free(dir_entries);
	free(fat);
	return ;
      }
      {
	unsigned int sid;
	struct OLE_DIR *dir_entry;
	for(sid=0, dir_entry=dir_entries;
	    sid<(1<<le16(header->uSectorShift))/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
	    sid++,dir_entry++)
	{
	    if(le32(dir_entry->start_block) > 0 && le32(dir_entry->size) > 0 &&
		((le32(dir_entry->size) >= le32(header->miniSectorCutoff)
		  && le32(dir_entry->start_block) > fat_entries) ||
		 le32(dir_entry->size) > doc_file_size))
	  {
#ifdef DEBUG_OLE
	    log_info("error at sid %u\n", sid);
#endif
	    free(dir_entries);
	    free(fat);
	    return ;
	  }
	}
      }
      free(dir_entries);
    }
  }
  free(fat);
  file_recovery->file_size=doc_file_size;
}
Пример #28
0
static int header_check_doc(const unsigned char *buffer, const unsigned int buffer_size, const unsigned int safe_header_only, const file_recovery_t *file_recovery, file_recovery_t *file_recovery_new)
{
  const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
  if(memcmp(buffer,doc_header,sizeof(doc_header))!=0)
    return 0;
  /* Check for Little Endian */
  if(le16(header->uByteOrder)!=0xFFFE)
    return 0;
  if(le16(header->uDllVersion)!=3 && le16(header->uDllVersion)!=4)
    return 0;
  if(le16(header->reserved)!=0 || le32(header->reserved1)!=0)
    return 0;
  if(le16(header->uMiniSectorShift)!=6)
    return 0;
  if(le16(header->uDllVersion)==3 && le16(header->uSectorShift)!=9)
    return 0;
  /* max and qbb file have uSectorShift=12 */
  if(le16(header->uDllVersion)==4 && le16(header->uSectorShift)!=12)
    return 0;
  if(le16(header->uDllVersion)==3 && le32(header->csectDir)!=0)
    return 0;
  /* max file have csectDir=1
   * qbb file have csectDir=4 */
  if(le16(header->uDllVersion)==4 && le32(header->csectDir)==0)
    return 0;
  /*
     num_FAT_blocks=109+num_extra_FAT_blocks*(512-1);
     maximum file size is 512+(num_FAT_blocks*128)*512, about 1.6GB
     */
  if(le32(header->num_FAT_blocks)==0 ||
      le32(header->num_extra_FAT_blocks)>50 ||
      le32(header->num_FAT_blocks)>109+le32(header->num_extra_FAT_blocks)*((1<<le16(header->uSectorShift))-1))
    return 0;
  reset_file_recovery(file_recovery_new);
  file_recovery_new->file_check=&file_check_doc;
  file_recovery_new->file_rename=&file_rename_doc;
  file_recovery_new->extension=ole_get_file_extension(buffer, buffer_size);
  if(file_recovery_new->extension!=NULL)
  {
    if(strcmp(file_recovery_new->extension,"sda")==0)
    {
      if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
	file_recovery_new->extension="sdd";
    }
    else if(strcmp(file_recovery_new->extension,"wps")==0)
    {
      /* Distinguish between MS Works .wps and MS Publisher .pub */
      if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
	file_recovery_new->extension="pub";
    }
    return 1;
  }
  if(td_memmem(buffer,buffer_size,"WordDocument",12)!=NULL)
  {
    file_recovery_new->extension="doc";
  }
  else if(td_memmem(buffer,buffer_size,"StarDraw",8)!=NULL)
  {
    file_recovery_new->extension="sda";
  }
  else if(td_memmem(buffer,buffer_size,"StarCalc",8)!=NULL)
  {
    file_recovery_new->extension="sdc";
  }
  else if(td_memmem(buffer,buffer_size,"StarImpress",11)!=NULL)
  {
    file_recovery_new->extension="sdd";
  }
  else if(td_memmem(buffer,buffer_size,"Worksheet",9)!=NULL ||
      td_memmem(buffer,buffer_size,"Book",4)!=NULL || 
      td_memmem(buffer,buffer_size,"Workbook",8)!=NULL || 
      td_memmem(buffer,buffer_size,"Calc",4)!=NULL)
  {
    file_recovery_new->extension="xls";
  }
  else if(td_memmem(buffer,buffer_size,"Power",5)!=NULL)
  {
    file_recovery_new->extension="ppt";
  }
  else if(td_memmem(buffer,buffer_size,"AccessObjSiteData",17)!=NULL)
  {
    file_recovery_new->extension="mdb";
  }
  else if(td_memmem(buffer,buffer_size,"Visio",5)!=NULL)
  {
    file_recovery_new->extension="vsd";
  }
  else if(td_memmem(buffer,buffer_size,"SfxDocument",11)!=NULL)
  {
    file_recovery_new->extension="sdw";
  }
  else if(td_memmem(buffer,buffer_size,"CPicPage",8)!=NULL)
  {	/* Flash Project File */
    file_recovery_new->extension="fla";
  }
  else if(td_memmem(buffer,buffer_size,"Microsoft Publisher",19)!=NULL)
  { /* Publisher */
    file_recovery_new->extension="pub";
  }
  else if(td_memmem(buffer, buffer_size, "Microsoft Works Database", 24)!=NULL
      || td_memmem( buffer, buffer_size, "MSWorksDBDoc", 12)!=NULL)
  { /* Microsoft Works .wdb */
    file_recovery_new->extension="wdb";
  }
  else if(td_memmem(buffer,buffer_size,"MetaStock",9)!=NULL)
  { /* MetaStock */
    file_recovery_new->extension="mws";
  }
  else
    file_recovery_new->extension=file_hint_doc.extension;
  return 1;
}
Пример #29
0
static const char *ole_get_file_extension(const unsigned char *buffer, const unsigned int buffer_size)
{
  const struct OLE_HDR *header=(const struct OLE_HDR *)buffer;
  const uint32_t *fat;
  unsigned int fat_entries;
  unsigned int block;
  unsigned int i;
  if(buffer_size<512)
    return NULL;
  if(le32(header->num_FAT_blocks)==0)
  {
    fat=(const uint32_t *)(header+1);
    fat_entries=109;
  }
  else
  {
    const uint32_t *fati=(const uint32_t *)(header+1);
    const unsigned int fat_offset=(1+le32(fati[0])) << le16(header->uSectorShift);
    fat=(const uint32_t *)&buffer[fat_offset];
    fat_entries=(le32(header->num_FAT_blocks) << le16(header->uSectorShift))/4;
    if(fat_offset>buffer_size)
      fat_entries=0;
    else if(fat_offset+fat_entries>buffer_size)
      fat_entries=buffer_size-fat_offset;
  }
  /* FFFFFFFE = ENDOFCHAIN
   * Use a loop count i to avoid endless loop */
#ifdef DEBUG_OLE
    log_info("ole_get_file_extension root_start_block=%u, fat_entries=%u\n", le32(header->root_start_block), fat_entries);
#endif
  for(block=le32(header->root_start_block), i=0;
      block<fat_entries && block!=0xFFFFFFFE && i<fat_entries;
      block=le32(fat[block]), i++)
  {
    const unsigned int offset_root_dir=(1+block)<<le16(header->uSectorShift);
#ifdef DEBUG_OLE
    log_info("Root Directory block=%u (0x%x)\n", block, block);
#endif
    if(offset_root_dir>buffer_size-512)
      return NULL;
    {
      unsigned int sid;
      const struct OLE_DIR *dir_entry;
      const char *ext=NULL;
      int is_db=0;
      for(sid=0,dir_entry=(const struct OLE_DIR *)&buffer[offset_root_dir];
	  sid<512/sizeof(struct OLE_DIR) && dir_entry->type!=NO_ENTRY;
	  sid++,dir_entry++)
      {
#ifdef DEBUG_OLE
	unsigned int j;
	for(j=0;j<64 && j<le16(dir_entry->namsiz) && dir_entry->name[j]!='\0';j+=2)
	{
	  log_info("%c",dir_entry->name[j]);
	}
	for(;j<64;j+=2)
	  log_info(" ");
	log_info(" type %u", dir_entry->type);
	log_info(" Flags=%s", (dir_entry->bflags==0?"Red  ":"Black"));
	log_info(" sector %u (%u bytes)\n",
	    (unsigned int)le32(dir_entry->start_block),
	    (unsigned int)le32(dir_entry->size));
#endif
	if(sid==1 && memcmp(&dir_entry->name, "1\0\0\0", 4)==0)
	  is_db++;
	else if(sid==2 && (memcmp(&dir_entry->name, "2\0\0\0", 4)==0 ||
	      memcmp(&dir_entry->name, "C\0a\0t\0a\0l\0o\0g\0", 14)==0))
	  is_db++;
	switch(le16(dir_entry->namsiz))
	{
	  case 12:
	    /* 3ds max */
	    if(memcmp(dir_entry->name, "S\0c\0e\0n\0e\0\0\0",12)==0)
	      return "max";
	    /* Licom AlphaCAM */
	    else if(memcmp(dir_entry->name,"L\0i\0c\0o\0m\0\0\0",12)==0)
	      return "amb";
	    break;
	  case 18:
	    /* MS Excel
	     * Note: Microsoft Works Spreadsheet contains the same signature */
	    if(memcmp(dir_entry->name, "W\0o\0r\0k\0b\0o\0o\0k\0\0\0",18)==0)
	      ext="xls";
	    /* Microsoft Works .wps */
	    else if(memcmp(dir_entry->name,"C\0O\0N\0T\0E\0N\0T\0S\0\0\0",18)==0)
	      return "wps";
	    break;
	  case 20:
	    /* Page Maker */
	    if(memcmp(&dir_entry->name, "P\0a\0g\0e\0M\0a\0k\0e\0r\0\0\0", 20)==0)
	      return "p65";
	    break;
	  case 22:
	    /* SigmaPlot .jnb */
	    if(memcmp(dir_entry->name, "J\0N\0B\0V\0e\0r\0s\0i\0o\0n\0\0", 22)==0)
	      return "jnb";
	    break;
	  case 24:
	    /* HP Photosmart Photo Printing Album */
	    if(memcmp(dir_entry->name,"I\0m\0a\0g\0e\0s\0S\0t\0o\0r\0e\0\0\0",24)==0)
	      return "albm";
	    break;
	  case 28:
	    /* Microsoft Works Spreadsheet or Chart */
	    if(memcmp(dir_entry->name,"W\0k\0s\0S\0S\0W\0o\0r\0k\0B\0o\0o\0k\0\0\0",28)==0)
	      return "xlr";
	    /* Visio */
	    else if(memcmp(dir_entry->name,"V\0i\0s\0i\0o\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",28)==0)
	      return "vsd";
	/* SolidWorks */
	    else if(memcmp(&dir_entry->name,"s\0w\0X\0m\0l\0C\0o\0n\0t\0e\0n\0t\0s\0\0\0",28)==0)
	    {
#ifdef DJGPP
	      return "sld";
#else
	      return "sldprt";
#endif
	    }
	    break;
	  case 34:
	    if(memcmp(dir_entry->name, "S\0t\0a\0r\0C\0a\0l\0c\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0",34)==0)
	      return "sdc";
	    break;
	  case 36:
	    if(memcmp(dir_entry->name, "S\0t\0a\0r\0D\0r\0a\0w\0D\0o\0c\0u\0m\0e\0n\0t\0003\0\0\0", 36)==0)
	      return "sda";
	    break;
	  case 38:
	    /* Quattro Pro spreadsheet */
	    if(memcmp(dir_entry->name, "N\0a\0t\0i\0v\0e\0C\0o\0n\0t\0e\0n\0t\0_\0M\0A\0I\0N\0\0\0", 38)==0)
	      return "qpw";
	    else if(memcmp(dir_entry->name, "S\0t\0a\0r\0W\0r\0i\0t\0e\0r\0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 38)==0)
	      return "sdw";
	    break;
	  case 40:
	    if(memcmp(dir_entry->name,"P\0o\0w\0e\0r\0P\0o\0i\0n\0t\0 \0D\0o\0c\0u\0m\0e\0n\0t\0\0\0", 40)==0)
	      return "ppt";
	    /* Outlook */
	    else if(memcmp(dir_entry->name,"_\0_\0n\0a\0m\0e\0i\0d\0_\0v\0e\0r\0s\0i\0o\0n\0001\0.\0000\0\0\0",40)==0)
	      return "msg";
	    break;
	  case 46:
	    if(memcmp(dir_entry->name,
		  "I\0S\0o\0l\0i\0d\0W\0o\0r\0k\0s\0I\0n\0f\0o\0r\0m\0a\0t\0i\0o\0n\0\0\0", 46)==0)
	    {
#ifdef DJGPP
	      return "sld";
#else
	      return "sldprt";
#endif
	    }
	    break;
	  case 56:
	    /* Wilcom ES Software */
	    if(memcmp(dir_entry->name, WilcomDesignInformationDDD, 56)==0)
	      return "emb";
	    break;
	}
	if(sid==1 && memcmp(&dir_entry->name, "D\0g\0n", 6)==0)
	  return "dgn";
      }
      if(ext!=NULL)
	return ext;
      /* Thumbs.db */
      if(is_db==2)
	return "db";
    }
  }
#ifdef DEBUG_OLE
  log_info("Root Directory end\n");
#endif
  return NULL;
}
Пример #30
0
void
ldpe(Biobuf *f, char *pkg, int64 len, char *pn)
{
	char *name;
	int32 base;
	int i, j, l, numaux;
	PeObj *obj;
	PeSect *sect, *rsect;
	IMAGE_SECTION_HEADER sh;
	uchar symbuf[18];
	Sym *s;
	Reloc *r, *rp;
	PeSym *sym;

	USED(len);
	USED(pkg);
	if(debug['v'])
		Bprint(&bso, "%5.2f ldpe %s\n", cputime(), pn);
	
	sect = nil;
	version++;
	base = Boffset(f);
	
	obj = mal(sizeof *obj);
	obj->f = f;
	obj->base = base;
	obj->name = pn;
	// read header
	if(Bread(f, &obj->fh, sizeof obj->fh) != sizeof obj->fh)
		goto bad;
	// load section list
	obj->sect = mal(obj->fh.NumberOfSections*sizeof obj->sect[0]);
	obj->nsect = obj->fh.NumberOfSections;
	for(i=0; i < obj->fh.NumberOfSections; i++) {
		if(Bread(f, &obj->sect[i].sh, sizeof sh) != sizeof sh)
			goto bad;
		obj->sect[i].size = obj->sect[i].sh.SizeOfRawData;
		obj->sect[i].name = (char*)obj->sect[i].sh.Name;
		// TODO return error if found .cormeta
	}
	// load string table
	Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, &l, sizeof l) != sizeof l) 
		goto bad;
	obj->snames = mal(l);
	Bseek(f, base+obj->fh.PointerToSymbolTable+18*obj->fh.NumberOfSymbols, 0);
	if(Bread(f, obj->snames, l) != l)
		goto bad;
	// read symbols
	obj->pesym = mal(obj->fh.NumberOfSymbols*sizeof obj->pesym[0]);
	obj->npesym = obj->fh.NumberOfSymbols;
	Bseek(f, base+obj->fh.PointerToSymbolTable, 0);
	for(i=0; i<obj->fh.NumberOfSymbols; i+=numaux+1) {
		Bseek(f, base+obj->fh.PointerToSymbolTable+sizeof(symbuf)*i, 0);
		if(Bread(f, symbuf, sizeof symbuf) != sizeof symbuf)
			goto bad;
		
		if((symbuf[0] == 0) && (symbuf[1] == 0) &&
			 (symbuf[2] == 0) && (symbuf[3] == 0)) {
			l = le32(&symbuf[4]);
			obj->pesym[i].name = (char*)&obj->snames[l];
		} else { // sym name length <= 8
			obj->pesym[i].name = mal(9);
			strncpy(obj->pesym[i].name, (char*)symbuf, 8);
			obj->pesym[i].name[8] = 0;
		}
		obj->pesym[i].value = le32(&symbuf[8]);
		obj->pesym[i].sectnum = le16(&symbuf[12]);
		obj->pesym[i].sclass = symbuf[16];
		obj->pesym[i].aux = symbuf[17];
		obj->pesym[i].type = le16(&symbuf[14]);
		numaux = obj->pesym[i].aux; 
		if (numaux < 0) 
			numaux = 0;
	}
	// create symbols for mapped sections
	for(i=0; i<obj->nsect; i++) {
		sect = &obj->sect[i];
		if(sect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;
		if(map(obj, sect) < 0)
			goto bad;
		
		name = smprint("%s(%s)", pn, sect->name);
		s = lookup(name, version);
		free(name);
		switch(sect->sh.Characteristics&(IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_CNT_INITIALIZED_DATA|
			IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE|IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE)) {
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ: //.rdata
				s->type = SRODATA;
				break;
			case IMAGE_SCN_CNT_UNINITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.bss
				s->type = SBSS;
				break;
			case IMAGE_SCN_CNT_INITIALIZED_DATA|IMAGE_SCN_MEM_READ|IMAGE_SCN_MEM_WRITE: //.data
				s->type = SDATA;
				break;
			case IMAGE_SCN_CNT_CODE|IMAGE_SCN_MEM_EXECUTE|IMAGE_SCN_MEM_READ: //.text
				s->type = STEXT;
				break;
			default:
				werrstr("unexpected flags for PE section %s", sect->name);
				goto bad;
		}
		s->p = sect->base;
		s->np = sect->size;
		s->size = sect->size;
		if(s->type == STEXT) {
			if(etextp)
				etextp->next = s;
			else
				textp = s;
			etextp = s;
		}
		sect->sym = s;
		if(strcmp(sect->name, ".rsrc") == 0)
			setpersrc(sect->sym);
	}
	
	// load relocations
	for(i=0; i<obj->nsect; i++) {
		rsect = &obj->sect[i];
		if(rsect->sym == 0 || rsect->sh.NumberOfRelocations == 0)
			continue;
		if(rsect->sh.Characteristics&IMAGE_SCN_MEM_DISCARDABLE)
			continue;
		r = mal(rsect->sh.NumberOfRelocations*sizeof r[0]);
		Bseek(f, obj->base+rsect->sh.PointerToRelocations, 0);
		for(j=0; j<rsect->sh.NumberOfRelocations; j++) {
			rp = &r[j];
			if(Bread(f, symbuf, 10) != 10)
				goto bad;
			
			uint32 rva, symindex;
			uint16 type;
			rva = le32(&symbuf[0]);
			symindex = le32(&symbuf[4]);
			type = le16(&symbuf[8]);
			if(readsym(obj, symindex, &sym) < 0)
				goto bad;
			if(sym->sym == nil) {
				werrstr("reloc of invalid sym %s idx=%d type=%d", sym->name, symindex, sym->type);
				goto bad;
			}
			rp->sym = sym->sym;
			rp->siz = 4;
			rp->off = rva;
			switch(type) {
				default:
					diag("%s: unknown relocation type %d;", pn, type);
				case IMAGE_REL_I386_REL32:
				case IMAGE_REL_AMD64_REL32:
				case IMAGE_REL_AMD64_ADDR32: // R_X86_64_PC32
				case IMAGE_REL_AMD64_ADDR32NB:
					rp->type = D_PCREL;
					rp->add = le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_I386_DIR32NB:
				case IMAGE_REL_I386_DIR32:
					rp->type = D_ADDR;
					// load addend from image
					rp->add = le32(rsect->base+rp->off);
					break;
				case IMAGE_REL_AMD64_ADDR64: // R_X86_64_64
					rp->siz = 8;
					rp->type = D_ADDR;
					// load addend from image
					rp->add = le64(rsect->base+rp->off);
					break;
			}
		}
		qsort(r, rsect->sh.NumberOfRelocations, sizeof r[0], rbyoff);
		
		s = rsect->sym;
		s->r = r;
		s->nr = rsect->sh.NumberOfRelocations;
	}
	
	// enter sub-symbols into symbol table.
	for(i=0; i<obj->npesym; i++) {
		if(obj->pesym[i].name == 0)
			continue;
		if(obj->pesym[i].name[0] == '.') //skip section
			continue;
		if(obj->pesym[i].sectnum > 0) {
			sect = &obj->sect[obj->pesym[i].sectnum-1];
			if(sect->sym == 0)
				continue;
		}
		if(readsym(obj, i, &sym) < 0)
			goto bad;
	
		s = sym->sym;
		if(sym->sectnum == 0) {// extern
			if(s->type == SDYNIMPORT)
				s->plt = -2; // flag for dynimport in PE object files.
			if (s->type == SXREF && sym->value > 0) {// global data
				s->type = SDATA; 
				s->size = sym->value;
			}
			continue;
		} else if (sym->sectnum > 0) {
			sect = &obj->sect[sym->sectnum-1];
			if(sect->sym == 0)
				diag("%s: %s sym == 0!", pn, s->name);
		} else {
			diag("%s: %s sectnum < 0!", pn, s->name);
		}

		if(sect == nil) 
			return;
		s->sub = sect->sym->sub;
		sect->sym->sub = s;
		s->type = sect->sym->type | SSUB;
		s->value = sym->value;
		s->size = 4;
		s->outer = sect->sym;
		if(sect->sym->type == STEXT) {
			Prog *p;
	
			if(s->text != P)
				diag("%s: duplicate definition of %s", pn, s->name);
			// build a TEXT instruction with a unique pc
			// just to make the rest of the linker happy.
			p = prg();
			p->as = ATEXT;
			p->from.type = D_EXTERN;
			p->from.sym = s;
			p->textflag = 7;
			p->to.type = D_CONST;
			p->link = nil;
			p->pc = pc++;
			s->text = p;
	
			etextp->next = s;
			etextp = s;
		}
	}

	return;
bad:
	diag("%s: malformed pe file: %r", pn);
}