Various changes/fixes
authorEric Biggers <ebiggers3@gmail.com>
Thu, 22 Nov 2012 19:58:41 +0000 (13:58 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 22 Nov 2012 19:58:41 +0000 (13:58 -0600)
src/extract.c
src/mount.c
src/ntfs-apply.c
src/split.c
src/wim.c
src/wimlib_internal.h
src/write.c

index a3942cf..8e80960 100644 (file)
@@ -433,12 +433,8 @@ static void calculate_bytes_to_extract(struct list_head *stream_list,
                                total_bytes += wim_resource_size(lte);
                        }
                } else {
-                       list_for_each_entry(inode, &lte->inode_list,
-                                           lte_inode_list)
-                       {
-                               num_streams++;
-                               total_bytes += wim_resource_size(lte);
-                       }
+                       num_streams += lte->out_refcnt;
+                       total_bytes += lte->out_refcnt * wim_resource_size(lte);
                }
        }
        progress->extract.num_streams = num_streams;
@@ -449,8 +445,7 @@ static void calculate_bytes_to_extract(struct list_head *stream_list,
 static void maybe_add_stream_for_extraction(struct lookup_table_entry *lte,
                                            struct list_head *stream_list)
 {
-       if (lte->out_refcnt == 0) {
-               lte->out_refcnt = 1;
+       if (++lte->out_refcnt == 1) {
                INIT_LIST_HEAD(&lte->inode_list);
                list_add_tail(&lte->staging_list, stream_list);
        }
@@ -474,7 +469,7 @@ static void inode_find_streams_for_extraction(struct inode *inode,
        if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
                for (unsigned i = 0; i < inode->num_ads; i++) {
                        if (inode->ads_entries[i].stream_name_len != 0) {
-                               lte = inode_stream_lte_resolved(inode, i + 1);
+                               lte = inode->ads_entries[i].lte;
                                if (lte) {
                                        maybe_add_stream_for_extraction(lte,
                                                                        stream_list);
@@ -523,8 +518,8 @@ static const struct apply_operations normal_apply_operations = {
 
 #ifdef WITH_NTFS_3G
 static const struct apply_operations ntfs_apply_operations = {
-       .apply_dentry = wim_apply_dentry_ntfs,
-       .apply_dentry_timestamps = wim_apply_dentry_timestamps,
+       .apply_dentry = apply_dentry_ntfs,
+       .apply_dentry_timestamps = apply_dentry_timestamps_ntfs,
 };
 #endif
 
@@ -539,8 +534,17 @@ static int apply_stream_list(struct list_head *stream_list,
        struct inode *inode;
        struct dentry *dentry;
        int ret = 0;
+
+       /* This complicated loop is actually just looping through the dentries
+        * (as for_dentry_in_tree() does), but the outer loop is actually over
+        * the distinct streams to be extracted so that sequential reading of
+        * the WIM can be implemented. */
+
+       /* For each distinct stream to be extracted */
        list_for_each_entry(lte, stream_list, staging_list) {
+               /* For each inode that contains the stream */
                list_for_each_entry(inode, &lte->inode_list, lte_inode_list) {
+                       /* For each dentry that points to the inode */
                        inode_for_each_dentry(dentry, inode) {
                                ret = ops->apply_dentry(dentry, args);
                                if (ret != 0)
@@ -589,13 +593,8 @@ static int extract_single_image(WIMStruct *w, int image,
                        ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s'", target);
                        return WIMLIB_ERR_NTFS_3G;
                }
-       }
-#endif
-
-#ifdef WITH_NTFS_3G
-       if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS)
                ops = &ntfs_apply_operations;
-       else
+       else
 #endif
                ops = &normal_apply_operations;
 
@@ -604,10 +603,9 @@ static int extract_single_image(WIMStruct *w, int image,
                goto out;
 
        inode_list = &w->image_metadata[image - 1].inode_list;
-       find_streams_for_extraction(inode_list,
-                                   &stream_list,
-                                   w->lookup_table,
-                                   extract_flags);
+
+       find_streams_for_extraction(inode_list, &stream_list,
+                                   w->lookup_table, extract_flags);
 
        calculate_bytes_to_extract(&stream_list, extract_flags,
                                   &args.progress);
@@ -630,7 +628,6 @@ static int extract_single_image(WIMStruct *w, int image,
                              &args.progress);
        }
 
-
        args.extract_flags |= WIMLIB_EXTRACT_FLAG_NO_STREAMS;
        ret = for_dentry_in_tree(wim_root_dentry(w), ops->apply_dentry, &args);
        args.extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_STREAMS;
@@ -730,8 +727,8 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
        if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
 #ifdef WITH_NTFS_3G
                if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))) {
-                       ERROR("Cannot specify symlink or hardlink flags when applying ");
-                       ERROR("directly to a NTFS volume");
+                       ERROR("Cannot specify symlink or hardlink flags when applying\n"
+                             "        directly to a NTFS volume");
                        return WIMLIB_ERR_INVALID_PARAM;
                }
                if (image == WIMLIB_ALL_IMAGES) {
index b0d256e..0122d84 100644 (file)
@@ -2018,8 +2018,8 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
 
        /* Mark dentry tree as modified if read-write mount. */
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
-               imd->modified = true;
-               imd->has_been_mounted_rw = true;
+               imd->modified = 1;
+               imd->has_been_mounted_rw = 1;
        }
 
        /* Resolve all the lookup table entries of the dentry tree */
index 7522ec8..1113a83 100644 (file)
@@ -161,10 +161,10 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry,
  *
  * Return 0 on success, nonzero on failure.
  */
-static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry,
-                                  const struct inode *inode,
-                                  ntfs_inode *dir_ni,
-                                  ntfs_inode **to_ni_ret)
+static int apply_hardlink_ntfs(const struct dentry *from_dentry,
+                              const struct inode *inode,
+                              ntfs_inode *dir_ni,
+                              ntfs_inode **to_ni_ret)
 {
        int ret;
        char *p;
@@ -313,8 +313,8 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry,
        return 0;
 }
 
-static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
-                                   struct apply_args *args);
+static int do_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
+                               struct apply_args *args);
 
 /*
  * If @dentry is part of a hard link group, search for hard-linked dentries in
@@ -355,8 +355,8 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
 
                DEBUG("pre-applying DOS name `%s'",
                      dentry_with_dos_name->full_path_utf8);
-               ret = do_wim_apply_dentry_ntfs(dentry_with_dos_name,
-                                              *dir_ni_p, args);
+               ret = do_apply_dentry_ntfs(dentry_with_dos_name,
+                                          *dir_ni_p, args);
                if (ret != 0)
                        return ret;
                p = dentry->full_path_utf8 + dentry->full_path_utf8_len;
@@ -387,8 +387,8 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry,
  *
  * @return:  0 on success; nonzero on failure.
  */
-static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
-                                   struct apply_args *args)
+static int do_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
+                               struct apply_args *args)
 {
        int ret = 0;
        mode_t type;
@@ -417,8 +417,8 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni,
                         * group.  We can make a hard link instead of extracting
                         * the file data. */
                        if (inode->extracted_file) {
-                               ret = wim_apply_hardlink_ntfs(dentry, inode,
-                                                             dir_ni, &ni);
+                               ret = apply_hardlink_ntfs(dentry, inode,
+                                                         dir_ni, &ni);
                                is_hardlink = true;
                                if (ret)
                                        goto out_close_dir_ni;
@@ -559,9 +559,8 @@ out_close_dir_ni:
        return ret;
 }
 
-static int wim_apply_root_dentry_ntfs(const struct dentry *dentry,
-                                     ntfs_volume *vol,
-                                     const WIMStruct *w)
+static int apply_root_dentry_ntfs(const struct dentry *dentry,
+                                 ntfs_volume *vol, const WIMStruct *w)
 {
        ntfs_inode *ni;
        int ret = 0;
@@ -582,7 +581,7 @@ static int wim_apply_root_dentry_ntfs(const struct dentry *dentry,
 }
 
 /* Applies a WIM dentry to the NTFS volume */
-int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
+int apply_dentry_ntfs(struct dentry *dentry, void *arg)
 {
        struct apply_args *args = arg;
        ntfs_volume *vol             = args->vol;
@@ -600,7 +599,6 @@ int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
                if (inode_unnamed_lte_resolved(dentry->d_inode))
                        return 0;
 
-
        DEBUG("Applying dentry `%s' to NTFS", dentry->full_path_utf8);
 
        if ((extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) &&
@@ -612,7 +610,7 @@ int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
        }
 
        if (dentry_is_root(dentry))
-               return wim_apply_root_dentry_ntfs(dentry, vol, w);
+               return apply_root_dentry_ntfs(dentry, vol, w);
 
        p = dentry->full_path_utf8 + dentry->full_path_utf8_len;
        do {
@@ -630,10 +628,10 @@ int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg)
                                 dir_name);
                return WIMLIB_ERR_NTFS_3G;
        }
-       return do_wim_apply_dentry_ntfs(dentry, dir_ni, arg);
+       return do_apply_dentry_ntfs(dentry, dir_ni, arg);
 }
 
-int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg)
+int apply_dentry_timestamps_ntfs(struct dentry *dentry, void *arg)
 {
        struct apply_args *args = arg;
        ntfs_volume *vol = args->vol;
index 091fa3f..649a9bf 100644 (file)
@@ -245,6 +245,7 @@ WIMLIBAPI int wimlib_split(WIMStruct *w, const char *swm_name,
                }
        }
 out:
+       close_wim_writable(w);
        memcpy(&w->hdr, &hdr_save, sizeof(struct wim_header));
        return ret;
 }
