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