int main(int argc, char **argv){ int i,j,fd; long size; int pagesize, pagesecs; unsigned char *bp; struct ext2_super_block *e2bp; struct fat16_boot_sector *fat16bs; struct fat32_boot_sector *fat32bs; progname = argv[0]; if (argc != 2) { fprintf(stderr, "call: %s device\n", progname); exit(1); } device = argv[1]; fd = open(device, O_RDONLY); if (fd < 0) { perror(device); fprintf(stderr, "%s: could not open %s\n", progname, device); exit(1); } if (ioctl(fd, BLKGETSIZE, &size)) { struct stat s; perror("BLKGETSIZE"); fprintf(stderr, "%s: could not get device size\n", progname); if (stat(device, &s)) { fprintf(stderr, "and also stat fails. Aborting.\n"); exit(1); } size = s.st_size / 512; } pagesize = getpagesize(); if (pagesize <= 0) pagesize = 4096; else if (pagesize > MAXPAGESZ) { fprintf(stderr, "%s: ridiculous pagesize %d\n", progname, pagesize); exit(1); } pagesecs = pagesize/512; printf("# partition table of %s\n", device); printf("# total size %ld sectors\n", size); printf("unit: sectors\n"); for(i=0; i<size; i++) { if (i/BUFSECS != bufstart) { int len, secno; bufstart = i/BUFSECS; secno = bufstart*BUFSECS; len = BUFSECS; if (size - secno < len) len = size - secno; len = (len / 2)*2; /* avoid reading the last (odd) sector */ read_sectors(fd, buf, secno, len); } j = i % BUFSECS; bp = buf + 512 * j; if (bp[510] == 0x55 && bp[511] == 0xAA) { char *cp = bp+512-2-64; int j; if (i==0) continue; /* the MBR is supposed to be broken */ /* Unfortunately one finds extended partition table sectors that look just like a fat boot sector, except that the partition table bytes have been overwritten */ /* typical FAT32 end: "nd then press ...", followed by IO.SYS and MSDOS.SYS and WINBOOT.SYS directory entries. typical extd part tab end: 2 entries, 32 nul bytes */ for(j=0; j<32; j++) if (cp[32+j]) goto nonzero; addepts(i, bp); if (i > 0) { j = create_extended_partition(fd, i, size); if (j && j > i) i = j; /* skip */ } continue; nonzero: fat16bs = (struct fat16_boot_sector *) bp; if (fat16bs->s.media == 0xf8 && fat16bs->m.extd_signature == 0x29 && !strncmp(fat16bs->m.fs_name, "FAT", 3)) { int lth; lth = fat16bs->s.sectors[0] + fat16bs->s.sectors[1]*256; if (lth) { outmsg("small fat partition", i, i+lth, 0x1); addpart(i, lth, 0x1); } else { lth = fat16bs->s.total_sect; outmsg("fat partition", i, i+lth, 0x6); addpart(i, lth, 0x6); } i = i+lth-1; /* skip */ continue; } fat32bs = (struct fat32_boot_sector *) bp; if (fat32bs->s.media == 0xf8 && fat32bs->m.extd_signature == 0x29 && !strncmp(fat32bs->m.fs_name, "FAT32 ", 8)) { int lth = fat32bs->s.total_sect; outmsg("fat32 partition", i, i+lth, 0xb); /* or 0xc */ addpart(i, lth, 0xb); i = i+lth-1; /* skip */ continue; } } if (!strncmp(bp+502, "SWAP-SPACE", 10)) { char *last; int ct; int ss = i-pagesecs+1; int es; char buf2[MAXPAGESZ]; read_sectors(fd, buf2, ss, pagesecs); for (last = buf2+pagesize-10-1; last > buf2; last--) if (*last) break; for (ct = 7; ct >= 0; ct--) if (*last & (1<<ct)) break; es = ((last - buf2)*8 + ct + 1)*pagesecs + ss; if (es <= size) { outmsg("old swap space", ss, es, 0x82); addpart(ss, es-ss, 0x82); i = es-1; /* skip */ continue; } } if (!strncmp(bp+502, "SWAPSPACE2", 10)) { int ss = i-pagesecs+1; int es, lth; char buf2[MAXPAGESZ]; struct swap_header_v1 *p; read_sectors(fd, buf2, ss, pagesecs); p = (struct swap_header_v1 *) buf2; lth = (p->last_page + 1)* pagesecs; es = ss + lth; if (es <= size) { outmsg("new swap space", ss, es, 0x82); addpart(ss, lth, 0x82); i = es-1; /* skip */ continue; } } e2bp = (struct ext2_super_block *) bp; if (e2bp->s_magic == EXT2_SUPER_MAGIC && is_time(e2bp->s_mtime) && is_time(e2bp->s_wtime) && is_ztime(e2bp->s_lastcheck) && e2bp->s_log_block_size <= 10 /* at most 1 MB blocks */) { char buf[512]; struct ext2_super_block *bp2; int ss, sz, es, gsz, j; ss = i-2; sz = (e2bp->s_blocks_count << (e2bp->s_log_block_size + 1)); gsz = (e2bp->s_blocks_per_group << (e2bp->s_log_block_size + 1)); if (e2bp->s_block_group_nr > 0) ss -= gsz * e2bp->s_block_group_nr; es = ss + sz; if (ss > 0 && es > i && es <= size) { if (e2bp->s_block_group_nr == 0) { outmsg("ext2 partition", ss, es, 0x83); addpart(ss, es-ss, 0x83); i = es-1; /* skip */ continue; } /* maybe we jumped into the middle of a partially obliterated ext2 partition? */ printf("# sector %d looks like an ext2 superblock copy #%d;\n" "# in a partition covering sectors %d-%d\n", i, e2bp->s_block_group_nr, ss, es-1); for (j=1; j<=e2bp->s_block_group_nr; j++) { read_sectors(fd, buf, i-j*gsz, 1); bp2 = (struct ext2_super_block *) buf; if (bp2->s_magic != EXT2_SUPER_MAGIC || bp2->s_block_group_nr != e2bp->s_block_group_nr - j) break; } if (j == 1) printf("# however, sector %d doesnt look like a sb.\n", i-gsz); else if (j <= e2bp->s_block_group_nr) printf("# also the preceding %d block groups seem OK\n" "# but before that things seem to be wrong.\n", j-1); else { printf("# found all preceding superblocks OK\n" "# Warning: overlapping partitions?\n"); outmsg("ext2 partition", ss, es, 0x83); addpart(ss, es-ss, 0x83); i = es-1; /* skip */ continue; } } } if (bp[4] == 0x0d && bp[5] == 0x60 && bp[6] == 0x5e && bp[7] == 0xca && /* CA5E600D */ bp[156] == 0xee && bp[157] == 0xde && bp[158] == 0x0d && bp[159] == 0x60) /* 600DDEEE */ { int ss, es; struct unixware_slice *u; printf("# Unixware partition seen\n"); u = (struct unixware_slice *)(bp + 216); if (u->slice_type == 5 /* entire disk */ && (u->slice_flags & 0x200)) /* valid */ { ss = u->start; es = u->start + u->size; outmsg("Unixware ptn", ss, es, 0x63); addpart(ss, es-ss, 0x63); i = es-1; continue; } else printf("# Unrecognized details\n"); } /* bsd disk magic 0x82564557UL */ if (bp[0] == 0x57 && bp[1] == 0x45 && bp[2] == 0x56 && bp[3] == 0x82) { int ss, es, npts, j; struct bsd_disklabel *l; struct bsd_partition *p; printf("# BSD magic seen in sector %d\n", i); l = (struct bsd_disklabel *) bp; if (l->d_magic2[0] != 0x57 || l->d_magic2[1] != 0x45 || l->d_magic2[2] != 0x56 || l->d_magic2[3] != 0x82) printf("# 2nd magic bad - ignored this sector\n"); else if ((npts = l->d_npartitions) > 16) printf("# strange number (%d) of subpartitions - " "ignored this sector\n", npts); else { for (j=0; j<npts; j++) { p = &(l->d_partitions[j]); if (p->p_size) printf("# part %c: size %9d, start %9d\n", 'a'+j, p->p_size, p->p_offset); } ss = l->d_partitions[2].p_offset; es = ss + l->d_partitions[2].p_size; if (ss != i-1) printf("# strange start of whole disk - " "ignored this sector\n"); else { /* FreeBSD 0xa5, OpenBSD 0xa6, NetBSD 0xa9, BSDI 0xb7 */ /* How to distinguish? */ outmsg("BSD partition", ss, es, 0xa5); addpart(ss, es-ss, 0xa5); i = es-1; continue; } } } } outparts(); exit(0); }
int vfs_parse_filedate (int idx, time_t * t) { char *p; struct tm tim; int d[3]; int got_year = 0; int l10n = 0; /* Locale's abbreviated month name */ time_t current_time; struct tm *local_time; /* Let's setup default time values */ current_time = time (NULL); local_time = localtime (¤t_time); tim.tm_mday = local_time->tm_mday; tim.tm_mon = local_time->tm_mon; tim.tm_year = local_time->tm_year; tim.tm_hour = 0; tim.tm_min = 0; tim.tm_sec = 0; tim.tm_isdst = -1; /* Let mktime() try to guess correct dst offset */ p = columns[idx++]; /* We eat weekday name in case of extfs */ if (is_week (p, &tim)) p = columns[idx++]; /* Month name */ if (is_month (p, &tim)) { /* And we expect, it followed by day number */ if (is_num (idx)) tim.tm_mday = (int) atol (columns[idx++]); else return 0; /* No day */ } else { /* We expect: 3 fields max or we'll see oddities with certain file names. So both year and time is not allowed. Mon DD hh:mm[:ss] Mon DD YYYY But in case of extfs we allow these date formats: MM-DD-YY hh:mm[:ss] where Mon is Jan-Dec, DD, MM, YY two digit day, month, year, YYYY four digit year, hh, mm, ss two digit hour, minute or second. */ /* Special case with MM-DD-YY or MM-DD-YYYY */ if (is_dos_date (p)) { p[2] = p[5] = '-'; if (sscanf (p, "%2d-%2d-%d", &d[0], &d[1], &d[2]) == 3) { /* Months are zero based */ if (d[0] > 0) d[0]--; if (d[2] > 1900) { d[2] -= 1900; } else { /* Y2K madness */ if (d[2] < 70) d[2] += 100; } tim.tm_mon = d[0]; tim.tm_mday = d[1]; tim.tm_year = d[2]; got_year = 1; } else return 0; /* sscanf failed */ } else { /* Locale's abbreviated month name followed by day number */ if (is_localized_month (p) && (is_num (idx++))) l10n = 1; else return 0; /* unsupported format */ } } /* Here we expect to find time or year */ if (is_num (idx) && (is_time (columns[idx], &tim) || (got_year = is_year (columns[idx], &tim)))) idx++; else return 0; /* Neither time nor date */ /* * If the date is less than 6 months in the past, it is shown without year * other dates in the past or future are shown with year but without time * This does not check for years before 1900 ... I don't know, how * to represent them at all */ if (!got_year && local_time->tm_mon < 6 && local_time->tm_mon < tim.tm_mon && tim.tm_mon - local_time->tm_mon >= 6) tim.tm_year--; *t = mktime (&tim); if (l10n || (*t < 0)) *t = 0; return idx; }
// @@@ Should make a_idxe const and use internal pointer in function loop static TSK_RETVAL_ENUM ntfs_proc_idxentry(NTFS_INFO * a_ntfs, TSK_FS_DIR * a_fs_dir, uint8_t a_is_del, ntfs_idxentry * a_idxe, uint32_t a_idxe_len, uint32_t a_used_len) { uintptr_t endaddr, endaddr_alloc; TSK_FS_NAME *fs_name; TSK_FS_INFO *fs = (TSK_FS_INFO *) & a_ntfs->fs_info; if ((fs_name = tsk_fs_name_alloc(NTFS_MAXNAMLEN_UTF8, 0)) == NULL) { return TSK_ERR; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Processing index entry: %" PRIu64 " Size: %" PRIu32 " Len: %" PRIu32 "\n", (uint64_t) ((uintptr_t) a_idxe), a_idxe_len, a_used_len); /* Sanity check */ if (a_idxe_len < a_used_len) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_proc_idxentry: Allocated length of index entries is larger than buffer length"); return TSK_ERR; } /* where is the end of the buffer */ endaddr = ((uintptr_t) a_idxe + a_idxe_len); /* where is the end of the allocated data */ endaddr_alloc = ((uintptr_t) a_idxe + a_used_len); /* cycle through the index entries, based on provided size */ while (((uintptr_t) & (a_idxe->stream) + sizeof(ntfs_attr_fname)) < endaddr) { ntfs_attr_fname *fname = (ntfs_attr_fname *) & a_idxe->stream; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: New IdxEnt: %" PRIu64 " $FILE_NAME Entry: %" PRIu64 " File Ref: %" PRIu64 " IdxEnt Len: %" PRIu16 " StrLen: %" PRIu16 "\n", (uint64_t) ((uintptr_t) a_idxe), (uint64_t) ((uintptr_t) fname), (uint64_t) tsk_getu48(fs->endian, a_idxe->file_ref), tsk_getu16(fs->endian, a_idxe->idxlen), tsk_getu16(fs->endian, a_idxe->strlen)); /* perform some sanity checks on index buffer head * and advance by 4-bytes if invalid */ if ((tsk_getu48(fs->endian, a_idxe->file_ref) > fs->last_inum) || (tsk_getu48(fs->endian, a_idxe->file_ref) < fs->first_inum) || (tsk_getu16(fs->endian, a_idxe->idxlen) <= tsk_getu16(fs->endian, a_idxe->strlen)) || (tsk_getu16(fs->endian, a_idxe->idxlen) % 4) || (tsk_getu16(fs->endian, a_idxe->idxlen) > a_idxe_len)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); continue; } /* do some sanity checks on the deleted entries */ if ((tsk_getu16(fs->endian, a_idxe->strlen) == 0) || (((uintptr_t) a_idxe + tsk_getu16(fs->endian, a_idxe->idxlen)) > endaddr_alloc)) { /* name space checks */ if ((fname->nspace != NTFS_FNAME_POSIX) && (fname->nspace != NTFS_FNAME_WIN32) && (fname->nspace != NTFS_FNAME_DOS) && (fname->nspace != NTFS_FNAME_WINDOS)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of invalid name space\n"); continue; } if ((tsk_getu64(fs->endian, fname->alloc_fsize) < tsk_getu64(fs->endian, fname->real_fsize)) || (fname->nlen == 0) || (*(uint8_t *) & fname->name == 0)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of reported file sizes, name length, or NULL name\n"); continue; } if ((is_time(tsk_getu64(fs->endian, fname->crtime)) == 0) || (is_time(tsk_getu64(fs->endian, fname->atime)) == 0) || (is_time(tsk_getu64(fs->endian, fname->mtime)) == 0)) { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of invalid times\n"); continue; } } /* For all fname entries, there will exist a DOS style 8.3 * entry. We don't process those because we already processed * them before in their full version. If the type is * full POSIX or WIN32 that does not satisfy DOS, then a * type NTFS_FNAME_DOS will exist. If the name is WIN32, * but already satisfies DOS, then a type NTFS_FNAME_WINDOS * will exist * * Note that we could be missing some info from deleted files * if the windows version was deleted and the DOS wasn't... * * @@@ This should be added to the shrt_name entry of TSK_FS_NAME. The short * name entry typically comes after the long name */ if (fname->nspace == NTFS_FNAME_DOS) { if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because of name space: %d\n", fname->nspace); goto incr_entry; } /* Copy it into the generic form */ if (ntfs_dent_copy(a_ntfs, a_idxe, fs_name)) { if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Skipping because error copying dent_entry\n"); goto incr_entry; } /* * Check if this entry is deleted * * The final check is to see if the end of this entry is * within the space that the idxallocbuf claimed was valid OR * if the parent directory is deleted */ if ((a_is_del == 1) || (tsk_getu16(fs->endian, a_idxe->strlen) == 0) || (((uintptr_t) a_idxe + tsk_getu16(fs->endian, a_idxe->idxlen)) > endaddr_alloc)) { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } else { fs_name->flags = TSK_FS_NAME_FLAG_ALLOC; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_proc_idxentry: Entry Details of %s: Str Len: %" PRIu16 " Len to end after current: %" PRIu64 " flags: %x\n", fs_name->name, tsk_getu16(fs->endian, a_idxe->strlen), (uint64_t) (endaddr_alloc - (uintptr_t) a_idxe - tsk_getu16(fs->endian, a_idxe->idxlen)), fs_name->flags); if (tsk_fs_dir_add(a_fs_dir, fs_name)) { tsk_fs_name_free(fs_name); return TSK_ERR; } incr_entry: /* the theory here is that deleted entries have strlen == 0 and * have been found to have idxlen == 16 * * if the strlen is 0, then guess how much the indexlen was * before it was deleted */ /* 16: size of idxentry before stream * 66: size of fname before name * 2*nlen: size of name (in unicode) */ if (tsk_getu16(fs->endian, a_idxe->strlen) == 0) { a_idxe = (ntfs_idxentry *) ((((uintptr_t) a_idxe + 16 + 66 + 2 * fname->nlen + 3) / 4) * 4); } else { a_idxe = (ntfs_idxentry *) ((uintptr_t) a_idxe + tsk_getu16(fs->endian, a_idxe->idxlen)); } } /* end of loop of index entries */ tsk_fs_name_free(fs_name); return TSK_OK; }
/** * Process a lsit of index entries and call the callback for * each. * * @param list_seen List of directories that have already been analyzed * @param idxe Buffer with index entries to process * @param idxe_len Length of idxe buffer (in bytes) * @param used_len Length of data as reported by idexlist header (everything * after which and less then idxe_len is considered deleted) * @param flags (All we care about is ALLOC and UNALLOC) * @param action Callback * @param ptr Pointer to data to pass to callback * * @returns 1 to stop, 0 on success, and -1 on error */ static int ntfs_dent_idxentry(NTFS_INFO * ntfs, NTFS_DINFO * dinfo, TSK_LIST ** list_seen, ntfs_idxentry * idxe, uint32_t idxe_len, uint32_t used_len, int flags, TSK_FS_DENT_TYPE_WALK_CB action, void *ptr) { uintptr_t endaddr, endaddr_alloc; TSK_FS_DENT *fs_dent; TSK_FS_INFO *fs = (TSK_FS_INFO *) & ntfs->fs_info; if ((fs_dent = tsk_fs_dent_alloc(NTFS_MAXNAMLEN_UTF8, 0)) == NULL) { return -1; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: Processing index entry: %" PRIu64 " Size: %" PRIu32 " Len: %" PRIu32 " Flags: %x\n", (uint64_t) ((uintptr_t) idxe), idxe_len, used_len, flags); /* Sanity check */ if (idxe_len < used_len) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_INODE_INT; snprintf(tsk_errstr, TSK_ERRSTR_L, "ntfs_dent_idxentry: Allocated length of index entries is larger than buffer length"); return 1; } /* where is the end of the buffer */ endaddr = ((uintptr_t) idxe + idxe_len); /* where is the end of the allocated data */ endaddr_alloc = ((uintptr_t) idxe + used_len); /* cycle through the index entries, based on provided size */ while (((uintptr_t) & (idxe->stream) + sizeof(ntfs_attr_fname)) < endaddr) { ntfs_attr_fname *fname = (ntfs_attr_fname *) & idxe->stream; if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: New IdxEnt: %" PRIu64 " $FILE_NAME Entry: %" PRIu64 " File Ref: %" PRIu64 " IdxEnt Len: %" PRIu16 " StrLen: %" PRIu16 "\n", (uint64_t) ((uintptr_t) idxe), (uint64_t) ((uintptr_t) fname), (uint64_t) tsk_getu48(fs->endian, idxe->file_ref), tsk_getu16(fs->endian, idxe->idxlen), tsk_getu16(fs->endian, idxe->strlen)); /* perform some sanity checks on index buffer head * and advance by 4-bytes if invalid */ if ((tsk_getu48(fs->endian, idxe->file_ref) > fs->last_inum) || (tsk_getu48(fs->endian, idxe->file_ref) < fs->first_inum) || (tsk_getu16(fs->endian, idxe->idxlen) <= tsk_getu16(fs->endian, idxe->strlen)) || (tsk_getu16(fs->endian, idxe->idxlen) % 4) || (tsk_getu16(fs->endian, idxe->idxlen) > idxe_len)) { idxe = (ntfs_idxentry *) ((uintptr_t) idxe + 4); continue; } /* do some sanity checks on the deleted entries */ if ((tsk_getu16(fs->endian, idxe->strlen) == 0) || (((uintptr_t) idxe + tsk_getu16(fs->endian, idxe->idxlen)) > endaddr_alloc)) { /* name space checks */ if ((fname->nspace != NTFS_FNAME_POSIX) && (fname->nspace != NTFS_FNAME_WIN32) && (fname->nspace != NTFS_FNAME_DOS) && (fname->nspace != NTFS_FNAME_WINDOS)) { idxe = (ntfs_idxentry *) ((uintptr_t) idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: Skipping because of invalid name space\n"); continue; } if ((tsk_getu64(fs->endian, fname->alloc_fsize) < tsk_getu64(fs->endian, fname->real_fsize)) || (fname->nlen == 0) || (*(uint8_t *) & fname->name == 0)) { idxe = (ntfs_idxentry *) ((uintptr_t) idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: Skipping because of reported file sizes, name length, or NULL name\n"); continue; } if ((is_time(tsk_getu64(fs->endian, fname->crtime)) == 0) || (is_time(tsk_getu64(fs->endian, fname->atime)) == 0) || (is_time(tsk_getu64(fs->endian, fname->mtime)) == 0)) { idxe = (ntfs_idxentry *) ((uintptr_t) idxe + 4); if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: Skipping because of invalid times\n"); continue; } } /* For all fname entries, there will exist a DOS style 8.3 * entry. We don't process those because we already processed * them before in their full version. If the type is * full POSIX or WIN32 that does not satisfy DOS, then a * type NTFS_FNAME_DOS will exist. If the name is WIN32, * but already satisfies DOS, then a type NTFS_FNAME_WINDOS * will exist * * Note that we could be missing some info from deleted files * if the windows version was deleted and the DOS wasn't... * * @@@ This should be added to the shrt_name entry of TSK_FS_DENT. The short * name entry typically comes after the long name */ if (fname->nspace == NTFS_FNAME_DOS) { if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: Skipping because of name space: %d\n", fname->nspace); goto incr_entry; } /* Copy it into the generic form */ if (ntfs_dent_copy(ntfs, dinfo, idxe, fs_dent)) { if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: Skipping because error copying dent_entry\n"); goto incr_entry; } /* * Check if this entry is deleted * * The final check is to see if the end of this entry is * within the space that the idxallocbuf claimed was valid */ if ((tsk_getu16(fs->endian, idxe->strlen) == 0) || (((uintptr_t) idxe + tsk_getu16(fs->endian, idxe->idxlen)) > endaddr_alloc)) { /* we know deleted entries with an inode of 0 are not legit because * that is the MFT value. Free it so it does not confuse * people with invalid data */ if ((fs_dent->inode == 0) && (fs_dent->fsi)) { tsk_fs_inode_free(fs_dent->fsi); fs_dent->fsi = NULL; } fs_dent->flags = TSK_FS_DENT_FLAG_UNALLOC; } else { fs_dent->flags = TSK_FS_DENT_FLAG_ALLOC; } if (tsk_verbose) tsk_fprintf(stderr, "ntfs_dent_idxentry: Entry Details of %s: Str Len: %" PRIu16 " Len to end after current: %" PRIu64 " flags: %x\n", fs_dent->name, tsk_getu16(fs->endian, idxe->strlen), (uint64_t) (endaddr_alloc - (uintptr_t) idxe - tsk_getu16(fs->endian, idxe->idxlen)), fs_dent->flags); if ((flags & fs_dent->flags) == fs_dent->flags) { int retval = action(fs, fs_dent, ptr); if (retval == TSK_WALK_STOP) { tsk_fs_dent_free(fs_dent); return 1; } else if (retval == TSK_WALK_ERROR) { tsk_fs_dent_free(fs_dent); return -1; } } /* Recurse if we need to */ if ((fs_dent->flags & TSK_FS_DENT_FLAG_ALLOC) && (flags & TSK_FS_DENT_FLAG_RECURSE) && (!TSK_FS_ISDOT(fs_dent->name)) && (fs_dent->fsi) && ((fs_dent->fsi->mode & TSK_FS_INODE_MODE_FMT) == TSK_FS_INODE_MODE_DIR) && (fs_dent->inode)) { int depth_added = 0; /* Make sure we do not get into an infinite loop */ if (0 == tsk_list_find(*list_seen, fs_dent->inode)) { if (tsk_list_add(list_seen, fs_dent->inode)) { tsk_fs_dent_free(fs_dent); return -1; } if ((dinfo->depth < MAX_DEPTH) && (DIR_STRSZ > strlen(dinfo->dirs) + strlen(fs_dent->name))) { dinfo->didx[dinfo->depth] = &dinfo->dirs[strlen(dinfo->dirs)]; strncpy(dinfo->didx[dinfo->depth], fs_dent->name, DIR_STRSZ - strlen(dinfo->dirs)); strncat(dinfo->dirs, "/", DIR_STRSZ); depth_added = 1; } dinfo->depth++; if (ntfs_dent_walk_lcl(&(ntfs->fs_info), dinfo, list_seen, fs_dent->inode, flags, action, ptr)) { if (tsk_verbose) tsk_fprintf(stderr, "Error recursing into directory\n"); tsk_error_reset(); } dinfo->depth--; if (depth_added) *dinfo->didx[dinfo->depth] = '\0'; } } /* end of recurse */ incr_entry: /* the theory here is that deleted entries have strlen == 0 and * have been found to have idxlen == 16 * * if the strlen is 0, then guess how much the indexlen was * before it was deleted */ /* 16: size of idxentry before stream * 66: size of fname before name * 2*nlen: size of name (in unicode) */ if (tsk_getu16(fs->endian, idxe->strlen) == 0) { idxe = (ntfs_idxentry *) ((((uintptr_t) idxe + 16 + 66 + 2 * fname->nlen + 3) / 4) * 4); } else { idxe = (ntfs_idxentry *) ((uintptr_t) idxe + tsk_getu16(fs->endian, idxe->idxlen)); } } /* end of loop of index entries */ tsk_fs_dent_free(fs_dent); return 0; }