From bdc18020a46938f142bf39f10f9e0f1c9126cb0b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 31 Mar 2013 00:02:43 -0500 Subject: [PATCH] Get capturing NTFS reparse points working again --- src/add_image.c | 17 +++++- src/lookup_table.h | 9 +-- src/mount_image.c | 3 +- src/ntfs-capture.c | 130 ++++++++++++++++++++++++++++-------------- src/resource.c | 2 +- src/wim.c | 19 +++--- src/wimlib_internal.h | 11 ++-- 7 files changed, 119 insertions(+), 72 deletions(-) diff --git a/src/add_image.c b/src/add_image.c index e3f022ad..e65e1bce 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -837,6 +837,9 @@ wimlib_add_image_multisource(WIMStruct *w, struct list_head unhashed_streams; int ret; struct sd_set sd_set; +#ifdef WITH_NTFS_3G + struct _ntfs_volume *ntfs_vol = NULL; +#endif if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) { #ifdef WITH_NTFS_3G @@ -850,7 +853,7 @@ wimlib_add_image_multisource(WIMStruct *w, return WIMLIB_ERR_INVALID_PARAM; } capture_tree = build_dentry_tree_ntfs; - extra_arg = &w->ntfs_vol; + extra_arg = &ntfs_vol; #else ERROR("wimlib was compiled without support for NTFS-3g, so\n" " cannot capture a WIM image directly from a NTFS volume!"); @@ -991,13 +994,23 @@ wimlib_add_image_multisource(WIMStruct *w, } ret = add_new_dentry_tree(w, root_dentry, sd); - if (ret) + + if (ret) { +#ifdef WITH_NTFS_3G + if (ntfs_vol) + do_ntfs_umount(ntfs_vol); +#endif goto out_free_dentry_tree; + } imd = w->image_metadata[w->hdr.image_count - 1]; INIT_LIST_HEAD(&imd->unhashed_streams); list_splice(&unhashed_streams, &imd->unhashed_streams); +#ifdef WITH_NTFS_3G + imd->ntfs_vol = ntfs_vol; +#endif + DEBUG("Assigning hard link group IDs"); inode_table_prepare_inode_list(&inode_table, &imd->inode_list); diff --git a/src/lookup_table.h b/src/lookup_table.h index 48ec965e..c1716088 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -40,7 +40,7 @@ struct ntfs_location { tchar *path; utf16lechar *stream_name; u16 stream_name_nchars; - struct _ntfs_volume **ntfs_vol_p; + struct _ntfs_volume *ntfs_vol; bool is_reparse_point; }; #endif @@ -223,13 +223,6 @@ struct wim_lookup_table_entry { struct list_head write_streams_list; }; - - #ifdef WITH_FUSE - /* Pointer to inode that contains the opened file descriptors to - * this stream (valid when resource_location == - * RESOURCE_IN_STAGING_FILE) */ - struct wim_inode *lte_inode; - #endif }; /* Temporary list fields */ diff --git a/src/mount_image.c b/src/mount_image.c index d0b5d2c8..4b4a87bf 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -645,7 +645,6 @@ extract_resource_to_staging_dir(struct wim_inode *inode, new_lte->refcnt = inode->i_nlink; new_lte->resource_location = RESOURCE_IN_STAGING_FILE; new_lte->staging_file_name = staging_file_name; - new_lte->lte_inode = inode; new_lte->resource_entry.original_size = size; lookup_table_insert_unhashed(ctx->wim->lookup_table, new_lte, @@ -796,7 +795,7 @@ rebuild_wim(struct wimfs_context *ctx, int write_flags, DEBUG("Closing all staging file descriptors."); image_for_each_unhashed_stream_safe(lte, tmp, imd) { - ret = inode_close_fds(lte->lte_inode); + ret = inode_close_fds(lte->back_inode); if (ret) return ret; } diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index 327040b3..2656d1dd 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -58,6 +58,22 @@ attr_record_name(ATTR_RECORD *ar) return (ntfschar*)((u8*)ar + le16_to_cpu(ar->name_offset)); } +static ntfs_attr * +open_ntfs_attr(ntfs_inode *ni, struct ntfs_location *loc) +{ + ntfs_attr *na; + + na = ntfs_attr_open(ni, + loc->is_reparse_point ? AT_REPARSE_POINT : AT_DATA, + loc->stream_name, + loc->stream_name_nchars); + if (!na) { + ERROR_WITH_ERRNO("Failed to open attribute of \"%"TS"\" in " + "NTFS volume", loc->path); + } + return na; +} + int read_ntfs_file_prefix(const struct wim_lookup_table_entry *lte, u64 size, @@ -66,7 +82,7 @@ read_ntfs_file_prefix(const struct wim_lookup_table_entry *lte, int _ignored_flags) { struct ntfs_location *loc = lte->ntfs_loc; - ntfs_volume *vol = *loc->ntfs_vol_p; + ntfs_volume *vol = loc->ntfs_vol; ntfs_inode *ni; ntfs_attr *na; s64 pos; @@ -81,32 +97,18 @@ read_ntfs_file_prefix(const struct wim_lookup_table_entry *lte, goto out; } - na = ntfs_attr_open(ni, - loc->is_reparse_point ? AT_REPARSE_POINT : AT_DATA, - loc->stream_name, - loc->stream_name_nchars); + na = open_ntfs_attr(ni, loc); if (!na) { - ERROR_WITH_ERRNO("Failed to open attribute of \"%"TS"\" in " - "NTFS volume", loc->path); ret = WIMLIB_ERR_NTFS_3G; goto out_close_ntfs_inode; } - /*if (is_reparse_point) {*/ - /*if (ntfs_attr_pread(na, 0, 8, buf) != 8)*/ - /*goto out_error;*/ - /**reparse_tag_ret = le32_to_cpu(*(u32*)buf);*/ - /*DEBUG("ReparseTag = %#x", *reparse_tag_ret);*/ - /*pos = 8;*/ - /*bytes_remaining -= 8;*/ - /*}*/ - if (cb) out_buf = alloca(WIM_CHUNK_SIZE); else out_buf = ctx_or_buf; - pos = 0; - bytes_remaining = na->data_size; + pos = (loc->is_reparse_point) ? 8 : 0; + bytes_remaining = size; while (bytes_remaining) { s64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE); if (ntfs_attr_pread(na, pos, to_read, out_buf) != to_read) { @@ -133,6 +135,35 @@ out: return ret; } +static int +read_reparse_tag(ntfs_inode *ni, struct ntfs_location *loc, + u32 *reparse_tag_ret) +{ + int ret; + u8 buf[8]; + ntfs_attr *na; + + na = open_ntfs_attr(ni, loc); + if (!na) { + ret = WIMLIB_ERR_NTFS_3G; + goto out; + } + + if (ntfs_attr_pread(na, 0, 8, buf) != 8) { + ERROR_WITH_ERRNO("Error reading reparse data"); + ret = WIMLIB_ERR_NTFS_3G; + goto out_close_ntfs_attr; + } + *reparse_tag_ret = le32_to_cpu(*(u32*)buf); + DEBUG("ReparseTag = %#x", *reparse_tag_ret); + ret = 0; +out_close_ntfs_attr: + ntfs_attr_close(na); +out: + return ret; + +} + /* Load the streams from a file or reparse point in the NTFS volume into the WIM * lookup table */ static int @@ -141,7 +172,7 @@ capture_ntfs_streams(struct wim_inode *inode, char *path, size_t path_len, struct wim_lookup_table *lookup_table, - ntfs_volume **ntfs_vol_p, + ntfs_volume *vol, ATTR_TYPES type) { ntfs_attr_search_ctx *actx; @@ -180,7 +211,7 @@ capture_ntfs_streams(struct wim_inode *inode, ntfs_loc = CALLOC(1, sizeof(*ntfs_loc)); if (!ntfs_loc) goto out_put_actx; - ntfs_loc->ntfs_vol_p = ntfs_vol_p; + ntfs_loc->ntfs_vol = vol; ntfs_loc->path = MALLOC(path_len + 1); if (!ntfs_loc->path) goto out_free_ntfs_loc; @@ -198,23 +229,26 @@ capture_ntfs_streams(struct wim_inode *inode, lte = new_lookup_table_entry(); if (!lte) goto out_free_ntfs_loc; - lte->ntfs_loc = ntfs_loc; lte->resource_location = RESOURCE_IN_NTFS_VOLUME; - #if 0 + lte->ntfs_loc = ntfs_loc; + ntfs_loc = NULL; if (type == AT_REPARSE_POINT) { - ntfs_loc->is_reparse_point = true; + if (data_size < 8) { + ERROR("Invalid reparse data (only %u bytes)!", + (unsigned)data_size); + ret = WIMLIB_ERR_NTFS_3G; + goto out_free_lte; + } + lte->ntfs_loc->is_reparse_point = true; lte->resource_entry.original_size = data_size - 8; - lte->resource_entry.size = data_size - 8; + ret = read_reparse_tag(ni, lte->ntfs_loc, + &inode->i_reparse_tag); + if (ret) + goto out_free_lte; } else { - ntfs_loc->is_reparse_point = false; + lte->ntfs_loc->is_reparse_point = false; lte->resource_entry.original_size = data_size; - lte->resource_entry.size = data_size; } - #else - ntfs_loc->is_reparse_point = (type == AT_REPARSE_POINT); - lte->resource_entry.original_size = data_size; - #endif - ntfs_loc = NULL; } if (name_length == 0) { /* Unnamed data stream. Put the reference to it in the @@ -401,7 +435,7 @@ struct readdir_ctx { struct sd_set *sd_set; struct dos_name_map *dos_name_map; const struct wimlib_capture_config *config; - ntfs_volume **ntfs_vol_p; + ntfs_volume *vol; int add_image_flags; wimlib_progress_func_t progress_func; }; @@ -417,7 +451,7 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p, struct wim_inode_table *inode_table, struct sd_set *sd_set, const struct wimlib_capture_config *config, - ntfs_volume **ntfs_vol_p, + ntfs_volume *ntfs_vol, int add_image_flags, wimlib_progress_func_t progress_func); @@ -481,7 +515,7 @@ wim_ntfs_capture_filldir(void *dirent, const ntfschar *name, ctx->lookup_table, ctx->inode_table, ctx->sd_set, - ctx->config, ctx->ntfs_vol_p, + ctx->config, ctx->vol, ctx->add_image_flags, ctx->progress_func); if (child) @@ -508,7 +542,7 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret, struct wim_inode_table *inode_table, struct sd_set *sd_set, const struct wimlib_capture_config *config, - ntfs_volume **ntfs_vol_p, + ntfs_volume *vol, int add_image_flags, wimlib_progress_func_t progress_func) { @@ -536,7 +570,7 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret, /* Get file attributes */ struct SECURITY_CONTEXT ctx; memset(&ctx, 0, sizeof(ctx)); - ctx.vol = ni->vol; + ctx.vol = vol; ret = ntfs_xattr_system_getxattr(&ctx, XATTR_NTFS_ATTRIB, ni, dir_ni, (char *)&attributes, sizeof(u32)); @@ -581,7 +615,7 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret, /* Junction point, symbolic link, or other reparse point */ ret = capture_ntfs_streams(inode, ni, path, path_len, lookup_table, - ntfs_vol_p, AT_REPARSE_POINT); + vol, AT_REPARSE_POINT); } else if (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY) { /* Normal directory */ @@ -597,7 +631,7 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret, .sd_set = sd_set, .dos_name_map = &dos_name_map, .config = config, - .ntfs_vol_p = ntfs_vol_p, + .vol = vol, .add_image_flags = add_image_flags, .progress_func = progress_func, }; @@ -614,7 +648,7 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_ret, /* Normal file */ ret = capture_ntfs_streams(inode, ni, path, path_len, lookup_table, - ntfs_vol_p, AT_DATA); + vol, AT_DATA); } if (ret) goto out; @@ -659,6 +693,17 @@ out: return ret; } + +int +do_ntfs_umount(struct _ntfs_volume *vol) +{ + DEBUG("Unmounting NTFS volume"); + if (ntfs_umount(vol, FALSE)) + return WIMLIB_ERR_NTFS_3G; + else + return 0; +} + int build_dentry_tree_ntfs(struct wim_dentry **root_p, const char *device, @@ -673,7 +718,6 @@ build_dentry_tree_ntfs(struct wim_dentry **root_p, ntfs_volume *vol; ntfs_inode *root_ni; int ret; - ntfs_volume **ntfs_vol_p = extra_arg; DEBUG("Mounting NTFS volume `%s' read-only", device); @@ -720,7 +764,7 @@ build_dentry_tree_ntfs(struct wim_dentry **root_p, FILE_NAME_POSIX, lookup_table, inode_table, sd_set, - config, ntfs_vol_p, + config, vol, add_image_flags, progress_func); out_cleanup: @@ -732,7 +776,7 @@ out: ntfs_inode_close(vol->secure_ni); if (ret) { - if (ntfs_umount(vol, FALSE) != 0) { + if (do_ntfs_umount(vol)) { ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", device); if (ret == 0) @@ -741,7 +785,7 @@ out: } else { /* We need to leave the NTFS volume mounted so that we can read * the NTFS files again when we are actually writing the WIM */ - *ntfs_vol_p = vol; + *(ntfs_volume**)extra_arg = vol; } return ret; } diff --git a/src/resource.c b/src/resource.c index dc5b7a80..8af92253 100644 --- a/src/resource.c +++ b/src/resource.c @@ -576,7 +576,7 @@ read_partial_wim_resource(const struct wim_lookup_table_entry *lte, while (size) { size_t bytes_to_read = min(WIM_CHUNK_SIZE, size); size_t bytes_read = fread(buf, 1, bytes_to_read, wim_fp); - + if (bytes_read != bytes_to_read) goto read_error; ret = cb(buf, bytes_read, ctx_or_buf); diff --git a/src/wim.c b/src/wim.c index 8f579f2c..128bddac 100644 --- a/src/wim.c +++ b/src/wim.c @@ -32,11 +32,6 @@ #include #include -#ifdef WITH_NTFS_3G -# include -# include -#endif - #ifdef __WIN32__ # include "win32.h" #else @@ -540,6 +535,12 @@ destroy_image_metadata(struct wim_image_metadata *imd, } INIT_LIST_HEAD(&imd->unhashed_streams); INIT_LIST_HEAD(&imd->inode_list); +#ifdef WITH_NTFS_3G + if (imd->ntfs_vol) { + do_ntfs_umount(imd->ntfs_vol); + imd->ntfs_vol = NULL; + } +#endif } void @@ -576,7 +577,7 @@ struct wim_image_metadata * new_image_metadata() { struct wim_image_metadata *imd; - + imd = CALLOC(1, sizeof(*imd)); if (imd) { imd->refcnt = 1; @@ -668,12 +669,6 @@ wimlib_free(WIMStruct *w) put_image_metadata(w->image_metadata[i], NULL); FREE(w->image_metadata); } -#ifdef WITH_NTFS_3G - if (w->ntfs_vol) { - DEBUG("Unmounting NTFS volume"); - ntfs_umount(w->ntfs_vol, FALSE); - } -#endif FREE(w); DEBUG("Freed WIMStruct"); } diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index f07935c1..44a2314d 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -270,6 +270,10 @@ struct wim_image_metadata { /* 1 iff this image has been mounted read-write */ u8 has_been_mounted_rw : 1; + +#ifdef WITH_NTFS_3G + struct _ntfs_volume *ntfs_vol; +#endif }; /* The opaque structure exposed to the wimlib API. */ @@ -310,10 +314,6 @@ struct WIMStruct { /* Temporary field */ void *private; -#ifdef WITH_NTFS_3G - struct _ntfs_volume *ntfs_vol; -#endif - /* The currently selected image, indexed starting at 1. If not 0, * subtract 1 from this to get the index of the current image in the * image_metadata array. */ @@ -552,6 +552,9 @@ build_dentry_tree_ntfs(struct wim_dentry **root_p, wimlib_progress_func_t progress_func, void *extra_arg); +extern int +do_ntfs_umount(struct _ntfs_volume *vol); + /* resource.c */ #define WIMLIB_RESOURCE_FLAG_RAW 0x1 -- 2.43.0