• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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