Ejemplo n.º 1
0
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);
}
Ejemplo n.º 2
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 (&current_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;
}
Ejemplo n.º 3
0
// @@@ 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;
}
Ejemplo n.º 4
0
/**
 * 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;
}