1 /*
2 * Redo or undo a list of logged actions
3 *
4 * Copyright (c) 2014-2017 Jean-Pierre Andre
5 *
6 */
7
8 /*
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program (in the main directory of the NTFS-3G
21 * distribution in the file COPYING); if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24
25 #include "config.h"
26
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30 #ifdef HAVE_STDIO_H
31 #include <stdio.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #ifdef HAVE_FCNTL_H
37 #include <fcntl.h>
38 #endif
39 #ifdef HAVE_ERRNO_H
40 #include <errno.h>
41 #endif
42 #ifdef HAVE_STRING_H
43 #include <string.h>
44 #endif
45 #ifdef HAVE_MALLOC_H
46 #include <malloc.h>
47 #endif
48 #ifdef HAVE_TIME_H
49 #include <time.h>
50 #endif
51
52 #include "types.h"
53 #include "endians.h"
54 #include "support.h"
55 #include "layout.h"
56 #include "param.h"
57 #include "ntfstime.h"
58 #include "device_io.h"
59 #include "device.h"
60 #include "logging.h"
61 #include "runlist.h"
62 #include "mft.h"
63 #include "inode.h"
64 #include "attrib.h"
65 #include "bitmap.h"
66 #include "index.h"
67 #include "volume.h"
68 #include "unistr.h"
69 #include "mst.h"
70 #include "logfile.h"
71 #include "ntfsrecover.h"
72 #include "misc.h"
73
74 struct STORE {
75 struct STORE *upper;
76 struct STORE *lower;
77 LCN lcn;
78 char data[1];
79 } ;
80
81 #define dump hexdump
82
83 struct STORE *cluster_door = (struct STORE*)NULL;
84
85 /* check whether a MFT or INDX record is older than action */
86 #define older_record(rec, logr) ((s64)(sle64_to_cpu((rec)->lsn) \
87 - sle64_to_cpu((logr)->this_lsn)) < 0)
88 /* check whether a MFT or INDX record is newer than action */
89 #define newer_record(rec, logr) ((s64)(sle64_to_cpu((rec)->lsn) \
90 - sle64_to_cpu((logr)->this_lsn)) > 0)
91
92 /*
93 * A few functions for debugging
94 */
95
matchcount(const char * d,const char * s,int n)96 static int matchcount(const char *d, const char *s, int n)
97 {
98 int m;
99
100 m = 0;
101 while ((--n >= 0) && (*d++ == *s++)) m++;
102 return (m);
103 }
104
105 /*
106 static void locate(const char *s, int n, const char *p, int m)
107 {
108 int i,j;
109
110 for (i=0; i<=(n - m); i++)
111 if (s[i] == *p) {
112 j = 1;
113 while ((j < m) && (s[i + j] == p[j]))
114 j++;
115 if (j == m)
116 printf("=== found at offset 0x%x %d\n",i,i);
117 }
118 }
119 */
120
inode_number(const LOG_RECORD * logr)121 static u64 inode_number(const LOG_RECORD *logr)
122 {
123 u64 offset;
124
125 offset = ((u64)sle64_to_cpu(logr->target_vcn)
126 << clusterbits)
127 + ((u32)le16_to_cpu(logr->cluster_index)
128 << NTFS_BLOCK_SIZE_BITS);
129 return (offset >> mftrecbits);
130 }
131
132 /*
133 * Find an in-memory copy of a needed cluster
134 *
135 * Optionally, allocate a copy.
136 */
137
getclusterentry(LCN lcn,BOOL create)138 static struct STORE *getclusterentry(LCN lcn, BOOL create)
139 {
140 struct STORE **current;
141 struct STORE *newone;
142
143 current = &cluster_door;
144 /* A minimal binary tree should be enough */
145 while (*current && (lcn != (*current)->lcn)) {
146 if (lcn > (*current)->lcn)
147 current = &(*current)->upper;
148 else
149 current = &(*current)->lower;
150 }
151 if (create && !*current) {
152 newone = (struct STORE*)malloc(sizeof(struct STORE)
153 + clustersz);
154 if (newone) {
155 newone->upper = (struct STORE*)NULL;
156 newone->lower = (struct STORE*)NULL;
157 newone->lcn = lcn;
158 *current = newone;
159 }
160 }
161 return (*current);
162 }
163
freeclusterentry(struct STORE * entry)164 void freeclusterentry(struct STORE *entry)
165 {
166 if (!entry) {
167 if (cluster_door)
168 freeclusterentry(cluster_door);
169 cluster_door = (struct STORE*)NULL;
170 } else {
171 if (optv)
172 printf("* cluster 0x%llx %s updated\n",
173 (long long)entry->lcn,
174 (optn ? "would be" : "was"));
175 if (entry->upper)
176 freeclusterentry(entry->upper);
177 if (entry->lower)
178 freeclusterentry(entry->lower);
179 free(entry);
180 }
181 }
182
183 /*
184 * Check whether an attribute type is a valid one
185 */
186
valid_type(ATTR_TYPES type)187 static BOOL valid_type(ATTR_TYPES type)
188 {
189 BOOL ok;
190
191 switch (type) {
192 case AT_STANDARD_INFORMATION :
193 case AT_ATTRIBUTE_LIST :
194 case AT_FILE_NAME :
195 case AT_OBJECT_ID :
196 case AT_SECURITY_DESCRIPTOR :
197 case AT_VOLUME_NAME :
198 case AT_VOLUME_INFORMATION :
199 case AT_DATA :
200 case AT_INDEX_ROOT :
201 case AT_INDEX_ALLOCATION :
202 case AT_BITMAP :
203 case AT_REPARSE_POINT :
204 case AT_EA_INFORMATION :
205 case AT_EA :
206 case AT_PROPERTY_SET :
207 case AT_LOGGED_UTILITY_STREAM :
208 case AT_FIRST_USER_DEFINED_ATTRIBUTE :
209 case AT_END :
210 ok = TRUE;
211 break;
212 default :
213 ok = FALSE;
214 break;
215 }
216 return (ok);
217 }
218
219 /*
220 * Rough check of sanity of an index list
221 */
222
sanity_indx_list(const char * buffer,u32 k,u32 end)223 static int sanity_indx_list(const char *buffer, u32 k, u32 end)
224 {
225 le64 inode;
226 int err;
227 int lth;
228 BOOL done;
229
230 err = 0;
231 done = FALSE;
232 while ((k <= end) && !done && !err) {
233 lth = getle16(buffer,k+8);
234 if (optv > 1)
235 /* Usual indexes can be determined from size */
236 switch (lth) {
237 case 16 : /* final without subnode */
238 case 24 : /* final with subnode */
239 printf("index to none lth 0x%x"
240 " flags 0x%x pos 0x%x\n",
241 (int)lth,
242 (int)getle16(buffer,k+12),(int)k);
243 break;
244 case 32 : /* $R in $Reparse */
245 /* Badly aligned */
246 memcpy(&inode, &buffer[k + 20], 8);
247 printf("index to reparse of 0x%016llx lth 0x%x"
248 " flags 0x%x pos 0x%x\n",
249 (long long)le64_to_cpu(inode),
250 (int)lth,
251 (int)getle16(buffer,k+12),(int)k);
252 break;
253 case 40 : /* $SII in $Secure */
254 printf("index to securid 0x%lx lth 0x%x"
255 " flags 0x%x pos 0x%x\n",
256 (long)getle32(buffer,k + 16),
257 (int)lth,
258 (int)getle16(buffer,k+12),(int)k);
259 break;
260 case 48 : /* $SDH in $Secure */
261 printf("index to securid 0x%lx lth 0x%x"
262 " flags 0x%x pos 0x%x\n",
263 (long)getle32(buffer,k + 20),
264 (int)lth,
265 (int)getle16(buffer,k+12),(int)k);
266 break;
267 default : /* at least 80 */
268 printf("index to inode 0x%016llx lth 0x%x"
269 " flags 0x%x pos 0x%x\n",
270 (long long)getle64(buffer,k),
271 (int)lth,
272 (int)getle16(buffer,k+12),(int)k);
273 if ((lth < 80) || (lth & 7)) {
274 printf("** Invalid index record"
275 " length %d\n",lth);
276 err = 1;
277 }
278 }
279 done = (feedle16(buffer,k+12) & INDEX_ENTRY_END) || !lth;
280 if (lth & 7) {
281 if (optv <= 1) /* Do not repeat the warning */
282 printf("** Invalid index record length %d\n",
283 lth);
284 err = 1;
285 } else
286 k += lth;
287 }
288 if (k != end) {
289 printf("** Bad index record length %ld (computed %ld)\n",
290 (long)end, (long)k);
291 err = 1;
292 }
293 if (!done) {
294 printf("** Missing end of index mark\n");
295 err = 1;
296 }
297 return (err);
298 }
299
300 /*
301 * Rough check of sanity of an mft record
302 */
303
sanity_mft(const char * buffer)304 static int sanity_mft(const char *buffer)
305 {
306 const MFT_RECORD *record;
307 const ATTR_RECORD *attr;
308 u64 instances;
309 u32 k;
310 u32 type;
311 u32 prevtype;
312 u16 nextinstance;
313 u16 instance;
314 int err;
315
316 err = 0;
317 record = (const MFT_RECORD*)buffer;
318 nextinstance = le16_to_cpu(record->next_attr_instance);
319 instances = 0;
320 k = le16_to_cpu(record->attrs_offset);
321 attr = (const ATTR_RECORD*)&buffer[k];
322 prevtype = 0;
323 while ((k < mftrecsz)
324 && (attr->type != AT_END)
325 && valid_type(attr->type)) {
326 type = le32_to_cpu(attr->type);
327 if (type < prevtype) {
328 printf("** Bad type ordering 0x%lx after 0x%lx\n",
329 (long)type, (long)prevtype);
330 err = 1;
331 }
332 instance = le16_to_cpu(attr->instance);
333 /* Can nextinstance wrap around ? */
334 if (instance >= nextinstance) {
335 printf("** Bad attr instance %d (max %d)\n",
336 (int)instance, (int)nextinstance - 1);
337 err = 1;
338 }
339 if (instance < 64) {
340 /* Only check up to 64 */
341 if (((u64)1 << instance) & instances) {
342 printf("** Duplicated attr instance %d\n",
343 (int)instance);
344 }
345 instances |= (u64)1 << instance;
346 }
347 if (optv > 1) {
348 if ((attr->type == AT_FILE_NAME)
349 && buffer[k + 88]) {
350 printf("attr %08lx offs 0x%x nres %d",
351 (long)type, (int)k,
352 (int)attr->non_resident);
353 showname(" ",&buffer[k+90],
354 buffer[k + 88] & 255);
355 } else
356 printf("attr %08lx offs 0x%x nres %d\n",
357 (long)type, (int)k,
358 (int)attr->non_resident);
359 }
360 if ((attr->type == AT_INDEX_ROOT)
361 && sanity_indx_list(buffer,
362 k + le16_to_cpu(attr->value_offset) + 32,
363 k + le32_to_cpu(attr->length))) {
364 err = 1;
365 }
366 k += le32_to_cpu(attr->length);
367 attr = (const ATTR_RECORD*)&buffer[k];
368 prevtype = type;
369 }
370 if ((optv > 1) && (attr->type == AT_END))
371 printf("attr %08lx offs 0x%x\n",
372 (long)le32_to_cpu(attr->type), (int)k);
373 if ((attr->type != AT_END)
374 || (le32_to_cpu(record->bytes_in_use) != (k + 8))
375 || (le32_to_cpu(record->bytes_allocated) < (k + 8))) {
376 printf("** Bad MFT record length %ld"
377 " (computed %ld allocated %ld)\n",
378 (long)le32_to_cpu(record->bytes_in_use),
379 (long)(k + 8),
380 (long)le32_to_cpu(record->bytes_allocated));
381 err = 1;
382 }
383 return (err);
384 }
385
386 /*
387 * Rough check of sanity of an index block
388 */
389
sanity_indx(ntfs_volume * vol,const char * buffer)390 static int sanity_indx(ntfs_volume *vol, const char *buffer)
391 {
392 const INDEX_BLOCK *indx;
393 u32 k;
394 int err;
395
396 err = 0;
397 indx = (const INDEX_BLOCK*)buffer;
398 k = offsetof(INDEX_BLOCK, index) +
399 le32_to_cpu(indx->index.entries_offset);
400 err = sanity_indx_list(buffer, k,
401 le32_to_cpu(indx->index.index_length) + 24);
402 if ((le32_to_cpu(indx->index.index_length)
403 > le32_to_cpu(indx->index.allocated_size))
404 || (le32_to_cpu(indx->index.allocated_size)
405 != (vol->indx_record_size - 24))) {
406 printf("** Bad index length %ld"
407 " (usable %ld allocated %ld)\n",
408 (long)le32_to_cpu(indx->index.index_length),
409 (long)(vol->indx_record_size - 24),
410 (long)le32_to_cpu(indx->index.allocated_size));
411 err = 1;
412 }
413 return (err);
414 }
415
416
417 /*
418 * Allocate a buffer and read a full set of raw clusters
419 *
420 * Do not use for accessing $LogFile.
421 * With option -n reading is first attempted from the memory store
422 */
423
read_raw(ntfs_volume * vol,const LOG_RECORD * logr)424 static char *read_raw(ntfs_volume *vol, const LOG_RECORD *logr)
425 {
426 char *buffer;
427 char *target;
428 struct STORE *store;
429 LCN lcn;
430 int count;
431 int i;
432 BOOL fail;
433
434 count = le16_to_cpu(logr->lcns_to_follow);
435 if (!count) {
436 printf("** Error : no lcn to read from\n");
437 buffer = (char*)NULL;
438 } else
439 buffer = (char*)malloc(clustersz*count);
440 // TODO error messages
441 if (buffer) {
442 fail = FALSE;
443 for (i=0; (i<count) && !fail; i++) {
444 store = (struct STORE*)NULL;
445 lcn = sle64_to_cpu(logr->lcn_list[i]);
446 target = buffer + clustersz*i;
447 if (optn) {
448 store = getclusterentry(lcn, FALSE);
449 if (store) {
450 memcpy(target, store->data, clustersz);
451 if (optv)
452 printf("== lcn 0x%llx from store\n",
453 (long long)lcn);
454 if ((optv > 1) && optc
455 && within_lcn_range(logr))
456 dump(store->data, clustersz);
457 }
458 }
459 if (!store
460 && (ntfs_pread(vol->dev, lcn << clusterbits,
461 clustersz, target) != clustersz)) {
462 fail = TRUE;
463 } else {
464 if (!store) {
465 if (optv)
466 printf("== lcn 0x%llx"
467 " from device\n",
468 (long long)lcn);
469 if ((optv > 1) && optc
470 && within_lcn_range(logr))
471 dump(target, clustersz);
472 }
473 }
474 }
475 if (fail) {
476 printf("** Could not read cluster 0x%llx\n",
477 (long long)lcn);
478 free(buffer);
479 buffer = (char*)NULL;
480 }
481 }
482 return (buffer);
483 }
484
485 /*
486 * Write a full set of raw clusters
487 *
488 * Do not use for accessing $LogFile.
489 * With option -n a copy of the buffer is kept in memory for later use.
490 */
491
write_raw(ntfs_volume * vol,const LOG_RECORD * logr,char * buffer)492 static int write_raw(ntfs_volume *vol, const LOG_RECORD *logr,
493 char *buffer)
494 {
495 int err;
496 struct STORE *store;
497 LCN lcn;
498 char *source;
499 int count;
500 int i;
501
502 err = 0;
503 count = le16_to_cpu(logr->lcns_to_follow);
504 if (!count)
505 printf("** Error : no lcn to write to\n");
506 if (optn) {
507 for (i=0; (i<count) && !err; i++) {
508 lcn = sle64_to_cpu(logr->lcn_list[i]);
509 source = buffer + clustersz*i;
510 store = getclusterentry(lcn, TRUE);
511 if (store) {
512 memcpy(store->data, source, clustersz);
513 if (optv)
514 printf("== lcn 0x%llx to store\n",
515 (long long)lcn);
516 if ((optv > 1) && optc
517 && within_lcn_range(logr))
518 dump(store->data, clustersz);
519 } else {
520 printf("** Could not store cluster 0x%llx\n",
521 (long long)lcn);
522 err = 1;
523 }
524 }
525 } else {
526 for (i=0; (i<count) && !err; i++) {
527 lcn = sle64_to_cpu(logr->lcn_list[i]);
528 if (optv)
529 printf("== lcn 0x%llx to device\n",
530 (long long)lcn);
531 source = buffer + clustersz*i;
532 if (ntfs_pwrite(vol->dev, lcn << clusterbits,
533 clustersz, source) != clustersz) {
534 printf("** Could not write cluster 0x%llx\n",
535 (long long)lcn);
536 err = 1;
537 }
538 }
539 }
540 return (err);
541 }
542
543 /*
544 * Write a full set of raw clusters to mft_mirr
545 */
546
write_mirr(ntfs_volume * vol,const LOG_RECORD * logr,char * buffer)547 static int write_mirr(ntfs_volume *vol, const LOG_RECORD *logr,
548 char *buffer)
549 {
550 int err;
551 LCN lcn;
552 char *source;
553 int count;
554 int i;
555
556 err = 0;
557 count = le16_to_cpu(logr->lcns_to_follow);
558 if (!count)
559 printf("** Error : no lcn to write to\n");
560 if (!optn) {
561 for (i=0; (i<count) && !err; i++) {
562 lcn = ntfs_attr_vcn_to_lcn(vol->mftmirr_na,
563 sle64_to_cpu(logr->target_vcn) + i);
564 source = buffer + clustersz*i;
565 if ((lcn < 0)
566 || (ntfs_pwrite(vol->dev, lcn << clusterbits,
567 clustersz, source) != clustersz)) {
568 printf("** Could not write cluster 0x%llx\n",
569 (long long)lcn);
570 err = 1;
571 }
572 }
573 }
574 return (err);
575 }
576
577 /*
578 * Allocate a buffer and read a single protected record
579 */
580
read_protected(ntfs_volume * vol,const LOG_RECORD * logr,u32 size,BOOL warn)581 static char *read_protected(ntfs_volume *vol, const LOG_RECORD *logr,
582 u32 size, BOOL warn)
583 {
584 char *buffer;
585 char *full;
586 u32 pos;
587 LCN lcn;
588
589 /* read full clusters */
590 buffer = read_raw(vol, logr);
591 /*
592 * if the record is smaller than a cluster,
593 * make a partial copy and free the full buffer
594 */
595 if (buffer && (size < clustersz)) {
596 full = buffer;
597 buffer = (char*)malloc(size);
598 if (buffer) {
599 pos = le16_to_cpu(logr->cluster_index)
600 << NTFS_BLOCK_SIZE_BITS;
601 memcpy(buffer, full + pos, size);
602 }
603 free(full);
604 }
605 if (buffer && (ntfs_mst_post_read_fixup_warn(
606 (NTFS_RECORD*)buffer, size, FALSE) < 0)) {
607 if (warn) {
608 lcn = sle64_to_cpu(logr->lcn_list[0]);
609 printf("** Invalid protected record at 0x%llx"
610 " index %d\n",
611 (long long)lcn,
612 (int)le16_to_cpu(logr->cluster_index));
613 }
614 free(buffer);
615 buffer = (char*)NULL;
616 }
617 return (buffer);
618 }
619
620 /*
621 * Protect a single record, write, and deallocate the buffer
622 *
623 * With option -n a copy of the buffer is kept in protected form in
624 * memory for later use.
625 * As the store only knows about clusters, if the record is smaller
626 * than a cluster, have to read, merge and write.
627 */
628
write_protected(ntfs_volume * vol,const LOG_RECORD * logr,char * buffer,u32 size)629 static int write_protected(ntfs_volume *vol, const LOG_RECORD *logr,
630 char *buffer, u32 size)
631 {
632 MFT_RECORD *record;
633 INDEX_BLOCK *indx;
634 char *full;
635 u32 pos;
636 BOOL mftmirr;
637 BOOL checked;
638 int err;
639
640 err = 0;
641 mftmirr = FALSE;
642 checked = FALSE;
643 if ((size == mftrecsz) && !memcmp(buffer,"FILE",4)) {
644 record = (MFT_RECORD*)buffer;
645 if (optv)
646 printf("update inode %ld lsn 0x%llx"
647 " (record %s than action 0x%llx)\n",
648 (long)le32_to_cpu(record->mft_record_number),
649 (long long)sle64_to_cpu(record->lsn),
650 ((s64)(sle64_to_cpu(record->lsn)
651 - sle64_to_cpu(logr->this_lsn)) < 0 ?
652 "older" : "newer"),
653 (long long)sle64_to_cpu(logr->this_lsn));
654 if (optv > 1)
655 printf("mft vcn %lld index %d\n",
656 (long long)sle64_to_cpu(logr->target_vcn),
657 (int)le16_to_cpu(logr->cluster_index));
658 err = sanity_mft(buffer);
659 /* Should set to some previous lsn for undos */
660 if (opts)
661 record->lsn = logr->this_lsn;
662 /* Duplicate on mftmirr if not overflowing its size */
663 mftmirr = (((u64)sle64_to_cpu(logr->target_vcn)
664 + le16_to_cpu(logr->lcns_to_follow))
665 << clusterbits)
666 <= (((u64)vol->mftmirr_size) << mftrecbits);
667 checked = TRUE;
668 }
669 if ((size == vol->indx_record_size) && !memcmp(buffer,"INDX",4)) {
670 indx = (INDEX_BLOCK*)buffer;
671 if (optv)
672 printf("update index lsn 0x%llx"
673 " (index %s than action 0x%llx)\n",
674 (long long)sle64_to_cpu(indx->lsn),
675 ((s64)(sle64_to_cpu(indx->lsn)
676 - sle64_to_cpu(logr->this_lsn)) < 0 ?
677 "older" : "newer"),
678 (long long)sle64_to_cpu(logr->this_lsn));
679 err = sanity_indx(vol, buffer);
680 /* Should set to some previous lsn for undos */
681 if (opts)
682 indx->lsn = logr->this_lsn;
683 checked = TRUE;
684 }
685 if (!checked) {
686 printf("** Error : writing protected record of unknown type\n");
687 err = 1;
688 }
689 if (!err) {
690 if (!ntfs_mst_pre_write_fixup((NTFS_RECORD*)buffer, size)) {
691 /*
692 * If the record is smaller than a cluster, get a full
693 * cluster, merge and write.
694 */
695 if (size < clustersz) {
696 full = read_raw(vol, logr);
697 if (full) {
698 pos = le16_to_cpu(logr->cluster_index)
699 << NTFS_BLOCK_SIZE_BITS;
700 memcpy(full + pos, buffer, size);
701 err = write_raw(vol, logr, full);
702 if (!err && mftmirr && !optn)
703 err = write_mirr(vol, logr,
704 full);
705 free(full);
706 } else
707 err = 1;
708 } else {
709 /* write full clusters */
710 err = write_raw(vol, logr, buffer);
711 if (!err && mftmirr && !optn)
712 err = write_mirr(vol, logr, buffer);
713 }
714 } else {
715 printf("** Failed to protect record\n");
716 err = 1;
717 }
718 }
719 return (err);
720 }
721
722 /*
723 * Resize attribute records
724 *
725 * The attribute value is resized to new size, but the attribute
726 * and MFT record must be kept aligned to 8 bytes.
727 */
728
resize_attribute(MFT_RECORD * entry,ATTR_RECORD * attr,INDEX_ROOT * index,int rawresize,int resize)729 static int resize_attribute(MFT_RECORD *entry, ATTR_RECORD *attr, INDEX_ROOT *index,
730 int rawresize, int resize)
731 {
732 int err;
733 u32 newlength;
734 u32 newused;
735 u32 newvalue;
736 u32 indexlth;
737 u32 indexalloc;
738
739 err = 0;
740 if (attr) {
741 newvalue = le32_to_cpu(attr->value_length) + rawresize;
742 attr->value_length = cpu_to_le32(newvalue);
743 newlength = le32_to_cpu(attr->length) + resize;
744 attr->length = cpu_to_le32(newlength);
745 }
746 if (entry) {
747 newused = le32_to_cpu(entry->bytes_in_use) + resize;
748 entry->bytes_in_use = cpu_to_le32(newused);
749 }
750 if (index) {
751 indexlth = le32_to_cpu(index->index.index_length) + resize;
752 index->index.index_length = cpu_to_le32(indexlth);
753 indexalloc = le32_to_cpu(index->index.allocated_size) + resize;
754 index->index.allocated_size = cpu_to_le32(indexalloc);
755 }
756 return (err);
757 }
758
759 /*
760 * Adjust the next attribute instance
761 *
762 * If a newly created attribute matches the next instance, then
763 * the next instance has to be incremented.
764 *
765 * Do the opposite when undoing an attribute creation, but
766 * do not change the next instance when deleting an attribute
767 * or undoing the deletion.
768 */
769
adjust_instance(const ATTR_RECORD * attr,MFT_RECORD * entry,int increment)770 static void adjust_instance(const ATTR_RECORD *attr, MFT_RECORD *entry, int increment)
771 {
772 u16 instance;
773
774 if (increment > 0) {
775 /* Allocating a new instance ? */
776 if (attr->instance == entry->next_attr_instance) {
777 instance = (le16_to_cpu(entry->next_attr_instance)
778 + 1) & 0xffff;
779 entry->next_attr_instance = cpu_to_le16(instance);
780 }
781 }
782 if (increment < 0) {
783 /* Freeing the latest instance ? */
784 instance = (le16_to_cpu(entry->next_attr_instance)
785 - 1) & 0xffff;
786 if (attr->instance == cpu_to_le16(instance))
787 entry->next_attr_instance = attr->instance;
788 }
789 }
790
791 /*
792 * Adjust the highest vcn according to mapping pairs
793 *
794 * The runlist has to be fully recomputed
795 */
796
adjust_high_vcn(ntfs_volume * vol,ATTR_RECORD * attr)797 static int adjust_high_vcn(ntfs_volume *vol, ATTR_RECORD *attr)
798 {
799 runlist_element *rl;
800 runlist_element *xrl;
801 VCN high_vcn;
802 int err;
803
804 err = 1;
805 attr->highest_vcn = const_cpu_to_sle64(0);
806 rl = ntfs_mapping_pairs_decompress(vol, attr, (runlist_element*)NULL);
807 if (rl) {
808 xrl = rl;
809 if (xrl->length)
810 xrl++;
811 while ((xrl->length) && (xrl->lcn != LCN_RL_NOT_MAPPED))
812 xrl++;
813 high_vcn = xrl->vcn - 1;
814 attr->highest_vcn = cpu_to_sle64(high_vcn);
815 free(rl);
816 err = 0;
817 } else {
818 printf("** Failed to decompress the runlist\n");
819 dump((char*)attr,128);
820 }
821 return (err);
822 }
823
824 /*
825 * Check index match, to be used for undos only
826 *
827 * The action UpdateFileNameRoot updates the time stamps and/or the
828 * sizes, but the lsn is not updated in the index record.
829 * As a consequence such UpdateFileNameRoot are not always undone
830 * and the actual record does not fully match the undo data.
831 * We however accept the match if the parent directory and the name
832 * match.
833 * Alternate workaround : do not check the lsn when undoing
834 * UpdateFileNameRoot
835 */
836
index_match_undo(const char * first,const char * second,int length)837 static BOOL index_match_undo(const char *first, const char *second, int length)
838 {
839 int len;
840 BOOL match;
841
842 match = !memcmp(first, second, length);
843 if (!match) {
844 if (optv) {
845 printf("The existing index does not match :\n");
846 dump(second,length);
847 }
848 len = (first[80] & 255)*2 + 2;
849 match = (feedle64(first, 16) == feedle64(second, 16))
850 && !memcmp(first + 80, second + 80, len);
851 if (match && optv)
852 printf("However parent dir and name do match\n");
853 }
854 return (match);
855 }
856
857
858 /*
859 * Generic idempotent change to a resident attribute
860 */
861
change_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length)862 static int change_resident(ntfs_volume *vol, const struct ACTION_RECORD *action,
863 char *buffer, const char *data, u32 target, u32 length)
864 {
865 LCN lcn;
866 ATTR_RECORD *attr;
867 u32 attrend;
868 int err;
869 int changed;
870
871 err = 1;
872 if (action->record.undo_length != action->record.redo_length)
873 printf("** Error size change in change_resident\n");
874 if (optv > 1) {
875 lcn = sle64_to_cpu(action->record.lcn_list[0]);
876 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
877 (long long)inode_number(&action->record),
878 (long long)lcn, (int)target, (int)length);
879 }
880 attr = (ATTR_RECORD*)(buffer
881 + le16_to_cpu(action->record.record_offset));
882 if (optv > 1) {
883 printf("-> existing record :\n");
884 dump(&buffer[target], length);
885 printf("-> full MFT record :\n");
886 dump(buffer,mftrecsz);
887 }
888 attrend = le16_to_cpu(action->record.record_offset)
889 + le32_to_cpu(attr->length);
890 if ((target + length) > attrend) {
891 printf("** Error : update overflows from attribute\n");
892 }
893 if (!(length & 7)
894 && ((target + length) <= attrend)
895 && (attrend <= mftrecsz)
896 && !sanity_mft(buffer)) {
897 changed = memcmp(buffer + target, data, length);
898 err = 0;
899 if (changed) {
900 memcpy(buffer + target, data, length);
901 if (optv > 1) {
902 printf("-> new record :\n");
903 dump(buffer + target, length);
904 }
905 err = write_protected(vol, &action->record,
906 buffer, mftrecsz);
907 }
908 if (optv > 1) {
909 printf("-> MFT record %s\n",
910 (changed ? "updated" : "unchanged"));
911 }
912 }
913 return (err);
914 }
915
change_resident_expect(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,const char * expected,u32 target,u32 length,ATTR_TYPES type)916 static int change_resident_expect(ntfs_volume *vol, const struct ACTION_RECORD *action,
917 char *buffer, const char *data, const char *expected,
918 u32 target, u32 length, ATTR_TYPES type)
919 {
920 LCN lcn;
921 ATTR_RECORD *attr;
922 int err;
923 BOOL found;
924
925 err = 1;
926 if (action->record.undo_length != action->record.redo_length)
927 printf("** Error size change in change_resident\n");
928 if (optv > 1) {
929 lcn = sle64_to_cpu(action->record.lcn_list[0]);
930 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
931 (long long)inode_number(&action->record),
932 (long long)lcn, (int)target, (int)length);
933 }
934 attr = (ATTR_RECORD*)(buffer
935 + le16_to_cpu(action->record.record_offset));
936 if (optv > 1) {
937 printf("-> existing record :\n");
938 dump(&buffer[target], length);
939 printf("-> full record :\n");
940 dump((char*)attr, le32_to_cpu(attr->length));
941 }
942 if ((attr->type == type)
943 && !(length & 7)
944 && ((target + length) <= mftrecsz)) {
945 found = !memcmp(buffer + target, expected, length);
946 err = 0;
947 if (found) {
948 memcpy(buffer + target, data, length);
949 if (optv > 1) {
950 printf("-> new record :\n");
951 dump(buffer + target, length);
952 }
953 err = write_protected(vol, &action->record,
954 buffer, mftrecsz);
955 }
956 if (optv > 1) {
957 printf("-> MFT record %s\n",
958 (found ? "updated" : "unchanged"));
959 }
960 }
961 return (err);
962 }
963
964 /*
965 * Generic idempotent change to a an index value
966 *
967 */
968
change_index_value(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length)969 static int change_index_value(ntfs_volume *vol, const struct ACTION_RECORD *action,
970 char *buffer, const char *data, u32 target, u32 length)
971 {
972 LCN lcn;
973 u32 count;
974 u32 xsize;
975 int changed;
976 int err;
977
978 err = 1;
979 count = le16_to_cpu(action->record.lcns_to_follow);
980 if (optv > 1) {
981 lcn = sle64_to_cpu(action->record.lcn_list[0]);
982 printf("-> lcn 0x%llx target 0x%x length %d\n",
983 (long long)lcn, (int)target, (int)length);
984 }
985 xsize = vol->indx_record_size;
986 if (optv > 1) {
987 printf("-> existing record :\n");
988 dump(&buffer[target], length);
989 }
990 if ((target + length) <= (count << clusterbits)) {
991 changed = memcmp(buffer + target, data, length);
992 err = 0;
993 if (changed) {
994 memcpy(buffer + target, data, length);
995 if (optv > 1) {
996 printf("-> new record :\n");
997 dump(buffer + target, length);
998 }
999 err = write_protected(vol, &action->record,
1000 buffer, xsize);
1001 }
1002 if (optv > 1) {
1003 printf("-> data record %s\n",
1004 (changed ? "updated" : "unchanged"));
1005 }
1006 }
1007 return (err);
1008 }
1009
1010 /*
1011 * Add one or more resident attributes
1012 */
1013
add_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length,u32 oldlength)1014 static int add_resident(ntfs_volume *vol, const struct ACTION_RECORD *action,
1015 char *buffer, const char *data, u32 target,
1016 u32 length, u32 oldlength)
1017 {
1018 LCN lcn;
1019 MFT_RECORD *entry;
1020 int err;
1021 BOOL found;
1022 int resize;
1023
1024 err = 1;
1025 if (optv > 1) {
1026 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1027 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
1028 (long long)inode_number(&action->record),
1029 (long long)lcn, (int)target, (int)length);
1030 }
1031 entry = (MFT_RECORD*)buffer;
1032 resize = length - oldlength;
1033 if (optv > 1) {
1034 printf("existing data :\n");
1035 dump(buffer + target,length);
1036 }
1037 if (!(length & 7)
1038 && !(oldlength & 7)
1039 && ((target + length) <= mftrecsz)) {
1040 /* This has to be an idempotent action */
1041 err = 0;
1042 if (data && length)
1043 found = !memcmp(buffer + target,
1044 data, length);
1045 else {
1046 found = TRUE;
1047 err = 1;
1048 }
1049 if (!found && !err) {
1050 /* Make space to insert the entry */
1051 memmove(buffer + target + resize,
1052 buffer + target,
1053 mftrecsz - target - resize);
1054 if (data)
1055 memcpy(buffer + target, data, length);
1056 else
1057 memset(buffer + target, 0, length);
1058 resize_attribute(entry, NULL, NULL,
1059 resize, resize);
1060 if (optv > 1) {
1061 printf("new data at same location :\n");
1062 dump(buffer + target, length);
1063 }
1064 err = write_protected(vol, &action->record,
1065 buffer, mftrecsz);
1066 }
1067 if (optv > 1) {
1068 printf("-> MFT record %s\n",
1069 (found ? "unchanged" : "expanded"));
1070 }
1071 }
1072 return (err);
1073 }
1074
1075 /*
1076 * Add one or more non-resident records
1077 */
1078
delete_non_resident(void)1079 static int delete_non_resident(void /*ntfs_volume *vol,
1080 const struct ACTION_RECORD *action,
1081 const char *data, u32 target, u32 length, u32 oldlength*/)
1082 {
1083 int err;
1084
1085 err = 1;
1086 printf("** delete_non_resident() not implemented\n");
1087 return (err);
1088 }
1089
1090 /*
1091 * Expand a single resident attribute
1092 */
1093
expand_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length,u32 oldlength)1094 static int expand_resident(ntfs_volume *vol, const struct ACTION_RECORD *action,
1095 char *buffer, const char *data, u32 target,
1096 u32 length, u32 oldlength)
1097 {
1098 LCN lcn;
1099 ATTR_RECORD *attr;
1100 MFT_RECORD *entry;
1101 int err;
1102 BOOL found;
1103 int resize;
1104 u16 base;
1105
1106 err = 1;
1107 if (optv > 1) {
1108 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1109 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
1110 (long long)inode_number(&action->record),
1111 (long long)lcn, (int)target, (int)length);
1112 }
1113 entry = (MFT_RECORD*)buffer;
1114 attr = (ATTR_RECORD*)(buffer
1115 + le16_to_cpu(action->record.record_offset));
1116 if (optv > 1) {
1117 printf("existing data :\n");
1118 dump(buffer + target,length);
1119 }
1120 base = 24 + 2*attr->name_length;
1121 resize = ((base + length - 1) | 7)
1122 - ((base + oldlength - 1) | 7);
1123 if ((target + length) <= mftrecsz) {
1124 /* This has to be an idempotent action */
1125 // TODO This test is wrong !
1126 found = le32_to_cpu(attr->value_length) == length;
1127 if (found && data && length)
1128 found = !memcmp(buffer + target, data, length);
1129 err = 0;
1130 if (!found) {
1131 /* Make space to insert the entry */
1132 memmove(buffer + target + resize,
1133 buffer + target,
1134 mftrecsz - target - resize);
1135 // TODO what to do if length is not a multiple of 8 ?
1136 if (data)
1137 memcpy(buffer + target, data, length);
1138 else
1139 memset(buffer + target, 0, length);
1140 resize_attribute(entry, attr, NULL,
1141 length - oldlength, resize);
1142 if (optv > 1) {
1143 printf("new data at same location :\n");
1144 dump(buffer + target, length);
1145 }
1146 err = write_protected(vol, &action->record,
1147 buffer, mftrecsz);
1148 }
1149 if (optv > 1) {
1150 printf("-> MFT record %s\n",
1151 (found ? "unchanged" : "expanded"));
1152 }
1153 }
1154 return (err);
1155 }
1156
1157 /*
1158 * Add one or more non-resident records
1159 */
1160
add_non_resident(void)1161 static int add_non_resident(void /*ntfs_volume *vol,
1162 const struct ACTION_RECORD *action,
1163 const char *data, u32 target, u32 length, u32 oldlength*/)
1164 {
1165 int err;
1166
1167 printf("** add_non_resident() not implemented\n");
1168 err = 0;
1169 return (err);
1170 }
1171
1172 /*
1173 * Generic insert a new resident attribute
1174 */
1175
insert_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length)1176 static int insert_resident(ntfs_volume *vol, const struct ACTION_RECORD *action,
1177 char *buffer, const char *data, u32 target,
1178 u32 length)
1179 {
1180 LCN lcn;
1181 ATTR_RECORD *attr;
1182 const ATTR_RECORD *newattr;
1183 MFT_RECORD *entry;
1184 u32 newused;
1185 u16 links;
1186 int err;
1187 BOOL found;
1188
1189 err = 1;
1190 if (optv > 1) {
1191 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1192 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
1193 (long long)inode_number(&action->record),
1194 (long long)lcn, (int)target, (int)length);
1195 }
1196 entry = (MFT_RECORD*)buffer;
1197 attr = (ATTR_RECORD*)(buffer
1198 + le16_to_cpu(action->record.record_offset));
1199 newattr = (const ATTR_RECORD*)data;
1200 if (optv > 1) {
1201 printf("existing record :\n");
1202 dump(buffer + target,length);
1203 if (le32_to_cpu(attr->type) < le32_to_cpu(newattr->type)) {
1204 printf("** Bad attribute order, full record :\n");
1205 dump(buffer, mftrecsz);
1206 }
1207 }
1208 /* Types must be in ascending order */
1209 if (valid_type(attr->type)
1210 && (le32_to_cpu(attr->type)
1211 >= le32_to_cpu(newattr->type))
1212 && !(length & 7)
1213 && ((target + length) <= mftrecsz)) {
1214 /* This has to be an idempotent action */
1215 found = !memcmp(buffer + target, data, length);
1216 err = 0;
1217 if (!found) {
1218 /* Make space to insert the entry */
1219 memmove(buffer + target + length,
1220 buffer + target,
1221 mftrecsz - target - length);
1222 memcpy(buffer + target, data, length);
1223 newused = le32_to_cpu(entry->bytes_in_use)
1224 + length;
1225 entry->bytes_in_use = cpu_to_le32(newused);
1226 if (action->record.redo_operation
1227 == const_cpu_to_le16(CreateAttribute)) {
1228 /*
1229 * For a real create, may have to adjust
1230 * the next attribute instance
1231 */
1232 adjust_instance(newattr, entry, 1);
1233 }
1234 if (newattr->type == AT_FILE_NAME) {
1235 links = le16_to_cpu(entry->link_count) + 1;
1236 entry->link_count = cpu_to_le16(links);
1237 }
1238 if (optv > 1) {
1239 printf("expanded record (now 0x%x"
1240 " bytes used) :\n",
1241 (int)newused);
1242 dump(buffer + target, 2*length);
1243 }
1244 err = write_protected(vol, &action->record,
1245 buffer, mftrecsz);
1246 }
1247 if (optv > 1) {
1248 printf("-> MFT record %s\n",
1249 (found ? "unchanged" : "expanded"));
1250 }
1251 }
1252 return (err);
1253 }
1254
1255 /*
1256 * Generic remove a single resident attribute
1257 */
1258
remove_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length)1259 static int remove_resident(ntfs_volume *vol, const struct ACTION_RECORD *action,
1260 char *buffer, const char *data, u32 target,
1261 u32 length)
1262 {
1263 LCN lcn;
1264 ATTR_RECORD *attr;
1265 MFT_RECORD *entry;
1266 u32 newused;
1267 u16 links;
1268 int err;
1269 BOOL found;
1270
1271 err = 1;
1272 if (optv > 1) {
1273 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1274 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
1275 (long long)inode_number(&action->record),
1276 (long long)lcn, (int)target, (int)length);
1277 }
1278 entry = (MFT_RECORD*)buffer;
1279 attr = (ATTR_RECORD*)(buffer
1280 + le16_to_cpu(action->record.record_offset));
1281 if (optv > 1) {
1282 printf("existing record :\n");
1283 dump(buffer + target,length);
1284 }
1285 if (!(length & 7)
1286 && ((target + length) <= mftrecsz)) {
1287 /* This has to be an idempotent action */
1288 /* For AT_DATA the value is not always present */
1289 if (attr->type == AT_DATA)
1290 found = !memcmp(buffer + target, data,
1291 le16_to_cpu(attr->value_offset));
1292 else
1293 found = !memcmp(buffer + target, data, length);
1294 if (!found && optv) {
1295 printf("data 0x%lx 0x%lx offset %d %ld\n",
1296 (long)le32_to_cpu(attr->type),
1297 (long)le32_to_cpu(AT_DATA),
1298 (int)offsetof(ATTR_RECORD, resident_end),
1299 (long)le16_to_cpu(attr->value_offset));
1300 printf("The existing record does not match (%d/%d)\n",
1301 (int)matchcount(buffer + target, data,
1302 length),(int)length);
1303 dump(data,length);
1304 printf("full attr :\n");
1305 dump((const char*)attr,mftrecsz
1306 - le16_to_cpu(action->record.record_offset));
1307 }
1308 err = 0;
1309 if (found) {
1310 if (attr->type == AT_FILE_NAME) {
1311 links = le16_to_cpu(entry->link_count) - 1;
1312 entry->link_count = cpu_to_le16(links);
1313 }
1314 if (action->record.redo_operation
1315 == const_cpu_to_le16(CreateAttribute)) {
1316 adjust_instance(attr, entry, -1);
1317 }
1318 /* Remove the entry */
1319 memmove(buffer + target,
1320 buffer + target + length,
1321 mftrecsz - target - length);
1322 newused = le32_to_cpu(entry->bytes_in_use) - length;
1323 entry->bytes_in_use = cpu_to_le32(newused);
1324 if (optv > 1) {
1325 printf("new record at same location"
1326 " (now 0x%x bytes used) :\n",
1327 (int)newused);
1328 dump(buffer + target, length);
1329 }
1330 err = write_protected(vol, &action->record,
1331 buffer, mftrecsz);
1332 }
1333 if (optv > 1) {
1334 printf("-> MFT record %s\n",
1335 (found ? "shrinked" : "unchanged"));
1336 }
1337 }
1338 return (err);
1339 }
1340
1341 /*
1342 * Delete one or more resident attributes
1343 */
1344
delete_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length,u32 oldlength)1345 static int delete_resident(ntfs_volume *vol, const struct ACTION_RECORD *action,
1346 char *buffer, const char *data, u32 target,
1347 u32 length, u32 oldlength)
1348 {
1349 LCN lcn;
1350 MFT_RECORD *entry;
1351 int err;
1352 BOOL found;
1353 int resize;
1354
1355 if (optv > 1)
1356 printf("-> %s()\n",__func__);
1357 err = 1;
1358 if (optv > 1) {
1359 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1360 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
1361 (long long)inode_number(&action->record),
1362 (long long)lcn, (int)target, (int)length);
1363 }
1364 entry = (MFT_RECORD*)buffer;
1365 if (optv > 1) {
1366 printf("existing data :\n");
1367 dump(buffer + target,length);
1368 }
1369 resize = length - oldlength;
1370 if (!(length & 7)
1371 && !(oldlength & 7)
1372 && ((target + oldlength) <= mftrecsz)) {
1373 /* This has to be an idempotent action */
1374 err = 0;
1375 if (data && length)
1376 found = !memcmp(buffer + target, data, length);
1377 else {
1378 found = FALSE;
1379 err = 1;
1380 }
1381 if (!found && !err) {
1382 /* Remove the entry, if present */
1383 memmove(buffer + target,
1384 buffer + target - resize,
1385 mftrecsz - target + resize);
1386 resize_attribute(entry, NULL, NULL,
1387 length - oldlength, resize);
1388 if (optv > 1) {
1389 printf("new data at same location :\n");
1390 dump(buffer + target, length);
1391 }
1392 err = write_protected(vol, &action->record,
1393 buffer, mftrecsz);
1394 }
1395 if (optv > 1) {
1396 printf("-> MFT record %s\n",
1397 (found ? "unchanged" : "shrinked"));
1398 }
1399 }
1400 return (err);
1401 }
1402
shrink_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length,u32 oldlength)1403 static int shrink_resident(ntfs_volume *vol, const struct ACTION_RECORD *action,
1404 char *buffer, const char *data, u32 target,
1405 u32 length, u32 oldlength)
1406 {
1407 LCN lcn;
1408 ATTR_RECORD *attr;
1409 MFT_RECORD *entry;
1410 int err;
1411 BOOL found;
1412 int resize;
1413 u16 base;
1414
1415 if (optv > 1)
1416 printf("-> %s()\n",__func__);
1417 err = 1;
1418 if (optv > 1) {
1419 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1420 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
1421 (long long)inode_number(&action->record),
1422 (long long)lcn, (int)target, (int)length);
1423 }
1424 entry = (MFT_RECORD*)buffer;
1425 attr = (ATTR_RECORD*)(buffer
1426 + le16_to_cpu(action->record.record_offset));
1427 if (optv > 1) {
1428 printf("existing data :\n");
1429 dump(buffer + target,length);
1430 }
1431 base = 24 + 2*attr->name_length;
1432 resize = ((base + length - 1) | 7)
1433 - ((base + oldlength - 1) | 7);
1434 if ((oldlength > length)
1435 // TODO limit to attr length
1436 && ((target + oldlength) <= mftrecsz)) {
1437 /* This has to be an idempotent action */
1438 if (data && length)
1439 found = !memcmp(buffer + target, data, length);
1440 else
1441 {
1442 // TODO wrong : need checking against the old data, but in known cases
1443 // redo data is not available either and existing data is not zero.
1444 found = FALSE;
1445 printf("* fake test, assuming not shrinked : value length %ld length %ld oldlength %ld\n",(long)le32_to_cpu(attr->value_length),(long)length,(long)oldlength);
1446 //dump(buffer + target, oldlength);
1447 }
1448 err = 0;
1449 if (!found) {
1450 if (length) {
1451 /* Relocate end of record */
1452 // TODO restrict to bytes_in_use
1453 memmove(buffer + target + length,
1454 buffer + target + oldlength,
1455 mftrecsz - target - oldlength);
1456 /* Insert new data or zeroes */
1457 if (data)
1458 memcpy(buffer + target, data, length);
1459 else
1460 memset(buffer + target, 0, length);
1461 } else {
1462 /* Remove the entry, unless targeted size */
1463 memmove(buffer + target,
1464 buffer + target - resize,
1465 mftrecsz - target + resize);
1466 }
1467 resize_attribute(entry, attr, NULL,
1468 length - oldlength, resize);
1469 if (optv > 1) {
1470 printf("new data at same location :\n");
1471 dump(buffer + target, length);
1472 }
1473 err = write_protected(vol, &action->record,
1474 buffer, mftrecsz);
1475 }
1476 if (optv > 1) {
1477 printf("-> MFT record %s\n",
1478 (found ? "unchanged" : "shrinked"));
1479 }
1480 }
1481 return (err);
1482 }
1483
update_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer,const char * data,u32 target,u32 length)1484 static int update_index(ntfs_volume *vol, const struct ACTION_RECORD *action,
1485 char *buffer, const char *data, u32 target, u32 length)
1486 {
1487 LCN lcn;
1488 INDEX_BLOCK *indx;
1489 u32 xsize;
1490 BOOL changed;
1491 int err;
1492
1493 err = 1;
1494 if (optv > 1) {
1495 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1496 printf("-> lcn 0x%llx target 0x%x length %d\n",
1497 (long long)lcn, (int)target, (int)length);
1498 }
1499 xsize = vol->indx_record_size;
1500 indx = (INDEX_BLOCK*)(buffer
1501 + le16_to_cpu(action->record.record_offset));
1502 if (optv > 1) {
1503 printf("-> existing index :\n");
1504 dump(&buffer[target], length);
1505 }
1506 if ((indx->magic == magic_INDX)
1507 && !(length & 7)
1508 && ((target + length) <= xsize)) {
1509 /* This has to be an idempotent action */
1510 changed = memcmp(buffer + target, data, length);
1511 err = 0;
1512 if (changed) {
1513 /* Update the entry */
1514 memcpy(buffer + target, data, length);
1515 if (optv > 1) {
1516 printf("-> new index :\n");
1517 dump(&buffer[target], length);
1518 }
1519 err = write_protected(vol, &action->record,
1520 buffer, xsize);
1521 }
1522 if (optv > 1) {
1523 printf("-> INDX record %s\n",
1524 (changed ? "updated" : "unchanged"));
1525 }
1526 }
1527 return (err);
1528 }
1529
1530 /*
1531 * Controversial deletion of file names, see undo_delete_file()
1532 */
1533
delete_names(char * buffer)1534 static int delete_names(char *buffer)
1535 {
1536 MFT_RECORD *record;
1537 ATTR_RECORD *attr;
1538 u32 used;
1539 u32 pos;
1540 int length;
1541 int cnt;
1542
1543 record = (MFT_RECORD*)buffer;
1544 pos = le16_to_cpu(record->attrs_offset);
1545 used = le32_to_cpu(record->bytes_in_use);
1546 cnt = 0;
1547 do {
1548 attr = (ATTR_RECORD*)&buffer[pos];
1549 length = le32_to_cpu(attr->length);
1550 if (attr->type == AT_FILE_NAME) {
1551 if (optv)
1552 showname("Controversial deletion of ",
1553 &buffer[pos+90], buffer[pos+88] & 255);
1554 memmove(buffer + pos, buffer + pos + length,
1555 mftrecsz - pos - length);
1556 used -= length;
1557 cnt++;
1558 } else
1559 pos += length;
1560 } while ((pos < used)
1561 && (le32_to_cpu(attr->type) <= le32_to_cpu(AT_FILE_NAME)));
1562 record->bytes_in_use = cpu_to_le32(used);
1563 record->link_count = cpu_to_le16(0);
1564 return (cnt ? 0 : 1);
1565 }
1566
rebuildname(const INDEX_ENTRY * index)1567 static int rebuildname(const INDEX_ENTRY *index)
1568 {
1569 ATTR_RECORD *attr;
1570 int headlth;
1571 int datalth;
1572
1573 datalth = le16_to_cpu(index->length)
1574 - offsetof(INDEX_ENTRY,key.file_name);
1575 headlth = offsetof(ATTR_RECORD,resident_end);
1576 attr = (ATTR_RECORD*)malloc(headlth + datalth);
1577 if (attr) {
1578 attr->type = AT_FILE_NAME;
1579 attr->length = cpu_to_le32(headlth + datalth);
1580 attr->non_resident = 0;
1581 attr->name_length = 0;
1582 attr->name_offset = const_cpu_to_le16(0);
1583 attr->flags = const_cpu_to_le16(0);
1584 attr->instance = const_cpu_to_le16(0);
1585 attr->value_length = cpu_to_le32(
1586 2*index->key.file_name.file_name_length
1587 + offsetof(FILE_NAME_ATTR, file_name));
1588 attr->value_offset = cpu_to_le16(headlth);
1589 attr->resident_flags = RESIDENT_ATTR_IS_INDEXED;
1590 memcpy(attr->resident_end, &index->key.file_name, datalth);
1591 free(attr);
1592 }
1593 return (0);
1594 }
1595
1596 /*
1597 * Controversial creation of an index allocation attribute
1598 *
1599 * This is useful for turning the clock backward, but cannot
1600 * work properly in the general case and must not be used for
1601 * a real sync.
1602 * The main problem is to synchronize the file names when an
1603 * inode is reused with a different name.
1604 */
1605
insert_index_allocation(ntfs_volume * vol,char * buffer,u32 offs)1606 static int insert_index_allocation(ntfs_volume *vol, char *buffer, u32 offs)
1607 {
1608 MFT_RECORD *record;
1609 ATTR_RECORD *attr;
1610 u32 used;
1611 u32 pos;
1612 u32 xsize;
1613 u16 instance;
1614 int length;
1615 int addedlength;
1616 int namelength;
1617 int err;
1618 static const unsigned char bitmap[] =
1619 { 1, 0, 0, 0, 0, 0, 0, 0 } ;
1620
1621 err = 1;
1622 if (opts) {
1623 printf("** Call to unsupported insert_index_allocation()\n");
1624 } else {
1625 record = (MFT_RECORD*)buffer;
1626 pos = le16_to_cpu(record->attrs_offset);
1627 used = le32_to_cpu(record->bytes_in_use);
1628 attr = (ATTR_RECORD*)&buffer[pos];
1629 while ((pos < used)
1630 && (le32_to_cpu(attr->type) < le32_to_cpu(AT_INDEX_ROOT))) {
1631 pos += le32_to_cpu(attr->length);
1632 attr = (ATTR_RECORD*)&buffer[pos];
1633 }
1634 length = le32_to_cpu(attr->length);
1635 addedlength = length - 8 /* index allocation */
1636 + length - 48; /* bitmap */
1637 if ((attr->type == AT_INDEX_ROOT)
1638 && ((pos + length) == offs)
1639 && ((used + addedlength) < mftrecsz)) {
1640 /* Make space for the attribute */
1641 memmove(buffer + offs + addedlength, buffer + offs,
1642 mftrecsz - offs - addedlength);
1643 record->bytes_in_use = cpu_to_le32(used + addedlength);
1644 /*
1645 * Insert an AT_INDEX_ALLOCATION
1646 */
1647 attr = (ATTR_RECORD*)&buffer[offs];
1648 attr->type = AT_INDEX_ALLOCATION;
1649 attr->length = cpu_to_le32(length - 8);
1650 attr->non_resident = 1;
1651 namelength = buffer[pos + 9] & 255;
1652 attr->name_length = namelength;
1653 attr->name_offset = const_cpu_to_le16(0x40);
1654 memcpy(buffer + offs + 0x40, buffer + pos + 0x18,
1655 2*namelength);
1656 attr->flags = const_cpu_to_le16(0);
1657 /* Should we really take a new instance ? */
1658 attr->instance = record->next_attr_instance;
1659 instance = le16_to_cpu(record->next_attr_instance) + 1;
1660 record->next_attr_instance = cpu_to_le16(instance);
1661 attr->lowest_vcn = const_cpu_to_sle64(0);
1662 attr->highest_vcn = const_cpu_to_sle64(0);
1663 attr->mapping_pairs_offset = cpu_to_le16(
1664 2*namelength + 0x40);
1665 attr->compression_unit = 0;
1666 xsize = vol->indx_record_size;
1667 attr->allocated_size = cpu_to_sle64(xsize);
1668 attr->data_size = attr->allocated_size;
1669 attr->initialized_size = attr->allocated_size;
1670 /*
1671 * Insert an AT_INDEX_BITMAP
1672 */
1673 attr = (ATTR_RECORD*)&buffer[offs + length - 8];
1674 attr->type = AT_BITMAP;
1675 attr->length = cpu_to_le32(length - 48);
1676 attr->non_resident = 0;
1677 namelength = buffer[pos + 9] & 255;
1678 attr->name_length = namelength;
1679 attr->name_offset = const_cpu_to_le16(0x18);
1680 memcpy(buffer + offs + length - 8 + 0x18,
1681 buffer + pos + 0x18, 2*namelength);
1682 attr->flags = const_cpu_to_le16(0);
1683 attr->value_length = const_cpu_to_le32(8);
1684 attr->value_offset = cpu_to_le16(2*namelength + 24);
1685 attr->resident_flags = 0;
1686 memcpy((char*)attr->resident_end + 2*namelength,
1687 bitmap, 8);
1688 /* Should we really take a new instance ? */
1689 attr->instance = record->next_attr_instance;
1690 instance = le16_to_cpu(record->next_attr_instance) + 1;
1691 record->next_attr_instance = cpu_to_le16(instance);
1692 err = sanity_mft(buffer);
1693 } else {
1694 printf("** index root does not match\n");
1695 err = 1;
1696 }
1697 }
1698 return (err);
1699 }
1700
1701 /*
1702 * Check whether a full MFT record is fed by an action
1703 *
1704 * If so, checking the validity of existing record is pointless
1705 */
1706
check_full_mft(const struct ACTION_RECORD * action,BOOL redoing)1707 static BOOL check_full_mft(const struct ACTION_RECORD *action, BOOL redoing)
1708 {
1709 const MFT_RECORD *record;
1710 const ATTR_RECORD *attr;
1711 u32 length;
1712 u32 k;
1713 BOOL ok;
1714
1715 if (redoing) {
1716 record = (const MFT_RECORD*)((const char*)&action->record
1717 + get_redo_offset(&action->record));
1718 length = le16_to_cpu(action->record.redo_length);
1719 } else {
1720 record = (const MFT_RECORD*)((const char*)&action->record
1721 + get_undo_offset(&action->record));
1722 length = le16_to_cpu(action->record.undo_length);
1723 }
1724 /* The length in use must be fed */
1725 ok = !action->record.record_offset
1726 && !action->record.attribute_offset
1727 && (record->magic == magic_FILE)
1728 && (length <= mftrecsz)
1729 && (length >= (offsetof(MFT_RECORD, bytes_in_use)
1730 + sizeof(record->bytes_in_use)));
1731 if (ok) {
1732 k = le16_to_cpu(record->attrs_offset);
1733 attr = (const ATTR_RECORD*)((const char*)record + k);
1734 while (((k + sizeof(attr->type)) <= length)
1735 && (attr->type != AT_END)
1736 && valid_type(attr->type)) {
1737 k += le32_to_cpu(attr->length);
1738 attr = (const ATTR_RECORD*)((const char*)record + k);
1739 }
1740 /* AT_END must be present */
1741 ok = ((k + sizeof(attr->type)) <= length)
1742 && (attr->type == AT_END);
1743 }
1744 return (ok);
1745 }
1746
1747 /*
1748 * Check whether a full index block is fed by the log record
1749 *
1750 * If so, checking the validity of existing record is pointless
1751 */
1752
check_full_index(const struct ACTION_RECORD * action,BOOL redoing)1753 static BOOL check_full_index(const struct ACTION_RECORD *action, BOOL redoing)
1754 {
1755 const INDEX_BLOCK *indx;
1756 u32 length;
1757
1758 if (redoing) {
1759 indx = (const INDEX_BLOCK*)((const char*)&action->record
1760 + get_redo_offset(&action->record));
1761 length = le16_to_cpu(action->record.redo_length);
1762 } else {
1763 indx = (const INDEX_BLOCK*)((const char*)&action->record
1764 + get_undo_offset(&action->record));
1765 length = le16_to_cpu(action->record.undo_length);
1766 }
1767 /* the index length must be fed, so must be the full index block */
1768 return (!action->record.record_offset
1769 && !action->record.attribute_offset
1770 && (indx->magic == magic_INDX)
1771 && (length >= (offsetof(INDEX_BLOCK, index.index_length) + 4))
1772 && (length >= (le32_to_cpu(indx->index.index_length) + 24)));
1773 }
1774
1775 /*
1776 * Create an index block for undoing its deletion
1777 *
1778 * This is useful for turning the clock backward, but cannot
1779 * work properly in the general case and must not be used for
1780 * a real sync.
1781 */
1782
create_indx(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)1783 static int create_indx(ntfs_volume *vol, const struct ACTION_RECORD *action,
1784 char *buffer)
1785 {
1786 INDEX_BLOCK *indx;
1787 INDEX_ENTRY_HEADER *ixhead;
1788 INDEX_ENTRY *ixentry;
1789 VCN vcn;
1790 int err;
1791
1792 if (opts) {
1793 printf("** Call to unsupported create_indx()\n");
1794 err = 1;
1795 } else {
1796 err = 0;
1797 indx = (INDEX_BLOCK*)buffer;
1798 indx->magic = magic_INDX;
1799 // TODO compute properly
1800 indx->usa_ofs = const_cpu_to_le16(0x28);
1801 indx->usa_count = const_cpu_to_le16(9);
1802 indx->lsn = action->record.this_lsn;
1803 vcn = sle64_to_cpu(action->record.target_vcn);
1804 /* beware of size change on big-endian cpus */
1805 indx->index_block_vcn = cpu_to_sle64(vcn);
1806 /* INDEX_HEADER */
1807 indx->index.entries_offset = const_cpu_to_le32(0x28);
1808 indx->index.index_length = const_cpu_to_le32(0x38);
1809 indx->index.allocated_size =
1810 cpu_to_le32(vol->indx_record_size - 24);
1811 indx->index.ih_flags = 0;
1812 /* INDEX_ENTRY_HEADER */
1813 ixhead = (INDEX_ENTRY_HEADER*)(buffer + 0x28);
1814 ixhead->length = cpu_to_le16(vol->indx_record_size - 24);
1815 /* terminating INDEX_ENTRY */
1816 ixentry = (INDEX_ENTRY*)(buffer + 0x40);
1817 ixentry->indexed_file = const_cpu_to_le64(0);
1818 ixentry->length = const_cpu_to_le16(16);
1819 ixentry->key_length = const_cpu_to_le16(0);
1820 ixentry->ie_flags = INDEX_ENTRY_END;
1821 }
1822 return (err);
1823 }
1824
redo_action37(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)1825 static int redo_action37(ntfs_volume *vol, const struct ACTION_RECORD *action,
1826 char *buffer)
1827 {
1828 u32 target;
1829 u32 length;
1830 int err;
1831
1832 if (optv > 1)
1833 printf("-> %s()\n",__func__);
1834 err = 1;
1835 length = le16_to_cpu(action->record.redo_length);
1836 target = le16_to_cpu(action->record.record_offset)
1837 + le16_to_cpu(action->record.attribute_offset);
1838 if (optv > 1) {
1839 printf("existing data :\n");
1840 dump(buffer + target,length);
1841 }
1842 if ((target + length) == mftrecsz) {
1843 memset(buffer + target, 0, length);
1844 err = write_protected(vol, &action->record,
1845 buffer, mftrecsz);
1846 if (optv > 1) {
1847 printf("-> MFT record trimmed\n");
1848 }
1849 } else {
1850 printf("** Bad action-37, inode %lld record :\n",
1851 (long long)inode_number(&action->record));
1852 printf("target %d length %d sum %d\n",
1853 (int)target,(int)length,(int)(target + length));
1854 dump(buffer,mftrecsz);
1855 }
1856 err = 0;
1857 return (err);
1858 }
1859
redo_add_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)1860 static int redo_add_index(ntfs_volume *vol, const struct ACTION_RECORD *action,
1861 char *buffer)
1862 {
1863 LCN lcn;
1864 const char *data;
1865 INDEX_BLOCK *indx;
1866 u32 target;
1867 u32 length;
1868 u32 xsize;
1869 u32 indexlth;
1870 int err;
1871 BOOL found;
1872
1873 if (optv > 1)
1874 printf("-> %s()\n",__func__);
1875 err = 1;
1876 data = ((const char*)&action->record)
1877 + get_redo_offset(&action->record);
1878 length = le16_to_cpu(action->record.redo_length);
1879 target = le16_to_cpu(action->record.record_offset)
1880 + le16_to_cpu(action->record.attribute_offset);
1881 if (optv > 1) {
1882 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1883 printf("-> lcn 0x%llx target 0x%x length %d\n",
1884 (long long)lcn, (int)target, (int)length);
1885 }
1886 xsize = vol->indx_record_size;
1887 indx = (INDEX_BLOCK*)(buffer
1888 + le16_to_cpu(action->record.record_offset));
1889 if (optv > 1) {
1890 printf("-> existing record :\n");
1891 dump(&buffer[target], length);
1892 }
1893 if ((indx->magic == magic_INDX)
1894 && !(length & 7)
1895 && ((target + length) <= xsize)) {
1896 /* This has to be an idempotent action */
1897 found = !memcmp(buffer + target, data, length);
1898 err = 0;
1899 if (!found) {
1900 /* Make space to insert the entry */
1901 memmove(buffer + target + length,
1902 buffer + target,
1903 xsize - target - length);
1904 memcpy(buffer + target, data, length);
1905 indexlth = le32_to_cpu(indx->index.index_length)
1906 + length;
1907 indx->index.index_length = cpu_to_le32(indexlth);
1908 if (optv > 1) {
1909 printf("-> inserted record :\n");
1910 dump(&buffer[target], length);
1911 }
1912 err = write_protected(vol, &action->record,
1913 buffer, xsize);
1914 }
1915 if (optv > 1) {
1916 printf("-> INDX record %s\n",
1917 (found ? "unchanged" : "inserted"));
1918 }
1919 }
1920 return (err);
1921 }
1922
redo_add_root_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)1923 static int redo_add_root_index(ntfs_volume *vol,
1924 const struct ACTION_RECORD *action, char *buffer)
1925 {
1926 LCN lcn;
1927 const char *data;
1928 ATTR_RECORD *attr;
1929 MFT_RECORD *entry;
1930 INDEX_ROOT *index;
1931 u32 target;
1932 u32 length;
1933 int err;
1934 BOOL found;
1935
1936 if (optv > 1)
1937 printf("-> %s()\n",__func__);
1938 err = 1;
1939 data = ((const char*)&action->record)
1940 + get_redo_offset(&action->record);
1941 length = le16_to_cpu(action->record.redo_length);
1942 target = le16_to_cpu(action->record.record_offset)
1943 + le16_to_cpu(action->record.attribute_offset);
1944 if (optv > 1) {
1945 lcn = sle64_to_cpu(action->record.lcn_list[0]);
1946 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
1947 (long long)inode_number(&action->record),
1948 (long long)lcn, (int)target, (int)length);
1949 }
1950 entry = (MFT_RECORD*)buffer;
1951 attr = (ATTR_RECORD*)(buffer
1952 + le16_to_cpu(action->record.record_offset));
1953 index = (INDEX_ROOT*)(((char*)attr)
1954 + le16_to_cpu(attr->value_offset));
1955 if (optv > 1) {
1956 printf("existing index :\n");
1957 dump(buffer + target,length);
1958 }
1959 if ((attr->type == AT_INDEX_ROOT)
1960 && !(length & 7)
1961 && ((target + length) <= mftrecsz)) {
1962 /* This has to be an idempotent action */
1963 found = !memcmp(buffer + target, data, length);
1964 err = 0;
1965 if (!found) {
1966 /* Make space to insert the entry */
1967 memmove(buffer + target + length,
1968 buffer + target,
1969 mftrecsz - target - length);
1970 memcpy(buffer + target, data, length);
1971 resize_attribute(entry, attr, index, length, length);
1972 if (optv > 1) {
1973 printf("new index at same location :\n");
1974 dump(buffer + target, length);
1975 }
1976 err = write_protected(vol, &action->record,
1977 buffer, mftrecsz);
1978 }
1979 if (optv > 1) {
1980 printf("-> MFT record %s\n",
1981 (found ? "unchanged" : "expanded"));
1982 }
1983 }
1984 return (err);
1985 }
1986
redo_compensate(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)1987 static int redo_compensate(ntfs_volume *vol __attribute__((unused)),
1988 const struct ACTION_RECORD *action,
1989 char *buffer __attribute__((unused)))
1990 {
1991 u64 lsn;
1992 s64 diff;
1993
1994 if (optv > 1)
1995 printf("-> %s()\n",__func__);
1996 lsn = sle64_to_cpu(action->record.this_lsn);
1997 diff = lsn - restart_lsn;
1998 if (diff > 0)
1999 restart_lsn = lsn;
2000 return (0);
2001 }
2002
redo_create_file(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2003 static int redo_create_file(ntfs_volume *vol,
2004 const struct ACTION_RECORD *action, char *buffer)
2005 {
2006 LCN lcn;
2007 const char *data;
2008 MFT_RECORD *record;
2009 u32 target;
2010 u32 length;
2011 int err;
2012 int changed;
2013
2014 if (optv > 1)
2015 printf("-> %s()\n",__func__);
2016 err = 1;
2017 data = ((const char*)&action->record)
2018 + get_redo_offset(&action->record);
2019 length = le16_to_cpu(action->record.redo_length);
2020 target = le16_to_cpu(action->record.record_offset)
2021 + le16_to_cpu(action->record.attribute_offset);
2022 if (optv > 1) {
2023 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2024 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
2025 (long long)inode_number(&action->record),
2026 (long long)lcn, (int)target, (int)length);
2027 }
2028 record = (MFT_RECORD*)buffer;
2029 if (optv > 1) {
2030 printf("-> existing record :\n");
2031 dump(buffer,mftrecsz);
2032 }
2033 if ((target + length) <= mftrecsz) {
2034 changed = memcmp(buffer + target, data, length);
2035 err = 0;
2036 if (changed || !(record->flags & MFT_RECORD_IN_USE)) {
2037 memcpy(buffer + target, data, length);
2038 record->flags |= MFT_RECORD_IN_USE;
2039 if (optv > 1) {
2040 printf("-> new record :\n");
2041 dump(buffer,mftrecsz);
2042 }
2043 err = write_protected(vol, &action->record,
2044 buffer, mftrecsz);
2045 }
2046 if (optv > 1) {
2047 printf("-> MFT record %s\n",
2048 (changed ? "updated" : "unchanged"));
2049 }
2050 } else {
2051 err = 1; /* record overflows */
2052 }
2053 return (err);
2054 }
2055
redo_create_attribute(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2056 static int redo_create_attribute(ntfs_volume *vol,
2057 const struct ACTION_RECORD *action, char *buffer)
2058 {
2059 const char *data;
2060 u32 target;
2061 u32 length;
2062 int err;
2063
2064 if (optv > 1)
2065 printf("-> %s()\n",__func__);
2066 err = 1;
2067 data = ((const char*)&action->record)
2068 + get_redo_offset(&action->record);
2069 length = le16_to_cpu(action->record.redo_length);
2070 target = le16_to_cpu(action->record.record_offset)
2071 + le16_to_cpu(action->record.attribute_offset);
2072 // Could also be AT_DATA or AT_INDEX_ALLOCATION
2073 if (!action->record.undo_length)
2074 err = insert_resident(vol, action, buffer, data,
2075 target, length);
2076 return (err);
2077 }
2078
redo_delete_attribute(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2079 static int redo_delete_attribute(ntfs_volume *vol,
2080 const struct ACTION_RECORD *action, char *buffer)
2081 {
2082 const char *data;
2083 u32 target;
2084 u32 length;
2085 int err;
2086
2087 if (optv > 1)
2088 printf("-> %s()\n",__func__);
2089 err = 1;
2090 data = ((const char*)&action->record)
2091 + get_undo_offset(&action->record);
2092 length = le16_to_cpu(action->record.undo_length);
2093 target = le16_to_cpu(action->record.record_offset)
2094 + le16_to_cpu(action->record.attribute_offset);
2095 if (!action->record.redo_length)
2096 err = remove_resident(vol, action, buffer, data,
2097 target, length);
2098 return (err);
2099 }
2100
redo_delete_file(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2101 static int redo_delete_file(ntfs_volume *vol,
2102 const struct ACTION_RECORD *action, char *buffer)
2103 {
2104 LCN lcn;
2105 const char *data;
2106 MFT_RECORD *record;
2107 u32 target;
2108 u32 length;
2109 int err;
2110 int changed;
2111
2112 if (optv > 1)
2113 printf("-> %s()\n",__func__);
2114 err = 1;
2115 data = ((const char*)&action->record)
2116 + get_undo_offset(&action->record);
2117 length = le16_to_cpu(action->record.undo_length);
2118 target = le16_to_cpu(action->record.record_offset)
2119 + le16_to_cpu(action->record.attribute_offset);
2120 if (optv > 1) {
2121 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2122 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
2123 (long long)inode_number(&action->record),
2124 (long long)lcn, (int)target, (int)length);
2125 }
2126 if (optv > 1) {
2127 printf("-> existing record :\n");
2128 dump(buffer,mftrecsz);
2129 }
2130 record = (MFT_RECORD*)buffer;
2131 if ((target + length) <= mftrecsz) {
2132 /* write a void mft entry (needed ?) */
2133 changed = (length && memcmp(buffer + target, data, length))
2134 || (record->flags & MFT_RECORD_IN_USE);
2135 err = 0;
2136 if (changed) {
2137 memcpy(buffer + target, data, length);
2138 record->flags &= ~MFT_RECORD_IN_USE;
2139 if (optv > 1) {
2140 printf("-> new record :\n");
2141 dump(buffer,mftrecsz);
2142 }
2143 err = write_protected(vol, &action->record,
2144 buffer, mftrecsz);
2145 }
2146 if (optv > 1) {
2147 printf("-> MFT record %s\n",
2148 (changed ? "updated" : "unchanged"));
2149 }
2150 }
2151 return (err);
2152 }
2153
redo_delete_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2154 static int redo_delete_index(ntfs_volume *vol,
2155 const struct ACTION_RECORD *action, char *buffer)
2156 {
2157 LCN lcn;
2158 const char *data;
2159 INDEX_BLOCK *indx;
2160 u32 target;
2161 u32 length;
2162 u32 xsize;
2163 u32 indexlth;
2164 int err;
2165 BOOL found;
2166
2167 if (optv > 1)
2168 printf("-> %s()\n",__func__);
2169 err = 1;
2170 data = ((const char*)&action->record)
2171 + get_undo_offset(&action->record);
2172 length = le16_to_cpu(action->record.undo_length);
2173 target = le16_to_cpu(action->record.record_offset)
2174 + le16_to_cpu(action->record.attribute_offset);
2175 if (optv > 1) {
2176 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2177 printf("-> lcn 0x%llx target 0x%x length %d\n",
2178 (long long)lcn, (int)target, (int)length);
2179 }
2180 xsize = vol->indx_record_size;
2181 indx = (INDEX_BLOCK*)(buffer
2182 + le16_to_cpu(action->record.record_offset));
2183 if (optv > 1) {
2184 printf("-> existing record :\n");
2185 dump(&buffer[target], length);
2186 }
2187 if ((indx->magic == magic_INDX)
2188 && !(length & 7)
2189 && ((target + length) <= xsize)) {
2190 /* This has to be an idempotent action */
2191 found = (action->record.undo_operation
2192 == const_cpu_to_le16(CompensationlogRecord))
2193 || !memcmp(buffer + target, data, length);
2194 err = 0;
2195 if (found) {
2196 /* Remove the entry */
2197 memmove(buffer + target,
2198 buffer + target + length,
2199 xsize - target - length);
2200 indexlth = le32_to_cpu(indx->index.index_length)
2201 - length;
2202 indx->index.index_length = cpu_to_le32(indexlth);
2203 err = write_protected(vol, &action->record,
2204 buffer, xsize);
2205 }
2206 if (optv > 1) {
2207 printf("-> INDX record %s\n",
2208 (found ? "removed" : "unchanged"));
2209 }
2210 }
2211 return (err);
2212 }
2213
redo_delete_root_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2214 static int redo_delete_root_index(ntfs_volume *vol,
2215 const struct ACTION_RECORD *action, char *buffer)
2216 {
2217 LCN lcn;
2218 const char *data;
2219 ATTR_RECORD *attr;
2220 MFT_RECORD *entry;
2221 INDEX_ROOT *index;
2222 BOOL found;
2223 u32 target;
2224 u32 length;
2225 int err;
2226
2227 if (optv > 1)
2228 printf("-> %s()\n",__func__);
2229 err = 1;
2230 data = ((const char*)&action->record)
2231 + get_undo_offset(&action->record);
2232 length = le16_to_cpu(action->record.undo_length);
2233 target = le16_to_cpu(action->record.record_offset)
2234 + le16_to_cpu(action->record.attribute_offset);
2235
2236 if (optv > 1) {
2237 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2238 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
2239 (long long)inode_number(&action->record),
2240 (long long)lcn, (int)target, (int)length);
2241 }
2242 entry = (MFT_RECORD*)buffer;
2243 attr = (ATTR_RECORD*)(buffer
2244 + le16_to_cpu(action->record.record_offset));
2245 index = (INDEX_ROOT*)(((char*)attr)
2246 + le16_to_cpu(attr->value_offset));
2247 if (optv > 1) {
2248 printf("existing index :\n");
2249 dump(buffer + target,length);
2250 }
2251 if ((attr->type == AT_INDEX_ROOT)
2252 && !(length & 7)
2253 && ((target + length) <= mftrecsz)) {
2254 /* This has to be an idempotent action */
2255 found = (action->record.undo_operation
2256 == const_cpu_to_le16(CompensationlogRecord))
2257 || !memcmp(buffer + target, data, length);
2258 err = 0;
2259 /* Only delete if present */
2260 if (found) {
2261 /* Remove the entry */
2262 memmove(buffer + target,
2263 buffer + target + length,
2264 mftrecsz - target - length);
2265 resize_attribute(entry, attr, index, -length, -length);
2266 if (optv > 1) {
2267 printf("new index at same location :\n");
2268 dump(buffer + target, length);
2269 }
2270 err = write_protected(vol, &action->record,
2271 buffer, mftrecsz);
2272 }
2273 if (optv > 1) {
2274 printf("-> MFT record %s\n",
2275 (found ? "shrinked" : "updated"));
2276 }
2277 }
2278 return (err);
2279 }
2280
redo_force_bits(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2281 static int redo_force_bits(ntfs_volume *vol,
2282 const struct ACTION_RECORD *action, char *buffer)
2283 {
2284 LCN lcn;
2285 const struct BITMAP_ACTION *data;
2286 u32 i;
2287 int err;
2288 int wanted;
2289 u32 firstbit;
2290 u32 count;
2291
2292 if (optv > 1)
2293 printf("-> %s()\n",__func__);
2294 err = 1;
2295 data = (const struct BITMAP_ACTION*)
2296 (((const char*)&action->record)
2297 + get_redo_offset(&action->record));
2298 firstbit = le32_to_cpu(data->firstbit);
2299 count = le32_to_cpu(data->count);
2300 if (action->record.redo_operation
2301 == const_cpu_to_le16(SetBitsInNonResidentBitMap))
2302 wanted = 1;
2303 else
2304 wanted = 0;
2305 // TODO consistency undo_offset == redo_offset, etc.
2306 // firstbit + count < 8*clustersz (multiple clusters possible ?)
2307 if (optv > 1) {
2308 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2309 printf("-> lcn 0x%llx firstbit %d count %d wanted %d\n",
2310 (long long)lcn,(int)firstbit,(int)count,(int)wanted);
2311 }
2312 for (i=0; i<count; i++)
2313 ntfs_bit_set((u8*)buffer, firstbit + i, wanted);
2314 if (!write_raw(vol, &action->record, buffer)) {
2315 err = 0;
2316 if (optv > 1)
2317 printf("-> record updated\n");
2318 }
2319 if (err)
2320 printf("** redo_clearbits failed\n");
2321 return (err);
2322 }
2323
redo_open_attribute(ntfs_volume * vol,const struct ACTION_RECORD * action)2324 static int redo_open_attribute(ntfs_volume *vol __attribute__((unused)),
2325 const struct ACTION_RECORD *action)
2326 {
2327 const char *data;
2328 struct ATTR *pa;
2329 const ATTR_OLD *attr_old;
2330 const ATTR_NEW *attr_new;
2331 const char *name;
2332 le64 inode;
2333 u32 namelen;
2334 u32 length;
2335 u32 extra;
2336 int err;
2337
2338 if (optv > 1)
2339 printf("-> %s()\n",__func__);
2340 err = 1;
2341 data = ((const char*)&action->record)
2342 + get_redo_offset(&action->record);
2343 length = le16_to_cpu(action->record.redo_length);
2344 extra = get_extra_offset(&action->record);
2345 if (action->record.undo_length) {
2346 name = ((const char*)&action->record) + extra;
2347 namelen = le32_to_cpu(action->record.client_data_length)
2348 + LOG_RECORD_HEAD_SZ - extra;
2349 /* fix namelen which was aligned modulo 8 */
2350 namelen = fixnamelen(name, namelen);
2351 if (optv > 1) {
2352 printf("-> length %d namelen %d",(int)length,
2353 (int)namelen);
2354 showname(", ", name, namelen/2);
2355 }
2356 } else {
2357 name = "";
2358 namelen = 0;
2359 }
2360 pa = getattrentry(le16_to_cpu(action->record.target_attribute),0);
2361 if (pa) {
2362 if (optv) {
2363 /*
2364 * If the actions have been displayed, the
2365 * attribute has already been fed. Check
2366 * whether it matches what we have in store.
2367 */
2368 switch (length) {
2369 case sizeof(ATTR_OLD) :
2370 attr_old = (const ATTR_OLD*)data;
2371 /* Badly aligned */
2372 memcpy(&inode, &attr_old->inode, 8);
2373 err = (MREF(le64_to_cpu(inode)) != pa->inode)
2374 || (attr_old->type != pa->type);
2375 break;
2376 case sizeof(ATTR_NEW) :
2377 attr_new = (const ATTR_NEW*)data;
2378 err = (MREF(le64_to_cpu(attr_new->inode))
2379 != pa->inode)
2380 || (attr_new->type != pa->type);
2381 break;
2382 default : err = 1;
2383 }
2384 if (!err) {
2385 err = (namelen != pa->namelen)
2386 || (namelen
2387 && memcmp(name, pa->name, namelen));
2388 }
2389 if (optv > 1)
2390 printf("-> attribute %s the recorded one\n",
2391 (err ? "does not match" : "matches"));
2392 } else {
2393 copy_attribute(pa, data, length);
2394 pa->namelen = namelen;
2395 if (namelen)
2396 memcpy(pa->name, data, namelen);
2397 err = 0;
2398 }
2399 } else
2400 if (optv)
2401 printf("* Unrecorded attribute\n");
2402 return (err);
2403 }
2404
redo_sizes(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2405 static int redo_sizes(ntfs_volume *vol, const struct ACTION_RECORD *action,
2406 char *buffer)
2407 {
2408 const char *data;
2409 u32 target;
2410 u32 length;
2411 int err;
2412
2413 if (optv > 1)
2414 printf("-> %s()\n",__func__);
2415 err = 1;
2416 data = ((const char*)&action->record)
2417 + get_redo_offset(&action->record);
2418 length = le16_to_cpu(action->record.redo_length);
2419 target = le16_to_cpu(action->record.record_offset)
2420 + le16_to_cpu(action->record.attribute_offset)
2421 + offsetof(ATTR_RECORD, allocated_size);
2422 err = change_resident(vol, action, buffer,
2423 data, target, length);
2424 return (err);
2425 }
2426
redo_update_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2427 static int redo_update_index(ntfs_volume *vol,
2428 const struct ACTION_RECORD *action, char *buffer)
2429 {
2430 const char *data;
2431 u32 target;
2432 u32 length;
2433 int err;
2434
2435 if (optv > 1)
2436 printf("-> %s()\n",__func__);
2437 err = 1;
2438 data = ((const char*)&action->record)
2439 + get_redo_offset(&action->record);
2440 length = le16_to_cpu(action->record.redo_length);
2441 /* target is left-justified to creation time */
2442 target = le16_to_cpu(action->record.record_offset)
2443 + le16_to_cpu(action->record.attribute_offset)
2444 + offsetof(INDEX_ENTRY, key.file_name.creation_time);
2445 err = update_index(vol, action, buffer, data, target, length);
2446 return (err);
2447 }
2448
redo_update_index_value(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2449 static int redo_update_index_value(ntfs_volume *vol,
2450 const struct ACTION_RECORD *action, char *buffer)
2451 {
2452 const char *data;
2453 u32 length;
2454 u32 target;
2455 int err;
2456
2457 if (optv > 1)
2458 printf("-> %s()\n",__func__);
2459 err = 1;
2460 data = ((const char*)&action->record)
2461 + get_redo_offset(&action->record);
2462 length = le16_to_cpu(action->record.redo_length);
2463 target = le16_to_cpu(action->record.record_offset)
2464 + le16_to_cpu(action->record.attribute_offset);
2465 err = change_index_value(vol, action, buffer, data, target, length);
2466 return (err);
2467 }
2468
redo_update_mapping(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2469 static int redo_update_mapping(ntfs_volume *vol,
2470 const struct ACTION_RECORD *action, char *buffer)
2471 {
2472 LCN lcn;
2473 const char *data;
2474 ATTR_RECORD *attr;
2475 MFT_RECORD *entry;
2476 u32 target;
2477 u32 length;
2478 u32 source;
2479 u32 alen;
2480 u32 newused;
2481 int resize;
2482 int err;
2483 int changed;
2484
2485 if (optv > 1)
2486 printf("-> %s()\n",__func__);
2487 err = 1;
2488 data = ((const char*)&action->record)
2489 + get_redo_offset(&action->record);
2490 length = le16_to_cpu(action->record.redo_length);
2491 resize = length - le16_to_cpu(action->record.undo_length);
2492 target = le16_to_cpu(action->record.record_offset)
2493 + le16_to_cpu(action->record.attribute_offset);
2494 if (optv > 1) {
2495 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2496 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
2497 (long long)inode_number(&action->record),
2498 (long long)lcn, (int)target, (int)length);
2499 }
2500 if (optv > 1) {
2501 printf("-> existing record :\n");
2502 dump(&buffer[target], length);
2503 }
2504 entry = (MFT_RECORD*)buffer;
2505 attr = (ATTR_RECORD*)(buffer
2506 + le16_to_cpu(action->record.record_offset));
2507 if (!attr->non_resident) {
2508 printf("** Error : update_mapping on resident attr\n");
2509 }
2510 if (valid_type(attr->type)
2511 && attr->non_resident
2512 && !(resize & 7)
2513 && ((target + length) <= mftrecsz)) {
2514 changed = memcmp(buffer + target, data, length);
2515 err = 0;
2516 if (changed) {
2517 /* Adjust space for new mapping pairs */
2518 source = target - resize;
2519 if (resize > 0) {
2520 memmove(buffer + target + length,
2521 buffer + source + length,
2522 mftrecsz - target - length);
2523 }
2524 if (resize < 0) {
2525 memmove(buffer + target + length,
2526 buffer + source + length,
2527 mftrecsz - source - length);
2528 }
2529 memcpy(buffer + target, data, length);
2530 /* Resize the attribute */
2531 alen = le32_to_cpu(attr->length) + resize;
2532 attr->length = cpu_to_le32(alen);
2533 /* Resize the mft record */
2534 newused = le32_to_cpu(entry->bytes_in_use)
2535 + resize;
2536 entry->bytes_in_use = cpu_to_le32(newused);
2537 /* Compute the new highest_vcn */
2538 err = adjust_high_vcn(vol, attr);
2539 if (optv > 1) {
2540 printf("-> new record :\n");
2541 dump(buffer + target, length);
2542 }
2543 if (!err) {
2544 err = write_protected(vol,
2545 &action->record,
2546 buffer, mftrecsz);
2547 }
2548 }
2549 if (optv > 1) {
2550 printf("-> MFT record %s\n",
2551 (changed ? "updated" : "unchanged"));
2552 }
2553 }
2554 return (err);
2555 }
2556
redo_update_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2557 static int redo_update_resident(ntfs_volume *vol,
2558 const struct ACTION_RECORD *action, char *buffer)
2559 {
2560 LCN lcn;
2561 const char *data;
2562 u32 target;
2563 u32 length;
2564 u32 oldlength;
2565 u32 end;
2566 u32 redo;
2567 int err;
2568 int changed;
2569
2570 if (optv > 1)
2571 printf("-> %s()\n",__func__);
2572 err = 1;
2573 end = le32_to_cpu(action->record.client_data_length)
2574 + LOG_RECORD_HEAD_SZ;
2575 length = le16_to_cpu(action->record.redo_length);
2576 redo = get_redo_offset(&action->record);
2577 if ((redo + length) > end)
2578 data = (char*)NULL;
2579 else
2580 data = ((const char*)&action->record) + redo;
2581 oldlength = le16_to_cpu(action->record.undo_length);
2582 target = le16_to_cpu(action->record.record_offset)
2583 + le16_to_cpu(action->record.attribute_offset);
2584 if (length == oldlength) {
2585 if (optv > 1) {
2586 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2587 printf("-> inode %lld lcn 0x%llx target 0x%x"
2588 " length %d\n",
2589 (long long)inode_number(&action->record),
2590 (long long)lcn, (int)target, (int)length);
2591 }
2592 if (optv > 1) {
2593 printf("-> existing record :\n");
2594 dump(&buffer[target], length);
2595 }
2596 if ((target + length) <= mftrecsz) {
2597 changed = (action->record.undo_operation
2598 == const_cpu_to_le16(CompensationlogRecord))
2599 || memcmp(buffer + target, data, length);
2600 err = 0;
2601 if (changed) {
2602 memcpy(buffer + target, data, length);
2603 if (optv > 1) {
2604 printf("-> new record :\n");
2605 dump(buffer + target, length);
2606 }
2607 err = write_protected(vol, &action->record,
2608 buffer, mftrecsz);
2609 }
2610 if (optv > 1) {
2611 printf("-> MFT record %s\n",
2612 (changed ? "updated" : "unchanged"));
2613 }
2614 }
2615 } else {
2616 if (length > oldlength)
2617 err = expand_resident(vol, action, buffer, data,
2618 target, length, oldlength);
2619 else
2620 err = shrink_resident(vol, action, buffer, data,
2621 target, length, oldlength);
2622 }
2623 return (err);
2624 }
2625
redo_update_root_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2626 static int redo_update_root_index(ntfs_volume *vol,
2627 const struct ACTION_RECORD *action, char *buffer)
2628 {
2629 const char *data;
2630 const char *expected;
2631 u32 target;
2632 u32 length;
2633 int err;
2634
2635 if (optv > 1)
2636 printf("-> %s()\n",__func__);
2637 err = 1;
2638 data = ((const char*)&action->record)
2639 + get_redo_offset(&action->record);
2640 expected = ((const char*)&action->record)
2641 + get_undo_offset(&action->record);
2642 length = le16_to_cpu(action->record.redo_length);
2643 /* the fixup is right-justified to the name length */
2644 target = le16_to_cpu(action->record.record_offset)
2645 + le16_to_cpu(action->record.attribute_offset)
2646 + offsetof(INDEX_ENTRY, key.file_name.file_name_length)
2647 - length;
2648 if (action->record.undo_operation
2649 == const_cpu_to_le16(CompensationlogRecord))
2650 err = change_resident(vol, action, buffer, data,
2651 target, length);
2652 else
2653 err = change_resident_expect(vol, action, buffer, data,
2654 expected, target, length, AT_INDEX_ROOT);
2655 return (err);
2656 }
2657
redo_update_root_vcn(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2658 static int redo_update_root_vcn(ntfs_volume *vol,
2659 const struct ACTION_RECORD *action, char *buffer)
2660 {
2661 const char *data;
2662 const char *expected;
2663 u32 target;
2664 u32 length;
2665 int err;
2666
2667 if (optv > 1)
2668 printf("-> %s()\n",__func__);
2669 err = 1;
2670 data = ((const char*)&action->record)
2671 + get_redo_offset(&action->record);
2672 expected = ((const char*)&action->record)
2673 + get_undo_offset(&action->record);
2674 length = le16_to_cpu(action->record.redo_length);
2675 if (length == 8) {
2676 target = le16_to_cpu(action->record.record_offset)
2677 + le16_to_cpu(action->record.attribute_offset);
2678 /* target is right-justified to end of attribute */
2679 target += getle16(buffer, target + 8) - length;
2680 err = change_resident_expect(vol, action, buffer, data,
2681 expected, target, length, AT_INDEX_ROOT);
2682 }
2683 return (err);
2684 }
2685
redo_update_value(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2686 static int redo_update_value(ntfs_volume *vol,
2687 const struct ACTION_RECORD *action, char *buffer)
2688 {
2689 LCN lcn;
2690 const char *data;
2691 u32 length;
2692 u32 target;
2693 u32 count;
2694 u32 redo;
2695 u32 end;
2696 u32 i;
2697 int changed;
2698 int err;
2699
2700 if (optv > 1)
2701 printf("-> %s()\n",__func__);
2702 err = 1;
2703 length = le16_to_cpu(action->record.redo_length);
2704 redo = get_redo_offset(&action->record);
2705 end = le32_to_cpu(action->record.client_data_length)
2706 + LOG_RECORD_HEAD_SZ;
2707 /* sometimes there is no redo data */
2708 if ((redo + length) > end)
2709 data = (char*)NULL;
2710 else
2711 data = ((const char*)&action->record) + redo;
2712 target = le16_to_cpu(action->record.record_offset)
2713 + le16_to_cpu(action->record.attribute_offset);
2714 count = le16_to_cpu(action->record.lcns_to_follow);
2715 if (optv > 1) {
2716 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2717 printf("-> lcn 0x%llx target 0x%x length %d\n",
2718 (long long)lcn, (int)target, (int)length);
2719 }
2720 if (optv > 1) {
2721 printf("-> existing record :\n");
2722 dump(&buffer[target], length);
2723 }
2724 if ((target + length) <= (count << clusterbits)) {
2725 if (data)
2726 changed = memcmp(buffer + target, data, length);
2727 else {
2728 for (i=0; (i<length) && !buffer[target+i]; i++) { }
2729 changed = length && (i < length);
2730 }
2731 err = 0;
2732 if (changed) {
2733 if (data)
2734 memcpy(buffer + target, data, length);
2735 else
2736 memset(buffer + target, 0, length);
2737 if (optv > 1) {
2738 printf("-> new record :\n");
2739 dump(buffer + target, length);
2740 }
2741 err = write_raw(vol, &action->record, buffer);
2742 }
2743 if (optv > 1) {
2744 printf("-> data record %s\n",
2745 (changed ? "updated" : "unchanged"));
2746 }
2747 }
2748
2749 return (err);
2750 }
2751
redo_update_vcn(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2752 static int redo_update_vcn(ntfs_volume *vol,
2753 const struct ACTION_RECORD *action, char *buffer)
2754 {
2755 const char *data;
2756 u32 target;
2757 u32 length;
2758 int err;
2759
2760 if (optv > 1)
2761 printf("-> %s()\n",__func__);
2762 err = 1;
2763 data = ((const char*)&action->record)
2764 + get_redo_offset(&action->record);
2765 length = le16_to_cpu(action->record.redo_length);
2766 if (length == 8) {
2767 target = le16_to_cpu(action->record.record_offset)
2768 + le16_to_cpu(action->record.attribute_offset);
2769 /* target is right-justified to end of attribute */
2770 target += getle16(buffer, target + 8) - length;
2771 err = update_index(vol, action, buffer, data, target, length);
2772 }
2773 return (err);
2774 }
2775
redo_write_end(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2776 static int redo_write_end(ntfs_volume *vol,
2777 const struct ACTION_RECORD *action, char *buffer)
2778 {
2779 LCN lcn;
2780 const char *data;
2781 u32 target;
2782 u32 length;
2783 u32 oldlength;
2784 u32 end;
2785 u32 redo;
2786 int err;
2787 int changed;
2788
2789 if (optv > 1)
2790 printf("-> %s()\n",__func__);
2791 err = 1;
2792 end = le32_to_cpu(action->record.client_data_length)
2793 + LOG_RECORD_HEAD_SZ;
2794 length = le16_to_cpu(action->record.redo_length);
2795 redo = get_redo_offset(&action->record);
2796 if ((redo + length) > end)
2797 data = (char*)NULL;
2798 else
2799 data = ((const char*)&action->record) + redo;
2800 oldlength = le16_to_cpu(action->record.undo_length);
2801 target = le16_to_cpu(action->record.record_offset)
2802 + le16_to_cpu(action->record.attribute_offset);
2803 if (length == oldlength) {
2804 if (optv > 1) {
2805 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2806 printf("-> inode %lld lcn 0x%llx target 0x%x"
2807 " length %d\n",
2808 (long long)inode_number(&action->record),
2809 (long long)lcn, (int)target, (int)length);
2810 }
2811 if (optv > 1) {
2812 printf("-> existing record :\n");
2813 dump(&buffer[target], length);
2814 }
2815 if ((target + length) <= mftrecsz) {
2816 changed = memcmp(buffer + target, data, length);
2817 err = 0;
2818 if (changed) {
2819 memcpy(buffer + target, data, length);
2820 if (optv > 1) {
2821 printf("-> new record :\n");
2822 dump(buffer + target, length);
2823 }
2824 err = write_protected(vol, &action->record,
2825 buffer, mftrecsz);
2826 }
2827 if (optv > 1) {
2828 printf("-> MFT record %s\n",
2829 (changed ? "updated" : "unchanged"));
2830 }
2831 }
2832 } else {
2833 if (length > oldlength)
2834 err = add_resident(vol, action, buffer, data,
2835 target, length, oldlength);
2836 else
2837 err = delete_resident(vol, action, buffer, data,
2838 target, length, oldlength);
2839 }
2840 return (err);
2841 }
2842
redo_write_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2843 static int redo_write_index(ntfs_volume *vol,
2844 const struct ACTION_RECORD *action, char *buffer)
2845 {
2846 LCN lcn;
2847 const char *data;
2848 INDEX_BLOCK *indx;
2849 u32 target;
2850 u32 length;
2851 u32 xsize;
2852 int err;
2853 int changed;
2854
2855 if (optv > 1)
2856 printf("-> %s()\n",__func__);
2857 err = 1;
2858 data = ((const char*)&action->record)
2859 + get_redo_offset(&action->record);
2860 length = le16_to_cpu(action->record.redo_length);
2861 /* target is left-justified to creation time */
2862 target = le16_to_cpu(action->record.record_offset)
2863 + le16_to_cpu(action->record.attribute_offset);
2864 if (optv > 1) {
2865 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2866 printf("-> lcn 0x%llx target 0x%x length %d\n",
2867 (long long)lcn, (int)target, (int)length);
2868 }
2869 xsize = vol->indx_record_size;
2870 indx = (INDEX_BLOCK*)buffer;
2871 if (action->record.record_offset) {
2872 printf("** Non-null record_offset in redo_write_index()\n");
2873 }
2874 if (optv > 1) {
2875 printf("-> existing index :\n");
2876 dump(&buffer[target], length);
2877 }
2878 if ((indx->magic == magic_INDX)
2879 && !(length & 7)
2880 && ((target + length) <= xsize)) {
2881 /* This has to be an idempotent action */
2882 changed = memcmp(buffer + target, data, length);
2883 err = 0;
2884 if (changed) {
2885 /* Update the entry */
2886 memcpy(buffer + target, data, length);
2887 /* If truncating, set the new size */
2888 indx->index.index_length =
2889 cpu_to_le32(target + length - 0x18);
2890 if (optv > 1) {
2891 printf("-> new index :\n");
2892 dump(&buffer[target], length);
2893 }
2894 err = write_protected(vol, &action->record,
2895 buffer, xsize);
2896 }
2897 if (optv > 1) {
2898 printf("-> INDX record %s\n",
2899 (changed ? "updated" : "unchanged"));
2900 }
2901 }
2902 return (err);
2903 }
2904
undo_action37(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2905 static int undo_action37(ntfs_volume *vol __attribute__((unused)),
2906 const struct ACTION_RECORD *action,
2907 char *buffer __attribute__((unused)))
2908 {
2909 /*
2910 const char *data;
2911 u32 target;
2912 u32 length;
2913 */
2914 int err;
2915
2916 if (optv > 1)
2917 printf("-> %s()\n",__func__);
2918 err = 1;
2919 /*
2920 data = ((const char*)&action->record)
2921 + get_redo_offset(&action->record);
2922 length = le16_to_cpu(action->record.redo_length);
2923 target = le16_to_cpu(action->record.record_offset)
2924 + le16_to_cpu(action->record.attribute_offset);
2925 */
2926 printf("* Ignored action-37, inode %lld record :\n",
2927 (long long)inode_number(&action->record));
2928 err = 0;
2929 return (err);
2930 }
2931
undo_add_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2932 static int undo_add_index(ntfs_volume *vol,
2933 const struct ACTION_RECORD *action, char *buffer)
2934 {
2935 LCN lcn;
2936 const char *data;
2937 INDEX_BLOCK *indx;
2938 u32 target;
2939 u32 length;
2940 u32 xsize;
2941 u32 indexlth;
2942 int err;
2943 BOOL found;
2944
2945 if (optv > 1)
2946 printf("-> %s()\n",__func__);
2947 err = 1;
2948 data = ((const char*)&action->record)
2949 + get_redo_offset(&action->record);
2950 length = le16_to_cpu(action->record.redo_length);
2951 target = le16_to_cpu(action->record.record_offset)
2952 + le16_to_cpu(action->record.attribute_offset);
2953 if (optv > 1) {
2954 lcn = sle64_to_cpu(action->record.lcn_list[0]);
2955 printf("-> lcn 0x%llx target 0x%x length %d\n",
2956 (long long)lcn, (int)target, (int)length);
2957 }
2958 xsize = vol->indx_record_size;
2959 indx = (INDEX_BLOCK*)(buffer
2960 + le16_to_cpu(action->record.record_offset));
2961 if (optv > 1) {
2962 printf("-> existing record :\n");
2963 dump(&buffer[target], length);
2964 }
2965 if ((indx->magic == magic_INDX)
2966 && !(length & 7)
2967 && ((target + length) <= xsize)) {
2968 /* This has to be an idempotent action */
2969 found = index_match_undo(buffer + target, data, length);
2970 err = 0;
2971 if (found) {
2972 /* Remove the entry */
2973 memmove(buffer + target,
2974 buffer + target + length,
2975 xsize - target - length);
2976 indexlth = le32_to_cpu(indx->index.index_length)
2977 - length;
2978 indx->index.index_length = cpu_to_le32(indexlth);
2979 err = write_protected(vol, &action->record,
2980 buffer, xsize);
2981 } else {
2982 sanity_indx(vol,buffer);
2983 printf("full record :\n");
2984 dump(buffer,xsize);
2985 }
2986 if (optv > 1) {
2987 printf("-> INDX record %s\n",
2988 (found ? "removed" : "unchanged"));
2989 }
2990 }
2991 return (err);
2992 }
2993
undo_add_root_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)2994 static int undo_add_root_index(ntfs_volume *vol,
2995 const struct ACTION_RECORD *action, char *buffer)
2996 {
2997 LCN lcn;
2998 const char *data;
2999 ATTR_RECORD *attr;
3000 MFT_RECORD *entry;
3001 INDEX_ROOT *index;
3002 BOOL found;
3003 u32 target;
3004 u32 length;
3005 int err;
3006
3007 if (optv > 1)
3008 printf("-> %s()\n",__func__);
3009 err = 1;
3010 data = ((const char*)&action->record)
3011 + get_redo_offset(&action->record);
3012 length = le16_to_cpu(action->record.redo_length);
3013 target = le16_to_cpu(action->record.record_offset)
3014 + le16_to_cpu(action->record.attribute_offset);
3015 if (optv > 1) {
3016 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3017 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
3018 (long long)inode_number(&action->record),
3019 (long long)lcn, (int)target, (int)length);
3020 }
3021 entry = (MFT_RECORD*)buffer;
3022 attr = (ATTR_RECORD*)(buffer
3023 + le16_to_cpu(action->record.record_offset));
3024 index = (INDEX_ROOT*)(((char*)attr)
3025 + le16_to_cpu(attr->value_offset));
3026 if (optv > 1) {
3027 printf("existing index :\n");
3028 dump(buffer + target,length);
3029 }
3030 if ((attr->type == AT_INDEX_ROOT)
3031 && !(length & 7)
3032 && ((target + length) <= mftrecsz)) {
3033 /* This has to be an idempotent action */
3034 found = index_match_undo(buffer + target, data, length);
3035 err = 0;
3036 if (found && !older_record(entry, &action->record)) {
3037 /* Remove the entry */
3038 memmove(buffer + target,
3039 buffer + target + length,
3040 mftrecsz - target - length);
3041 resize_attribute(entry, attr, index, -length, -length);
3042 if (optv > 1) {
3043 printf("new index at same location :\n");
3044 dump(buffer + target, length);
3045 }
3046 err = write_protected(vol, &action->record,
3047 buffer, mftrecsz);
3048 }
3049 if (optv > 1) {
3050 printf("-> MFT record %s\n",
3051 (found ? "shrinked" : "unchanged"));
3052 }
3053 }
3054 return (err);
3055 }
3056
undo_create_attribute(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3057 static int undo_create_attribute(ntfs_volume *vol,
3058 const struct ACTION_RECORD *action, char *buffer)
3059 {
3060 const char *data;
3061 u32 target;
3062 u32 length;
3063 int err;
3064
3065 if (optv > 1)
3066 printf("-> %s()\n",__func__);
3067 err = 1;
3068 data = ((const char*)&action->record)
3069 + get_redo_offset(&action->record);
3070 length = le16_to_cpu(action->record.redo_length);
3071 target = le16_to_cpu(action->record.record_offset)
3072 + le16_to_cpu(action->record.attribute_offset);
3073 if (!action->record.undo_length)
3074 err = remove_resident(vol, action, buffer, data,
3075 target, length);
3076 return (err);
3077 }
3078
undo_delete_attribute(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3079 static int undo_delete_attribute(ntfs_volume *vol,
3080 const struct ACTION_RECORD *action, char *buffer)
3081 {
3082 const char *data;
3083 u32 target;
3084 u32 length;
3085 int err;
3086
3087 if (optv > 1)
3088 printf("-> %s()\n",__func__);
3089 err = 1;
3090 data = ((const char*)&action->record)
3091 + get_undo_offset(&action->record);
3092 length = le16_to_cpu(action->record.undo_length);
3093 target = le16_to_cpu(action->record.record_offset)
3094 + le16_to_cpu(action->record.attribute_offset);
3095 if (!action->record.redo_length)
3096 err = insert_resident(vol, action, buffer, data,
3097 target, length);
3098 return (err);
3099 }
3100
undo_delete_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3101 static int undo_delete_index(ntfs_volume *vol,
3102 const struct ACTION_RECORD *action, char *buffer)
3103 {
3104 LCN lcn;
3105 const char *data;
3106 INDEX_BLOCK *indx;
3107 u32 target;
3108 u32 length;
3109 u32 xsize;
3110 u32 indexlth;
3111 int err;
3112 BOOL found;
3113
3114 // MERGE with redo_add_root_index() ?
3115 if (optv > 1)
3116 printf("-> %s()\n",__func__);
3117 err = 1;
3118 data = ((const char*)&action->record)
3119 + get_undo_offset(&action->record);
3120 length = le16_to_cpu(action->record.undo_length);
3121 target = le16_to_cpu(action->record.record_offset)
3122 + le16_to_cpu(action->record.attribute_offset);
3123 if (optv > 1) {
3124 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3125 printf("-> lcn 0x%llx target 0x%x length %d\n",
3126 (long long)lcn, (int)target, (int)length);
3127 }
3128 xsize = vol->indx_record_size;
3129 indx = (INDEX_BLOCK*)(buffer
3130 + le16_to_cpu(action->record.record_offset));
3131 if (optv > 1) {
3132 printf("-> existing record :\n");
3133 dump(&buffer[target], length);
3134 }
3135 if ((indx->magic == magic_INDX)
3136 && !(length & 7)
3137 && ((target + length) <= xsize)
3138 && !sanity_indx(vol,buffer)) {
3139 /* This has to be an idempotent action */
3140 found = !memcmp(buffer + target, data, length);
3141 err = 0;
3142 if (!found) {
3143 /* Make space to insert the entry */
3144 memmove(buffer + target + length,
3145 buffer + target,
3146 xsize - target - length);
3147 memcpy(buffer + target, data, length);
3148 indexlth = le32_to_cpu(indx->index.index_length)
3149 + length;
3150 indx->index.index_length = cpu_to_le32(indexlth);
3151 if (optv > 1) {
3152 printf("-> inserted record :\n");
3153 dump(&buffer[target], length);
3154 }
3155 /* rebuildname() has no effect currently, should drop */
3156 rebuildname((const INDEX_ENTRY*)data);
3157 err = write_protected(vol, &action->record,
3158 buffer, xsize);
3159 }
3160 if (optv > 1) {
3161 printf("-> INDX record %s\n",
3162 (found ? "unchanged" : "inserted"));
3163 }
3164 }
3165 return (err);
3166 }
3167
undo_delete_root_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3168 static int undo_delete_root_index(ntfs_volume *vol,
3169 const struct ACTION_RECORD *action, char *buffer)
3170 {
3171 LCN lcn;
3172 const char *data;
3173 ATTR_RECORD *attr;
3174 MFT_RECORD *entry;
3175 INDEX_ROOT *index;
3176 u32 target;
3177 u32 length;
3178 int err;
3179 BOOL found;
3180
3181 if (optv > 1)
3182 printf("-> %s()\n",__func__);
3183 err = 1;
3184 data = ((const char*)&action->record)
3185 + get_undo_offset(&action->record);
3186 length = le16_to_cpu(action->record.undo_length);
3187 target = le16_to_cpu(action->record.record_offset)
3188 + le16_to_cpu(action->record.attribute_offset);
3189 if (optv > 1) {
3190 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3191 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
3192 (long long)inode_number(&action->record),
3193 (long long)lcn, (int)target, (int)length);
3194 }
3195 entry = (MFT_RECORD*)buffer;
3196 attr = (ATTR_RECORD*)(buffer
3197 + le16_to_cpu(action->record.record_offset));
3198 index = (INDEX_ROOT*)(((char*)attr)
3199 + le16_to_cpu(attr->value_offset));
3200 if (attr->type != AT_INDEX_ROOT) {
3201 printf("** Unexpected attr type 0x%lx\n",
3202 (long)le32_to_cpu(attr->type));
3203 printf("existing mft\n");
3204 dump((char*)buffer,512);
3205 printf("existing index\n");
3206 dump(buffer + target,length);
3207 }
3208 if (optv > 1) {
3209 printf("existing index :\n");
3210 dump(buffer + target,length);
3211 }
3212 if ((attr->type == AT_INDEX_ROOT)
3213 && !(length & 7)
3214 && ((target + length) <= mftrecsz)) {
3215 /* This has to be an idempotent action */
3216 found = !memcmp(buffer + target, data, length);
3217 err = 0;
3218 /* Do not insert if present */
3219 if (!found) {
3220 /* Make space to insert the entry */
3221 memmove(buffer + target + length,
3222 buffer + target,
3223 mftrecsz - target - length);
3224 memcpy(buffer + target, data, length);
3225 resize_attribute(entry, attr, index, length, length);
3226 if (optv > 1) {
3227 printf("new index :\n");
3228 dump(buffer + target, length);
3229 }
3230 err = write_protected(vol, &action->record,
3231 buffer, mftrecsz);
3232 }
3233 if (optv > 1) {
3234 printf("-> MFT record %s\n",
3235 (found ? "unchanged" : "expanded"));
3236 }
3237 }
3238 return (err);
3239 }
3240
undo_create_file(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3241 static int undo_create_file(ntfs_volume *vol,
3242 const struct ACTION_RECORD *action, char *buffer)
3243 {
3244 LCN lcn;
3245 const char *data;
3246 MFT_RECORD *record;
3247 u32 target;
3248 u32 length;
3249 int err;
3250 int changed;
3251
3252 if (optv > 1)
3253 printf("-> %s()\n",__func__);
3254 err = 1;
3255 /* redo initialize, clearing the in_use flag ? */
3256 data = ((const char*)&action->record)
3257 + get_redo_offset(&action->record);
3258 length = le16_to_cpu(action->record.redo_length);
3259 target = le16_to_cpu(action->record.record_offset)
3260 + le16_to_cpu(action->record.attribute_offset);
3261 if (optv > 1) {
3262 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3263 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
3264 (long long)inode_number(&action->record),
3265 (long long)lcn, (int)target, (int)length);
3266 }
3267 record = (MFT_RECORD*)buffer;
3268 if (optv > 1) {
3269 printf("-> existing record :\n");
3270 dump(buffer,mftrecsz);
3271 }
3272 if ((target + length) <= mftrecsz) {
3273 changed = memcmp(buffer + target, data, length);
3274 err = 0;
3275 if (changed || (record->flags & MFT_RECORD_IN_USE)) {
3276 memcpy(buffer + target, data, length);
3277 record->flags &= ~MFT_RECORD_IN_USE;
3278 if (optv > 1) {
3279 printf("-> new record :\n");
3280 dump(buffer,mftrecsz);
3281 }
3282 err = write_protected(vol, &action->record,
3283 buffer, mftrecsz);
3284 }
3285 if (optv > 1) {
3286 printf("-> MFT record %s\n",
3287 (changed ? "updated" : "unchanged"));
3288 }
3289 }
3290 return (err);
3291 }
3292
undo_delete_file(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3293 static int undo_delete_file(ntfs_volume *vol,
3294 const struct ACTION_RECORD *action, char *buffer)
3295 {
3296 LCN lcn;
3297 const char *data;
3298 MFT_RECORD *record;
3299 u32 target;
3300 u32 length;
3301 int err;
3302 int changed;
3303
3304 if (optv > 1)
3305 printf("-> %s()\n",__func__);
3306 err = 1;
3307 data = ((const char*)&action->record)
3308 + get_undo_offset(&action->record);
3309 length = le16_to_cpu(action->record.undo_length);
3310 target = le16_to_cpu(action->record.record_offset)
3311 + le16_to_cpu(action->record.attribute_offset);
3312 if (optv > 1) {
3313 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3314 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
3315 (long long)inode_number(&action->record),
3316 (long long)lcn, (int)target, (int)length);
3317 }
3318 if (optv > 1) {
3319 printf("-> existing record :\n");
3320 dump(buffer,mftrecsz);
3321 }
3322 record = (MFT_RECORD*)buffer;
3323 if ((target + length) <= mftrecsz) {
3324 changed = memcmp(buffer + target, data, length)
3325 || !(record->flags & MFT_RECORD_IN_USE);
3326 err = 0;
3327 if (changed) {
3328 memcpy(buffer + target, data, length);
3329 /*
3330 * Unclear what we should do for recreating a file.
3331 * Only 24 bytes are available, the used length is not known,
3332 * the number of links suggests we should keep the current
3333 * names... If so, when will they be deleted ?
3334 * We will have to make stamp changes in the standard
3335 * information attribute, so better not to delete it.
3336 * Should we create a data or index attribute ?
3337 * Here, we assume we should delete the file names when
3338 * the record now appears to not be in use and there are
3339 * links.
3340 */
3341 if (record->link_count
3342 && !(record->flags & MFT_RECORD_IN_USE))
3343 err = delete_names(buffer);
3344 record->flags |= MFT_RECORD_IN_USE;
3345 if (optv > 1) {
3346 printf("-> new record :\n");
3347 dump(buffer,mftrecsz);
3348 }
3349 if (!err)
3350 err = write_protected(vol,
3351 &action->record,
3352 buffer, mftrecsz);
3353 }
3354 if (optv > 1) {
3355 printf("-> MFT record %s\n",
3356 (changed ? "updated" : "unchanged"));
3357 }
3358 }
3359 return (err);
3360 }
3361
undo_force_bits(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3362 static int undo_force_bits(ntfs_volume *vol,
3363 const struct ACTION_RECORD *action, char *buffer)
3364 {
3365 LCN lcn;
3366 const struct BITMAP_ACTION *data;
3367 u32 i;
3368 int err;
3369 int wanted;
3370 u32 firstbit;
3371 u32 count;
3372
3373 if (optv > 1)
3374 printf("-> %s()\n",__func__);
3375 err = 1;
3376 data = (const struct BITMAP_ACTION*)
3377 (((const char*)&action->record)
3378 + get_redo_offset(&action->record));
3379 firstbit = le32_to_cpu(data->firstbit);
3380 count = le32_to_cpu(data->count);
3381 if (action->record.redo_operation
3382 == const_cpu_to_le16(SetBitsInNonResidentBitMap))
3383 wanted = 0;
3384 else
3385 wanted = 1;
3386 // TODO consistency undo_offset == redo_offset, etc.
3387 // firstbit + count < 8*clustersz (multiple clusters possible ?)
3388 if (optv > 1) {
3389 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3390 printf("-> lcn 0x%llx firstbit %d count %d wanted %d\n",
3391 (long long)lcn,(int)firstbit,(int)count,(int)wanted);
3392 }
3393 for (i=0; i<count; i++)
3394 ntfs_bit_set((u8*)buffer, firstbit + i, wanted);
3395 if (!write_raw(vol, &action->record, buffer)) {
3396 err = 0;
3397 if (optv > 1)
3398 printf("-> record updated\n");
3399 }
3400 if (err)
3401 printf("** redo_clearbits failed\n");
3402 return (err);
3403 }
3404
undo_open_attribute(ntfs_volume * vol,const struct ACTION_RECORD * action)3405 static int undo_open_attribute(ntfs_volume *vol __attribute__((unused)),
3406 const struct ACTION_RECORD *action)
3407 {
3408 const char *data;
3409 struct ATTR *pa;
3410 const ATTR_OLD *attr_old;
3411 const ATTR_NEW *attr_new;
3412 const char *name;
3413 le64 inode;
3414 u32 namelen;
3415 u32 length;
3416 u32 extra;
3417 int err;
3418
3419 if (optv > 1)
3420 printf("-> %s()\n",__func__);
3421 err = 1;
3422 data = ((const char*)&action->record)
3423 + get_redo_offset(&action->record);
3424 length = le16_to_cpu(action->record.redo_length);
3425 extra = get_extra_offset(&action->record);
3426 if (action->record.undo_length) {
3427 name = ((const char*)&action->record) + extra;
3428 namelen = le32_to_cpu(action->record.client_data_length)
3429 + LOG_RECORD_HEAD_SZ - extra;
3430 /* fix namelen which was aligned modulo 8 */
3431 namelen = fixnamelen(name, namelen);
3432 if (optv > 1) {
3433 printf("-> length %d namelen %d",(int)length,
3434 (int)namelen);
3435 showname(", ", name, namelen/2);
3436 }
3437 } else {
3438 namelen = 0;
3439 name = "";
3440 }
3441 pa = getattrentry(le16_to_cpu(action->record.target_attribute),0);
3442 // TODO Only process is attr is not older ?
3443 if (pa) {
3444 /* check whether the redo attr matches what we have in store */
3445 switch (length) {
3446 case sizeof(ATTR_OLD) :
3447 attr_old = (const ATTR_OLD*)data;
3448 /* Badly aligned */
3449 memcpy(&inode, &attr_old->inode, 8);
3450 err = (MREF(le64_to_cpu(inode)) != pa->inode)
3451 || (attr_old->type != pa->type);
3452 break;
3453 case sizeof(ATTR_NEW) :
3454 attr_new = (const ATTR_NEW*)data;
3455 err = (MREF(le64_to_cpu(attr_new->inode))!= pa->inode)
3456 || (attr_new->type != pa->type);
3457 break;
3458 default : err = 1;
3459 }
3460 if (!err) {
3461 err = (namelen != pa->namelen)
3462 || (namelen
3463 && memcmp(name, pa->name, namelen));
3464 }
3465 if (optv > 1)
3466 printf("-> attribute %s the recorded one\n",
3467 (err ? "does not match" : "matches"));
3468 } else
3469 if (optv)
3470 printf("* Unrecorded attribute\n");
3471 err = 0;
3472 return (err);
3473 }
3474
undo_sizes(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3475 static int undo_sizes(ntfs_volume *vol,
3476 const struct ACTION_RECORD *action, char *buffer)
3477 {
3478 const char *data;
3479 MFT_RECORD *entry;
3480 ATTR_RECORD *attr;
3481 u32 target;
3482 u32 length;
3483 u32 offs;
3484 int err;
3485
3486 if (optv > 1)
3487 printf("-> %s()\n",__func__);
3488 err = 1;
3489 data = ((const char*)&action->record)
3490 + get_undo_offset(&action->record);
3491 length = le16_to_cpu(action->record.undo_length);
3492 target = le16_to_cpu(action->record.record_offset)
3493 + le16_to_cpu(action->record.attribute_offset)
3494 + offsetof(ATTR_RECORD, allocated_size);
3495 entry = (MFT_RECORD*)buffer;
3496 if (!(entry->flags & MFT_RECORD_IS_DIRECTORY))
3497 err = change_resident(vol, action, buffer,
3498 data, target, length);
3499 else {
3500 /* On a directory, may have to build an index allocation */
3501 offs = le16_to_cpu(action->record.record_offset);
3502 attr = (ATTR_RECORD*)(buffer + offs);
3503 if (attr->type != AT_INDEX_ALLOCATION) {
3504 err = insert_index_allocation(vol, buffer, offs);
3505 if (!err)
3506 err = change_resident(vol, action, buffer,
3507 data, target, length);
3508 } else
3509 err = change_resident(vol, action, buffer,
3510 data, target, length);
3511 }
3512 return (err);
3513 }
3514
undo_update_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3515 static int undo_update_index(ntfs_volume *vol, const struct ACTION_RECORD *action,
3516 char *buffer)
3517 {
3518 const char *data;
3519 u32 target;
3520 u32 length;
3521 int err;
3522
3523 if (optv > 1)
3524 printf("-> %s()\n",__func__);
3525 err = 1;
3526 data = ((const char*)&action->record)
3527 + get_undo_offset(&action->record);
3528 length = le16_to_cpu(action->record.undo_length);
3529 /* target is left-justified to creation time */
3530 target = le16_to_cpu(action->record.record_offset)
3531 + le16_to_cpu(action->record.attribute_offset)
3532 + offsetof(INDEX_ENTRY, key.file_name.creation_time);
3533 err = update_index(vol, action, buffer, data, target, length);
3534 return (err);
3535 }
3536
undo_update_index_value(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3537 static int undo_update_index_value(ntfs_volume *vol,
3538 const struct ACTION_RECORD *action, char *buffer)
3539 {
3540 LCN lcn;
3541 const char *data;
3542 u32 length;
3543 u32 target;
3544 int changed;
3545 int err;
3546
3547 if (optv > 1)
3548 printf("-> %s()\n",__func__);
3549 err = 1;
3550 data = ((const char*)&action->record)
3551 + get_undo_offset(&action->record);
3552 length = le16_to_cpu(action->record.undo_length);
3553 target = le16_to_cpu(action->record.record_offset)
3554 + le16_to_cpu(action->record.attribute_offset);
3555 if (optv > 1) {
3556 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3557 printf("-> lcn 0x%llx target 0x%x length %d\n",
3558 (long long)lcn, (int)target, (int)length);
3559 }
3560 if (optv > 1) {
3561 printf("-> existing record :\n");
3562 dump(&buffer[target], length);
3563 }
3564 if ((target + length) <= vol->indx_record_size) {
3565 changed = length && memcmp(buffer + target, data, length);
3566 err = 0;
3567 if (changed) {
3568 memcpy(buffer + target, data, length);
3569 if (optv > 1) {
3570 printf("-> new record :\n");
3571 dump(buffer + target, length);
3572 }
3573 err = write_protected(vol, &action->record, buffer,
3574 vol->indx_record_size);
3575 }
3576 if (optv > 1) {
3577 printf("-> data record %s\n",
3578 (changed ? "updated" : "unchanged"));
3579 }
3580 }
3581 return (err);
3582 }
3583
undo_update_vcn(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3584 static int undo_update_vcn(ntfs_volume *vol, const struct ACTION_RECORD *action,
3585 char *buffer)
3586 {
3587 const char *data;
3588 u32 target;
3589 u32 length;
3590 int err;
3591
3592 if (optv > 1)
3593 printf("-> %s()\n",__func__);
3594 err = 1;
3595 data = ((const char*)&action->record)
3596 + get_undo_offset(&action->record);
3597 length = le16_to_cpu(action->record.undo_length);
3598 if (length == 8) {
3599 target = le16_to_cpu(action->record.record_offset)
3600 + le16_to_cpu(action->record.attribute_offset);
3601 /* target is right-justified to end of attribute */
3602 target += getle16(buffer, target + 8) - length;
3603 err = update_index(vol, action, buffer, data, target, length);
3604 }
3605 return (err);
3606 }
3607
undo_update_mapping(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3608 static int undo_update_mapping(ntfs_volume *vol, const struct ACTION_RECORD *action,
3609 char *buffer)
3610 {
3611 LCN lcn;
3612 const char *data;
3613 ATTR_RECORD *attr;
3614 MFT_RECORD *entry;
3615 u32 target;
3616 u32 length;
3617 u32 source;
3618 u32 alen;
3619 u32 newused;
3620 int err;
3621 int changed;
3622 int resize;
3623
3624 if (optv > 1)
3625 printf("-> %s()\n",__func__);
3626 err = 1;
3627 data = ((const char*)&action->record)
3628 + get_undo_offset(&action->record);
3629 length = le16_to_cpu(action->record.undo_length);
3630 resize = length - le16_to_cpu(action->record.redo_length);
3631 target = le16_to_cpu(action->record.record_offset)
3632 + le16_to_cpu(action->record.attribute_offset);
3633 if (optv > 1) {
3634 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3635 printf("-> inode %lld lcn 0x%llx target 0x%x new length %d resize %d\n",
3636 (long long)inode_number(&action->record),
3637 (long long)lcn, (int)target, (int)length, (int)resize);
3638 }
3639 // TODO share with redo_update_mapping()
3640 if (optv > 1) {
3641 printf("-> existing record :\n");
3642 dump(&buffer[target], length);
3643 }
3644 entry = (MFT_RECORD*)buffer;
3645 attr = (ATTR_RECORD*)(buffer
3646 + le16_to_cpu(action->record.record_offset));
3647 if (!attr->non_resident) {
3648 printf("** Error : update_mapping on resident attr\n");
3649 }
3650 if (valid_type(attr->type)
3651 && attr->non_resident
3652 && !(resize & 7)
3653 && ((target + length) <= mftrecsz)) {
3654 changed = memcmp(buffer + target, data, length);
3655 err = 0;
3656 if (changed) {
3657 /* Adjust space for new mapping pairs */
3658 source = target - resize;
3659 if (resize > 0) {
3660 memmove(buffer + target + length,
3661 buffer + source + length,
3662 mftrecsz - target - length);
3663 }
3664 if (resize < 0) {
3665 memmove(buffer + target + length,
3666 buffer + source + length,
3667 mftrecsz - source - length);
3668 }
3669 memcpy(buffer + target, data, length);
3670 /* Resize the attribute */
3671 alen = le32_to_cpu(attr->length) + resize;
3672 attr->length = cpu_to_le32(alen);
3673 /* Resize the mft record */
3674 newused = le32_to_cpu(entry->bytes_in_use)
3675 + resize;
3676 entry->bytes_in_use = cpu_to_le32(newused);
3677 /* Compute the new highest_vcn */
3678 err = adjust_high_vcn(vol, attr);
3679 if (optv > 1) {
3680 printf("-> new record :\n");
3681 dump(buffer + target, length);
3682 }
3683 if (!err) {
3684 err = write_protected(vol,
3685 &action->record, buffer,
3686 mftrecsz);
3687 }
3688 }
3689 if (optv > 1) {
3690 printf("-> MFT record %s\n",
3691 (changed ? "updated" : "unchanged"));
3692 }
3693 }
3694 return (err);
3695 }
3696
undo_update_resident(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3697 static int undo_update_resident(ntfs_volume *vol,
3698 const struct ACTION_RECORD *action, char *buffer)
3699 {
3700 LCN lcn;
3701 const char *data;
3702 u32 target;
3703 u32 length;
3704 u32 oldlength;
3705 u32 end;
3706 u32 undo;
3707 int err;
3708 int changed;
3709
3710 if (optv > 1)
3711 printf("-> %s()\n",__func__);
3712 err = 1;
3713 end = le32_to_cpu(action->record.client_data_length)
3714 + LOG_RECORD_HEAD_SZ;
3715 length = le16_to_cpu(action->record.undo_length);
3716 undo = get_undo_offset(&action->record);
3717 if ((undo + length) > end)
3718 data = (char*)NULL;
3719 else
3720 data = ((const char*)&action->record) + undo;
3721 oldlength = le16_to_cpu(action->record.redo_length);
3722 target = le16_to_cpu(action->record.record_offset)
3723 + le16_to_cpu(action->record.attribute_offset);
3724 if (length == oldlength) {
3725 if (optv > 1) {
3726 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3727 printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n",
3728 (long long)inode_number(&action->record),
3729 (long long)lcn, (int)target, (int)length);
3730 }
3731 if (optv > 1) {
3732 printf("-> existing record :\n");
3733 dump(&buffer[target], length);
3734 }
3735 if ((target + length) <= mftrecsz) {
3736 changed = memcmp(buffer + target, data, length);
3737 err = 0;
3738 if (changed) {
3739 memcpy(buffer + target, data, length);
3740 if (optv > 1) {
3741 printf("-> new record :\n");
3742 dump(buffer + target, length);
3743 }
3744 err = write_protected(vol, &action->record,
3745 buffer, mftrecsz);
3746 }
3747 if (optv > 1) {
3748 printf("-> MFT record %s\n",
3749 (changed ? "updated" : "unchanged"));
3750 }
3751 }
3752 } else {
3753 if (length > oldlength)
3754 err = expand_resident(vol, action, buffer, data,
3755 target, length, oldlength);
3756 else
3757 err = shrink_resident(vol, action, buffer, data,
3758 target, length, oldlength);
3759 }
3760 return (err);
3761 }
3762
undo_update_root_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3763 static int undo_update_root_index(ntfs_volume *vol,
3764 const struct ACTION_RECORD *action, char *buffer)
3765 {
3766 const char *data;
3767 const char *expected;
3768 u32 target;
3769 u32 length;
3770 int err;
3771
3772 if (optv > 1)
3773 printf("-> %s()\n",__func__);
3774 err = 1;
3775 data = ((const char*)&action->record)
3776 + get_undo_offset(&action->record);
3777 expected = ((const char*)&action->record)
3778 + get_redo_offset(&action->record);
3779 length = le16_to_cpu(action->record.undo_length);
3780 /* the fixup is right-justified to the name length */
3781 target = le16_to_cpu(action->record.record_offset)
3782 + le16_to_cpu(action->record.attribute_offset)
3783 + offsetof(INDEX_ENTRY, key.file_name.file_name_length)
3784 - length;
3785 err = change_resident_expect(vol, action, buffer, data, expected,
3786 target, length, AT_INDEX_ROOT);
3787 return (err);
3788 }
3789
undo_update_root_vcn(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3790 static int undo_update_root_vcn(ntfs_volume *vol,
3791 const struct ACTION_RECORD *action, char *buffer)
3792 {
3793 const char *data;
3794 const char *expected;
3795 u32 target;
3796 u32 length;
3797 int err;
3798
3799 if (optv > 1)
3800 printf("-> %s()\n",__func__);
3801 err = 1;
3802 data = ((const char*)&action->record)
3803 + get_undo_offset(&action->record);
3804 expected = ((const char*)&action->record)
3805 + get_redo_offset(&action->record);
3806 length = le16_to_cpu(action->record.undo_length);
3807 if (length == 8) {
3808 target = le16_to_cpu(action->record.record_offset)
3809 + le16_to_cpu(action->record.attribute_offset);
3810 /* target is right-justified to end of attribute */
3811 target += getle16(buffer, target + 8) - length;
3812 err = change_resident_expect(vol, action, buffer, data,
3813 expected, target, length, AT_INDEX_ROOT);
3814 }
3815 return (err);
3816 }
3817
undo_update_value(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3818 static int undo_update_value(ntfs_volume *vol,
3819 const struct ACTION_RECORD *action, char *buffer)
3820 {
3821 LCN lcn;
3822 const char *data;
3823 u32 length;
3824 u32 target;
3825 u32 count;
3826 int changed;
3827 int err;
3828
3829 if (optv > 1)
3830 printf("-> %s()\n",__func__);
3831 err = 1;
3832 data = ((const char*)&action->record)
3833 + get_undo_offset(&action->record);
3834 length = le16_to_cpu(action->record.undo_length);
3835 target = le16_to_cpu(action->record.record_offset)
3836 + le16_to_cpu(action->record.attribute_offset);
3837 count = le16_to_cpu(action->record.lcns_to_follow);
3838 if (optv > 1) {
3839 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3840 printf("-> lcn 0x%llx target 0x%x length %d\n",
3841 (long long)lcn, (int)target, (int)length);
3842 }
3843 if (length) {
3844 if (optv > 1) {
3845 printf("-> existing record :\n");
3846 dump(&buffer[target], length);
3847 }
3848 if ((target + length) <= (count << clusterbits)) {
3849 changed = memcmp(buffer + target, data, length);
3850 err = 0;
3851 if (changed) {
3852 memcpy(buffer + target, data, length);
3853 if (optv > 1) {
3854 printf("-> new record :\n");
3855 dump(buffer + target, length);
3856 }
3857 err = write_raw(vol, &action->record, buffer);
3858 }
3859 if (optv > 1) {
3860 printf("-> data record %s\n",
3861 (changed ? "updated" : "unchanged"));
3862 }
3863 }
3864 } else {
3865 /*
3866 * No undo data, we cannot undo, sometimes the redo
3867 * data even overflows from record.
3868 * Just ignore for now.
3869 */
3870 if (optv)
3871 printf("Cannot undo, there is no undo data\n");
3872 err = 0;
3873 }
3874
3875 return (err);
3876 }
3877
undo_write_end(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3878 static int undo_write_end(ntfs_volume *vol,
3879 const struct ACTION_RECORD *action, char *buffer)
3880 {
3881 LCN lcn;
3882 const char *data;
3883 u32 target;
3884 u32 length;
3885 u32 oldlength;
3886 u32 end;
3887 u32 undo;
3888 int err;
3889 int changed;
3890
3891 if (optv > 1)
3892 printf("-> %s()\n",__func__);
3893 err = 1;
3894 end = le32_to_cpu(action->record.client_data_length)
3895 + LOG_RECORD_HEAD_SZ;
3896 length = le16_to_cpu(action->record.undo_length);
3897 undo = get_undo_offset(&action->record);
3898 if ((undo + length) > end)
3899 data = (char*)NULL;
3900 else
3901 data = ((const char*)&action->record) + undo;
3902 oldlength = le16_to_cpu(action->record.redo_length);
3903 target = le16_to_cpu(action->record.record_offset)
3904 + le16_to_cpu(action->record.attribute_offset);
3905 if (length == oldlength) {
3906 if (optv > 1) {
3907 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3908 printf("-> inode %lld lcn 0x%llx target 0x%x"
3909 " length %d\n",
3910 (long long)inode_number(&action->record),
3911 (long long)lcn, (int)target, (int)length);
3912 }
3913 if (optv > 1) {
3914 printf("-> existing record :\n");
3915 dump(&buffer[target], length);
3916 }
3917 if ((target + length) <= mftrecsz) {
3918 changed = memcmp(buffer + target, data, length);
3919 err = 0;
3920 if (changed) {
3921 memcpy(buffer + target, data, length);
3922 if (optv > 1) {
3923 printf("-> new record :\n");
3924 dump(buffer + target, length);
3925 }
3926 err = write_protected(vol, &action->record,
3927 buffer, mftrecsz);
3928 }
3929 if (optv > 1) {
3930 printf("-> MFT record %s\n",
3931 (changed ? "updated" : "unchanged"));
3932 }
3933 }
3934 } else {
3935 if (length > oldlength)
3936 err = add_resident(vol, action, buffer, data,
3937 target, length, oldlength);
3938 else
3939 err = delete_resident(vol, action, buffer, data,
3940 target, length, oldlength);
3941 }
3942 return (err);
3943 }
3944
undo_write_index(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)3945 static int undo_write_index(ntfs_volume *vol,
3946 const struct ACTION_RECORD *action, char *buffer)
3947 {
3948 LCN lcn;
3949 const char *data;
3950 u32 target;
3951 u32 length;
3952 u32 oldlength;
3953 u32 end;
3954 u32 undo;
3955 int err;
3956 int changed;
3957
3958 if (optv > 1)
3959 printf("-> %s()\n",__func__);
3960 err = 1;
3961 end = le32_to_cpu(action->record.client_data_length)
3962 + LOG_RECORD_HEAD_SZ;
3963 length = le16_to_cpu(action->record.undo_length);
3964 undo = get_undo_offset(&action->record);
3965 if ((undo + length) > end)
3966 data = (char*)NULL;
3967 else
3968 data = ((const char*)&action->record) + undo;
3969 oldlength = le16_to_cpu(action->record.redo_length);
3970 target = le16_to_cpu(action->record.record_offset)
3971 + le16_to_cpu(action->record.attribute_offset);
3972 if (length == oldlength) {
3973 if (optv > 1) {
3974 lcn = sle64_to_cpu(action->record.lcn_list[0]);
3975 printf("-> inode %lld lcn 0x%llx target 0x%x"
3976 " length %d\n",
3977 (long long)inode_number(&action->record),
3978 (long long)lcn, (int)target, (int)length);
3979 }
3980 if (optv > 1) {
3981 printf("-> existing record :\n");
3982 dump(&buffer[target], length);
3983 }
3984 if ((target + length) <= mftrecsz) {
3985 changed = memcmp(buffer + target, data, length);
3986 err = 0;
3987 if (changed) {
3988 memcpy(buffer + target, data, length);
3989 if (optv > 1) {
3990 printf("-> new record :\n");
3991 dump(buffer + target, length);
3992 }
3993 err = write_protected(vol, &action->record,
3994 buffer, mftrecsz);
3995 }
3996 if (optv > 1) {
3997 printf("-> MFT record %s\n",
3998 (changed ? "updated" : "unchanged"));
3999 }
4000 }
4001 } else {
4002 if (length > oldlength)
4003 err = add_non_resident(/*vol, action, data,
4004 target, length, oldlength*/);
4005 else
4006 err = delete_non_resident(/*vol, action, data,
4007 target, length, oldlength*/);
4008 }
4009 return (err);
4010 }
4011
4012 enum ACTION_KIND { ON_NONE, ON_MFT, ON_INDX, ON_RAW } ;
4013
get_action_kind(const struct ACTION_RECORD * action)4014 static enum ACTION_KIND get_action_kind(const struct ACTION_RECORD *action)
4015 {
4016 struct ATTR *pa;
4017 const char *data;
4018 enum ACTION_KIND kind;
4019 /*
4020 * If we are sure the action was defined by Vista
4021 * or subsequent, just use attribute_flags.
4022 * Unfortunately, only on some cases we can determine
4023 * the action was defined by Win10 (or subsequent).
4024 */
4025 if (action->record.log_record_flags
4026 & (LOG_RECORD_DELETING | LOG_RECORD_ADDING)) {
4027 if (action->record.attribute_flags & ACTS_ON_INDX)
4028 kind = ON_INDX;
4029 else
4030 if (action->record.attribute_flags & ACTS_ON_MFT)
4031 kind = ON_MFT;
4032 else
4033 kind = ON_RAW;
4034 } else {
4035 /*
4036 * In other cases, we have to rely on the attribute
4037 * definition, but this has defects when undoing.
4038 */
4039 pa = getattrentry(le16_to_cpu(
4040 action->record.target_attribute),0);
4041 if (!pa || !pa->type) {
4042 /*
4043 * Even when the attribute has not been recorded,
4044 * we can sometimes tell the record does not apply
4045 * to MFT or INDX : such records always have a zero
4046 * record_offset, and if attribute_offset is zero, their
4047 * magic can be checked. If neither condition is true,
4048 * the action cannot apply to MFT or INDX.
4049 * (this is useful for undoing)
4050 */
4051 data = (const char*)&action->record
4052 + get_redo_offset(&action->record);
4053 if (action->record.record_offset
4054 || (!action->record.attribute_offset
4055 && (le16_to_cpu(action->record.redo_length)
4056 >= 4)
4057 && memcmp(data,"FILE",4)
4058 && memcmp(data,"INDX",4))) {
4059 kind = ON_RAW;
4060 } else {
4061 printf("** Error : attribute 0x%x"
4062 " is not defined\n",
4063 (int)le16_to_cpu(
4064 action->record.target_attribute));
4065 kind = ON_NONE;
4066 }
4067 } else {
4068 if (pa->type == AT_INDEX_ALLOCATION)
4069 kind = ON_INDX;
4070 else
4071 kind = ON_RAW;
4072 }
4073 }
4074 return (kind);
4075 }
4076
4077
4078 /*
4079 * Display the redo actions which were executed
4080 *
4081 * Useful for getting indications on the coverage of a test
4082 */
4083
show_redos(void)4084 void show_redos(void)
4085 {
4086 int i;
4087
4088 if (optv && redos_met) {
4089 printf("Redo actions which were executed :\n");
4090 for (i=0; i<64; i++)
4091 if ((((u64)1) << i) & redos_met)
4092 printf("%s\n", actionname(i));
4093 }
4094 }
4095
distribute_redos(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)4096 static int distribute_redos(ntfs_volume *vol,
4097 const struct ACTION_RECORD *action, char *buffer)
4098 {
4099 int rop, uop;
4100 int err;
4101
4102 err = 0;
4103 rop = le16_to_cpu(action->record.redo_operation);
4104 uop = le16_to_cpu(action->record.undo_operation);
4105 switch (rop) {
4106 case AddIndexEntryAllocation :
4107 if (action->record.undo_operation
4108 == const_cpu_to_le16(DeleteIndexEntryAllocation))
4109 err = redo_add_index(vol, action, buffer);
4110 break;
4111 case AddIndexEntryRoot :
4112 if (action->record.undo_operation
4113 == const_cpu_to_le16(DeleteIndexEntryRoot))
4114 err = redo_add_root_index(vol, action, buffer);
4115 break;
4116 case ClearBitsInNonResidentBitMap :
4117 if ((action->record.undo_operation
4118 == const_cpu_to_le16(SetBitsInNonResidentBitMap))
4119 || (action->record.undo_operation
4120 == const_cpu_to_le16(CompensationlogRecord)))
4121 err = redo_force_bits(vol, action, buffer);
4122 break;
4123 case CompensationlogRecord :
4124 if (action->record.undo_operation
4125 == const_cpu_to_le16(Noop))
4126 err = redo_compensate(vol, action, buffer);
4127 break;
4128 case CreateAttribute :
4129 if ((action->record.undo_operation
4130 == const_cpu_to_le16(DeleteAttribute))
4131 || (action->record.undo_operation
4132 == const_cpu_to_le16(CompensationlogRecord)))
4133 err = redo_create_attribute(vol, action, buffer);
4134 break;
4135 case DeallocateFileRecordSegment :
4136 if ((action->record.undo_operation
4137 == const_cpu_to_le16(InitializeFileRecordSegment))
4138 || (action->record.undo_operation
4139 == const_cpu_to_le16(CompensationlogRecord)))
4140 err = redo_delete_file(vol, action, buffer);
4141 break;
4142 case DeleteAttribute :
4143 if ((action->record.undo_operation
4144 == const_cpu_to_le16(CreateAttribute))
4145 || (action->record.undo_operation
4146 == const_cpu_to_le16(CompensationlogRecord)))
4147 err = redo_delete_attribute(vol, action, buffer);
4148 break;
4149 case DeleteIndexEntryAllocation :
4150 if ((action->record.undo_operation
4151 == const_cpu_to_le16(AddIndexEntryAllocation))
4152 || (action->record.undo_operation
4153 == const_cpu_to_le16(CompensationlogRecord)))
4154 err = redo_delete_index(vol, action, buffer);
4155 break;
4156 case DeleteIndexEntryRoot :
4157 if ((action->record.undo_operation
4158 == const_cpu_to_le16(AddIndexEntryRoot))
4159 || (action->record.undo_operation
4160 == const_cpu_to_le16(CompensationlogRecord)))
4161 err = redo_delete_root_index(vol, action, buffer);
4162 break;
4163 case InitializeFileRecordSegment :
4164 if (action->record.undo_operation
4165 == const_cpu_to_le16(Noop))
4166 err = redo_create_file(vol, action, buffer);
4167 break;
4168 case OpenNonResidentAttribute :
4169 if (action->record.undo_operation
4170 == const_cpu_to_le16(Noop))
4171 err = redo_open_attribute(vol, action);
4172 break;
4173 case SetBitsInNonResidentBitMap :
4174 if (action->record.undo_operation
4175 == const_cpu_to_le16(ClearBitsInNonResidentBitMap))
4176 err = redo_force_bits(vol, action, buffer);
4177 break;
4178 case SetIndexEntryVcnAllocation :
4179 if ((action->record.undo_operation
4180 == const_cpu_to_le16(SetIndexEntryVcnAllocation))
4181 || (action->record.undo_operation
4182 == const_cpu_to_le16(CompensationlogRecord)))
4183 err = redo_update_vcn(vol, action, buffer);
4184 break;
4185 case SetIndexEntryVcnRoot :
4186 if (action->record.undo_operation
4187 == const_cpu_to_le16(SetIndexEntryVcnRoot))
4188 err = redo_update_root_vcn(vol, action, buffer);
4189 break;
4190 case SetNewAttributeSizes :
4191 if ((action->record.undo_operation
4192 == const_cpu_to_le16(SetNewAttributeSizes))
4193 || (action->record.undo_operation
4194 == const_cpu_to_le16(CompensationlogRecord)))
4195 err = redo_sizes(vol, action, buffer);
4196 break;
4197 case UpdateFileNameAllocation :
4198 if ((action->record.undo_operation
4199 == const_cpu_to_le16(UpdateFileNameAllocation))
4200 || (action->record.undo_operation
4201 == const_cpu_to_le16(CompensationlogRecord)))
4202 err = redo_update_index(vol, action, buffer);
4203 break;
4204 case UpdateFileNameRoot :
4205 if ((action->record.undo_operation
4206 == const_cpu_to_le16(UpdateFileNameRoot))
4207 || (action->record.undo_operation
4208 == const_cpu_to_le16(CompensationlogRecord)))
4209 err = redo_update_root_index(vol, action, buffer);
4210 break;
4211 case UpdateMappingPairs :
4212 if (action->record.undo_operation
4213 == const_cpu_to_le16(UpdateMappingPairs))
4214 err = redo_update_mapping(vol, action, buffer);
4215 break;
4216 case UpdateNonResidentValue :
4217 switch (get_action_kind(action)) {
4218 case ON_INDX :
4219 err = redo_update_index_value(vol, action, buffer);
4220 break;
4221 case ON_RAW :
4222 err = redo_update_value(vol, action, buffer);
4223 break;
4224 default :
4225 printf("** Bad attribute type\n");
4226 err = 1;
4227 }
4228 break;
4229 case UpdateResidentValue :
4230 if ((action->record.undo_operation
4231 == const_cpu_to_le16(UpdateResidentValue))
4232 || (action->record.undo_operation
4233 == const_cpu_to_le16(CompensationlogRecord)))
4234 err = redo_update_resident(vol, action, buffer);
4235 break;
4236 case Win10Action37 :
4237 if (action->record.undo_operation
4238 == const_cpu_to_le16(Noop))
4239 err = redo_action37(vol, action, buffer);
4240 break;
4241 case WriteEndofFileRecordSegment :
4242 if (action->record.undo_operation
4243 == const_cpu_to_le16(WriteEndofFileRecordSegment))
4244 err = redo_write_end(vol, action, buffer);
4245 break;
4246 case WriteEndOfIndexBuffer :
4247 if ((action->record.undo_operation
4248 == const_cpu_to_le16(WriteEndOfIndexBuffer))
4249 || (action->record.undo_operation
4250 == const_cpu_to_le16(CompensationlogRecord)))
4251 err = redo_write_index(vol, action, buffer);
4252 break;
4253 case AttributeNamesDump :
4254 case DirtyPageTableDump :
4255 case ForgetTransaction :
4256 case Noop :
4257 case OpenAttributeTableDump :
4258 break;
4259 default :
4260 printf("** Unsupported redo %s\n", actionname(rop));
4261 err = 1;
4262 break;
4263 }
4264 redos_met |= ((u64)1) << rop;
4265 if (err)
4266 printf("* Redoing action %d %s (%s) failed\n",
4267 action->num,actionname(rop), actionname(uop));
4268 return (err);
4269 }
4270
4271 /*
4272 * Redo a single action
4273 *
4274 * The record the action acts on is read and, when it is an MFT or
4275 * INDX one, the need for redoing is checked.
4276 *
4277 * When this is an action which creates a new MFT or INDX record
4278 * and the old one cannot be read (usually because it was not
4279 * initialized), a zeroed buffer is allocated.
4280 */
4281
play_one_redo(ntfs_volume * vol,const struct ACTION_RECORD * action)4282 static int play_one_redo(ntfs_volume *vol, const struct ACTION_RECORD *action)
4283 {
4284 MFT_RECORD *entry;
4285 INDEX_BLOCK *indx;
4286 char *buffer;
4287 s64 this_lsn;
4288 s64 data_lsn;
4289 u32 xsize;
4290 int err;
4291 BOOL warn;
4292 BOOL executed;
4293 enum ACTION_KIND kind;
4294 u16 rop;
4295 u16 uop;
4296
4297 err = 0;
4298 rop = le16_to_cpu(action->record.redo_operation);
4299 uop = le16_to_cpu(action->record.undo_operation);
4300 this_lsn = sle64_to_cpu(action->record.this_lsn);
4301 if (optv)
4302 printf("Redo action %d %s (%s) 0x%llx\n",
4303 action->num,
4304 actionname(rop), actionname(uop),
4305 (long long)sle64_to_cpu(
4306 action->record.this_lsn));
4307 buffer = (char*)NULL;
4308 switch (rop) {
4309 /* Actions always acting on MFT */
4310 case AddIndexEntryRoot :
4311 case CreateAttribute :
4312 case DeallocateFileRecordSegment :
4313 case DeleteAttribute :
4314 case DeleteIndexEntryRoot :
4315 case InitializeFileRecordSegment :
4316 case SetIndexEntryVcnRoot :
4317 case SetNewAttributeSizes :
4318 case UpdateFileNameRoot :
4319 case UpdateMappingPairs :
4320 case UpdateResidentValue :
4321 case Win10Action37 :
4322 case WriteEndofFileRecordSegment :
4323 kind = ON_MFT;
4324 break;
4325 /* Actions always acting on INDX */
4326 case AddIndexEntryAllocation :
4327 case DeleteIndexEntryAllocation :
4328 case SetIndexEntryVcnAllocation :
4329 case UpdateFileNameAllocation :
4330 case WriteEndOfIndexBuffer :
4331 kind = ON_INDX;
4332 break;
4333 /* Actions never acting on MFT or INDX */
4334 case ClearBitsInNonResidentBitMap :
4335 case SetBitsInNonResidentBitMap :
4336 kind = ON_RAW;
4337 break;
4338 /* Actions which may act on MFT */
4339 case Noop : /* on MFT if DeallocateFileRecordSegment */
4340 kind = ON_NONE;
4341 break;
4342 /* Actions which may act on INDX */
4343 case UpdateNonResidentValue :
4344 /* Known cases : INDX, $SDS, ATTR_LIST */
4345 kind = get_action_kind(action);
4346 if (kind == ON_NONE)
4347 err = 1;
4348 break;
4349 case CompensationlogRecord :
4350 case OpenNonResidentAttribute :
4351 /* probably not important */
4352 kind = ON_NONE;
4353 break;
4354 /* Actions currently ignored */
4355 case AttributeNamesDump :
4356 case DirtyPageTableDump :
4357 case ForgetTransaction :
4358 case OpenAttributeTableDump :
4359 case TransactionTableDump :
4360 kind = ON_NONE;
4361 break;
4362 /* Actions with no known use case */
4363 case CommitTransaction :
4364 case DeleteDirtyClusters :
4365 case EndTopLevelAction :
4366 case HotFix :
4367 case PrepareTransaction :
4368 case UpdateRecordDataAllocation :
4369 case UpdateRecordDataRoot :
4370 case Win10Action35 :
4371 case Win10Action36 :
4372 default :
4373 err = 1;
4374 kind = ON_NONE;
4375 break;
4376 }
4377 executed = FALSE;
4378 switch (kind) {
4379 case ON_MFT :
4380 /*
4381 the check below cannot be used on WinXP
4382 if (!(action->record.attribute_flags & ACTS_ON_MFT))
4383 printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num);
4384 */
4385 /* Check whether data is to be discarded */
4386 warn = (rop != InitializeFileRecordSegment)
4387 || !check_full_mft(action,TRUE);
4388 buffer = read_protected(vol, &action->record,
4389 mftrecsz, warn);
4390 entry = (MFT_RECORD*)buffer;
4391 if (entry && (entry->magic == magic_FILE)) {
4392 data_lsn = sle64_to_cpu(entry->lsn);
4393 /*
4394 * Beware of records not updated
4395 * during the last session which may
4396 * have a stale lsn (consequence
4397 * of ntfs-3g resetting the log)
4398 */
4399 executed = ((s64)(data_lsn - this_lsn) >= 0)
4400 && (((s64)(data_lsn - latest_lsn)) <= 0)
4401 && !exception(action->num);
4402 } else {
4403 if (!warn) {
4404 /* Old record not needed */
4405 if (!buffer)
4406 buffer = (char*)calloc(1, mftrecsz);
4407 if (buffer)
4408 executed = FALSE;
4409 else
4410 err = 1;
4411 } else {
4412 printf("** %s (action %d) not"
4413 " acting on MFT\n",
4414 actionname(rop),
4415 (int)action->num);
4416 err = 1;
4417 }
4418 }
4419 break;
4420 case ON_INDX :
4421 /*
4422 the check below cannot be used on WinXP
4423 if (!(action->record.attribute_flags & ACTS_ON_INDX))
4424 printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num);
4425 */
4426 xsize = vol->indx_record_size;
4427 /* Check whether data is to be discarded */
4428 warn = (rop != UpdateNonResidentValue)
4429 || !check_full_index(action,TRUE);
4430 buffer = read_protected(vol, &action->record,
4431 xsize, warn);
4432 indx = (INDEX_BLOCK*)buffer;
4433 if (indx && (indx->magic == magic_INDX)) {
4434 data_lsn = sle64_to_cpu(indx->lsn);
4435 /*
4436 * Beware of records not updated
4437 * during the last session which may
4438 * have a stale lsn (consequence
4439 * of ntfs-3g resetting the log)
4440 */
4441 executed = ((s64)(data_lsn - this_lsn) >= 0)
4442 && (((s64)(data_lsn - latest_lsn)) <= 0)
4443 && ! exception(action->num);
4444 } else {
4445 if (!warn) {
4446 /* Old record not needed */
4447 if (!buffer)
4448 buffer = (char*)calloc(1, xsize);
4449 if (buffer)
4450 executed = FALSE;
4451 else
4452 err = 1;
4453 } else {
4454 printf("** %s (action %d) not"
4455 " acting on INDX\n",
4456 actionname(rop),
4457 (int)action->num);
4458 err = 1;
4459 }
4460 }
4461 break;
4462 case ON_RAW :
4463 if (action->record.attribute_flags
4464 & (ACTS_ON_INDX | ACTS_ON_MFT)) {
4465 printf("** Error : action %s on MFT"
4466 " or INDX\n",
4467 actionname(rop));
4468 err = 1;
4469 } else {
4470 buffer = read_raw(vol, &action->record);
4471 if (!buffer)
4472 err = 1;
4473 }
4474 break;
4475 default :
4476 buffer = (char*)NULL;
4477 break;
4478 }
4479 if (!err && (!executed || !opts)) {
4480 err = distribute_redos(vol, action, buffer);
4481 redocount++;
4482 } else {
4483 if (optv)
4484 printf("Action %d %s (%s) not redone\n",
4485 action->num,
4486 actionname(rop),
4487 actionname(uop));
4488 }
4489 if (buffer)
4490 free(buffer);
4491 return (err);
4492 }
4493
4494
4495 /*
4496 * Play the redo actions from earliest to latest
4497 *
4498 * Currently we can only redo the last undone transaction,
4499 * otherwise the attribute table would be out of phase.
4500 */
4501
play_redos(ntfs_volume * vol,const struct ACTION_RECORD * firstaction)4502 int play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstaction)
4503 {
4504 const struct ACTION_RECORD *action;
4505 int err;
4506
4507 err = 0;
4508 action = firstaction;
4509 while (action && !err) {
4510 /* Only committed actions should be redone */
4511 if ((!optc || within_lcn_range(&action->record))
4512 && (action->flags & ACTION_TO_REDO))
4513 err = play_one_redo(vol, action);
4514 if (!err)
4515 action = action->next;
4516 }
4517 return (err);
4518 }
4519
distribute_undos(ntfs_volume * vol,const struct ACTION_RECORD * action,char * buffer)4520 static int distribute_undos(ntfs_volume *vol, const struct ACTION_RECORD *action,
4521 char *buffer)
4522 {
4523 int rop, uop;
4524 int err;
4525
4526 err = 0;
4527 rop = le16_to_cpu(action->record.redo_operation);
4528 uop = le16_to_cpu(action->record.undo_operation);
4529 switch (rop) {
4530 case AddIndexEntryAllocation :
4531 if (action->record.undo_operation
4532 == const_cpu_to_le16(DeleteIndexEntryAllocation))
4533 err = undo_add_index(vol, action, buffer);
4534 break;
4535 case AddIndexEntryRoot :
4536 if (action->record.undo_operation
4537 == const_cpu_to_le16(DeleteIndexEntryRoot))
4538 err = undo_add_root_index(vol, action, buffer);
4539 break;
4540 case ClearBitsInNonResidentBitMap :
4541 if (action->record.undo_operation
4542 == const_cpu_to_le16(SetBitsInNonResidentBitMap))
4543 err = undo_force_bits(vol, action, buffer);
4544 break;
4545 case CreateAttribute :
4546 if (action->record.undo_operation
4547 == const_cpu_to_le16(DeleteAttribute))
4548 err = undo_create_attribute(vol, action, buffer);
4549 break;
4550 case DeallocateFileRecordSegment :
4551 if (action->record.undo_operation
4552 == const_cpu_to_le16(InitializeFileRecordSegment))
4553 err = undo_delete_file(vol, action, buffer);
4554 break;
4555 case DeleteAttribute :
4556 if (action->record.undo_operation
4557 == const_cpu_to_le16(CreateAttribute))
4558 err = undo_delete_attribute(vol, action, buffer);
4559 break;
4560 case DeleteIndexEntryAllocation :
4561 if (action->record.undo_operation
4562 == const_cpu_to_le16(AddIndexEntryAllocation))
4563 err = undo_delete_index(vol, action, buffer);
4564 break;
4565 case DeleteIndexEntryRoot :
4566 if (action->record.undo_operation
4567 == const_cpu_to_le16(AddIndexEntryRoot))
4568 err = undo_delete_root_index(vol, action, buffer);
4569 break;
4570 case InitializeFileRecordSegment :
4571 if (action->record.undo_operation
4572 == const_cpu_to_le16(Noop))
4573 err = undo_create_file(vol, action, buffer);
4574 break;
4575 case OpenNonResidentAttribute :
4576 if (action->record.undo_operation
4577 == const_cpu_to_le16(Noop))
4578 err = undo_open_attribute(vol, action);
4579 break;
4580 case SetBitsInNonResidentBitMap :
4581 if (action->record.undo_operation
4582 == const_cpu_to_le16(ClearBitsInNonResidentBitMap))
4583 err = undo_force_bits(vol, action, buffer);
4584 break;
4585 case SetIndexEntryVcnAllocation :
4586 if (action->record.undo_operation
4587 == const_cpu_to_le16(SetIndexEntryVcnAllocation))
4588 err = undo_update_vcn(vol, action, buffer);
4589 break;
4590 case SetIndexEntryVcnRoot :
4591 if (action->record.undo_operation
4592 == const_cpu_to_le16(SetIndexEntryVcnRoot))
4593 err = undo_update_root_vcn(vol, action, buffer);
4594 break;
4595 case SetNewAttributeSizes :
4596 if (action->record.undo_operation
4597 == const_cpu_to_le16(SetNewAttributeSizes))
4598 err = undo_sizes(vol, action, buffer);
4599 break;
4600 case UpdateFileNameAllocation :
4601 if (action->record.undo_operation
4602 == const_cpu_to_le16(UpdateFileNameAllocation))
4603 err = undo_update_index(vol, action, buffer);
4604 break;
4605 case UpdateFileNameRoot :
4606 if (action->record.undo_operation
4607 == const_cpu_to_le16(UpdateFileNameRoot))
4608 err = undo_update_root_index(vol, action, buffer);
4609 break;
4610 case UpdateMappingPairs :
4611 if (action->record.undo_operation
4612 == const_cpu_to_le16(UpdateMappingPairs))
4613 err = undo_update_mapping(vol, action, buffer);
4614 break;
4615 case UpdateNonResidentValue :
4616 switch (get_action_kind(action)) {
4617 case ON_INDX :
4618 err = undo_update_index_value(vol, action, buffer);
4619 break;
4620 case ON_RAW :
4621 err = undo_update_value(vol, action, buffer);
4622 break;
4623 default :
4624 printf("** Bad attribute type\n");
4625 err = 1;
4626 }
4627 break;
4628 case UpdateResidentValue :
4629 if (action->record.undo_operation
4630 == const_cpu_to_le16(UpdateResidentValue))
4631 err = undo_update_resident(vol, action, buffer);
4632 break;
4633 case Win10Action37 :
4634 if (action->record.undo_operation
4635 == const_cpu_to_le16(Noop))
4636 err = undo_action37(vol, action, buffer);
4637 break;
4638 case WriteEndofFileRecordSegment :
4639 if (action->record.undo_operation
4640 == const_cpu_to_le16(WriteEndofFileRecordSegment))
4641 err = undo_write_end(vol, action, buffer);
4642 break;
4643 case WriteEndOfIndexBuffer :
4644 if (action->record.undo_operation
4645 == const_cpu_to_le16(WriteEndOfIndexBuffer))
4646 err = undo_write_index(vol, action, buffer);
4647 break;
4648 case AttributeNamesDump :
4649 case CompensationlogRecord :
4650 case DirtyPageTableDump :
4651 case ForgetTransaction :
4652 case Noop :
4653 case OpenAttributeTableDump :
4654 break;
4655 default :
4656 printf("** Unsupported undo %s\n", actionname(rop));
4657 err = 1;
4658 break;
4659 }
4660 if (err)
4661 printf("* Undoing action %d %s (%s) failed\n",
4662 action->num,actionname(rop), actionname(uop));
4663 return (err);
4664 }
4665
4666 /*
4667 * Undo a single action
4668 *
4669 * The record the action acts on is read and, when it is an MFT or
4670 * INDX one, the need for undoing is checked.
4671 */
4672
play_one_undo(ntfs_volume * vol,const struct ACTION_RECORD * action)4673 static int play_one_undo(ntfs_volume *vol, const struct ACTION_RECORD *action)
4674 {
4675 MFT_RECORD *entry;
4676 INDEX_BLOCK *indx;
4677 char *buffer;
4678 u32 xsize;
4679 u16 rop;
4680 u16 uop;
4681 int err;
4682 BOOL executed;
4683 enum ACTION_KIND kind;
4684
4685 err = 0;
4686 rop = le16_to_cpu(action->record.redo_operation);
4687 uop = le16_to_cpu(action->record.undo_operation);
4688 if (optv)
4689 printf("Undo action %d %s (%s) lsn 0x%llx\n",
4690 action->num,
4691 actionname(rop), actionname(uop),
4692 (long long)sle64_to_cpu(
4693 action->record.this_lsn));
4694 buffer = (char*)NULL;
4695 executed = FALSE;
4696 kind = ON_NONE;
4697 switch (rop) {
4698 /* Actions always acting on MFT */
4699 case AddIndexEntryRoot :
4700 case CreateAttribute :
4701 case DeallocateFileRecordSegment :
4702 case DeleteAttribute :
4703 case DeleteIndexEntryRoot :
4704 case InitializeFileRecordSegment :
4705 case SetIndexEntryVcnRoot :
4706 case SetNewAttributeSizes :
4707 case UpdateFileNameRoot :
4708 case UpdateMappingPairs :
4709 case UpdateResidentValue :
4710 case Win10Action37 :
4711 case WriteEndofFileRecordSegment :
4712 kind = ON_MFT;
4713 break;
4714 /* Actions always acting on INDX */
4715 case AddIndexEntryAllocation :
4716 case DeleteIndexEntryAllocation :
4717 case SetIndexEntryVcnAllocation :
4718 case UpdateFileNameAllocation :
4719 case WriteEndOfIndexBuffer :
4720 kind = ON_INDX;
4721 break;
4722 /* Actions never acting on MFT or INDX */
4723 case ClearBitsInNonResidentBitMap :
4724 case SetBitsInNonResidentBitMap :
4725 kind = ON_RAW;
4726 break;
4727 /* Actions which may act on MFT */
4728 case Noop : /* on MFT if DeallocateFileRecordSegment */
4729 break;
4730 /* Actions which may act on INDX */
4731 case UpdateNonResidentValue :
4732 /* Known cases : INDX, $SDS, ATTR_LIST */
4733 kind = get_action_kind(action);
4734 if (kind == ON_NONE)
4735 err = 1;
4736 break;
4737 case OpenNonResidentAttribute :
4738 /* probably not important */
4739 kind = ON_NONE;
4740 break;
4741 /* Actions currently ignored */
4742 case AttributeNamesDump :
4743 case CommitTransaction :
4744 case CompensationlogRecord :
4745 case DeleteDirtyClusters :
4746 case DirtyPageTableDump :
4747 case EndTopLevelAction :
4748 case ForgetTransaction :
4749 case HotFix :
4750 case OpenAttributeTableDump :
4751 case PrepareTransaction :
4752 case TransactionTableDump :
4753 case UpdateRecordDataAllocation :
4754 case UpdateRecordDataRoot :
4755 case Win10Action35 :
4756 case Win10Action36 :
4757 kind = ON_NONE;
4758 break;
4759 }
4760 switch (kind) {
4761 case ON_MFT :
4762 /*
4763 the check below cannot be used on WinXP
4764 if (!(action->record.attribute_flags & ACTS_ON_MFT))
4765 printf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num);
4766 */
4767 buffer = read_protected(vol, &action->record, mftrecsz, TRUE);
4768 entry = (MFT_RECORD*)buffer;
4769 if (entry) {
4770 if (entry->magic == magic_FILE) {
4771 executed = !older_record(entry,
4772 &action->record);
4773 if (!executed
4774 && exception(action->num))
4775 executed = TRUE;
4776 if (optv > 1)
4777 printf("record lsn 0x%llx is %s than action %d lsn 0x%llx\n",
4778 (long long)sle64_to_cpu(entry->lsn),
4779 (executed ? "not older" : "older"),
4780 (int)action->num,
4781 (long long)sle64_to_cpu(action->record.this_lsn));
4782 } else {
4783 printf("** %s (action %d) not acting on MFT\n",
4784 actionname(rop), (int)action->num);
4785 err = 1;
4786 }
4787 } else {
4788 /*
4789 * Could not read the MFT record :
4790 * if this is undoing a record create (from scratch)
4791 * which did not take place, there is nothing to redo,
4792 * otherwise this is an error.
4793 */
4794 if (check_full_mft(action,TRUE))
4795 executed = FALSE;
4796 else
4797 err = 1;
4798 }
4799 break;
4800 case ON_INDX :
4801 /*
4802 the check below cannot be used on WinXP
4803 if (!(action->record.attribute_flags & ACTS_ON_INDX))
4804 printf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num);
4805 */
4806 xsize = vol->indx_record_size;
4807 buffer = read_protected(vol, &action->record, xsize, TRUE);
4808 indx = (INDEX_BLOCK*)buffer;
4809 if (indx) {
4810 if (indx->magic == magic_INDX) {
4811 executed = !older_record(indx,
4812 &action->record);
4813 if (!executed
4814 && exception(action->num))
4815 executed = TRUE;
4816 if (optv > 1)
4817 printf("index lsn 0x%llx is %s than action %d lsn 0x%llx\n",
4818 (long long)sle64_to_cpu(indx->lsn),
4819 (executed ? "not older" : "older"),
4820 (int)action->num,
4821 (long long)sle64_to_cpu(action->record.this_lsn));
4822 } else {
4823 printf("** %s (action %d) not acting on INDX\n",
4824 actionname(rop), (int)action->num);
4825 err = 1;
4826 }
4827 } else {
4828 /*
4829 * Could not read the INDX record :
4830 * if this is undoing a record create (from scratch)
4831 * which did not take place, there is nothing to redo,
4832 * otherwise this must be an error.
4833 * However, after deleting the last index allocation
4834 * in a block, the block is apparently zeroed
4835 * and cannot be read. In this case we have to
4836 * create an initial index block and apply the undo.
4837 */
4838 if (check_full_index(action,TRUE))
4839 executed = FALSE;
4840 else {
4841 err = 1;
4842 if (uop == AddIndexEntryAllocation) {
4843 executed = TRUE;
4844 buffer = (char*)calloc(1, xsize);
4845 if (buffer)
4846 err = create_indx(vol,
4847 action, buffer);
4848 }
4849 }
4850 }
4851 break;
4852 case ON_RAW :
4853 if (action->record.attribute_flags
4854 & (ACTS_ON_INDX | ACTS_ON_MFT)) {
4855 printf("** Error : action %s on MFT or INDX\n",
4856 actionname(rop));
4857 err = 1;
4858 } else {
4859 buffer = read_raw(vol, &action->record);
4860 if (!buffer)
4861 err = 1;
4862 }
4863 executed = TRUE;
4864 break;
4865 default :
4866 executed = TRUE;
4867 buffer = (char*)NULL;
4868 break;
4869 }
4870 if (!err && executed) {
4871 err = distribute_undos(vol, action, buffer);
4872 undocount++;
4873 }
4874 if (buffer)
4875 free(buffer);
4876
4877 return (err);
4878 }
4879
4880 /*
4881 * Play the undo actions from latest to earliest
4882 *
4883 * For structured record, a check is made on the lsn to only
4884 * try to undo the actions which were executed. This implies
4885 * identifying actions on a structured record.
4886 *
4887 * Returns 0 if successful
4888 */
4889
play_undos(ntfs_volume * vol,const struct ACTION_RECORD * lastaction)4890 int play_undos(ntfs_volume *vol, const struct ACTION_RECORD *lastaction)
4891 {
4892 const struct ACTION_RECORD *action;
4893 int err;
4894
4895 err = 0;
4896 action = lastaction;
4897 while (action && !err) {
4898 if (!optc || within_lcn_range(&action->record))
4899 err = play_one_undo(vol, action);
4900 if (!err)
4901 action = action->prev;
4902 }
4903 return (err);
4904 }
4905