• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *		Process log data from an NTFS partition
3  *
4  * Copyright (c) 2012-2017 Jean-Pierre Andre
5  *
6  *	This program examines the Windows log file of an ntfs partition
7  *	and plays the committed transactions in order to restore the
8  *	integrity of metadata.
9  *
10  *	It can also display the contents of the log file in human-readable
11  *	text, either from a full partition or from the log file itself.
12  *
13  *
14  *            History
15  *
16  *  Sep 2012
17  *     - displayed textual logfile contents forward
18  *
19  *  Nov 2014
20  *     - decoded multi-page log records
21  *     - displayed textual logfile contents backward
22  *
23  *  Nov 2015
24  *     - made a general cleaning and redesigned as an ntfsprogs
25  *     - applied committed actions from logfile
26  */
27 
28 /*
29  * This program is free software; you can redistribute it and/or modify
30  * it under the terms of the GNU General Public License as published by
31  * the Free Software Foundation; either version 2 of the License, or
32  * (at your option) any later version.
33  *
34  * This program is distributed in the hope that it will be useful,
35  * but WITHOUT ANY WARRANTY; without even the implied warranty of
36  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
37  * GNU General Public License for more details.
38  *
39  * You should have received a copy of the GNU General Public License
40  * along with this program (in the main directory of the NTFS-3G
41  * distribution in the file COPYING); if not, write to the Free Software
42  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
43  */
44 
45 #define BASEBLKS 4 /* number of special blocks (always shown) */
46 #define BASEBLKS2 34 /* number of special blocks when version >= 2.0 */
47 #define RSTBLKS 2 /* number of restart blocks */
48 #define BUFFERCNT 64 /* number of block buffers - a power of 2 */
49 #define NTFSBLKLTH 512 /* usa block size */
50 #define SHOWATTRS 20 /* max attrs shown in a dump */
51 #define SHOWLISTS 10 /* max lcn or lsn shown in a list */
52 #define BLOCKBITS 9 /* This is only used to read the restart page */
53 #define MAXEXCEPTION 10 /* Max number of exceptions (option -x) */
54 #define MINRECSIZE 48 /* Minimal log record size */
55 #define MAXRECSIZE 65536 /* Maximal log record size (seen > 56000) */
56 
57 #include "config.h"
58 
59 #ifdef HAVE_STDLIB_H
60 #include <stdlib.h>
61 #endif
62 #ifdef HAVE_STDIO_H
63 #include <stdio.h>
64 #endif
65 #ifdef HAVE_UNISTD_H
66 #include <unistd.h>
67 #endif
68 #ifdef HAVE_FCNTL_H
69 #include <fcntl.h>
70 #endif
71 #ifdef HAVE_ERRNO_H
72 #include <errno.h>
73 #endif
74 #ifdef HAVE_STRING_H
75 #include <string.h>
76 #endif
77 #ifdef HAVE_GETOPT_H
78 #include <getopt.h>
79 #endif
80 #ifdef HAVE_MALLOC_H
81 #include <malloc.h>
82 #endif
83 #ifdef HAVE_TIME_H
84 #include <time.h>
85 #endif
86 
87 #include "types.h"
88 #include "endians.h"
89 #include "support.h"
90 #include "layout.h"
91 #include "param.h"
92 #include "ntfstime.h"
93 #include "device_io.h"
94 #include "device.h"
95 #include "logging.h"
96 #include "runlist.h"
97 #include "mft.h"
98 #include "inode.h"
99 #include "attrib.h"
100 #include "bitmap.h"
101 #include "index.h"
102 #include "volume.h"
103 #include "unistr.h"
104 #include "mst.h"
105 #include "logfile.h"
106 #include "ntfsrecover.h"
107 #include "utils.h"
108 #include "misc.h"
109 
110 typedef struct {
111 	ntfs_volume *vol;
112 	FILE *file;
113 	struct ACTION_RECORD *firstaction;
114 	struct ACTION_RECORD *lastaction;
115 } CONTEXT;
116 
117 typedef enum { T_OK, T_ERR, T_DONE } TRISTATE;
118 
119 RESTART_PAGE_HEADER log_header;
120 RESTART_AREA restart;
121 LOG_CLIENT_RECORD client;
122 u32 clustersz = 0;
123 int clusterbits;
124 u32 blocksz;
125 int blockbits;
126 int log_major;
127 u16 bytespersect;
128 u64 mftlcn;
129 u32 mftrecsz;
130 int mftrecbits;
131 u32 mftcnt; /* number of entries */
132 ntfs_inode *log_ni;
133 ntfs_attr *log_na;
134 u64 logfilelcn;
135 u32 logfilesz; /* bytes */
136 u64 redos_met;
137 u64 committed_lsn;
138 u64 synced_lsn;
139 u64 latest_lsn;
140 u64 restart_lsn;
141 u64 offset_mask; /* block number in an lsn */
142 unsigned long firstblk; /* first block to dump (option -r) */
143 unsigned long lastblk;  /* last block to dump (option -r) */
144 u64 firstlcn; /* first block to dump (option -c) */
145 u64 lastlcn;  /* last block to dump (option -c) */
146 BOOL optb; /* show the log backward */
147 BOOL optc; /* restrict to cluster range */
148 BOOL optd; /* device argument present*/
149 BOOL opth; /* show help */
150 BOOL opti; /* show invalid (stale) records */
151 BOOL optf; /* show full log */
152 BOOL optk; /* kill fast restart */
153 BOOL optn; /* do not apply modifications */
154 BOOL optp; /* count of transaction sets to play */
155 BOOL optr; /* show a range of blocks */
156 int opts; /* sync the file system */
157 BOOL optt; /* show transactions */
158 BOOL optu; /* count of transaction sets to undo */
159 int optv; /* verbose */
160 int optV; /* version */
161 int optx[MAXEXCEPTION + 1];
162 struct ATTR **attrtable;
163 unsigned int actionnum;
164 unsigned int attrcount;
165 unsigned int playcount;
166 unsigned int playedactions; // change the name
167 unsigned int redocount;
168 unsigned int undocount;
169 struct BUFFER *buffer_table[BASEBLKS + BUFFERCNT];
170 unsigned int redirect[BASEBLKS2];
171 
172 static const le16 SDS[4] = {
173 	const_cpu_to_le16('$'), const_cpu_to_le16('S'),
174 	const_cpu_to_le16('D'), const_cpu_to_le16('S')
175 } ;
176 
177 static const le16 I30[4] = {
178 	const_cpu_to_le16('$'), const_cpu_to_le16('I'),
179 	const_cpu_to_le16('3'), const_cpu_to_le16('0')
180 } ;
181 
182 /*
183  *		Byte address of a log block
184  */
185 
loclogblk(CONTEXT * ctx,unsigned int blk)186 static s64 loclogblk(CONTEXT *ctx, unsigned int blk)
187 {
188 	s64 loc;
189 	LCN lcn;
190 
191 	if (ctx->vol) {
192 		lcn = ntfs_attr_vcn_to_lcn(log_na,
193 				((s64)blk << blockbits) >> clusterbits);
194 		loc = lcn << clusterbits;
195 	} else {
196 		if (((s64)blk << blockbits) >= logfilesz)
197 			loc = -1;
198 		else
199 			loc = (logfilelcn << clusterbits)
200 				+ ((s64)blk << blockbits);
201 	}
202 	return (loc);
203 }
204 
205 /*
206  *		Deprotect a block
207  *	Only to be used for log buffers
208  *
209  *	Returns 0 if block was found correct
210  */
211 
replaceusa(struct BUFFER * buffer,unsigned int lth)212 static int replaceusa(struct BUFFER *buffer, unsigned int lth)
213 {
214 	char *buf;
215 	RECORD_PAGE_HEADER *record;
216 	unsigned int j;
217 	BOOL err;
218 	unsigned int used;
219 	unsigned int xusa, nusa;
220 
221 	err = FALSE;
222 			/* Restart blocks have no protection */
223 	if (buffer->num >= RSTBLKS) {
224 			/* Do not check beyond used sectors */
225 		record = &buffer->block.record;
226 		used = blocksz;
227 		xusa = le16_to_cpu(record->usa_ofs);
228 		nusa = le16_to_cpu(record->usa_count);
229 		if (xusa && nusa
230 		   && ((xusa + 1) < lth)
231 		   && ((nusa - 1)*NTFSBLKLTH == lth)) {
232 			buf = buffer->block.data;
233 			for (j=1; (j<nusa) && ((j-1)*NTFSBLKLTH<used); j++)
234 				if ((buf[xusa] == buf[j*NTFSBLKLTH - 2])
235 				   && (buf[xusa+1] == buf[j*NTFSBLKLTH - 1])) {
236 					buf[j*NTFSBLKLTH - 2] = buf[xusa + 2*j];
237 					buf[j*NTFSBLKLTH - 1] = buf[xusa + 2*j + 1];
238 				} else {
239 					printf("* Update sequence number %d does not match\n",j);
240 					err = TRUE;
241 				}
242 		}
243 	}
244    return (err);
245    }
246 
247 /*
248  *		Dynamically allocate an attribute key.
249  *
250  *	As the possible values for a key depend on the version, we
251  *	cannot convert it to an index, so we make dichotomical searches
252  */
253 
getattrentry(unsigned int key,unsigned int lth)254 struct ATTR *getattrentry(unsigned int key, unsigned int lth)
255 {
256 	struct ATTR *pa;
257 	struct ATTR **old;
258 	unsigned int low, mid, high;
259 
260 	low = 0;
261 	if (attrcount) {
262 		high = attrcount;
263 		while ((low + 1) < high) {
264 			mid = (low + high) >> 1;
265 			if (key < attrtable[mid]->key)
266 				high = mid;
267 			else
268 				if (key > attrtable[mid]->key)
269 					low = mid;
270 				else {
271 					low = mid;
272 					high = mid + 1;
273 				}
274 		}
275 	}
276 	if ((low < attrcount) && (attrtable[low]->key == key)) {
277 		pa = attrtable[low];
278 		if (pa->namelen < lth) {
279 			pa = (struct ATTR*)realloc(pa,
280 					sizeof(struct ATTR) + lth);
281 			attrtable[low] = pa;
282 		}
283 	} else {
284 		mid = low + 1;
285                 if (!low && attrcount && (attrtable[0]->key > key))
286                    mid = 0;
287 		pa = (struct ATTR*)malloc(sizeof(struct ATTR) + lth);
288 		if (pa) {
289 			if (attrcount++) {
290 				old = attrtable;
291 				attrtable = (struct ATTR**)realloc(attrtable,
292 					attrcount*sizeof(struct ATTR*));
293 				if (attrtable) {
294 					high = attrcount;
295 					while (--high > mid)
296 						attrtable[high]
297 							= attrtable[high - 1];
298 					attrtable[mid] = pa;
299 				} else
300 					attrtable = old;
301 			} else {
302 				attrtable = (struct ATTR**)
303 						malloc(sizeof(struct ATTR*));
304 				attrtable[0] = pa;
305 			}
306 		pa->key = key;
307 		pa->namelen = 0;
308 		pa->type = const_cpu_to_le32(0);
309 		pa->inode = 0;
310 		}
311 	}
312 	return (pa);
313 }
314 
315 /*
316  *		Read blocks in a circular buffer
317  *
318  *	returns NULL if block cannot be read or it is found bad
319  *		otherwise returns the full unprotected block data
320  */
321 
read_buffer(CONTEXT * ctx,unsigned int num)322 static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num)
323 {
324 	struct BUFFER *buffer;
325 	BOOL got;
326 	int k;
327 	unsigned int rnum;
328 
329 		/*
330 		 * The first four blocks are stored apart, to make
331 		 * sure pages 2 and 3 and the page which is logically
332 		 * before them can be accessed at the same time.
333 		 * (Only two blocks are stored apart if version >= 2.0)
334 		 * Also, block 0 is smaller because it has to be read
335 		 * before the block size is known.
336 		 * Note : the last block is supposed to have an odd
337 		 * number, and cannot be overwritten by block 4 (or 34
338 		 * if version >= 2.0) which follows logically.
339 		 */
340 	if ((num < RSTBLKS)
341 	    || ((log_major < 2) && (num < BASEBLKS)))
342 		buffer = buffer_table[num + BUFFERCNT];
343 	else
344 		buffer = buffer_table[num & (BUFFERCNT - 1)];
345 	if (buffer && (buffer->size < blocksz)) {
346 		free(buffer);
347 		buffer = (struct BUFFER*)NULL;
348 	}
349 	if (!buffer) {
350 		buffer = (struct BUFFER*)
351 			malloc(sizeof(struct BUFFER) + blocksz);
352 		buffer->size = blocksz;
353 		buffer->rnum = num + 1; /* forced to being read */
354 		buffer->safe = FALSE;
355 		if (num < BASEBLKS)
356 			buffer_table[num + BUFFERCNT] = buffer;
357 		else
358 			buffer_table[num & (BUFFERCNT - 1)] = buffer;
359 	}
360 	rnum = num;
361 	if (log_major >= 2) {
362 		for (k=RSTBLKS; k<BASEBLKS2; k++)
363 			if (redirect[k] == num)
364 				rnum = k;
365 	}
366 	if (buffer && (buffer->rnum != rnum)) {
367 		buffer->num = num;
368 		buffer->rnum = rnum;
369 		if (ctx->vol)
370 			got = (ntfs_attr_pread(log_na,(u64)rnum << blockbits,
371                 		blocksz, buffer->block.data) == blocksz);
372 		else
373 			got = !fseek(ctx->file, loclogblk(ctx, rnum), 0)
374 			    && (fread(buffer->block.data, blocksz,
375 						1, ctx->file) == 1);
376 		if (got) {
377 			char *data = buffer->block.data;
378 			buffer->headsz = sizeof(RECORD_PAGE_HEADER)
379 				+ ((2*getle16(data,6) - 1) | 7) + 1;
380 			buffer->safe = !replaceusa(buffer, blocksz);
381 		} else {
382 			buffer->safe = FALSE;
383 			fprintf(stderr,"** Could not read block %d\n", rnum);
384 		}
385 	}
386 	return (buffer && buffer->safe ? buffer : (const struct BUFFER*)NULL);
387 }
388 
hexdump(const char * buf,unsigned int lth)389 void hexdump(const char *buf, unsigned int lth)
390 {
391 	unsigned int i,j,k;
392 
393 	for (i=0; i<lth; i+=16) {
394 		printf("%04x ",i);
395 		k = ((lth - i) < 16 ? lth : 16 + i);
396 		for (j=i; j<k; j++)
397 			printf((j & 3 ? "%02x" : " %02x"),buf[j] & 255);
398 		printf("%*c",(152 - 9*(j - i))/4,' ');
399 		for (j=i; j<k; j++)
400 			if ((buf[j] > 0x20) && (buf[j] < 0x7f))
401 				printf("%c",buf[j]);
402 			else
403 				printf(".");
404 		printf("\n");
405 	}
406 }
407 
408 /*
409  *	       Display a date
410  */
411 
showdate(const char * text,le64 lestamp)412 static void showdate(const char *text, le64 lestamp)
413 {
414 	time_t utime;
415 	struct tm *ptm;
416 	s64 stamp;
417 	const char *months[]
418 		= { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
419 		    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } ;
420 
421 	stamp = le64_to_cpu(lestamp);
422 	if ((stamp < ((2147000000 + 134774*86400LL)*10000000LL))
423 	    && (stamp > ((-2147000000 + 134774*86400LL)*10000000LL))) {
424 				/* date within traditional Unix limits */
425 		utime = stamp/10000000 - 134774*86400LL;
426 		ptm = gmtime(&utime);
427 		printf("%s %02d %3s %4d %2d:%02d:%02d UTC\n",
428 			text,
429 			ptm->tm_mday,months[ptm->tm_mon],ptm->tm_year+1900,
430 			ptm->tm_hour,ptm->tm_min,ptm->tm_sec);
431 	} else {
432 		u32 days;
433 		unsigned int year;
434 		int mon;
435 		int cnt;
436 
437 		days = stamp/(86400*10000000LL);
438 		year = 1601;
439 					/* periods of 400 years */
440 		cnt = days/146097;
441 		days -= 146097*cnt;
442 		year += 400*cnt;
443 					/* periods of 100 years */
444 		cnt = (3*days + 3)/109573;
445 		days -= 36524*cnt;
446 		year += 100*cnt;
447 					/* periods of 4 years */
448 		cnt = days/1461;
449 		days -= 1461L*cnt;
450 		year += 4*cnt;
451 					/* periods of a single year */
452 		cnt = (3*days + 3)/1096;
453 		days -= 365*cnt;
454 		year += cnt;
455 
456 		if ((!(year % 100) ? (year % 400) : (year % 4))
457 		    && (days > 58)) days++;
458 		if (days > 59) {
459 			mon = (5*days + 161)/153;
460 			days -= (153*mon - 162)/5;
461 		} else {
462 			mon = days/31 + 1;
463 			days -= 31*(mon - 1) - 1;
464 		}
465 if (mon > 12)
466 {
467 printf("** Bad day stamp %lld days %lu mon %d year %u\n",
468 (long long)stamp,(unsigned long)days,mon,year);
469 }
470 		printf("%s %02u %3s %4u\n",text,
471 			(unsigned int)days,months[mon-1],(unsigned int)year);
472 	}
473 }
474 
showname(const char * prefix,const char * name,int cnt)475 void showname(const char *prefix, const char *name, int cnt)
476 {
477 	const le16 *n;
478 	int i;
479 	int c;
480 
481 	printf("%s",prefix);
482 	n = (const le16*)name;
483 	for (i=0; (i<cnt) && n[i]; i++) {
484 		c = le16_to_cpu(n[i]);
485 		if (c < 0x20)
486 			printf(".");
487 		else
488 			if (c < 0x80)
489 				printf("%c",c);
490 			else
491 				if (c < 0x800)
492 					printf("%c%c",
493 						(c >> 6) + 0xc0,
494 						(c & 63) + 0x80);
495 				else
496 					printf("%c%c%c",
497 						(c >> 12) + 0xe0,
498 						((c >> 6) & 63) + 0x80,
499 						(c & 63) + 0x80);
500 	}
501 	printf("\n");
502 }
503 
commitment(u64 lsn)504 static const char *commitment(u64 lsn)
505 {
506 	const char *commit;
507 	s64 diff;
508 
509 	/* Computations assume lsn could wraparound, they probably never do */
510 	diff = lsn - synced_lsn;
511 	if (diff <= 0)
512 		commit = "synced";
513 	else {
514 		diff = lsn - committed_lsn;
515 		if (diff <= 0)
516 			commit = "committed";
517 		else {
518 			/* may find lsn from older session */
519 			diff = lsn - latest_lsn;
520 			if (diff <= 0)
521 				commit = "*uncommitted*";
522 			else
523 				commit = "*stale*";
524 		}
525 	}
526 	return (commit);
527 }
528 
actionname(int op)529 const char *actionname(int op)
530 {
531 	static char buffer[24];
532 	const char *p;
533 
534 	switch (op) {
535 	case Noop :
536 		p = "Noop";
537 		break;
538 	case CompensationlogRecord :
539 		p = "CompensationlogRecord";
540 		break;
541 	case InitializeFileRecordSegment :
542 		p = "InitializeFileRecordSegment";
543 		break;
544 	case DeallocateFileRecordSegment :
545 		p = "DeallocateFileRecordSegment";
546 		break;
547 	case WriteEndofFileRecordSegment :
548 		p = "WriteEndofFileRecordSegment";
549 		break;
550 	case CreateAttribute :
551 		p = "CreateAttribute";
552 		break;
553 	case DeleteAttribute :
554 		p = "DeleteAttribute";
555 		break;
556 	case UpdateResidentValue :
557 		p = "UpdateResidentValue";
558 		break;
559 	case UpdateNonResidentValue :
560 		p = "UpdateNonResidentValue";
561 		break;
562 	case UpdateMappingPairs :
563 		p = "UpdateMappingPairs";
564 		break;
565 	case DeleteDirtyClusters :
566 		p = "DeleteDirtyClusters";
567 		break;
568 	case SetNewAttributeSizes :
569 		p = "SetNewAttributeSizes";
570 		break;
571 	case AddIndexEntryRoot :
572 		p = "AddIndexEntryRoot";
573 		break;
574 	case DeleteIndexEntryRoot :
575 		p = "DeleteIndexEntryRoot";
576 		break;
577 	case AddIndexEntryAllocation :
578 		p = "AddIndexEntryAllocation";
579 		break;
580 	case DeleteIndexEntryAllocation :
581 		p = "DeleteIndexEntryAllocation";
582 		break;
583 	case WriteEndOfIndexBuffer :
584 		p = "WriteEndOfIndexBuffer";
585 		break;
586 	case SetIndexEntryVcnRoot :
587 		p = "SetIndexEntryVcnRoot";
588 		break;
589 	case SetIndexEntryVcnAllocation :
590 		p = "SetIndexEntryVcnAllocation";
591 		break;
592 	case UpdateFileNameRoot :
593 		p = "UpdateFileNameRoot";
594 		break;
595 	case UpdateFileNameAllocation :
596 		p = "UpdateFileNameAllocation";
597 		break;
598 	case SetBitsInNonResidentBitMap :
599 		p = "SetBitsInNonResidentBitMap";
600 		break;
601 	case ClearBitsInNonResidentBitMap :
602 		p = "ClearBitsInNonResidentBitMap";
603 		break;
604 	case HotFix :
605 		p = "HotFix";
606 		break;
607 	case EndTopLevelAction :
608 		p = "EndTopLevelAction";
609 		break;
610 	case PrepareTransaction :
611 		p = "PrepareTransaction";
612 		break;
613 	case CommitTransaction :
614 		p = "CommitTransaction";
615 		break;
616 	case ForgetTransaction :
617 		p = "ForgetTransaction";
618 		break;
619 	case OpenNonResidentAttribute :
620 		p = "OpenNonResidentAttribute";
621 		break;
622 	case OpenAttributeTableDump :
623 		p = "OpenAttributeTableDump";
624 		break;
625 	case AttributeNamesDump :
626 		p = "AttributeNamesDump";
627 		break;
628 	case DirtyPageTableDump :
629 		p = "DirtyPageTableDump";
630 		break;
631 	case TransactionTableDump :
632 		p = "TransactionTableDump";
633 		break;
634 	case UpdateRecordDataRoot :
635 		p = "UpdateRecordDataRoot";
636 		break;
637 	case UpdateRecordDataAllocation :
638 		p = "UpdateRecordDataAllocation";
639 		break;
640 	case Win10Action35 :
641 		p = "Win10Action35";
642 		break;
643 	case Win10Action36 :
644 		p = "Win10Action36";
645 		break;
646 	case Win10Action37 :
647 		p = "Win10Action37";
648 		break;
649 	default  :
650 		sprintf(buffer,"*Unknown-Action-%d*",op);
651 		p = buffer;
652 		break;
653 	}
654 	return (p);
655 }
656 
attrname(unsigned int key)657 static const char *attrname(unsigned int key)
658 {
659 	static char name[256];
660 	const char *p;
661 	struct ATTR *pa;
662 	unsigned int i;
663 
664 	if ((key <= 65535) && !(key & 3)) {
665 		pa = getattrentry(key,0);
666 		if (pa) {
667 			if (!pa->namelen)
668 				p = "Unnamed";
669 			else {
670 				p = name;
671 					/* Assume ascii for now */
672 				for (i=0; 2*i<pa->namelen; i++)
673 					name[i] = le16_to_cpu(pa->name[i]);
674 				name[i] = 0;
675 			}
676 		} else
677 			p = "Undefined";
678 	} else
679 		p = "Invalid";
680 	return (p);
681 }
682 
fixnamelen(const char * name,int len)683 int fixnamelen(const char *name, int len)
684 {
685 	int i;
686 
687 	i = 0;
688 	while ((i < len) && (name[i] || name[i + 1]))
689 		i += 2;
690 	return (i);
691 }
692 
mftattrname(ATTR_TYPES attr)693 const char *mftattrname(ATTR_TYPES attr)
694 {
695 	static char badattr[24];
696 	const char *p;
697 
698 	switch (attr) {
699 	case AT_STANDARD_INFORMATION :
700 		p = "Standard-Information";
701 		break;
702 	case AT_ATTRIBUTE_LIST :
703 		p = "Attribute-List";
704 		break;
705 	case AT_FILE_NAME :
706 		p = "Name";
707 		break;
708 	case AT_OBJECT_ID :
709 		p = "Volume-Version";
710 		break;
711 	case AT_SECURITY_DESCRIPTOR :
712 		p = "Security-Descriptor";
713 		break;
714 	case AT_VOLUME_NAME :
715 		p = "Volume-Name";
716 		break;
717 	case AT_VOLUME_INFORMATION :
718 		p = "Volume-Information";
719 		break;
720 	case AT_DATA :
721 		p = "Data";
722 		break;
723 	case AT_INDEX_ROOT :
724 		p = "Index-Root";
725 		break;
726 	case AT_INDEX_ALLOCATION :
727 		p = "Index-Allocation";
728 		break;
729 	case AT_BITMAP :
730 		p = "Bitmap";
731 		break;
732 	case AT_REPARSE_POINT :
733 		p = "Reparse-Point";
734 		break;
735 	case AT_EA_INFORMATION :
736 		p = "EA-Information";
737 		break;
738 	case AT_EA :
739 		p = "EA";
740 		break;
741 	case AT_PROPERTY_SET :
742 		p = "Property-Set";
743 		break;
744 	case AT_LOGGED_UTILITY_STREAM :
745 		p = "Logged-Utility-Stream";
746 		break;
747 	case AT_END :
748 		p = "End";
749 		break;
750 	default :
751 		sprintf(badattr,"*0x%x-Unknown*",attr);
752 		p = badattr;
753 		break;
754 	}
755 	return (p);
756 }
757 
showattribute(const char * prefix,const struct ATTR * pa)758 static void showattribute(const char *prefix, const struct ATTR *pa)
759 {
760 	if (pa) {
761 		if (pa->type) {
762 			printf("%sattr 0x%x : inode %lld type %s",
763 				prefix, pa->key, (long long)pa->inode,
764 				mftattrname(pa->type));
765 			if (pa->namelen)
766 				showname(" name ",(const char*)pa->name,
767 					pa->namelen/2);
768 			else
769 				printf("\n");
770 		} else {
771 			if (pa->namelen) {
772 				printf("%sattr 0x%x : type Unknown",
773 						prefix, pa->key);
774 				showname(" name ",(const char*)pa->name,
775 						pa->namelen/2);
776 			} else
777 				printf("%s(definition of attr 0x%x not met)\n",
778 						prefix, pa->key);
779 		}
780 	}
781 }
782 
783 /*
784  *		Determine if an action acts on the MFT
785  */
786 
acts_on_mft(int op)787 static BOOL acts_on_mft(int op)
788 {
789 	BOOL onmft;
790 
791 			/* A few actions may have to be added to the list */
792 	switch (op) {
793 	case InitializeFileRecordSegment :
794 	case DeallocateFileRecordSegment :
795 	case CreateAttribute :
796 	case DeleteAttribute :
797 	case UpdateResidentValue :
798 	case UpdateMappingPairs :
799 	case SetNewAttributeSizes :
800 	case AddIndexEntryRoot :
801 	case DeleteIndexEntryRoot :
802 	case UpdateFileNameRoot :
803 	case WriteEndofFileRecordSegment :
804 	case Win10Action37 :
805 		onmft = TRUE;
806 		break;
807 	default :
808 		onmft = FALSE;
809 		break;
810 	}
811 	return (onmft);
812 }
813 
get_undo_offset(const LOG_RECORD * logr)814 u32 get_undo_offset(const LOG_RECORD *logr)
815 {
816 	u32 offset;
817 
818 	if (logr->lcns_to_follow)
819 		offset = 0x30 + le16_to_cpu(logr->undo_offset);
820 	else
821 		offset = 0x28 + le16_to_cpu(logr->undo_offset);
822 	return (offset);
823 }
824 
get_redo_offset(const LOG_RECORD * logr)825 u32 get_redo_offset(const LOG_RECORD *logr)
826 {
827 	u32 offset;
828 
829 	if (logr->lcns_to_follow)
830 		offset = 0x30 + le16_to_cpu(logr->redo_offset);
831 	else
832 		offset = 0x28 + le16_to_cpu(logr->redo_offset);
833 	return (offset);
834 }
835 
get_extra_offset(const LOG_RECORD * logr)836 u32 get_extra_offset(const LOG_RECORD *logr)
837 {
838 	u32 uoffset;
839 	u32 roffset;
840 
841 	roffset = get_redo_offset(logr)
842 				+ le16_to_cpu(logr->redo_length);
843 	uoffset = get_undo_offset(logr)
844 				+ le16_to_cpu(logr->undo_length);
845 	return ((((uoffset > roffset ? uoffset : roffset) - 1) | 7) + 1);
846 }
847 
likelyop(const LOG_RECORD * logr)848 static BOOL likelyop(const LOG_RECORD *logr)
849 {
850 	BOOL likely;
851 
852 	switch (logr->record_type) {
853 	case LOG_STANDARD : /* standard record */
854 	     /* Operations in range 0..LastAction-1, can be both null */
855 		likely = ((unsigned int)le16_to_cpu(logr->redo_operation)
856 						< LastAction)
857 		    && ((unsigned int)le16_to_cpu(logr->undo_operation)
858 						< LastAction)
859 	     /* Offsets aligned to 8 bytes */
860 		    && !(le16_to_cpu(logr->redo_offset) & 7)
861 		    && !(le16_to_cpu(logr->undo_offset) & 7)
862 	     /* transaction id must not be null */
863 		    && logr->transaction_id
864 	     /* client data length aligned to 8 bytes */
865 		    && !(le32_to_cpu(logr->client_data_length) & 7)
866 	     /* client data length less than 64K (131K ?) */
867 		    && (le32_to_cpu(logr->client_data_length) < MAXRECSIZE)
868 	     /* if there is redo data, offset must be >= 0x28 */
869 		    && (!le16_to_cpu(logr->redo_length)
870 		       || ((unsigned int)le16_to_cpu(logr->redo_offset) >= 0x28))
871 	     /* if there is undo data, offset must be >= 0x28 */
872 		    && (!le16_to_cpu(logr->undo_length)
873 		       || ((unsigned int)le16_to_cpu(logr->undo_offset) >= 0x28));
874 	     /* undo data and redo data should be contiguous when both present */
875 		if (likely && logr->redo_length && logr->undo_length) {
876 	     /* undo and redo data may be the same when both present and same size */
877 			if (logr->undo_offset == logr->redo_offset) {
878 				if (logr->redo_length != logr->undo_length)
879 					likely = FALSE;
880 			} else {
881 				if (le16_to_cpu(logr->redo_offset)
882 					< le16_to_cpu(logr->undo_offset)) {
883 			/* undo expected just after redo */
884 					if ((((le16_to_cpu(logr->redo_offset)
885 					    + le16_to_cpu(logr->redo_length)
886 					    - 1) | 7) + 1)
887 					    != le16_to_cpu(logr->undo_offset))
888 						likely = FALSE;
889 				} else {
890 			/* redo expected just after undo */
891 					if ((((le16_to_cpu(logr->undo_offset)
892 					    + le16_to_cpu(logr->undo_length)
893 					    - 1) | 7) + 1)
894 					    != le16_to_cpu(logr->redo_offset))
895 						likely = FALSE;
896 				}
897 			}
898 		}
899 		break;
900 	case LOG_CHECKPOINT : /* check-point */
901 	     /*
902 	      * undo and redo operations are null
903 	      * or CompensationlogRecord with no data
904 	      */
905 		likely = (!logr->redo_operation
906 			|| ((logr->redo_operation == const_cpu_to_le16(1))
907 			    && !logr->redo_length))
908 		    && (!logr->undo_operation
909 			|| ((logr->undo_operation == const_cpu_to_le16(1))
910 			    && !logr->undo_length))
911 	     /* transaction id must be null */
912 		    && !logr->transaction_id
913 	     /* client_data_length is 0x68 or 0x70 (Vista and subsequent) */
914 		    && ((le32_to_cpu(logr->client_data_length) == 0x68)
915 			|| (le32_to_cpu(logr->client_data_length) == 0x70));
916 		break;
917 	default :
918 		likely = FALSE;
919 		break;
920 	}
921 	return (likely);
922 }
923 
924 /*
925  *		Search for a likely record in a block
926  *
927  *	Must not be used when syncing.
928  *
929  *	Returns 0 when not found
930  */
931 
searchlikely(const struct BUFFER * buf)932 static u16 searchlikely(const struct BUFFER *buf)
933 {
934 	const LOG_RECORD *logr;
935 	const char *data;
936 	u16 k;
937 
938 	if (opts)
939 		printf("** Error : searchlikely() used for syncing\n");
940         data = buf->block.data;
941    	k = buf->headsz;
942 	logr = (const LOG_RECORD*)&data[k];
943 	if (!likelyop(logr)) {
944 		do {
945 			k += 8;
946 			logr = (const LOG_RECORD*)&data[k];
947 		} while ((k <= (blocksz - LOG_RECORD_HEAD_SZ))
948 		    && !likelyop(logr));
949 		if (k > (blocksz - LOG_RECORD_HEAD_SZ))
950 			k = 0;
951 	}
952 	return (k);
953 }
954 
955 /*
956  *	From a previous block, determine the location of first record
957  *
958  *	The previous block must have the beginning of an overlapping
959  *	record, and the current block must have the beginning of next
960  *	record (which can overlap on next blocks).
961  *	The argument "skipped" is the number of blocks in-between.
962  *
963  *	Note : the overlapping record from previous block does not reach
964  *	the current block when it ends near the end of the last skipped block.
965  *
966  *	Returns 0 if some bad condition is found
967  *	Returns near blocksz when there is no beginning of record in
968  *		the current block
969  */
970 
firstrecord(int skipped,const struct BUFFER * buf,const struct BUFFER * prevbuf)971 static u16 firstrecord(int skipped, const struct BUFFER *buf,
972 		   const struct BUFFER *prevbuf)
973 {
974 	const RECORD_PAGE_HEADER *rph;
975 	const RECORD_PAGE_HEADER *prevrph;
976 	const LOG_RECORD *logr;
977 	const char *data;
978 	const char *prevdata;
979 	u16 k;
980 	u16 blkheadsz;
981 	s32 size;
982 
983 	rph = &buf->block.record;
984 	data = buf->block.data;
985 	if (prevbuf) {
986 		prevrph = &prevbuf->block.record;
987 		prevdata = prevbuf->block.data;
988 		blkheadsz = prevbuf->headsz;
989 		/* From previous page, determine where the current one starts */
990 		k = le16_to_cpu(prevrph->next_record_offset);
991 		/* a null value means there is no full record in next block */
992 		if (!k)
993 			k = blkheadsz;
994 	} else
995 		k = 0;
996 		/* Minimal size is apparently 48 : offset of redo_operation */
997 	if (k && ((blocksz - k) >= LOG_RECORD_HEAD_SZ)) {
998 		logr = (const LOG_RECORD*)&prevdata[k];
999 		if (!logr->client_data_length) {
1000 			/*
1001 			 * Sometimes the end of record is free space.
1002 			 * This apparently means reaching the end of
1003 			 * a previous session, and must be considered
1004 			 * as an error.
1005 			 * We however tolerate this, unless syncing
1006 			 * is requested.
1007 			 */
1008 			printf("* Reaching free space at end of block %d\n",
1009 					(int)prevbuf->num);
1010 			/* As a consequence, there cannot be skipped blocks */
1011 			if (skipped) {
1012 				printf("*** Inconsistency : blocks skipped after free space\n");
1013 				k = 0; /* error returned */
1014 			}
1015 			if (opts)
1016 				k = 0;
1017 			else {
1018 				k = searchlikely(buf);
1019 				printf("* Skipping over free space\n");
1020 			}
1021 		} else {
1022 			size = le32_to_cpu(logr->client_data_length)
1023 					+ LOG_RECORD_HEAD_SZ;
1024 			if ((size < MINRECSIZE) || (size > MAXRECSIZE)) {
1025 				printf("** Bad record size %ld in block %ld"
1026 					" offset 0x%x\n",
1027 					(long)size,(long)prevbuf->num,(int)k);
1028 				k = blkheadsz;
1029 			} else {
1030 				if ((int)(blocksz - k) >= size)
1031 					printf("*** Inconsistency : the final"
1032 						" record does not overlap\n");
1033 				k += size - (blocksz - blkheadsz)*(skipped + 1);
1034 			}
1035 			if ((k <= blkheadsz)
1036 			    && (k > (blkheadsz - LOG_RECORD_HEAD_SZ))) {
1037 			/* There were not enough space in the last skipped block */
1038 				k = blkheadsz;
1039 			} else {
1040 				if (optv
1041 				    && ((blocksz - k) < LOG_RECORD_HEAD_SZ)) {
1042 					/* Not an error : just no space */
1043 					printf("No minimal record space\n");
1044 				}
1045 				if (optv >= 2)
1046 					printf("Overlapping record from block %d,"
1047 						" starting at offset 0x%x\n",
1048 						(int)prevbuf->num,(int)k);
1049 			}
1050 		}
1051 	} else {
1052 		k = buf->headsz;
1053 		if (optv >= 2) {
1054 			if (prevbuf)
1055 				printf("No minimal record from block %d,"
1056 					" starting at offset 0x%x\n",
1057 					(int)prevbuf->num, (int)k);
1058 			else
1059 				printf("No block before %d,"
1060 					" starting at offset 0x%x\n",
1061 					(int)buf->num, (int)k);
1062 		}
1063 	}
1064 		/*
1065 		 * In a wraparound situation, there is frequently no
1066 		 * match... because there were no wraparound.
1067 		 * Return an error if syncing is requested, otherwise
1068 		 * try to find a starting record.
1069 		 */
1070 	if (k && prevbuf && (prevbuf->num > buf->num)) {
1071 		logr = (const LOG_RECORD*)&data[k];
1072 			/* Accept reaching the end with no record beginning */
1073 		if ((k != le16_to_cpu(rph->next_record_offset))
1074 		    && !likelyop(logr)) {
1075 			if (opts) {
1076 				k = 0;
1077 				printf("** Could not wraparound\n");
1078 			} else {
1079 				k = searchlikely(buf);
1080 				printf("* Skipping over bad wraparound\n");
1081 			}
1082 		}
1083 	}
1084 	return (k);
1085 }
1086 
1087 /*
1088  *		Find the block which defines the first record in current one
1089  *
1090  *	Either the wanted block has the beginning of a record overlapping
1091  *	on current one, or it ends in such as there is no space for an
1092  *	overlapping one.
1093  *
1094  *	Returns 0 if the previous block cannot be determined.
1095  */
1096 
findprevious(CONTEXT * ctx,const struct BUFFER * buf)1097 static const struct BUFFER *findprevious(CONTEXT *ctx, const struct BUFFER *buf)
1098 {
1099 	const struct BUFFER *prevbuf;
1100 	const struct BUFFER *savebuf;
1101 	const RECORD_PAGE_HEADER *rph;
1102 	int skipped;
1103 	int prevblk;
1104 	BOOL prevmiddle;
1105 	BOOL error;
1106 	u16 endoff;
1107 
1108 	error = FALSE;
1109 	prevblk = buf->num;
1110 	savebuf = (struct BUFFER*)NULL;
1111 	skipped = 0;
1112 	do {
1113 		prevmiddle = FALSE;
1114 		if (prevblk > (log_major < 2 ? BASEBLKS : BASEBLKS2))
1115 			prevblk--;
1116 		else
1117 			if (prevblk == (log_major < 2 ? BASEBLKS : BASEBLKS2))
1118 				prevblk = (logfilesz >> blockbits) - 1;
1119 			else {
1120 				rph = &buf->block.record;
1121 				if (log_major < 2)
1122 					prevblk = (sle64_to_cpu(
1123 						rph->copy.file_offset)
1124 							>> blockbits) - 1;
1125 				else
1126 					prevblk = (sle64_to_cpu(
1127 						rph->copy.last_lsn)
1128 						    & offset_mask)
1129 							>> (blockbits - 3);
1130 				/*
1131 				 * If an initial block leads to block 4, it
1132 				 * can mean the last block or no previous
1133 				 * block at all. Using the last block is safer,
1134 				 * its lsn will indicate whether it is stale.
1135 				 */
1136 				if (prevblk
1137 				    < (log_major < 2 ? BASEBLKS : BASEBLKS2))
1138 					prevblk = (logfilesz >> blockbits) - 1;
1139 			}
1140 		/* No previous block if the log only consists of block 2 or 3 */
1141 		if (prevblk < BASEBLKS) {
1142 			prevbuf = (struct BUFFER*)NULL;
1143 			error = TRUE; /* not a real error */
1144 		} else {
1145 			prevbuf = read_buffer(ctx, prevblk);
1146 			if (prevbuf) {
1147 				rph = &prevbuf->block.record;
1148 				prevmiddle = !(rph->flags
1149 						& const_cpu_to_le32(1))
1150 					|| !rph->next_record_offset;
1151 				if (prevmiddle) {
1152 					savebuf = prevbuf;
1153 					skipped++;
1154 				}
1155 			} else {
1156 				error = TRUE;
1157 				printf("** Could not read block %d\n",
1158 								(int)prevblk);
1159 			}
1160 		}
1161 	} while (prevmiddle && !error);
1162 
1163 	if (!prevmiddle && !error && skipped) {
1164 	 /* No luck if there is not enough space in this record */
1165 		rph = &prevbuf->block.record;
1166 		endoff = le16_to_cpu(rph->next_record_offset);
1167 		if (endoff > (blocksz - LOG_RECORD_HEAD_SZ)) {
1168 			prevbuf = savebuf;
1169 		}
1170 	}
1171 	return (error ? (struct BUFFER*)NULL : prevbuf);
1172 }
1173 
copy_attribute(struct ATTR * pa,const char * buf,int length)1174 void copy_attribute(struct ATTR *pa, const char *buf, int length)
1175 {
1176 	const ATTR_NEW *panew;
1177 	ATTR_OLD old_aligned;
1178 
1179 	if (pa) {
1180 		switch (length) {
1181 		case sizeof(ATTR_NEW) :
1182 			panew = (const ATTR_NEW*)buf;
1183 			pa->type = panew->type;
1184 			pa->lsn = sle64_to_cpu(panew->lsn);
1185 			pa->inode = MREF(le64_to_cpu(panew->inode));
1186 			break;
1187 		case sizeof(ATTR_OLD) :
1188 				/* Badly aligned, first realign */
1189 			memcpy(&old_aligned,buf,sizeof(old_aligned));
1190 			pa->type = old_aligned.type;
1191 			pa->lsn = sle64_to_cpu(old_aligned.lsn);
1192 			pa->inode = MREF(le64_to_cpu(old_aligned.inode));
1193 			break;
1194 		default :
1195 			printf("** Unexpected attribute format, length %d\n",
1196 					length);
1197 		}
1198 	}
1199 }
1200 
refresh_attributes(const struct ACTION_RECORD * firstaction)1201 static int refresh_attributes(const struct ACTION_RECORD *firstaction)
1202 {
1203 	const struct ACTION_RECORD *action;
1204 	const LOG_RECORD *logr;
1205 	struct ATTR *pa;
1206 	const char *buf;
1207 	u32 extra;
1208 	u32 length;
1209 	u32 len;
1210 	u32 key;
1211 	u32 x;
1212 	u32 i;
1213 	u32 step;
1214 	u32 used;
1215 
1216 	for (action=firstaction; action; action=action->next) {
1217 		logr = &action->record;
1218 		buf = ((const char*)logr) + get_redo_offset(logr);
1219 		length = le16_to_cpu(logr->redo_length);
1220 		switch (le16_to_cpu(action->record.redo_operation)) {
1221 		case OpenNonResidentAttribute :
1222 			extra = get_extra_offset(logr)
1223 						- get_redo_offset(logr);
1224 			if (logr->undo_length) {
1225 				len = le32_to_cpu(logr->client_data_length)
1226 					+ LOG_RECORD_HEAD_SZ
1227 					- get_extra_offset(logr);
1228 				/* this gives a length aligned modulo 8 */
1229 				len = fixnamelen(&buf[extra], len);
1230 			} else
1231 				len = 0;
1232 			pa = getattrentry(le16_to_cpu(logr->target_attribute),
1233 						len);
1234 			if (pa) {
1235 				copy_attribute(pa, buf, length);
1236 				pa->namelen = len;
1237 				if (len) {
1238 					memcpy(pa->name,&buf[extra],len);
1239 				}
1240 			}
1241 			break;
1242 		case OpenAttributeTableDump :
1243 			i = 24;
1244 			step = getle16(buf, 8);
1245 			used = getle16(buf, 12);
1246 	    		/*
1247 			 * Changed from Win10, formerly we got step = 44.
1248 			 * The record layout has also changed
1249 			 */
1250 			for (x=0; (x<used) && (i<length); i+=step, x++) {
1251 				pa = getattrentry(i,0);
1252 				if (pa) {
1253 					copy_attribute(pa, buf + i, step);
1254 				}
1255 			}
1256 			break;
1257 		case AttributeNamesDump :
1258 			i = 8;
1259 			if (i < length) {
1260 				x = 0;
1261 				do {
1262 					len = getle16(buf, i + 2);
1263 					key = getle16(buf, i);
1264 					if (len > 510) {
1265 						printf("** Error : bad"
1266 							" attribute name"
1267 							" length %d\n",
1268 							len);
1269 						key = 0;
1270 					}
1271 					if (key) { /* Apparently, may have to stop before reaching the end */
1272 						pa = getattrentry(key,len);
1273 						if (pa) {
1274 							pa->namelen = len;
1275 							memcpy(pa->name,
1276 								&buf[i+4],len);
1277 						}
1278 						i += len + 6;
1279 						x++;
1280 					}
1281 				} while (key && (i < length));
1282 			}
1283 			break;
1284 		default :
1285 			break;
1286 		}
1287 	}
1288 	return (0);
1289 }
1290 
1291 /*
1292  *              Display a fixup
1293  */
1294 
fixup(CONTEXT * ctx,const LOG_RECORD * logr,const char * buf,BOOL redo)1295 static void fixup(CONTEXT *ctx, const LOG_RECORD *logr, const char *buf,
1296 				BOOL redo)
1297 {
1298 	struct ATTR *pa;
1299 	int action;
1300 	int attr;
1301 	int offs;
1302 	s32 length;
1303 	int extra;
1304 	s32 i;
1305 	int p;
1306 	s32 base;
1307 	u16 firstpos; /* position of first mft attribute */
1308 	le32 v;
1309 	ATTR_TYPES mftattr;
1310 	le64 w;
1311 	le64 inode;
1312 	le64 size;
1313 	int lth;
1314 	int len;
1315 
1316 	attr = le16_to_cpu(logr->target_attribute);
1317 	offs = le16_to_cpu(logr->attribute_offset);
1318 	if (redo) {
1319 		action = le16_to_cpu(logr->redo_operation);
1320 		length = le16_to_cpu(logr->redo_length);
1321 	} else {
1322 		action = le16_to_cpu(logr->undo_operation);
1323 		length = le16_to_cpu(logr->undo_length);
1324 	}
1325 	if (redo)
1326 		printf("redo fixup %dR %s attr 0x%x offs 0x%x\n",
1327 			actionnum, actionname(action), attr, offs);
1328 	else
1329 		printf("undo fixup %dU %s attr 0x%x offs 0x%x\n",
1330 			actionnum, actionname(action), attr, offs);
1331 	switch (action) {
1332 	case InitializeFileRecordSegment : /* 2 */
1333 			/*
1334 			 * When this is a redo (with a NoOp undo), the
1335 			 *   full MFT record is logged.
1336 			 * When this is an undo (with DeallocateFileRecordSegment redo),
1337 			 *   only the header of the MFT record is logged.
1338 			 */
1339 		if (!ctx->vol && !mftrecsz && (length > 8)) {
1340 			/* mftrecsz can be determined from usa_count */
1341 			mftrecsz = (getle16(buf,6) - 1)*512;
1342 			mftrecbits = 1;
1343 			while ((u32)(1 << mftrecbits) < mftrecsz)
1344 				mftrecbits++;
1345 		}
1346 		printf("   new base MFT record, attr 0x%x (%s)\n",attr,attrname(attr));
1347 		printf("   inode      %lld\n",
1348 				(((long long)sle64_to_cpu(logr->target_vcn)
1349 					<< clusterbits)
1350 				+ (le16_to_cpu(logr->cluster_index) << 9))
1351 					>> mftrecbits);
1352 		if (length >= 18)
1353 			printf("   seq number 0x%04x\n",(int)getle16(buf, 16));
1354 		if (length >= 20)
1355 			printf("   link count %d\n",(int)getle16(buf, 18));
1356 		if (length >= 24) {
1357 			u16 flags;
1358 
1359 			flags = getle16(buf, 22);
1360 			printf("   flags      0x%x",(int)flags);
1361 			switch (flags & 3) {
1362 			case 1 :
1363 				printf(" (file in use)\n");
1364 				break;
1365 			case 3 :
1366 				printf(" (directory in use)\n");
1367 				break;
1368 			default :
1369 				printf(" (not in use)\n");
1370 				break;
1371 			}
1372 		}
1373 		base = getle16(buf, 4) + ((getle16(buf, 6)*2 - 1) | 7) + 1;
1374 		while (base < length) {
1375 			mftattr = feedle32(buf, base);
1376 			printf("   attrib 0x%lx (%s) at offset 0x%x\n",
1377 				(long)le32_to_cpu(mftattr),
1378 				mftattrname(mftattr), (int)base);
1379 		if (mftattr == AT_FILE_NAME) {
1380 			showname("      name ",&buf[base + 90],
1381 					buf[base + 88] & 255);
1382 			inode = feedle64(buf, base + 24);
1383 			printf("      parent dir inode %lld\n",
1384 					(long long)MREF(le64_to_cpu(inode)));
1385 		}
1386 		lth =  getle32(buf, base + 4);
1387 		if ((lth <= 0) || (lth & 7))
1388 			base = length;
1389 		else
1390 			base += lth;
1391 		}
1392 		break;
1393 	case DeallocateFileRecordSegment : /* 3 */
1394 		printf("   free base MFT record, attr 0x%x (%s)\n",
1395 				attr,attrname(attr));
1396 		printf("   inode %lld\n",
1397 		    (((long long)sle64_to_cpu(logr->target_vcn) << clusterbits)
1398 		    + (le16_to_cpu(logr->cluster_index) << 9)) >> mftrecbits);
1399 		break;
1400 	case CreateAttribute : /* 5 */
1401 		pa = getattrentry(attr,0);
1402 		base = 24;
1403 		/* Assume the beginning of the attribute is always present */
1404 		switch (getle32(buf,0)) {
1405 		case 0x30 :
1406 			printf("   create file name, attr 0x%x\n",attr);
1407 			if (pa)
1408 				showattribute("      ",pa);
1409 			showname("   file ",
1410 				&buf[base + 66],buf[base + 64] & 255);
1411 			if (base >= -8)
1412 				showdate("   created  ",feedle64(buf,base + 8));
1413 			if (base >= -16)
1414 				showdate("   modified ",feedle64(buf,base + 16));
1415 			if (base >= -24)
1416 				showdate("   changed  ",feedle64(buf,base + 24));
1417 			if (base >= -32)
1418 				showdate("   read     ",feedle64(buf,base + 32));
1419 			size = feedle64(buf,base + 40);
1420 			printf("   allocated size %lld\n",
1421 					(long long)le64_to_cpu(size));
1422 			size = feedle64(buf,base + 48);
1423 			printf("   real size %lld\n",
1424 					(long long)le64_to_cpu(size));
1425 			v = feedle32(buf,base + 56);
1426 			printf("   DOS flags 0x%lx\n",
1427 					(long)le32_to_cpu(v));
1428 			break;
1429 		case 0x80 :
1430 			printf("   create a data stream, attr 0x%x\n",attr);
1431 			break;
1432 		case 0xc0 :
1433 			printf("   create reparse data\n");
1434 			if (pa)
1435 				showattribute("      ",pa);
1436 			printf("   tag 0x%lx\n",(long)getle32(buf, base));
1437 			showname("   print name ",
1438 				&buf[base + 20 + getle16(buf, base + 12)],
1439 				getle16(buf, base + 14)/2);
1440 			break;
1441 		}
1442 		break;
1443       case UpdateResidentValue : /* 7 */
1444 		/*
1445 		 * The record offset designates the mft attribute offset,
1446 		 * offs and length define a right-justified window in this
1447 		 * attribute.
1448 		 * At this stage, we do not know which kind of mft
1449 		 * attribute this is about, we assume this is standard
1450 		 * information when it is the first attribute in the
1451 		 * record.
1452 		 */
1453 	 	base = 0x18 - offs; /* p 8 */
1454 		pa = getattrentry(attr,0);
1455 		firstpos = 0x30 + (((mftrecsz/512 + 1)*2 - 1 ) | 7) + 1;
1456 		if (pa
1457 		   && !pa->inode
1458 		   && (pa->type == const_cpu_to_le32(0x80))
1459 		   && !(offs & 3)
1460 		   && (le16_to_cpu(logr->record_offset) == firstpos)) {
1461 			printf("   set standard information, attr 0x%x\n",attr);
1462 			showattribute("      ",pa);
1463 	    		if ((base >= 0) && ((base + 8) <= length))
1464 	       			showdate("   created  ",
1465 						feedle64(buf,base));
1466 	    		if (((base + 8) >= 0) && ((base + 16) <= length))
1467 	       			showdate("   modified ",
1468 						feedle64(buf,base + 8));
1469 	    		if (((base + 16) >= 0) && ((base + 24) <= length))
1470 	       			showdate("   changed  ",
1471 						feedle64(buf,base + 16));
1472 	    		if (((base + 24) >= 0) && ((base + 32) <= length))
1473 	       			showdate("   read     ",
1474 						feedle64(buf,base + 24));
1475 	    		if (((base + 32) >= 0) && ((base + 36) <= length)) {
1476 	       			v = feedle32(buf, base + 32);
1477 	       			printf("   DOS flags 0x%lx\n",
1478 						(long)le32_to_cpu(v));
1479 	       		}
1480 	    		if (((base + 52) >= 0) && ((base + 56) <= length)) {
1481 	       			v = feedle32(buf, base + 52);
1482 	       			printf("   security id 0x%lx\n",
1483 						(long)le32_to_cpu(v));
1484 	       		}
1485 	    		if (((base + 64) >= 0) && ((base + 72) <= length)) {
1486 				/*
1487 				 * This is badly aligned for Sparc when
1488 				 * stamps not present and base == 52
1489 				 */
1490 				memcpy(&w, &buf[base + 64], 8);
1491 	       			printf("   journal idx 0x%llx\n",
1492 						(long long)le64_to_cpu(w));
1493 	       		}
1494 	    	} else {
1495 			printf("   set an MFT attribute at offset 0x%x, attr 0x%x\n",
1496 					(int)offs, attr);
1497 			if (pa)
1498 				showattribute("      ",pa);
1499 		}
1500 	 	break;
1501 	case UpdateNonResidentValue : /* 8 */
1502 		printf("   set attr 0x%x (%s)\n",attr,attrname(attr));
1503 		pa = getattrentry(attr,0);
1504 		if (pa)
1505 			showattribute("      ",pa);
1506 		base = 0; /* ? */
1507 // Should not be decoded, unless attr is of identified type (I30, ...)
1508 		if (pa && (pa->namelen == 8) && !memcmp(pa->name, SDS, 8)) {
1509 			if (length >= 4)
1510 				printf("   security hash 0x%lx\n",
1511 						(long)getle32(buf, 0));
1512 			if (length >= 8)
1513 				printf("   security id 0x%lx\n",
1514 						(long)getle32(buf, 4));
1515 			if (length >= 20)
1516 				printf("   entry size  %ld\n",
1517 						(long)getle32(buf, 16));
1518 		}
1519 		if (pa && (pa->namelen == 8) && !memcmp(pa->name, I30, 8)) {
1520 			if (!memcmp(buf, "INDX", 4))
1521 				base = 64; /* full record */
1522 			else
1523 				base = 0;  /* entries */
1524 			inode = feedle64(buf, base);
1525 			printf("   inode  %lld\n",
1526 			     (long long)MREF(le64_to_cpu(inode)));
1527 			inode = feedle64(buf, base + 16);
1528 			printf("   parent inode %lld\n",
1529 			     (long long)MREF(le64_to_cpu(inode)));
1530 			showname("   file    ",&buf[base + 82],
1531 							buf[base + 80] & 255);
1532 			showdate("   date    ",feedle64(buf, base + 32));
1533 		}
1534 		break;
1535 	case UpdateMappingPairs : /* 9 */
1536 		printf("   update runlist in attr 0x%x (%s)\n",attr,
1537 				attrname(attr));
1538 	       /* argument is a compressed runlist (or part of it ?) */
1539 	       /* stop when finding 00 */
1540 		break;
1541 	case SetNewAttributeSizes : /* 11 */
1542 		printf("   set sizes in attr 0x%x (%s)\n",attr,attrname(attr));
1543 		base = 0; /* left justified ? */
1544 		size = feedle64(buf,0);
1545 		printf("     allocated size %lld\n",(long long)le64_to_cpu(size));
1546 		size = feedle64(buf,8);
1547 		printf("          real size %lld\n",(long long)le64_to_cpu(size));
1548 		size = feedle64(buf,16);
1549 		printf("   initialized size %lld\n",(long long)le64_to_cpu(size));
1550 		break;
1551 	case AddIndexEntryRoot : /* 12 */
1552 	case AddIndexEntryAllocation : /* 14 */
1553 		/*
1554 		 * The record offset designates the mft attribute offset,
1555 		 * offs and length define a left-justified window in this
1556 		 * attribute.
1557 		 */
1558 		if (action == AddIndexEntryRoot)
1559 			printf("   add resident index entry, attr 0x%x\n",attr);
1560 		else
1561 			printf("   add nonres index entry, attr 0x%x\n",attr);
1562 		pa = getattrentry(attr,0);
1563 		if (pa)
1564 			showattribute("      ",pa);
1565 		base = 0;
1566 		p = getle16(buf, base + 8);
1567 		/* index types may be discriminated by inode in base+0 */
1568 		switch (p) { /* size of index entry */
1569 		case 32 :  /* $R entry */
1570 			memcpy(&inode, &buf[base + 20], 8); /* bad align */
1571 			printf("   $R reparse index\n");
1572 			printf("   reparsed inode 0x%016llx\n",
1573 					(long long)le64_to_cpu(inode));
1574 			printf("   reparse tag 0x%lx\n",
1575 					(long)getle32(buf, 16));
1576 			break;
1577 		case 40 :  /* $SII entry */
1578 			printf("   $SII security id index\n");
1579 			printf("   security id 0x%lx\n",
1580 					(long)getle32(buf, 16));
1581 			printf("   security hash 0x%lx\n",
1582 					(long)getle32(buf, 20));
1583 			break;
1584 		case 48 :  /* $SDH entry */
1585 			printf("   $SDH security id index\n");
1586 			printf("   security id 0x%lx\n",
1587 					(long)getle32(buf, 20));
1588 			printf("   security hash 0x%lx\n",
1589 					(long)getle32(buf, 16));
1590 			break;
1591 		default :
1592 		  /* directory index are at least 84 bytes long, ntfsdoc p 98 */
1593 		  /* have everything needed to create the index */
1594 			lth = buf[base + 80] & 255;
1595 		  /* consistency of file name length */
1596 			if (getle16(buf,10) == (u32)(2*lth + 66)) {
1597 				printf("   directory index\n");
1598 				inode = feedle64(buf,16);
1599 				printf("   parent dir inode %lld\n",
1600 					(long long)MREF(le64_to_cpu(inode)));
1601 				if (feedle32(buf,72)
1602 						& const_cpu_to_le32(0x10000000))
1603 					showname("   file (dir) ",
1604 						&buf[base + 82],
1605 						buf[base + 80] & 255);
1606 				else
1607 					showname("   file ",
1608 						&buf[base + 82],
1609 						buf[base + 80] & 255);
1610 				inode = feedle64(buf,0);
1611 				printf("   file inode %lld\n",
1612 					(long long)MREF(le64_to_cpu(inode)));
1613 				size = feedle64(buf,64);
1614 				printf("   file size %lld\n",
1615 					(long long)le64_to_cpu(size));
1616 				showdate("   created  ",
1617 						feedle64(buf,base + 24));
1618 				showdate("   modified ",
1619 						feedle64(buf,base + 32));
1620 				showdate("   changed  ",
1621 						feedle64(buf,base + 40));
1622 				showdate("   read     ",
1623 						feedle64(buf,base + 48));
1624 			} else
1625 				printf("   unknown index type\n");
1626 			break;
1627 			}
1628 		break;
1629 	case SetIndexEntryVcnRoot : /* 17 */
1630 		printf("   set vcn of non-resident index root, attr 0x%x\n",
1631 				attr);
1632 		pa = getattrentry(attr,0);
1633 		if (pa)
1634 			showattribute("      ",pa);
1635 		printf("   vcn %lld\n", (long long)getle64(buf,0));
1636 		break;
1637 	case UpdateFileNameRoot : /* 19 */
1638 		/*
1639 		 * Update an entry in a resident directory index.
1640 		 * The record offset designates the mft attribute offset,
1641 		 * offs and length define a right-justified window in this
1642 		 * attribute.
1643 		 */
1644 		printf("   set directory resident entry, attr 0x%x\n",attr);
1645 		base = length - 0x50;
1646 		pa = getattrentry(attr,0);
1647 		if (pa)
1648 			showattribute("      ",pa);
1649 		if (pa
1650 		   && !pa->inode
1651 		   && (pa->type == const_cpu_to_le32(0x80))
1652 		   && !(offs & 3)) {
1653 			if (base >= -24)
1654 				showdate("   created  ",feedle64(buf,
1655 							base + 24));
1656 			if (base >= -32)
1657 				showdate("   modified ",feedle64(buf,
1658 							base + 32));
1659 			if (base >= -40)
1660 				showdate("   changed  ",feedle64(buf,
1661 							base + 40));
1662 			if (base >= -48)
1663 				showdate("   read     ",feedle64(buf,
1664 							base + 48));
1665 			if (base >= -56) {
1666 				size = feedle64(buf,base + 56);
1667 				printf("   allocated size %lld\n",
1668 						(long long)le64_to_cpu(size));
1669 			}
1670 			if (base >= -64) {
1671 				size = feedle64(buf,base + 64);
1672 				printf("   real size %lld\n",
1673 						(long long)le64_to_cpu(size));
1674 			}
1675 			if (base > -72) {
1676 				v = feedle32(buf,base + 72);
1677 				printf("   DOS flags 0x%lx\n",
1678 						(long)le32_to_cpu(v));
1679 			}
1680 		} else {
1681 			/* Usually caused by attr not yet defined */
1682 			if (pa && pa->type)
1683 				printf("** Unexpected index parameters\n");
1684 		}
1685 		break;
1686 	case UpdateFileNameAllocation : /* 20 */
1687 		     /* update entry in directory index */
1688 		     /* only dates, sizes and attrib */
1689 		base = length - 64; /* p 12 */
1690 		printf("   set directory nonres entry, attr 0x%x\n",attr);
1691 		pa = getattrentry(attr,0);
1692 		if (pa)
1693 			showattribute("      ",pa);
1694 		if (base >= -8)
1695 			showdate("   created  ",feedle64(buf, base + 8));
1696 		if (base >= -16)
1697 			showdate("   modified ",feedle64(buf, base + 16));
1698 		if (base >= -24)
1699 			showdate("   changed  ",feedle64(buf, base + 24));
1700 		if (base >= -32)
1701 			showdate("   read     ",*(const le64*)&buf[base + 32]);
1702 		if (base >= -40) {
1703 			size = feedle64(buf, base + 40);
1704 			printf("   allocated size %lld\n",
1705 						(long long)le64_to_cpu(size));
1706 		}
1707 		if (base >= -48) {
1708 			size = feedle64(buf, base + 48);
1709 			printf("   real size %lld\n",
1710 						(long long)le64_to_cpu(size));
1711 		}
1712 		if (base >= -56) {
1713 			v = feedle32(buf, base + 56);
1714 			printf("   DOS flags 0x%lx\n",(long)le32_to_cpu(v));
1715 		}
1716 		break;
1717       	case SetBitsInNonResidentBitMap : /* 21 */
1718 	case ClearBitsInNonResidentBitMap : /* 22 */
1719 		if (action == SetBitsInNonResidentBitMap)
1720 			printf("   SetBitsInNonResidentBitMap, attr 0x%x\n",
1721 					attr);
1722 		else
1723 			printf("   ClearBitsInNonResidentBitMap, attr 0x%x\n",
1724 					attr);
1725 		pa = getattrentry(attr,0);
1726 		if (pa)
1727 			showattribute("      ",pa);
1728 		v = feedle32(buf, 0);
1729 		printf("   first bit %ld\n",(long)le32_to_cpu(v));
1730 		v = feedle32(buf, 4);
1731 		printf("   bit count %ld\n",(long)le32_to_cpu(v));
1732 		break;
1733 	case OpenNonResidentAttribute : /* 28 */
1734 		printf("   OpenNonResidentAttribute, attr 0x%x\n",attr);
1735 		extra = get_extra_offset(logr)
1736 			- (redo ? get_redo_offset(logr)
1737 				: get_undo_offset(logr));
1738 		if (logr->undo_length) {
1739 			len = le32_to_cpu(logr->client_data_length)
1740 				+ LOG_RECORD_HEAD_SZ
1741 				- get_extra_offset(logr);
1742 			/* this gives a length aligned modulo 8 */
1743 			len = fixnamelen(&buf[extra], len);
1744 		} else
1745 			len = 0;
1746 		pa = getattrentry(attr,len);
1747 		if (pa && redo) {
1748 			/*
1749 			 * If this is a redo, collect the attribute data.
1750 			 * This should only be done when walking forward.
1751 			 */
1752 			copy_attribute(pa, buf, length);
1753 			pa->namelen = len;
1754 			if (len)
1755 				memcpy(pa->name,&buf[extra],len);
1756 			printf("   MFT attribute 0x%lx (%s)\n",
1757 				(long)le32_to_cpu(pa->type),
1758 				mftattrname(pa->type));
1759 			printf("   lsn   0x%016llx\n",
1760 				(long long)pa->lsn);
1761 			printf("   inode %lld\n",
1762 				(long long)pa->inode);
1763 		}
1764 		if (logr->undo_length)
1765 			showname("   extra : attr name ", &buf[extra], len/2);
1766 		if (!redo && length) {
1767 			printf("   * undo attr not shown\n");
1768 		}
1769 		break;
1770 	case OpenAttributeTableDump : /* 29 */
1771 		printf("   OpenAttributeTableDump, attr 0x%x (%s)\n",
1772 				attr,attrname(attr));
1773 		i = 24;
1774 		if (i < length) {
1775 			int x;
1776 			int more;
1777 			int step;
1778 			int used;
1779 
1780 			step = getle16(buf, 8);
1781 			used = getle16(buf, 12);
1782 			    /*
1783 			     * Changed from Win10, formerly we got step = 44.
1784 			     * The record layout has also changed
1785 			     */
1786 			if ((step != sizeof(ATTR_OLD))
1787 			    && (step != sizeof(ATTR_NEW))) {
1788 				printf("   ** Unexpected step %d\n",step);
1789 			}
1790 			more = 0;
1791 			for (x=0; (x<used) && (i<length); i+=step, x++) {
1792 				pa = getattrentry(i,0);
1793 				if (pa) {
1794 					copy_attribute(pa, &buf[i], step);
1795 					if (x <= SHOWATTRS) {
1796 						printf("   attr 0x%x inode %lld"
1797 							" type %s",
1798 							(int)i,
1799 							(long long)pa->inode,
1800 							mftattrname(pa->type));
1801 						if (pa->namelen)
1802 							showname(" name ",
1803 								(char*)pa->name,
1804 								pa->namelen/2);
1805 						else
1806 							printf("\n");
1807 					} else
1808 						more++;
1809 				}
1810 			}
1811 			if (more)
1812 				printf("   (%d more attrs not shown)\n",more);
1813 		}
1814 		break;
1815 	case AttributeNamesDump : /* 30 */
1816 		printf("   AttributeNamesDump, attr 0x%x (%s)\n",
1817 			       attr,attrname(attr));
1818 		i = 8;
1819 		if (i < length) {
1820 			unsigned int l;
1821 			unsigned int key;
1822 			int x;
1823 			int more;
1824 
1825 			more = 0;
1826 			x = 0;
1827 			do {
1828 				l = le16_to_cpu(*(const le16*)&buf[i+2]);
1829 				key = le16_to_cpu(*(const le16*)&buf[i]);
1830 				if (l > 510) {
1831 					printf("** Error : bad attribute name"
1832 							" length %d\n",l);
1833 					key = 0;
1834 				}
1835 		 /* Apparently, may have to stop before reaching the end */
1836 				if (key) {
1837 					pa = getattrentry(key,l);
1838 					if (pa) {
1839 						pa->namelen = l;
1840 						memcpy(pa->name,&buf[i+4],l);
1841 					}
1842 					if (x < SHOWATTRS) {
1843 						printf("   attr 0x%x is",key);
1844 						showname("  ",&buf[i+4],l/2);
1845 					} else
1846 						more++;
1847 					i += l + 6;
1848 					x++;
1849 				}
1850 			} while (key && (i < length));
1851 			if (more)
1852 				printf("   (%d more attrs not shown)\n",more);
1853 		}
1854 		break;
1855 	default :
1856 		break;
1857 	}
1858 }
1859 
detaillogr(CONTEXT * ctx,const LOG_RECORD * logr)1860 static void detaillogr(CONTEXT *ctx, const LOG_RECORD *logr)
1861 {
1862 	u64 lcn;
1863 	u64 baselcn;
1864 	unsigned int i;
1865 	unsigned int off;
1866 	unsigned int undo;
1867 	unsigned int redo;
1868 	unsigned int extra;
1869 	unsigned int end;
1870 	unsigned int listsize;
1871 	BOOL onmft;
1872 
1873 	switch (logr->record_type) {
1874 	case LOG_STANDARD :
1875 		onmft = logr->cluster_index
1876 			|| acts_on_mft(le16_to_cpu(logr->redo_operation))
1877 			|| acts_on_mft(le16_to_cpu(logr->undo_operation));
1878 		printf("redo_operation         %04x %s\n",
1879 			(int)le16_to_cpu(logr->redo_operation),
1880 			actionname(le16_to_cpu(logr->redo_operation)));
1881 		printf("undo_operation         %04x %s\n",
1882 			(int)le16_to_cpu(logr->undo_operation),
1883 			actionname(le16_to_cpu(logr->undo_operation)));
1884 		printf("redo_offset            %04x\n",
1885 			(int)le16_to_cpu(logr->redo_offset));
1886 		printf("redo_length            %04x\n",
1887 			(int)le16_to_cpu(logr->redo_length));
1888 		printf("undo_offset            %04x\n",
1889 			(int)le16_to_cpu(logr->undo_offset));
1890 		printf("undo_length            %04x\n",
1891 			(int)le16_to_cpu(logr->undo_length));
1892 		printf("target_attribute       %04x\n",
1893 			(int)le16_to_cpu(logr->target_attribute));
1894 		printf("lcns_to_follow         %04x\n",
1895 			(int)le16_to_cpu(logr->lcns_to_follow));
1896 		printf("record_offset          %04x\n",
1897 			(int)le16_to_cpu(logr->record_offset));
1898 		printf("attribute_offset       %04x\n",
1899 			(int)le16_to_cpu(logr->attribute_offset));
1900 		printf("cluster_index          %04x\n",
1901 			(int)le16_to_cpu(logr->cluster_index));
1902 		printf("attribute_flags        %04x\n",
1903 			(int)le16_to_cpu(logr->attribute_flags));
1904 		if (mftrecbits && onmft)
1905 			printf("target_vcn             %016llx (inode %lld)\n",
1906 				(long long)sle64_to_cpu(logr->target_vcn),
1907 				(((long long)sle64_to_cpu(logr->target_vcn)
1908 					<< clusterbits)
1909 				+ (le16_to_cpu(logr->cluster_index) << 9))
1910 					 >> mftrecbits);
1911 		else
1912 			printf("target_vcn             %016llx\n",
1913 				(long long)sle64_to_cpu(logr->target_vcn));
1914 			/* Compute a base for the current run of mft */
1915 		baselcn = sle64_to_cpu(logr->lcn_list[0])
1916 					- sle64_to_cpu(logr->target_vcn);
1917 		for (i=0; i<le16_to_cpu(logr->lcns_to_follow)
1918 						&& (i<SHOWLISTS); i++) {
1919 			lcn = sle64_to_cpu(logr->lcn_list[i]);
1920 			printf("  (%d offs 0x%x) lcn    %016llx",i,
1921 				(int)(8*i + sizeof(LOG_RECORD) - 8),
1922 				(long long)lcn);
1923 			lcn &= 0xffffffffffffULL;
1924 			if (mftrecsz && onmft) {
1925 				if (clustersz > mftrecsz)
1926 					printf(" (MFT records for inodes"
1927 						" %lld-%lld)\n",
1928 						(long long)((lcn - baselcn)
1929 							*clustersz/mftrecsz),
1930 						(long long)((lcn + 1 - baselcn)
1931 							*clustersz/mftrecsz - 1));
1932 				else
1933 					printf(" (MFT record for inode %lld)\n",
1934 						(long long)((lcn - baselcn)
1935 							*clustersz/mftrecsz));
1936 				printf("     assuming record for inode %lld\n",
1937 					(long long)((lcn - baselcn)
1938 						*clustersz/mftrecsz
1939 					+ (le16_to_cpu(logr->cluster_index)
1940 						 >> 1)));
1941 			} else
1942 				printf("\n");
1943 		}
1944                 /*
1945                  *  redo_offset and undo_offset are considered unsafe
1946 		 *  (actually they are safe when you know the logic)
1947                  *  2) redo : redo (defined by redo_offset)
1948                  *  3) undo : undo (defined by undo_offset)
1949                  *  4) extra : unknown data (end of undo to data_length)
1950                  */
1951          end = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ;
1952          if (logr->redo_length && logr->undo_length)
1953             {
1954                           /* both undo and redo are present */
1955             if (le16_to_cpu(logr->undo_offset) <=
1956 						le16_to_cpu(logr->redo_offset))
1957                {
1958                undo = sizeof(LOG_RECORD) - 8
1959 					+ 8*le16_to_cpu(logr->lcns_to_follow);
1960                if (logr->redo_offset == logr->undo_offset)
1961                   redo = undo;
1962                else
1963                   redo = undo + ((le16_to_cpu(logr->undo_length) - 1) | 7) + 1;
1964                extra = redo + ((le16_to_cpu(logr->redo_length) - 1) | 7) + 1;
1965                }
1966             else
1967                {
1968                redo = sizeof(LOG_RECORD) - 8
1969 					+ 8*le16_to_cpu(logr->lcns_to_follow);
1970                undo = redo + ((le16_to_cpu(logr->redo_length) - 1) | 7) + 1;
1971                extra = undo + ((le16_to_cpu(logr->undo_length) - 1) | 7) + 1;
1972                }
1973             }
1974          else
1975             if (logr->redo_length)
1976                {
1977                                   /* redo and not undo */
1978                redo = undo = sizeof(LOG_RECORD) - 8
1979 					+ 8*le16_to_cpu(logr->lcns_to_follow);
1980                extra = redo + ((le16_to_cpu(logr->redo_length) - 1) | 7) + 1;
1981                }
1982             else
1983                {
1984                                   /* optional undo and not redo */
1985                redo = undo = sizeof(LOG_RECORD) - 8
1986 					+ 8*le16_to_cpu(logr->lcns_to_follow);
1987                extra = undo + ((le16_to_cpu(logr->undo_length) - 1) | 7) + 1;
1988                }
1989 
1990          printf("redo 0x%x (%u) undo 0x%x (%u) extra 0x%x (%d)\n",
1991                   redo,(int)(((le16_to_cpu(logr->redo_length) - 1) | 7) + 1),
1992                   undo,(int)(((le16_to_cpu(logr->undo_length) - 1) | 7) + 1),
1993                   extra,(int)(end > extra ? end - extra : 0));
1994 
1995 	if (logr->redo_length && (get_redo_offset(logr) != redo))
1996 		printf("** Unexpected redo offset 0x%x %u (%u)\n",
1997 			get_redo_offset(logr),(int)redo,
1998 			(int)le16_to_cpu(logr->lcns_to_follow));
1999 	if (logr->undo_length && (get_undo_offset(logr) != undo))
2000 		printf("** Unexpected undo offset 0x%x %u (%u)\n",
2001 			get_undo_offset(logr),(int)undo,
2002 			(int)le16_to_cpu(logr->lcns_to_follow));
2003 	if (get_extra_offset(logr) != extra)
2004 		printf("** Unexpected extra offset 0x%x %u (%u)\n",
2005 			get_extra_offset(logr),(int)extra,
2006 			(int)le16_to_cpu(logr->lcns_to_follow));
2007 
2008          if (extra <= end)
2009             {
2010                                        /* show redo data */
2011             if (logr->redo_length)
2012                {
2013                if (logr->lcns_to_follow)
2014                   {
2015                   off = le16_to_cpu(logr->record_offset)
2016 					+ le16_to_cpu(logr->attribute_offset);
2017                   printf("redo data (new data) cluster 0x%llx pos 0x%x :\n",
2018                         (long long)sle64_to_cpu(logr->lcn_list[off
2019 						>> clusterbits]),
2020                         (int)(off & (clustersz - 1)));
2021                   }
2022                else
2023 			printf("redo data (new data) at offs 0x%x :\n",redo);
2024                if ((u32)(redo + le16_to_cpu(logr->redo_length))
2025                     <= end)
2026                   {
2027                   hexdump((const char*)logr
2028 				+ redo,le16_to_cpu(logr->redo_length));
2029                   fixup(ctx, logr, (const char*)logr + redo, TRUE);
2030                   }
2031                else printf("redo data overflowing from record\n");
2032                }
2033             else
2034                {
2035                printf("no redo data (new data)\n");
2036                fixup(ctx, logr, (const char*)logr + redo, TRUE);
2037                }
2038 
2039                                      /* show undo data */
2040             if (logr->undo_length)
2041                {
2042                if (logr->lcns_to_follow)
2043                    {
2044                    off = le16_to_cpu(logr->record_offset)
2045 					+ le16_to_cpu(logr->attribute_offset);
2046                    printf("undo data (old data) cluster 0x%llx pos 0x%x :\n",
2047                          (long long)sle64_to_cpu(logr->lcn_list[off
2048 							>> clusterbits]),
2049                          (int)(off & (clustersz - 1)));
2050                    }
2051                else printf("undo data (old data) at offs 0x%x :\n",undo);
2052                if ((u32)(undo + le16_to_cpu(logr->undo_length)) <= end)
2053                   {
2054                   if ((undo + le16_to_cpu(logr->undo_length)) < 2*blocksz)
2055                      {
2056                      hexdump((const char*)logr
2057 					+ undo,le16_to_cpu(logr->undo_length));
2058                      fixup(ctx, logr, (const char*)logr + undo, FALSE);
2059                      }
2060                   else printf("undo data overflowing from two blocks\n");
2061                   }
2062                else printf("undo data overflowing from record\n");
2063                }
2064             else
2065                {
2066                printf("no undo data (old data)\n");
2067                fixup(ctx, logr, (const char*)logr + undo, FALSE);
2068                }
2069 
2070                                     /* show extra data, if any */
2071             if (extra != end)
2072                {
2073                if (end > blocksz)
2074                   printf("invalid extra data size\n");
2075                else
2076                   {
2077                   printf("extra data at offs 0x%x\n",extra);
2078                   hexdump((const char*)logr + extra,
2079                             end - extra);
2080                   }
2081                }
2082             }
2083          else
2084             {
2085 			/* sometimes the designated data overflows */
2086             if (logr->redo_length
2087               && ((u32)(redo + le16_to_cpu(logr->redo_length)) > end))
2088                 printf("* redo data overflows from record\n");
2089             if (logr->undo_length
2090               && ((u32)(undo + le16_to_cpu(logr->undo_length)) > end))
2091                 printf("* undo data overflows from record\n");
2092 	    }
2093          	break;
2094 	case LOG_CHECKPOINT :
2095 		printf("---> checkpoint record\n");
2096 		printf("redo_operation         %04x %s\n",
2097 			(int)le16_to_cpu(logr->redo_operation),
2098 			actionname(le16_to_cpu(logr->redo_operation)));
2099 		printf("undo_operation         %04x %s\n",
2100 			(int)le16_to_cpu(logr->undo_operation),
2101 			actionname(le16_to_cpu(logr->undo_operation)));
2102 		printf("redo_offset            %04x\n",
2103 			(int)le16_to_cpu(logr->redo_offset));
2104 		printf("redo_length            %04x\n",
2105 			(int)le16_to_cpu(logr->redo_length));
2106 		printf("transaction_lsn        %016llx\n",
2107 			(long long)sle64_to_cpu(logr->transaction_lsn));
2108 		printf("attributes_lsn         %016llx\n",
2109 			(long long)sle64_to_cpu(logr->attributes_lsn));
2110 		printf("names_lsn              %016llx\n",
2111 			(long long)sle64_to_cpu(logr->names_lsn));
2112 		printf("dirty_pages_lsn        %016llx\n",
2113 			(long long)sle64_to_cpu(logr->dirty_pages_lsn));
2114 		listsize = le32_to_cpu(logr->client_data_length)
2115 				+ LOG_RECORD_HEAD_SZ
2116 				- offsetof(LOG_RECORD, unknown_list);
2117 		if (listsize > 8*SHOWLISTS)
2118 			listsize = 8*SHOWLISTS;
2119 		for (i=0; 8*i<listsize; i++)
2120 			printf("unknown-%u              %016llx\n",i,
2121 				(long long)le64_to_cpu(logr->unknown_list[i]));
2122 		break;
2123 	default :
2124 		printf("** Unknown action type\n");
2125 		if (le32_to_cpu(logr->client_data_length) < blocksz) {
2126 			printf("client_data for record type %ld\n",
2127 				(long)le32_to_cpu(logr->record_type));
2128 			hexdump((const char*)&logr->redo_operation,
2129 				le32_to_cpu(logr->client_data_length));
2130 		} else
2131 			printf("** Bad client data\n");
2132 		break;
2133 	}
2134 }
2135 
within_lcn_range(const LOG_RECORD * logr)2136 BOOL within_lcn_range(const LOG_RECORD *logr)
2137 {
2138 	u64 lcn;
2139 	unsigned int i;
2140 	BOOL within;
2141 
2142 	within = FALSE;
2143    	switch (logr->record_type) {
2144       	case LOG_STANDARD :
2145          	for (i=0; i<le16_to_cpu(logr->lcns_to_follow); i++) {
2146 			lcn = MREF(sle64_to_cpu(logr->lcn_list[i]));
2147 			if ((lcn >= firstlcn) && (lcn <= lastlcn))
2148 				within = TRUE;
2149 		}
2150 		break;
2151 	default :
2152 		break;
2153 	}
2154 	return (within);
2155 }
2156 
showlogr(CONTEXT * ctx,int k,const LOG_RECORD * logr)2157 static void showlogr(CONTEXT *ctx, int k, const LOG_RECORD *logr)
2158 {
2159 	s32 diff;
2160 
2161 	if (optv && (!optc || within_lcn_range(logr))) {
2162 		diff = sle64_to_cpu(logr->this_lsn) - synced_lsn;
2163 		printf("this_lsn               %016llx (synced%s%ld) %s\n",
2164 			(long long)sle64_to_cpu(logr->this_lsn),
2165 			(diff < 0 ? "" : "+"),(long)diff,
2166 			commitment(diff + synced_lsn));
2167 		printf("client_previous_lsn    %016llx\n",
2168 			(long long)sle64_to_cpu(logr->client_previous_lsn));
2169 		printf("client_undo_next_lsn   %016llx\n",
2170 			(long long)sle64_to_cpu(logr->client_undo_next_lsn));
2171 		printf("client_data_length     %08lx\n",
2172 			(long)le32_to_cpu(logr->client_data_length));
2173 		printf("seq_number             %d\n",
2174 			(int)le16_to_cpu(logr->client_id.seq_number));
2175 		printf("client_index           %d\n",
2176 			(int)le16_to_cpu(logr->client_id.client_index));
2177 		printf("record_type            %08lx\n",
2178 			(long)le32_to_cpu(logr->record_type));
2179 		printf("transaction_id         %08lx\n",
2180 			(long)le32_to_cpu(logr->transaction_id));
2181 		printf("log_record_flags       %04x\n",
2182 			(int)le16_to_cpu(logr->log_record_flags));
2183 		printf("reserved1              %04x %04x %04x\n",
2184 			(int)le16_to_cpu(logr->reserved_or_alignment[0]),
2185 		(int)le16_to_cpu(logr->reserved_or_alignment[1]),
2186 		(int)le16_to_cpu(logr->reserved_or_alignment[2]));
2187 		detaillogr(ctx, logr);
2188 	}
2189 	if (optt) {
2190 		const char *state;
2191 
2192 		if (logr->record_type == LOG_CHECKPOINT)
2193 			state = "--checkpoint--";
2194 		else
2195 			state = commitment(sle64_to_cpu(logr->this_lsn));
2196 		printf("      at %04x  %016llx %s (%ld) %s\n",k,
2197 			(long long)sle64_to_cpu(logr->this_lsn),
2198 			state,
2199 			(long)(sle64_to_cpu(logr->this_lsn) - synced_lsn),
2200 			actionname(le16_to_cpu(logr->redo_operation)));
2201 		if (logr->client_previous_lsn || logr->client_undo_next_lsn) {
2202 			if (logr->client_previous_lsn
2203 					== logr->client_undo_next_lsn) {
2204 				printf("                               "
2205 					" previous and undo %016llx\n",
2206 					(long long)sle64_to_cpu(
2207 						logr->client_previous_lsn));
2208 			} else {
2209 				printf("                               "
2210 					" previous %016llx",
2211 					(long long)sle64_to_cpu(
2212 						logr->client_previous_lsn));
2213 
2214 				if (logr->client_undo_next_lsn)
2215 					printf(" undo %016llx\n",
2216 						(long long)sle64_to_cpu(
2217 						logr->client_undo_next_lsn));
2218 				else
2219 					printf("\n");
2220 			}
2221 		}
2222 	}
2223 }
2224 
2225 /*
2226  *		Mark transactions which should be redone
2227  */
2228 
mark_transactions(struct ACTION_RECORD * lastaction)2229 static void mark_transactions(struct ACTION_RECORD *lastaction)
2230 {
2231 	struct ACTION_RECORD *action;
2232 	const LOG_RECORD *logr;
2233 	le32 id;
2234 	int actives;
2235 	BOOL more;
2236 	BOOL committed;
2237 
2238 	actives = 0;
2239 	do {
2240 		more = FALSE;
2241 		id = const_cpu_to_le32(0);
2242 		for (action=lastaction; action; action=action->prev) {
2243 			logr = &action->record;
2244 			if ((logr->redo_operation
2245 				== const_cpu_to_le16(ForgetTransaction))
2246 			    && !(action->flags & ACTION_TO_REDO)
2247 			    && !id) {
2248 				id = logr->transaction_id;
2249 				action->flags |= ACTION_TO_REDO;
2250 				if (optv)
2251 					printf("Marking transaction 0x%x\n",
2252 						(int)le32_to_cpu(id));
2253 			}
2254 			committed = ((s64)(sle64_to_cpu(logr->this_lsn)
2255 					- committed_lsn)) <= 0;
2256 			if (!logr->transaction_id
2257 			    && committed)
2258 				action->flags |= ACTION_TO_REDO;
2259 			if (id
2260 			    && (logr->transaction_id == id)
2261 			    && committed) {
2262 				action->flags |= ACTION_TO_REDO;
2263 				more = TRUE;
2264 			}
2265 		}
2266 	if (more)
2267 		actives++;
2268 	} while (more);
2269 		/*
2270 		 * Show unmarked (aborted) actions
2271 		 */
2272 	if (optv) {
2273 		for (action=lastaction; action; action=action->prev) {
2274 			logr = &action->record;
2275 			if (logr->transaction_id
2276 			   && !(action->flags & ACTION_TO_REDO))
2277 				printf("** Action %d was aborted\n",
2278 					(int)action->num);
2279 		}
2280 	}
2281 	if (optv && (actives > 1))
2282 		printf("%d active transactions in set\n",actives);
2283 }
2284 
2285 /*
2286  *		Enqueue an action and play the queued actions on end of set
2287  */
2288 
enqueue_action(CONTEXT * ctx,const LOG_RECORD * logr,int size,int num)2289 static TRISTATE enqueue_action(CONTEXT *ctx, const LOG_RECORD *logr,
2290 				int size, int num)
2291 {
2292 	struct ACTION_RECORD *action;
2293 	TRISTATE state;
2294 	int err;
2295 
2296 	err = 1;
2297 	state = T_ERR;
2298 		/* enqueue record */
2299 	action = (struct ACTION_RECORD*)
2300 			malloc(size + offsetof(struct ACTION_RECORD, record));
2301 	if (action) {
2302 		memcpy(&action->record, logr, size);
2303 		action->num = num;
2304 		action->flags = 0;
2305 		/* enqueue ahead of list, firstaction is the oldest one */
2306 		action->prev = (struct ACTION_RECORD*)NULL;
2307 		action->next = ctx->firstaction;
2308 		if (ctx->firstaction)
2309 			ctx->firstaction->prev = action;
2310 		else
2311 			ctx->lastaction = action;
2312 		ctx->firstaction = action;
2313 		err = 0;
2314 		state = T_OK;
2315 		if ((optp || optu)
2316 		    && (logr->record_type == LOG_CHECKPOINT)) {
2317 			/* if chkp process queue, and increment count */
2318 			playedactions++;
2319 			if (playedactions <= playcount) {
2320 				if (optv)
2321 					printf("* Refreshing attributes\n");
2322 				err = refresh_attributes(ctx->firstaction);
2323 				if (optv)
2324 					printf("* Undoing transaction set %d"
2325 						" (actions %d->%d)\n",
2326 						(int)playedactions,
2327 						(int)ctx->lastaction->num,
2328 						(int)ctx->firstaction->num);
2329 				err = play_undos(ctx->vol, ctx->lastaction);
2330 				if (err)
2331 					printf("* Undoing transaction"
2332 							" set failed\n");
2333 			}
2334 			if (!err && optp && (playedactions == playcount)) {
2335 				if (optv)
2336 					printf("* Redoing transaction set %d"
2337 						" (actions %d->%d)\n",
2338 						(int)playedactions,
2339 						(int)ctx->firstaction->num,
2340 						(int)ctx->lastaction->num);
2341 				mark_transactions(ctx->lastaction);
2342 				err = play_redos(ctx->vol, ctx->firstaction);
2343 				if (err)
2344 					printf("* Redoing transaction"
2345 							" set failed\n");
2346 			}
2347 			if (err)
2348 				state = T_ERR;
2349 			else
2350 				if (playedactions == playcount)
2351 					state = T_DONE;
2352 				/* free queue */
2353 			while (ctx->firstaction) {
2354 				action = ctx->firstaction->next;
2355 				free(ctx->firstaction);
2356 				ctx->firstaction = action;
2357 			}
2358 			ctx->lastaction = (struct ACTION_RECORD*)NULL;
2359  		}
2360 		if (opts
2361 		    && ((s64)(sle64_to_cpu(logr->this_lsn) - synced_lsn) <= 0)) {
2362 			if (optv)
2363 				printf("* Refreshing attributes\n");
2364 // should refresh backward ?
2365 			err = refresh_attributes(ctx->firstaction);
2366 			mark_transactions(ctx->lastaction);
2367 			if (!err) {
2368 				if (optv)
2369 					printf("* Syncing actions %d->%d\n",
2370 						(int)ctx->firstaction->num,
2371 						(int)ctx->lastaction->num);
2372 				err = play_redos(ctx->vol, ctx->firstaction);
2373 			}
2374 			if (err) {
2375 				printf("* Syncing actions failed\n");
2376 				state = T_ERR;
2377 			} else
2378 				state = T_DONE;
2379 		}
2380 	}
2381 	return (state);
2382 }
2383 
2384 
showheadrcrd(u32 blk,const RECORD_PAGE_HEADER * rph)2385 static void showheadrcrd(u32 blk, const RECORD_PAGE_HEADER *rph)
2386 {
2387 	s32 diff;
2388 
2389 	if (optv) {
2390 		printf("magic              %08lx\n",
2391 			(long)le32_to_cpu(rph->magic));
2392 		printf("usa_ofs            %04x\n",
2393 			(int)le16_to_cpu(rph->usa_ofs));
2394 		printf("usa_count          %04x\n",
2395 			(int)le16_to_cpu(rph->usa_count));
2396 		if (blk < 4)
2397 			printf("file_offset        %016llx\n",
2398 				(long long)sle64_to_cpu(rph->copy.file_offset));
2399 		else {
2400 			diff = sle64_to_cpu(rph->copy.last_lsn) - synced_lsn;
2401 			printf("last_lsn           %016llx"
2402 				" (synced%s%ld)\n",
2403 				(long long)sle64_to_cpu(rph->copy.last_lsn),
2404 				(diff < 0 ? "" : "+"),(long)diff);
2405 		}
2406 		printf("flags              %08lx\n",
2407 			(long)le32_to_cpu(rph->flags));
2408 		printf("page_count         %d\n",
2409 			(int)le16_to_cpu(rph->page_count));
2410 		printf("page_position      %d\n",
2411 			(int)le16_to_cpu(rph->page_position));
2412 		printf("next_record_offset %04x\n",
2413 			(int)le16_to_cpu(rph->next_record_offset));
2414 		printf("reserved4          %04x %04x %04x\n",
2415 			(int)le16_to_cpu(rph->reserved[0]),
2416 			(int)le16_to_cpu(rph->reserved[1]),
2417 			(int)le16_to_cpu(rph->reserved[2]));
2418 		diff = sle64_to_cpu(rph->last_end_lsn) - synced_lsn;
2419 		printf("last_end_lsn       %016llx (synced%s%ld)\n",
2420 			(long long)sle64_to_cpu(rph->last_end_lsn),
2421 			(diff < 0 ? "" : "+"),(long)diff);
2422 		printf("usn                %04x\n",
2423 			(int)getle16(rph,le16_to_cpu(rph->usa_ofs)));
2424 		printf("\n");
2425 	} else {
2426 		if (optt) {
2427 			const char *state;
2428 
2429 			state = commitment(sle64_to_cpu(rph->copy.last_lsn));
2430 			diff = sle64_to_cpu(rph->copy.last_lsn) - synced_lsn;
2431 			printf("   last        %016llx (synced%s%ld) %s\n",
2432 				(long long)sle64_to_cpu(rph->copy.last_lsn),
2433 				(diff < 0 ? "" : "+"),(long)diff, state);
2434 			state = commitment(sle64_to_cpu(rph->last_end_lsn));
2435 			diff = sle64_to_cpu(rph->last_end_lsn) - synced_lsn;
2436 			printf("   last_end    %016llx (synced%s%ld) %s\n",
2437 				(long long)sle64_to_cpu(rph->last_end_lsn),
2438 				(diff < 0 ? "" : "+"),(long)diff, state);
2439 		}
2440 	}
2441 }
2442 
2443 /*
2444  *		Analyze and display an action overlapping log blocks
2445  *
2446  *	Returns the position of first action in next block. If this is
2447  *	greater than a block size (for actions overlapping more than
2448  *	two blocks), then some blocks have to be skipped.
2449  *
2450  *	Returns 0 in case of error
2451  */
2452 
overlapshow(CONTEXT * ctx,u16 k,u32 blk,const struct BUFFER * buf,const struct BUFFER * nextbuf)2453 static u16 overlapshow(CONTEXT *ctx, u16 k, u32 blk, const struct BUFFER *buf,
2454 			const struct BUFFER *nextbuf)
2455 {
2456 	const LOG_RECORD *logr;
2457 	const char *data;
2458 	const char *nextdata;
2459 	char *fullrec;
2460 	u32 size;
2461 	u32 nextspace;
2462 	u32 space;
2463 	BOOL likely;
2464 	u16 blkheadsz;
2465 
2466 	data = buf->block.data;
2467 	logr = (const LOG_RECORD*)&data[k];
2468 	size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ;
2469 	blkheadsz = buf->headsz;
2470 	if (nextbuf && (blk >= BASEBLKS)) {
2471 		nextdata = nextbuf->block.data;
2472 		space = blocksz - k;
2473 		nextspace = blocksz - blkheadsz;
2474 		if ((space >= LOG_RECORD_HEAD_SZ)
2475 		    && (size > space)) {
2476 			fullrec = (char*)malloc(size);
2477 			if (size <= (space + nextspace)) {
2478 				/* Overlap on two blocks */
2479 				memcpy(fullrec,&data[k],space);
2480 				memcpy(&fullrec[space],
2481 					nextdata + blkheadsz,
2482 					size - space);
2483 				likely = likelyop((LOG_RECORD*)fullrec);
2484 				actionnum++;
2485 				if (optv) {
2486 					printf("\nOverlapping record %u at 0x%x"
2487 						" size %d (next at 0x%x)\n",
2488 						(int)actionnum,(int)k,
2489 						(int)size, (int)(k + size));
2490 					printf("Overlap marked for block %ld"
2491 						" space %d likely %d\n",
2492 						(long)blk,(int)space,likely);
2493 				}
2494 				if (likely)
2495 					showlogr(ctx, k,
2496 						(LOG_RECORD*)fullrec);
2497 				else
2498 					printf("** Skipping unlikely"
2499 						" overlapping record\n");
2500 				k += size - blocksz + blkheadsz;
2501 			} else {
2502 				const struct BUFFER *midbuf;
2503 				int skip;
2504 				u32 next;
2505 				u32 pos;
2506 				int i;
2507 
2508 			/*
2509 			 * The maximum size of of log record is 131104
2510 			 * (when both offset and length are 65528 for
2511 			 * redo or undo).
2512 			 * So up to 33 log blocks (useful size 4032)
2513 			 * could be needed. However never both undo and
2514 			 * redo have been found big, and 17 should be
2515 			 * the real maximum.
2516 			 */
2517 				if (optv)
2518 					printf("More than two blocks required"
2519 						" (size %lu)\n",(long)size);
2520 				memcpy(fullrec,&data[k],space);
2521 
2522 				skip = (size - space - 1)/nextspace;
2523 				pos = space;
2524 				likely = TRUE;
2525 				for (i=1; (i<=skip) && likely; i++) {
2526 					midbuf = read_buffer(ctx, blk + i);
2527 					if (midbuf) {
2528 						memcpy(&fullrec[pos],
2529 							&midbuf->block
2530 							    .data[blkheadsz],
2531 							nextspace);
2532 						pos += nextspace;
2533 					} else
2534 						likely = FALSE;
2535 				}
2536 				if (pos >= size) {
2537 					printf("** Error : bad big overlap"
2538 						" pos %d size %d\n",
2539 						(int)pos,(int)size);
2540 					likely = FALSE;
2541 				}
2542 				midbuf = read_buffer(ctx, blk + skip + 1);
2543 				if (midbuf)
2544 					memcpy(&fullrec[pos],
2545 						&midbuf->block.data[blkheadsz],
2546 						size - pos);
2547 				else
2548 					likely = FALSE;
2549 				if (!likelyop((LOG_RECORD*)fullrec))
2550 					likely = FALSE;
2551 				actionnum++;
2552 				if (optv) {
2553 					printf("\nBig overlapping record %u at "
2554 						"0x%x size %u (next at 0x%x)\n",
2555 						(int)actionnum,(int)k,(int)size,
2556 						(int)(k + size));
2557 					printf("Overlap marked for block %ld"
2558 						" space %d likely %d\n",
2559 						(long)blk,(int)space,likely);
2560 				}
2561 				if (likely)
2562 					showlogr(ctx, k,
2563 						(LOG_RECORD*)fullrec);
2564 				else
2565 					printf("** Skipping unlikely"
2566 						" overlapping record\n");
2567 				/* next and skip are only for displaying */
2568 				next = (size - space) % nextspace
2569 							+ blkheadsz;
2570 				if ((blocksz - next) < LOG_RECORD_HEAD_SZ)
2571 					next = blkheadsz;
2572 				if (next == blkheadsz)
2573 					skip++;
2574 				if (optv)
2575 					printf("Next record expected in"
2576 						" block %lu index 0x%x\n",
2577 						(long)(blk + skip + 1),next);
2578 					/* Quick check, with no consequences */
2579 				if (firstrecord(skip,buf,buf) != next)
2580 					printf("** Error next != firstrecord"
2581 						" after block %d\n",blk);
2582 				k += size - blocksz + blkheadsz;
2583 			}
2584 			if (!likely)
2585 				k = 0;
2586 			else
2587 				if (!k)
2588 					printf("* Bad return from overlap()\n");
2589 			free(fullrec);
2590 		} else {
2591 			/* No conditions for overlap, usually a new session */
2592 			printf("* No block found overlapping on block %d\n",
2593 					(int)blk);
2594 			k = 0;
2595 		}
2596 	} else {
2597 		/* blocks 2, 3 and the last one have no next block */
2598 		k = 0;
2599 	}
2600 	return (k);
2601 }
2602 
2603 /*
2604  *		Analyze and forward display the actions in a log block
2605  *
2606  *	Returns the position of first action in next block. If this is
2607  *	greater than a block size, then some blocks have to be skipped.
2608  *
2609  *	Returns 0 in case of error
2610  */
2611 
forward_rcrd(CONTEXT * ctx,u32 blk,u16 pos,const struct BUFFER * buf,const struct BUFFER * nextbuf)2612 static u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos,
2613 			const struct BUFFER *buf, const struct BUFFER *nextbuf)
2614 {
2615 	const RECORD_PAGE_HEADER *rph;
2616 	const LOG_RECORD *logr;
2617 	const char *data;
2618 	u16 k;
2619 	u16 endoff;
2620 	BOOL stop;
2621 
2622 	rph = &buf->block.record;
2623 	if (rph && (rph->magic == magic_RCRD)) {
2624 		data = buf->block.data;
2625 		showheadrcrd(blk, rph);
2626 		k = buf->headsz;
2627 		if ((k < pos) && (pos < blocksz)) {
2628 			k = ((pos - 1) | 7) + 1;
2629 		}
2630 // TODO check bad start > blocksz - 48
2631 		logr = (const LOG_RECORD*)&data[k];
2632 		stop = FALSE;
2633 		if (!likelyop(logr)) {
2634 			if (optv)
2635 				printf("* Bad start 0x%x for block %d\n",
2636 					(int)pos,(int)blk);
2637 			k = searchlikely(buf);
2638 			if ((k + sizeof(LOG_RECORD)) > blocksz) {
2639 				printf("No likely full record in block %lu\n",
2640 						(unsigned long)blk);
2641 		      /* there can be a partial one */
2642 				k = le16_to_cpu(rph->next_record_offset);
2643 				if ((k < (u16)sizeof(RECORD_PAGE_HEADER))
2644 				    || ((blocksz - k) < LOG_RECORD_HEAD_SZ))
2645 					stop = TRUE;
2646 			} else {
2647 				if (optv)
2648 					printf("First record computed at"
2649 						" offset 0x%x\n", (int)k);
2650 			}
2651 		}
2652 		while (!stop) {
2653 			s32 size;
2654 
2655 			logr = (const LOG_RECORD*)&data[k];
2656 			size = le32_to_cpu(logr->client_data_length)
2657 						+ LOG_RECORD_HEAD_SZ;
2658 			if ((size < MINRECSIZE)
2659 			    || (size > MAXRECSIZE)
2660 			    || (size & 7)) {
2661 				printf("** Bad record size %ld in block %ld"
2662 					" offset 0x%x\n",
2663 					(long)size, (long)buf->num, (int)k);
2664 				showlogr(ctx, k, logr);
2665 				k = 0;
2666 				stop = TRUE;
2667 			} else {
2668 				endoff = le16_to_cpu(rph->next_record_offset);
2669 				if (((u32)(k + size) <= blocksz)
2670 				    && ((u32)(k + size) <= endoff)) {
2671 					actionnum++;
2672 					if (optv) {
2673 						printf("\n* log action %u at"
2674 							" 0x%x size %d (next"
2675 							" at 0x%x)\n",
2676 							actionnum,k,size,
2677 							k + size);
2678 					}
2679 					showlogr(ctx, k, logr);
2680 					if (!logr->client_data_length) {
2681 						printf("** Bad"
2682 						    " client_data_length\n");
2683 						stop = TRUE;
2684 					}
2685 					k += size;
2686 					if ((blocksz - k)
2687 							< LOG_RECORD_HEAD_SZ) {
2688 						k = nextbuf->headsz;
2689 						stop = TRUE;
2690 					}
2691 				} else {
2692 					k = overlapshow(ctx, k, blk,
2693 								buf, nextbuf);
2694 					stop = TRUE;
2695 	       			}
2696 	    		}
2697 		}
2698 	} else {
2699 		printf("** Not a RCRD record, MAGIC 0x%08lx\n",
2700 			(long)le32_to_cpu(rph->magic));
2701 		k = 0;
2702 	}
2703 	return (k);
2704 }
2705 
2706 /*
2707  *                Display a restart page
2708  */
2709 
showrest(const RESTART_PAGE_HEADER * rest)2710 static void showrest(const RESTART_PAGE_HEADER *rest)
2711 {
2712 	const RESTART_AREA *resa;
2713 	const LOG_CLIENT_RECORD *rcli;
2714 	const char *data;
2715 
2716 	data = (const char*)rest;
2717 	if ((rest->magic == magic_RSTR)
2718 			|| (rest->magic == magic_CHKD)) {
2719 		if (optv) {
2720 			printf("magic                  %08lx\n",
2721 				(long)le32_to_cpu(rest->magic));
2722 			printf("usa_ofs                %04x\n",
2723 				(int)le16_to_cpu(rest->usa_ofs));
2724 			printf("usa_count              %04x\n",
2725 				(int)le16_to_cpu(rest->usa_count));
2726 			printf("chkdsk_lsn             %016llx\n",
2727 				(long long)sle64_to_cpu(rest->chkdsk_lsn));
2728 			printf("system_page_size       %08lx\n",
2729 				(long)le32_to_cpu(rest->system_page_size));
2730 			printf("log_page_size          %08lx\n",
2731 				(long)le32_to_cpu(rest->log_page_size));
2732 			printf("restart_area_offset    %04x\n",
2733 				(int)le16_to_cpu(rest->restart_area_offset));
2734 			printf("minor_vers             %d\n",
2735 				(int)sle16_to_cpu(rest->minor_ver));
2736 			printf("major_vers             %d\n",
2737 				(int)sle16_to_cpu(rest->major_ver));
2738 			printf("usn                    %04x\n",
2739 				(int)le16_to_cpu(rest->usn));
2740 			printf("\n");
2741 		} else {
2742 			if (optt)
2743 				printf("    chkdsk         %016llx\n",
2744 				    (long long)sle64_to_cpu(rest->chkdsk_lsn));
2745 		}
2746 		resa = (const RESTART_AREA*)
2747 				&data[le16_to_cpu(rest->restart_area_offset)];
2748 		if (optv) {
2749 			printf("current_lsn            %016llx\n",
2750 				(long long)sle64_to_cpu(resa->current_lsn));
2751 			printf("log_clients            %04x\n",
2752 				(int)le16_to_cpu(resa->log_clients));
2753 			printf("client_free_list       %04x\n",
2754 				(int)le16_to_cpu(resa->client_free_list));
2755 			printf("client_in_use_list     %04x\n",
2756 				(int)le16_to_cpu(resa->client_in_use_list));
2757 			printf("flags                  %04x\n",
2758 				(int)le16_to_cpu(resa->flags));
2759 			printf("seq_number_bits        %08lx\n",
2760 				(long)le32_to_cpu(resa->seq_number_bits));
2761 			printf("restart_area_length    %04x\n",
2762 				(int)le16_to_cpu(resa->restart_area_length));
2763 			printf("client_array_offset    %04x\n",
2764 				(int)le16_to_cpu(resa->client_array_offset));
2765 			printf("file_size              %016llx\n",
2766 				(long long)sle64_to_cpu(resa->file_size));
2767 			printf("last_lsn_data_len      %08lx\n",
2768 				(long)le32_to_cpu(resa->last_lsn_data_length));
2769 			printf("record_length          %04x\n",
2770 				(int)le16_to_cpu(resa->log_record_header_length));
2771 			printf("log_page_data_offs     %04x\n",
2772 				(int)le16_to_cpu(resa->log_page_data_offset));
2773 			printf("restart_log_open_count %08lx\n",
2774 				(long)le32_to_cpu(resa->restart_log_open_count));
2775 			printf("\n");
2776 		} else {
2777 			if (optt)
2778 				printf("    latest         %016llx\n",
2779 				    (long long)sle64_to_cpu(resa->current_lsn));
2780 		}
2781 
2782 		rcli = (const LOG_CLIENT_RECORD*)
2783 				&data[le16_to_cpu(rest->restart_area_offset)
2784 				+ le16_to_cpu(resa->client_array_offset)];
2785 		if (optv) {
2786 			printf("oldest_lsn             %016llx\n",
2787 				(long long)sle64_to_cpu(rcli->oldest_lsn));
2788 			printf("client_restart_lsn     %016llx\n",
2789 				(long long)sle64_to_cpu(rcli->client_restart_lsn));
2790 			printf("prev_client            %04x\n",
2791 				(int)le16_to_cpu(rcli->prev_client));
2792 			printf("next_client            %04x\n",
2793 				(int)le16_to_cpu(rcli->next_client));
2794 			printf("seq_number             %04x\n",
2795 				(int)le16_to_cpu(rcli->seq_number));
2796 			printf("client_name_length     %08x\n",
2797 				(int)le32_to_cpu(rcli->client_name_length));
2798 			showname("client_name            ",
2799 				(const char*)rcli->client_name,
2800 				le32_to_cpu(rcli->client_name_length) >> 1);
2801 		} else {
2802 			if (optt) {
2803 				printf("    synced         %016llx\n",
2804 					(long long)sle64_to_cpu(
2805 						rcli->oldest_lsn));
2806 				printf("    committed      %016llx\n",
2807 					(long long)sle64_to_cpu(
2808 						rcli->client_restart_lsn));
2809 			}
2810 		}
2811 	} else
2812 		printf("Not a RSTR or CHKD record, MAGIC 0x%08lx\n",
2813 			(long)le32_to_cpu(rest->magic));
2814 }
2815 
dorest(CONTEXT * ctx,unsigned long blk,const RESTART_PAGE_HEADER * rph,BOOL initial)2816 static BOOL dorest(CONTEXT *ctx, unsigned long blk,
2817 			const RESTART_PAGE_HEADER *rph, BOOL initial)
2818 {
2819 	const RESTART_AREA *resa;
2820 	const LOG_CLIENT_RECORD *rcli;
2821 	const char *data;
2822 	s64 diff;
2823 	int offs;
2824 	int size;
2825 	BOOL change;
2826 	BOOL dirty;
2827 
2828 	data = (const char*)rph;
2829 	offs = le16_to_cpu(rph->restart_area_offset);
2830 	resa = (const RESTART_AREA*)&data[offs];
2831 	rcli = (const LOG_CLIENT_RECORD*)&data[offs
2832 				+ le16_to_cpu(resa->client_array_offset)];
2833 	if (initial) {
2834 		/* Information from block initially found best */
2835 		latest_lsn = sle64_to_cpu(resa->current_lsn);
2836 		committed_lsn = sle64_to_cpu(rcli->client_restart_lsn);
2837 		synced_lsn = sle64_to_cpu(rcli->oldest_lsn);
2838 		memcpy(&log_header, rph,
2839 				sizeof(RESTART_PAGE_HEADER));
2840 		offs = le16_to_cpu(log_header.restart_area_offset);
2841 		memcpy(&restart, &data[offs],
2842 				sizeof(RESTART_AREA));
2843 		offs += le16_to_cpu(restart.client_array_offset);
2844 		memcpy(&client, &data[offs],
2845 				sizeof(LOG_CLIENT_RECORD));
2846 		dirty = !(resa->flags & RESTART_VOLUME_IS_CLEAN);
2847 		if (optv || optt)
2848 			printf("* Using initial restart page,"
2849 				" syncing from 0x%llx, %s\n",
2850 				(long long)synced_lsn,
2851 				(dirty ? "dirty" : "clean"));
2852 			 /* Get the block page size */
2853 		blocksz = le32_to_cpu(rph->log_page_size);
2854 		if (optv)
2855 			printf("* Block size %ld bytes\n", (long)blocksz);
2856 		blockbits = 1;
2857 		while ((u32)(1 << blockbits) < blocksz)
2858 			blockbits++;
2859 	} else {
2860 		size = offs + le16_to_cpu(resa->restart_area_length);
2861 		if (optv) {
2862 			if (optv >= 2)
2863 				hexdump(data,size);
2864 			printf("* RSTR in block %ld 0x%lx (addr 0x%llx)\n",
2865 					(long)blk,(long)blk,
2866 					(long long)loclogblk(ctx, blk));
2867 		} else {
2868 			if (optt)
2869 				printf("restart %ld\n",(long)blk);
2870 		}
2871 		showrest(rph);
2872 		/* Information from an older restart block if requested */
2873 		dirty = !(restart.flags & RESTART_VOLUME_IS_CLEAN);
2874 		diff = sle64_to_cpu(rcli->client_restart_lsn) - committed_lsn;
2875 		if (ctx->vol) {
2876 			change = (opts > 1) && (diff < 0);
2877 		} else {
2878 			change = (opts > 1 ? diff < 0 : diff > 0);
2879 		}
2880 		if (change) {
2881 			committed_lsn = sle64_to_cpu(rcli->client_restart_lsn);
2882 			synced_lsn = sle64_to_cpu(rcli->oldest_lsn);
2883 			latest_lsn = sle64_to_cpu(resa->current_lsn);
2884 			memcpy(&log_header, rph,
2885 					sizeof(RESTART_PAGE_HEADER));
2886 			offs = le16_to_cpu(log_header.restart_area_offset);
2887 			memcpy(&restart, &data[offs],
2888 					sizeof(RESTART_AREA));
2889 			offs += le16_to_cpu(restart.client_array_offset);
2890 			memcpy(&client, &data[offs],
2891 					sizeof(LOG_CLIENT_RECORD));
2892 			dirty = !(resa->flags & RESTART_VOLUME_IS_CLEAN);
2893 			if (optv || optt)
2894 				printf("* Using %s restart page,"
2895 					" syncing from 0x%llx, %s\n",
2896 					(diff < 0 ? "older" : "newer"),
2897 					(long long)synced_lsn,
2898 					(dirty ? "dirty" : "clean"));
2899 		}
2900 	}
2901 	restart_lsn = synced_lsn;
2902 	offset_mask = ((u64)1 << (64 - le32_to_cpu(restart.seq_number_bits)))
2903 				- (1 << (blockbits - 3));
2904 	return (dirty);
2905 }
2906 
2907 /*
2908  *		Read and process the first restart block
2909  *
2910  *	In full mode, both restart page are silently analyzed by the
2911  *	library and the most recent readable one is used to define the
2912  *	sync parameters.
2913  *
2914  *	Returns the first restart buffer
2915  *		or NULL if the restart block is not valid
2916  */
2917 
2918 
read_restart(CONTEXT * ctx)2919 static const struct BUFFER *read_restart(CONTEXT *ctx)
2920 {
2921 	const struct BUFFER *buf;
2922 	BOOL bad;
2923 	int blk;
2924 	int major, minor;
2925 
2926 	bad = FALSE;
2927 	for (blk=0; blk<BASEBLKS2; blk++)
2928 		redirect[blk] = 0;
2929 	log_major = 0; /* needed for reading into a buffer */
2930 	if (ctx->vol) {
2931 		RESTART_PAGE_HEADER *rph;
2932 
2933 		rph = (RESTART_PAGE_HEADER*)NULL;
2934 		/* Full mode : use the restart page selected by the library */
2935 		if (ntfs_check_logfile(log_na, &rph)) {
2936 			/* rph is left unchanged for a wiped out log file */
2937 			if (rph) {
2938 				dorest(ctx, 0, rph, TRUE);
2939 				free(rph);
2940 				buf = read_buffer(ctx,0);
2941 			} else {
2942 				buf = (const struct BUFFER*)NULL;
2943 				printf("** The log file has been wiped out\n");
2944 			}
2945 		} else {
2946 			buf = (const struct BUFFER*)NULL;
2947 			printf("** Could not get any restart page\n");
2948 		}
2949 	} else {
2950 		/* Reduced mode : rely on first restart page */
2951 		blockbits = BLOCKBITS;	/* Until the correct value is read */
2952 		blocksz = 1L << blockbits;
2953 		buf = read_buffer(ctx,0);
2954 	}
2955 	if (buf) {
2956 		NTFS_RECORD_TYPES magic;
2957 
2958 		magic = buf->block.restart.magic;
2959 		switch (magic) {
2960 		case magic_RSTR :
2961 			break;
2962 		case magic_CHKD :
2963 			printf("** The log file has been obsoleted by chkdsk\n");
2964 			bad = TRUE;
2965 			break;
2966 		case magic_empty :
2967 			printf("** The log file has been wiped out\n");
2968 			bad = TRUE;
2969 			break;
2970 		default :
2971 			printf("** Invalid restart block\n");
2972 			bad = TRUE;
2973 			break;
2974 		}
2975 		if (!bad && !ctx->vol)
2976 			dorest(ctx, 0, &buf->block.restart, TRUE);
2977 		major = sle16_to_cpu(buf->block.restart.major_ver);
2978 		minor = sle16_to_cpu(buf->block.restart.minor_ver);
2979 		if ((major == 2) && (minor == 0)) {
2980 			if (!optk) {
2981 				printf("** Fast restart mode detected,"
2982 						" data could be lost\n");
2983 				printf("   Use option --kill-fast-restart"
2984 						" to bypass\n");
2985 				bad = TRUE;
2986 			}
2987 		} else
2988 			if ((major != 1) || (minor != 1)) {
2989 				printf("** Unsupported $LogFile version %d.%d\n",
2990 					major, minor);
2991 				bad = TRUE;
2992 			}
2993 		log_major = major;
2994 		if (bad) {
2995 			buf = (const struct BUFFER*)NULL;
2996 		}
2997 	}
2998 	return (buf);
2999 }
3000 
3001 /*
3002  *		Mark the logfile as synced
3003  */
3004 
reset_logfile(CONTEXT * ctx)3005 static int reset_logfile(CONTEXT *ctx __attribute__((unused)))
3006 {
3007 	char *buffer;
3008 	int off;
3009 	int err;
3010 
3011 	err = 1;
3012 	buffer = (char*)malloc(blocksz);
3013 	if (buffer) {
3014 		memset(buffer, 0, blocksz);
3015 		restart.client_in_use_list = LOGFILE_NO_CLIENT;
3016 		restart.flags |= RESTART_VOLUME_IS_CLEAN;
3017 		client.oldest_lsn = cpu_to_sle64(restart_lsn);
3018 		/* Set $LogFile version to 1.1 so that volume can be mounted */
3019 		log_header.major_ver = const_cpu_to_sle16(1);
3020 		log_header.minor_ver = const_cpu_to_sle16(1);
3021 		memcpy(buffer, &log_header,
3022 					sizeof(RESTART_PAGE_HEADER));
3023 		off = le16_to_cpu(log_header.restart_area_offset);
3024 		memcpy(&buffer[off], &restart,
3025 					sizeof(RESTART_AREA));
3026 		off += le16_to_cpu(restart.client_array_offset);
3027 		memcpy(&buffer[off], &client,
3028 					sizeof(LOG_CLIENT_RECORD));
3029 		if (!ntfs_mst_pre_write_fixup((NTFS_RECORD*)buffer, blocksz)
3030 		    && (ntfs_attr_pwrite(log_na, 0,
3031                 		blocksz, buffer) == blocksz)
3032 		    && (ntfs_attr_pwrite(log_na, (u64)1 << blockbits,
3033                 		blocksz, buffer) == blocksz))
3034 			err = 0;
3035 		free(buffer);
3036 	}
3037 	return (err);
3038 }
3039 
3040 /*
3041  *		Determine the most recent valid record block
3042  */
3043 
best_start(const struct BUFFER * buf,const struct BUFFER * altbuf)3044 static const struct BUFFER *best_start(const struct BUFFER *buf,
3045 				const struct BUFFER *altbuf)
3046 {
3047 	const struct BUFFER *best;
3048 	const RECORD_PAGE_HEADER *head;
3049 	const RECORD_PAGE_HEADER *althead;
3050 	s64 diff;
3051 
3052 	if (!buf || !altbuf)
3053 		best = (buf ? buf : altbuf);
3054 	else {
3055 		head = &buf->block.record;
3056 		althead = &altbuf->block.record;
3057 		/* determine most recent, caring for wraparounds */
3058 		diff = sle64_to_cpu(althead->last_end_lsn)
3059 					- sle64_to_cpu(head->last_end_lsn);
3060 		if (diff > 0)
3061 			best = altbuf;
3062 		else
3063 			best = buf;
3064 	}
3065 	if (best && (best->block.record.magic != magic_RCRD))
3066 		best = (const struct BUFFER*)NULL;
3067 	return (best);
3068 }
3069 
3070 /*
3071  *                 Interpret the boot data
3072  *
3073  *	Probably not needed any more, use ctx->vol
3074  */
3075 
getboot(const char * buf)3076 static BOOL getboot(const char *buf)
3077 {
3078 	u64 sectors;
3079 	u64 clusters;
3080 	u16 sectpercluster;
3081 	BOOL ok;
3082 
3083 	ok = TRUE;
3084 	/* Beware : bad alignment */
3085 	bytespersect = (buf[11] & 255) + ((buf[12] & 255) << 8);
3086 	sectpercluster = buf[13] & 255;
3087 	clustersz = bytespersect * (u32)sectpercluster;
3088 	clusterbits = 1;
3089 	while ((u32)(1 << clusterbits) < clustersz)
3090 		clusterbits++;
3091 	sectors = getle64(buf, 0x28);
3092 	clusters = sectors/sectpercluster;
3093 	mftlcn = getle64(buf, 0x30);
3094 	if (buf[0x40] & 0x80)
3095 		mftrecsz = 1 << (16 - (buf[0x40] & 15));
3096 	else
3097 		mftrecsz = (buf[0x40] & 127)*clustersz;
3098 	mftrecbits = 1;
3099 	while ((u32)(1 << mftrecbits) < mftrecsz)
3100 		mftrecbits++;
3101 	if (optv) {
3102 		if ((long long)sectors*bytespersect > 10000000000LL)
3103 			printf("Capacity %lld bytes (%lld GB)\n",
3104 				(long long)sectors*bytespersect,
3105 				(long long)sectors*bytespersect/1000000000);
3106 		else
3107 			printf("Capacity %lld bytes (%lld MB)\n",
3108 				(long long)sectors*bytespersect,
3109 				(long long)sectors*bytespersect/1000000);
3110 		printf("sectors %lld (0x%llx), sector size %d\n",
3111 				(long long)sectors,(long long)sectors,
3112 				(int)bytespersect);
3113 		printf("clusters %lld (0x%llx), cluster size %d (%d bits)\n",
3114 				(long long)clusters,(long long)clusters,
3115 				(int)clustersz,(int)clusterbits);
3116 		printf("MFT at cluster %lld (0x%llx), entry size %lu\n",
3117 				(long long)mftlcn,(long long)mftlcn,
3118 				(unsigned long)mftrecsz);
3119 		if (mftrecsz > clustersz)
3120 			printf("%ld clusters per MFT entry\n",
3121 				(long)(mftrecsz/clustersz));
3122 		else
3123 			printf("%ld MFT entries per cluster\n",
3124 				(long)(clustersz/mftrecsz));
3125 	}
3126 	return (ok);
3127 }
3128 
locatelogfile(CONTEXT * ctx)3129 static int locatelogfile(CONTEXT *ctx)
3130 {
3131 	int err;
3132 
3133 	err = 1;
3134 	log_ni = ntfs_inode_open(ctx->vol, FILE_LogFile);
3135 	if (log_ni) {
3136 		log_na = ntfs_attr_open(log_ni, AT_DATA, AT_UNNAMED, 0);
3137 		if (log_na) {
3138 			logfilesz = log_na->data_size;
3139 			err = 0;
3140 		}
3141 	}
3142 	return (err);
3143 }
3144 
3145 /*
3146  *		Analyze a $LogFile copy
3147  *
3148  *	A $LogFile cannot be played. It can be however be analyzed in
3149  *	stand-alone mode.
3150  *	The location of the $MFT will have to be determined elsewhere.
3151  */
3152 
getlogfiledata(CONTEXT * ctx,const char * boot)3153 static BOOL getlogfiledata(CONTEXT *ctx, const char *boot)
3154 {
3155 	const RESTART_PAGE_HEADER *rph;
3156 	const RESTART_AREA *rest;
3157 	BOOL ok;
3158 	u32 off;
3159 	s64 size;
3160 	u32 system_page_size;
3161 	u32 log_page_size;
3162 
3163 	ok = FALSE;
3164 	fseek(ctx->file,0L,2);
3165 	size = ftell(ctx->file);
3166 	rph = (const RESTART_PAGE_HEADER*)boot;
3167 	off = le16_to_cpu(rph->restart_area_offset);
3168 	/*
3169 	 * If the system or log page sizes are smaller than the ntfs block size
3170 	 * or either is not a power of 2 we cannot handle this log file.
3171 	 */
3172 	system_page_size = le32_to_cpu(rph->system_page_size);
3173 	log_page_size = le32_to_cpu(rph->log_page_size);
3174 	if (system_page_size < NTFS_BLOCK_SIZE ||
3175 			log_page_size < NTFS_BLOCK_SIZE ||
3176 			system_page_size & (system_page_size - 1) ||
3177 			log_page_size & (log_page_size - 1)) {
3178 		printf("** Unsupported page size.\n");
3179 		goto out;
3180 	}
3181 	if (off & 7 || off > system_page_size) {
3182 		printf("** Inconsistent restart area offset.\n");
3183 		goto out;
3184 	}
3185 	rest = (const RESTART_AREA*)&boot[off];
3186 
3187 		/* estimate cluster size from log file size (unreliable) */
3188 	switch (le32_to_cpu(rest->seq_number_bits)) {
3189 	case 45 : clustersz = 512; break;
3190 	case 43 : clustersz = 1024; break; /* can be 1024 or 2048 */
3191 	case 40 :
3192 	default : clustersz = 4096; break;
3193 	}
3194 
3195 	clusterbits = 1;
3196 	while ((u32)(1 << clusterbits) < clustersz)
3197 		clusterbits++;
3198 	printf("* Assuming cluster size %ld\n",(long)clustersz);
3199 	logfilelcn = 0;
3200 	logfilesz = size;
3201 	if (optv)
3202 		printf("Log file size %lld bytes, cluster size %ld\n",
3203 			(long long)size, (long)clustersz);
3204 	/* Have to wait an InitializeFileRecordSegment to get these values */
3205 	mftrecsz = 0;
3206 	mftrecbits = 0;
3207 	ok = TRUE;
3208 out:
3209 	return (ok);
3210 }
3211 
3212 /*
3213  *                 Get basic volume data
3214  *
3215  *	Locate the MFT and Logfile
3216  *	Not supposed to read the first log block...
3217  */
3218 
getvolumedata(CONTEXT * ctx,char * boot)3219 static BOOL getvolumedata(CONTEXT *ctx, char *boot)
3220 {
3221 	const RESTART_AREA *rest;
3222 	BOOL ok;
3223 
3224 	ok = FALSE;
3225 	rest = (const RESTART_AREA*)NULL;
3226 	if (ctx->vol) {
3227 		getboot(boot);
3228 		mftlcn = ctx->vol->mft_lcn;
3229 		mftcnt = ctx->vol->mft_na->data_size/mftrecsz;
3230 		if (!locatelogfile(ctx))
3231 			ok = TRUE;
3232 		else {
3233 			fprintf(stderr,"** Could not read the log file\n");
3234 		}
3235 	} else {
3236 		if (ctx->file
3237 		    && (!memcmp(boot,"RSTR",4) || !memcmp(boot,"CHKD",4))) {
3238 			printf("* Assuming a log file copy\n");
3239 			ok = getlogfiledata(ctx, boot);
3240 			if (!ok)
3241 				goto out;
3242 		} else
3243 			fprintf(stderr,"** Not an NTFS image or log file\n");
3244 		}
3245 // TODO get rest ?, meaningful ?
3246 	if (ok && rest) {
3247 		if (rest->client_in_use_list
3248 		   || !(rest->flags & const_cpu_to_le16(2)))
3249 			printf("Volume was not unmounted safely\n");
3250 		else
3251 			printf("Volume was unmounted safely\n");
3252 		if (le16_to_cpu(rest->client_in_use_list) > 1)
3253 			printf("** multiple clients not implemented\n");
3254 	}
3255 out:
3256 	return (ok);
3257 }
3258 
3259 /*
3260  *		Open the volume (or the log file) and gets its parameters
3261  *
3262  *	Returns TRUE if successful
3263  */
3264 
open_volume(CONTEXT * ctx,const char * device_name)3265 static BOOL open_volume(CONTEXT *ctx, const char *device_name)
3266 {
3267 	union {
3268 		char buf[1024];
3269 		 /* alignment may be needed in getboot() */
3270 		long long force_align;
3271 	} boot;
3272 	BOOL ok;
3273 	int got;
3274 
3275 	ok =FALSE;
3276 		/*
3277 		 * First check the boot sector, to avoid library errors
3278 		 * when trying to mount a log file.
3279 		 * If the device cannot be fopened or fread, then it is
3280 		 * unlikely to be a file.
3281 		 */
3282 	ctx->vol = (ntfs_volume*)NULL;
3283 	ctx->file = fopen(device_name, "rb");
3284 	if (ctx->file) {
3285 		got = fread(boot.buf,1,1024,ctx->file);
3286 		if ((got == 1024)
3287 		    && (!memcmp(boot.buf, "RSTR", 4)
3288 				|| !memcmp(boot.buf, "CHKD", 4))) {
3289 			/* This appears to be a log file */
3290 			ctx->vol = (ntfs_volume*)NULL;
3291 			ok = getvolumedata(ctx, boot.buf);
3292 			if (!ok) {
3293 				fclose(ctx->file);
3294 				goto out;
3295 			}
3296 		} else {
3297 			fclose(ctx->file);
3298 		}
3299 	}
3300 	if (!ok) {
3301 		/* Not a log file, assume an ntfs device, mount it */
3302 		ctx->file = (FILE*)NULL;
3303 		ctx->vol = ntfs_mount(device_name,
3304 			((optk || optp || optu || opts) && !optn
3305 				? NTFS_MNT_FORENSIC : NTFS_MNT_RDONLY));
3306 		if (ctx->vol) {
3307 			ok = getvolumedata(ctx, boot.buf);
3308 			if (!ok)
3309 				ntfs_umount(ctx->vol, TRUE);
3310 		}
3311 	}
3312 out:
3313 	return (ok);
3314 }
3315 
dorcrd(CONTEXT * ctx,u32 blk,u16 pos,const struct BUFFER * buf,const struct BUFFER * nextbuf)3316 static u16 dorcrd(CONTEXT *ctx, u32 blk, u16 pos, const struct BUFFER *buf,
3317 			const struct BUFFER *nextbuf)
3318 {
3319 	if (optv) {
3320 		if (optv >= 2)
3321 			hexdump(buf->block.data,blocksz);
3322 		printf("* RCRD in block %ld 0x%lx (addr 0x%llx)"
3323 			" from pos 0x%x\n",
3324 			(long)blk,(long)blk,
3325 			(long long)loclogblk(ctx, blk),(int)pos);
3326 	} else {
3327 		if (optt)
3328 			printf("block %ld\n",(long)blk);
3329 	}
3330 	return (forward_rcrd(ctx, blk, pos, buf, nextbuf));
3331 }
3332 
3333 /*
3334  *		Concatenate and process a record overlapping on several blocks
3335  */
3336 
backoverlap(CONTEXT * ctx,int blk,const char * data,const char * nextdata,int k)3337 static TRISTATE backoverlap(CONTEXT *ctx, int blk,
3338 			const char *data, const char *nextdata, int k)
3339 {
3340 	const LOG_RECORD *logr;
3341 	char *fullrec;
3342 	s32 size;
3343 	int space;
3344 	int nextspace;
3345 	TRISTATE state;
3346 	u16 blkheadsz;
3347 
3348 	logr = (const LOG_RECORD*)&data[k];
3349 	state = T_ERR;
3350 	size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ;
3351 	space = blocksz - k;
3352 	blkheadsz = sizeof(RECORD_PAGE_HEADER)
3353 			+ ((2*getle16(data,6) - 1) | 7) + 1;
3354 	nextspace = blocksz - blkheadsz;
3355 	if ((space >= LOG_RECORD_HEAD_SZ)
3356 	    && (size > space)
3357 	    && (size < MAXRECSIZE)) {
3358 		fullrec = (char*)malloc(size);
3359 		memcpy(fullrec,&data[k],space);
3360 		if (size <= (space + nextspace))
3361 			memcpy(&fullrec[space], nextdata + blkheadsz,
3362 						size - space);
3363 		else {
3364 			const struct BUFFER *morebuf;
3365 			const char *moredata;
3366 			int total;
3367 			int more;
3368 			unsigned int mblk;
3369 
3370 			if (optv)
3371 				printf("* big record, size %d\n",size);
3372 			total = space;
3373 			mblk = blk + 1;
3374 			while (total < size) {
3375 				if (mblk >= (logfilesz >> blockbits))
3376 					mblk = (log_major < 2 ? BASEBLKS
3377 							: BASEBLKS2);
3378 				more = size - total;
3379 				if (more > nextspace)
3380 					more = nextspace;
3381 				morebuf = read_buffer(ctx, mblk);
3382 				if (morebuf) {
3383 					moredata = morebuf->block.data;
3384 					memcpy(&fullrec[total],
3385 						moredata + blkheadsz, more);
3386 				}
3387 				total += more;
3388 				mblk++;
3389 			}
3390 		}
3391 
3392 		state = (likelyop((LOG_RECORD*)fullrec) ? T_OK : T_ERR);
3393 		actionnum++;
3394 		if (optv) {
3395 			printf("\nOverlapping backward action %d at 0x%x"
3396 				" size %d (next at 0x%x)\n",
3397 				(int)actionnum,(int)k,
3398 				(int)size,(int)(k + size));
3399 			printf("Overlap marked for block %ld space %d"
3400 				" likely %d\n",
3401 				(long)blk,(int)space,(state == T_OK));
3402 		}
3403 		if (state == T_OK) {
3404 			showlogr(ctx, k, (LOG_RECORD*)fullrec);
3405 			if (optp || optu || opts)
3406 				state = enqueue_action(ctx,
3407 						(LOG_RECORD*)fullrec,
3408 						size, actionnum);
3409 		} else {
3410 			/* Try to go on unless playing actions */
3411 			if (optb && (state == T_ERR))
3412 				state = T_OK;
3413 		}
3414 		free(fullrec);
3415 	} else {
3416 			/* Error conditions */
3417 		if ((size < MINRECSIZE) || (size > MAXRECSIZE)) {
3418 			printf("** Invalid record size %ld"
3419 					" in block %ld\n",
3420 					(long)size,(long)blk);
3421 		} else
3422 			printf("** Inconsistency : the final"
3423 						" record in block %ld"
3424 						" does not overlap\n",
3425 						(long)blk);
3426 			/* Do not abort, unless playing actions */
3427 		state = (optb ? T_OK : T_ERR);
3428 	}
3429 	return (state);
3430 }
3431 
backward_rcrd(CONTEXT * ctx,u32 blk,int skipped,const struct BUFFER * buf,const struct BUFFER * prevbuf,const struct BUFFER * nextbuf)3432 static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped,
3433                   const struct BUFFER *buf, const struct BUFFER *prevbuf,
3434                   const struct BUFFER *nextbuf)
3435 {
3436 	u16 poslist[75]; /* 4096/sizeof(LOG_RECORD) */
3437 	const RECORD_PAGE_HEADER *rph;
3438 	const RECORD_PAGE_HEADER *prevrph;
3439 	const LOG_RECORD *logr;
3440 	const char *data;
3441 	const char *nextdata;
3442 	BOOL stop;
3443 	TRISTATE state;
3444 	s32 size;
3445 	int cnt;
3446 	u16 k;
3447 	u16 endoff;
3448 	int j;
3449 
3450 	state = T_ERR;
3451 	rph = &buf->block.record;
3452 	prevrph = (RECORD_PAGE_HEADER*)NULL;
3453 	if (prevbuf)
3454 		prevrph = &prevbuf->block.record;
3455 	data = buf->block.data;
3456 	if (rph && (rph->magic == magic_RCRD)
3457 	    && (!prevrph || (prevrph->magic == magic_RCRD))) {
3458 		if (optv) {
3459 			if (optv >= 2)
3460 				hexdump(data,blocksz);
3461 			if (buf->rnum != blk)
3462 				printf("* RCRD for block %ld 0x%lx"
3463 				     " in block %ld (addr 0x%llx)\n",
3464 				     (long)blk,(long)blk,(long)buf->rnum,
3465 				     (long long)loclogblk(ctx, blk));
3466 			else
3467 				printf("* RCRD in block %ld 0x%lx (addr 0x%llx)\n",
3468 				     (long)blk,(long)blk,
3469 				     (long long)loclogblk(ctx, blk));
3470 		} else {
3471 			if (optt)
3472 				printf("block %ld\n",(long)blk);
3473 		}
3474 		showheadrcrd(blk, rph);
3475 		if (!prevbuf)
3476 			k = buf->headsz;
3477 		else
3478 			k = firstrecord(skipped, buf, prevbuf);
3479 		logr = (const LOG_RECORD*)&data[k];
3480 		cnt = 0;
3481 	   /* check whether there is at least one beginning of record */
3482 		endoff = le16_to_cpu(rph->next_record_offset);
3483 		if (k && ((k < endoff) || !endoff)) {
3484 			logr = (const LOG_RECORD*)&data[k];
3485 			if (likelyop(logr)) {
3486 				stop = FALSE;
3487 				state = T_OK;
3488 				if (optv)
3489 					printf("First record checked"
3490 						" at offset 0x%x\n", (int)k);
3491 			} else {
3492 				printf("** Bad first record at offset 0x%x\n",
3493 								(int)k);
3494 				if (optv)
3495 					showlogr(ctx, k,logr);
3496 				k = searchlikely(buf);
3497 				stop = !k;
3498 				if (stop) {
3499 					printf("** Could not recover,"
3500 						" stopping at block %d\n",
3501 						(int)blk);
3502 					state = T_ERR;
3503 				} else {
3504 					/* Try to go on, unless running */
3505 					if (optb)
3506 						state = T_OK;
3507 				}
3508 			}
3509 			while (!stop) {
3510 				logr = (const LOG_RECORD*)&data[k];
3511 				size = le32_to_cpu(logr->client_data_length)
3512 						+ LOG_RECORD_HEAD_SZ;
3513 				if ((size < MINRECSIZE)
3514 				    || (size > MAXRECSIZE)
3515 				    || (size & 7)) {
3516 					printf("** Bad size %ld in block %ld"
3517 						" offset 0x%x, stopping\n",
3518 						(long)size,(long)blk,(int)k);
3519 					stop = TRUE;
3520 				} else {
3521 					if (((u32)(k + size) <= blocksz)
3522 					    && ((u32)(k + size) <= endoff)) {
3523 						poslist[cnt++] = k;
3524 						if (!logr->client_data_length)
3525 							stop = TRUE;
3526 						k += size;
3527 						if ((u32)(k
3528 						    + LOG_RECORD_HEAD_SZ)
3529 						    > blocksz)
3530 							stop = TRUE;
3531 					} else {
3532 						stop = TRUE;
3533 					}
3534 				}
3535 			}
3536 		} else {
3537 			stop = TRUE;
3538 			state = (k ? T_OK : T_ERR);
3539 		}
3540 		      /* Now examine an overlapping record */
3541 		if (k
3542 		    && ((k == endoff) || !endoff)
3543 		    && ((u32)(k + LOG_RECORD_HEAD_SZ) <= blocksz)) {
3544 			if (nextbuf && (blk >= BASEBLKS)) {
3545 				nextdata = nextbuf->block.data;
3546 				state = backoverlap(ctx, blk,
3547 						data, nextdata, k);
3548 			}
3549 		}
3550 		for (j=cnt-1; (j>=0) && (state==T_OK); j--) {
3551 			k = poslist[j];
3552 			logr = (const LOG_RECORD*)&data[k];
3553 			size = le32_to_cpu(logr->client_data_length)
3554 					+ LOG_RECORD_HEAD_SZ;
3555 			actionnum++;
3556 			if (optv && (!optc || within_lcn_range(logr))) {
3557 				printf("\n* log backward action %u at 0x%x"
3558 					" size %d (next at 0x%x)\n",
3559 					actionnum, k, size, k + size);
3560 			}
3561 			if ((optv | optt)
3562 			    && (!nextbuf && (j == (cnt - 1)))) {
3563 				printf("* This is the latest record\n");
3564 				if (logr->this_lsn == restart.current_lsn)
3565 					printf("   its lsn matches the global"
3566 						" restart lsn\n");
3567 				if (logr->this_lsn == client.client_restart_lsn)
3568 					printf("   its lsn matches the client"
3569 						" restart lsn\n");
3570 				if (logr->client_data_length
3571 				    == restart.last_lsn_data_length)
3572 					printf("   its length matches the"
3573 						" last record length\n");
3574 			}
3575 		showlogr(ctx, k, logr);
3576 		if (optp || optu || opts)
3577 			state = enqueue_action(ctx, logr, size, actionnum);
3578 		}
3579 	}
3580 	return (state);
3581 }
3582 
walkback(CONTEXT * ctx,const struct BUFFER * buf,u32 blk,const struct BUFFER * prevbuf,u32 prevblk)3583 static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk,
3584 			const struct BUFFER *prevbuf, u32 prevblk)
3585 {
3586 	const struct BUFFER *nextbuf;
3587 	NTFS_RECORD_TYPES magic;
3588 	u32 stopblk;
3589 	TRISTATE state;
3590 
3591 	if (optv) {
3592 		if ((log_major >= 2) && (buf->rnum != blk))
3593 			printf("\n* block %d for block %d at 0x%llx\n",
3594 					(int)buf->rnum,(int)blk,
3595 					(long long)loclogblk(ctx, buf->rnum));
3596 		else
3597 			printf("\n* block %d at 0x%llx\n",(int)blk,
3598 					(long long)loclogblk(ctx, blk));
3599 	}
3600 	ctx->firstaction = (struct ACTION_RECORD*)NULL;
3601 	ctx->lastaction = (struct ACTION_RECORD*)NULL;
3602 	nextbuf = (const struct BUFFER*)NULL;
3603 	stopblk = prevblk + 2; // wraparound !
3604 	state = backward_rcrd(ctx, blk, 0, buf,
3605 			prevbuf, (struct BUFFER*)NULL);
3606 	while ((state == T_OK)
3607 	   && !((blk > stopblk) && (prevblk <= stopblk))
3608 	   && (!(optp || optu) || (playedactions < playcount))) {
3609 		int skipped;
3610 
3611 		nextbuf = buf;
3612 		buf = prevbuf;
3613 		blk = prevblk;
3614 		skipped = 0;
3615 		prevbuf = findprevious(ctx, buf);
3616 		if (prevbuf) {
3617 			prevblk = prevbuf->num;
3618 			if (prevblk < blk)
3619 				skipped = blk - prevblk - 1;
3620 			else
3621 				skipped = blk - prevblk - 1
3622 					+ (logfilesz >> blockbits)
3623 					- (log_major < 2 ? BASEBLKS
3624 							: BASEBLKS2);
3625 			magic = prevbuf->block.record.magic;
3626 			switch (magic) {
3627 			case magic_RCRD :
3628 				break;
3629 			case magic_CHKD :
3630 				printf("** Unexpected block type CHKD\n");
3631 				break;
3632 			case magic_RSTR :
3633 				printf("** Unexpected block type RSTR\n");
3634 				break;
3635 			default :
3636 				printf("** Invalid block %d\n",(int)prevblk);
3637 				break;
3638 			}
3639 			if (optv) {
3640 				if (skipped)
3641 					printf("\n* block %ld at 0x%llx (block"
3642 						" %ld used as previous one)\n",
3643 						(long)blk,
3644 						(long long)loclogblk(ctx, blk),
3645 						(long)prevblk);
3646 				else
3647 					if ((log_major >= 2)
3648 					    && (buf->rnum != blk))
3649 						printf("\n* block %ld for block %ld at 0x%llx\n",
3650 							(long)buf->rnum,
3651 							(long)blk,
3652 							(long long)loclogblk(
3653 							    ctx,buf->rnum));
3654 					else
3655 						printf("\n* block %ld at 0x%llx\n",
3656 							(long)blk,
3657 							(long long)loclogblk(
3658 								ctx, blk));
3659 			}
3660 			state = backward_rcrd(ctx, blk, skipped,
3661 						buf, prevbuf, nextbuf);
3662 		} else {
3663 			fprintf(stderr,"** Could not read block %lu\n",
3664 								(long)prevblk);
3665 			state = T_ERR;
3666 		}
3667 	}
3668 	if ((blk > stopblk) && (prevblk <= stopblk))
3669 		printf("* Earliest block reached\n");
3670 	if ((optp || optu) && (playedactions >= playcount))
3671 		printf("* Transaction set count reached\n");
3672 	if (opts)
3673 		printf("* %s %s after playing %u actions\n",
3674 				(optn ? "Sync simulation" : "Syncing"),
3675 				(state == T_ERR ? "failed" : "successful"),
3676 				redocount);
3677 			/* free queue */
3678 	while (ctx->firstaction) {
3679 		struct ACTION_RECORD *action;
3680 
3681 		action = ctx->firstaction->next;
3682 		free(ctx->firstaction);
3683 		ctx->firstaction = action;
3684 		}
3685 	ctx->lastaction = (struct ACTION_RECORD*)NULL;
3686 	return (state == T_ERR ? 1 : 0);
3687 }
3688 
3689 /*
3690  *		Find the latest log block
3691  *
3692  *	Usually, the latest block is either block 2 or 3 which act as
3693  *	temporary block before being copied to target location.
3694  *	However under some unknown condition the block are written
3695  *	immediately to target location, and we have to scan for the
3696  *	latest one.
3697  *	Currently this is not checked for logfile version 2.x which
3698  *	use a different layout of temporary blocks.
3699  */
3700 
find_latest_block(CONTEXT * ctx,u32 baseblk,const struct BUFFER * basebuf)3701 static const struct BUFFER *find_latest_block(CONTEXT *ctx, u32 baseblk,
3702 			const struct BUFFER *basebuf)
3703 {
3704 	le64 offset;
3705 	leLSN prevlsn;
3706 	leLSN curlsn;
3707 	u32 curblk;
3708 	u32 prevblk;
3709 	const struct BUFFER *prevbuf;
3710 	const struct BUFFER *curbuf;
3711 
3712 	offset = basebuf->block.record.copy.file_offset;
3713 	curbuf = (const struct BUFFER*)NULL;
3714 	curlsn = const_cpu_to_le64(0);
3715 	prevblk = 0;
3716 	curblk = baseblk;
3717 	do {
3718 		if (curblk < BASEBLKS) {
3719 			prevbuf = basebuf;
3720 			prevlsn = basebuf->block.record.last_end_lsn;
3721 			prevblk = baseblk;
3722 			curblk = le64_to_cpu(offset) >> blockbits;
3723 		} else {
3724 			if (optv)
3725 				printf("block %d is more recent than block %d\n",
3726 					(int)curblk, (int)prevblk);
3727 			prevbuf = curbuf;
3728 			prevlsn = curlsn;
3729 			prevblk = curblk;
3730 			curblk++;
3731 			if (curblk >= (logfilesz >> blockbits))
3732 				curblk = (log_major < 2 ? BASEBLKS : BASEBLKS2);
3733 		}
3734 		curbuf = read_buffer(ctx, curblk);
3735 		if (curbuf && (curbuf->block.record.magic == magic_RCRD)) {
3736 			curlsn = curbuf->block.record.copy.last_lsn;
3737 		}
3738 	} while (curbuf
3739 		&& (curbuf->block.record.magic == magic_RCRD)
3740 		&& (le64_to_cpu(curlsn) > le64_to_cpu(prevlsn)));
3741 	if (optv)
3742 		printf("Block %d is the latest one\n",(int)prevblk);
3743 	return (prevbuf);
3744 }
3745 
3746 /*
3747  *		Determine the sequencing of blocks (when version >= 2.0)
3748  *
3749  *	Blocks 2..17 and 18..33 are temporary blocks being filled until
3750  *	they are copied to their target locations, so there are three
3751  *	possible location for recent blocks.
3752  *
3753  *	Returns the latest target block number
3754  */
3755 
block_sequence(CONTEXT * ctx)3756 static int block_sequence(CONTEXT *ctx)
3757 {
3758 	const struct BUFFER *buf;
3759 	int blk;
3760 	int k;
3761 	int target_blk;
3762 	int latest_blk;
3763 	s64 final_lsn;
3764 	s64 last_lsn;
3765 	s64 last_lsn12;
3766 	s64 last_lsn1, last_lsn2;
3767 
3768 	final_lsn = 0;
3769 	for (blk=RSTBLKS; 2*blk<(RSTBLKS+BASEBLKS2); blk++) {
3770 			/* First temporary block */
3771 		last_lsn1 = 0;
3772 		buf = read_buffer(ctx, blk);
3773 		if (buf && (buf->block.record.magic == magic_RCRD)) {
3774 			last_lsn1 = le64_to_cpu(
3775 					buf->block.record.copy.last_lsn);
3776 			if (!final_lsn
3777 			    || ((s64)(last_lsn1 - final_lsn) > 0))
3778 				final_lsn = last_lsn1;
3779 		}
3780 			/* Second temporary block */
3781 		buf = read_buffer(ctx, blk + (BASEBLKS2 - RSTBLKS)/2);
3782 		last_lsn2 = 0;
3783 		if (buf && (buf->block.record.magic == magic_RCRD)) {
3784 			last_lsn2 = le64_to_cpu(
3785 					buf->block.record.copy.last_lsn);
3786 			if (!final_lsn
3787 			    || ((s64)(last_lsn2 - final_lsn) > 0))
3788 				final_lsn = last_lsn2;
3789 		}
3790 			/* the latest last_lsn defines the target block */
3791 		last_lsn12 = 0;
3792 		latest_blk = 0;
3793 		if (last_lsn1 || last_lsn2) {
3794 			if (!last_lsn2
3795 			    || ((s64)(last_lsn1 - last_lsn2) > 0)) {
3796 				last_lsn12 = last_lsn1;
3797 				latest_blk = blk;
3798 			}
3799 			if (!last_lsn1
3800 			    || ((s64)(last_lsn1 - last_lsn2) <= 0)) {
3801 				last_lsn12 = last_lsn2;
3802 				latest_blk = blk + (BASEBLKS2 - RSTBLKS)/2;
3803 			}
3804 		}
3805 		last_lsn = 0;
3806 		target_blk = 0;
3807 		if (last_lsn12) {
3808 			target_blk = (last_lsn12 & offset_mask)
3809 							>> (blockbits - 3);
3810 			buf = read_buffer(ctx, target_blk);
3811 			if (buf && (buf->block.record.magic == magic_RCRD)) {
3812 				last_lsn = le64_to_cpu(
3813 					buf->block.record.copy.last_lsn);
3814 				if (!final_lsn
3815 				    || ((s64)(last_lsn - final_lsn) > 0))
3816 					final_lsn = last_lsn;
3817 			}
3818 		}
3819 			/* redirect to the latest block */
3820 		if (latest_blk
3821 		    && (!last_lsn || ((s64)(last_lsn - last_lsn12) < 0)))
3822 			redirect[latest_blk] = target_blk;
3823 	}
3824 	if (optv) {
3825 		printf("\n Blocks redirected :\n");
3826 		for (k=RSTBLKS; k<BASEBLKS2; k++)
3827 			if (redirect[k])
3828 				printf("* block %d to block %d\n",
3829 					(int)redirect[k],(int)k);
3830 	}
3831 	latest_lsn = final_lsn;
3832 	blk = (final_lsn & offset_mask) >> (blockbits - 3);
3833 	if (optv > 1)
3834 		printf("final lsn %llx in blk %d\n",(long long)final_lsn,blk);
3835 	return (blk);
3836 }
3837 
walk(CONTEXT * ctx)3838 static int walk(CONTEXT *ctx)
3839 {
3840 	const struct BUFFER *buf;
3841 	const struct BUFFER *nextbuf;
3842 	const struct BUFFER *prevbuf;
3843 	const struct BUFFER *startbuf;
3844 	const NTFS_RECORD *record;
3845 	const RECORD_PAGE_HEADER *rph;
3846 	NTFS_RECORD_TYPES magic;
3847 	u32 blk;
3848 	u32 nextblk;
3849 	u32 prevblk;
3850 	u32 finalblk;
3851 	int err;
3852 	u16 blkheadsz;
3853 	u16 pos;
3854 	BOOL dirty;
3855 	BOOL done;
3856 
3857 	buf = (struct BUFFER*)NULL;
3858 	nextbuf = (struct BUFFER*)NULL;
3859 	if (optb || optp || optu || opts) {
3860 		prevbuf = (struct BUFFER*)NULL;
3861 	}
3862 	done = FALSE;
3863 	dirty = TRUE;
3864 	finalblk = 0;
3865 	err = 0;
3866 	blk = 0;
3867 	pos = 0;
3868 			/* read and process the first restart block */
3869 	buf = read_restart(ctx);
3870 	if (buf) {
3871 		if (optv)
3872 			printf("\n* block %d at 0x%llx\n",(int)blk,
3873 					(long long)loclogblk(ctx, blk));
3874 	} else {
3875 		done = TRUE;
3876 		err = 1;
3877 	}
3878 
3879 	nextblk = blk + 1;
3880 	while (!done) {
3881 		 /* next block is needed to process the current one */
3882 		if ((nextblk >= (logfilesz >> blockbits)) && (optr || optf))
3883 			nextbuf = read_buffer(ctx,
3884 					(log_major < 2 ? BASEBLKS : BASEBLKS2));
3885 		else
3886 			nextbuf = read_buffer(ctx,nextblk);
3887 		if (nextbuf) {
3888 			record = (const NTFS_RECORD*)&nextbuf->block.data;
3889 			blkheadsz = nextbuf->headsz;
3890 			magic = record->magic;
3891 			switch (magic) {
3892 			case magic_CHKD :
3893 			case magic_RSTR :
3894 			case magic_RCRD :
3895 				break;
3896 			default :
3897 				printf("** Invalid block\n");
3898 				err = 1;
3899 				break;
3900 			}
3901 			magic = buf->block.record.magic;
3902 			switch (magic) {
3903 			case magic_CHKD :
3904 			case magic_RSTR :
3905 				dirty = dorest(ctx, blk, &buf->block.restart,
3906 								FALSE);
3907 				break;
3908 			case magic_RCRD :
3909 				if (blk < BASEBLKS)
3910 					pos = buf->headsz;
3911 				pos = dorcrd(ctx, blk, pos, buf, nextbuf);
3912 				while (pos >= blocksz) {
3913 					if (optv > 1)
3914 						printf("Skipping block %d"
3915 						" pos 0x%x\n",
3916 						(int)nextblk,(int)pos);
3917 					pos -= (blocksz - blkheadsz);
3918 					nextblk++;
3919 					}
3920 				if ((blocksz - pos) < LOG_RECORD_HEAD_SZ) {
3921 					pos = 0;
3922 					nextblk++;
3923 				}
3924 				if (nextblk != (blk + 1)) {
3925 					nextbuf = read_buffer(ctx,nextblk);
3926 				}
3927 				break;
3928 			default :
3929 				if (!~magic) {
3930 					if (optv)
3931 						printf("   empty block\n");
3932 				}
3933 				break;
3934 			}
3935 		} else {
3936 			fprintf(stderr,"* Could not read block %d\n",nextblk);
3937 			if (ctx->vol) {
3938 			/* In full mode, ignore errors on restart blocks */
3939 				if (blk >= RSTBLKS) {
3940 					done = TRUE;
3941 					err = 1;
3942 				}
3943 			} else {
3944 				done = TRUE;
3945 				err = 1;
3946 			}
3947 		}
3948 		blk = nextblk;
3949 		nextblk++;
3950 
3951 		if (!optr && (log_major >= 2) && (nextblk == RSTBLKS)) {
3952 			finalblk = block_sequence(ctx);
3953 			if (!finalblk) {
3954 				done = TRUE;
3955 				err = 1;
3956 			}
3957 		}
3958 
3959 		if (optr) { /* Only selected range */
3960 			u32 endblk;
3961 
3962 			endblk = (log_major < 2 ? BASEBLKS : RSTBLKS);
3963 			if ((nextblk == endblk) && (nextblk < firstblk))
3964 				 nextblk = firstblk;
3965 			if ((blk >= endblk) && (blk > lastblk))
3966 				done = TRUE;
3967 		} else
3968 			if (optf) { /* Full log, forward */
3969 				if (blk*blocksz >= logfilesz)
3970 					done = TRUE;
3971 			} else
3972 				if (optb || optp || optu || opts
3973 				    || (log_major >= 2)) {
3974 					/* Restart blocks only (2 blocks) */
3975 					if (blk >= RSTBLKS)
3976 						done = TRUE;
3977 				} else { /* Base blocks only (4 blocks) */
3978 					if (blk >= BASEBLKS)
3979 						done = TRUE;
3980 				}
3981 		if (!done) {
3982 			buf = nextbuf;
3983 			if (blk >= RSTBLKS && blk < BASEBLKS) {
3984 				/* The latest buf may be more recent
3985 				   than restart */
3986 				rph = &buf->block.record;
3987 				if ((s64)(sle64_to_cpu(rph->last_end_lsn)
3988 					  - committed_lsn) > 0) {
3989 					committed_lsn =
3990 						sle64_to_cpu(rph->last_end_lsn);
3991 					if (optv)
3992 						printf("* Restart page was "
3993 						       "obsolete, updated "
3994 						       "committed lsn\n");
3995 				}
3996 			}
3997 			if (optv)
3998 				printf("\n* block %d at 0x%llx\n",(int)blk,
3999 					(long long)loclogblk(ctx, blk));
4000 		}
4001 	}
4002 	if (optv && opts && !dirty)
4003 		printf("* Volume is clean, nothing to do\n");
4004 	if (log_major >= 2)
4005 		blk = finalblk;
4006 	if (!err
4007 	    && (optb || optp || optu || (opts && dirty))) {
4008 		playedactions = 0;
4009 		ctx->firstaction = (struct ACTION_RECORD*)NULL;
4010 		ctx->lastaction = (struct ACTION_RECORD*)NULL;
4011 		if (log_major < 2) {
4012 			buf = nextbuf;
4013 			nextbuf = read_buffer(ctx, blk+1);
4014 			startbuf = best_start(buf,nextbuf);
4015 			if (startbuf && (startbuf == nextbuf)) {
4016 				/* nextbuf is better, show blk */
4017 				if (optv && buf) {
4018 					printf("* Ignored block %d at 0x%llx\n",
4019 						(int)blk,
4020 						(long long)loclogblk(ctx, blk));
4021 					if (optv >= 2)
4022 						hexdump(buf->block.data,
4023 								blocksz);
4024 					showheadrcrd(blk, &buf->block.record);
4025 				}
4026 				blk++;
4027 				buf = nextbuf;
4028 			} else {
4029 				/* buf is better, show blk + 1 */
4030 				if (optv && nextbuf) {
4031 					printf("* Ignored block %d at 0x%llx\n",
4032 						(int)(blk + 1),
4033 						(long long)loclogblk(ctx,
4034 								blk + 1));
4035 					if (optv >= 2)
4036 						hexdump(nextbuf->block.data,
4037 								blocksz);
4038 					showheadrcrd(blk + 1,
4039 							&nextbuf->block.record);
4040 				}
4041 			}
4042 			if (startbuf && opts) {
4043 				buf = startbuf = find_latest_block(ctx,
4044 						blk, startbuf);
4045 				latest_lsn = le64_to_cpu(
4046 					buf->block.record.last_end_lsn);
4047 			}
4048 		} else {
4049 			buf = startbuf = read_buffer(ctx, blk);
4050 			nextbuf = (const struct BUFFER*)NULL;
4051 		}
4052 		if (startbuf) {
4053 			/* The latest buf may be more recent than restart */
4054 			rph = &buf->block.record;
4055 			if ((s64)(sle64_to_cpu(rph->last_end_lsn)
4056 					- committed_lsn) > 0) {
4057 				committed_lsn = sle64_to_cpu(rph->last_end_lsn);
4058 				if (optv)
4059 					printf("* Restart page was obsolete\n");
4060 			}
4061 			nextbuf = (const struct BUFFER*)NULL;
4062 			prevbuf = findprevious(ctx, buf);
4063 			if (prevbuf) {
4064 				prevblk = prevbuf->num;
4065 				magic = prevbuf->block.record.magic;
4066 				switch (magic) {
4067 				case magic_RCRD :
4068 					break;
4069 				case magic_CHKD :
4070 					printf("** Unexpected block type CHKD\n");
4071 					err = 1;
4072 					break;
4073 				case magic_RSTR :
4074 					err = 1;
4075 					printf("** Unexpected block type RSTR\n");
4076 					break;
4077 				default :
4078 					err = 1;
4079 					printf("** Invalid block\n");
4080 					break;
4081 				}
4082 			} else
4083 				prevblk = BASEBLKS;
4084 			if (!err)
4085 				err = walkback(ctx, buf, blk,
4086 							prevbuf, prevblk);
4087 		} else {
4088 			fprintf(stderr,"** No valid start block, aborting\n");
4089 			err = 1;
4090 		}
4091 	}
4092 	return (err);
4093 }
4094 
exception(int num)4095 BOOL exception(int num)
4096 {
4097 	int i;
4098 
4099 	i = 0;
4100 	while ((i < 10) && optx[i] && (optx[i] != num))
4101 		i++;
4102 	return (optx[i] == num);
4103 }
4104 
version(void)4105 static void version(void)
4106 {
4107 	printf("\n%s v%s (libntfs-3g) - Recover updates committed by Windows"
4108 			" on an NTFS Volume.\n\n", "ntfsrecover", VERSION);
4109 	printf("Copyright (c) 2012-2017 Jean-Pierre Andre\n");
4110 	printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home);
4111 }
4112 
usage(void)4113 static void usage(void)
4114 {
4115 	fprintf(stderr,"Usage : for recovering the updates committed by Windows :\n");
4116 	fprintf(stderr,"        ntfsrecover partition\n");
4117 	fprintf(stderr,"                (e.g. ntfsrecover /dev/sda1)\n");
4118 	fprintf(stderr,"Advanced : ntfsrecover [-b] [-c first-last] [-i] [-f] [-n] [-p count]\n");
4119 	fprintf(stderr,"                    [-r first-last] [-t] [-u count] [-v] partition\n");
4120 	fprintf(stderr,"	   -b : show the full log backward\n");
4121 	fprintf(stderr,"	   -c : restrict to the actions related to cluster range\n");
4122 	fprintf(stderr,"	   -i : show invalid (stale) records\n");
4123 	fprintf(stderr,"	   -f : show the full log forward\n");
4124 	fprintf(stderr,"	   -h : show this help information\n");
4125 	fprintf(stderr,"	   -k : kill fast restart data\n");
4126 	fprintf(stderr,"	   -n : do not apply any modification\n");
4127 	fprintf(stderr,"	   -p : undo the latest count transaction sets and play one\n");
4128 	fprintf(stderr,"	   -r : show a range of log blocks forward\n");
4129 	fprintf(stderr,"	   -s : sync the committed changes (default)\n");
4130 	fprintf(stderr,"	   -t : show transactions\n");
4131 	fprintf(stderr,"	   -u : undo the latest count transaction sets\n");
4132 	fprintf(stderr,"	   -v : show more information (-vv yet more)\n");
4133 	fprintf(stderr,"	   -V : show version and exit\n");
4134 }
4135 
4136 /*
4137  *		Process command options
4138  */
4139 
getoptions(int argc,char * argv[])4140 static BOOL getoptions(int argc, char *argv[])
4141 {
4142 	int c;
4143 	int xcount;
4144 	u32 xval;
4145 	char *endptr;
4146 	BOOL err;
4147 	static const char *sopt = "-bc:hifknp:r:stu:vVx:";
4148 	static const struct option lopt[] = {
4149 		{ "backward",		no_argument,		NULL, 'b' },
4150 		{ "clusters",		required_argument,	NULL, 'c' },
4151 		{ "forward",		no_argument,		NULL, 'f' },
4152 		{ "help",		no_argument,		NULL, 'h' },
4153 		{ "kill-fast-restart",	no_argument,		NULL, 'k' },
4154 		{ "no-action",		no_argument,		NULL, 'n' },
4155 		{ "play",		required_argument,	NULL, 'p' },
4156 		{ "range",		required_argument,	NULL, 'r' },
4157 		{ "sync",		no_argument,		NULL, 's' },
4158 		{ "transactions",	no_argument,		NULL, 't' },
4159 		{ "undo",		required_argument,	NULL, 'u' },
4160 		{ "verbose",		no_argument,		NULL, 'v' },
4161 		{ "version",		no_argument,		NULL, 'V' },
4162 		{ "exceptions",		required_argument,	NULL, 'x' },
4163 		{ NULL, 		0, NULL, 0 }
4164 	};
4165 
4166 	err = FALSE;
4167 	optb = FALSE;
4168 	optc = FALSE;
4169 	optd = FALSE;
4170 	optf = FALSE;
4171 	opth = FALSE;
4172 	opti = FALSE;
4173 	optk = FALSE;
4174 	optn = FALSE;
4175 	optp = FALSE;
4176 	optr = FALSE;
4177 	opts = 0;
4178 	optt = FALSE;
4179 	optu = FALSE;
4180 	optv = 0;
4181 	optV = FALSE;
4182 	optx[0] = 0;
4183 
4184 	while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
4185 		switch (c) {
4186 		case 1:	/* A non-option argument */
4187 			if (optind == argc)
4188 				optd = TRUE;
4189 			else {
4190 				fprintf(stderr, "Device must be the"
4191 						" last argument.\n");
4192 				err = TRUE;
4193 			}
4194 			break;
4195 		case 'b':
4196 			optb = TRUE;
4197 			break;
4198 		case 'c':
4199 			firstlcn = strtoull(optarg, &endptr, 0);
4200 			lastlcn = firstlcn;
4201 			if (*endptr == '-')
4202 				lastlcn = strtoull(++endptr, &endptr, 0);
4203 			if (*endptr || (lastlcn < firstlcn)) {
4204 				fprintf(stderr,"Bad cluster range\n");
4205 				err = TRUE;
4206 			} else
4207 				optc = TRUE;
4208 			break;
4209 		case 'f':
4210 			optf = TRUE;
4211 			break;
4212 		case '?':
4213 		case 'h':
4214 			opth = TRUE;
4215 			break;
4216 		case 'k':
4217 			optk = TRUE;
4218 			break;
4219 		case 'n':
4220 			optn = TRUE;
4221 			break;
4222 		case 'p':
4223 			playcount = strtoull(optarg, &endptr, 0);
4224 			if (*endptr) {
4225 				fprintf(stderr,"Bad play count\n");
4226 				err = TRUE;
4227 			} else
4228 				optp = TRUE;
4229 			break;
4230 		case 'r' :
4231 			firstblk = strtoull(optarg, &endptr, 0);
4232 			lastblk = firstblk;
4233 			if (*endptr == '-')
4234 				lastblk = strtoull(++endptr, &endptr, 0);
4235 			if (*endptr || (lastblk < firstblk)) {
4236 				fprintf(stderr,"Bad log block range\n");
4237 				err = TRUE;
4238 			} else
4239 				optr = TRUE;
4240 			break;
4241 		case 's':
4242 			opts++;
4243 			break;
4244 		case 't':
4245 			optt = TRUE;
4246 			break;
4247 		case 'u':
4248 			playcount = strtoull(optarg, &endptr, 0);
4249 			if (*endptr) {
4250 				fprintf(stderr,"Bad undo count\n");
4251 				err = TRUE;
4252 			} else
4253 				optu = TRUE;
4254 			break;
4255 		case 'v':
4256 			optv++;
4257 			break;
4258 		case 'V':
4259 			optV = TRUE;
4260 			break;
4261 		case 'x':
4262 				/*
4263 				 * Undocumented : actions to execute, though
4264 				 * they should be skipped under normal rules.
4265 				 */
4266 			xcount = 0;
4267 			xval = strtoull(optarg, &endptr, 0);
4268 			while ((*endptr == ',')
4269 			    && (xcount < (MAXEXCEPTION - 1))) {
4270 				optx[xcount++] = xval;
4271 				xval = strtoull(++endptr, &endptr, 0);
4272 			}
4273 			if (*endptr || (xcount >= MAXEXCEPTION)) {
4274 				fprintf(stderr,"Bad exception list\n");
4275 				err = TRUE;
4276 			} else {
4277 				optx[xcount++] = xval;
4278 				optx[xcount] = 0;
4279 			}
4280 			break;
4281 		default:
4282 			fprintf(stderr,"Unknown option '%s'.\n",
4283 							argv[optind - 1]);
4284 			err = TRUE;
4285 		}
4286 	}
4287 
4288 	if (!optd && !optV && !opth) {
4289 		fprintf(stderr,"Device argument is missing\n");
4290 		err = TRUE;
4291 	}
4292 	if (!(optb || optf || optp || optr || opts || optt || optu || optV))
4293 		opts = 1;
4294 	if (optb && (optf || optr || opts)) {
4295 		fprintf(stderr,"Options -f, -r and -s are incompatible with -b\n");
4296 		err = TRUE;
4297 	}
4298 	if (optf && (optp || opts || optu)) {
4299 		fprintf(stderr,"Options -p, -s and -u are incompatible with -f\n");
4300 		err = TRUE;
4301 	}
4302 	if (optp && (optr || opts || optt || optu)) {
4303 		fprintf(stderr,"Options -r, -s, -t and -u are incompatible with -p\n");
4304 		err = TRUE;
4305 	}
4306 	if (optr && (opts || optu)) {
4307 		fprintf(stderr,"Options -s and -u are incompatible with -r\n");
4308 		err = TRUE;
4309 	}
4310 	if (opts && (optt || optu)) {
4311 		fprintf(stderr,"Options -t and -u are incompatible with -s\n");
4312 		err = TRUE;
4313 	}
4314 
4315 	if (opth || err)
4316 		usage();
4317 	else
4318 		if (optV)
4319 			version();
4320 	return (!err);
4321 }
4322 
4323 /*
4324  *		Quick checks on the layout of needed structs
4325  */
4326 
checkstructs(void)4327 static BOOL checkstructs(void)
4328 {
4329 	BOOL ok;
4330 
4331 	ok = TRUE;
4332    	if (sizeof(RECORD_PAGE_HEADER) != 40) {
4333       		fprintf(stderr,
4334 			"* error : bad sizeof(RECORD_PAGE_HEADER) %d\n",
4335 			(int)sizeof(RECORD_PAGE_HEADER));
4336 		ok = FALSE;
4337 	}
4338 	if (sizeof(LOG_RECORD) != 88) {
4339       		fprintf(stderr,
4340 			"* error : bad sizeof(LOG_RECORD) %d\n",
4341 			(int)sizeof(LOG_RECORD));
4342 		ok = FALSE;
4343 	}
4344    	if (sizeof(RESTART_PAGE_HEADER) != 32) {
4345       		fprintf(stderr,
4346 			"* error : bad sizeof(RESTART_PAGE_HEADER) %d\n",
4347 			(int)sizeof(RESTART_PAGE_HEADER));
4348 		ok = FALSE;
4349 	}
4350    	if (sizeof(RESTART_AREA) != 48) {
4351       		fprintf(stderr,
4352 			"* error : bad sizeof(RESTART_AREA) %d\n",
4353 			(int)sizeof(RESTART_AREA));
4354 		ok = FALSE;
4355 	}
4356    	if (sizeof(ATTR_OLD) != 44) {
4357       		fprintf(stderr,
4358 			"* error : bad sizeof(ATTR_OLD) %d\n",
4359 			(int)sizeof(ATTR_OLD));
4360 		ok = FALSE;
4361 	}
4362    	if (sizeof(ATTR_NEW) != 40) {
4363       		fprintf(stderr,
4364 			"* error : bad sizeof(ATTR_NEW) %d\n",
4365 			(int)sizeof(ATTR_NEW));
4366 		ok = FALSE;
4367 	}
4368 	if (LastAction != 38) {
4369       		fprintf(stderr,
4370 			"* error : bad action list, %d actions\n",
4371 			(int)LastAction);
4372 		ok = FALSE;
4373 	}
4374 	return (ok);
4375 }
4376 
main(int argc,char * argv[])4377 int main(int argc, char *argv[])
4378 {
4379 	CONTEXT ctx;
4380 	unsigned int i;
4381 	int err;
4382 
4383 	err = 1;
4384 	if (checkstructs()
4385 	    && getoptions(argc,argv)) {
4386 		if (optV || opth) {
4387 			err = 0;
4388 		} else {
4389 			redocount = 0;
4390 			undocount = 0;
4391 			actionnum = 0;
4392 			attrcount = 0;
4393 			redos_met = 0;
4394 			attrtable = (struct ATTR**)NULL;
4395 			for (i=0; i<(BUFFERCNT + BASEBLKS); i++)
4396 				buffer_table[i] = (struct BUFFER*)NULL;
4397 			ntfs_log_set_handler(ntfs_log_handler_outerr);
4398 			if (open_volume(&ctx, argv[argc - 1])) {
4399 				if (!ctx.vol
4400 				    && (opts || optp || optu)) {
4401 					printf("Options -s, -p and -u"
4402 						" require a full device\n");
4403 					err = 1;
4404 				} else {
4405 					err = walk(&ctx);
4406 					if (ctx.vol) {
4407 						if ((optp || optu || opts)
4408 						    && !err
4409 						    && !optn) {
4410 							reset_logfile(&ctx);
4411 						}
4412 						ntfs_attr_close(log_na);
4413 						ntfs_inode_close(log_ni);
4414 						ntfs_umount(ctx.vol, TRUE);
4415 					} else
4416 						fclose(ctx.file);
4417 				}
4418 			} else
4419 				fprintf(stderr,"Could not open %s\n",
4420 							argv[argc - 1]);
4421 			for (i=0; i<(BUFFERCNT + BASEBLKS); i++)
4422 				free(buffer_table[i]);
4423 			for (i=0; i<attrcount; i++)
4424 				free(attrtable[i]);
4425 			free(attrtable);
4426 			if (ctx.vol) {
4427 				freeclusterentry((struct STORE*)NULL);
4428 				show_redos();
4429 			}
4430 		}
4431 	}
4432 	if (err)
4433 		exit(1);
4434 	return (0);
4435 }
4436