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