static uint8_t ntfs_dent_copy(NTFS_INFO * ntfs, ntfs_idxentry * idxe, TSK_FS_NAME * fs_name) { ntfs_attr_fname *fname = (ntfs_attr_fname *) & idxe->stream; TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info; UTF16 *name16; UTF8 *name8; int retVal; int i; fs_name->meta_addr = tsk_getu48(fs->endian, idxe->file_ref); fs_name->meta_seq = tsk_getu16(fs->endian, idxe->seq_num); name16 = (UTF16 *) & fname->name; name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) ((uintptr_t) name16 + fname->nlen * 2), &name8, (UTF8 *) ((uintptr_t) name8 + fs_name->name_size), TSKlenientConversion); if (retVal != TSKconversionOK) { *name8 = '\0'; if (tsk_verbose) tsk_fprintf(stderr, "Error converting NTFS name to UTF8: %d %" PRIuINUM, retVal, fs_name->meta_addr); } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + fs_name->name_size) fs_name->name[fs_name->name_size] = '\0'; else *name8 = '\0'; /* Clean up name */ i = 0; while (fs_name->name[i] != '\0') { if (TSK_IS_CNTRL(fs_name->name[i])) fs_name->name[i] = '^'; i++; } if (tsk_getu64(fs->endian, fname->flags) & NTFS_FNAME_FLAGS_DIR) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; fs_name->flags = 0; return 0; }
/* * Inspects a byte address for an XTAF superblock structure. * * @param offset Offset in sectors. * * Returns 0 on finding a sane-looking XTAF superblock. * Returns 1 on finding non-XTAF-superblock data. * Returns <0 on more basic errors (memory, I/O). */ int tsk_vs_xtaf_verifysb(TSK_IMG_INFO * img_info, TSK_DADDR_T offset, unsigned int sector_size){ ssize_t cnt; xtaffs_sb* xtafsb; unsigned int xtafsb_len; xtafsb_len = sizeof(xtaffs_sb); /* Allocate superblock struct. */ xtafsb = (xtaffs_sb*) tsk_malloc(xtafsb_len); if (NULL == xtafsb) { tsk_fprintf(stderr, "tsk_vs_xtaf_verifysb: Failed to allocate superblock for partition %d.\n"); free(xtafsb); return -ENOMEM; } /* Read in superblock. */ /* NOTE: This is read as a char* instead of a xtaffs_sb to keep img_read() happy. */ cnt = tsk_img_read(img_info, offset, (char *) xtafsb, xtafsb_len); /* Check for a failed read. */ if (cnt != xtafsb_len) { tsk_fprintf(stderr, "tsk_vs_xtaf_verifysb: Failed to read at disk offset %" PRIuDADDR " bytes.\n", offset * sector_size); free(xtafsb); return -EIO; } /* Sanity test: Check the magic. */ if(strncmp((char*) xtafsb->magic, "XTAF", 4)){ if (tsk_verbose) tsk_fprintf(stderr, "tsk_vs_xtaf_verifysb: Partition at %" PRIuDADDR " bytes is not an XTAF file system.\n", offset * sector_size); free(xtafsb); return 1; } /* The partition at this point is sane. No further need to check the superblock. */ free(xtafsb); return 0; }
/* Used to process orphan directories and make sure that their contents * are now marked as reachable */ static TSK_WALK_RET_ENUM load_orphan_dir_walk_cb(TSK_FS_FILE * a_fs_file, const char *a_path, void *a_ptr) { FIND_ORPHAN_DATA *data = (FIND_ORPHAN_DATA *) a_ptr; // ignore DOT entries if ((a_fs_file->name) && (a_fs_file->name->name) && (TSK_FS_ISDOT(a_fs_file->name->name))) return TSK_WALK_CONT; // add this entry to the orphan list if (a_fs_file->meta) { /* Stop if we hit an allocated entry. We shouldn't get these, but did * have some trouble images that went into allocated clusters on * a FAT file system. */ if (a_fs_file->meta->flags & TSK_FS_META_FLAG_ALLOC) { if (tsk_verbose) { tsk_fprintf(stderr, "load_orphan_dir_walk_cb: Skipping an allocated file (ID: %" PRIuINUM ")\n", a_fs_file->meta->addr); } return TSK_WALK_STOP; } /* check if we have already added it as an orphan (in a subdirectory) * Not entirely sure how possible this is, but it was added while * debugging an infinite loop problem. */ if (tsk_list_find(data->orphan_subdir_list, a_fs_file->meta->addr)) { if (tsk_verbose) fprintf(stderr, "load_orphan_dir_walk_cb: Detected loop with address %" PRIuINUM, a_fs_file->meta->addr); return TSK_WALK_STOP; } tsk_list_add(&data->orphan_subdir_list, a_fs_file->meta->addr); /* FAT file systems spend a lot of time hunting for parent * directory addresses, so we put this code in here to save * the info when we have it. */ if ((a_fs_file->meta->type == TSK_FS_META_TYPE_DIR) && (TSK_FS_TYPE_ISFAT(a_fs_file->fs_info->ftype))) { if (fatfs_dir_buf_add((FATFS_INFO *) a_fs_file->fs_info, a_fs_file->name->par_addr, a_fs_file->meta->addr)) return TSK_WALK_ERROR; } } return TSK_WALK_CONT; }
/* * Parse the UsnJrnl record. * Calls the action callback. * Returns TSK_WALK_CONT on success, TSK_WALK_ERROR on error. */ static TSK_WALK_RET_ENUM parse_record(const unsigned char *buf, TSK_USN_RECORD_HEADER *header, TSK_ENDIAN_ENUM endian, TSK_FS_USNJENTRY_WALK_CB action, void *ptr) { TSK_WALK_RET_ENUM ret; switch (header->major_version) { case 2: { TSK_USN_RECORD_V2 record; ret = parse_v2_record(buf, header, &record, endian); if (ret == 1) return TSK_WALK_ERROR; ret = (*action)(header, &record, ptr); free(record.fname); return ret; } case 3: { if (tsk_verbose) tsk_fprintf(stderr, "parse_record: USN records V 3 not supported yet."); return TSK_WALK_CONT; } case 4: { if (tsk_verbose) tsk_fprintf(stderr, "parse_record: USN records V 4 not supported yet."); return TSK_WALK_CONT; } default: return TSK_WALK_ERROR; } }
/* Place journal data in *fs * * Return 0 on success and 1 on error * */ uint8_t ext2fs_jopen(TSK_FS_INFO * fs, TSK_INUM_T inum) { EXT2FS_INFO *ext2fs = (EXT2FS_INFO *) fs; EXT2FS_JINFO *jinfo; // clean up any error messages that are lying around tsk_error_reset(); if (!fs) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2fs_jopen: fs is null"); return 1; } ext2fs->jinfo = jinfo = (EXT2FS_JINFO *) tsk_malloc(sizeof(EXT2FS_JINFO)); if (jinfo == NULL) { return 1; } jinfo->j_inum = inum; jinfo->fs_file = tsk_fs_file_open_meta(fs, NULL, inum); if (!jinfo->fs_file) { free(jinfo); return 1; // error("error finding journal inode %" PRIu32, inum); } if (tsk_fs_file_walk(jinfo->fs_file, 0, load_sb_action, NULL)) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_FWALK; snprintf(tsk_errstr, TSK_ERRSTR_L, "Error loading ext3 journal"); tsk_fs_file_close(jinfo->fs_file); free(jinfo); return 1; } if (tsk_verbose) tsk_fprintf(stderr, "journal opened at inode %" PRIuINUM " bsize: %" PRIu32 " First JBlk: %" PRIuDADDR " Last JBlk: %" PRIuDADDR "\n", inum, jinfo->bsize, jinfo->first_block, jinfo->last_block); return 0; }
/* print_block - write data block to stdout */ static TSK_WALK_RET_ENUM print_block(TSK_FS_INFO * fs, TSK_DADDR_T addr, char *buf, TSK_FS_BLOCK_FLAG_ENUM flags, void *ptr) { if (tsk_verbose) tsk_fprintf(stderr, "write block %" PRIuDADDR "\n", addr); if (fwrite(buf, fs->block_size, 1, stdout) != 1) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_WRITE; snprintf(tsk_errstr, TSK_ERRSTR_L, "dls_lib: error writing to stdout: %s", strerror(errno)); return TSK_WALK_ERROR; } return TSK_WALK_CONT; }
/* print_block - write data block to stdout */ static TSK_WALK_RET_ENUM print_block(const TSK_FS_BLOCK * fs_block, void *ptr) { if (tsk_verbose) tsk_fprintf(stderr, "write block %" PRIuDADDR "\n", fs_block->addr); if (fwrite(fs_block->buf, fs_block->fs_info->block_size, 1, stdout) != 1) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WRITE); tsk_error_set_errstr("blkls_lib: error writing to stdout: %s", strerror(errno)); return TSK_WALK_ERROR; } return TSK_WALK_CONT; }
static void usage() { fprintf(stderr, "usage: %s [-vV] [-f fstype] [-i imgtype] [-b dev_sector_size] [-o imgoffset] image [images]\n", progname); fprintf(stderr, "\t-i imgtype: The format of the image file\n"); tsk_fprintf(stderr, "\t-b dev_sector_size: The size (in bytes) of the device sectors\n"); fprintf(stderr, "\t-o imgoffset: The offset of the file system in the image (in sectors)\n"); fprintf(stderr, "\t-v: verbose output to stderr\n"); fprintf(stderr, "\t-V: Print version\n"); fprintf(stderr, "\t-f fstype: File system type\n"); fs_print_types(stderr); img_print_types(stderr); exit(1); }
static TSK_WALK_RET_ENUM slack_file_act(TSK_FS_FILE * fs_file, TSK_OFF_T a_off, TSK_DADDR_T addr, char *buf, size_t size, TSK_FS_BLOCK_FLAG_ENUM flags, void *ptr) { BLKLS_DATA *data = (BLKLS_DATA *) ptr; if (tsk_verbose) tsk_fprintf(stderr, "slack_file_act: File: %" PRIuINUM " Remaining File: %" PRIuOFF " Buffer: %u\n", fs_file->meta->addr, data->flen, size); /* This is not the last data unit */ if (data->flen >= size) { data->flen -= size; } /* We have passed the end of the allocated space */ else if (data->flen == 0) { if (fwrite(buf, size, 1, stdout) != 1) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WRITE); tsk_error_set_errstr("blkls_lib: error writing to stdout: %s", strerror(errno)); return TSK_WALK_ERROR; } } /* This is the last data unit and there is unused space */ else if (data->flen < size) { /* Clear the used space and print it */ memset(buf, 0, (size_t) data->flen); if (fwrite(buf, size, 1, stdout) != 1) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WRITE); tsk_error_set_errstr("blkls_lib: error writing to stdout: %s", strerror(errno)); return TSK_WALK_ERROR; } data->flen = 0; } return TSK_WALK_CONT; }
/* ** find_inode ** ** Callback action for inode_walk */ static TSK_WALK_RET_ENUM ifind_data_act(TSK_FS_FILE * fs_file, void *ptr) { IFIND_DATA_DATA *data = (IFIND_DATA_DATA *) ptr; int file_flags = (TSK_FS_FILE_WALK_FLAG_AONLY | TSK_FS_FILE_WALK_FLAG_SLACK); int i, cnt; data->curinode = fs_file->meta->addr; /* Search all attributes */ cnt = tsk_fs_file_attr_getsize(fs_file); for (i = 0; i < cnt; i++) { const TSK_FS_ATTR *fs_attr = tsk_fs_file_attr_get_idx(fs_file, i); if (!fs_attr) continue; data->curtype = fs_attr->type; data->curid = fs_attr->id; if (fs_attr->flags & TSK_FS_ATTR_NONRES) { if (tsk_fs_attr_walk(fs_attr, file_flags, ifind_data_file_act, ptr)) { if (tsk_verbose) tsk_fprintf(stderr, "Error walking file %" PRIuINUM " Attribute: %i", fs_file->meta->addr, i); /* Ignore these errors */ tsk_error_reset(); } // stop if we only want one hit if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL))) break; } } if ((data->found) && (!(data->flags & TSK_FS_IFIND_ALL))) return TSK_WALK_STOP; else return TSK_WALK_CONT; }
/* usage - explain and terminate */ static void usage() { TFPRINTF(stderr, _TSK_T ("usage: %s [-f fstype] [-i imgtype] [-b dev_sector_size] [-o imgoffset] [-vV] image [images] [inode] blk\n"), progname); tsk_fprintf(stderr, "\tblk: The journal block to view\n"); tsk_fprintf(stderr, "\tinode: The file system inode where the journal is located\n"); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use '-i list' for supported types)\n"); tsk_fprintf(stderr, "\t-b dev_sector_size: The size (in bytes) of the device sectors\n"); tsk_fprintf(stderr, "\t-f fstype: File system type (use '-f list' for supported types)\n"); tsk_fprintf(stderr, "\t-o imgoffset: The offset of the file system in the image (in sectors)\n"); tsk_fprintf(stderr, "\t-v: verbose output to stderr\n"); tsk_fprintf(stderr, "\t-V: print version\n"); exit(1); }
/** * \ingroup fslib * Process a specific attribute in a file and call a callback function with the file contents. The callback will be * called with chunks of data that are fs->block_size or less. The address given in the callback * will be correct only for raw files (when the raw file contents were stored in the block). For * compressed and sparse files, the address may be zero. If the file system you are analyzing does * not have multiple attributes per file, then you can use tsk_fs_file_walk(). For incomplete or * corrupt files, some missing runs will be identified as SPARSE and zeros will be returned in the content. * * @param a_fs_file File to process * @param a_type Attribute type to process * @param a_id Id if attribute to process * @param a_flags Flags to use while processing file * @param a_action Callback action to call with content * @param a_ptr Pointer that will passed to callback * @returns 1 on error and 0 on success. */ uint8_t tsk_fs_file_walk_type(TSK_FS_FILE * a_fs_file, TSK_FS_ATTR_TYPE_ENUM a_type, uint16_t a_id, TSK_FS_FILE_WALK_FLAG_ENUM a_flags, TSK_FS_FILE_WALK_CB a_action, void *a_ptr) { const TSK_FS_ATTR *fs_attr; TSK_FS_INFO *fs; // clean up any error messages that are lying around tsk_error_reset(); // check the FS_INFO, FS_FILE structures if ((a_fs_file == NULL) || (a_fs_file->meta == NULL) || (a_fs_file->fs_info == NULL)) { tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_fs_file_walk: called with NULL pointers"); return 1; } else if ((a_fs_file->fs_info->tag != TSK_FS_INFO_TAG) || (a_fs_file->meta->tag != TSK_FS_META_TAG)) { tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_fs_file_walk: called with unallocated structures"); return 1; } fs = a_fs_file->fs_info; if (tsk_verbose) tsk_fprintf(stderr, "tsk_fs_file_walk: Processing file %" PRIuINUM "\n", a_fs_file->meta->addr); if ((fs_attr = tsk_fs_file_attr_get_type(a_fs_file, a_type, a_id, (a_flags & TSK_FS_FILE_WALK_FLAG_NOID) ? 0 : 1)) == NULL) return 1; return tsk_fs_attr_walk(fs_attr, a_flags, a_action, a_ptr); }
/* usage - explain and terminate */ static void usage() { TFPRINTF(stderr, _TSK_T ("usage: %s [-b num] [-f fstype] [-i imgtype] [-o imgoffset] [-z zone] [-s seconds] [-vV] image inum\n"), progname); tsk_fprintf(stderr, "\t-b num: force the display of NUM address of block pointers\n"); tsk_fprintf(stderr, "\t-z zone: time zone of original machine (i.e. EST5EDT or GMT)\n"); tsk_fprintf(stderr, "\t-s seconds: Time skew of original machine (in seconds)\n"); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use '-i list' for supported types)\n"); tsk_fprintf(stderr, "\t-f fstype: File system type (use '-f list' for supported types)\n"); tsk_fprintf(stderr, "\t-o imgoffset: The offset of the file system in the image (in sectors)\n"); tsk_fprintf(stderr, "\t-v: verbose output to stderr\n"); tsk_fprintf(stderr, "\t-V: print version\n"); exit(1); }
static int tsk_printf_conv(WCHAR * wbuf, int wlen, const char *msg, va_list * args) { char *cbuf; UTF8 *ptr8; UTF16 *ptr16; int retVal; size_t len, clen; wbuf[0] = '\0'; /* Allocate a UTF-8 buffer and process the printf args */ clen = wlen * 3; if (NULL == (cbuf = (char *) tsk_malloc(clen))) { return 1; } memset(cbuf, 0, clen); #ifdef _MSC_VER vsnprintf_s(cbuf, clen - 1, _TRUNCATE, msg, *args); #else vsnprintf(cbuf, clen - 1, msg, *args); #endif len = strlen(cbuf); //Convert to UTF-16 ptr8 = (UTF8 *) cbuf; ptr16 = (UTF16 *) wbuf; retVal = tsk_UTF8toUTF16((const UTF8 **) &ptr8, &ptr8[len + 1], &ptr16, &ptr16[wlen], TSKlenientConversion); if (retVal != TSKconversionOK) { *ptr16 = '\0'; if (tsk_verbose) tsk_fprintf(stderr, "tsk_printf_conv: error converting string to UTF-16\n"); } free(cbuf); return 0; }
void usage() { TFPRINTF(stderr, _TSK_T ("%s [-i imgtype] [-o imgoffset] [-brvV] [-t mmtype] image [images]\n"), progname); tsk_fprintf(stderr, "\t-t mmtype: The type of partition system (use '-t list' for list of supported types)\n"); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use '-i list' for list supported types)\n"); tsk_fprintf(stderr, "\t-o imgoffset: Offset to the start of the volume that contains the partition system (in sectors)\n"); tsk_fprintf(stderr, "\t-b: print the rounded length in bytes\n"); tsk_fprintf(stderr, "\t-r: recurse and look for other partition tables in partitions (DOS Only)\n"); tsk_fprintf(stderr, "\t-v: verbose output\n"); tsk_fprintf(stderr, "\t-V: print the version\n"); exit(1); }
/** * Display information about the disk image set. * * @param img_info Disk image to analyze * @param hFile Handle to print information to */ void split_imgstat(TSK_IMG_INFO * img_info, FILE * hFile) { IMG_SPLIT_INFO *split_info = (IMG_SPLIT_INFO *) img_info; int i; tsk_fprintf(hFile, "IMAGE FILE INFORMATION\n"); tsk_fprintf(hFile, "--------------------------------------------\n"); tsk_fprintf(hFile, "Image Type: split\n"); tsk_fprintf(hFile, "\nSize in bytes: %" PRIuOFF "\n", img_info->size); tsk_fprintf(hFile, "\n--------------------------------------------\n"); tsk_fprintf(hFile, "Split Information:\n"); for (i = 0; i < split_info->num_img; i++) { tsk_fprintf(hFile, "%s (%" PRIuOFF " to %" PRIuOFF ")\n", split_info->images[i], (OFF_T) (i == 0) ? 0 : split_info->max_off[i - 1], (OFF_T) (split_info->max_off[i] - 1)); } }
static void usage() { TFPRINTF(stderr, _TSK_T ("usage: %s [-tvV] [-f fstype] [-i imgtype] [-b dev_sector_size] [-o imgoffset] image\n"), progname); tsk_fprintf(stderr, "\t-t: display type only\n"); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use '-i list' for supported types)\n"); tsk_fprintf(stderr, "\t-b dev_sector_size: The size (in bytes) of the device sectors\n"); tsk_fprintf(stderr, "\t-f fstype: File system type (use '-f list' for supported types)\n"); tsk_fprintf(stderr, "\t-o imgoffset: The offset of the file system in the image (in sectors)\n"); tsk_fprintf(stderr, "\t-v: verbose output to stderr\n"); tsk_fprintf(stderr, "\t-V: Print version\n"); exit(1); }
/* SLACK SPACE call backs */ static TSK_WALK_RET_ENUM count_slack_file_act(TSK_FS_FILE * fs_file, TSK_OFF_T a_off, TSK_DADDR_T addr, char *buf, size_t size, TSK_FS_BLOCK_FLAG_ENUM flags, void *ptr) { BLKCALC_DATA *data = (BLKCALC_DATA *) ptr; if (tsk_verbose) tsk_fprintf(stderr, "count_slack_file_act: Remaining File: %" PRIuOFF " Buffer: %" PRIuSIZE "\n", data->flen, size); /* This is not the last data unit */ if (data->flen >= size) { data->flen -= size; } /* We have passed the end of the allocated space */ else if (data->flen == 0) { if (data->count-- == 0) { tsk_printf("%" PRIuDADDR "\n", addr); data->found = 1; return TSK_WALK_STOP; } } /* This is the last data unit and there is unused space */ else if (data->flen < size) { if (data->count-- == 0) { tsk_printf("%" PRIuDADDR "\n", addr); data->found = 1; return TSK_WALK_STOP; } data->flen = 0; } return TSK_WALK_CONT; }
static int tsk_printf_conv(WCHAR * wbuf, int wlen, char *msg, va_list * args) { char *cbuf; UTF8 *ptr8; UTF16 *ptr16; int retVal; size_t len, clen; wbuf[0] = '\0'; clen = wlen * 3; if (NULL == (cbuf = (char *) tsk_malloc(clen))) { return 1; } memset(cbuf, 0, clen); vsnprintf_s(cbuf, clen - 1, _TRUNCATE, msg, *args); len = strlen(cbuf); //Convert to UTF-16 ptr8 = (UTF8 *) cbuf; ptr16 = (UTF16 *) wbuf; retVal = tsk_UTF8toUTF16(&ptr8, &ptr8[len + 1], &ptr16, &ptr16[wlen], TSKlenientConversion); if (retVal != TSKconversionOK) { *ptr16 = '\0'; if (tsk_verbose) tsk_fprintf(stderr, "tsk_printf_conv: error converting string to UTF-16\n"); } free(cbuf); return 0; }
/** * Open the Update Sequence Number Journal stored at the inode inum. * * @param ntfs File system where the journal is stored * @param inum file reference number where the USN journal is located * @returns 0 on success, 1 otherwise */ uint8_t tsk_ntfs_usnjopen(TSK_FS_INFO *fs, TSK_INUM_T inum) { NTFS_INFO *ntfs = (NTFS_INFO*)fs; tsk_error_reset(); if (ntfs == NULL || ntfs->fs_info.ftype != TSK_FS_TYPE_NTFS) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("Invalid FS type in tsk_ntfs_usnjopen"); return 1; } /* Initialize usnjinfo support structure */ ntfs->usnjinfo = tsk_malloc(sizeof *ntfs->usnjinfo); if (ntfs->usnjinfo == NULL) return 1; ntfs->usnjinfo->usnj_inum = inum; ntfs->usnjinfo->bsize = ntfs->fs_info.block_size; ntfs->usnjinfo->fs_file = tsk_fs_file_open_meta(&ntfs->fs_info, NULL, inum); if (ntfs->usnjinfo->fs_file == NULL) { tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("ntfs_usnjopen: tsk_fs_file_open_meta"); free(ntfs->usnjinfo); return 1; } if (tsk_verbose) tsk_fprintf(stderr, "usn journal opened at inode %" PRIuINUM " bsize: %" PRIu32 "\n", ntfs->usnjinfo->usnj_inum, ntfs->usnjinfo->bsize); return 0; }
void usage() { TFPRINTF(stderr, _TSK_T ("%s [-i imgtype] [-b dev_sector_size] [-o imgoffset] [-vV] [-t vstype] image [images]\n"), progname); tsk_fprintf(stderr, "\t-t vstype: The volume system type (use '-t list' for list of supported types)\n"); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use '-i list' for list of supported types)\n"); tsk_fprintf(stderr, "\t-b dev_sector_size: The size (in bytes) of the device sectors\n"); tsk_fprintf(stderr, "\t-o imgoffset: Offset to the start of the volume that contains the partition system (in sectors)\n"); tsk_fprintf(stderr, "\t-v: verbose output\n"); tsk_fprintf(stderr, "\t-V: print the version\n"); exit(1); }
static void usage() { TFPRINTF(stderr, _TSK_T ("usage: %s [-vV] [-i imgtype] [-b dev_sector_size] [-s start_sector] [-e stop_sector] image\n"), progname); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use 'i list' for supported types)\n"); tsk_fprintf(stderr, "\t-b dev_sector_size: The size (in bytes) of the device sectors\n"); tsk_fprintf(stderr, "\t-s start_sector: The sector number to start at\n"); tsk_fprintf(stderr, "\t-e stop_sector: The sector number to stop at\n"); tsk_fprintf(stderr, "\t-v: verbose output to stderr\n"); tsk_fprintf(stderr, "\t-V: Print version\n"); exit(1); }
static void usage() { TFPRINTF(stderr, _TSK_T ("usage: %s [-vV] [-i imgtype] [-b dev_sector_size] [-z zone] [-s seconds] image [image]\n"), progname); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use '-i list' for supported types)\n"); tsk_fprintf(stderr, "\t-b dev_sector_size: The size (in bytes) of the device sectors\n"); tsk_fprintf(stderr, "\t-v: verbose output to stderr\n"); tsk_fprintf(stderr, "\t-V: Print version\n"); tsk_fprintf(stderr, "\t-z: Time zone of original machine (i.e. EST5EDT or GMT) (only useful with -l)\n"); tsk_fprintf(stderr, "\t-s seconds: Time skew of original machine (in seconds) (only useful with -l & -m)\n"); exit(1); }
/** \internal * Process a directory and load up FS_DIR with the entries. If a pointer to * an already allocated FS_DIR struture is given, it will be cleared. If no existing * FS_DIR structure is passed (i.e. NULL), then a new one will be created. If the return * value is error or corruption, then the FS_DIR structure could * have entries (depending on when the error occured). * * @param a_fs File system to analyze * @param a_fs_dir Pointer to FS_DIR pointer. Can contain an already allocated * structure or a new structure. * @param a_addr Address of directory to process. * @returns error, corruption, ok etc. */ TSK_RETVAL_ENUM ffs_dir_open_meta(TSK_FS_INFO * a_fs, TSK_FS_DIR ** a_fs_dir, TSK_INUM_T a_addr) { TSK_OFF_T size; FFS_INFO *ffs = (FFS_INFO *) a_fs; char *dirbuf; int nchnk, cidx; TSK_FS_LOAD_FILE load_file; TSK_FS_DIR *fs_dir; /* If we get corruption in one of the blocks, then continue processing. * retval_final will change when corruption is detected. Errors are * returned immediately. */ TSK_RETVAL_ENUM retval_tmp; TSK_RETVAL_ENUM retval_final = TSK_OK; if (a_addr < a_fs->first_inum || a_addr > a_fs->last_inum) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_WALK_RNG); tsk_error_set_errstr("ffs_dir_open_meta: Invalid inode value: %" PRIuINUM, a_addr); return TSK_ERR; } else if (a_fs_dir == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr ("ffs_dir_open_meta: NULL fs_attr argument given"); return TSK_ERR; } if (tsk_verbose) tsk_fprintf(stderr, "ffs_dir_open_meta: Processing directory %" PRIuINUM "\n", a_addr); fs_dir = *a_fs_dir; if (fs_dir) { tsk_fs_dir_reset(fs_dir); } else { if ((*a_fs_dir = fs_dir = tsk_fs_dir_alloc(a_fs, a_addr, 128)) == NULL) { return TSK_ERR; } } // handle the orphan directory if its contents were requested if (a_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { return tsk_fs_dir_find_orphans(a_fs, fs_dir); } if ((fs_dir->fs_file = tsk_fs_file_open_meta(a_fs, NULL, a_addr)) == NULL) { tsk_error_reset(); tsk_error_errstr2_concat("- ffs_dir_open_meta"); return TSK_COR; } /* make a copy of the directory contents that we can process */ /* round up cause we want the slack space too */ size = roundup(fs_dir->fs_file->meta->size, FFS_DIRBLKSIZ); if ((dirbuf = tsk_malloc((size_t) size)) == NULL) { return TSK_ERR; } load_file.total = load_file.left = (size_t) size; load_file.base = load_file.cur = dirbuf; if (tsk_fs_file_walk(fs_dir->fs_file, TSK_FS_FILE_WALK_FLAG_SLACK, tsk_fs_load_file_action, (void *) &load_file)) { tsk_error_reset(); tsk_error_errstr2_concat("- ffs_dir_open_meta"); free(dirbuf); return TSK_COR; } /* Not all of the directory was copied, so we return */ if (load_file.left > 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_FWALK); tsk_error_set_errstr("ffs_dir_open_meta: Error reading directory %" PRIuINUM, a_addr); free(dirbuf); return TSK_COR; } /* Directory entries are written in chunks of DIRBLKSIZ ** determine how many chunks of this size we have to read to ** get a full block ** ** Entries do not cross over the DIRBLKSIZ boundary */ nchnk = (int) (size) / (FFS_DIRBLKSIZ) + 1; for (cidx = 0; cidx < nchnk && (int64_t) size > 0; cidx++) { int len = (FFS_DIRBLKSIZ < size) ? FFS_DIRBLKSIZ : (int) size; retval_tmp = ffs_dent_parse_block(ffs, fs_dir, (fs_dir->fs_file-> meta->flags & TSK_FS_META_FLAG_UNALLOC) ? 1 : 0, dirbuf + cidx * FFS_DIRBLKSIZ, len); if (retval_tmp == TSK_ERR) { retval_final = TSK_ERR; break; } else if (retval_tmp == TSK_COR) { retval_final = TSK_COR; } size -= len; } free(dirbuf); // if we are listing the root directory, add the Orphan directory entry if (a_addr == a_fs->root_inum) { TSK_FS_NAME *fs_name = tsk_fs_name_alloc(256, 0); if (fs_name == NULL) return TSK_ERR; if (tsk_fs_dir_make_orphan_dir_name(a_fs, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } if (tsk_fs_dir_add(fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } tsk_fs_name_free(fs_name); } return retval_final; }
TSK_VS_INFO * tsk_vs_gpt_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) { TSK_VS_INFO *vs; // clean up any errors that are lying around tsk_error_reset(); vs = (TSK_VS_INFO *) tsk_malloc(sizeof(*vs)); if (vs == NULL) return NULL; vs->img_info = img_info; vs->vstype = TSK_VS_TYPE_GPT; vs->tag = TSK_VS_INFO_TAG; /* If an offset was given, then use that too */ vs->offset = offset; /* inititialize settings */ vs->part_list = NULL; vs->part_count = 0; vs->endian = 0; vs->block_size = img_info->sector_size; /* Assign functions */ vs->close = gpt_close; /* Load the partitions into the sorted list */ if (gpt_load_table(vs)) { int found = 0; if (tsk_verbose) tsk_fprintf(stderr, "gpt_open: Trying other sector sizes\n"); /* Before we give up, lets try some other sector sizes */ vs->block_size = 512; while (vs->block_size <= 8192) { if (tsk_verbose) tsk_fprintf(stderr, "gpt_open: Trying sector size: %d\n", vs->block_size); if (gpt_load_table(vs)) { vs->block_size *= 2; continue; } found = 1; break; } if (found == 0) { gpt_close(vs); return NULL; } } /* fill in the sorted list with the 'unknown' values */ if (tsk_vs_part_unused(vs)) { gpt_close(vs); return NULL; } return vs; }
/* * Process the partition table at the sector address * * It is loaded into the internal sorted list */ static uint8_t gpt_load_table(TSK_VS_INFO * vs) { gpt_head *head; gpt_entry *ent; dos_sect *dos_part; unsigned int i, a; uint32_t ent_size; char *safe_str, *head_str, *tab_str, *ent_buf; ssize_t cnt; char *sect_buf; TSK_DADDR_T taddr = vs->offset / vs->block_size + GPT_PART_SOFFSET; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector if (tsk_verbose) tsk_fprintf(stderr, "gpt_load_table: Sector: %" PRIuDADDR "\n", taddr); if ((sect_buf = tsk_malloc(vs->block_size)) == NULL) return 1; dos_part = (dos_sect *) sect_buf; cnt = tsk_vs_read_block (vs, GPT_PART_SOFFSET, sect_buf, vs->block_size); /* if -1, then tsk_errno is already set */ if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2 ("Error reading DOS safety partition table in Sector: %" PRIuDADDR, taddr); free(sect_buf); return 1; } /* Sanity Check */ if (tsk_vs_guessu16(vs, dos_part->magic, DOS_MAGIC)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("Missing DOS safety partition (invalid magic) (Sector: %" PRIuDADDR ")", taddr); free(sect_buf); return 1; } if (dos_part->ptable[0].ptype != GPT_DOS_TYPE) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr ("Missing DOS safety partition (invalid type in table: %d)", dos_part->ptable[0].ptype); free(sect_buf); return 1; } /* Read the GPT header */ head = (gpt_head *) sect_buf; cnt = tsk_vs_read_block (vs, GPT_PART_SOFFSET + 1, sect_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("GPT Header structure in Sector: %" PRIuDADDR, taddr + 1); free(sect_buf); return 1; } if (tsk_getu64(vs->endian, &head->signature) != GPT_HEAD_SIG) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr("GPT Header: %" PRIx64, tsk_getu64(vs->endian, &head->signature)); free(sect_buf); return 1; } // now that we checked the sig, lets make the meta entries if ((safe_str = tsk_malloc(16)) == NULL) { free(sect_buf); return 1; } snprintf(safe_str, 16, "Safety Table"); if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 0, (TSK_DADDR_T) 1, TSK_VS_PART_FLAG_META, safe_str, -1, -1)) { free(sect_buf); return 1; } if ((head_str = tsk_malloc(16)) == NULL) { free(sect_buf); return 1; } snprintf(head_str, 16, "GPT Header"); if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 1, (TSK_DADDR_T) ((tsk_getu32(vs->endian, &head->head_size_b) + (vs->block_size-1)) / vs->block_size), TSK_VS_PART_FLAG_META, head_str, -1, -1)) { free(sect_buf); return 1; } /* Allocate a buffer for each table entry */ ent_size = tsk_getu32(vs->endian, &head->tab_size_b); if (ent_size < sizeof(gpt_entry)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); tsk_error_set_errstr("Header reports partition entry size of %" PRIu32 " and not %" PRIuSIZE "", ent_size, sizeof(gpt_entry)); free(sect_buf); return 1; } if ((tab_str = tsk_malloc(20)) == NULL) { free(sect_buf); return 1; } snprintf(tab_str, 20, "Partition Table"); if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) tsk_getu64(vs->endian, &head->tab_start_lba), (TSK_DADDR_T) ((ent_size * tsk_getu32(vs->endian, &head->tab_num_ent) + (vs->block_size-1)) / vs->block_size), TSK_VS_PART_FLAG_META, tab_str, -1, -1)) { free(sect_buf); return 1; } /* Process the partition table */ if ((ent_buf = tsk_malloc(vs->block_size)) == NULL) { free(sect_buf); return 1; } i = 0; for (a = 0; i < tsk_getu32(vs->endian, &head->tab_num_ent); a++) { char *name; /* Read a sector */ cnt = tsk_vs_read_block(vs, tsk_getu64(vs->endian, &head->tab_start_lba) + a, ent_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2 ("Error reading GPT partition table sector : %" PRIuDADDR, tsk_getu64(vs->endian, &head->tab_start_lba) + a); free(ent_buf); free(sect_buf); return 1; } /* Process the sector */ ent = (gpt_entry *) ent_buf; for (; (uintptr_t) ent < (uintptr_t) ent_buf + vs->block_size && i < tsk_getu32(vs->endian, &head->tab_num_ent); i++) { UTF16 *name16; UTF8 *name8; int retVal; if (tsk_verbose) tsk_fprintf(stderr, "gpt_load: %d Starting Sector: %" PRIu64 " End: %" PRIu64 " Flag: %" PRIx64 "\n", i, tsk_getu64(vs->endian, ent->start_lba), tsk_getu64(vs->endian, ent->end_lba), tsk_getu64(vs->endian, ent->flags)); if (tsk_getu64(vs->endian, ent->start_lba) == 0) { ent++; continue; } // make sure the first couple are in the image bounds if ((i < 2) && (tsk_getu64(vs->endian, ent->start_lba) > max_addr)) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_BLK_NUM); tsk_error_set_errstr ("gpt_load_table: Starting sector too large for image"); free(sect_buf); free(ent_buf); return 1; } if ((name = tsk_malloc(256)) == NULL) { free(sect_buf); free(ent_buf); return 1; } name16 = (UTF16 *) ((uintptr_t) ent->name); name8 = (UTF8 *) name; retVal = tsk_UTF16toUTF8(vs->endian, (const UTF16 **) &name16, (UTF16 *) ((uintptr_t) name16 + sizeof(ent->name)), &name8, (UTF8 *) ((uintptr_t) name8 + 256), TSKlenientConversion); if (retVal != TSKconversionOK) { if (tsk_verbose) tsk_fprintf(stderr, "gpt_load_table: Error converting name to UTF8: %d\n", retVal); *name = '\0'; } if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) tsk_getu64(vs->endian, ent->start_lba), (TSK_DADDR_T) (tsk_getu64(vs->endian, ent->end_lba) - tsk_getu64(vs->endian, ent->start_lba) + 1), TSK_VS_PART_FLAG_ALLOC, name, -1, i)) { free(sect_buf); free(ent_buf); return 1; } ent++; } } free(sect_buf); free(ent_buf); return 0; }
/* dir_walk local function that is used for recursive calls. Callers * should initially call the non-local version. */ static TSK_WALK_RET_ENUM tsk_fs_dir_walk_lcl(TSK_FS_INFO * a_fs, DENT_DINFO * a_dinfo, TSK_INUM_T a_addr, TSK_FS_DIR_WALK_FLAG_ENUM a_flags, TSK_FS_DIR_WALK_CB a_action, void *a_ptr) { TSK_FS_DIR *fs_dir; TSK_FS_FILE *fs_file; size_t i; // get the list of entries in the directory if ((fs_dir = tsk_fs_dir_open_meta(a_fs, a_addr)) == NULL) { return TSK_WALK_ERROR; } /* Allocate a file structure for the callbacks. We * will allocate fs_meta structures as needed and * point into the fs_dir structure for the names. */ if ((fs_file = tsk_fs_file_alloc(a_fs)) == NULL) { tsk_fs_dir_close(fs_dir); return TSK_WALK_ERROR; } for (i = 0; i < fs_dir->names_used; i++) { TSK_WALK_RET_ENUM retval; /* Point name to the buffer of names. We need to be * careful about resetting this before we free fs_file */ fs_file->name = (TSK_FS_NAME *) & fs_dir->names[i]; /* load the fs_meta structure if possible. * Must have non-zero inode addr or have allocated name (if inode is 0) */ if (((fs_file->name->meta_addr) || (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC))) { if (a_fs->file_add_meta(a_fs, fs_file, fs_file->name->meta_addr)) { if (tsk_verbose) tsk_error_print(stderr); tsk_error_reset(); } } // call the action if we have the right flags. if ((fs_file->name->flags & a_flags) == fs_file->name->flags) { retval = a_action(fs_file, a_dinfo->dirs, a_ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); /* free the list -- fs_dir_walk has no way * of knowing that we stopped early w/out error. */ if (a_dinfo->save_inum_named) { tsk_list_free(a_dinfo->list_inum_named); a_dinfo->list_inum_named = NULL; a_dinfo->save_inum_named = 0; } return TSK_WALK_STOP; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_ERROR; } } // save the inode info for orphan finding - if requested if ((a_dinfo->save_inum_named) && (fs_file->meta) && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) { if (tsk_list_add(&a_dinfo->list_inum_named, fs_file->meta->addr)) { // if there is an error, then clear the list tsk_list_free(a_dinfo->list_inum_named); a_dinfo->list_inum_named = NULL; a_dinfo->save_inum_named = 0; } } /* Recurse into a directory if: * - Both dir entry and inode have DIR type (or name is undefined) * - Recurse flag is set * - dir entry is allocated OR both are unallocated * - not one of the '.' or '..' entries * - A Non-Orphan Dir or the Orphan Dir with the NOORPHAN flag not set. */ if (((fs_file->name->type == TSK_FS_NAME_TYPE_DIR) || (fs_file->name->type == TSK_FS_NAME_TYPE_UNDEF)) && (fs_file->meta) && (fs_file->meta->type == TSK_FS_META_TYPE_DIR) && (a_flags & TSK_FS_DIR_WALK_FLAG_RECURSE) && ((fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) || ((fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC) && (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC)) ) && (!TSK_FS_ISDOT(fs_file->name->name)) && ((fs_file->name->meta_addr != TSK_FS_ORPHANDIR_INUM(a_fs)) || ((a_flags & TSK_FS_DIR_WALK_FLAG_NOORPHAN) == 0)) ) { /* Make sure we do not get into an infinite loop */ if (0 == tsk_stack_find(a_dinfo->stack_seen, fs_file->name->meta_addr)) { int depth_added = 0; uint8_t save_bak = 0; if (tsk_stack_push(a_dinfo->stack_seen, fs_file->name->meta_addr)) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_ERROR; } if ((a_dinfo->depth < MAX_DEPTH) && (DIR_STRSZ > strlen(a_dinfo->dirs) + strlen(fs_file->name->name))) { a_dinfo->didx[a_dinfo->depth] = &a_dinfo->dirs[strlen(a_dinfo->dirs)]; strncpy(a_dinfo->didx[a_dinfo->depth], fs_file->name->name, DIR_STRSZ - strlen(a_dinfo->dirs)); strncat(a_dinfo->dirs, "/", DIR_STRSZ); depth_added = 1; } a_dinfo->depth++; /* We do not want to save info about named unalloc files * when we go into the Orphan directory (because then we have * no orphans). So, disable it for this recursion. */ if (fs_file->name->meta_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { save_bak = a_dinfo->save_inum_named; a_dinfo->save_inum_named = 0; } retval = tsk_fs_dir_walk_lcl(a_fs, a_dinfo, fs_file->name->meta_addr, a_flags, a_action, a_ptr); if (retval == TSK_WALK_ERROR) { /* If this fails because the directory could not be * loaded, then we still continue */ if (tsk_verbose) { tsk_fprintf(stderr, "tsk_fs_dir_walk_lcl: error reading directory: %" PRIuINUM "\n", fs_file->name->meta_addr); tsk_error_print(stderr); } tsk_error_reset(); } else if (retval == TSK_WALK_STOP) { tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_STOP; } // reset the save status if (fs_file->name->meta_addr == TSK_FS_ORPHANDIR_INUM(a_fs)) { a_dinfo->save_inum_named = save_bak; } tsk_stack_pop(a_dinfo->stack_seen); a_dinfo->depth--; if (depth_added) *a_dinfo->didx[a_dinfo->depth] = '\0'; } else { if (tsk_verbose) fprintf(stderr, "tsk_fs_dir_walk_lcl: Loop detected with address %" PRIuINUM, fs_file->name->meta_addr); } } // remove the pointer to name buffer fs_file->name = NULL; // free the metadata if we allocated it if (fs_file->meta) { tsk_fs_meta_close(fs_file->meta); fs_file->meta = NULL; } } tsk_fs_dir_close(fs_dir); fs_file->name = NULL; tsk_fs_file_close(fs_file); return TSK_WALK_CONT; }
/** \internal * Add a FS_DENT structure to a FS_DIR structure by copying its * contents into the internal buffer. Checks for * duplicates and expands buffer as needed. * @param a_fs_dir DIR to add to * @param a_fs_name DENT to add * @returns 1 on error (memory allocation problems) and 0 on success */ uint8_t tsk_fs_dir_add(TSK_FS_DIR * a_fs_dir, const TSK_FS_NAME * a_fs_name) { TSK_FS_NAME *fs_name_dest = NULL; size_t i; /* see if we already have it in the buffer / queue * We skip this check for FAT because it will always fail because two entries * never have the same meta address. */ // @@@ We could do something more effecient here too with orphan files because we do not // need to check the contents of that directory either and this takes a lot of time on those // large images. if (TSK_FS_TYPE_ISFAT(a_fs_dir->fs_info->ftype) == 0) { for (i = 0; i < a_fs_dir->names_used; i++) { if ((a_fs_name->meta_addr == a_fs_dir->names[i].meta_addr) && (strcmp(a_fs_name->name, a_fs_dir->names[i].name) == 0)) { if (tsk_verbose) tsk_fprintf(stderr, "tsk_fs_dir_add: removing duplicate entry: %s (%" PRIuINUM ")\n", a_fs_name->name, a_fs_name->meta_addr); /* We do not check type because then we cannot detect NTFS orphan file * duplicates that are added as "-/r" while a similar entry exists as "r/r" (a_fs_name->type == a_fs_dir->names[i].type)) { */ // if the one in the list is unalloc and we have an alloc, replace it if ((a_fs_dir->names[i].flags & TSK_FS_NAME_FLAG_UNALLOC) && (a_fs_name->flags & TSK_FS_NAME_FLAG_ALLOC)) { fs_name_dest = &a_fs_dir->names[i]; // free the memory - not the most effecient, but prevents // duplicate code. if (fs_name_dest->name) { free(fs_name_dest->name); fs_name_dest->name = NULL; fs_name_dest->name_size = 0; } if (fs_name_dest->shrt_name) { free(fs_name_dest->shrt_name); fs_name_dest->shrt_name = NULL; fs_name_dest->shrt_name_size = 0; } break; } else { return 0; } } } } if (fs_name_dest == NULL) { // make sure we got the room if (a_fs_dir->names_used >= a_fs_dir->names_alloc) { if (tsk_fs_dir_realloc(a_fs_dir, a_fs_dir->names_used + 512)) return 1; } fs_name_dest = &a_fs_dir->names[a_fs_dir->names_used++]; } if (tsk_fs_name_copy(fs_name_dest, a_fs_name)) return 1; // add the parent address if (a_fs_dir->addr) fs_name_dest->par_addr = a_fs_dir->addr; return 0; }
/* main - open file system, list inode info */ int main(int argc, char **argv1) { TSK_IMG_TYPE_ENUM imgtype = TSK_IMG_TYPE_DETECT; TSK_IMG_INFO *img; TSK_OFF_T imgaddr = 0; TSK_FS_TYPE_ENUM fstype = TSK_FS_TYPE_DETECT; TSK_FS_INFO *fs; TSK_TCHAR *cp, *dash; TSK_INUM_T istart = 0, ilast = 0; int ch; int flags = TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED; int ils_flags = 0; int set_range = 1; TSK_TCHAR *image = NULL; int32_t sec_skew = 0; TSK_TCHAR **argv; unsigned int ssize = 0; #ifdef TSK_WIN32 // On Windows, get the wide arguments (mingw doesn't support wmain) argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv == NULL) { fprintf(stderr, "Error getting wide arguments\n"); exit(1); } #else argv = (TSK_TCHAR **) argv1; #endif progname = argv[0]; setlocale(LC_ALL, ""); /* * Provide convenience options for the most commonly selected feature * combinations. */ while ((ch = GETOPT(argc, argv, _TSK_T("aAb:ef:i:lLmo:Oprs:vVzZ"))) > 0) { switch (ch) { case _TSK_T('?'): default: TFPRINTF(stderr, _TSK_T("Invalid argument: %s\n"), argv[OPTIND]); usage(); case _TSK_T('b'): ssize = (unsigned int) TSTRTOUL(OPTARG, &cp, 0); if (*cp || *cp == *OPTARG || ssize < 1) { TFPRINTF(stderr, _TSK_T ("invalid argument: sector size must be positive: %s\n"), OPTARG); usage(); } break; case _TSK_T('f'): if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) { tsk_fs_type_print(stderr); exit(1); } fstype = tsk_fs_type_toid(OPTARG); if (fstype == TSK_FS_TYPE_UNSUPP) { TFPRINTF(stderr, _TSK_T("Unsupported file system type: %s\n"), OPTARG); usage(); } break; case _TSK_T('i'): if (TSTRCMP(OPTARG, _TSK_T("list")) == 0) { tsk_img_type_print(stderr); exit(1); } imgtype = tsk_img_type_toid(OPTARG); if (imgtype == TSK_IMG_TYPE_UNSUPP) { TFPRINTF(stderr, _TSK_T("Unsupported image type: %s\n"), OPTARG); usage(); } break; case _TSK_T('e'): flags |= (TSK_FS_META_FLAG_ALLOC | TSK_FS_META_FLAG_UNALLOC); flags &= ~TSK_FS_META_FLAG_USED; break; case _TSK_T('m'): ils_flags |= TSK_FS_ILS_MAC; break; case _TSK_T('o'): if ((imgaddr = tsk_parse_offset(OPTARG)) == -1) { tsk_error_print(stderr); exit(1); } break; case _TSK_T('O'): flags |= TSK_FS_META_FLAG_UNALLOC; flags &= ~TSK_FS_META_FLAG_ALLOC; ils_flags |= TSK_FS_ILS_OPEN; break; case _TSK_T('p'): flags |= (TSK_FS_META_FLAG_ORPHAN | TSK_FS_META_FLAG_UNALLOC); flags &= ~TSK_FS_META_FLAG_ALLOC; break; case _TSK_T('r'): flags |= (TSK_FS_META_FLAG_UNALLOC | TSK_FS_META_FLAG_USED); flags &= ~TSK_FS_META_FLAG_ALLOC; break; case _TSK_T('s'): sec_skew = TATOI(OPTARG); break; case _TSK_T('v'): tsk_verbose++; break; case _TSK_T('V'): tsk_version_print(stdout); exit(0); /* * Provide fine controls to tweak one feature at a time. */ case _TSK_T('a'): flags |= TSK_FS_META_FLAG_ALLOC; flags &= ~TSK_FS_META_FLAG_UNALLOC; break; case _TSK_T('A'): flags |= TSK_FS_META_FLAG_UNALLOC; break; case _TSK_T('l'): ils_flags |= TSK_FS_ILS_LINK; break; case _TSK_T('L'): ils_flags |= TSK_FS_ILS_UNLINK; break; case _TSK_T('z'): flags |= TSK_FS_META_FLAG_UNUSED; break; case _TSK_T('Z'): flags |= TSK_FS_META_FLAG_USED; break; } } if (OPTIND >= argc) { tsk_fprintf(stderr, "Missing image name\n"); usage(); } if ((ils_flags & TSK_FS_ILS_LINK) && (ils_flags & TSK_FS_ILS_UNLINK)) { tsk_fprintf(stderr, "ERROR: Only linked or unlinked should be used\n"); usage(); } /* We need to determine if an inode or inode range was given */ if ((dash = TSTRCHR(argv[argc - 1], _TSK_T('-'))) == NULL) { /* Check if is a single number */ istart = TSTRTOULL(argv[argc - 1], &cp, 0); if (*cp || *cp == *argv[argc - 1]) { /* Not a number - consider it a file name */ image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } else { /* Single address set end addr to start */ ilast = istart; set_range = 0; image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND - 1, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } } else { /* We have a dash, but it could be part of the file name */ *dash = '\0'; istart = TSTRTOULL(argv[argc - 1], &cp, 0); if (*cp || *cp == *argv[argc - 1]) { /* Not a number - consider it a file name */ *dash = _TSK_T('-'); image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } else { dash++; ilast = TSTRTOULL(dash, &cp, 0); if (*cp || *cp == *dash) { /* Not a number - consider it a file name */ dash--; *dash = '-'; image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } else { set_range = 0; /* It was a block range, so do not include it in the open */ image = argv[OPTIND]; if ((img = tsk_img_open(argc - OPTIND - 1, &argv[OPTIND], imgtype, ssize)) == NULL) { tsk_error_print(stderr); exit(1); } if ((imgaddr * img->sector_size) >= img->size) { tsk_fprintf(stderr, "Sector offset supplied is larger than disk image (maximum: %" PRIu64 ")\n", img->size / img->sector_size); exit(1); } } } } if ((fs = tsk_fs_open_img(img, imgaddr * img->sector_size, fstype)) == NULL) { tsk_error_print(stderr); if (tsk_error_get_errno() == TSK_ERR_FS_UNSUPTYPE) tsk_fs_type_print(stderr); img->close(img); exit(1); } /* do we need to set the range or just check them? */ if (set_range) { istart = fs->first_inum; ilast = fs->last_inum; } else { if (istart < fs->first_inum) istart = fs->first_inum; if (ilast > fs->last_inum) ilast = fs->last_inum; } /* NTFS uses alloc and link different than UNIX so change * the default behavior * * The link value can be > 0 on deleted files (even when closed) */ /* NTFS and FAT have no notion of deleted but still open */ if ((ils_flags & TSK_FS_ILS_OPEN) && (TSK_FS_TYPE_ISNTFS(fs->ftype) || TSK_FS_TYPE_ISFAT(fs->ftype))) { fprintf(stderr, "Error: '-O' argument does not work with NTFS and FAT images\n"); exit(1); } if (tsk_fs_ils(fs, (TSK_FS_ILS_FLAG_ENUM) ils_flags, istart, ilast, (TSK_FS_META_FLAG_ENUM) flags, sec_skew, image)) { tsk_error_print(stderr); fs->close(fs); img->close(img); exit(1); } fs->close(fs); img->close(img); exit(0); }
/* usage - explain and terminate */ static void usage() { TFPRINTF(stderr, _TSK_T ("usage: %s [-emOpvV] [-aAlLzZ] [-f fstype] [-i imgtype] [-b dev_sector_size] [-o imgoffset] [-s seconds] image [images] [inum[-end]]\n"), progname); tsk_fprintf(stderr, "\t-e: Display all inodes\n"); tsk_fprintf(stderr, "\t-m: Display output in the mactime format\n"); tsk_fprintf(stderr, "\t-O: Display inodes that are unallocated, but were sill open (UFS/ExtX only)\n"); tsk_fprintf(stderr, "\t-p: Display orphan inodes (unallocated with no file name)\n"); tsk_fprintf(stderr, "\t-s seconds: Time skew of original machine (in seconds)\n"); tsk_fprintf(stderr, "\t-a: Allocated inodes\n"); tsk_fprintf(stderr, "\t-A: Unallocated inodes\n"); tsk_fprintf(stderr, "\t-l: Linked inodes\n"); tsk_fprintf(stderr, "\t-L: Unlinked inodes\n"); tsk_fprintf(stderr, "\t-z: Unused inodes\n"); tsk_fprintf(stderr, "\t-Z: Used inodes\n"); tsk_fprintf(stderr, "\t-i imgtype: The format of the image file (use '-i list' for supported types)\n"); tsk_fprintf(stderr, "\t-b dev_sector_size: The size (in bytes) of the device sectors\n"); tsk_fprintf(stderr, "\t-f fstype: File system type (use '-f list' for supported types)\n"); tsk_fprintf(stderr, "\t-o imgoffset: The offset of the file system in the image (in sectors)\n"); tsk_fprintf(stderr, "\t-v: verbose output to stderr\n"); tsk_fprintf(stderr, "\t-V: Display version number\n"); exit(1); }