Android-x86
Fork
Donation

  • R/O
  • HTTP
  • SSH
  • HTTPS

external-ntfs-3g: Commit

external/ntfs-3g


Commit MetaInfo

Revision81f7a32edf1ec454a69dc5070b386c62e718247f (tree)
Time2017-06-01 12:18:38
AuthorChih-Wei Huang <cwhuang@linu...>
CommiterChih-Wei Huang

Log Message

Merge branch 'edge' of git://git.code.sf.net/p/ntfs-3g/ntfs-3g into nougat-x86

Change Summary

Incremental Difference

--- a/ntfsprogs/ntfsclone.c
+++ b/ntfsprogs/ntfsclone.c
@@ -3,7 +3,7 @@
33 *
44 * Copyright (c) 2003-2006 Szabolcs Szakacsits
55 * Copyright (c) 2004-2006 Anton Altaparmakov
6- * Copyright (c) 2010-2016 Jean-Pierre Andre
6+ * Copyright (c) 2010-2017 Jean-Pierre Andre
77 * Special image format support copyright (c) 2004 Per Olofsson
88 *
99 * 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)
17111711
17121712 for (j = 0; j < lcn_length; j++) {
17131713 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+ }
17181725 }
17191726
17201727 if (!opt.metadata_image)
--- a/ntfsprogs/ntfsrecover.c
+++ b/ntfsprogs/ntfsrecover.c
@@ -1,7 +1,7 @@
11 /*
22 * Process log data from an NTFS partition
33 *
4- * Copyright (c) 2012-2016 Jean-Pierre Andre
4+ * Copyright (c) 2012-2017 Jean-Pierre Andre
55 *
66 * This program examines the Windows log file of an ntfs partition
77 * and plays the committed transactions in order to restore the
@@ -43,6 +43,7 @@
4343 */
4444
4545 #define BASEBLKS 4 /* number of special blocks (always shown) */
46+#define BASEBLKS2 34 /* number of special blocks when version >= 2.0 */
4647 #define RSTBLKS 2 /* number of restart blocks */
4748 #define BUFFERCNT 64 /* number of block buffers - a power of 2 */
4849 #define NTFSBLKLTH 512 /* usa block size */
@@ -122,6 +123,7 @@ u32 clustersz = 0;
122123 int clusterbits;
123124 u32 blocksz;
124125 int blockbits;
126+int log_major;
125127 u16 bytespersect;
126128 u64 mftlcn;
127129 u32 mftrecsz;
@@ -136,6 +138,7 @@ u64 committed_lsn;
136138 u64 synced_lsn;
137139 u64 latest_lsn;
138140 u64 restart_lsn;
141+u64 offset_mask; /* block number in an lsn */
139142 unsigned long firstblk; /* first block to dump (option -r) */
140143 unsigned long lastblk; /* last block to dump (option -r) */
141144 u64 firstlcn; /* first block to dump (option -c) */
@@ -164,6 +167,7 @@ unsigned int playedactions; // change the name
164167 unsigned int redocount;
165168 unsigned int undocount;
166169 struct BUFFER *buffer_table[BASEBLKS + BUFFERCNT];
170+unsigned int redirect[BASEBLKS2];
167171
168172 static const le16 SDS[4] = {
169173 const_cpu_to_le16('$'), const_cpu_to_le16('S'),
@@ -319,18 +323,22 @@ static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num)
319323 {
320324 struct BUFFER *buffer;
321325 BOOL got;
326+ int k;
327+ unsigned int rnum;
322328
323329 /*
324330 * The first four blocks are stored apart, to make
325331 * sure pages 2 and 3 and the page which is logically
326332 * before them can be accessed at the same time.
333+ * (Only two blocks are stored apart if version >= 2.0)
327334 * Also, block 0 is smaller because it has to be read
328335 * before the block size is known.
329336 * 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.
332339 */
333- if (num < BASEBLKS)
340+ if ((num < RSTBLKS)
341+ || ((log_major < 2) && (num < BASEBLKS)))
334342 buffer = buffer_table[num + BUFFERCNT];
335343 else
336344 buffer = buffer_table[num & (BUFFERCNT - 1)];
@@ -342,20 +350,27 @@ static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num)
342350 buffer = (struct BUFFER*)
343351 malloc(sizeof(struct BUFFER) + blocksz);
344352 buffer->size = blocksz;
345- buffer->num = num + 1; /* forced to being read */
353+ buffer->rnum = num + 1; /* forced to being read */
346354 buffer->safe = FALSE;
347355 if (num < BASEBLKS)
348356 buffer_table[num + BUFFERCNT] = buffer;
349357 else
350358 buffer_table[num & (BUFFERCNT - 1)] = buffer;
351359 }
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)) {
353367 buffer->num = num;
368+ buffer->rnum = rnum;
354369 if (ctx->vol)
355- got = (ntfs_attr_pread(log_na,(u64)num << blockbits,
370+ got = (ntfs_attr_pread(log_na,(u64)rnum << blockbits,
356371 blocksz, buffer->block.data) == blocksz);
357372 else
358- got = !fseek(ctx->file, loclogblk(ctx, num), 0)
373+ got = !fseek(ctx->file, loclogblk(ctx, rnum), 0)
359374 && (fread(buffer->block.data, blocksz,
360375 1, ctx->file) == 1);
361376 if (got) {
@@ -365,7 +380,7 @@ static const struct BUFFER *read_buffer(CONTEXT *ctx, unsigned int num)
365380 buffer->safe = !replaceusa(buffer, blocksz);
366381 } else {
367382 buffer->safe = FALSE;
368- fprintf(stderr,"** Could not read block %d\n", num);
383+ fprintf(stderr,"** Could not read block %d\n", rnum);
369384 }
370385 }
371386 return (buffer && buffer->safe ? buffer : (const struct BUFFER*)NULL);
@@ -1096,22 +1111,30 @@ static const struct BUFFER *findprevious(CONTEXT *ctx, const struct BUFFER *buf)
10961111 skipped = 0;
10971112 do {
10981113 prevmiddle = FALSE;
1099- if (prevblk > BASEBLKS)
1114+ if (prevblk > (log_major < 2 ? BASEBLKS : BASEBLKS2))
11001115 prevblk--;
11011116 else
1102- if (prevblk == BASEBLKS)
1117+ if (prevblk == (log_major < 2 ? BASEBLKS : BASEBLKS2))
11031118 prevblk = (logfilesz >> blockbits) - 1;
11041119 else {
11051120 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)
11071124 >> blockbits) - 1;
1125+ else
1126+ prevblk = (sle64_to_cpu(
1127+ rph->copy.last_lsn)
1128+ & offset_mask)
1129+ >> (blockbits - 3);
11081130 /*
11091131 * If an initial block leads to block 4, it
11101132 * can mean the last block or no previous
11111133 * block at all. Using the last block is safer,
11121134 * its lsn will indicate whether it is stale.
11131135 */
1114- if (prevblk < BASEBLKS)
1136+ if (prevblk
1137+ < (log_major < 2 ? BASEBLKS : BASEBLKS2))
11151138 prevblk = (logfilesz >> blockbits) - 1;
11161139 }
11171140 /* 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)
27062729 (long)le32_to_cpu(rest->system_page_size));
27072730 printf("log_page_size %08lx\n",
27082731 (long)le32_to_cpu(rest->log_page_size));
2709- printf("restart_area_offset %04x\n",
2732+ printf("restart_area_offset %04x\n",
27102733 (int)le16_to_cpu(rest->restart_area_offset));
27112734 printf("minor_vers %d\n",
27122735 (int)sle16_to_cpu(rest->minor_ver));
@@ -2876,6 +2899,8 @@ static BOOL dorest(CONTEXT *ctx, unsigned long blk,
28762899 }
28772900 }
28782901 restart_lsn = synced_lsn;
2902+ offset_mask = ((u64)1 << (64 - le32_to_cpu(restart.seq_number_bits)))
2903+ - (1 << (blockbits - 3));
28792904 return (dirty);
28802905 }
28812906
@@ -2895,9 +2920,13 @@ static const struct BUFFER *read_restart(CONTEXT *ctx)
28952920 {
28962921 const struct BUFFER *buf;
28972922 BOOL bad;
2923+ int blk;
28982924 int major, minor;
28992925
29002926 bad = FALSE;
2927+ for (blk=0; blk<BASEBLKS2; blk++)
2928+ redirect[blk] = 0;
2929+ log_major = 0; /* needed for reading into a buffer */
29012930 if (ctx->vol) {
29022931 RESTART_PAGE_HEADER *rph;
29032932
@@ -2961,6 +2990,7 @@ static const struct BUFFER *read_restart(CONTEXT *ctx)
29612990 major, minor);
29622991 bad = TRUE;
29632992 }
2993+ log_major = major;
29642994 if (bad) {
29652995 buf = (const struct BUFFER*)NULL;
29662996 }
@@ -3343,7 +3373,8 @@ static TRISTATE backoverlap(CONTEXT *ctx, int blk,
33433373 mblk = blk + 1;
33443374 while (total < size) {
33453375 if (mblk >= (logfilesz >> blockbits))
3346- mblk = BASEBLKS;
3376+ mblk = (log_major < 2 ? BASEBLKS
3377+ : BASEBLKS2);
33473378 more = size - total;
33483379 if (more > nextspace)
33493380 more = nextspace;
@@ -3427,9 +3458,15 @@ static TRISTATE backward_rcrd(CONTEXT *ctx, u32 blk, int skipped,
34273458 if (optv) {
34283459 if (optv >= 2)
34293460 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));
34333470 } else {
34343471 if (optt)
34353472 printf("block %ld\n",(long)blk);
@@ -3551,9 +3588,15 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk,
35513588 u32 stopblk;
35523589 TRISTATE state;
35533590
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,
35563598 (long long)loclogblk(ctx, blk));
3599+ }
35573600 ctx->firstaction = (struct ACTION_RECORD*)NULL;
35583601 ctx->lastaction = (struct ACTION_RECORD*)NULL;
35593602 nextbuf = (const struct BUFFER*)NULL;
@@ -3576,7 +3619,9 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk,
35763619 skipped = blk - prevblk - 1;
35773620 else
35783621 skipped = blk - prevblk - 1
3579- + (logfilesz >> blockbits) - BASEBLKS;
3622+ + (logfilesz >> blockbits)
3623+ - (log_major < 2 ? BASEBLKS
3624+ : BASEBLKS2);
35803625 magic = prevbuf->block.record.magic;
35813626 switch (magic) {
35823627 case magic_RCRD :
@@ -3599,9 +3644,18 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk,
35993644 (long long)loclogblk(ctx, blk),
36003645 (long)prevblk);
36013646 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));
36053659 }
36063660 state = backward_rcrd(ctx, blk, skipped,
36073661 buf, prevbuf, nextbuf);
@@ -3632,6 +3686,98 @@ static int walkback(CONTEXT *ctx, const struct BUFFER *buf, u32 blk,
36323686 return (state == T_ERR ? 1 : 0);
36333687 }
36343688
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+
36353781 static int walk(CONTEXT *ctx)
36363782 {
36373783 const struct BUFFER *buf;
@@ -3644,6 +3790,7 @@ static int walk(CONTEXT *ctx)
36443790 u32 blk;
36453791 u32 nextblk;
36463792 u32 prevblk;
3793+ u32 finalblk;
36473794 int err;
36483795 u16 blkheadsz;
36493796 u16 pos;
@@ -3657,6 +3804,7 @@ static int walk(CONTEXT *ctx)
36573804 }
36583805 done = FALSE;
36593806 dirty = TRUE;
3807+ finalblk = 0;
36603808 err = 0;
36613809 blk = 0;
36623810 pos = 0;
@@ -3675,7 +3823,8 @@ static int walk(CONTEXT *ctx)
36753823 while (!done) {
36763824 /* next block is needed to process the current one */
36773825 if ((nextblk >= (logfilesz >> blockbits)) && (optr || optf))
3678- nextbuf = read_buffer(ctx, BASEBLKS);
3826+ nextbuf = read_buffer(ctx,
3827+ (log_major < 2 ? BASEBLKS : BASEBLKS2));
36793828 else
36803829 nextbuf = read_buffer(ctx,nextblk);
36813830 if (nextbuf) {
@@ -3741,17 +3890,30 @@ static int walk(CONTEXT *ctx)
37413890 }
37423891 blk = nextblk;
37433892 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+
37443902 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))
37463907 nextblk = firstblk;
3747- if ((blk >= BASEBLKS) && (blk > lastblk))
3908+ if ((blk >= endblk) && (blk > lastblk))
37483909 done = TRUE;
37493910 } else
37503911 if (optf) { /* Full log, forward */
37513912 if (blk*blocksz >= logfilesz)
37523913 done = TRUE;
37533914 } else
3754- if (optb || optp || optu || opts) {
3915+ if (optb || optp || optu || opts
3916+ || (log_major >= 2)) {
37553917 /* Restart blocks only (2 blocks) */
37563918 if (blk >= RSTBLKS)
37573919 done = TRUE;
@@ -3782,16 +3944,18 @@ static int walk(CONTEXT *ctx)
37823944 }
37833945 if (optv && opts && !dirty)
37843946 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))) {
37873951 playedactions = 0;
37883952 ctx->firstaction = (struct ACTION_RECORD*)NULL;
37893953 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)) {
37953959 /* nextbuf is better, show blk */
37963960 if (optv && buf) {
37973961 printf("* Ignored block %d at 0x%llx\n",
@@ -3818,6 +3982,11 @@ static int walk(CONTEXT *ctx)
38183982 &nextbuf->block.record);
38193983 }
38203984 }
3985+ } else {
3986+ buf = startbuf = read_buffer(ctx, blk);
3987+ nextbuf = (const struct BUFFER*)NULL;
3988+ }
3989+ if (startbuf) {
38213990 /* The latest buf may be more recent than restart */
38223991 rph = &buf->block.record;
38233992 if ((s64)(sle64_to_cpu(rph->last_end_lsn)
--- a/ntfsprogs/ntfsrecover.h
+++ b/ntfsprogs/ntfsrecover.h
@@ -74,6 +74,7 @@ enum ACTIONS {
7474
7575 struct BUFFER {
7676 unsigned int num;
77+ unsigned int rnum;
7778 unsigned int size;
7879 unsigned int headsz;
7980 BOOL safe;
--- a/ntfsprogs/playlog.c
+++ b/ntfsprogs/playlog.c
@@ -1,7 +1,7 @@
11 /*
22 * Redo or undo a list of logged actions
33 *
4- * Copyright (c) 2014-2016 Jean-Pierre Andre
4+ * Copyright (c) 2014-2017 Jean-Pierre Andre
55 *
66 */
77
@@ -229,7 +229,7 @@ static int sanity_indx_list(const char *buffer, u32 k, u32 end)
229229
230230 err = 0;
231231 done = FALSE;
232- while ((k <= end) && !done) {
232+ while ((k <= end) && !done && !err) {
233233 lth = getle16(buffer,k+8);
234234 if (optv > 1)
235235 /* Usual indexes can be determined from size */
@@ -270,9 +270,20 @@ static int sanity_indx_list(const char *buffer, u32 k, u32 end)
270270 (long long)getle64(buffer,k),
271271 (int)lth,
272272 (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+ }
273278 }
274279 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;
276287 }
277288 if (k != end) {
278289 printf("** Bad index record length %ld (computed %ld)\n",
@@ -795,7 +806,9 @@ static int adjust_high_vcn(ntfs_volume *vol, ATTR_RECORD *attr)
795806 rl = ntfs_mapping_pairs_decompress(vol, attr, (runlist_element*)NULL);
796807 if (rl) {
797808 xrl = rl;
798- while (xrl->length)
809+ if (xrl->length)
810+ xrl++;
811+ while ((xrl->length) && (xrl->lcn != LCN_RL_NOT_MAPPED))
799812 xrl++;
800813 high_vcn = xrl->vcn - 1;
801814 attr->highest_vcn = cpu_to_sle64(high_vcn);
Show on old repository browser