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