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