* capture</b> for full details on how this mode works.
*
* In addition to the error codes that wimlib_add_image() can return,
- * wimlib_add_image_multisource() can return ::WIMLIB_ERR_INVALID_OVERLAY
- * when trying to overlay a non-directory on a directory or when otherwise
- * trying to overlay multiple conflicting files to the same location in the WIM
- * image. It will also return ::WIMLIB_ERR_INVALID_PARAM if
- * ::WIMLIB_ADD_FLAG_NTFS was specified in @p add_flags but there
- * was not exactly one capture source with the target being the root directory.
- * (In this respect, there is no advantage to using
- * wimlib_add_image_multisource() instead of wimlib_add_image() when requesting
- * NTFS mode.)
+ * wimlib_add_image_multisource() can return ::WIMLIB_ERR_INVALID_OVERLAY when
+ * trying to overlay a non-directory on a directory or when otherwise trying to
+ * overlay multiple conflicting files to the same location in the WIM image.
*/
extern int
wimlib_add_image_multisource(WIMStruct *wim,
* Attempted to perform an add command that conflicted with previously
* existing files in the WIM when an overlay was attempted.
* @retval ::WIMLIB_ERR_INVALID_PARAM
- * An unknown operation type was specified in the update commands; or,
- * attempted to execute an add command where ::WIMLIB_ADD_FLAG_NTFS was set
- * in the @p add_flags, but the same image had previously already been
- * added from an NTFS volume; or, both ::WIMLIB_ADD_FLAG_RPFIX and
- * ::WIMLIB_ADD_FLAG_NORPFIX were specified in the @p add_flags for one add
- * command; or, ::WIMLIB_ADD_FLAG_NTFS or ::WIMLIB_ADD_FLAG_RPFIX were
+ * An unknown operation type was specified in the update commands; or, both
+ * ::WIMLIB_ADD_FLAG_RPFIX and ::WIMLIB_ADD_FLAG_NORPFIX were specified in
+ * the @p add_flags for one add command; or ::WIMLIB_ADD_FLAG_RPFIX were
* specified in the @p add_flags for an add command in which @p
* wim_target_path was not the root directory of the WIM image.
* @retval ::WIMLIB_ERR_INVALID_REPARSE_DATA
#ifdef WITH_NTFS_3G
/* The blob's data is available as the contents of an NTFS attribute
- * accessible through libntfs-3g. The attribute is identified by
- * volume, path to an inode, attribute name, and attribute type.
- * @ntfs_loc points to a structure containing this information. */
+ * accessible through libntfs-3g. @ntfs_loc points to a structure which
+ * identifies the attribute. */
BLOB_IN_NTFS_VOLUME,
#endif
/* Flags that affect the capture operation (WIMLIB_ADD_FLAG_*) */
int add_flags;
- /* Extra argument; set to point to a pointer to the ntfs_volume for
- * libntfs-3g capture. */
- void *extra_arg;
-
/* If non-NULL, the user-supplied progress function. */
wimlib_progress_func_t progfunc;
void *progctx;
#include "wimlib/types.h"
#include "wimlib/wim.h"
-#ifdef WITH_NTFS_3G
-struct _ntfs_volume;
-#endif
-
/* Metadata for a WIM image */
struct wim_image_metadata {
* the WIM file. If this is the case, the memory for the dentry tree
* should not be freed when switching to a different WIM image. */
u8 modified : 1;
-
-#ifdef WITH_NTFS_3G
- struct _ntfs_volume *ntfs_vol;
-#endif
};
/* Retrieve the metadata of the image in @wim currently selected with
#ifndef _WIMLIB_NTFS_3G_H
#define _WIMLIB_NTFS_3G_H
+#ifdef WITH_NTFS_3G
+
#include "wimlib/callback.h"
#include "wimlib/types.h"
struct blob_descriptor;
-struct _ntfs_volume;
-
-#ifdef WITH_NTFS_3G
-struct _ntfs_volume;
-struct ntfs_location {
- struct _ntfs_volume *ntfs_vol;
- u64 mft_no;
- utf16lechar *attr_name;
- unsigned attr_name_nchars;
- unsigned attr_type;
- u64 sort_key;
-};
-#endif
+struct ntfs_location;
extern void
libntfs3g_global_init(void);
read_ntfs_attribute_prefix(const struct blob_descriptor *blob, u64 size,
consume_data_callback_t cb, void *cb_ctx);
+extern struct ntfs_location *
+clone_ntfs_location(const struct ntfs_location *loc);
+
+extern void
+free_ntfs_location(struct ntfs_location *loc);
+
extern int
-do_ntfs_umount(struct _ntfs_volume *vol);
+cmp_ntfs_locations(const struct ntfs_location *loc1,
+ const struct ntfs_location *loc2);
+
+#endif /* WITH_NTFS_3G */
-#endif
+#endif /* _WIMLIB_NTFS_3G_H */
break;
#ifdef WITH_NTFS_3G
case BLOB_IN_NTFS_VOLUME:
- if (old->ntfs_loc) {
- new->ntfs_loc = memdup(old->ntfs_loc,
- sizeof(struct ntfs_location));
- if (new->ntfs_loc == NULL)
- goto out_free;
- if (new->ntfs_loc->attr_name != NULL) {
- new->ntfs_loc->attr_name =
- utf16le_dup(new->ntfs_loc->attr_name);
- if (new->ntfs_loc->attr_name == NULL)
- goto out_free;
- }
- }
+ new->ntfs_loc = clone_ntfs_location(old->ntfs_loc);
+ if (!new->ntfs_loc)
+ goto out_free;
break;
#endif
}
break;
#ifdef WITH_NTFS_3G
case BLOB_IN_NTFS_VOLUME:
- if (blob->ntfs_loc) {
- FREE(blob->ntfs_loc->attr_name);
- FREE(blob->ntfs_loc);
- }
+ if (blob->ntfs_loc)
+ free_ntfs_location(blob->ntfs_loc);
break;
#endif
- default:
- break;
}
}
return tstrcmp(blob1->file_on_disk, blob2->file_on_disk);
#ifdef WITH_NTFS_3G
case BLOB_IN_NTFS_VOLUME:
- return cmp_u64(blob1->ntfs_loc->sort_key, blob2->ntfs_loc->sort_key);
+ return cmp_ntfs_locations(blob1->ntfs_loc, blob2->ntfs_loc);
#endif
default:
/* No additional sorting order defined for this resource
#include "wimlib/reparse.h"
#include "wimlib/security.h"
+/* A reference-counted NTFS volume than is automatically unmounted when the
+ * reference count reaches 0 */
+struct ntfs_volume_wrapper {
+ ntfs_volume *vol;
+ size_t refcnt;
+};
+
+/* Description of where data is located in an NTFS volume */
+struct ntfs_location {
+ struct ntfs_volume_wrapper *volume;
+ u64 mft_no;
+ utf16lechar *attr_name;
+ unsigned attr_name_nchars;
+ unsigned attr_type;
+ u64 sort_key;
+};
+
+static struct ntfs_volume_wrapper *
+get_ntfs_volume(struct ntfs_volume_wrapper *volume)
+{
+ volume->refcnt++;
+ return volume;
+}
+
+static void
+put_ntfs_volume(struct ntfs_volume_wrapper *volume)
+{
+ if (--volume->refcnt == 0) {
+ ntfs_umount(volume->vol, FALSE);
+ FREE(volume);
+ }
+}
+
static inline const ntfschar *
attr_record_name(const ATTR_RECORD *record)
{
consume_data_callback_t cb, void *cb_ctx)
{
const struct ntfs_location *loc = blob->ntfs_loc;
- ntfs_volume *vol = loc->ntfs_vol;
+ ntfs_volume *vol = loc->volume->vol;
ntfs_inode *ni;
ntfs_attr *na;
s64 pos;
return ret;
}
+void
+free_ntfs_location(struct ntfs_location *loc)
+{
+ put_ntfs_volume(loc->volume);
+ FREE(loc->attr_name);
+ FREE(loc);
+}
+
+struct ntfs_location *
+clone_ntfs_location(const struct ntfs_location *loc)
+{
+ struct ntfs_location *new = memdup(loc, sizeof(*loc));
+ if (!new)
+ goto err0;
+ if (loc->attr_name) {
+ new->attr_name = utf16le_dup(loc->attr_name);
+ if (!new->attr_name)
+ goto err1;
+ }
+ new->volume = get_ntfs_volume(loc->volume);
+ return new;
+
+err1:
+ FREE(new);
+err0:
+ return NULL;
+}
+
+int
+cmp_ntfs_locations(const struct ntfs_location *loc1,
+ const struct ntfs_location *loc2)
+{
+ return cmp_u64(loc1->sort_key, loc2->sort_key);
+}
+
static int
read_reparse_tag(ntfs_inode *ni, struct ntfs_location *loc,
u32 *reparse_tag_ret)
const char *path,
size_t path_len,
struct list_head *unhashed_blobs,
- ntfs_volume *vol,
+ struct ntfs_volume_wrapper *volume,
ATTR_TYPES type,
const ATTR_RECORD *record)
{
blob->blob_location = BLOB_IN_NTFS_VOLUME;
blob->size = data_size;
- blob->ntfs_loc->ntfs_vol = vol;
+ blob->ntfs_loc->volume = get_ntfs_volume(volume);
blob->ntfs_loc->attr_type = type;
blob->ntfs_loc->mft_no = ni->mft_no;
char *path,
size_t path_len,
struct list_head *unhashed_blobs,
- ntfs_volume *vol,
+ struct ntfs_volume_wrapper *volume,
ATTR_TYPES type)
{
ntfs_attr_search_ctx *actx;
path,
path_len,
unhashed_blobs,
- vol,
+ volume,
type,
actx->attr);
if (ret)
char *path;
size_t path_len;
struct dos_name_map *dos_name_map;
- ntfs_volume *vol;
+ struct ntfs_volume_wrapper *volume;
struct capture_params *params;
int ret;
};
char *path,
size_t path_len,
int name_type,
- ntfs_volume *ntfs_vol,
+ struct ntfs_volume_wrapper *volume,
struct capture_params *params);
static int
/* Open the inode for this directory entry and recursively capture the
* directory tree rooted at it */
- ntfs_inode *ni = ntfs_inode_open(ctx->vol, mref);
+ ntfs_inode *ni = ntfs_inode_open(ctx->volume->vol, mref);
if (!ni) {
/* XXX This used to be treated as an error, but NTFS-3g seemed
* to be unable to read some inodes on a Windows 8 image for
child = NULL;
ret = build_dentry_tree_ntfs_recursive(&child, ni, ctx->path,
path_len, name_type,
- ctx->vol, ctx->params);
+ ctx->volume, ctx->params);
path_len -= mbs_name_nbytes + 1;
if (child)
dentry_add_child(ctx->parent, child);
char *path,
size_t path_len,
int name_type,
- ntfs_volume *vol,
+ struct ntfs_volume_wrapper *volume,
struct capture_params *params)
{
u32 attributes;
/* Scan the reparse point stream. */
ret = scan_ntfs_attrs_with_type(inode, ni, path, path_len,
params->unhashed_blobs,
- vol, AT_REPARSE_POINT);
+ volume, AT_REPARSE_POINT);
if (ret)
goto out;
}
* points) can have an unnamed data stream as well as named data
* streams. */
ret = scan_ntfs_attrs_with_type(inode, ni, path, path_len,
- params->unhashed_blobs, vol, AT_DATA);
+ params->unhashed_blobs,
+ volume, AT_DATA);
if (ret)
goto out;
.path = path,
.path_len = path_len,
.dos_name_map = &dos_name_map,
- .vol = vol,
+ .volume = volume,
.params = params,
.ret = 0,
};
/* Get security descriptor */
memset(&sec_ctx, 0, sizeof(sec_ctx));
- sec_ctx.vol = vol;
+ sec_ctx.vol = volume->vol;
errno = 0;
sd = _sd;
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,
struct capture_params *params)
{
+ struct ntfs_volume_wrapper *volume;
ntfs_volume *vol;
ntfs_inode *root_ni;
+ char *path;
int ret;
+ volume = MALLOC(sizeof(struct ntfs_volume_wrapper));
+ if (!volume)
+ return WIMLIB_ERR_NOMEM;
+
DEBUG("Mounting NTFS volume `%s' read-only", device);
-/* NTFS-3g 2013 renamed the "read-only" mount flag from MS_RDONLY to
- * NTFS_MNT_RDONLY.
- *
- * Unfortunately we can't check for defined(NTFS_MNT_RDONLY) because
- * NTFS_MNT_RDONLY is an enumerated constant. Also, the NTFS-3g headers don't
- * seem to contain any explicit version information. So we have to rely on a
- * test done at configure time to detect whether NTFS_MNT_RDONLY should be used.
- * */
+ /* NTFS-3g 2013 renamed the "read-only" mount flag from MS_RDONLY to
+ * NTFS_MNT_RDONLY.
+ *
+ * Unfortunately we can't check for defined(NTFS_MNT_RDONLY) because
+ * NTFS_MNT_RDONLY is an enumerated constant. Also, the NTFS-3g headers
+ * don't seem to contain any explicit version information. So we have
+ * to rely on a test done at configure time to detect whether
+ * NTFS_MNT_RDONLY should be used. */
#ifdef HAVE_NTFS_MNT_RDONLY
/* NTFS-3g 2013 */
vol = ntfs_mount(device, NTFS_MNT_RDONLY);
if (!vol) {
ERROR_WITH_ERRNO("Failed to mount NTFS volume `%s' read-only",
device);
+ FREE(volume);
return WIMLIB_ERR_NTFS_3G;
}
+
+ volume->vol = vol;
+ volume->refcnt = 1;
+
ntfs_open_secure(vol);
/* We don't want to capture the special NTFS files such as $Bitmap. Not
ERROR_WITH_ERRNO("Failed to open root inode of NTFS volume "
"`%s'", device);
ret = WIMLIB_ERR_NTFS_3G;
- goto out;
+ goto out_put_ntfs_volume;
}
/* Currently we assume that all the paths fit into this length and there
* is no check for overflow. */
- char *path = MALLOC(32768);
+ path = MALLOC(32768);
if (!path) {
- ERROR("Could not allocate memory for NTFS pathname");
ret = WIMLIB_ERR_NOMEM;
- goto out_cleanup;
+ goto out_close_root_ni;
}
path[0] = '/';
path[1] = '\0';
ret = build_dentry_tree_ntfs_recursive(root_p, root_ni, path, 1,
- FILE_NAME_POSIX, vol, params);
-out_cleanup:
+ FILE_NAME_POSIX, volume, params);
FREE(path);
+out_close_root_ni:
ntfs_inode_close(root_ni);
-out:
+out_put_ntfs_volume:
ntfs_index_ctx_put(vol->secure_xsii);
ntfs_index_ctx_put(vol->secure_xsdh);
ntfs_inode_close(vol->secure_ni);
-
- if (ret) {
- if (do_ntfs_umount(vol)) {
- ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'",
- device);
- }
- } 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_volume**)params->extra_arg = vol;
- }
+ put_ntfs_volume(volume);
return ret;
}
#endif /* WITH_NTFS_3G */
#include "wimlib/endianness.h"
#include "wimlib/error.h"
#include "wimlib/file_io.h"
+#include "wimlib/ntfs_3g.h" /* for read_ntfs_attribute_prefix() */
#include "wimlib/resource.h"
#include "wimlib/sha1.h"
#include "wimlib/wim.h"
# include "wimlib/win32.h"
#endif
-#ifdef WITH_NTFS_3G
-/* for read_ntfs_attribute_prefix() */
-# include "wimlib/ntfs_3g.h"
-#endif
-
-
/*
* Compressed WIM resources
*
#include "wimlib/endianness.h"
#include "wimlib/error.h"
#include "wimlib/metadata.h"
-#ifdef WITH_NTFS_3G
-# include "wimlib/ntfs_3g.h" /* for do_ntfs_umount() */
-#endif
#include "wimlib/paths.h"
#include "wimlib/progress.h"
#include "wimlib/xml.h"
struct capture_params params;
struct capture_config config;
capture_tree_t capture_tree = platform_default_capture_tree;
-#ifdef WITH_NTFS_3G
- struct _ntfs_volume *ntfs_vol = NULL;
-#endif
- void *extra_arg = NULL;
struct wim_dentry *branch;
add_flags = add_cmd->add.add_flags;
memset(¶ms, 0, sizeof(params));
#ifdef WITH_NTFS_3G
- if (add_flags & WIMLIB_ADD_FLAG_NTFS) {
+ if (add_flags & WIMLIB_ADD_FLAG_NTFS)
capture_tree = build_dentry_tree_ntfs;
- extra_arg = &ntfs_vol;
- if (wim_get_current_image_metadata(wim)->ntfs_vol != NULL) {
- ERROR("NTFS volume already set");
- ret = WIMLIB_ERR_INVALID_PARAM;
- goto out;
- }
- }
#endif
ret = get_capture_config(config_file, &config,
params.sd_set = sd_set;
params.config = &config;
params.add_flags = add_flags;
- params.extra_arg = extra_arg;
params.progfunc = wim->progfunc;
params.progctx = wim->progctx;
¶ms.progress, params.progctx);
if (ret) {
free_dentry_tree(branch, wim->blob_table);
- goto out_cleanup_after_capture;
+ goto out_destroy_config;
}
if (WIMLIB_IS_WIM_ROOT_PATH(wim_target_path) &&
ERROR("\"%"TS"\" is not a directory!", fs_source_path);
ret = WIMLIB_ERR_NOTDIR;
free_dentry_tree(branch, wim->blob_table);
- goto out_cleanup_after_capture;
+ goto out_destroy_config;
}
ret = attach_branch(branch, wim_target_path, j,
add_flags, params.progfunc, params.progctx);
if (ret)
- goto out_cleanup_after_capture;
+ goto out_destroy_config;
if (config_file && (add_flags & WIMLIB_ADD_FLAG_WIMBOOT) &&
WIMLIB_IS_WIM_ROOT_PATH(wim_target_path))
* /Windows/System32/WimBootCompress.ini in the WIM image. */
ret = platform_default_capture_tree(&branch, config_file, ¶ms);
if (ret)
- goto out_cleanup_after_capture;
+ goto out_destroy_config;
ret = attach_branch(branch, wimboot_cfgfile, j, 0, NULL, NULL);
if (ret)
- goto out_cleanup_after_capture;
+ goto out_destroy_config;
}
-#ifdef WITH_NTFS_3G
- wim_get_current_image_metadata(wim)->ntfs_vol = ntfs_vol;
-#endif
ret = 0;
- goto out_destroy_config;
-out_cleanup_after_capture:
-#ifdef WITH_NTFS_3G
- if (ntfs_vol)
- do_ntfs_umount(ntfs_vol);
-#endif
out_destroy_config:
destroy_capture_config(&config);
out:
#ifndef WITH_NTFS_3G
if (add_flags & WIMLIB_ADD_FLAG_NTFS) {
- ERROR("wimlib was compiled without support for NTFS-3g, so\n"
- " we cannot capture a WIM image directly "
- "from an NTFS volume");
+ ERROR("NTFS-3g capture mode is unsupported because wimlib "
+ "was compiled --without-ntfs-3g");
return WIMLIB_ERR_UNSUPPORTED;
}
#endif
}
if (!is_entire_image) {
- if (add_flags & WIMLIB_ADD_FLAG_NTFS) {
- ERROR("Cannot add directly from an NTFS volume "
- "when not capturing a full image!");
- return WIMLIB_ERR_INVALID_PARAM;
- }
-
if (add_flags & WIMLIB_ADD_FLAG_RPFIX) {
ERROR("Cannot do reparse point fixups when "
"not capturing a full image!");
#include "wimlib/file_io.h"
#include "wimlib/integrity.h"
#include "wimlib/metadata.h"
-#ifdef WITH_NTFS_3G
-# include "wimlib/ntfs_3g.h" /* for do_ntfs_umount() */
-#endif
+#include "wimlib/ntfs_3g.h" /* for libntfs3g_global_init() */
#include "wimlib/security.h"
#include "wimlib/wim.h"
#include "wimlib/xml.h"
}
INIT_LIST_HEAD(&imd->unhashed_blobs);
INIT_HLIST_HEAD(&imd->inode_list);
-#ifdef WITH_NTFS_3G
- if (imd->ntfs_vol) {
- do_ntfs_umount(imd->ntfs_vol);
- imd->ntfs_vol = NULL;
- }
-#endif
}
void