extracted from the WIM image(s):
.IP \[bu] 4
-Security descriptors (file permissions)
+Security descriptors (file permissions) except through the extensions available
+through the \fB--unix-data\fR option
.IP \[bu]
The alternate (named) data streams for each file
.IP \[bu]
the \fBmkntfs\fR (8) command.
The NTFS extraction mode is not available if wimlib was compiled using the
---without-ntfs-3g option.
+\fB--without-ntfs-3g\fR option.
Please note that the NTFS extraction mode is \fInot\fR entered if \fITARGET\fR
is a directory, even if a NTFS filesystem is mounted on \fITARGET\fR. You must
well).
Here's an example. The names for the split WIMs usually go something like:
-
+
.RS
.PP
.nf
\fB--ref\fR="\fIGLOB\fR"
File glob of additional split WIM parts that are part of the split WIM being
applied. See \fBSPLIT_WIMS\fR.
+.TP
+\fB--unix-data\fR
+This option may only be given in the normal extraction mode (not NTFS).
+By default, in the normal extraction mode, \fBimagex apply\fR will ignore both
+Windows-style security descriptors and UNIX-specific file owners, groups, and
+modes set when using \fBimagex capture\fR with the \fB--unix-data\fR flag. By
+passing \fB--unix-data\fR to \fBimagex apply\fR instead, this causes this
+UNIX-specific data to be restored when available.
.SH NOTES
.IP \[bu] 4
File permissions. The resulting WIM image will not contain any security
descriptors because the format of the security descriptors is Windows-specific,
-and they cannot contain UNIX file modes.
+and they cannot contain UNIX file modes. (Exception: see the \fB--unix-data\fR
+option.)
+
.IP \[bu]
No alternate data streams will be captured, since these do not exist on
POSIX-compliant filesystems. The resulting WIM image will not contain any
.RE
.RE
+.TP
+\fB--unix-data\fR
+Store the UNIX owner, group, and mode of regular files, symbolic links, and
+directories. This is done by adding a special alternate data stream to each
+directory entry that contains this information. Please note that this flag is
+for convenience only, in case you want to use \fBimagex\fR to archive files on
+UNIX. Microsoft's software will not understand this special information.
+
.SH NOTES
\fBimage append\fR does not support appending an image to a split WIM.
Append an image to the WIM we just captured, but do it from a NTFS volume on the
partition /dev/sda2, and name the image "Windows 7" and give it a description.
You do not need to specify the compression type, because the WIM already is
-using LZX compression and this cannot be changed. You need to specify --check
-if you don't want the integrity table to be discarded.
+using LZX compression and this cannot be changed. You need to specify
+\fB--check\fR if you don't want the integrity table to be discarded.
.RS
.PP
imagex append /dev/sda2 mywim.wim --check "Windows 7" "Warning: This operating
well).
Here's an example. The names for the split WIMs usually go something like:
-
+
.RS
.PP
.nf
.SH NOTES
-Unless --rebuild is specified, aborting an \fBimagex export\fR command mid-way
-through has a small chance of corrupting the destination WIM file. However, a
-precaution is taken against this, so it should be very unlikely. In the event
-of an aborted \fBimagex export\fR, \fBimagex optimize\fR can be run to remove
-extra data that may have been partially appended to the physical destination WIM
-file but not yet incorporated into the structure of the WIM.
+Unless \fB--rebuild\fR is specified, aborting an \fBimagex export\fR command
+mid-way through has a small chance of corrupting the destination WIM file.
+However, a precaution is taken against this, so it should be very unlikely. In
+the event of an aborted \fBimagex export\fR, \fBimagex optimize\fR can be run to
+remove extra data that may have been partially appended to the physical
+destination WIM file but not yet incorporated into the structure of the WIM.
.SH EXAMPLES
Export the second image of 'boot.wim' to the new WIM file 'new.wim', and
imagex-mount, imagex-mountrw, imagex-unmount \- Mount and unmount an image from a WIM archive
.SH SYNOPSIS
-\fBimagex mount\fR \fIWIMFILE\fR \fIIMAGE\fR \fIDIRECTORY\fR [--check]
-[--streams-interface=\fIINTERFACE\fR] [--ref="\fIGLOB\fR"]
+\fBimagex mount\fR \fIWIMFILE\fR \fIIMAGE\fR \fIDIRECTORY\fR [\fIOPTION\fR]...
.br
-\fBimagex mountrw\fR \fIWIMFILE\fR \fIIMAGE\fR \fIDIRECTORY\fR [--check]
-[--streams-interface=\fIINTERFACE\fR] [--staging-dir=\fIDIR\fR]
+\fBimagex mountrw\fR \fIWIMFILE\fR \fIIMAGE\fR \fIDIRECTORY\fR [\fIOPTION\fR]...
.br
\fBimagex unmount\fR \fIDIRECTORY\fR [--commit] [--check] [--rebuild]
well).
Here's an example. The names for the split WIMs usually go something like:
-
+
.RS
.PP
.nf
.SH NOTES
-If wimlib was configured using the --without-fuse flag, then the \fBimagex
+If wimlib was configured using the \fB--without-fuse\fR flag, then the \fBimagex
mount\fR, \fBimagex mountrw\fR, and \fBimagex unmount\fR commands will not work.
You can mount multiple images from a WIM file read-only at the same time, but
\fB--staging-dir\fR=\fIDIR\fR
Store temporary staging files in the directory \fIDIR\fR. Only valid for
\fBimagex mountrw\fR.
+.TP
+\fB--unix-data\fR
+By default, \fBimagex mount\fR and \fBimagex mountrw\fR will ignore both
+Windows-style security descriptors (which may have been set either from Windows or by
+\fBimagex capture\fR from a NTFS-volume) and UNIX-specific data (which is from using
+\fBimagex capture\fR with the \fB--unix-data\fR flag). In this default mode,
+all files will simply be owned by the user running \fBimagex\fR and will have mode 0777.
+(Note: they will still not be accessible to other users unless you also specify
+\fB--allow-other\fR.) If you instead provide the \fB--unix-data\fR flag, these
+default permissions will be overridden on a per-file basis with the
+UNIX-specific data when available, and in the case of \fBimagex mountrw\fR it
+will be possible to change the UNIX permissions using the standard UNIX
+tools and functions.
+.TP
+\fB--allow-other\fR
+Pass the \fBallow_other\fR option to the FUSE mount. See \fBmount.fuse\fR (8).
+Note: to do this is a non-root user, \fBuser_allow_other\fR needs to be
+specified in /etc/fuse.conf (with the FUSE implementation on Linux, at least).
.SH UNMOUNT OPTIONS
.TP
\fB--check\fR
When writing \fIWIMFILE\fR, include an integrity table. Has no effect if the
-mount is read-only or if --commit was not specified.
+mount is read-only or if \fB--commit\fR was not specified.
.TP
\fB--rebuild\fR
Rebuild the entire WIM rather than appending any new data to the end of it.
Rebuilding the WIM is slower, but will save a little bit of space that would
otherwise be left as a hole in the WIM. Even more space will be saved if the
read-write mount resulted in streams being deleted from the WIM. Also see
-\fBimagex optimize\fR. Has no effect if the mount is read-only or if --commit
-was not specified.
+\fBimagex optimize\fR. Has no effect if the mount is read-only or if
+\fB--commit\fR was not specified.
.SH IMPLEMENTATION DETAILS
"imagex append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
" [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n"
" [--verbose] [--dereference] [--config=FILE]\n"
-" [--threads=NUM_THREADS] [--rebuild]\n",
+" [--threads=NUM_THREADS] [--rebuild] [--unix-data]\n",
[APPLY] =
"imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n"
" (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n"
-" [--symlink] [--verbose] [--ref=\"GLOB\"]\n",
+" [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\n",
[CAPTURE] =
"imagex capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
" [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n"
" [--flags EDITION_ID] [--verbose] [--dereference]\n"
-" [--config=FILE] [--threads=NUM_THREADS]\n",
+" [--config=FILE] [--threads=NUM_THREADS] [--unix-data]\n",
[DELETE] =
"imagex delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n",
[DIR] =
[MOUNT] =
"imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n"
" [--check] [--debug] [--streams-interface=INTERFACE]\n"
-" [--ref=\"GLOB\"]\n",
+" [--ref=\"GLOB\"] [--unix-data] [--allow-other]\n",
[MOUNTRW] =
"imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n"
" [--check] [--debug] [--streams-interface=INTERFACE]\n"
-" [--staging-dir=DIR]\n",
+" [--staging-dir=DIR] [--unix-data] [--allow-other]\n",
[OPTIMIZE] =
"imagex optimize WIMFILE [--check] [--recompress] [--compress=TYPE]\n",
[SPLIT] =
};
static const struct option apply_options[] = {
- {"check", no_argument, NULL, 'c'},
- {"hardlink", no_argument, NULL, 'h'},
- {"symlink", no_argument, NULL, 's'},
- {"verbose", no_argument, NULL, 'v'},
- {"ref", required_argument, NULL, 'r'},
+ {"check", no_argument, NULL, 'c'},
+ {"hardlink", no_argument, NULL, 'h'},
+ {"symlink", no_argument, NULL, 's'},
+ {"verbose", no_argument, NULL, 'v'},
+ {"ref", required_argument, NULL, 'r'},
+ {"unix-data", no_argument, NULL, 'U'},
{NULL, 0, NULL, 0},
};
static const struct option capture_or_append_options[] = {
{"verbose", no_argument, NULL, 'v'},
{"threads", required_argument, NULL, 't'},
{"rebuild", no_argument, NULL, 'R'},
+ {"unix-data", no_argument, NULL, 'U'},
{NULL, 0, NULL, 0},
};
static const struct option delete_options[] = {
{"streams-interface", required_argument, NULL, 's'},
{"ref", required_argument, NULL, 'r'},
{"staging-dir", required_argument, NULL, 'D'},
+ {"unix-data", no_argument, NULL, 'U'},
+ {"allow-other", no_argument, NULL, 'A'},
{NULL, 0, NULL, 0},
};
case 'r':
swm_glob = optarg;
break;
+ case 'U':
+ extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
+ break;
default:
usage(APPLY);
return -1;
case 'R':
write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
break;
+ case 'U':
+ add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA;
+ break;
default:
usage(cmd);
return -1;
for_opt(c, mount_options) {
switch (c) {
+ case 'A':
+ mount_flags |= WIMLIB_MOUNT_FLAG_ALLOW_OTHER;
+ break;
case 'c':
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
break;
case 'D':
staging_dir = optarg;
break;
+ case 'U':
+ mount_flags |= WIMLIB_MOUNT_FLAG_UNIX_DATA;
+ break;
default:
goto mount_usage;
}
else
inode->i_ino = (u64)root_stbuf.st_ino |
((u64)root_stbuf.st_dev << ((sizeof(ino_t) * 8) & 63));
-
- add_image_flags &= ~WIMLIB_ADD_IMAGE_FLAG_ROOT;
inode->i_resolved = 1;
-
+ if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
+ ret = inode_set_unix_data(inode, root_stbuf.st_uid,
+ root_stbuf.st_gid,
+ root_stbuf.st_mode,
+ lookup_table,
+ UNIX_DATA_ALL | UNIX_DATA_CREATE);
+ if (ret)
+ goto out;
+ }
+ add_image_flags &= ~WIMLIB_ADD_IMAGE_FLAG_ROOT;
if (S_ISREG(root_stbuf.st_mode)) { /* Archiving a regular file */
struct wim_lookup_table_entry *lte;
if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) {
#ifdef WITH_NTFS_3G
- if (add_image_flags & (WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE)) {
+ if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE) {
ERROR("Cannot dereference files when capturing directly from NTFS");
return WIMLIB_ERR_INVALID_PARAM;
}
+ if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) {
+ ERROR("Capturing UNIX owner and mode not supported "
+ "when capturing directly from NTFS");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
capture_tree = build_dentry_tree_ntfs;
extra_arg = &w->ntfs_vol;
#else
return true;
}
-#ifdef WITH_FUSE
/* Unlink a WIM dentry from the directory entry tree. */
void unlink_dentry(struct wim_dentry *dentry)
{
return;
rb_erase(&dentry->rb_node, &parent->d_inode->i_children);
}
-#endif
-#ifdef WITH_FUSE
-/*
+/*
* Returns the alternate data stream entry belonging to @inode that has the
* stream name @stream_name.
*/
}
return NULL;
}
-#endif
-#if defined(WITH_FUSE) || defined(WITH_NTFS_3G)
/*
* Add an alternate stream entry to a WIM inode and return a pointer to it, or
* NULL if memory could not be allocated.
inode->i_num_ads = num_ads;
return new_entry;
}
-#endif
-#ifdef WITH_FUSE
+int inode_add_ads_with_data(struct wim_inode *inode, const char *name,
+ const u8 *value, size_t size,
+ struct wim_lookup_table *lookup_table)
+{
+ int ret = WIMLIB_ERR_NOMEM;
+ struct wim_ads_entry *new_ads_entry;
+ struct wim_lookup_table_entry *existing_lte;
+ struct wim_lookup_table_entry *lte;
+ u8 value_hash[SHA1_HASH_SIZE];
+
+ wimlib_assert(inode->i_resolved);
+ new_ads_entry = inode_add_ads(inode, name);
+ if (!new_ads_entry)
+ goto out;
+ sha1_buffer((const u8*)value, size, value_hash);
+ existing_lte = __lookup_resource(lookup_table, value_hash);
+ if (existing_lte) {
+ lte = existing_lte;
+ lte->refcnt++;
+ } else {
+ u8 *value_copy;
+ lte = new_lookup_table_entry();
+ if (!lte)
+ goto out_free_ads_entry;
+ value_copy = MALLOC(size);
+ if (!value_copy) {
+ FREE(lte);
+ goto out_free_ads_entry;
+ }
+ memcpy(value_copy, value, size);
+ lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER;
+ lte->attached_buffer = value_copy;
+ lte->resource_entry.original_size = size;
+ lte->resource_entry.size = size;
+ lte->resource_entry.flags = 0;
+ copy_hash(lte->hash, value_hash);
+ lookup_table_insert(lookup_table, lte);
+ }
+ new_ads_entry->lte = lte;
+ ret = 0;
+ goto out;
+out_free_ads_entry:
+ inode_remove_ads(inode, new_ads_entry - inode->i_ads_entries,
+ lookup_table);
+out:
+ return ret;
+}
+
/* Remove an alternate data stream from a WIM inode */
void inode_remove_ads(struct wim_inode *inode, u16 idx,
struct wim_lookup_table *lookup_table)
(inode->i_num_ads - idx - 1) * sizeof(inode->i_ads_entries[0]));
inode->i_num_ads--;
}
-#endif
+int inode_get_unix_data(const struct wim_inode *inode,
+ struct wimlib_unix_data *unix_data,
+ u16 *stream_idx_ret)
+{
+ const struct wim_ads_entry *ads_entry;
+ const struct wim_lookup_table_entry *lte;
+ size_t size;
+ int ret;
+
+ wimlib_assert(inode->i_resolved);
+
+ ads_entry = inode_get_ads_entry((struct wim_inode*)inode,
+ WIMLIB_UNIX_DATA_TAG, NULL);
+ if (!ads_entry)
+ return NO_UNIX_DATA;
+ if (stream_idx_ret)
+ *stream_idx_ret = ads_entry - inode->i_ads_entries;
+
+ lte = ads_entry->lte;
+ if (!lte)
+ return NO_UNIX_DATA;
+
+ size = wim_resource_size(lte);
+ if (size != sizeof(struct wimlib_unix_data))
+ return BAD_UNIX_DATA;
+
+ ret = read_full_wim_resource(lte, (u8*)unix_data, 0);
+ if (ret)
+ return ret;
+
+ if (unix_data->version != 0)
+ return BAD_UNIX_DATA;
+ return 0;
+}
+
+int inode_set_unix_data(struct wim_inode *inode,
+ uid_t uid, gid_t gid, mode_t mode,
+ struct wim_lookup_table *lookup_table,
+ int which)
+{
+ struct wimlib_unix_data unix_data;
+ int ret;
+ bool have_good_unix_data = false;
+ bool have_unix_data = false;
+ u16 stream_idx;
+
+ if (!(which & UNIX_DATA_CREATE)) {
+ ret = inode_get_unix_data(inode, &unix_data, &stream_idx);
+ if (ret == 0 || ret == BAD_UNIX_DATA || ret > 0)
+ have_unix_data = true;
+ if (ret == 0)
+ have_good_unix_data = true;
+ }
+ unix_data.version = 0;
+ if (which & UNIX_DATA_UID || !have_good_unix_data)
+ unix_data.uid = uid;
+ if (which & UNIX_DATA_GID || !have_good_unix_data)
+ unix_data.gid = gid;
+ if (which & UNIX_DATA_MODE || !have_good_unix_data)
+ unix_data.mode = mode;
+ ret = inode_add_ads_with_data(inode, WIMLIB_UNIX_DATA_TAG,
+ (const u8*)&unix_data,
+ sizeof(struct wimlib_unix_data),
+ lookup_table);
+ if (ret == 0 && have_unix_data)
+ inode_remove_ads(inode, stream_idx, lookup_table);
+ return ret;
+}
/*
* Reads the alternate data stream entries of a WIM dentry.
extern struct wim_ads_entry *inode_add_ads(struct wim_inode *dentry,
const char *stream_name);
+extern int inode_add_ads_with_data(struct wim_inode *inode, const char *name,
+ const u8 *value, size_t size,
+ struct wim_lookup_table *lookup_table);
extern void inode_remove_ads(struct wim_inode *inode, u16 idx,
struct wim_lookup_table *lookup_table);
+#define WIMLIB_UNIX_DATA_TAG "$$__wimlib_UNIX_data"
+
+#define WIMLIB_UNIX_DATA_TAG_LEN (sizeof(WIMLIB_UNIX_DATA_TAG) - 1)
+
+/* Format for special alternate data stream entries to store UNIX data for files
+ * and directories (see: WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */
+struct wimlib_unix_data {
+ u16 version; /* Must be 0 */
+ u16 uid;
+ u16 gid;
+ u16 mode;
+} PACKED;
+#define NO_UNIX_DATA (-1)
+#define BAD_UNIX_DATA (-2)
+extern int inode_get_unix_data(const struct wim_inode *inode,
+ struct wimlib_unix_data *unix_data,
+ u16 *stream_idx_ret);
+
+#define UNIX_DATA_UID 0x1
+#define UNIX_DATA_GID 0x2
+#define UNIX_DATA_MODE 0x4
+#define UNIX_DATA_ALL (UNIX_DATA_UID | UNIX_DATA_GID | UNIX_DATA_MODE)
+#define UNIX_DATA_CREATE 0x8
+extern int inode_set_unix_data(struct wim_inode *inode,
+ uid_t uid, gid_t gid, mode_t mode,
+ struct wim_lookup_table *lookup_table,
+ int which);
+
extern int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
u64 offset, struct wim_dentry *dentry);
return 0;
}
+static int symlink_apply_unix_data(const char *link,
+ const struct wimlib_unix_data *unix_data)
+{
+ if (lchown(link, unix_data->uid, unix_data->gid)) {
+ if (errno == EPERM) {
+ /* Ignore */
+ WARNING_WITH_ERRNO("failed to set symlink UNIX owner/group");
+ } else {
+ ERROR_WITH_ERRNO("failed to set symlink UNIX owner/group");
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ }
+ return 0;
+}
+
+static int fd_apply_unix_data(int fd, const struct wimlib_unix_data *unix_data)
+{
+ if (fchown(fd, unix_data->uid, unix_data->gid)) {
+ if (errno == EPERM) {
+ WARNING_WITH_ERRNO("failed to set file UNIX owner/group");
+ /* Ignore? */
+ } else {
+ ERROR_WITH_ERRNO("failed to set file UNIX owner/group");
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ }
+
+ if (fchmod(fd, unix_data->mode)) {
+ if (errno == EPERM) {
+ WARNING_WITH_ERRNO("failed to set UNIX file mode");
+ /* Ignore? */
+ } else {
+ ERROR_WITH_ERRNO("failed to set UNIX file mode");
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ }
+ return 0;
+}
+
+static int dir_apply_unix_data(const char *dir,
+ const struct wimlib_unix_data *unix_data)
+{
+ int dfd = open(dir, O_RDONLY);
+ int ret;
+ if (dfd >= 0) {
+ ret = fd_apply_unix_data(dfd, unix_data);
+ if (close(dfd)) {
+ ERROR_WITH_ERRNO("can't close directory `%s'", dir);
+ ret = WIMLIB_ERR_MKDIR;
+ }
+ } else {
+ ERROR_WITH_ERRNO("can't open directory `%s'", dir);
+ ret = WIMLIB_ERR_MKDIR;
+ }
+ return ret;
+}
+
static int extract_regular_file_unlinked(struct wim_dentry *dentry,
struct apply_args *args,
const char *output_path,
/* Empty file with no lookup table entry */
DEBUG("Empty file `%s'.", output_path);
ret = 0;
- goto out;
+ goto out_extract_unix_data;
}
ret = extract_wim_resource_to_fd(lte, out_fd, wim_resource_size(lte));
ERROR("Failed to extract resource to `%s'", output_path);
goto out;
}
- args->progress.extract.completed_bytes += wim_resource_size(lte);
+
+out_extract_unix_data:
+ if (args->extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
+ struct wimlib_unix_data unix_data;
+ ret = inode_get_unix_data(inode, &unix_data, NULL);
+ if (ret > 0)
+ ;
+ else if (ret < 0)
+ ret = 0;
+ else
+ ret = fd_apply_unix_data(out_fd, &unix_data);
+ if (ret != 0)
+ goto out;
+ }
+ if (lte)
+ args->progress.extract.completed_bytes += wim_resource_size(lte);
out:
if (close(out_fd) != 0) {
ERROR_WITH_ERRNO("Failed to close file `%s'", output_path);
- ret = WIMLIB_ERR_WRITE;
+ if (ret == 0)
+ ret = WIMLIB_ERR_WRITE;
}
return ret;
}
return WIMLIB_ERR_LINK;
}
lte = inode_unnamed_lte_resolved(dentry->d_inode);
+ wimlib_assert(lte != NULL);
+ if (args->extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
+ struct wimlib_unix_data unix_data;
+ ret = inode_get_unix_data(dentry->d_inode, &unix_data, NULL);
+ if (ret > 0)
+ ;
+ else if (ret < 0)
+ ret = 0;
+ else
+ ret = symlink_apply_unix_data(output_path, &unix_data);
+ if (ret != 0)
+ return ret;
+ }
args->progress.extract.completed_bytes += wim_resource_size(lte);
return 0;
}
-static int extract_directory(const char *output_path, bool is_root)
+static int extract_directory(struct wim_dentry *dentry,
+ const char *output_path, bool is_root)
{
int ret;
struct stat stbuf;
+
ret = stat(output_path, &stbuf);
if (ret == 0) {
if (S_ISDIR(stbuf.st_mode)) {
/*if (!is_root)*/
/*WARNING("`%s' already exists", output_path);*/
- return 0;
+ goto dir_exists;
} else {
ERROR("`%s' is not a directory", output_path);
return WIMLIB_ERR_MKDIR;
output_path);
return WIMLIB_ERR_MKDIR;
}
- return 0;
+dir_exists:
+ if (dentry) {
+ struct wimlib_unix_data unix_data;
+ ret = inode_get_unix_data(dentry->d_inode, &unix_data, NULL);
+ if (ret > 0)
+ ;
+ else if (ret < 0)
+ ret = 0;
+ else
+ ret = dir_apply_unix_data(output_path, &unix_data);
+ } else {
+ ret = 0;
+ }
+ return ret;
}
/* Extracts a file, directory, or symbolic link from the WIM archive. */
if (inode_is_symlink(inode))
return extract_symlink(dentry, args, output_path);
else if (inode_is_directory(inode))
- return extract_directory(output_path, false);
+ return extract_directory((args->extract_flags &
+ WIMLIB_EXTRACT_FLAG_UNIX_DATA) ? dentry : NULL,
+ output_path, false);
else
return extract_regular_file(dentry, args, output_path);
}
int image;
const char *image_name;
- ret = extract_directory(target, true);
+ ret = extract_directory(NULL, target, true);
if (ret != 0)
return ret;
"directly to a NTFS volume");
return WIMLIB_ERR_INVALID_PARAM;
}
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
+ ERROR("Cannot restore UNIX-specific data in the NTFS extraction mode");
+ return WIMLIB_ERR_INVALID_PARAM;
+ }
#else
ERROR("wimlib was compiled without support for NTFS-3g, so");
ERROR("we cannot apply a WIM image directly to a NTFS volume");
char *daemon_to_unmount_mq_name;
mqd_t unmount_to_daemon_mq;
mqd_t daemon_to_unmount_mq;
+
+ uid_t default_uid;
+ gid_t default_gid;
};
static void init_wimfs_context(struct wimfs_context *ctx)
INIT_LIST_HEAD(&ctx->staging_list);
}
+#define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
+
static inline struct wimfs_context *wimfs_get_context()
{
- return (struct wimfs_context*)fuse_get_context()->private_data;
+ return WIMFS_CTX(fuse_get_context());
}
static inline WIMStruct *wimfs_get_WIMStruct()
/*
* Add a new dentry with a new inode to a WIM image.
*
- * @ctx: Context for the mounted WIM image.
- * @path: Path to create the dentry at.
- * @dentry_ret: Return the pointer to the dentry if successful.
- *
* Returns 0 on success, or negative error number on failure.
*/
-static int create_dentry(struct wimfs_context *ctx, const char *path,
+static int create_dentry(struct fuse_context *fuse_ctx,const char *path,
+ mode_t mode, int attributes,
struct wim_dentry **dentry_ret)
{
struct wim_dentry *parent;
struct wim_dentry *new;
const char *basename;
+ struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
- parent = get_parent_dentry(ctx->wim, path);
+ parent = get_parent_dentry(wimfs_ctx->wim, path);
if (!parent)
return -errno;
return -errno;
new->d_inode->i_resolved = 1;
- new->d_inode->i_ino = ctx->next_ino++;
+ new->d_inode->i_ino = wimfs_ctx->next_ino++;
+ new->d_inode->i_attributes = attributes;
+
+ if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
+ if (inode_set_unix_data(new->d_inode,
+ fuse_ctx->uid,
+ fuse_ctx->gid,
+ mode & ~fuse_ctx->umask,
+ wimfs_ctx->wim->lookup_table,
+ UNIX_DATA_ALL | UNIX_DATA_CREATE))
+ {
+ free_dentry(new);
+ return -ENOMEM;
+ }
+ }
dentry_add_child(parent, new);
- hlist_add_head(&new->d_inode->i_hlist, ctx->image_inode_list);
- *dentry_ret = new;
+ hlist_add_head(&new->d_inode->i_hlist, wimfs_ctx->image_inode_list);
+ if (dentry_ret)
+ *dentry_ret = new;
return 0;
}
put_dentry(dentry);
}
+static mode_t inode_default_unix_mode(const struct wim_inode *inode)
+{
+ if (inode_is_symlink(inode))
+ return S_IFLNK | 0777;
+ else if (inode_is_directory(inode))
+ return S_IFDIR | 0777;
+ else
+ return S_IFREG | 0777;
+}
+
/* Transfers file attributes from a struct wim_inode to a `stat' buffer.
*
* The lookup table entry tells us which stream in the inode we are statting.
const struct wim_lookup_table_entry *lte,
struct stat *stbuf)
{
- if (inode_is_symlink(inode))
- stbuf->st_mode = S_IFLNK | 0777;
- else if (inode_is_directory(inode))
- stbuf->st_mode = S_IFDIR | 0755;
- else
- stbuf->st_mode = S_IFREG | 0755;
-
- stbuf->st_ino = (ino_t)inode->i_ino;
+ const struct wimfs_context *ctx = wimfs_get_context();
+
+ memset(stbuf, 0, sizeof(struct stat));
+ stbuf->st_mode = inode_default_unix_mode(inode);
+ stbuf->st_uid = ctx->default_uid;
+ stbuf->st_gid = ctx->default_gid;
+ if (ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) {
+ struct wimlib_unix_data unix_data;
+ if (inode_get_unix_data(inode, &unix_data, NULL) == 0) {
+ stbuf->st_uid = unix_data.uid;
+ stbuf->st_gid = unix_data.gid;
+ stbuf->st_mode = unix_data.mode;
+ }
+ }
+ stbuf->st_ino = (ino_t)inode->i_ino;
stbuf->st_nlink = inode->i_nlink;
- stbuf->st_uid = getuid();
- stbuf->st_gid = getgid();
-
if (lte) {
if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
struct stat native_stat;
stbuf->st_size = 0;
}
- stbuf->st_atime = wim_timestamp_to_unix(inode->i_last_access_time);
- stbuf->st_mtime = wim_timestamp_to_unix(inode->i_last_write_time);
- stbuf->st_ctime = wim_timestamp_to_unix(inode->i_creation_time);
- stbuf->st_blocks = (stbuf->st_size + 511) / 512;
+ stbuf->st_atime = wim_timestamp_to_unix(inode->i_last_access_time);
+ stbuf->st_mtime = wim_timestamp_to_unix(inode->i_last_write_time);
+ stbuf->st_ctime = wim_timestamp_to_unix(inode->i_creation_time);
+ stbuf->st_blocks = (stbuf->st_size + 511) / 512;
return 0;
}
{
int unmount_to_daemon_mq_flags = O_WRONLY | O_CREAT;
int daemon_to_unmount_mq_flags = O_RDONLY | O_CREAT;
+ mode_t mode;
+ mode_t orig_umask;
+ int ret;
- if (daemon)
+ if (daemon) {
swap(unmount_to_daemon_mq_flags, daemon_to_unmount_mq_flags);
+ mode = 0600;
+ } else {
+ mode = 0666;
+ }
+ orig_umask = umask(0000);
DEBUG("Opening message queue \"%s\"", ctx->unmount_to_daemon_mq_name);
ctx->unmount_to_daemon_mq = mq_open(ctx->unmount_to_daemon_mq_name,
- unmount_to_daemon_mq_flags, 0700, NULL);
+ unmount_to_daemon_mq_flags, mode, NULL);
if (ctx->unmount_to_daemon_mq == (mqd_t)-1) {
ERROR_WITH_ERRNO("mq_open()");
- return WIMLIB_ERR_MQUEUE;
+ ret = WIMLIB_ERR_MQUEUE;
+ goto out;
}
DEBUG("Opening message queue \"%s\"", ctx->daemon_to_unmount_mq_name);
ctx->daemon_to_unmount_mq = mq_open(ctx->daemon_to_unmount_mq_name,
- daemon_to_unmount_mq_flags, 0700, NULL);
+ daemon_to_unmount_mq_flags, mode, NULL);
if (ctx->daemon_to_unmount_mq == (mqd_t)-1) {
ERROR_WITH_ERRNO("mq_open()");
mq_close(ctx->unmount_to_daemon_mq);
mq_unlink(ctx->unmount_to_daemon_mq_name);
ctx->unmount_to_daemon_mq = (mqd_t)-1;
- return WIMLIB_ERR_MQUEUE;
+ ret = WIMLIB_ERR_MQUEUE;
+ goto out;
}
- return 0;
+ ret = 0;
+out:
+ umask(orig_umask);
+ return ret;
}
/* Try to determine the maximum message size of a message queue. The return
return 0;
}
+#if 0
static int wimfs_access(const char *path, int mask)
{
- /* Permissions not implemented */
- return 0;
+ return -ENOSYS;
}
+#endif
static int wimfs_chmod(const char *path, mode_t mask)
{
struct wim_dentry *dentry;
struct wimfs_context *ctx = wimfs_get_context();
- struct wim_inode *inode;
- struct stat stbuf;
int ret;
- ret = lookup_resource(ctx->wim, path,
- get_lookup_flags(ctx) | LOOKUP_FLAG_DIRECTORY_OK,
+ if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
+ return -EPERM;
+
+ ret = lookup_resource(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
&dentry, NULL, NULL);
- if (ret != 0)
+ if (ret)
return ret;
- inode = dentry->d_inode;
- inode_to_stbuf(inode, NULL, &stbuf);
- if (mask == stbuf.st_mode)
- return 0;
- else
+
+ ret = inode_set_unix_data(dentry->d_inode, ctx->default_uid,
+ ctx->default_gid, mask,
+ ctx->wim->lookup_table, UNIX_DATA_MODE);
+ return ret ? -ENOMEM : 0;
+}
+
+static int wimfs_chown(const char *path, uid_t uid, gid_t gid)
+{
+ struct wim_dentry *dentry;
+ struct wimfs_context *ctx = wimfs_get_context();
+ int ret;
+
+ if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
return -EPERM;
+
+ ret = lookup_resource(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
+ &dentry, NULL, NULL);
+ if (ret)
+ return ret;
+
+ ret = inode_set_unix_data(dentry->d_inode, uid, gid,
+ inode_default_unix_mode(dentry->d_inode),
+ ctx->wim->lookup_table,
+ UNIX_DATA_UID | UNIX_DATA_GID);
+ return ret ? -ENOMEM : 0;
}
/* Called when the filesystem is unmounted. */
#endif
-/* Create a directory in the WIM.
- * @mode is currently ignored. */
+/* Create a directory in the WIM image. */
static int wimfs_mkdir(const char *path, mode_t mode)
{
- struct wim_dentry *dentry;
- int ret;
-
- ret = create_dentry(wimfs_get_context(), path, &dentry);
- if (ret == 0)
- dentry->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY;
- return ret;
+ return create_dentry(fuse_get_context(), path, mode | S_IFDIR,
+ FILE_ATTRIBUTE_DIRECTORY, NULL);
}
-/* Create a regular file in the WIM.
- * @mode is currently ignored. */
+/* Create a regular file or alternate data stream in the WIM image. */
static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
{
const char *stream_name;
- struct wimfs_context *ctx = wimfs_get_context();
- if ((ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
+ struct fuse_context *fuse_ctx = fuse_get_context();
+ struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
+
+ if (!S_ISREG(mode))
+ return -EPERM;
+
+ if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
&& (stream_name = path_stream_name(path))) {
/* Make an alternate data stream */
struct wim_ads_entry *new_entry;
wimlib_assert(*p == ':');
*p = '\0';
- inode = wim_pathname_to_inode(ctx->wim, path);
+ inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
if (!inode)
return -errno;
if (inode->i_attributes &
return -ENOMEM;
return 0;
} else {
- struct wim_dentry *dentry;
- int ret;
-
/* Make a normal file (not an alternate data stream) */
- ret = create_dentry(ctx, path, &dentry);
- if (ret == 0)
- dentry->d_inode->i_attributes = FILE_ATTRIBUTE_NORMAL;
- return ret;
+ return create_dentry(fuse_ctx, path, mode | S_IFREG,
+ FILE_ATTRIBUTE_NORMAL, NULL);
}
}
/* Remove a directory */
static int wimfs_rmdir(const char *path)
{
- struct wim_dentry *parent, *dentry;
+ struct wim_dentry *dentry;
WIMStruct *w = wimfs_get_WIMStruct();
dentry = get_dentry(w, path);
const char *value, size_t size, int flags)
{
struct wim_ads_entry *existing_ads_entry;
- struct wim_ads_entry *new_ads_entry;
- struct wim_lookup_table_entry *existing_lte;
- struct wim_lookup_table_entry *lte;
struct wim_inode *inode;
- u8 value_hash[SHA1_HASH_SIZE];
u16 ads_idx;
struct wimfs_context *ctx = wimfs_get_context();
+ int ret;
if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
return -ENOTSUP;
if (flags & XATTR_REPLACE)
return -ENOATTR;
}
- new_ads_entry = inode_add_ads(inode, name);
- if (!new_ads_entry)
- return -ENOMEM;
-
- sha1_buffer((const u8*)value, size, value_hash);
- existing_lte = __lookup_resource(ctx->wim->lookup_table, value_hash);
-
- if (existing_lte) {
- lte = existing_lte;
- lte->refcnt++;
- } else {
- u8 *value_copy;
- lte = new_lookup_table_entry();
- if (!lte)
- return -ENOMEM;
- value_copy = MALLOC(size);
- if (!value_copy) {
- FREE(lte);
- return -ENOMEM;
- }
- memcpy(value_copy, value, size);
- lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER;
- lte->attached_buffer = value_copy;
- lte->resource_entry.original_size = size;
- lte->resource_entry.size = size;
- lte->resource_entry.flags = 0;
- copy_hash(lte->hash, value_hash);
- lookup_table_insert(ctx->wim->lookup_table, lte);
- }
- new_ads_entry->lte = lte;
- return 0;
+ ret = inode_add_ads_with_data(inode, name, (const u8*)value,
+ size, ctx->wim->lookup_table);
+ return ret ? -ENOMEM : 0;
}
#endif
static int wimfs_symlink(const char *to, const char *from)
{
- struct wimfs_context *ctx = wimfs_get_context();
+ struct fuse_context *fuse_ctx = fuse_get_context();
+ struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
struct wim_dentry *dentry;
int ret;
- ret = create_dentry(ctx, from, &dentry);
+ ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777,
+ FILE_ATTRIBUTE_REPARSE_POINT, &dentry);
if (ret == 0) {
- dentry->d_inode->i_attributes = FILE_ATTRIBUTE_REPARSE_POINT;
dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK;
if (inode_set_symlink(dentry->d_inode, to,
- ctx->wim->lookup_table, NULL))
+ wimfs_ctx->wim->lookup_table, NULL))
{
- unlink_dentry(dentry);
- free_dentry(dentry);
+ remove_dentry(dentry, wimfs_ctx->wim->lookup_table);
ret = -ENOMEM;
}
}
}
static struct fuse_operations wimfs_operations = {
+#if 0
.access = wimfs_access,
+#endif
.chmod = wimfs_chmod,
+ .chown = wimfs_chown,
.destroy = wimfs_destroy,
#if 0
.fallocate = wimfs_fallocate,
ctx.wim = wim;
ctx.mount_flags = mount_flags;
ctx.image_inode_list = &imd->inode_list;
-
+ ctx.default_uid = getuid();
+ ctx.default_gid = getgid();
if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
#if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8)
",hard_remove"
#endif
+ ",default_permissions"
;
argv[argc++] = "-o";
argv[argc++] = optstring;
/* Read-only mount */
strcat(optstring, ",ro");
}
+ if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER)
+ strcat(optstring, ",allow_other");
argv[argc] = NULL;
#ifdef ENABLE_DEBUG
unsigned stream_idx = 0;
ntfschar *stream_name = AT_UNNAMED;
u32 stream_name_len = 0;
+ const char *stream_name_utf8;
const struct wim_inode *inode = dentry->d_inode;
struct wim_lookup_table_entry *lte;
lte = inode->i_lte;
while (1) {
if (stream_name_len) {
+
+ /* Skip special UNIX data entries (see documentation for
+ * WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */
+ if (stream_name_len == WIMLIB_UNIX_DATA_TAG_LEN
+ && !memcmp(stream_name_utf8,
+ WIMLIB_UNIX_DATA_TAG,
+ WIMLIB_UNIX_DATA_TAG_LEN))
+ goto cont;
+
/* Create an empty named stream. */
ret = ntfs_attr_add(ni, AT_DATA, stream_name,
stream_name_len, NULL, 0);
* have been extracted. */
progress_info->extract.completed_bytes += wim_resource_size(lte);
}
+ cont:
if (stream_idx == inode->i_num_ads) /* Has the last stream been extracted? */
break;
/* Get the name and lookup table entry for the next stream. */
stream_name = (ntfschar*)inode->i_ads_entries[stream_idx].stream_name;
+ stream_name_utf8 = inode->i_ads_entries[stream_idx].stream_name_utf8;
stream_name_len = inode->i_ads_entries[stream_idx].stream_name_len / 2;
lte = inode->i_ads_entries[stream_idx].lte;
stream_idx++;
/* Check that lookup table entries for all the inode's stream exist,
* except if the SHA1 message digest is all 0's, which indicates an
- * empty stream.
+ * empty stream.
*
* This check is skipped on split WIMs. */
if (w->hdr.total_parts == 1) {
* message being printed.
*
* wimlib is thread-safe as long as different ::WIMStruct's are used, except for
- * the fact that wimlib_set_print_errors() and wimlib_set_memory_allocator()
- * both apply globally, and you also must call wimlib_global_init() in the main
- * thread to avoid any race conditions with one-time allocations of memory.
+ * the following exceptions:
+ * - wimlib_set_print_errors() and wimlib_set_memory_allocator() both apply globally.
+ * - You also must call wimlib_global_init() in the main thread to avoid any
+ * race conditions with one-time allocations of memory.
+ * - wimlib_mount_image(), while it can be used to mount multiple WIMs
+ * concurrently in the same process, will daemonize the entire process when it
+ * does so for the first time. This includes changing the working directory
+ * to the root directory.
*
* To open an existing WIM, use wimlib_open_wim().
*
#include <stdbool.h>
#include <inttypes.h>
+/** Major version of the library (for example, the 1 in 1.2.5). */
#define WIMLIB_MAJOR_VERSION 1
+
+/** Minor version of the library (for example, the 2 in 1.2.5). */
#define WIMLIB_MINOR_VERSION 2
+
+/** Patch version of the library (for example, the 5 in 1.2.5). */
#define WIMLIB_PATCH_VERSION 5
/**
* WIMLIB_ADD_IMAGE_FLAG_* *
*****************************/
-/** Directly capture a NTFS volume rather than a generic directory */
+/** Directly capture a NTFS volume rather than a generic directory. This flag
+ * cannot be combined with ::WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE or
+ * ::WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA. */
#define WIMLIB_ADD_IMAGE_FLAG_NTFS 0x00000001
/** Follow symlinks; archive and dump the files they point to. Cannot be used
/** Mark the image being added as the bootable image of the WIM. */
#define WIMLIB_ADD_IMAGE_FLAG_BOOT 0x00000008
+/** Store the UNIX owner, group, and mode. This is done by adding a special
+ * alternate data stream to each regular file, symbolic link, and directory to
+ * contain this information. Please note that this flag is for convenience
+ * only; Microsoft's version of imagex.exe will not understand this special
+ * information. This flag cannot be combined with ::WIMLIB_ADD_IMAGE_FLAG_NTFS.
+ * */
+#define WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA 0x00000010
+
/******************************
* WIMLIB_EXPORT_FLAG_* *
******************************/
/** Read the WIM file sequentially while extracting the image. */
#define WIMLIB_EXTRACT_FLAG_SEQUENTIAL 0x00000010
+/** Extract special UNIX data captured with ::WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA.
+ * Cannot be used with ::WIMLIB_EXTRACT_FLAG_NTFS. */
+#define WIMLIB_EXTRACT_FLAG_UNIX_DATA 0x00000020
+
/******************************
* WIMLIB_MOUNT_FLAG_* *
******************************/
* file name, a colon, then the alternate file stream name. */
#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS 0x00000010
+/** Use UNIX file owners, groups, and modes if available in the WIM (see
+ * ::WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA). */
+#define WIMLIB_MOUNT_FLAG_UNIX_DATA 0x00000020
+
+/** Allow other users to see the mounted filesystem. (this passes the @c
+ * allow_other option to FUSE mount) */
+#define WIMLIB_MOUNT_FLAG_ALLOW_OTHER 0x00000040
+
/******************************
* WIMLIB_OPEN_FLAG_* *
******************************/
* invalid.
* @retval ::WIMLIB_ERR_INVALID_PARAM
* @a target was @c NULL, or both ::WIMLIB_EXTRACT_FLAG_HARDLINK and
- * ::WIMLIB_EXTRACT_FLAG_SYMLINK were specified in @a extract_flags, or
+ * ::WIMLIB_EXTRACT_FLAG_SYMLINK were specified in @a extract_flags; or
* both ::WIMLIB_EXTRACT_FLAG_NTFS and either
* ::WIMLIB_EXTRACT_FLAG_HARDLINK or ::WIMLIB_EXTRACT_FLAG_SYMLINK were
- * specified in @a extract_flags, or ::WIMLIB_EXTRACT_FLAG_NTFS was
- * specified in @a extract_flags and @a image was ::WIMLIB_ALL_IMAGES.
+ * specified in @a extract_flags; or ::WIMLIB_EXTRACT_FLAG_NTFS was
+ * specified in @a extract_flags and @a image was ::WIMLIB_ALL_IMAGES; or
+ * both ::WIMLIB_EXTRACT_FLAG_NTFS and ::WIMLIB_EXTRACT_FLAG_UNIX_DATA were
+ * specified in @a extract_flag.
* @retval ::WIMLIB_ERR_INVALID_RESOURCE_HASH
* The SHA1 message digest of an extracted stream did not match the SHA1
* message digest given in the WIM file.
* @retval ::WIMLIB_ERR_NOMEM
* Could not allocate memory.
* @retval ::WIMLIB_ERR_ICONV_NOT_AVAILABLE
- * wimlib was configured --without-libntfs-3g at compilation time, and at
- * runtime the iconv() set of functions did not seem to be available,
+ * wimlib was configured @c --without-libntfs-3g at compilation time, and
+ * at runtime the @c iconv() set of functions did not seem to be available,
* perhaps due to missing files in the C library installation.
*
* If this function is not called or returns nonzero, then it will not be safe
/**
* Mounts an image in a WIM file on a directory read-only or read-write.
*
- * The calling thread will be daemonized to service the filesystem, and this
- * function will not return until the image is unmounted, unless an error occurs
- * before the filesystem is successfully mounted.
+ * Unless ::WIMLIB_MOUNT_FLAG_DEBUG is specified or an early error occurs, the
+ * process shall be daemonized.
*
* If the mount is read-write (::WIMLIB_MOUNT_FLAG_READWRITE specified),
* modifications to the WIM are staged in a temporary directory.
* @retval ::WIMLIB_ERR_INVALID_PARAM
* @a image is shared among multiple ::WIMStruct's as a result of a call to
* wimlib_export_image(), or @a image has been added with
- * wimlib_add_image() or wimlib_add_image_from_ntfs_volume().
+ * wimlib_add_image().
* @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE
* The metadata resource for @a image in @a wim is invalid.
* @retval ::WIMLIB_ERR_INVALID_SECURITY_DATA
* @a image does not specify a single existing image in @a wim, and is not
* ::WIMLIB_ALL_IMAGES.
* @retval ::WIMLIB_ERR_INVALID_RESOURCE_HASH
- * A file that had previously been scanned for inclusion in the WIM by the
- * wimlib_add_image() or wimlib_add_image_from_ntfs_volume() functions was
- * concurrently modified, so it failed the SHA1 message digest check.
+ * A file that had previously been scanned for inclusion in the WIM by
+ * wimlib_add_image() was concurrently modified, so it failed the SHA1
+ * message digest check.
* @retval ::WIMLIB_ERR_INVALID_PARAM
* @a path was @c NULL.
* @retval ::WIMLIB_ERR_INVALID_RESOURCE_SIZE
tar cf ../test.tar .
cd ..
- if ! imagex mountrw test.wim tmp.mnt; then
+ if ! imagex mountrw test.wim tmp.mnt --unix-data; then
error "Failed to mount WIM read-write"
fi
cd tmp.mnt
- if ! tar xf ../test.tar --no-same-owner; then
+ if ! tar xf ../test.tar; then
error "Failed to untar archive on read-write mounted WIM"
fi
cd ..
fi
cd tmp.mnt
- if ! tar xf ../test.tar --no-same-owner; then
+ if ! tar xf ../test.tar; then
error "Failed to untar archive on read-write mounted WIM"
fi
cd ..