static TSK_WALK_RET_ENUM blkstat_act(const TSK_FS_BLOCK * fs_block, void *ptr) { tsk_printf("%s: %" PRIuDADDR "\n", fs_block->fs_info->duname, fs_block->addr); tsk_printf("%sAllocated%s\n", (fs_block->flags & TSK_FS_BLOCK_FLAG_ALLOC) ? "" : "Not ", (fs_block->flags & TSK_FS_BLOCK_FLAG_META) ? " (Meta)" : ""); if (TSK_FS_TYPE_ISFFS(fs_block->fs_info->ftype)) { FFS_INFO *ffs = (FFS_INFO *) fs_block->fs_info; tsk_printf("Group: %" PRI_FFSGRP "\n", ffs->grp_num); } else if (TSK_FS_TYPE_ISEXT(fs_block->fs_info->ftype)) { EXT2FS_INFO *ext2fs = (EXT2FS_INFO *) fs_block->fs_info; if (fs_block->addr >= ext2fs->first_data_block) tsk_printf("Group: %" PRI_EXT2GRP "\n", ext2fs->grp_num); } else if (TSK_FS_TYPE_ISFAT(fs_block->fs_info->ftype)) { FATFS_INFO *fatfs = (FATFS_INFO *) fs_block->fs_info; /* Does this have a cluster address? */ if (fs_block->addr >= fatfs->firstclustsect) { tsk_printf("Cluster: %" PRIuDADDR "\n", (2 + (fs_block->addr - fatfs->firstclustsect) / fatfs->csize)); } } return TSK_WALK_STOP; }
/* 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) { 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; }
/* Process a temporal value */ void file_infot(const string name,time_t t0, TSK_FS_TYPE_ENUM ftype) { const char * tm_format = NULL; if(TSK_FS_TYPE_ISFAT(ftype)) { #ifdef _MSC_VER tm_format="%Y-%m-%dT%H:%M:%S"; #else tm_format="%FT%T"; #endif } else { #ifdef _MSC_VER tm_format="%Y-%m-%dT%H:%M:%SZ"; #else tm_format="%FT%TZ"; #endif } if(a) a->add_valuet(name,t0); // struct tm *temp_time = gmtime(&t0); if(x){ char buf[32]; strftime(buf,sizeof(buf),tm_format,gmtime(&t0)); if(TSK_FS_TYPE_ISFAT(ftype)) { if (!name.compare("atime")) x->xmlout(name,buf,"prec=\"86400\"", false); if (!name.compare("mtime")) x->xmlout(name,buf,"prec=\"2\"", false); if (!name.compare("crtime")) x->xmlout(name,buf,"prec=\"2\"", false); } else x->xmlout(name,buf); } if(t) { char buf[64]; fprintf(t,"%s: %ld\n",name.c_str(),(long)t0); strftime(buf,sizeof(buf),tm_format,gmtime(&t0)); fprintf(t,"%s_txt: %s\n",name.c_str(),buf); } }
/* 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; }
/** * Utility method to help determine if a file is a FAT file system file (such as $MBR). * * @returns 1 if the file is an FAT System file, 0 if not. */ uint8_t TskAuto::isFATSystemFiles(TSK_FS_FILE * a_fs_file) { if ((a_fs_file) && (a_fs_file->fs_info) && (TSK_FS_TYPE_ISFAT(a_fs_file->fs_info->ftype)) && (a_fs_file->name->meta_addr == FATFS_MBRINO(a_fs_file->fs_info) || a_fs_file->name->meta_addr == FATFS_FAT1INO(a_fs_file->fs_info) || a_fs_file->name->meta_addr == FATFS_FAT2INO(a_fs_file->fs_info))) return 1; else return 0; }
/* used to identify the unnamed metadata structures */ static TSK_WALK_RET_ENUM find_orphan_meta_walk_cb(TSK_FS_FILE * a_fs_file, void *a_ptr) { FIND_ORPHAN_DATA *data = (FIND_ORPHAN_DATA *) a_ptr; TSK_FS_INFO *fs = a_fs_file->fs_info; /* We want only orphans, then check if this * inode is in the seen list */ tsk_take_lock(&fs->list_inum_named_lock); if ((fs->list_inum_named) && (tsk_list_find(fs->list_inum_named, a_fs_file->meta->addr))) { tsk_release_lock(&fs->list_inum_named_lock); return TSK_WALK_CONT; } tsk_release_lock(&fs->list_inum_named_lock); // check if we have already added it as an orphan (in a subdirectory) if (tsk_list_find(data->orphan_subdir_list, a_fs_file->meta->addr)) { return TSK_WALK_CONT; } // use their name if they have one if (a_fs_file->meta->name2) { strncpy(data->fs_name->name, a_fs_file->meta->name2->name, data->fs_name->name_size); } else { snprintf(data->fs_name->name, data->fs_name->name_size, "OrphanFile-%" PRIuINUM, a_fs_file->meta->addr); } data->fs_name->meta_addr = a_fs_file->meta->addr; data->fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; data->fs_name->type = TSK_FS_NAME_TYPE_UNDEF; if (tsk_fs_dir_add(data->fs_dir, data->fs_name)) return TSK_WALK_ERROR; /* 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 (TSK_FS_TYPE_ISFAT(fs->ftype)) { if (fatfs_dir_buf_add((FATFS_INFO *) fs, TSK_FS_ORPHANDIR_INUM(fs), a_fs_file->meta->addr)) return TSK_WALK_ERROR; } /* Go into directories to mark their contents as "seen" */ if (a_fs_file->meta->type == TSK_FS_META_TYPE_DIR) { if (tsk_verbose) fprintf(stderr, "find_orphan_meta_walk_cb: Going into directory %" PRIuINUM " to mark contents as seen\n", a_fs_file->meta->addr); if (tsk_fs_dir_walk(fs, a_fs_file->meta->addr, TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE | TSK_FS_DIR_WALK_FLAG_NOORPHAN, load_orphan_dir_walk_cb, data)) { tsk_error_errstr2_concat (" - find_orphan_meta_walk_cb: identifying inodes allocated by file names"); return TSK_WALK_ERROR; } } 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); }
/** * \ingroup fslib * Tries to process data in a disk image at a given offset as a file system. * Returns a structure that can be used for analysis and reporting. * * @param a_img_info Disk image to analyze * @param a_offset Byte offset to start analyzing from * @param a_ftype Type of file system (or autodetect) * * @return NULL on error */ TSK_FS_INFO * tsk_fs_open_img(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset, TSK_FS_TYPE_ENUM a_ftype) { if (a_img_info == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "tsk_fs_open_img: Null image handle"); return NULL; } /* We will try different file systems ... * We need to try all of them in case more than one matches */ if (a_ftype == TSK_FS_TYPE_DETECT) { TSK_FS_INFO *fs_info, *fs_set = NULL; char *set = NULL; if (tsk_verbose) tsk_fprintf(stderr, "fsopen: Auto detection mode at offset %" PRIuOFF "\n", a_offset); if ((fs_info = ntfs_open(a_img_info, a_offset, TSK_FS_TYPE_NTFS_DETECT, 1)) != NULL) { set = "NTFS"; fs_set = fs_info; } else { tsk_error_reset(); } if ((fs_info = fatfs_open(a_img_info, a_offset, TSK_FS_TYPE_FAT_DETECT, 1)) != NULL) { if (set == NULL) { set = "FAT"; fs_set = fs_info; } else { fs_set->close(fs_set); fs_info->close(fs_info); tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNKTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "FAT or %s", set); return NULL; } } else { tsk_error_reset(); } if ((fs_info = ext2fs_open(a_img_info, a_offset, TSK_FS_TYPE_EXT_DETECT, 1)) != NULL) { if (set == NULL) { set = "EXT2/3"; fs_set = fs_info; } else { fs_set->close(fs_set); fs_info->close(fs_info); tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNKTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "EXT2/3 or %s", set); return NULL; } } else { tsk_error_reset(); } if ((fs_info = ffs_open(a_img_info, a_offset, TSK_FS_TYPE_FFS_DETECT)) != NULL) { if (set == NULL) { set = "UFS"; fs_set = fs_info; } else { fs_set->close(fs_set); fs_info->close(fs_info); tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNKTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "UFS or %s", set); return NULL; } } else { tsk_error_reset(); } #if TSK_USE_HFS if ((fs_info = hfs_open(a_img_info, a_offset, TSK_FS_TYPE_HFS_DETECT, 1)) != NULL) { if (set == NULL) { set = "HFS"; fs_set = fs_info; } else { fs_set->close(fs_set); fs_info->close(fs_info); tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNKTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "HFS or %s", set); return NULL; } } else { tsk_error_reset(); } #endif if ((fs_info = iso9660_open(a_img_info, a_offset, TSK_FS_TYPE_ISO9660_DETECT, 1)) != NULL) { if (set != NULL) { fs_set->close(fs_set); fs_info->close(fs_info); tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNKTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "ISO9660 or %s", set); return NULL; } fs_set = fs_info; } else { tsk_error_reset(); } if (fs_set == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNKTYPE; tsk_errstr[0] = '\0'; tsk_errstr2[0] = '\0'; return NULL; } return fs_set; } else { if (TSK_FS_TYPE_ISNTFS(a_ftype)) return ntfs_open(a_img_info, a_offset, a_ftype, 0); else if (TSK_FS_TYPE_ISFAT(a_ftype)) return fatfs_open(a_img_info, a_offset, a_ftype, 0); else if (TSK_FS_TYPE_ISFFS(a_ftype)) return ffs_open(a_img_info, a_offset, a_ftype); else if (TSK_FS_TYPE_ISEXT(a_ftype)) return ext2fs_open(a_img_info, a_offset, a_ftype, 0); else if (TSK_FS_TYPE_ISHFS(a_ftype)) return hfs_open(a_img_info, a_offset, a_ftype, 0); else if (TSK_FS_TYPE_ISISO9660(a_ftype)) return iso9660_open(a_img_info, a_offset, a_ftype, 0); else if (TSK_FS_TYPE_ISRAW(a_ftype)) return rawfs_open(a_img_info, a_offset); else if (TSK_FS_TYPE_ISSWAP(a_ftype)) return swapfs_open(a_img_info, a_offset); else { tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNSUPTYPE; snprintf(tsk_errstr, TSK_ERRSTR_L, "%X", (int) a_ftype); return NULL; } } }
// XXX([email protected]): had better fix the comment // find file of the given inode // // \param fs filesystem info structure defined in sleuthkit // \param lclflags traverse options defined in sleuthkit // \param a_inode the inode of the file // \param type filesystem type number // \param type_used don't know what it is, just give a 0(XXX) // \param id the id of file attribute that the inode refers // \param id_used don't know what it is, just give a 0(XXX) // \param flags traverse options difned in sleuthkit // // Return 0 if error, otherwise a pointer static MBA_FFIND_DATA* fs_ffind(TSK_FS_INFO * fs, TSK_FS_FFIND_FLAG_ENUM lclflags, TSK_INUM_T a_inode, TSK_FS_ATTR_TYPE_ENUM type, uint8_t type_used, uint16_t id, uint8_t id_used, TSK_FS_DIR_WALK_FLAG_ENUM flags) { MBA_FFIND_DATA* data=(MBA_FFIND_DATA*)malloc(sizeof(MBA_FFIND_DATA)); char* orphan =NULL; int size = 0; if(data == NULL) { printf("Cannot allocate memory\n"); return NULL; } data->found = 0; data->flags = lclflags; data->inode = a_inode; utarray_new(data->filenames, &ut_str_icd); /* Since we start the walk on the root inode, then this will not show ** up in the above functions, so do it now */ if (data->inode == fs->root_inum) { if (flags & TSK_FS_DIR_WALK_FLAG_ALLOC) { //tsk_printf("/\n"); data->found = 1; if (!(lclflags & TSK_FS_FFIND_ALL)) return data; } } if (TSK_FS_TYPE_ISNTFS(fs->ftype)) { if (ntfs_find_file(fs, data->inode, type, type_used, id, id_used, flags, find_file_act, data)) return NULL; } else { if (tsk_fs_dir_walk(fs, fs->root_inum, flags, find_file_act, data)) return NULL; } if (data->found == 0) { /* With FAT, we can at least give the name of the file and call * it orphan */ if (TSK_FS_TYPE_ISFAT(fs->ftype)) { TSK_FS_FILE *fs_file = tsk_fs_file_open_meta(fs, NULL, data->inode); if ((fs_file != NULL) && (fs_file->meta != NULL) && (fs_file->meta->name2 != NULL)) { //if (fs_file->meta->flags & TSK_FS_META_FLAG_UNALLOC) // tsk_printf("* "); //tsk_printf("%s/%s\n", TSK_FS_ORPHAN_STR, // fs_file->meta->name2->name); //Added Ophan file into file list size = strlen(TSK_FS_ORPHAN_STR) + strlen(fs_file->meta->name2->name)+2; orphan = (char*)malloc(size); if(orphan == NULL) { printf("Cannot allocate memory\n"); }else { snprintf(orphan, size, "%s/%s", TSK_FS_ORPHAN_STR,fs_file->meta->name2->name); utarray_push_back(data->filenames, orphan ); } } if (fs_file) tsk_fs_file_close(fs_file); } else { tsk_printf("File name not found for inode\n"); } } return data; }
/** * \internal * Print contents of fs_name entry format like ls -l ** ** All elements are tab delimited ** ** If path is NULL, then skip else use. it has the full directory name ** It needs to end with "/" */ void tsk_fs_name_print_long(FILE * hFile, const TSK_FS_FILE * fs_file, const char *a_path, TSK_FS_INFO * fs, const TSK_FS_ATTR * fs_attr, uint8_t print_path, int32_t sec_skew) { tsk_fs_name_print(hFile, fs_file, a_path, fs, fs_attr, print_path); if ((fs == NULL) || (fs_file->meta == NULL)) { tsk_fprintf(hFile, "\t"); tsk_fs_print_time(hFile, 0); // mtime tsk_fprintf(hFile, "\t"); tsk_fs_print_time(hFile, 0); // atime tsk_fprintf(hFile, "\t"); tsk_fs_print_time(hFile, 0); // ctime tsk_fprintf(hFile, "\t"); tsk_fs_print_time(hFile, 0); // crtime // size, uid, gid tsk_fprintf(hFile, "\t0\t0\t0\n"); } else { /* MAC times */ tsk_fprintf(hFile, "\t"); if (fs_file->meta->mtime) tsk_fs_print_time(hFile, fs_file->meta->mtime - sec_skew); else tsk_fs_print_time(hFile, fs_file->meta->mtime); tsk_fprintf(hFile, "\t"); /* FAT only gives the day of last access */ if ((TSK_FS_TYPE_ISFAT(fs->ftype)) || (fs_file->meta->atime == 0)) tsk_fs_print_day(hFile, fs_file->meta->atime); else tsk_fs_print_time(hFile, fs_file->meta->atime - sec_skew); tsk_fprintf(hFile, "\t"); if (fs_file->meta->ctime) tsk_fs_print_time(hFile, fs_file->meta->ctime - sec_skew); else tsk_fs_print_time(hFile, fs_file->meta->ctime); tsk_fprintf(hFile, "\t"); if (fs_file->meta->crtime) tsk_fs_print_time(hFile, fs_file->meta->crtime - sec_skew); else tsk_fs_print_time(hFile, fs_file->meta->crtime); /* use the stream size if one was given */ if (fs_attr) tsk_fprintf(hFile, "\t%" PRIuOFF, fs_attr->size); else tsk_fprintf(hFile, "\t%" PRIuOFF, fs_file->meta->size); tsk_fprintf(hFile, "\t%" PRIuGID "\t%" PRIuUID "\n", fs_file->meta->gid, fs_file->meta->uid); } return; }
/** * \ingroup fslib * * Find the meta data address for a given file name (UTF-8). * The basic idea of the function is to break the given name into its * subdirectories and start looking for each (starting in the root * directory). * * @param a_fs FS to analyze * @param a_path UTF-8 path of file to search for * @param [out] a_result Meta data address of file * @param [out] a_fs_name Copy of name details (or NULL if details not wanted) * @returns -1 on (system) error, 0 if found, and 1 if not found */ int8_t tsk_fs_path2inum(TSK_FS_INFO * a_fs, const char *a_path, TSK_INUM_T * a_result, TSK_FS_NAME * a_fs_name) { char *cpath; size_t clen; char *cur_dir; // The "current" directory or file we are looking for char *cur_attr; // The "current" attribute of the dir we are looking for TSK_INUM_T next_meta; uint8_t is_done; char *strtok_last; *a_result = 0; // copy path to a buffer that we can modify clen = strlen(a_path) + 1; if ((cpath = (char *) tsk_malloc(clen)) == NULL) { return -1; } strncpy(cpath, a_path, clen); // Get the first part of the directory path. cur_dir = (char *) strtok_r(cpath, "/", &strtok_last); cur_attr = NULL; /* If there is no token, then only a '/' was given */ if (cur_dir == NULL) { free(cpath); *a_result = a_fs->root_inum; // create the dummy entry if needed if (a_fs_name) { a_fs_name->meta_addr = a_fs->root_inum; // Note that we are not filling in meta_seq -- we could, we just aren't a_fs_name->type = TSK_FS_NAME_TYPE_DIR; a_fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; if (a_fs_name->name) a_fs_name->name[0] = '\0'; if (a_fs_name->shrt_name) a_fs_name->shrt_name[0] = '\0'; } return 0; } /* If this is NTFS, seperate out the attribute of the current directory */ if (TSK_FS_TYPE_ISNTFS(a_fs->ftype) && ((cur_attr = strchr(cur_dir, ':')) != NULL)) { *(cur_attr) = '\0'; cur_attr++; } if (tsk_verbose) tsk_fprintf(stderr, "Looking for %s\n", cur_dir); // initialize the first place to look, the root dir next_meta = a_fs->root_inum; // we loop until we know the outcome and then exit. // everything should return from inside the loop. is_done = 0; while (is_done == 0) { size_t i; TSK_FS_FILE *fs_file_alloc = NULL; // set to the allocated file that is our target TSK_FS_FILE *fs_file_del = NULL; // set to an unallocated file that matches our criteria TSK_FS_DIR *fs_dir = NULL; // open the next directory in the recursion if ((fs_dir = tsk_fs_dir_open_meta(a_fs, next_meta)) == NULL) { free(cpath); return -1; } /* Verify this is indeed a directory. We had one reported * problem where a file was a disk image and opening it as * a directory found the directory entries inside of the file * and this caused problems... */ if (fs_dir->fs_file->meta->type != TSK_FS_META_TYPE_DIR) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_GENFS); tsk_error_set_errstr("Address %" PRIuINUM " is not for a directory\n", next_meta); free(cpath); return -1; } // cycle through each entry for (i = 0; i < tsk_fs_dir_getsize(fs_dir); i++) { TSK_FS_FILE *fs_file; uint8_t found_name = 0; if ((fs_file = tsk_fs_dir_get(fs_dir, i)) == NULL) { tsk_fs_dir_close(fs_dir); free(cpath); return -1; } /* * Check if this is the name that we are currently looking for, * as identified in 'cur_dir' */ /* FAT is a special case because we check the short name */ if (TSK_FS_TYPE_ISFAT(a_fs->ftype)) { if ((fs_file->name->name) && (a_fs->name_cmp(a_fs, fs_file->name->name, cur_dir) == 0)) { found_name = 1; } else if ((fs_file->name->shrt_name) && (a_fs->name_cmp(a_fs, fs_file->name->shrt_name, cur_dir) == 0)) { found_name = 1; } } /* NTFS gets a case insensitive comparison */ else if (TSK_FS_TYPE_ISNTFS(a_fs->ftype)) { if ((fs_file->name->name) && (a_fs->name_cmp(a_fs, fs_file->name->name, cur_dir) == 0)) { /* ensure we have the right attribute name */ if (cur_attr == NULL) { found_name = 1; } else { if (fs_file->meta) { int cnt, i; // cycle through the 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; if ((fs_attr->name) && (a_fs->name_cmp(a_fs, fs_attr->name, cur_attr) == 0)) { found_name = 1; } } } } } } else { if ((fs_file->name->name) && (a_fs->name_cmp(a_fs, fs_file->name->name, cur_dir) == 0)) { found_name = 1; } } if (found_name) { /* If we found our file and it is allocated, then stop. If * it is unallocated, keep on going to see if we can get * an allocated hit */ if (fs_file->name->flags & TSK_FS_NAME_FLAG_ALLOC) { fs_file_alloc = fs_file; break; } else { // if we already have an unalloc and its addr is 0, then use the new one if ((fs_file_del) && (fs_file_del->name->meta_addr == 0)) { tsk_fs_file_close(fs_file_del); } fs_file_del = fs_file; } } // close the file if we did not save it for future analysis. else { tsk_fs_file_close(fs_file); fs_file = NULL; } } // we found a directory, go into it if ((fs_file_alloc) || (fs_file_del)) { const char *pname; TSK_FS_FILE *fs_file_tmp; // choose the alloc one first (if they both exist) if (fs_file_alloc) fs_file_tmp = fs_file_alloc; else fs_file_tmp = fs_file_del; pname = cur_dir; // save a copy of the current name pointer // advance to the next name cur_dir = (char *) strtok_r(NULL, "/", &(strtok_last)); cur_attr = NULL; if (tsk_verbose) tsk_fprintf(stderr, "Found it (%s), now looking for %s\n", pname, cur_dir); /* That was the last name in the path -- we found the file! */ if (cur_dir == NULL) { *a_result = fs_file_tmp->name->meta_addr; // make a copy if one was requested if (a_fs_name) { tsk_fs_name_copy(a_fs_name, fs_file_tmp->name); } tsk_fs_dir_close(fs_dir); free(cpath); return 0; } // update the attribute field, if needed if (TSK_FS_TYPE_ISNTFS(a_fs->ftype) && ((cur_attr = strchr(cur_dir, ':')) != NULL)) { *(cur_attr) = '\0'; cur_attr++; } // update the value for the next directory to open next_meta = fs_file_tmp->name->meta_addr; if (fs_file_alloc) { tsk_fs_file_close(fs_file_alloc); fs_file_alloc = NULL; } if (fs_file_del) { tsk_fs_file_close(fs_file_del); fs_file_del = NULL; } } // no hit in directory else { is_done = 1; } tsk_fs_dir_close(fs_dir); fs_dir = NULL; } free(cpath); return 1; }
/** * \ingroup fslib * Tries to process data in a disk image at a given offset as a file system. * Returns a structure that can be used for analysis and reporting. * * @param a_img_info Disk image to analyze * @param a_offset Byte offset to start analyzing from * @param a_ftype Type of file system (or autodetect) * * @return NULL on error */ TSK_FS_INFO * tsk_fs_open_img(TSK_IMG_INFO * a_img_info, TSK_OFF_T a_offset, TSK_FS_TYPE_ENUM a_ftype) { TSK_FS_INFO *fs_info; const struct { char* name; TSK_FS_INFO* (*open)(TSK_IMG_INFO*, TSK_OFF_T, TSK_FS_TYPE_ENUM, uint8_t); TSK_FS_TYPE_ENUM type; } FS_OPENERS[] = { { "NTFS", ntfs_open, TSK_FS_TYPE_NTFS_DETECT }, { "FAT", fatfs_open, TSK_FS_TYPE_FAT_DETECT }, { "EXT2/3/4", ext2fs_open, TSK_FS_TYPE_EXT_DETECT }, { "UFS", ffs_open, TSK_FS_TYPE_FFS_DETECT }, { "YAFFS2", yaffs2_open, TSK_FS_TYPE_YAFFS2_DETECT }, #if TSK_USE_HFS { "HFS", hfs_open, TSK_FS_TYPE_HFS_DETECT }, #endif { "ISO9660", iso9660_open, TSK_FS_TYPE_ISO9660_DETECT } }; if (a_img_info == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_ARG); tsk_error_set_errstr("tsk_fs_open_img: Null image handle"); return NULL; } /* We will try different file systems ... * We need to try all of them in case more than one matches */ if (a_ftype == TSK_FS_TYPE_DETECT) { unsigned long i; const char *name_first = ""; TSK_FS_INFO *fs_first = NULL; if (tsk_verbose) tsk_fprintf(stderr, "fsopen: Auto detection mode at offset %" PRIuOFF "\n", a_offset); for (i = 0; i < sizeof(FS_OPENERS)/sizeof(FS_OPENERS[0]); ++i) { if ((fs_info = FS_OPENERS[i].open( a_img_info, a_offset, FS_OPENERS[i].type, 1)) != NULL) { // fs opens as type i if (fs_first == NULL) { // first success opening fs name_first = FS_OPENERS[i].name; fs_first = fs_info; } else { // second success opening fs, which means we // cannot autodetect the fs type and must give up fs_first->close(fs_first); fs_info->close(fs_info); tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNKTYPE); tsk_error_set_errstr( "%s or %s", FS_OPENERS[i].name, name_first); return NULL; } } else { // fs does not open as type i tsk_error_reset(); } } if (fs_first == NULL) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNKTYPE); } return fs_first; } else if (TSK_FS_TYPE_ISNTFS(a_ftype)) { return ntfs_open(a_img_info, a_offset, a_ftype, 0); } else if (TSK_FS_TYPE_ISFAT(a_ftype)) { return fatfs_open(a_img_info, a_offset, a_ftype, 0); } else if (TSK_FS_TYPE_ISFFS(a_ftype)) { return ffs_open(a_img_info, a_offset, a_ftype, 0); } else if (TSK_FS_TYPE_ISEXT(a_ftype)) { return ext2fs_open(a_img_info, a_offset, a_ftype, 0); } else if (TSK_FS_TYPE_ISHFS(a_ftype)) { return hfs_open(a_img_info, a_offset, a_ftype, 0); } else if (TSK_FS_TYPE_ISISO9660(a_ftype)) { return iso9660_open(a_img_info, a_offset, a_ftype, 0); } else if (TSK_FS_TYPE_ISRAW(a_ftype)) { return rawfs_open(a_img_info, a_offset); } else if (TSK_FS_TYPE_ISSWAP(a_ftype)) { return swapfs_open(a_img_info, a_offset); } else if (TSK_FS_TYPE_ISYAFFS2(a_ftype)) { return yaffs2_open(a_img_info, a_offset, a_ftype, 0); } tsk_error_reset(); tsk_error_set_errno(TSK_ERR_FS_UNSUPTYPE); tsk_error_set_errstr("%X", (int) a_ftype); return NULL; }