diff --git a/libntfs-3g/runlist.c b/libntfs-3g/runlist.c index 7e158d44..c83c2b7d 100644 --- a/libntfs-3g/runlist.c +++ b/libntfs-3g/runlist.c @@ -939,40 +939,45 @@ mpa_err: "attribute.\n"); goto err_out; } - /* Setup not mapped runlist element if this is the base extent. */ - if (!attr->lowest_vcn) { - VCN max_cluster; - max_cluster = ((sle64_to_cpu(attr->allocated_size) + + /* + * If this is the base of runlist (if 'lowest_vcn' is 0), then + * 'allocated_size' is valid, and we can use it to compute the total + * number of clusters across all extents. If the runlist covers all + * clusters, then it fits into a single extent and we can terminate + * the runlist with LCN_NOENT. Otherwise, we must terminate the runlist + * with LCN_RL_NOT_MAPPED and let the caller look for more extents. + */ + if (!attr->lowest_vcn) { + VCN num_clusters; + + num_clusters = ((sle64_to_cpu(attr->allocated_size) + vol->cluster_size - 1) >> - vol->cluster_size_bits) - 1; - /* - * A highest_vcn of zero means this is a single extent - * attribute so simply terminate the runlist with LCN_ENOENT). - */ - if (deltaxcn) { + vol->cluster_size_bits); + + if (num_clusters > vcn) { /* - * If there is a difference between the highest_vcn and - * the highest cluster, the runlist is either corrupt - * or, more likely, there are more extents following - * this one. + * The runlist doesn't cover all the clusters, so there + * must be more extents. */ - if (deltaxcn < max_cluster) { - ntfs_log_debug("More extents to follow; deltaxcn = " - "0x%llx, max_cluster = 0x%llx\n", - (long long)deltaxcn, - (long long)max_cluster); - rl[rlpos].vcn = vcn; - vcn += rl[rlpos].length = max_cluster - deltaxcn; - rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED; - rlpos++; - } else if (deltaxcn > max_cluster) { - ntfs_log_debug("Corrupt attribute. deltaxcn = " - "0x%llx, max_cluster = 0x%llx\n", - (long long)deltaxcn, - (long long)max_cluster); - goto mpa_err; - } + ntfs_log_debug("More extents to follow; vcn = 0x%llx, " + "num_clusters = 0x%llx\n", + (long long)vcn, + (long long)num_clusters); + rl[rlpos].vcn = vcn; + vcn += rl[rlpos].length = num_clusters - vcn; + rl[rlpos].lcn = (LCN)LCN_RL_NOT_MAPPED; + rlpos++; + } else if (vcn > num_clusters) { + /* + * There are more VCNs in the runlist than expected, so + * the runlist is corrupt. + */ + ntfs_log_error("Corrupt attribute. vcn = 0x%llx, " + "num_clusters = 0x%llx\n", + (long long)vcn, + (long long)num_clusters); + goto mpa_err; } rl[rlpos].lcn = (LCN)LCN_ENOENT; } else /* Not the base extent. There may be more extents to follow. */