index 44653f1..cd024b1 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -225,6 +225,7 @@ int select_wim_image(WIMStruct *w, int image)
                        destroy_image_metadata(imd, NULL);
                        imd->root_dentry = NULL;
                        imd->security_data = NULL;
+                       INIT_HLIST_HEAD(&imd->inode_list);
                }
        }
 
@@ -419,21 +420,6 @@ WIMLIBAPI int wimlib_get_boot_idx(const WIMStruct *w)
        return w->hdr.boot_idx;
 }
 
-/* Opens a WIM readable */
-static int open_wim_readable(WIMStruct *w, const char *path)
-{
-       if (w->fp != NULL)
-               fclose(w->fp);
-       wimlib_assert(path != NULL);
-       w->fp = fopen(path, "rb");
-       if (!w->fp) {
-               ERROR_WITH_ERRNO("Failed to open `%s' for reading",
-                                path);
-               return WIMLIB_ERR_OPEN;
-       }
-       return 0;
-}
-
 /*
  * Begins the reading of a WIM file; opens the file and reads its header and
  * lookup table, and optionally checks the integrity.
@@ -446,10 +432,22 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags,
 
        DEBUG("Reading the WIM file `%s'", in_wim_path);
 
-       ret = open_wim_readable(w, in_wim_path);
-       if (ret != 0)
-               goto out;
+       w->fp = fopen(in_wim_path, "rb");
+       if (!w->fp) {
+               ERROR_WITH_ERRNO("Failed to open `%s' for reading",
+                                in_wim_path);
+               return WIMLIB_ERR_OPEN;
+       }
 
+       /* The absolute path to the WIM is requested so that wimlib_overwrite()
+        * still works even if the process changes its working directory.  This
+        * actually happens if a WIM is mounted read-write, since the FUSE
+        * thread changes directory to "/", and it needs to be able to find the
+        * WIM file again.
+        *
+        * This will break if the full path to the WIM changes in the
+        * intervening time...
+        */
        w->filename = realpath(in_wim_path, NULL);
        if (!w->filename) {
                ERROR_WITH_ERRNO("Failed to resolve WIM filename");
@@ -597,7 +595,8 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags,
        WIMStruct *w;
        int ret;
 
-       DEBUG("wim_file = `%s', open_flags = %#x", wim_file, open_flags);
+       if (!wim_file || !w_ret)
+               return WIMLIB_ERR_INVALID_PARAM;
        w = new_wim_struct();
        if (!w) {
                ERROR("Failed to allocate memory for WIMStruct");
index 9b8c6b7..840348d 100644 (file)
@@ -250,7 +250,6 @@ struct image_metadata {
         * the case, the memory for the filesystem is not freed when switching
         * to a different WIM image. */
        u8 modified : 1;
-
        u8 has_been_mounted_rw : 1;
 };
 
@@ -457,8 +456,8 @@ struct apply_args {
        wimlib_progress_func_t progress_func;
 };
 
-extern int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg);
-extern int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg);
+extern int apply_dentry_ntfs(struct dentry *dentry, void *arg);
+extern int apply_dentry_timestamps_ntfs(struct dentry *dentry, void *arg);
 
 /* ntfs-capture.c */
 extern int build_dentry_tree_ntfs(struct dentry **root_p,
@@ -541,6 +540,7 @@ extern int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *));
 
 /* write.c */
 extern int begin_write(WIMStruct *w, const char *path, int write_flags);
+extern void close_wim_writable(WIMStruct *w);
 
 extern int finish_write(WIMStruct *w, int image, int write_flags,
                        wimlib_progress_func_t progress_func);
index 5b586ce..061f0e7 100644 (file)
@@ -1529,7 +1529,6 @@ static int open_wim_writable(WIMStruct *w, const char *path,
                             bool trunc, bool readable)
 {
        const char *mode;
-       int ret = 0;
        if (trunc)
                if (readable)
                        mode = "w+b";
@@ -1538,26 +1537,18 @@ static int open_wim_writable(WIMStruct *w, const char *path,
        else
                mode = "r+b";
 
-       DEBUG("Opening `%s' read-write", path);
        wimlib_assert(w->out_fp == NULL);
-       wimlib_assert(path != NULL);
        w->out_fp = fopen(path, mode);
-       if (!w->out_fp) {
+       if (w->out_fp) {
+               return 0;
+       } else {
                ERROR_WITH_ERRNO("Failed to open `%s' for writing", path);
                return WIMLIB_ERR_OPEN;
        }
-       if (trunc) {
-               ret = lock_wim(w->out_fp, path);
-               if (ret != 0) {
-                       fclose(w->out_fp);
-                       w->out_fp = NULL;
-               }
-       }
-       return ret;
 }
 
 
-static void close_wim_writable(WIMStruct *w)
+void close_wim_writable(WIMStruct *w)
 {
        if (w->out_fp) {
                if (fclose(w->out_fp) != 0) {
@@ -1572,12 +1563,8 @@ static void close_wim_writable(WIMStruct *w)
 int begin_write(WIMStruct *w, const char *path, int write_flags)
 {
        int ret;
-       bool need_readable = false;
-       bool trunc = true;
-       if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY)
-               need_readable = true;
-
-       ret = open_wim_writable(w, path, trunc, need_readable);
+       ret = open_wim_writable(w, path, true,
+                               (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) != 0);
        if (ret != 0)
                return ret;
        /* Write dummy header. It will be overwritten later. */
@@ -1751,10 +1738,6 @@ static int overwrite_wim_inplace(WIMStruct *w, int write_flags,
        INIT_LIST_HEAD(&stream_list);
        for (int i = modified_image_idx; i < w->hdr.image_count; i++) {
                DEBUG("Identifiying streams in image %d", i + 1);
-               wimlib_assert(w->image_metadata[i].modified);
-               wimlib_assert(!w->image_metadata[i].has_been_mounted_rw);
-               wimlib_assert(w->image_metadata[i].root_dentry != NULL);
-               wimlib_assert(w->image_metadata[i].metadata_lte != NULL);
                w->private = &stream_list;
                for_dentry_in_tree(w->image_metadata[i].root_dentry,
                                   dentry_find_streams_to_write, w);
@@ -1773,7 +1756,6 @@ static int overwrite_wim_inplace(WIMStruct *w, int write_flags,
        if (modified_image_idx == w->hdr.image_count && !w->deletion_occurred) {
                /* If no images have been modified and no images have been
                 * deleted, a new lookup table does not need to be written. */
-               wimlib_assert(list_empty(&stream_list));
                old_wim_end = w->hdr.lookup_table_res_entry.offset +
                              w->hdr.lookup_table_res_entry.size;
                write_flags |= WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE |
@@ -1789,9 +1771,17 @@ static int overwrite_wim_inplace(WIMStruct *w, int write_flags,
        if (ret != 0)
                return ret;
 
+       ret = lock_wim(w->out_fp, w->filename);
+       if (ret != 0) {
+               fclose(w->out_fp);
+               w->out_fp = NULL;
+               return ret;
+       }
+
        if (fseeko(w->out_fp, old_wim_end, SEEK_SET) != 0) {
                ERROR_WITH_ERRNO("Can't seek to end of WIM");
-               return WIMLIB_ERR_WRITE;
+               ret = WIMLIB_ERR_WRITE;
+               goto out_ftruncate;
        }
 
        if (!list_empty(&stream_list)) {
@@ -1851,12 +1841,6 @@ static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags,
                goto err;
        }
 
-       /* Close the original WIM file that was opened for reading. */
-       if (w->fp != NULL) {
-               fclose(w->fp);
-               w->fp = NULL;
-       }
-
        DEBUG("Renaming `%s' to `%s'", tmpfile, w->filename);
 
        /* Rename the new file to the old file .*/
@@ -1874,12 +1858,20 @@ static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags,
                progress_func(WIMLIB_PROGRESS_MSG_RENAME, &progress);
        }
 
+       /* Close the original WIM file that was opened for reading. */
+       if (w->fp != NULL) {
+               fclose(w->fp);
+               w->fp = NULL;
+       }
+
        /* Re-open the WIM read-only. */
        w->fp = fopen(w->filename, "rb");
        if (w->fp == NULL) {
                ret = WIMLIB_ERR_REOPEN;
                WARNING("Failed to re-open `%s' read-only: %s",
                        w->filename, strerror(errno));
+               FREE(w->filename);
+               w->filename = NULL;
        }
        return ret;
 err: