From aa3c49bc5bc3f78cd0ac449e1949ca2d519fccd3 Mon Sep 17 00:00:00 2001 From: "cantab.net!aia21" Date: Fri, 9 Jan 2004 12:38:56 +0000 Subject: [PATCH] Patch from Matthew Fanto with fixups from me. (Logical change 1.259) --- ntfsprogs/ntfsinfo.c | 341 ++++++++++++++++++++++++++++++++++++------- 1 file changed, 288 insertions(+), 53 deletions(-) diff --git a/ntfsprogs/ntfsinfo.c b/ntfsprogs/ntfsinfo.c index 65932059..449779bb 100644 --- a/ntfsprogs/ntfsinfo.c +++ b/ntfsprogs/ntfsinfo.c @@ -1,8 +1,8 @@ /** * ntfsinfo - Part of the Linux-NTFS project. * - * Copyright (c) 2002 Matthew J. Fanto - * Copyright (c) 2002-2003 Anton Altaparmakov + * Copyright (c) 2002-2004 Matthew J. Fanto + * Copyright (c) 2002-2004 Anton Altaparmakov * Copyright (c) 2002-2003 Richard Russon * * This utility will dump a file's attributes. @@ -22,13 +22,34 @@ * distribution in the file COPYING); if not, write to the Free Software * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* TODO LIST: + * 1. Better error checking. In fact, my error checking sucks. + * 2. Fix output issues. + * 3. Check on the 72/48 issue + * 4. Comment things better + * + * Still not dumping certain attributes. Need to find the best + * way to output some of these attributes. + * + * Still need to do: + * $OBJECT_ID - dump correctly + * $SECURITY_DESCRIPTOR + */ + + + #include "config.h" #include #include +#include #include #include +#ifdef HAVE_ERRNO_H +#include +#endif + #include "types.h" #include "mft.h" #include "attrib.h" @@ -46,6 +67,7 @@ static struct options { int force; /* Override common sense */ int epochtime; /* Report all timestamps as "Thu Jan 1 00:00:00 1970" */ int notime; /* Don't report timestamps at all */ + int mft; /* Dump information about the volume as well */ } opts; GEN_PRINTF (Eprintf, stderr, NULL, FALSE) @@ -64,7 +86,7 @@ void version (void) printf ("\n%s v%s - Display information about an NTFS Volume.\n\n", EXEC_NAME, VERSION); printf ("Copyright (c)\n"); - printf (" 2002 Matthew J. Fanto\n"); + printf (" 2002-2004 Matthew J. Fanto\n"); printf (" 2002 Anton Altaparmakov\n"); printf (" 2002-2003 Richard Russon\n"); printf (" 2003 Leonard Norrgård\n"); @@ -83,6 +105,7 @@ void usage (void) printf ("\nUsage: %s [options] -d dev\n" " -d dev --device dev The ntfs volume to display information about\n" " -i num --inode num Display information about this inode\n" + " -m --mft Dump information about the volume\n" " -t --epochtime Report all timestamps as \"Thu Jan 1 00:00:00 1970\"\n" " -T --notime Don't report timestamps at all\n" "\n" @@ -117,6 +140,7 @@ int parse_options (int argc, char *argv[]) { "version", no_argument, NULL, 'V' }, { "epochtime", no_argument, NULL, 't' }, { "notime", no_argument, NULL, 'T' }, + { "mft", no_argument, NULL, 'm' }, { NULL, 0, NULL, 0 }, }; @@ -167,6 +191,9 @@ int parse_options (int argc, char *argv[]) case 'V': ver++; break; + case 'm': + opts.mft++; + break; default: if ((optopt == 'i') && (!optarg)) { Eprintf ("Option '%s' requires an argument.\n", argv[optind-1]); @@ -213,20 +240,135 @@ int parse_options (int argc, char *argv[]) } +/** + * ntfs_dump_volume - dump information about the volume + */ +void ntfs_dump_volume(ntfs_volume *vol) +{ + + printf("Volume Information \n"); + printf("\tName of device: %s\n", vol->dev->d_name); + printf("\tDevice state: %lu\n", vol->dev->d_state); + printf("\tVolume Name: %s\n", vol->vol_name); + printf("\tVolume State: %lu\n", vol->state); + printf("\tVolume Version: %u.%u\n", vol->major_ver, vol->minor_ver); + printf("\tSector Size: %hu\n", vol->sector_size); + printf("\tCluster Size: %u\n", vol->cluster_size); + printf("\tVolume Size in Clusters: %lld\n", vol->nr_clusters); + + + printf("MFT Information \n"); + printf("\tMFT Record Size: %u\n", vol->mft_record_size); + printf("\tMFT Zone Multiplier: %u\n", vol->mft_zone_multiplier); + printf("\tMFT Data Position: %lld\n", vol->mft_data_pos); + printf("\tMFT Zone Start: %lld\n", vol->mft_zone_start); + printf("\tMFT Zone End: %lld\n", vol->mft_zone_end); + printf("\tMFT Zone Position: %lld\n", vol->mft_zone_pos); + printf("\tCurrent Position in First Data Zone: %lld\n", vol->data1_zone_pos); + printf("\tCurrent Position in Second Data Zone: %lld\n", vol->data2_zone_pos); + printf("\tNumber of Records in MFT: %lld\n", vol->nr_mft_records); + printf("\tLCN of Data Attribute for FILE_MFT: %lld\n", vol->mft_lcn); + printf("\tFILE_MFTMirr Size: %d\n", vol->mftmirr_size); + printf("\tLCN of Data Attribute for File_MFTMirr: %lld\n", vol->mftmirr_lcn); + printf("\tSize of Attribute Definition Table: %d\n", vol->attrdef_len); + + + printf("FILE_Bitmap Information \n"); + printf("\tFILE_Bitmap MFT Record Number: %lld\n", vol->lcnbmp_ni->mft_no); + printf("\tState of FILE_Bitmap Inode: %lu\n", vol->lcnbmp_ni->state); + printf("\tLength of Attribute List: %u\n", vol->lcnbmp_ni->attr_list_size); + printf("\tAttribute List: %s\n", vol->lcnbmp_ni->attr_list); + printf("\tNumber of Attached Extent Inodes: %d\n", vol->lcnbmp_ni->nr_extents); + //FIXME: need to add code for the union if nr_extens != 0, but + //i dont know if it will ever != 0 with FILE_Bitmap + + printf("FILE_Bitmap Data Attribute Information\n"); + printf("\tDecompressed Runlist: not done yet\n"); + printf("\tBase Inode: %lld\n", vol->lcnbmp_na->ni->mft_no); + printf("\tAttribute Types: not done yet\n"); + //printf("\tAttribute Name: %s\n", vol->lcnbmp_na->name); + printf("\tAttribute Name Length: %u\n", vol->lcnbmp_na->name_len); + printf("\tAttribute State: %lu\n", vol->lcnbmp_na->state); + printf("\tAttribute Allocated Size: %lld\n", vol->lcnbmp_na->allocated_size); + printf("\tAttribute Data Size: %lld\n", vol->lcnbmp_na->data_size); + printf("\tAttribute Initialized Size: %lld\n", vol->lcnbmp_na->initialized_size); + printf("\tAttribute Compressed Size: %lld\n", vol->lcnbmp_na->compressed_size); + printf("\tCompression Block Size: %u\n", vol->lcnbmp_na->compression_block_size); + printf("\tCompression Block Size Bits: %u\n", vol->lcnbmp_na->compression_block_size_bits); + printf("\tCompression Block Clusters: %u\n", vol->lcnbmp_na->compression_block_clusters); + + + //TODO: Still need to add a few more attributes + +} + + + +/** + * ntfs_dump_standard_information + */ +void ntfs_dump_standard_information_attr(ntfs_inode *inode) +{ + + STANDARD_INFORMATION *standard_attr = NULL; + ATTR_RECORD *attr = NULL; + ntfs_attr_search_ctx *ctx = NULL; + + ctx = ntfs_attr_get_search_ctx(inode, NULL); + + if(ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + fprintf(stderr, "ntfsinfo error: cannot look up attribute AT_STANDARD_INFORMATION!\n"); + ntfs_attr_put_search_ctx(ctx); //free ctx + return; + } + + attr = ctx->attr; + + standard_attr = (STANDARD_INFORMATION*)((char *)attr + le16_to_cpu(attr->value_offset)); + + printf("Dumping $STANDARD_INFORMATION (0x10)\n"); + + //check with flatcap/anton and make sure this is correct + if (sizeof(STANDARD_INFORMATION) == 48) { + printf("\t$STANDARD_INFORMATION fields maximum_versions, version_number, \ + class_id, owner_id, security_id missing. This volume has \ + not been upgraded\n"); + } + if (sizeof(STANDARD_INFORMATION) == 72) { + printf("\tMaximum Number of Versions: \t %d \n", le32_to_cpu (standard_attr->maximum_versions)); + printf("\tVersion Number: \t\t %d \n", le32_to_cpu (standard_attr->version_number)); + printf("\tClass ID: \t\t\t %d \n", le32_to_cpu (standard_attr->class_id)); + printf("\tUser ID: \t\t\t %d \n", le32_to_cpu (standard_attr->owner_id)); + printf("\tSecurity ID: \t\t\t %d \n", le32_to_cpu (standard_attr->security_id)); + } + + else { + printf("\tSize of STANDARD_INFORMATION is %d. It should be either 72 or 48, \ + something is wrong...\n",sizeof(STANDARD_INFORMATION)); + } + + + ntfs_attr_put_search_ctx(ctx); //free ctx + +} + + + /** * ntfs_dump_file_name_attribute */ -void ntfs_dump_file_name_attribute(ntfs_inode *inode, MFT_RECORD *mrec) +void ntfs_dump_file_name_attr(ntfs_inode *inode) { FILE_NAME_ATTR *file_name_attr = NULL; ATTR_RECORD *attr = NULL; ntfs_attr_search_ctx *ctx = NULL; char *file_name = NULL; - ctx = ntfs_attr_get_search_ctx(inode, mrec); + ctx = ntfs_attr_get_search_ctx(inode, NULL); if(ntfs_attr_lookup(AT_FILE_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { fprintf(stderr, "ntfsinfo error: cannot lookup attribute AT_FILE_NAME!\n"); + ntfs_attr_put_search_ctx(ctx); //free ctx return; } @@ -241,94 +383,187 @@ void ntfs_dump_file_name_attribute(ntfs_inode *inode, MFT_RECORD *mrec) printf("Dumping $FILE_NAME (0x30)\n"); //basic stuff about the file - printf("File Name: \t\t %s\n",file_name); - printf("File Name Length: \t %d\n",file_name_attr->file_name_length); - printf("Allocated File Size: \t %lld\n", sle64_to_cpu(file_name_attr->allocated_size)); - printf("Real File Size: \t %lld\n", sle64_to_cpu(file_name_attr->data_size)); + printf("\tFile Name: \t\t %s\n",file_name); + printf("\tFile Name Length: \t %d\n",file_name_attr->file_name_length); + printf("\tAllocated File Size: \t %lld\n", sle64_to_cpu(file_name_attr->allocated_size)); + printf("\tReal File Size: \t %lld\n", sle64_to_cpu(file_name_attr->data_size)); //time conversion stuff if (!opts.notime) { time_t ntfs_time = { 0 }; - + if (!opts.epochtime) { ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->creation_time)); - printf("File Creation Time: \t %s",ctime(&ntfs_time)); + printf("\tFile Creation Time: \t %s",ctime(&ntfs_time)); ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->last_data_change_time)); - printf("File Altered Time: \t %s",ctime(&ntfs_time)); + printf("\tFile Altered Time: \t %s",ctime(&ntfs_time)); ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->last_mft_change_time)); - printf("MFT Changed Time: \t %s",ctime(&ntfs_time)); + printf("\tMFT Changed Time: \t %s",ctime(&ntfs_time)); ntfs_time = ntfs2utc (sle64_to_cpu (file_name_attr->last_access_time)); - printf("Last Accessed Time: \t %s",ctime(&ntfs_time)); + printf("\tLast Accessed Time: \t %s",ctime(&ntfs_time)); } else { char *t = asctime(gmtime(&ntfs_time)); - - printf("File Creation Time: \t %s",t); - printf("File Altered Time: \t %s",t); - printf("MFT Changed Time: \t %s",t); - printf("Last Accessed Time: \t %s",t); + printf("\tFile Creation Time: \t %s",t); + printf("\tFile Altered Time: \t %s",t); + printf("\tMFT Changed Time: \t %s",t); + printf("\tLast Accessed Time: \t %s",t); } } + free(file_name); + ntfs_attr_put_search_ctx(ctx); //free ctx } -/** - * ntfs_dump_standard_information + +/* + * ntfs_dump_object_id + * + * dump the $OBJECT_ID attribute - not present on all systems + * */ -void ntfs_dump_standard_information(ntfs_inode *inode, MFT_RECORD *mrec) +void ntfs_dump_object_id_attr(ntfs_inode *inode) { + + OBJECT_ID_ATTR *obj_id_attr = NULL; + ATTR_RECORD *attr = NULL; + ntfs_attr_search_ctx *ctx = NULL; - STANDARD_INFORMATION *standard_attr = NULL; - ATTR_RECORD *attr = NULL; - ntfs_attr_search_ctx *ctx = NULL; + ctx = ntfs_attr_get_search_ctx(inode, NULL); - ctx = ntfs_attr_get_search_ctx(inode, mrec); + if(ntfs_attr_lookup(AT_OBJECT_ID, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + fprintf(stderr, "ntfsinfo error: cannot look up attribute AT_OBJECT_ID: %s\n", + strerror(errno)); + ntfs_attr_put_search_ctx(ctx); + return; + } - if(ntfs_attr_lookup(AT_STANDARD_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { - fprintf(stderr, "ntfsinfo error: cannot look up attribute AT_STANDARD_INFORMATION!\n"); - return; - } + attr = ctx->attr; - attr = ctx->attr; + obj_id_attr = (OBJECT_ID_ATTR*)((char *)attr + le16_to_cpu(attr->value_offset)); //the attribute plus the offset - standard_attr = (STANDARD_INFORMATION*)((char *)attr + le16_to_cpu(attr->value_offset)); + printf("Dumping $OBJECT_ID (0x40)\n"); - printf("Dumping $STANDARD_INFORMATION (0x10)\n"); + //I believe these attributes are only present on volume versions > 3.0. It was introduced + //in Win2k, which is 3.0 - printf("Maximum Number of Versions: \t %d \n", le32_to_cpu (standard_attr->maximum_versions)); - printf("Version Number: \t\t %d \n", le32_to_cpu (standard_attr->version_number)); - printf("Class ID: \t\t\t %d \n", le32_to_cpu (standard_attr->class_id)); - printf("User ID: \t\t\t %d \n", le32_to_cpu (standard_attr->owner_id)); - printf("Security ID: \t\t\t %d \n", le32_to_cpu (standard_attr->security_id)); + //FIXME: Need to do a check to make sure these attributes are actually present + //even if it is > 3.0. + if (inode->vol->major_ver >= 3.0) { + printf("\tVolume Version > 3.0... Dumping Attributes\n"); + + //printf("\tObject ID: \t\t\t %d\n", obj_id_attr->object_id); + //printf("\tBirth Volume ID: \t\t\t %d\n", obj_id_attr->birth_volume_id); + //printf("\tBirth Object ID: \t\t\t %d\n", obj_id_attr->birth_object_id); + } + else + printf("\t$OBJECT_ID not present. Only NTFS versions > 3.0 have $OBJECT_ID. \ + Your version of NTFS is %d\n", inode->vol->major_ver); + + ntfs_attr_put_search_ctx(ctx); } + +/* + * ntfs_dump_volume_name() + * + * dump the name of the volume the inode belongs to + * + */ +void ntfs_dump_volume_name_attr(ntfs_inode *inode) +{ + VOLUME_NAME *vol_name = NULL; + ATTR_RECORD *attr = NULL; + ntfs_attr_search_ctx *ctx = NULL; + + ctx = ntfs_attr_get_search_ctx(inode, NULL); + + if(ntfs_attr_lookup(AT_VOLUME_NAME, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + fprintf(stderr, "ntfsinfo error: cannot look up attribute AT_VOLUME_NAME: %s\n", + strerror(errno)); + ntfs_attr_put_search_ctx(ctx); + return; + } + + attr = ctx->attr; + + vol_name = (VOLUME_NAME*)((char *)attr + le16_to_cpu(attr->value_offset)); + + printf("Dumping $VOLUME_NAME (0x60)\n"); + + //printf("\tVolume Name: \t\t\t %s\n", vol_name->name); + + ntfs_attr_put_search_ctx(ctx); +} + + +/* + * ntfs_dump_volume_information() + * + * dump the information for the volume the inode belongs to + * + */ +void ntfs_dump_volume_information_attr(ntfs_inode *inode) +{ + VOLUME_INFORMATION *vol_information = NULL; + ATTR_RECORD *attr = NULL; + ntfs_attr_search_ctx *ctx = NULL; + + ctx = ntfs_attr_get_search_ctx(inode, NULL); + + if(ntfs_attr_lookup(AT_VOLUME_INFORMATION, AT_UNNAMED, 0, 0, 0, NULL, 0, ctx)) { + fprintf(stderr, "ntfsinfo error: cannot look up attribute AT_VOLUME_INFORMATION: %s\n", + strerror(errno)); + ntfs_attr_put_search_ctx(ctx); + return; + } + + attr = ctx->attr; + + vol_information = (VOLUME_INFORMATION*)((char *)attr + le16_to_cpu(attr->value_offset)); + + printf("Dumping $VOLUME_INFORMATION (0x70)\n"); + + printf("\tVolume Major Version: \t\t\t %d\n", vol_information->major_ver); + printf("\tVolume Minor Version: \t\t\t %d\n", vol_information->minor_ver); + printf("\tFlags: \t\t\t Not Finished Yet! \n"); + + ntfs_attr_put_search_ctx(ctx); +} + + + /** * ntfs_get_file_attributes */ -void ntfs_get_file_attributes(ntfs_volume *vol, s64 i) +void ntfs_get_file_attributes(ntfs_volume *vol, s64 mft_no, int dump_volume) { - MFT_REF mref; - MFT_RECORD *mrec = NULL; - //ntfs_attr_search_ctx *ctx = NULL; ntfs_inode *inode = NULL; //int error; - mref = (MFT_REF) i; - inode = ntfs_inode_open(vol, mref); + inode = ntfs_inode_open(vol, MK_MREF(mft_no, 0)); - if (ntfs_file_record_read(vol, mref, &mrec, NULL)) { - fprintf(stderr, "ntfsinfo error: error reading file record!\n"); - exit(1); - } + /* if opts.mft is not 0, then we will print out information about + * the volume, such as the sector size and whatnot. + */ +// if (dump_volume) + ntfs_dump_volume(vol); - //see flatcap.org/ntfs/info for what formatting should look like - //ntfs_dump_boot_sector_information(inode, mrec); - ntfs_dump_file_name_attribute(inode, mrec); - ntfs_dump_standard_information(inode, mrec); + + //see flatcap.org/ntfs/info for what formatting should look likei + //FIXME: both $FILE_NAME_ATTR and $STANDARD_INFORMATION has times, when do + //we want to output it? + ntfs_dump_standard_information_attr(inode); + ntfs_dump_file_name_attr(inode); + ntfs_dump_object_id_attr(inode); + ntfs_dump_volume_name_attr(inode); + ntfs_dump_volume_information_attr(inode); + + ntfs_inode_close(inode); } /** @@ -352,7 +587,7 @@ int main(int argc, char **argv) if (!vol) return 1; - ntfs_get_file_attributes (vol, opts.inode); + ntfs_get_file_attributes (vol, opts.inode, opts.mft); ntfs_umount (vol, FALSE); return 0;