total_bytes += wim_resource_size(lte);
}
} else {
- list_for_each_entry(inode, <e->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;
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(<e->inode_list);
list_add_tail(<e->staging_list, stream_list);
}
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);
#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
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, <e->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)
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;
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);
&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;
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) {
/* 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 */
*
* 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;
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
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;
*
* @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;
* 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;
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;
}
/* 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;
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) &&
}
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 {
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;
}
}
out:
+ close_wim_writable(w);
memcpy(&w->hdr, &hdr_save, sizeof(struct wim_header));
return ret;
}
destroy_image_metadata(imd, NULL);
imd->root_dentry = NULL;
imd->security_data = NULL;
+ INIT_HLIST_HEAD(&imd->inode_list);
}
}
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.
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");
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");
* 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;
};
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,
/* 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);
bool trunc, bool readable)
{
const char *mode;
- int ret = 0;
if (trunc)
if (readable)
mode = "w+b";
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) {
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. */
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);
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 |
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)) {
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 .*/
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: