ntfsinfo.c revision 9663:ace9a2ac3683
1/** 2 * ntfsinfo - Part of the Linux-NTFS project. 3 * 4 * Copyright (c) 2002-2004 Matthew J. Fanto 5 * Copyright (c) 2002-2006 Anton Altaparmakov 6 * Copyright (c) 2002-2005 Richard Russon 7 * Copyright (c) 2003-2006 Szabolcs Szakacsits 8 * Copyright (c) 2004-2005 Yuval Fledel 9 * Copyright (c) 2004-2007 Yura Pakhuchiy 10 * Copyright (c) 2005 Cristian Klein 11 * 12 * This utility will dump a file's attributes. 13 * 14 * This program is free software; you can redistribute it and/or modify 15 * it under the terms of the GNU General Public License as published by 16 * the Free Software Foundation; either version 2 of the License, or 17 * (at your option) any later version. 18 * 19 * This program is distributed in the hope that it will be useful, 20 * but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * GNU General Public License for more details. 23 * 24 * You should have received a copy of the GNU General Public License 25 * along with this program (in the main directory of the Linux-NTFS 26 * distribution in the file COPYING); if not, write to the Free Software 27 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 28 */ 29/* 30 * TODO LIST: 31 * - Better error checking. (focus on ntfs_dump_volume) 32 * - Comment things better. 33 * - More things at verbose mode. 34 * - Dump ACLs when security_id exists (NTFS 3+ only). 35 * - Clean ups. 36 * - Internationalization. 37 * - Add more Indexed Attr Types. 38 * - Make formatting look more like www.flatcap.org/ntfs/info 39 * 40 * Still not dumping certain attributes. Need to find the best 41 * way to output some of these attributes. 42 * 43 * Still need to do: 44 * $REPARSE_POINT/$SYMBOLIC_LINK 45 * $LOGGED_UTILITY_STREAM 46 */ 47 48#include "config.h" 49 50#ifdef HAVE_STDIO_H 51#include <stdio.h> 52#endif 53#ifdef HAVE_STDLIB_H 54#include <stdlib.h> 55#endif 56#ifdef HAVE_STRING_H 57#include <string.h> 58#endif 59#ifdef HAVE_TIME_H 60#include <time.h> 61#endif 62#ifdef HAVE_GETOPT_H 63#include <getopt.h> 64#endif 65#ifdef HAVE_ERRNO_H 66#include <errno.h> 67#endif 68 69#include "types.h" 70#include "mft.h" 71#include "attrib.h" 72#include "layout.h" 73#include "inode.h" 74#include "index.h" 75#include "utils.h" 76#include "security.h" 77#include "mst.h" 78#include "dir.h" 79#include "ntfstime.h" 80#include "version.h" 81#include "support.h" 82 83static const char *EXEC_NAME = "ntfsinfo"; 84 85static struct options { 86 const char *device; /* Device/File to work with */ 87 const char *filename; /* Resolve this filename to mft number */ 88 s64 inode; /* Info for this inode */ 89 int debug; /* Debug output */ 90 int quiet; /* Less output */ 91 int verbose; /* Extra output */ 92 int force; /* Override common sense */ 93 int notime; /* Don't report timestamps at all */ 94 int mft; /* Dump information about the volume as well */ 95} opts; 96 97/** 98 * version - Print version information about the program 99 * 100 * Print a copyright statement and a brief description of the program. 101 * 102 * Return: none 103 */ 104static void version(void) 105{ 106 printf("\n%s v%s (libntfs %s) - Display information about an NTFS " 107 "Volume.\n\n", EXEC_NAME, VERSION, 108 ntfs_libntfs_version()); 109 printf("Copyright (c)\n"); 110 printf(" 2002-2004 Matthew J. Fanto\n"); 111 printf(" 2002-2006 Anton Altaparmakov\n"); 112 printf(" 2002-2005 Richard Russon\n"); 113 printf(" 2003-2006 Szabolcs Szakacsits\n"); 114 printf(" 2003 Leonard Norrg��rd\n"); 115 printf(" 2004-2005 Yuval Fledel\n"); 116 printf(" 2004-2007 Yura Pakhuchiy\n"); 117 printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); 118} 119 120/** 121 * usage - Print a list of the parameters to the program 122 * 123 * Print a list of the parameters and options for the program. 124 * 125 * Return: none 126 */ 127static void usage(void) 128{ 129 printf("\nUsage: %s [options] device\n" 130 " -i, --inode NUM Display information about this inode\n" 131 " -F, --file FILE Display information about this file (absolute path)\n" 132 " -m, --mft Dump information about the volume\n" 133 " -t, --notime Don't report timestamps\n" 134 "\n" 135 " -f, --force Use less caution\n" 136 " -q, --quiet Less output\n" 137 " -v, --verbose More output\n" 138 " -V, --version Display version information\n" 139 " -h, --help Display this help\n" 140#ifdef DEBUG 141 " -d, --debug Show debug information\n" 142#endif 143 "\n", 144 EXEC_NAME); 145 printf("%s%s\n", ntfs_bugs, ntfs_home); 146} 147 148/** 149 * parse_options - Read and validate the programs command line 150 * 151 * Read the command line, verify the syntax and parse the options. 152 * This function is very long, but quite simple. 153 * 154 * Return: 1 Success 155 * 0 Error, one or more problems 156 */ 157static int parse_options(int argc, char *argv[]) 158{ 159 static const char *sopt = "-:dfhi:F:mqtTvV"; 160 static const struct option lopt[] = { 161#ifdef DEBUG 162 { "debug", no_argument, NULL, 'd' }, 163#endif 164 { "force", no_argument, NULL, 'f' }, 165 { "help", no_argument, NULL, 'h' }, 166 { "inode", required_argument, NULL, 'i' }, 167 { "file", required_argument, NULL, 'F' }, 168 { "quiet", no_argument, NULL, 'q' }, 169 { "verbose", no_argument, NULL, 'v' }, 170 { "version", no_argument, NULL, 'V' }, 171 { "notime", no_argument, NULL, 'T' }, 172 { "mft", no_argument, NULL, 'm' }, 173 { NULL, 0, NULL, 0 } 174 }; 175 176 int c = -1; 177 int err = 0; 178 int ver = 0; 179 int help = 0; 180 int levels = 0; 181 182 opterr = 0; /* We'll handle the errors, thank you. */ 183 184 opts.inode = -1; 185 opts.filename = NULL; 186 187 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { 188 switch (c) { 189 case 1: 190 if (!opts.device) 191 opts.device = optarg; 192 else 193 err++; 194 break; 195 case 'd': 196 opts.debug++; 197 break; 198 case 'i': 199 if ((opts.inode != -1) || 200 (!utils_parse_size(optarg, &opts.inode, FALSE))) { 201 err++; 202 } 203 break; 204 case 'F': 205 if (opts.filename == NULL) { 206 /* The inode can not be resolved here, 207 store the filename */ 208 opts.filename = argv[optind-1]; 209 } else { 210 /* "-F" can't appear more than once */ 211 err++; 212 } 213 break; 214 case 'f': 215 opts.force++; 216 break; 217 case 'h': 218 help++; 219 break; 220 case 'q': 221 opts.quiet++; 222 ntfs_log_clear_levels(NTFS_LOG_LEVEL_QUIET); 223 break; 224 case 't': 225 opts.notime++; 226 break; 227 case 'T': 228 /* 'T' is deprecated, notify */ 229 ntfs_log_error("Option 'T' is deprecated, it was " 230 "replaced by 't'.\n"); 231 err++; 232 break; 233 case 'v': 234 opts.verbose++; 235 ntfs_log_set_levels(NTFS_LOG_LEVEL_VERBOSE); 236 break; 237 case 'V': 238 ver++; 239 break; 240 case 'm': 241 opts.mft++; 242 break; 243 case '?': 244 if (optopt=='?') { 245 help++; 246 continue; 247 } 248 if (ntfs_log_parse_option(argv[optind-1])) 249 continue; 250 ntfs_log_error("Unknown option '%s'.\n", 251 argv[optind-1]); 252 err++; 253 break; 254 case ':': 255 ntfs_log_error("Option '%s' requires an " 256 "argument.\n", argv[optind-1]); 257 err++; 258 break; 259 default: 260 ntfs_log_error("Unhandled option case: %d.\n", c); 261 err++; 262 break; 263 } 264 } 265 266 /* Make sure we're in sync with the log levels */ 267 levels = ntfs_log_get_levels(); 268 if (levels & NTFS_LOG_LEVEL_VERBOSE) 269 opts.verbose++; 270 if (!(levels & NTFS_LOG_LEVEL_QUIET)) 271 opts.quiet++; 272 273 if (help || ver) { 274 opts.quiet = 0; 275 } else { 276 if (opts.device == NULL) { 277 if (argc > 1) 278 ntfs_log_error("You must specify exactly one " 279 "device.\n"); 280 err++; 281 } 282 283 if ((opts.inode == -1) && (opts.filename == NULL) && !opts.mft) { 284 if (argc > 1) 285 ntfs_log_error("You must specify an inode to " 286 "learn about.\n"); 287 err++; 288 } 289 290 if (opts.quiet && opts.verbose) { 291 ntfs_log_error("You may not use --quiet and --verbose " 292 "at the same time.\n"); 293 err++; 294 } 295 296 if ((opts.inode != -1) && (opts.filename != NULL)) { 297 if (argc > 1) 298 ntfs_log_error("You may not specify --inode " 299 "and --file together.\n"); 300 err++; 301 } 302 303 } 304 305#ifdef DEBUG 306 if (!opts.debug) 307 if (!freopen("/dev/null", "w", stderr)) { 308 ntfs_log_perror("Failed to freopen stderr to /dev/null"); 309 exit(1); 310 } 311#endif 312 313 if (ver) 314 version(); 315 if (help || err) 316 usage(); 317 318 return (!err && !help && !ver); 319} 320 321 322/* *************** utility functions ******************** */ 323/** 324 * ntfsinfo_time_to_str() - 325 * @sle_ntfs_clock: on disk time format in 100ns units since 1st jan 1601 326 * in little-endian format 327 * 328 * Return char* in a format 'Thu Jan 1 00:00:00 1970'. 329 * No need to free the returned memory. 330 * 331 * Example of usage: 332 * char *time_str = ntfsinfo_time_to_str( 333 * sle64_to_cpu(standard_attr->creation_time)); 334 * printf("\tFile Creation Time:\t %s", time_str); 335 */ 336static char *ntfsinfo_time_to_str(const sle64 sle_ntfs_clock) 337{ 338 time_t unix_clock = ntfs2utc(sle_ntfs_clock); 339 return ctime(&unix_clock); 340} 341 342/** 343 * ntfs_attr_get_name() 344 * @attr: a valid attribute record 345 * 346 * return multi-byte string containing the attribute name if exist. the user 347 * is then responsible of freeing that memory. 348 * null if no name exists (attr->name_length==0). no memory allocated. 349 * null if cannot convert to multi-byte string. errno would contain the 350 * error id. no memory allocated in that case 351 */ 352static char *ntfs_attr_get_name_mbs(ATTR_RECORD *attr) 353{ 354 ntfschar *ucs_attr_name; 355 char *mbs_attr_name = NULL; 356 int mbs_attr_name_size; 357 358 /* Get name in unicode. */ 359 ucs_attr_name = ntfs_attr_get_name(attr); 360 /* Convert unicode to printable format. */ 361 mbs_attr_name_size = ntfs_ucstombs(ucs_attr_name, attr->name_length, 362 &mbs_attr_name, 0); 363 if (mbs_attr_name_size > 0) 364 return mbs_attr_name; 365 else 366 return NULL; 367} 368 369 370/* *************** functions for dumping global info ******************** */ 371/** 372 * ntfs_dump_volume - dump information about the volume 373 */ 374static void ntfs_dump_volume(ntfs_volume *vol) 375{ 376 printf("Volume Information \n"); 377 printf("\tName of device: %s\n", vol->u.dev->d_name); 378 printf("\tDevice state: %lu\n", vol->u.dev->d_state); 379 printf("\tVolume Name: %s\n", vol->vol_name); 380 printf("\tVolume State: %lu\n", vol->state); 381 printf("\tVolume Version: %u.%u\n", vol->major_ver, vol->minor_ver); 382 printf("\tSector Size: %hu\n", vol->sector_size); 383 printf("\tCluster Size: %u\n", (unsigned int)vol->cluster_size); 384 printf("\tVolume Size in Clusters: %lld\n", 385 (long long)vol->nr_clusters); 386 387 printf("MFT Information \n"); 388 printf("\tMFT Record Size: %u\n", (unsigned int)vol->mft_record_size); 389 printf("\tMFT Zone Multiplier: %u\n", vol->mft_zone_multiplier); 390 printf("\tMFT Data Position: %lld\n", (long long)vol->mft_data_pos); 391 printf("\tMFT Zone Start: %lld\n", (long long)vol->mft_zone_start); 392 printf("\tMFT Zone End: %lld\n", (long long)vol->mft_zone_end); 393 printf("\tMFT Zone Position: %lld\n", (long long)vol->mft_zone_pos); 394 printf("\tCurrent Position in First Data Zone: %lld\n", 395 (long long)vol->data1_zone_pos); 396 printf("\tCurrent Position in Second Data Zone: %lld\n", 397 (long long)vol->data2_zone_pos); 398 printf("\tLCN of Data Attribute for FILE_MFT: %lld\n", 399 (long long)vol->mft_lcn); 400 printf("\tFILE_MFTMirr Size: %d\n", vol->mftmirr_size); 401 printf("\tLCN of Data Attribute for File_MFTMirr: %lld\n", 402 (long long)vol->mftmirr_lcn); 403 printf("\tSize of Attribute Definition Table: %d\n", 404 (int)vol->attrdef_len); 405 406 printf("FILE_Bitmap Information \n"); 407 printf("\tFILE_Bitmap MFT Record Number: %llu\n", 408 (unsigned long long)vol->lcnbmp_ni->mft_no); 409 printf("\tState of FILE_Bitmap Inode: %lu\n", vol->lcnbmp_ni->state); 410 printf("\tLength of Attribute List: %u\n", 411 (unsigned int)vol->lcnbmp_ni->attr_list_size); 412 printf("\tAttribute List: %s\n", vol->lcnbmp_ni->attr_list); 413 printf("\tNumber of Attached Extent Inodes: %d\n", 414 (int)vol->lcnbmp_ni->nr_extents); 415 /* FIXME: need to add code for the union if nr_extens != 0, but 416 i dont know if it will ever != 0 with FILE_Bitmap */ 417 418 printf("FILE_Bitmap Data Attribute Information\n"); 419 printf("\tDecompressed Runlist: not done yet\n"); 420 printf("\tBase Inode: %llu\n", 421 (unsigned long long)vol->lcnbmp_na->ni->mft_no); 422 printf("\tAttribute Types: not done yet\n"); 423 //printf("\tAttribute Name: %s\n", vol->lcnbmp_na->name); 424 printf("\tAttribute Name Length: %u\n", 425 (unsigned int)vol->lcnbmp_na->name_len); 426 printf("\tAttribute State: %lu\n", vol->lcnbmp_na->state); 427 printf("\tAttribute Allocated Size: %lld\n", 428 (long long)vol->lcnbmp_na->allocated_size); 429 printf("\tAttribute Data Size: %lld\n", 430 (long long)vol->lcnbmp_na->data_size); 431 printf("\tAttribute Initialized Size: %lld\n", 432 (long long)vol->lcnbmp_na->initialized_size); 433 printf("\tAttribute Compressed Size: %lld\n", 434 (long long)vol->lcnbmp_na->compressed_size); 435 printf("\tCompression Block Size: %u\n", 436 (unsigned int)vol->lcnbmp_na->compression_block_size); 437 printf("\tCompression Block Size Bits: %u\n", 438 vol->lcnbmp_na->compression_block_size_bits); 439 printf("\tCompression Block Clusters: %u\n", 440 vol->lcnbmp_na->compression_block_clusters); 441 442 //TODO: Still need to add a few more attributes 443} 444 445/** 446 * ntfs_dump_flags - Dump flags for STANDARD_INFORMATION and FILE_NAME. 447 * @type: dump flags for this attribute type 448 * @flags: flags for dumping 449 */ 450static void ntfs_dump_flags(const char *indent, ATTR_TYPES type, le32 flags) 451{ 452 printf("%sFile attributes:\t", indent); 453 if (flags & FILE_ATTR_READONLY) { 454 printf(" READONLY"); 455 flags &= ~FILE_ATTR_READONLY; 456 } 457 if (flags & FILE_ATTR_HIDDEN) { 458 printf(" HIDDEN"); 459 flags &= ~FILE_ATTR_HIDDEN; 460 } 461 if (flags & FILE_ATTR_SYSTEM) { 462 printf(" SYSTEM"); 463 flags &= ~FILE_ATTR_SYSTEM; 464 } 465 if (flags & FILE_ATTR_DIRECTORY) { 466 printf(" DIRECTORY"); 467 flags &= ~FILE_ATTR_DIRECTORY; 468 } 469 if (flags & FILE_ATTR_ARCHIVE) { 470 printf(" ARCHIVE"); 471 flags &= ~FILE_ATTR_ARCHIVE; 472 } 473 if (flags & FILE_ATTR_DEVICE) { 474 printf(" DEVICE"); 475 flags &= ~FILE_ATTR_DEVICE; 476 } 477 if (flags & FILE_ATTR_NORMAL) { 478 printf(" NORMAL"); 479 flags &= ~FILE_ATTR_NORMAL; 480 } 481 if (flags & FILE_ATTR_TEMPORARY) { 482 printf(" TEMPORARY"); 483 flags &= ~FILE_ATTR_TEMPORARY; 484 } 485 if (flags & FILE_ATTR_SPARSE_FILE) { 486 printf(" SPARSE_FILE"); 487 flags &= ~FILE_ATTR_SPARSE_FILE; 488 } 489 if (flags & FILE_ATTR_REPARSE_POINT) { 490 printf(" REPARSE_POINT"); 491 flags &= ~FILE_ATTR_REPARSE_POINT; 492 } 493 if (flags & FILE_ATTR_COMPRESSED) { 494 printf(" COMPRESSED"); 495 flags &= ~FILE_ATTR_COMPRESSED; 496 } 497 if (flags & FILE_ATTR_OFFLINE) { 498 printf(" OFFLINE"); 499 flags &= ~FILE_ATTR_OFFLINE; 500 } 501 if (flags & FILE_ATTR_NOT_CONTENT_INDEXED) { 502 printf(" NOT_CONTENT_INDEXED"); 503 flags &= ~FILE_ATTR_NOT_CONTENT_INDEXED; 504 } 505 if (flags & FILE_ATTR_ENCRYPTED) { 506 printf(" ENCRYPTED"); 507 flags &= ~FILE_ATTR_ENCRYPTED; 508 } 509 /* We know that FILE_ATTR_I30_INDEX_PRESENT only exists on $FILE_NAME, 510 and in case we are wrong, let it appear as UNKNOWN */ 511 if (type == AT_FILE_NAME) { 512 if (flags & FILE_ATTR_I30_INDEX_PRESENT) { 513 printf(" I30_INDEX"); 514 flags &= ~FILE_ATTR_I30_INDEX_PRESENT; 515 } 516 } 517 if (flags & FILE_ATTR_VIEW_INDEX_PRESENT) { 518 printf(" VIEW_INDEX"); 519 flags &= ~FILE_ATTR_VIEW_INDEX_PRESENT; 520 } 521 if (flags) 522 printf(" UNKNOWN: 0x%08x", (unsigned int)le32_to_cpu(flags)); 523 /* Print all the flags in hex. */ 524 printf(" (0x%08x)\n", (unsigned)le32_to_cpu(flags)); 525} 526 527/** 528 * ntfs_dump_namespace 529 */ 530static void ntfs_dump_namespace(const char *indent, u8 file_name_type) 531{ 532 const char *mbs_file_type; 533 534 /* name space */ 535 switch (file_name_type) { 536 case FILE_NAME_POSIX: 537 mbs_file_type = "POSIX"; 538 break; 539 case FILE_NAME_WIN32: 540 mbs_file_type = "Win32"; 541 break; 542 case FILE_NAME_DOS: 543 mbs_file_type = "DOS"; 544 break; 545 case FILE_NAME_WIN32_AND_DOS: 546 mbs_file_type = "Win32 & DOS"; 547 break; 548 default: 549 mbs_file_type = "(unknown)"; 550 } 551 printf("%sNamespace:\t\t %s\n", indent, mbs_file_type); 552} 553 554/* *************** functions for dumping attributes ******************** */ 555/** 556 * ntfs_dump_standard_information 557 */ 558static void ntfs_dump_attr_standard_information(ATTR_RECORD *attr) 559{ 560 STANDARD_INFORMATION *standard_attr = NULL; 561 u32 value_length; 562 563 standard_attr = (STANDARD_INFORMATION*)((char *)attr + 564 le16_to_cpu(attr->u.res.value_offset)); 565 566 /* time conversion stuff */ 567 if (!opts.notime) { 568 char *ntfs_time_str = NULL; 569 570 ntfs_time_str = ntfsinfo_time_to_str(standard_attr->creation_time); 571 printf("\tFile Creation Time:\t %s",ntfs_time_str); 572 573 ntfs_time_str = ntfsinfo_time_to_str( 574 standard_attr->last_data_change_time); 575 printf("\tFile Altered Time:\t %s",ntfs_time_str); 576 577 ntfs_time_str = ntfsinfo_time_to_str( 578 standard_attr->last_mft_change_time); 579 printf("\tMFT Changed Time:\t %s",ntfs_time_str); 580 581 ntfs_time_str = ntfsinfo_time_to_str(standard_attr->last_access_time); 582 printf("\tLast Accessed Time:\t %s",ntfs_time_str); 583 } 584 ntfs_dump_flags("\t", attr->type, standard_attr->file_attributes); 585 586 value_length = le32_to_cpu(attr->u.res.value_length); 587 if (value_length == 48) { 588 /* Only 12 reserved bytes here */ 589 } else if (value_length == 72) { 590 printf("\tMaximum versions:\t %u \n", (unsigned int) 591 le32_to_cpu(standard_attr->u.v30.maximum_versions)); 592 printf("\tVersion number:\t\t %u \n", (unsigned int) 593 le32_to_cpu(standard_attr->u.v30.version_number)); 594 printf("\tClass ID:\t\t %u \n", 595 (unsigned int)le32_to_cpu(standard_attr->u.v30.class_id)); 596 printf("\tUser ID:\t\t %u (0x%x)\n", 597 (unsigned int)le32_to_cpu(standard_attr->u.v30.owner_id), 598 (unsigned int)le32_to_cpu(standard_attr->u.v30.owner_id)); 599 printf("\tSecurity ID:\t\t %u (0x%x)\n", 600 (unsigned int)le32_to_cpu(standard_attr->u.v30.security_id), 601 (unsigned int)le32_to_cpu(standard_attr->u.v30.security_id)); 602 printf("\tQuota charged:\t\t %llu (0x%llx)\n", 603 (unsigned long long) 604 le64_to_cpu(standard_attr->u.v30.quota_charged), 605 (unsigned long long) 606 le64_to_cpu(standard_attr->u.v30.quota_charged)); 607 printf("\tUpdate Sequence Number:\t %llu (0x%llx)\n", 608 (unsigned long long) 609 le64_to_cpu(standard_attr->u.v30.usn), 610 (unsigned long long) 611 le64_to_cpu(standard_attr->u.v30.usn)); 612 } else { 613 printf("\tSize of STANDARD_INFORMATION is %u (0x%x). It " 614 "should be either 72 or 48, something is " 615 "wrong...\n", (unsigned int)value_length, 616 (unsigned)value_length); 617 } 618} 619 620static void ntfs_dump_bytes(u8 *buf, int start, int stop) 621{ 622 int i; 623 624 for (i = start; i < stop; i++) { 625 printf("%02x ", buf[i]); 626 } 627} 628 629/** 630 * ntfs_dump_attr_list() 631 */ 632static void ntfs_dump_attr_list(ATTR_RECORD *attr, ntfs_volume *vol) 633{ 634 ATTR_LIST_ENTRY *entry; 635 u8 *value; 636 s64 l; 637 638 if (!opts.verbose) 639 return; 640 641 l = ntfs_get_attribute_value_length(attr); 642 if (!l) { 643 ntfs_log_perror("ntfs_get_attribute_value_length failed"); 644 return; 645 } 646 value = ntfs_malloc(l); 647 if (!value) 648 return; 649 650 l = ntfs_get_attribute_value(vol, attr, value); 651 if (!l) { 652 ntfs_log_perror("ntfs_get_attribute_value failed"); 653 free(value); 654 return; 655 } 656 printf("\tDumping attribute list:"); 657 entry = (ATTR_LIST_ENTRY *) value; 658 for (;(u8 *)entry < (u8 *) value + l; entry = (ATTR_LIST_ENTRY *) 659 ((u8 *) entry + le16_to_cpu(entry->length))) { 660 printf("\n"); 661 printf("\t\tAttribute type:\t0x%x\n", 662 (unsigned int)le32_to_cpu(entry->type)); 663 printf("\t\tRecord length:\t%u (0x%x)\n", 664 (unsigned)le16_to_cpu(entry->length), 665 (unsigned)le16_to_cpu(entry->length)); 666 printf("\t\tName length:\t%u (0x%x)\n", 667 (unsigned)entry->name_length, 668 (unsigned)entry->name_length); 669 printf("\t\tName offset:\t%u (0x%x)\n", 670 (unsigned)entry->name_offset, 671 (unsigned)entry->name_offset); 672 printf("\t\tStarting VCN:\t%lld (0x%llx)\n", 673 (long long)sle64_to_cpu(entry->lowest_vcn), 674 (unsigned long long) 675 sle64_to_cpu(entry->lowest_vcn)); 676 printf("\t\tMFT reference:\t%lld (0x%llx)\n", 677 (unsigned long long) 678 MREF_LE(entry->mft_reference), 679 (unsigned long long) 680 MREF_LE(entry->mft_reference)); 681 printf("\t\tInstance:\t%u (0x%x)\n", 682 (unsigned)le16_to_cpu(entry->instance), 683 (unsigned)le16_to_cpu(entry->instance)); 684 printf("\t\tName:\t\t"); 685 if (entry->name_length) { 686 char *name = NULL; 687 int name_size; 688 689 name_size = ntfs_ucstombs(entry->name, 690 entry->name_length, &name, 0); 691 692 if (name_size > 0) { 693 printf("%s\n", name); 694 free(name); 695 } else 696 ntfs_log_perror("ntfs_ucstombs failed"); 697 } else 698 printf("unnamed\n"); 699 printf("\t\tPadding:\t"); 700 ntfs_dump_bytes((u8 *)entry, entry->name_offset + 701 sizeof(ntfschar) * entry->name_length, 702 le16_to_cpu(entry->length)); 703 printf("\n"); 704 } 705 free(value); 706 printf("\tEnd of attribute list reached.\n"); 707} 708 709/** 710 * ntfs_dump_filename() 711 */ 712static void ntfs_dump_filename(const char *indent, 713 FILE_NAME_ATTR *file_name_attr) 714{ 715 printf("%sParent directory:\t %lld (0x%llx)\n", indent, 716 (long long)MREF_LE(file_name_attr->parent_directory), 717 (long long)MREF_LE(file_name_attr->parent_directory)); 718 /* time stuff */ 719 if (!opts.notime) { 720 char *ntfs_time_str; 721 722 ntfs_time_str = ntfsinfo_time_to_str( 723 file_name_attr->creation_time); 724 printf("%sFile Creation Time:\t %s", indent, ntfs_time_str); 725 726 ntfs_time_str = ntfsinfo_time_to_str( 727 file_name_attr->last_data_change_time); 728 printf("%sFile Altered Time:\t %s", indent, ntfs_time_str); 729 730 ntfs_time_str = ntfsinfo_time_to_str( 731 file_name_attr->last_mft_change_time); 732 printf("%sMFT Changed Time:\t %s", indent, ntfs_time_str); 733 734 ntfs_time_str = ntfsinfo_time_to_str( 735 file_name_attr->last_access_time); 736 printf("%sLast Accessed Time:\t %s", indent, ntfs_time_str); 737 } 738 /* other basic stuff about the file */ 739 printf("%sAllocated Size:\t\t %lld (0x%llx)\n", indent, (long long) 740 sle64_to_cpu(file_name_attr->allocated_size), 741 (unsigned long long) 742 sle64_to_cpu(file_name_attr->allocated_size)); 743 printf("%sData Size:\t\t %lld (0x%llx)\n", indent, 744 (long long)sle64_to_cpu(file_name_attr->data_size), 745 (unsigned long long) 746 sle64_to_cpu(file_name_attr->data_size)); 747 printf("%sFilename Length:\t %d (0x%x)\n", indent, 748 (unsigned)file_name_attr->file_name_length, 749 (unsigned)file_name_attr->file_name_length); 750 ntfs_dump_flags(indent, AT_FILE_NAME, file_name_attr->file_attributes); 751 if (file_name_attr->file_attributes & FILE_ATTR_REPARSE_POINT && 752 file_name_attr->u.reparse_point_tag) 753 printf("%sReparse point tag:\t 0x%x\n", indent, (unsigned) 754 le32_to_cpu(file_name_attr->u.reparse_point_tag)); 755 else if (file_name_attr->u.reparse_point_tag) { 756 printf("%sEA Length:\t\t %d (0x%x)\n", indent, (unsigned) 757 le16_to_cpu(file_name_attr->u.s.packed_ea_size), 758 (unsigned) 759 le16_to_cpu(file_name_attr->u.s.packed_ea_size)); 760 if (file_name_attr->u.s.reserved) 761 printf("%sReserved:\t\t %d (0x%x)\n", indent, 762 (unsigned) 763 le16_to_cpu(file_name_attr->u.s.reserved), 764 (unsigned) 765 le16_to_cpu(file_name_attr->u.s.reserved)); 766 } 767 /* The filename. */ 768 ntfs_dump_namespace(indent, file_name_attr->file_name_type); 769 if (file_name_attr->file_name_length > 0) { 770 /* but first we need to convert the little endian unicode string 771 into a printable format */ 772 char *mbs_file_name = NULL; 773 int mbs_file_name_size; 774 775 mbs_file_name_size = ntfs_ucstombs(file_name_attr->file_name, 776 file_name_attr->file_name_length,&mbs_file_name,0); 777 778 if (mbs_file_name_size>0) { 779 printf("%sFilename:\t\t '%s'\n", indent, mbs_file_name); 780 free(mbs_file_name); 781 } else { 782 /* an error occurred, errno holds the reason - notify the user */ 783 ntfs_log_perror("ntfsinfo error: could not parse file name"); 784 } 785 } else { 786 printf("%sFile Name:\t\t unnamed?!?\n", indent); 787 } 788} 789 790/** 791 * ntfs_dump_attr_file_name() 792 */ 793static void ntfs_dump_attr_file_name(ATTR_RECORD *attr) 794{ 795 ntfs_dump_filename("\t", (FILE_NAME_ATTR*)((u8*)attr + 796 le16_to_cpu(attr->u.res.value_offset))); 797} 798 799/** 800 * ntfs_dump_object_id 801 * 802 * dump the $OBJECT_ID attribute - not present on all systems 803 */ 804static void ntfs_dump_attr_object_id(ATTR_RECORD *attr,ntfs_volume *vol) 805{ 806 OBJECT_ID_ATTR *obj_id_attr = NULL; 807 808 obj_id_attr = (OBJECT_ID_ATTR *)((u8*)attr + 809 le16_to_cpu(attr->u.res.value_offset)); 810 811 if (vol->major_ver >= 3.0) { 812 u32 value_length; 813 char printable_GUID[37]; 814 815 value_length = le32_to_cpu(attr->u.res.value_length); 816 817 /* Object ID is mandatory. */ 818 ntfs_guid_to_mbs(&obj_id_attr->object_id, printable_GUID); 819 printf("\tObject ID:\t\t %s\n", printable_GUID); 820 821 /* Dump Birth Volume ID. */ 822 if ((value_length > sizeof(GUID)) && !ntfs_guid_is_zero( 823 &obj_id_attr->u.s.birth_volume_id)) { 824 ntfs_guid_to_mbs(&obj_id_attr->u.s.birth_volume_id, 825 printable_GUID); 826 printf("\tBirth Volume ID:\t\t %s\n", printable_GUID); 827 } else 828 printf("\tBirth Volume ID:\t missing\n"); 829 830 /* Dumping Birth Object ID */ 831 if ((value_length > sizeof(GUID)) && !ntfs_guid_is_zero( 832 &obj_id_attr->u.s.birth_object_id)) { 833 ntfs_guid_to_mbs(&obj_id_attr->u.s.birth_object_id, 834 printable_GUID); 835 printf("\tBirth Object ID:\t\t %s\n", printable_GUID); 836 } else 837 printf("\tBirth Object ID:\t missing\n"); 838 839 /* Dumping Domain_id - reserved for now */ 840 if ((value_length > sizeof(GUID)) && !ntfs_guid_is_zero( 841 &obj_id_attr->u.s.domain_id)) { 842 ntfs_guid_to_mbs(&obj_id_attr->u.s.domain_id, 843 printable_GUID); 844 printf("\tDomain ID:\t\t\t %s\n", printable_GUID); 845 } else 846 printf("\tDomain ID:\t\t missing\n"); 847 } else 848 printf("\t$OBJECT_ID not present. Only NTFS versions > 3.0\n" 849 "\thave $OBJECT_ID. Your version of NTFS is %d.\n", 850 vol->major_ver); 851} 852 853/** 854 * ntfs_dump_acl 855 * 856 * given an acl, print it in a beautiful & lovely way. 857 */ 858static void ntfs_dump_acl(const char *prefix, ACL *acl) 859{ 860 unsigned int i; 861 u16 ace_count; 862 ACCESS_ALLOWED_ACE *ace; 863 864 printf("%sRevision\t %u\n", prefix, acl->revision); 865 866 /* 867 * Do not recalculate le16_to_cpu every iteration (minor speedup on 868 * big-endian machines. 869 */ 870 ace_count = le16_to_cpu(acl->ace_count); 871 872 /* initialize 'ace' to the first ace (if any) */ 873 ace = (ACCESS_ALLOWED_ACE *)((char *)acl + 8); 874 875 /* iterate through ACE's */ 876 for (i = 1; i <= ace_count; i++) { 877 const char *ace_type; 878 char *sid; 879 880 /* set ace_type. */ 881 switch (ace->type) { 882 case ACCESS_ALLOWED_ACE_TYPE: 883 ace_type = "allow"; 884 break; 885 case ACCESS_DENIED_ACE_TYPE: 886 ace_type = "deny"; 887 break; 888 case SYSTEM_AUDIT_ACE_TYPE: 889 ace_type = "audit"; 890 break; 891 default: 892 ace_type = "unknown"; 893 break; 894 } 895 896 printf("%sACE:\t\t type:%s flags:0x%x access:0x%x\n", prefix, 897 ace_type, (unsigned int)ace->flags, 898 (unsigned int)le32_to_cpu(ace->mask)); 899 /* get a SID string */ 900 sid = ntfs_sid_to_mbs(&ace->sid, NULL, 0); 901 printf("%s\t\t SID: %s\n", prefix, sid); 902 free(sid); 903 904 /* proceed to next ACE */ 905 ace = (ACCESS_ALLOWED_ACE *)(((char *)ace) + 906 le16_to_cpu(ace->size)); 907 } 908} 909 910 911static void ntfs_dump_security_descriptor(SECURITY_DESCRIPTOR_ATTR *sec_desc, 912 const char *indent) 913{ 914 char *sid; 915 916 printf("%s\tRevision:\t\t %u\n", indent, sec_desc->revision); 917 918 /* TODO: parse the flags */ 919 printf("%s\tControl:\t\t 0x%04x\n", indent, 920 le16_to_cpu(sec_desc->control)); 921 922 if (~sec_desc->control & SE_SELF_RELATIVE) { 923 SECURITY_DESCRIPTOR *sd = (SECURITY_DESCRIPTOR *)sec_desc; 924 925 printf("%s\tOwner SID pointer:\t %p\n", indent, sd->owner); 926 printf("%s\tGroup SID pointer:\t %p\n", indent, sd->group); 927 printf("%s\tSACL pointer:\t\t %p\n", indent, sd->sacl); 928 printf("%s\tDACL pointer:\t\t %p\n", indent, sd->dacl); 929 930 return; 931 } 932 933 if (sec_desc->owner) { 934 sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + 935 le32_to_cpu(sec_desc->owner)), NULL, 0); 936 printf("%s\tOwner SID:\t\t %s\n", indent, sid); 937 free(sid); 938 } else 939 printf("%s\tOwner SID:\t\t missing\n", indent); 940 941 if (sec_desc->group) { 942 sid = ntfs_sid_to_mbs((SID *)((char *)sec_desc + 943 le32_to_cpu(sec_desc->group)), NULL, 0); 944 printf("%s\tGroup SID:\t\t %s\n", indent, sid); 945 free(sid); 946 } else 947 printf("%s\tGroup SID:\t\t missing\n", indent); 948 949 printf("%s\tSystem ACL:\t\t ", indent); 950 if (sec_desc->control & SE_SACL_PRESENT) { 951 if (sec_desc->control & SE_SACL_DEFAULTED) { 952 printf("defaulted"); 953 } 954 printf("\n"); 955 ntfs_dump_acl(indent ? "\t\t\t" : "\t\t", 956 (ACL *)((char *)sec_desc + 957 le32_to_cpu(sec_desc->sacl))); 958 } else { 959 printf("missing\n"); 960 } 961 962 printf("%s\tDiscretionary ACL:\t ", indent); 963 if (sec_desc->control & SE_DACL_PRESENT) { 964 if (sec_desc->control & SE_SACL_DEFAULTED) { 965 printf("defaulted"); 966 } 967 printf("\n"); 968 ntfs_dump_acl(indent ? "\t\t\t" : "\t\t", 969 (ACL *)((char *)sec_desc + 970 le32_to_cpu(sec_desc->dacl))); 971 } else { 972 printf("missing\n"); 973 } 974} 975 976/** 977 * ntfs_dump_security_descriptor() 978 * 979 * dump the security information about the file 980 */ 981static void ntfs_dump_attr_security_descriptor(ATTR_RECORD *attr, ntfs_volume *vol) 982{ 983 SECURITY_DESCRIPTOR_ATTR *sec_desc_attr; 984 985 if (attr->non_resident) { 986 /* FIXME: We don't handle fragmented mapping pairs case. */ 987 runlist *rl = ntfs_mapping_pairs_decompress(vol, attr, NULL); 988 if (rl) { 989 s64 data_size, bytes_read; 990 991 data_size = sle64_to_cpu(attr->u.nonres.data_size); 992 sec_desc_attr = ntfs_malloc(data_size); 993 if (!sec_desc_attr) { 994 free(rl); 995 return; 996 } 997 bytes_read = ntfs_rl_pread(vol, rl, 0, 998 data_size, sec_desc_attr); 999 if (bytes_read != data_size) { 1000 ntfs_log_error("ntfsinfo error: could not " 1001 "read security descriptor\n"); 1002 free(rl); 1003 free(sec_desc_attr); 1004 return; 1005 } 1006 free(rl); 1007 } else { 1008 ntfs_log_error("ntfsinfo error: could not " 1009 "decompress runlist\n"); 1010 return; 1011 } 1012 } else { 1013 sec_desc_attr = (SECURITY_DESCRIPTOR_ATTR *)((u8*)attr + 1014 le16_to_cpu(attr->u.res.value_offset)); 1015 } 1016 1017 ntfs_dump_security_descriptor(sec_desc_attr, ""); 1018 1019 if (attr->non_resident) 1020 free(sec_desc_attr); 1021} 1022 1023/** 1024 * ntfs_dump_volume_name() 1025 * 1026 * dump the name of the volume the inode belongs to 1027 */ 1028static void ntfs_dump_attr_volume_name(ATTR_RECORD *attr) 1029{ 1030 ntfschar *ucs_vol_name = NULL; 1031 1032 if (le32_to_cpu(attr->u.res.value_length) > 0) { 1033 char *mbs_vol_name = NULL; 1034 int mbs_vol_name_size; 1035 /* calculate volume name position */ 1036 ucs_vol_name = (ntfschar*)((u8*)attr + 1037 le16_to_cpu(attr->u.res.value_offset)); 1038 /* convert the name to current locale multibyte sequence */ 1039 mbs_vol_name_size = ntfs_ucstombs(ucs_vol_name, 1040 le32_to_cpu(attr->u.res.value_length) / 1041 sizeof(ntfschar), &mbs_vol_name, 0); 1042 1043 if (mbs_vol_name_size>0) { 1044 /* output the converted name. */ 1045 printf("\tVolume Name:\t\t '%s'\n", mbs_vol_name); 1046 free(mbs_vol_name); 1047 } else 1048 ntfs_log_perror("ntfsinfo error: could not parse " 1049 "volume name"); 1050 } else 1051 printf("\tVolume Name:\t\t unnamed\n"); 1052} 1053 1054/** 1055 * ntfs_dump_volume_information() 1056 * 1057 * dump the information for the volume the inode belongs to 1058 * 1059 */ 1060static void ntfs_dump_attr_volume_information(ATTR_RECORD *attr) 1061{ 1062 VOLUME_INFORMATION *vol_information = NULL; 1063 1064 vol_information = (VOLUME_INFORMATION*)((char *)attr+ 1065 le16_to_cpu(attr->u.res.value_offset)); 1066 1067 printf("\tVolume Version:\t\t %d.%d\n", vol_information->major_ver, 1068 vol_information->minor_ver); 1069 printf("\tVolume Flags:\t\t "); 1070 if (vol_information->flags & VOLUME_IS_DIRTY) 1071 printf("DIRTY "); 1072 if (vol_information->flags & VOLUME_RESIZE_LOG_FILE) 1073 printf("RESIZE_LOG "); 1074 if (vol_information->flags & VOLUME_UPGRADE_ON_MOUNT) 1075 printf("UPG_ON_MOUNT "); 1076 if (vol_information->flags & VOLUME_MOUNTED_ON_NT4) 1077 printf("MOUNTED_NT4 "); 1078 if (vol_information->flags & VOLUME_DELETE_USN_UNDERWAY) 1079 printf("DEL_USN "); 1080 if (vol_information->flags & VOLUME_REPAIR_OBJECT_ID) 1081 printf("REPAIR_OBJID "); 1082 if (vol_information->flags & VOLUME_CHKDSK_UNDERWAY) 1083 printf("CHKDSK_UNDERWAY "); 1084 if (vol_information->flags & VOLUME_MODIFIED_BY_CHKDSK) 1085 printf("MOD_BY_CHKDSK "); 1086 if (vol_information->flags & VOLUME_FLAGS_MASK) { 1087 printf("(0x%04x)\n", 1088 (unsigned)le16_to_cpu(vol_information->flags)); 1089 } else 1090 printf("none set (0x0000)\n"); 1091 if (vol_information->flags & (~VOLUME_FLAGS_MASK)) 1092 printf("\t\t\t\t Unknown Flags: 0x%04x\n", 1093 le16_to_cpu(vol_information->flags & 1094 (~VOLUME_FLAGS_MASK))); 1095} 1096 1097static ntfschar NTFS_DATA_SDS[5] = { const_cpu_to_le16('$'), 1098 const_cpu_to_le16('S'), const_cpu_to_le16('D'), 1099 const_cpu_to_le16('S'), const_cpu_to_le16('\0') }; 1100 1101static void ntfs_dump_sds_entry(SECURITY_DESCRIPTOR_HEADER *sds) 1102{ 1103 SECURITY_DESCRIPTOR_RELATIVE *sd; 1104 1105 ntfs_log_verbose("\n"); 1106 ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", 1107 (unsigned)le32_to_cpu(sds->hash)); 1108 ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", 1109 (unsigned)le32_to_cpu(sds->security_id), 1110 (unsigned)le32_to_cpu(sds->security_id)); 1111 ntfs_log_verbose("\t\tOffset:\t\t\t %llu (0x%llx)\n", 1112 (unsigned long long)le64_to_cpu(sds->offset), 1113 (unsigned long long)le64_to_cpu(sds->offset)); 1114 ntfs_log_verbose("\t\tLength:\t\t\t %u (0x%x)\n", 1115 (unsigned)le32_to_cpu(sds->length), 1116 (unsigned)le32_to_cpu(sds->length)); 1117 1118 sd = (SECURITY_DESCRIPTOR_RELATIVE *)((char *)sds + 1119 sizeof(SECURITY_DESCRIPTOR_HEADER)); 1120 1121 ntfs_dump_security_descriptor(sd, "\t"); 1122} 1123 1124static void ntfs_dump_sds(ATTR_RECORD *attr, ntfs_inode *ni) 1125{ 1126 SECURITY_DESCRIPTOR_HEADER *sds, *sd; 1127 ntfschar *name; 1128 int name_len; 1129 s64 data_size; 1130 u64 inode; 1131 1132 inode = ni->mft_no; 1133 if (ni->nr_extents < 0) 1134 inode = ni->u.base_ni->mft_no; 1135 if (FILE_Secure != inode) 1136 return; 1137 1138 name_len = attr->name_length; 1139 if (!name_len) 1140 return; 1141 1142 name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); 1143 if (!ntfs_names_are_equal(NTFS_DATA_SDS, sizeof(NTFS_DATA_SDS) / 2 - 1, 1144 name, name_len, 0, NULL, 0)) 1145 return; 1146 1147 sd = sds = ntfs_attr_readall(ni, AT_DATA, name, name_len, &data_size); 1148 if (!sd) { 1149 ntfs_log_perror("Failed to read $SDS attribute"); 1150 return; 1151 } 1152 /* 1153 * FIXME: The right way is based on the indexes, so we couldn't 1154 * miss real entries. For now, dump until it makes sense. 1155 */ 1156 while (sd->length && sd->hash && 1157 le64_to_cpu(sd->offset) < (u64)data_size && 1158 le32_to_cpu(sd->length) < (u64)data_size && 1159 le64_to_cpu(sd->offset) + 1160 le32_to_cpu(sd->length) < (u64)data_size) { 1161 ntfs_dump_sds_entry(sd); 1162 sd = (SECURITY_DESCRIPTOR_HEADER *)((char*)sd + 1163 ((le32_to_cpu(sd->length) + 15) & ~15)); 1164 } 1165 free(sds); 1166} 1167 1168static const char *get_attribute_type_name(le32 type) 1169{ 1170 switch (type) { 1171 case AT_UNUSED: return "$UNUSED"; 1172 case AT_STANDARD_INFORMATION: return "$STANDARD_INFORMATION"; 1173 case AT_ATTRIBUTE_LIST: return "$ATTRIBUTE_LIST"; 1174 case AT_FILE_NAME: return "$FILE_NAME"; 1175 case AT_OBJECT_ID: return "$OBJECT_ID"; 1176 case AT_SECURITY_DESCRIPTOR: return "$SECURITY_DESCRIPTOR"; 1177 case AT_VOLUME_NAME: return "$VOLUME_NAME"; 1178 case AT_VOLUME_INFORMATION: return "$VOLUME_INFORMATION"; 1179 case AT_DATA: return "$DATA"; 1180 case AT_INDEX_ROOT: return "$INDEX_ROOT"; 1181 case AT_INDEX_ALLOCATION: return "$INDEX_ALLOCATION"; 1182 case AT_BITMAP: return "$BITMAP"; 1183 case AT_REPARSE_POINT: return "$REPARSE_POINT"; 1184 case AT_EA_INFORMATION: return "$EA_INFORMATION"; 1185 case AT_EA: return "$EA"; 1186 case AT_PROPERTY_SET: return "$PROPERTY_SET"; 1187 case AT_LOGGED_UTILITY_STREAM: return "$LOGGED_UTILITY_STREAM"; 1188 case AT_END: return "$END"; 1189 } 1190 1191 return "$UNKNOWN"; 1192} 1193 1194static const char * ntfs_dump_lcn(LCN lcn) 1195{ 1196 switch (lcn) { 1197 case LCN_HOLE: 1198 return "<HOLE>\t"; 1199 case LCN_RL_NOT_MAPPED: 1200 return "<RL_NOT_MAPPED>"; 1201 case LCN_ENOENT: 1202 return "<ENOENT>\t"; 1203 case LCN_EINVAL: 1204 return "<EINVAL>\t"; 1205 case LCN_EIO: 1206 return "<EIO>\t"; 1207 default: 1208 ntfs_log_error("Invalid LCN value %llx passed to " 1209 "ntfs_dump_lcn().\n", lcn); 1210 return "???\t"; 1211 } 1212} 1213 1214static void ntfs_dump_attribute_header(ntfs_attr_search_ctx *ctx, 1215 ntfs_volume *vol) 1216{ 1217 ATTR_RECORD *a = ctx->attr; 1218 1219 printf("Dumping attribute %s (0x%x) from mft record %lld (0x%llx)\n", 1220 get_attribute_type_name(a->type), 1221 (unsigned)le32_to_cpu(a->type), 1222 (unsigned long long)ctx->ntfs_ino->mft_no, 1223 (unsigned long long)ctx->ntfs_ino->mft_no); 1224 1225 ntfs_log_verbose("\tAttribute length:\t %u (0x%x)\n", 1226 (unsigned)le32_to_cpu(a->length), 1227 (unsigned)le32_to_cpu(a->length)); 1228 printf("\tResident: \t\t %s\n", a->non_resident ? "No" : "Yes"); 1229 ntfs_log_verbose("\tName length:\t\t %u (0x%x)\n", 1230 (unsigned)a->name_length, (unsigned)a->name_length); 1231 ntfs_log_verbose("\tName offset:\t\t %u (0x%x)\n", 1232 (unsigned)le16_to_cpu(a->name_offset), 1233 (unsigned)le16_to_cpu(a->name_offset)); 1234 1235 /* Dump the attribute (stream) name */ 1236 if (a->name_length) { 1237 char *attribute_name = NULL; 1238 1239 attribute_name = ntfs_attr_get_name_mbs(a); 1240 if (attribute_name) { 1241 printf("\tAttribute name:\t\t '%s'\n", attribute_name); 1242 free(attribute_name); 1243 } else 1244 ntfs_log_perror("Error: couldn't parse attribute name"); 1245 } 1246 1247 /* TODO: parse the flags */ 1248 printf("\tAttribute flags:\t 0x%04x\n", 1249 (unsigned)le16_to_cpu(a->flags)); 1250 printf("\tAttribute instance:\t %u (0x%x)\n", 1251 (unsigned)le16_to_cpu(a->instance), 1252 (unsigned)le16_to_cpu(a->instance)); 1253 1254 /* Resident attribute */ 1255 if (!a->non_resident) { 1256 printf("\tData size:\t\t %u (0x%x)\n", 1257 (unsigned)le32_to_cpu(a->u.res.value_length), 1258 (unsigned)le32_to_cpu(a->u.res.value_length)); 1259 ntfs_log_verbose("\tData offset:\t\t %u (0x%x)\n", 1260 (unsigned)le16_to_cpu(a->u.res.value_offset), 1261 (unsigned)le16_to_cpu(a->u.res.value_offset)); 1262 /* TODO: parse the flags */ 1263 printf("\tResident flags:\t\t 0x%02x\n", 1264 (unsigned)a->u.res.resident_flags); 1265 ntfs_log_verbose("\tReservedR:\t\t %d (0x%x)\n", 1266 (unsigned)a->u.res.reservedR, (unsigned)a->u.res.reservedR); 1267 return; 1268 } 1269 1270 /* Non-resident attribute */ 1271 ntfs_log_verbose("\tLowest VCN\t\t %lld (0x%llx)\n", 1272 (long long)sle64_to_cpu(a->u.nonres.lowest_vcn), 1273 (unsigned long long)sle64_to_cpu(a->u.nonres.lowest_vcn)); 1274 ntfs_log_verbose("\tHighest VCN:\t\t %lld (0x%llx)\n", 1275 (long long)sle64_to_cpu(a->u.nonres.highest_vcn), 1276 (unsigned long long)sle64_to_cpu(a->u.nonres.highest_vcn)); 1277 ntfs_log_verbose("\tMapping pairs offset:\t %u (0x%x)\n", 1278 (unsigned)le16_to_cpu(a->u.nonres.mapping_pairs_offset), 1279 (unsigned)le16_to_cpu(a->u.nonres.mapping_pairs_offset)); 1280 printf("\tCompression unit:\t %u (0x%x)\n", 1281 (unsigned)a->u.nonres.compression_unit, 1282 (unsigned)a->u.nonres.compression_unit); 1283 /* TODO: dump the 5 reserved bytes here in verbose mode */ 1284 1285 if (!a->u.nonres.lowest_vcn) { 1286 printf("\tData size:\t\t %llu (0x%llx)\n", 1287 (long long)sle64_to_cpu(a->u.nonres.data_size), 1288 (unsigned long long)sle64_to_cpu(a->u.nonres.data_size)); 1289 printf("\tAllocated size:\t\t %llu (0x%llx)\n", 1290 (long long)sle64_to_cpu(a->u.nonres.allocated_size), 1291 (unsigned long long) 1292 sle64_to_cpu(a->u.nonres.allocated_size)); 1293 printf("\tInitialized size:\t %llu (0x%llx)\n", 1294 (long long)sle64_to_cpu(a->u.nonres.initialized_size), 1295 (unsigned long long) 1296 sle64_to_cpu(a->u.nonres.initialized_size)); 1297 if (a->u.nonres.compression_unit || a->flags & ATTR_IS_COMPRESSED || 1298 a->flags & ATTR_IS_SPARSE) 1299 printf("\tCompressed size:\t %llu (0x%llx)\n", 1300 (signed long long) 1301 sle64_to_cpu(a->u.nonres.compressed_size), 1302 (signed long long) 1303 sle64_to_cpu(a->u.nonres.compressed_size)); 1304 } 1305 1306 if (opts.verbose) { 1307 runlist *rl; 1308 1309 rl = ntfs_mapping_pairs_decompress(vol, a, NULL); 1310 if (rl) { 1311 runlist *rlc = rl; 1312 1313 // TODO: Switch this to properly aligned hex... 1314 printf("\tRunlist:\tVCN\t\tLCN\t\tLength\n"); 1315 while (rlc->length) { 1316 if (rlc->lcn >= 0) 1317 printf("\t\t\t0x%llx\t\t0x%llx\t\t" 1318 "0x%llx\n", rlc->vcn, 1319 rlc->lcn, rlc->length); 1320 else 1321 printf("\t\t\t0x%llx\t\t%s\t" 1322 "0x%llx\n", rlc->vcn, 1323 ntfs_dump_lcn(rlc->lcn), 1324 rlc->length); 1325 rlc++; 1326 } 1327 free(rl); 1328 } else 1329 ntfs_log_error("Error: couldn't decompress runlist\n"); 1330 } 1331} 1332 1333/** 1334 * ntfs_dump_data_attr() 1335 * 1336 * dump some info about the data attribute if it's metadata 1337 */ 1338static void ntfs_dump_attr_data(ATTR_RECORD *attr, ntfs_inode *ni) 1339{ 1340 if (opts.verbose) 1341 ntfs_dump_sds(attr, ni); 1342} 1343 1344typedef enum { 1345 INDEX_ATTR_UNKNOWN, 1346 INDEX_ATTR_DIRECTORY_I30, 1347 INDEX_ATTR_SECURE_SII, 1348 INDEX_ATTR_SECURE_SDH, 1349 INDEX_ATTR_OBJID_O, 1350 INDEX_ATTR_REPARSE_R, 1351 INDEX_ATTR_QUOTA_O, 1352 INDEX_ATTR_QUOTA_Q, 1353} INDEX_ATTR_TYPE; 1354 1355static void ntfs_dump_index_key(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) 1356{ 1357 char *sid; 1358 char printable_GUID[37]; 1359 1360 switch (type) { 1361 case INDEX_ATTR_SECURE_SII: 1362 ntfs_log_verbose("\t\tKey security id:\t %u (0x%x)\n", 1363 (unsigned) 1364 le32_to_cpu(entry->key.sii.security_id), 1365 (unsigned) 1366 le32_to_cpu(entry->key.sii.security_id)); 1367 break; 1368 case INDEX_ATTR_SECURE_SDH: 1369 ntfs_log_verbose("\t\tKey hash:\t\t 0x%08x\n", 1370 (unsigned)le32_to_cpu(entry->key.sdh.hash)); 1371 ntfs_log_verbose("\t\tKey security id:\t %u (0x%x)\n", 1372 (unsigned) 1373 le32_to_cpu(entry->key.sdh.security_id), 1374 (unsigned) 1375 le32_to_cpu(entry->key.sdh.security_id)); 1376 break; 1377 case INDEX_ATTR_OBJID_O: 1378 ntfs_guid_to_mbs(&entry->key.object_id, printable_GUID); 1379 ntfs_log_verbose("\t\tKey GUID:\t\t %s\n", printable_GUID); 1380 break; 1381 case INDEX_ATTR_REPARSE_R: 1382 ntfs_log_verbose("\t\tKey reparse tag:\t 0x%08x\n", (unsigned) 1383 le32_to_cpu(entry->key.reparse.reparse_tag)); 1384 ntfs_log_verbose("\t\tKey file id:\t\t %llu (0x%llx)\n", 1385 (unsigned long long) 1386 le64_to_cpu(entry->key.reparse.file_id), 1387 (unsigned long long) 1388 le64_to_cpu(entry->key.reparse.file_id)); 1389 break; 1390 case INDEX_ATTR_QUOTA_O: 1391 sid = ntfs_sid_to_mbs(&entry->key.sid, NULL, 0); 1392 ntfs_log_verbose("\t\tKey SID:\t\t %s\n", sid); 1393 free(sid); 1394 break; 1395 case INDEX_ATTR_QUOTA_Q: 1396 ntfs_log_verbose("\t\tKey owner id:\t\t %u (0x%x)\n", 1397 (unsigned)le32_to_cpu(entry->key.owner_id), 1398 (unsigned)le32_to_cpu(entry->key.owner_id)); 1399 break; 1400 default: 1401 ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", 1402 (unsigned)type); 1403 break; 1404 } 1405} 1406 1407#ifdef __sun 1408#pragma pack(1) 1409#endif 1410typedef union { 1411 SII_INDEX_DATA sii; /* $SII index data in $Secure */ 1412 SDH_INDEX_DATA sdh; /* $SDH index data in $Secure */ 1413 QUOTA_O_INDEX_DATA quota_o; /* $O index data in $Quota */ 1414 QUOTA_CONTROL_ENTRY quota_q; /* $Q index data in $Quota */ 1415} __attribute__((__packed__)) INDEX_ENTRY_DATA; 1416#ifdef __sun 1417#pragma pack() 1418#endif 1419 1420static void ntfs_dump_index_data(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) 1421{ 1422 INDEX_ENTRY_DATA *data; 1423 1424 data = (INDEX_ENTRY_DATA *)((u8 *)entry + 1425 le16_to_cpu(entry->u.s.data_offset)); 1426 1427 switch (type) { 1428 case INDEX_ATTR_SECURE_SII: 1429 ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", 1430 (unsigned)le32_to_cpu(data->sii.hash)); 1431 ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", 1432 (unsigned)le32_to_cpu(data->sii.security_id), 1433 (unsigned)le32_to_cpu(data->sii.security_id)); 1434 ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu (0x%llx)\n", 1435 (unsigned long long) 1436 le64_to_cpu(data->sii.offset), 1437 (unsigned long long) 1438 le64_to_cpu(data->sii.offset)); 1439 ntfs_log_verbose("\t\tLength in $SDS:\t\t %u (0x%x)\n", 1440 (unsigned)le32_to_cpu(data->sii.length), 1441 (unsigned)le32_to_cpu(data->sii.length)); 1442 break; 1443 case INDEX_ATTR_SECURE_SDH: 1444 ntfs_log_verbose("\t\tHash:\t\t\t 0x%08x\n", 1445 (unsigned)le32_to_cpu(data->sdh.hash)); 1446 ntfs_log_verbose("\t\tSecurity id:\t\t %u (0x%x)\n", 1447 (unsigned)le32_to_cpu(data->sdh.security_id), 1448 (unsigned)le32_to_cpu(data->sdh.security_id)); 1449 ntfs_log_verbose("\t\tOffset in $SDS:\t\t %llu (0x%llx)\n", 1450 (unsigned long long) 1451 le64_to_cpu(data->sdh.offset), 1452 (unsigned long long) 1453 le64_to_cpu(data->sdh.offset)); 1454 ntfs_log_verbose("\t\tLength in $SDS:\t\t %u (0x%x)\n", 1455 (unsigned)le32_to_cpu(data->sdh.length), 1456 (unsigned)le32_to_cpu(data->sdh.length)); 1457 ntfs_log_verbose("\t\tUnknown (padding):\t 0x%08x\n", 1458 (unsigned)le32_to_cpu(data->sdh.reserved_II)); 1459 break; 1460 case INDEX_ATTR_OBJID_O: { 1461 OBJ_ID_INDEX_DATA *object_id_data; 1462 char printable_GUID[37]; 1463 1464 object_id_data = (OBJ_ID_INDEX_DATA*)((u8*)entry + 1465 le16_to_cpu(entry->u.s.data_offset)); 1466 ntfs_log_verbose("\t\tMFT Number:\t\t 0x%llx\n", 1467 (unsigned long long) 1468 MREF_LE(object_id_data->mft_reference)); 1469 ntfs_log_verbose("\t\tMFT Sequence Number:\t 0x%x\n", 1470 (unsigned) 1471 MSEQNO_LE(object_id_data->mft_reference)); 1472 ntfs_guid_to_mbs(&object_id_data->u.s.birth_volume_id, 1473 printable_GUID); 1474 ntfs_log_verbose("\t\tBirth volume id GUID:\t %s\n", 1475 printable_GUID); 1476 ntfs_guid_to_mbs(&object_id_data->u.s.birth_object_id, 1477 printable_GUID); 1478 ntfs_log_verbose("\t\tBirth object id GUID:\t %s\n", 1479 printable_GUID); 1480 ntfs_guid_to_mbs(&object_id_data->u.s.domain_id, printable_GUID); 1481 ntfs_log_verbose("\t\tDomain id GUID:\t\t %s\n", 1482 printable_GUID); 1483 } 1484 break; 1485 case INDEX_ATTR_REPARSE_R: 1486 /* TODO */ 1487 break; 1488 case INDEX_ATTR_QUOTA_O: 1489 ntfs_log_verbose("\t\tOwner id:\t\t %u (0x%x)\n", 1490 (unsigned)le32_to_cpu(data->quota_o.owner_id), 1491 (unsigned)le32_to_cpu(data->quota_o.owner_id)); 1492 ntfs_log_verbose("\t\tUnknown:\t\t %u (0x%x)\n", 1493 (unsigned)le32_to_cpu(data->quota_o.unknown), 1494 (unsigned)le32_to_cpu(data->quota_o.unknown)); 1495 break; 1496 case INDEX_ATTR_QUOTA_Q: 1497 ntfs_log_verbose("\t\tVersion:\t\t %u\n", 1498 (unsigned)le32_to_cpu(data->quota_q.version)); 1499 ntfs_log_verbose("\t\tQuota flags:\t\t 0x%08x\n", 1500 (unsigned)le32_to_cpu(data->quota_q.flags)); 1501 ntfs_log_verbose("\t\tBytes used:\t\t %llu (0x%llx)\n", 1502 (unsigned long long) 1503 le64_to_cpu(data->quota_q.bytes_used), 1504 (unsigned long long) 1505 le64_to_cpu(data->quota_q.bytes_used)); 1506 ntfs_log_verbose("\t\tLast changed:\t\t %s", 1507 ntfsinfo_time_to_str( 1508 data->quota_q.change_time)); 1509 ntfs_log_verbose("\t\tThreshold:\t\t %lld (0x%llx)\n", 1510 (unsigned long long) 1511 sle64_to_cpu(data->quota_q.threshold), 1512 (unsigned long long) 1513 sle64_to_cpu(data->quota_q.threshold)); 1514 ntfs_log_verbose("\t\tLimit:\t\t\t %lld (0x%llx)\n", 1515 (unsigned long long) 1516 sle64_to_cpu(data->quota_q.limit), 1517 (unsigned long long) 1518 sle64_to_cpu(data->quota_q.limit)); 1519 ntfs_log_verbose("\t\tExceeded time:\t\t %lld (0x%llx)\n", 1520 (unsigned long long) 1521 sle64_to_cpu(data->quota_q.exceeded_time), 1522 (unsigned long long) 1523 sle64_to_cpu(data->quota_q.exceeded_time)); 1524 if (le16_to_cpu(entry->u.s.data_length) > 48) { 1525 char *sid; 1526 sid = ntfs_sid_to_mbs(&data->quota_q.sid, NULL, 0); 1527 ntfs_log_verbose("\t\tOwner SID:\t\t %s\n", sid); 1528 free(sid); 1529 } 1530 break; 1531 default: 1532 ntfs_log_verbose("\t\tIndex attr type is UNKNOWN: \t 0x%08x\n", 1533 (unsigned)type); 1534 break; 1535 } 1536} 1537 1538/** 1539 * ntfs_dump_index_entries() 1540 * 1541 * dump sequence of index_entries and return number of entries dumped. 1542 */ 1543static int ntfs_dump_index_entries(INDEX_ENTRY *entry, INDEX_ATTR_TYPE type) 1544{ 1545 int numb_entries = 1; 1546 while (1) { 1547 if (!opts.verbose) { 1548 if (entry->flags & INDEX_ENTRY_END) 1549 break; 1550 entry = (INDEX_ENTRY *)((u8 *)entry + 1551 le16_to_cpu(entry->length)); 1552 numb_entries++; 1553 continue; 1554 } 1555 ntfs_log_verbose("\t\tEntry length:\t\t %u (0x%x)\n", 1556 (unsigned)le16_to_cpu(entry->length), 1557 (unsigned)le16_to_cpu(entry->length)); 1558 ntfs_log_verbose("\t\tKey length:\t\t %u (0x%x)\n", 1559 (unsigned)le16_to_cpu(entry->key_length), 1560 (unsigned)le16_to_cpu(entry->key_length)); 1561 ntfs_log_verbose("\t\tIndex entry flags:\t 0x%02x\n", 1562 (unsigned)le16_to_cpu(entry->flags)); 1563 1564 if (entry->flags & INDEX_ENTRY_NODE) 1565 ntfs_log_verbose("\t\tSubnode VCN:\t\t %lld (0x%llx)\n", 1566 ntfs_ie_get_vcn(entry), 1567 ntfs_ie_get_vcn(entry)); 1568 if (entry->flags & INDEX_ENTRY_END) 1569 break; 1570 1571 switch (type) { 1572 case INDEX_ATTR_DIRECTORY_I30: 1573 ntfs_log_verbose("\t\tFILE record number:\t %llu " 1574 "(0x%llx)\n", (unsigned long long) 1575 MREF_LE(entry->u.indexed_file), 1576 (unsigned long long) 1577 MREF_LE(entry->u.indexed_file)); 1578 ntfs_dump_filename("\t\t", &entry->key.file_name); 1579 break; 1580 default: 1581 ntfs_log_verbose("\t\tData offset:\t\t %u (0x%x)\n", 1582 (unsigned) 1583 le16_to_cpu(entry->u.s.data_offset), 1584 (unsigned) 1585 le16_to_cpu(entry->u.s.data_offset)); 1586 ntfs_log_verbose("\t\tData length:\t\t %u (0x%x)\n", 1587 (unsigned) 1588 le16_to_cpu(entry->u.s.data_length), 1589 (unsigned) 1590 le16_to_cpu(entry->u.s.data_length)); 1591 ntfs_dump_index_key(entry, type); 1592 ntfs_log_verbose("\t\tKey Data:\n"); 1593 ntfs_dump_index_data(entry, type); 1594 break; 1595 } 1596 if (!entry->length) { 1597 ntfs_log_verbose("\tWARNING: Corrupt index entry, " 1598 "skipping the remainder of this index " 1599 "block.\n"); 1600 break; 1601 } 1602 entry = (INDEX_ENTRY*)((u8*)entry + le16_to_cpu(entry->length)); 1603 numb_entries++; 1604 ntfs_log_verbose("\n"); 1605 } 1606 ntfs_log_verbose("\tEnd of index block reached\n"); 1607 return numb_entries; 1608} 1609 1610#define COMPARE_INDEX_NAMES(attr, name) \ 1611 ntfs_names_are_equal((name), sizeof(name) / 2 - 1, \ 1612 (ntfschar*)((char*)(attr) + le16_to_cpu((attr)->name_offset)), \ 1613 (attr)->name_length, 0, NULL, 0) 1614 1615static INDEX_ATTR_TYPE get_index_attr_type(ntfs_inode *ni, ATTR_RECORD *attr, 1616 INDEX_ROOT *index_root) 1617{ 1618 char file_name[64]; 1619 1620 if (!attr->name_length) 1621 return INDEX_ATTR_UNKNOWN; 1622 1623 if (index_root->type) { 1624 if (index_root->type == AT_FILE_NAME) 1625 return INDEX_ATTR_DIRECTORY_I30; 1626 else 1627 /* weird, this should be illegal */ 1628 ntfs_log_error("Unknown index attribute type: 0x%0X\n", 1629 index_root->type); 1630 return INDEX_ATTR_UNKNOWN; 1631 } 1632 1633 if (utils_is_metadata(ni) <= 0) 1634 return INDEX_ATTR_UNKNOWN; 1635 if (utils_inode_get_name(ni, file_name, sizeof(file_name)) <= 0) 1636 return INDEX_ATTR_UNKNOWN; 1637 1638 if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SDH)) 1639 return INDEX_ATTR_SECURE_SDH; 1640 else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SII)) 1641 return INDEX_ATTR_SECURE_SII; 1642 else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_SII)) 1643 return INDEX_ATTR_SECURE_SII; 1644 else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_Q)) 1645 return INDEX_ATTR_QUOTA_Q; 1646 else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_R)) 1647 return INDEX_ATTR_REPARSE_R; 1648 else if (COMPARE_INDEX_NAMES(attr, NTFS_INDEX_O)) { 1649 if (!strcmp(file_name, "/$Extend/$Quota")) 1650 return INDEX_ATTR_QUOTA_O; 1651 else if (!strcmp(file_name, "/$Extend/$ObjId")) 1652 return INDEX_ATTR_OBJID_O; 1653 } 1654 1655 return INDEX_ATTR_UNKNOWN; 1656} 1657 1658static void ntfs_dump_index_attr_type(INDEX_ATTR_TYPE type) 1659{ 1660 if (type == INDEX_ATTR_DIRECTORY_I30) 1661 printf("DIRECTORY_I30"); 1662 else if (type == INDEX_ATTR_SECURE_SDH) 1663 printf("SECURE_SDH"); 1664 else if (type == INDEX_ATTR_SECURE_SII) 1665 printf("SECURE_SII"); 1666 else if (type == INDEX_ATTR_OBJID_O) 1667 printf("OBJID_O"); 1668 else if (type == INDEX_ATTR_QUOTA_O) 1669 printf("QUOTA_O"); 1670 else if (type == INDEX_ATTR_QUOTA_Q) 1671 printf("QUOTA_Q"); 1672 else if (type == INDEX_ATTR_REPARSE_R) 1673 printf("REPARSE_R"); 1674 else 1675 printf("UNKNOWN"); 1676 printf("\n"); 1677} 1678 1679static void ntfs_dump_index_header(const char *indent, INDEX_HEADER *idx) 1680{ 1681 printf("%sEntries Offset:\t\t %u (0x%x)\n", indent, 1682 (unsigned)le32_to_cpu(idx->entries_offset), 1683 (unsigned)le32_to_cpu(idx->entries_offset)); 1684 printf("%sIndex Size:\t\t %u (0x%x)\n", indent, 1685 (unsigned)le32_to_cpu(idx->index_length), 1686 (unsigned)le32_to_cpu(idx->index_length)); 1687 printf("%sAllocated Size:\t\t %u (0x%x)\n", indent, 1688 (unsigned)le32_to_cpu(idx->allocated_size), 1689 (unsigned)le32_to_cpu(idx->allocated_size)); 1690 printf("%sIndex header flags:\t 0x%02x\n", indent, idx->flags); 1691 1692 /* FIXME: there are 3 reserved bytes here */ 1693} 1694 1695/** 1696 * ntfs_dump_attr_index_root() 1697 * 1698 * dump the index_root attribute 1699 */ 1700static void ntfs_dump_attr_index_root(ATTR_RECORD *attr, ntfs_inode *ni) 1701{ 1702 INDEX_ATTR_TYPE type; 1703 INDEX_ROOT *index_root = NULL; 1704 INDEX_ENTRY *entry; 1705 1706 index_root = (INDEX_ROOT*)((u8*)attr + le16_to_cpu(attr->u.res.value_offset)); 1707 1708 /* attr_type dumping */ 1709 type = get_index_attr_type(ni, attr, index_root); 1710 printf("\tIndexed Attr Type:\t "); 1711 ntfs_dump_index_attr_type(type); 1712 1713 /* collation rule dumping */ 1714 printf("\tCollation Rule:\t\t %u (0x%x)\n", 1715 (unsigned)le32_to_cpu(index_root->collation_rule), 1716 (unsigned)le32_to_cpu(index_root->collation_rule)); 1717/* COLLATION_BINARY, COLLATION_FILE_NAME, COLLATION_UNICODE_STRING, 1718 COLLATION_NTOFS_ULONG, COLLATION_NTOFS_SID, 1719 COLLATION_NTOFS_SECURITY_HASH, COLLATION_NTOFS_ULONGS */ 1720 1721 printf("\tIndex Block Size:\t %u (0x%x)\n", 1722 (unsigned)le32_to_cpu(index_root->index_block_size), 1723 (unsigned)le32_to_cpu(index_root->index_block_size)); 1724 printf("\tClusters Per Block:\t %u (0x%x)\n", 1725 (unsigned)index_root->clusters_per_index_block, 1726 (unsigned)index_root->clusters_per_index_block); 1727 1728 ntfs_dump_index_header("\t", &index_root->index); 1729 1730 entry = (INDEX_ENTRY*)((u8*)index_root + 1731 le32_to_cpu(index_root->index.entries_offset) + 0x10); 1732 ntfs_log_verbose("\tDumping index root:\n"); 1733 printf("\tIndex entries total:\t %d\n", 1734 ntfs_dump_index_entries(entry, type)); 1735} 1736 1737static void ntfs_dump_usa_lsn(const char *indent, MFT_RECORD *mrec) 1738{ 1739 printf("%sUpd. Seq. Array Off.:\t %u (0x%x)\n", indent, 1740 (unsigned)le16_to_cpu(mrec->usa_ofs), 1741 (unsigned)le16_to_cpu(mrec->usa_ofs)); 1742 printf("%sUpd. Seq. Array Count:\t %u (0x%x)\n", indent, 1743 (unsigned)le16_to_cpu(mrec->usa_count), 1744 (unsigned)le16_to_cpu(mrec->usa_count)); 1745 printf("%sUpd. Seq. Number:\t %u (0x%x)\n", indent, 1746 (unsigned)le16_to_cpup((u16 *)((u8 *)mrec + 1747 le16_to_cpu(mrec->usa_ofs))), 1748 (unsigned)le16_to_cpup((u16 *)((u8 *)mrec + 1749 le16_to_cpu(mrec->usa_ofs)))); 1750 printf("%sLogFile Seq. Number:\t 0x%llx\n", indent, 1751 (unsigned long long)sle64_to_cpu(mrec->lsn)); 1752} 1753 1754 1755static s32 ntfs_dump_index_block(INDEX_BLOCK *ib, INDEX_ATTR_TYPE type, 1756 u32 ib_size) 1757{ 1758 INDEX_ENTRY *entry; 1759 1760 if (ntfs_mst_post_read_fixup((NTFS_RECORD*)ib, ib_size)) { 1761 ntfs_log_perror("Damaged INDX record"); 1762 return -1; 1763 } 1764 ntfs_log_verbose("\tDumping index block:\n"); 1765 if (opts.verbose) 1766 ntfs_dump_usa_lsn("\t\t", (MFT_RECORD*)ib); 1767 1768 ntfs_log_verbose("\t\tNode VCN:\t\t %lld (0x%llx)\n", 1769 (unsigned long long)sle64_to_cpu(ib->index_block_vcn), 1770 (unsigned long long)sle64_to_cpu(ib->index_block_vcn)); 1771 1772 entry = (INDEX_ENTRY*)((u8*)ib + 1773 le32_to_cpu(ib->index.entries_offset) + 0x18); 1774 1775 if (opts.verbose) { 1776 ntfs_dump_index_header("\t\t", &ib->index); 1777 printf("\n"); 1778 } 1779 1780 return ntfs_dump_index_entries(entry, type); 1781} 1782 1783/** 1784 * ntfs_dump_attr_index_allocation() 1785 * 1786 * dump context of the index_allocation attribute 1787 */ 1788static void ntfs_dump_attr_index_allocation(ATTR_RECORD *attr, ntfs_inode *ni) 1789{ 1790 INDEX_ALLOCATION *allocation, *tmp_alloc; 1791 INDEX_ROOT *ir; 1792 INDEX_ATTR_TYPE type; 1793 int total_entries = 0; 1794 int total_indx_blocks = 0; 1795 u8 *bitmap, *byte; 1796 int bit; 1797 ntfschar *name; 1798 u32 name_len; 1799 s64 data_size; 1800 1801 ir = ntfs_index_root_get(ni, attr); 1802 if (!ir) { 1803 ntfs_log_perror("Failed to read $INDEX_ROOT attribute"); 1804 return; 1805 } 1806 1807 type = get_index_attr_type(ni, attr, ir); 1808 1809 name = (ntfschar *)((u8 *)attr + le16_to_cpu(attr->name_offset)); 1810 name_len = attr->name_length; 1811 1812 byte = bitmap = ntfs_attr_readall(ni, AT_BITMAP, name, name_len, NULL); 1813 if (!byte) { 1814 ntfs_log_perror("Failed to read $BITMAP attribute"); 1815 goto out_index_root; 1816 } 1817 1818 tmp_alloc = allocation = ntfs_attr_readall(ni, AT_INDEX_ALLOCATION, 1819 name, name_len, &data_size); 1820 if (!tmp_alloc) { 1821 ntfs_log_perror("Failed to read $INDEX_ALLOCATION attribute"); 1822 goto out_bitmap; 1823 } 1824 1825 bit = 0; 1826 while ((u8 *)tmp_alloc < (u8 *)allocation + data_size) { 1827 if (*byte & (1 << bit)) { 1828 int entries; 1829 1830 entries = ntfs_dump_index_block(tmp_alloc, type, 1831 le32_to_cpu( 1832 ir->index_block_size)); 1833 if (entries != -1) { 1834 total_entries += entries; 1835 total_indx_blocks++; 1836 ntfs_log_verbose("\tIndex entries:\t\t %d\n", 1837 entries); 1838 } 1839 } 1840 tmp_alloc = (INDEX_ALLOCATION *)((u8 *)tmp_alloc + 1841 le32_to_cpu( 1842 ir->index_block_size)); 1843 bit++; 1844 if (bit > 7) { 1845 bit = 0; 1846 byte++; 1847 } 1848 } 1849 1850 printf("\tIndex entries total:\t %d\n", total_entries); 1851 printf("\tINDX blocks total:\t %d\n", total_indx_blocks); 1852 1853 free(allocation); 1854out_bitmap: 1855 free(bitmap); 1856out_index_root: 1857 free(ir); 1858} 1859 1860/** 1861 * ntfs_dump_attr_bitmap() 1862 * 1863 * dump the bitmap attribute 1864 */ 1865static void ntfs_dump_attr_bitmap(ATTR_RECORD *attr __attribute__((unused))) 1866{ 1867 /* TODO */ 1868} 1869 1870/** 1871 * ntfs_dump_attr_reparse_point() 1872 * 1873 * of ntfs 3.x dumps the reparse_point attribute 1874 */ 1875static void ntfs_dump_attr_reparse_point(ATTR_RECORD *attr __attribute__((unused))) 1876{ 1877 /* TODO */ 1878} 1879 1880/** 1881 * ntfs_dump_attr_ea_information() 1882 * 1883 * dump the ea_information attribute 1884 */ 1885static void ntfs_dump_attr_ea_information(ATTR_RECORD *attr) 1886{ 1887 EA_INFORMATION *ea_info; 1888 1889 ea_info = (EA_INFORMATION*)((u8*)attr + 1890 le16_to_cpu(attr->u.res.value_offset)); 1891 printf("\tPacked EA length:\t %u (0x%x)\n", 1892 (unsigned)le16_to_cpu(ea_info->ea_length), 1893 (unsigned)le16_to_cpu(ea_info->ea_length)); 1894 printf("\tNEED_EA count:\t\t %u (0x%x)\n", 1895 (unsigned)le16_to_cpu(ea_info->need_ea_count), 1896 (unsigned)le16_to_cpu(ea_info->need_ea_count)); 1897 printf("\tUnpacked EA length:\t %u (0x%x)\n", 1898 (unsigned)le32_to_cpu(ea_info->ea_query_length), 1899 (unsigned)le32_to_cpu(ea_info->ea_query_length)); 1900} 1901 1902/** 1903 * ntfs_dump_attr_ea() 1904 * 1905 * dump the ea attribute 1906 */ 1907static void ntfs_dump_attr_ea(ATTR_RECORD *attr, ntfs_volume *vol) 1908{ 1909 EA_ATTR *ea; 1910 u8 *buf = NULL; 1911 s64 data_size; 1912 1913 if (attr->non_resident) { 1914 runlist *rl; 1915 1916 data_size = sle64_to_cpu(attr->u.nonres.data_size); 1917 if (!opts.verbose) 1918 return; 1919 /* FIXME: We don't handle fragmented mapping pairs case. */ 1920 rl = ntfs_mapping_pairs_decompress(vol, attr, NULL); 1921 if (rl) { 1922 s64 bytes_read; 1923 1924 buf = ntfs_malloc(data_size); 1925 if (!buf) { 1926 free(rl); 1927 return; 1928 } 1929 bytes_read = ntfs_rl_pread(vol, rl, 0, data_size, buf); 1930 if (bytes_read != data_size) { 1931 ntfs_log_perror("ntfs_rl_pread failed"); 1932 free(buf); 1933 free(rl); 1934 return; 1935 } 1936 free(rl); 1937 ea = (EA_ATTR*)buf; 1938 } else { 1939 ntfs_log_perror("ntfs_mapping_pairs_decompress failed"); 1940 return; 1941 } 1942 } else { 1943 data_size = le32_to_cpu(attr->u.res.value_length); 1944 if (!opts.verbose) 1945 return; 1946 ea = (EA_ATTR*)((u8*)attr + le16_to_cpu(attr->u.res.value_offset)); 1947 } 1948 while (1) { 1949 printf("\n\tEA flags:\t\t "); 1950 if (ea->flags) { 1951 if (ea->flags == NEED_EA) 1952 printf("NEED_EA\n"); 1953 else 1954 printf("Unknown (0x%02x)\n", 1955 (unsigned)ea->flags); 1956 } else 1957 printf("NONE\n"); 1958 printf("\tName length:\t %d (0x%x)\n", 1959 (unsigned)ea->name_length, 1960 (unsigned)ea->name_length); 1961 printf("\tValue length:\t %d (0x%x)\n", 1962 (unsigned)le16_to_cpu(ea->value_length), 1963 (unsigned)le16_to_cpu(ea->value_length)); 1964 printf("\tName:\t\t '%s'\n", ea->name); 1965 printf("\tValue:\t\t "); 1966 if (ea->name_length == 11 && 1967 !strncmp((const char*)"SETFILEBITS", 1968 (const char*)ea->name, 11)) 1969 printf("0%o\n", (unsigned)le32_to_cpu(*(le32*) 1970 (ea->name + ea->name_length + 1))); 1971 else 1972 printf("'%s'\n", ea->name + ea->name_length + 1); 1973 if (ea->next_entry_offset) 1974 ea = (EA_ATTR*)((u8*)ea + 1975 le32_to_cpu(ea->next_entry_offset)); 1976 else 1977 break; 1978 if ((u8*)ea - buf >= data_size) 1979 break; 1980 } 1981 free(buf); 1982} 1983 1984/** 1985 * ntfs_dump_attr_property_set() 1986 * 1987 * dump the property_set attribute 1988 */ 1989static void ntfs_dump_attr_property_set(ATTR_RECORD *attr __attribute__((unused))) 1990{ 1991 /* TODO */ 1992} 1993 1994static void ntfs_hex_dump(void *buf,unsigned int length); 1995 1996/** 1997 * ntfs_dump_attr_logged_utility_stream() 1998 * 1999 * dump the property_set attribute 2000 */ 2001static void ntfs_dump_attr_logged_utility_stream(ATTR_RECORD *attr, 2002 ntfs_inode *ni) 2003{ 2004 char *buf; 2005 s64 size; 2006 2007 if (!opts.verbose) 2008 return; 2009 buf = ntfs_attr_readall(ni, AT_LOGGED_UTILITY_STREAM, 2010 ntfs_attr_get_name(attr), attr->name_length, &size); 2011 if (buf) 2012 ntfs_hex_dump(buf, size); 2013 free(buf); 2014 /* TODO */ 2015} 2016 2017/** 2018 * ntfs_hex_dump 2019 */ 2020static void ntfs_hex_dump(void *buf,unsigned int length) 2021{ 2022 unsigned int i=0; 2023 while (i<length) { 2024 unsigned int j; 2025 2026 /* line start */ 2027 printf("\t%04X ",i); 2028 2029 /* hex content */ 2030 for (j=i;(j<length) && (j<i+16);j++) { 2031 unsigned char c = *((char *)buf + j); 2032 printf("%02hhX ",c); 2033 } 2034 2035 /* realign */ 2036 for (;j<i+16;j++) { 2037 printf(" "); 2038 } 2039 2040 /* char content */ 2041 for (j=i;(j<length) && (j<i+16);j++) { 2042 unsigned char c = *((char *)buf + j); 2043 /* display unprintable chars as '.' */ 2044 if ((c<32) || (c>126)) { 2045 c = '.'; 2046 } 2047 printf("%c",c); 2048 } 2049 2050 /* end line */ 2051 printf("\n"); 2052 i=j; 2053 } 2054} 2055 2056/** 2057 * ntfs_dump_attr_unknown 2058 */ 2059static void ntfs_dump_attr_unknown(ATTR_RECORD *attr) 2060{ 2061 printf("===== Please report this unknown attribute type to %s =====\n", 2062 NTFS_DEV_LIST); 2063 2064 if (!attr->non_resident) { 2065 /* hex dump */ 2066 printf("\tDumping some of the attribute data:\n"); 2067 ntfs_hex_dump((u8*)attr + le16_to_cpu(attr->u.res.value_offset), 2068 (le32_to_cpu(attr->u.res.value_length) > 128) ? 2069 128 : le32_to_cpu(attr->u.res.value_length)); 2070 } 2071} 2072 2073/** 2074 * ntfs_dump_inode_general_info 2075 */ 2076static void ntfs_dump_inode_general_info(ntfs_inode *inode) 2077{ 2078 MFT_RECORD *mrec = inode->mrec; 2079 le16 inode_flags = mrec->flags; 2080 2081 printf("Dumping Inode %llu (0x%llx)\n", 2082 (long long)inode->mft_no, 2083 (unsigned long long)inode->mft_no); 2084 2085 ntfs_dump_usa_lsn("", mrec); 2086 printf("MFT Record Seq. Numb.:\t %u (0x%x)\n", 2087 (unsigned)le16_to_cpu(mrec->sequence_number), 2088 (unsigned)le16_to_cpu(mrec->sequence_number)); 2089 printf("Number of Hard Links:\t %u (0x%x)\n", 2090 (unsigned)le16_to_cpu(mrec->link_count), 2091 (unsigned)le16_to_cpu(mrec->link_count)); 2092 printf("Attribute Offset:\t %u (0x%x)\n", 2093 (unsigned)le16_to_cpu(mrec->attrs_offset), 2094 (unsigned)le16_to_cpu(mrec->attrs_offset)); 2095 2096 printf("MFT Record Flags:\t "); 2097 if (inode_flags) { 2098 if (MFT_RECORD_IN_USE & inode_flags) { 2099 printf("IN_USE "); 2100 inode_flags &= ~MFT_RECORD_IN_USE; 2101 } 2102 if (MFT_RECORD_IS_DIRECTORY & inode_flags) { 2103 printf("DIRECTORY "); 2104 inode_flags &= ~MFT_RECORD_IS_DIRECTORY; 2105 } 2106 /* The meaning of IS_4 is illusive but not its existence. */ 2107 if (MFT_RECORD_IS_4 & inode_flags) { 2108 printf("IS_4 "); 2109 inode_flags &= ~MFT_RECORD_IS_4; 2110 } 2111 if (MFT_RECORD_IS_VIEW_INDEX & inode_flags) { 2112 printf("VIEW_INDEX "); 2113 inode_flags &= ~MFT_RECORD_IS_VIEW_INDEX; 2114 } 2115 if (inode_flags) 2116 printf("UNKNOWN: 0x%04x", (unsigned)le16_to_cpu( 2117 inode_flags)); 2118 } else { 2119 printf("none"); 2120 } 2121 printf("\n"); 2122 2123 printf("Bytes Used:\t\t %u (0x%x) bytes\n", 2124 (unsigned)le32_to_cpu(mrec->bytes_in_use), 2125 (unsigned)le32_to_cpu(mrec->bytes_in_use)); 2126 printf("Bytes Allocated:\t %u (0x%x) bytes\n", 2127 (unsigned)le32_to_cpu(mrec->bytes_allocated), 2128 (unsigned)le32_to_cpu(mrec->bytes_allocated)); 2129 2130 if (mrec->base_mft_record) { 2131 printf("Base MFT Record:\t %llu (0x%llx)\n", 2132 (unsigned long long) 2133 MREF_LE(mrec->base_mft_record), 2134 (unsigned long long) 2135 MREF_LE(mrec->base_mft_record)); 2136 } 2137 printf("Next Attribute Instance: %u (0x%x)\n", 2138 (unsigned)le16_to_cpu(mrec->next_attr_instance), 2139 (unsigned)le16_to_cpu(mrec->next_attr_instance)); 2140 2141 printf("MFT Padding:\t"); 2142 ntfs_dump_bytes((u8 *)mrec, le16_to_cpu(mrec->usa_ofs) + 2143 2 * le16_to_cpu(mrec->usa_count), 2144 le16_to_cpu(mrec->attrs_offset)); 2145 printf("\n"); 2146} 2147 2148/** 2149 * ntfs_get_file_attributes 2150 */ 2151static void ntfs_dump_file_attributes(ntfs_inode *inode) 2152{ 2153 ntfs_attr_search_ctx *ctx = NULL; 2154 2155 /* then start enumerating attributes 2156 see ntfs_attr_lookup documentation for detailed explanation */ 2157 ctx = ntfs_attr_get_search_ctx(inode, NULL); 2158 while (!ntfs_attr_lookup(AT_UNUSED, NULL, 0, 0, 0, NULL, 0, ctx)) { 2159 if (ctx->attr->type == AT_END || ctx->attr->type == AT_UNUSED) { 2160 printf("Weird: %s attribute type was found, please " 2161 "report this.\n", 2162 get_attribute_type_name( 2163 ctx->attr->type)); 2164 continue; 2165 } 2166 2167 ntfs_dump_attribute_header(ctx, inode->vol); 2168 2169 switch (ctx->attr->type) { 2170 case AT_STANDARD_INFORMATION: 2171 ntfs_dump_attr_standard_information(ctx->attr); 2172 break; 2173 case AT_ATTRIBUTE_LIST: 2174 ntfs_dump_attr_list(ctx->attr, inode->vol); 2175 break; 2176 case AT_FILE_NAME: 2177 ntfs_dump_attr_file_name(ctx->attr); 2178 break; 2179 case AT_OBJECT_ID: 2180 ntfs_dump_attr_object_id(ctx->attr, inode->vol); 2181 break; 2182 case AT_SECURITY_DESCRIPTOR: 2183 ntfs_dump_attr_security_descriptor(ctx->attr, 2184 inode->vol); 2185 break; 2186 case AT_VOLUME_NAME: 2187 ntfs_dump_attr_volume_name(ctx->attr); 2188 break; 2189 case AT_VOLUME_INFORMATION: 2190 ntfs_dump_attr_volume_information(ctx->attr); 2191 break; 2192 case AT_DATA: 2193 ntfs_dump_attr_data(ctx->attr, inode); 2194 break; 2195 case AT_INDEX_ROOT: 2196 ntfs_dump_attr_index_root(ctx->attr, inode); 2197 break; 2198 case AT_INDEX_ALLOCATION: 2199 ntfs_dump_attr_index_allocation(ctx->attr, inode); 2200 break; 2201 case AT_BITMAP: 2202 ntfs_dump_attr_bitmap(ctx->attr); 2203 break; 2204 case AT_REPARSE_POINT: 2205 ntfs_dump_attr_reparse_point(ctx->attr); 2206 break; 2207 case AT_EA_INFORMATION: 2208 ntfs_dump_attr_ea_information(ctx->attr); 2209 break; 2210 case AT_EA: 2211 ntfs_dump_attr_ea(ctx->attr, inode->vol); 2212 break; 2213 case AT_PROPERTY_SET: 2214 ntfs_dump_attr_property_set(ctx->attr); 2215 break; 2216 case AT_LOGGED_UTILITY_STREAM: 2217 ntfs_dump_attr_logged_utility_stream(ctx->attr, inode); 2218 break; 2219 default: 2220 ntfs_dump_attr_unknown(ctx->attr); 2221 } 2222 } 2223 2224 /* if we exited the loop before we're done - notify the user */ 2225 if (errno != ENOENT) { 2226 ntfs_log_perror("ntfsinfo error: stopped before finished " 2227 "enumerating attributes"); 2228 } else { 2229 printf("End of inode reached\n"); 2230 } 2231 2232 /* close all data-structures we used */ 2233 ntfs_attr_put_search_ctx(ctx); 2234 ntfs_inode_close(inode); 2235} 2236 2237/** 2238 * main() - Begin here 2239 * 2240 * Start from here. 2241 * 2242 * Return: 0 Success, the program worked 2243 * 1 Error, something went wrong 2244 */ 2245int main(int argc, char **argv) 2246{ 2247 ntfs_volume *vol; 2248 2249 setlinebuf(stdout); 2250 2251 ntfs_log_set_handler(ntfs_log_handler_outerr); 2252 2253 if (!parse_options(argc, argv)) { 2254 printf("Failed to parse command line options\n"); 2255 exit(1); 2256 } 2257 2258 utils_set_locale(); 2259 2260 vol = utils_mount_volume(opts.device, NTFS_MNT_RDONLY | 2261 (opts.force ? NTFS_MNT_FORCE : 0)); 2262 if (!vol) { 2263 printf("Failed to open '%s'.\n", opts.device); 2264 exit(1); 2265 } 2266 2267 /* 2268 * if opts.mft is not 0, then we will print out information about 2269 * the volume, such as the sector size and whatnot. 2270 */ 2271 if (opts.mft) 2272 ntfs_dump_volume(vol); 2273 2274 if ((opts.inode != -1) || opts.filename) { 2275 ntfs_inode *inode; 2276 /* obtain the inode */ 2277 if (opts.filename) { 2278 inode = ntfs_pathname_to_inode(vol, NULL, 2279 opts.filename); 2280 } else { 2281 inode = ntfs_inode_open(vol, MK_MREF(opts.inode, 0)); 2282 } 2283 2284 /* dump the inode information */ 2285 if (inode) { 2286 /* general info about the inode's mft record */ 2287 ntfs_dump_inode_general_info(inode); 2288 /* dump attributes */ 2289 ntfs_dump_file_attributes(inode); 2290 } else { 2291 /* can't open inode */ 2292 /* 2293 * note: when the specified inode does not exist, either 2294 * EIO or or ESPIPE is returned, we should notify better 2295 * in those cases 2296 */ 2297 ntfs_log_perror("Error loading node"); 2298 } 2299 } 2300 2301 ntfs_umount(vol, FALSE); 2302 return 0; 2303} 2304 2305