1987da915Sopenharmony_ci/* 2987da915Sopenharmony_ci * Redo or undo a list of logged actions 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2014-2017 Jean-Pierre Andre 5987da915Sopenharmony_ci * 6987da915Sopenharmony_ci */ 7987da915Sopenharmony_ci 8987da915Sopenharmony_ci/* 9987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 10987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by 11987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 12987da915Sopenharmony_ci * (at your option) any later version. 13987da915Sopenharmony_ci * 14987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful, 15987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 16987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17987da915Sopenharmony_ci * GNU General Public License for more details. 18987da915Sopenharmony_ci * 19987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 20987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G 21987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 22987da915Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 23987da915Sopenharmony_ci */ 24987da915Sopenharmony_ci 25987da915Sopenharmony_ci#include "config.h" 26987da915Sopenharmony_ci 27987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 28987da915Sopenharmony_ci#include <stdlib.h> 29987da915Sopenharmony_ci#endif 30987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 31987da915Sopenharmony_ci#include <stdio.h> 32987da915Sopenharmony_ci#endif 33987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H 34987da915Sopenharmony_ci#include <unistd.h> 35987da915Sopenharmony_ci#endif 36987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H 37987da915Sopenharmony_ci#include <fcntl.h> 38987da915Sopenharmony_ci#endif 39987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 40987da915Sopenharmony_ci#include <errno.h> 41987da915Sopenharmony_ci#endif 42987da915Sopenharmony_ci#ifdef HAVE_STRING_H 43987da915Sopenharmony_ci#include <string.h> 44987da915Sopenharmony_ci#endif 45987da915Sopenharmony_ci#ifdef HAVE_MALLOC_H 46987da915Sopenharmony_ci#include <malloc.h> 47987da915Sopenharmony_ci#endif 48987da915Sopenharmony_ci#ifdef HAVE_TIME_H 49987da915Sopenharmony_ci#include <time.h> 50987da915Sopenharmony_ci#endif 51987da915Sopenharmony_ci 52987da915Sopenharmony_ci#include "types.h" 53987da915Sopenharmony_ci#include "endians.h" 54987da915Sopenharmony_ci#include "support.h" 55987da915Sopenharmony_ci#include "layout.h" 56987da915Sopenharmony_ci#include "param.h" 57987da915Sopenharmony_ci#include "ntfstime.h" 58987da915Sopenharmony_ci#include "device_io.h" 59987da915Sopenharmony_ci#include "device.h" 60987da915Sopenharmony_ci#include "logging.h" 61987da915Sopenharmony_ci#include "runlist.h" 62987da915Sopenharmony_ci#include "mft.h" 63987da915Sopenharmony_ci#include "inode.h" 64987da915Sopenharmony_ci#include "attrib.h" 65987da915Sopenharmony_ci#include "bitmap.h" 66987da915Sopenharmony_ci#include "index.h" 67987da915Sopenharmony_ci#include "volume.h" 68987da915Sopenharmony_ci#include "unistr.h" 69987da915Sopenharmony_ci#include "mst.h" 70987da915Sopenharmony_ci#include "logfile.h" 71987da915Sopenharmony_ci#include "ntfsrecover.h" 72987da915Sopenharmony_ci#include "misc.h" 73987da915Sopenharmony_ci 74987da915Sopenharmony_cistruct STORE { 75987da915Sopenharmony_ci struct STORE *upper; 76987da915Sopenharmony_ci struct STORE *lower; 77987da915Sopenharmony_ci LCN lcn; 78987da915Sopenharmony_ci char data[1]; 79987da915Sopenharmony_ci} ; 80987da915Sopenharmony_ci 81987da915Sopenharmony_ci#define dump hexdump 82987da915Sopenharmony_ci 83987da915Sopenharmony_cistruct STORE *cluster_door = (struct STORE*)NULL; 84987da915Sopenharmony_ci 85987da915Sopenharmony_ci/* check whether a MFT or INDX record is older than action */ 86987da915Sopenharmony_ci#define older_record(rec, logr) ((s64)(sle64_to_cpu((rec)->lsn) \ 87987da915Sopenharmony_ci - sle64_to_cpu((logr)->this_lsn)) < 0) 88987da915Sopenharmony_ci/* check whether a MFT or INDX record is newer than action */ 89987da915Sopenharmony_ci#define newer_record(rec, logr) ((s64)(sle64_to_cpu((rec)->lsn) \ 90987da915Sopenharmony_ci - sle64_to_cpu((logr)->this_lsn)) > 0) 91987da915Sopenharmony_ci 92987da915Sopenharmony_ci/* 93987da915Sopenharmony_ci * A few functions for debugging 94987da915Sopenharmony_ci */ 95987da915Sopenharmony_ci 96987da915Sopenharmony_cistatic int matchcount(const char *d, const char *s, int n) 97987da915Sopenharmony_ci{ 98987da915Sopenharmony_ci int m; 99987da915Sopenharmony_ci 100987da915Sopenharmony_ci m = 0; 101987da915Sopenharmony_ci while ((--n >= 0) && (*d++ == *s++)) m++; 102987da915Sopenharmony_ci return (m); 103987da915Sopenharmony_ci} 104987da915Sopenharmony_ci 105987da915Sopenharmony_ci/* 106987da915Sopenharmony_cistatic void locate(const char *s, int n, const char *p, int m) 107987da915Sopenharmony_ci{ 108987da915Sopenharmony_ci int i,j; 109987da915Sopenharmony_ci 110987da915Sopenharmony_ci for (i=0; i<=(n - m); i++) 111987da915Sopenharmony_ci if (s[i] == *p) { 112987da915Sopenharmony_ci j = 1; 113987da915Sopenharmony_ci while ((j < m) && (s[i + j] == p[j])) 114987da915Sopenharmony_ci j++; 115987da915Sopenharmony_ci if (j == m) 116987da915Sopenharmony_ci printf("=== found at offset 0x%x %d\n",i,i); 117987da915Sopenharmony_ci } 118987da915Sopenharmony_ci} 119987da915Sopenharmony_ci*/ 120987da915Sopenharmony_ci 121987da915Sopenharmony_cistatic u64 inode_number(const LOG_RECORD *logr) 122987da915Sopenharmony_ci{ 123987da915Sopenharmony_ci u64 offset; 124987da915Sopenharmony_ci 125987da915Sopenharmony_ci offset = ((u64)sle64_to_cpu(logr->target_vcn) 126987da915Sopenharmony_ci << clusterbits) 127987da915Sopenharmony_ci + ((u32)le16_to_cpu(logr->cluster_index) 128987da915Sopenharmony_ci << NTFS_BLOCK_SIZE_BITS); 129987da915Sopenharmony_ci return (offset >> mftrecbits); 130987da915Sopenharmony_ci} 131987da915Sopenharmony_ci 132987da915Sopenharmony_ci/* 133987da915Sopenharmony_ci * Find an in-memory copy of a needed cluster 134987da915Sopenharmony_ci * 135987da915Sopenharmony_ci * Optionally, allocate a copy. 136987da915Sopenharmony_ci */ 137987da915Sopenharmony_ci 138987da915Sopenharmony_cistatic struct STORE *getclusterentry(LCN lcn, BOOL create) 139987da915Sopenharmony_ci{ 140987da915Sopenharmony_ci struct STORE **current; 141987da915Sopenharmony_ci struct STORE *newone; 142987da915Sopenharmony_ci 143987da915Sopenharmony_ci current = &cluster_door; 144987da915Sopenharmony_ci /* A minimal binary tree should be enough */ 145987da915Sopenharmony_ci while (*current && (lcn != (*current)->lcn)) { 146987da915Sopenharmony_ci if (lcn > (*current)->lcn) 147987da915Sopenharmony_ci current = &(*current)->upper; 148987da915Sopenharmony_ci else 149987da915Sopenharmony_ci current = &(*current)->lower; 150987da915Sopenharmony_ci } 151987da915Sopenharmony_ci if (create && !*current) { 152987da915Sopenharmony_ci newone = (struct STORE*)malloc(sizeof(struct STORE) 153987da915Sopenharmony_ci + clustersz); 154987da915Sopenharmony_ci if (newone) { 155987da915Sopenharmony_ci newone->upper = (struct STORE*)NULL; 156987da915Sopenharmony_ci newone->lower = (struct STORE*)NULL; 157987da915Sopenharmony_ci newone->lcn = lcn; 158987da915Sopenharmony_ci *current = newone; 159987da915Sopenharmony_ci } 160987da915Sopenharmony_ci } 161987da915Sopenharmony_ci return (*current); 162987da915Sopenharmony_ci} 163987da915Sopenharmony_ci 164987da915Sopenharmony_civoid freeclusterentry(struct STORE *entry) 165987da915Sopenharmony_ci{ 166987da915Sopenharmony_ci if (!entry) { 167987da915Sopenharmony_ci if (cluster_door) 168987da915Sopenharmony_ci freeclusterentry(cluster_door); 169987da915Sopenharmony_ci cluster_door = (struct STORE*)NULL; 170987da915Sopenharmony_ci } else { 171987da915Sopenharmony_ci if (optv) 172987da915Sopenharmony_ci printf("* cluster 0x%llx %s updated\n", 173987da915Sopenharmony_ci (long long)entry->lcn, 174987da915Sopenharmony_ci (optn ? "would be" : "was")); 175987da915Sopenharmony_ci if (entry->upper) 176987da915Sopenharmony_ci freeclusterentry(entry->upper); 177987da915Sopenharmony_ci if (entry->lower) 178987da915Sopenharmony_ci freeclusterentry(entry->lower); 179987da915Sopenharmony_ci free(entry); 180987da915Sopenharmony_ci } 181987da915Sopenharmony_ci} 182987da915Sopenharmony_ci 183987da915Sopenharmony_ci/* 184987da915Sopenharmony_ci * Check whether an attribute type is a valid one 185987da915Sopenharmony_ci */ 186987da915Sopenharmony_ci 187987da915Sopenharmony_cistatic BOOL valid_type(ATTR_TYPES type) 188987da915Sopenharmony_ci{ 189987da915Sopenharmony_ci BOOL ok; 190987da915Sopenharmony_ci 191987da915Sopenharmony_ci switch (type) { 192987da915Sopenharmony_ci case AT_STANDARD_INFORMATION : 193987da915Sopenharmony_ci case AT_ATTRIBUTE_LIST : 194987da915Sopenharmony_ci case AT_FILE_NAME : 195987da915Sopenharmony_ci case AT_OBJECT_ID : 196987da915Sopenharmony_ci case AT_SECURITY_DESCRIPTOR : 197987da915Sopenharmony_ci case AT_VOLUME_NAME : 198987da915Sopenharmony_ci case AT_VOLUME_INFORMATION : 199987da915Sopenharmony_ci case AT_DATA : 200987da915Sopenharmony_ci case AT_INDEX_ROOT : 201987da915Sopenharmony_ci case AT_INDEX_ALLOCATION : 202987da915Sopenharmony_ci case AT_BITMAP : 203987da915Sopenharmony_ci case AT_REPARSE_POINT : 204987da915Sopenharmony_ci case AT_EA_INFORMATION : 205987da915Sopenharmony_ci case AT_EA : 206987da915Sopenharmony_ci case AT_PROPERTY_SET : 207987da915Sopenharmony_ci case AT_LOGGED_UTILITY_STREAM : 208987da915Sopenharmony_ci case AT_FIRST_USER_DEFINED_ATTRIBUTE : 209987da915Sopenharmony_ci case AT_END : 210987da915Sopenharmony_ci ok = TRUE; 211987da915Sopenharmony_ci break; 212987da915Sopenharmony_ci default : 213987da915Sopenharmony_ci ok = FALSE; 214987da915Sopenharmony_ci break; 215987da915Sopenharmony_ci } 216987da915Sopenharmony_ci return (ok); 217987da915Sopenharmony_ci} 218987da915Sopenharmony_ci 219987da915Sopenharmony_ci/* 220987da915Sopenharmony_ci * Rough check of sanity of an index list 221987da915Sopenharmony_ci */ 222987da915Sopenharmony_ci 223987da915Sopenharmony_cistatic int sanity_indx_list(const char *buffer, u32 k, u32 end) 224987da915Sopenharmony_ci{ 225987da915Sopenharmony_ci le64 inode; 226987da915Sopenharmony_ci int err; 227987da915Sopenharmony_ci int lth; 228987da915Sopenharmony_ci BOOL done; 229987da915Sopenharmony_ci 230987da915Sopenharmony_ci err = 0; 231987da915Sopenharmony_ci done = FALSE; 232987da915Sopenharmony_ci while ((k <= end) && !done && !err) { 233987da915Sopenharmony_ci lth = getle16(buffer,k+8); 234987da915Sopenharmony_ci if (optv > 1) 235987da915Sopenharmony_ci /* Usual indexes can be determined from size */ 236987da915Sopenharmony_ci switch (lth) { 237987da915Sopenharmony_ci case 16 : /* final without subnode */ 238987da915Sopenharmony_ci case 24 : /* final with subnode */ 239987da915Sopenharmony_ci printf("index to none lth 0x%x" 240987da915Sopenharmony_ci " flags 0x%x pos 0x%x\n", 241987da915Sopenharmony_ci (int)lth, 242987da915Sopenharmony_ci (int)getle16(buffer,k+12),(int)k); 243987da915Sopenharmony_ci break; 244987da915Sopenharmony_ci case 32 : /* $R in $Reparse */ 245987da915Sopenharmony_ci /* Badly aligned */ 246987da915Sopenharmony_ci memcpy(&inode, &buffer[k + 20], 8); 247987da915Sopenharmony_ci printf("index to reparse of 0x%016llx lth 0x%x" 248987da915Sopenharmony_ci " flags 0x%x pos 0x%x\n", 249987da915Sopenharmony_ci (long long)le64_to_cpu(inode), 250987da915Sopenharmony_ci (int)lth, 251987da915Sopenharmony_ci (int)getle16(buffer,k+12),(int)k); 252987da915Sopenharmony_ci break; 253987da915Sopenharmony_ci case 40 : /* $SII in $Secure */ 254987da915Sopenharmony_ci printf("index to securid 0x%lx lth 0x%x" 255987da915Sopenharmony_ci " flags 0x%x pos 0x%x\n", 256987da915Sopenharmony_ci (long)getle32(buffer,k + 16), 257987da915Sopenharmony_ci (int)lth, 258987da915Sopenharmony_ci (int)getle16(buffer,k+12),(int)k); 259987da915Sopenharmony_ci break; 260987da915Sopenharmony_ci case 48 : /* $SDH in $Secure */ 261987da915Sopenharmony_ci printf("index to securid 0x%lx lth 0x%x" 262987da915Sopenharmony_ci " flags 0x%x pos 0x%x\n", 263987da915Sopenharmony_ci (long)getle32(buffer,k + 20), 264987da915Sopenharmony_ci (int)lth, 265987da915Sopenharmony_ci (int)getle16(buffer,k+12),(int)k); 266987da915Sopenharmony_ci break; 267987da915Sopenharmony_ci default : /* at least 80 */ 268987da915Sopenharmony_ci printf("index to inode 0x%016llx lth 0x%x" 269987da915Sopenharmony_ci " flags 0x%x pos 0x%x\n", 270987da915Sopenharmony_ci (long long)getle64(buffer,k), 271987da915Sopenharmony_ci (int)lth, 272987da915Sopenharmony_ci (int)getle16(buffer,k+12),(int)k); 273987da915Sopenharmony_ci if ((lth < 80) || (lth & 7)) { 274987da915Sopenharmony_ci printf("** Invalid index record" 275987da915Sopenharmony_ci " length %d\n",lth); 276987da915Sopenharmony_ci err = 1; 277987da915Sopenharmony_ci } 278987da915Sopenharmony_ci } 279987da915Sopenharmony_ci done = (feedle16(buffer,k+12) & INDEX_ENTRY_END) || !lth; 280987da915Sopenharmony_ci if (lth & 7) { 281987da915Sopenharmony_ci if (optv <= 1) /* Do not repeat the warning */ 282987da915Sopenharmony_ci printf("** Invalid index record length %d\n", 283987da915Sopenharmony_ci lth); 284987da915Sopenharmony_ci err = 1; 285987da915Sopenharmony_ci } else 286987da915Sopenharmony_ci k += lth; 287987da915Sopenharmony_ci } 288987da915Sopenharmony_ci if (k != end) { 289987da915Sopenharmony_ci printf("** Bad index record length %ld (computed %ld)\n", 290987da915Sopenharmony_ci (long)end, (long)k); 291987da915Sopenharmony_ci err = 1; 292987da915Sopenharmony_ci } 293987da915Sopenharmony_ci if (!done) { 294987da915Sopenharmony_ci printf("** Missing end of index mark\n"); 295987da915Sopenharmony_ci err = 1; 296987da915Sopenharmony_ci } 297987da915Sopenharmony_ci return (err); 298987da915Sopenharmony_ci} 299987da915Sopenharmony_ci 300987da915Sopenharmony_ci/* 301987da915Sopenharmony_ci * Rough check of sanity of an mft record 302987da915Sopenharmony_ci */ 303987da915Sopenharmony_ci 304987da915Sopenharmony_cistatic int sanity_mft(const char *buffer) 305987da915Sopenharmony_ci{ 306987da915Sopenharmony_ci const MFT_RECORD *record; 307987da915Sopenharmony_ci const ATTR_RECORD *attr; 308987da915Sopenharmony_ci u64 instances; 309987da915Sopenharmony_ci u32 k; 310987da915Sopenharmony_ci u32 type; 311987da915Sopenharmony_ci u32 prevtype; 312987da915Sopenharmony_ci u16 nextinstance; 313987da915Sopenharmony_ci u16 instance; 314987da915Sopenharmony_ci int err; 315987da915Sopenharmony_ci 316987da915Sopenharmony_ci err = 0; 317987da915Sopenharmony_ci record = (const MFT_RECORD*)buffer; 318987da915Sopenharmony_ci nextinstance = le16_to_cpu(record->next_attr_instance); 319987da915Sopenharmony_ci instances = 0; 320987da915Sopenharmony_ci k = le16_to_cpu(record->attrs_offset); 321987da915Sopenharmony_ci attr = (const ATTR_RECORD*)&buffer[k]; 322987da915Sopenharmony_ci prevtype = 0; 323987da915Sopenharmony_ci while ((k < mftrecsz) 324987da915Sopenharmony_ci && (attr->type != AT_END) 325987da915Sopenharmony_ci && valid_type(attr->type)) { 326987da915Sopenharmony_ci type = le32_to_cpu(attr->type); 327987da915Sopenharmony_ci if (type < prevtype) { 328987da915Sopenharmony_ci printf("** Bad type ordering 0x%lx after 0x%lx\n", 329987da915Sopenharmony_ci (long)type, (long)prevtype); 330987da915Sopenharmony_ci err = 1; 331987da915Sopenharmony_ci } 332987da915Sopenharmony_ci instance = le16_to_cpu(attr->instance); 333987da915Sopenharmony_ci /* Can nextinstance wrap around ? */ 334987da915Sopenharmony_ci if (instance >= nextinstance) { 335987da915Sopenharmony_ci printf("** Bad attr instance %d (max %d)\n", 336987da915Sopenharmony_ci (int)instance, (int)nextinstance - 1); 337987da915Sopenharmony_ci err = 1; 338987da915Sopenharmony_ci } 339987da915Sopenharmony_ci if (instance < 64) { 340987da915Sopenharmony_ci /* Only check up to 64 */ 341987da915Sopenharmony_ci if (((u64)1 << instance) & instances) { 342987da915Sopenharmony_ci printf("** Duplicated attr instance %d\n", 343987da915Sopenharmony_ci (int)instance); 344987da915Sopenharmony_ci } 345987da915Sopenharmony_ci instances |= (u64)1 << instance; 346987da915Sopenharmony_ci } 347987da915Sopenharmony_ci if (optv > 1) { 348987da915Sopenharmony_ci if ((attr->type == AT_FILE_NAME) 349987da915Sopenharmony_ci && buffer[k + 88]) { 350987da915Sopenharmony_ci printf("attr %08lx offs 0x%x nres %d", 351987da915Sopenharmony_ci (long)type, (int)k, 352987da915Sopenharmony_ci (int)attr->non_resident); 353987da915Sopenharmony_ci showname(" ",&buffer[k+90], 354987da915Sopenharmony_ci buffer[k + 88] & 255); 355987da915Sopenharmony_ci } else 356987da915Sopenharmony_ci printf("attr %08lx offs 0x%x nres %d\n", 357987da915Sopenharmony_ci (long)type, (int)k, 358987da915Sopenharmony_ci (int)attr->non_resident); 359987da915Sopenharmony_ci } 360987da915Sopenharmony_ci if ((attr->type == AT_INDEX_ROOT) 361987da915Sopenharmony_ci && sanity_indx_list(buffer, 362987da915Sopenharmony_ci k + le16_to_cpu(attr->value_offset) + 32, 363987da915Sopenharmony_ci k + le32_to_cpu(attr->length))) { 364987da915Sopenharmony_ci err = 1; 365987da915Sopenharmony_ci } 366987da915Sopenharmony_ci k += le32_to_cpu(attr->length); 367987da915Sopenharmony_ci attr = (const ATTR_RECORD*)&buffer[k]; 368987da915Sopenharmony_ci prevtype = type; 369987da915Sopenharmony_ci } 370987da915Sopenharmony_ci if ((optv > 1) && (attr->type == AT_END)) 371987da915Sopenharmony_ci printf("attr %08lx offs 0x%x\n", 372987da915Sopenharmony_ci (long)le32_to_cpu(attr->type), (int)k); 373987da915Sopenharmony_ci if ((attr->type != AT_END) 374987da915Sopenharmony_ci || (le32_to_cpu(record->bytes_in_use) != (k + 8)) 375987da915Sopenharmony_ci || (le32_to_cpu(record->bytes_allocated) < (k + 8))) { 376987da915Sopenharmony_ci printf("** Bad MFT record length %ld" 377987da915Sopenharmony_ci " (computed %ld allocated %ld)\n", 378987da915Sopenharmony_ci (long)le32_to_cpu(record->bytes_in_use), 379987da915Sopenharmony_ci (long)(k + 8), 380987da915Sopenharmony_ci (long)le32_to_cpu(record->bytes_allocated)); 381987da915Sopenharmony_ci err = 1; 382987da915Sopenharmony_ci } 383987da915Sopenharmony_ci return (err); 384987da915Sopenharmony_ci} 385987da915Sopenharmony_ci 386987da915Sopenharmony_ci/* 387987da915Sopenharmony_ci * Rough check of sanity of an index block 388987da915Sopenharmony_ci */ 389987da915Sopenharmony_ci 390987da915Sopenharmony_cistatic int sanity_indx(ntfs_volume *vol, const char *buffer) 391987da915Sopenharmony_ci{ 392987da915Sopenharmony_ci const INDEX_BLOCK *indx; 393987da915Sopenharmony_ci u32 k; 394987da915Sopenharmony_ci int err; 395987da915Sopenharmony_ci 396987da915Sopenharmony_ci err = 0; 397987da915Sopenharmony_ci indx = (const INDEX_BLOCK*)buffer; 398987da915Sopenharmony_ci k = offsetof(INDEX_BLOCK, index) + 399987da915Sopenharmony_ci le32_to_cpu(indx->index.entries_offset); 400987da915Sopenharmony_ci err = sanity_indx_list(buffer, k, 401987da915Sopenharmony_ci le32_to_cpu(indx->index.index_length) + 24); 402987da915Sopenharmony_ci if ((le32_to_cpu(indx->index.index_length) 403987da915Sopenharmony_ci > le32_to_cpu(indx->index.allocated_size)) 404987da915Sopenharmony_ci || (le32_to_cpu(indx->index.allocated_size) 405987da915Sopenharmony_ci != (vol->indx_record_size - 24))) { 406987da915Sopenharmony_ci printf("** Bad index length %ld" 407987da915Sopenharmony_ci " (usable %ld allocated %ld)\n", 408987da915Sopenharmony_ci (long)le32_to_cpu(indx->index.index_length), 409987da915Sopenharmony_ci (long)(vol->indx_record_size - 24), 410987da915Sopenharmony_ci (long)le32_to_cpu(indx->index.allocated_size)); 411987da915Sopenharmony_ci err = 1; 412987da915Sopenharmony_ci } 413987da915Sopenharmony_ci return (err); 414987da915Sopenharmony_ci} 415987da915Sopenharmony_ci 416987da915Sopenharmony_ci 417987da915Sopenharmony_ci/* 418987da915Sopenharmony_ci * Allocate a buffer and read a full set of raw clusters 419987da915Sopenharmony_ci * 420987da915Sopenharmony_ci * Do not use for accessing $LogFile. 421987da915Sopenharmony_ci * With option -n reading is first attempted from the memory store 422987da915Sopenharmony_ci */ 423987da915Sopenharmony_ci 424987da915Sopenharmony_cistatic char *read_raw(ntfs_volume *vol, const LOG_RECORD *logr) 425987da915Sopenharmony_ci{ 426987da915Sopenharmony_ci char *buffer; 427987da915Sopenharmony_ci char *target; 428987da915Sopenharmony_ci struct STORE *store; 429987da915Sopenharmony_ci LCN lcn; 430987da915Sopenharmony_ci int count; 431987da915Sopenharmony_ci int i; 432987da915Sopenharmony_ci BOOL fail; 433987da915Sopenharmony_ci 434987da915Sopenharmony_ci count = le16_to_cpu(logr->lcns_to_follow); 435987da915Sopenharmony_ci if (!count) { 436987da915Sopenharmony_ci printf("** Error : no lcn to read from\n"); 437987da915Sopenharmony_ci buffer = (char*)NULL; 438987da915Sopenharmony_ci } else 439987da915Sopenharmony_ci buffer = (char*)malloc(clustersz*count); 440987da915Sopenharmony_ci// TODO error messages 441987da915Sopenharmony_ci if (buffer) { 442987da915Sopenharmony_ci fail = FALSE; 443987da915Sopenharmony_ci for (i=0; (i<count) && !fail; i++) { 444987da915Sopenharmony_ci store = (struct STORE*)NULL; 445987da915Sopenharmony_ci lcn = sle64_to_cpu(logr->lcn_list[i]); 446987da915Sopenharmony_ci target = buffer + clustersz*i; 447987da915Sopenharmony_ci if (optn) { 448987da915Sopenharmony_ci store = getclusterentry(lcn, FALSE); 449987da915Sopenharmony_ci if (store) { 450987da915Sopenharmony_ci memcpy(target, store->data, clustersz); 451987da915Sopenharmony_ci if (optv) 452987da915Sopenharmony_ci printf("== lcn 0x%llx from store\n", 453987da915Sopenharmony_ci (long long)lcn); 454987da915Sopenharmony_ci if ((optv > 1) && optc 455987da915Sopenharmony_ci && within_lcn_range(logr)) 456987da915Sopenharmony_ci dump(store->data, clustersz); 457987da915Sopenharmony_ci } 458987da915Sopenharmony_ci } 459987da915Sopenharmony_ci if (!store 460987da915Sopenharmony_ci && (ntfs_pread(vol->dev, lcn << clusterbits, 461987da915Sopenharmony_ci clustersz, target) != clustersz)) { 462987da915Sopenharmony_ci fail = TRUE; 463987da915Sopenharmony_ci } else { 464987da915Sopenharmony_ci if (!store) { 465987da915Sopenharmony_ci if (optv) 466987da915Sopenharmony_ci printf("== lcn 0x%llx" 467987da915Sopenharmony_ci " from device\n", 468987da915Sopenharmony_ci (long long)lcn); 469987da915Sopenharmony_ci if ((optv > 1) && optc 470987da915Sopenharmony_ci && within_lcn_range(logr)) 471987da915Sopenharmony_ci dump(target, clustersz); 472987da915Sopenharmony_ci } 473987da915Sopenharmony_ci } 474987da915Sopenharmony_ci } 475987da915Sopenharmony_ci if (fail) { 476987da915Sopenharmony_ci printf("** Could not read cluster 0x%llx\n", 477987da915Sopenharmony_ci (long long)lcn); 478987da915Sopenharmony_ci free(buffer); 479987da915Sopenharmony_ci buffer = (char*)NULL; 480987da915Sopenharmony_ci } 481987da915Sopenharmony_ci } 482987da915Sopenharmony_ci return (buffer); 483987da915Sopenharmony_ci} 484987da915Sopenharmony_ci 485987da915Sopenharmony_ci/* 486987da915Sopenharmony_ci * Write a full set of raw clusters 487987da915Sopenharmony_ci * 488987da915Sopenharmony_ci * Do not use for accessing $LogFile. 489987da915Sopenharmony_ci * With option -n a copy of the buffer is kept in memory for later use. 490987da915Sopenharmony_ci */ 491987da915Sopenharmony_ci 492987da915Sopenharmony_cistatic int write_raw(ntfs_volume *vol, const LOG_RECORD *logr, 493987da915Sopenharmony_ci char *buffer) 494987da915Sopenharmony_ci{ 495987da915Sopenharmony_ci int err; 496987da915Sopenharmony_ci struct STORE *store; 497987da915Sopenharmony_ci LCN lcn; 498987da915Sopenharmony_ci char *source; 499987da915Sopenharmony_ci int count; 500987da915Sopenharmony_ci int i; 501987da915Sopenharmony_ci 502987da915Sopenharmony_ci err = 0; 503987da915Sopenharmony_ci count = le16_to_cpu(logr->lcns_to_follow); 504987da915Sopenharmony_ci if (!count) 505987da915Sopenharmony_ci printf("** Error : no lcn to write to\n"); 506987da915Sopenharmony_ci if (optn) { 507987da915Sopenharmony_ci for (i=0; (i<count) && !err; i++) { 508987da915Sopenharmony_ci lcn = sle64_to_cpu(logr->lcn_list[i]); 509987da915Sopenharmony_ci source = buffer + clustersz*i; 510987da915Sopenharmony_ci store = getclusterentry(lcn, TRUE); 511987da915Sopenharmony_ci if (store) { 512987da915Sopenharmony_ci memcpy(store->data, source, clustersz); 513987da915Sopenharmony_ci if (optv) 514987da915Sopenharmony_ci printf("== lcn 0x%llx to store\n", 515987da915Sopenharmony_ci (long long)lcn); 516987da915Sopenharmony_ci if ((optv > 1) && optc 517987da915Sopenharmony_ci && within_lcn_range(logr)) 518987da915Sopenharmony_ci dump(store->data, clustersz); 519987da915Sopenharmony_ci } else { 520987da915Sopenharmony_ci printf("** Could not store cluster 0x%llx\n", 521987da915Sopenharmony_ci (long long)lcn); 522987da915Sopenharmony_ci err = 1; 523987da915Sopenharmony_ci } 524987da915Sopenharmony_ci } 525987da915Sopenharmony_ci } else { 526987da915Sopenharmony_ci for (i=0; (i<count) && !err; i++) { 527987da915Sopenharmony_ci lcn = sle64_to_cpu(logr->lcn_list[i]); 528987da915Sopenharmony_ci if (optv) 529987da915Sopenharmony_ci printf("== lcn 0x%llx to device\n", 530987da915Sopenharmony_ci (long long)lcn); 531987da915Sopenharmony_ci source = buffer + clustersz*i; 532987da915Sopenharmony_ci if (ntfs_pwrite(vol->dev, lcn << clusterbits, 533987da915Sopenharmony_ci clustersz, source) != clustersz) { 534987da915Sopenharmony_ci printf("** Could not write cluster 0x%llx\n", 535987da915Sopenharmony_ci (long long)lcn); 536987da915Sopenharmony_ci err = 1; 537987da915Sopenharmony_ci } 538987da915Sopenharmony_ci } 539987da915Sopenharmony_ci } 540987da915Sopenharmony_ci return (err); 541987da915Sopenharmony_ci} 542987da915Sopenharmony_ci 543987da915Sopenharmony_ci/* 544987da915Sopenharmony_ci * Write a full set of raw clusters to mft_mirr 545987da915Sopenharmony_ci */ 546987da915Sopenharmony_ci 547987da915Sopenharmony_cistatic int write_mirr(ntfs_volume *vol, const LOG_RECORD *logr, 548987da915Sopenharmony_ci char *buffer) 549987da915Sopenharmony_ci{ 550987da915Sopenharmony_ci int err; 551987da915Sopenharmony_ci LCN lcn; 552987da915Sopenharmony_ci char *source; 553987da915Sopenharmony_ci int count; 554987da915Sopenharmony_ci int i; 555987da915Sopenharmony_ci 556987da915Sopenharmony_ci err = 0; 557987da915Sopenharmony_ci count = le16_to_cpu(logr->lcns_to_follow); 558987da915Sopenharmony_ci if (!count) 559987da915Sopenharmony_ci printf("** Error : no lcn to write to\n"); 560987da915Sopenharmony_ci if (!optn) { 561987da915Sopenharmony_ci for (i=0; (i<count) && !err; i++) { 562987da915Sopenharmony_ci lcn = ntfs_attr_vcn_to_lcn(vol->mftmirr_na, 563987da915Sopenharmony_ci sle64_to_cpu(logr->target_vcn) + i); 564987da915Sopenharmony_ci source = buffer + clustersz*i; 565987da915Sopenharmony_ci if ((lcn < 0) 566987da915Sopenharmony_ci || (ntfs_pwrite(vol->dev, lcn << clusterbits, 567987da915Sopenharmony_ci clustersz, source) != clustersz)) { 568987da915Sopenharmony_ci printf("** Could not write cluster 0x%llx\n", 569987da915Sopenharmony_ci (long long)lcn); 570987da915Sopenharmony_ci err = 1; 571987da915Sopenharmony_ci } 572987da915Sopenharmony_ci } 573987da915Sopenharmony_ci } 574987da915Sopenharmony_ci return (err); 575987da915Sopenharmony_ci} 576987da915Sopenharmony_ci 577987da915Sopenharmony_ci/* 578987da915Sopenharmony_ci * Allocate a buffer and read a single protected record 579987da915Sopenharmony_ci */ 580987da915Sopenharmony_ci 581987da915Sopenharmony_cistatic char *read_protected(ntfs_volume *vol, const LOG_RECORD *logr, 582987da915Sopenharmony_ci u32 size, BOOL warn) 583987da915Sopenharmony_ci{ 584987da915Sopenharmony_ci char *buffer; 585987da915Sopenharmony_ci char *full; 586987da915Sopenharmony_ci u32 pos; 587987da915Sopenharmony_ci LCN lcn; 588987da915Sopenharmony_ci 589987da915Sopenharmony_ci /* read full clusters */ 590987da915Sopenharmony_ci buffer = read_raw(vol, logr); 591987da915Sopenharmony_ci /* 592987da915Sopenharmony_ci * if the record is smaller than a cluster, 593987da915Sopenharmony_ci * make a partial copy and free the full buffer 594987da915Sopenharmony_ci */ 595987da915Sopenharmony_ci if (buffer && (size < clustersz)) { 596987da915Sopenharmony_ci full = buffer; 597987da915Sopenharmony_ci buffer = (char*)malloc(size); 598987da915Sopenharmony_ci if (buffer) { 599987da915Sopenharmony_ci pos = le16_to_cpu(logr->cluster_index) 600987da915Sopenharmony_ci << NTFS_BLOCK_SIZE_BITS; 601987da915Sopenharmony_ci memcpy(buffer, full + pos, size); 602987da915Sopenharmony_ci } 603987da915Sopenharmony_ci free(full); 604987da915Sopenharmony_ci } 605987da915Sopenharmony_ci if (buffer && (ntfs_mst_post_read_fixup_warn( 606987da915Sopenharmony_ci (NTFS_RECORD*)buffer, size, FALSE) < 0)) { 607987da915Sopenharmony_ci if (warn) { 608987da915Sopenharmony_ci lcn = sle64_to_cpu(logr->lcn_list[0]); 609987da915Sopenharmony_ci printf("** Invalid protected record at 0x%llx" 610987da915Sopenharmony_ci " index %d\n", 611987da915Sopenharmony_ci (long long)lcn, 612987da915Sopenharmony_ci (int)le16_to_cpu(logr->cluster_index)); 613987da915Sopenharmony_ci } 614987da915Sopenharmony_ci free(buffer); 615987da915Sopenharmony_ci buffer = (char*)NULL; 616987da915Sopenharmony_ci } 617987da915Sopenharmony_ci return (buffer); 618987da915Sopenharmony_ci} 619987da915Sopenharmony_ci 620987da915Sopenharmony_ci/* 621987da915Sopenharmony_ci * Protect a single record, write, and deallocate the buffer 622987da915Sopenharmony_ci * 623987da915Sopenharmony_ci * With option -n a copy of the buffer is kept in protected form in 624987da915Sopenharmony_ci * memory for later use. 625987da915Sopenharmony_ci * As the store only knows about clusters, if the record is smaller 626987da915Sopenharmony_ci * than a cluster, have to read, merge and write. 627987da915Sopenharmony_ci */ 628987da915Sopenharmony_ci 629987da915Sopenharmony_cistatic int write_protected(ntfs_volume *vol, const LOG_RECORD *logr, 630987da915Sopenharmony_ci char *buffer, u32 size) 631987da915Sopenharmony_ci{ 632987da915Sopenharmony_ci MFT_RECORD *record; 633987da915Sopenharmony_ci INDEX_BLOCK *indx; 634987da915Sopenharmony_ci char *full; 635987da915Sopenharmony_ci u32 pos; 636987da915Sopenharmony_ci BOOL mftmirr; 637987da915Sopenharmony_ci BOOL checked; 638987da915Sopenharmony_ci int err; 639987da915Sopenharmony_ci 640987da915Sopenharmony_ci err = 0; 641987da915Sopenharmony_ci mftmirr = FALSE; 642987da915Sopenharmony_ci checked = FALSE; 643987da915Sopenharmony_ci if ((size == mftrecsz) && !memcmp(buffer,"FILE",4)) { 644987da915Sopenharmony_ci record = (MFT_RECORD*)buffer; 645987da915Sopenharmony_ci if (optv) 646987da915Sopenharmony_ci printf("update inode %ld lsn 0x%llx" 647987da915Sopenharmony_ci " (record %s than action 0x%llx)\n", 648987da915Sopenharmony_ci (long)le32_to_cpu(record->mft_record_number), 649987da915Sopenharmony_ci (long long)sle64_to_cpu(record->lsn), 650987da915Sopenharmony_ci ((s64)(sle64_to_cpu(record->lsn) 651987da915Sopenharmony_ci - sle64_to_cpu(logr->this_lsn)) < 0 ? 652987da915Sopenharmony_ci "older" : "newer"), 653987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->this_lsn)); 654987da915Sopenharmony_ci if (optv > 1) 655987da915Sopenharmony_ci printf("mft vcn %lld index %d\n", 656987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->target_vcn), 657987da915Sopenharmony_ci (int)le16_to_cpu(logr->cluster_index)); 658987da915Sopenharmony_ci err = sanity_mft(buffer); 659987da915Sopenharmony_ci /* Should set to some previous lsn for undos */ 660987da915Sopenharmony_ci if (opts) 661987da915Sopenharmony_ci record->lsn = logr->this_lsn; 662987da915Sopenharmony_ci /* Duplicate on mftmirr if not overflowing its size */ 663987da915Sopenharmony_ci mftmirr = (((u64)sle64_to_cpu(logr->target_vcn) 664987da915Sopenharmony_ci + le16_to_cpu(logr->lcns_to_follow)) 665987da915Sopenharmony_ci << clusterbits) 666987da915Sopenharmony_ci <= (((u64)vol->mftmirr_size) << mftrecbits); 667987da915Sopenharmony_ci checked = TRUE; 668987da915Sopenharmony_ci } 669987da915Sopenharmony_ci if ((size == vol->indx_record_size) && !memcmp(buffer,"INDX",4)) { 670987da915Sopenharmony_ci indx = (INDEX_BLOCK*)buffer; 671987da915Sopenharmony_ci if (optv) 672987da915Sopenharmony_ci printf("update index lsn 0x%llx" 673987da915Sopenharmony_ci " (index %s than action 0x%llx)\n", 674987da915Sopenharmony_ci (long long)sle64_to_cpu(indx->lsn), 675987da915Sopenharmony_ci ((s64)(sle64_to_cpu(indx->lsn) 676987da915Sopenharmony_ci - sle64_to_cpu(logr->this_lsn)) < 0 ? 677987da915Sopenharmony_ci "older" : "newer"), 678987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->this_lsn)); 679987da915Sopenharmony_ci err = sanity_indx(vol, buffer); 680987da915Sopenharmony_ci /* Should set to some previous lsn for undos */ 681987da915Sopenharmony_ci if (opts) 682987da915Sopenharmony_ci indx->lsn = logr->this_lsn; 683987da915Sopenharmony_ci checked = TRUE; 684987da915Sopenharmony_ci } 685987da915Sopenharmony_ci if (!checked) { 686987da915Sopenharmony_ci printf("** Error : writing protected record of unknown type\n"); 687987da915Sopenharmony_ci err = 1; 688987da915Sopenharmony_ci } 689987da915Sopenharmony_ci if (!err) { 690987da915Sopenharmony_ci if (!ntfs_mst_pre_write_fixup((NTFS_RECORD*)buffer, size)) { 691987da915Sopenharmony_ci /* 692987da915Sopenharmony_ci * If the record is smaller than a cluster, get a full 693987da915Sopenharmony_ci * cluster, merge and write. 694987da915Sopenharmony_ci */ 695987da915Sopenharmony_ci if (size < clustersz) { 696987da915Sopenharmony_ci full = read_raw(vol, logr); 697987da915Sopenharmony_ci if (full) { 698987da915Sopenharmony_ci pos = le16_to_cpu(logr->cluster_index) 699987da915Sopenharmony_ci << NTFS_BLOCK_SIZE_BITS; 700987da915Sopenharmony_ci memcpy(full + pos, buffer, size); 701987da915Sopenharmony_ci err = write_raw(vol, logr, full); 702987da915Sopenharmony_ci if (!err && mftmirr && !optn) 703987da915Sopenharmony_ci err = write_mirr(vol, logr, 704987da915Sopenharmony_ci full); 705987da915Sopenharmony_ci free(full); 706987da915Sopenharmony_ci } else 707987da915Sopenharmony_ci err = 1; 708987da915Sopenharmony_ci } else { 709987da915Sopenharmony_ci /* write full clusters */ 710987da915Sopenharmony_ci err = write_raw(vol, logr, buffer); 711987da915Sopenharmony_ci if (!err && mftmirr && !optn) 712987da915Sopenharmony_ci err = write_mirr(vol, logr, buffer); 713987da915Sopenharmony_ci } 714987da915Sopenharmony_ci } else { 715987da915Sopenharmony_ci printf("** Failed to protect record\n"); 716987da915Sopenharmony_ci err = 1; 717987da915Sopenharmony_ci } 718987da915Sopenharmony_ci } 719987da915Sopenharmony_ci return (err); 720987da915Sopenharmony_ci} 721987da915Sopenharmony_ci 722987da915Sopenharmony_ci/* 723987da915Sopenharmony_ci * Resize attribute records 724987da915Sopenharmony_ci * 725987da915Sopenharmony_ci * The attribute value is resized to new size, but the attribute 726987da915Sopenharmony_ci * and MFT record must be kept aligned to 8 bytes. 727987da915Sopenharmony_ci */ 728987da915Sopenharmony_ci 729987da915Sopenharmony_cistatic int resize_attribute(MFT_RECORD *entry, ATTR_RECORD *attr, INDEX_ROOT *index, 730987da915Sopenharmony_ci int rawresize, int resize) 731987da915Sopenharmony_ci{ 732987da915Sopenharmony_ci int err; 733987da915Sopenharmony_ci u32 newlength; 734987da915Sopenharmony_ci u32 newused; 735987da915Sopenharmony_ci u32 newvalue; 736987da915Sopenharmony_ci u32 indexlth; 737987da915Sopenharmony_ci u32 indexalloc; 738987da915Sopenharmony_ci 739987da915Sopenharmony_ci err = 0; 740987da915Sopenharmony_ci if (attr) { 741987da915Sopenharmony_ci newvalue = le32_to_cpu(attr->value_length) + rawresize; 742987da915Sopenharmony_ci attr->value_length = cpu_to_le32(newvalue); 743987da915Sopenharmony_ci newlength = le32_to_cpu(attr->length) + resize; 744987da915Sopenharmony_ci attr->length = cpu_to_le32(newlength); 745987da915Sopenharmony_ci } 746987da915Sopenharmony_ci if (entry) { 747987da915Sopenharmony_ci newused = le32_to_cpu(entry->bytes_in_use) + resize; 748987da915Sopenharmony_ci entry->bytes_in_use = cpu_to_le32(newused); 749987da915Sopenharmony_ci } 750987da915Sopenharmony_ci if (index) { 751987da915Sopenharmony_ci indexlth = le32_to_cpu(index->index.index_length) + resize; 752987da915Sopenharmony_ci index->index.index_length = cpu_to_le32(indexlth); 753987da915Sopenharmony_ci indexalloc = le32_to_cpu(index->index.allocated_size) + resize; 754987da915Sopenharmony_ci index->index.allocated_size = cpu_to_le32(indexalloc); 755987da915Sopenharmony_ci } 756987da915Sopenharmony_ci return (err); 757987da915Sopenharmony_ci} 758987da915Sopenharmony_ci 759987da915Sopenharmony_ci/* 760987da915Sopenharmony_ci * Adjust the next attribute instance 761987da915Sopenharmony_ci * 762987da915Sopenharmony_ci * If a newly created attribute matches the next instance, then 763987da915Sopenharmony_ci * the next instance has to be incremented. 764987da915Sopenharmony_ci * 765987da915Sopenharmony_ci * Do the opposite when undoing an attribute creation, but 766987da915Sopenharmony_ci * do not change the next instance when deleting an attribute 767987da915Sopenharmony_ci * or undoing the deletion. 768987da915Sopenharmony_ci */ 769987da915Sopenharmony_ci 770987da915Sopenharmony_cistatic void adjust_instance(const ATTR_RECORD *attr, MFT_RECORD *entry, int increment) 771987da915Sopenharmony_ci{ 772987da915Sopenharmony_ci u16 instance; 773987da915Sopenharmony_ci 774987da915Sopenharmony_ci if (increment > 0) { 775987da915Sopenharmony_ci /* Allocating a new instance ? */ 776987da915Sopenharmony_ci if (attr->instance == entry->next_attr_instance) { 777987da915Sopenharmony_ci instance = (le16_to_cpu(entry->next_attr_instance) 778987da915Sopenharmony_ci + 1) & 0xffff; 779987da915Sopenharmony_ci entry->next_attr_instance = cpu_to_le16(instance); 780987da915Sopenharmony_ci } 781987da915Sopenharmony_ci } 782987da915Sopenharmony_ci if (increment < 0) { 783987da915Sopenharmony_ci /* Freeing the latest instance ? */ 784987da915Sopenharmony_ci instance = (le16_to_cpu(entry->next_attr_instance) 785987da915Sopenharmony_ci - 1) & 0xffff; 786987da915Sopenharmony_ci if (attr->instance == cpu_to_le16(instance)) 787987da915Sopenharmony_ci entry->next_attr_instance = attr->instance; 788987da915Sopenharmony_ci } 789987da915Sopenharmony_ci} 790987da915Sopenharmony_ci 791987da915Sopenharmony_ci/* 792987da915Sopenharmony_ci * Adjust the highest vcn according to mapping pairs 793987da915Sopenharmony_ci * 794987da915Sopenharmony_ci * The runlist has to be fully recomputed 795987da915Sopenharmony_ci */ 796987da915Sopenharmony_ci 797987da915Sopenharmony_cistatic int adjust_high_vcn(ntfs_volume *vol, ATTR_RECORD *attr) 798987da915Sopenharmony_ci{ 799987da915Sopenharmony_ci runlist_element *rl; 800987da915Sopenharmony_ci runlist_element *xrl; 801987da915Sopenharmony_ci VCN high_vcn; 802987da915Sopenharmony_ci int err; 803987da915Sopenharmony_ci 804987da915Sopenharmony_ci err = 1; 805987da915Sopenharmony_ci attr->highest_vcn = const_cpu_to_sle64(0); 806987da915Sopenharmony_ci rl = ntfs_mapping_pairs_decompress(vol, attr, (runlist_element*)NULL); 807987da915Sopenharmony_ci if (rl) { 808987da915Sopenharmony_ci xrl = rl; 809987da915Sopenharmony_ci if (xrl->length) 810987da915Sopenharmony_ci xrl++; 811987da915Sopenharmony_ci while ((xrl->length) && (xrl->lcn != LCN_RL_NOT_MAPPED)) 812987da915Sopenharmony_ci xrl++; 813987da915Sopenharmony_ci high_vcn = xrl->vcn - 1; 814987da915Sopenharmony_ci attr->highest_vcn = cpu_to_sle64(high_vcn); 815987da915Sopenharmony_ci free(rl); 816987da915Sopenharmony_ci err = 0; 817987da915Sopenharmony_ci } else { 818987da915Sopenharmony_ci printf("** Failed to decompress the runlist\n"); 819987da915Sopenharmony_ci dump((char*)attr,128); 820987da915Sopenharmony_ci } 821987da915Sopenharmony_ci return (err); 822987da915Sopenharmony_ci} 823987da915Sopenharmony_ci 824987da915Sopenharmony_ci/* 825987da915Sopenharmony_ci * Check index match, to be used for undos only 826987da915Sopenharmony_ci * 827987da915Sopenharmony_ci * The action UpdateFileNameRoot updates the time stamps and/or the 828987da915Sopenharmony_ci * sizes, but the lsn is not updated in the index record. 829987da915Sopenharmony_ci * As a consequence such UpdateFileNameRoot are not always undone 830987da915Sopenharmony_ci * and the actual record does not fully match the undo data. 831987da915Sopenharmony_ci * We however accept the match if the parent directory and the name 832987da915Sopenharmony_ci * match. 833987da915Sopenharmony_ci * Alternate workaround : do not check the lsn when undoing 834987da915Sopenharmony_ci * UpdateFileNameRoot 835987da915Sopenharmony_ci */ 836987da915Sopenharmony_ci 837987da915Sopenharmony_cistatic BOOL index_match_undo(const char *first, const char *second, int length) 838987da915Sopenharmony_ci{ 839987da915Sopenharmony_ci int len; 840987da915Sopenharmony_ci BOOL match; 841987da915Sopenharmony_ci 842987da915Sopenharmony_ci match = !memcmp(first, second, length); 843987da915Sopenharmony_ci if (!match) { 844987da915Sopenharmony_ci if (optv) { 845987da915Sopenharmony_ci printf("The existing index does not match :\n"); 846987da915Sopenharmony_ci dump(second,length); 847987da915Sopenharmony_ci } 848987da915Sopenharmony_ci len = (first[80] & 255)*2 + 2; 849987da915Sopenharmony_ci match = (feedle64(first, 16) == feedle64(second, 16)) 850987da915Sopenharmony_ci && !memcmp(first + 80, second + 80, len); 851987da915Sopenharmony_ci if (match && optv) 852987da915Sopenharmony_ci printf("However parent dir and name do match\n"); 853987da915Sopenharmony_ci } 854987da915Sopenharmony_ci return (match); 855987da915Sopenharmony_ci} 856987da915Sopenharmony_ci 857987da915Sopenharmony_ci 858987da915Sopenharmony_ci/* 859987da915Sopenharmony_ci * Generic idempotent change to a resident attribute 860987da915Sopenharmony_ci */ 861987da915Sopenharmony_ci 862987da915Sopenharmony_cistatic int change_resident(ntfs_volume *vol, const struct ACTION_RECORD *action, 863987da915Sopenharmony_ci char *buffer, const char *data, u32 target, u32 length) 864987da915Sopenharmony_ci{ 865987da915Sopenharmony_ci LCN lcn; 866987da915Sopenharmony_ci ATTR_RECORD *attr; 867987da915Sopenharmony_ci u32 attrend; 868987da915Sopenharmony_ci int err; 869987da915Sopenharmony_ci int changed; 870987da915Sopenharmony_ci 871987da915Sopenharmony_ci err = 1; 872987da915Sopenharmony_ci if (action->record.undo_length != action->record.redo_length) 873987da915Sopenharmony_ci printf("** Error size change in change_resident\n"); 874987da915Sopenharmony_ci if (optv > 1) { 875987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 876987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 877987da915Sopenharmony_ci (long long)inode_number(&action->record), 878987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 879987da915Sopenharmony_ci } 880987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 881987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 882987da915Sopenharmony_ci if (optv > 1) { 883987da915Sopenharmony_ci printf("-> existing record :\n"); 884987da915Sopenharmony_ci dump(&buffer[target], length); 885987da915Sopenharmony_ci printf("-> full MFT record :\n"); 886987da915Sopenharmony_ci dump(buffer,mftrecsz); 887987da915Sopenharmony_ci } 888987da915Sopenharmony_ci attrend = le16_to_cpu(action->record.record_offset) 889987da915Sopenharmony_ci + le32_to_cpu(attr->length); 890987da915Sopenharmony_ci if ((target + length) > attrend) { 891987da915Sopenharmony_ci printf("** Error : update overflows from attribute\n"); 892987da915Sopenharmony_ci } 893987da915Sopenharmony_ci if (!(length & 7) 894987da915Sopenharmony_ci && ((target + length) <= attrend) 895987da915Sopenharmony_ci && (attrend <= mftrecsz) 896987da915Sopenharmony_ci && !sanity_mft(buffer)) { 897987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 898987da915Sopenharmony_ci err = 0; 899987da915Sopenharmony_ci if (changed) { 900987da915Sopenharmony_ci memcpy(buffer + target, data, length); 901987da915Sopenharmony_ci if (optv > 1) { 902987da915Sopenharmony_ci printf("-> new record :\n"); 903987da915Sopenharmony_ci dump(buffer + target, length); 904987da915Sopenharmony_ci } 905987da915Sopenharmony_ci err = write_protected(vol, &action->record, 906987da915Sopenharmony_ci buffer, mftrecsz); 907987da915Sopenharmony_ci } 908987da915Sopenharmony_ci if (optv > 1) { 909987da915Sopenharmony_ci printf("-> MFT record %s\n", 910987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 911987da915Sopenharmony_ci } 912987da915Sopenharmony_ci } 913987da915Sopenharmony_ci return (err); 914987da915Sopenharmony_ci} 915987da915Sopenharmony_ci 916987da915Sopenharmony_cistatic int change_resident_expect(ntfs_volume *vol, const struct ACTION_RECORD *action, 917987da915Sopenharmony_ci char *buffer, const char *data, const char *expected, 918987da915Sopenharmony_ci u32 target, u32 length, ATTR_TYPES type) 919987da915Sopenharmony_ci{ 920987da915Sopenharmony_ci LCN lcn; 921987da915Sopenharmony_ci ATTR_RECORD *attr; 922987da915Sopenharmony_ci int err; 923987da915Sopenharmony_ci BOOL found; 924987da915Sopenharmony_ci 925987da915Sopenharmony_ci err = 1; 926987da915Sopenharmony_ci if (action->record.undo_length != action->record.redo_length) 927987da915Sopenharmony_ci printf("** Error size change in change_resident\n"); 928987da915Sopenharmony_ci if (optv > 1) { 929987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 930987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 931987da915Sopenharmony_ci (long long)inode_number(&action->record), 932987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 933987da915Sopenharmony_ci } 934987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 935987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 936987da915Sopenharmony_ci if (optv > 1) { 937987da915Sopenharmony_ci printf("-> existing record :\n"); 938987da915Sopenharmony_ci dump(&buffer[target], length); 939987da915Sopenharmony_ci printf("-> full record :\n"); 940987da915Sopenharmony_ci dump((char*)attr, le32_to_cpu(attr->length)); 941987da915Sopenharmony_ci } 942987da915Sopenharmony_ci if ((attr->type == type) 943987da915Sopenharmony_ci && !(length & 7) 944987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 945987da915Sopenharmony_ci found = !memcmp(buffer + target, expected, length); 946987da915Sopenharmony_ci err = 0; 947987da915Sopenharmony_ci if (found) { 948987da915Sopenharmony_ci memcpy(buffer + target, data, length); 949987da915Sopenharmony_ci if (optv > 1) { 950987da915Sopenharmony_ci printf("-> new record :\n"); 951987da915Sopenharmony_ci dump(buffer + target, length); 952987da915Sopenharmony_ci } 953987da915Sopenharmony_ci err = write_protected(vol, &action->record, 954987da915Sopenharmony_ci buffer, mftrecsz); 955987da915Sopenharmony_ci } 956987da915Sopenharmony_ci if (optv > 1) { 957987da915Sopenharmony_ci printf("-> MFT record %s\n", 958987da915Sopenharmony_ci (found ? "updated" : "unchanged")); 959987da915Sopenharmony_ci } 960987da915Sopenharmony_ci } 961987da915Sopenharmony_ci return (err); 962987da915Sopenharmony_ci} 963987da915Sopenharmony_ci 964987da915Sopenharmony_ci/* 965987da915Sopenharmony_ci * Generic idempotent change to a an index value 966987da915Sopenharmony_ci * 967987da915Sopenharmony_ci */ 968987da915Sopenharmony_ci 969987da915Sopenharmony_cistatic int change_index_value(ntfs_volume *vol, const struct ACTION_RECORD *action, 970987da915Sopenharmony_ci char *buffer, const char *data, u32 target, u32 length) 971987da915Sopenharmony_ci{ 972987da915Sopenharmony_ci LCN lcn; 973987da915Sopenharmony_ci u32 count; 974987da915Sopenharmony_ci u32 xsize; 975987da915Sopenharmony_ci int changed; 976987da915Sopenharmony_ci int err; 977987da915Sopenharmony_ci 978987da915Sopenharmony_ci err = 1; 979987da915Sopenharmony_ci count = le16_to_cpu(action->record.lcns_to_follow); 980987da915Sopenharmony_ci if (optv > 1) { 981987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 982987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 983987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 984987da915Sopenharmony_ci } 985987da915Sopenharmony_ci xsize = vol->indx_record_size; 986987da915Sopenharmony_ci if (optv > 1) { 987987da915Sopenharmony_ci printf("-> existing record :\n"); 988987da915Sopenharmony_ci dump(&buffer[target], length); 989987da915Sopenharmony_ci } 990987da915Sopenharmony_ci if ((target + length) <= (count << clusterbits)) { 991987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 992987da915Sopenharmony_ci err = 0; 993987da915Sopenharmony_ci if (changed) { 994987da915Sopenharmony_ci memcpy(buffer + target, data, length); 995987da915Sopenharmony_ci if (optv > 1) { 996987da915Sopenharmony_ci printf("-> new record :\n"); 997987da915Sopenharmony_ci dump(buffer + target, length); 998987da915Sopenharmony_ci } 999987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1000987da915Sopenharmony_ci buffer, xsize); 1001987da915Sopenharmony_ci } 1002987da915Sopenharmony_ci if (optv > 1) { 1003987da915Sopenharmony_ci printf("-> data record %s\n", 1004987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 1005987da915Sopenharmony_ci } 1006987da915Sopenharmony_ci } 1007987da915Sopenharmony_ci return (err); 1008987da915Sopenharmony_ci} 1009987da915Sopenharmony_ci 1010987da915Sopenharmony_ci/* 1011987da915Sopenharmony_ci * Add one or more resident attributes 1012987da915Sopenharmony_ci */ 1013987da915Sopenharmony_ci 1014987da915Sopenharmony_cistatic int add_resident(ntfs_volume *vol, const struct ACTION_RECORD *action, 1015987da915Sopenharmony_ci char *buffer, const char *data, u32 target, 1016987da915Sopenharmony_ci u32 length, u32 oldlength) 1017987da915Sopenharmony_ci{ 1018987da915Sopenharmony_ci LCN lcn; 1019987da915Sopenharmony_ci MFT_RECORD *entry; 1020987da915Sopenharmony_ci int err; 1021987da915Sopenharmony_ci BOOL found; 1022987da915Sopenharmony_ci int resize; 1023987da915Sopenharmony_ci 1024987da915Sopenharmony_ci err = 1; 1025987da915Sopenharmony_ci if (optv > 1) { 1026987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1027987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 1028987da915Sopenharmony_ci (long long)inode_number(&action->record), 1029987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1030987da915Sopenharmony_ci } 1031987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 1032987da915Sopenharmony_ci resize = length - oldlength; 1033987da915Sopenharmony_ci if (optv > 1) { 1034987da915Sopenharmony_ci printf("existing data :\n"); 1035987da915Sopenharmony_ci dump(buffer + target,length); 1036987da915Sopenharmony_ci } 1037987da915Sopenharmony_ci if (!(length & 7) 1038987da915Sopenharmony_ci && !(oldlength & 7) 1039987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 1040987da915Sopenharmony_ci /* This has to be an idempotent action */ 1041987da915Sopenharmony_ci err = 0; 1042987da915Sopenharmony_ci if (data && length) 1043987da915Sopenharmony_ci found = !memcmp(buffer + target, 1044987da915Sopenharmony_ci data, length); 1045987da915Sopenharmony_ci else { 1046987da915Sopenharmony_ci found = TRUE; 1047987da915Sopenharmony_ci err = 1; 1048987da915Sopenharmony_ci } 1049987da915Sopenharmony_ci if (!found && !err) { 1050987da915Sopenharmony_ci /* Make space to insert the entry */ 1051987da915Sopenharmony_ci memmove(buffer + target + resize, 1052987da915Sopenharmony_ci buffer + target, 1053987da915Sopenharmony_ci mftrecsz - target - resize); 1054987da915Sopenharmony_ci if (data) 1055987da915Sopenharmony_ci memcpy(buffer + target, data, length); 1056987da915Sopenharmony_ci else 1057987da915Sopenharmony_ci memset(buffer + target, 0, length); 1058987da915Sopenharmony_ci resize_attribute(entry, NULL, NULL, 1059987da915Sopenharmony_ci resize, resize); 1060987da915Sopenharmony_ci if (optv > 1) { 1061987da915Sopenharmony_ci printf("new data at same location :\n"); 1062987da915Sopenharmony_ci dump(buffer + target, length); 1063987da915Sopenharmony_ci } 1064987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1065987da915Sopenharmony_ci buffer, mftrecsz); 1066987da915Sopenharmony_ci } 1067987da915Sopenharmony_ci if (optv > 1) { 1068987da915Sopenharmony_ci printf("-> MFT record %s\n", 1069987da915Sopenharmony_ci (found ? "unchanged" : "expanded")); 1070987da915Sopenharmony_ci } 1071987da915Sopenharmony_ci } 1072987da915Sopenharmony_ci return (err); 1073987da915Sopenharmony_ci} 1074987da915Sopenharmony_ci 1075987da915Sopenharmony_ci/* 1076987da915Sopenharmony_ci * Add one or more non-resident records 1077987da915Sopenharmony_ci */ 1078987da915Sopenharmony_ci 1079987da915Sopenharmony_cistatic int delete_non_resident(void /*ntfs_volume *vol, 1080987da915Sopenharmony_ci const struct ACTION_RECORD *action, 1081987da915Sopenharmony_ci const char *data, u32 target, u32 length, u32 oldlength*/) 1082987da915Sopenharmony_ci{ 1083987da915Sopenharmony_ci int err; 1084987da915Sopenharmony_ci 1085987da915Sopenharmony_ci err = 1; 1086987da915Sopenharmony_ci printf("** delete_non_resident() not implemented\n"); 1087987da915Sopenharmony_ci return (err); 1088987da915Sopenharmony_ci} 1089987da915Sopenharmony_ci 1090987da915Sopenharmony_ci/* 1091987da915Sopenharmony_ci * Expand a single resident attribute 1092987da915Sopenharmony_ci */ 1093987da915Sopenharmony_ci 1094987da915Sopenharmony_cistatic int expand_resident(ntfs_volume *vol, const struct ACTION_RECORD *action, 1095987da915Sopenharmony_ci char *buffer, const char *data, u32 target, 1096987da915Sopenharmony_ci u32 length, u32 oldlength) 1097987da915Sopenharmony_ci{ 1098987da915Sopenharmony_ci LCN lcn; 1099987da915Sopenharmony_ci ATTR_RECORD *attr; 1100987da915Sopenharmony_ci MFT_RECORD *entry; 1101987da915Sopenharmony_ci int err; 1102987da915Sopenharmony_ci BOOL found; 1103987da915Sopenharmony_ci int resize; 1104987da915Sopenharmony_ci u16 base; 1105987da915Sopenharmony_ci 1106987da915Sopenharmony_ci err = 1; 1107987da915Sopenharmony_ci if (optv > 1) { 1108987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1109987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 1110987da915Sopenharmony_ci (long long)inode_number(&action->record), 1111987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1112987da915Sopenharmony_ci } 1113987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 1114987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 1115987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 1116987da915Sopenharmony_ci if (optv > 1) { 1117987da915Sopenharmony_ci printf("existing data :\n"); 1118987da915Sopenharmony_ci dump(buffer + target,length); 1119987da915Sopenharmony_ci } 1120987da915Sopenharmony_ci base = 24 + 2*attr->name_length; 1121987da915Sopenharmony_ci resize = ((base + length - 1) | 7) 1122987da915Sopenharmony_ci - ((base + oldlength - 1) | 7); 1123987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 1124987da915Sopenharmony_ci /* This has to be an idempotent action */ 1125987da915Sopenharmony_ci// TODO This test is wrong ! 1126987da915Sopenharmony_ci found = le32_to_cpu(attr->value_length) == length; 1127987da915Sopenharmony_ci if (found && data && length) 1128987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 1129987da915Sopenharmony_ci err = 0; 1130987da915Sopenharmony_ci if (!found) { 1131987da915Sopenharmony_ci /* Make space to insert the entry */ 1132987da915Sopenharmony_ci memmove(buffer + target + resize, 1133987da915Sopenharmony_ci buffer + target, 1134987da915Sopenharmony_ci mftrecsz - target - resize); 1135987da915Sopenharmony_ci// TODO what to do if length is not a multiple of 8 ? 1136987da915Sopenharmony_ci if (data) 1137987da915Sopenharmony_ci memcpy(buffer + target, data, length); 1138987da915Sopenharmony_ci else 1139987da915Sopenharmony_ci memset(buffer + target, 0, length); 1140987da915Sopenharmony_ci resize_attribute(entry, attr, NULL, 1141987da915Sopenharmony_ci length - oldlength, resize); 1142987da915Sopenharmony_ci if (optv > 1) { 1143987da915Sopenharmony_ci printf("new data at same location :\n"); 1144987da915Sopenharmony_ci dump(buffer + target, length); 1145987da915Sopenharmony_ci } 1146987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1147987da915Sopenharmony_ci buffer, mftrecsz); 1148987da915Sopenharmony_ci } 1149987da915Sopenharmony_ci if (optv > 1) { 1150987da915Sopenharmony_ci printf("-> MFT record %s\n", 1151987da915Sopenharmony_ci (found ? "unchanged" : "expanded")); 1152987da915Sopenharmony_ci } 1153987da915Sopenharmony_ci } 1154987da915Sopenharmony_ci return (err); 1155987da915Sopenharmony_ci} 1156987da915Sopenharmony_ci 1157987da915Sopenharmony_ci/* 1158987da915Sopenharmony_ci * Add one or more non-resident records 1159987da915Sopenharmony_ci */ 1160987da915Sopenharmony_ci 1161987da915Sopenharmony_cistatic int add_non_resident(void /*ntfs_volume *vol, 1162987da915Sopenharmony_ci const struct ACTION_RECORD *action, 1163987da915Sopenharmony_ci const char *data, u32 target, u32 length, u32 oldlength*/) 1164987da915Sopenharmony_ci{ 1165987da915Sopenharmony_ci int err; 1166987da915Sopenharmony_ci 1167987da915Sopenharmony_ci printf("** add_non_resident() not implemented\n"); 1168987da915Sopenharmony_ci err = 0; 1169987da915Sopenharmony_ci return (err); 1170987da915Sopenharmony_ci} 1171987da915Sopenharmony_ci 1172987da915Sopenharmony_ci/* 1173987da915Sopenharmony_ci * Generic insert a new resident attribute 1174987da915Sopenharmony_ci */ 1175987da915Sopenharmony_ci 1176987da915Sopenharmony_cistatic int insert_resident(ntfs_volume *vol, const struct ACTION_RECORD *action, 1177987da915Sopenharmony_ci char *buffer, const char *data, u32 target, 1178987da915Sopenharmony_ci u32 length) 1179987da915Sopenharmony_ci{ 1180987da915Sopenharmony_ci LCN lcn; 1181987da915Sopenharmony_ci ATTR_RECORD *attr; 1182987da915Sopenharmony_ci const ATTR_RECORD *newattr; 1183987da915Sopenharmony_ci MFT_RECORD *entry; 1184987da915Sopenharmony_ci u32 newused; 1185987da915Sopenharmony_ci u16 links; 1186987da915Sopenharmony_ci int err; 1187987da915Sopenharmony_ci BOOL found; 1188987da915Sopenharmony_ci 1189987da915Sopenharmony_ci err = 1; 1190987da915Sopenharmony_ci if (optv > 1) { 1191987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1192987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 1193987da915Sopenharmony_ci (long long)inode_number(&action->record), 1194987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1195987da915Sopenharmony_ci } 1196987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 1197987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 1198987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 1199987da915Sopenharmony_ci newattr = (const ATTR_RECORD*)data; 1200987da915Sopenharmony_ci if (optv > 1) { 1201987da915Sopenharmony_ci printf("existing record :\n"); 1202987da915Sopenharmony_ci dump(buffer + target,length); 1203987da915Sopenharmony_ci if (le32_to_cpu(attr->type) < le32_to_cpu(newattr->type)) { 1204987da915Sopenharmony_ci printf("** Bad attribute order, full record :\n"); 1205987da915Sopenharmony_ci dump(buffer, mftrecsz); 1206987da915Sopenharmony_ci } 1207987da915Sopenharmony_ci } 1208987da915Sopenharmony_ci /* Types must be in ascending order */ 1209987da915Sopenharmony_ci if (valid_type(attr->type) 1210987da915Sopenharmony_ci && (le32_to_cpu(attr->type) 1211987da915Sopenharmony_ci >= le32_to_cpu(newattr->type)) 1212987da915Sopenharmony_ci && !(length & 7) 1213987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 1214987da915Sopenharmony_ci /* This has to be an idempotent action */ 1215987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 1216987da915Sopenharmony_ci err = 0; 1217987da915Sopenharmony_ci if (!found) { 1218987da915Sopenharmony_ci /* Make space to insert the entry */ 1219987da915Sopenharmony_ci memmove(buffer + target + length, 1220987da915Sopenharmony_ci buffer + target, 1221987da915Sopenharmony_ci mftrecsz - target - length); 1222987da915Sopenharmony_ci memcpy(buffer + target, data, length); 1223987da915Sopenharmony_ci newused = le32_to_cpu(entry->bytes_in_use) 1224987da915Sopenharmony_ci + length; 1225987da915Sopenharmony_ci entry->bytes_in_use = cpu_to_le32(newused); 1226987da915Sopenharmony_ci if (action->record.redo_operation 1227987da915Sopenharmony_ci == const_cpu_to_le16(CreateAttribute)) { 1228987da915Sopenharmony_ci /* 1229987da915Sopenharmony_ci * For a real create, may have to adjust 1230987da915Sopenharmony_ci * the next attribute instance 1231987da915Sopenharmony_ci */ 1232987da915Sopenharmony_ci adjust_instance(newattr, entry, 1); 1233987da915Sopenharmony_ci } 1234987da915Sopenharmony_ci if (newattr->type == AT_FILE_NAME) { 1235987da915Sopenharmony_ci links = le16_to_cpu(entry->link_count) + 1; 1236987da915Sopenharmony_ci entry->link_count = cpu_to_le16(links); 1237987da915Sopenharmony_ci } 1238987da915Sopenharmony_ci if (optv > 1) { 1239987da915Sopenharmony_ci printf("expanded record (now 0x%x" 1240987da915Sopenharmony_ci " bytes used) :\n", 1241987da915Sopenharmony_ci (int)newused); 1242987da915Sopenharmony_ci dump(buffer + target, 2*length); 1243987da915Sopenharmony_ci } 1244987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1245987da915Sopenharmony_ci buffer, mftrecsz); 1246987da915Sopenharmony_ci } 1247987da915Sopenharmony_ci if (optv > 1) { 1248987da915Sopenharmony_ci printf("-> MFT record %s\n", 1249987da915Sopenharmony_ci (found ? "unchanged" : "expanded")); 1250987da915Sopenharmony_ci } 1251987da915Sopenharmony_ci } 1252987da915Sopenharmony_ci return (err); 1253987da915Sopenharmony_ci} 1254987da915Sopenharmony_ci 1255987da915Sopenharmony_ci/* 1256987da915Sopenharmony_ci * Generic remove a single resident attribute 1257987da915Sopenharmony_ci */ 1258987da915Sopenharmony_ci 1259987da915Sopenharmony_cistatic int remove_resident(ntfs_volume *vol, const struct ACTION_RECORD *action, 1260987da915Sopenharmony_ci char *buffer, const char *data, u32 target, 1261987da915Sopenharmony_ci u32 length) 1262987da915Sopenharmony_ci{ 1263987da915Sopenharmony_ci LCN lcn; 1264987da915Sopenharmony_ci ATTR_RECORD *attr; 1265987da915Sopenharmony_ci MFT_RECORD *entry; 1266987da915Sopenharmony_ci u32 newused; 1267987da915Sopenharmony_ci u16 links; 1268987da915Sopenharmony_ci int err; 1269987da915Sopenharmony_ci BOOL found; 1270987da915Sopenharmony_ci 1271987da915Sopenharmony_ci err = 1; 1272987da915Sopenharmony_ci if (optv > 1) { 1273987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1274987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 1275987da915Sopenharmony_ci (long long)inode_number(&action->record), 1276987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1277987da915Sopenharmony_ci } 1278987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 1279987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 1280987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 1281987da915Sopenharmony_ci if (optv > 1) { 1282987da915Sopenharmony_ci printf("existing record :\n"); 1283987da915Sopenharmony_ci dump(buffer + target,length); 1284987da915Sopenharmony_ci } 1285987da915Sopenharmony_ci if (!(length & 7) 1286987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 1287987da915Sopenharmony_ci /* This has to be an idempotent action */ 1288987da915Sopenharmony_ci /* For AT_DATA the value is not always present */ 1289987da915Sopenharmony_ci if (attr->type == AT_DATA) 1290987da915Sopenharmony_ci found = !memcmp(buffer + target, data, 1291987da915Sopenharmony_ci le16_to_cpu(attr->value_offset)); 1292987da915Sopenharmony_ci else 1293987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 1294987da915Sopenharmony_ci if (!found && optv) { 1295987da915Sopenharmony_ci printf("data 0x%lx 0x%lx offset %d %ld\n", 1296987da915Sopenharmony_ci (long)le32_to_cpu(attr->type), 1297987da915Sopenharmony_ci (long)le32_to_cpu(AT_DATA), 1298987da915Sopenharmony_ci (int)offsetof(ATTR_RECORD, resident_end), 1299987da915Sopenharmony_ci (long)le16_to_cpu(attr->value_offset)); 1300987da915Sopenharmony_ci printf("The existing record does not match (%d/%d)\n", 1301987da915Sopenharmony_ci (int)matchcount(buffer + target, data, 1302987da915Sopenharmony_ci length),(int)length); 1303987da915Sopenharmony_ci dump(data,length); 1304987da915Sopenharmony_ci printf("full attr :\n"); 1305987da915Sopenharmony_ci dump((const char*)attr,mftrecsz 1306987da915Sopenharmony_ci - le16_to_cpu(action->record.record_offset)); 1307987da915Sopenharmony_ci } 1308987da915Sopenharmony_ci err = 0; 1309987da915Sopenharmony_ci if (found) { 1310987da915Sopenharmony_ci if (attr->type == AT_FILE_NAME) { 1311987da915Sopenharmony_ci links = le16_to_cpu(entry->link_count) - 1; 1312987da915Sopenharmony_ci entry->link_count = cpu_to_le16(links); 1313987da915Sopenharmony_ci } 1314987da915Sopenharmony_ci if (action->record.redo_operation 1315987da915Sopenharmony_ci == const_cpu_to_le16(CreateAttribute)) { 1316987da915Sopenharmony_ci adjust_instance(attr, entry, -1); 1317987da915Sopenharmony_ci } 1318987da915Sopenharmony_ci /* Remove the entry */ 1319987da915Sopenharmony_ci memmove(buffer + target, 1320987da915Sopenharmony_ci buffer + target + length, 1321987da915Sopenharmony_ci mftrecsz - target - length); 1322987da915Sopenharmony_ci newused = le32_to_cpu(entry->bytes_in_use) - length; 1323987da915Sopenharmony_ci entry->bytes_in_use = cpu_to_le32(newused); 1324987da915Sopenharmony_ci if (optv > 1) { 1325987da915Sopenharmony_ci printf("new record at same location" 1326987da915Sopenharmony_ci " (now 0x%x bytes used) :\n", 1327987da915Sopenharmony_ci (int)newused); 1328987da915Sopenharmony_ci dump(buffer + target, length); 1329987da915Sopenharmony_ci } 1330987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1331987da915Sopenharmony_ci buffer, mftrecsz); 1332987da915Sopenharmony_ci } 1333987da915Sopenharmony_ci if (optv > 1) { 1334987da915Sopenharmony_ci printf("-> MFT record %s\n", 1335987da915Sopenharmony_ci (found ? "shrinked" : "unchanged")); 1336987da915Sopenharmony_ci } 1337987da915Sopenharmony_ci } 1338987da915Sopenharmony_ci return (err); 1339987da915Sopenharmony_ci} 1340987da915Sopenharmony_ci 1341987da915Sopenharmony_ci/* 1342987da915Sopenharmony_ci * Delete one or more resident attributes 1343987da915Sopenharmony_ci */ 1344987da915Sopenharmony_ci 1345987da915Sopenharmony_cistatic int delete_resident(ntfs_volume *vol, const struct ACTION_RECORD *action, 1346987da915Sopenharmony_ci char *buffer, const char *data, u32 target, 1347987da915Sopenharmony_ci u32 length, u32 oldlength) 1348987da915Sopenharmony_ci{ 1349987da915Sopenharmony_ci LCN lcn; 1350987da915Sopenharmony_ci MFT_RECORD *entry; 1351987da915Sopenharmony_ci int err; 1352987da915Sopenharmony_ci BOOL found; 1353987da915Sopenharmony_ci int resize; 1354987da915Sopenharmony_ci 1355987da915Sopenharmony_ci if (optv > 1) 1356987da915Sopenharmony_ci printf("-> %s()\n",__func__); 1357987da915Sopenharmony_ci err = 1; 1358987da915Sopenharmony_ci if (optv > 1) { 1359987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1360987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 1361987da915Sopenharmony_ci (long long)inode_number(&action->record), 1362987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1363987da915Sopenharmony_ci } 1364987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 1365987da915Sopenharmony_ci if (optv > 1) { 1366987da915Sopenharmony_ci printf("existing data :\n"); 1367987da915Sopenharmony_ci dump(buffer + target,length); 1368987da915Sopenharmony_ci } 1369987da915Sopenharmony_ci resize = length - oldlength; 1370987da915Sopenharmony_ci if (!(length & 7) 1371987da915Sopenharmony_ci && !(oldlength & 7) 1372987da915Sopenharmony_ci && ((target + oldlength) <= mftrecsz)) { 1373987da915Sopenharmony_ci /* This has to be an idempotent action */ 1374987da915Sopenharmony_ci err = 0; 1375987da915Sopenharmony_ci if (data && length) 1376987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 1377987da915Sopenharmony_ci else { 1378987da915Sopenharmony_ci found = FALSE; 1379987da915Sopenharmony_ci err = 1; 1380987da915Sopenharmony_ci } 1381987da915Sopenharmony_ci if (!found && !err) { 1382987da915Sopenharmony_ci /* Remove the entry, if present */ 1383987da915Sopenharmony_ci memmove(buffer + target, 1384987da915Sopenharmony_ci buffer + target - resize, 1385987da915Sopenharmony_ci mftrecsz - target + resize); 1386987da915Sopenharmony_ci resize_attribute(entry, NULL, NULL, 1387987da915Sopenharmony_ci length - oldlength, resize); 1388987da915Sopenharmony_ci if (optv > 1) { 1389987da915Sopenharmony_ci printf("new data at same location :\n"); 1390987da915Sopenharmony_ci dump(buffer + target, length); 1391987da915Sopenharmony_ci } 1392987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1393987da915Sopenharmony_ci buffer, mftrecsz); 1394987da915Sopenharmony_ci } 1395987da915Sopenharmony_ci if (optv > 1) { 1396987da915Sopenharmony_ci printf("-> MFT record %s\n", 1397987da915Sopenharmony_ci (found ? "unchanged" : "shrinked")); 1398987da915Sopenharmony_ci } 1399987da915Sopenharmony_ci } 1400987da915Sopenharmony_ci return (err); 1401987da915Sopenharmony_ci} 1402987da915Sopenharmony_ci 1403987da915Sopenharmony_cistatic int shrink_resident(ntfs_volume *vol, const struct ACTION_RECORD *action, 1404987da915Sopenharmony_ci char *buffer, const char *data, u32 target, 1405987da915Sopenharmony_ci u32 length, u32 oldlength) 1406987da915Sopenharmony_ci{ 1407987da915Sopenharmony_ci LCN lcn; 1408987da915Sopenharmony_ci ATTR_RECORD *attr; 1409987da915Sopenharmony_ci MFT_RECORD *entry; 1410987da915Sopenharmony_ci int err; 1411987da915Sopenharmony_ci BOOL found; 1412987da915Sopenharmony_ci int resize; 1413987da915Sopenharmony_ci u16 base; 1414987da915Sopenharmony_ci 1415987da915Sopenharmony_ci if (optv > 1) 1416987da915Sopenharmony_ci printf("-> %s()\n",__func__); 1417987da915Sopenharmony_ci err = 1; 1418987da915Sopenharmony_ci if (optv > 1) { 1419987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1420987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 1421987da915Sopenharmony_ci (long long)inode_number(&action->record), 1422987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1423987da915Sopenharmony_ci } 1424987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 1425987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 1426987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 1427987da915Sopenharmony_ci if (optv > 1) { 1428987da915Sopenharmony_ci printf("existing data :\n"); 1429987da915Sopenharmony_ci dump(buffer + target,length); 1430987da915Sopenharmony_ci } 1431987da915Sopenharmony_ci base = 24 + 2*attr->name_length; 1432987da915Sopenharmony_ci resize = ((base + length - 1) | 7) 1433987da915Sopenharmony_ci - ((base + oldlength - 1) | 7); 1434987da915Sopenharmony_ci if ((oldlength > length) 1435987da915Sopenharmony_ci// TODO limit to attr length 1436987da915Sopenharmony_ci && ((target + oldlength) <= mftrecsz)) { 1437987da915Sopenharmony_ci /* This has to be an idempotent action */ 1438987da915Sopenharmony_ci if (data && length) 1439987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 1440987da915Sopenharmony_ci else 1441987da915Sopenharmony_ci{ 1442987da915Sopenharmony_ci// TODO wrong : need checking against the old data, but in known cases 1443987da915Sopenharmony_ci// redo data is not available either and existing data is not zero. 1444987da915Sopenharmony_ci found = FALSE; 1445987da915Sopenharmony_ciprintf("* fake test, assuming not shrinked : value length %ld length %ld oldlength %ld\n",(long)le32_to_cpu(attr->value_length),(long)length,(long)oldlength); 1446987da915Sopenharmony_ci//dump(buffer + target, oldlength); 1447987da915Sopenharmony_ci} 1448987da915Sopenharmony_ci err = 0; 1449987da915Sopenharmony_ci if (!found) { 1450987da915Sopenharmony_ci if (length) { 1451987da915Sopenharmony_ci /* Relocate end of record */ 1452987da915Sopenharmony_ci// TODO restrict to bytes_in_use 1453987da915Sopenharmony_ci memmove(buffer + target + length, 1454987da915Sopenharmony_ci buffer + target + oldlength, 1455987da915Sopenharmony_ci mftrecsz - target - oldlength); 1456987da915Sopenharmony_ci /* Insert new data or zeroes */ 1457987da915Sopenharmony_ci if (data) 1458987da915Sopenharmony_ci memcpy(buffer + target, data, length); 1459987da915Sopenharmony_ci else 1460987da915Sopenharmony_ci memset(buffer + target, 0, length); 1461987da915Sopenharmony_ci } else { 1462987da915Sopenharmony_ci /* Remove the entry, unless targeted size */ 1463987da915Sopenharmony_ci memmove(buffer + target, 1464987da915Sopenharmony_ci buffer + target - resize, 1465987da915Sopenharmony_ci mftrecsz - target + resize); 1466987da915Sopenharmony_ci } 1467987da915Sopenharmony_ci resize_attribute(entry, attr, NULL, 1468987da915Sopenharmony_ci length - oldlength, resize); 1469987da915Sopenharmony_ci if (optv > 1) { 1470987da915Sopenharmony_ci printf("new data at same location :\n"); 1471987da915Sopenharmony_ci dump(buffer + target, length); 1472987da915Sopenharmony_ci } 1473987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1474987da915Sopenharmony_ci buffer, mftrecsz); 1475987da915Sopenharmony_ci } 1476987da915Sopenharmony_ci if (optv > 1) { 1477987da915Sopenharmony_ci printf("-> MFT record %s\n", 1478987da915Sopenharmony_ci (found ? "unchanged" : "shrinked")); 1479987da915Sopenharmony_ci } 1480987da915Sopenharmony_ci } 1481987da915Sopenharmony_ci return (err); 1482987da915Sopenharmony_ci} 1483987da915Sopenharmony_ci 1484987da915Sopenharmony_cistatic int update_index(ntfs_volume *vol, const struct ACTION_RECORD *action, 1485987da915Sopenharmony_ci char *buffer, const char *data, u32 target, u32 length) 1486987da915Sopenharmony_ci{ 1487987da915Sopenharmony_ci LCN lcn; 1488987da915Sopenharmony_ci INDEX_BLOCK *indx; 1489987da915Sopenharmony_ci u32 xsize; 1490987da915Sopenharmony_ci BOOL changed; 1491987da915Sopenharmony_ci int err; 1492987da915Sopenharmony_ci 1493987da915Sopenharmony_ci err = 1; 1494987da915Sopenharmony_ci if (optv > 1) { 1495987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1496987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 1497987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1498987da915Sopenharmony_ci } 1499987da915Sopenharmony_ci xsize = vol->indx_record_size; 1500987da915Sopenharmony_ci indx = (INDEX_BLOCK*)(buffer 1501987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 1502987da915Sopenharmony_ci if (optv > 1) { 1503987da915Sopenharmony_ci printf("-> existing index :\n"); 1504987da915Sopenharmony_ci dump(&buffer[target], length); 1505987da915Sopenharmony_ci } 1506987da915Sopenharmony_ci if ((indx->magic == magic_INDX) 1507987da915Sopenharmony_ci && !(length & 7) 1508987da915Sopenharmony_ci && ((target + length) <= xsize)) { 1509987da915Sopenharmony_ci /* This has to be an idempotent action */ 1510987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 1511987da915Sopenharmony_ci err = 0; 1512987da915Sopenharmony_ci if (changed) { 1513987da915Sopenharmony_ci /* Update the entry */ 1514987da915Sopenharmony_ci memcpy(buffer + target, data, length); 1515987da915Sopenharmony_ci if (optv > 1) { 1516987da915Sopenharmony_ci printf("-> new index :\n"); 1517987da915Sopenharmony_ci dump(&buffer[target], length); 1518987da915Sopenharmony_ci } 1519987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1520987da915Sopenharmony_ci buffer, xsize); 1521987da915Sopenharmony_ci } 1522987da915Sopenharmony_ci if (optv > 1) { 1523987da915Sopenharmony_ci printf("-> INDX record %s\n", 1524987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 1525987da915Sopenharmony_ci } 1526987da915Sopenharmony_ci } 1527987da915Sopenharmony_ci return (err); 1528987da915Sopenharmony_ci} 1529987da915Sopenharmony_ci 1530987da915Sopenharmony_ci/* 1531987da915Sopenharmony_ci * Controversial deletion of file names, see undo_delete_file() 1532987da915Sopenharmony_ci */ 1533987da915Sopenharmony_ci 1534987da915Sopenharmony_cistatic int delete_names(char *buffer) 1535987da915Sopenharmony_ci{ 1536987da915Sopenharmony_ci MFT_RECORD *record; 1537987da915Sopenharmony_ci ATTR_RECORD *attr; 1538987da915Sopenharmony_ci u32 used; 1539987da915Sopenharmony_ci u32 pos; 1540987da915Sopenharmony_ci int length; 1541987da915Sopenharmony_ci int cnt; 1542987da915Sopenharmony_ci 1543987da915Sopenharmony_ci record = (MFT_RECORD*)buffer; 1544987da915Sopenharmony_ci pos = le16_to_cpu(record->attrs_offset); 1545987da915Sopenharmony_ci used = le32_to_cpu(record->bytes_in_use); 1546987da915Sopenharmony_ci cnt = 0; 1547987da915Sopenharmony_ci do { 1548987da915Sopenharmony_ci attr = (ATTR_RECORD*)&buffer[pos]; 1549987da915Sopenharmony_ci length = le32_to_cpu(attr->length); 1550987da915Sopenharmony_ci if (attr->type == AT_FILE_NAME) { 1551987da915Sopenharmony_ci if (optv) 1552987da915Sopenharmony_ci showname("Controversial deletion of ", 1553987da915Sopenharmony_ci &buffer[pos+90], buffer[pos+88] & 255); 1554987da915Sopenharmony_ci memmove(buffer + pos, buffer + pos + length, 1555987da915Sopenharmony_ci mftrecsz - pos - length); 1556987da915Sopenharmony_ci used -= length; 1557987da915Sopenharmony_ci cnt++; 1558987da915Sopenharmony_ci } else 1559987da915Sopenharmony_ci pos += length; 1560987da915Sopenharmony_ci } while ((pos < used) 1561987da915Sopenharmony_ci && (le32_to_cpu(attr->type) <= le32_to_cpu(AT_FILE_NAME))); 1562987da915Sopenharmony_ci record->bytes_in_use = cpu_to_le32(used); 1563987da915Sopenharmony_ci record->link_count = cpu_to_le16(0); 1564987da915Sopenharmony_ci return (cnt ? 0 : 1); 1565987da915Sopenharmony_ci} 1566987da915Sopenharmony_ci 1567987da915Sopenharmony_cistatic int rebuildname(const INDEX_ENTRY *index) 1568987da915Sopenharmony_ci{ 1569987da915Sopenharmony_ci ATTR_RECORD *attr; 1570987da915Sopenharmony_ci int headlth; 1571987da915Sopenharmony_ci int datalth; 1572987da915Sopenharmony_ci 1573987da915Sopenharmony_ci datalth = le16_to_cpu(index->length) 1574987da915Sopenharmony_ci - offsetof(INDEX_ENTRY,key.file_name); 1575987da915Sopenharmony_ci headlth = offsetof(ATTR_RECORD,resident_end); 1576987da915Sopenharmony_ci attr = (ATTR_RECORD*)malloc(headlth + datalth); 1577987da915Sopenharmony_ci if (attr) { 1578987da915Sopenharmony_ci attr->type = AT_FILE_NAME; 1579987da915Sopenharmony_ci attr->length = cpu_to_le32(headlth + datalth); 1580987da915Sopenharmony_ci attr->non_resident = 0; 1581987da915Sopenharmony_ci attr->name_length = 0; 1582987da915Sopenharmony_ci attr->name_offset = const_cpu_to_le16(0); 1583987da915Sopenharmony_ci attr->flags = const_cpu_to_le16(0); 1584987da915Sopenharmony_ci attr->instance = const_cpu_to_le16(0); 1585987da915Sopenharmony_ci attr->value_length = cpu_to_le32( 1586987da915Sopenharmony_ci 2*index->key.file_name.file_name_length 1587987da915Sopenharmony_ci + offsetof(FILE_NAME_ATTR, file_name)); 1588987da915Sopenharmony_ci attr->value_offset = cpu_to_le16(headlth); 1589987da915Sopenharmony_ci attr->resident_flags = RESIDENT_ATTR_IS_INDEXED; 1590987da915Sopenharmony_ci memcpy(attr->resident_end, &index->key.file_name, datalth); 1591987da915Sopenharmony_ci free(attr); 1592987da915Sopenharmony_ci } 1593987da915Sopenharmony_ci return (0); 1594987da915Sopenharmony_ci} 1595987da915Sopenharmony_ci 1596987da915Sopenharmony_ci/* 1597987da915Sopenharmony_ci * Controversial creation of an index allocation attribute 1598987da915Sopenharmony_ci * 1599987da915Sopenharmony_ci * This is useful for turning the clock backward, but cannot 1600987da915Sopenharmony_ci * work properly in the general case and must not be used for 1601987da915Sopenharmony_ci * a real sync. 1602987da915Sopenharmony_ci * The main problem is to synchronize the file names when an 1603987da915Sopenharmony_ci * inode is reused with a different name. 1604987da915Sopenharmony_ci */ 1605987da915Sopenharmony_ci 1606987da915Sopenharmony_cistatic int insert_index_allocation(ntfs_volume *vol, char *buffer, u32 offs) 1607987da915Sopenharmony_ci{ 1608987da915Sopenharmony_ci MFT_RECORD *record; 1609987da915Sopenharmony_ci ATTR_RECORD *attr; 1610987da915Sopenharmony_ci u32 used; 1611987da915Sopenharmony_ci u32 pos; 1612987da915Sopenharmony_ci u32 xsize; 1613987da915Sopenharmony_ci u16 instance; 1614987da915Sopenharmony_ci int length; 1615987da915Sopenharmony_ci int addedlength; 1616987da915Sopenharmony_ci int namelength; 1617987da915Sopenharmony_ci int err; 1618987da915Sopenharmony_ci static const unsigned char bitmap[] = 1619987da915Sopenharmony_ci { 1, 0, 0, 0, 0, 0, 0, 0 } ; 1620987da915Sopenharmony_ci 1621987da915Sopenharmony_ci err = 1; 1622987da915Sopenharmony_ci if (opts) { 1623987da915Sopenharmony_ci printf("** Call to unsupported insert_index_allocation()\n"); 1624987da915Sopenharmony_ci } else { 1625987da915Sopenharmony_ci record = (MFT_RECORD*)buffer; 1626987da915Sopenharmony_ci pos = le16_to_cpu(record->attrs_offset); 1627987da915Sopenharmony_ci used = le32_to_cpu(record->bytes_in_use); 1628987da915Sopenharmony_ci attr = (ATTR_RECORD*)&buffer[pos]; 1629987da915Sopenharmony_ci while ((pos < used) 1630987da915Sopenharmony_ci && (le32_to_cpu(attr->type) < le32_to_cpu(AT_INDEX_ROOT))) { 1631987da915Sopenharmony_ci pos += le32_to_cpu(attr->length); 1632987da915Sopenharmony_ci attr = (ATTR_RECORD*)&buffer[pos]; 1633987da915Sopenharmony_ci } 1634987da915Sopenharmony_ci length = le32_to_cpu(attr->length); 1635987da915Sopenharmony_ci addedlength = length - 8 /* index allocation */ 1636987da915Sopenharmony_ci + length - 48; /* bitmap */ 1637987da915Sopenharmony_ci if ((attr->type == AT_INDEX_ROOT) 1638987da915Sopenharmony_ci && ((pos + length) == offs) 1639987da915Sopenharmony_ci && ((used + addedlength) < mftrecsz)) { 1640987da915Sopenharmony_ci /* Make space for the attribute */ 1641987da915Sopenharmony_ci memmove(buffer + offs + addedlength, buffer + offs, 1642987da915Sopenharmony_ci mftrecsz - offs - addedlength); 1643987da915Sopenharmony_ci record->bytes_in_use = cpu_to_le32(used + addedlength); 1644987da915Sopenharmony_ci /* 1645987da915Sopenharmony_ci * Insert an AT_INDEX_ALLOCATION 1646987da915Sopenharmony_ci */ 1647987da915Sopenharmony_ci attr = (ATTR_RECORD*)&buffer[offs]; 1648987da915Sopenharmony_ci attr->type = AT_INDEX_ALLOCATION; 1649987da915Sopenharmony_ci attr->length = cpu_to_le32(length - 8); 1650987da915Sopenharmony_ci attr->non_resident = 1; 1651987da915Sopenharmony_ci namelength = buffer[pos + 9] & 255; 1652987da915Sopenharmony_ci attr->name_length = namelength; 1653987da915Sopenharmony_ci attr->name_offset = const_cpu_to_le16(0x40); 1654987da915Sopenharmony_ci memcpy(buffer + offs + 0x40, buffer + pos + 0x18, 1655987da915Sopenharmony_ci 2*namelength); 1656987da915Sopenharmony_ci attr->flags = const_cpu_to_le16(0); 1657987da915Sopenharmony_ci /* Should we really take a new instance ? */ 1658987da915Sopenharmony_ci attr->instance = record->next_attr_instance; 1659987da915Sopenharmony_ci instance = le16_to_cpu(record->next_attr_instance) + 1; 1660987da915Sopenharmony_ci record->next_attr_instance = cpu_to_le16(instance); 1661987da915Sopenharmony_ci attr->lowest_vcn = const_cpu_to_sle64(0); 1662987da915Sopenharmony_ci attr->highest_vcn = const_cpu_to_sle64(0); 1663987da915Sopenharmony_ci attr->mapping_pairs_offset = cpu_to_le16( 1664987da915Sopenharmony_ci 2*namelength + 0x40); 1665987da915Sopenharmony_ci attr->compression_unit = 0; 1666987da915Sopenharmony_ci xsize = vol->indx_record_size; 1667987da915Sopenharmony_ci attr->allocated_size = cpu_to_sle64(xsize); 1668987da915Sopenharmony_ci attr->data_size = attr->allocated_size; 1669987da915Sopenharmony_ci attr->initialized_size = attr->allocated_size; 1670987da915Sopenharmony_ci /* 1671987da915Sopenharmony_ci * Insert an AT_INDEX_BITMAP 1672987da915Sopenharmony_ci */ 1673987da915Sopenharmony_ci attr = (ATTR_RECORD*)&buffer[offs + length - 8]; 1674987da915Sopenharmony_ci attr->type = AT_BITMAP; 1675987da915Sopenharmony_ci attr->length = cpu_to_le32(length - 48); 1676987da915Sopenharmony_ci attr->non_resident = 0; 1677987da915Sopenharmony_ci namelength = buffer[pos + 9] & 255; 1678987da915Sopenharmony_ci attr->name_length = namelength; 1679987da915Sopenharmony_ci attr->name_offset = const_cpu_to_le16(0x18); 1680987da915Sopenharmony_ci memcpy(buffer + offs + length - 8 + 0x18, 1681987da915Sopenharmony_ci buffer + pos + 0x18, 2*namelength); 1682987da915Sopenharmony_ci attr->flags = const_cpu_to_le16(0); 1683987da915Sopenharmony_ci attr->value_length = const_cpu_to_le32(8); 1684987da915Sopenharmony_ci attr->value_offset = cpu_to_le16(2*namelength + 24); 1685987da915Sopenharmony_ci attr->resident_flags = 0; 1686987da915Sopenharmony_ci memcpy((char*)attr->resident_end + 2*namelength, 1687987da915Sopenharmony_ci bitmap, 8); 1688987da915Sopenharmony_ci /* Should we really take a new instance ? */ 1689987da915Sopenharmony_ci attr->instance = record->next_attr_instance; 1690987da915Sopenharmony_ci instance = le16_to_cpu(record->next_attr_instance) + 1; 1691987da915Sopenharmony_ci record->next_attr_instance = cpu_to_le16(instance); 1692987da915Sopenharmony_ci err = sanity_mft(buffer); 1693987da915Sopenharmony_ci } else { 1694987da915Sopenharmony_ci printf("** index root does not match\n"); 1695987da915Sopenharmony_ci err = 1; 1696987da915Sopenharmony_ci } 1697987da915Sopenharmony_ci } 1698987da915Sopenharmony_ci return (err); 1699987da915Sopenharmony_ci} 1700987da915Sopenharmony_ci 1701987da915Sopenharmony_ci/* 1702987da915Sopenharmony_ci * Check whether a full MFT record is fed by an action 1703987da915Sopenharmony_ci * 1704987da915Sopenharmony_ci * If so, checking the validity of existing record is pointless 1705987da915Sopenharmony_ci */ 1706987da915Sopenharmony_ci 1707987da915Sopenharmony_cistatic BOOL check_full_mft(const struct ACTION_RECORD *action, BOOL redoing) 1708987da915Sopenharmony_ci{ 1709987da915Sopenharmony_ci const MFT_RECORD *record; 1710987da915Sopenharmony_ci const ATTR_RECORD *attr; 1711987da915Sopenharmony_ci u32 length; 1712987da915Sopenharmony_ci u32 k; 1713987da915Sopenharmony_ci BOOL ok; 1714987da915Sopenharmony_ci 1715987da915Sopenharmony_ci if (redoing) { 1716987da915Sopenharmony_ci record = (const MFT_RECORD*)((const char*)&action->record 1717987da915Sopenharmony_ci + get_redo_offset(&action->record)); 1718987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 1719987da915Sopenharmony_ci } else { 1720987da915Sopenharmony_ci record = (const MFT_RECORD*)((const char*)&action->record 1721987da915Sopenharmony_ci + get_undo_offset(&action->record)); 1722987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 1723987da915Sopenharmony_ci } 1724987da915Sopenharmony_ci /* The length in use must be fed */ 1725987da915Sopenharmony_ci ok = !action->record.record_offset 1726987da915Sopenharmony_ci && !action->record.attribute_offset 1727987da915Sopenharmony_ci && (record->magic == magic_FILE) 1728987da915Sopenharmony_ci && (length <= mftrecsz) 1729987da915Sopenharmony_ci && (length >= (offsetof(MFT_RECORD, bytes_in_use) 1730987da915Sopenharmony_ci + sizeof(record->bytes_in_use))); 1731987da915Sopenharmony_ci if (ok) { 1732987da915Sopenharmony_ci k = le16_to_cpu(record->attrs_offset); 1733987da915Sopenharmony_ci attr = (const ATTR_RECORD*)((const char*)record + k); 1734987da915Sopenharmony_ci while (((k + sizeof(attr->type)) <= length) 1735987da915Sopenharmony_ci && (attr->type != AT_END) 1736987da915Sopenharmony_ci && valid_type(attr->type)) { 1737987da915Sopenharmony_ci k += le32_to_cpu(attr->length); 1738987da915Sopenharmony_ci attr = (const ATTR_RECORD*)((const char*)record + k); 1739987da915Sopenharmony_ci } 1740987da915Sopenharmony_ci /* AT_END must be present */ 1741987da915Sopenharmony_ci ok = ((k + sizeof(attr->type)) <= length) 1742987da915Sopenharmony_ci && (attr->type == AT_END); 1743987da915Sopenharmony_ci } 1744987da915Sopenharmony_ci return (ok); 1745987da915Sopenharmony_ci} 1746987da915Sopenharmony_ci 1747987da915Sopenharmony_ci/* 1748987da915Sopenharmony_ci * Check whether a full index block is fed by the log record 1749987da915Sopenharmony_ci * 1750987da915Sopenharmony_ci * If so, checking the validity of existing record is pointless 1751987da915Sopenharmony_ci */ 1752987da915Sopenharmony_ci 1753987da915Sopenharmony_cistatic BOOL check_full_index(const struct ACTION_RECORD *action, BOOL redoing) 1754987da915Sopenharmony_ci{ 1755987da915Sopenharmony_ci const INDEX_BLOCK *indx; 1756987da915Sopenharmony_ci u32 length; 1757987da915Sopenharmony_ci 1758987da915Sopenharmony_ci if (redoing) { 1759987da915Sopenharmony_ci indx = (const INDEX_BLOCK*)((const char*)&action->record 1760987da915Sopenharmony_ci + get_redo_offset(&action->record)); 1761987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 1762987da915Sopenharmony_ci } else { 1763987da915Sopenharmony_ci indx = (const INDEX_BLOCK*)((const char*)&action->record 1764987da915Sopenharmony_ci + get_undo_offset(&action->record)); 1765987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 1766987da915Sopenharmony_ci } 1767987da915Sopenharmony_ci /* the index length must be fed, so must be the full index block */ 1768987da915Sopenharmony_ci return (!action->record.record_offset 1769987da915Sopenharmony_ci && !action->record.attribute_offset 1770987da915Sopenharmony_ci && (indx->magic == magic_INDX) 1771987da915Sopenharmony_ci && (length >= (offsetof(INDEX_BLOCK, index.index_length) + 4)) 1772987da915Sopenharmony_ci && (length >= (le32_to_cpu(indx->index.index_length) + 24))); 1773987da915Sopenharmony_ci} 1774987da915Sopenharmony_ci 1775987da915Sopenharmony_ci/* 1776987da915Sopenharmony_ci * Create an index block for undoing its deletion 1777987da915Sopenharmony_ci * 1778987da915Sopenharmony_ci * This is useful for turning the clock backward, but cannot 1779987da915Sopenharmony_ci * work properly in the general case and must not be used for 1780987da915Sopenharmony_ci * a real sync. 1781987da915Sopenharmony_ci */ 1782987da915Sopenharmony_ci 1783987da915Sopenharmony_cistatic int create_indx(ntfs_volume *vol, const struct ACTION_RECORD *action, 1784987da915Sopenharmony_ci char *buffer) 1785987da915Sopenharmony_ci{ 1786987da915Sopenharmony_ci INDEX_BLOCK *indx; 1787987da915Sopenharmony_ci INDEX_ENTRY_HEADER *ixhead; 1788987da915Sopenharmony_ci INDEX_ENTRY *ixentry; 1789987da915Sopenharmony_ci VCN vcn; 1790987da915Sopenharmony_ci int err; 1791987da915Sopenharmony_ci 1792987da915Sopenharmony_ci if (opts) { 1793987da915Sopenharmony_ci printf("** Call to unsupported create_indx()\n"); 1794987da915Sopenharmony_ci err = 1; 1795987da915Sopenharmony_ci } else { 1796987da915Sopenharmony_ci err = 0; 1797987da915Sopenharmony_ci indx = (INDEX_BLOCK*)buffer; 1798987da915Sopenharmony_ci indx->magic = magic_INDX; 1799987da915Sopenharmony_ci// TODO compute properly 1800987da915Sopenharmony_ci indx->usa_ofs = const_cpu_to_le16(0x28); 1801987da915Sopenharmony_ci indx->usa_count = const_cpu_to_le16(9); 1802987da915Sopenharmony_ci indx->lsn = action->record.this_lsn; 1803987da915Sopenharmony_ci vcn = sle64_to_cpu(action->record.target_vcn); 1804987da915Sopenharmony_ci /* beware of size change on big-endian cpus */ 1805987da915Sopenharmony_ci indx->index_block_vcn = cpu_to_sle64(vcn); 1806987da915Sopenharmony_ci /* INDEX_HEADER */ 1807987da915Sopenharmony_ci indx->index.entries_offset = const_cpu_to_le32(0x28); 1808987da915Sopenharmony_ci indx->index.index_length = const_cpu_to_le32(0x38); 1809987da915Sopenharmony_ci indx->index.allocated_size = 1810987da915Sopenharmony_ci cpu_to_le32(vol->indx_record_size - 24); 1811987da915Sopenharmony_ci indx->index.ih_flags = 0; 1812987da915Sopenharmony_ci /* INDEX_ENTRY_HEADER */ 1813987da915Sopenharmony_ci ixhead = (INDEX_ENTRY_HEADER*)(buffer + 0x28); 1814987da915Sopenharmony_ci ixhead->length = cpu_to_le16(vol->indx_record_size - 24); 1815987da915Sopenharmony_ci /* terminating INDEX_ENTRY */ 1816987da915Sopenharmony_ci ixentry = (INDEX_ENTRY*)(buffer + 0x40); 1817987da915Sopenharmony_ci ixentry->indexed_file = const_cpu_to_le64(0); 1818987da915Sopenharmony_ci ixentry->length = const_cpu_to_le16(16); 1819987da915Sopenharmony_ci ixentry->key_length = const_cpu_to_le16(0); 1820987da915Sopenharmony_ci ixentry->ie_flags = INDEX_ENTRY_END; 1821987da915Sopenharmony_ci } 1822987da915Sopenharmony_ci return (err); 1823987da915Sopenharmony_ci} 1824987da915Sopenharmony_ci 1825987da915Sopenharmony_cistatic int redo_action37(ntfs_volume *vol, const struct ACTION_RECORD *action, 1826987da915Sopenharmony_ci char *buffer) 1827987da915Sopenharmony_ci{ 1828987da915Sopenharmony_ci u32 target; 1829987da915Sopenharmony_ci u32 length; 1830987da915Sopenharmony_ci int err; 1831987da915Sopenharmony_ci 1832987da915Sopenharmony_ci if (optv > 1) 1833987da915Sopenharmony_ci printf("-> %s()\n",__func__); 1834987da915Sopenharmony_ci err = 1; 1835987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 1836987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 1837987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 1838987da915Sopenharmony_ci if (optv > 1) { 1839987da915Sopenharmony_ci printf("existing data :\n"); 1840987da915Sopenharmony_ci dump(buffer + target,length); 1841987da915Sopenharmony_ci } 1842987da915Sopenharmony_ci if ((target + length) == mftrecsz) { 1843987da915Sopenharmony_ci memset(buffer + target, 0, length); 1844987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1845987da915Sopenharmony_ci buffer, mftrecsz); 1846987da915Sopenharmony_ci if (optv > 1) { 1847987da915Sopenharmony_ci printf("-> MFT record trimmed\n"); 1848987da915Sopenharmony_ci } 1849987da915Sopenharmony_ci } else { 1850987da915Sopenharmony_ci printf("** Bad action-37, inode %lld record :\n", 1851987da915Sopenharmony_ci (long long)inode_number(&action->record)); 1852987da915Sopenharmony_ci printf("target %d length %d sum %d\n", 1853987da915Sopenharmony_ci (int)target,(int)length,(int)(target + length)); 1854987da915Sopenharmony_ci dump(buffer,mftrecsz); 1855987da915Sopenharmony_ci } 1856987da915Sopenharmony_ci err = 0; 1857987da915Sopenharmony_ci return (err); 1858987da915Sopenharmony_ci} 1859987da915Sopenharmony_ci 1860987da915Sopenharmony_cistatic int redo_add_index(ntfs_volume *vol, const struct ACTION_RECORD *action, 1861987da915Sopenharmony_ci char *buffer) 1862987da915Sopenharmony_ci{ 1863987da915Sopenharmony_ci LCN lcn; 1864987da915Sopenharmony_ci const char *data; 1865987da915Sopenharmony_ci INDEX_BLOCK *indx; 1866987da915Sopenharmony_ci u32 target; 1867987da915Sopenharmony_ci u32 length; 1868987da915Sopenharmony_ci u32 xsize; 1869987da915Sopenharmony_ci u32 indexlth; 1870987da915Sopenharmony_ci int err; 1871987da915Sopenharmony_ci BOOL found; 1872987da915Sopenharmony_ci 1873987da915Sopenharmony_ci if (optv > 1) 1874987da915Sopenharmony_ci printf("-> %s()\n",__func__); 1875987da915Sopenharmony_ci err = 1; 1876987da915Sopenharmony_ci data = ((const char*)&action->record) 1877987da915Sopenharmony_ci + get_redo_offset(&action->record); 1878987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 1879987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 1880987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 1881987da915Sopenharmony_ci if (optv > 1) { 1882987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1883987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 1884987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1885987da915Sopenharmony_ci } 1886987da915Sopenharmony_ci xsize = vol->indx_record_size; 1887987da915Sopenharmony_ci indx = (INDEX_BLOCK*)(buffer 1888987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 1889987da915Sopenharmony_ci if (optv > 1) { 1890987da915Sopenharmony_ci printf("-> existing record :\n"); 1891987da915Sopenharmony_ci dump(&buffer[target], length); 1892987da915Sopenharmony_ci } 1893987da915Sopenharmony_ci if ((indx->magic == magic_INDX) 1894987da915Sopenharmony_ci && !(length & 7) 1895987da915Sopenharmony_ci && ((target + length) <= xsize)) { 1896987da915Sopenharmony_ci /* This has to be an idempotent action */ 1897987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 1898987da915Sopenharmony_ci err = 0; 1899987da915Sopenharmony_ci if (!found) { 1900987da915Sopenharmony_ci /* Make space to insert the entry */ 1901987da915Sopenharmony_ci memmove(buffer + target + length, 1902987da915Sopenharmony_ci buffer + target, 1903987da915Sopenharmony_ci xsize - target - length); 1904987da915Sopenharmony_ci memcpy(buffer + target, data, length); 1905987da915Sopenharmony_ci indexlth = le32_to_cpu(indx->index.index_length) 1906987da915Sopenharmony_ci + length; 1907987da915Sopenharmony_ci indx->index.index_length = cpu_to_le32(indexlth); 1908987da915Sopenharmony_ci if (optv > 1) { 1909987da915Sopenharmony_ci printf("-> inserted record :\n"); 1910987da915Sopenharmony_ci dump(&buffer[target], length); 1911987da915Sopenharmony_ci } 1912987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1913987da915Sopenharmony_ci buffer, xsize); 1914987da915Sopenharmony_ci } 1915987da915Sopenharmony_ci if (optv > 1) { 1916987da915Sopenharmony_ci printf("-> INDX record %s\n", 1917987da915Sopenharmony_ci (found ? "unchanged" : "inserted")); 1918987da915Sopenharmony_ci } 1919987da915Sopenharmony_ci } 1920987da915Sopenharmony_ci return (err); 1921987da915Sopenharmony_ci} 1922987da915Sopenharmony_ci 1923987da915Sopenharmony_cistatic int redo_add_root_index(ntfs_volume *vol, 1924987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 1925987da915Sopenharmony_ci{ 1926987da915Sopenharmony_ci LCN lcn; 1927987da915Sopenharmony_ci const char *data; 1928987da915Sopenharmony_ci ATTR_RECORD *attr; 1929987da915Sopenharmony_ci MFT_RECORD *entry; 1930987da915Sopenharmony_ci INDEX_ROOT *index; 1931987da915Sopenharmony_ci u32 target; 1932987da915Sopenharmony_ci u32 length; 1933987da915Sopenharmony_ci int err; 1934987da915Sopenharmony_ci BOOL found; 1935987da915Sopenharmony_ci 1936987da915Sopenharmony_ci if (optv > 1) 1937987da915Sopenharmony_ci printf("-> %s()\n",__func__); 1938987da915Sopenharmony_ci err = 1; 1939987da915Sopenharmony_ci data = ((const char*)&action->record) 1940987da915Sopenharmony_ci + get_redo_offset(&action->record); 1941987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 1942987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 1943987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 1944987da915Sopenharmony_ci if (optv > 1) { 1945987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 1946987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 1947987da915Sopenharmony_ci (long long)inode_number(&action->record), 1948987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 1949987da915Sopenharmony_ci } 1950987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 1951987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 1952987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 1953987da915Sopenharmony_ci index = (INDEX_ROOT*)(((char*)attr) 1954987da915Sopenharmony_ci + le16_to_cpu(attr->value_offset)); 1955987da915Sopenharmony_ci if (optv > 1) { 1956987da915Sopenharmony_ci printf("existing index :\n"); 1957987da915Sopenharmony_ci dump(buffer + target,length); 1958987da915Sopenharmony_ci } 1959987da915Sopenharmony_ci if ((attr->type == AT_INDEX_ROOT) 1960987da915Sopenharmony_ci && !(length & 7) 1961987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 1962987da915Sopenharmony_ci /* This has to be an idempotent action */ 1963987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 1964987da915Sopenharmony_ci err = 0; 1965987da915Sopenharmony_ci if (!found) { 1966987da915Sopenharmony_ci /* Make space to insert the entry */ 1967987da915Sopenharmony_ci memmove(buffer + target + length, 1968987da915Sopenharmony_ci buffer + target, 1969987da915Sopenharmony_ci mftrecsz - target - length); 1970987da915Sopenharmony_ci memcpy(buffer + target, data, length); 1971987da915Sopenharmony_ci resize_attribute(entry, attr, index, length, length); 1972987da915Sopenharmony_ci if (optv > 1) { 1973987da915Sopenharmony_ci printf("new index at same location :\n"); 1974987da915Sopenharmony_ci dump(buffer + target, length); 1975987da915Sopenharmony_ci } 1976987da915Sopenharmony_ci err = write_protected(vol, &action->record, 1977987da915Sopenharmony_ci buffer, mftrecsz); 1978987da915Sopenharmony_ci } 1979987da915Sopenharmony_ci if (optv > 1) { 1980987da915Sopenharmony_ci printf("-> MFT record %s\n", 1981987da915Sopenharmony_ci (found ? "unchanged" : "expanded")); 1982987da915Sopenharmony_ci } 1983987da915Sopenharmony_ci } 1984987da915Sopenharmony_ci return (err); 1985987da915Sopenharmony_ci} 1986987da915Sopenharmony_ci 1987987da915Sopenharmony_cistatic int redo_compensate(ntfs_volume *vol __attribute__((unused)), 1988987da915Sopenharmony_ci const struct ACTION_RECORD *action, 1989987da915Sopenharmony_ci char *buffer __attribute__((unused))) 1990987da915Sopenharmony_ci{ 1991987da915Sopenharmony_ci u64 lsn; 1992987da915Sopenharmony_ci s64 diff; 1993987da915Sopenharmony_ci 1994987da915Sopenharmony_ci if (optv > 1) 1995987da915Sopenharmony_ci printf("-> %s()\n",__func__); 1996987da915Sopenharmony_ci lsn = sle64_to_cpu(action->record.this_lsn); 1997987da915Sopenharmony_ci diff = lsn - restart_lsn; 1998987da915Sopenharmony_ci if (diff > 0) 1999987da915Sopenharmony_ci restart_lsn = lsn; 2000987da915Sopenharmony_ci return (0); 2001987da915Sopenharmony_ci} 2002987da915Sopenharmony_ci 2003987da915Sopenharmony_cistatic int redo_create_file(ntfs_volume *vol, 2004987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2005987da915Sopenharmony_ci{ 2006987da915Sopenharmony_ci LCN lcn; 2007987da915Sopenharmony_ci const char *data; 2008987da915Sopenharmony_ci MFT_RECORD *record; 2009987da915Sopenharmony_ci u32 target; 2010987da915Sopenharmony_ci u32 length; 2011987da915Sopenharmony_ci int err; 2012987da915Sopenharmony_ci int changed; 2013987da915Sopenharmony_ci 2014987da915Sopenharmony_ci if (optv > 1) 2015987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2016987da915Sopenharmony_ci err = 1; 2017987da915Sopenharmony_ci data = ((const char*)&action->record) 2018987da915Sopenharmony_ci + get_redo_offset(&action->record); 2019987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2020987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2021987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2022987da915Sopenharmony_ci if (optv > 1) { 2023987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2024987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 2025987da915Sopenharmony_ci (long long)inode_number(&action->record), 2026987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2027987da915Sopenharmony_ci } 2028987da915Sopenharmony_ci record = (MFT_RECORD*)buffer; 2029987da915Sopenharmony_ci if (optv > 1) { 2030987da915Sopenharmony_ci printf("-> existing record :\n"); 2031987da915Sopenharmony_ci dump(buffer,mftrecsz); 2032987da915Sopenharmony_ci } 2033987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 2034987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 2035987da915Sopenharmony_ci err = 0; 2036987da915Sopenharmony_ci if (changed || !(record->flags & MFT_RECORD_IN_USE)) { 2037987da915Sopenharmony_ci memcpy(buffer + target, data, length); 2038987da915Sopenharmony_ci record->flags |= MFT_RECORD_IN_USE; 2039987da915Sopenharmony_ci if (optv > 1) { 2040987da915Sopenharmony_ci printf("-> new record :\n"); 2041987da915Sopenharmony_ci dump(buffer,mftrecsz); 2042987da915Sopenharmony_ci } 2043987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2044987da915Sopenharmony_ci buffer, mftrecsz); 2045987da915Sopenharmony_ci } 2046987da915Sopenharmony_ci if (optv > 1) { 2047987da915Sopenharmony_ci printf("-> MFT record %s\n", 2048987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 2049987da915Sopenharmony_ci } 2050987da915Sopenharmony_ci } else { 2051987da915Sopenharmony_ci err = 1; /* record overflows */ 2052987da915Sopenharmony_ci } 2053987da915Sopenharmony_ci return (err); 2054987da915Sopenharmony_ci} 2055987da915Sopenharmony_ci 2056987da915Sopenharmony_cistatic int redo_create_attribute(ntfs_volume *vol, 2057987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2058987da915Sopenharmony_ci{ 2059987da915Sopenharmony_ci const char *data; 2060987da915Sopenharmony_ci u32 target; 2061987da915Sopenharmony_ci u32 length; 2062987da915Sopenharmony_ci int err; 2063987da915Sopenharmony_ci 2064987da915Sopenharmony_ci if (optv > 1) 2065987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2066987da915Sopenharmony_ci err = 1; 2067987da915Sopenharmony_ci data = ((const char*)&action->record) 2068987da915Sopenharmony_ci + get_redo_offset(&action->record); 2069987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2070987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2071987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2072987da915Sopenharmony_ci// Could also be AT_DATA or AT_INDEX_ALLOCATION 2073987da915Sopenharmony_ci if (!action->record.undo_length) 2074987da915Sopenharmony_ci err = insert_resident(vol, action, buffer, data, 2075987da915Sopenharmony_ci target, length); 2076987da915Sopenharmony_ci return (err); 2077987da915Sopenharmony_ci} 2078987da915Sopenharmony_ci 2079987da915Sopenharmony_cistatic int redo_delete_attribute(ntfs_volume *vol, 2080987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2081987da915Sopenharmony_ci{ 2082987da915Sopenharmony_ci const char *data; 2083987da915Sopenharmony_ci u32 target; 2084987da915Sopenharmony_ci u32 length; 2085987da915Sopenharmony_ci int err; 2086987da915Sopenharmony_ci 2087987da915Sopenharmony_ci if (optv > 1) 2088987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2089987da915Sopenharmony_ci err = 1; 2090987da915Sopenharmony_ci data = ((const char*)&action->record) 2091987da915Sopenharmony_ci + get_undo_offset(&action->record); 2092987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 2093987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2094987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2095987da915Sopenharmony_ci if (!action->record.redo_length) 2096987da915Sopenharmony_ci err = remove_resident(vol, action, buffer, data, 2097987da915Sopenharmony_ci target, length); 2098987da915Sopenharmony_ci return (err); 2099987da915Sopenharmony_ci} 2100987da915Sopenharmony_ci 2101987da915Sopenharmony_cistatic int redo_delete_file(ntfs_volume *vol, 2102987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2103987da915Sopenharmony_ci{ 2104987da915Sopenharmony_ci LCN lcn; 2105987da915Sopenharmony_ci const char *data; 2106987da915Sopenharmony_ci MFT_RECORD *record; 2107987da915Sopenharmony_ci u32 target; 2108987da915Sopenharmony_ci u32 length; 2109987da915Sopenharmony_ci int err; 2110987da915Sopenharmony_ci int changed; 2111987da915Sopenharmony_ci 2112987da915Sopenharmony_ci if (optv > 1) 2113987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2114987da915Sopenharmony_ci err = 1; 2115987da915Sopenharmony_ci data = ((const char*)&action->record) 2116987da915Sopenharmony_ci + get_undo_offset(&action->record); 2117987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 2118987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2119987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2120987da915Sopenharmony_ci if (optv > 1) { 2121987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2122987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 2123987da915Sopenharmony_ci (long long)inode_number(&action->record), 2124987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2125987da915Sopenharmony_ci } 2126987da915Sopenharmony_ci if (optv > 1) { 2127987da915Sopenharmony_ci printf("-> existing record :\n"); 2128987da915Sopenharmony_ci dump(buffer,mftrecsz); 2129987da915Sopenharmony_ci } 2130987da915Sopenharmony_ci record = (MFT_RECORD*)buffer; 2131987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 2132987da915Sopenharmony_ci /* write a void mft entry (needed ?) */ 2133987da915Sopenharmony_ci changed = (length && memcmp(buffer + target, data, length)) 2134987da915Sopenharmony_ci || (record->flags & MFT_RECORD_IN_USE); 2135987da915Sopenharmony_ci err = 0; 2136987da915Sopenharmony_ci if (changed) { 2137987da915Sopenharmony_ci memcpy(buffer + target, data, length); 2138987da915Sopenharmony_ci record->flags &= ~MFT_RECORD_IN_USE; 2139987da915Sopenharmony_ci if (optv > 1) { 2140987da915Sopenharmony_ci printf("-> new record :\n"); 2141987da915Sopenharmony_ci dump(buffer,mftrecsz); 2142987da915Sopenharmony_ci } 2143987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2144987da915Sopenharmony_ci buffer, mftrecsz); 2145987da915Sopenharmony_ci } 2146987da915Sopenharmony_ci if (optv > 1) { 2147987da915Sopenharmony_ci printf("-> MFT record %s\n", 2148987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 2149987da915Sopenharmony_ci } 2150987da915Sopenharmony_ci } 2151987da915Sopenharmony_ci return (err); 2152987da915Sopenharmony_ci} 2153987da915Sopenharmony_ci 2154987da915Sopenharmony_cistatic int redo_delete_index(ntfs_volume *vol, 2155987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2156987da915Sopenharmony_ci{ 2157987da915Sopenharmony_ci LCN lcn; 2158987da915Sopenharmony_ci const char *data; 2159987da915Sopenharmony_ci INDEX_BLOCK *indx; 2160987da915Sopenharmony_ci u32 target; 2161987da915Sopenharmony_ci u32 length; 2162987da915Sopenharmony_ci u32 xsize; 2163987da915Sopenharmony_ci u32 indexlth; 2164987da915Sopenharmony_ci int err; 2165987da915Sopenharmony_ci BOOL found; 2166987da915Sopenharmony_ci 2167987da915Sopenharmony_ci if (optv > 1) 2168987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2169987da915Sopenharmony_ci err = 1; 2170987da915Sopenharmony_ci data = ((const char*)&action->record) 2171987da915Sopenharmony_ci + get_undo_offset(&action->record); 2172987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 2173987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2174987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2175987da915Sopenharmony_ci if (optv > 1) { 2176987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2177987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 2178987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2179987da915Sopenharmony_ci } 2180987da915Sopenharmony_ci xsize = vol->indx_record_size; 2181987da915Sopenharmony_ci indx = (INDEX_BLOCK*)(buffer 2182987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 2183987da915Sopenharmony_ci if (optv > 1) { 2184987da915Sopenharmony_ci printf("-> existing record :\n"); 2185987da915Sopenharmony_ci dump(&buffer[target], length); 2186987da915Sopenharmony_ci } 2187987da915Sopenharmony_ci if ((indx->magic == magic_INDX) 2188987da915Sopenharmony_ci && !(length & 7) 2189987da915Sopenharmony_ci && ((target + length) <= xsize)) { 2190987da915Sopenharmony_ci /* This has to be an idempotent action */ 2191987da915Sopenharmony_ci found = (action->record.undo_operation 2192987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord)) 2193987da915Sopenharmony_ci || !memcmp(buffer + target, data, length); 2194987da915Sopenharmony_ci err = 0; 2195987da915Sopenharmony_ci if (found) { 2196987da915Sopenharmony_ci /* Remove the entry */ 2197987da915Sopenharmony_ci memmove(buffer + target, 2198987da915Sopenharmony_ci buffer + target + length, 2199987da915Sopenharmony_ci xsize - target - length); 2200987da915Sopenharmony_ci indexlth = le32_to_cpu(indx->index.index_length) 2201987da915Sopenharmony_ci - length; 2202987da915Sopenharmony_ci indx->index.index_length = cpu_to_le32(indexlth); 2203987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2204987da915Sopenharmony_ci buffer, xsize); 2205987da915Sopenharmony_ci } 2206987da915Sopenharmony_ci if (optv > 1) { 2207987da915Sopenharmony_ci printf("-> INDX record %s\n", 2208987da915Sopenharmony_ci (found ? "removed" : "unchanged")); 2209987da915Sopenharmony_ci } 2210987da915Sopenharmony_ci } 2211987da915Sopenharmony_ci return (err); 2212987da915Sopenharmony_ci} 2213987da915Sopenharmony_ci 2214987da915Sopenharmony_cistatic int redo_delete_root_index(ntfs_volume *vol, 2215987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2216987da915Sopenharmony_ci{ 2217987da915Sopenharmony_ci LCN lcn; 2218987da915Sopenharmony_ci const char *data; 2219987da915Sopenharmony_ci ATTR_RECORD *attr; 2220987da915Sopenharmony_ci MFT_RECORD *entry; 2221987da915Sopenharmony_ci INDEX_ROOT *index; 2222987da915Sopenharmony_ci BOOL found; 2223987da915Sopenharmony_ci u32 target; 2224987da915Sopenharmony_ci u32 length; 2225987da915Sopenharmony_ci int err; 2226987da915Sopenharmony_ci 2227987da915Sopenharmony_ci if (optv > 1) 2228987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2229987da915Sopenharmony_ci err = 1; 2230987da915Sopenharmony_ci data = ((const char*)&action->record) 2231987da915Sopenharmony_ci + get_undo_offset(&action->record); 2232987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 2233987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2234987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2235987da915Sopenharmony_ci 2236987da915Sopenharmony_ci if (optv > 1) { 2237987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2238987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 2239987da915Sopenharmony_ci (long long)inode_number(&action->record), 2240987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2241987da915Sopenharmony_ci } 2242987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 2243987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 2244987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 2245987da915Sopenharmony_ci index = (INDEX_ROOT*)(((char*)attr) 2246987da915Sopenharmony_ci + le16_to_cpu(attr->value_offset)); 2247987da915Sopenharmony_ci if (optv > 1) { 2248987da915Sopenharmony_ci printf("existing index :\n"); 2249987da915Sopenharmony_ci dump(buffer + target,length); 2250987da915Sopenharmony_ci } 2251987da915Sopenharmony_ci if ((attr->type == AT_INDEX_ROOT) 2252987da915Sopenharmony_ci && !(length & 7) 2253987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 2254987da915Sopenharmony_ci /* This has to be an idempotent action */ 2255987da915Sopenharmony_ci found = (action->record.undo_operation 2256987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord)) 2257987da915Sopenharmony_ci || !memcmp(buffer + target, data, length); 2258987da915Sopenharmony_ci err = 0; 2259987da915Sopenharmony_ci /* Only delete if present */ 2260987da915Sopenharmony_ci if (found) { 2261987da915Sopenharmony_ci /* Remove the entry */ 2262987da915Sopenharmony_ci memmove(buffer + target, 2263987da915Sopenharmony_ci buffer + target + length, 2264987da915Sopenharmony_ci mftrecsz - target - length); 2265987da915Sopenharmony_ci resize_attribute(entry, attr, index, -length, -length); 2266987da915Sopenharmony_ci if (optv > 1) { 2267987da915Sopenharmony_ci printf("new index at same location :\n"); 2268987da915Sopenharmony_ci dump(buffer + target, length); 2269987da915Sopenharmony_ci } 2270987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2271987da915Sopenharmony_ci buffer, mftrecsz); 2272987da915Sopenharmony_ci } 2273987da915Sopenharmony_ci if (optv > 1) { 2274987da915Sopenharmony_ci printf("-> MFT record %s\n", 2275987da915Sopenharmony_ci (found ? "shrinked" : "updated")); 2276987da915Sopenharmony_ci } 2277987da915Sopenharmony_ci } 2278987da915Sopenharmony_ci return (err); 2279987da915Sopenharmony_ci} 2280987da915Sopenharmony_ci 2281987da915Sopenharmony_cistatic int redo_force_bits(ntfs_volume *vol, 2282987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2283987da915Sopenharmony_ci{ 2284987da915Sopenharmony_ci LCN lcn; 2285987da915Sopenharmony_ci const struct BITMAP_ACTION *data; 2286987da915Sopenharmony_ci u32 i; 2287987da915Sopenharmony_ci int err; 2288987da915Sopenharmony_ci int wanted; 2289987da915Sopenharmony_ci u32 firstbit; 2290987da915Sopenharmony_ci u32 count; 2291987da915Sopenharmony_ci 2292987da915Sopenharmony_ci if (optv > 1) 2293987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2294987da915Sopenharmony_ci err = 1; 2295987da915Sopenharmony_ci data = (const struct BITMAP_ACTION*) 2296987da915Sopenharmony_ci (((const char*)&action->record) 2297987da915Sopenharmony_ci + get_redo_offset(&action->record)); 2298987da915Sopenharmony_ci firstbit = le32_to_cpu(data->firstbit); 2299987da915Sopenharmony_ci count = le32_to_cpu(data->count); 2300987da915Sopenharmony_ci if (action->record.redo_operation 2301987da915Sopenharmony_ci == const_cpu_to_le16(SetBitsInNonResidentBitMap)) 2302987da915Sopenharmony_ci wanted = 1; 2303987da915Sopenharmony_ci else 2304987da915Sopenharmony_ci wanted = 0; 2305987da915Sopenharmony_ci// TODO consistency undo_offset == redo_offset, etc. 2306987da915Sopenharmony_ci// firstbit + count < 8*clustersz (multiple clusters possible ?) 2307987da915Sopenharmony_ci if (optv > 1) { 2308987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2309987da915Sopenharmony_ci printf("-> lcn 0x%llx firstbit %d count %d wanted %d\n", 2310987da915Sopenharmony_ci (long long)lcn,(int)firstbit,(int)count,(int)wanted); 2311987da915Sopenharmony_ci } 2312987da915Sopenharmony_ci for (i=0; i<count; i++) 2313987da915Sopenharmony_ci ntfs_bit_set((u8*)buffer, firstbit + i, wanted); 2314987da915Sopenharmony_ci if (!write_raw(vol, &action->record, buffer)) { 2315987da915Sopenharmony_ci err = 0; 2316987da915Sopenharmony_ci if (optv > 1) 2317987da915Sopenharmony_ci printf("-> record updated\n"); 2318987da915Sopenharmony_ci } 2319987da915Sopenharmony_ci if (err) 2320987da915Sopenharmony_ci printf("** redo_clearbits failed\n"); 2321987da915Sopenharmony_ci return (err); 2322987da915Sopenharmony_ci} 2323987da915Sopenharmony_ci 2324987da915Sopenharmony_cistatic int redo_open_attribute(ntfs_volume *vol __attribute__((unused)), 2325987da915Sopenharmony_ci const struct ACTION_RECORD *action) 2326987da915Sopenharmony_ci{ 2327987da915Sopenharmony_ci const char *data; 2328987da915Sopenharmony_ci struct ATTR *pa; 2329987da915Sopenharmony_ci const ATTR_OLD *attr_old; 2330987da915Sopenharmony_ci const ATTR_NEW *attr_new; 2331987da915Sopenharmony_ci const char *name; 2332987da915Sopenharmony_ci le64 inode; 2333987da915Sopenharmony_ci u32 namelen; 2334987da915Sopenharmony_ci u32 length; 2335987da915Sopenharmony_ci u32 extra; 2336987da915Sopenharmony_ci int err; 2337987da915Sopenharmony_ci 2338987da915Sopenharmony_ci if (optv > 1) 2339987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2340987da915Sopenharmony_ci err = 1; 2341987da915Sopenharmony_ci data = ((const char*)&action->record) 2342987da915Sopenharmony_ci + get_redo_offset(&action->record); 2343987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2344987da915Sopenharmony_ci extra = get_extra_offset(&action->record); 2345987da915Sopenharmony_ci if (action->record.undo_length) { 2346987da915Sopenharmony_ci name = ((const char*)&action->record) + extra; 2347987da915Sopenharmony_ci namelen = le32_to_cpu(action->record.client_data_length) 2348987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ - extra; 2349987da915Sopenharmony_ci /* fix namelen which was aligned modulo 8 */ 2350987da915Sopenharmony_ci namelen = fixnamelen(name, namelen); 2351987da915Sopenharmony_ci if (optv > 1) { 2352987da915Sopenharmony_ci printf("-> length %d namelen %d",(int)length, 2353987da915Sopenharmony_ci (int)namelen); 2354987da915Sopenharmony_ci showname(", ", name, namelen/2); 2355987da915Sopenharmony_ci } 2356987da915Sopenharmony_ci } else { 2357987da915Sopenharmony_ci name = ""; 2358987da915Sopenharmony_ci namelen = 0; 2359987da915Sopenharmony_ci } 2360987da915Sopenharmony_ci pa = getattrentry(le16_to_cpu(action->record.target_attribute),0); 2361987da915Sopenharmony_ci if (pa) { 2362987da915Sopenharmony_ci if (optv) { 2363987da915Sopenharmony_ci /* 2364987da915Sopenharmony_ci * If the actions have been displayed, the 2365987da915Sopenharmony_ci * attribute has already been fed. Check 2366987da915Sopenharmony_ci * whether it matches what we have in store. 2367987da915Sopenharmony_ci */ 2368987da915Sopenharmony_ci switch (length) { 2369987da915Sopenharmony_ci case sizeof(ATTR_OLD) : 2370987da915Sopenharmony_ci attr_old = (const ATTR_OLD*)data; 2371987da915Sopenharmony_ci /* Badly aligned */ 2372987da915Sopenharmony_ci memcpy(&inode, &attr_old->inode, 8); 2373987da915Sopenharmony_ci err = (MREF(le64_to_cpu(inode)) != pa->inode) 2374987da915Sopenharmony_ci || (attr_old->type != pa->type); 2375987da915Sopenharmony_ci break; 2376987da915Sopenharmony_ci case sizeof(ATTR_NEW) : 2377987da915Sopenharmony_ci attr_new = (const ATTR_NEW*)data; 2378987da915Sopenharmony_ci err = (MREF(le64_to_cpu(attr_new->inode)) 2379987da915Sopenharmony_ci != pa->inode) 2380987da915Sopenharmony_ci || (attr_new->type != pa->type); 2381987da915Sopenharmony_ci break; 2382987da915Sopenharmony_ci default : err = 1; 2383987da915Sopenharmony_ci } 2384987da915Sopenharmony_ci if (!err) { 2385987da915Sopenharmony_ci err = (namelen != pa->namelen) 2386987da915Sopenharmony_ci || (namelen 2387987da915Sopenharmony_ci && memcmp(name, pa->name, namelen)); 2388987da915Sopenharmony_ci } 2389987da915Sopenharmony_ci if (optv > 1) 2390987da915Sopenharmony_ci printf("-> attribute %s the recorded one\n", 2391987da915Sopenharmony_ci (err ? "does not match" : "matches")); 2392987da915Sopenharmony_ci } else { 2393987da915Sopenharmony_ci copy_attribute(pa, data, length); 2394987da915Sopenharmony_ci pa->namelen = namelen; 2395987da915Sopenharmony_ci if (namelen) 2396987da915Sopenharmony_ci memcpy(pa->name, data, namelen); 2397987da915Sopenharmony_ci err = 0; 2398987da915Sopenharmony_ci } 2399987da915Sopenharmony_ci } else 2400987da915Sopenharmony_ci if (optv) 2401987da915Sopenharmony_ci printf("* Unrecorded attribute\n"); 2402987da915Sopenharmony_ci return (err); 2403987da915Sopenharmony_ci} 2404987da915Sopenharmony_ci 2405987da915Sopenharmony_cistatic int redo_sizes(ntfs_volume *vol, const struct ACTION_RECORD *action, 2406987da915Sopenharmony_ci char *buffer) 2407987da915Sopenharmony_ci{ 2408987da915Sopenharmony_ci const char *data; 2409987da915Sopenharmony_ci u32 target; 2410987da915Sopenharmony_ci u32 length; 2411987da915Sopenharmony_ci int err; 2412987da915Sopenharmony_ci 2413987da915Sopenharmony_ci if (optv > 1) 2414987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2415987da915Sopenharmony_ci err = 1; 2416987da915Sopenharmony_ci data = ((const char*)&action->record) 2417987da915Sopenharmony_ci + get_redo_offset(&action->record); 2418987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2419987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2420987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset) 2421987da915Sopenharmony_ci + offsetof(ATTR_RECORD, allocated_size); 2422987da915Sopenharmony_ci err = change_resident(vol, action, buffer, 2423987da915Sopenharmony_ci data, target, length); 2424987da915Sopenharmony_ci return (err); 2425987da915Sopenharmony_ci} 2426987da915Sopenharmony_ci 2427987da915Sopenharmony_cistatic int redo_update_index(ntfs_volume *vol, 2428987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2429987da915Sopenharmony_ci{ 2430987da915Sopenharmony_ci const char *data; 2431987da915Sopenharmony_ci u32 target; 2432987da915Sopenharmony_ci u32 length; 2433987da915Sopenharmony_ci int err; 2434987da915Sopenharmony_ci 2435987da915Sopenharmony_ci if (optv > 1) 2436987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2437987da915Sopenharmony_ci err = 1; 2438987da915Sopenharmony_ci data = ((const char*)&action->record) 2439987da915Sopenharmony_ci + get_redo_offset(&action->record); 2440987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2441987da915Sopenharmony_ci /* target is left-justified to creation time */ 2442987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2443987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset) 2444987da915Sopenharmony_ci + offsetof(INDEX_ENTRY, key.file_name.creation_time); 2445987da915Sopenharmony_ci err = update_index(vol, action, buffer, data, target, length); 2446987da915Sopenharmony_ci return (err); 2447987da915Sopenharmony_ci} 2448987da915Sopenharmony_ci 2449987da915Sopenharmony_cistatic int redo_update_index_value(ntfs_volume *vol, 2450987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2451987da915Sopenharmony_ci{ 2452987da915Sopenharmony_ci const char *data; 2453987da915Sopenharmony_ci u32 length; 2454987da915Sopenharmony_ci u32 target; 2455987da915Sopenharmony_ci int err; 2456987da915Sopenharmony_ci 2457987da915Sopenharmony_ci if (optv > 1) 2458987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2459987da915Sopenharmony_ci err = 1; 2460987da915Sopenharmony_ci data = ((const char*)&action->record) 2461987da915Sopenharmony_ci + get_redo_offset(&action->record); 2462987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2463987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2464987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2465987da915Sopenharmony_ci err = change_index_value(vol, action, buffer, data, target, length); 2466987da915Sopenharmony_ci return (err); 2467987da915Sopenharmony_ci} 2468987da915Sopenharmony_ci 2469987da915Sopenharmony_cistatic int redo_update_mapping(ntfs_volume *vol, 2470987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2471987da915Sopenharmony_ci{ 2472987da915Sopenharmony_ci LCN lcn; 2473987da915Sopenharmony_ci const char *data; 2474987da915Sopenharmony_ci ATTR_RECORD *attr; 2475987da915Sopenharmony_ci MFT_RECORD *entry; 2476987da915Sopenharmony_ci u32 target; 2477987da915Sopenharmony_ci u32 length; 2478987da915Sopenharmony_ci u32 source; 2479987da915Sopenharmony_ci u32 alen; 2480987da915Sopenharmony_ci u32 newused; 2481987da915Sopenharmony_ci int resize; 2482987da915Sopenharmony_ci int err; 2483987da915Sopenharmony_ci int changed; 2484987da915Sopenharmony_ci 2485987da915Sopenharmony_ci if (optv > 1) 2486987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2487987da915Sopenharmony_ci err = 1; 2488987da915Sopenharmony_ci data = ((const char*)&action->record) 2489987da915Sopenharmony_ci + get_redo_offset(&action->record); 2490987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2491987da915Sopenharmony_ci resize = length - le16_to_cpu(action->record.undo_length); 2492987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2493987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2494987da915Sopenharmony_ci if (optv > 1) { 2495987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2496987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 2497987da915Sopenharmony_ci (long long)inode_number(&action->record), 2498987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2499987da915Sopenharmony_ci } 2500987da915Sopenharmony_ci if (optv > 1) { 2501987da915Sopenharmony_ci printf("-> existing record :\n"); 2502987da915Sopenharmony_ci dump(&buffer[target], length); 2503987da915Sopenharmony_ci } 2504987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 2505987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 2506987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 2507987da915Sopenharmony_ci if (!attr->non_resident) { 2508987da915Sopenharmony_ci printf("** Error : update_mapping on resident attr\n"); 2509987da915Sopenharmony_ci } 2510987da915Sopenharmony_ci if (valid_type(attr->type) 2511987da915Sopenharmony_ci && attr->non_resident 2512987da915Sopenharmony_ci && !(resize & 7) 2513987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 2514987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 2515987da915Sopenharmony_ci err = 0; 2516987da915Sopenharmony_ci if (changed) { 2517987da915Sopenharmony_ci /* Adjust space for new mapping pairs */ 2518987da915Sopenharmony_ci source = target - resize; 2519987da915Sopenharmony_ci if (resize > 0) { 2520987da915Sopenharmony_ci memmove(buffer + target + length, 2521987da915Sopenharmony_ci buffer + source + length, 2522987da915Sopenharmony_ci mftrecsz - target - length); 2523987da915Sopenharmony_ci } 2524987da915Sopenharmony_ci if (resize < 0) { 2525987da915Sopenharmony_ci memmove(buffer + target + length, 2526987da915Sopenharmony_ci buffer + source + length, 2527987da915Sopenharmony_ci mftrecsz - source - length); 2528987da915Sopenharmony_ci } 2529987da915Sopenharmony_ci memcpy(buffer + target, data, length); 2530987da915Sopenharmony_ci /* Resize the attribute */ 2531987da915Sopenharmony_ci alen = le32_to_cpu(attr->length) + resize; 2532987da915Sopenharmony_ci attr->length = cpu_to_le32(alen); 2533987da915Sopenharmony_ci /* Resize the mft record */ 2534987da915Sopenharmony_ci newused = le32_to_cpu(entry->bytes_in_use) 2535987da915Sopenharmony_ci + resize; 2536987da915Sopenharmony_ci entry->bytes_in_use = cpu_to_le32(newused); 2537987da915Sopenharmony_ci /* Compute the new highest_vcn */ 2538987da915Sopenharmony_ci err = adjust_high_vcn(vol, attr); 2539987da915Sopenharmony_ci if (optv > 1) { 2540987da915Sopenharmony_ci printf("-> new record :\n"); 2541987da915Sopenharmony_ci dump(buffer + target, length); 2542987da915Sopenharmony_ci } 2543987da915Sopenharmony_ci if (!err) { 2544987da915Sopenharmony_ci err = write_protected(vol, 2545987da915Sopenharmony_ci &action->record, 2546987da915Sopenharmony_ci buffer, mftrecsz); 2547987da915Sopenharmony_ci } 2548987da915Sopenharmony_ci } 2549987da915Sopenharmony_ci if (optv > 1) { 2550987da915Sopenharmony_ci printf("-> MFT record %s\n", 2551987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 2552987da915Sopenharmony_ci } 2553987da915Sopenharmony_ci } 2554987da915Sopenharmony_ci return (err); 2555987da915Sopenharmony_ci} 2556987da915Sopenharmony_ci 2557987da915Sopenharmony_cistatic int redo_update_resident(ntfs_volume *vol, 2558987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2559987da915Sopenharmony_ci{ 2560987da915Sopenharmony_ci LCN lcn; 2561987da915Sopenharmony_ci const char *data; 2562987da915Sopenharmony_ci u32 target; 2563987da915Sopenharmony_ci u32 length; 2564987da915Sopenharmony_ci u32 oldlength; 2565987da915Sopenharmony_ci u32 end; 2566987da915Sopenharmony_ci u32 redo; 2567987da915Sopenharmony_ci int err; 2568987da915Sopenharmony_ci int changed; 2569987da915Sopenharmony_ci 2570987da915Sopenharmony_ci if (optv > 1) 2571987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2572987da915Sopenharmony_ci err = 1; 2573987da915Sopenharmony_ci end = le32_to_cpu(action->record.client_data_length) 2574987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 2575987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2576987da915Sopenharmony_ci redo = get_redo_offset(&action->record); 2577987da915Sopenharmony_ci if ((redo + length) > end) 2578987da915Sopenharmony_ci data = (char*)NULL; 2579987da915Sopenharmony_ci else 2580987da915Sopenharmony_ci data = ((const char*)&action->record) + redo; 2581987da915Sopenharmony_ci oldlength = le16_to_cpu(action->record.undo_length); 2582987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2583987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2584987da915Sopenharmony_ci if (length == oldlength) { 2585987da915Sopenharmony_ci if (optv > 1) { 2586987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2587987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x" 2588987da915Sopenharmony_ci " length %d\n", 2589987da915Sopenharmony_ci (long long)inode_number(&action->record), 2590987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2591987da915Sopenharmony_ci } 2592987da915Sopenharmony_ci if (optv > 1) { 2593987da915Sopenharmony_ci printf("-> existing record :\n"); 2594987da915Sopenharmony_ci dump(&buffer[target], length); 2595987da915Sopenharmony_ci } 2596987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 2597987da915Sopenharmony_ci changed = (action->record.undo_operation 2598987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord)) 2599987da915Sopenharmony_ci || memcmp(buffer + target, data, length); 2600987da915Sopenharmony_ci err = 0; 2601987da915Sopenharmony_ci if (changed) { 2602987da915Sopenharmony_ci memcpy(buffer + target, data, length); 2603987da915Sopenharmony_ci if (optv > 1) { 2604987da915Sopenharmony_ci printf("-> new record :\n"); 2605987da915Sopenharmony_ci dump(buffer + target, length); 2606987da915Sopenharmony_ci } 2607987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2608987da915Sopenharmony_ci buffer, mftrecsz); 2609987da915Sopenharmony_ci } 2610987da915Sopenharmony_ci if (optv > 1) { 2611987da915Sopenharmony_ci printf("-> MFT record %s\n", 2612987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 2613987da915Sopenharmony_ci } 2614987da915Sopenharmony_ci } 2615987da915Sopenharmony_ci } else { 2616987da915Sopenharmony_ci if (length > oldlength) 2617987da915Sopenharmony_ci err = expand_resident(vol, action, buffer, data, 2618987da915Sopenharmony_ci target, length, oldlength); 2619987da915Sopenharmony_ci else 2620987da915Sopenharmony_ci err = shrink_resident(vol, action, buffer, data, 2621987da915Sopenharmony_ci target, length, oldlength); 2622987da915Sopenharmony_ci } 2623987da915Sopenharmony_ci return (err); 2624987da915Sopenharmony_ci} 2625987da915Sopenharmony_ci 2626987da915Sopenharmony_cistatic int redo_update_root_index(ntfs_volume *vol, 2627987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2628987da915Sopenharmony_ci{ 2629987da915Sopenharmony_ci const char *data; 2630987da915Sopenharmony_ci const char *expected; 2631987da915Sopenharmony_ci u32 target; 2632987da915Sopenharmony_ci u32 length; 2633987da915Sopenharmony_ci int err; 2634987da915Sopenharmony_ci 2635987da915Sopenharmony_ci if (optv > 1) 2636987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2637987da915Sopenharmony_ci err = 1; 2638987da915Sopenharmony_ci data = ((const char*)&action->record) 2639987da915Sopenharmony_ci + get_redo_offset(&action->record); 2640987da915Sopenharmony_ci expected = ((const char*)&action->record) 2641987da915Sopenharmony_ci + get_undo_offset(&action->record); 2642987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2643987da915Sopenharmony_ci /* the fixup is right-justified to the name length */ 2644987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2645987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset) 2646987da915Sopenharmony_ci + offsetof(INDEX_ENTRY, key.file_name.file_name_length) 2647987da915Sopenharmony_ci - length; 2648987da915Sopenharmony_ci if (action->record.undo_operation 2649987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord)) 2650987da915Sopenharmony_ci err = change_resident(vol, action, buffer, data, 2651987da915Sopenharmony_ci target, length); 2652987da915Sopenharmony_ci else 2653987da915Sopenharmony_ci err = change_resident_expect(vol, action, buffer, data, 2654987da915Sopenharmony_ci expected, target, length, AT_INDEX_ROOT); 2655987da915Sopenharmony_ci return (err); 2656987da915Sopenharmony_ci} 2657987da915Sopenharmony_ci 2658987da915Sopenharmony_cistatic int redo_update_root_vcn(ntfs_volume *vol, 2659987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2660987da915Sopenharmony_ci{ 2661987da915Sopenharmony_ci const char *data; 2662987da915Sopenharmony_ci const char *expected; 2663987da915Sopenharmony_ci u32 target; 2664987da915Sopenharmony_ci u32 length; 2665987da915Sopenharmony_ci int err; 2666987da915Sopenharmony_ci 2667987da915Sopenharmony_ci if (optv > 1) 2668987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2669987da915Sopenharmony_ci err = 1; 2670987da915Sopenharmony_ci data = ((const char*)&action->record) 2671987da915Sopenharmony_ci + get_redo_offset(&action->record); 2672987da915Sopenharmony_ci expected = ((const char*)&action->record) 2673987da915Sopenharmony_ci + get_undo_offset(&action->record); 2674987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2675987da915Sopenharmony_ci if (length == 8) { 2676987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2677987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2678987da915Sopenharmony_ci /* target is right-justified to end of attribute */ 2679987da915Sopenharmony_ci target += getle16(buffer, target + 8) - length; 2680987da915Sopenharmony_ci err = change_resident_expect(vol, action, buffer, data, 2681987da915Sopenharmony_ci expected, target, length, AT_INDEX_ROOT); 2682987da915Sopenharmony_ci } 2683987da915Sopenharmony_ci return (err); 2684987da915Sopenharmony_ci} 2685987da915Sopenharmony_ci 2686987da915Sopenharmony_cistatic int redo_update_value(ntfs_volume *vol, 2687987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2688987da915Sopenharmony_ci{ 2689987da915Sopenharmony_ci LCN lcn; 2690987da915Sopenharmony_ci const char *data; 2691987da915Sopenharmony_ci u32 length; 2692987da915Sopenharmony_ci u32 target; 2693987da915Sopenharmony_ci u32 count; 2694987da915Sopenharmony_ci u32 redo; 2695987da915Sopenharmony_ci u32 end; 2696987da915Sopenharmony_ci u32 i; 2697987da915Sopenharmony_ci int changed; 2698987da915Sopenharmony_ci int err; 2699987da915Sopenharmony_ci 2700987da915Sopenharmony_ci if (optv > 1) 2701987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2702987da915Sopenharmony_ci err = 1; 2703987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2704987da915Sopenharmony_ci redo = get_redo_offset(&action->record); 2705987da915Sopenharmony_ci end = le32_to_cpu(action->record.client_data_length) 2706987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 2707987da915Sopenharmony_ci /* sometimes there is no redo data */ 2708987da915Sopenharmony_ci if ((redo + length) > end) 2709987da915Sopenharmony_ci data = (char*)NULL; 2710987da915Sopenharmony_ci else 2711987da915Sopenharmony_ci data = ((const char*)&action->record) + redo; 2712987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2713987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2714987da915Sopenharmony_ci count = le16_to_cpu(action->record.lcns_to_follow); 2715987da915Sopenharmony_ci if (optv > 1) { 2716987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2717987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 2718987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2719987da915Sopenharmony_ci } 2720987da915Sopenharmony_ci if (optv > 1) { 2721987da915Sopenharmony_ci printf("-> existing record :\n"); 2722987da915Sopenharmony_ci dump(&buffer[target], length); 2723987da915Sopenharmony_ci } 2724987da915Sopenharmony_ci if ((target + length) <= (count << clusterbits)) { 2725987da915Sopenharmony_ci if (data) 2726987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 2727987da915Sopenharmony_ci else { 2728987da915Sopenharmony_ci for (i=0; (i<length) && !buffer[target+i]; i++) { } 2729987da915Sopenharmony_ci changed = length && (i < length); 2730987da915Sopenharmony_ci } 2731987da915Sopenharmony_ci err = 0; 2732987da915Sopenharmony_ci if (changed) { 2733987da915Sopenharmony_ci if (data) 2734987da915Sopenharmony_ci memcpy(buffer + target, data, length); 2735987da915Sopenharmony_ci else 2736987da915Sopenharmony_ci memset(buffer + target, 0, length); 2737987da915Sopenharmony_ci if (optv > 1) { 2738987da915Sopenharmony_ci printf("-> new record :\n"); 2739987da915Sopenharmony_ci dump(buffer + target, length); 2740987da915Sopenharmony_ci } 2741987da915Sopenharmony_ci err = write_raw(vol, &action->record, buffer); 2742987da915Sopenharmony_ci } 2743987da915Sopenharmony_ci if (optv > 1) { 2744987da915Sopenharmony_ci printf("-> data record %s\n", 2745987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 2746987da915Sopenharmony_ci } 2747987da915Sopenharmony_ci } 2748987da915Sopenharmony_ci 2749987da915Sopenharmony_ci return (err); 2750987da915Sopenharmony_ci} 2751987da915Sopenharmony_ci 2752987da915Sopenharmony_cistatic int redo_update_vcn(ntfs_volume *vol, 2753987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2754987da915Sopenharmony_ci{ 2755987da915Sopenharmony_ci const char *data; 2756987da915Sopenharmony_ci u32 target; 2757987da915Sopenharmony_ci u32 length; 2758987da915Sopenharmony_ci int err; 2759987da915Sopenharmony_ci 2760987da915Sopenharmony_ci if (optv > 1) 2761987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2762987da915Sopenharmony_ci err = 1; 2763987da915Sopenharmony_ci data = ((const char*)&action->record) 2764987da915Sopenharmony_ci + get_redo_offset(&action->record); 2765987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2766987da915Sopenharmony_ci if (length == 8) { 2767987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2768987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2769987da915Sopenharmony_ci /* target is right-justified to end of attribute */ 2770987da915Sopenharmony_ci target += getle16(buffer, target + 8) - length; 2771987da915Sopenharmony_ci err = update_index(vol, action, buffer, data, target, length); 2772987da915Sopenharmony_ci } 2773987da915Sopenharmony_ci return (err); 2774987da915Sopenharmony_ci} 2775987da915Sopenharmony_ci 2776987da915Sopenharmony_cistatic int redo_write_end(ntfs_volume *vol, 2777987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2778987da915Sopenharmony_ci{ 2779987da915Sopenharmony_ci LCN lcn; 2780987da915Sopenharmony_ci const char *data; 2781987da915Sopenharmony_ci u32 target; 2782987da915Sopenharmony_ci u32 length; 2783987da915Sopenharmony_ci u32 oldlength; 2784987da915Sopenharmony_ci u32 end; 2785987da915Sopenharmony_ci u32 redo; 2786987da915Sopenharmony_ci int err; 2787987da915Sopenharmony_ci int changed; 2788987da915Sopenharmony_ci 2789987da915Sopenharmony_ci if (optv > 1) 2790987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2791987da915Sopenharmony_ci err = 1; 2792987da915Sopenharmony_ci end = le32_to_cpu(action->record.client_data_length) 2793987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 2794987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2795987da915Sopenharmony_ci redo = get_redo_offset(&action->record); 2796987da915Sopenharmony_ci if ((redo + length) > end) 2797987da915Sopenharmony_ci data = (char*)NULL; 2798987da915Sopenharmony_ci else 2799987da915Sopenharmony_ci data = ((const char*)&action->record) + redo; 2800987da915Sopenharmony_ci oldlength = le16_to_cpu(action->record.undo_length); 2801987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2802987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2803987da915Sopenharmony_ci if (length == oldlength) { 2804987da915Sopenharmony_ci if (optv > 1) { 2805987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2806987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x" 2807987da915Sopenharmony_ci " length %d\n", 2808987da915Sopenharmony_ci (long long)inode_number(&action->record), 2809987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2810987da915Sopenharmony_ci } 2811987da915Sopenharmony_ci if (optv > 1) { 2812987da915Sopenharmony_ci printf("-> existing record :\n"); 2813987da915Sopenharmony_ci dump(&buffer[target], length); 2814987da915Sopenharmony_ci } 2815987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 2816987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 2817987da915Sopenharmony_ci err = 0; 2818987da915Sopenharmony_ci if (changed) { 2819987da915Sopenharmony_ci memcpy(buffer + target, data, length); 2820987da915Sopenharmony_ci if (optv > 1) { 2821987da915Sopenharmony_ci printf("-> new record :\n"); 2822987da915Sopenharmony_ci dump(buffer + target, length); 2823987da915Sopenharmony_ci } 2824987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2825987da915Sopenharmony_ci buffer, mftrecsz); 2826987da915Sopenharmony_ci } 2827987da915Sopenharmony_ci if (optv > 1) { 2828987da915Sopenharmony_ci printf("-> MFT record %s\n", 2829987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 2830987da915Sopenharmony_ci } 2831987da915Sopenharmony_ci } 2832987da915Sopenharmony_ci } else { 2833987da915Sopenharmony_ci if (length > oldlength) 2834987da915Sopenharmony_ci err = add_resident(vol, action, buffer, data, 2835987da915Sopenharmony_ci target, length, oldlength); 2836987da915Sopenharmony_ci else 2837987da915Sopenharmony_ci err = delete_resident(vol, action, buffer, data, 2838987da915Sopenharmony_ci target, length, oldlength); 2839987da915Sopenharmony_ci } 2840987da915Sopenharmony_ci return (err); 2841987da915Sopenharmony_ci} 2842987da915Sopenharmony_ci 2843987da915Sopenharmony_cistatic int redo_write_index(ntfs_volume *vol, 2844987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2845987da915Sopenharmony_ci{ 2846987da915Sopenharmony_ci LCN lcn; 2847987da915Sopenharmony_ci const char *data; 2848987da915Sopenharmony_ci INDEX_BLOCK *indx; 2849987da915Sopenharmony_ci u32 target; 2850987da915Sopenharmony_ci u32 length; 2851987da915Sopenharmony_ci u32 xsize; 2852987da915Sopenharmony_ci int err; 2853987da915Sopenharmony_ci int changed; 2854987da915Sopenharmony_ci 2855987da915Sopenharmony_ci if (optv > 1) 2856987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2857987da915Sopenharmony_ci err = 1; 2858987da915Sopenharmony_ci data = ((const char*)&action->record) 2859987da915Sopenharmony_ci + get_redo_offset(&action->record); 2860987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2861987da915Sopenharmony_ci /* target is left-justified to creation time */ 2862987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2863987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2864987da915Sopenharmony_ci if (optv > 1) { 2865987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2866987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 2867987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2868987da915Sopenharmony_ci } 2869987da915Sopenharmony_ci xsize = vol->indx_record_size; 2870987da915Sopenharmony_ci indx = (INDEX_BLOCK*)buffer; 2871987da915Sopenharmony_ci if (action->record.record_offset) { 2872987da915Sopenharmony_ci printf("** Non-null record_offset in redo_write_index()\n"); 2873987da915Sopenharmony_ci } 2874987da915Sopenharmony_ci if (optv > 1) { 2875987da915Sopenharmony_ci printf("-> existing index :\n"); 2876987da915Sopenharmony_ci dump(&buffer[target], length); 2877987da915Sopenharmony_ci } 2878987da915Sopenharmony_ci if ((indx->magic == magic_INDX) 2879987da915Sopenharmony_ci && !(length & 7) 2880987da915Sopenharmony_ci && ((target + length) <= xsize)) { 2881987da915Sopenharmony_ci /* This has to be an idempotent action */ 2882987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 2883987da915Sopenharmony_ci err = 0; 2884987da915Sopenharmony_ci if (changed) { 2885987da915Sopenharmony_ci /* Update the entry */ 2886987da915Sopenharmony_ci memcpy(buffer + target, data, length); 2887987da915Sopenharmony_ci /* If truncating, set the new size */ 2888987da915Sopenharmony_ci indx->index.index_length = 2889987da915Sopenharmony_ci cpu_to_le32(target + length - 0x18); 2890987da915Sopenharmony_ci if (optv > 1) { 2891987da915Sopenharmony_ci printf("-> new index :\n"); 2892987da915Sopenharmony_ci dump(&buffer[target], length); 2893987da915Sopenharmony_ci } 2894987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2895987da915Sopenharmony_ci buffer, xsize); 2896987da915Sopenharmony_ci } 2897987da915Sopenharmony_ci if (optv > 1) { 2898987da915Sopenharmony_ci printf("-> INDX record %s\n", 2899987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 2900987da915Sopenharmony_ci } 2901987da915Sopenharmony_ci } 2902987da915Sopenharmony_ci return (err); 2903987da915Sopenharmony_ci} 2904987da915Sopenharmony_ci 2905987da915Sopenharmony_cistatic int undo_action37(ntfs_volume *vol __attribute__((unused)), 2906987da915Sopenharmony_ci const struct ACTION_RECORD *action, 2907987da915Sopenharmony_ci char *buffer __attribute__((unused))) 2908987da915Sopenharmony_ci{ 2909987da915Sopenharmony_ci/* 2910987da915Sopenharmony_ci const char *data; 2911987da915Sopenharmony_ci u32 target; 2912987da915Sopenharmony_ci u32 length; 2913987da915Sopenharmony_ci*/ 2914987da915Sopenharmony_ci int err; 2915987da915Sopenharmony_ci 2916987da915Sopenharmony_ci if (optv > 1) 2917987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2918987da915Sopenharmony_ci err = 1; 2919987da915Sopenharmony_ci/* 2920987da915Sopenharmony_ci data = ((const char*)&action->record) 2921987da915Sopenharmony_ci + get_redo_offset(&action->record); 2922987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2923987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2924987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2925987da915Sopenharmony_ci*/ 2926987da915Sopenharmony_ci printf("* Ignored action-37, inode %lld record :\n", 2927987da915Sopenharmony_ci (long long)inode_number(&action->record)); 2928987da915Sopenharmony_ci err = 0; 2929987da915Sopenharmony_ci return (err); 2930987da915Sopenharmony_ci} 2931987da915Sopenharmony_ci 2932987da915Sopenharmony_cistatic int undo_add_index(ntfs_volume *vol, 2933987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2934987da915Sopenharmony_ci{ 2935987da915Sopenharmony_ci LCN lcn; 2936987da915Sopenharmony_ci const char *data; 2937987da915Sopenharmony_ci INDEX_BLOCK *indx; 2938987da915Sopenharmony_ci u32 target; 2939987da915Sopenharmony_ci u32 length; 2940987da915Sopenharmony_ci u32 xsize; 2941987da915Sopenharmony_ci u32 indexlth; 2942987da915Sopenharmony_ci int err; 2943987da915Sopenharmony_ci BOOL found; 2944987da915Sopenharmony_ci 2945987da915Sopenharmony_ci if (optv > 1) 2946987da915Sopenharmony_ci printf("-> %s()\n",__func__); 2947987da915Sopenharmony_ci err = 1; 2948987da915Sopenharmony_ci data = ((const char*)&action->record) 2949987da915Sopenharmony_ci + get_redo_offset(&action->record); 2950987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 2951987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 2952987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 2953987da915Sopenharmony_ci if (optv > 1) { 2954987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 2955987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 2956987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 2957987da915Sopenharmony_ci } 2958987da915Sopenharmony_ci xsize = vol->indx_record_size; 2959987da915Sopenharmony_ci indx = (INDEX_BLOCK*)(buffer 2960987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 2961987da915Sopenharmony_ci if (optv > 1) { 2962987da915Sopenharmony_ci printf("-> existing record :\n"); 2963987da915Sopenharmony_ci dump(&buffer[target], length); 2964987da915Sopenharmony_ci } 2965987da915Sopenharmony_ci if ((indx->magic == magic_INDX) 2966987da915Sopenharmony_ci && !(length & 7) 2967987da915Sopenharmony_ci && ((target + length) <= xsize)) { 2968987da915Sopenharmony_ci /* This has to be an idempotent action */ 2969987da915Sopenharmony_ci found = index_match_undo(buffer + target, data, length); 2970987da915Sopenharmony_ci err = 0; 2971987da915Sopenharmony_ci if (found) { 2972987da915Sopenharmony_ci /* Remove the entry */ 2973987da915Sopenharmony_ci memmove(buffer + target, 2974987da915Sopenharmony_ci buffer + target + length, 2975987da915Sopenharmony_ci xsize - target - length); 2976987da915Sopenharmony_ci indexlth = le32_to_cpu(indx->index.index_length) 2977987da915Sopenharmony_ci - length; 2978987da915Sopenharmony_ci indx->index.index_length = cpu_to_le32(indexlth); 2979987da915Sopenharmony_ci err = write_protected(vol, &action->record, 2980987da915Sopenharmony_ci buffer, xsize); 2981987da915Sopenharmony_ci } else { 2982987da915Sopenharmony_ci sanity_indx(vol,buffer); 2983987da915Sopenharmony_ci printf("full record :\n"); 2984987da915Sopenharmony_ci dump(buffer,xsize); 2985987da915Sopenharmony_ci } 2986987da915Sopenharmony_ci if (optv > 1) { 2987987da915Sopenharmony_ci printf("-> INDX record %s\n", 2988987da915Sopenharmony_ci (found ? "removed" : "unchanged")); 2989987da915Sopenharmony_ci } 2990987da915Sopenharmony_ci } 2991987da915Sopenharmony_ci return (err); 2992987da915Sopenharmony_ci} 2993987da915Sopenharmony_ci 2994987da915Sopenharmony_cistatic int undo_add_root_index(ntfs_volume *vol, 2995987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 2996987da915Sopenharmony_ci{ 2997987da915Sopenharmony_ci LCN lcn; 2998987da915Sopenharmony_ci const char *data; 2999987da915Sopenharmony_ci ATTR_RECORD *attr; 3000987da915Sopenharmony_ci MFT_RECORD *entry; 3001987da915Sopenharmony_ci INDEX_ROOT *index; 3002987da915Sopenharmony_ci BOOL found; 3003987da915Sopenharmony_ci u32 target; 3004987da915Sopenharmony_ci u32 length; 3005987da915Sopenharmony_ci int err; 3006987da915Sopenharmony_ci 3007987da915Sopenharmony_ci if (optv > 1) 3008987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3009987da915Sopenharmony_ci err = 1; 3010987da915Sopenharmony_ci data = ((const char*)&action->record) 3011987da915Sopenharmony_ci + get_redo_offset(&action->record); 3012987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 3013987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3014987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3015987da915Sopenharmony_ci if (optv > 1) { 3016987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3017987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 3018987da915Sopenharmony_ci (long long)inode_number(&action->record), 3019987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3020987da915Sopenharmony_ci } 3021987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 3022987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 3023987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 3024987da915Sopenharmony_ci index = (INDEX_ROOT*)(((char*)attr) 3025987da915Sopenharmony_ci + le16_to_cpu(attr->value_offset)); 3026987da915Sopenharmony_ci if (optv > 1) { 3027987da915Sopenharmony_ci printf("existing index :\n"); 3028987da915Sopenharmony_ci dump(buffer + target,length); 3029987da915Sopenharmony_ci } 3030987da915Sopenharmony_ci if ((attr->type == AT_INDEX_ROOT) 3031987da915Sopenharmony_ci && !(length & 7) 3032987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 3033987da915Sopenharmony_ci /* This has to be an idempotent action */ 3034987da915Sopenharmony_ci found = index_match_undo(buffer + target, data, length); 3035987da915Sopenharmony_ci err = 0; 3036987da915Sopenharmony_ci if (found && !older_record(entry, &action->record)) { 3037987da915Sopenharmony_ci /* Remove the entry */ 3038987da915Sopenharmony_ci memmove(buffer + target, 3039987da915Sopenharmony_ci buffer + target + length, 3040987da915Sopenharmony_ci mftrecsz - target - length); 3041987da915Sopenharmony_ci resize_attribute(entry, attr, index, -length, -length); 3042987da915Sopenharmony_ci if (optv > 1) { 3043987da915Sopenharmony_ci printf("new index at same location :\n"); 3044987da915Sopenharmony_ci dump(buffer + target, length); 3045987da915Sopenharmony_ci } 3046987da915Sopenharmony_ci err = write_protected(vol, &action->record, 3047987da915Sopenharmony_ci buffer, mftrecsz); 3048987da915Sopenharmony_ci } 3049987da915Sopenharmony_ci if (optv > 1) { 3050987da915Sopenharmony_ci printf("-> MFT record %s\n", 3051987da915Sopenharmony_ci (found ? "shrinked" : "unchanged")); 3052987da915Sopenharmony_ci } 3053987da915Sopenharmony_ci } 3054987da915Sopenharmony_ci return (err); 3055987da915Sopenharmony_ci} 3056987da915Sopenharmony_ci 3057987da915Sopenharmony_cistatic int undo_create_attribute(ntfs_volume *vol, 3058987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3059987da915Sopenharmony_ci{ 3060987da915Sopenharmony_ci const char *data; 3061987da915Sopenharmony_ci u32 target; 3062987da915Sopenharmony_ci u32 length; 3063987da915Sopenharmony_ci int err; 3064987da915Sopenharmony_ci 3065987da915Sopenharmony_ci if (optv > 1) 3066987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3067987da915Sopenharmony_ci err = 1; 3068987da915Sopenharmony_ci data = ((const char*)&action->record) 3069987da915Sopenharmony_ci + get_redo_offset(&action->record); 3070987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 3071987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3072987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3073987da915Sopenharmony_ci if (!action->record.undo_length) 3074987da915Sopenharmony_ci err = remove_resident(vol, action, buffer, data, 3075987da915Sopenharmony_ci target, length); 3076987da915Sopenharmony_ci return (err); 3077987da915Sopenharmony_ci} 3078987da915Sopenharmony_ci 3079987da915Sopenharmony_cistatic int undo_delete_attribute(ntfs_volume *vol, 3080987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3081987da915Sopenharmony_ci{ 3082987da915Sopenharmony_ci const char *data; 3083987da915Sopenharmony_ci u32 target; 3084987da915Sopenharmony_ci u32 length; 3085987da915Sopenharmony_ci int err; 3086987da915Sopenharmony_ci 3087987da915Sopenharmony_ci if (optv > 1) 3088987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3089987da915Sopenharmony_ci err = 1; 3090987da915Sopenharmony_ci data = ((const char*)&action->record) 3091987da915Sopenharmony_ci + get_undo_offset(&action->record); 3092987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3093987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3094987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3095987da915Sopenharmony_ci if (!action->record.redo_length) 3096987da915Sopenharmony_ci err = insert_resident(vol, action, buffer, data, 3097987da915Sopenharmony_ci target, length); 3098987da915Sopenharmony_ci return (err); 3099987da915Sopenharmony_ci} 3100987da915Sopenharmony_ci 3101987da915Sopenharmony_cistatic int undo_delete_index(ntfs_volume *vol, 3102987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3103987da915Sopenharmony_ci{ 3104987da915Sopenharmony_ci LCN lcn; 3105987da915Sopenharmony_ci const char *data; 3106987da915Sopenharmony_ci INDEX_BLOCK *indx; 3107987da915Sopenharmony_ci u32 target; 3108987da915Sopenharmony_ci u32 length; 3109987da915Sopenharmony_ci u32 xsize; 3110987da915Sopenharmony_ci u32 indexlth; 3111987da915Sopenharmony_ci int err; 3112987da915Sopenharmony_ci BOOL found; 3113987da915Sopenharmony_ci 3114987da915Sopenharmony_ci// MERGE with redo_add_root_index() ? 3115987da915Sopenharmony_ci if (optv > 1) 3116987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3117987da915Sopenharmony_ci err = 1; 3118987da915Sopenharmony_ci data = ((const char*)&action->record) 3119987da915Sopenharmony_ci + get_undo_offset(&action->record); 3120987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3121987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3122987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3123987da915Sopenharmony_ci if (optv > 1) { 3124987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3125987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 3126987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3127987da915Sopenharmony_ci } 3128987da915Sopenharmony_ci xsize = vol->indx_record_size; 3129987da915Sopenharmony_ci indx = (INDEX_BLOCK*)(buffer 3130987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 3131987da915Sopenharmony_ci if (optv > 1) { 3132987da915Sopenharmony_ci printf("-> existing record :\n"); 3133987da915Sopenharmony_ci dump(&buffer[target], length); 3134987da915Sopenharmony_ci } 3135987da915Sopenharmony_ci if ((indx->magic == magic_INDX) 3136987da915Sopenharmony_ci && !(length & 7) 3137987da915Sopenharmony_ci && ((target + length) <= xsize) 3138987da915Sopenharmony_ci && !sanity_indx(vol,buffer)) { 3139987da915Sopenharmony_ci /* This has to be an idempotent action */ 3140987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 3141987da915Sopenharmony_ci err = 0; 3142987da915Sopenharmony_ci if (!found) { 3143987da915Sopenharmony_ci /* Make space to insert the entry */ 3144987da915Sopenharmony_ci memmove(buffer + target + length, 3145987da915Sopenharmony_ci buffer + target, 3146987da915Sopenharmony_ci xsize - target - length); 3147987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3148987da915Sopenharmony_ci indexlth = le32_to_cpu(indx->index.index_length) 3149987da915Sopenharmony_ci + length; 3150987da915Sopenharmony_ci indx->index.index_length = cpu_to_le32(indexlth); 3151987da915Sopenharmony_ci if (optv > 1) { 3152987da915Sopenharmony_ci printf("-> inserted record :\n"); 3153987da915Sopenharmony_ci dump(&buffer[target], length); 3154987da915Sopenharmony_ci } 3155987da915Sopenharmony_ci /* rebuildname() has no effect currently, should drop */ 3156987da915Sopenharmony_ci rebuildname((const INDEX_ENTRY*)data); 3157987da915Sopenharmony_ci err = write_protected(vol, &action->record, 3158987da915Sopenharmony_ci buffer, xsize); 3159987da915Sopenharmony_ci } 3160987da915Sopenharmony_ci if (optv > 1) { 3161987da915Sopenharmony_ci printf("-> INDX record %s\n", 3162987da915Sopenharmony_ci (found ? "unchanged" : "inserted")); 3163987da915Sopenharmony_ci } 3164987da915Sopenharmony_ci } 3165987da915Sopenharmony_ci return (err); 3166987da915Sopenharmony_ci} 3167987da915Sopenharmony_ci 3168987da915Sopenharmony_cistatic int undo_delete_root_index(ntfs_volume *vol, 3169987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3170987da915Sopenharmony_ci{ 3171987da915Sopenharmony_ci LCN lcn; 3172987da915Sopenharmony_ci const char *data; 3173987da915Sopenharmony_ci ATTR_RECORD *attr; 3174987da915Sopenharmony_ci MFT_RECORD *entry; 3175987da915Sopenharmony_ci INDEX_ROOT *index; 3176987da915Sopenharmony_ci u32 target; 3177987da915Sopenharmony_ci u32 length; 3178987da915Sopenharmony_ci int err; 3179987da915Sopenharmony_ci BOOL found; 3180987da915Sopenharmony_ci 3181987da915Sopenharmony_ci if (optv > 1) 3182987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3183987da915Sopenharmony_ci err = 1; 3184987da915Sopenharmony_ci data = ((const char*)&action->record) 3185987da915Sopenharmony_ci + get_undo_offset(&action->record); 3186987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3187987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3188987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3189987da915Sopenharmony_ci if (optv > 1) { 3190987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3191987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 3192987da915Sopenharmony_ci (long long)inode_number(&action->record), 3193987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3194987da915Sopenharmony_ci } 3195987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 3196987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 3197987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 3198987da915Sopenharmony_ci index = (INDEX_ROOT*)(((char*)attr) 3199987da915Sopenharmony_ci + le16_to_cpu(attr->value_offset)); 3200987da915Sopenharmony_ci if (attr->type != AT_INDEX_ROOT) { 3201987da915Sopenharmony_ci printf("** Unexpected attr type 0x%lx\n", 3202987da915Sopenharmony_ci (long)le32_to_cpu(attr->type)); 3203987da915Sopenharmony_ci printf("existing mft\n"); 3204987da915Sopenharmony_ci dump((char*)buffer,512); 3205987da915Sopenharmony_ci printf("existing index\n"); 3206987da915Sopenharmony_ci dump(buffer + target,length); 3207987da915Sopenharmony_ci } 3208987da915Sopenharmony_ci if (optv > 1) { 3209987da915Sopenharmony_ci printf("existing index :\n"); 3210987da915Sopenharmony_ci dump(buffer + target,length); 3211987da915Sopenharmony_ci } 3212987da915Sopenharmony_ci if ((attr->type == AT_INDEX_ROOT) 3213987da915Sopenharmony_ci && !(length & 7) 3214987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 3215987da915Sopenharmony_ci /* This has to be an idempotent action */ 3216987da915Sopenharmony_ci found = !memcmp(buffer + target, data, length); 3217987da915Sopenharmony_ci err = 0; 3218987da915Sopenharmony_ci /* Do not insert if present */ 3219987da915Sopenharmony_ci if (!found) { 3220987da915Sopenharmony_ci /* Make space to insert the entry */ 3221987da915Sopenharmony_ci memmove(buffer + target + length, 3222987da915Sopenharmony_ci buffer + target, 3223987da915Sopenharmony_ci mftrecsz - target - length); 3224987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3225987da915Sopenharmony_ci resize_attribute(entry, attr, index, length, length); 3226987da915Sopenharmony_ci if (optv > 1) { 3227987da915Sopenharmony_ci printf("new index :\n"); 3228987da915Sopenharmony_ci dump(buffer + target, length); 3229987da915Sopenharmony_ci } 3230987da915Sopenharmony_ci err = write_protected(vol, &action->record, 3231987da915Sopenharmony_ci buffer, mftrecsz); 3232987da915Sopenharmony_ci } 3233987da915Sopenharmony_ci if (optv > 1) { 3234987da915Sopenharmony_ci printf("-> MFT record %s\n", 3235987da915Sopenharmony_ci (found ? "unchanged" : "expanded")); 3236987da915Sopenharmony_ci } 3237987da915Sopenharmony_ci } 3238987da915Sopenharmony_ci return (err); 3239987da915Sopenharmony_ci} 3240987da915Sopenharmony_ci 3241987da915Sopenharmony_cistatic int undo_create_file(ntfs_volume *vol, 3242987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3243987da915Sopenharmony_ci{ 3244987da915Sopenharmony_ci LCN lcn; 3245987da915Sopenharmony_ci const char *data; 3246987da915Sopenharmony_ci MFT_RECORD *record; 3247987da915Sopenharmony_ci u32 target; 3248987da915Sopenharmony_ci u32 length; 3249987da915Sopenharmony_ci int err; 3250987da915Sopenharmony_ci int changed; 3251987da915Sopenharmony_ci 3252987da915Sopenharmony_ci if (optv > 1) 3253987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3254987da915Sopenharmony_ci err = 1; 3255987da915Sopenharmony_ci /* redo initialize, clearing the in_use flag ? */ 3256987da915Sopenharmony_ci data = ((const char*)&action->record) 3257987da915Sopenharmony_ci + get_redo_offset(&action->record); 3258987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 3259987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3260987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3261987da915Sopenharmony_ci if (optv > 1) { 3262987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3263987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 3264987da915Sopenharmony_ci (long long)inode_number(&action->record), 3265987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3266987da915Sopenharmony_ci } 3267987da915Sopenharmony_ci record = (MFT_RECORD*)buffer; 3268987da915Sopenharmony_ci if (optv > 1) { 3269987da915Sopenharmony_ci printf("-> existing record :\n"); 3270987da915Sopenharmony_ci dump(buffer,mftrecsz); 3271987da915Sopenharmony_ci } 3272987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 3273987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 3274987da915Sopenharmony_ci err = 0; 3275987da915Sopenharmony_ci if (changed || (record->flags & MFT_RECORD_IN_USE)) { 3276987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3277987da915Sopenharmony_ci record->flags &= ~MFT_RECORD_IN_USE; 3278987da915Sopenharmony_ci if (optv > 1) { 3279987da915Sopenharmony_ci printf("-> new record :\n"); 3280987da915Sopenharmony_ci dump(buffer,mftrecsz); 3281987da915Sopenharmony_ci } 3282987da915Sopenharmony_ci err = write_protected(vol, &action->record, 3283987da915Sopenharmony_ci buffer, mftrecsz); 3284987da915Sopenharmony_ci } 3285987da915Sopenharmony_ci if (optv > 1) { 3286987da915Sopenharmony_ci printf("-> MFT record %s\n", 3287987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3288987da915Sopenharmony_ci } 3289987da915Sopenharmony_ci } 3290987da915Sopenharmony_ci return (err); 3291987da915Sopenharmony_ci} 3292987da915Sopenharmony_ci 3293987da915Sopenharmony_cistatic int undo_delete_file(ntfs_volume *vol, 3294987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3295987da915Sopenharmony_ci{ 3296987da915Sopenharmony_ci LCN lcn; 3297987da915Sopenharmony_ci const char *data; 3298987da915Sopenharmony_ci MFT_RECORD *record; 3299987da915Sopenharmony_ci u32 target; 3300987da915Sopenharmony_ci u32 length; 3301987da915Sopenharmony_ci int err; 3302987da915Sopenharmony_ci int changed; 3303987da915Sopenharmony_ci 3304987da915Sopenharmony_ci if (optv > 1) 3305987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3306987da915Sopenharmony_ci err = 1; 3307987da915Sopenharmony_ci data = ((const char*)&action->record) 3308987da915Sopenharmony_ci + get_undo_offset(&action->record); 3309987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3310987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3311987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3312987da915Sopenharmony_ci if (optv > 1) { 3313987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3314987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 3315987da915Sopenharmony_ci (long long)inode_number(&action->record), 3316987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3317987da915Sopenharmony_ci } 3318987da915Sopenharmony_ci if (optv > 1) { 3319987da915Sopenharmony_ci printf("-> existing record :\n"); 3320987da915Sopenharmony_ci dump(buffer,mftrecsz); 3321987da915Sopenharmony_ci } 3322987da915Sopenharmony_ci record = (MFT_RECORD*)buffer; 3323987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 3324987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length) 3325987da915Sopenharmony_ci || !(record->flags & MFT_RECORD_IN_USE); 3326987da915Sopenharmony_ci err = 0; 3327987da915Sopenharmony_ci if (changed) { 3328987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3329987da915Sopenharmony_ci /* 3330987da915Sopenharmony_ci * Unclear what we should do for recreating a file. 3331987da915Sopenharmony_ci * Only 24 bytes are available, the used length is not known, 3332987da915Sopenharmony_ci * the number of links suggests we should keep the current 3333987da915Sopenharmony_ci * names... If so, when will they be deleted ? 3334987da915Sopenharmony_ci * We will have to make stamp changes in the standard 3335987da915Sopenharmony_ci * information attribute, so better not to delete it. 3336987da915Sopenharmony_ci * Should we create a data or index attribute ? 3337987da915Sopenharmony_ci * Here, we assume we should delete the file names when 3338987da915Sopenharmony_ci * the record now appears to not be in use and there are 3339987da915Sopenharmony_ci * links. 3340987da915Sopenharmony_ci */ 3341987da915Sopenharmony_ci if (record->link_count 3342987da915Sopenharmony_ci && !(record->flags & MFT_RECORD_IN_USE)) 3343987da915Sopenharmony_ci err = delete_names(buffer); 3344987da915Sopenharmony_ci record->flags |= MFT_RECORD_IN_USE; 3345987da915Sopenharmony_ci if (optv > 1) { 3346987da915Sopenharmony_ci printf("-> new record :\n"); 3347987da915Sopenharmony_ci dump(buffer,mftrecsz); 3348987da915Sopenharmony_ci } 3349987da915Sopenharmony_ci if (!err) 3350987da915Sopenharmony_ci err = write_protected(vol, 3351987da915Sopenharmony_ci &action->record, 3352987da915Sopenharmony_ci buffer, mftrecsz); 3353987da915Sopenharmony_ci } 3354987da915Sopenharmony_ci if (optv > 1) { 3355987da915Sopenharmony_ci printf("-> MFT record %s\n", 3356987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3357987da915Sopenharmony_ci } 3358987da915Sopenharmony_ci } 3359987da915Sopenharmony_ci return (err); 3360987da915Sopenharmony_ci} 3361987da915Sopenharmony_ci 3362987da915Sopenharmony_cistatic int undo_force_bits(ntfs_volume *vol, 3363987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3364987da915Sopenharmony_ci{ 3365987da915Sopenharmony_ci LCN lcn; 3366987da915Sopenharmony_ci const struct BITMAP_ACTION *data; 3367987da915Sopenharmony_ci u32 i; 3368987da915Sopenharmony_ci int err; 3369987da915Sopenharmony_ci int wanted; 3370987da915Sopenharmony_ci u32 firstbit; 3371987da915Sopenharmony_ci u32 count; 3372987da915Sopenharmony_ci 3373987da915Sopenharmony_ci if (optv > 1) 3374987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3375987da915Sopenharmony_ci err = 1; 3376987da915Sopenharmony_ci data = (const struct BITMAP_ACTION*) 3377987da915Sopenharmony_ci (((const char*)&action->record) 3378987da915Sopenharmony_ci + get_redo_offset(&action->record)); 3379987da915Sopenharmony_ci firstbit = le32_to_cpu(data->firstbit); 3380987da915Sopenharmony_ci count = le32_to_cpu(data->count); 3381987da915Sopenharmony_ci if (action->record.redo_operation 3382987da915Sopenharmony_ci == const_cpu_to_le16(SetBitsInNonResidentBitMap)) 3383987da915Sopenharmony_ci wanted = 0; 3384987da915Sopenharmony_ci else 3385987da915Sopenharmony_ci wanted = 1; 3386987da915Sopenharmony_ci// TODO consistency undo_offset == redo_offset, etc. 3387987da915Sopenharmony_ci// firstbit + count < 8*clustersz (multiple clusters possible ?) 3388987da915Sopenharmony_ci if (optv > 1) { 3389987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3390987da915Sopenharmony_ci printf("-> lcn 0x%llx firstbit %d count %d wanted %d\n", 3391987da915Sopenharmony_ci (long long)lcn,(int)firstbit,(int)count,(int)wanted); 3392987da915Sopenharmony_ci } 3393987da915Sopenharmony_ci for (i=0; i<count; i++) 3394987da915Sopenharmony_ci ntfs_bit_set((u8*)buffer, firstbit + i, wanted); 3395987da915Sopenharmony_ci if (!write_raw(vol, &action->record, buffer)) { 3396987da915Sopenharmony_ci err = 0; 3397987da915Sopenharmony_ci if (optv > 1) 3398987da915Sopenharmony_ci printf("-> record updated\n"); 3399987da915Sopenharmony_ci } 3400987da915Sopenharmony_ci if (err) 3401987da915Sopenharmony_ci printf("** redo_clearbits failed\n"); 3402987da915Sopenharmony_ci return (err); 3403987da915Sopenharmony_ci} 3404987da915Sopenharmony_ci 3405987da915Sopenharmony_cistatic int undo_open_attribute(ntfs_volume *vol __attribute__((unused)), 3406987da915Sopenharmony_ci const struct ACTION_RECORD *action) 3407987da915Sopenharmony_ci{ 3408987da915Sopenharmony_ci const char *data; 3409987da915Sopenharmony_ci struct ATTR *pa; 3410987da915Sopenharmony_ci const ATTR_OLD *attr_old; 3411987da915Sopenharmony_ci const ATTR_NEW *attr_new; 3412987da915Sopenharmony_ci const char *name; 3413987da915Sopenharmony_ci le64 inode; 3414987da915Sopenharmony_ci u32 namelen; 3415987da915Sopenharmony_ci u32 length; 3416987da915Sopenharmony_ci u32 extra; 3417987da915Sopenharmony_ci int err; 3418987da915Sopenharmony_ci 3419987da915Sopenharmony_ci if (optv > 1) 3420987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3421987da915Sopenharmony_ci err = 1; 3422987da915Sopenharmony_ci data = ((const char*)&action->record) 3423987da915Sopenharmony_ci + get_redo_offset(&action->record); 3424987da915Sopenharmony_ci length = le16_to_cpu(action->record.redo_length); 3425987da915Sopenharmony_ci extra = get_extra_offset(&action->record); 3426987da915Sopenharmony_ci if (action->record.undo_length) { 3427987da915Sopenharmony_ci name = ((const char*)&action->record) + extra; 3428987da915Sopenharmony_ci namelen = le32_to_cpu(action->record.client_data_length) 3429987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ - extra; 3430987da915Sopenharmony_ci /* fix namelen which was aligned modulo 8 */ 3431987da915Sopenharmony_ci namelen = fixnamelen(name, namelen); 3432987da915Sopenharmony_ci if (optv > 1) { 3433987da915Sopenharmony_ci printf("-> length %d namelen %d",(int)length, 3434987da915Sopenharmony_ci (int)namelen); 3435987da915Sopenharmony_ci showname(", ", name, namelen/2); 3436987da915Sopenharmony_ci } 3437987da915Sopenharmony_ci } else { 3438987da915Sopenharmony_ci namelen = 0; 3439987da915Sopenharmony_ci name = ""; 3440987da915Sopenharmony_ci } 3441987da915Sopenharmony_ci pa = getattrentry(le16_to_cpu(action->record.target_attribute),0); 3442987da915Sopenharmony_ci// TODO Only process is attr is not older ? 3443987da915Sopenharmony_ci if (pa) { 3444987da915Sopenharmony_ci /* check whether the redo attr matches what we have in store */ 3445987da915Sopenharmony_ci switch (length) { 3446987da915Sopenharmony_ci case sizeof(ATTR_OLD) : 3447987da915Sopenharmony_ci attr_old = (const ATTR_OLD*)data; 3448987da915Sopenharmony_ci /* Badly aligned */ 3449987da915Sopenharmony_ci memcpy(&inode, &attr_old->inode, 8); 3450987da915Sopenharmony_ci err = (MREF(le64_to_cpu(inode)) != pa->inode) 3451987da915Sopenharmony_ci || (attr_old->type != pa->type); 3452987da915Sopenharmony_ci break; 3453987da915Sopenharmony_ci case sizeof(ATTR_NEW) : 3454987da915Sopenharmony_ci attr_new = (const ATTR_NEW*)data; 3455987da915Sopenharmony_ci err = (MREF(le64_to_cpu(attr_new->inode))!= pa->inode) 3456987da915Sopenharmony_ci || (attr_new->type != pa->type); 3457987da915Sopenharmony_ci break; 3458987da915Sopenharmony_ci default : err = 1; 3459987da915Sopenharmony_ci } 3460987da915Sopenharmony_ci if (!err) { 3461987da915Sopenharmony_ci err = (namelen != pa->namelen) 3462987da915Sopenharmony_ci || (namelen 3463987da915Sopenharmony_ci && memcmp(name, pa->name, namelen)); 3464987da915Sopenharmony_ci } 3465987da915Sopenharmony_ci if (optv > 1) 3466987da915Sopenharmony_ci printf("-> attribute %s the recorded one\n", 3467987da915Sopenharmony_ci (err ? "does not match" : "matches")); 3468987da915Sopenharmony_ci } else 3469987da915Sopenharmony_ci if (optv) 3470987da915Sopenharmony_ci printf("* Unrecorded attribute\n"); 3471987da915Sopenharmony_cierr = 0; 3472987da915Sopenharmony_ci return (err); 3473987da915Sopenharmony_ci} 3474987da915Sopenharmony_ci 3475987da915Sopenharmony_cistatic int undo_sizes(ntfs_volume *vol, 3476987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3477987da915Sopenharmony_ci{ 3478987da915Sopenharmony_ci const char *data; 3479987da915Sopenharmony_ci MFT_RECORD *entry; 3480987da915Sopenharmony_ci ATTR_RECORD *attr; 3481987da915Sopenharmony_ci u32 target; 3482987da915Sopenharmony_ci u32 length; 3483987da915Sopenharmony_ci u32 offs; 3484987da915Sopenharmony_ci int err; 3485987da915Sopenharmony_ci 3486987da915Sopenharmony_ci if (optv > 1) 3487987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3488987da915Sopenharmony_ci err = 1; 3489987da915Sopenharmony_ci data = ((const char*)&action->record) 3490987da915Sopenharmony_ci + get_undo_offset(&action->record); 3491987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3492987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3493987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset) 3494987da915Sopenharmony_ci + offsetof(ATTR_RECORD, allocated_size); 3495987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 3496987da915Sopenharmony_ci if (!(entry->flags & MFT_RECORD_IS_DIRECTORY)) 3497987da915Sopenharmony_ci err = change_resident(vol, action, buffer, 3498987da915Sopenharmony_ci data, target, length); 3499987da915Sopenharmony_ci else { 3500987da915Sopenharmony_ci /* On a directory, may have to build an index allocation */ 3501987da915Sopenharmony_ci offs = le16_to_cpu(action->record.record_offset); 3502987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer + offs); 3503987da915Sopenharmony_ci if (attr->type != AT_INDEX_ALLOCATION) { 3504987da915Sopenharmony_ci err = insert_index_allocation(vol, buffer, offs); 3505987da915Sopenharmony_ci if (!err) 3506987da915Sopenharmony_ci err = change_resident(vol, action, buffer, 3507987da915Sopenharmony_ci data, target, length); 3508987da915Sopenharmony_ci } else 3509987da915Sopenharmony_ci err = change_resident(vol, action, buffer, 3510987da915Sopenharmony_ci data, target, length); 3511987da915Sopenharmony_ci } 3512987da915Sopenharmony_ci return (err); 3513987da915Sopenharmony_ci} 3514987da915Sopenharmony_ci 3515987da915Sopenharmony_cistatic int undo_update_index(ntfs_volume *vol, const struct ACTION_RECORD *action, 3516987da915Sopenharmony_ci char *buffer) 3517987da915Sopenharmony_ci{ 3518987da915Sopenharmony_ci const char *data; 3519987da915Sopenharmony_ci u32 target; 3520987da915Sopenharmony_ci u32 length; 3521987da915Sopenharmony_ci int err; 3522987da915Sopenharmony_ci 3523987da915Sopenharmony_ci if (optv > 1) 3524987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3525987da915Sopenharmony_ci err = 1; 3526987da915Sopenharmony_ci data = ((const char*)&action->record) 3527987da915Sopenharmony_ci + get_undo_offset(&action->record); 3528987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3529987da915Sopenharmony_ci /* target is left-justified to creation time */ 3530987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3531987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset) 3532987da915Sopenharmony_ci + offsetof(INDEX_ENTRY, key.file_name.creation_time); 3533987da915Sopenharmony_ci err = update_index(vol, action, buffer, data, target, length); 3534987da915Sopenharmony_ci return (err); 3535987da915Sopenharmony_ci} 3536987da915Sopenharmony_ci 3537987da915Sopenharmony_cistatic int undo_update_index_value(ntfs_volume *vol, 3538987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3539987da915Sopenharmony_ci{ 3540987da915Sopenharmony_ci LCN lcn; 3541987da915Sopenharmony_ci const char *data; 3542987da915Sopenharmony_ci u32 length; 3543987da915Sopenharmony_ci u32 target; 3544987da915Sopenharmony_ci int changed; 3545987da915Sopenharmony_ci int err; 3546987da915Sopenharmony_ci 3547987da915Sopenharmony_ci if (optv > 1) 3548987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3549987da915Sopenharmony_ci err = 1; 3550987da915Sopenharmony_ci data = ((const char*)&action->record) 3551987da915Sopenharmony_ci + get_undo_offset(&action->record); 3552987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3553987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3554987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3555987da915Sopenharmony_ci if (optv > 1) { 3556987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3557987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 3558987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3559987da915Sopenharmony_ci } 3560987da915Sopenharmony_ci if (optv > 1) { 3561987da915Sopenharmony_ci printf("-> existing record :\n"); 3562987da915Sopenharmony_ci dump(&buffer[target], length); 3563987da915Sopenharmony_ci } 3564987da915Sopenharmony_ci if ((target + length) <= vol->indx_record_size) { 3565987da915Sopenharmony_ci changed = length && memcmp(buffer + target, data, length); 3566987da915Sopenharmony_ci err = 0; 3567987da915Sopenharmony_ci if (changed) { 3568987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3569987da915Sopenharmony_ci if (optv > 1) { 3570987da915Sopenharmony_ci printf("-> new record :\n"); 3571987da915Sopenharmony_ci dump(buffer + target, length); 3572987da915Sopenharmony_ci } 3573987da915Sopenharmony_ci err = write_protected(vol, &action->record, buffer, 3574987da915Sopenharmony_ci vol->indx_record_size); 3575987da915Sopenharmony_ci } 3576987da915Sopenharmony_ci if (optv > 1) { 3577987da915Sopenharmony_ci printf("-> data record %s\n", 3578987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3579987da915Sopenharmony_ci } 3580987da915Sopenharmony_ci } 3581987da915Sopenharmony_ci return (err); 3582987da915Sopenharmony_ci} 3583987da915Sopenharmony_ci 3584987da915Sopenharmony_cistatic int undo_update_vcn(ntfs_volume *vol, const struct ACTION_RECORD *action, 3585987da915Sopenharmony_ci char *buffer) 3586987da915Sopenharmony_ci{ 3587987da915Sopenharmony_ci const char *data; 3588987da915Sopenharmony_ci u32 target; 3589987da915Sopenharmony_ci u32 length; 3590987da915Sopenharmony_ci int err; 3591987da915Sopenharmony_ci 3592987da915Sopenharmony_ci if (optv > 1) 3593987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3594987da915Sopenharmony_ci err = 1; 3595987da915Sopenharmony_ci data = ((const char*)&action->record) 3596987da915Sopenharmony_ci + get_undo_offset(&action->record); 3597987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3598987da915Sopenharmony_ci if (length == 8) { 3599987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3600987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3601987da915Sopenharmony_ci /* target is right-justified to end of attribute */ 3602987da915Sopenharmony_ci target += getle16(buffer, target + 8) - length; 3603987da915Sopenharmony_ci err = update_index(vol, action, buffer, data, target, length); 3604987da915Sopenharmony_ci } 3605987da915Sopenharmony_ci return (err); 3606987da915Sopenharmony_ci} 3607987da915Sopenharmony_ci 3608987da915Sopenharmony_cistatic int undo_update_mapping(ntfs_volume *vol, const struct ACTION_RECORD *action, 3609987da915Sopenharmony_ci char *buffer) 3610987da915Sopenharmony_ci{ 3611987da915Sopenharmony_ci LCN lcn; 3612987da915Sopenharmony_ci const char *data; 3613987da915Sopenharmony_ci ATTR_RECORD *attr; 3614987da915Sopenharmony_ci MFT_RECORD *entry; 3615987da915Sopenharmony_ci u32 target; 3616987da915Sopenharmony_ci u32 length; 3617987da915Sopenharmony_ci u32 source; 3618987da915Sopenharmony_ci u32 alen; 3619987da915Sopenharmony_ci u32 newused; 3620987da915Sopenharmony_ci int err; 3621987da915Sopenharmony_ci int changed; 3622987da915Sopenharmony_ci int resize; 3623987da915Sopenharmony_ci 3624987da915Sopenharmony_ci if (optv > 1) 3625987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3626987da915Sopenharmony_ci err = 1; 3627987da915Sopenharmony_ci data = ((const char*)&action->record) 3628987da915Sopenharmony_ci + get_undo_offset(&action->record); 3629987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3630987da915Sopenharmony_ci resize = length - le16_to_cpu(action->record.redo_length); 3631987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3632987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3633987da915Sopenharmony_ci if (optv > 1) { 3634987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3635987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x new length %d resize %d\n", 3636987da915Sopenharmony_ci (long long)inode_number(&action->record), 3637987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length, (int)resize); 3638987da915Sopenharmony_ci } 3639987da915Sopenharmony_ci// TODO share with redo_update_mapping() 3640987da915Sopenharmony_ci if (optv > 1) { 3641987da915Sopenharmony_ci printf("-> existing record :\n"); 3642987da915Sopenharmony_ci dump(&buffer[target], length); 3643987da915Sopenharmony_ci } 3644987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 3645987da915Sopenharmony_ci attr = (ATTR_RECORD*)(buffer 3646987da915Sopenharmony_ci + le16_to_cpu(action->record.record_offset)); 3647987da915Sopenharmony_ci if (!attr->non_resident) { 3648987da915Sopenharmony_ci printf("** Error : update_mapping on resident attr\n"); 3649987da915Sopenharmony_ci } 3650987da915Sopenharmony_ci if (valid_type(attr->type) 3651987da915Sopenharmony_ci && attr->non_resident 3652987da915Sopenharmony_ci && !(resize & 7) 3653987da915Sopenharmony_ci && ((target + length) <= mftrecsz)) { 3654987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 3655987da915Sopenharmony_ci err = 0; 3656987da915Sopenharmony_ci if (changed) { 3657987da915Sopenharmony_ci /* Adjust space for new mapping pairs */ 3658987da915Sopenharmony_ci source = target - resize; 3659987da915Sopenharmony_ci if (resize > 0) { 3660987da915Sopenharmony_ci memmove(buffer + target + length, 3661987da915Sopenharmony_ci buffer + source + length, 3662987da915Sopenharmony_ci mftrecsz - target - length); 3663987da915Sopenharmony_ci } 3664987da915Sopenharmony_ci if (resize < 0) { 3665987da915Sopenharmony_ci memmove(buffer + target + length, 3666987da915Sopenharmony_ci buffer + source + length, 3667987da915Sopenharmony_ci mftrecsz - source - length); 3668987da915Sopenharmony_ci } 3669987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3670987da915Sopenharmony_ci /* Resize the attribute */ 3671987da915Sopenharmony_ci alen = le32_to_cpu(attr->length) + resize; 3672987da915Sopenharmony_ci attr->length = cpu_to_le32(alen); 3673987da915Sopenharmony_ci /* Resize the mft record */ 3674987da915Sopenharmony_ci newused = le32_to_cpu(entry->bytes_in_use) 3675987da915Sopenharmony_ci + resize; 3676987da915Sopenharmony_ci entry->bytes_in_use = cpu_to_le32(newused); 3677987da915Sopenharmony_ci /* Compute the new highest_vcn */ 3678987da915Sopenharmony_ci err = adjust_high_vcn(vol, attr); 3679987da915Sopenharmony_ci if (optv > 1) { 3680987da915Sopenharmony_ci printf("-> new record :\n"); 3681987da915Sopenharmony_ci dump(buffer + target, length); 3682987da915Sopenharmony_ci } 3683987da915Sopenharmony_ci if (!err) { 3684987da915Sopenharmony_ci err = write_protected(vol, 3685987da915Sopenharmony_ci &action->record, buffer, 3686987da915Sopenharmony_ci mftrecsz); 3687987da915Sopenharmony_ci } 3688987da915Sopenharmony_ci } 3689987da915Sopenharmony_ci if (optv > 1) { 3690987da915Sopenharmony_ci printf("-> MFT record %s\n", 3691987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3692987da915Sopenharmony_ci } 3693987da915Sopenharmony_ci } 3694987da915Sopenharmony_ci return (err); 3695987da915Sopenharmony_ci} 3696987da915Sopenharmony_ci 3697987da915Sopenharmony_cistatic int undo_update_resident(ntfs_volume *vol, 3698987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3699987da915Sopenharmony_ci{ 3700987da915Sopenharmony_ci LCN lcn; 3701987da915Sopenharmony_ci const char *data; 3702987da915Sopenharmony_ci u32 target; 3703987da915Sopenharmony_ci u32 length; 3704987da915Sopenharmony_ci u32 oldlength; 3705987da915Sopenharmony_ci u32 end; 3706987da915Sopenharmony_ci u32 undo; 3707987da915Sopenharmony_ci int err; 3708987da915Sopenharmony_ci int changed; 3709987da915Sopenharmony_ci 3710987da915Sopenharmony_ci if (optv > 1) 3711987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3712987da915Sopenharmony_ci err = 1; 3713987da915Sopenharmony_ci end = le32_to_cpu(action->record.client_data_length) 3714987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 3715987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3716987da915Sopenharmony_ci undo = get_undo_offset(&action->record); 3717987da915Sopenharmony_ci if ((undo + length) > end) 3718987da915Sopenharmony_ci data = (char*)NULL; 3719987da915Sopenharmony_ci else 3720987da915Sopenharmony_ci data = ((const char*)&action->record) + undo; 3721987da915Sopenharmony_ci oldlength = le16_to_cpu(action->record.redo_length); 3722987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3723987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3724987da915Sopenharmony_ci if (length == oldlength) { 3725987da915Sopenharmony_ci if (optv > 1) { 3726987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3727987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x length %d\n", 3728987da915Sopenharmony_ci (long long)inode_number(&action->record), 3729987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3730987da915Sopenharmony_ci } 3731987da915Sopenharmony_ci if (optv > 1) { 3732987da915Sopenharmony_ci printf("-> existing record :\n"); 3733987da915Sopenharmony_ci dump(&buffer[target], length); 3734987da915Sopenharmony_ci } 3735987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 3736987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 3737987da915Sopenharmony_ci err = 0; 3738987da915Sopenharmony_ci if (changed) { 3739987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3740987da915Sopenharmony_ci if (optv > 1) { 3741987da915Sopenharmony_ci printf("-> new record :\n"); 3742987da915Sopenharmony_ci dump(buffer + target, length); 3743987da915Sopenharmony_ci } 3744987da915Sopenharmony_ci err = write_protected(vol, &action->record, 3745987da915Sopenharmony_ci buffer, mftrecsz); 3746987da915Sopenharmony_ci } 3747987da915Sopenharmony_ci if (optv > 1) { 3748987da915Sopenharmony_ci printf("-> MFT record %s\n", 3749987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3750987da915Sopenharmony_ci } 3751987da915Sopenharmony_ci } 3752987da915Sopenharmony_ci } else { 3753987da915Sopenharmony_ci if (length > oldlength) 3754987da915Sopenharmony_ci err = expand_resident(vol, action, buffer, data, 3755987da915Sopenharmony_ci target, length, oldlength); 3756987da915Sopenharmony_ci else 3757987da915Sopenharmony_ci err = shrink_resident(vol, action, buffer, data, 3758987da915Sopenharmony_ci target, length, oldlength); 3759987da915Sopenharmony_ci } 3760987da915Sopenharmony_ci return (err); 3761987da915Sopenharmony_ci} 3762987da915Sopenharmony_ci 3763987da915Sopenharmony_cistatic int undo_update_root_index(ntfs_volume *vol, 3764987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3765987da915Sopenharmony_ci{ 3766987da915Sopenharmony_ci const char *data; 3767987da915Sopenharmony_ci const char *expected; 3768987da915Sopenharmony_ci u32 target; 3769987da915Sopenharmony_ci u32 length; 3770987da915Sopenharmony_ci int err; 3771987da915Sopenharmony_ci 3772987da915Sopenharmony_ci if (optv > 1) 3773987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3774987da915Sopenharmony_ci err = 1; 3775987da915Sopenharmony_ci data = ((const char*)&action->record) 3776987da915Sopenharmony_ci + get_undo_offset(&action->record); 3777987da915Sopenharmony_ci expected = ((const char*)&action->record) 3778987da915Sopenharmony_ci + get_redo_offset(&action->record); 3779987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3780987da915Sopenharmony_ci /* the fixup is right-justified to the name length */ 3781987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3782987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset) 3783987da915Sopenharmony_ci + offsetof(INDEX_ENTRY, key.file_name.file_name_length) 3784987da915Sopenharmony_ci - length; 3785987da915Sopenharmony_ci err = change_resident_expect(vol, action, buffer, data, expected, 3786987da915Sopenharmony_ci target, length, AT_INDEX_ROOT); 3787987da915Sopenharmony_ci return (err); 3788987da915Sopenharmony_ci} 3789987da915Sopenharmony_ci 3790987da915Sopenharmony_cistatic int undo_update_root_vcn(ntfs_volume *vol, 3791987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3792987da915Sopenharmony_ci{ 3793987da915Sopenharmony_ci const char *data; 3794987da915Sopenharmony_ci const char *expected; 3795987da915Sopenharmony_ci u32 target; 3796987da915Sopenharmony_ci u32 length; 3797987da915Sopenharmony_ci int err; 3798987da915Sopenharmony_ci 3799987da915Sopenharmony_ci if (optv > 1) 3800987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3801987da915Sopenharmony_ci err = 1; 3802987da915Sopenharmony_ci data = ((const char*)&action->record) 3803987da915Sopenharmony_ci + get_undo_offset(&action->record); 3804987da915Sopenharmony_ci expected = ((const char*)&action->record) 3805987da915Sopenharmony_ci + get_redo_offset(&action->record); 3806987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3807987da915Sopenharmony_ci if (length == 8) { 3808987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3809987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3810987da915Sopenharmony_ci /* target is right-justified to end of attribute */ 3811987da915Sopenharmony_ci target += getle16(buffer, target + 8) - length; 3812987da915Sopenharmony_ci err = change_resident_expect(vol, action, buffer, data, 3813987da915Sopenharmony_ci expected, target, length, AT_INDEX_ROOT); 3814987da915Sopenharmony_ci } 3815987da915Sopenharmony_ci return (err); 3816987da915Sopenharmony_ci} 3817987da915Sopenharmony_ci 3818987da915Sopenharmony_cistatic int undo_update_value(ntfs_volume *vol, 3819987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3820987da915Sopenharmony_ci{ 3821987da915Sopenharmony_ci LCN lcn; 3822987da915Sopenharmony_ci const char *data; 3823987da915Sopenharmony_ci u32 length; 3824987da915Sopenharmony_ci u32 target; 3825987da915Sopenharmony_ci u32 count; 3826987da915Sopenharmony_ci int changed; 3827987da915Sopenharmony_ci int err; 3828987da915Sopenharmony_ci 3829987da915Sopenharmony_ci if (optv > 1) 3830987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3831987da915Sopenharmony_ci err = 1; 3832987da915Sopenharmony_ci data = ((const char*)&action->record) 3833987da915Sopenharmony_ci + get_undo_offset(&action->record); 3834987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3835987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3836987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3837987da915Sopenharmony_ci count = le16_to_cpu(action->record.lcns_to_follow); 3838987da915Sopenharmony_ci if (optv > 1) { 3839987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3840987da915Sopenharmony_ci printf("-> lcn 0x%llx target 0x%x length %d\n", 3841987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3842987da915Sopenharmony_ci } 3843987da915Sopenharmony_ci if (length) { 3844987da915Sopenharmony_ci if (optv > 1) { 3845987da915Sopenharmony_ci printf("-> existing record :\n"); 3846987da915Sopenharmony_ci dump(&buffer[target], length); 3847987da915Sopenharmony_ci } 3848987da915Sopenharmony_ci if ((target + length) <= (count << clusterbits)) { 3849987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 3850987da915Sopenharmony_ci err = 0; 3851987da915Sopenharmony_ci if (changed) { 3852987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3853987da915Sopenharmony_ci if (optv > 1) { 3854987da915Sopenharmony_ci printf("-> new record :\n"); 3855987da915Sopenharmony_ci dump(buffer + target, length); 3856987da915Sopenharmony_ci } 3857987da915Sopenharmony_ci err = write_raw(vol, &action->record, buffer); 3858987da915Sopenharmony_ci } 3859987da915Sopenharmony_ci if (optv > 1) { 3860987da915Sopenharmony_ci printf("-> data record %s\n", 3861987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3862987da915Sopenharmony_ci } 3863987da915Sopenharmony_ci } 3864987da915Sopenharmony_ci } else { 3865987da915Sopenharmony_ci /* 3866987da915Sopenharmony_ci * No undo data, we cannot undo, sometimes the redo 3867987da915Sopenharmony_ci * data even overflows from record. 3868987da915Sopenharmony_ci * Just ignore for now. 3869987da915Sopenharmony_ci */ 3870987da915Sopenharmony_ci if (optv) 3871987da915Sopenharmony_ci printf("Cannot undo, there is no undo data\n"); 3872987da915Sopenharmony_ci err = 0; 3873987da915Sopenharmony_ci } 3874987da915Sopenharmony_ci 3875987da915Sopenharmony_ci return (err); 3876987da915Sopenharmony_ci} 3877987da915Sopenharmony_ci 3878987da915Sopenharmony_cistatic int undo_write_end(ntfs_volume *vol, 3879987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3880987da915Sopenharmony_ci{ 3881987da915Sopenharmony_ci LCN lcn; 3882987da915Sopenharmony_ci const char *data; 3883987da915Sopenharmony_ci u32 target; 3884987da915Sopenharmony_ci u32 length; 3885987da915Sopenharmony_ci u32 oldlength; 3886987da915Sopenharmony_ci u32 end; 3887987da915Sopenharmony_ci u32 undo; 3888987da915Sopenharmony_ci int err; 3889987da915Sopenharmony_ci int changed; 3890987da915Sopenharmony_ci 3891987da915Sopenharmony_ci if (optv > 1) 3892987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3893987da915Sopenharmony_ci err = 1; 3894987da915Sopenharmony_ci end = le32_to_cpu(action->record.client_data_length) 3895987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 3896987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3897987da915Sopenharmony_ci undo = get_undo_offset(&action->record); 3898987da915Sopenharmony_ci if ((undo + length) > end) 3899987da915Sopenharmony_ci data = (char*)NULL; 3900987da915Sopenharmony_ci else 3901987da915Sopenharmony_ci data = ((const char*)&action->record) + undo; 3902987da915Sopenharmony_ci oldlength = le16_to_cpu(action->record.redo_length); 3903987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3904987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3905987da915Sopenharmony_ci if (length == oldlength) { 3906987da915Sopenharmony_ci if (optv > 1) { 3907987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3908987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x" 3909987da915Sopenharmony_ci " length %d\n", 3910987da915Sopenharmony_ci (long long)inode_number(&action->record), 3911987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3912987da915Sopenharmony_ci } 3913987da915Sopenharmony_ci if (optv > 1) { 3914987da915Sopenharmony_ci printf("-> existing record :\n"); 3915987da915Sopenharmony_ci dump(&buffer[target], length); 3916987da915Sopenharmony_ci } 3917987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 3918987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 3919987da915Sopenharmony_ci err = 0; 3920987da915Sopenharmony_ci if (changed) { 3921987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3922987da915Sopenharmony_ci if (optv > 1) { 3923987da915Sopenharmony_ci printf("-> new record :\n"); 3924987da915Sopenharmony_ci dump(buffer + target, length); 3925987da915Sopenharmony_ci } 3926987da915Sopenharmony_ci err = write_protected(vol, &action->record, 3927987da915Sopenharmony_ci buffer, mftrecsz); 3928987da915Sopenharmony_ci } 3929987da915Sopenharmony_ci if (optv > 1) { 3930987da915Sopenharmony_ci printf("-> MFT record %s\n", 3931987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3932987da915Sopenharmony_ci } 3933987da915Sopenharmony_ci } 3934987da915Sopenharmony_ci } else { 3935987da915Sopenharmony_ci if (length > oldlength) 3936987da915Sopenharmony_ci err = add_resident(vol, action, buffer, data, 3937987da915Sopenharmony_ci target, length, oldlength); 3938987da915Sopenharmony_ci else 3939987da915Sopenharmony_ci err = delete_resident(vol, action, buffer, data, 3940987da915Sopenharmony_ci target, length, oldlength); 3941987da915Sopenharmony_ci } 3942987da915Sopenharmony_ci return (err); 3943987da915Sopenharmony_ci} 3944987da915Sopenharmony_ci 3945987da915Sopenharmony_cistatic int undo_write_index(ntfs_volume *vol, 3946987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 3947987da915Sopenharmony_ci{ 3948987da915Sopenharmony_ci LCN lcn; 3949987da915Sopenharmony_ci const char *data; 3950987da915Sopenharmony_ci u32 target; 3951987da915Sopenharmony_ci u32 length; 3952987da915Sopenharmony_ci u32 oldlength; 3953987da915Sopenharmony_ci u32 end; 3954987da915Sopenharmony_ci u32 undo; 3955987da915Sopenharmony_ci int err; 3956987da915Sopenharmony_ci int changed; 3957987da915Sopenharmony_ci 3958987da915Sopenharmony_ci if (optv > 1) 3959987da915Sopenharmony_ci printf("-> %s()\n",__func__); 3960987da915Sopenharmony_ci err = 1; 3961987da915Sopenharmony_ci end = le32_to_cpu(action->record.client_data_length) 3962987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 3963987da915Sopenharmony_ci length = le16_to_cpu(action->record.undo_length); 3964987da915Sopenharmony_ci undo = get_undo_offset(&action->record); 3965987da915Sopenharmony_ci if ((undo + length) > end) 3966987da915Sopenharmony_ci data = (char*)NULL; 3967987da915Sopenharmony_ci else 3968987da915Sopenharmony_ci data = ((const char*)&action->record) + undo; 3969987da915Sopenharmony_ci oldlength = le16_to_cpu(action->record.redo_length); 3970987da915Sopenharmony_ci target = le16_to_cpu(action->record.record_offset) 3971987da915Sopenharmony_ci + le16_to_cpu(action->record.attribute_offset); 3972987da915Sopenharmony_ci if (length == oldlength) { 3973987da915Sopenharmony_ci if (optv > 1) { 3974987da915Sopenharmony_ci lcn = sle64_to_cpu(action->record.lcn_list[0]); 3975987da915Sopenharmony_ci printf("-> inode %lld lcn 0x%llx target 0x%x" 3976987da915Sopenharmony_ci " length %d\n", 3977987da915Sopenharmony_ci (long long)inode_number(&action->record), 3978987da915Sopenharmony_ci (long long)lcn, (int)target, (int)length); 3979987da915Sopenharmony_ci } 3980987da915Sopenharmony_ci if (optv > 1) { 3981987da915Sopenharmony_ci printf("-> existing record :\n"); 3982987da915Sopenharmony_ci dump(&buffer[target], length); 3983987da915Sopenharmony_ci } 3984987da915Sopenharmony_ci if ((target + length) <= mftrecsz) { 3985987da915Sopenharmony_ci changed = memcmp(buffer + target, data, length); 3986987da915Sopenharmony_ci err = 0; 3987987da915Sopenharmony_ci if (changed) { 3988987da915Sopenharmony_ci memcpy(buffer + target, data, length); 3989987da915Sopenharmony_ci if (optv > 1) { 3990987da915Sopenharmony_ci printf("-> new record :\n"); 3991987da915Sopenharmony_ci dump(buffer + target, length); 3992987da915Sopenharmony_ci } 3993987da915Sopenharmony_ci err = write_protected(vol, &action->record, 3994987da915Sopenharmony_ci buffer, mftrecsz); 3995987da915Sopenharmony_ci } 3996987da915Sopenharmony_ci if (optv > 1) { 3997987da915Sopenharmony_ci printf("-> MFT record %s\n", 3998987da915Sopenharmony_ci (changed ? "updated" : "unchanged")); 3999987da915Sopenharmony_ci } 4000987da915Sopenharmony_ci } 4001987da915Sopenharmony_ci } else { 4002987da915Sopenharmony_ci if (length > oldlength) 4003987da915Sopenharmony_ci err = add_non_resident(/*vol, action, data, 4004987da915Sopenharmony_ci target, length, oldlength*/); 4005987da915Sopenharmony_ci else 4006987da915Sopenharmony_ci err = delete_non_resident(/*vol, action, data, 4007987da915Sopenharmony_ci target, length, oldlength*/); 4008987da915Sopenharmony_ci } 4009987da915Sopenharmony_ci return (err); 4010987da915Sopenharmony_ci} 4011987da915Sopenharmony_ci 4012987da915Sopenharmony_cienum ACTION_KIND { ON_NONE, ON_MFT, ON_INDX, ON_RAW } ; 4013987da915Sopenharmony_ci 4014987da915Sopenharmony_cistatic enum ACTION_KIND get_action_kind(const struct ACTION_RECORD *action) 4015987da915Sopenharmony_ci{ 4016987da915Sopenharmony_ci struct ATTR *pa; 4017987da915Sopenharmony_ci const char *data; 4018987da915Sopenharmony_ci enum ACTION_KIND kind; 4019987da915Sopenharmony_ci /* 4020987da915Sopenharmony_ci * If we are sure the action was defined by Vista 4021987da915Sopenharmony_ci * or subsequent, just use attribute_flags. 4022987da915Sopenharmony_ci * Unfortunately, only on some cases we can determine 4023987da915Sopenharmony_ci * the action was defined by Win10 (or subsequent). 4024987da915Sopenharmony_ci */ 4025987da915Sopenharmony_ci if (action->record.log_record_flags 4026987da915Sopenharmony_ci & (LOG_RECORD_DELETING | LOG_RECORD_ADDING)) { 4027987da915Sopenharmony_ci if (action->record.attribute_flags & ACTS_ON_INDX) 4028987da915Sopenharmony_ci kind = ON_INDX; 4029987da915Sopenharmony_ci else 4030987da915Sopenharmony_ci if (action->record.attribute_flags & ACTS_ON_MFT) 4031987da915Sopenharmony_ci kind = ON_MFT; 4032987da915Sopenharmony_ci else 4033987da915Sopenharmony_ci kind = ON_RAW; 4034987da915Sopenharmony_ci } else { 4035987da915Sopenharmony_ci /* 4036987da915Sopenharmony_ci * In other cases, we have to rely on the attribute 4037987da915Sopenharmony_ci * definition, but this has defects when undoing. 4038987da915Sopenharmony_ci */ 4039987da915Sopenharmony_ci pa = getattrentry(le16_to_cpu( 4040987da915Sopenharmony_ci action->record.target_attribute),0); 4041987da915Sopenharmony_ci if (!pa || !pa->type) { 4042987da915Sopenharmony_ci /* 4043987da915Sopenharmony_ci * Even when the attribute has not been recorded, 4044987da915Sopenharmony_ci * we can sometimes tell the record does not apply 4045987da915Sopenharmony_ci * to MFT or INDX : such records always have a zero 4046987da915Sopenharmony_ci * record_offset, and if attribute_offset is zero, their 4047987da915Sopenharmony_ci * magic can be checked. If neither condition is true, 4048987da915Sopenharmony_ci * the action cannot apply to MFT or INDX. 4049987da915Sopenharmony_ci * (this is useful for undoing) 4050987da915Sopenharmony_ci */ 4051987da915Sopenharmony_ci data = (const char*)&action->record 4052987da915Sopenharmony_ci + get_redo_offset(&action->record); 4053987da915Sopenharmony_ci if (action->record.record_offset 4054987da915Sopenharmony_ci || (!action->record.attribute_offset 4055987da915Sopenharmony_ci && (le16_to_cpu(action->record.redo_length) 4056987da915Sopenharmony_ci >= 4) 4057987da915Sopenharmony_ci && memcmp(data,"FILE",4) 4058987da915Sopenharmony_ci && memcmp(data,"INDX",4))) { 4059987da915Sopenharmony_ci kind = ON_RAW; 4060987da915Sopenharmony_ci } else { 4061987da915Sopenharmony_ci printf("** Error : attribute 0x%x" 4062987da915Sopenharmony_ci " is not defined\n", 4063987da915Sopenharmony_ci (int)le16_to_cpu( 4064987da915Sopenharmony_ci action->record.target_attribute)); 4065987da915Sopenharmony_ci kind = ON_NONE; 4066987da915Sopenharmony_ci } 4067987da915Sopenharmony_ci } else { 4068987da915Sopenharmony_ci if (pa->type == AT_INDEX_ALLOCATION) 4069987da915Sopenharmony_ci kind = ON_INDX; 4070987da915Sopenharmony_ci else 4071987da915Sopenharmony_ci kind = ON_RAW; 4072987da915Sopenharmony_ci } 4073987da915Sopenharmony_ci } 4074987da915Sopenharmony_ci return (kind); 4075987da915Sopenharmony_ci} 4076987da915Sopenharmony_ci 4077987da915Sopenharmony_ci 4078987da915Sopenharmony_ci/* 4079987da915Sopenharmony_ci * Display the redo actions which were executed 4080987da915Sopenharmony_ci * 4081987da915Sopenharmony_ci * Useful for getting indications on the coverage of a test 4082987da915Sopenharmony_ci */ 4083987da915Sopenharmony_ci 4084987da915Sopenharmony_civoid show_redos(void) 4085987da915Sopenharmony_ci{ 4086987da915Sopenharmony_ci int i; 4087987da915Sopenharmony_ci 4088987da915Sopenharmony_ci if (optv && redos_met) { 4089987da915Sopenharmony_ci printf("Redo actions which were executed :\n"); 4090987da915Sopenharmony_ci for (i=0; i<64; i++) 4091987da915Sopenharmony_ci if ((((u64)1) << i) & redos_met) 4092987da915Sopenharmony_ci printf("%s\n", actionname(i)); 4093987da915Sopenharmony_ci } 4094987da915Sopenharmony_ci} 4095987da915Sopenharmony_ci 4096987da915Sopenharmony_cistatic int distribute_redos(ntfs_volume *vol, 4097987da915Sopenharmony_ci const struct ACTION_RECORD *action, char *buffer) 4098987da915Sopenharmony_ci{ 4099987da915Sopenharmony_ci int rop, uop; 4100987da915Sopenharmony_ci int err; 4101987da915Sopenharmony_ci 4102987da915Sopenharmony_ci err = 0; 4103987da915Sopenharmony_ci rop = le16_to_cpu(action->record.redo_operation); 4104987da915Sopenharmony_ci uop = le16_to_cpu(action->record.undo_operation); 4105987da915Sopenharmony_ci switch (rop) { 4106987da915Sopenharmony_ci case AddIndexEntryAllocation : 4107987da915Sopenharmony_ci if (action->record.undo_operation 4108987da915Sopenharmony_ci == const_cpu_to_le16(DeleteIndexEntryAllocation)) 4109987da915Sopenharmony_ci err = redo_add_index(vol, action, buffer); 4110987da915Sopenharmony_ci break; 4111987da915Sopenharmony_ci case AddIndexEntryRoot : 4112987da915Sopenharmony_ci if (action->record.undo_operation 4113987da915Sopenharmony_ci == const_cpu_to_le16(DeleteIndexEntryRoot)) 4114987da915Sopenharmony_ci err = redo_add_root_index(vol, action, buffer); 4115987da915Sopenharmony_ci break; 4116987da915Sopenharmony_ci case ClearBitsInNonResidentBitMap : 4117987da915Sopenharmony_ci if ((action->record.undo_operation 4118987da915Sopenharmony_ci == const_cpu_to_le16(SetBitsInNonResidentBitMap)) 4119987da915Sopenharmony_ci || (action->record.undo_operation 4120987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4121987da915Sopenharmony_ci err = redo_force_bits(vol, action, buffer); 4122987da915Sopenharmony_ci break; 4123987da915Sopenharmony_ci case CompensationlogRecord : 4124987da915Sopenharmony_ci if (action->record.undo_operation 4125987da915Sopenharmony_ci == const_cpu_to_le16(Noop)) 4126987da915Sopenharmony_ci err = redo_compensate(vol, action, buffer); 4127987da915Sopenharmony_ci break; 4128987da915Sopenharmony_ci case CreateAttribute : 4129987da915Sopenharmony_ci if ((action->record.undo_operation 4130987da915Sopenharmony_ci == const_cpu_to_le16(DeleteAttribute)) 4131987da915Sopenharmony_ci || (action->record.undo_operation 4132987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4133987da915Sopenharmony_ci err = redo_create_attribute(vol, action, buffer); 4134987da915Sopenharmony_ci break; 4135987da915Sopenharmony_ci case DeallocateFileRecordSegment : 4136987da915Sopenharmony_ci if ((action->record.undo_operation 4137987da915Sopenharmony_ci == const_cpu_to_le16(InitializeFileRecordSegment)) 4138987da915Sopenharmony_ci || (action->record.undo_operation 4139987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4140987da915Sopenharmony_ci err = redo_delete_file(vol, action, buffer); 4141987da915Sopenharmony_ci break; 4142987da915Sopenharmony_ci case DeleteAttribute : 4143987da915Sopenharmony_ci if ((action->record.undo_operation 4144987da915Sopenharmony_ci == const_cpu_to_le16(CreateAttribute)) 4145987da915Sopenharmony_ci || (action->record.undo_operation 4146987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4147987da915Sopenharmony_ci err = redo_delete_attribute(vol, action, buffer); 4148987da915Sopenharmony_ci break; 4149987da915Sopenharmony_ci case DeleteIndexEntryAllocation : 4150987da915Sopenharmony_ci if ((action->record.undo_operation 4151987da915Sopenharmony_ci == const_cpu_to_le16(AddIndexEntryAllocation)) 4152987da915Sopenharmony_ci || (action->record.undo_operation 4153987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4154987da915Sopenharmony_ci err = redo_delete_index(vol, action, buffer); 4155987da915Sopenharmony_ci break; 4156987da915Sopenharmony_ci case DeleteIndexEntryRoot : 4157987da915Sopenharmony_ci if ((action->record.undo_operation 4158987da915Sopenharmony_ci == const_cpu_to_le16(AddIndexEntryRoot)) 4159987da915Sopenharmony_ci || (action->record.undo_operation 4160987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4161987da915Sopenharmony_ci err = redo_delete_root_index(vol, action, buffer); 4162987da915Sopenharmony_ci break; 4163987da915Sopenharmony_ci case InitializeFileRecordSegment : 4164987da915Sopenharmony_ci if (action->record.undo_operation 4165987da915Sopenharmony_ci == const_cpu_to_le16(Noop)) 4166987da915Sopenharmony_ci err = redo_create_file(vol, action, buffer); 4167987da915Sopenharmony_ci break; 4168987da915Sopenharmony_ci case OpenNonResidentAttribute : 4169987da915Sopenharmony_ci if (action->record.undo_operation 4170987da915Sopenharmony_ci == const_cpu_to_le16(Noop)) 4171987da915Sopenharmony_ci err = redo_open_attribute(vol, action); 4172987da915Sopenharmony_ci break; 4173987da915Sopenharmony_ci case SetBitsInNonResidentBitMap : 4174987da915Sopenharmony_ci if (action->record.undo_operation 4175987da915Sopenharmony_ci == const_cpu_to_le16(ClearBitsInNonResidentBitMap)) 4176987da915Sopenharmony_ci err = redo_force_bits(vol, action, buffer); 4177987da915Sopenharmony_ci break; 4178987da915Sopenharmony_ci case SetIndexEntryVcnAllocation : 4179987da915Sopenharmony_ci if ((action->record.undo_operation 4180987da915Sopenharmony_ci == const_cpu_to_le16(SetIndexEntryVcnAllocation)) 4181987da915Sopenharmony_ci || (action->record.undo_operation 4182987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4183987da915Sopenharmony_ci err = redo_update_vcn(vol, action, buffer); 4184987da915Sopenharmony_ci break; 4185987da915Sopenharmony_ci case SetIndexEntryVcnRoot : 4186987da915Sopenharmony_ci if (action->record.undo_operation 4187987da915Sopenharmony_ci == const_cpu_to_le16(SetIndexEntryVcnRoot)) 4188987da915Sopenharmony_ci err = redo_update_root_vcn(vol, action, buffer); 4189987da915Sopenharmony_ci break; 4190987da915Sopenharmony_ci case SetNewAttributeSizes : 4191987da915Sopenharmony_ci if ((action->record.undo_operation 4192987da915Sopenharmony_ci == const_cpu_to_le16(SetNewAttributeSizes)) 4193987da915Sopenharmony_ci || (action->record.undo_operation 4194987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4195987da915Sopenharmony_ci err = redo_sizes(vol, action, buffer); 4196987da915Sopenharmony_ci break; 4197987da915Sopenharmony_ci case UpdateFileNameAllocation : 4198987da915Sopenharmony_ci if ((action->record.undo_operation 4199987da915Sopenharmony_ci == const_cpu_to_le16(UpdateFileNameAllocation)) 4200987da915Sopenharmony_ci || (action->record.undo_operation 4201987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4202987da915Sopenharmony_ci err = redo_update_index(vol, action, buffer); 4203987da915Sopenharmony_ci break; 4204987da915Sopenharmony_ci case UpdateFileNameRoot : 4205987da915Sopenharmony_ci if ((action->record.undo_operation 4206987da915Sopenharmony_ci == const_cpu_to_le16(UpdateFileNameRoot)) 4207987da915Sopenharmony_ci || (action->record.undo_operation 4208987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4209987da915Sopenharmony_ci err = redo_update_root_index(vol, action, buffer); 4210987da915Sopenharmony_ci break; 4211987da915Sopenharmony_ci case UpdateMappingPairs : 4212987da915Sopenharmony_ci if (action->record.undo_operation 4213987da915Sopenharmony_ci == const_cpu_to_le16(UpdateMappingPairs)) 4214987da915Sopenharmony_ci err = redo_update_mapping(vol, action, buffer); 4215987da915Sopenharmony_ci break; 4216987da915Sopenharmony_ci case UpdateNonResidentValue : 4217987da915Sopenharmony_ci switch (get_action_kind(action)) { 4218987da915Sopenharmony_ci case ON_INDX : 4219987da915Sopenharmony_ci err = redo_update_index_value(vol, action, buffer); 4220987da915Sopenharmony_ci break; 4221987da915Sopenharmony_ci case ON_RAW : 4222987da915Sopenharmony_ci err = redo_update_value(vol, action, buffer); 4223987da915Sopenharmony_ci break; 4224987da915Sopenharmony_ci default : 4225987da915Sopenharmony_ci printf("** Bad attribute type\n"); 4226987da915Sopenharmony_ci err = 1; 4227987da915Sopenharmony_ci } 4228987da915Sopenharmony_ci break; 4229987da915Sopenharmony_ci case UpdateResidentValue : 4230987da915Sopenharmony_ci if ((action->record.undo_operation 4231987da915Sopenharmony_ci == const_cpu_to_le16(UpdateResidentValue)) 4232987da915Sopenharmony_ci || (action->record.undo_operation 4233987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4234987da915Sopenharmony_ci err = redo_update_resident(vol, action, buffer); 4235987da915Sopenharmony_ci break; 4236987da915Sopenharmony_ci case Win10Action37 : 4237987da915Sopenharmony_ci if (action->record.undo_operation 4238987da915Sopenharmony_ci == const_cpu_to_le16(Noop)) 4239987da915Sopenharmony_ci err = redo_action37(vol, action, buffer); 4240987da915Sopenharmony_ci break; 4241987da915Sopenharmony_ci case WriteEndofFileRecordSegment : 4242987da915Sopenharmony_ci if (action->record.undo_operation 4243987da915Sopenharmony_ci == const_cpu_to_le16(WriteEndofFileRecordSegment)) 4244987da915Sopenharmony_ci err = redo_write_end(vol, action, buffer); 4245987da915Sopenharmony_ci break; 4246987da915Sopenharmony_ci case WriteEndOfIndexBuffer : 4247987da915Sopenharmony_ci if ((action->record.undo_operation 4248987da915Sopenharmony_ci == const_cpu_to_le16(WriteEndOfIndexBuffer)) 4249987da915Sopenharmony_ci || (action->record.undo_operation 4250987da915Sopenharmony_ci == const_cpu_to_le16(CompensationlogRecord))) 4251987da915Sopenharmony_ci err = redo_write_index(vol, action, buffer); 4252987da915Sopenharmony_ci break; 4253987da915Sopenharmony_ci case AttributeNamesDump : 4254987da915Sopenharmony_ci case DirtyPageTableDump : 4255987da915Sopenharmony_ci case ForgetTransaction : 4256987da915Sopenharmony_ci case Noop : 4257987da915Sopenharmony_ci case OpenAttributeTableDump : 4258987da915Sopenharmony_ci break; 4259987da915Sopenharmony_ci default : 4260987da915Sopenharmony_ci printf("** Unsupported redo %s\n", actionname(rop)); 4261987da915Sopenharmony_ci err = 1; 4262987da915Sopenharmony_ci break; 4263987da915Sopenharmony_ci } 4264987da915Sopenharmony_ci redos_met |= ((u64)1) << rop; 4265987da915Sopenharmony_ci if (err) 4266987da915Sopenharmony_ci printf("* Redoing action %d %s (%s) failed\n", 4267987da915Sopenharmony_ci action->num,actionname(rop), actionname(uop)); 4268987da915Sopenharmony_ci return (err); 4269987da915Sopenharmony_ci} 4270987da915Sopenharmony_ci 4271987da915Sopenharmony_ci/* 4272987da915Sopenharmony_ci * Redo a single action 4273987da915Sopenharmony_ci * 4274987da915Sopenharmony_ci * The record the action acts on is read and, when it is an MFT or 4275987da915Sopenharmony_ci * INDX one, the need for redoing is checked. 4276987da915Sopenharmony_ci * 4277987da915Sopenharmony_ci * When this is an action which creates a new MFT or INDX record 4278987da915Sopenharmony_ci * and the old one cannot be read (usually because it was not 4279987da915Sopenharmony_ci * initialized), a zeroed buffer is allocated. 4280987da915Sopenharmony_ci */ 4281987da915Sopenharmony_ci 4282987da915Sopenharmony_cistatic int play_one_redo(ntfs_volume *vol, const struct ACTION_RECORD *action) 4283987da915Sopenharmony_ci{ 4284987da915Sopenharmony_ci MFT_RECORD *entry; 4285987da915Sopenharmony_ci INDEX_BLOCK *indx; 4286987da915Sopenharmony_ci char *buffer; 4287987da915Sopenharmony_ci s64 this_lsn; 4288987da915Sopenharmony_ci s64 data_lsn; 4289987da915Sopenharmony_ci u32 xsize; 4290987da915Sopenharmony_ci int err; 4291987da915Sopenharmony_ci BOOL warn; 4292987da915Sopenharmony_ci BOOL executed; 4293987da915Sopenharmony_ci enum ACTION_KIND kind; 4294987da915Sopenharmony_ci u16 rop; 4295987da915Sopenharmony_ci u16 uop; 4296987da915Sopenharmony_ci 4297987da915Sopenharmony_ci err = 0; 4298987da915Sopenharmony_ci rop = le16_to_cpu(action->record.redo_operation); 4299987da915Sopenharmony_ci uop = le16_to_cpu(action->record.undo_operation); 4300987da915Sopenharmony_ci this_lsn = sle64_to_cpu(action->record.this_lsn); 4301987da915Sopenharmony_ci if (optv) 4302987da915Sopenharmony_ci printf("Redo action %d %s (%s) 0x%llx\n", 4303987da915Sopenharmony_ci action->num, 4304987da915Sopenharmony_ci actionname(rop), actionname(uop), 4305987da915Sopenharmony_ci (long long)sle64_to_cpu( 4306987da915Sopenharmony_ci action->record.this_lsn)); 4307987da915Sopenharmony_ci buffer = (char*)NULL; 4308987da915Sopenharmony_ci switch (rop) { 4309987da915Sopenharmony_ci /* Actions always acting on MFT */ 4310987da915Sopenharmony_ci case AddIndexEntryRoot : 4311987da915Sopenharmony_ci case CreateAttribute : 4312987da915Sopenharmony_ci case DeallocateFileRecordSegment : 4313987da915Sopenharmony_ci case DeleteAttribute : 4314987da915Sopenharmony_ci case DeleteIndexEntryRoot : 4315987da915Sopenharmony_ci case InitializeFileRecordSegment : 4316987da915Sopenharmony_ci case SetIndexEntryVcnRoot : 4317987da915Sopenharmony_ci case SetNewAttributeSizes : 4318987da915Sopenharmony_ci case UpdateFileNameRoot : 4319987da915Sopenharmony_ci case UpdateMappingPairs : 4320987da915Sopenharmony_ci case UpdateResidentValue : 4321987da915Sopenharmony_ci case Win10Action37 : 4322987da915Sopenharmony_ci case WriteEndofFileRecordSegment : 4323987da915Sopenharmony_ci kind = ON_MFT; 4324987da915Sopenharmony_ci break; 4325987da915Sopenharmony_ci /* Actions always acting on INDX */ 4326987da915Sopenharmony_ci case AddIndexEntryAllocation : 4327987da915Sopenharmony_ci case DeleteIndexEntryAllocation : 4328987da915Sopenharmony_ci case SetIndexEntryVcnAllocation : 4329987da915Sopenharmony_ci case UpdateFileNameAllocation : 4330987da915Sopenharmony_ci case WriteEndOfIndexBuffer : 4331987da915Sopenharmony_ci kind = ON_INDX; 4332987da915Sopenharmony_ci break; 4333987da915Sopenharmony_ci /* Actions never acting on MFT or INDX */ 4334987da915Sopenharmony_ci case ClearBitsInNonResidentBitMap : 4335987da915Sopenharmony_ci case SetBitsInNonResidentBitMap : 4336987da915Sopenharmony_ci kind = ON_RAW; 4337987da915Sopenharmony_ci break; 4338987da915Sopenharmony_ci /* Actions which may act on MFT */ 4339987da915Sopenharmony_ci case Noop : /* on MFT if DeallocateFileRecordSegment */ 4340987da915Sopenharmony_ci kind = ON_NONE; 4341987da915Sopenharmony_ci break; 4342987da915Sopenharmony_ci /* Actions which may act on INDX */ 4343987da915Sopenharmony_ci case UpdateNonResidentValue : 4344987da915Sopenharmony_ci /* Known cases : INDX, $SDS, ATTR_LIST */ 4345987da915Sopenharmony_ci kind = get_action_kind(action); 4346987da915Sopenharmony_ci if (kind == ON_NONE) 4347987da915Sopenharmony_ci err = 1; 4348987da915Sopenharmony_ci break; 4349987da915Sopenharmony_ci case CompensationlogRecord : 4350987da915Sopenharmony_ci case OpenNonResidentAttribute : 4351987da915Sopenharmony_ci /* probably not important */ 4352987da915Sopenharmony_ci kind = ON_NONE; 4353987da915Sopenharmony_ci break; 4354987da915Sopenharmony_ci /* Actions currently ignored */ 4355987da915Sopenharmony_ci case AttributeNamesDump : 4356987da915Sopenharmony_ci case DirtyPageTableDump : 4357987da915Sopenharmony_ci case ForgetTransaction : 4358987da915Sopenharmony_ci case OpenAttributeTableDump : 4359987da915Sopenharmony_ci case TransactionTableDump : 4360987da915Sopenharmony_ci kind = ON_NONE; 4361987da915Sopenharmony_ci break; 4362987da915Sopenharmony_ci /* Actions with no known use case */ 4363987da915Sopenharmony_ci case CommitTransaction : 4364987da915Sopenharmony_ci case DeleteDirtyClusters : 4365987da915Sopenharmony_ci case EndTopLevelAction : 4366987da915Sopenharmony_ci case HotFix : 4367987da915Sopenharmony_ci case PrepareTransaction : 4368987da915Sopenharmony_ci case UpdateRecordDataAllocation : 4369987da915Sopenharmony_ci case UpdateRecordDataRoot : 4370987da915Sopenharmony_ci case Win10Action35 : 4371987da915Sopenharmony_ci case Win10Action36 : 4372987da915Sopenharmony_ci default : 4373987da915Sopenharmony_ci err = 1; 4374987da915Sopenharmony_ci kind = ON_NONE; 4375987da915Sopenharmony_ci break; 4376987da915Sopenharmony_ci } 4377987da915Sopenharmony_ci executed = FALSE; 4378987da915Sopenharmony_ci switch (kind) { 4379987da915Sopenharmony_ci case ON_MFT : 4380987da915Sopenharmony_ci/* 4381987da915Sopenharmony_ci the check below cannot be used on WinXP 4382987da915Sopenharmony_ciif (!(action->record.attribute_flags & ACTS_ON_MFT)) 4383987da915Sopenharmony_ciprintf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num); 4384987da915Sopenharmony_ci*/ 4385987da915Sopenharmony_ci /* Check whether data is to be discarded */ 4386987da915Sopenharmony_ci warn = (rop != InitializeFileRecordSegment) 4387987da915Sopenharmony_ci || !check_full_mft(action,TRUE); 4388987da915Sopenharmony_ci buffer = read_protected(vol, &action->record, 4389987da915Sopenharmony_ci mftrecsz, warn); 4390987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 4391987da915Sopenharmony_ci if (entry && (entry->magic == magic_FILE)) { 4392987da915Sopenharmony_ci data_lsn = sle64_to_cpu(entry->lsn); 4393987da915Sopenharmony_ci /* 4394987da915Sopenharmony_ci * Beware of records not updated 4395987da915Sopenharmony_ci * during the last session which may 4396987da915Sopenharmony_ci * have a stale lsn (consequence 4397987da915Sopenharmony_ci * of ntfs-3g resetting the log) 4398987da915Sopenharmony_ci */ 4399987da915Sopenharmony_ci executed = ((s64)(data_lsn - this_lsn) >= 0) 4400987da915Sopenharmony_ci && (((s64)(data_lsn - latest_lsn)) <= 0) 4401987da915Sopenharmony_ci && !exception(action->num); 4402987da915Sopenharmony_ci } else { 4403987da915Sopenharmony_ci if (!warn) { 4404987da915Sopenharmony_ci /* Old record not needed */ 4405987da915Sopenharmony_ci if (!buffer) 4406987da915Sopenharmony_ci buffer = (char*)calloc(1, mftrecsz); 4407987da915Sopenharmony_ci if (buffer) 4408987da915Sopenharmony_ci executed = FALSE; 4409987da915Sopenharmony_ci else 4410987da915Sopenharmony_ci err = 1; 4411987da915Sopenharmony_ci } else { 4412987da915Sopenharmony_ci printf("** %s (action %d) not" 4413987da915Sopenharmony_ci " acting on MFT\n", 4414987da915Sopenharmony_ci actionname(rop), 4415987da915Sopenharmony_ci (int)action->num); 4416987da915Sopenharmony_ci err = 1; 4417987da915Sopenharmony_ci } 4418987da915Sopenharmony_ci } 4419987da915Sopenharmony_ci break; 4420987da915Sopenharmony_ci case ON_INDX : 4421987da915Sopenharmony_ci/* 4422987da915Sopenharmony_ci the check below cannot be used on WinXP 4423987da915Sopenharmony_ciif (!(action->record.attribute_flags & ACTS_ON_INDX)) 4424987da915Sopenharmony_ciprintf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num); 4425987da915Sopenharmony_ci*/ 4426987da915Sopenharmony_ci xsize = vol->indx_record_size; 4427987da915Sopenharmony_ci /* Check whether data is to be discarded */ 4428987da915Sopenharmony_ci warn = (rop != UpdateNonResidentValue) 4429987da915Sopenharmony_ci || !check_full_index(action,TRUE); 4430987da915Sopenharmony_ci buffer = read_protected(vol, &action->record, 4431987da915Sopenharmony_ci xsize, warn); 4432987da915Sopenharmony_ci indx = (INDEX_BLOCK*)buffer; 4433987da915Sopenharmony_ci if (indx && (indx->magic == magic_INDX)) { 4434987da915Sopenharmony_ci data_lsn = sle64_to_cpu(indx->lsn); 4435987da915Sopenharmony_ci /* 4436987da915Sopenharmony_ci * Beware of records not updated 4437987da915Sopenharmony_ci * during the last session which may 4438987da915Sopenharmony_ci * have a stale lsn (consequence 4439987da915Sopenharmony_ci * of ntfs-3g resetting the log) 4440987da915Sopenharmony_ci */ 4441987da915Sopenharmony_ci executed = ((s64)(data_lsn - this_lsn) >= 0) 4442987da915Sopenharmony_ci && (((s64)(data_lsn - latest_lsn)) <= 0) 4443987da915Sopenharmony_ci && ! exception(action->num); 4444987da915Sopenharmony_ci } else { 4445987da915Sopenharmony_ci if (!warn) { 4446987da915Sopenharmony_ci /* Old record not needed */ 4447987da915Sopenharmony_ci if (!buffer) 4448987da915Sopenharmony_ci buffer = (char*)calloc(1, xsize); 4449987da915Sopenharmony_ci if (buffer) 4450987da915Sopenharmony_ci executed = FALSE; 4451987da915Sopenharmony_ci else 4452987da915Sopenharmony_ci err = 1; 4453987da915Sopenharmony_ci } else { 4454987da915Sopenharmony_ci printf("** %s (action %d) not" 4455987da915Sopenharmony_ci " acting on INDX\n", 4456987da915Sopenharmony_ci actionname(rop), 4457987da915Sopenharmony_ci (int)action->num); 4458987da915Sopenharmony_ci err = 1; 4459987da915Sopenharmony_ci } 4460987da915Sopenharmony_ci } 4461987da915Sopenharmony_ci break; 4462987da915Sopenharmony_ci case ON_RAW : 4463987da915Sopenharmony_ci if (action->record.attribute_flags 4464987da915Sopenharmony_ci & (ACTS_ON_INDX | ACTS_ON_MFT)) { 4465987da915Sopenharmony_ci printf("** Error : action %s on MFT" 4466987da915Sopenharmony_ci " or INDX\n", 4467987da915Sopenharmony_ci actionname(rop)); 4468987da915Sopenharmony_ci err = 1; 4469987da915Sopenharmony_ci } else { 4470987da915Sopenharmony_ci buffer = read_raw(vol, &action->record); 4471987da915Sopenharmony_ci if (!buffer) 4472987da915Sopenharmony_ci err = 1; 4473987da915Sopenharmony_ci } 4474987da915Sopenharmony_ci break; 4475987da915Sopenharmony_ci default : 4476987da915Sopenharmony_ci buffer = (char*)NULL; 4477987da915Sopenharmony_ci break; 4478987da915Sopenharmony_ci } 4479987da915Sopenharmony_ci if (!err && (!executed || !opts)) { 4480987da915Sopenharmony_ci err = distribute_redos(vol, action, buffer); 4481987da915Sopenharmony_ci redocount++; 4482987da915Sopenharmony_ci } else { 4483987da915Sopenharmony_ci if (optv) 4484987da915Sopenharmony_ci printf("Action %d %s (%s) not redone\n", 4485987da915Sopenharmony_ci action->num, 4486987da915Sopenharmony_ci actionname(rop), 4487987da915Sopenharmony_ci actionname(uop)); 4488987da915Sopenharmony_ci } 4489987da915Sopenharmony_ci if (buffer) 4490987da915Sopenharmony_ci free(buffer); 4491987da915Sopenharmony_ci return (err); 4492987da915Sopenharmony_ci} 4493987da915Sopenharmony_ci 4494987da915Sopenharmony_ci 4495987da915Sopenharmony_ci/* 4496987da915Sopenharmony_ci * Play the redo actions from earliest to latest 4497987da915Sopenharmony_ci * 4498987da915Sopenharmony_ci * Currently we can only redo the last undone transaction, 4499987da915Sopenharmony_ci * otherwise the attribute table would be out of phase. 4500987da915Sopenharmony_ci */ 4501987da915Sopenharmony_ci 4502987da915Sopenharmony_ciint play_redos(ntfs_volume *vol, const struct ACTION_RECORD *firstaction) 4503987da915Sopenharmony_ci{ 4504987da915Sopenharmony_ci const struct ACTION_RECORD *action; 4505987da915Sopenharmony_ci int err; 4506987da915Sopenharmony_ci 4507987da915Sopenharmony_ci err = 0; 4508987da915Sopenharmony_ci action = firstaction; 4509987da915Sopenharmony_ci while (action && !err) { 4510987da915Sopenharmony_ci /* Only committed actions should be redone */ 4511987da915Sopenharmony_ci if ((!optc || within_lcn_range(&action->record)) 4512987da915Sopenharmony_ci && (action->flags & ACTION_TO_REDO)) 4513987da915Sopenharmony_ci err = play_one_redo(vol, action); 4514987da915Sopenharmony_ci if (!err) 4515987da915Sopenharmony_ci action = action->next; 4516987da915Sopenharmony_ci } 4517987da915Sopenharmony_ci return (err); 4518987da915Sopenharmony_ci} 4519987da915Sopenharmony_ci 4520987da915Sopenharmony_cistatic int distribute_undos(ntfs_volume *vol, const struct ACTION_RECORD *action, 4521987da915Sopenharmony_ci char *buffer) 4522987da915Sopenharmony_ci{ 4523987da915Sopenharmony_ci int rop, uop; 4524987da915Sopenharmony_ci int err; 4525987da915Sopenharmony_ci 4526987da915Sopenharmony_ci err = 0; 4527987da915Sopenharmony_ci rop = le16_to_cpu(action->record.redo_operation); 4528987da915Sopenharmony_ci uop = le16_to_cpu(action->record.undo_operation); 4529987da915Sopenharmony_ci switch (rop) { 4530987da915Sopenharmony_ci case AddIndexEntryAllocation : 4531987da915Sopenharmony_ci if (action->record.undo_operation 4532987da915Sopenharmony_ci == const_cpu_to_le16(DeleteIndexEntryAllocation)) 4533987da915Sopenharmony_ci err = undo_add_index(vol, action, buffer); 4534987da915Sopenharmony_ci break; 4535987da915Sopenharmony_ci case AddIndexEntryRoot : 4536987da915Sopenharmony_ci if (action->record.undo_operation 4537987da915Sopenharmony_ci == const_cpu_to_le16(DeleteIndexEntryRoot)) 4538987da915Sopenharmony_ci err = undo_add_root_index(vol, action, buffer); 4539987da915Sopenharmony_ci break; 4540987da915Sopenharmony_ci case ClearBitsInNonResidentBitMap : 4541987da915Sopenharmony_ci if (action->record.undo_operation 4542987da915Sopenharmony_ci == const_cpu_to_le16(SetBitsInNonResidentBitMap)) 4543987da915Sopenharmony_ci err = undo_force_bits(vol, action, buffer); 4544987da915Sopenharmony_ci break; 4545987da915Sopenharmony_ci case CreateAttribute : 4546987da915Sopenharmony_ci if (action->record.undo_operation 4547987da915Sopenharmony_ci == const_cpu_to_le16(DeleteAttribute)) 4548987da915Sopenharmony_ci err = undo_create_attribute(vol, action, buffer); 4549987da915Sopenharmony_ci break; 4550987da915Sopenharmony_ci case DeallocateFileRecordSegment : 4551987da915Sopenharmony_ci if (action->record.undo_operation 4552987da915Sopenharmony_ci == const_cpu_to_le16(InitializeFileRecordSegment)) 4553987da915Sopenharmony_ci err = undo_delete_file(vol, action, buffer); 4554987da915Sopenharmony_ci break; 4555987da915Sopenharmony_ci case DeleteAttribute : 4556987da915Sopenharmony_ci if (action->record.undo_operation 4557987da915Sopenharmony_ci == const_cpu_to_le16(CreateAttribute)) 4558987da915Sopenharmony_ci err = undo_delete_attribute(vol, action, buffer); 4559987da915Sopenharmony_ci break; 4560987da915Sopenharmony_ci case DeleteIndexEntryAllocation : 4561987da915Sopenharmony_ci if (action->record.undo_operation 4562987da915Sopenharmony_ci == const_cpu_to_le16(AddIndexEntryAllocation)) 4563987da915Sopenharmony_ci err = undo_delete_index(vol, action, buffer); 4564987da915Sopenharmony_ci break; 4565987da915Sopenharmony_ci case DeleteIndexEntryRoot : 4566987da915Sopenharmony_ci if (action->record.undo_operation 4567987da915Sopenharmony_ci == const_cpu_to_le16(AddIndexEntryRoot)) 4568987da915Sopenharmony_ci err = undo_delete_root_index(vol, action, buffer); 4569987da915Sopenharmony_ci break; 4570987da915Sopenharmony_ci case InitializeFileRecordSegment : 4571987da915Sopenharmony_ci if (action->record.undo_operation 4572987da915Sopenharmony_ci == const_cpu_to_le16(Noop)) 4573987da915Sopenharmony_ci err = undo_create_file(vol, action, buffer); 4574987da915Sopenharmony_ci break; 4575987da915Sopenharmony_ci case OpenNonResidentAttribute : 4576987da915Sopenharmony_ci if (action->record.undo_operation 4577987da915Sopenharmony_ci == const_cpu_to_le16(Noop)) 4578987da915Sopenharmony_ci err = undo_open_attribute(vol, action); 4579987da915Sopenharmony_ci break; 4580987da915Sopenharmony_ci case SetBitsInNonResidentBitMap : 4581987da915Sopenharmony_ci if (action->record.undo_operation 4582987da915Sopenharmony_ci == const_cpu_to_le16(ClearBitsInNonResidentBitMap)) 4583987da915Sopenharmony_ci err = undo_force_bits(vol, action, buffer); 4584987da915Sopenharmony_ci break; 4585987da915Sopenharmony_ci case SetIndexEntryVcnAllocation : 4586987da915Sopenharmony_ci if (action->record.undo_operation 4587987da915Sopenharmony_ci == const_cpu_to_le16(SetIndexEntryVcnAllocation)) 4588987da915Sopenharmony_ci err = undo_update_vcn(vol, action, buffer); 4589987da915Sopenharmony_ci break; 4590987da915Sopenharmony_ci case SetIndexEntryVcnRoot : 4591987da915Sopenharmony_ci if (action->record.undo_operation 4592987da915Sopenharmony_ci == const_cpu_to_le16(SetIndexEntryVcnRoot)) 4593987da915Sopenharmony_ci err = undo_update_root_vcn(vol, action, buffer); 4594987da915Sopenharmony_ci break; 4595987da915Sopenharmony_ci case SetNewAttributeSizes : 4596987da915Sopenharmony_ci if (action->record.undo_operation 4597987da915Sopenharmony_ci == const_cpu_to_le16(SetNewAttributeSizes)) 4598987da915Sopenharmony_ci err = undo_sizes(vol, action, buffer); 4599987da915Sopenharmony_ci break; 4600987da915Sopenharmony_ci case UpdateFileNameAllocation : 4601987da915Sopenharmony_ci if (action->record.undo_operation 4602987da915Sopenharmony_ci == const_cpu_to_le16(UpdateFileNameAllocation)) 4603987da915Sopenharmony_ci err = undo_update_index(vol, action, buffer); 4604987da915Sopenharmony_ci break; 4605987da915Sopenharmony_ci case UpdateFileNameRoot : 4606987da915Sopenharmony_ci if (action->record.undo_operation 4607987da915Sopenharmony_ci == const_cpu_to_le16(UpdateFileNameRoot)) 4608987da915Sopenharmony_ci err = undo_update_root_index(vol, action, buffer); 4609987da915Sopenharmony_ci break; 4610987da915Sopenharmony_ci case UpdateMappingPairs : 4611987da915Sopenharmony_ci if (action->record.undo_operation 4612987da915Sopenharmony_ci == const_cpu_to_le16(UpdateMappingPairs)) 4613987da915Sopenharmony_ci err = undo_update_mapping(vol, action, buffer); 4614987da915Sopenharmony_ci break; 4615987da915Sopenharmony_ci case UpdateNonResidentValue : 4616987da915Sopenharmony_ci switch (get_action_kind(action)) { 4617987da915Sopenharmony_ci case ON_INDX : 4618987da915Sopenharmony_ci err = undo_update_index_value(vol, action, buffer); 4619987da915Sopenharmony_ci break; 4620987da915Sopenharmony_ci case ON_RAW : 4621987da915Sopenharmony_ci err = undo_update_value(vol, action, buffer); 4622987da915Sopenharmony_ci break; 4623987da915Sopenharmony_ci default : 4624987da915Sopenharmony_ci printf("** Bad attribute type\n"); 4625987da915Sopenharmony_ci err = 1; 4626987da915Sopenharmony_ci } 4627987da915Sopenharmony_ci break; 4628987da915Sopenharmony_ci case UpdateResidentValue : 4629987da915Sopenharmony_ci if (action->record.undo_operation 4630987da915Sopenharmony_ci == const_cpu_to_le16(UpdateResidentValue)) 4631987da915Sopenharmony_ci err = undo_update_resident(vol, action, buffer); 4632987da915Sopenharmony_ci break; 4633987da915Sopenharmony_ci case Win10Action37 : 4634987da915Sopenharmony_ci if (action->record.undo_operation 4635987da915Sopenharmony_ci == const_cpu_to_le16(Noop)) 4636987da915Sopenharmony_ci err = undo_action37(vol, action, buffer); 4637987da915Sopenharmony_ci break; 4638987da915Sopenharmony_ci case WriteEndofFileRecordSegment : 4639987da915Sopenharmony_ci if (action->record.undo_operation 4640987da915Sopenharmony_ci == const_cpu_to_le16(WriteEndofFileRecordSegment)) 4641987da915Sopenharmony_ci err = undo_write_end(vol, action, buffer); 4642987da915Sopenharmony_ci break; 4643987da915Sopenharmony_ci case WriteEndOfIndexBuffer : 4644987da915Sopenharmony_ci if (action->record.undo_operation 4645987da915Sopenharmony_ci == const_cpu_to_le16(WriteEndOfIndexBuffer)) 4646987da915Sopenharmony_ci err = undo_write_index(vol, action, buffer); 4647987da915Sopenharmony_ci break; 4648987da915Sopenharmony_ci case AttributeNamesDump : 4649987da915Sopenharmony_ci case CompensationlogRecord : 4650987da915Sopenharmony_ci case DirtyPageTableDump : 4651987da915Sopenharmony_ci case ForgetTransaction : 4652987da915Sopenharmony_ci case Noop : 4653987da915Sopenharmony_ci case OpenAttributeTableDump : 4654987da915Sopenharmony_ci break; 4655987da915Sopenharmony_ci default : 4656987da915Sopenharmony_ci printf("** Unsupported undo %s\n", actionname(rop)); 4657987da915Sopenharmony_ci err = 1; 4658987da915Sopenharmony_ci break; 4659987da915Sopenharmony_ci } 4660987da915Sopenharmony_ci if (err) 4661987da915Sopenharmony_ci printf("* Undoing action %d %s (%s) failed\n", 4662987da915Sopenharmony_ci action->num,actionname(rop), actionname(uop)); 4663987da915Sopenharmony_ci return (err); 4664987da915Sopenharmony_ci} 4665987da915Sopenharmony_ci 4666987da915Sopenharmony_ci/* 4667987da915Sopenharmony_ci * Undo a single action 4668987da915Sopenharmony_ci * 4669987da915Sopenharmony_ci * The record the action acts on is read and, when it is an MFT or 4670987da915Sopenharmony_ci * INDX one, the need for undoing is checked. 4671987da915Sopenharmony_ci */ 4672987da915Sopenharmony_ci 4673987da915Sopenharmony_cistatic int play_one_undo(ntfs_volume *vol, const struct ACTION_RECORD *action) 4674987da915Sopenharmony_ci{ 4675987da915Sopenharmony_ci MFT_RECORD *entry; 4676987da915Sopenharmony_ci INDEX_BLOCK *indx; 4677987da915Sopenharmony_ci char *buffer; 4678987da915Sopenharmony_ci u32 xsize; 4679987da915Sopenharmony_ci u16 rop; 4680987da915Sopenharmony_ci u16 uop; 4681987da915Sopenharmony_ci int err; 4682987da915Sopenharmony_ci BOOL executed; 4683987da915Sopenharmony_ci enum ACTION_KIND kind; 4684987da915Sopenharmony_ci 4685987da915Sopenharmony_ci err = 0; 4686987da915Sopenharmony_ci rop = le16_to_cpu(action->record.redo_operation); 4687987da915Sopenharmony_ci uop = le16_to_cpu(action->record.undo_operation); 4688987da915Sopenharmony_ci if (optv) 4689987da915Sopenharmony_ci printf("Undo action %d %s (%s) lsn 0x%llx\n", 4690987da915Sopenharmony_ci action->num, 4691987da915Sopenharmony_ci actionname(rop), actionname(uop), 4692987da915Sopenharmony_ci (long long)sle64_to_cpu( 4693987da915Sopenharmony_ci action->record.this_lsn)); 4694987da915Sopenharmony_ci buffer = (char*)NULL; 4695987da915Sopenharmony_ci executed = FALSE; 4696987da915Sopenharmony_ci kind = ON_NONE; 4697987da915Sopenharmony_ci switch (rop) { 4698987da915Sopenharmony_ci /* Actions always acting on MFT */ 4699987da915Sopenharmony_ci case AddIndexEntryRoot : 4700987da915Sopenharmony_ci case CreateAttribute : 4701987da915Sopenharmony_ci case DeallocateFileRecordSegment : 4702987da915Sopenharmony_ci case DeleteAttribute : 4703987da915Sopenharmony_ci case DeleteIndexEntryRoot : 4704987da915Sopenharmony_ci case InitializeFileRecordSegment : 4705987da915Sopenharmony_ci case SetIndexEntryVcnRoot : 4706987da915Sopenharmony_ci case SetNewAttributeSizes : 4707987da915Sopenharmony_ci case UpdateFileNameRoot : 4708987da915Sopenharmony_ci case UpdateMappingPairs : 4709987da915Sopenharmony_ci case UpdateResidentValue : 4710987da915Sopenharmony_ci case Win10Action37 : 4711987da915Sopenharmony_ci case WriteEndofFileRecordSegment : 4712987da915Sopenharmony_ci kind = ON_MFT; 4713987da915Sopenharmony_ci break; 4714987da915Sopenharmony_ci /* Actions always acting on INDX */ 4715987da915Sopenharmony_ci case AddIndexEntryAllocation : 4716987da915Sopenharmony_ci case DeleteIndexEntryAllocation : 4717987da915Sopenharmony_ci case SetIndexEntryVcnAllocation : 4718987da915Sopenharmony_ci case UpdateFileNameAllocation : 4719987da915Sopenharmony_ci case WriteEndOfIndexBuffer : 4720987da915Sopenharmony_ci kind = ON_INDX; 4721987da915Sopenharmony_ci break; 4722987da915Sopenharmony_ci /* Actions never acting on MFT or INDX */ 4723987da915Sopenharmony_ci case ClearBitsInNonResidentBitMap : 4724987da915Sopenharmony_ci case SetBitsInNonResidentBitMap : 4725987da915Sopenharmony_ci kind = ON_RAW; 4726987da915Sopenharmony_ci break; 4727987da915Sopenharmony_ci /* Actions which may act on MFT */ 4728987da915Sopenharmony_ci case Noop : /* on MFT if DeallocateFileRecordSegment */ 4729987da915Sopenharmony_ci break; 4730987da915Sopenharmony_ci /* Actions which may act on INDX */ 4731987da915Sopenharmony_ci case UpdateNonResidentValue : 4732987da915Sopenharmony_ci /* Known cases : INDX, $SDS, ATTR_LIST */ 4733987da915Sopenharmony_ci kind = get_action_kind(action); 4734987da915Sopenharmony_ci if (kind == ON_NONE) 4735987da915Sopenharmony_ci err = 1; 4736987da915Sopenharmony_ci break; 4737987da915Sopenharmony_ci case OpenNonResidentAttribute : 4738987da915Sopenharmony_ci /* probably not important */ 4739987da915Sopenharmony_ci kind = ON_NONE; 4740987da915Sopenharmony_ci break; 4741987da915Sopenharmony_ci /* Actions currently ignored */ 4742987da915Sopenharmony_ci case AttributeNamesDump : 4743987da915Sopenharmony_ci case CommitTransaction : 4744987da915Sopenharmony_ci case CompensationlogRecord : 4745987da915Sopenharmony_ci case DeleteDirtyClusters : 4746987da915Sopenharmony_ci case DirtyPageTableDump : 4747987da915Sopenharmony_ci case EndTopLevelAction : 4748987da915Sopenharmony_ci case ForgetTransaction : 4749987da915Sopenharmony_ci case HotFix : 4750987da915Sopenharmony_ci case OpenAttributeTableDump : 4751987da915Sopenharmony_ci case PrepareTransaction : 4752987da915Sopenharmony_ci case TransactionTableDump : 4753987da915Sopenharmony_ci case UpdateRecordDataAllocation : 4754987da915Sopenharmony_ci case UpdateRecordDataRoot : 4755987da915Sopenharmony_ci case Win10Action35 : 4756987da915Sopenharmony_ci case Win10Action36 : 4757987da915Sopenharmony_ci kind = ON_NONE; 4758987da915Sopenharmony_ci break; 4759987da915Sopenharmony_ci } 4760987da915Sopenharmony_ci switch (kind) { 4761987da915Sopenharmony_ci case ON_MFT : 4762987da915Sopenharmony_ci/* 4763987da915Sopenharmony_ci the check below cannot be used on WinXP 4764987da915Sopenharmony_ciif (!(action->record.attribute_flags & ACTS_ON_MFT)) 4765987da915Sopenharmony_ciprintf("** %s (action %d) not acting on MFT\n",actionname(rop),(int)action->num); 4766987da915Sopenharmony_ci*/ 4767987da915Sopenharmony_ci buffer = read_protected(vol, &action->record, mftrecsz, TRUE); 4768987da915Sopenharmony_ci entry = (MFT_RECORD*)buffer; 4769987da915Sopenharmony_ci if (entry) { 4770987da915Sopenharmony_ci if (entry->magic == magic_FILE) { 4771987da915Sopenharmony_ci executed = !older_record(entry, 4772987da915Sopenharmony_ci &action->record); 4773987da915Sopenharmony_ci if (!executed 4774987da915Sopenharmony_ci && exception(action->num)) 4775987da915Sopenharmony_ci executed = TRUE; 4776987da915Sopenharmony_ciif (optv > 1) 4777987da915Sopenharmony_ciprintf("record lsn 0x%llx is %s than action %d lsn 0x%llx\n", 4778987da915Sopenharmony_ci(long long)sle64_to_cpu(entry->lsn), 4779987da915Sopenharmony_ci(executed ? "not older" : "older"), 4780987da915Sopenharmony_ci(int)action->num, 4781987da915Sopenharmony_ci(long long)sle64_to_cpu(action->record.this_lsn)); 4782987da915Sopenharmony_ci } else { 4783987da915Sopenharmony_ci printf("** %s (action %d) not acting on MFT\n", 4784987da915Sopenharmony_ci actionname(rop), (int)action->num); 4785987da915Sopenharmony_ci err = 1; 4786987da915Sopenharmony_ci } 4787987da915Sopenharmony_ci } else { 4788987da915Sopenharmony_ci /* 4789987da915Sopenharmony_ci * Could not read the MFT record : 4790987da915Sopenharmony_ci * if this is undoing a record create (from scratch) 4791987da915Sopenharmony_ci * which did not take place, there is nothing to redo, 4792987da915Sopenharmony_ci * otherwise this is an error. 4793987da915Sopenharmony_ci */ 4794987da915Sopenharmony_ci if (check_full_mft(action,TRUE)) 4795987da915Sopenharmony_ci executed = FALSE; 4796987da915Sopenharmony_ci else 4797987da915Sopenharmony_ci err = 1; 4798987da915Sopenharmony_ci } 4799987da915Sopenharmony_ci break; 4800987da915Sopenharmony_ci case ON_INDX : 4801987da915Sopenharmony_ci/* 4802987da915Sopenharmony_ci the check below cannot be used on WinXP 4803987da915Sopenharmony_ciif (!(action->record.attribute_flags & ACTS_ON_INDX)) 4804987da915Sopenharmony_ciprintf("** %s (action %d) not acting on INDX\n",actionname(rop),(int)action->num); 4805987da915Sopenharmony_ci*/ 4806987da915Sopenharmony_ci xsize = vol->indx_record_size; 4807987da915Sopenharmony_ci buffer = read_protected(vol, &action->record, xsize, TRUE); 4808987da915Sopenharmony_ci indx = (INDEX_BLOCK*)buffer; 4809987da915Sopenharmony_ci if (indx) { 4810987da915Sopenharmony_ci if (indx->magic == magic_INDX) { 4811987da915Sopenharmony_ci executed = !older_record(indx, 4812987da915Sopenharmony_ci &action->record); 4813987da915Sopenharmony_ci if (!executed 4814987da915Sopenharmony_ci && exception(action->num)) 4815987da915Sopenharmony_ci executed = TRUE; 4816987da915Sopenharmony_ciif (optv > 1) 4817987da915Sopenharmony_ciprintf("index lsn 0x%llx is %s than action %d lsn 0x%llx\n", 4818987da915Sopenharmony_ci(long long)sle64_to_cpu(indx->lsn), 4819987da915Sopenharmony_ci(executed ? "not older" : "older"), 4820987da915Sopenharmony_ci(int)action->num, 4821987da915Sopenharmony_ci(long long)sle64_to_cpu(action->record.this_lsn)); 4822987da915Sopenharmony_ci } else { 4823987da915Sopenharmony_ci printf("** %s (action %d) not acting on INDX\n", 4824987da915Sopenharmony_ci actionname(rop), (int)action->num); 4825987da915Sopenharmony_ci err = 1; 4826987da915Sopenharmony_ci } 4827987da915Sopenharmony_ci } else { 4828987da915Sopenharmony_ci /* 4829987da915Sopenharmony_ci * Could not read the INDX record : 4830987da915Sopenharmony_ci * if this is undoing a record create (from scratch) 4831987da915Sopenharmony_ci * which did not take place, there is nothing to redo, 4832987da915Sopenharmony_ci * otherwise this must be an error. 4833987da915Sopenharmony_ci * However, after deleting the last index allocation 4834987da915Sopenharmony_ci * in a block, the block is apparently zeroed 4835987da915Sopenharmony_ci * and cannot be read. In this case we have to 4836987da915Sopenharmony_ci * create an initial index block and apply the undo. 4837987da915Sopenharmony_ci */ 4838987da915Sopenharmony_ci if (check_full_index(action,TRUE)) 4839987da915Sopenharmony_ci executed = FALSE; 4840987da915Sopenharmony_ci else { 4841987da915Sopenharmony_ci err = 1; 4842987da915Sopenharmony_ci if (uop == AddIndexEntryAllocation) { 4843987da915Sopenharmony_ci executed = TRUE; 4844987da915Sopenharmony_ci buffer = (char*)calloc(1, xsize); 4845987da915Sopenharmony_ci if (buffer) 4846987da915Sopenharmony_ci err = create_indx(vol, 4847987da915Sopenharmony_ci action, buffer); 4848987da915Sopenharmony_ci } 4849987da915Sopenharmony_ci } 4850987da915Sopenharmony_ci } 4851987da915Sopenharmony_ci break; 4852987da915Sopenharmony_ci case ON_RAW : 4853987da915Sopenharmony_ci if (action->record.attribute_flags 4854987da915Sopenharmony_ci & (ACTS_ON_INDX | ACTS_ON_MFT)) { 4855987da915Sopenharmony_ci printf("** Error : action %s on MFT or INDX\n", 4856987da915Sopenharmony_ci actionname(rop)); 4857987da915Sopenharmony_ci err = 1; 4858987da915Sopenharmony_ci } else { 4859987da915Sopenharmony_ci buffer = read_raw(vol, &action->record); 4860987da915Sopenharmony_ci if (!buffer) 4861987da915Sopenharmony_ci err = 1; 4862987da915Sopenharmony_ci } 4863987da915Sopenharmony_ci executed = TRUE; 4864987da915Sopenharmony_ci break; 4865987da915Sopenharmony_ci default : 4866987da915Sopenharmony_ci executed = TRUE; 4867987da915Sopenharmony_ci buffer = (char*)NULL; 4868987da915Sopenharmony_ci break; 4869987da915Sopenharmony_ci } 4870987da915Sopenharmony_ci if (!err && executed) { 4871987da915Sopenharmony_ci err = distribute_undos(vol, action, buffer); 4872987da915Sopenharmony_ci undocount++; 4873987da915Sopenharmony_ci } 4874987da915Sopenharmony_ci if (buffer) 4875987da915Sopenharmony_ci free(buffer); 4876987da915Sopenharmony_ci 4877987da915Sopenharmony_ci return (err); 4878987da915Sopenharmony_ci} 4879987da915Sopenharmony_ci 4880987da915Sopenharmony_ci/* 4881987da915Sopenharmony_ci * Play the undo actions from latest to earliest 4882987da915Sopenharmony_ci * 4883987da915Sopenharmony_ci * For structured record, a check is made on the lsn to only 4884987da915Sopenharmony_ci * try to undo the actions which were executed. This implies 4885987da915Sopenharmony_ci * identifying actions on a structured record. 4886987da915Sopenharmony_ci * 4887987da915Sopenharmony_ci * Returns 0 if successful 4888987da915Sopenharmony_ci */ 4889987da915Sopenharmony_ci 4890987da915Sopenharmony_ciint play_undos(ntfs_volume *vol, const struct ACTION_RECORD *lastaction) 4891987da915Sopenharmony_ci{ 4892987da915Sopenharmony_ci const struct ACTION_RECORD *action; 4893987da915Sopenharmony_ci int err; 4894987da915Sopenharmony_ci 4895987da915Sopenharmony_ci err = 0; 4896987da915Sopenharmony_ci action = lastaction; 4897987da915Sopenharmony_ci while (action && !err) { 4898987da915Sopenharmony_ci if (!optc || within_lcn_range(&action->record)) 4899987da915Sopenharmony_ci err = play_one_undo(vol, action); 4900987da915Sopenharmony_ci if (!err) 4901987da915Sopenharmony_ci action = action->prev; 4902987da915Sopenharmony_ci } 4903987da915Sopenharmony_ci return (err); 4904987da915Sopenharmony_ci} 4905