1987da915Sopenharmony_ci/* 2987da915Sopenharmony_ci * Process log data from an NTFS partition 3987da915Sopenharmony_ci * 4987da915Sopenharmony_ci * Copyright (c) 2012-2017 Jean-Pierre Andre 5987da915Sopenharmony_ci * 6987da915Sopenharmony_ci * This program examines the Windows log file of an ntfs partition 7987da915Sopenharmony_ci * and plays the committed transactions in order to restore the 8987da915Sopenharmony_ci * integrity of metadata. 9987da915Sopenharmony_ci * 10987da915Sopenharmony_ci * It can also display the contents of the log file in human-readable 11987da915Sopenharmony_ci * text, either from a full partition or from the log file itself. 12987da915Sopenharmony_ci * 13987da915Sopenharmony_ci * 14987da915Sopenharmony_ci * History 15987da915Sopenharmony_ci * 16987da915Sopenharmony_ci * Sep 2012 17987da915Sopenharmony_ci * - displayed textual logfile contents forward 18987da915Sopenharmony_ci * 19987da915Sopenharmony_ci * Nov 2014 20987da915Sopenharmony_ci * - decoded multi-page log records 21987da915Sopenharmony_ci * - displayed textual logfile contents backward 22987da915Sopenharmony_ci * 23987da915Sopenharmony_ci * Nov 2015 24987da915Sopenharmony_ci * - made a general cleaning and redesigned as an ntfsprogs 25987da915Sopenharmony_ci * - applied committed actions from logfile 26987da915Sopenharmony_ci */ 27987da915Sopenharmony_ci 28987da915Sopenharmony_ci/* 29987da915Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 30987da915Sopenharmony_ci * it under the terms of the GNU General Public License as published by 31987da915Sopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 32987da915Sopenharmony_ci * (at your option) any later version. 33987da915Sopenharmony_ci * 34987da915Sopenharmony_ci * This program is distributed in the hope that it will be useful, 35987da915Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 36987da915Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 37987da915Sopenharmony_ci * GNU General Public License for more details. 38987da915Sopenharmony_ci * 39987da915Sopenharmony_ci * You should have received a copy of the GNU General Public License 40987da915Sopenharmony_ci * along with this program (in the main directory of the NTFS-3G 41987da915Sopenharmony_ci * distribution in the file COPYING); if not, write to the Free Software 42987da915Sopenharmony_ci * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 43987da915Sopenharmony_ci */ 44987da915Sopenharmony_ci 45987da915Sopenharmony_ci#define BASEBLKS 4 /* number of special blocks (always shown) */ 46987da915Sopenharmony_ci#define BASEBLKS2 34 /* number of special blocks when version >= 2.0 */ 47987da915Sopenharmony_ci#define RSTBLKS 2 /* number of restart blocks */ 48987da915Sopenharmony_ci#define BUFFERCNT 64 /* number of block buffers - a power of 2 */ 49987da915Sopenharmony_ci#define NTFSBLKLTH 512 /* usa block size */ 50987da915Sopenharmony_ci#define SHOWATTRS 20 /* max attrs shown in a dump */ 51987da915Sopenharmony_ci#define SHOWLISTS 10 /* max lcn or lsn shown in a list */ 52987da915Sopenharmony_ci#define BLOCKBITS 9 /* This is only used to read the restart page */ 53987da915Sopenharmony_ci#define MAXEXCEPTION 10 /* Max number of exceptions (option -x) */ 54987da915Sopenharmony_ci#define MINRECSIZE 48 /* Minimal log record size */ 55987da915Sopenharmony_ci#define MAXRECSIZE 65536 /* Maximal log record size (seen > 56000) */ 56987da915Sopenharmony_ci 57987da915Sopenharmony_ci#include "config.h" 58987da915Sopenharmony_ci 59987da915Sopenharmony_ci#ifdef HAVE_STDLIB_H 60987da915Sopenharmony_ci#include <stdlib.h> 61987da915Sopenharmony_ci#endif 62987da915Sopenharmony_ci#ifdef HAVE_STDIO_H 63987da915Sopenharmony_ci#include <stdio.h> 64987da915Sopenharmony_ci#endif 65987da915Sopenharmony_ci#ifdef HAVE_UNISTD_H 66987da915Sopenharmony_ci#include <unistd.h> 67987da915Sopenharmony_ci#endif 68987da915Sopenharmony_ci#ifdef HAVE_FCNTL_H 69987da915Sopenharmony_ci#include <fcntl.h> 70987da915Sopenharmony_ci#endif 71987da915Sopenharmony_ci#ifdef HAVE_ERRNO_H 72987da915Sopenharmony_ci#include <errno.h> 73987da915Sopenharmony_ci#endif 74987da915Sopenharmony_ci#ifdef HAVE_STRING_H 75987da915Sopenharmony_ci#include <string.h> 76987da915Sopenharmony_ci#endif 77987da915Sopenharmony_ci#ifdef HAVE_GETOPT_H 78987da915Sopenharmony_ci#include <getopt.h> 79987da915Sopenharmony_ci#endif 80987da915Sopenharmony_ci#ifdef HAVE_MALLOC_H 81987da915Sopenharmony_ci#include <malloc.h> 82987da915Sopenharmony_ci#endif 83987da915Sopenharmony_ci#ifdef HAVE_TIME_H 84987da915Sopenharmony_ci#include <time.h> 85987da915Sopenharmony_ci#endif 86987da915Sopenharmony_ci 87987da915Sopenharmony_ci#include "types.h" 88987da915Sopenharmony_ci#include "endians.h" 89987da915Sopenharmony_ci#include "support.h" 90987da915Sopenharmony_ci#include "layout.h" 91987da915Sopenharmony_ci#include "param.h" 92987da915Sopenharmony_ci#include "ntfstime.h" 93987da915Sopenharmony_ci#include "device_io.h" 94987da915Sopenharmony_ci#include "device.h" 95987da915Sopenharmony_ci#include "logging.h" 96987da915Sopenharmony_ci#include "runlist.h" 97987da915Sopenharmony_ci#include "mft.h" 98987da915Sopenharmony_ci#include "inode.h" 99987da915Sopenharmony_ci#include "attrib.h" 100987da915Sopenharmony_ci#include "bitmap.h" 101987da915Sopenharmony_ci#include "index.h" 102987da915Sopenharmony_ci#include "volume.h" 103987da915Sopenharmony_ci#include "unistr.h" 104987da915Sopenharmony_ci#include "mst.h" 105987da915Sopenharmony_ci#include "logfile.h" 106987da915Sopenharmony_ci#include "ntfsrecover.h" 107987da915Sopenharmony_ci#include "utils.h" 108987da915Sopenharmony_ci#include "misc.h" 109987da915Sopenharmony_ci 110987da915Sopenharmony_citypedef struct { 111987da915Sopenharmony_ci ntfs_volume *vol; 112987da915Sopenharmony_ci FILE *file; 113987da915Sopenharmony_ci struct ACTION_RECORD *firstaction; 114987da915Sopenharmony_ci struct ACTION_RECORD *lastaction; 115987da915Sopenharmony_ci} CONTEXT; 116987da915Sopenharmony_ci 117987da915Sopenharmony_citypedef enum { T_OK, T_ERR, T_DONE } TRISTATE; 118987da915Sopenharmony_ci 119987da915Sopenharmony_ciRESTART_PAGE_HEADER log_header; 120987da915Sopenharmony_ciRESTART_AREA restart; 121987da915Sopenharmony_ciLOG_CLIENT_RECORD client; 122987da915Sopenharmony_ciu32 clustersz = 0; 123987da915Sopenharmony_ciint clusterbits; 124987da915Sopenharmony_ciu32 blocksz; 125987da915Sopenharmony_ciint blockbits; 126987da915Sopenharmony_ciint log_major; 127987da915Sopenharmony_ciu16 bytespersect; 128987da915Sopenharmony_ciu64 mftlcn; 129987da915Sopenharmony_ciu32 mftrecsz; 130987da915Sopenharmony_ciint mftrecbits; 131987da915Sopenharmony_ciu32 mftcnt; /* number of entries */ 132987da915Sopenharmony_cintfs_inode *log_ni; 133987da915Sopenharmony_cintfs_attr *log_na; 134987da915Sopenharmony_ciu64 logfilelcn; 135987da915Sopenharmony_ciu32 logfilesz; /* bytes */ 136987da915Sopenharmony_ciu64 redos_met; 137987da915Sopenharmony_ciu64 committed_lsn; 138987da915Sopenharmony_ciu64 synced_lsn; 139987da915Sopenharmony_ciu64 latest_lsn; 140987da915Sopenharmony_ciu64 restart_lsn; 141987da915Sopenharmony_ciu64 offset_mask; /* block number in an lsn */ 142987da915Sopenharmony_ciunsigned long firstblk; /* first block to dump (option -r) */ 143987da915Sopenharmony_ciunsigned long lastblk; /* last block to dump (option -r) */ 144987da915Sopenharmony_ciu64 firstlcn; /* first block to dump (option -c) */ 145987da915Sopenharmony_ciu64 lastlcn; /* last block to dump (option -c) */ 146987da915Sopenharmony_ciBOOL optb; /* show the log backward */ 147987da915Sopenharmony_ciBOOL optc; /* restrict to cluster range */ 148987da915Sopenharmony_ciBOOL optd; /* device argument present*/ 149987da915Sopenharmony_ciBOOL opth; /* show help */ 150987da915Sopenharmony_ciBOOL opti; /* show invalid (stale) records */ 151987da915Sopenharmony_ciBOOL optf; /* show full log */ 152987da915Sopenharmony_ciBOOL optk; /* kill fast restart */ 153987da915Sopenharmony_ciBOOL optn; /* do not apply modifications */ 154987da915Sopenharmony_ciBOOL optp; /* count of transaction sets to play */ 155987da915Sopenharmony_ciBOOL optr; /* show a range of blocks */ 156987da915Sopenharmony_ciint opts; /* sync the file system */ 157987da915Sopenharmony_ciBOOL optt; /* show transactions */ 158987da915Sopenharmony_ciBOOL optu; /* count of transaction sets to undo */ 159987da915Sopenharmony_ciint optv; /* verbose */ 160987da915Sopenharmony_ciint optV; /* version */ 161987da915Sopenharmony_ciint optx[MAXEXCEPTION + 1]; 162987da915Sopenharmony_cistruct ATTR **attrtable; 163987da915Sopenharmony_ciunsigned int actionnum; 164987da915Sopenharmony_ciunsigned int attrcount; 165987da915Sopenharmony_ciunsigned int playcount; 166987da915Sopenharmony_ciunsigned int playedactions; // change the name 167987da915Sopenharmony_ciunsigned int redocount; 168987da915Sopenharmony_ciunsigned int undocount; 169987da915Sopenharmony_cistruct BUFFER *buffer_table[BASEBLKS + BUFFERCNT]; 170987da915Sopenharmony_ciunsigned int redirect[BASEBLKS2]; 171987da915Sopenharmony_ci 172987da915Sopenharmony_cistatic const le16 SDS[4] = { 173987da915Sopenharmony_ci const_cpu_to_le16('$'), const_cpu_to_le16('S'), 174987da915Sopenharmony_ci const_cpu_to_le16('D'), const_cpu_to_le16('S') 175987da915Sopenharmony_ci} ; 176987da915Sopenharmony_ci 177987da915Sopenharmony_cistatic const le16 I30[4] = { 178987da915Sopenharmony_ci const_cpu_to_le16('$'), const_cpu_to_le16('I'), 179987da915Sopenharmony_ci const_cpu_to_le16('3'), const_cpu_to_le16('0') 180987da915Sopenharmony_ci} ; 181987da915Sopenharmony_ci 182987da915Sopenharmony_ci/* 183987da915Sopenharmony_ci * Byte address of a log block 184987da915Sopenharmony_ci */ 185987da915Sopenharmony_ci 186987da915Sopenharmony_cistatic s64 loclogblk(CONTEXT *ctx, unsigned int blk) 187987da915Sopenharmony_ci{ 188987da915Sopenharmony_ci s64 loc; 189987da915Sopenharmony_ci LCN lcn; 190987da915Sopenharmony_ci 191987da915Sopenharmony_ci if (ctx->vol) { 192987da915Sopenharmony_ci lcn = ntfs_attr_vcn_to_lcn(log_na, 193987da915Sopenharmony_ci ((s64)blk << blockbits) >> clusterbits); 194987da915Sopenharmony_ci loc = lcn << clusterbits; 195987da915Sopenharmony_ci } else { 196987da915Sopenharmony_ci if (((s64)blk << blockbits) >= logfilesz) 197987da915Sopenharmony_ci loc = -1; 198987da915Sopenharmony_ci else 199987da915Sopenharmony_ci loc = (logfilelcn << clusterbits) 200987da915Sopenharmony_ci + ((s64)blk << blockbits); 201987da915Sopenharmony_ci } 202987da915Sopenharmony_ci return (loc); 203987da915Sopenharmony_ci} 204987da915Sopenharmony_ci 205987da915Sopenharmony_ci/* 206987da915Sopenharmony_ci * Deprotect a block 207987da915Sopenharmony_ci * Only to be used for log buffers 208987da915Sopenharmony_ci * 209987da915Sopenharmony_ci * Returns 0 if block was found correct 210987da915Sopenharmony_ci */ 211987da915Sopenharmony_ci 212987da915Sopenharmony_cistatic int replaceusa(struct BUFFER *buffer, unsigned int lth) 213987da915Sopenharmony_ci{ 214987da915Sopenharmony_ci char *buf; 215987da915Sopenharmony_ci RECORD_PAGE_HEADER *record; 216987da915Sopenharmony_ci unsigned int j; 217987da915Sopenharmony_ci BOOL err; 218987da915Sopenharmony_ci unsigned int used; 219987da915Sopenharmony_ci unsigned int xusa, nusa; 220987da915Sopenharmony_ci 221987da915Sopenharmony_ci err = FALSE; 222987da915Sopenharmony_ci /* Restart blocks have no protection */ 223987da915Sopenharmony_ci if (buffer->num >= RSTBLKS) { 224987da915Sopenharmony_ci /* Do not check beyond used sectors */ 225987da915Sopenharmony_ci record = &buffer->block.record; 226987da915Sopenharmony_ci used = blocksz; 227987da915Sopenharmony_ci xusa = le16_to_cpu(record->usa_ofs); 228987da915Sopenharmony_ci nusa = le16_to_cpu(record->usa_count); 229987da915Sopenharmony_ci if (xusa && nusa 230987da915Sopenharmony_ci && ((xusa + 1) < lth) 231987da915Sopenharmony_ci && ((nusa - 1)*NTFSBLKLTH == lth)) { 232987da915Sopenharmony_ci buf = buffer->block.data; 233987da915Sopenharmony_ci for (j=1; (j<nusa) && ((j-1)*NTFSBLKLTH<used); j++) 234987da915Sopenharmony_ci if ((buf[xusa] == buf[j*NTFSBLKLTH - 2]) 235987da915Sopenharmony_ci && (buf[xusa+1] == buf[j*NTFSBLKLTH - 1])) { 236987da915Sopenharmony_ci buf[j*NTFSBLKLTH - 2] = buf[xusa + 2*j]; 237987da915Sopenharmony_ci buf[j*NTFSBLKLTH - 1] = buf[xusa + 2*j + 1]; 238987da915Sopenharmony_ci } else { 239987da915Sopenharmony_ci printf("* Update sequence number %d does not match\n",j); 240987da915Sopenharmony_ci err = TRUE; 241987da915Sopenharmony_ci } 242987da915Sopenharmony_ci } 243987da915Sopenharmony_ci } 244987da915Sopenharmony_ci return (err); 245987da915Sopenharmony_ci } 246987da915Sopenharmony_ci 247987da915Sopenharmony_ci/* 248987da915Sopenharmony_ci * Dynamically allocate an attribute key. 249987da915Sopenharmony_ci * 250987da915Sopenharmony_ci * As the possible values for a key depend on the version, we 251987da915Sopenharmony_ci * cannot convert it to an index, so we make dichotomical searches 252987da915Sopenharmony_ci */ 253987da915Sopenharmony_ci 254987da915Sopenharmony_cistruct ATTR *getattrentry(unsigned int key, unsigned int lth) 255987da915Sopenharmony_ci{ 256987da915Sopenharmony_ci struct ATTR *pa; 257987da915Sopenharmony_ci struct ATTR **old; 258987da915Sopenharmony_ci unsigned int low, mid, high; 259987da915Sopenharmony_ci 260987da915Sopenharmony_ci low = 0; 261987da915Sopenharmony_ci if (attrcount) { 262987da915Sopenharmony_ci high = attrcount; 263987da915Sopenharmony_ci while ((low + 1) < high) { 264987da915Sopenharmony_ci mid = (low + high) >> 1; 265987da915Sopenharmony_ci if (key < attrtable[mid]->key) 266987da915Sopenharmony_ci high = mid; 267987da915Sopenharmony_ci else 268987da915Sopenharmony_ci if (key > attrtable[mid]->key) 269987da915Sopenharmony_ci low = mid; 270987da915Sopenharmony_ci else { 271987da915Sopenharmony_ci low = mid; 272987da915Sopenharmony_ci high = mid + 1; 273987da915Sopenharmony_ci } 274987da915Sopenharmony_ci } 275987da915Sopenharmony_ci } 276987da915Sopenharmony_ci if ((low < attrcount) && (attrtable[low]->key == key)) { 277987da915Sopenharmony_ci pa = attrtable[low]; 278987da915Sopenharmony_ci if (pa->namelen < lth) { 279987da915Sopenharmony_ci pa = (struct ATTR*)realloc(pa, 280987da915Sopenharmony_ci sizeof(struct ATTR) + lth); 281987da915Sopenharmony_ci attrtable[low] = pa; 282987da915Sopenharmony_ci } 283987da915Sopenharmony_ci } else { 284987da915Sopenharmony_ci mid = low + 1; 285987da915Sopenharmony_ci if (!low && attrcount && (attrtable[0]->key > key)) 286987da915Sopenharmony_ci mid = 0; 287987da915Sopenharmony_ci pa = (struct ATTR*)malloc(sizeof(struct ATTR) + lth); 288987da915Sopenharmony_ci if (pa) { 289987da915Sopenharmony_ci if (attrcount++) { 290987da915Sopenharmony_ci old = attrtable; 291987da915Sopenharmony_ci attrtable = (struct ATTR**)realloc(attrtable, 292987da915Sopenharmony_ci attrcount*sizeof(struct ATTR*)); 293987da915Sopenharmony_ci if (attrtable) { 294987da915Sopenharmony_ci high = attrcount; 295987da915Sopenharmony_ci while (--high > mid) 296987da915Sopenharmony_ci attrtable[high] 297987da915Sopenharmony_ci = attrtable[high - 1]; 298987da915Sopenharmony_ci attrtable[mid] = pa; 299987da915Sopenharmony_ci } else 300987da915Sopenharmony_ci attrtable = old; 301987da915Sopenharmony_ci } else { 302987da915Sopenharmony_ci attrtable = (struct ATTR**) 303987da915Sopenharmony_ci malloc(sizeof(struct ATTR*)); 304987da915Sopenharmony_ci attrtable[0] = pa; 305987da915Sopenharmony_ci } 306987da915Sopenharmony_ci pa->key = key; 307987da915Sopenharmony_ci pa->namelen = 0; 308987da915Sopenharmony_ci pa->type = const_cpu_to_le32(0); 309987da915Sopenharmony_ci pa->inode = 0; 310987da915Sopenharmony_ci } 311987da915Sopenharmony_ci } 312987da915Sopenharmony_ci return (pa); 313987da915Sopenharmony_ci} 314987da915Sopenharmony_ci 315987da915Sopenharmony_ci/* 316987da915Sopenharmony_ci * Read blocks in a circular buffer 317987da915Sopenharmony_ci * 318987da915Sopenharmony_ci * returns NULL if block cannot be read or it is found bad 319987da915Sopenharmony_ci * otherwise returns the full unprotected block data 320987da915Sopenharmony_ci */ 321987da915Sopenharmony_ci 322987da915Sopenharmony_cistatic const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num) 323987da915Sopenharmony_ci{ 324987da915Sopenharmony_ci struct BUFFER *buffer; 325987da915Sopenharmony_ci BOOL got; 326987da915Sopenharmony_ci int k; 327987da915Sopenharmony_ci unsigned int rnum; 328987da915Sopenharmony_ci 329987da915Sopenharmony_ci /* 330987da915Sopenharmony_ci * The first four blocks are stored apart, to make 331987da915Sopenharmony_ci * sure pages 2 and 3 and the page which is logically 332987da915Sopenharmony_ci * before them can be accessed at the same time. 333987da915Sopenharmony_ci * (Only two blocks are stored apart if version >= 2.0) 334987da915Sopenharmony_ci * Also, block 0 is smaller because it has to be read 335987da915Sopenharmony_ci * before the block size is known. 336987da915Sopenharmony_ci * Note : the last block is supposed to have an odd 337987da915Sopenharmony_ci * number, and cannot be overwritten by block 4 (or 34 338987da915Sopenharmony_ci * if version >= 2.0) which follows logically. 339987da915Sopenharmony_ci */ 340987da915Sopenharmony_ci if ((num < RSTBLKS) 341987da915Sopenharmony_ci || ((log_major < 2) && (num < BASEBLKS))) 342987da915Sopenharmony_ci buffer = buffer_table[num + BUFFERCNT]; 343987da915Sopenharmony_ci else 344987da915Sopenharmony_ci buffer = buffer_table[num & (BUFFERCNT - 1)]; 345987da915Sopenharmony_ci if (buffer && (buffer->size < blocksz)) { 346987da915Sopenharmony_ci free(buffer); 347987da915Sopenharmony_ci buffer = (struct BUFFER*)NULL; 348987da915Sopenharmony_ci } 349987da915Sopenharmony_ci if (!buffer) { 350987da915Sopenharmony_ci buffer = (struct BUFFER*) 351987da915Sopenharmony_ci malloc(sizeof(struct BUFFER) + blocksz); 352987da915Sopenharmony_ci buffer->size = blocksz; 353987da915Sopenharmony_ci buffer->rnum = num + 1; /* forced to being read */ 354987da915Sopenharmony_ci buffer->safe = FALSE; 355987da915Sopenharmony_ci if (num < BASEBLKS) 356987da915Sopenharmony_ci buffer_table[num + BUFFERCNT] = buffer; 357987da915Sopenharmony_ci else 358987da915Sopenharmony_ci buffer_table[num & (BUFFERCNT - 1)] = buffer; 359987da915Sopenharmony_ci } 360987da915Sopenharmony_ci rnum = num; 361987da915Sopenharmony_ci if (log_major >= 2) { 362987da915Sopenharmony_ci for (k=RSTBLKS; k<BASEBLKS2; k++) 363987da915Sopenharmony_ci if (redirect[k] == num) 364987da915Sopenharmony_ci rnum = k; 365987da915Sopenharmony_ci } 366987da915Sopenharmony_ci if (buffer && (buffer->rnum != rnum)) { 367987da915Sopenharmony_ci buffer->num = num; 368987da915Sopenharmony_ci buffer->rnum = rnum; 369987da915Sopenharmony_ci if (ctx->vol) 370987da915Sopenharmony_ci got = (ntfs_attr_pread(log_na,(u64)rnum << blockbits, 371987da915Sopenharmony_ci blocksz, buffer->block.data) == blocksz); 372987da915Sopenharmony_ci else 373987da915Sopenharmony_ci got = !fseek(ctx->file, loclogblk(ctx, rnum), 0) 374987da915Sopenharmony_ci && (fread(buffer->block.data, blocksz, 375987da915Sopenharmony_ci 1, ctx->file) == 1); 376987da915Sopenharmony_ci if (got) { 377987da915Sopenharmony_ci char *data = buffer->block.data; 378987da915Sopenharmony_ci buffer->headsz = sizeof(RECORD_PAGE_HEADER) 379987da915Sopenharmony_ci + ((2*getle16(data,6) - 1) | 7) + 1; 380987da915Sopenharmony_ci buffer->safe = !replaceusa(buffer, blocksz); 381987da915Sopenharmony_ci } else { 382987da915Sopenharmony_ci buffer->safe = FALSE; 383987da915Sopenharmony_ci fprintf(stderr,"** Could not read block %d\n", rnum); 384987da915Sopenharmony_ci } 385987da915Sopenharmony_ci } 386987da915Sopenharmony_ci return (buffer && buffer->safe ? buffer : (const struct BUFFER*)NULL); 387987da915Sopenharmony_ci} 388987da915Sopenharmony_ci 389987da915Sopenharmony_civoid hexdump(const char *buf, unsigned int lth) 390987da915Sopenharmony_ci{ 391987da915Sopenharmony_ci unsigned int i,j,k; 392987da915Sopenharmony_ci 393987da915Sopenharmony_ci for (i=0; i<lth; i+=16) { 394987da915Sopenharmony_ci printf("%04x ",i); 395987da915Sopenharmony_ci k = ((lth - i) < 16 ? lth : 16 + i); 396987da915Sopenharmony_ci for (j=i; j<k; j++) 397987da915Sopenharmony_ci printf((j & 3 ? "%02x" : " %02x"),buf[j] & 255); 398987da915Sopenharmony_ci printf("%*c",(152 - 9*(j - i))/4,' '); 399987da915Sopenharmony_ci for (j=i; j<k; j++) 400987da915Sopenharmony_ci if ((buf[j] > 0x20) && (buf[j] < 0x7f)) 401987da915Sopenharmony_ci printf("%c",buf[j]); 402987da915Sopenharmony_ci else 403987da915Sopenharmony_ci printf("."); 404987da915Sopenharmony_ci printf("\n"); 405987da915Sopenharmony_ci } 406987da915Sopenharmony_ci} 407987da915Sopenharmony_ci 408987da915Sopenharmony_ci/* 409987da915Sopenharmony_ci * Display a date 410987da915Sopenharmony_ci */ 411987da915Sopenharmony_ci 412987da915Sopenharmony_cistatic void showdate(const char *text, le64 lestamp) 413987da915Sopenharmony_ci{ 414987da915Sopenharmony_ci time_t utime; 415987da915Sopenharmony_ci struct tm *ptm; 416987da915Sopenharmony_ci s64 stamp; 417987da915Sopenharmony_ci const char *months[] 418987da915Sopenharmony_ci = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", 419987da915Sopenharmony_ci "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" } ; 420987da915Sopenharmony_ci 421987da915Sopenharmony_ci stamp = le64_to_cpu(lestamp); 422987da915Sopenharmony_ci if ((stamp < ((2147000000 + 134774*86400LL)*10000000LL)) 423987da915Sopenharmony_ci && (stamp > ((-2147000000 + 134774*86400LL)*10000000LL))) { 424987da915Sopenharmony_ci /* date within traditional Unix limits */ 425987da915Sopenharmony_ci utime = stamp/10000000 - 134774*86400LL; 426987da915Sopenharmony_ci ptm = gmtime(&utime); 427987da915Sopenharmony_ci printf("%s %02d %3s %4d %2d:%02d:%02d UTC\n", 428987da915Sopenharmony_ci text, 429987da915Sopenharmony_ci ptm->tm_mday,months[ptm->tm_mon],ptm->tm_year+1900, 430987da915Sopenharmony_ci ptm->tm_hour,ptm->tm_min,ptm->tm_sec); 431987da915Sopenharmony_ci } else { 432987da915Sopenharmony_ci u32 days; 433987da915Sopenharmony_ci unsigned int year; 434987da915Sopenharmony_ci int mon; 435987da915Sopenharmony_ci int cnt; 436987da915Sopenharmony_ci 437987da915Sopenharmony_ci days = stamp/(86400*10000000LL); 438987da915Sopenharmony_ci year = 1601; 439987da915Sopenharmony_ci /* periods of 400 years */ 440987da915Sopenharmony_ci cnt = days/146097; 441987da915Sopenharmony_ci days -= 146097*cnt; 442987da915Sopenharmony_ci year += 400*cnt; 443987da915Sopenharmony_ci /* periods of 100 years */ 444987da915Sopenharmony_ci cnt = (3*days + 3)/109573; 445987da915Sopenharmony_ci days -= 36524*cnt; 446987da915Sopenharmony_ci year += 100*cnt; 447987da915Sopenharmony_ci /* periods of 4 years */ 448987da915Sopenharmony_ci cnt = days/1461; 449987da915Sopenharmony_ci days -= 1461L*cnt; 450987da915Sopenharmony_ci year += 4*cnt; 451987da915Sopenharmony_ci /* periods of a single year */ 452987da915Sopenharmony_ci cnt = (3*days + 3)/1096; 453987da915Sopenharmony_ci days -= 365*cnt; 454987da915Sopenharmony_ci year += cnt; 455987da915Sopenharmony_ci 456987da915Sopenharmony_ci if ((!(year % 100) ? (year % 400) : (year % 4)) 457987da915Sopenharmony_ci && (days > 58)) days++; 458987da915Sopenharmony_ci if (days > 59) { 459987da915Sopenharmony_ci mon = (5*days + 161)/153; 460987da915Sopenharmony_ci days -= (153*mon - 162)/5; 461987da915Sopenharmony_ci } else { 462987da915Sopenharmony_ci mon = days/31 + 1; 463987da915Sopenharmony_ci days -= 31*(mon - 1) - 1; 464987da915Sopenharmony_ci } 465987da915Sopenharmony_ciif (mon > 12) 466987da915Sopenharmony_ci{ 467987da915Sopenharmony_ciprintf("** Bad day stamp %lld days %lu mon %d year %u\n", 468987da915Sopenharmony_ci(long long)stamp,(unsigned long)days,mon,year); 469987da915Sopenharmony_ci} 470987da915Sopenharmony_ci printf("%s %02u %3s %4u\n",text, 471987da915Sopenharmony_ci (unsigned int)days,months[mon-1],(unsigned int)year); 472987da915Sopenharmony_ci } 473987da915Sopenharmony_ci} 474987da915Sopenharmony_ci 475987da915Sopenharmony_civoid showname(const char *prefix, const char *name, int cnt) 476987da915Sopenharmony_ci{ 477987da915Sopenharmony_ci const le16 *n; 478987da915Sopenharmony_ci int i; 479987da915Sopenharmony_ci int c; 480987da915Sopenharmony_ci 481987da915Sopenharmony_ci printf("%s",prefix); 482987da915Sopenharmony_ci n = (const le16*)name; 483987da915Sopenharmony_ci for (i=0; (i<cnt) && n[i]; i++) { 484987da915Sopenharmony_ci c = le16_to_cpu(n[i]); 485987da915Sopenharmony_ci if (c < 0x20) 486987da915Sopenharmony_ci printf("."); 487987da915Sopenharmony_ci else 488987da915Sopenharmony_ci if (c < 0x80) 489987da915Sopenharmony_ci printf("%c",c); 490987da915Sopenharmony_ci else 491987da915Sopenharmony_ci if (c < 0x800) 492987da915Sopenharmony_ci printf("%c%c", 493987da915Sopenharmony_ci (c >> 6) + 0xc0, 494987da915Sopenharmony_ci (c & 63) + 0x80); 495987da915Sopenharmony_ci else 496987da915Sopenharmony_ci printf("%c%c%c", 497987da915Sopenharmony_ci (c >> 12) + 0xe0, 498987da915Sopenharmony_ci ((c >> 6) & 63) + 0x80, 499987da915Sopenharmony_ci (c & 63) + 0x80); 500987da915Sopenharmony_ci } 501987da915Sopenharmony_ci printf("\n"); 502987da915Sopenharmony_ci} 503987da915Sopenharmony_ci 504987da915Sopenharmony_cistatic const char *commitment(u64 lsn) 505987da915Sopenharmony_ci{ 506987da915Sopenharmony_ci const char *commit; 507987da915Sopenharmony_ci s64 diff; 508987da915Sopenharmony_ci 509987da915Sopenharmony_ci /* Computations assume lsn could wraparound, they probably never do */ 510987da915Sopenharmony_ci diff = lsn - synced_lsn; 511987da915Sopenharmony_ci if (diff <= 0) 512987da915Sopenharmony_ci commit = "synced"; 513987da915Sopenharmony_ci else { 514987da915Sopenharmony_ci diff = lsn - committed_lsn; 515987da915Sopenharmony_ci if (diff <= 0) 516987da915Sopenharmony_ci commit = "committed"; 517987da915Sopenharmony_ci else { 518987da915Sopenharmony_ci /* may find lsn from older session */ 519987da915Sopenharmony_ci diff = lsn - latest_lsn; 520987da915Sopenharmony_ci if (diff <= 0) 521987da915Sopenharmony_ci commit = "*uncommitted*"; 522987da915Sopenharmony_ci else 523987da915Sopenharmony_ci commit = "*stale*"; 524987da915Sopenharmony_ci } 525987da915Sopenharmony_ci } 526987da915Sopenharmony_ci return (commit); 527987da915Sopenharmony_ci} 528987da915Sopenharmony_ci 529987da915Sopenharmony_ciconst char *actionname(int op) 530987da915Sopenharmony_ci{ 531987da915Sopenharmony_ci static char buffer[24]; 532987da915Sopenharmony_ci const char *p; 533987da915Sopenharmony_ci 534987da915Sopenharmony_ci switch (op) { 535987da915Sopenharmony_ci case Noop : 536987da915Sopenharmony_ci p = "Noop"; 537987da915Sopenharmony_ci break; 538987da915Sopenharmony_ci case CompensationlogRecord : 539987da915Sopenharmony_ci p = "CompensationlogRecord"; 540987da915Sopenharmony_ci break; 541987da915Sopenharmony_ci case InitializeFileRecordSegment : 542987da915Sopenharmony_ci p = "InitializeFileRecordSegment"; 543987da915Sopenharmony_ci break; 544987da915Sopenharmony_ci case DeallocateFileRecordSegment : 545987da915Sopenharmony_ci p = "DeallocateFileRecordSegment"; 546987da915Sopenharmony_ci break; 547987da915Sopenharmony_ci case WriteEndofFileRecordSegment : 548987da915Sopenharmony_ci p = "WriteEndofFileRecordSegment"; 549987da915Sopenharmony_ci break; 550987da915Sopenharmony_ci case CreateAttribute : 551987da915Sopenharmony_ci p = "CreateAttribute"; 552987da915Sopenharmony_ci break; 553987da915Sopenharmony_ci case DeleteAttribute : 554987da915Sopenharmony_ci p = "DeleteAttribute"; 555987da915Sopenharmony_ci break; 556987da915Sopenharmony_ci case UpdateResidentValue : 557987da915Sopenharmony_ci p = "UpdateResidentValue"; 558987da915Sopenharmony_ci break; 559987da915Sopenharmony_ci case UpdateNonResidentValue : 560987da915Sopenharmony_ci p = "UpdateNonResidentValue"; 561987da915Sopenharmony_ci break; 562987da915Sopenharmony_ci case UpdateMappingPairs : 563987da915Sopenharmony_ci p = "UpdateMappingPairs"; 564987da915Sopenharmony_ci break; 565987da915Sopenharmony_ci case DeleteDirtyClusters : 566987da915Sopenharmony_ci p = "DeleteDirtyClusters"; 567987da915Sopenharmony_ci break; 568987da915Sopenharmony_ci case SetNewAttributeSizes : 569987da915Sopenharmony_ci p = "SetNewAttributeSizes"; 570987da915Sopenharmony_ci break; 571987da915Sopenharmony_ci case AddIndexEntryRoot : 572987da915Sopenharmony_ci p = "AddIndexEntryRoot"; 573987da915Sopenharmony_ci break; 574987da915Sopenharmony_ci case DeleteIndexEntryRoot : 575987da915Sopenharmony_ci p = "DeleteIndexEntryRoot"; 576987da915Sopenharmony_ci break; 577987da915Sopenharmony_ci case AddIndexEntryAllocation : 578987da915Sopenharmony_ci p = "AddIndexEntryAllocation"; 579987da915Sopenharmony_ci break; 580987da915Sopenharmony_ci case DeleteIndexEntryAllocation : 581987da915Sopenharmony_ci p = "DeleteIndexEntryAllocation"; 582987da915Sopenharmony_ci break; 583987da915Sopenharmony_ci case WriteEndOfIndexBuffer : 584987da915Sopenharmony_ci p = "WriteEndOfIndexBuffer"; 585987da915Sopenharmony_ci break; 586987da915Sopenharmony_ci case SetIndexEntryVcnRoot : 587987da915Sopenharmony_ci p = "SetIndexEntryVcnRoot"; 588987da915Sopenharmony_ci break; 589987da915Sopenharmony_ci case SetIndexEntryVcnAllocation : 590987da915Sopenharmony_ci p = "SetIndexEntryVcnAllocation"; 591987da915Sopenharmony_ci break; 592987da915Sopenharmony_ci case UpdateFileNameRoot : 593987da915Sopenharmony_ci p = "UpdateFileNameRoot"; 594987da915Sopenharmony_ci break; 595987da915Sopenharmony_ci case UpdateFileNameAllocation : 596987da915Sopenharmony_ci p = "UpdateFileNameAllocation"; 597987da915Sopenharmony_ci break; 598987da915Sopenharmony_ci case SetBitsInNonResidentBitMap : 599987da915Sopenharmony_ci p = "SetBitsInNonResidentBitMap"; 600987da915Sopenharmony_ci break; 601987da915Sopenharmony_ci case ClearBitsInNonResidentBitMap : 602987da915Sopenharmony_ci p = "ClearBitsInNonResidentBitMap"; 603987da915Sopenharmony_ci break; 604987da915Sopenharmony_ci case HotFix : 605987da915Sopenharmony_ci p = "HotFix"; 606987da915Sopenharmony_ci break; 607987da915Sopenharmony_ci case EndTopLevelAction : 608987da915Sopenharmony_ci p = "EndTopLevelAction"; 609987da915Sopenharmony_ci break; 610987da915Sopenharmony_ci case PrepareTransaction : 611987da915Sopenharmony_ci p = "PrepareTransaction"; 612987da915Sopenharmony_ci break; 613987da915Sopenharmony_ci case CommitTransaction : 614987da915Sopenharmony_ci p = "CommitTransaction"; 615987da915Sopenharmony_ci break; 616987da915Sopenharmony_ci case ForgetTransaction : 617987da915Sopenharmony_ci p = "ForgetTransaction"; 618987da915Sopenharmony_ci break; 619987da915Sopenharmony_ci case OpenNonResidentAttribute : 620987da915Sopenharmony_ci p = "OpenNonResidentAttribute"; 621987da915Sopenharmony_ci break; 622987da915Sopenharmony_ci case OpenAttributeTableDump : 623987da915Sopenharmony_ci p = "OpenAttributeTableDump"; 624987da915Sopenharmony_ci break; 625987da915Sopenharmony_ci case AttributeNamesDump : 626987da915Sopenharmony_ci p = "AttributeNamesDump"; 627987da915Sopenharmony_ci break; 628987da915Sopenharmony_ci case DirtyPageTableDump : 629987da915Sopenharmony_ci p = "DirtyPageTableDump"; 630987da915Sopenharmony_ci break; 631987da915Sopenharmony_ci case TransactionTableDump : 632987da915Sopenharmony_ci p = "TransactionTableDump"; 633987da915Sopenharmony_ci break; 634987da915Sopenharmony_ci case UpdateRecordDataRoot : 635987da915Sopenharmony_ci p = "UpdateRecordDataRoot"; 636987da915Sopenharmony_ci break; 637987da915Sopenharmony_ci case UpdateRecordDataAllocation : 638987da915Sopenharmony_ci p = "UpdateRecordDataAllocation"; 639987da915Sopenharmony_ci break; 640987da915Sopenharmony_ci case Win10Action35 : 641987da915Sopenharmony_ci p = "Win10Action35"; 642987da915Sopenharmony_ci break; 643987da915Sopenharmony_ci case Win10Action36 : 644987da915Sopenharmony_ci p = "Win10Action36"; 645987da915Sopenharmony_ci break; 646987da915Sopenharmony_ci case Win10Action37 : 647987da915Sopenharmony_ci p = "Win10Action37"; 648987da915Sopenharmony_ci break; 649987da915Sopenharmony_ci default : 650987da915Sopenharmony_ci sprintf(buffer,"*Unknown-Action-%d*",op); 651987da915Sopenharmony_ci p = buffer; 652987da915Sopenharmony_ci break; 653987da915Sopenharmony_ci } 654987da915Sopenharmony_ci return (p); 655987da915Sopenharmony_ci} 656987da915Sopenharmony_ci 657987da915Sopenharmony_cistatic const char *attrname(unsigned int key) 658987da915Sopenharmony_ci{ 659987da915Sopenharmony_ci static char name[256]; 660987da915Sopenharmony_ci const char *p; 661987da915Sopenharmony_ci struct ATTR *pa; 662987da915Sopenharmony_ci unsigned int i; 663987da915Sopenharmony_ci 664987da915Sopenharmony_ci if ((key <= 65535) && !(key & 3)) { 665987da915Sopenharmony_ci pa = getattrentry(key,0); 666987da915Sopenharmony_ci if (pa) { 667987da915Sopenharmony_ci if (!pa->namelen) 668987da915Sopenharmony_ci p = "Unnamed"; 669987da915Sopenharmony_ci else { 670987da915Sopenharmony_ci p = name; 671987da915Sopenharmony_ci /* Assume ascii for now */ 672987da915Sopenharmony_ci for (i=0; 2*i<pa->namelen; i++) 673987da915Sopenharmony_ci name[i] = le16_to_cpu(pa->name[i]); 674987da915Sopenharmony_ci name[i] = 0; 675987da915Sopenharmony_ci } 676987da915Sopenharmony_ci } else 677987da915Sopenharmony_ci p = "Undefined"; 678987da915Sopenharmony_ci } else 679987da915Sopenharmony_ci p = "Invalid"; 680987da915Sopenharmony_ci return (p); 681987da915Sopenharmony_ci} 682987da915Sopenharmony_ci 683987da915Sopenharmony_ciint fixnamelen(const char *name, int len) 684987da915Sopenharmony_ci{ 685987da915Sopenharmony_ci int i; 686987da915Sopenharmony_ci 687987da915Sopenharmony_ci i = 0; 688987da915Sopenharmony_ci while ((i < len) && (name[i] || name[i + 1])) 689987da915Sopenharmony_ci i += 2; 690987da915Sopenharmony_ci return (i); 691987da915Sopenharmony_ci} 692987da915Sopenharmony_ci 693987da915Sopenharmony_ciconst char *mftattrname(ATTR_TYPES attr) 694987da915Sopenharmony_ci{ 695987da915Sopenharmony_ci static char badattr[24]; 696987da915Sopenharmony_ci const char *p; 697987da915Sopenharmony_ci 698987da915Sopenharmony_ci switch (attr) { 699987da915Sopenharmony_ci case AT_STANDARD_INFORMATION : 700987da915Sopenharmony_ci p = "Standard-Information"; 701987da915Sopenharmony_ci break; 702987da915Sopenharmony_ci case AT_ATTRIBUTE_LIST : 703987da915Sopenharmony_ci p = "Attribute-List"; 704987da915Sopenharmony_ci break; 705987da915Sopenharmony_ci case AT_FILE_NAME : 706987da915Sopenharmony_ci p = "Name"; 707987da915Sopenharmony_ci break; 708987da915Sopenharmony_ci case AT_OBJECT_ID : 709987da915Sopenharmony_ci p = "Volume-Version"; 710987da915Sopenharmony_ci break; 711987da915Sopenharmony_ci case AT_SECURITY_DESCRIPTOR : 712987da915Sopenharmony_ci p = "Security-Descriptor"; 713987da915Sopenharmony_ci break; 714987da915Sopenharmony_ci case AT_VOLUME_NAME : 715987da915Sopenharmony_ci p = "Volume-Name"; 716987da915Sopenharmony_ci break; 717987da915Sopenharmony_ci case AT_VOLUME_INFORMATION : 718987da915Sopenharmony_ci p = "Volume-Information"; 719987da915Sopenharmony_ci break; 720987da915Sopenharmony_ci case AT_DATA : 721987da915Sopenharmony_ci p = "Data"; 722987da915Sopenharmony_ci break; 723987da915Sopenharmony_ci case AT_INDEX_ROOT : 724987da915Sopenharmony_ci p = "Index-Root"; 725987da915Sopenharmony_ci break; 726987da915Sopenharmony_ci case AT_INDEX_ALLOCATION : 727987da915Sopenharmony_ci p = "Index-Allocation"; 728987da915Sopenharmony_ci break; 729987da915Sopenharmony_ci case AT_BITMAP : 730987da915Sopenharmony_ci p = "Bitmap"; 731987da915Sopenharmony_ci break; 732987da915Sopenharmony_ci case AT_REPARSE_POINT : 733987da915Sopenharmony_ci p = "Reparse-Point"; 734987da915Sopenharmony_ci break; 735987da915Sopenharmony_ci case AT_EA_INFORMATION : 736987da915Sopenharmony_ci p = "EA-Information"; 737987da915Sopenharmony_ci break; 738987da915Sopenharmony_ci case AT_EA : 739987da915Sopenharmony_ci p = "EA"; 740987da915Sopenharmony_ci break; 741987da915Sopenharmony_ci case AT_PROPERTY_SET : 742987da915Sopenharmony_ci p = "Property-Set"; 743987da915Sopenharmony_ci break; 744987da915Sopenharmony_ci case AT_LOGGED_UTILITY_STREAM : 745987da915Sopenharmony_ci p = "Logged-Utility-Stream"; 746987da915Sopenharmony_ci break; 747987da915Sopenharmony_ci case AT_END : 748987da915Sopenharmony_ci p = "End"; 749987da915Sopenharmony_ci break; 750987da915Sopenharmony_ci default : 751987da915Sopenharmony_ci sprintf(badattr,"*0x%x-Unknown*",attr); 752987da915Sopenharmony_ci p = badattr; 753987da915Sopenharmony_ci break; 754987da915Sopenharmony_ci } 755987da915Sopenharmony_ci return (p); 756987da915Sopenharmony_ci} 757987da915Sopenharmony_ci 758987da915Sopenharmony_cistatic void showattribute(const char *prefix, const struct ATTR *pa) 759987da915Sopenharmony_ci{ 760987da915Sopenharmony_ci if (pa) { 761987da915Sopenharmony_ci if (pa->type) { 762987da915Sopenharmony_ci printf("%sattr 0x%x : inode %lld type %s", 763987da915Sopenharmony_ci prefix, pa->key, (long long)pa->inode, 764987da915Sopenharmony_ci mftattrname(pa->type)); 765987da915Sopenharmony_ci if (pa->namelen) 766987da915Sopenharmony_ci showname(" name ",(const char*)pa->name, 767987da915Sopenharmony_ci pa->namelen/2); 768987da915Sopenharmony_ci else 769987da915Sopenharmony_ci printf("\n"); 770987da915Sopenharmony_ci } else { 771987da915Sopenharmony_ci if (pa->namelen) { 772987da915Sopenharmony_ci printf("%sattr 0x%x : type Unknown", 773987da915Sopenharmony_ci prefix, pa->key); 774987da915Sopenharmony_ci showname(" name ",(const char*)pa->name, 775987da915Sopenharmony_ci pa->namelen/2); 776987da915Sopenharmony_ci } else 777987da915Sopenharmony_ci printf("%s(definition of attr 0x%x not met)\n", 778987da915Sopenharmony_ci prefix, pa->key); 779987da915Sopenharmony_ci } 780987da915Sopenharmony_ci } 781987da915Sopenharmony_ci} 782987da915Sopenharmony_ci 783987da915Sopenharmony_ci/* 784987da915Sopenharmony_ci * Determine if an action acts on the MFT 785987da915Sopenharmony_ci */ 786987da915Sopenharmony_ci 787987da915Sopenharmony_cistatic BOOL acts_on_mft(int op) 788987da915Sopenharmony_ci{ 789987da915Sopenharmony_ci BOOL onmft; 790987da915Sopenharmony_ci 791987da915Sopenharmony_ci /* A few actions may have to be added to the list */ 792987da915Sopenharmony_ci switch (op) { 793987da915Sopenharmony_ci case InitializeFileRecordSegment : 794987da915Sopenharmony_ci case DeallocateFileRecordSegment : 795987da915Sopenharmony_ci case CreateAttribute : 796987da915Sopenharmony_ci case DeleteAttribute : 797987da915Sopenharmony_ci case UpdateResidentValue : 798987da915Sopenharmony_ci case UpdateMappingPairs : 799987da915Sopenharmony_ci case SetNewAttributeSizes : 800987da915Sopenharmony_ci case AddIndexEntryRoot : 801987da915Sopenharmony_ci case DeleteIndexEntryRoot : 802987da915Sopenharmony_ci case UpdateFileNameRoot : 803987da915Sopenharmony_ci case WriteEndofFileRecordSegment : 804987da915Sopenharmony_ci case Win10Action37 : 805987da915Sopenharmony_ci onmft = TRUE; 806987da915Sopenharmony_ci break; 807987da915Sopenharmony_ci default : 808987da915Sopenharmony_ci onmft = FALSE; 809987da915Sopenharmony_ci break; 810987da915Sopenharmony_ci } 811987da915Sopenharmony_ci return (onmft); 812987da915Sopenharmony_ci} 813987da915Sopenharmony_ci 814987da915Sopenharmony_ciu32 get_undo_offset(const LOG_RECORD *logr) 815987da915Sopenharmony_ci{ 816987da915Sopenharmony_ci u32 offset; 817987da915Sopenharmony_ci 818987da915Sopenharmony_ci if (logr->lcns_to_follow) 819987da915Sopenharmony_ci offset = 0x30 + le16_to_cpu(logr->undo_offset); 820987da915Sopenharmony_ci else 821987da915Sopenharmony_ci offset = 0x28 + le16_to_cpu(logr->undo_offset); 822987da915Sopenharmony_ci return (offset); 823987da915Sopenharmony_ci} 824987da915Sopenharmony_ci 825987da915Sopenharmony_ciu32 get_redo_offset(const LOG_RECORD *logr) 826987da915Sopenharmony_ci{ 827987da915Sopenharmony_ci u32 offset; 828987da915Sopenharmony_ci 829987da915Sopenharmony_ci if (logr->lcns_to_follow) 830987da915Sopenharmony_ci offset = 0x30 + le16_to_cpu(logr->redo_offset); 831987da915Sopenharmony_ci else 832987da915Sopenharmony_ci offset = 0x28 + le16_to_cpu(logr->redo_offset); 833987da915Sopenharmony_ci return (offset); 834987da915Sopenharmony_ci} 835987da915Sopenharmony_ci 836987da915Sopenharmony_ciu32 get_extra_offset(const LOG_RECORD *logr) 837987da915Sopenharmony_ci{ 838987da915Sopenharmony_ci u32 uoffset; 839987da915Sopenharmony_ci u32 roffset; 840987da915Sopenharmony_ci 841987da915Sopenharmony_ci roffset = get_redo_offset(logr) 842987da915Sopenharmony_ci + le16_to_cpu(logr->redo_length); 843987da915Sopenharmony_ci uoffset = get_undo_offset(logr) 844987da915Sopenharmony_ci + le16_to_cpu(logr->undo_length); 845987da915Sopenharmony_ci return ((((uoffset > roffset ? uoffset : roffset) - 1) | 7) + 1); 846987da915Sopenharmony_ci} 847987da915Sopenharmony_ci 848987da915Sopenharmony_cistatic BOOL likelyop(const LOG_RECORD *logr) 849987da915Sopenharmony_ci{ 850987da915Sopenharmony_ci BOOL likely; 851987da915Sopenharmony_ci 852987da915Sopenharmony_ci switch (logr->record_type) { 853987da915Sopenharmony_ci case LOG_STANDARD : /* standard record */ 854987da915Sopenharmony_ci /* Operations in range 0..LastAction-1, can be both null */ 855987da915Sopenharmony_ci likely = ((unsigned int)le16_to_cpu(logr->redo_operation) 856987da915Sopenharmony_ci < LastAction) 857987da915Sopenharmony_ci && ((unsigned int)le16_to_cpu(logr->undo_operation) 858987da915Sopenharmony_ci < LastAction) 859987da915Sopenharmony_ci /* Offsets aligned to 8 bytes */ 860987da915Sopenharmony_ci && !(le16_to_cpu(logr->redo_offset) & 7) 861987da915Sopenharmony_ci && !(le16_to_cpu(logr->undo_offset) & 7) 862987da915Sopenharmony_ci /* transaction id must not be null */ 863987da915Sopenharmony_ci && logr->transaction_id 864987da915Sopenharmony_ci /* client data length aligned to 8 bytes */ 865987da915Sopenharmony_ci && !(le32_to_cpu(logr->client_data_length) & 7) 866987da915Sopenharmony_ci /* client data length less than 64K (131K ?) */ 867987da915Sopenharmony_ci && (le32_to_cpu(logr->client_data_length) < MAXRECSIZE) 868987da915Sopenharmony_ci /* if there is redo data, offset must be >= 0x28 */ 869987da915Sopenharmony_ci && (!le16_to_cpu(logr->redo_length) 870987da915Sopenharmony_ci || ((unsigned int)le16_to_cpu(logr->redo_offset) >= 0x28)) 871987da915Sopenharmony_ci /* if there is undo data, offset must be >= 0x28 */ 872987da915Sopenharmony_ci && (!le16_to_cpu(logr->undo_length) 873987da915Sopenharmony_ci || ((unsigned int)le16_to_cpu(logr->undo_offset) >= 0x28)); 874987da915Sopenharmony_ci /* undo data and redo data should be contiguous when both present */ 875987da915Sopenharmony_ci if (likely && logr->redo_length && logr->undo_length) { 876987da915Sopenharmony_ci /* undo and redo data may be the same when both present and same size */ 877987da915Sopenharmony_ci if (logr->undo_offset == logr->redo_offset) { 878987da915Sopenharmony_ci if (logr->redo_length != logr->undo_length) 879987da915Sopenharmony_ci likely = FALSE; 880987da915Sopenharmony_ci } else { 881987da915Sopenharmony_ci if (le16_to_cpu(logr->redo_offset) 882987da915Sopenharmony_ci < le16_to_cpu(logr->undo_offset)) { 883987da915Sopenharmony_ci /* undo expected just after redo */ 884987da915Sopenharmony_ci if ((((le16_to_cpu(logr->redo_offset) 885987da915Sopenharmony_ci + le16_to_cpu(logr->redo_length) 886987da915Sopenharmony_ci - 1) | 7) + 1) 887987da915Sopenharmony_ci != le16_to_cpu(logr->undo_offset)) 888987da915Sopenharmony_ci likely = FALSE; 889987da915Sopenharmony_ci } else { 890987da915Sopenharmony_ci /* redo expected just after undo */ 891987da915Sopenharmony_ci if ((((le16_to_cpu(logr->undo_offset) 892987da915Sopenharmony_ci + le16_to_cpu(logr->undo_length) 893987da915Sopenharmony_ci - 1) | 7) + 1) 894987da915Sopenharmony_ci != le16_to_cpu(logr->redo_offset)) 895987da915Sopenharmony_ci likely = FALSE; 896987da915Sopenharmony_ci } 897987da915Sopenharmony_ci } 898987da915Sopenharmony_ci } 899987da915Sopenharmony_ci break; 900987da915Sopenharmony_ci case LOG_CHECKPOINT : /* check-point */ 901987da915Sopenharmony_ci /* 902987da915Sopenharmony_ci * undo and redo operations are null 903987da915Sopenharmony_ci * or CompensationlogRecord with no data 904987da915Sopenharmony_ci */ 905987da915Sopenharmony_ci likely = (!logr->redo_operation 906987da915Sopenharmony_ci || ((logr->redo_operation == const_cpu_to_le16(1)) 907987da915Sopenharmony_ci && !logr->redo_length)) 908987da915Sopenharmony_ci && (!logr->undo_operation 909987da915Sopenharmony_ci || ((logr->undo_operation == const_cpu_to_le16(1)) 910987da915Sopenharmony_ci && !logr->undo_length)) 911987da915Sopenharmony_ci /* transaction id must be null */ 912987da915Sopenharmony_ci && !logr->transaction_id 913987da915Sopenharmony_ci /* client_data_length is 0x68 or 0x70 (Vista and subsequent) */ 914987da915Sopenharmony_ci && ((le32_to_cpu(logr->client_data_length) == 0x68) 915987da915Sopenharmony_ci || (le32_to_cpu(logr->client_data_length) == 0x70)); 916987da915Sopenharmony_ci break; 917987da915Sopenharmony_ci default : 918987da915Sopenharmony_ci likely = FALSE; 919987da915Sopenharmony_ci break; 920987da915Sopenharmony_ci } 921987da915Sopenharmony_ci return (likely); 922987da915Sopenharmony_ci} 923987da915Sopenharmony_ci 924987da915Sopenharmony_ci/* 925987da915Sopenharmony_ci * Search for a likely record in a block 926987da915Sopenharmony_ci * 927987da915Sopenharmony_ci * Must not be used when syncing. 928987da915Sopenharmony_ci * 929987da915Sopenharmony_ci * Returns 0 when not found 930987da915Sopenharmony_ci */ 931987da915Sopenharmony_ci 932987da915Sopenharmony_cistatic u16 searchlikely(const struct BUFFER *buf) 933987da915Sopenharmony_ci{ 934987da915Sopenharmony_ci const LOG_RECORD *logr; 935987da915Sopenharmony_ci const char *data; 936987da915Sopenharmony_ci u16 k; 937987da915Sopenharmony_ci 938987da915Sopenharmony_ci if (opts) 939987da915Sopenharmony_ci printf("** Error : searchlikely() used for syncing\n"); 940987da915Sopenharmony_ci data = buf->block.data; 941987da915Sopenharmony_ci k = buf->headsz; 942987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 943987da915Sopenharmony_ci if (!likelyop(logr)) { 944987da915Sopenharmony_ci do { 945987da915Sopenharmony_ci k += 8; 946987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 947987da915Sopenharmony_ci } while ((k <= (blocksz - LOG_RECORD_HEAD_SZ)) 948987da915Sopenharmony_ci && !likelyop(logr)); 949987da915Sopenharmony_ci if (k > (blocksz - LOG_RECORD_HEAD_SZ)) 950987da915Sopenharmony_ci k = 0; 951987da915Sopenharmony_ci } 952987da915Sopenharmony_ci return (k); 953987da915Sopenharmony_ci} 954987da915Sopenharmony_ci 955987da915Sopenharmony_ci/* 956987da915Sopenharmony_ci * From a previous block, determine the location of first record 957987da915Sopenharmony_ci * 958987da915Sopenharmony_ci * The previous block must have the beginning of an overlapping 959987da915Sopenharmony_ci * record, and the current block must have the beginning of next 960987da915Sopenharmony_ci * record (which can overlap on next blocks). 961987da915Sopenharmony_ci * The argument "skipped" is the number of blocks in-between. 962987da915Sopenharmony_ci * 963987da915Sopenharmony_ci * Note : the overlapping record from previous block does not reach 964987da915Sopenharmony_ci * the current block when it ends near the end of the last skipped block. 965987da915Sopenharmony_ci * 966987da915Sopenharmony_ci * Returns 0 if some bad condition is found 967987da915Sopenharmony_ci * Returns near blocksz when there is no beginning of record in 968987da915Sopenharmony_ci * the current block 969987da915Sopenharmony_ci */ 970987da915Sopenharmony_ci 971987da915Sopenharmony_cistatic u16 firstrecord(int skipped, const struct BUFFER *buf, 972987da915Sopenharmony_ci const struct BUFFER *prevbuf) 973987da915Sopenharmony_ci{ 974987da915Sopenharmony_ci const RECORD_PAGE_HEADER *rph; 975987da915Sopenharmony_ci const RECORD_PAGE_HEADER *prevrph; 976987da915Sopenharmony_ci const LOG_RECORD *logr; 977987da915Sopenharmony_ci const char *data; 978987da915Sopenharmony_ci const char *prevdata; 979987da915Sopenharmony_ci u16 k; 980987da915Sopenharmony_ci u16 blkheadsz; 981987da915Sopenharmony_ci s32 size; 982987da915Sopenharmony_ci 983987da915Sopenharmony_ci rph = &buf->block.record; 984987da915Sopenharmony_ci data = buf->block.data; 985987da915Sopenharmony_ci if (prevbuf) { 986987da915Sopenharmony_ci prevrph = &prevbuf->block.record; 987987da915Sopenharmony_ci prevdata = prevbuf->block.data; 988987da915Sopenharmony_ci blkheadsz = prevbuf->headsz; 989987da915Sopenharmony_ci /* From previous page, determine where the current one starts */ 990987da915Sopenharmony_ci k = le16_to_cpu(prevrph->next_record_offset); 991987da915Sopenharmony_ci /* a null value means there is no full record in next block */ 992987da915Sopenharmony_ci if (!k) 993987da915Sopenharmony_ci k = blkheadsz; 994987da915Sopenharmony_ci } else 995987da915Sopenharmony_ci k = 0; 996987da915Sopenharmony_ci /* Minimal size is apparently 48 : offset of redo_operation */ 997987da915Sopenharmony_ci if (k && ((blocksz - k) >= LOG_RECORD_HEAD_SZ)) { 998987da915Sopenharmony_ci logr = (const LOG_RECORD*)&prevdata[k]; 999987da915Sopenharmony_ci if (!logr->client_data_length) { 1000987da915Sopenharmony_ci /* 1001987da915Sopenharmony_ci * Sometimes the end of record is free space. 1002987da915Sopenharmony_ci * This apparently means reaching the end of 1003987da915Sopenharmony_ci * a previous session, and must be considered 1004987da915Sopenharmony_ci * as an error. 1005987da915Sopenharmony_ci * We however tolerate this, unless syncing 1006987da915Sopenharmony_ci * is requested. 1007987da915Sopenharmony_ci */ 1008987da915Sopenharmony_ci printf("* Reaching free space at end of block %d\n", 1009987da915Sopenharmony_ci (int)prevbuf->num); 1010987da915Sopenharmony_ci /* As a consequence, there cannot be skipped blocks */ 1011987da915Sopenharmony_ci if (skipped) { 1012987da915Sopenharmony_ci printf("*** Inconsistency : blocks skipped after free space\n"); 1013987da915Sopenharmony_ci k = 0; /* error returned */ 1014987da915Sopenharmony_ci } 1015987da915Sopenharmony_ci if (opts) 1016987da915Sopenharmony_ci k = 0; 1017987da915Sopenharmony_ci else { 1018987da915Sopenharmony_ci k = searchlikely(buf); 1019987da915Sopenharmony_ci printf("* Skipping over free space\n"); 1020987da915Sopenharmony_ci } 1021987da915Sopenharmony_ci } else { 1022987da915Sopenharmony_ci size = le32_to_cpu(logr->client_data_length) 1023987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 1024987da915Sopenharmony_ci if ((size < MINRECSIZE) || (size > MAXRECSIZE)) { 1025987da915Sopenharmony_ci printf("** Bad record size %ld in block %ld" 1026987da915Sopenharmony_ci " offset 0x%x\n", 1027987da915Sopenharmony_ci (long)size,(long)prevbuf->num,(int)k); 1028987da915Sopenharmony_ci k = blkheadsz; 1029987da915Sopenharmony_ci } else { 1030987da915Sopenharmony_ci if ((int)(blocksz - k) >= size) 1031987da915Sopenharmony_ci printf("*** Inconsistency : the final" 1032987da915Sopenharmony_ci " record does not overlap\n"); 1033987da915Sopenharmony_ci k += size - (blocksz - blkheadsz)*(skipped + 1); 1034987da915Sopenharmony_ci } 1035987da915Sopenharmony_ci if ((k <= blkheadsz) 1036987da915Sopenharmony_ci && (k > (blkheadsz - LOG_RECORD_HEAD_SZ))) { 1037987da915Sopenharmony_ci /* There were not enough space in the last skipped block */ 1038987da915Sopenharmony_ci k = blkheadsz; 1039987da915Sopenharmony_ci } else { 1040987da915Sopenharmony_ci if (optv 1041987da915Sopenharmony_ci && ((blocksz - k) < LOG_RECORD_HEAD_SZ)) { 1042987da915Sopenharmony_ci /* Not an error : just no space */ 1043987da915Sopenharmony_ci printf("No minimal record space\n"); 1044987da915Sopenharmony_ci } 1045987da915Sopenharmony_ci if (optv >= 2) 1046987da915Sopenharmony_ci printf("Overlapping record from block %d," 1047987da915Sopenharmony_ci " starting at offset 0x%x\n", 1048987da915Sopenharmony_ci (int)prevbuf->num,(int)k); 1049987da915Sopenharmony_ci } 1050987da915Sopenharmony_ci } 1051987da915Sopenharmony_ci } else { 1052987da915Sopenharmony_ci k = buf->headsz; 1053987da915Sopenharmony_ci if (optv >= 2) { 1054987da915Sopenharmony_ci if (prevbuf) 1055987da915Sopenharmony_ci printf("No minimal record from block %d," 1056987da915Sopenharmony_ci " starting at offset 0x%x\n", 1057987da915Sopenharmony_ci (int)prevbuf->num, (int)k); 1058987da915Sopenharmony_ci else 1059987da915Sopenharmony_ci printf("No block before %d," 1060987da915Sopenharmony_ci " starting at offset 0x%x\n", 1061987da915Sopenharmony_ci (int)buf->num, (int)k); 1062987da915Sopenharmony_ci } 1063987da915Sopenharmony_ci } 1064987da915Sopenharmony_ci /* 1065987da915Sopenharmony_ci * In a wraparound situation, there is frequently no 1066987da915Sopenharmony_ci * match... because there were no wraparound. 1067987da915Sopenharmony_ci * Return an error if syncing is requested, otherwise 1068987da915Sopenharmony_ci * try to find a starting record. 1069987da915Sopenharmony_ci */ 1070987da915Sopenharmony_ci if (k && prevbuf && (prevbuf->num > buf->num)) { 1071987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 1072987da915Sopenharmony_ci /* Accept reaching the end with no record beginning */ 1073987da915Sopenharmony_ci if ((k != le16_to_cpu(rph->next_record_offset)) 1074987da915Sopenharmony_ci && !likelyop(logr)) { 1075987da915Sopenharmony_ci if (opts) { 1076987da915Sopenharmony_ci k = 0; 1077987da915Sopenharmony_ci printf("** Could not wraparound\n"); 1078987da915Sopenharmony_ci } else { 1079987da915Sopenharmony_ci k = searchlikely(buf); 1080987da915Sopenharmony_ci printf("* Skipping over bad wraparound\n"); 1081987da915Sopenharmony_ci } 1082987da915Sopenharmony_ci } 1083987da915Sopenharmony_ci } 1084987da915Sopenharmony_ci return (k); 1085987da915Sopenharmony_ci} 1086987da915Sopenharmony_ci 1087987da915Sopenharmony_ci/* 1088987da915Sopenharmony_ci * Find the block which defines the first record in current one 1089987da915Sopenharmony_ci * 1090987da915Sopenharmony_ci * Either the wanted block has the beginning of a record overlapping 1091987da915Sopenharmony_ci * on current one, or it ends in such as there is no space for an 1092987da915Sopenharmony_ci * overlapping one. 1093987da915Sopenharmony_ci * 1094987da915Sopenharmony_ci * Returns 0 if the previous block cannot be determined. 1095987da915Sopenharmony_ci */ 1096987da915Sopenharmony_ci 1097987da915Sopenharmony_cistatic const struct BUFFER *findprevious(CONTEXT *ctx, const struct BUFFER *buf) 1098987da915Sopenharmony_ci{ 1099987da915Sopenharmony_ci const struct BUFFER *prevbuf; 1100987da915Sopenharmony_ci const struct BUFFER *savebuf; 1101987da915Sopenharmony_ci const RECORD_PAGE_HEADER *rph; 1102987da915Sopenharmony_ci int skipped; 1103987da915Sopenharmony_ci int prevblk; 1104987da915Sopenharmony_ci BOOL prevmiddle; 1105987da915Sopenharmony_ci BOOL error; 1106987da915Sopenharmony_ci u16 endoff; 1107987da915Sopenharmony_ci 1108987da915Sopenharmony_ci error = FALSE; 1109987da915Sopenharmony_ci prevblk = buf->num; 1110987da915Sopenharmony_ci savebuf = (struct BUFFER*)NULL; 1111987da915Sopenharmony_ci skipped = 0; 1112987da915Sopenharmony_ci do { 1113987da915Sopenharmony_ci prevmiddle = FALSE; 1114987da915Sopenharmony_ci if (prevblk > (log_major < 2 ? BASEBLKS : BASEBLKS2)) 1115987da915Sopenharmony_ci prevblk--; 1116987da915Sopenharmony_ci else 1117987da915Sopenharmony_ci if (prevblk == (log_major < 2 ? BASEBLKS : BASEBLKS2)) 1118987da915Sopenharmony_ci prevblk = (logfilesz >> blockbits) - 1; 1119987da915Sopenharmony_ci else { 1120987da915Sopenharmony_ci rph = &buf->block.record; 1121987da915Sopenharmony_ci if (log_major < 2) 1122987da915Sopenharmony_ci prevblk = (sle64_to_cpu( 1123987da915Sopenharmony_ci rph->copy.file_offset) 1124987da915Sopenharmony_ci >> blockbits) - 1; 1125987da915Sopenharmony_ci else 1126987da915Sopenharmony_ci prevblk = (sle64_to_cpu( 1127987da915Sopenharmony_ci rph->copy.last_lsn) 1128987da915Sopenharmony_ci & offset_mask) 1129987da915Sopenharmony_ci >> (blockbits - 3); 1130987da915Sopenharmony_ci /* 1131987da915Sopenharmony_ci * If an initial block leads to block 4, it 1132987da915Sopenharmony_ci * can mean the last block or no previous 1133987da915Sopenharmony_ci * block at all. Using the last block is safer, 1134987da915Sopenharmony_ci * its lsn will indicate whether it is stale. 1135987da915Sopenharmony_ci */ 1136987da915Sopenharmony_ci if (prevblk 1137987da915Sopenharmony_ci < (log_major < 2 ? BASEBLKS : BASEBLKS2)) 1138987da915Sopenharmony_ci prevblk = (logfilesz >> blockbits) - 1; 1139987da915Sopenharmony_ci } 1140987da915Sopenharmony_ci /* No previous block if the log only consists of block 2 or 3 */ 1141987da915Sopenharmony_ci if (prevblk < BASEBLKS) { 1142987da915Sopenharmony_ci prevbuf = (struct BUFFER*)NULL; 1143987da915Sopenharmony_ci error = TRUE; /* not a real error */ 1144987da915Sopenharmony_ci } else { 1145987da915Sopenharmony_ci prevbuf = read_buffer(ctx, prevblk); 1146987da915Sopenharmony_ci if (prevbuf) { 1147987da915Sopenharmony_ci rph = &prevbuf->block.record; 1148987da915Sopenharmony_ci prevmiddle = !(rph->flags 1149987da915Sopenharmony_ci & const_cpu_to_le32(1)) 1150987da915Sopenharmony_ci || !rph->next_record_offset; 1151987da915Sopenharmony_ci if (prevmiddle) { 1152987da915Sopenharmony_ci savebuf = prevbuf; 1153987da915Sopenharmony_ci skipped++; 1154987da915Sopenharmony_ci } 1155987da915Sopenharmony_ci } else { 1156987da915Sopenharmony_ci error = TRUE; 1157987da915Sopenharmony_ci printf("** Could not read block %d\n", 1158987da915Sopenharmony_ci (int)prevblk); 1159987da915Sopenharmony_ci } 1160987da915Sopenharmony_ci } 1161987da915Sopenharmony_ci } while (prevmiddle && !error); 1162987da915Sopenharmony_ci 1163987da915Sopenharmony_ci if (!prevmiddle && !error && skipped) { 1164987da915Sopenharmony_ci /* No luck if there is not enough space in this record */ 1165987da915Sopenharmony_ci rph = &prevbuf->block.record; 1166987da915Sopenharmony_ci endoff = le16_to_cpu(rph->next_record_offset); 1167987da915Sopenharmony_ci if (endoff > (blocksz - LOG_RECORD_HEAD_SZ)) { 1168987da915Sopenharmony_ci prevbuf = savebuf; 1169987da915Sopenharmony_ci } 1170987da915Sopenharmony_ci } 1171987da915Sopenharmony_ci return (error ? (struct BUFFER*)NULL : prevbuf); 1172987da915Sopenharmony_ci} 1173987da915Sopenharmony_ci 1174987da915Sopenharmony_civoid copy_attribute(struct ATTR *pa, const char *buf, int length) 1175987da915Sopenharmony_ci{ 1176987da915Sopenharmony_ci const ATTR_NEW *panew; 1177987da915Sopenharmony_ci ATTR_OLD old_aligned; 1178987da915Sopenharmony_ci 1179987da915Sopenharmony_ci if (pa) { 1180987da915Sopenharmony_ci switch (length) { 1181987da915Sopenharmony_ci case sizeof(ATTR_NEW) : 1182987da915Sopenharmony_ci panew = (const ATTR_NEW*)buf; 1183987da915Sopenharmony_ci pa->type = panew->type; 1184987da915Sopenharmony_ci pa->lsn = sle64_to_cpu(panew->lsn); 1185987da915Sopenharmony_ci pa->inode = MREF(le64_to_cpu(panew->inode)); 1186987da915Sopenharmony_ci break; 1187987da915Sopenharmony_ci case sizeof(ATTR_OLD) : 1188987da915Sopenharmony_ci /* Badly aligned, first realign */ 1189987da915Sopenharmony_ci memcpy(&old_aligned,buf,sizeof(old_aligned)); 1190987da915Sopenharmony_ci pa->type = old_aligned.type; 1191987da915Sopenharmony_ci pa->lsn = sle64_to_cpu(old_aligned.lsn); 1192987da915Sopenharmony_ci pa->inode = MREF(le64_to_cpu(old_aligned.inode)); 1193987da915Sopenharmony_ci break; 1194987da915Sopenharmony_ci default : 1195987da915Sopenharmony_ci printf("** Unexpected attribute format, length %d\n", 1196987da915Sopenharmony_ci length); 1197987da915Sopenharmony_ci } 1198987da915Sopenharmony_ci } 1199987da915Sopenharmony_ci} 1200987da915Sopenharmony_ci 1201987da915Sopenharmony_cistatic int refresh_attributes(const struct ACTION_RECORD *firstaction) 1202987da915Sopenharmony_ci{ 1203987da915Sopenharmony_ci const struct ACTION_RECORD *action; 1204987da915Sopenharmony_ci const LOG_RECORD *logr; 1205987da915Sopenharmony_ci struct ATTR *pa; 1206987da915Sopenharmony_ci const char *buf; 1207987da915Sopenharmony_ci u32 extra; 1208987da915Sopenharmony_ci u32 length; 1209987da915Sopenharmony_ci u32 len; 1210987da915Sopenharmony_ci u32 key; 1211987da915Sopenharmony_ci u32 x; 1212987da915Sopenharmony_ci u32 i; 1213987da915Sopenharmony_ci u32 step; 1214987da915Sopenharmony_ci u32 used; 1215987da915Sopenharmony_ci 1216987da915Sopenharmony_ci for (action=firstaction; action; action=action->next) { 1217987da915Sopenharmony_ci logr = &action->record; 1218987da915Sopenharmony_ci buf = ((const char*)logr) + get_redo_offset(logr); 1219987da915Sopenharmony_ci length = le16_to_cpu(logr->redo_length); 1220987da915Sopenharmony_ci switch (le16_to_cpu(action->record.redo_operation)) { 1221987da915Sopenharmony_ci case OpenNonResidentAttribute : 1222987da915Sopenharmony_ci extra = get_extra_offset(logr) 1223987da915Sopenharmony_ci - get_redo_offset(logr); 1224987da915Sopenharmony_ci if (logr->undo_length) { 1225987da915Sopenharmony_ci len = le32_to_cpu(logr->client_data_length) 1226987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ 1227987da915Sopenharmony_ci - get_extra_offset(logr); 1228987da915Sopenharmony_ci /* this gives a length aligned modulo 8 */ 1229987da915Sopenharmony_ci len = fixnamelen(&buf[extra], len); 1230987da915Sopenharmony_ci } else 1231987da915Sopenharmony_ci len = 0; 1232987da915Sopenharmony_ci pa = getattrentry(le16_to_cpu(logr->target_attribute), 1233987da915Sopenharmony_ci len); 1234987da915Sopenharmony_ci if (pa) { 1235987da915Sopenharmony_ci copy_attribute(pa, buf, length); 1236987da915Sopenharmony_ci pa->namelen = len; 1237987da915Sopenharmony_ci if (len) { 1238987da915Sopenharmony_ci memcpy(pa->name,&buf[extra],len); 1239987da915Sopenharmony_ci } 1240987da915Sopenharmony_ci } 1241987da915Sopenharmony_ci break; 1242987da915Sopenharmony_ci case OpenAttributeTableDump : 1243987da915Sopenharmony_ci i = 24; 1244987da915Sopenharmony_ci step = getle16(buf, 8); 1245987da915Sopenharmony_ci used = getle16(buf, 12); 1246987da915Sopenharmony_ci /* 1247987da915Sopenharmony_ci * Changed from Win10, formerly we got step = 44. 1248987da915Sopenharmony_ci * The record layout has also changed 1249987da915Sopenharmony_ci */ 1250987da915Sopenharmony_ci for (x=0; (x<used) && (i<length); i+=step, x++) { 1251987da915Sopenharmony_ci pa = getattrentry(i,0); 1252987da915Sopenharmony_ci if (pa) { 1253987da915Sopenharmony_ci copy_attribute(pa, buf + i, step); 1254987da915Sopenharmony_ci } 1255987da915Sopenharmony_ci } 1256987da915Sopenharmony_ci break; 1257987da915Sopenharmony_ci case AttributeNamesDump : 1258987da915Sopenharmony_ci i = 8; 1259987da915Sopenharmony_ci if (i < length) { 1260987da915Sopenharmony_ci x = 0; 1261987da915Sopenharmony_ci do { 1262987da915Sopenharmony_ci len = getle16(buf, i + 2); 1263987da915Sopenharmony_ci key = getle16(buf, i); 1264987da915Sopenharmony_ci if (len > 510) { 1265987da915Sopenharmony_ci printf("** Error : bad" 1266987da915Sopenharmony_ci " attribute name" 1267987da915Sopenharmony_ci " length %d\n", 1268987da915Sopenharmony_ci len); 1269987da915Sopenharmony_ci key = 0; 1270987da915Sopenharmony_ci } 1271987da915Sopenharmony_ci if (key) { /* Apparently, may have to stop before reaching the end */ 1272987da915Sopenharmony_ci pa = getattrentry(key,len); 1273987da915Sopenharmony_ci if (pa) { 1274987da915Sopenharmony_ci pa->namelen = len; 1275987da915Sopenharmony_ci memcpy(pa->name, 1276987da915Sopenharmony_ci &buf[i+4],len); 1277987da915Sopenharmony_ci } 1278987da915Sopenharmony_ci i += len + 6; 1279987da915Sopenharmony_ci x++; 1280987da915Sopenharmony_ci } 1281987da915Sopenharmony_ci } while (key && (i < length)); 1282987da915Sopenharmony_ci } 1283987da915Sopenharmony_ci break; 1284987da915Sopenharmony_ci default : 1285987da915Sopenharmony_ci break; 1286987da915Sopenharmony_ci } 1287987da915Sopenharmony_ci } 1288987da915Sopenharmony_ci return (0); 1289987da915Sopenharmony_ci} 1290987da915Sopenharmony_ci 1291987da915Sopenharmony_ci/* 1292987da915Sopenharmony_ci * Display a fixup 1293987da915Sopenharmony_ci */ 1294987da915Sopenharmony_ci 1295987da915Sopenharmony_cistatic void fixup(CONTEXT *ctx, const LOG_RECORD *logr, const char *buf, 1296987da915Sopenharmony_ci BOOL redo) 1297987da915Sopenharmony_ci{ 1298987da915Sopenharmony_ci struct ATTR *pa; 1299987da915Sopenharmony_ci int action; 1300987da915Sopenharmony_ci int attr; 1301987da915Sopenharmony_ci int offs; 1302987da915Sopenharmony_ci s32 length; 1303987da915Sopenharmony_ci int extra; 1304987da915Sopenharmony_ci s32 i; 1305987da915Sopenharmony_ci int p; 1306987da915Sopenharmony_ci s32 base; 1307987da915Sopenharmony_ci u16 firstpos; /* position of first mft attribute */ 1308987da915Sopenharmony_ci le32 v; 1309987da915Sopenharmony_ci ATTR_TYPES mftattr; 1310987da915Sopenharmony_ci le64 w; 1311987da915Sopenharmony_ci le64 inode; 1312987da915Sopenharmony_ci le64 size; 1313987da915Sopenharmony_ci int lth; 1314987da915Sopenharmony_ci int len; 1315987da915Sopenharmony_ci 1316987da915Sopenharmony_ci attr = le16_to_cpu(logr->target_attribute); 1317987da915Sopenharmony_ci offs = le16_to_cpu(logr->attribute_offset); 1318987da915Sopenharmony_ci if (redo) { 1319987da915Sopenharmony_ci action = le16_to_cpu(logr->redo_operation); 1320987da915Sopenharmony_ci length = le16_to_cpu(logr->redo_length); 1321987da915Sopenharmony_ci } else { 1322987da915Sopenharmony_ci action = le16_to_cpu(logr->undo_operation); 1323987da915Sopenharmony_ci length = le16_to_cpu(logr->undo_length); 1324987da915Sopenharmony_ci } 1325987da915Sopenharmony_ci if (redo) 1326987da915Sopenharmony_ci printf("redo fixup %dR %s attr 0x%x offs 0x%x\n", 1327987da915Sopenharmony_ci actionnum, actionname(action), attr, offs); 1328987da915Sopenharmony_ci else 1329987da915Sopenharmony_ci printf("undo fixup %dU %s attr 0x%x offs 0x%x\n", 1330987da915Sopenharmony_ci actionnum, actionname(action), attr, offs); 1331987da915Sopenharmony_ci switch (action) { 1332987da915Sopenharmony_ci case InitializeFileRecordSegment : /* 2 */ 1333987da915Sopenharmony_ci /* 1334987da915Sopenharmony_ci * When this is a redo (with a NoOp undo), the 1335987da915Sopenharmony_ci * full MFT record is logged. 1336987da915Sopenharmony_ci * When this is an undo (with DeallocateFileRecordSegment redo), 1337987da915Sopenharmony_ci * only the header of the MFT record is logged. 1338987da915Sopenharmony_ci */ 1339987da915Sopenharmony_ci if (!ctx->vol && !mftrecsz && (length > 8)) { 1340987da915Sopenharmony_ci /* mftrecsz can be determined from usa_count */ 1341987da915Sopenharmony_ci mftrecsz = (getle16(buf,6) - 1)*512; 1342987da915Sopenharmony_ci mftrecbits = 1; 1343987da915Sopenharmony_ci while ((u32)(1 << mftrecbits) < mftrecsz) 1344987da915Sopenharmony_ci mftrecbits++; 1345987da915Sopenharmony_ci } 1346987da915Sopenharmony_ci printf(" new base MFT record, attr 0x%x (%s)\n",attr,attrname(attr)); 1347987da915Sopenharmony_ci printf(" inode %lld\n", 1348987da915Sopenharmony_ci (((long long)sle64_to_cpu(logr->target_vcn) 1349987da915Sopenharmony_ci << clusterbits) 1350987da915Sopenharmony_ci + (le16_to_cpu(logr->cluster_index) << 9)) 1351987da915Sopenharmony_ci >> mftrecbits); 1352987da915Sopenharmony_ci if (length >= 18) 1353987da915Sopenharmony_ci printf(" seq number 0x%04x\n",(int)getle16(buf, 16)); 1354987da915Sopenharmony_ci if (length >= 20) 1355987da915Sopenharmony_ci printf(" link count %d\n",(int)getle16(buf, 18)); 1356987da915Sopenharmony_ci if (length >= 24) { 1357987da915Sopenharmony_ci u16 flags; 1358987da915Sopenharmony_ci 1359987da915Sopenharmony_ci flags = getle16(buf, 22); 1360987da915Sopenharmony_ci printf(" flags 0x%x",(int)flags); 1361987da915Sopenharmony_ci switch (flags & 3) { 1362987da915Sopenharmony_ci case 1 : 1363987da915Sopenharmony_ci printf(" (file in use)\n"); 1364987da915Sopenharmony_ci break; 1365987da915Sopenharmony_ci case 3 : 1366987da915Sopenharmony_ci printf(" (directory in use)\n"); 1367987da915Sopenharmony_ci break; 1368987da915Sopenharmony_ci default : 1369987da915Sopenharmony_ci printf(" (not in use)\n"); 1370987da915Sopenharmony_ci break; 1371987da915Sopenharmony_ci } 1372987da915Sopenharmony_ci } 1373987da915Sopenharmony_ci base = getle16(buf, 4) + ((getle16(buf, 6)*2 - 1) | 7) + 1; 1374987da915Sopenharmony_ci while (base < length) { 1375987da915Sopenharmony_ci mftattr = feedle32(buf, base); 1376987da915Sopenharmony_ci printf(" attrib 0x%lx (%s) at offset 0x%x\n", 1377987da915Sopenharmony_ci (long)le32_to_cpu(mftattr), 1378987da915Sopenharmony_ci mftattrname(mftattr), (int)base); 1379987da915Sopenharmony_ci if (mftattr == AT_FILE_NAME) { 1380987da915Sopenharmony_ci showname(" name ",&buf[base + 90], 1381987da915Sopenharmony_ci buf[base + 88] & 255); 1382987da915Sopenharmony_ci inode = feedle64(buf, base + 24); 1383987da915Sopenharmony_ci printf(" parent dir inode %lld\n", 1384987da915Sopenharmony_ci (long long)MREF(le64_to_cpu(inode))); 1385987da915Sopenharmony_ci } 1386987da915Sopenharmony_ci lth = getle32(buf, base + 4); 1387987da915Sopenharmony_ci if ((lth <= 0) || (lth & 7)) 1388987da915Sopenharmony_ci base = length; 1389987da915Sopenharmony_ci else 1390987da915Sopenharmony_ci base += lth; 1391987da915Sopenharmony_ci } 1392987da915Sopenharmony_ci break; 1393987da915Sopenharmony_ci case DeallocateFileRecordSegment : /* 3 */ 1394987da915Sopenharmony_ci printf(" free base MFT record, attr 0x%x (%s)\n", 1395987da915Sopenharmony_ci attr,attrname(attr)); 1396987da915Sopenharmony_ci printf(" inode %lld\n", 1397987da915Sopenharmony_ci (((long long)sle64_to_cpu(logr->target_vcn) << clusterbits) 1398987da915Sopenharmony_ci + (le16_to_cpu(logr->cluster_index) << 9)) >> mftrecbits); 1399987da915Sopenharmony_ci break; 1400987da915Sopenharmony_ci case CreateAttribute : /* 5 */ 1401987da915Sopenharmony_ci pa = getattrentry(attr,0); 1402987da915Sopenharmony_ci base = 24; 1403987da915Sopenharmony_ci /* Assume the beginning of the attribute is always present */ 1404987da915Sopenharmony_ci switch (getle32(buf,0)) { 1405987da915Sopenharmony_ci case 0x30 : 1406987da915Sopenharmony_ci printf(" create file name, attr 0x%x\n",attr); 1407987da915Sopenharmony_ci if (pa) 1408987da915Sopenharmony_ci showattribute(" ",pa); 1409987da915Sopenharmony_ci showname(" file ", 1410987da915Sopenharmony_ci &buf[base + 66],buf[base + 64] & 255); 1411987da915Sopenharmony_ci if (base >= -8) 1412987da915Sopenharmony_ci showdate(" created ",feedle64(buf,base + 8)); 1413987da915Sopenharmony_ci if (base >= -16) 1414987da915Sopenharmony_ci showdate(" modified ",feedle64(buf,base + 16)); 1415987da915Sopenharmony_ci if (base >= -24) 1416987da915Sopenharmony_ci showdate(" changed ",feedle64(buf,base + 24)); 1417987da915Sopenharmony_ci if (base >= -32) 1418987da915Sopenharmony_ci showdate(" read ",feedle64(buf,base + 32)); 1419987da915Sopenharmony_ci size = feedle64(buf,base + 40); 1420987da915Sopenharmony_ci printf(" allocated size %lld\n", 1421987da915Sopenharmony_ci (long long)le64_to_cpu(size)); 1422987da915Sopenharmony_ci size = feedle64(buf,base + 48); 1423987da915Sopenharmony_ci printf(" real size %lld\n", 1424987da915Sopenharmony_ci (long long)le64_to_cpu(size)); 1425987da915Sopenharmony_ci v = feedle32(buf,base + 56); 1426987da915Sopenharmony_ci printf(" DOS flags 0x%lx\n", 1427987da915Sopenharmony_ci (long)le32_to_cpu(v)); 1428987da915Sopenharmony_ci break; 1429987da915Sopenharmony_ci case 0x80 : 1430987da915Sopenharmony_ci printf(" create a data stream, attr 0x%x\n",attr); 1431987da915Sopenharmony_ci break; 1432987da915Sopenharmony_ci case 0xc0 : 1433987da915Sopenharmony_ci printf(" create reparse data\n"); 1434987da915Sopenharmony_ci if (pa) 1435987da915Sopenharmony_ci showattribute(" ",pa); 1436987da915Sopenharmony_ci printf(" tag 0x%lx\n",(long)getle32(buf, base)); 1437987da915Sopenharmony_ci showname(" print name ", 1438987da915Sopenharmony_ci &buf[base + 20 + getle16(buf, base + 12)], 1439987da915Sopenharmony_ci getle16(buf, base + 14)/2); 1440987da915Sopenharmony_ci break; 1441987da915Sopenharmony_ci } 1442987da915Sopenharmony_ci break; 1443987da915Sopenharmony_ci case UpdateResidentValue : /* 7 */ 1444987da915Sopenharmony_ci /* 1445987da915Sopenharmony_ci * The record offset designates the mft attribute offset, 1446987da915Sopenharmony_ci * offs and length define a right-justified window in this 1447987da915Sopenharmony_ci * attribute. 1448987da915Sopenharmony_ci * At this stage, we do not know which kind of mft 1449987da915Sopenharmony_ci * attribute this is about, we assume this is standard 1450987da915Sopenharmony_ci * information when it is the first attribute in the 1451987da915Sopenharmony_ci * record. 1452987da915Sopenharmony_ci */ 1453987da915Sopenharmony_ci base = 0x18 - offs; /* p 8 */ 1454987da915Sopenharmony_ci pa = getattrentry(attr,0); 1455987da915Sopenharmony_ci firstpos = 0x30 + (((mftrecsz/512 + 1)*2 - 1 ) | 7) + 1; 1456987da915Sopenharmony_ci if (pa 1457987da915Sopenharmony_ci && !pa->inode 1458987da915Sopenharmony_ci && (pa->type == const_cpu_to_le32(0x80)) 1459987da915Sopenharmony_ci && !(offs & 3) 1460987da915Sopenharmony_ci && (le16_to_cpu(logr->record_offset) == firstpos)) { 1461987da915Sopenharmony_ci printf(" set standard information, attr 0x%x\n",attr); 1462987da915Sopenharmony_ci showattribute(" ",pa); 1463987da915Sopenharmony_ci if ((base >= 0) && ((base + 8) <= length)) 1464987da915Sopenharmony_ci showdate(" created ", 1465987da915Sopenharmony_ci feedle64(buf,base)); 1466987da915Sopenharmony_ci if (((base + 8) >= 0) && ((base + 16) <= length)) 1467987da915Sopenharmony_ci showdate(" modified ", 1468987da915Sopenharmony_ci feedle64(buf,base + 8)); 1469987da915Sopenharmony_ci if (((base + 16) >= 0) && ((base + 24) <= length)) 1470987da915Sopenharmony_ci showdate(" changed ", 1471987da915Sopenharmony_ci feedle64(buf,base + 16)); 1472987da915Sopenharmony_ci if (((base + 24) >= 0) && ((base + 32) <= length)) 1473987da915Sopenharmony_ci showdate(" read ", 1474987da915Sopenharmony_ci feedle64(buf,base + 24)); 1475987da915Sopenharmony_ci if (((base + 32) >= 0) && ((base + 36) <= length)) { 1476987da915Sopenharmony_ci v = feedle32(buf, base + 32); 1477987da915Sopenharmony_ci printf(" DOS flags 0x%lx\n", 1478987da915Sopenharmony_ci (long)le32_to_cpu(v)); 1479987da915Sopenharmony_ci } 1480987da915Sopenharmony_ci if (((base + 52) >= 0) && ((base + 56) <= length)) { 1481987da915Sopenharmony_ci v = feedle32(buf, base + 52); 1482987da915Sopenharmony_ci printf(" security id 0x%lx\n", 1483987da915Sopenharmony_ci (long)le32_to_cpu(v)); 1484987da915Sopenharmony_ci } 1485987da915Sopenharmony_ci if (((base + 64) >= 0) && ((base + 72) <= length)) { 1486987da915Sopenharmony_ci /* 1487987da915Sopenharmony_ci * This is badly aligned for Sparc when 1488987da915Sopenharmony_ci * stamps not present and base == 52 1489987da915Sopenharmony_ci */ 1490987da915Sopenharmony_ci memcpy(&w, &buf[base + 64], 8); 1491987da915Sopenharmony_ci printf(" journal idx 0x%llx\n", 1492987da915Sopenharmony_ci (long long)le64_to_cpu(w)); 1493987da915Sopenharmony_ci } 1494987da915Sopenharmony_ci } else { 1495987da915Sopenharmony_ci printf(" set an MFT attribute at offset 0x%x, attr 0x%x\n", 1496987da915Sopenharmony_ci (int)offs, attr); 1497987da915Sopenharmony_ci if (pa) 1498987da915Sopenharmony_ci showattribute(" ",pa); 1499987da915Sopenharmony_ci } 1500987da915Sopenharmony_ci break; 1501987da915Sopenharmony_ci case UpdateNonResidentValue : /* 8 */ 1502987da915Sopenharmony_ci printf(" set attr 0x%x (%s)\n",attr,attrname(attr)); 1503987da915Sopenharmony_ci pa = getattrentry(attr,0); 1504987da915Sopenharmony_ci if (pa) 1505987da915Sopenharmony_ci showattribute(" ",pa); 1506987da915Sopenharmony_ci base = 0; /* ? */ 1507987da915Sopenharmony_ci// Should not be decoded, unless attr is of identified type (I30, ...) 1508987da915Sopenharmony_ci if (pa && (pa->namelen == 8) && !memcmp(pa->name, SDS, 8)) { 1509987da915Sopenharmony_ci if (length >= 4) 1510987da915Sopenharmony_ci printf(" security hash 0x%lx\n", 1511987da915Sopenharmony_ci (long)getle32(buf, 0)); 1512987da915Sopenharmony_ci if (length >= 8) 1513987da915Sopenharmony_ci printf(" security id 0x%lx\n", 1514987da915Sopenharmony_ci (long)getle32(buf, 4)); 1515987da915Sopenharmony_ci if (length >= 20) 1516987da915Sopenharmony_ci printf(" entry size %ld\n", 1517987da915Sopenharmony_ci (long)getle32(buf, 16)); 1518987da915Sopenharmony_ci } 1519987da915Sopenharmony_ci if (pa && (pa->namelen == 8) && !memcmp(pa->name, I30, 8)) { 1520987da915Sopenharmony_ci if (!memcmp(buf, "INDX", 4)) 1521987da915Sopenharmony_ci base = 64; /* full record */ 1522987da915Sopenharmony_ci else 1523987da915Sopenharmony_ci base = 0; /* entries */ 1524987da915Sopenharmony_ci inode = feedle64(buf, base); 1525987da915Sopenharmony_ci printf(" inode %lld\n", 1526987da915Sopenharmony_ci (long long)MREF(le64_to_cpu(inode))); 1527987da915Sopenharmony_ci inode = feedle64(buf, base + 16); 1528987da915Sopenharmony_ci printf(" parent inode %lld\n", 1529987da915Sopenharmony_ci (long long)MREF(le64_to_cpu(inode))); 1530987da915Sopenharmony_ci showname(" file ",&buf[base + 82], 1531987da915Sopenharmony_ci buf[base + 80] & 255); 1532987da915Sopenharmony_ci showdate(" date ",feedle64(buf, base + 32)); 1533987da915Sopenharmony_ci } 1534987da915Sopenharmony_ci break; 1535987da915Sopenharmony_ci case UpdateMappingPairs : /* 9 */ 1536987da915Sopenharmony_ci printf(" update runlist in attr 0x%x (%s)\n",attr, 1537987da915Sopenharmony_ci attrname(attr)); 1538987da915Sopenharmony_ci /* argument is a compressed runlist (or part of it ?) */ 1539987da915Sopenharmony_ci /* stop when finding 00 */ 1540987da915Sopenharmony_ci break; 1541987da915Sopenharmony_ci case SetNewAttributeSizes : /* 11 */ 1542987da915Sopenharmony_ci printf(" set sizes in attr 0x%x (%s)\n",attr,attrname(attr)); 1543987da915Sopenharmony_ci base = 0; /* left justified ? */ 1544987da915Sopenharmony_ci size = feedle64(buf,0); 1545987da915Sopenharmony_ci printf(" allocated size %lld\n",(long long)le64_to_cpu(size)); 1546987da915Sopenharmony_ci size = feedle64(buf,8); 1547987da915Sopenharmony_ci printf(" real size %lld\n",(long long)le64_to_cpu(size)); 1548987da915Sopenharmony_ci size = feedle64(buf,16); 1549987da915Sopenharmony_ci printf(" initialized size %lld\n",(long long)le64_to_cpu(size)); 1550987da915Sopenharmony_ci break; 1551987da915Sopenharmony_ci case AddIndexEntryRoot : /* 12 */ 1552987da915Sopenharmony_ci case AddIndexEntryAllocation : /* 14 */ 1553987da915Sopenharmony_ci /* 1554987da915Sopenharmony_ci * The record offset designates the mft attribute offset, 1555987da915Sopenharmony_ci * offs and length define a left-justified window in this 1556987da915Sopenharmony_ci * attribute. 1557987da915Sopenharmony_ci */ 1558987da915Sopenharmony_ci if (action == AddIndexEntryRoot) 1559987da915Sopenharmony_ci printf(" add resident index entry, attr 0x%x\n",attr); 1560987da915Sopenharmony_ci else 1561987da915Sopenharmony_ci printf(" add nonres index entry, attr 0x%x\n",attr); 1562987da915Sopenharmony_ci pa = getattrentry(attr,0); 1563987da915Sopenharmony_ci if (pa) 1564987da915Sopenharmony_ci showattribute(" ",pa); 1565987da915Sopenharmony_ci base = 0; 1566987da915Sopenharmony_ci p = getle16(buf, base + 8); 1567987da915Sopenharmony_ci /* index types may be discriminated by inode in base+0 */ 1568987da915Sopenharmony_ci switch (p) { /* size of index entry */ 1569987da915Sopenharmony_ci case 32 : /* $R entry */ 1570987da915Sopenharmony_ci memcpy(&inode, &buf[base + 20], 8); /* bad align */ 1571987da915Sopenharmony_ci printf(" $R reparse index\n"); 1572987da915Sopenharmony_ci printf(" reparsed inode 0x%016llx\n", 1573987da915Sopenharmony_ci (long long)le64_to_cpu(inode)); 1574987da915Sopenharmony_ci printf(" reparse tag 0x%lx\n", 1575987da915Sopenharmony_ci (long)getle32(buf, 16)); 1576987da915Sopenharmony_ci break; 1577987da915Sopenharmony_ci case 40 : /* $SII entry */ 1578987da915Sopenharmony_ci printf(" $SII security id index\n"); 1579987da915Sopenharmony_ci printf(" security id 0x%lx\n", 1580987da915Sopenharmony_ci (long)getle32(buf, 16)); 1581987da915Sopenharmony_ci printf(" security hash 0x%lx\n", 1582987da915Sopenharmony_ci (long)getle32(buf, 20)); 1583987da915Sopenharmony_ci break; 1584987da915Sopenharmony_ci case 48 : /* $SDH entry */ 1585987da915Sopenharmony_ci printf(" $SDH security id index\n"); 1586987da915Sopenharmony_ci printf(" security id 0x%lx\n", 1587987da915Sopenharmony_ci (long)getle32(buf, 20)); 1588987da915Sopenharmony_ci printf(" security hash 0x%lx\n", 1589987da915Sopenharmony_ci (long)getle32(buf, 16)); 1590987da915Sopenharmony_ci break; 1591987da915Sopenharmony_ci default : 1592987da915Sopenharmony_ci /* directory index are at least 84 bytes long, ntfsdoc p 98 */ 1593987da915Sopenharmony_ci /* have everything needed to create the index */ 1594987da915Sopenharmony_ci lth = buf[base + 80] & 255; 1595987da915Sopenharmony_ci /* consistency of file name length */ 1596987da915Sopenharmony_ci if (getle16(buf,10) == (u32)(2*lth + 66)) { 1597987da915Sopenharmony_ci printf(" directory index\n"); 1598987da915Sopenharmony_ci inode = feedle64(buf,16); 1599987da915Sopenharmony_ci printf(" parent dir inode %lld\n", 1600987da915Sopenharmony_ci (long long)MREF(le64_to_cpu(inode))); 1601987da915Sopenharmony_ci if (feedle32(buf,72) 1602987da915Sopenharmony_ci & const_cpu_to_le32(0x10000000)) 1603987da915Sopenharmony_ci showname(" file (dir) ", 1604987da915Sopenharmony_ci &buf[base + 82], 1605987da915Sopenharmony_ci buf[base + 80] & 255); 1606987da915Sopenharmony_ci else 1607987da915Sopenharmony_ci showname(" file ", 1608987da915Sopenharmony_ci &buf[base + 82], 1609987da915Sopenharmony_ci buf[base + 80] & 255); 1610987da915Sopenharmony_ci inode = feedle64(buf,0); 1611987da915Sopenharmony_ci printf(" file inode %lld\n", 1612987da915Sopenharmony_ci (long long)MREF(le64_to_cpu(inode))); 1613987da915Sopenharmony_ci size = feedle64(buf,64); 1614987da915Sopenharmony_ci printf(" file size %lld\n", 1615987da915Sopenharmony_ci (long long)le64_to_cpu(size)); 1616987da915Sopenharmony_ci showdate(" created ", 1617987da915Sopenharmony_ci feedle64(buf,base + 24)); 1618987da915Sopenharmony_ci showdate(" modified ", 1619987da915Sopenharmony_ci feedle64(buf,base + 32)); 1620987da915Sopenharmony_ci showdate(" changed ", 1621987da915Sopenharmony_ci feedle64(buf,base + 40)); 1622987da915Sopenharmony_ci showdate(" read ", 1623987da915Sopenharmony_ci feedle64(buf,base + 48)); 1624987da915Sopenharmony_ci } else 1625987da915Sopenharmony_ci printf(" unknown index type\n"); 1626987da915Sopenharmony_ci break; 1627987da915Sopenharmony_ci } 1628987da915Sopenharmony_ci break; 1629987da915Sopenharmony_ci case SetIndexEntryVcnRoot : /* 17 */ 1630987da915Sopenharmony_ci printf(" set vcn of non-resident index root, attr 0x%x\n", 1631987da915Sopenharmony_ci attr); 1632987da915Sopenharmony_ci pa = getattrentry(attr,0); 1633987da915Sopenharmony_ci if (pa) 1634987da915Sopenharmony_ci showattribute(" ",pa); 1635987da915Sopenharmony_ci printf(" vcn %lld\n", (long long)getle64(buf,0)); 1636987da915Sopenharmony_ci break; 1637987da915Sopenharmony_ci case UpdateFileNameRoot : /* 19 */ 1638987da915Sopenharmony_ci /* 1639987da915Sopenharmony_ci * Update an entry in a resident directory index. 1640987da915Sopenharmony_ci * The record offset designates the mft attribute offset, 1641987da915Sopenharmony_ci * offs and length define a right-justified window in this 1642987da915Sopenharmony_ci * attribute. 1643987da915Sopenharmony_ci */ 1644987da915Sopenharmony_ci printf(" set directory resident entry, attr 0x%x\n",attr); 1645987da915Sopenharmony_ci base = length - 0x50; 1646987da915Sopenharmony_ci pa = getattrentry(attr,0); 1647987da915Sopenharmony_ci if (pa) 1648987da915Sopenharmony_ci showattribute(" ",pa); 1649987da915Sopenharmony_ci if (pa 1650987da915Sopenharmony_ci && !pa->inode 1651987da915Sopenharmony_ci && (pa->type == const_cpu_to_le32(0x80)) 1652987da915Sopenharmony_ci && !(offs & 3)) { 1653987da915Sopenharmony_ci if (base >= -24) 1654987da915Sopenharmony_ci showdate(" created ",feedle64(buf, 1655987da915Sopenharmony_ci base + 24)); 1656987da915Sopenharmony_ci if (base >= -32) 1657987da915Sopenharmony_ci showdate(" modified ",feedle64(buf, 1658987da915Sopenharmony_ci base + 32)); 1659987da915Sopenharmony_ci if (base >= -40) 1660987da915Sopenharmony_ci showdate(" changed ",feedle64(buf, 1661987da915Sopenharmony_ci base + 40)); 1662987da915Sopenharmony_ci if (base >= -48) 1663987da915Sopenharmony_ci showdate(" read ",feedle64(buf, 1664987da915Sopenharmony_ci base + 48)); 1665987da915Sopenharmony_ci if (base >= -56) { 1666987da915Sopenharmony_ci size = feedle64(buf,base + 56); 1667987da915Sopenharmony_ci printf(" allocated size %lld\n", 1668987da915Sopenharmony_ci (long long)le64_to_cpu(size)); 1669987da915Sopenharmony_ci } 1670987da915Sopenharmony_ci if (base >= -64) { 1671987da915Sopenharmony_ci size = feedle64(buf,base + 64); 1672987da915Sopenharmony_ci printf(" real size %lld\n", 1673987da915Sopenharmony_ci (long long)le64_to_cpu(size)); 1674987da915Sopenharmony_ci } 1675987da915Sopenharmony_ci if (base > -72) { 1676987da915Sopenharmony_ci v = feedle32(buf,base + 72); 1677987da915Sopenharmony_ci printf(" DOS flags 0x%lx\n", 1678987da915Sopenharmony_ci (long)le32_to_cpu(v)); 1679987da915Sopenharmony_ci } 1680987da915Sopenharmony_ci } else { 1681987da915Sopenharmony_ci /* Usually caused by attr not yet defined */ 1682987da915Sopenharmony_ci if (pa && pa->type) 1683987da915Sopenharmony_ci printf("** Unexpected index parameters\n"); 1684987da915Sopenharmony_ci } 1685987da915Sopenharmony_ci break; 1686987da915Sopenharmony_ci case UpdateFileNameAllocation : /* 20 */ 1687987da915Sopenharmony_ci /* update entry in directory index */ 1688987da915Sopenharmony_ci /* only dates, sizes and attrib */ 1689987da915Sopenharmony_ci base = length - 64; /* p 12 */ 1690987da915Sopenharmony_ci printf(" set directory nonres entry, attr 0x%x\n",attr); 1691987da915Sopenharmony_ci pa = getattrentry(attr,0); 1692987da915Sopenharmony_ci if (pa) 1693987da915Sopenharmony_ci showattribute(" ",pa); 1694987da915Sopenharmony_ci if (base >= -8) 1695987da915Sopenharmony_ci showdate(" created ",feedle64(buf, base + 8)); 1696987da915Sopenharmony_ci if (base >= -16) 1697987da915Sopenharmony_ci showdate(" modified ",feedle64(buf, base + 16)); 1698987da915Sopenharmony_ci if (base >= -24) 1699987da915Sopenharmony_ci showdate(" changed ",feedle64(buf, base + 24)); 1700987da915Sopenharmony_ci if (base >= -32) 1701987da915Sopenharmony_ci showdate(" read ",*(const le64*)&buf[base + 32]); 1702987da915Sopenharmony_ci if (base >= -40) { 1703987da915Sopenharmony_ci size = feedle64(buf, base + 40); 1704987da915Sopenharmony_ci printf(" allocated size %lld\n", 1705987da915Sopenharmony_ci (long long)le64_to_cpu(size)); 1706987da915Sopenharmony_ci } 1707987da915Sopenharmony_ci if (base >= -48) { 1708987da915Sopenharmony_ci size = feedle64(buf, base + 48); 1709987da915Sopenharmony_ci printf(" real size %lld\n", 1710987da915Sopenharmony_ci (long long)le64_to_cpu(size)); 1711987da915Sopenharmony_ci } 1712987da915Sopenharmony_ci if (base >= -56) { 1713987da915Sopenharmony_ci v = feedle32(buf, base + 56); 1714987da915Sopenharmony_ci printf(" DOS flags 0x%lx\n",(long)le32_to_cpu(v)); 1715987da915Sopenharmony_ci } 1716987da915Sopenharmony_ci break; 1717987da915Sopenharmony_ci case SetBitsInNonResidentBitMap : /* 21 */ 1718987da915Sopenharmony_ci case ClearBitsInNonResidentBitMap : /* 22 */ 1719987da915Sopenharmony_ci if (action == SetBitsInNonResidentBitMap) 1720987da915Sopenharmony_ci printf(" SetBitsInNonResidentBitMap, attr 0x%x\n", 1721987da915Sopenharmony_ci attr); 1722987da915Sopenharmony_ci else 1723987da915Sopenharmony_ci printf(" ClearBitsInNonResidentBitMap, attr 0x%x\n", 1724987da915Sopenharmony_ci attr); 1725987da915Sopenharmony_ci pa = getattrentry(attr,0); 1726987da915Sopenharmony_ci if (pa) 1727987da915Sopenharmony_ci showattribute(" ",pa); 1728987da915Sopenharmony_ci v = feedle32(buf, 0); 1729987da915Sopenharmony_ci printf(" first bit %ld\n",(long)le32_to_cpu(v)); 1730987da915Sopenharmony_ci v = feedle32(buf, 4); 1731987da915Sopenharmony_ci printf(" bit count %ld\n",(long)le32_to_cpu(v)); 1732987da915Sopenharmony_ci break; 1733987da915Sopenharmony_ci case OpenNonResidentAttribute : /* 28 */ 1734987da915Sopenharmony_ci printf(" OpenNonResidentAttribute, attr 0x%x\n",attr); 1735987da915Sopenharmony_ci extra = get_extra_offset(logr) 1736987da915Sopenharmony_ci - (redo ? get_redo_offset(logr) 1737987da915Sopenharmony_ci : get_undo_offset(logr)); 1738987da915Sopenharmony_ci if (logr->undo_length) { 1739987da915Sopenharmony_ci len = le32_to_cpu(logr->client_data_length) 1740987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ 1741987da915Sopenharmony_ci - get_extra_offset(logr); 1742987da915Sopenharmony_ci /* this gives a length aligned modulo 8 */ 1743987da915Sopenharmony_ci len = fixnamelen(&buf[extra], len); 1744987da915Sopenharmony_ci } else 1745987da915Sopenharmony_ci len = 0; 1746987da915Sopenharmony_ci pa = getattrentry(attr,len); 1747987da915Sopenharmony_ci if (pa && redo) { 1748987da915Sopenharmony_ci /* 1749987da915Sopenharmony_ci * If this is a redo, collect the attribute data. 1750987da915Sopenharmony_ci * This should only be done when walking forward. 1751987da915Sopenharmony_ci */ 1752987da915Sopenharmony_ci copy_attribute(pa, buf, length); 1753987da915Sopenharmony_ci pa->namelen = len; 1754987da915Sopenharmony_ci if (len) 1755987da915Sopenharmony_ci memcpy(pa->name,&buf[extra],len); 1756987da915Sopenharmony_ci printf(" MFT attribute 0x%lx (%s)\n", 1757987da915Sopenharmony_ci (long)le32_to_cpu(pa->type), 1758987da915Sopenharmony_ci mftattrname(pa->type)); 1759987da915Sopenharmony_ci printf(" lsn 0x%016llx\n", 1760987da915Sopenharmony_ci (long long)pa->lsn); 1761987da915Sopenharmony_ci printf(" inode %lld\n", 1762987da915Sopenharmony_ci (long long)pa->inode); 1763987da915Sopenharmony_ci } 1764987da915Sopenharmony_ci if (logr->undo_length) 1765987da915Sopenharmony_ci showname(" extra : attr name ", &buf[extra], len/2); 1766987da915Sopenharmony_ci if (!redo && length) { 1767987da915Sopenharmony_ci printf(" * undo attr not shown\n"); 1768987da915Sopenharmony_ci } 1769987da915Sopenharmony_ci break; 1770987da915Sopenharmony_ci case OpenAttributeTableDump : /* 29 */ 1771987da915Sopenharmony_ci printf(" OpenAttributeTableDump, attr 0x%x (%s)\n", 1772987da915Sopenharmony_ci attr,attrname(attr)); 1773987da915Sopenharmony_ci i = 24; 1774987da915Sopenharmony_ci if (i < length) { 1775987da915Sopenharmony_ci int x; 1776987da915Sopenharmony_ci int more; 1777987da915Sopenharmony_ci int step; 1778987da915Sopenharmony_ci int used; 1779987da915Sopenharmony_ci 1780987da915Sopenharmony_ci step = getle16(buf, 8); 1781987da915Sopenharmony_ci used = getle16(buf, 12); 1782987da915Sopenharmony_ci /* 1783987da915Sopenharmony_ci * Changed from Win10, formerly we got step = 44. 1784987da915Sopenharmony_ci * The record layout has also changed 1785987da915Sopenharmony_ci */ 1786987da915Sopenharmony_ci if ((step != sizeof(ATTR_OLD)) 1787987da915Sopenharmony_ci && (step != sizeof(ATTR_NEW))) { 1788987da915Sopenharmony_ci printf(" ** Unexpected step %d\n",step); 1789987da915Sopenharmony_ci } 1790987da915Sopenharmony_ci more = 0; 1791987da915Sopenharmony_ci for (x=0; (x<used) && (i<length); i+=step, x++) { 1792987da915Sopenharmony_ci pa = getattrentry(i,0); 1793987da915Sopenharmony_ci if (pa) { 1794987da915Sopenharmony_ci copy_attribute(pa, &buf[i], step); 1795987da915Sopenharmony_ci if (x <= SHOWATTRS) { 1796987da915Sopenharmony_ci printf(" attr 0x%x inode %lld" 1797987da915Sopenharmony_ci " type %s", 1798987da915Sopenharmony_ci (int)i, 1799987da915Sopenharmony_ci (long long)pa->inode, 1800987da915Sopenharmony_ci mftattrname(pa->type)); 1801987da915Sopenharmony_ci if (pa->namelen) 1802987da915Sopenharmony_ci showname(" name ", 1803987da915Sopenharmony_ci (char*)pa->name, 1804987da915Sopenharmony_ci pa->namelen/2); 1805987da915Sopenharmony_ci else 1806987da915Sopenharmony_ci printf("\n"); 1807987da915Sopenharmony_ci } else 1808987da915Sopenharmony_ci more++; 1809987da915Sopenharmony_ci } 1810987da915Sopenharmony_ci } 1811987da915Sopenharmony_ci if (more) 1812987da915Sopenharmony_ci printf(" (%d more attrs not shown)\n",more); 1813987da915Sopenharmony_ci } 1814987da915Sopenharmony_ci break; 1815987da915Sopenharmony_ci case AttributeNamesDump : /* 30 */ 1816987da915Sopenharmony_ci printf(" AttributeNamesDump, attr 0x%x (%s)\n", 1817987da915Sopenharmony_ci attr,attrname(attr)); 1818987da915Sopenharmony_ci i = 8; 1819987da915Sopenharmony_ci if (i < length) { 1820987da915Sopenharmony_ci unsigned int l; 1821987da915Sopenharmony_ci unsigned int key; 1822987da915Sopenharmony_ci int x; 1823987da915Sopenharmony_ci int more; 1824987da915Sopenharmony_ci 1825987da915Sopenharmony_ci more = 0; 1826987da915Sopenharmony_ci x = 0; 1827987da915Sopenharmony_ci do { 1828987da915Sopenharmony_ci l = le16_to_cpu(*(const le16*)&buf[i+2]); 1829987da915Sopenharmony_ci key = le16_to_cpu(*(const le16*)&buf[i]); 1830987da915Sopenharmony_ci if (l > 510) { 1831987da915Sopenharmony_ci printf("** Error : bad attribute name" 1832987da915Sopenharmony_ci " length %d\n",l); 1833987da915Sopenharmony_ci key = 0; 1834987da915Sopenharmony_ci } 1835987da915Sopenharmony_ci /* Apparently, may have to stop before reaching the end */ 1836987da915Sopenharmony_ci if (key) { 1837987da915Sopenharmony_ci pa = getattrentry(key,l); 1838987da915Sopenharmony_ci if (pa) { 1839987da915Sopenharmony_ci pa->namelen = l; 1840987da915Sopenharmony_ci memcpy(pa->name,&buf[i+4],l); 1841987da915Sopenharmony_ci } 1842987da915Sopenharmony_ci if (x < SHOWATTRS) { 1843987da915Sopenharmony_ci printf(" attr 0x%x is",key); 1844987da915Sopenharmony_ci showname(" ",&buf[i+4],l/2); 1845987da915Sopenharmony_ci } else 1846987da915Sopenharmony_ci more++; 1847987da915Sopenharmony_ci i += l + 6; 1848987da915Sopenharmony_ci x++; 1849987da915Sopenharmony_ci } 1850987da915Sopenharmony_ci } while (key && (i < length)); 1851987da915Sopenharmony_ci if (more) 1852987da915Sopenharmony_ci printf(" (%d more attrs not shown)\n",more); 1853987da915Sopenharmony_ci } 1854987da915Sopenharmony_ci break; 1855987da915Sopenharmony_ci default : 1856987da915Sopenharmony_ci break; 1857987da915Sopenharmony_ci } 1858987da915Sopenharmony_ci} 1859987da915Sopenharmony_ci 1860987da915Sopenharmony_cistatic void detaillogr(CONTEXT *ctx, const LOG_RECORD *logr) 1861987da915Sopenharmony_ci{ 1862987da915Sopenharmony_ci u64 lcn; 1863987da915Sopenharmony_ci u64 baselcn; 1864987da915Sopenharmony_ci unsigned int i; 1865987da915Sopenharmony_ci unsigned int off; 1866987da915Sopenharmony_ci unsigned int undo; 1867987da915Sopenharmony_ci unsigned int redo; 1868987da915Sopenharmony_ci unsigned int extra; 1869987da915Sopenharmony_ci unsigned int end; 1870987da915Sopenharmony_ci unsigned int listsize; 1871987da915Sopenharmony_ci BOOL onmft; 1872987da915Sopenharmony_ci 1873987da915Sopenharmony_ci switch (logr->record_type) { 1874987da915Sopenharmony_ci case LOG_STANDARD : 1875987da915Sopenharmony_ci onmft = logr->cluster_index 1876987da915Sopenharmony_ci || acts_on_mft(le16_to_cpu(logr->redo_operation)) 1877987da915Sopenharmony_ci || acts_on_mft(le16_to_cpu(logr->undo_operation)); 1878987da915Sopenharmony_ci printf("redo_operation %04x %s\n", 1879987da915Sopenharmony_ci (int)le16_to_cpu(logr->redo_operation), 1880987da915Sopenharmony_ci actionname(le16_to_cpu(logr->redo_operation))); 1881987da915Sopenharmony_ci printf("undo_operation %04x %s\n", 1882987da915Sopenharmony_ci (int)le16_to_cpu(logr->undo_operation), 1883987da915Sopenharmony_ci actionname(le16_to_cpu(logr->undo_operation))); 1884987da915Sopenharmony_ci printf("redo_offset %04x\n", 1885987da915Sopenharmony_ci (int)le16_to_cpu(logr->redo_offset)); 1886987da915Sopenharmony_ci printf("redo_length %04x\n", 1887987da915Sopenharmony_ci (int)le16_to_cpu(logr->redo_length)); 1888987da915Sopenharmony_ci printf("undo_offset %04x\n", 1889987da915Sopenharmony_ci (int)le16_to_cpu(logr->undo_offset)); 1890987da915Sopenharmony_ci printf("undo_length %04x\n", 1891987da915Sopenharmony_ci (int)le16_to_cpu(logr->undo_length)); 1892987da915Sopenharmony_ci printf("target_attribute %04x\n", 1893987da915Sopenharmony_ci (int)le16_to_cpu(logr->target_attribute)); 1894987da915Sopenharmony_ci printf("lcns_to_follow %04x\n", 1895987da915Sopenharmony_ci (int)le16_to_cpu(logr->lcns_to_follow)); 1896987da915Sopenharmony_ci printf("record_offset %04x\n", 1897987da915Sopenharmony_ci (int)le16_to_cpu(logr->record_offset)); 1898987da915Sopenharmony_ci printf("attribute_offset %04x\n", 1899987da915Sopenharmony_ci (int)le16_to_cpu(logr->attribute_offset)); 1900987da915Sopenharmony_ci printf("cluster_index %04x\n", 1901987da915Sopenharmony_ci (int)le16_to_cpu(logr->cluster_index)); 1902987da915Sopenharmony_ci printf("attribute_flags %04x\n", 1903987da915Sopenharmony_ci (int)le16_to_cpu(logr->attribute_flags)); 1904987da915Sopenharmony_ci if (mftrecbits && onmft) 1905987da915Sopenharmony_ci printf("target_vcn %016llx (inode %lld)\n", 1906987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->target_vcn), 1907987da915Sopenharmony_ci (((long long)sle64_to_cpu(logr->target_vcn) 1908987da915Sopenharmony_ci << clusterbits) 1909987da915Sopenharmony_ci + (le16_to_cpu(logr->cluster_index) << 9)) 1910987da915Sopenharmony_ci >> mftrecbits); 1911987da915Sopenharmony_ci else 1912987da915Sopenharmony_ci printf("target_vcn %016llx\n", 1913987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->target_vcn)); 1914987da915Sopenharmony_ci /* Compute a base for the current run of mft */ 1915987da915Sopenharmony_ci baselcn = sle64_to_cpu(logr->lcn_list[0]) 1916987da915Sopenharmony_ci - sle64_to_cpu(logr->target_vcn); 1917987da915Sopenharmony_ci for (i=0; i<le16_to_cpu(logr->lcns_to_follow) 1918987da915Sopenharmony_ci && (i<SHOWLISTS); i++) { 1919987da915Sopenharmony_ci lcn = sle64_to_cpu(logr->lcn_list[i]); 1920987da915Sopenharmony_ci printf(" (%d offs 0x%x) lcn %016llx",i, 1921987da915Sopenharmony_ci (int)(8*i + sizeof(LOG_RECORD) - 8), 1922987da915Sopenharmony_ci (long long)lcn); 1923987da915Sopenharmony_ci lcn &= 0xffffffffffffULL; 1924987da915Sopenharmony_ci if (mftrecsz && onmft) { 1925987da915Sopenharmony_ci if (clustersz > mftrecsz) 1926987da915Sopenharmony_ci printf(" (MFT records for inodes" 1927987da915Sopenharmony_ci " %lld-%lld)\n", 1928987da915Sopenharmony_ci (long long)((lcn - baselcn) 1929987da915Sopenharmony_ci *clustersz/mftrecsz), 1930987da915Sopenharmony_ci (long long)((lcn + 1 - baselcn) 1931987da915Sopenharmony_ci *clustersz/mftrecsz - 1)); 1932987da915Sopenharmony_ci else 1933987da915Sopenharmony_ci printf(" (MFT record for inode %lld)\n", 1934987da915Sopenharmony_ci (long long)((lcn - baselcn) 1935987da915Sopenharmony_ci *clustersz/mftrecsz)); 1936987da915Sopenharmony_ci printf(" assuming record for inode %lld\n", 1937987da915Sopenharmony_ci (long long)((lcn - baselcn) 1938987da915Sopenharmony_ci *clustersz/mftrecsz 1939987da915Sopenharmony_ci + (le16_to_cpu(logr->cluster_index) 1940987da915Sopenharmony_ci >> 1))); 1941987da915Sopenharmony_ci } else 1942987da915Sopenharmony_ci printf("\n"); 1943987da915Sopenharmony_ci } 1944987da915Sopenharmony_ci /* 1945987da915Sopenharmony_ci * redo_offset and undo_offset are considered unsafe 1946987da915Sopenharmony_ci * (actually they are safe when you know the logic) 1947987da915Sopenharmony_ci * 2) redo : redo (defined by redo_offset) 1948987da915Sopenharmony_ci * 3) undo : undo (defined by undo_offset) 1949987da915Sopenharmony_ci * 4) extra : unknown data (end of undo to data_length) 1950987da915Sopenharmony_ci */ 1951987da915Sopenharmony_ci end = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; 1952987da915Sopenharmony_ci if (logr->redo_length && logr->undo_length) 1953987da915Sopenharmony_ci { 1954987da915Sopenharmony_ci /* both undo and redo are present */ 1955987da915Sopenharmony_ci if (le16_to_cpu(logr->undo_offset) <= 1956987da915Sopenharmony_ci le16_to_cpu(logr->redo_offset)) 1957987da915Sopenharmony_ci { 1958987da915Sopenharmony_ci undo = sizeof(LOG_RECORD) - 8 1959987da915Sopenharmony_ci + 8*le16_to_cpu(logr->lcns_to_follow); 1960987da915Sopenharmony_ci if (logr->redo_offset == logr->undo_offset) 1961987da915Sopenharmony_ci redo = undo; 1962987da915Sopenharmony_ci else 1963987da915Sopenharmony_ci redo = undo + ((le16_to_cpu(logr->undo_length) - 1) | 7) + 1; 1964987da915Sopenharmony_ci extra = redo + ((le16_to_cpu(logr->redo_length) - 1) | 7) + 1; 1965987da915Sopenharmony_ci } 1966987da915Sopenharmony_ci else 1967987da915Sopenharmony_ci { 1968987da915Sopenharmony_ci redo = sizeof(LOG_RECORD) - 8 1969987da915Sopenharmony_ci + 8*le16_to_cpu(logr->lcns_to_follow); 1970987da915Sopenharmony_ci undo = redo + ((le16_to_cpu(logr->redo_length) - 1) | 7) + 1; 1971987da915Sopenharmony_ci extra = undo + ((le16_to_cpu(logr->undo_length) - 1) | 7) + 1; 1972987da915Sopenharmony_ci } 1973987da915Sopenharmony_ci } 1974987da915Sopenharmony_ci else 1975987da915Sopenharmony_ci if (logr->redo_length) 1976987da915Sopenharmony_ci { 1977987da915Sopenharmony_ci /* redo and not undo */ 1978987da915Sopenharmony_ci redo = undo = sizeof(LOG_RECORD) - 8 1979987da915Sopenharmony_ci + 8*le16_to_cpu(logr->lcns_to_follow); 1980987da915Sopenharmony_ci extra = redo + ((le16_to_cpu(logr->redo_length) - 1) | 7) + 1; 1981987da915Sopenharmony_ci } 1982987da915Sopenharmony_ci else 1983987da915Sopenharmony_ci { 1984987da915Sopenharmony_ci /* optional undo and not redo */ 1985987da915Sopenharmony_ci redo = undo = sizeof(LOG_RECORD) - 8 1986987da915Sopenharmony_ci + 8*le16_to_cpu(logr->lcns_to_follow); 1987987da915Sopenharmony_ci extra = undo + ((le16_to_cpu(logr->undo_length) - 1) | 7) + 1; 1988987da915Sopenharmony_ci } 1989987da915Sopenharmony_ci 1990987da915Sopenharmony_ci printf("redo 0x%x (%u) undo 0x%x (%u) extra 0x%x (%d)\n", 1991987da915Sopenharmony_ci redo,(int)(((le16_to_cpu(logr->redo_length) - 1) | 7) + 1), 1992987da915Sopenharmony_ci undo,(int)(((le16_to_cpu(logr->undo_length) - 1) | 7) + 1), 1993987da915Sopenharmony_ci extra,(int)(end > extra ? end - extra : 0)); 1994987da915Sopenharmony_ci 1995987da915Sopenharmony_ci if (logr->redo_length && (get_redo_offset(logr) != redo)) 1996987da915Sopenharmony_ci printf("** Unexpected redo offset 0x%x %u (%u)\n", 1997987da915Sopenharmony_ci get_redo_offset(logr),(int)redo, 1998987da915Sopenharmony_ci (int)le16_to_cpu(logr->lcns_to_follow)); 1999987da915Sopenharmony_ci if (logr->undo_length && (get_undo_offset(logr) != undo)) 2000987da915Sopenharmony_ci printf("** Unexpected undo offset 0x%x %u (%u)\n", 2001987da915Sopenharmony_ci get_undo_offset(logr),(int)undo, 2002987da915Sopenharmony_ci (int)le16_to_cpu(logr->lcns_to_follow)); 2003987da915Sopenharmony_ci if (get_extra_offset(logr) != extra) 2004987da915Sopenharmony_ci printf("** Unexpected extra offset 0x%x %u (%u)\n", 2005987da915Sopenharmony_ci get_extra_offset(logr),(int)extra, 2006987da915Sopenharmony_ci (int)le16_to_cpu(logr->lcns_to_follow)); 2007987da915Sopenharmony_ci 2008987da915Sopenharmony_ci if (extra <= end) 2009987da915Sopenharmony_ci { 2010987da915Sopenharmony_ci /* show redo data */ 2011987da915Sopenharmony_ci if (logr->redo_length) 2012987da915Sopenharmony_ci { 2013987da915Sopenharmony_ci if (logr->lcns_to_follow) 2014987da915Sopenharmony_ci { 2015987da915Sopenharmony_ci off = le16_to_cpu(logr->record_offset) 2016987da915Sopenharmony_ci + le16_to_cpu(logr->attribute_offset); 2017987da915Sopenharmony_ci printf("redo data (new data) cluster 0x%llx pos 0x%x :\n", 2018987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->lcn_list[off 2019987da915Sopenharmony_ci >> clusterbits]), 2020987da915Sopenharmony_ci (int)(off & (clustersz - 1))); 2021987da915Sopenharmony_ci } 2022987da915Sopenharmony_ci else 2023987da915Sopenharmony_ci printf("redo data (new data) at offs 0x%x :\n",redo); 2024987da915Sopenharmony_ci if ((u32)(redo + le16_to_cpu(logr->redo_length)) 2025987da915Sopenharmony_ci <= end) 2026987da915Sopenharmony_ci { 2027987da915Sopenharmony_ci hexdump((const char*)logr 2028987da915Sopenharmony_ci + redo,le16_to_cpu(logr->redo_length)); 2029987da915Sopenharmony_ci fixup(ctx, logr, (const char*)logr + redo, TRUE); 2030987da915Sopenharmony_ci } 2031987da915Sopenharmony_ci else printf("redo data overflowing from record\n"); 2032987da915Sopenharmony_ci } 2033987da915Sopenharmony_ci else 2034987da915Sopenharmony_ci { 2035987da915Sopenharmony_ci printf("no redo data (new data)\n"); 2036987da915Sopenharmony_ci fixup(ctx, logr, (const char*)logr + redo, TRUE); 2037987da915Sopenharmony_ci } 2038987da915Sopenharmony_ci 2039987da915Sopenharmony_ci /* show undo data */ 2040987da915Sopenharmony_ci if (logr->undo_length) 2041987da915Sopenharmony_ci { 2042987da915Sopenharmony_ci if (logr->lcns_to_follow) 2043987da915Sopenharmony_ci { 2044987da915Sopenharmony_ci off = le16_to_cpu(logr->record_offset) 2045987da915Sopenharmony_ci + le16_to_cpu(logr->attribute_offset); 2046987da915Sopenharmony_ci printf("undo data (old data) cluster 0x%llx pos 0x%x :\n", 2047987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->lcn_list[off 2048987da915Sopenharmony_ci >> clusterbits]), 2049987da915Sopenharmony_ci (int)(off & (clustersz - 1))); 2050987da915Sopenharmony_ci } 2051987da915Sopenharmony_ci else printf("undo data (old data) at offs 0x%x :\n",undo); 2052987da915Sopenharmony_ci if ((u32)(undo + le16_to_cpu(logr->undo_length)) <= end) 2053987da915Sopenharmony_ci { 2054987da915Sopenharmony_ci if ((undo + le16_to_cpu(logr->undo_length)) < 2*blocksz) 2055987da915Sopenharmony_ci { 2056987da915Sopenharmony_ci hexdump((const char*)logr 2057987da915Sopenharmony_ci + undo,le16_to_cpu(logr->undo_length)); 2058987da915Sopenharmony_ci fixup(ctx, logr, (const char*)logr + undo, FALSE); 2059987da915Sopenharmony_ci } 2060987da915Sopenharmony_ci else printf("undo data overflowing from two blocks\n"); 2061987da915Sopenharmony_ci } 2062987da915Sopenharmony_ci else printf("undo data overflowing from record\n"); 2063987da915Sopenharmony_ci } 2064987da915Sopenharmony_ci else 2065987da915Sopenharmony_ci { 2066987da915Sopenharmony_ci printf("no undo data (old data)\n"); 2067987da915Sopenharmony_ci fixup(ctx, logr, (const char*)logr + undo, FALSE); 2068987da915Sopenharmony_ci } 2069987da915Sopenharmony_ci 2070987da915Sopenharmony_ci /* show extra data, if any */ 2071987da915Sopenharmony_ci if (extra != end) 2072987da915Sopenharmony_ci { 2073987da915Sopenharmony_ci if (end > blocksz) 2074987da915Sopenharmony_ci printf("invalid extra data size\n"); 2075987da915Sopenharmony_ci else 2076987da915Sopenharmony_ci { 2077987da915Sopenharmony_ci printf("extra data at offs 0x%x\n",extra); 2078987da915Sopenharmony_ci hexdump((const char*)logr + extra, 2079987da915Sopenharmony_ci end - extra); 2080987da915Sopenharmony_ci } 2081987da915Sopenharmony_ci } 2082987da915Sopenharmony_ci } 2083987da915Sopenharmony_ci else 2084987da915Sopenharmony_ci { 2085987da915Sopenharmony_ci /* sometimes the designated data overflows */ 2086987da915Sopenharmony_ci if (logr->redo_length 2087987da915Sopenharmony_ci && ((u32)(redo + le16_to_cpu(logr->redo_length)) > end)) 2088987da915Sopenharmony_ci printf("* redo data overflows from record\n"); 2089987da915Sopenharmony_ci if (logr->undo_length 2090987da915Sopenharmony_ci && ((u32)(undo + le16_to_cpu(logr->undo_length)) > end)) 2091987da915Sopenharmony_ci printf("* undo data overflows from record\n"); 2092987da915Sopenharmony_ci } 2093987da915Sopenharmony_ci break; 2094987da915Sopenharmony_ci case LOG_CHECKPOINT : 2095987da915Sopenharmony_ci printf("---> checkpoint record\n"); 2096987da915Sopenharmony_ci printf("redo_operation %04x %s\n", 2097987da915Sopenharmony_ci (int)le16_to_cpu(logr->redo_operation), 2098987da915Sopenharmony_ci actionname(le16_to_cpu(logr->redo_operation))); 2099987da915Sopenharmony_ci printf("undo_operation %04x %s\n", 2100987da915Sopenharmony_ci (int)le16_to_cpu(logr->undo_operation), 2101987da915Sopenharmony_ci actionname(le16_to_cpu(logr->undo_operation))); 2102987da915Sopenharmony_ci printf("redo_offset %04x\n", 2103987da915Sopenharmony_ci (int)le16_to_cpu(logr->redo_offset)); 2104987da915Sopenharmony_ci printf("redo_length %04x\n", 2105987da915Sopenharmony_ci (int)le16_to_cpu(logr->redo_length)); 2106987da915Sopenharmony_ci printf("transaction_lsn %016llx\n", 2107987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->transaction_lsn)); 2108987da915Sopenharmony_ci printf("attributes_lsn %016llx\n", 2109987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->attributes_lsn)); 2110987da915Sopenharmony_ci printf("names_lsn %016llx\n", 2111987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->names_lsn)); 2112987da915Sopenharmony_ci printf("dirty_pages_lsn %016llx\n", 2113987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->dirty_pages_lsn)); 2114987da915Sopenharmony_ci listsize = le32_to_cpu(logr->client_data_length) 2115987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ 2116987da915Sopenharmony_ci - offsetof(LOG_RECORD, unknown_list); 2117987da915Sopenharmony_ci if (listsize > 8*SHOWLISTS) 2118987da915Sopenharmony_ci listsize = 8*SHOWLISTS; 2119987da915Sopenharmony_ci for (i=0; 8*i<listsize; i++) 2120987da915Sopenharmony_ci printf("unknown-%u %016llx\n",i, 2121987da915Sopenharmony_ci (long long)le64_to_cpu(logr->unknown_list[i])); 2122987da915Sopenharmony_ci break; 2123987da915Sopenharmony_ci default : 2124987da915Sopenharmony_ci printf("** Unknown action type\n"); 2125987da915Sopenharmony_ci if (le32_to_cpu(logr->client_data_length) < blocksz) { 2126987da915Sopenharmony_ci printf("client_data for record type %ld\n", 2127987da915Sopenharmony_ci (long)le32_to_cpu(logr->record_type)); 2128987da915Sopenharmony_ci hexdump((const char*)&logr->redo_operation, 2129987da915Sopenharmony_ci le32_to_cpu(logr->client_data_length)); 2130987da915Sopenharmony_ci } else 2131987da915Sopenharmony_ci printf("** Bad client data\n"); 2132987da915Sopenharmony_ci break; 2133987da915Sopenharmony_ci } 2134987da915Sopenharmony_ci} 2135987da915Sopenharmony_ci 2136987da915Sopenharmony_ciBOOL within_lcn_range(const LOG_RECORD *logr) 2137987da915Sopenharmony_ci{ 2138987da915Sopenharmony_ci u64 lcn; 2139987da915Sopenharmony_ci unsigned int i; 2140987da915Sopenharmony_ci BOOL within; 2141987da915Sopenharmony_ci 2142987da915Sopenharmony_ci within = FALSE; 2143987da915Sopenharmony_ci switch (logr->record_type) { 2144987da915Sopenharmony_ci case LOG_STANDARD : 2145987da915Sopenharmony_ci for (i=0; i<le16_to_cpu(logr->lcns_to_follow); i++) { 2146987da915Sopenharmony_ci lcn = MREF(sle64_to_cpu(logr->lcn_list[i])); 2147987da915Sopenharmony_ci if ((lcn >= firstlcn) && (lcn <= lastlcn)) 2148987da915Sopenharmony_ci within = TRUE; 2149987da915Sopenharmony_ci } 2150987da915Sopenharmony_ci break; 2151987da915Sopenharmony_ci default : 2152987da915Sopenharmony_ci break; 2153987da915Sopenharmony_ci } 2154987da915Sopenharmony_ci return (within); 2155987da915Sopenharmony_ci} 2156987da915Sopenharmony_ci 2157987da915Sopenharmony_cistatic void showlogr(CONTEXT *ctx, int k, const LOG_RECORD *logr) 2158987da915Sopenharmony_ci{ 2159987da915Sopenharmony_ci s32 diff; 2160987da915Sopenharmony_ci 2161987da915Sopenharmony_ci if (optv && (!optc || within_lcn_range(logr))) { 2162987da915Sopenharmony_ci diff = sle64_to_cpu(logr->this_lsn) - synced_lsn; 2163987da915Sopenharmony_ci printf("this_lsn %016llx (synced%s%ld) %s\n", 2164987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->this_lsn), 2165987da915Sopenharmony_ci (diff < 0 ? "" : "+"),(long)diff, 2166987da915Sopenharmony_ci commitment(diff + synced_lsn)); 2167987da915Sopenharmony_ci printf("client_previous_lsn %016llx\n", 2168987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->client_previous_lsn)); 2169987da915Sopenharmony_ci printf("client_undo_next_lsn %016llx\n", 2170987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->client_undo_next_lsn)); 2171987da915Sopenharmony_ci printf("client_data_length %08lx\n", 2172987da915Sopenharmony_ci (long)le32_to_cpu(logr->client_data_length)); 2173987da915Sopenharmony_ci printf("seq_number %d\n", 2174987da915Sopenharmony_ci (int)le16_to_cpu(logr->client_id.seq_number)); 2175987da915Sopenharmony_ci printf("client_index %d\n", 2176987da915Sopenharmony_ci (int)le16_to_cpu(logr->client_id.client_index)); 2177987da915Sopenharmony_ci printf("record_type %08lx\n", 2178987da915Sopenharmony_ci (long)le32_to_cpu(logr->record_type)); 2179987da915Sopenharmony_ci printf("transaction_id %08lx\n", 2180987da915Sopenharmony_ci (long)le32_to_cpu(logr->transaction_id)); 2181987da915Sopenharmony_ci printf("log_record_flags %04x\n", 2182987da915Sopenharmony_ci (int)le16_to_cpu(logr->log_record_flags)); 2183987da915Sopenharmony_ci printf("reserved1 %04x %04x %04x\n", 2184987da915Sopenharmony_ci (int)le16_to_cpu(logr->reserved_or_alignment[0]), 2185987da915Sopenharmony_ci (int)le16_to_cpu(logr->reserved_or_alignment[1]), 2186987da915Sopenharmony_ci (int)le16_to_cpu(logr->reserved_or_alignment[2])); 2187987da915Sopenharmony_ci detaillogr(ctx, logr); 2188987da915Sopenharmony_ci } 2189987da915Sopenharmony_ci if (optt) { 2190987da915Sopenharmony_ci const char *state; 2191987da915Sopenharmony_ci 2192987da915Sopenharmony_ci if (logr->record_type == LOG_CHECKPOINT) 2193987da915Sopenharmony_ci state = "--checkpoint--"; 2194987da915Sopenharmony_ci else 2195987da915Sopenharmony_ci state = commitment(sle64_to_cpu(logr->this_lsn)); 2196987da915Sopenharmony_ci printf(" at %04x %016llx %s (%ld) %s\n",k, 2197987da915Sopenharmony_ci (long long)sle64_to_cpu(logr->this_lsn), 2198987da915Sopenharmony_ci state, 2199987da915Sopenharmony_ci (long)(sle64_to_cpu(logr->this_lsn) - synced_lsn), 2200987da915Sopenharmony_ci actionname(le16_to_cpu(logr->redo_operation))); 2201987da915Sopenharmony_ci if (logr->client_previous_lsn || logr->client_undo_next_lsn) { 2202987da915Sopenharmony_ci if (logr->client_previous_lsn 2203987da915Sopenharmony_ci == logr->client_undo_next_lsn) { 2204987da915Sopenharmony_ci printf(" " 2205987da915Sopenharmony_ci " previous and undo %016llx\n", 2206987da915Sopenharmony_ci (long long)sle64_to_cpu( 2207987da915Sopenharmony_ci logr->client_previous_lsn)); 2208987da915Sopenharmony_ci } else { 2209987da915Sopenharmony_ci printf(" " 2210987da915Sopenharmony_ci " previous %016llx", 2211987da915Sopenharmony_ci (long long)sle64_to_cpu( 2212987da915Sopenharmony_ci logr->client_previous_lsn)); 2213987da915Sopenharmony_ci 2214987da915Sopenharmony_ci if (logr->client_undo_next_lsn) 2215987da915Sopenharmony_ci printf(" undo %016llx\n", 2216987da915Sopenharmony_ci (long long)sle64_to_cpu( 2217987da915Sopenharmony_ci logr->client_undo_next_lsn)); 2218987da915Sopenharmony_ci else 2219987da915Sopenharmony_ci printf("\n"); 2220987da915Sopenharmony_ci } 2221987da915Sopenharmony_ci } 2222987da915Sopenharmony_ci } 2223987da915Sopenharmony_ci} 2224987da915Sopenharmony_ci 2225987da915Sopenharmony_ci/* 2226987da915Sopenharmony_ci * Mark transactions which should be redone 2227987da915Sopenharmony_ci */ 2228987da915Sopenharmony_ci 2229987da915Sopenharmony_cistatic void mark_transactions(struct ACTION_RECORD *lastaction) 2230987da915Sopenharmony_ci{ 2231987da915Sopenharmony_ci struct ACTION_RECORD *action; 2232987da915Sopenharmony_ci const LOG_RECORD *logr; 2233987da915Sopenharmony_ci le32 id; 2234987da915Sopenharmony_ci int actives; 2235987da915Sopenharmony_ci BOOL more; 2236987da915Sopenharmony_ci BOOL committed; 2237987da915Sopenharmony_ci 2238987da915Sopenharmony_ci actives = 0; 2239987da915Sopenharmony_ci do { 2240987da915Sopenharmony_ci more = FALSE; 2241987da915Sopenharmony_ci id = const_cpu_to_le32(0); 2242987da915Sopenharmony_ci for (action=lastaction; action; action=action->prev) { 2243987da915Sopenharmony_ci logr = &action->record; 2244987da915Sopenharmony_ci if ((logr->redo_operation 2245987da915Sopenharmony_ci == const_cpu_to_le16(ForgetTransaction)) 2246987da915Sopenharmony_ci && !(action->flags & ACTION_TO_REDO) 2247987da915Sopenharmony_ci && !id) { 2248987da915Sopenharmony_ci id = logr->transaction_id; 2249987da915Sopenharmony_ci action->flags |= ACTION_TO_REDO; 2250987da915Sopenharmony_ci if (optv) 2251987da915Sopenharmony_ci printf("Marking transaction 0x%x\n", 2252987da915Sopenharmony_ci (int)le32_to_cpu(id)); 2253987da915Sopenharmony_ci } 2254987da915Sopenharmony_ci committed = ((s64)(sle64_to_cpu(logr->this_lsn) 2255987da915Sopenharmony_ci - committed_lsn)) <= 0; 2256987da915Sopenharmony_ci if (!logr->transaction_id 2257987da915Sopenharmony_ci && committed) 2258987da915Sopenharmony_ci action->flags |= ACTION_TO_REDO; 2259987da915Sopenharmony_ci if (id 2260987da915Sopenharmony_ci && (logr->transaction_id == id) 2261987da915Sopenharmony_ci && committed) { 2262987da915Sopenharmony_ci action->flags |= ACTION_TO_REDO; 2263987da915Sopenharmony_ci more = TRUE; 2264987da915Sopenharmony_ci } 2265987da915Sopenharmony_ci } 2266987da915Sopenharmony_ci if (more) 2267987da915Sopenharmony_ci actives++; 2268987da915Sopenharmony_ci } while (more); 2269987da915Sopenharmony_ci /* 2270987da915Sopenharmony_ci * Show unmarked (aborted) actions 2271987da915Sopenharmony_ci */ 2272987da915Sopenharmony_ci if (optv) { 2273987da915Sopenharmony_ci for (action=lastaction; action; action=action->prev) { 2274987da915Sopenharmony_ci logr = &action->record; 2275987da915Sopenharmony_ci if (logr->transaction_id 2276987da915Sopenharmony_ci && !(action->flags & ACTION_TO_REDO)) 2277987da915Sopenharmony_ci printf("** Action %d was aborted\n", 2278987da915Sopenharmony_ci (int)action->num); 2279987da915Sopenharmony_ci } 2280987da915Sopenharmony_ci } 2281987da915Sopenharmony_ci if (optv && (actives > 1)) 2282987da915Sopenharmony_ci printf("%d active transactions in set\n",actives); 2283987da915Sopenharmony_ci} 2284987da915Sopenharmony_ci 2285987da915Sopenharmony_ci/* 2286987da915Sopenharmony_ci * Enqueue an action and play the queued actions on end of set 2287987da915Sopenharmony_ci */ 2288987da915Sopenharmony_ci 2289987da915Sopenharmony_cistatic TRISTATE enqueue_action(CONTEXT *ctx, const LOG_RECORD *logr, 2290987da915Sopenharmony_ci int size, int num) 2291987da915Sopenharmony_ci{ 2292987da915Sopenharmony_ci struct ACTION_RECORD *action; 2293987da915Sopenharmony_ci TRISTATE state; 2294987da915Sopenharmony_ci int err; 2295987da915Sopenharmony_ci 2296987da915Sopenharmony_ci err = 1; 2297987da915Sopenharmony_ci state = T_ERR; 2298987da915Sopenharmony_ci /* enqueue record */ 2299987da915Sopenharmony_ci action = (struct ACTION_RECORD*) 2300987da915Sopenharmony_ci malloc(size + offsetof(struct ACTION_RECORD, record)); 2301987da915Sopenharmony_ci if (action) { 2302987da915Sopenharmony_ci memcpy(&action->record, logr, size); 2303987da915Sopenharmony_ci action->num = num; 2304987da915Sopenharmony_ci action->flags = 0; 2305987da915Sopenharmony_ci /* enqueue ahead of list, firstaction is the oldest one */ 2306987da915Sopenharmony_ci action->prev = (struct ACTION_RECORD*)NULL; 2307987da915Sopenharmony_ci action->next = ctx->firstaction; 2308987da915Sopenharmony_ci if (ctx->firstaction) 2309987da915Sopenharmony_ci ctx->firstaction->prev = action; 2310987da915Sopenharmony_ci else 2311987da915Sopenharmony_ci ctx->lastaction = action; 2312987da915Sopenharmony_ci ctx->firstaction = action; 2313987da915Sopenharmony_ci err = 0; 2314987da915Sopenharmony_ci state = T_OK; 2315987da915Sopenharmony_ci if ((optp || optu) 2316987da915Sopenharmony_ci && (logr->record_type == LOG_CHECKPOINT)) { 2317987da915Sopenharmony_ci /* if chkp process queue, and increment count */ 2318987da915Sopenharmony_ci playedactions++; 2319987da915Sopenharmony_ci if (playedactions <= playcount) { 2320987da915Sopenharmony_ci if (optv) 2321987da915Sopenharmony_ci printf("* Refreshing attributes\n"); 2322987da915Sopenharmony_ci err = refresh_attributes(ctx->firstaction); 2323987da915Sopenharmony_ci if (optv) 2324987da915Sopenharmony_ci printf("* Undoing transaction set %d" 2325987da915Sopenharmony_ci " (actions %d->%d)\n", 2326987da915Sopenharmony_ci (int)playedactions, 2327987da915Sopenharmony_ci (int)ctx->lastaction->num, 2328987da915Sopenharmony_ci (int)ctx->firstaction->num); 2329987da915Sopenharmony_ci err = play_undos(ctx->vol, ctx->lastaction); 2330987da915Sopenharmony_ci if (err) 2331987da915Sopenharmony_ci printf("* Undoing transaction" 2332987da915Sopenharmony_ci " set failed\n"); 2333987da915Sopenharmony_ci } 2334987da915Sopenharmony_ci if (!err && optp && (playedactions == playcount)) { 2335987da915Sopenharmony_ci if (optv) 2336987da915Sopenharmony_ci printf("* Redoing transaction set %d" 2337987da915Sopenharmony_ci " (actions %d->%d)\n", 2338987da915Sopenharmony_ci (int)playedactions, 2339987da915Sopenharmony_ci (int)ctx->firstaction->num, 2340987da915Sopenharmony_ci (int)ctx->lastaction->num); 2341987da915Sopenharmony_ci mark_transactions(ctx->lastaction); 2342987da915Sopenharmony_ci err = play_redos(ctx->vol, ctx->firstaction); 2343987da915Sopenharmony_ci if (err) 2344987da915Sopenharmony_ci printf("* Redoing transaction" 2345987da915Sopenharmony_ci " set failed\n"); 2346987da915Sopenharmony_ci } 2347987da915Sopenharmony_ci if (err) 2348987da915Sopenharmony_ci state = T_ERR; 2349987da915Sopenharmony_ci else 2350987da915Sopenharmony_ci if (playedactions == playcount) 2351987da915Sopenharmony_ci state = T_DONE; 2352987da915Sopenharmony_ci /* free queue */ 2353987da915Sopenharmony_ci while (ctx->firstaction) { 2354987da915Sopenharmony_ci action = ctx->firstaction->next; 2355987da915Sopenharmony_ci free(ctx->firstaction); 2356987da915Sopenharmony_ci ctx->firstaction = action; 2357987da915Sopenharmony_ci } 2358987da915Sopenharmony_ci ctx->lastaction = (struct ACTION_RECORD*)NULL; 2359987da915Sopenharmony_ci } 2360987da915Sopenharmony_ci if (opts 2361987da915Sopenharmony_ci && ((s64)(sle64_to_cpu(logr->this_lsn) - synced_lsn) <= 0)) { 2362987da915Sopenharmony_ci if (optv) 2363987da915Sopenharmony_ci printf("* Refreshing attributes\n"); 2364987da915Sopenharmony_ci// should refresh backward ? 2365987da915Sopenharmony_ci err = refresh_attributes(ctx->firstaction); 2366987da915Sopenharmony_ci mark_transactions(ctx->lastaction); 2367987da915Sopenharmony_ci if (!err) { 2368987da915Sopenharmony_ci if (optv) 2369987da915Sopenharmony_ci printf("* Syncing actions %d->%d\n", 2370987da915Sopenharmony_ci (int)ctx->firstaction->num, 2371987da915Sopenharmony_ci (int)ctx->lastaction->num); 2372987da915Sopenharmony_ci err = play_redos(ctx->vol, ctx->firstaction); 2373987da915Sopenharmony_ci } 2374987da915Sopenharmony_ci if (err) { 2375987da915Sopenharmony_ci printf("* Syncing actions failed\n"); 2376987da915Sopenharmony_ci state = T_ERR; 2377987da915Sopenharmony_ci } else 2378987da915Sopenharmony_ci state = T_DONE; 2379987da915Sopenharmony_ci } 2380987da915Sopenharmony_ci } 2381987da915Sopenharmony_ci return (state); 2382987da915Sopenharmony_ci} 2383987da915Sopenharmony_ci 2384987da915Sopenharmony_ci 2385987da915Sopenharmony_cistatic void showheadrcrd(u32 blk, const RECORD_PAGE_HEADER *rph) 2386987da915Sopenharmony_ci{ 2387987da915Sopenharmony_ci s32 diff; 2388987da915Sopenharmony_ci 2389987da915Sopenharmony_ci if (optv) { 2390987da915Sopenharmony_ci printf("magic %08lx\n", 2391987da915Sopenharmony_ci (long)le32_to_cpu(rph->magic)); 2392987da915Sopenharmony_ci printf("usa_ofs %04x\n", 2393987da915Sopenharmony_ci (int)le16_to_cpu(rph->usa_ofs)); 2394987da915Sopenharmony_ci printf("usa_count %04x\n", 2395987da915Sopenharmony_ci (int)le16_to_cpu(rph->usa_count)); 2396987da915Sopenharmony_ci if (blk < 4) 2397987da915Sopenharmony_ci printf("file_offset %016llx\n", 2398987da915Sopenharmony_ci (long long)sle64_to_cpu(rph->copy.file_offset)); 2399987da915Sopenharmony_ci else { 2400987da915Sopenharmony_ci diff = sle64_to_cpu(rph->copy.last_lsn) - synced_lsn; 2401987da915Sopenharmony_ci printf("last_lsn %016llx" 2402987da915Sopenharmony_ci " (synced%s%ld)\n", 2403987da915Sopenharmony_ci (long long)sle64_to_cpu(rph->copy.last_lsn), 2404987da915Sopenharmony_ci (diff < 0 ? "" : "+"),(long)diff); 2405987da915Sopenharmony_ci } 2406987da915Sopenharmony_ci printf("flags %08lx\n", 2407987da915Sopenharmony_ci (long)le32_to_cpu(rph->flags)); 2408987da915Sopenharmony_ci printf("page_count %d\n", 2409987da915Sopenharmony_ci (int)le16_to_cpu(rph->page_count)); 2410987da915Sopenharmony_ci printf("page_position %d\n", 2411987da915Sopenharmony_ci (int)le16_to_cpu(rph->page_position)); 2412987da915Sopenharmony_ci printf("next_record_offset %04x\n", 2413987da915Sopenharmony_ci (int)le16_to_cpu(rph->next_record_offset)); 2414987da915Sopenharmony_ci printf("reserved4 %04x %04x %04x\n", 2415987da915Sopenharmony_ci (int)le16_to_cpu(rph->reserved[0]), 2416987da915Sopenharmony_ci (int)le16_to_cpu(rph->reserved[1]), 2417987da915Sopenharmony_ci (int)le16_to_cpu(rph->reserved[2])); 2418987da915Sopenharmony_ci diff = sle64_to_cpu(rph->last_end_lsn) - synced_lsn; 2419987da915Sopenharmony_ci printf("last_end_lsn %016llx (synced%s%ld)\n", 2420987da915Sopenharmony_ci (long long)sle64_to_cpu(rph->last_end_lsn), 2421987da915Sopenharmony_ci (diff < 0 ? "" : "+"),(long)diff); 2422987da915Sopenharmony_ci printf("usn %04x\n", 2423987da915Sopenharmony_ci (int)getle16(rph,le16_to_cpu(rph->usa_ofs))); 2424987da915Sopenharmony_ci printf("\n"); 2425987da915Sopenharmony_ci } else { 2426987da915Sopenharmony_ci if (optt) { 2427987da915Sopenharmony_ci const char *state; 2428987da915Sopenharmony_ci 2429987da915Sopenharmony_ci state = commitment(sle64_to_cpu(rph->copy.last_lsn)); 2430987da915Sopenharmony_ci diff = sle64_to_cpu(rph->copy.last_lsn) - synced_lsn; 2431987da915Sopenharmony_ci printf(" last %016llx (synced%s%ld) %s\n", 2432987da915Sopenharmony_ci (long long)sle64_to_cpu(rph->copy.last_lsn), 2433987da915Sopenharmony_ci (diff < 0 ? "" : "+"),(long)diff, state); 2434987da915Sopenharmony_ci state = commitment(sle64_to_cpu(rph->last_end_lsn)); 2435987da915Sopenharmony_ci diff = sle64_to_cpu(rph->last_end_lsn) - synced_lsn; 2436987da915Sopenharmony_ci printf(" last_end %016llx (synced%s%ld) %s\n", 2437987da915Sopenharmony_ci (long long)sle64_to_cpu(rph->last_end_lsn), 2438987da915Sopenharmony_ci (diff < 0 ? "" : "+"),(long)diff, state); 2439987da915Sopenharmony_ci } 2440987da915Sopenharmony_ci } 2441987da915Sopenharmony_ci} 2442987da915Sopenharmony_ci 2443987da915Sopenharmony_ci/* 2444987da915Sopenharmony_ci * Analyze and display an action overlapping log blocks 2445987da915Sopenharmony_ci * 2446987da915Sopenharmony_ci * Returns the position of first action in next block. If this is 2447987da915Sopenharmony_ci * greater than a block size (for actions overlapping more than 2448987da915Sopenharmony_ci * two blocks), then some blocks have to be skipped. 2449987da915Sopenharmony_ci * 2450987da915Sopenharmony_ci * Returns 0 in case of error 2451987da915Sopenharmony_ci */ 2452987da915Sopenharmony_ci 2453987da915Sopenharmony_cistatic u16 overlapshow(CONTEXT *ctx, u16 k, u32 blk, const struct BUFFER *buf, 2454987da915Sopenharmony_ci const struct BUFFER *nextbuf) 2455987da915Sopenharmony_ci{ 2456987da915Sopenharmony_ci const LOG_RECORD *logr; 2457987da915Sopenharmony_ci const char *data; 2458987da915Sopenharmony_ci const char *nextdata; 2459987da915Sopenharmony_ci char *fullrec; 2460987da915Sopenharmony_ci u32 size; 2461987da915Sopenharmony_ci u32 nextspace; 2462987da915Sopenharmony_ci u32 space; 2463987da915Sopenharmony_ci BOOL likely; 2464987da915Sopenharmony_ci u16 blkheadsz; 2465987da915Sopenharmony_ci 2466987da915Sopenharmony_ci data = buf->block.data; 2467987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 2468987da915Sopenharmony_ci size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; 2469987da915Sopenharmony_ci blkheadsz = buf->headsz; 2470987da915Sopenharmony_ci if (nextbuf && (blk >= BASEBLKS)) { 2471987da915Sopenharmony_ci nextdata = nextbuf->block.data; 2472987da915Sopenharmony_ci space = blocksz - k; 2473987da915Sopenharmony_ci nextspace = blocksz - blkheadsz; 2474987da915Sopenharmony_ci if ((space >= LOG_RECORD_HEAD_SZ) 2475987da915Sopenharmony_ci && (size > space)) { 2476987da915Sopenharmony_ci fullrec = (char*)malloc(size); 2477987da915Sopenharmony_ci if (size <= (space + nextspace)) { 2478987da915Sopenharmony_ci /* Overlap on two blocks */ 2479987da915Sopenharmony_ci memcpy(fullrec,&data[k],space); 2480987da915Sopenharmony_ci memcpy(&fullrec[space], 2481987da915Sopenharmony_ci nextdata + blkheadsz, 2482987da915Sopenharmony_ci size - space); 2483987da915Sopenharmony_ci likely = likelyop((LOG_RECORD*)fullrec); 2484987da915Sopenharmony_ci actionnum++; 2485987da915Sopenharmony_ci if (optv) { 2486987da915Sopenharmony_ci printf("\nOverlapping record %u at 0x%x" 2487987da915Sopenharmony_ci " size %d (next at 0x%x)\n", 2488987da915Sopenharmony_ci (int)actionnum,(int)k, 2489987da915Sopenharmony_ci (int)size, (int)(k + size)); 2490987da915Sopenharmony_ci printf("Overlap marked for block %ld" 2491987da915Sopenharmony_ci " space %d likely %d\n", 2492987da915Sopenharmony_ci (long)blk,(int)space,likely); 2493987da915Sopenharmony_ci } 2494987da915Sopenharmony_ci if (likely) 2495987da915Sopenharmony_ci showlogr(ctx, k, 2496987da915Sopenharmony_ci (LOG_RECORD*)fullrec); 2497987da915Sopenharmony_ci else 2498987da915Sopenharmony_ci printf("** Skipping unlikely" 2499987da915Sopenharmony_ci " overlapping record\n"); 2500987da915Sopenharmony_ci k += size - blocksz + blkheadsz; 2501987da915Sopenharmony_ci } else { 2502987da915Sopenharmony_ci const struct BUFFER *midbuf; 2503987da915Sopenharmony_ci int skip; 2504987da915Sopenharmony_ci u32 next; 2505987da915Sopenharmony_ci u32 pos; 2506987da915Sopenharmony_ci int i; 2507987da915Sopenharmony_ci 2508987da915Sopenharmony_ci /* 2509987da915Sopenharmony_ci * The maximum size of of log record is 131104 2510987da915Sopenharmony_ci * (when both offset and length are 65528 for 2511987da915Sopenharmony_ci * redo or undo). 2512987da915Sopenharmony_ci * So up to 33 log blocks (useful size 4032) 2513987da915Sopenharmony_ci * could be needed. However never both undo and 2514987da915Sopenharmony_ci * redo have been found big, and 17 should be 2515987da915Sopenharmony_ci * the real maximum. 2516987da915Sopenharmony_ci */ 2517987da915Sopenharmony_ci if (optv) 2518987da915Sopenharmony_ci printf("More than two blocks required" 2519987da915Sopenharmony_ci " (size %lu)\n",(long)size); 2520987da915Sopenharmony_ci memcpy(fullrec,&data[k],space); 2521987da915Sopenharmony_ci 2522987da915Sopenharmony_ci skip = (size - space - 1)/nextspace; 2523987da915Sopenharmony_ci pos = space; 2524987da915Sopenharmony_ci likely = TRUE; 2525987da915Sopenharmony_ci for (i=1; (i<=skip) && likely; i++) { 2526987da915Sopenharmony_ci midbuf = read_buffer(ctx, blk + i); 2527987da915Sopenharmony_ci if (midbuf) { 2528987da915Sopenharmony_ci memcpy(&fullrec[pos], 2529987da915Sopenharmony_ci &midbuf->block 2530987da915Sopenharmony_ci .data[blkheadsz], 2531987da915Sopenharmony_ci nextspace); 2532987da915Sopenharmony_ci pos += nextspace; 2533987da915Sopenharmony_ci } else 2534987da915Sopenharmony_ci likely = FALSE; 2535987da915Sopenharmony_ci } 2536987da915Sopenharmony_ci if (pos >= size) { 2537987da915Sopenharmony_ci printf("** Error : bad big overlap" 2538987da915Sopenharmony_ci " pos %d size %d\n", 2539987da915Sopenharmony_ci (int)pos,(int)size); 2540987da915Sopenharmony_ci likely = FALSE; 2541987da915Sopenharmony_ci } 2542987da915Sopenharmony_ci midbuf = read_buffer(ctx, blk + skip + 1); 2543987da915Sopenharmony_ci if (midbuf) 2544987da915Sopenharmony_ci memcpy(&fullrec[pos], 2545987da915Sopenharmony_ci &midbuf->block.data[blkheadsz], 2546987da915Sopenharmony_ci size - pos); 2547987da915Sopenharmony_ci else 2548987da915Sopenharmony_ci likely = FALSE; 2549987da915Sopenharmony_ci if (!likelyop((LOG_RECORD*)fullrec)) 2550987da915Sopenharmony_ci likely = FALSE; 2551987da915Sopenharmony_ci actionnum++; 2552987da915Sopenharmony_ci if (optv) { 2553987da915Sopenharmony_ci printf("\nBig overlapping record %u at " 2554987da915Sopenharmony_ci "0x%x size %u (next at 0x%x)\n", 2555987da915Sopenharmony_ci (int)actionnum,(int)k,(int)size, 2556987da915Sopenharmony_ci (int)(k + size)); 2557987da915Sopenharmony_ci printf("Overlap marked for block %ld" 2558987da915Sopenharmony_ci " space %d likely %d\n", 2559987da915Sopenharmony_ci (long)blk,(int)space,likely); 2560987da915Sopenharmony_ci } 2561987da915Sopenharmony_ci if (likely) 2562987da915Sopenharmony_ci showlogr(ctx, k, 2563987da915Sopenharmony_ci (LOG_RECORD*)fullrec); 2564987da915Sopenharmony_ci else 2565987da915Sopenharmony_ci printf("** Skipping unlikely" 2566987da915Sopenharmony_ci " overlapping record\n"); 2567987da915Sopenharmony_ci /* next and skip are only for displaying */ 2568987da915Sopenharmony_ci next = (size - space) % nextspace 2569987da915Sopenharmony_ci + blkheadsz; 2570987da915Sopenharmony_ci if ((blocksz - next) < LOG_RECORD_HEAD_SZ) 2571987da915Sopenharmony_ci next = blkheadsz; 2572987da915Sopenharmony_ci if (next == blkheadsz) 2573987da915Sopenharmony_ci skip++; 2574987da915Sopenharmony_ci if (optv) 2575987da915Sopenharmony_ci printf("Next record expected in" 2576987da915Sopenharmony_ci " block %lu index 0x%x\n", 2577987da915Sopenharmony_ci (long)(blk + skip + 1),next); 2578987da915Sopenharmony_ci /* Quick check, with no consequences */ 2579987da915Sopenharmony_ci if (firstrecord(skip,buf,buf) != next) 2580987da915Sopenharmony_ci printf("** Error next != firstrecord" 2581987da915Sopenharmony_ci " after block %d\n",blk); 2582987da915Sopenharmony_ci k += size - blocksz + blkheadsz; 2583987da915Sopenharmony_ci } 2584987da915Sopenharmony_ci if (!likely) 2585987da915Sopenharmony_ci k = 0; 2586987da915Sopenharmony_ci else 2587987da915Sopenharmony_ci if (!k) 2588987da915Sopenharmony_ci printf("* Bad return from overlap()\n"); 2589987da915Sopenharmony_ci free(fullrec); 2590987da915Sopenharmony_ci } else { 2591987da915Sopenharmony_ci /* No conditions for overlap, usually a new session */ 2592987da915Sopenharmony_ci printf("* No block found overlapping on block %d\n", 2593987da915Sopenharmony_ci (int)blk); 2594987da915Sopenharmony_ci k = 0; 2595987da915Sopenharmony_ci } 2596987da915Sopenharmony_ci } else { 2597987da915Sopenharmony_ci /* blocks 2, 3 and the last one have no next block */ 2598987da915Sopenharmony_ci k = 0; 2599987da915Sopenharmony_ci } 2600987da915Sopenharmony_ci return (k); 2601987da915Sopenharmony_ci} 2602987da915Sopenharmony_ci 2603987da915Sopenharmony_ci/* 2604987da915Sopenharmony_ci * Analyze and forward display the actions in a log block 2605987da915Sopenharmony_ci * 2606987da915Sopenharmony_ci * Returns the position of first action in next block. If this is 2607987da915Sopenharmony_ci * greater than a block size, then some blocks have to be skipped. 2608987da915Sopenharmony_ci * 2609987da915Sopenharmony_ci * Returns 0 in case of error 2610987da915Sopenharmony_ci */ 2611987da915Sopenharmony_ci 2612987da915Sopenharmony_cistatic u16 forward_rcrd(CONTEXT *ctx, u32 blk, u16 pos, 2613987da915Sopenharmony_ci const struct BUFFER *buf, const struct BUFFER *nextbuf) 2614987da915Sopenharmony_ci{ 2615987da915Sopenharmony_ci const RECORD_PAGE_HEADER *rph; 2616987da915Sopenharmony_ci const LOG_RECORD *logr; 2617987da915Sopenharmony_ci const char *data; 2618987da915Sopenharmony_ci u16 k; 2619987da915Sopenharmony_ci u16 endoff; 2620987da915Sopenharmony_ci BOOL stop; 2621987da915Sopenharmony_ci 2622987da915Sopenharmony_ci rph = &buf->block.record; 2623987da915Sopenharmony_ci if (rph && (rph->magic == magic_RCRD)) { 2624987da915Sopenharmony_ci data = buf->block.data; 2625987da915Sopenharmony_ci showheadrcrd(blk, rph); 2626987da915Sopenharmony_ci k = buf->headsz; 2627987da915Sopenharmony_ci if ((k < pos) && (pos < blocksz)) { 2628987da915Sopenharmony_ci k = ((pos - 1) | 7) + 1; 2629987da915Sopenharmony_ci } 2630987da915Sopenharmony_ci// TODO check bad start > blocksz - 48 2631987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 2632987da915Sopenharmony_ci stop = FALSE; 2633987da915Sopenharmony_ci if (!likelyop(logr)) { 2634987da915Sopenharmony_ci if (optv) 2635987da915Sopenharmony_ci printf("* Bad start 0x%x for block %d\n", 2636987da915Sopenharmony_ci (int)pos,(int)blk); 2637987da915Sopenharmony_ci k = searchlikely(buf); 2638987da915Sopenharmony_ci if ((k + sizeof(LOG_RECORD)) > blocksz) { 2639987da915Sopenharmony_ci printf("No likely full record in block %lu\n", 2640987da915Sopenharmony_ci (unsigned long)blk); 2641987da915Sopenharmony_ci /* there can be a partial one */ 2642987da915Sopenharmony_ci k = le16_to_cpu(rph->next_record_offset); 2643987da915Sopenharmony_ci if ((k < (u16)sizeof(RECORD_PAGE_HEADER)) 2644987da915Sopenharmony_ci || ((blocksz - k) < LOG_RECORD_HEAD_SZ)) 2645987da915Sopenharmony_ci stop = TRUE; 2646987da915Sopenharmony_ci } else { 2647987da915Sopenharmony_ci if (optv) 2648987da915Sopenharmony_ci printf("First record computed at" 2649987da915Sopenharmony_ci " offset 0x%x\n", (int)k); 2650987da915Sopenharmony_ci } 2651987da915Sopenharmony_ci } 2652987da915Sopenharmony_ci while (!stop) { 2653987da915Sopenharmony_ci s32 size; 2654987da915Sopenharmony_ci 2655987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 2656987da915Sopenharmony_ci size = le32_to_cpu(logr->client_data_length) 2657987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 2658987da915Sopenharmony_ci if ((size < MINRECSIZE) 2659987da915Sopenharmony_ci || (size > MAXRECSIZE) 2660987da915Sopenharmony_ci || (size & 7)) { 2661987da915Sopenharmony_ci printf("** Bad record size %ld in block %ld" 2662987da915Sopenharmony_ci " offset 0x%x\n", 2663987da915Sopenharmony_ci (long)size, (long)buf->num, (int)k); 2664987da915Sopenharmony_ci showlogr(ctx, k, logr); 2665987da915Sopenharmony_ci k = 0; 2666987da915Sopenharmony_ci stop = TRUE; 2667987da915Sopenharmony_ci } else { 2668987da915Sopenharmony_ci endoff = le16_to_cpu(rph->next_record_offset); 2669987da915Sopenharmony_ci if (((u32)(k + size) <= blocksz) 2670987da915Sopenharmony_ci && ((u32)(k + size) <= endoff)) { 2671987da915Sopenharmony_ci actionnum++; 2672987da915Sopenharmony_ci if (optv) { 2673987da915Sopenharmony_ci printf("\n* log action %u at" 2674987da915Sopenharmony_ci " 0x%x size %d (next" 2675987da915Sopenharmony_ci " at 0x%x)\n", 2676987da915Sopenharmony_ci actionnum,k,size, 2677987da915Sopenharmony_ci k + size); 2678987da915Sopenharmony_ci } 2679987da915Sopenharmony_ci showlogr(ctx, k, logr); 2680987da915Sopenharmony_ci if (!logr->client_data_length) { 2681987da915Sopenharmony_ci printf("** Bad" 2682987da915Sopenharmony_ci " client_data_length\n"); 2683987da915Sopenharmony_ci stop = TRUE; 2684987da915Sopenharmony_ci } 2685987da915Sopenharmony_ci k += size; 2686987da915Sopenharmony_ci if ((blocksz - k) 2687987da915Sopenharmony_ci < LOG_RECORD_HEAD_SZ) { 2688987da915Sopenharmony_ci k = nextbuf->headsz; 2689987da915Sopenharmony_ci stop = TRUE; 2690987da915Sopenharmony_ci } 2691987da915Sopenharmony_ci } else { 2692987da915Sopenharmony_ci k = overlapshow(ctx, k, blk, 2693987da915Sopenharmony_ci buf, nextbuf); 2694987da915Sopenharmony_ci stop = TRUE; 2695987da915Sopenharmony_ci } 2696987da915Sopenharmony_ci } 2697987da915Sopenharmony_ci } 2698987da915Sopenharmony_ci } else { 2699987da915Sopenharmony_ci printf("** Not a RCRD record, MAGIC 0x%08lx\n", 2700987da915Sopenharmony_ci (long)le32_to_cpu(rph->magic)); 2701987da915Sopenharmony_ci k = 0; 2702987da915Sopenharmony_ci } 2703987da915Sopenharmony_ci return (k); 2704987da915Sopenharmony_ci} 2705987da915Sopenharmony_ci 2706987da915Sopenharmony_ci/* 2707987da915Sopenharmony_ci * Display a restart page 2708987da915Sopenharmony_ci */ 2709987da915Sopenharmony_ci 2710987da915Sopenharmony_cistatic void showrest(const RESTART_PAGE_HEADER *rest) 2711987da915Sopenharmony_ci{ 2712987da915Sopenharmony_ci const RESTART_AREA *resa; 2713987da915Sopenharmony_ci const LOG_CLIENT_RECORD *rcli; 2714987da915Sopenharmony_ci const char *data; 2715987da915Sopenharmony_ci 2716987da915Sopenharmony_ci data = (const char*)rest; 2717987da915Sopenharmony_ci if ((rest->magic == magic_RSTR) 2718987da915Sopenharmony_ci || (rest->magic == magic_CHKD)) { 2719987da915Sopenharmony_ci if (optv) { 2720987da915Sopenharmony_ci printf("magic %08lx\n", 2721987da915Sopenharmony_ci (long)le32_to_cpu(rest->magic)); 2722987da915Sopenharmony_ci printf("usa_ofs %04x\n", 2723987da915Sopenharmony_ci (int)le16_to_cpu(rest->usa_ofs)); 2724987da915Sopenharmony_ci printf("usa_count %04x\n", 2725987da915Sopenharmony_ci (int)le16_to_cpu(rest->usa_count)); 2726987da915Sopenharmony_ci printf("chkdsk_lsn %016llx\n", 2727987da915Sopenharmony_ci (long long)sle64_to_cpu(rest->chkdsk_lsn)); 2728987da915Sopenharmony_ci printf("system_page_size %08lx\n", 2729987da915Sopenharmony_ci (long)le32_to_cpu(rest->system_page_size)); 2730987da915Sopenharmony_ci printf("log_page_size %08lx\n", 2731987da915Sopenharmony_ci (long)le32_to_cpu(rest->log_page_size)); 2732987da915Sopenharmony_ci printf("restart_area_offset %04x\n", 2733987da915Sopenharmony_ci (int)le16_to_cpu(rest->restart_area_offset)); 2734987da915Sopenharmony_ci printf("minor_vers %d\n", 2735987da915Sopenharmony_ci (int)sle16_to_cpu(rest->minor_ver)); 2736987da915Sopenharmony_ci printf("major_vers %d\n", 2737987da915Sopenharmony_ci (int)sle16_to_cpu(rest->major_ver)); 2738987da915Sopenharmony_ci printf("usn %04x\n", 2739987da915Sopenharmony_ci (int)le16_to_cpu(rest->usn)); 2740987da915Sopenharmony_ci printf("\n"); 2741987da915Sopenharmony_ci } else { 2742987da915Sopenharmony_ci if (optt) 2743987da915Sopenharmony_ci printf(" chkdsk %016llx\n", 2744987da915Sopenharmony_ci (long long)sle64_to_cpu(rest->chkdsk_lsn)); 2745987da915Sopenharmony_ci } 2746987da915Sopenharmony_ci resa = (const RESTART_AREA*) 2747987da915Sopenharmony_ci &data[le16_to_cpu(rest->restart_area_offset)]; 2748987da915Sopenharmony_ci if (optv) { 2749987da915Sopenharmony_ci printf("current_lsn %016llx\n", 2750987da915Sopenharmony_ci (long long)sle64_to_cpu(resa->current_lsn)); 2751987da915Sopenharmony_ci printf("log_clients %04x\n", 2752987da915Sopenharmony_ci (int)le16_to_cpu(resa->log_clients)); 2753987da915Sopenharmony_ci printf("client_free_list %04x\n", 2754987da915Sopenharmony_ci (int)le16_to_cpu(resa->client_free_list)); 2755987da915Sopenharmony_ci printf("client_in_use_list %04x\n", 2756987da915Sopenharmony_ci (int)le16_to_cpu(resa->client_in_use_list)); 2757987da915Sopenharmony_ci printf("flags %04x\n", 2758987da915Sopenharmony_ci (int)le16_to_cpu(resa->flags)); 2759987da915Sopenharmony_ci printf("seq_number_bits %08lx\n", 2760987da915Sopenharmony_ci (long)le32_to_cpu(resa->seq_number_bits)); 2761987da915Sopenharmony_ci printf("restart_area_length %04x\n", 2762987da915Sopenharmony_ci (int)le16_to_cpu(resa->restart_area_length)); 2763987da915Sopenharmony_ci printf("client_array_offset %04x\n", 2764987da915Sopenharmony_ci (int)le16_to_cpu(resa->client_array_offset)); 2765987da915Sopenharmony_ci printf("file_size %016llx\n", 2766987da915Sopenharmony_ci (long long)sle64_to_cpu(resa->file_size)); 2767987da915Sopenharmony_ci printf("last_lsn_data_len %08lx\n", 2768987da915Sopenharmony_ci (long)le32_to_cpu(resa->last_lsn_data_length)); 2769987da915Sopenharmony_ci printf("record_length %04x\n", 2770987da915Sopenharmony_ci (int)le16_to_cpu(resa->log_record_header_length)); 2771987da915Sopenharmony_ci printf("log_page_data_offs %04x\n", 2772987da915Sopenharmony_ci (int)le16_to_cpu(resa->log_page_data_offset)); 2773987da915Sopenharmony_ci printf("restart_log_open_count %08lx\n", 2774987da915Sopenharmony_ci (long)le32_to_cpu(resa->restart_log_open_count)); 2775987da915Sopenharmony_ci printf("\n"); 2776987da915Sopenharmony_ci } else { 2777987da915Sopenharmony_ci if (optt) 2778987da915Sopenharmony_ci printf(" latest %016llx\n", 2779987da915Sopenharmony_ci (long long)sle64_to_cpu(resa->current_lsn)); 2780987da915Sopenharmony_ci } 2781987da915Sopenharmony_ci 2782987da915Sopenharmony_ci rcli = (const LOG_CLIENT_RECORD*) 2783987da915Sopenharmony_ci &data[le16_to_cpu(rest->restart_area_offset) 2784987da915Sopenharmony_ci + le16_to_cpu(resa->client_array_offset)]; 2785987da915Sopenharmony_ci if (optv) { 2786987da915Sopenharmony_ci printf("oldest_lsn %016llx\n", 2787987da915Sopenharmony_ci (long long)sle64_to_cpu(rcli->oldest_lsn)); 2788987da915Sopenharmony_ci printf("client_restart_lsn %016llx\n", 2789987da915Sopenharmony_ci (long long)sle64_to_cpu(rcli->client_restart_lsn)); 2790987da915Sopenharmony_ci printf("prev_client %04x\n", 2791987da915Sopenharmony_ci (int)le16_to_cpu(rcli->prev_client)); 2792987da915Sopenharmony_ci printf("next_client %04x\n", 2793987da915Sopenharmony_ci (int)le16_to_cpu(rcli->next_client)); 2794987da915Sopenharmony_ci printf("seq_number %04x\n", 2795987da915Sopenharmony_ci (int)le16_to_cpu(rcli->seq_number)); 2796987da915Sopenharmony_ci printf("client_name_length %08x\n", 2797987da915Sopenharmony_ci (int)le32_to_cpu(rcli->client_name_length)); 2798987da915Sopenharmony_ci showname("client_name ", 2799987da915Sopenharmony_ci (const char*)rcli->client_name, 2800987da915Sopenharmony_ci le32_to_cpu(rcli->client_name_length) >> 1); 2801987da915Sopenharmony_ci } else { 2802987da915Sopenharmony_ci if (optt) { 2803987da915Sopenharmony_ci printf(" synced %016llx\n", 2804987da915Sopenharmony_ci (long long)sle64_to_cpu( 2805987da915Sopenharmony_ci rcli->oldest_lsn)); 2806987da915Sopenharmony_ci printf(" committed %016llx\n", 2807987da915Sopenharmony_ci (long long)sle64_to_cpu( 2808987da915Sopenharmony_ci rcli->client_restart_lsn)); 2809987da915Sopenharmony_ci } 2810987da915Sopenharmony_ci } 2811987da915Sopenharmony_ci } else 2812987da915Sopenharmony_ci printf("Not a RSTR or CHKD record, MAGIC 0x%08lx\n", 2813987da915Sopenharmony_ci (long)le32_to_cpu(rest->magic)); 2814987da915Sopenharmony_ci} 2815987da915Sopenharmony_ci 2816987da915Sopenharmony_cistatic BOOL dorest(CONTEXT *ctx, unsigned long blk, 2817987da915Sopenharmony_ci const RESTART_PAGE_HEADER *rph, BOOL initial) 2818987da915Sopenharmony_ci{ 2819987da915Sopenharmony_ci const RESTART_AREA *resa; 2820987da915Sopenharmony_ci const LOG_CLIENT_RECORD *rcli; 2821987da915Sopenharmony_ci const char *data; 2822987da915Sopenharmony_ci s64 diff; 2823987da915Sopenharmony_ci int offs; 2824987da915Sopenharmony_ci int size; 2825987da915Sopenharmony_ci BOOL change; 2826987da915Sopenharmony_ci BOOL dirty; 2827987da915Sopenharmony_ci 2828987da915Sopenharmony_ci data = (const char*)rph; 2829987da915Sopenharmony_ci offs = le16_to_cpu(rph->restart_area_offset); 2830987da915Sopenharmony_ci resa = (const RESTART_AREA*)&data[offs]; 2831987da915Sopenharmony_ci rcli = (const LOG_CLIENT_RECORD*)&data[offs 2832987da915Sopenharmony_ci + le16_to_cpu(resa->client_array_offset)]; 2833987da915Sopenharmony_ci if (initial) { 2834987da915Sopenharmony_ci /* Information from block initially found best */ 2835987da915Sopenharmony_ci latest_lsn = sle64_to_cpu(resa->current_lsn); 2836987da915Sopenharmony_ci committed_lsn = sle64_to_cpu(rcli->client_restart_lsn); 2837987da915Sopenharmony_ci synced_lsn = sle64_to_cpu(rcli->oldest_lsn); 2838987da915Sopenharmony_ci memcpy(&log_header, rph, 2839987da915Sopenharmony_ci sizeof(RESTART_PAGE_HEADER)); 2840987da915Sopenharmony_ci offs = le16_to_cpu(log_header.restart_area_offset); 2841987da915Sopenharmony_ci memcpy(&restart, &data[offs], 2842987da915Sopenharmony_ci sizeof(RESTART_AREA)); 2843987da915Sopenharmony_ci offs += le16_to_cpu(restart.client_array_offset); 2844987da915Sopenharmony_ci memcpy(&client, &data[offs], 2845987da915Sopenharmony_ci sizeof(LOG_CLIENT_RECORD)); 2846987da915Sopenharmony_ci dirty = !(resa->flags & RESTART_VOLUME_IS_CLEAN); 2847987da915Sopenharmony_ci if (optv || optt) 2848987da915Sopenharmony_ci printf("* Using initial restart page," 2849987da915Sopenharmony_ci " syncing from 0x%llx, %s\n", 2850987da915Sopenharmony_ci (long long)synced_lsn, 2851987da915Sopenharmony_ci (dirty ? "dirty" : "clean")); 2852987da915Sopenharmony_ci /* Get the block page size */ 2853987da915Sopenharmony_ci blocksz = le32_to_cpu(rph->log_page_size); 2854987da915Sopenharmony_ci if (optv) 2855987da915Sopenharmony_ci printf("* Block size %ld bytes\n", (long)blocksz); 2856987da915Sopenharmony_ci blockbits = 1; 2857987da915Sopenharmony_ci while ((u32)(1 << blockbits) < blocksz) 2858987da915Sopenharmony_ci blockbits++; 2859987da915Sopenharmony_ci } else { 2860987da915Sopenharmony_ci size = offs + le16_to_cpu(resa->restart_area_length); 2861987da915Sopenharmony_ci if (optv) { 2862987da915Sopenharmony_ci if (optv >= 2) 2863987da915Sopenharmony_ci hexdump(data,size); 2864987da915Sopenharmony_ci printf("* RSTR in block %ld 0x%lx (addr 0x%llx)\n", 2865987da915Sopenharmony_ci (long)blk,(long)blk, 2866987da915Sopenharmony_ci (long long)loclogblk(ctx, blk)); 2867987da915Sopenharmony_ci } else { 2868987da915Sopenharmony_ci if (optt) 2869987da915Sopenharmony_ci printf("restart %ld\n",(long)blk); 2870987da915Sopenharmony_ci } 2871987da915Sopenharmony_ci showrest(rph); 2872987da915Sopenharmony_ci /* Information from an older restart block if requested */ 2873987da915Sopenharmony_ci dirty = !(restart.flags & RESTART_VOLUME_IS_CLEAN); 2874987da915Sopenharmony_ci diff = sle64_to_cpu(rcli->client_restart_lsn) - committed_lsn; 2875987da915Sopenharmony_ci if (ctx->vol) { 2876987da915Sopenharmony_ci change = (opts > 1) && (diff < 0); 2877987da915Sopenharmony_ci } else { 2878987da915Sopenharmony_ci change = (opts > 1 ? diff < 0 : diff > 0); 2879987da915Sopenharmony_ci } 2880987da915Sopenharmony_ci if (change) { 2881987da915Sopenharmony_ci committed_lsn = sle64_to_cpu(rcli->client_restart_lsn); 2882987da915Sopenharmony_ci synced_lsn = sle64_to_cpu(rcli->oldest_lsn); 2883987da915Sopenharmony_ci latest_lsn = sle64_to_cpu(resa->current_lsn); 2884987da915Sopenharmony_ci memcpy(&log_header, rph, 2885987da915Sopenharmony_ci sizeof(RESTART_PAGE_HEADER)); 2886987da915Sopenharmony_ci offs = le16_to_cpu(log_header.restart_area_offset); 2887987da915Sopenharmony_ci memcpy(&restart, &data[offs], 2888987da915Sopenharmony_ci sizeof(RESTART_AREA)); 2889987da915Sopenharmony_ci offs += le16_to_cpu(restart.client_array_offset); 2890987da915Sopenharmony_ci memcpy(&client, &data[offs], 2891987da915Sopenharmony_ci sizeof(LOG_CLIENT_RECORD)); 2892987da915Sopenharmony_ci dirty = !(resa->flags & RESTART_VOLUME_IS_CLEAN); 2893987da915Sopenharmony_ci if (optv || optt) 2894987da915Sopenharmony_ci printf("* Using %s restart page," 2895987da915Sopenharmony_ci " syncing from 0x%llx, %s\n", 2896987da915Sopenharmony_ci (diff < 0 ? "older" : "newer"), 2897987da915Sopenharmony_ci (long long)synced_lsn, 2898987da915Sopenharmony_ci (dirty ? "dirty" : "clean")); 2899987da915Sopenharmony_ci } 2900987da915Sopenharmony_ci } 2901987da915Sopenharmony_ci restart_lsn = synced_lsn; 2902987da915Sopenharmony_ci offset_mask = ((u64)1 << (64 - le32_to_cpu(restart.seq_number_bits))) 2903987da915Sopenharmony_ci - (1 << (blockbits - 3)); 2904987da915Sopenharmony_ci return (dirty); 2905987da915Sopenharmony_ci} 2906987da915Sopenharmony_ci 2907987da915Sopenharmony_ci/* 2908987da915Sopenharmony_ci * Read and process the first restart block 2909987da915Sopenharmony_ci * 2910987da915Sopenharmony_ci * In full mode, both restart page are silently analyzed by the 2911987da915Sopenharmony_ci * library and the most recent readable one is used to define the 2912987da915Sopenharmony_ci * sync parameters. 2913987da915Sopenharmony_ci * 2914987da915Sopenharmony_ci * Returns the first restart buffer 2915987da915Sopenharmony_ci * or NULL if the restart block is not valid 2916987da915Sopenharmony_ci */ 2917987da915Sopenharmony_ci 2918987da915Sopenharmony_ci 2919987da915Sopenharmony_cistatic const struct BUFFER *read_restart(CONTEXT *ctx) 2920987da915Sopenharmony_ci{ 2921987da915Sopenharmony_ci const struct BUFFER *buf; 2922987da915Sopenharmony_ci BOOL bad; 2923987da915Sopenharmony_ci int blk; 2924987da915Sopenharmony_ci int major, minor; 2925987da915Sopenharmony_ci 2926987da915Sopenharmony_ci bad = FALSE; 2927987da915Sopenharmony_ci for (blk=0; blk<BASEBLKS2; blk++) 2928987da915Sopenharmony_ci redirect[blk] = 0; 2929987da915Sopenharmony_ci log_major = 0; /* needed for reading into a buffer */ 2930987da915Sopenharmony_ci if (ctx->vol) { 2931987da915Sopenharmony_ci RESTART_PAGE_HEADER *rph; 2932987da915Sopenharmony_ci 2933987da915Sopenharmony_ci rph = (RESTART_PAGE_HEADER*)NULL; 2934987da915Sopenharmony_ci /* Full mode : use the restart page selected by the library */ 2935987da915Sopenharmony_ci if (ntfs_check_logfile(log_na, &rph)) { 2936987da915Sopenharmony_ci /* rph is left unchanged for a wiped out log file */ 2937987da915Sopenharmony_ci if (rph) { 2938987da915Sopenharmony_ci dorest(ctx, 0, rph, TRUE); 2939987da915Sopenharmony_ci free(rph); 2940987da915Sopenharmony_ci buf = read_buffer(ctx,0); 2941987da915Sopenharmony_ci } else { 2942987da915Sopenharmony_ci buf = (const struct BUFFER*)NULL; 2943987da915Sopenharmony_ci printf("** The log file has been wiped out\n"); 2944987da915Sopenharmony_ci } 2945987da915Sopenharmony_ci } else { 2946987da915Sopenharmony_ci buf = (const struct BUFFER*)NULL; 2947987da915Sopenharmony_ci printf("** Could not get any restart page\n"); 2948987da915Sopenharmony_ci } 2949987da915Sopenharmony_ci } else { 2950987da915Sopenharmony_ci /* Reduced mode : rely on first restart page */ 2951987da915Sopenharmony_ci blockbits = BLOCKBITS; /* Until the correct value is read */ 2952987da915Sopenharmony_ci blocksz = 1L << blockbits; 2953987da915Sopenharmony_ci buf = read_buffer(ctx,0); 2954987da915Sopenharmony_ci } 2955987da915Sopenharmony_ci if (buf) { 2956987da915Sopenharmony_ci NTFS_RECORD_TYPES magic; 2957987da915Sopenharmony_ci 2958987da915Sopenharmony_ci magic = buf->block.restart.magic; 2959987da915Sopenharmony_ci switch (magic) { 2960987da915Sopenharmony_ci case magic_RSTR : 2961987da915Sopenharmony_ci break; 2962987da915Sopenharmony_ci case magic_CHKD : 2963987da915Sopenharmony_ci printf("** The log file has been obsoleted by chkdsk\n"); 2964987da915Sopenharmony_ci bad = TRUE; 2965987da915Sopenharmony_ci break; 2966987da915Sopenharmony_ci case magic_empty : 2967987da915Sopenharmony_ci printf("** The log file has been wiped out\n"); 2968987da915Sopenharmony_ci bad = TRUE; 2969987da915Sopenharmony_ci break; 2970987da915Sopenharmony_ci default : 2971987da915Sopenharmony_ci printf("** Invalid restart block\n"); 2972987da915Sopenharmony_ci bad = TRUE; 2973987da915Sopenharmony_ci break; 2974987da915Sopenharmony_ci } 2975987da915Sopenharmony_ci if (!bad && !ctx->vol) 2976987da915Sopenharmony_ci dorest(ctx, 0, &buf->block.restart, TRUE); 2977987da915Sopenharmony_ci major = sle16_to_cpu(buf->block.restart.major_ver); 2978987da915Sopenharmony_ci minor = sle16_to_cpu(buf->block.restart.minor_ver); 2979987da915Sopenharmony_ci if ((major == 2) && (minor == 0)) { 2980987da915Sopenharmony_ci if (!optk) { 2981987da915Sopenharmony_ci printf("** Fast restart mode detected," 2982987da915Sopenharmony_ci " data could be lost\n"); 2983987da915Sopenharmony_ci printf(" Use option --kill-fast-restart" 2984987da915Sopenharmony_ci " to bypass\n"); 2985987da915Sopenharmony_ci bad = TRUE; 2986987da915Sopenharmony_ci } 2987987da915Sopenharmony_ci } else 2988987da915Sopenharmony_ci if ((major != 1) || (minor != 1)) { 2989987da915Sopenharmony_ci printf("** Unsupported $LogFile version %d.%d\n", 2990987da915Sopenharmony_ci major, minor); 2991987da915Sopenharmony_ci bad = TRUE; 2992987da915Sopenharmony_ci } 2993987da915Sopenharmony_ci log_major = major; 2994987da915Sopenharmony_ci if (bad) { 2995987da915Sopenharmony_ci buf = (const struct BUFFER*)NULL; 2996987da915Sopenharmony_ci } 2997987da915Sopenharmony_ci } 2998987da915Sopenharmony_ci return (buf); 2999987da915Sopenharmony_ci} 3000987da915Sopenharmony_ci 3001987da915Sopenharmony_ci/* 3002987da915Sopenharmony_ci * Mark the logfile as synced 3003987da915Sopenharmony_ci */ 3004987da915Sopenharmony_ci 3005987da915Sopenharmony_cistatic int reset_logfile(CONTEXT *ctx __attribute__((unused))) 3006987da915Sopenharmony_ci{ 3007987da915Sopenharmony_ci char *buffer; 3008987da915Sopenharmony_ci int off; 3009987da915Sopenharmony_ci int err; 3010987da915Sopenharmony_ci 3011987da915Sopenharmony_ci err = 1; 3012987da915Sopenharmony_ci buffer = (char*)malloc(blocksz); 3013987da915Sopenharmony_ci if (buffer) { 3014987da915Sopenharmony_ci memset(buffer, 0, blocksz); 3015987da915Sopenharmony_ci restart.client_in_use_list = LOGFILE_NO_CLIENT; 3016987da915Sopenharmony_ci restart.flags |= RESTART_VOLUME_IS_CLEAN; 3017987da915Sopenharmony_ci client.oldest_lsn = cpu_to_sle64(restart_lsn); 3018987da915Sopenharmony_ci /* Set $LogFile version to 1.1 so that volume can be mounted */ 3019987da915Sopenharmony_ci log_header.major_ver = const_cpu_to_sle16(1); 3020987da915Sopenharmony_ci log_header.minor_ver = const_cpu_to_sle16(1); 3021987da915Sopenharmony_ci memcpy(buffer, &log_header, 3022987da915Sopenharmony_ci sizeof(RESTART_PAGE_HEADER)); 3023987da915Sopenharmony_ci off = le16_to_cpu(log_header.restart_area_offset); 3024987da915Sopenharmony_ci memcpy(&buffer[off], &restart, 3025987da915Sopenharmony_ci sizeof(RESTART_AREA)); 3026987da915Sopenharmony_ci off += le16_to_cpu(restart.client_array_offset); 3027987da915Sopenharmony_ci memcpy(&buffer[off], &client, 3028987da915Sopenharmony_ci sizeof(LOG_CLIENT_RECORD)); 3029987da915Sopenharmony_ci if (!ntfs_mst_pre_write_fixup((NTFS_RECORD*)buffer, blocksz) 3030987da915Sopenharmony_ci && (ntfs_attr_pwrite(log_na, 0, 3031987da915Sopenharmony_ci blocksz, buffer) == blocksz) 3032987da915Sopenharmony_ci && (ntfs_attr_pwrite(log_na, (u64)1 << blockbits, 3033987da915Sopenharmony_ci blocksz, buffer) == blocksz)) 3034987da915Sopenharmony_ci err = 0; 3035987da915Sopenharmony_ci free(buffer); 3036987da915Sopenharmony_ci } 3037987da915Sopenharmony_ci return (err); 3038987da915Sopenharmony_ci} 3039987da915Sopenharmony_ci 3040987da915Sopenharmony_ci/* 3041987da915Sopenharmony_ci * Determine the most recent valid record block 3042987da915Sopenharmony_ci */ 3043987da915Sopenharmony_ci 3044987da915Sopenharmony_cistatic const struct BUFFER *best_start(const struct BUFFER *buf, 3045987da915Sopenharmony_ci const struct BUFFER *altbuf) 3046987da915Sopenharmony_ci{ 3047987da915Sopenharmony_ci const struct BUFFER *best; 3048987da915Sopenharmony_ci const RECORD_PAGE_HEADER *head; 3049987da915Sopenharmony_ci const RECORD_PAGE_HEADER *althead; 3050987da915Sopenharmony_ci s64 diff; 3051987da915Sopenharmony_ci 3052987da915Sopenharmony_ci if (!buf || !altbuf) 3053987da915Sopenharmony_ci best = (buf ? buf : altbuf); 3054987da915Sopenharmony_ci else { 3055987da915Sopenharmony_ci head = &buf->block.record; 3056987da915Sopenharmony_ci althead = &altbuf->block.record; 3057987da915Sopenharmony_ci /* determine most recent, caring for wraparounds */ 3058987da915Sopenharmony_ci diff = sle64_to_cpu(althead->last_end_lsn) 3059987da915Sopenharmony_ci - sle64_to_cpu(head->last_end_lsn); 3060987da915Sopenharmony_ci if (diff > 0) 3061987da915Sopenharmony_ci best = altbuf; 3062987da915Sopenharmony_ci else 3063987da915Sopenharmony_ci best = buf; 3064987da915Sopenharmony_ci } 3065987da915Sopenharmony_ci if (best && (best->block.record.magic != magic_RCRD)) 3066987da915Sopenharmony_ci best = (const struct BUFFER*)NULL; 3067987da915Sopenharmony_ci return (best); 3068987da915Sopenharmony_ci} 3069987da915Sopenharmony_ci 3070987da915Sopenharmony_ci/* 3071987da915Sopenharmony_ci * Interpret the boot data 3072987da915Sopenharmony_ci * 3073987da915Sopenharmony_ci * Probably not needed any more, use ctx->vol 3074987da915Sopenharmony_ci */ 3075987da915Sopenharmony_ci 3076987da915Sopenharmony_cistatic BOOL getboot(const char *buf) 3077987da915Sopenharmony_ci{ 3078987da915Sopenharmony_ci u64 sectors; 3079987da915Sopenharmony_ci u64 clusters; 3080987da915Sopenharmony_ci u16 sectpercluster; 3081987da915Sopenharmony_ci BOOL ok; 3082987da915Sopenharmony_ci 3083987da915Sopenharmony_ci ok = TRUE; 3084987da915Sopenharmony_ci /* Beware : bad alignment */ 3085987da915Sopenharmony_ci bytespersect = (buf[11] & 255) + ((buf[12] & 255) << 8); 3086987da915Sopenharmony_ci sectpercluster = buf[13] & 255; 3087987da915Sopenharmony_ci clustersz = bytespersect * (u32)sectpercluster; 3088987da915Sopenharmony_ci clusterbits = 1; 3089987da915Sopenharmony_ci while ((u32)(1 << clusterbits) < clustersz) 3090987da915Sopenharmony_ci clusterbits++; 3091987da915Sopenharmony_ci sectors = getle64(buf, 0x28); 3092987da915Sopenharmony_ci clusters = sectors/sectpercluster; 3093987da915Sopenharmony_ci mftlcn = getle64(buf, 0x30); 3094987da915Sopenharmony_ci if (buf[0x40] & 0x80) 3095987da915Sopenharmony_ci mftrecsz = 1 << (16 - (buf[0x40] & 15)); 3096987da915Sopenharmony_ci else 3097987da915Sopenharmony_ci mftrecsz = (buf[0x40] & 127)*clustersz; 3098987da915Sopenharmony_ci mftrecbits = 1; 3099987da915Sopenharmony_ci while ((u32)(1 << mftrecbits) < mftrecsz) 3100987da915Sopenharmony_ci mftrecbits++; 3101987da915Sopenharmony_ci if (optv) { 3102987da915Sopenharmony_ci if ((long long)sectors*bytespersect > 10000000000LL) 3103987da915Sopenharmony_ci printf("Capacity %lld bytes (%lld GB)\n", 3104987da915Sopenharmony_ci (long long)sectors*bytespersect, 3105987da915Sopenharmony_ci (long long)sectors*bytespersect/1000000000); 3106987da915Sopenharmony_ci else 3107987da915Sopenharmony_ci printf("Capacity %lld bytes (%lld MB)\n", 3108987da915Sopenharmony_ci (long long)sectors*bytespersect, 3109987da915Sopenharmony_ci (long long)sectors*bytespersect/1000000); 3110987da915Sopenharmony_ci printf("sectors %lld (0x%llx), sector size %d\n", 3111987da915Sopenharmony_ci (long long)sectors,(long long)sectors, 3112987da915Sopenharmony_ci (int)bytespersect); 3113987da915Sopenharmony_ci printf("clusters %lld (0x%llx), cluster size %d (%d bits)\n", 3114987da915Sopenharmony_ci (long long)clusters,(long long)clusters, 3115987da915Sopenharmony_ci (int)clustersz,(int)clusterbits); 3116987da915Sopenharmony_ci printf("MFT at cluster %lld (0x%llx), entry size %lu\n", 3117987da915Sopenharmony_ci (long long)mftlcn,(long long)mftlcn, 3118987da915Sopenharmony_ci (unsigned long)mftrecsz); 3119987da915Sopenharmony_ci if (mftrecsz > clustersz) 3120987da915Sopenharmony_ci printf("%ld clusters per MFT entry\n", 3121987da915Sopenharmony_ci (long)(mftrecsz/clustersz)); 3122987da915Sopenharmony_ci else 3123987da915Sopenharmony_ci printf("%ld MFT entries per cluster\n", 3124987da915Sopenharmony_ci (long)(clustersz/mftrecsz)); 3125987da915Sopenharmony_ci } 3126987da915Sopenharmony_ci return (ok); 3127987da915Sopenharmony_ci} 3128987da915Sopenharmony_ci 3129987da915Sopenharmony_cistatic int locatelogfile(CONTEXT *ctx) 3130987da915Sopenharmony_ci{ 3131987da915Sopenharmony_ci int err; 3132987da915Sopenharmony_ci 3133987da915Sopenharmony_ci err = 1; 3134987da915Sopenharmony_ci log_ni = ntfs_inode_open(ctx->vol, FILE_LogFile); 3135987da915Sopenharmony_ci if (log_ni) { 3136987da915Sopenharmony_ci log_na = ntfs_attr_open(log_ni, AT_DATA, AT_UNNAMED, 0); 3137987da915Sopenharmony_ci if (log_na) { 3138987da915Sopenharmony_ci logfilesz = log_na->data_size; 3139987da915Sopenharmony_ci err = 0; 3140987da915Sopenharmony_ci } 3141987da915Sopenharmony_ci } 3142987da915Sopenharmony_ci return (err); 3143987da915Sopenharmony_ci} 3144987da915Sopenharmony_ci 3145987da915Sopenharmony_ci/* 3146987da915Sopenharmony_ci * Analyze a $LogFile copy 3147987da915Sopenharmony_ci * 3148987da915Sopenharmony_ci * A $LogFile cannot be played. It can be however be analyzed in 3149987da915Sopenharmony_ci * stand-alone mode. 3150987da915Sopenharmony_ci * The location of the $MFT will have to be determined elsewhere. 3151987da915Sopenharmony_ci */ 3152987da915Sopenharmony_ci 3153987da915Sopenharmony_cistatic BOOL getlogfiledata(CONTEXT *ctx, const char *boot) 3154987da915Sopenharmony_ci{ 3155987da915Sopenharmony_ci const RESTART_PAGE_HEADER *rph; 3156987da915Sopenharmony_ci const RESTART_AREA *rest; 3157987da915Sopenharmony_ci BOOL ok; 3158987da915Sopenharmony_ci u32 off; 3159987da915Sopenharmony_ci s64 size; 3160987da915Sopenharmony_ci u32 system_page_size; 3161987da915Sopenharmony_ci u32 log_page_size; 3162987da915Sopenharmony_ci 3163987da915Sopenharmony_ci ok = FALSE; 3164987da915Sopenharmony_ci fseek(ctx->file,0L,2); 3165987da915Sopenharmony_ci size = ftell(ctx->file); 3166987da915Sopenharmony_ci rph = (const RESTART_PAGE_HEADER*)boot; 3167987da915Sopenharmony_ci off = le16_to_cpu(rph->restart_area_offset); 3168987da915Sopenharmony_ci /* 3169987da915Sopenharmony_ci * If the system or log page sizes are smaller than the ntfs block size 3170987da915Sopenharmony_ci * or either is not a power of 2 we cannot handle this log file. 3171987da915Sopenharmony_ci */ 3172987da915Sopenharmony_ci system_page_size = le32_to_cpu(rph->system_page_size); 3173987da915Sopenharmony_ci log_page_size = le32_to_cpu(rph->log_page_size); 3174987da915Sopenharmony_ci if (system_page_size < NTFS_BLOCK_SIZE || 3175987da915Sopenharmony_ci log_page_size < NTFS_BLOCK_SIZE || 3176987da915Sopenharmony_ci system_page_size & (system_page_size - 1) || 3177987da915Sopenharmony_ci log_page_size & (log_page_size - 1)) { 3178987da915Sopenharmony_ci printf("** Unsupported page size.\n"); 3179987da915Sopenharmony_ci goto out; 3180987da915Sopenharmony_ci } 3181987da915Sopenharmony_ci if (off & 7 || off > system_page_size) { 3182987da915Sopenharmony_ci printf("** Inconsistent restart area offset.\n"); 3183987da915Sopenharmony_ci goto out; 3184987da915Sopenharmony_ci } 3185987da915Sopenharmony_ci rest = (const RESTART_AREA*)&boot[off]; 3186987da915Sopenharmony_ci 3187987da915Sopenharmony_ci /* estimate cluster size from log file size (unreliable) */ 3188987da915Sopenharmony_ci switch (le32_to_cpu(rest->seq_number_bits)) { 3189987da915Sopenharmony_ci case 45 : clustersz = 512; break; 3190987da915Sopenharmony_ci case 43 : clustersz = 1024; break; /* can be 1024 or 2048 */ 3191987da915Sopenharmony_ci case 40 : 3192987da915Sopenharmony_ci default : clustersz = 4096; break; 3193987da915Sopenharmony_ci } 3194987da915Sopenharmony_ci 3195987da915Sopenharmony_ci clusterbits = 1; 3196987da915Sopenharmony_ci while ((u32)(1 << clusterbits) < clustersz) 3197987da915Sopenharmony_ci clusterbits++; 3198987da915Sopenharmony_ci printf("* Assuming cluster size %ld\n",(long)clustersz); 3199987da915Sopenharmony_ci logfilelcn = 0; 3200987da915Sopenharmony_ci logfilesz = size; 3201987da915Sopenharmony_ci if (optv) 3202987da915Sopenharmony_ci printf("Log file size %lld bytes, cluster size %ld\n", 3203987da915Sopenharmony_ci (long long)size, (long)clustersz); 3204987da915Sopenharmony_ci /* Have to wait an InitializeFileRecordSegment to get these values */ 3205987da915Sopenharmony_ci mftrecsz = 0; 3206987da915Sopenharmony_ci mftrecbits = 0; 3207987da915Sopenharmony_ci ok = TRUE; 3208987da915Sopenharmony_ciout: 3209987da915Sopenharmony_ci return (ok); 3210987da915Sopenharmony_ci} 3211987da915Sopenharmony_ci 3212987da915Sopenharmony_ci/* 3213987da915Sopenharmony_ci * Get basic volume data 3214987da915Sopenharmony_ci * 3215987da915Sopenharmony_ci * Locate the MFT and Logfile 3216987da915Sopenharmony_ci * Not supposed to read the first log block... 3217987da915Sopenharmony_ci */ 3218987da915Sopenharmony_ci 3219987da915Sopenharmony_cistatic BOOL getvolumedata(CONTEXT *ctx, char *boot) 3220987da915Sopenharmony_ci{ 3221987da915Sopenharmony_ci const RESTART_AREA *rest; 3222987da915Sopenharmony_ci BOOL ok; 3223987da915Sopenharmony_ci 3224987da915Sopenharmony_ci ok = FALSE; 3225987da915Sopenharmony_ci rest = (const RESTART_AREA*)NULL; 3226987da915Sopenharmony_ci if (ctx->vol) { 3227987da915Sopenharmony_ci getboot(boot); 3228987da915Sopenharmony_ci mftlcn = ctx->vol->mft_lcn; 3229987da915Sopenharmony_ci mftcnt = ctx->vol->mft_na->data_size/mftrecsz; 3230987da915Sopenharmony_ci if (!locatelogfile(ctx)) 3231987da915Sopenharmony_ci ok = TRUE; 3232987da915Sopenharmony_ci else { 3233987da915Sopenharmony_ci fprintf(stderr,"** Could not read the log file\n"); 3234987da915Sopenharmony_ci } 3235987da915Sopenharmony_ci } else { 3236987da915Sopenharmony_ci if (ctx->file 3237987da915Sopenharmony_ci && (!memcmp(boot,"RSTR",4) || !memcmp(boot,"CHKD",4))) { 3238987da915Sopenharmony_ci printf("* Assuming a log file copy\n"); 3239987da915Sopenharmony_ci ok = getlogfiledata(ctx, boot); 3240987da915Sopenharmony_ci if (!ok) 3241987da915Sopenharmony_ci goto out; 3242987da915Sopenharmony_ci } else 3243987da915Sopenharmony_ci fprintf(stderr,"** Not an NTFS image or log file\n"); 3244987da915Sopenharmony_ci } 3245987da915Sopenharmony_ci// TODO get rest ?, meaningful ? 3246987da915Sopenharmony_ci if (ok && rest) { 3247987da915Sopenharmony_ci if (rest->client_in_use_list 3248987da915Sopenharmony_ci || !(rest->flags & const_cpu_to_le16(2))) 3249987da915Sopenharmony_ci printf("Volume was not unmounted safely\n"); 3250987da915Sopenharmony_ci else 3251987da915Sopenharmony_ci printf("Volume was unmounted safely\n"); 3252987da915Sopenharmony_ci if (le16_to_cpu(rest->client_in_use_list) > 1) 3253987da915Sopenharmony_ci printf("** multiple clients not implemented\n"); 3254987da915Sopenharmony_ci } 3255987da915Sopenharmony_ciout: 3256987da915Sopenharmony_ci return (ok); 3257987da915Sopenharmony_ci} 3258987da915Sopenharmony_ci 3259987da915Sopenharmony_ci/* 3260987da915Sopenharmony_ci * Open the volume (or the log file) and gets its parameters 3261987da915Sopenharmony_ci * 3262987da915Sopenharmony_ci * Returns TRUE if successful 3263987da915Sopenharmony_ci */ 3264987da915Sopenharmony_ci 3265987da915Sopenharmony_cistatic BOOL open_volume(CONTEXT *ctx, const char *device_name) 3266987da915Sopenharmony_ci{ 3267987da915Sopenharmony_ci union { 3268987da915Sopenharmony_ci char buf[1024]; 3269987da915Sopenharmony_ci /* alignment may be needed in getboot() */ 3270987da915Sopenharmony_ci long long force_align; 3271987da915Sopenharmony_ci } boot; 3272987da915Sopenharmony_ci BOOL ok; 3273987da915Sopenharmony_ci int got; 3274987da915Sopenharmony_ci 3275987da915Sopenharmony_ci ok =FALSE; 3276987da915Sopenharmony_ci /* 3277987da915Sopenharmony_ci * First check the boot sector, to avoid library errors 3278987da915Sopenharmony_ci * when trying to mount a log file. 3279987da915Sopenharmony_ci * If the device cannot be fopened or fread, then it is 3280987da915Sopenharmony_ci * unlikely to be a file. 3281987da915Sopenharmony_ci */ 3282987da915Sopenharmony_ci ctx->vol = (ntfs_volume*)NULL; 3283987da915Sopenharmony_ci ctx->file = fopen(device_name, "rb"); 3284987da915Sopenharmony_ci if (ctx->file) { 3285987da915Sopenharmony_ci got = fread(boot.buf,1,1024,ctx->file); 3286987da915Sopenharmony_ci if ((got == 1024) 3287987da915Sopenharmony_ci && (!memcmp(boot.buf, "RSTR", 4) 3288987da915Sopenharmony_ci || !memcmp(boot.buf, "CHKD", 4))) { 3289987da915Sopenharmony_ci /* This appears to be a log file */ 3290987da915Sopenharmony_ci ctx->vol = (ntfs_volume*)NULL; 3291987da915Sopenharmony_ci ok = getvolumedata(ctx, boot.buf); 3292987da915Sopenharmony_ci if (!ok) { 3293987da915Sopenharmony_ci fclose(ctx->file); 3294987da915Sopenharmony_ci goto out; 3295987da915Sopenharmony_ci } 3296987da915Sopenharmony_ci } else { 3297987da915Sopenharmony_ci fclose(ctx->file); 3298987da915Sopenharmony_ci } 3299987da915Sopenharmony_ci } 3300987da915Sopenharmony_ci if (!ok) { 3301987da915Sopenharmony_ci /* Not a log file, assume an ntfs device, mount it */ 3302987da915Sopenharmony_ci ctx->file = (FILE*)NULL; 3303987da915Sopenharmony_ci ctx->vol = ntfs_mount(device_name, 3304987da915Sopenharmony_ci ((optk || optp || optu || opts) && !optn 3305987da915Sopenharmony_ci ? NTFS_MNT_FORENSIC : NTFS_MNT_RDONLY)); 3306987da915Sopenharmony_ci if (ctx->vol) { 3307987da915Sopenharmony_ci ok = getvolumedata(ctx, boot.buf); 3308987da915Sopenharmony_ci if (!ok) 3309987da915Sopenharmony_ci ntfs_umount(ctx->vol, TRUE); 3310987da915Sopenharmony_ci } 3311987da915Sopenharmony_ci } 3312987da915Sopenharmony_ciout: 3313987da915Sopenharmony_ci return (ok); 3314987da915Sopenharmony_ci} 3315987da915Sopenharmony_ci 3316987da915Sopenharmony_cistatic u16 dorcrd(CONTEXT *ctx, u32 blk, u16 pos, const struct BUFFER *buf, 3317987da915Sopenharmony_ci const struct BUFFER *nextbuf) 3318987da915Sopenharmony_ci{ 3319987da915Sopenharmony_ci if (optv) { 3320987da915Sopenharmony_ci if (optv >= 2) 3321987da915Sopenharmony_ci hexdump(buf->block.data,blocksz); 3322987da915Sopenharmony_ci printf("* RCRD in block %ld 0x%lx (addr 0x%llx)" 3323987da915Sopenharmony_ci " from pos 0x%x\n", 3324987da915Sopenharmony_ci (long)blk,(long)blk, 3325987da915Sopenharmony_ci (long long)loclogblk(ctx, blk),(int)pos); 3326987da915Sopenharmony_ci } else { 3327987da915Sopenharmony_ci if (optt) 3328987da915Sopenharmony_ci printf("block %ld\n",(long)blk); 3329987da915Sopenharmony_ci } 3330987da915Sopenharmony_ci return (forward_rcrd(ctx, blk, pos, buf, nextbuf)); 3331987da915Sopenharmony_ci} 3332987da915Sopenharmony_ci 3333987da915Sopenharmony_ci/* 3334987da915Sopenharmony_ci * Concatenate and process a record overlapping on several blocks 3335987da915Sopenharmony_ci */ 3336987da915Sopenharmony_ci 3337987da915Sopenharmony_cistatic TRISTATE backoverlap(CONTEXT *ctx, int blk, 3338987da915Sopenharmony_ci const char *data, const char *nextdata, int k) 3339987da915Sopenharmony_ci{ 3340987da915Sopenharmony_ci const LOG_RECORD *logr; 3341987da915Sopenharmony_ci char *fullrec; 3342987da915Sopenharmony_ci s32 size; 3343987da915Sopenharmony_ci int space; 3344987da915Sopenharmony_ci int nextspace; 3345987da915Sopenharmony_ci TRISTATE state; 3346987da915Sopenharmony_ci u16 blkheadsz; 3347987da915Sopenharmony_ci 3348987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 3349987da915Sopenharmony_ci state = T_ERR; 3350987da915Sopenharmony_ci size = le32_to_cpu(logr->client_data_length) + LOG_RECORD_HEAD_SZ; 3351987da915Sopenharmony_ci space = blocksz - k; 3352987da915Sopenharmony_ci blkheadsz = sizeof(RECORD_PAGE_HEADER) 3353987da915Sopenharmony_ci + ((2*getle16(data,6) - 1) | 7) + 1; 3354987da915Sopenharmony_ci nextspace = blocksz - blkheadsz; 3355987da915Sopenharmony_ci if ((space >= LOG_RECORD_HEAD_SZ) 3356987da915Sopenharmony_ci && (size > space) 3357987da915Sopenharmony_ci && (size < MAXRECSIZE)) { 3358987da915Sopenharmony_ci fullrec = (char*)malloc(size); 3359987da915Sopenharmony_ci memcpy(fullrec,&data[k],space); 3360987da915Sopenharmony_ci if (size <= (space + nextspace)) 3361987da915Sopenharmony_ci memcpy(&fullrec[space], nextdata + blkheadsz, 3362987da915Sopenharmony_ci size - space); 3363987da915Sopenharmony_ci else { 3364987da915Sopenharmony_ci const struct BUFFER *morebuf; 3365987da915Sopenharmony_ci const char *moredata; 3366987da915Sopenharmony_ci int total; 3367987da915Sopenharmony_ci int more; 3368987da915Sopenharmony_ci unsigned int mblk; 3369987da915Sopenharmony_ci 3370987da915Sopenharmony_ci if (optv) 3371987da915Sopenharmony_ci printf("* big record, size %d\n",size); 3372987da915Sopenharmony_ci total = space; 3373987da915Sopenharmony_ci mblk = blk + 1; 3374987da915Sopenharmony_ci while (total < size) { 3375987da915Sopenharmony_ci if (mblk >= (logfilesz >> blockbits)) 3376987da915Sopenharmony_ci mblk = (log_major < 2 ? BASEBLKS 3377987da915Sopenharmony_ci : BASEBLKS2); 3378987da915Sopenharmony_ci more = size - total; 3379987da915Sopenharmony_ci if (more > nextspace) 3380987da915Sopenharmony_ci more = nextspace; 3381987da915Sopenharmony_ci morebuf = read_buffer(ctx, mblk); 3382987da915Sopenharmony_ci if (morebuf) { 3383987da915Sopenharmony_ci moredata = morebuf->block.data; 3384987da915Sopenharmony_ci memcpy(&fullrec[total], 3385987da915Sopenharmony_ci moredata + blkheadsz, more); 3386987da915Sopenharmony_ci } 3387987da915Sopenharmony_ci total += more; 3388987da915Sopenharmony_ci mblk++; 3389987da915Sopenharmony_ci } 3390987da915Sopenharmony_ci } 3391987da915Sopenharmony_ci 3392987da915Sopenharmony_ci state = (likelyop((LOG_RECORD*)fullrec) ? T_OK : T_ERR); 3393987da915Sopenharmony_ci actionnum++; 3394987da915Sopenharmony_ci if (optv) { 3395987da915Sopenharmony_ci printf("\nOverlapping backward action %d at 0x%x" 3396987da915Sopenharmony_ci " size %d (next at 0x%x)\n", 3397987da915Sopenharmony_ci (int)actionnum,(int)k, 3398987da915Sopenharmony_ci (int)size,(int)(k + size)); 3399987da915Sopenharmony_ci printf("Overlap marked for block %ld space %d" 3400987da915Sopenharmony_ci " likely %d\n", 3401987da915Sopenharmony_ci (long)blk,(int)space,(state == T_OK)); 3402987da915Sopenharmony_ci } 3403987da915Sopenharmony_ci if (state == T_OK) { 3404987da915Sopenharmony_ci showlogr(ctx, k, (LOG_RECORD*)fullrec); 3405987da915Sopenharmony_ci if (optp || optu || opts) 3406987da915Sopenharmony_ci state = enqueue_action(ctx, 3407987da915Sopenharmony_ci (LOG_RECORD*)fullrec, 3408987da915Sopenharmony_ci size, actionnum); 3409987da915Sopenharmony_ci } else { 3410987da915Sopenharmony_ci /* Try to go on unless playing actions */ 3411987da915Sopenharmony_ci if (optb && (state == T_ERR)) 3412987da915Sopenharmony_ci state = T_OK; 3413987da915Sopenharmony_ci } 3414987da915Sopenharmony_ci free(fullrec); 3415987da915Sopenharmony_ci } else { 3416987da915Sopenharmony_ci /* Error conditions */ 3417987da915Sopenharmony_ci if ((size < MINRECSIZE) || (size > MAXRECSIZE)) { 3418987da915Sopenharmony_ci printf("** Invalid record size %ld" 3419987da915Sopenharmony_ci " in block %ld\n", 3420987da915Sopenharmony_ci (long)size,(long)blk); 3421987da915Sopenharmony_ci } else 3422987da915Sopenharmony_ci printf("** Inconsistency : the final" 3423987da915Sopenharmony_ci " record in block %ld" 3424987da915Sopenharmony_ci " does not overlap\n", 3425987da915Sopenharmony_ci (long)blk); 3426987da915Sopenharmony_ci /* Do not abort, unless playing actions */ 3427987da915Sopenharmony_ci state = (optb ? T_OK : T_ERR); 3428987da915Sopenharmony_ci } 3429987da915Sopenharmony_ci return (state); 3430987da915Sopenharmony_ci} 3431987da915Sopenharmony_ci 3432987da915Sopenharmony_cistatic TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, 3433987da915Sopenharmony_ci const struct BUFFER *buf, const struct BUFFER *prevbuf, 3434987da915Sopenharmony_ci const struct BUFFER *nextbuf) 3435987da915Sopenharmony_ci{ 3436987da915Sopenharmony_ci u16 poslist[75]; /* 4096/sizeof(LOG_RECORD) */ 3437987da915Sopenharmony_ci const RECORD_PAGE_HEADER *rph; 3438987da915Sopenharmony_ci const RECORD_PAGE_HEADER *prevrph; 3439987da915Sopenharmony_ci const LOG_RECORD *logr; 3440987da915Sopenharmony_ci const char *data; 3441987da915Sopenharmony_ci const char *nextdata; 3442987da915Sopenharmony_ci BOOL stop; 3443987da915Sopenharmony_ci TRISTATE state; 3444987da915Sopenharmony_ci s32 size; 3445987da915Sopenharmony_ci int cnt; 3446987da915Sopenharmony_ci u16 k; 3447987da915Sopenharmony_ci u16 endoff; 3448987da915Sopenharmony_ci int j; 3449987da915Sopenharmony_ci 3450987da915Sopenharmony_ci state = T_ERR; 3451987da915Sopenharmony_ci rph = &buf->block.record; 3452987da915Sopenharmony_ci prevrph = (RECORD_PAGE_HEADER*)NULL; 3453987da915Sopenharmony_ci if (prevbuf) 3454987da915Sopenharmony_ci prevrph = &prevbuf->block.record; 3455987da915Sopenharmony_ci data = buf->block.data; 3456987da915Sopenharmony_ci if (rph && (rph->magic == magic_RCRD) 3457987da915Sopenharmony_ci && (!prevrph || (prevrph->magic == magic_RCRD))) { 3458987da915Sopenharmony_ci if (optv) { 3459987da915Sopenharmony_ci if (optv >= 2) 3460987da915Sopenharmony_ci hexdump(data,blocksz); 3461987da915Sopenharmony_ci if (buf->rnum != blk) 3462987da915Sopenharmony_ci printf("* RCRD for block %ld 0x%lx" 3463987da915Sopenharmony_ci " in block %ld (addr 0x%llx)\n", 3464987da915Sopenharmony_ci (long)blk,(long)blk,(long)buf->rnum, 3465987da915Sopenharmony_ci (long long)loclogblk(ctx, blk)); 3466987da915Sopenharmony_ci else 3467987da915Sopenharmony_ci printf("* RCRD in block %ld 0x%lx (addr 0x%llx)\n", 3468987da915Sopenharmony_ci (long)blk,(long)blk, 3469987da915Sopenharmony_ci (long long)loclogblk(ctx, blk)); 3470987da915Sopenharmony_ci } else { 3471987da915Sopenharmony_ci if (optt) 3472987da915Sopenharmony_ci printf("block %ld\n",(long)blk); 3473987da915Sopenharmony_ci } 3474987da915Sopenharmony_ci showheadrcrd(blk, rph); 3475987da915Sopenharmony_ci if (!prevbuf) 3476987da915Sopenharmony_ci k = buf->headsz; 3477987da915Sopenharmony_ci else 3478987da915Sopenharmony_ci k = firstrecord(skipped, buf, prevbuf); 3479987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 3480987da915Sopenharmony_ci cnt = 0; 3481987da915Sopenharmony_ci /* check whether there is at least one beginning of record */ 3482987da915Sopenharmony_ci endoff = le16_to_cpu(rph->next_record_offset); 3483987da915Sopenharmony_ci if (k && ((k < endoff) || !endoff)) { 3484987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 3485987da915Sopenharmony_ci if (likelyop(logr)) { 3486987da915Sopenharmony_ci stop = FALSE; 3487987da915Sopenharmony_ci state = T_OK; 3488987da915Sopenharmony_ci if (optv) 3489987da915Sopenharmony_ci printf("First record checked" 3490987da915Sopenharmony_ci " at offset 0x%x\n", (int)k); 3491987da915Sopenharmony_ci } else { 3492987da915Sopenharmony_ci printf("** Bad first record at offset 0x%x\n", 3493987da915Sopenharmony_ci (int)k); 3494987da915Sopenharmony_ci if (optv) 3495987da915Sopenharmony_ci showlogr(ctx, k,logr); 3496987da915Sopenharmony_ci k = searchlikely(buf); 3497987da915Sopenharmony_ci stop = !k; 3498987da915Sopenharmony_ci if (stop) { 3499987da915Sopenharmony_ci printf("** Could not recover," 3500987da915Sopenharmony_ci " stopping at block %d\n", 3501987da915Sopenharmony_ci (int)blk); 3502987da915Sopenharmony_ci state = T_ERR; 3503987da915Sopenharmony_ci } else { 3504987da915Sopenharmony_ci /* Try to go on, unless running */ 3505987da915Sopenharmony_ci if (optb) 3506987da915Sopenharmony_ci state = T_OK; 3507987da915Sopenharmony_ci } 3508987da915Sopenharmony_ci } 3509987da915Sopenharmony_ci while (!stop) { 3510987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 3511987da915Sopenharmony_ci size = le32_to_cpu(logr->client_data_length) 3512987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 3513987da915Sopenharmony_ci if ((size < MINRECSIZE) 3514987da915Sopenharmony_ci || (size > MAXRECSIZE) 3515987da915Sopenharmony_ci || (size & 7)) { 3516987da915Sopenharmony_ci printf("** Bad size %ld in block %ld" 3517987da915Sopenharmony_ci " offset 0x%x, stopping\n", 3518987da915Sopenharmony_ci (long)size,(long)blk,(int)k); 3519987da915Sopenharmony_ci stop = TRUE; 3520987da915Sopenharmony_ci } else { 3521987da915Sopenharmony_ci if (((u32)(k + size) <= blocksz) 3522987da915Sopenharmony_ci && ((u32)(k + size) <= endoff)) { 3523987da915Sopenharmony_ci poslist[cnt++] = k; 3524987da915Sopenharmony_ci if (!logr->client_data_length) 3525987da915Sopenharmony_ci stop = TRUE; 3526987da915Sopenharmony_ci k += size; 3527987da915Sopenharmony_ci if ((u32)(k 3528987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ) 3529987da915Sopenharmony_ci > blocksz) 3530987da915Sopenharmony_ci stop = TRUE; 3531987da915Sopenharmony_ci } else { 3532987da915Sopenharmony_ci stop = TRUE; 3533987da915Sopenharmony_ci } 3534987da915Sopenharmony_ci } 3535987da915Sopenharmony_ci } 3536987da915Sopenharmony_ci } else { 3537987da915Sopenharmony_ci stop = TRUE; 3538987da915Sopenharmony_ci state = (k ? T_OK : T_ERR); 3539987da915Sopenharmony_ci } 3540987da915Sopenharmony_ci /* Now examine an overlapping record */ 3541987da915Sopenharmony_ci if (k 3542987da915Sopenharmony_ci && ((k == endoff) || !endoff) 3543987da915Sopenharmony_ci && ((u32)(k + LOG_RECORD_HEAD_SZ) <= blocksz)) { 3544987da915Sopenharmony_ci if (nextbuf && (blk >= BASEBLKS)) { 3545987da915Sopenharmony_ci nextdata = nextbuf->block.data; 3546987da915Sopenharmony_ci state = backoverlap(ctx, blk, 3547987da915Sopenharmony_ci data, nextdata, k); 3548987da915Sopenharmony_ci } 3549987da915Sopenharmony_ci } 3550987da915Sopenharmony_ci for (j=cnt-1; (j>=0) && (state==T_OK); j--) { 3551987da915Sopenharmony_ci k = poslist[j]; 3552987da915Sopenharmony_ci logr = (const LOG_RECORD*)&data[k]; 3553987da915Sopenharmony_ci size = le32_to_cpu(logr->client_data_length) 3554987da915Sopenharmony_ci + LOG_RECORD_HEAD_SZ; 3555987da915Sopenharmony_ci actionnum++; 3556987da915Sopenharmony_ci if (optv && (!optc || within_lcn_range(logr))) { 3557987da915Sopenharmony_ci printf("\n* log backward action %u at 0x%x" 3558987da915Sopenharmony_ci " size %d (next at 0x%x)\n", 3559987da915Sopenharmony_ci actionnum, k, size, k + size); 3560987da915Sopenharmony_ci } 3561987da915Sopenharmony_ci if ((optv | optt) 3562987da915Sopenharmony_ci && (!nextbuf && (j == (cnt - 1)))) { 3563987da915Sopenharmony_ci printf("* This is the latest record\n"); 3564987da915Sopenharmony_ci if (logr->this_lsn == restart.current_lsn) 3565987da915Sopenharmony_ci printf(" its lsn matches the global" 3566987da915Sopenharmony_ci " restart lsn\n"); 3567987da915Sopenharmony_ci if (logr->this_lsn == client.client_restart_lsn) 3568987da915Sopenharmony_ci printf(" its lsn matches the client" 3569987da915Sopenharmony_ci " restart lsn\n"); 3570987da915Sopenharmony_ci if (logr->client_data_length 3571987da915Sopenharmony_ci == restart.last_lsn_data_length) 3572987da915Sopenharmony_ci printf(" its length matches the" 3573987da915Sopenharmony_ci " last record length\n"); 3574987da915Sopenharmony_ci } 3575987da915Sopenharmony_ci showlogr(ctx, k, logr); 3576987da915Sopenharmony_ci if (optp || optu || opts) 3577987da915Sopenharmony_ci state = enqueue_action(ctx, logr, size, actionnum); 3578987da915Sopenharmony_ci } 3579987da915Sopenharmony_ci } 3580987da915Sopenharmony_ci return (state); 3581987da915Sopenharmony_ci} 3582987da915Sopenharmony_ci 3583987da915Sopenharmony_cistatic int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk, 3584987da915Sopenharmony_ci const struct BUFFER *prevbuf, u32 prevblk) 3585987da915Sopenharmony_ci{ 3586987da915Sopenharmony_ci const struct BUFFER *nextbuf; 3587987da915Sopenharmony_ci NTFS_RECORD_TYPES magic; 3588987da915Sopenharmony_ci u32 stopblk; 3589987da915Sopenharmony_ci TRISTATE state; 3590987da915Sopenharmony_ci 3591987da915Sopenharmony_ci if (optv) { 3592987da915Sopenharmony_ci if ((log_major >= 2) && (buf->rnum != blk)) 3593987da915Sopenharmony_ci printf("\n* block %d for block %d at 0x%llx\n", 3594987da915Sopenharmony_ci (int)buf->rnum,(int)blk, 3595987da915Sopenharmony_ci (long long)loclogblk(ctx, buf->rnum)); 3596987da915Sopenharmony_ci else 3597987da915Sopenharmony_ci printf("\n* block %d at 0x%llx\n",(int)blk, 3598987da915Sopenharmony_ci (long long)loclogblk(ctx, blk)); 3599987da915Sopenharmony_ci } 3600987da915Sopenharmony_ci ctx->firstaction = (struct ACTION_RECORD*)NULL; 3601987da915Sopenharmony_ci ctx->lastaction = (struct ACTION_RECORD*)NULL; 3602987da915Sopenharmony_ci nextbuf = (const struct BUFFER*)NULL; 3603987da915Sopenharmony_ci stopblk = prevblk + 2; // wraparound ! 3604987da915Sopenharmony_ci state = backward_rcrd(ctx, blk, 0, buf, 3605987da915Sopenharmony_ci prevbuf, (struct BUFFER*)NULL); 3606987da915Sopenharmony_ci while ((state == T_OK) 3607987da915Sopenharmony_ci && !((blk > stopblk) && (prevblk <= stopblk)) 3608987da915Sopenharmony_ci && (!(optp || optu) || (playedactions < playcount))) { 3609987da915Sopenharmony_ci int skipped; 3610987da915Sopenharmony_ci 3611987da915Sopenharmony_ci nextbuf = buf; 3612987da915Sopenharmony_ci buf = prevbuf; 3613987da915Sopenharmony_ci blk = prevblk; 3614987da915Sopenharmony_ci skipped = 0; 3615987da915Sopenharmony_ci prevbuf = findprevious(ctx, buf); 3616987da915Sopenharmony_ci if (prevbuf) { 3617987da915Sopenharmony_ci prevblk = prevbuf->num; 3618987da915Sopenharmony_ci if (prevblk < blk) 3619987da915Sopenharmony_ci skipped = blk - prevblk - 1; 3620987da915Sopenharmony_ci else 3621987da915Sopenharmony_ci skipped = blk - prevblk - 1 3622987da915Sopenharmony_ci + (logfilesz >> blockbits) 3623987da915Sopenharmony_ci - (log_major < 2 ? BASEBLKS 3624987da915Sopenharmony_ci : BASEBLKS2); 3625987da915Sopenharmony_ci magic = prevbuf->block.record.magic; 3626987da915Sopenharmony_ci switch (magic) { 3627987da915Sopenharmony_ci case magic_RCRD : 3628987da915Sopenharmony_ci break; 3629987da915Sopenharmony_ci case magic_CHKD : 3630987da915Sopenharmony_ci printf("** Unexpected block type CHKD\n"); 3631987da915Sopenharmony_ci break; 3632987da915Sopenharmony_ci case magic_RSTR : 3633987da915Sopenharmony_ci printf("** Unexpected block type RSTR\n"); 3634987da915Sopenharmony_ci break; 3635987da915Sopenharmony_ci default : 3636987da915Sopenharmony_ci printf("** Invalid block %d\n",(int)prevblk); 3637987da915Sopenharmony_ci break; 3638987da915Sopenharmony_ci } 3639987da915Sopenharmony_ci if (optv) { 3640987da915Sopenharmony_ci if (skipped) 3641987da915Sopenharmony_ci printf("\n* block %ld at 0x%llx (block" 3642987da915Sopenharmony_ci " %ld used as previous one)\n", 3643987da915Sopenharmony_ci (long)blk, 3644987da915Sopenharmony_ci (long long)loclogblk(ctx, blk), 3645987da915Sopenharmony_ci (long)prevblk); 3646987da915Sopenharmony_ci else 3647987da915Sopenharmony_ci if ((log_major >= 2) 3648987da915Sopenharmony_ci && (buf->rnum != blk)) 3649987da915Sopenharmony_ci printf("\n* block %ld for block %ld at 0x%llx\n", 3650987da915Sopenharmony_ci (long)buf->rnum, 3651987da915Sopenharmony_ci (long)blk, 3652987da915Sopenharmony_ci (long long)loclogblk( 3653987da915Sopenharmony_ci ctx,buf->rnum)); 3654987da915Sopenharmony_ci else 3655987da915Sopenharmony_ci printf("\n* block %ld at 0x%llx\n", 3656987da915Sopenharmony_ci (long)blk, 3657987da915Sopenharmony_ci (long long)loclogblk( 3658987da915Sopenharmony_ci ctx, blk)); 3659987da915Sopenharmony_ci } 3660987da915Sopenharmony_ci state = backward_rcrd(ctx, blk, skipped, 3661987da915Sopenharmony_ci buf, prevbuf, nextbuf); 3662987da915Sopenharmony_ci } else { 3663987da915Sopenharmony_ci fprintf(stderr,"** Could not read block %lu\n", 3664987da915Sopenharmony_ci (long)prevblk); 3665987da915Sopenharmony_ci state = T_ERR; 3666987da915Sopenharmony_ci } 3667987da915Sopenharmony_ci } 3668987da915Sopenharmony_ci if ((blk > stopblk) && (prevblk <= stopblk)) 3669987da915Sopenharmony_ci printf("* Earliest block reached\n"); 3670987da915Sopenharmony_ci if ((optp || optu) && (playedactions >= playcount)) 3671987da915Sopenharmony_ci printf("* Transaction set count reached\n"); 3672987da915Sopenharmony_ci if (opts) 3673987da915Sopenharmony_ci printf("* %s %s after playing %u actions\n", 3674987da915Sopenharmony_ci (optn ? "Sync simulation" : "Syncing"), 3675987da915Sopenharmony_ci (state == T_ERR ? "failed" : "successful"), 3676987da915Sopenharmony_ci redocount); 3677987da915Sopenharmony_ci /* free queue */ 3678987da915Sopenharmony_ci while (ctx->firstaction) { 3679987da915Sopenharmony_ci struct ACTION_RECORD *action; 3680987da915Sopenharmony_ci 3681987da915Sopenharmony_ci action = ctx->firstaction->next; 3682987da915Sopenharmony_ci free(ctx->firstaction); 3683987da915Sopenharmony_ci ctx->firstaction = action; 3684987da915Sopenharmony_ci } 3685987da915Sopenharmony_ci ctx->lastaction = (struct ACTION_RECORD*)NULL; 3686987da915Sopenharmony_ci return (state == T_ERR ? 1 : 0); 3687987da915Sopenharmony_ci} 3688987da915Sopenharmony_ci 3689987da915Sopenharmony_ci/* 3690987da915Sopenharmony_ci * Find the latest log block 3691987da915Sopenharmony_ci * 3692987da915Sopenharmony_ci * Usually, the latest block is either block 2 or 3 which act as 3693987da915Sopenharmony_ci * temporary block before being copied to target location. 3694987da915Sopenharmony_ci * However under some unknown condition the block are written 3695987da915Sopenharmony_ci * immediately to target location, and we have to scan for the 3696987da915Sopenharmony_ci * latest one. 3697987da915Sopenharmony_ci * Currently this is not checked for logfile version 2.x which 3698987da915Sopenharmony_ci * use a different layout of temporary blocks. 3699987da915Sopenharmony_ci */ 3700987da915Sopenharmony_ci 3701987da915Sopenharmony_cistatic const struct BUFFER *find_latest_block(CONTEXT *ctx, u32 baseblk, 3702987da915Sopenharmony_ci const struct BUFFER *basebuf) 3703987da915Sopenharmony_ci{ 3704987da915Sopenharmony_ci le64 offset; 3705987da915Sopenharmony_ci leLSN prevlsn; 3706987da915Sopenharmony_ci leLSN curlsn; 3707987da915Sopenharmony_ci u32 curblk; 3708987da915Sopenharmony_ci u32 prevblk; 3709987da915Sopenharmony_ci const struct BUFFER *prevbuf; 3710987da915Sopenharmony_ci const struct BUFFER *curbuf; 3711987da915Sopenharmony_ci 3712987da915Sopenharmony_ci offset = basebuf->block.record.copy.file_offset; 3713987da915Sopenharmony_ci curbuf = (const struct BUFFER*)NULL; 3714987da915Sopenharmony_ci curlsn = const_cpu_to_le64(0); 3715987da915Sopenharmony_ci prevblk = 0; 3716987da915Sopenharmony_ci curblk = baseblk; 3717987da915Sopenharmony_ci do { 3718987da915Sopenharmony_ci if (curblk < BASEBLKS) { 3719987da915Sopenharmony_ci prevbuf = basebuf; 3720987da915Sopenharmony_ci prevlsn = basebuf->block.record.last_end_lsn; 3721987da915Sopenharmony_ci prevblk = baseblk; 3722987da915Sopenharmony_ci curblk = le64_to_cpu(offset) >> blockbits; 3723987da915Sopenharmony_ci } else { 3724987da915Sopenharmony_ci if (optv) 3725987da915Sopenharmony_ci printf("block %d is more recent than block %d\n", 3726987da915Sopenharmony_ci (int)curblk, (int)prevblk); 3727987da915Sopenharmony_ci prevbuf = curbuf; 3728987da915Sopenharmony_ci prevlsn = curlsn; 3729987da915Sopenharmony_ci prevblk = curblk; 3730987da915Sopenharmony_ci curblk++; 3731987da915Sopenharmony_ci if (curblk >= (logfilesz >> blockbits)) 3732987da915Sopenharmony_ci curblk = (log_major < 2 ? BASEBLKS : BASEBLKS2); 3733987da915Sopenharmony_ci } 3734987da915Sopenharmony_ci curbuf = read_buffer(ctx, curblk); 3735987da915Sopenharmony_ci if (curbuf && (curbuf->block.record.magic == magic_RCRD)) { 3736987da915Sopenharmony_ci curlsn = curbuf->block.record.copy.last_lsn; 3737987da915Sopenharmony_ci } 3738987da915Sopenharmony_ci } while (curbuf 3739987da915Sopenharmony_ci && (curbuf->block.record.magic == magic_RCRD) 3740987da915Sopenharmony_ci && (le64_to_cpu(curlsn) > le64_to_cpu(prevlsn))); 3741987da915Sopenharmony_ci if (optv) 3742987da915Sopenharmony_ci printf("Block %d is the latest one\n",(int)prevblk); 3743987da915Sopenharmony_ci return (prevbuf); 3744987da915Sopenharmony_ci} 3745987da915Sopenharmony_ci 3746987da915Sopenharmony_ci/* 3747987da915Sopenharmony_ci * Determine the sequencing of blocks (when version >= 2.0) 3748987da915Sopenharmony_ci * 3749987da915Sopenharmony_ci * Blocks 2..17 and 18..33 are temporary blocks being filled until 3750987da915Sopenharmony_ci * they are copied to their target locations, so there are three 3751987da915Sopenharmony_ci * possible location for recent blocks. 3752987da915Sopenharmony_ci * 3753987da915Sopenharmony_ci * Returns the latest target block number 3754987da915Sopenharmony_ci */ 3755987da915Sopenharmony_ci 3756987da915Sopenharmony_cistatic int block_sequence(CONTEXT *ctx) 3757987da915Sopenharmony_ci{ 3758987da915Sopenharmony_ci const struct BUFFER *buf; 3759987da915Sopenharmony_ci int blk; 3760987da915Sopenharmony_ci int k; 3761987da915Sopenharmony_ci int target_blk; 3762987da915Sopenharmony_ci int latest_blk; 3763987da915Sopenharmony_ci s64 final_lsn; 3764987da915Sopenharmony_ci s64 last_lsn; 3765987da915Sopenharmony_ci s64 last_lsn12; 3766987da915Sopenharmony_ci s64 last_lsn1, last_lsn2; 3767987da915Sopenharmony_ci 3768987da915Sopenharmony_ci final_lsn = 0; 3769987da915Sopenharmony_ci for (blk=RSTBLKS; 2*blk<(RSTBLKS+BASEBLKS2); blk++) { 3770987da915Sopenharmony_ci /* First temporary block */ 3771987da915Sopenharmony_ci last_lsn1 = 0; 3772987da915Sopenharmony_ci buf = read_buffer(ctx, blk); 3773987da915Sopenharmony_ci if (buf && (buf->block.record.magic == magic_RCRD)) { 3774987da915Sopenharmony_ci last_lsn1 = le64_to_cpu( 3775987da915Sopenharmony_ci buf->block.record.copy.last_lsn); 3776987da915Sopenharmony_ci if (!final_lsn 3777987da915Sopenharmony_ci || ((s64)(last_lsn1 - final_lsn) > 0)) 3778987da915Sopenharmony_ci final_lsn = last_lsn1; 3779987da915Sopenharmony_ci } 3780987da915Sopenharmony_ci /* Second temporary block */ 3781987da915Sopenharmony_ci buf = read_buffer(ctx, blk + (BASEBLKS2 - RSTBLKS)/2); 3782987da915Sopenharmony_ci last_lsn2 = 0; 3783987da915Sopenharmony_ci if (buf && (buf->block.record.magic == magic_RCRD)) { 3784987da915Sopenharmony_ci last_lsn2 = le64_to_cpu( 3785987da915Sopenharmony_ci buf->block.record.copy.last_lsn); 3786987da915Sopenharmony_ci if (!final_lsn 3787987da915Sopenharmony_ci || ((s64)(last_lsn2 - final_lsn) > 0)) 3788987da915Sopenharmony_ci final_lsn = last_lsn2; 3789987da915Sopenharmony_ci } 3790987da915Sopenharmony_ci /* the latest last_lsn defines the target block */ 3791987da915Sopenharmony_ci last_lsn12 = 0; 3792987da915Sopenharmony_ci latest_blk = 0; 3793987da915Sopenharmony_ci if (last_lsn1 || last_lsn2) { 3794987da915Sopenharmony_ci if (!last_lsn2 3795987da915Sopenharmony_ci || ((s64)(last_lsn1 - last_lsn2) > 0)) { 3796987da915Sopenharmony_ci last_lsn12 = last_lsn1; 3797987da915Sopenharmony_ci latest_blk = blk; 3798987da915Sopenharmony_ci } 3799987da915Sopenharmony_ci if (!last_lsn1 3800987da915Sopenharmony_ci || ((s64)(last_lsn1 - last_lsn2) <= 0)) { 3801987da915Sopenharmony_ci last_lsn12 = last_lsn2; 3802987da915Sopenharmony_ci latest_blk = blk + (BASEBLKS2 - RSTBLKS)/2; 3803987da915Sopenharmony_ci } 3804987da915Sopenharmony_ci } 3805987da915Sopenharmony_ci last_lsn = 0; 3806987da915Sopenharmony_ci target_blk = 0; 3807987da915Sopenharmony_ci if (last_lsn12) { 3808987da915Sopenharmony_ci target_blk = (last_lsn12 & offset_mask) 3809987da915Sopenharmony_ci >> (blockbits - 3); 3810987da915Sopenharmony_ci buf = read_buffer(ctx, target_blk); 3811987da915Sopenharmony_ci if (buf && (buf->block.record.magic == magic_RCRD)) { 3812987da915Sopenharmony_ci last_lsn = le64_to_cpu( 3813987da915Sopenharmony_ci buf->block.record.copy.last_lsn); 3814987da915Sopenharmony_ci if (!final_lsn 3815987da915Sopenharmony_ci || ((s64)(last_lsn - final_lsn) > 0)) 3816987da915Sopenharmony_ci final_lsn = last_lsn; 3817987da915Sopenharmony_ci } 3818987da915Sopenharmony_ci } 3819987da915Sopenharmony_ci /* redirect to the latest block */ 3820987da915Sopenharmony_ci if (latest_blk 3821987da915Sopenharmony_ci && (!last_lsn || ((s64)(last_lsn - last_lsn12) < 0))) 3822987da915Sopenharmony_ci redirect[latest_blk] = target_blk; 3823987da915Sopenharmony_ci } 3824987da915Sopenharmony_ci if (optv) { 3825987da915Sopenharmony_ci printf("\n Blocks redirected :\n"); 3826987da915Sopenharmony_ci for (k=RSTBLKS; k<BASEBLKS2; k++) 3827987da915Sopenharmony_ci if (redirect[k]) 3828987da915Sopenharmony_ci printf("* block %d to block %d\n", 3829987da915Sopenharmony_ci (int)redirect[k],(int)k); 3830987da915Sopenharmony_ci } 3831987da915Sopenharmony_ci latest_lsn = final_lsn; 3832987da915Sopenharmony_ci blk = (final_lsn & offset_mask) >> (blockbits - 3); 3833987da915Sopenharmony_ci if (optv > 1) 3834987da915Sopenharmony_ci printf("final lsn %llx in blk %d\n",(long long)final_lsn,blk); 3835987da915Sopenharmony_ci return (blk); 3836987da915Sopenharmony_ci} 3837987da915Sopenharmony_ci 3838987da915Sopenharmony_cistatic int walk(CONTEXT *ctx) 3839987da915Sopenharmony_ci{ 3840987da915Sopenharmony_ci const struct BUFFER *buf; 3841987da915Sopenharmony_ci const struct BUFFER *nextbuf; 3842987da915Sopenharmony_ci const struct BUFFER *prevbuf; 3843987da915Sopenharmony_ci const struct BUFFER *startbuf; 3844987da915Sopenharmony_ci const NTFS_RECORD *record; 3845987da915Sopenharmony_ci const RECORD_PAGE_HEADER *rph; 3846987da915Sopenharmony_ci NTFS_RECORD_TYPES magic; 3847987da915Sopenharmony_ci u32 blk; 3848987da915Sopenharmony_ci u32 nextblk; 3849987da915Sopenharmony_ci u32 prevblk; 3850987da915Sopenharmony_ci u32 finalblk; 3851987da915Sopenharmony_ci int err; 3852987da915Sopenharmony_ci u16 blkheadsz; 3853987da915Sopenharmony_ci u16 pos; 3854987da915Sopenharmony_ci BOOL dirty; 3855987da915Sopenharmony_ci BOOL done; 3856987da915Sopenharmony_ci 3857987da915Sopenharmony_ci buf = (struct BUFFER*)NULL; 3858987da915Sopenharmony_ci nextbuf = (struct BUFFER*)NULL; 3859987da915Sopenharmony_ci if (optb || optp || optu || opts) { 3860987da915Sopenharmony_ci prevbuf = (struct BUFFER*)NULL; 3861987da915Sopenharmony_ci } 3862987da915Sopenharmony_ci done = FALSE; 3863987da915Sopenharmony_ci dirty = TRUE; 3864987da915Sopenharmony_ci finalblk = 0; 3865987da915Sopenharmony_ci err = 0; 3866987da915Sopenharmony_ci blk = 0; 3867987da915Sopenharmony_ci pos = 0; 3868987da915Sopenharmony_ci /* read and process the first restart block */ 3869987da915Sopenharmony_ci buf = read_restart(ctx); 3870987da915Sopenharmony_ci if (buf) { 3871987da915Sopenharmony_ci if (optv) 3872987da915Sopenharmony_ci printf("\n* block %d at 0x%llx\n",(int)blk, 3873987da915Sopenharmony_ci (long long)loclogblk(ctx, blk)); 3874987da915Sopenharmony_ci } else { 3875987da915Sopenharmony_ci done = TRUE; 3876987da915Sopenharmony_ci err = 1; 3877987da915Sopenharmony_ci } 3878987da915Sopenharmony_ci 3879987da915Sopenharmony_ci nextblk = blk + 1; 3880987da915Sopenharmony_ci while (!done) { 3881987da915Sopenharmony_ci /* next block is needed to process the current one */ 3882987da915Sopenharmony_ci if ((nextblk >= (logfilesz >> blockbits)) && (optr || optf)) 3883987da915Sopenharmony_ci nextbuf = read_buffer(ctx, 3884987da915Sopenharmony_ci (log_major < 2 ? BASEBLKS : BASEBLKS2)); 3885987da915Sopenharmony_ci else 3886987da915Sopenharmony_ci nextbuf = read_buffer(ctx,nextblk); 3887987da915Sopenharmony_ci if (nextbuf) { 3888987da915Sopenharmony_ci record = (const NTFS_RECORD*)&nextbuf->block.data; 3889987da915Sopenharmony_ci blkheadsz = nextbuf->headsz; 3890987da915Sopenharmony_ci magic = record->magic; 3891987da915Sopenharmony_ci switch (magic) { 3892987da915Sopenharmony_ci case magic_CHKD : 3893987da915Sopenharmony_ci case magic_RSTR : 3894987da915Sopenharmony_ci case magic_RCRD : 3895987da915Sopenharmony_ci break; 3896987da915Sopenharmony_ci default : 3897987da915Sopenharmony_ci printf("** Invalid block\n"); 3898987da915Sopenharmony_ci err = 1; 3899987da915Sopenharmony_ci break; 3900987da915Sopenharmony_ci } 3901987da915Sopenharmony_ci magic = buf->block.record.magic; 3902987da915Sopenharmony_ci switch (magic) { 3903987da915Sopenharmony_ci case magic_CHKD : 3904987da915Sopenharmony_ci case magic_RSTR : 3905987da915Sopenharmony_ci dirty = dorest(ctx, blk, &buf->block.restart, 3906987da915Sopenharmony_ci FALSE); 3907987da915Sopenharmony_ci break; 3908987da915Sopenharmony_ci case magic_RCRD : 3909987da915Sopenharmony_ci if (blk < BASEBLKS) 3910987da915Sopenharmony_ci pos = buf->headsz; 3911987da915Sopenharmony_ci pos = dorcrd(ctx, blk, pos, buf, nextbuf); 3912987da915Sopenharmony_ci while (pos >= blocksz) { 3913987da915Sopenharmony_ci if (optv > 1) 3914987da915Sopenharmony_ci printf("Skipping block %d" 3915987da915Sopenharmony_ci " pos 0x%x\n", 3916987da915Sopenharmony_ci (int)nextblk,(int)pos); 3917987da915Sopenharmony_ci pos -= (blocksz - blkheadsz); 3918987da915Sopenharmony_ci nextblk++; 3919987da915Sopenharmony_ci } 3920987da915Sopenharmony_ci if ((blocksz - pos) < LOG_RECORD_HEAD_SZ) { 3921987da915Sopenharmony_ci pos = 0; 3922987da915Sopenharmony_ci nextblk++; 3923987da915Sopenharmony_ci } 3924987da915Sopenharmony_ci if (nextblk != (blk + 1)) { 3925987da915Sopenharmony_ci nextbuf = read_buffer(ctx,nextblk); 3926987da915Sopenharmony_ci } 3927987da915Sopenharmony_ci break; 3928987da915Sopenharmony_ci default : 3929987da915Sopenharmony_ci if (!~magic) { 3930987da915Sopenharmony_ci if (optv) 3931987da915Sopenharmony_ci printf(" empty block\n"); 3932987da915Sopenharmony_ci } 3933987da915Sopenharmony_ci break; 3934987da915Sopenharmony_ci } 3935987da915Sopenharmony_ci } else { 3936987da915Sopenharmony_ci fprintf(stderr,"* Could not read block %d\n",nextblk); 3937987da915Sopenharmony_ci if (ctx->vol) { 3938987da915Sopenharmony_ci /* In full mode, ignore errors on restart blocks */ 3939987da915Sopenharmony_ci if (blk >= RSTBLKS) { 3940987da915Sopenharmony_ci done = TRUE; 3941987da915Sopenharmony_ci err = 1; 3942987da915Sopenharmony_ci } 3943987da915Sopenharmony_ci } else { 3944987da915Sopenharmony_ci done = TRUE; 3945987da915Sopenharmony_ci err = 1; 3946987da915Sopenharmony_ci } 3947987da915Sopenharmony_ci } 3948987da915Sopenharmony_ci blk = nextblk; 3949987da915Sopenharmony_ci nextblk++; 3950987da915Sopenharmony_ci 3951987da915Sopenharmony_ci if (!optr && (log_major >= 2) && (nextblk == RSTBLKS)) { 3952987da915Sopenharmony_ci finalblk = block_sequence(ctx); 3953987da915Sopenharmony_ci if (!finalblk) { 3954987da915Sopenharmony_ci done = TRUE; 3955987da915Sopenharmony_ci err = 1; 3956987da915Sopenharmony_ci } 3957987da915Sopenharmony_ci } 3958987da915Sopenharmony_ci 3959987da915Sopenharmony_ci if (optr) { /* Only selected range */ 3960987da915Sopenharmony_ci u32 endblk; 3961987da915Sopenharmony_ci 3962987da915Sopenharmony_ci endblk = (log_major < 2 ? BASEBLKS : RSTBLKS); 3963987da915Sopenharmony_ci if ((nextblk == endblk) && (nextblk < firstblk)) 3964987da915Sopenharmony_ci nextblk = firstblk; 3965987da915Sopenharmony_ci if ((blk >= endblk) && (blk > lastblk)) 3966987da915Sopenharmony_ci done = TRUE; 3967987da915Sopenharmony_ci } else 3968987da915Sopenharmony_ci if (optf) { /* Full log, forward */ 3969987da915Sopenharmony_ci if (blk*blocksz >= logfilesz) 3970987da915Sopenharmony_ci done = TRUE; 3971987da915Sopenharmony_ci } else 3972987da915Sopenharmony_ci if (optb || optp || optu || opts 3973987da915Sopenharmony_ci || (log_major >= 2)) { 3974987da915Sopenharmony_ci /* Restart blocks only (2 blocks) */ 3975987da915Sopenharmony_ci if (blk >= RSTBLKS) 3976987da915Sopenharmony_ci done = TRUE; 3977987da915Sopenharmony_ci } else { /* Base blocks only (4 blocks) */ 3978987da915Sopenharmony_ci if (blk >= BASEBLKS) 3979987da915Sopenharmony_ci done = TRUE; 3980987da915Sopenharmony_ci } 3981987da915Sopenharmony_ci if (!done) { 3982987da915Sopenharmony_ci buf = nextbuf; 3983987da915Sopenharmony_ci if (blk >= RSTBLKS && blk < BASEBLKS) { 3984987da915Sopenharmony_ci /* The latest buf may be more recent 3985987da915Sopenharmony_ci than restart */ 3986987da915Sopenharmony_ci rph = &buf->block.record; 3987987da915Sopenharmony_ci if ((s64)(sle64_to_cpu(rph->last_end_lsn) 3988987da915Sopenharmony_ci - committed_lsn) > 0) { 3989987da915Sopenharmony_ci committed_lsn = 3990987da915Sopenharmony_ci sle64_to_cpu(rph->last_end_lsn); 3991987da915Sopenharmony_ci if (optv) 3992987da915Sopenharmony_ci printf("* Restart page was " 3993987da915Sopenharmony_ci "obsolete, updated " 3994987da915Sopenharmony_ci "committed lsn\n"); 3995987da915Sopenharmony_ci } 3996987da915Sopenharmony_ci } 3997987da915Sopenharmony_ci if (optv) 3998987da915Sopenharmony_ci printf("\n* block %d at 0x%llx\n",(int)blk, 3999987da915Sopenharmony_ci (long long)loclogblk(ctx, blk)); 4000987da915Sopenharmony_ci } 4001987da915Sopenharmony_ci } 4002987da915Sopenharmony_ci if (optv && opts && !dirty) 4003987da915Sopenharmony_ci printf("* Volume is clean, nothing to do\n"); 4004987da915Sopenharmony_ci if (log_major >= 2) 4005987da915Sopenharmony_ci blk = finalblk; 4006987da915Sopenharmony_ci if (!err 4007987da915Sopenharmony_ci && (optb || optp || optu || (opts && dirty))) { 4008987da915Sopenharmony_ci playedactions = 0; 4009987da915Sopenharmony_ci ctx->firstaction = (struct ACTION_RECORD*)NULL; 4010987da915Sopenharmony_ci ctx->lastaction = (struct ACTION_RECORD*)NULL; 4011987da915Sopenharmony_ci if (log_major < 2) { 4012987da915Sopenharmony_ci buf = nextbuf; 4013987da915Sopenharmony_ci nextbuf = read_buffer(ctx, blk+1); 4014987da915Sopenharmony_ci startbuf = best_start(buf,nextbuf); 4015987da915Sopenharmony_ci if (startbuf && (startbuf == nextbuf)) { 4016987da915Sopenharmony_ci /* nextbuf is better, show blk */ 4017987da915Sopenharmony_ci if (optv && buf) { 4018987da915Sopenharmony_ci printf("* Ignored block %d at 0x%llx\n", 4019987da915Sopenharmony_ci (int)blk, 4020987da915Sopenharmony_ci (long long)loclogblk(ctx, blk)); 4021987da915Sopenharmony_ci if (optv >= 2) 4022987da915Sopenharmony_ci hexdump(buf->block.data, 4023987da915Sopenharmony_ci blocksz); 4024987da915Sopenharmony_ci showheadrcrd(blk, &buf->block.record); 4025987da915Sopenharmony_ci } 4026987da915Sopenharmony_ci blk++; 4027987da915Sopenharmony_ci buf = nextbuf; 4028987da915Sopenharmony_ci } else { 4029987da915Sopenharmony_ci /* buf is better, show blk + 1 */ 4030987da915Sopenharmony_ci if (optv && nextbuf) { 4031987da915Sopenharmony_ci printf("* Ignored block %d at 0x%llx\n", 4032987da915Sopenharmony_ci (int)(blk + 1), 4033987da915Sopenharmony_ci (long long)loclogblk(ctx, 4034987da915Sopenharmony_ci blk + 1)); 4035987da915Sopenharmony_ci if (optv >= 2) 4036987da915Sopenharmony_ci hexdump(nextbuf->block.data, 4037987da915Sopenharmony_ci blocksz); 4038987da915Sopenharmony_ci showheadrcrd(blk + 1, 4039987da915Sopenharmony_ci &nextbuf->block.record); 4040987da915Sopenharmony_ci } 4041987da915Sopenharmony_ci } 4042987da915Sopenharmony_ci if (startbuf && opts) { 4043987da915Sopenharmony_ci buf = startbuf = find_latest_block(ctx, 4044987da915Sopenharmony_ci blk, startbuf); 4045987da915Sopenharmony_ci latest_lsn = le64_to_cpu( 4046987da915Sopenharmony_ci buf->block.record.last_end_lsn); 4047987da915Sopenharmony_ci } 4048987da915Sopenharmony_ci } else { 4049987da915Sopenharmony_ci buf = startbuf = read_buffer(ctx, blk); 4050987da915Sopenharmony_ci nextbuf = (const struct BUFFER*)NULL; 4051987da915Sopenharmony_ci } 4052987da915Sopenharmony_ci if (startbuf) { 4053987da915Sopenharmony_ci /* The latest buf may be more recent than restart */ 4054987da915Sopenharmony_ci rph = &buf->block.record; 4055987da915Sopenharmony_ci if ((s64)(sle64_to_cpu(rph->last_end_lsn) 4056987da915Sopenharmony_ci - committed_lsn) > 0) { 4057987da915Sopenharmony_ci committed_lsn = sle64_to_cpu(rph->last_end_lsn); 4058987da915Sopenharmony_ci if (optv) 4059987da915Sopenharmony_ci printf("* Restart page was obsolete\n"); 4060987da915Sopenharmony_ci } 4061987da915Sopenharmony_ci nextbuf = (const struct BUFFER*)NULL; 4062987da915Sopenharmony_ci prevbuf = findprevious(ctx, buf); 4063987da915Sopenharmony_ci if (prevbuf) { 4064987da915Sopenharmony_ci prevblk = prevbuf->num; 4065987da915Sopenharmony_ci magic = prevbuf->block.record.magic; 4066987da915Sopenharmony_ci switch (magic) { 4067987da915Sopenharmony_ci case magic_RCRD : 4068987da915Sopenharmony_ci break; 4069987da915Sopenharmony_ci case magic_CHKD : 4070987da915Sopenharmony_ci printf("** Unexpected block type CHKD\n"); 4071987da915Sopenharmony_ci err = 1; 4072987da915Sopenharmony_ci break; 4073987da915Sopenharmony_ci case magic_RSTR : 4074987da915Sopenharmony_ci err = 1; 4075987da915Sopenharmony_ci printf("** Unexpected block type RSTR\n"); 4076987da915Sopenharmony_ci break; 4077987da915Sopenharmony_ci default : 4078987da915Sopenharmony_ci err = 1; 4079987da915Sopenharmony_ci printf("** Invalid block\n"); 4080987da915Sopenharmony_ci break; 4081987da915Sopenharmony_ci } 4082987da915Sopenharmony_ci } else 4083987da915Sopenharmony_ci prevblk = BASEBLKS; 4084987da915Sopenharmony_ci if (!err) 4085987da915Sopenharmony_ci err = walkback(ctx, buf, blk, 4086987da915Sopenharmony_ci prevbuf, prevblk); 4087987da915Sopenharmony_ci } else { 4088987da915Sopenharmony_ci fprintf(stderr,"** No valid start block, aborting\n"); 4089987da915Sopenharmony_ci err = 1; 4090987da915Sopenharmony_ci } 4091987da915Sopenharmony_ci } 4092987da915Sopenharmony_ci return (err); 4093987da915Sopenharmony_ci} 4094987da915Sopenharmony_ci 4095987da915Sopenharmony_ciBOOL exception(int num) 4096987da915Sopenharmony_ci{ 4097987da915Sopenharmony_ci int i; 4098987da915Sopenharmony_ci 4099987da915Sopenharmony_ci i = 0; 4100987da915Sopenharmony_ci while ((i < 10) && optx[i] && (optx[i] != num)) 4101987da915Sopenharmony_ci i++; 4102987da915Sopenharmony_ci return (optx[i] == num); 4103987da915Sopenharmony_ci} 4104987da915Sopenharmony_ci 4105987da915Sopenharmony_cistatic void version(void) 4106987da915Sopenharmony_ci{ 4107987da915Sopenharmony_ci printf("\n%s v%s (libntfs-3g) - Recover updates committed by Windows" 4108987da915Sopenharmony_ci " on an NTFS Volume.\n\n", "ntfsrecover", VERSION); 4109987da915Sopenharmony_ci printf("Copyright (c) 2012-2017 Jean-Pierre Andre\n"); 4110987da915Sopenharmony_ci printf("\n%s\n%s%s\n", ntfs_gpl, ntfs_bugs, ntfs_home); 4111987da915Sopenharmony_ci} 4112987da915Sopenharmony_ci 4113987da915Sopenharmony_cistatic void usage(void) 4114987da915Sopenharmony_ci{ 4115987da915Sopenharmony_ci fprintf(stderr,"Usage : for recovering the updates committed by Windows :\n"); 4116987da915Sopenharmony_ci fprintf(stderr," ntfsrecover partition\n"); 4117987da915Sopenharmony_ci fprintf(stderr," (e.g. ntfsrecover /dev/sda1)\n"); 4118987da915Sopenharmony_ci fprintf(stderr,"Advanced : ntfsrecover [-b] [-c first-last] [-i] [-f] [-n] [-p count]\n"); 4119987da915Sopenharmony_ci fprintf(stderr," [-r first-last] [-t] [-u count] [-v] partition\n"); 4120987da915Sopenharmony_ci fprintf(stderr," -b : show the full log backward\n"); 4121987da915Sopenharmony_ci fprintf(stderr," -c : restrict to the actions related to cluster range\n"); 4122987da915Sopenharmony_ci fprintf(stderr," -i : show invalid (stale) records\n"); 4123987da915Sopenharmony_ci fprintf(stderr," -f : show the full log forward\n"); 4124987da915Sopenharmony_ci fprintf(stderr," -h : show this help information\n"); 4125987da915Sopenharmony_ci fprintf(stderr," -k : kill fast restart data\n"); 4126987da915Sopenharmony_ci fprintf(stderr," -n : do not apply any modification\n"); 4127987da915Sopenharmony_ci fprintf(stderr," -p : undo the latest count transaction sets and play one\n"); 4128987da915Sopenharmony_ci fprintf(stderr," -r : show a range of log blocks forward\n"); 4129987da915Sopenharmony_ci fprintf(stderr," -s : sync the committed changes (default)\n"); 4130987da915Sopenharmony_ci fprintf(stderr," -t : show transactions\n"); 4131987da915Sopenharmony_ci fprintf(stderr," -u : undo the latest count transaction sets\n"); 4132987da915Sopenharmony_ci fprintf(stderr," -v : show more information (-vv yet more)\n"); 4133987da915Sopenharmony_ci fprintf(stderr," -V : show version and exit\n"); 4134987da915Sopenharmony_ci} 4135987da915Sopenharmony_ci 4136987da915Sopenharmony_ci/* 4137987da915Sopenharmony_ci * Process command options 4138987da915Sopenharmony_ci */ 4139987da915Sopenharmony_ci 4140987da915Sopenharmony_cistatic BOOL getoptions(int argc, char *argv[]) 4141987da915Sopenharmony_ci{ 4142987da915Sopenharmony_ci int c; 4143987da915Sopenharmony_ci int xcount; 4144987da915Sopenharmony_ci u32 xval; 4145987da915Sopenharmony_ci char *endptr; 4146987da915Sopenharmony_ci BOOL err; 4147987da915Sopenharmony_ci static const char *sopt = "-bc:hifknp:r:stu:vVx:"; 4148987da915Sopenharmony_ci static const struct option lopt[] = { 4149987da915Sopenharmony_ci { "backward", no_argument, NULL, 'b' }, 4150987da915Sopenharmony_ci { "clusters", required_argument, NULL, 'c' }, 4151987da915Sopenharmony_ci { "forward", no_argument, NULL, 'f' }, 4152987da915Sopenharmony_ci { "help", no_argument, NULL, 'h' }, 4153987da915Sopenharmony_ci { "kill-fast-restart", no_argument, NULL, 'k' }, 4154987da915Sopenharmony_ci { "no-action", no_argument, NULL, 'n' }, 4155987da915Sopenharmony_ci { "play", required_argument, NULL, 'p' }, 4156987da915Sopenharmony_ci { "range", required_argument, NULL, 'r' }, 4157987da915Sopenharmony_ci { "sync", no_argument, NULL, 's' }, 4158987da915Sopenharmony_ci { "transactions", no_argument, NULL, 't' }, 4159987da915Sopenharmony_ci { "undo", required_argument, NULL, 'u' }, 4160987da915Sopenharmony_ci { "verbose", no_argument, NULL, 'v' }, 4161987da915Sopenharmony_ci { "version", no_argument, NULL, 'V' }, 4162987da915Sopenharmony_ci { "exceptions", required_argument, NULL, 'x' }, 4163987da915Sopenharmony_ci { NULL, 0, NULL, 0 } 4164987da915Sopenharmony_ci }; 4165987da915Sopenharmony_ci 4166987da915Sopenharmony_ci err = FALSE; 4167987da915Sopenharmony_ci optb = FALSE; 4168987da915Sopenharmony_ci optc = FALSE; 4169987da915Sopenharmony_ci optd = FALSE; 4170987da915Sopenharmony_ci optf = FALSE; 4171987da915Sopenharmony_ci opth = FALSE; 4172987da915Sopenharmony_ci opti = FALSE; 4173987da915Sopenharmony_ci optk = FALSE; 4174987da915Sopenharmony_ci optn = FALSE; 4175987da915Sopenharmony_ci optp = FALSE; 4176987da915Sopenharmony_ci optr = FALSE; 4177987da915Sopenharmony_ci opts = 0; 4178987da915Sopenharmony_ci optt = FALSE; 4179987da915Sopenharmony_ci optu = FALSE; 4180987da915Sopenharmony_ci optv = 0; 4181987da915Sopenharmony_ci optV = FALSE; 4182987da915Sopenharmony_ci optx[0] = 0; 4183987da915Sopenharmony_ci 4184987da915Sopenharmony_ci while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) { 4185987da915Sopenharmony_ci switch (c) { 4186987da915Sopenharmony_ci case 1: /* A non-option argument */ 4187987da915Sopenharmony_ci if (optind == argc) 4188987da915Sopenharmony_ci optd = TRUE; 4189987da915Sopenharmony_ci else { 4190987da915Sopenharmony_ci fprintf(stderr, "Device must be the" 4191987da915Sopenharmony_ci " last argument.\n"); 4192987da915Sopenharmony_ci err = TRUE; 4193987da915Sopenharmony_ci } 4194987da915Sopenharmony_ci break; 4195987da915Sopenharmony_ci case 'b': 4196987da915Sopenharmony_ci optb = TRUE; 4197987da915Sopenharmony_ci break; 4198987da915Sopenharmony_ci case 'c': 4199987da915Sopenharmony_ci firstlcn = strtoull(optarg, &endptr, 0); 4200987da915Sopenharmony_ci lastlcn = firstlcn; 4201987da915Sopenharmony_ci if (*endptr == '-') 4202987da915Sopenharmony_ci lastlcn = strtoull(++endptr, &endptr, 0); 4203987da915Sopenharmony_ci if (*endptr || (lastlcn < firstlcn)) { 4204987da915Sopenharmony_ci fprintf(stderr,"Bad cluster range\n"); 4205987da915Sopenharmony_ci err = TRUE; 4206987da915Sopenharmony_ci } else 4207987da915Sopenharmony_ci optc = TRUE; 4208987da915Sopenharmony_ci break; 4209987da915Sopenharmony_ci case 'f': 4210987da915Sopenharmony_ci optf = TRUE; 4211987da915Sopenharmony_ci break; 4212987da915Sopenharmony_ci case '?': 4213987da915Sopenharmony_ci case 'h': 4214987da915Sopenharmony_ci opth = TRUE; 4215987da915Sopenharmony_ci break; 4216987da915Sopenharmony_ci case 'k': 4217987da915Sopenharmony_ci optk = TRUE; 4218987da915Sopenharmony_ci break; 4219987da915Sopenharmony_ci case 'n': 4220987da915Sopenharmony_ci optn = TRUE; 4221987da915Sopenharmony_ci break; 4222987da915Sopenharmony_ci case 'p': 4223987da915Sopenharmony_ci playcount = strtoull(optarg, &endptr, 0); 4224987da915Sopenharmony_ci if (*endptr) { 4225987da915Sopenharmony_ci fprintf(stderr,"Bad play count\n"); 4226987da915Sopenharmony_ci err = TRUE; 4227987da915Sopenharmony_ci } else 4228987da915Sopenharmony_ci optp = TRUE; 4229987da915Sopenharmony_ci break; 4230987da915Sopenharmony_ci case 'r' : 4231987da915Sopenharmony_ci firstblk = strtoull(optarg, &endptr, 0); 4232987da915Sopenharmony_ci lastblk = firstblk; 4233987da915Sopenharmony_ci if (*endptr == '-') 4234987da915Sopenharmony_ci lastblk = strtoull(++endptr, &endptr, 0); 4235987da915Sopenharmony_ci if (*endptr || (lastblk < firstblk)) { 4236987da915Sopenharmony_ci fprintf(stderr,"Bad log block range\n"); 4237987da915Sopenharmony_ci err = TRUE; 4238987da915Sopenharmony_ci } else 4239987da915Sopenharmony_ci optr = TRUE; 4240987da915Sopenharmony_ci break; 4241987da915Sopenharmony_ci case 's': 4242987da915Sopenharmony_ci opts++; 4243987da915Sopenharmony_ci break; 4244987da915Sopenharmony_ci case 't': 4245987da915Sopenharmony_ci optt = TRUE; 4246987da915Sopenharmony_ci break; 4247987da915Sopenharmony_ci case 'u': 4248987da915Sopenharmony_ci playcount = strtoull(optarg, &endptr, 0); 4249987da915Sopenharmony_ci if (*endptr) { 4250987da915Sopenharmony_ci fprintf(stderr,"Bad undo count\n"); 4251987da915Sopenharmony_ci err = TRUE; 4252987da915Sopenharmony_ci } else 4253987da915Sopenharmony_ci optu = TRUE; 4254987da915Sopenharmony_ci break; 4255987da915Sopenharmony_ci case 'v': 4256987da915Sopenharmony_ci optv++; 4257987da915Sopenharmony_ci break; 4258987da915Sopenharmony_ci case 'V': 4259987da915Sopenharmony_ci optV = TRUE; 4260987da915Sopenharmony_ci break; 4261987da915Sopenharmony_ci case 'x': 4262987da915Sopenharmony_ci /* 4263987da915Sopenharmony_ci * Undocumented : actions to execute, though 4264987da915Sopenharmony_ci * they should be skipped under normal rules. 4265987da915Sopenharmony_ci */ 4266987da915Sopenharmony_ci xcount = 0; 4267987da915Sopenharmony_ci xval = strtoull(optarg, &endptr, 0); 4268987da915Sopenharmony_ci while ((*endptr == ',') 4269987da915Sopenharmony_ci && (xcount < (MAXEXCEPTION - 1))) { 4270987da915Sopenharmony_ci optx[xcount++] = xval; 4271987da915Sopenharmony_ci xval = strtoull(++endptr, &endptr, 0); 4272987da915Sopenharmony_ci } 4273987da915Sopenharmony_ci if (*endptr || (xcount >= MAXEXCEPTION)) { 4274987da915Sopenharmony_ci fprintf(stderr,"Bad exception list\n"); 4275987da915Sopenharmony_ci err = TRUE; 4276987da915Sopenharmony_ci } else { 4277987da915Sopenharmony_ci optx[xcount++] = xval; 4278987da915Sopenharmony_ci optx[xcount] = 0; 4279987da915Sopenharmony_ci } 4280987da915Sopenharmony_ci break; 4281987da915Sopenharmony_ci default: 4282987da915Sopenharmony_ci fprintf(stderr,"Unknown option '%s'.\n", 4283987da915Sopenharmony_ci argv[optind - 1]); 4284987da915Sopenharmony_ci err = TRUE; 4285987da915Sopenharmony_ci } 4286987da915Sopenharmony_ci } 4287987da915Sopenharmony_ci 4288987da915Sopenharmony_ci if (!optd && !optV && !opth) { 4289987da915Sopenharmony_ci fprintf(stderr,"Device argument is missing\n"); 4290987da915Sopenharmony_ci err = TRUE; 4291987da915Sopenharmony_ci } 4292987da915Sopenharmony_ci if (!(optb || optf || optp || optr || opts || optt || optu || optV)) 4293987da915Sopenharmony_ci opts = 1; 4294987da915Sopenharmony_ci if (optb && (optf || optr || opts)) { 4295987da915Sopenharmony_ci fprintf(stderr,"Options -f, -r and -s are incompatible with -b\n"); 4296987da915Sopenharmony_ci err = TRUE; 4297987da915Sopenharmony_ci } 4298987da915Sopenharmony_ci if (optf && (optp || opts || optu)) { 4299987da915Sopenharmony_ci fprintf(stderr,"Options -p, -s and -u are incompatible with -f\n"); 4300987da915Sopenharmony_ci err = TRUE; 4301987da915Sopenharmony_ci } 4302987da915Sopenharmony_ci if (optp && (optr || opts || optt || optu)) { 4303987da915Sopenharmony_ci fprintf(stderr,"Options -r, -s, -t and -u are incompatible with -p\n"); 4304987da915Sopenharmony_ci err = TRUE; 4305987da915Sopenharmony_ci } 4306987da915Sopenharmony_ci if (optr && (opts || optu)) { 4307987da915Sopenharmony_ci fprintf(stderr,"Options -s and -u are incompatible with -r\n"); 4308987da915Sopenharmony_ci err = TRUE; 4309987da915Sopenharmony_ci } 4310987da915Sopenharmony_ci if (opts && (optt || optu)) { 4311987da915Sopenharmony_ci fprintf(stderr,"Options -t and -u are incompatible with -s\n"); 4312987da915Sopenharmony_ci err = TRUE; 4313987da915Sopenharmony_ci } 4314987da915Sopenharmony_ci 4315987da915Sopenharmony_ci if (opth || err) 4316987da915Sopenharmony_ci usage(); 4317987da915Sopenharmony_ci else 4318987da915Sopenharmony_ci if (optV) 4319987da915Sopenharmony_ci version(); 4320987da915Sopenharmony_ci return (!err); 4321987da915Sopenharmony_ci} 4322987da915Sopenharmony_ci 4323987da915Sopenharmony_ci/* 4324987da915Sopenharmony_ci * Quick checks on the layout of needed structs 4325987da915Sopenharmony_ci */ 4326987da915Sopenharmony_ci 4327987da915Sopenharmony_cistatic BOOL checkstructs(void) 4328987da915Sopenharmony_ci{ 4329987da915Sopenharmony_ci BOOL ok; 4330987da915Sopenharmony_ci 4331987da915Sopenharmony_ci ok = TRUE; 4332987da915Sopenharmony_ci if (sizeof(RECORD_PAGE_HEADER) != 40) { 4333987da915Sopenharmony_ci fprintf(stderr, 4334987da915Sopenharmony_ci "* error : bad sizeof(RECORD_PAGE_HEADER) %d\n", 4335987da915Sopenharmony_ci (int)sizeof(RECORD_PAGE_HEADER)); 4336987da915Sopenharmony_ci ok = FALSE; 4337987da915Sopenharmony_ci } 4338987da915Sopenharmony_ci if (sizeof(LOG_RECORD) != 88) { 4339987da915Sopenharmony_ci fprintf(stderr, 4340987da915Sopenharmony_ci "* error : bad sizeof(LOG_RECORD) %d\n", 4341987da915Sopenharmony_ci (int)sizeof(LOG_RECORD)); 4342987da915Sopenharmony_ci ok = FALSE; 4343987da915Sopenharmony_ci } 4344987da915Sopenharmony_ci if (sizeof(RESTART_PAGE_HEADER) != 32) { 4345987da915Sopenharmony_ci fprintf(stderr, 4346987da915Sopenharmony_ci "* error : bad sizeof(RESTART_PAGE_HEADER) %d\n", 4347987da915Sopenharmony_ci (int)sizeof(RESTART_PAGE_HEADER)); 4348987da915Sopenharmony_ci ok = FALSE; 4349987da915Sopenharmony_ci } 4350987da915Sopenharmony_ci if (sizeof(RESTART_AREA) != 48) { 4351987da915Sopenharmony_ci fprintf(stderr, 4352987da915Sopenharmony_ci "* error : bad sizeof(RESTART_AREA) %d\n", 4353987da915Sopenharmony_ci (int)sizeof(RESTART_AREA)); 4354987da915Sopenharmony_ci ok = FALSE; 4355987da915Sopenharmony_ci } 4356987da915Sopenharmony_ci if (sizeof(ATTR_OLD) != 44) { 4357987da915Sopenharmony_ci fprintf(stderr, 4358987da915Sopenharmony_ci "* error : bad sizeof(ATTR_OLD) %d\n", 4359987da915Sopenharmony_ci (int)sizeof(ATTR_OLD)); 4360987da915Sopenharmony_ci ok = FALSE; 4361987da915Sopenharmony_ci } 4362987da915Sopenharmony_ci if (sizeof(ATTR_NEW) != 40) { 4363987da915Sopenharmony_ci fprintf(stderr, 4364987da915Sopenharmony_ci "* error : bad sizeof(ATTR_NEW) %d\n", 4365987da915Sopenharmony_ci (int)sizeof(ATTR_NEW)); 4366987da915Sopenharmony_ci ok = FALSE; 4367987da915Sopenharmony_ci } 4368987da915Sopenharmony_ci if (LastAction != 38) { 4369987da915Sopenharmony_ci fprintf(stderr, 4370987da915Sopenharmony_ci "* error : bad action list, %d actions\n", 4371987da915Sopenharmony_ci (int)LastAction); 4372987da915Sopenharmony_ci ok = FALSE; 4373987da915Sopenharmony_ci } 4374987da915Sopenharmony_ci return (ok); 4375987da915Sopenharmony_ci} 4376987da915Sopenharmony_ci 4377987da915Sopenharmony_ciint main(int argc, char *argv[]) 4378987da915Sopenharmony_ci{ 4379987da915Sopenharmony_ci CONTEXT ctx; 4380987da915Sopenharmony_ci unsigned int i; 4381987da915Sopenharmony_ci int err; 4382987da915Sopenharmony_ci 4383987da915Sopenharmony_ci err = 1; 4384987da915Sopenharmony_ci if (checkstructs() 4385987da915Sopenharmony_ci && getoptions(argc,argv)) { 4386987da915Sopenharmony_ci if (optV || opth) { 4387987da915Sopenharmony_ci err = 0; 4388987da915Sopenharmony_ci } else { 4389987da915Sopenharmony_ci redocount = 0; 4390987da915Sopenharmony_ci undocount = 0; 4391987da915Sopenharmony_ci actionnum = 0; 4392987da915Sopenharmony_ci attrcount = 0; 4393987da915Sopenharmony_ci redos_met = 0; 4394987da915Sopenharmony_ci attrtable = (struct ATTR**)NULL; 4395987da915Sopenharmony_ci for (i=0; i<(BUFFERCNT + BASEBLKS); i++) 4396987da915Sopenharmony_ci buffer_table[i] = (struct BUFFER*)NULL; 4397987da915Sopenharmony_ci ntfs_log_set_handler(ntfs_log_handler_outerr); 4398987da915Sopenharmony_ci if (open_volume(&ctx, argv[argc - 1])) { 4399987da915Sopenharmony_ci if (!ctx.vol 4400987da915Sopenharmony_ci && (opts || optp || optu)) { 4401987da915Sopenharmony_ci printf("Options -s, -p and -u" 4402987da915Sopenharmony_ci " require a full device\n"); 4403987da915Sopenharmony_ci err = 1; 4404987da915Sopenharmony_ci } else { 4405987da915Sopenharmony_ci err = walk(&ctx); 4406987da915Sopenharmony_ci if (ctx.vol) { 4407987da915Sopenharmony_ci if ((optp || optu || opts) 4408987da915Sopenharmony_ci && !err 4409987da915Sopenharmony_ci && !optn) { 4410987da915Sopenharmony_ci reset_logfile(&ctx); 4411987da915Sopenharmony_ci } 4412987da915Sopenharmony_ci ntfs_attr_close(log_na); 4413987da915Sopenharmony_ci ntfs_inode_close(log_ni); 4414987da915Sopenharmony_ci ntfs_umount(ctx.vol, TRUE); 4415987da915Sopenharmony_ci } else 4416987da915Sopenharmony_ci fclose(ctx.file); 4417987da915Sopenharmony_ci } 4418987da915Sopenharmony_ci } else 4419987da915Sopenharmony_ci fprintf(stderr,"Could not open %s\n", 4420987da915Sopenharmony_ci argv[argc - 1]); 4421987da915Sopenharmony_ci for (i=0; i<(BUFFERCNT + BASEBLKS); i++) 4422987da915Sopenharmony_ci free(buffer_table[i]); 4423987da915Sopenharmony_ci for (i=0; i<attrcount; i++) 4424987da915Sopenharmony_ci free(attrtable[i]); 4425987da915Sopenharmony_ci free(attrtable); 4426987da915Sopenharmony_ci if (ctx.vol) { 4427987da915Sopenharmony_ci freeclusterentry((struct STORE*)NULL); 4428987da915Sopenharmony_ci show_redos(); 4429987da915Sopenharmony_ci } 4430987da915Sopenharmony_ci } 4431987da915Sopenharmony_ci } 4432987da915Sopenharmony_ci if (err) 4433987da915Sopenharmony_ci exit(1); 4434987da915Sopenharmony_ci return (0); 4435987da915Sopenharmony_ci} 4436