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; }
/* * * NoTe that this does not set the flag value. * * return 1 on error and 0 on success */ static uint8_t ext2fs_dent_copy(EXT2FS_INFO * ext2fs, EXT2FS_DINFO * dinfo, char *ext2_dent, TSK_FS_DENT * fs_dent) { TSK_FS_INFO *fs = &(ext2fs->fs_info); int i; if (ext2fs->deentry_type == EXT2_DE_V1) { ext2fs_dentry1 *dir = (ext2fs_dentry1 *) ext2_dent; fs_dent->inode = tsk_getu32(fs->endian, dir->inode); /* ext2 does not null terminate */ if (tsk_getu16(fs->endian, dir->name_len) >= fs_dent->name_max) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2fs_dent_copy: Name Space too Small %d %lu", tsk_getu16(fs->endian, dir->name_len), fs_dent->name_max); return 1; } /* Copy and Null Terminate */ strncpy(fs_dent->name, dir->name, tsk_getu16(fs->endian, dir->name_len)); fs_dent->name[tsk_getu16(fs->endian, dir->name_len)] = '\0'; fs_dent->ent_type = TSK_FS_DENT_TYPE_UNDEF; } else { ext2fs_dentry2 *dir = (ext2fs_dentry2 *) ext2_dent; fs_dent->inode = tsk_getu32(fs->endian, dir->inode); /* ext2 does not null terminate */ if (dir->name_len >= fs_dent->name_max) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "ext2_dent_copy: Name Space too Small %d %lu", dir->name_len, fs_dent->name_max); return 1; } /* Copy and Null Terminate */ strncpy(fs_dent->name, dir->name, dir->name_len); fs_dent->name[dir->name_len] = '\0'; switch (dir->type) { case EXT2_DE_REG_FILE: fs_dent->ent_type = TSK_FS_DENT_TYPE_REG; break; case EXT2_DE_DIR: fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR; break; case EXT2_DE_CHRDEV: fs_dent->ent_type = TSK_FS_DENT_TYPE_CHR; break; case EXT2_DE_BLKDEV: fs_dent->ent_type = TSK_FS_DENT_TYPE_BLK; break; case EXT2_DE_FIFO: fs_dent->ent_type = TSK_FS_DENT_TYPE_FIFO; break; case EXT2_DE_SOCK: fs_dent->ent_type = TSK_FS_DENT_TYPE_SOCK; break; case EXT2_DE_SYMLINK: fs_dent->ent_type = TSK_FS_DENT_TYPE_LNK; break; case EXT2_DE_UNKNOWN: default: fs_dent->ent_type = TSK_FS_DENT_TYPE_UNDEF; break; } } /* Clean up name */ i = 0; while (fs_dent->name[i] != '\0') { if (TSK_IS_CNTRL(fs_dent->name[i])) fs_dent->name[i] = '^'; i++; } fs_dent->path = dinfo->dirs; fs_dent->pathdepth = dinfo->depth; if ((fs != NULL) && (fs_dent->inode) && (fs_dent->inode <= fs->last_inum)) { /* Get inode */ if (fs_dent->fsi) tsk_fs_inode_free(fs_dent->fsi); if ((fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode)) == NULL) { strncat(tsk_errstr2, " - ext2fs_dent_copy", TSK_ERRSTR_L - strlen(tsk_errstr2)); return 1; } } else { if (fs_dent->fsi) tsk_fs_inode_free(fs_dent->fsi); fs_dent->fsi = NULL; } fs_dent->flags = 0; return 0; }
/* * Process the contents of a directory and add them to FS_DIR. * * @param fatfs File system information structure * @param a_fs_dir Structure to store the files in. * @param list_seen List of directory inodes that have been seen thus far in * directory walking (can be a pointer to a NULL pointer on first call). * @param buf Buffer that contains the directory contents. * @param len Length of buffer in bytes (must be a multiple of sector size) * @param addrs Array where each element is the original address of the * corresponding block in buf (size of array is number of blocks in directory). * * @return -1 on error, 0 on success, and 1 to stop */ static TSK_RETVAL_ENUM fatfs_dent_parse_buf(FATFS_INFO * fatfs, TSK_FS_DIR * a_fs_dir, char *buf, TSK_OFF_T len, TSK_DADDR_T * addrs) { unsigned int idx, sidx; int a, b; TSK_INUM_T inode, ibase; fatfs_dentry *dep; TSK_FS_INFO *fs = (TSK_FS_INFO *) & fatfs->fs_info; int sectalloc; TSK_FS_NAME *fs_name; FATFS_LFN lfninfo; if (buf == NULL) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_dent_parse_buf: buffer is NULL"); return TSK_ERR; } dep = (fatfs_dentry *) buf; if ((fs_name = tsk_fs_name_alloc(FATFS_MAXNAMLEN_UTF8, 32)) == NULL) { return TSK_ERR; } memset(&lfninfo, 0, sizeof(FATFS_LFN)); lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; for (sidx = 0; sidx < (unsigned int) (len / fatfs->ssize); sidx++) { /* Get the base inode for this sector */ ibase = FATFS_SECT_2_INODE(fatfs, addrs[sidx]); if (ibase > fs->last_inum) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_ARG; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_parse: inode address is too large"); tsk_fs_name_free(fs_name); return TSK_COR; } if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Parsing sector %" PRIuDADDR "\n", addrs[sidx]); if ((sectalloc = fatfs_is_sectalloc(fatfs, addrs[sidx])) == -1) { if (tsk_verbose) { tsk_fprintf(stderr, "fatfs_dent_parse_buf: Error looking up sector allocation: %" PRIuDADDR "\n", addrs[sidx]); tsk_error_print(stderr); } tsk_error_reset(); continue; } /* cycle through the directory entries */ for (idx = 0; idx < fatfs->dentry_cnt_se; idx++, dep++) { fatfs_dentry *dir; int i; /* is it a valid dentry? */ if (0 == fatfs_isdentry(fatfs, dep)) { if (tsk_verbose) tsk_fprintf(stderr, "fatfs_dent_parse_buf: Entry %u is invalid\n", idx); continue; } /* Copy the directory entry into the TSK_FS_NAME structure */ dir = (fatfs_dentry *) dep; inode = ibase + idx; /* Take care of the name * Copy a long name to a buffer and take action if it * is a small name */ if ((dir->attrib & FATFS_ATTR_LFN) == FATFS_ATTR_LFN) { fatfs_dentry_lfn *dirl = (fatfs_dentry_lfn *) dir; /* Store the name in dinfo until we get the 8.3 name * Use the checksum to identify a new sequence * */ if (((dirl->seq & FATFS_LFN_SEQ_FIRST) && (dirl->seq != FATFS_SLOT_DELETED)) || (dirl->chksum != lfninfo.chk)) { // @@@ Do a partial output here /* Reset the values */ lfninfo.seq = dirl->seq & FATFS_LFN_SEQ_MASK; lfninfo.chk = dirl->chksum; lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; } else if (dirl->seq != lfninfo.seq - 1) { // @@@ Check the sequence number - the checksum is correct though... } /* Copy the UTF16 values starting at end of buffer */ for (a = 3; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part3[a]; } for (a = 11; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part2[a]; } for (a = 9; a >= 0; a--) { if ((lfninfo.start > 0)) lfninfo.name[lfninfo.start--] = dirl->part1[a]; } // Skip ahead until we get a new sequence num or the 8.3 name continue; } /* Special case for volume label: name does not have an * extension and we add a note at the end that it is a label */ else if ((dir->attrib & FATFS_ATTR_VOLUME) == FATFS_ATTR_VOLUME) { a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] >= 0x20) && (dir->name[b] != 0xff)) { fs_name->name[a++] = dir->name[b]; } else { fs_name->name[a++] = '^'; } } for (b = 0; b < 3; b++) { if ((dir->ext[b] >= 0x20) && (dir->ext[b] != 0xff)) { fs_name->name[a++] = dir->ext[b]; } else { fs_name->name[a++] = '^'; } } fs_name->name[a] = '\0'; /* Append a string to show it is a label */ if (a + 22 < FATFS_MAXNAMLEN_UTF8) { char *volstr = " (Volume Label Entry)"; strncat(fs_name->name, volstr, FATFS_MAXNAMLEN_UTF8 - a); } } /* A short (8.3) entry */ else { char *name_ptr; // The dest location for the short name /* if we have a lfn, copy it into fs_name->name * and put the short name in fs_name->shrt_name */ if (lfninfo.start != FATFS_MAXNAMLEN_UTF8 - 1) { int retVal; /* @@@ Check the checksum */ /* Convert the UTF16 to UTF8 */ UTF16 *name16 = (UTF16 *) ((uintptr_t) & lfninfo.name[lfninfo. start + 1]); UTF8 *name8 = (UTF8 *) fs_name->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) & lfninfo.name[FATFS_MAXNAMLEN_UTF8], &name8, (UTF8 *) ((uintptr_t) name8 + FATFS_MAXNAMLEN_UTF8), TSKlenientConversion); if (retVal != TSKconversionOK) { tsk_error_reset(); tsk_errno = TSK_ERR_FS_UNICODE; snprintf(tsk_errstr, TSK_ERRSTR_L, "fatfs_parse: Error converting FAT LFN to UTF8: %d", retVal); continue; } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_name->name + FATFS_MAXNAMLEN_UTF8) fs_name->name[FATFS_MAXNAMLEN_UTF8 - 1] = '\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++; } lfninfo.start = FATFS_MAXNAMLEN_UTF8 - 1; name_ptr = fs_name->shrt_name; // put 8.3 into shrt_name } /* We don't have a LFN, so put the short name in * fs_name->name */ else { fs_name->shrt_name[0] = '\0'; name_ptr = fs_name->name; // put 8.3 into normal location } /* copy in the short name into the place specified above. * Skip spaces and put in the . */ a = 0; for (b = 0; b < 8; b++) { if ((dir->name[b] != 0) && (dir->name[b] != 0xff) && (dir->name[b] != 0x20)) { if ((b == 0) && (dir->name[0] == FATFS_SLOT_DELETED)) { name_ptr[a++] = '_'; } else if ((dir->lowercase & FATFS_CASE_LOWER_BASE) && (dir->name[b] >= 'A') && (dir->name[b] <= 'Z')) { name_ptr[a++] = dir->name[b] + 32; } else { name_ptr[a++] = dir->name[b]; } } } for (b = 0; b < 3; b++) { if ((dir->ext[b] != 0) && (dir->ext[b] != 0xff) && (dir->ext[b] != 0x20)) { if (b == 0) name_ptr[a++] = '.'; if ((dir->lowercase & FATFS_CASE_LOWER_EXT) && (dir->ext[b] >= 'A') && (dir->ext[b] <= 'Z')) name_ptr[a++] = dir->ext[b] + 32; else name_ptr[a++] = dir->ext[b]; } } name_ptr[a] = '\0'; } /* Clean up name to remove control chars */ i = 0; while (fs_name->name[i] != '\0') { if (TSK_IS_CNTRL(fs_name->name[i])) fs_name->name[i] = '^'; i++; } /* file type: FAT only knows DIR and FILE */ if ((dir->attrib & FATFS_ATTR_DIRECTORY) == FATFS_ATTR_DIRECTORY) fs_name->type = TSK_FS_NAME_TYPE_DIR; else fs_name->type = TSK_FS_NAME_TYPE_REG; /* Get inode */ fs_name->meta_addr = inode; /* Handle the . and .. entries specially * The current inode 'address' they have is for the current * slot in the cluster, but it needs to refer to the original * slot */ if (TSK_FS_ISDOT(fs_name->name)) { if (fs_name->name[1] == '\0') { inode = fs_name->meta_addr = a_fs_dir->fs_file->meta->addr; } /* for the parent directory, look up in the list that * is maintained in fafs_info */ else if (fs_name->name[1] == '.') { size_t q; uint8_t dir_found = 0; for (q = 0; q < fatfs->dir_buf_next; q++) { if (fatfs->dir_buf[q] == a_fs_dir->fs_file->meta->addr) { inode = fs_name->meta_addr = fatfs->par_buf[q]; dir_found = 1; break; } } if ((dir_found == 0) && (fs->isOrphanHunting)) { /* if we are currently scanning the fs to determine the orphan files, * then we do not care about the value of '..' and this can only cause * infinite loop problems */ inode = fs_name->meta_addr = 0; dir_found = 1; } if ((dir_found == 0) && (addrs[0] == fatfs->firstdatasect)) { /* if we are currently in the root directory, we aren't going to find * a parent. This shouldn't happen, but could result in an infinite loop. */ inode = fs_name->meta_addr = 0; dir_found = 1; } if (dir_found == 0) { /* The parent directory is not in the list. We are going to walk * the directory until we hit this directory. This process will * populate the buffer table and we will then rescan it */ if (tsk_fs_dir_walk(fs, fs->root_inum, TSK_FS_DIR_WALK_FLAG_ALLOC | TSK_FS_DIR_WALK_FLAG_UNALLOC | TSK_FS_DIR_WALK_FLAG_RECURSE, find_parent_act, (void *) &a_fs_dir->fs_file->meta->addr)) { return 0; } for (q = 0; q < fatfs->dir_buf_next; q++) { if (fatfs->dir_buf[q] == a_fs_dir->fs_file->meta->addr) { inode = fs_name->meta_addr = fatfs->par_buf[q]; dir_found = 1; break; } } // if we did not find it, then it was probably // from the orphan directory... if (dir_found == 0) inode = fs_name->meta_addr = TSK_FS_ORPHANDIR_INUM(fs); } } } else { /* Save the (non-. or ..) directory to parent directory info to local * structures so that we can later fill into the inode * info for '..' entries */ if (fs_name->type == TSK_FS_NAME_TYPE_DIR) { if (fatfs_dir_buf_add(fatfs, a_fs_dir->fs_file->meta->addr, inode)) return TSK_ERR; } } /* The allocation status of an entry is based on the allocation * status of the sector it is in and the flag. Deleted directories * do not always clear the flags of each entry */ if (sectalloc == 1) { fs_name->flags = (dep->name[0] == FATFS_SLOT_DELETED) ? TSK_FS_NAME_FLAG_UNALLOC : TSK_FS_NAME_FLAG_ALLOC; } else { fs_name->flags = TSK_FS_NAME_FLAG_UNALLOC; } tsk_fs_dir_add(a_fs_dir, fs_name); } } tsk_fs_name_free(fs_name); return TSK_OK; }
/* * copy the index (directory) entry into the generic structure * * uses the global variables 'dirs' and 'depth' * * Returns 1 on eror and 0 on success */ static uint8_t ntfs_dent_copy(NTFS_INFO * ntfs, NTFS_DINFO * dinfo, ntfs_idxentry * idxe, TSK_FS_DENT * fs_dent) { 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_dent->inode = tsk_getu48(fs->endian, idxe->file_ref); name16 = (UTF16 *) & fname->name; name8 = (UTF8 *) fs_dent->name; retVal = tsk_UTF16toUTF8(fs->endian, (const UTF16 **) &name16, (UTF16 *) ((uintptr_t) name16 + fname->nlen * 2), &name8, (UTF8 *) ((uintptr_t) name8 + fs_dent->name_max), TSKlenientConversion); if (retVal != TSKconversionOK) { *name8 = '\0'; if (tsk_verbose) tsk_fprintf(stderr, "Error converting NTFS name to UTF8: %d %" PRIuINUM, retVal, fs_dent->inode); } /* Make sure it is NULL Terminated */ if ((uintptr_t) name8 > (uintptr_t) fs_dent->name + fs_dent->name_max) fs_dent->name[fs_dent->name_max] = '\0'; else *name8 = '\0'; /* Clean up name */ i = 0; while (fs_dent->name[i] != '\0') { if (TSK_IS_CNTRL(fs_dent->name[i])) fs_dent->name[i] = '^'; i++; } /* copy the path data */ fs_dent->path = dinfo->dirs; fs_dent->pathdepth = dinfo->depth; /* Get the actual inode */ if (fs_dent->fsi != NULL) tsk_fs_inode_free(fs_dent->fsi); if (NULL == (fs_dent->fsi = fs->inode_lookup(fs, fs_dent->inode))) { if (tsk_verbose) { tsk_fprintf(stderr, "ntfs_dent_copy: error looking up inode: %" PRIuINUM "\n", fs_dent->inode); tsk_error_print(stderr); tsk_error_reset(); } } if (tsk_getu64(fs->endian, fname->flags) & NTFS_FNAME_FLAGS_DIR) fs_dent->ent_type = TSK_FS_DENT_TYPE_DIR; else fs_dent->ent_type = TSK_FS_DENT_TYPE_REG; fs_dent->flags = 0; return 0; }
/** * \internal * ** Print output in the format that mactime reads. ** ** If the flags in the fs_file->meta structure are set to FS_FLAG_ALLOC ** then it is assumed that the inode has been reallocated and the ** contents are not displayed ** ** fs is not required (only used for block size). * @param hFile handle to print results to * @param fs_file File to print details about * @param a_path Parent directory of file (needs to end with "/") * @param fs_attr Attribute in file that is being called for (NULL for non-NTFS) * @param prefix Path of mounting point for image * @param time_skew number of seconds skew to adjust time */ void tsk_fs_name_print_mac(FILE * hFile, const TSK_FS_FILE * fs_file, const char *a_path, const TSK_FS_ATTR * fs_attr, const char *prefix, int32_t time_skew) { char ls[12]; size_t i; uint8_t isADS = 0; if ((!hFile) || (!fs_file)) return; /* see if we are going to be printing the name of the attribute * We don't do it for FNAME attributes, which we handle specially below. */ if ((fs_attr) && (fs_attr->name) && (fs_attr->type != TSK_FS_ATTR_TYPE_NTFS_FNAME) && ((fs_attr->type != TSK_FS_ATTR_TYPE_NTFS_IDXROOT) || (strcmp(fs_attr->name, "$I30") != 0))) { isADS = 1; } /* md5 */ tsk_fprintf(hFile, "0|"); /* file name */ tsk_fprintf(hFile, "%s", prefix); // remove any control chars as we print the names if (a_path != NULL) { for (i = 0; i < strlen(a_path); i++) { if (TSK_IS_CNTRL(a_path[i])) tsk_fprintf(hFile, "^"); else tsk_fprintf(hFile, "%c", a_path[i]); } } for (i = 0; i < strlen(fs_file->name->name); i++) { if (TSK_IS_CNTRL(fs_file->name->name[i])) tsk_fprintf(hFile, "^"); else tsk_fprintf(hFile, "%c", fs_file->name->name[i]); } /* print the data stream name if it exists and is not the default NTFS */ if (isADS) { tsk_fprintf(hFile, ":"); for (i = 0; i < strlen(fs_attr->name); i++) { if (TSK_IS_CNTRL(fs_attr->name[i])) tsk_fprintf(hFile, "^"); else tsk_fprintf(hFile, "%c", fs_attr->name[i]); } } // special label if FNAME if ((fs_attr) && (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_FNAME)) { tsk_fprintf(hFile, " ($FILE_NAME)"); } if ((fs_file->meta) && (fs_file->meta->type == TSK_FS_META_TYPE_LNK) && (fs_file->meta->link)) { tsk_fprintf(hFile, " -> %s", fs_file->meta->link); } /* if filename is deleted add a comment and if the inode is now * allocated, then add realloc comment */ if (fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC) tsk_fprintf(hFile, " (deleted%s)", ((fs_file->meta) && (fs_file-> meta->flags & TSK_FS_META_FLAG_ALLOC)) ? "-realloc" : ""); /* inode */ tsk_fprintf(hFile, "|%" PRIuINUM, fs_file->name->meta_addr); if (fs_attr) tsk_fprintf(hFile, "-%" PRIu32 "-%" PRIu16 "", fs_attr->type, fs_attr->id); tsk_fprintf(hFile, "|"); /* TYPE as specified in the directory entry */ if (fs_file->name->type < TSK_FS_NAME_TYPE_STR_MAX) tsk_fprintf(hFile, "%s/", tsk_fs_name_type_str[fs_file->name->type]); else tsk_fprintf(hFile, "-/"); if (!fs_file->meta) { tsk_fprintf(hFile, "----------|0|0|0|"); } else { /* mode as string */ tsk_fs_meta_make_ls(fs_file->meta, ls, sizeof(ls)); tsk_fprintf(hFile, "%s|", ls); /* uid, gid */ tsk_fprintf(hFile, "%" PRIuUID "|%" PRIuGID "|", fs_file->meta->uid, fs_file->meta->gid); /* size - use data stream if we have it */ if (fs_attr) tsk_fprintf(hFile, "%" PRIuOFF "|", fs_attr->size); else tsk_fprintf(hFile, "%" PRIuOFF "|", fs_file->meta->size); } if (!fs_file->meta) { tsk_fprintf(hFile, "0|0|0|0\n"); } else { // special case for NTFS FILE_NAME attribute if ((fs_attr) && (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_FNAME)) { /* atime, mtime, ctime, crtime */ if (fs_file->meta->time2.ntfs.fn_atime) tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->time2.ntfs.fn_atime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->time2.ntfs.fn_atime); if (fs_file->meta->time2.ntfs.fn_mtime) tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->time2.ntfs.fn_mtime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->time2.ntfs.fn_mtime); if (fs_file->meta->time2.ntfs.fn_ctime) tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->time2.ntfs.fn_ctime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->time2.ntfs.fn_ctime); if (fs_file->meta->time2.ntfs.fn_crtime) tsk_fprintf(hFile, "%" PRIu32 "\n", fs_file->meta->time2.ntfs.fn_crtime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "\n", fs_file->meta->time2.ntfs.fn_crtime); } else { /* atime, mtime, ctime, crtime */ if (fs_file->meta->atime) tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->atime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->atime); if (fs_file->meta->mtime) tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->mtime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->mtime); if (fs_file->meta->ctime) tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->ctime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "|", fs_file->meta->ctime); if (fs_file->meta->crtime) tsk_fprintf(hFile, "%" PRIu32 "\n", fs_file->meta->crtime - time_skew); else tsk_fprintf(hFile, "%" PRIu32 "\n", fs_file->meta->crtime); } } }
/** * \internal * Simple print of dentry type / inode type, deleted, inode, and * name * * fs_attr is used for alternate data streams in NTFS, set to NULL * for all other file systems * * A newline is not printed at the end * * If path is NULL, then skip else use. it has the full directory name * It needs to end with "/" */ void tsk_fs_name_print(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) { size_t i; /* type of file - based on dentry type */ if (fs_file->name->type < TSK_FS_NAME_TYPE_STR_MAX) tsk_fprintf(hFile, "%s/", tsk_fs_name_type_str[fs_file->name->type]); else tsk_fprintf(hFile, "-/"); /* type of file - based on inode type: we want letters though for * regular files so we use the dent_str though */ if (fs_file->meta) { /* * An NTFS directory can have a Data stream, in which * case it would be printed with modes of a * directory, although it is really a file * So, to avoid confusion we will set the modes * to a file so it is printed that way. The * entry for the directory itself will still be * printed as a directory */ if ((fs_attr) && (fs_attr->type == TSK_FS_ATTR_TYPE_NTFS_DATA) && (fs_file->meta->type == TSK_FS_META_TYPE_DIR)) { tsk_fprintf(hFile, "r "); } else { if (fs_file->meta->type < TSK_FS_META_TYPE_STR_MAX) tsk_fprintf(hFile, "%s ", tsk_fs_meta_type_str[fs_file->meta->type]); else tsk_fprintf(hFile, "- "); } } else { tsk_fprintf(hFile, "- "); } /* print a * if it is deleted */ if (fs_file->name->flags & TSK_FS_NAME_FLAG_UNALLOC) tsk_fprintf(hFile, "* "); tsk_fprintf(hFile, "%" PRIuINUM "", fs_file->name->meta_addr); /* print the id and type if we have fs_attr (NTFS) */ if (fs_attr) tsk_fprintf(hFile, "-%" PRIu32 "-%" PRIu16 "", fs_attr->type, fs_attr->id); tsk_fprintf(hFile, "%s:\t", ((fs_file->meta) && (fs_file->meta->flags & TSK_FS_META_FLAG_ALLOC) && (fs_file-> name->flags & TSK_FS_NAME_FLAG_UNALLOC)) ? "(realloc)" : ""); if ((print_path) && (a_path != NULL)) { for (i = 0; i < strlen(a_path); i++) { if (TSK_IS_CNTRL(a_path[i])) tsk_fprintf(hFile, "^"); else tsk_fprintf(hFile, "%c", a_path[i]); } } for (i = 0; i < strlen(fs_file->name->name); i++) { if (TSK_IS_CNTRL(fs_file->name->name[i])) tsk_fprintf(hFile, "^"); else tsk_fprintf(hFile, "%c", fs_file->name->name[i]); } /* This will add the short name in parentheses if (fs_file->name->shrt_name != NULL && fs_file->name->shrt_name[0] != '\0') tsk_fprintf(hFile, " (%s)", fs_file->name->shrt_name); */ /* print the data stream name if we the non-data NTFS stream */ if ((fs_attr) && (fs_attr->name)) { if ((fs_attr->type != TSK_FS_ATTR_TYPE_NTFS_IDXROOT) || (strcmp(fs_attr->name, "$I30") != 0)) { tsk_fprintf(hFile, ":"); for (i = 0; i < strlen(fs_attr->name); i++) { if (TSK_IS_CNTRL(fs_attr->name[i])) tsk_fprintf(hFile, "^"); else tsk_fprintf(hFile, "%c", fs_attr->name[i]); } } } return; }