diff --git a/ntfsprogs/ntfscat.8.in b/ntfsprogs/ntfscat.8.in index 5227beb5..253e4e34 100644 --- a/ntfsprogs/ntfscat.8.in +++ b/ntfsprogs/ntfscat.8.in @@ -32,13 +32,48 @@ is equivalent to .BR "\-f \-v" . Long named options can be abbreviated to any unique prefix of their name. .TP -.B \-f +.B "\-a " desc .br .ns .TP -.B \-\-force -This will override some sensible defaults, such as not working with a mounted -volume. Use this option with caution. +.B "\-\-attribute " desc +Display the contents of a particular attribute. By default, the unname $DATA +attribute will be shown. The attribute can be specified by number (in decimal +or hexadecimal), or by name. +.TS +lB lB lB +l l l. +Hex Decimal Name +0x10 16 "$STANDARD_INFORMATION", +0x20 32 "$ATTRIBUTE_LIST", +0x30 48 "$FILE_NAME", +0x40 64 "$OBJECT_ID", +0x50 80 "$SECURITY_DESCRIPTOR", +0x60 96 "$VOLUME_NAME", +0x70 112 "$VOLUME_INFORMATION", +0x80 128 "$DATA", +0x90 144 "$INDEX_ROOT", +0xA0 160 "$INDEX_ALLOCATION", +0xB0 176 "$BITMAP", +0xC0 192 "$REPARSE_POINT", +0xD0 208 "$EA_INFORMATION", +0xE0 224 "$EA", +0xF0 240 "$PROPERTY_SET", +0x100 256 "$LOGGED_UTILITY_STREAM", +.TE +.br +.B Notes +.br +The attribute names may be given without the leading $ symbol. +.br +If you use the $ symbol, you must escape it from the shell. +.TP +.B "\-i " num +.br +.ns +.TP +.B "\-\-inode " num +Specify a file by its inode number instead of its name. .TP .B \-h .br @@ -66,7 +101,7 @@ Show the version number, copyright and license .br .ns .TP -.B \-\-vebose +.B \-\-verbose Display more debug/warning/error messages. .SH EXAMPLES Display the contents of a file in the root of an NTFS volume. @@ -79,6 +114,14 @@ Display the contents of a file in a subdirectory of an NTFS volume. .RS .sp .B ntfscat /dev/hda1 /winnt/system32/drivers/etc/hosts +.RE +.sp +Display the contents of the $INDEX_ROOT attribute of the root directory (inode +5). +.RS +.sp +.B ntfscat /dev/hda1 \-a INDEX_ROOT \-i 5 | hexdump \-C +.RE .SH BUGS .B ntfscat was written in a short time, to get something "out there". It needs a lot more work. diff --git a/ntfsprogs/ntfscat.c b/ntfsprogs/ntfscat.c index 5bae325f..6f977424 100644 --- a/ntfsprogs/ntfscat.c +++ b/ntfsprogs/ntfscat.c @@ -1,8 +1,8 @@ /** * ntfscat - Part of the Linux-NTFS project. * - * Copyright (c) 2003 Richard Russon - * Copyright (c) 2003 Anton Altaparmakov + * Copyright (c) 2003-2005 Richard Russon + * Copyright (c) 2003 Anton Altaparmakov * * This utility will concatenate files and print on the standard output. * @@ -70,7 +70,7 @@ static void version (void) static void usage (void) { Printf ("\nUsage: %s [options] device [file]\n\n" - " -a, --attribute num Display this attribute\n" + " -a, --attribute desc Display this attribute (name or number)\n" " -i, --inode num Display this inode\n\n" " -f --force Use less caution\n" " -h --help Print this help\n" @@ -84,6 +84,60 @@ static void usage (void) Printf ("%s%s\n", ntfs_bugs, ntfs_home); } +/** + * parse_attribute - Read an attribute name, or number + * @value: String to be parsed + * @attr: Resulting attribute id (on success) + * + * Read a string representing an attribute. It may be a decimal, octal or + * hexadecimal number, or the attribute name in full. The leading $ sign is + * optional. + * + * Return: 1 Success, a valid attribute name or number + * 0 Error, not an attribute name or number + */ +static int parse_attribute (const char *value, ATTR_TYPES *attr) +{ + static const char *attr_name[] = { + "$STANDARD_INFORMATION", + "$ATTRIBUTE_LIST", + "$FILE_NAME", + "$OBJECT_ID", + "$SECURITY_DESCRIPTOR", + "$VOLUME_NAME", + "$VOLUME_INFORMATION", + "$DATA", + "$INDEX_ROOT", + "$INDEX_ALLOCATION", + "$BITMAP", + "$REPARSE_POINT", + "$EA_INFORMATION", + "$EA", + "$PROPERTY_SET", + "$LOGGED_UTILITY_STREAM", + NULL + }; + + int i; + long num; + + for (i = 0; attr_name[i]; i++) { + if ((strcmp (value, attr_name[i]) == 0) || + (strcmp (value, attr_name[i]+1) == 0)) { + *attr = (ATTR_TYPES) ((i+1)*16); + return 1; + } + } + + num = strtol (value, NULL, 0); + if ((num > 0) && (num < 257)) { + *attr = (ATTR_TYPES) num; + return 1; + } + + return 0; +} + /** * parse_options - Read and validate the programs command line * @@ -113,7 +167,7 @@ static int parse_options (int argc, char **argv) int err = 0; int ver = 0; int help = 0; - s64 attr; + ATTR_TYPES attr = AT_UNUSED; opterr = 0; /* We'll handle the errors, thank you. */ @@ -133,16 +187,16 @@ static int parse_options (int argc, char **argv) } break; case 'a': - if (opts.attr != (ATTR_TYPES)-1) + if (opts.attr != (ATTR_TYPES)-1) { Eprintf("You must specify exactly one attribute.\n"); - else if (utils_parse_size(optarg, &attr, FALSE)) { - opts.attr = (ATTR_TYPES)attr; + } else if (parse_attribute (optarg, &attr) > 0) { + opts.attr = attr; break; - } else - Eprintf("Couldn't parse attribute number.\n"); + } else { + Eprintf("Couldn't parse attribute.\n"); + } err++; break; - case 'f': opts.force++; break; @@ -207,19 +261,42 @@ static int parse_options (int argc, char **argv) return (!err && !help && !ver); } +/** + * index_get_size - Find the INDX block size from the index root + * @inode: Inode of the directory to be checked + * + * Find the size of a directory's INDX block from the INDEX_ROOT attribute. + * + * Return: n Success, the INDX blocks are n bytes in size + * 0 Error, not a directory + */ +static int index_get_size (ntfs_inode *inode) +{ + ATTR_RECORD *attr90; + INDEX_ROOT *iroot; + + attr90 = find_first_attribute (AT_INDEX_ROOT, inode->mrec); + if (!attr90) + return 0; // not a directory + + iroot = (INDEX_ROOT*)((u8*)attr90 + le16_to_cpu(attr90->value_offset)); + + return iroot->index_block_size; +} + /** * cat */ -static int cat (ntfs_volume *vol __attribute__((unused)), ntfs_inode *inode, - ATTR_TYPES type, ntfschar *name __attribute__((unused)), +static int cat (ntfs_volume *vol, ntfs_inode *inode, ATTR_TYPES type, + ntfschar *name __attribute__((unused)), int namelen __attribute__((unused))) { - /* increase 1024 only if you fix partial writes below */ - const int bufsize = 1024; + const int bufsize = 4096; char *buffer; ntfs_attr *attr; s64 bytes_read, written; s64 offset; + u32 block_size; buffer = malloc (bufsize); if (!buffer) @@ -227,14 +304,28 @@ static int cat (ntfs_volume *vol __attribute__((unused)), ntfs_inode *inode, attr = ntfs_attr_open (inode, type, NULL, 0); if (!attr) { - Eprintf ("Cannot cat a directory.\n"); + Eprintf ("Cannot find attribute type 0x%lx.\n", (long) type); free (buffer); return 1; } + if ((inode->mft_no < 2) && (attr->type == AT_DATA)) + block_size = vol->mft_record_size; + else if (attr->type == AT_INDEX_ALLOCATION) + block_size = index_get_size (inode); + else + block_size = 0; + offset = 0; for (;;) { - bytes_read = ntfs_attr_pread (attr, offset, bufsize, buffer); + if (block_size > 0) { + // These types have fixup + bytes_read = ntfs_attr_mst_pread(attr, offset, 1, block_size, buffer); + bytes_read *= block_size; + } else { + bytes_read = ntfs_attr_pread (attr, offset, bufsize, buffer); + } + //fprintf (stderr, "read %lld bytes\n", bytes_read); if (bytes_read == -1) { perror ("ERROR: Couldn't read file"); break; @@ -275,8 +366,6 @@ int main (int argc, char *argv[]) utils_set_locale(); - //XXX quieten errors, temporarily - vol = utils_mount_volume (opts.device, MS_RDONLY, opts.force); if (!vol) { perror("ERROR: couldn't mount volume"); @@ -301,12 +390,8 @@ int main (int argc, char *argv[]) ntfs_inode_close (inode); ntfs_umount (vol, FALSE); -#if 0 - if (result) - Printf ("failed\n"); - else - Printf ("success\n"); -#endif + return result; } +