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