external/ntfs-3g
Revision | 81f7a32edf1ec454a69dc5070b386c62e718247f (tree) |
---|---|
Time | 2017-06-01 12:18:38 |
Author | Chih-Wei Huang <cwhuang@linu...> |
Commiter | Chih-Wei Huang |
Merge branch 'edge' of git://git.code.sf.net/p/ntfs-3g/ntfs-3g into nougat-x86
@@ -3,7 +3,7 @@ | ||
3 | 3 | * |
4 | 4 | * Copyright (c) 2003-2006 Szabolcs Szakacsits |
5 | 5 | * Copyright (c) 2004-2006 Anton Altaparmakov |
6 | - * Copyright (c) 2010-2016 Jean-Pierre Andre | |
6 | + * Copyright (c) 2010-2017 Jean-Pierre Andre | |
7 | 7 | * Special image format support copyright (c) 2004 Per Olofsson |
8 | 8 | * |
9 | 9 | * Clone NTFS data and/or metadata to a sparse file, image, device or stdout. |
@@ -1711,10 +1711,17 @@ static void walk_runs(struct ntfs_walk_cluster *walk) | ||
1711 | 1711 | |
1712 | 1712 | for (j = 0; j < lcn_length; j++) { |
1713 | 1713 | u64 k = (u64)lcn + j; |
1714 | - if (ntfs_bit_get_and_set(lcn_bitmap.bm, k, 1)) | |
1715 | - err_exit("Cluster %llu referenced twice!\n" | |
1716 | - "You didn't shutdown your Windows " | |
1717 | - "properly?\n", (unsigned long long)k); | |
1714 | + if (ntfs_bit_get_and_set(lcn_bitmap.bm, k, 1)) { | |
1715 | + if (opt.ignore_fs_check) | |
1716 | + Printf("Cluster %llu is referenced" | |
1717 | + " twice!\n", | |
1718 | + (unsigned long long)k); | |
1719 | + else | |
1720 | + err_exit("Cluster %llu referenced" | |
1721 | + " twice!\nYou didn't shutdown" | |
1722 | + " your Windows properly?\n", | |
1723 | + (unsigned long long)k); | |
1724 | + } | |
1718 | 1725 | } |
1719 | 1726 | |
1720 | 1727 | if (!opt.metadata_image) |
@@ -1,7 +1,7 @@ | ||
1 | 1 | /* |
2 | 2 | * Process log data from an NTFS partition |
3 | 3 | * |
4 | - * Copyright (c) 2012-2016 Jean-Pierre Andre | |
4 | + * Copyright (c) 2012-2017 Jean-Pierre Andre | |
5 | 5 | * |
6 | 6 | * This program examines the Windows log file of an ntfs partition |
7 | 7 | * and plays the committed transactions in order to restore the |
@@ -43,6 +43,7 @@ | ||
43 | 43 | */ |
44 | 44 | |
45 | 45 | #define BASEBLKS 4 /* number of special blocks (always shown) */ |
46 | +#define BASEBLKS2 34 /* number of special blocks when version >= 2.0 */ | |
46 | 47 | #define RSTBLKS 2 /* number of restart blocks */ |
47 | 48 | #define BUFFERCNT 64 /* number of block buffers - a power of 2 */ |
48 | 49 | #define NTFSBLKLTH 512 /* usa block size */ |
@@ -122,6 +123,7 @@ u32 clustersz = 0; | ||
122 | 123 | int clusterbits; |
123 | 124 | u32 blocksz; |
124 | 125 | int blockbits; |
126 | +int log_major; | |
125 | 127 | u16 bytespersect; |
126 | 128 | u64 mftlcn; |
127 | 129 | u32 mftrecsz; |
@@ -136,6 +138,7 @@ u64 committed_lsn; | ||
136 | 138 | u64 synced_lsn; |
137 | 139 | u64 latest_lsn; |
138 | 140 | u64 restart_lsn; |
141 | +u64 offset_mask; /* block number in an lsn */ | |
139 | 142 | unsigned long firstblk; /* first block to dump (option -r) */ |
140 | 143 | unsigned long lastblk; /* last block to dump (option -r) */ |
141 | 144 | u64 firstlcn; /* first block to dump (option -c) */ |
@@ -164,6 +167,7 @@ unsigned int playedactions; // change the name | ||
164 | 167 | unsigned int redocount; |
165 | 168 | unsigned int undocount; |
166 | 169 | struct BUFFER *buffer_table[BASEBLKS + BUFFERCNT]; |
170 | +unsigned int redirect[BASEBLKS2]; | |
167 | 171 | |
168 | 172 | static const le16 SDS[4] = { |
169 | 173 | const_cpu_to_le16('$'), const_cpu_to_le16('S'), |
@@ -319,18 +323,22 @@ static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num) | ||
319 | 323 | { |
320 | 324 | struct BUFFER *buffer; |
321 | 325 | BOOL got; |
326 | + int k; | |
327 | + unsigned int rnum; | |
322 | 328 | |
323 | 329 | /* |
324 | 330 | * The first four blocks are stored apart, to make |
325 | 331 | * sure pages 2 and 3 and the page which is logically |
326 | 332 | * before them can be accessed at the same time. |
333 | + * (Only two blocks are stored apart if version >= 2.0) | |
327 | 334 | * Also, block 0 is smaller because it has to be read |
328 | 335 | * before the block size is known. |
329 | 336 | * Note : the last block is supposed to have an odd |
330 | - * number, and cannot be overwritten by block 4 which | |
331 | - * follows logically. | |
337 | + * number, and cannot be overwritten by block 4 (or 34 | |
338 | + * if version >= 2.0) which follows logically. | |
332 | 339 | */ |
333 | - if (num < BASEBLKS) | |
340 | + if ((num < RSTBLKS) | |
341 | + || ((log_major < 2) && (num < BASEBLKS))) | |
334 | 342 | buffer = buffer_table[num + BUFFERCNT]; |
335 | 343 | else |
336 | 344 | buffer = buffer_table[num & (BUFFERCNT - 1)]; |
@@ -342,20 +350,27 @@ static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num) | ||
342 | 350 | buffer = (struct BUFFER*) |
343 | 351 | malloc(sizeof(struct BUFFER) + blocksz); |
344 | 352 | buffer->size = blocksz; |
345 | - buffer->num = num + 1; /* forced to being read */ | |
353 | + buffer->rnum = num + 1; /* forced to being read */ | |
346 | 354 | buffer->safe = FALSE; |
347 | 355 | if (num < BASEBLKS) |
348 | 356 | buffer_table[num + BUFFERCNT] = buffer; |
349 | 357 | else |
350 | 358 | buffer_table[num & (BUFFERCNT - 1)] = buffer; |
351 | 359 | } |
352 | - if (buffer && (buffer->num != num)) { | |
360 | + rnum = num; | |
361 | + if (log_major >= 2) { | |
362 | + for (k=RSTBLKS; k<BASEBLKS2; k++) | |
363 | + if (redirect[k] == num) | |
364 | + rnum = k; | |
365 | + } | |
366 | + if (buffer && (buffer->rnum != rnum)) { | |
353 | 367 | buffer->num = num; |
368 | + buffer->rnum = rnum; | |
354 | 369 | if (ctx->vol) |
355 | - got = (ntfs_attr_pread(log_na,(u64)num << blockbits, | |
370 | + got = (ntfs_attr_pread(log_na,(u64)rnum << blockbits, | |
356 | 371 | blocksz, buffer->block.data) == blocksz); |
357 | 372 | else |
358 | - got = !fseek(ctx->file, loclogblk(ctx, num), 0) | |
373 | + got = !fseek(ctx->file, loclogblk(ctx, rnum), 0) | |
359 | 374 | && (fread(buffer->block.data, blocksz, |
360 | 375 | 1, ctx->file) == 1); |
361 | 376 | if (got) { |
@@ -365,7 +380,7 @@ static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num) | ||
365 | 380 | buffer->safe = !replaceusa(buffer, blocksz); |
366 | 381 | } else { |
367 | 382 | buffer->safe = FALSE; |
368 | - fprintf(stderr,"** Could not read block %d\n", num); | |
383 | + fprintf(stderr,"** Could not read block %d\n", rnum); | |
369 | 384 | } |
370 | 385 | } |
371 | 386 | return (buffer && buffer->safe ? buffer : (const struct BUFFER*)NULL); |
@@ -1096,22 +1111,30 @@ static const struct BUFFER *findprevious(CONTEXT *ctx, const struct BUFFER *buf) | ||
1096 | 1111 | skipped = 0; |
1097 | 1112 | do { |
1098 | 1113 | prevmiddle = FALSE; |
1099 | - if (prevblk > BASEBLKS) | |
1114 | + if (prevblk > (log_major < 2 ? BASEBLKS : BASEBLKS2)) | |
1100 | 1115 | prevblk--; |
1101 | 1116 | else |
1102 | - if (prevblk == BASEBLKS) | |
1117 | + if (prevblk == (log_major < 2 ? BASEBLKS : BASEBLKS2)) | |
1103 | 1118 | prevblk = (logfilesz >> blockbits) - 1; |
1104 | 1119 | else { |
1105 | 1120 | rph = &buf->block.record; |
1106 | - prevblk = (sle64_to_cpu(rph->copy.file_offset) | |
1121 | + if (log_major < 2) | |
1122 | + prevblk = (sle64_to_cpu( | |
1123 | + rph->copy.file_offset) | |
1107 | 1124 | >> blockbits) - 1; |
1125 | + else | |
1126 | + prevblk = (sle64_to_cpu( | |
1127 | + rph->copy.last_lsn) | |
1128 | + & offset_mask) | |
1129 | + >> (blockbits - 3); | |
1108 | 1130 | /* |
1109 | 1131 | * If an initial block leads to block 4, it |
1110 | 1132 | * can mean the last block or no previous |
1111 | 1133 | * block at all. Using the last block is safer, |
1112 | 1134 | * its lsn will indicate whether it is stale. |
1113 | 1135 | */ |
1114 | - if (prevblk < BASEBLKS) | |
1136 | + if (prevblk | |
1137 | + < (log_major < 2 ? BASEBLKS : BASEBLKS2)) | |
1115 | 1138 | prevblk = (logfilesz >> blockbits) - 1; |
1116 | 1139 | } |
1117 | 1140 | /* No previous block if the log only consists of block 2 or 3 */ |
@@ -2706,7 +2729,7 @@ static void showrest(const RESTART_PAGE_HEADER *rest) | ||
2706 | 2729 | (long)le32_to_cpu(rest->system_page_size)); |
2707 | 2730 | printf("log_page_size %08lx\n", |
2708 | 2731 | (long)le32_to_cpu(rest->log_page_size)); |
2709 | - printf("restart_area_offset %04x\n", | |
2732 | + printf("restart_area_offset %04x\n", | |
2710 | 2733 | (int)le16_to_cpu(rest->restart_area_offset)); |
2711 | 2734 | printf("minor_vers %d\n", |
2712 | 2735 | (int)sle16_to_cpu(rest->minor_ver)); |
@@ -2876,6 +2899,8 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk, | ||
2876 | 2899 | } |
2877 | 2900 | } |
2878 | 2901 | restart_lsn = synced_lsn; |
2902 | + offset_mask = ((u64)1 << (64 - le32_to_cpu(restart.seq_number_bits))) | |
2903 | + - (1 << (blockbits - 3)); | |
2879 | 2904 | return (dirty); |
2880 | 2905 | } |
2881 | 2906 |
@@ -2895,9 +2920,13 @@ static const struct BUFFER *read_restart(CONTEXT *ctx) | ||
2895 | 2920 | { |
2896 | 2921 | const struct BUFFER *buf; |
2897 | 2922 | BOOL bad; |
2923 | + int blk; | |
2898 | 2924 | int major, minor; |
2899 | 2925 | |
2900 | 2926 | bad = FALSE; |
2927 | + for (blk=0; blk<BASEBLKS2; blk++) | |
2928 | + redirect[blk] = 0; | |
2929 | + log_major = 0; /* needed for reading into a buffer */ | |
2901 | 2930 | if (ctx->vol) { |
2902 | 2931 | RESTART_PAGE_HEADER *rph; |
2903 | 2932 |
@@ -2961,6 +2990,7 @@ static const struct BUFFER *read_restart(CONTEXT *ctx) | ||
2961 | 2990 | major, minor); |
2962 | 2991 | bad = TRUE; |
2963 | 2992 | } |
2993 | + log_major = major; | |
2964 | 2994 | if (bad) { |
2965 | 2995 | buf = (const struct BUFFER*)NULL; |
2966 | 2996 | } |
@@ -3343,7 +3373,8 @@ static TRISTATE backoverlap(CONTEXT *ctx, int blk, | ||
3343 | 3373 | mblk = blk + 1; |
3344 | 3374 | while (total < size) { |
3345 | 3375 | if (mblk >= (logfilesz >> blockbits)) |
3346 | - mblk = BASEBLKS; | |
3376 | + mblk = (log_major < 2 ? BASEBLKS | |
3377 | + : BASEBLKS2); | |
3347 | 3378 | more = size - total; |
3348 | 3379 | if (more > nextspace) |
3349 | 3380 | more = nextspace; |
@@ -3427,9 +3458,15 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped, | ||
3427 | 3458 | if (optv) { |
3428 | 3459 | if (optv >= 2) |
3429 | 3460 | hexdump(data,blocksz); |
3430 | - printf("* RCRD in block %ld 0x%lx (addr 0x%llx)\n", | |
3431 | - (long)blk,(long)blk, | |
3432 | - (long long)loclogblk(ctx, blk)); | |
3461 | + if (buf->rnum != blk) | |
3462 | + printf("* RCRD for block %ld 0x%lx" | |
3463 | + " in block %ld (addr 0x%llx)\n", | |
3464 | + (long)blk,(long)blk,(long)buf->rnum, | |
3465 | + (long long)loclogblk(ctx, blk)); | |
3466 | + else | |
3467 | + printf("* RCRD in block %ld 0x%lx (addr 0x%llx)\n", | |
3468 | + (long)blk,(long)blk, | |
3469 | + (long long)loclogblk(ctx, blk)); | |
3433 | 3470 | } else { |
3434 | 3471 | if (optt) |
3435 | 3472 | printf("block %ld\n",(long)blk); |
@@ -3551,9 +3588,15 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk, | ||
3551 | 3588 | u32 stopblk; |
3552 | 3589 | TRISTATE state; |
3553 | 3590 | |
3554 | - if (optv) | |
3555 | - printf("\n* block %d at 0x%llx\n",(int)blk, | |
3591 | + if (optv) { | |
3592 | + if ((log_major >= 2) && (buf->rnum != blk)) | |
3593 | + printf("\n* block %d for block %d at 0x%llx\n", | |
3594 | + (int)buf->rnum,(int)blk, | |
3595 | + (long long)loclogblk(ctx, buf->rnum)); | |
3596 | + else | |
3597 | + printf("\n* block %d at 0x%llx\n",(int)blk, | |
3556 | 3598 | (long long)loclogblk(ctx, blk)); |
3599 | + } | |
3557 | 3600 | ctx->firstaction = (struct ACTION_RECORD*)NULL; |
3558 | 3601 | ctx->lastaction = (struct ACTION_RECORD*)NULL; |
3559 | 3602 | nextbuf = (const struct BUFFER*)NULL; |
@@ -3576,7 +3619,9 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk, | ||
3576 | 3619 | skipped = blk - prevblk - 1; |
3577 | 3620 | else |
3578 | 3621 | skipped = blk - prevblk - 1 |
3579 | - + (logfilesz >> blockbits) - BASEBLKS; | |
3622 | + + (logfilesz >> blockbits) | |
3623 | + - (log_major < 2 ? BASEBLKS | |
3624 | + : BASEBLKS2); | |
3580 | 3625 | magic = prevbuf->block.record.magic; |
3581 | 3626 | switch (magic) { |
3582 | 3627 | case magic_RCRD : |
@@ -3599,9 +3644,18 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk, | ||
3599 | 3644 | (long long)loclogblk(ctx, blk), |
3600 | 3645 | (long)prevblk); |
3601 | 3646 | else |
3602 | - printf("\n* block %ld at 0x%llx\n", | |
3603 | - (long)blk, | |
3604 | - (long long)loclogblk(ctx, blk)); | |
3647 | + if ((log_major >= 2) | |
3648 | + && (buf->rnum != blk)) | |
3649 | + printf("\n* block %ld for block %ld at 0x%llx\n", | |
3650 | + (long)buf->rnum, | |
3651 | + (long)blk, | |
3652 | + (long long)loclogblk( | |
3653 | + ctx,buf->rnum)); | |
3654 | + else | |
3655 | + printf("\n* block %ld at 0x%llx\n", | |
3656 | + (long)blk, | |
3657 | + (long long)loclogblk( | |
3658 | + ctx, blk)); | |
3605 | 3659 | } |
3606 | 3660 | state = backward_rcrd(ctx, blk, skipped, |
3607 | 3661 | buf, prevbuf, nextbuf); |
@@ -3632,6 +3686,98 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk, | ||
3632 | 3686 | return (state == T_ERR ? 1 : 0); |
3633 | 3687 | } |
3634 | 3688 | |
3689 | +/* | |
3690 | + * Determine the sequencing of blocks (when version >= 2.0) | |
3691 | + * | |
3692 | + * Blocks 2..17 and 18..33 are temporary blocks being filled until | |
3693 | + * they are copied to their target locations, so there are three | |
3694 | + * possible location for recent blocks. | |
3695 | + * | |
3696 | + * Returns the latest target block number | |
3697 | + */ | |
3698 | + | |
3699 | +static int block_sequence(CONTEXT *ctx) | |
3700 | +{ | |
3701 | + const struct BUFFER *buf; | |
3702 | + int blk; | |
3703 | + int k; | |
3704 | + int target_blk; | |
3705 | + int latest_blk; | |
3706 | + s64 final_lsn; | |
3707 | + s64 last_lsn; | |
3708 | + s64 last_lsn12; | |
3709 | + s64 last_lsn1, last_lsn2; | |
3710 | + | |
3711 | + final_lsn = 0; | |
3712 | + for (blk=RSTBLKS; 2*blk<(RSTBLKS+BASEBLKS2); blk++) { | |
3713 | + /* First temporary block */ | |
3714 | + last_lsn1 = 0; | |
3715 | + buf = read_buffer(ctx, blk); | |
3716 | + if (buf && (buf->block.record.magic == magic_RCRD)) { | |
3717 | + last_lsn1 = le64_to_cpu( | |
3718 | + buf->block.record.copy.last_lsn); | |
3719 | + if (!final_lsn | |
3720 | + || ((s64)(last_lsn1 - final_lsn) > 0)) | |
3721 | + final_lsn = last_lsn1; | |
3722 | + } | |
3723 | + /* Second temporary block */ | |
3724 | + buf = read_buffer(ctx, blk + (BASEBLKS2 - RSTBLKS)/2); | |
3725 | + last_lsn2 = 0; | |
3726 | + if (buf && (buf->block.record.magic == magic_RCRD)) { | |
3727 | + last_lsn2 = le64_to_cpu( | |
3728 | + buf->block.record.copy.last_lsn); | |
3729 | + if (!final_lsn | |
3730 | + || ((s64)(last_lsn2 - final_lsn) > 0)) | |
3731 | + final_lsn = last_lsn2; | |
3732 | + } | |
3733 | + /* the latest last_lsn defines the target block */ | |
3734 | + last_lsn12 = 0; | |
3735 | + latest_blk = 0; | |
3736 | + if (last_lsn1 || last_lsn2) { | |
3737 | + if (!last_lsn2 | |
3738 | + || ((s64)(last_lsn1 - last_lsn2) > 0)) { | |
3739 | + last_lsn12 = last_lsn1; | |
3740 | + latest_blk = blk; | |
3741 | + } | |
3742 | + if (!last_lsn1 | |
3743 | + || ((s64)(last_lsn1 - last_lsn2) <= 0)) { | |
3744 | + last_lsn12 = last_lsn2; | |
3745 | + latest_blk = blk + (BASEBLKS2 - RSTBLKS)/2; | |
3746 | + } | |
3747 | + } | |
3748 | + last_lsn = 0; | |
3749 | + target_blk = 0; | |
3750 | + if (last_lsn12) { | |
3751 | + target_blk = (last_lsn12 & offset_mask) | |
3752 | + >> (blockbits - 3); | |
3753 | + buf = read_buffer(ctx, target_blk); | |
3754 | + if (buf && (buf->block.record.magic == magic_RCRD)) { | |
3755 | + last_lsn = le64_to_cpu( | |
3756 | + buf->block.record.copy.last_lsn); | |
3757 | + if (!final_lsn | |
3758 | + || ((s64)(last_lsn - final_lsn) > 0)) | |
3759 | + final_lsn = last_lsn; | |
3760 | + } | |
3761 | + } | |
3762 | + /* redirect to the latest block */ | |
3763 | + if (latest_blk | |
3764 | + && (!last_lsn || ((s64)(last_lsn - last_lsn12) < 0))) | |
3765 | + redirect[latest_blk] = target_blk; | |
3766 | + } | |
3767 | + if (optv) { | |
3768 | + printf("\n Blocks redirected :\n"); | |
3769 | + for (k=RSTBLKS; k<BASEBLKS2; k++) | |
3770 | + if (redirect[k]) | |
3771 | + printf("* block %d to block %d\n", | |
3772 | + (int)redirect[k],(int)k); | |
3773 | + } | |
3774 | + latest_lsn = final_lsn; | |
3775 | + blk = (final_lsn & offset_mask) >> (blockbits - 3); | |
3776 | + if (optv > 1) | |
3777 | + printf("final lsn %llx in blk %d\n",(long long)final_lsn,blk); | |
3778 | + return (blk); | |
3779 | +} | |
3780 | + | |
3635 | 3781 | static int walk(CONTEXT *ctx) |
3636 | 3782 | { |
3637 | 3783 | const struct BUFFER *buf; |
@@ -3644,6 +3790,7 @@ static int walk(CONTEXT *ctx) | ||
3644 | 3790 | u32 blk; |
3645 | 3791 | u32 nextblk; |
3646 | 3792 | u32 prevblk; |
3793 | + u32 finalblk; | |
3647 | 3794 | int err; |
3648 | 3795 | u16 blkheadsz; |
3649 | 3796 | u16 pos; |
@@ -3657,6 +3804,7 @@ static int walk(CONTEXT *ctx) | ||
3657 | 3804 | } |
3658 | 3805 | done = FALSE; |
3659 | 3806 | dirty = TRUE; |
3807 | + finalblk = 0; | |
3660 | 3808 | err = 0; |
3661 | 3809 | blk = 0; |
3662 | 3810 | pos = 0; |
@@ -3675,7 +3823,8 @@ static int walk(CONTEXT *ctx) | ||
3675 | 3823 | while (!done) { |
3676 | 3824 | /* next block is needed to process the current one */ |
3677 | 3825 | if ((nextblk >= (logfilesz >> blockbits)) && (optr || optf)) |
3678 | - nextbuf = read_buffer(ctx, BASEBLKS); | |
3826 | + nextbuf = read_buffer(ctx, | |
3827 | + (log_major < 2 ? BASEBLKS : BASEBLKS2)); | |
3679 | 3828 | else |
3680 | 3829 | nextbuf = read_buffer(ctx,nextblk); |
3681 | 3830 | if (nextbuf) { |
@@ -3741,17 +3890,30 @@ static int walk(CONTEXT *ctx) | ||
3741 | 3890 | } |
3742 | 3891 | blk = nextblk; |
3743 | 3892 | nextblk++; |
3893 | + | |
3894 | + if (!optr && (log_major >= 2) && (nextblk == RSTBLKS)) { | |
3895 | + finalblk = block_sequence(ctx); | |
3896 | + if (!finalblk) { | |
3897 | + done = TRUE; | |
3898 | + err = 1; | |
3899 | + } | |
3900 | + } | |
3901 | + | |
3744 | 3902 | if (optr) { /* Only selected range */ |
3745 | - if ((nextblk == BASEBLKS) && (nextblk < firstblk)) | |
3903 | + u32 endblk; | |
3904 | + | |
3905 | + endblk = (log_major < 2 ? BASEBLKS : RSTBLKS); | |
3906 | + if ((nextblk == endblk) && (nextblk < firstblk)) | |
3746 | 3907 | nextblk = firstblk; |
3747 | - if ((blk >= BASEBLKS) && (blk > lastblk)) | |
3908 | + if ((blk >= endblk) && (blk > lastblk)) | |
3748 | 3909 | done = TRUE; |
3749 | 3910 | } else |
3750 | 3911 | if (optf) { /* Full log, forward */ |
3751 | 3912 | if (blk*blocksz >= logfilesz) |
3752 | 3913 | done = TRUE; |
3753 | 3914 | } else |
3754 | - if (optb || optp || optu || opts) { | |
3915 | + if (optb || optp || optu || opts | |
3916 | + || (log_major >= 2)) { | |
3755 | 3917 | /* Restart blocks only (2 blocks) */ |
3756 | 3918 | if (blk >= RSTBLKS) |
3757 | 3919 | done = TRUE; |
@@ -3782,16 +3944,18 @@ static int walk(CONTEXT *ctx) | ||
3782 | 3944 | } |
3783 | 3945 | if (optv && opts && !dirty) |
3784 | 3946 | printf("* Volume is clean, nothing to do\n"); |
3785 | - if (optb || optp || optu | |
3786 | - || (opts && dirty)) { | |
3947 | + if (log_major >= 2) | |
3948 | + blk = finalblk; | |
3949 | + if (!err | |
3950 | + && (optb || optp || optu || (opts && dirty))) { | |
3787 | 3951 | playedactions = 0; |
3788 | 3952 | ctx->firstaction = (struct ACTION_RECORD*)NULL; |
3789 | 3953 | ctx->lastaction = (struct ACTION_RECORD*)NULL; |
3790 | - buf = nextbuf; | |
3791 | - nextbuf = read_buffer(ctx, blk+1); | |
3792 | - startbuf = best_start(buf,nextbuf); | |
3793 | - if (startbuf) { | |
3794 | - if (startbuf == nextbuf) { | |
3954 | + if (log_major < 2) { | |
3955 | + buf = nextbuf; | |
3956 | + nextbuf = read_buffer(ctx, blk+1); | |
3957 | + startbuf = best_start(buf,nextbuf); | |
3958 | + if (startbuf && (startbuf == nextbuf)) { | |
3795 | 3959 | /* nextbuf is better, show blk */ |
3796 | 3960 | if (optv && buf) { |
3797 | 3961 | printf("* Ignored block %d at 0x%llx\n", |
@@ -3818,6 +3982,11 @@ static int walk(CONTEXT *ctx) | ||
3818 | 3982 | &nextbuf->block.record); |
3819 | 3983 | } |
3820 | 3984 | } |
3985 | + } else { | |
3986 | + buf = startbuf = read_buffer(ctx, blk); | |
3987 | + nextbuf = (const struct BUFFER*)NULL; | |
3988 | + } | |
3989 | + if (startbuf) { | |
3821 | 3990 | /* The latest buf may be more recent than restart */ |
3822 | 3991 | rph = &buf->block.record; |
3823 | 3992 | if ((s64)(sle64_to_cpu(rph->last_end_lsn) |
@@ -74,6 +74,7 @@ enum ACTIONS { | ||
74 | 74 | |
75 | 75 | struct BUFFER { |
76 | 76 | unsigned int num; |
77 | + unsigned int rnum; | |
77 | 78 | unsigned int size; |
78 | 79 | unsigned int headsz; |
79 | 80 | BOOL safe; |
@@ -1,7 +1,7 @@ | ||
1 | 1 | /* |
2 | 2 | * Redo or undo a list of logged actions |
3 | 3 | * |
4 | - * Copyright (c) 2014-2016 Jean-Pierre Andre | |
4 | + * Copyright (c) 2014-2017 Jean-Pierre Andre | |
5 | 5 | * |
6 | 6 | */ |
7 | 7 |
@@ -229,7 +229,7 @@ static int sanity_indx_list(const char *buffer, u32 k, u32 end) | ||
229 | 229 | |
230 | 230 | err = 0; |
231 | 231 | done = FALSE; |
232 | - while ((k <= end) && !done) { | |
232 | + while ((k <= end) && !done && !err) { | |
233 | 233 | lth = getle16(buffer,k+8); |
234 | 234 | if (optv > 1) |
235 | 235 | /* Usual indexes can be determined from size */ |
@@ -270,9 +270,20 @@ static int sanity_indx_list(const char *buffer, u32 k, u32 end) | ||
270 | 270 | (long long)getle64(buffer,k), |
271 | 271 | (int)lth, |
272 | 272 | (int)getle16(buffer,k+12),(int)k); |
273 | + if ((lth < 80) || (lth & 7)) { | |
274 | + printf("** Invalid index record" | |
275 | + " length %d\n",lth); | |
276 | + err = 1; | |
277 | + } | |
273 | 278 | } |
274 | 279 | done = (feedle16(buffer,k+12) & INDEX_ENTRY_END) || !lth; |
275 | - k += lth; | |
280 | + if (lth & 7) { | |
281 | + if (optv <= 1) /* Do not repeat the warning */ | |
282 | + printf("** Invalid index record length %d\n", | |
283 | + lth); | |
284 | + err = 1; | |
285 | + } else | |
286 | + k += lth; | |
276 | 287 | } |
277 | 288 | if (k != end) { |
278 | 289 | printf("** Bad index record length %ld (computed %ld)\n", |
@@ -795,7 +806,9 @@ static int adjust_high_vcn(ntfs_volume *vol, ATTR_RECORD *attr) | ||
795 | 806 | rl = ntfs_mapping_pairs_decompress(vol, attr, (runlist_element*)NULL); |
796 | 807 | if (rl) { |
797 | 808 | xrl = rl; |
798 | - while (xrl->length) | |
809 | + if (xrl->length) | |
810 | + xrl++; | |
811 | + while ((xrl->length) && (xrl->lcn != LCN_RL_NOT_MAPPED)) | |
799 | 812 | xrl++; |
800 | 813 | high_vcn = xrl->vcn - 1; |
801 | 814 | attr->highest_vcn = cpu_to_sle64(high_vcn); |