Merge /spare/repo/linux-2.6/
[powerpc.git] / fs / ntfs / attrib.c
index 23ca3bd..cd0f9e7 100644 (file)
  *
  * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
  *
- * Return 0 on success and -errno on error.
+ * Return 0 on success and -errno on error.  There is one special error code
+ * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
+ * of bounds of the runlist.
  *
  * Locking: - The runlist must be locked for writing.
  *         - This function modifies the runlist.
  */
 int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn)
 {
+       VCN end_vcn;
        ntfs_inode *base_ni;
-       MFT_RECORD *mrec;
+       MFT_RECORD *m;
+       ATTR_RECORD *a;
        ntfs_attr_search_ctx *ctx;
        runlist_element *rl;
        int err = 0;
@@ -58,26 +62,43 @@ int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn)
                base_ni = ni;
        else
                base_ni = ni->ext.base_ntfs_ino;
-       mrec = map_mft_record(base_ni);
-       if (IS_ERR(mrec))
-               return PTR_ERR(mrec);
-       ctx = ntfs_attr_get_search_ctx(base_ni, mrec);
+       m = map_mft_record(base_ni);
+       if (IS_ERR(m))
+               return PTR_ERR(m);
+       ctx = ntfs_attr_get_search_ctx(base_ni, m);
        if (unlikely(!ctx)) {
                err = -ENOMEM;
                goto err_out;
        }
        err = ntfs_attr_lookup(ni->type, ni->name, ni->name_len,
                        CASE_SENSITIVE, vcn, NULL, 0, ctx);
-       if (likely(!err)) {
-               rl = ntfs_mapping_pairs_decompress(ni->vol, ctx->attr,
-                               ni->runlist.rl);
-               if (IS_ERR(rl))
-                       err = PTR_ERR(rl);
-               else
-                       ni->runlist.rl = rl;
+       if (unlikely(err)) {
+               if (err == -ENOENT)
+                       err = -EIO;
+               goto err_out;
        }
-       ntfs_attr_put_search_ctx(ctx);
+       a = ctx->attr;
+       /*
+        * Only decompress the mapping pairs if @vcn is inside it.  Otherwise
+        * we get into problems when we try to map an out of bounds vcn because
+        * we then try to map the already mapped runlist fragment and
+        * ntfs_mapping_pairs_decompress() fails.
+        */
+       end_vcn = sle64_to_cpu(a->data.non_resident.highest_vcn) + 1;
+       if (unlikely(!a->data.non_resident.lowest_vcn && end_vcn <= 1))
+               end_vcn = ni->allocated_size >> ni->vol->cluster_size_bits;
+       if (unlikely(vcn >= end_vcn)) {
+               err = -ENOENT;
+               goto err_out;
+       }
+       rl = ntfs_mapping_pairs_decompress(ni->vol, a, ni->runlist.rl);
+       if (IS_ERR(rl))
+               err = PTR_ERR(rl);
+       else
+               ni->runlist.rl = rl;
 err_out:
+       if (likely(ctx))
+               ntfs_attr_put_search_ctx(ctx);
        unmap_mft_record(base_ni);
        return err;
 }
@@ -89,7 +110,9 @@ err_out:
  *
  * Map the part of a runlist containing the @vcn of the ntfs inode @ni.
  *
- * Return 0 on success and -errno on error.
+ * Return 0 on success and -errno on error.  There is one special error code
+ * which is not an error as such.  This is -ENOENT.  It means that @vcn is out
+ * of bounds of the runlist.
  *
  * Locking: - The runlist must be unlocked on entry and is unlocked on return.
  *         - This function takes the runlist lock for writing and modifies the
@@ -287,11 +310,11 @@ retry_remap:
                        goto retry_remap;
                }
                /*
-                * -EINVAL and -ENOENT coming from a failed mapping attempt are
-                * equivalent to i/o errors for us as they should not happen in
-                * our code paths.
+                * -EINVAL coming from a failed mapping attempt is equivalent
+                * to i/o error for us as it should not happen in our code
+                * paths.
                 */
-               if (err == -EINVAL || err == -ENOENT)
+               if (err == -EINVAL)
                        err = -EIO;
        } else if (!err)
                err = -EIO;
@@ -982,15 +1005,14 @@ int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
 static inline void ntfs_attr_init_search_ctx(ntfs_attr_search_ctx *ctx,
                ntfs_inode *ni, MFT_RECORD *mrec)
 {
-       ctx->mrec = mrec;
-       /* Sanity checks are performed elsewhere. */
-       ctx->attr = (ATTR_RECORD*)((u8*)mrec + le16_to_cpu(mrec->attrs_offset));
-       ctx->is_first = TRUE;
-       ctx->ntfs_ino = ni;
-       ctx->al_entry = NULL;
-       ctx->base_ntfs_ino = NULL;
-       ctx->base_mrec = NULL;
-       ctx->base_attr = NULL;
+       *ctx = (ntfs_attr_search_ctx) {
+               .mrec = mrec,
+               /* Sanity checks are performed elsewhere. */
+               .attr = (ATTR_RECORD*)((u8*)mrec +
+                               le16_to_cpu(mrec->attrs_offset)),
+               .is_first = TRUE,
+               .ntfs_ino = ni,
+       };
 }
 
 /**
@@ -1286,6 +1308,8 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni)
        new_size = (i_size_read(vi) + vol->cluster_size - 1) &
                        ~(vol->cluster_size - 1);
        if (new_size > 0) {
+               runlist_element *rl2;
+
                /*
                 * Will need the page later and since the page lock nests
                 * outside all ntfs locks, we need to get the page now.
@@ -1300,17 +1324,23 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni)
                if (IS_ERR(rl)) {
                        err = PTR_ERR(rl);
                        ntfs_debug("Failed to allocate cluster%s, error code "
-                                       "%i.\n", (new_size >>
+                                       "%i.", (new_size >>
                                        vol->cluster_size_bits) > 1 ? "s" : "",
                                        err);
                        goto page_err_out;
                }
+               /* Change the runlist terminator to LCN_ENOENT. */
+               rl2 = rl;
+               while (rl2->length)
+                       rl2++;
+               BUG_ON(rl2->lcn != LCN_RL_NOT_MAPPED);
+               rl2->lcn = LCN_ENOENT;
        } else {
                rl = NULL;
                page = NULL;
        }
        /* Determine the size of the mapping pairs array. */
-       mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0);
+       mp_size = ntfs_get_size_for_mapping_pairs(vol, rl, 0, -1);
        if (unlikely(mp_size < 0)) {
                err = mp_size;
                ntfs_debug("Failed to get size for mapping pairs array, error "
@@ -1409,7 +1439,7 @@ int ntfs_attr_make_non_resident(ntfs_inode *ni)
                        cpu_to_sle64(attr_size);
        /* Generate the mapping pairs array into the attribute record. */
        err = ntfs_mapping_pairs_build(vol, (u8*)a + mp_ofs,
-                       arec_size - mp_ofs, rl, 0, NULL);
+                       arec_size - mp_ofs, rl, 0, -1, NULL);
        if (unlikely(err)) {
                ntfs_debug("Failed to build mapping pairs, error code %i.",
                                err);