From: Eric Biggers Date: Tue, 5 Mar 2013 20:22:04 +0000 (-0600) Subject: Support for UNIX-specific data X-Git-Tag: v1.2.6~11 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=4016a9dba036f4d2eca0253c99370e6647a9ccb6 Support for UNIX-specific data --- diff --git a/doc/imagex-apply.1.in b/doc/imagex-apply.1.in index 7621ef73..5d83d857 100644 --- a/doc/imagex-apply.1.in +++ b/doc/imagex-apply.1.in @@ -56,7 +56,8 @@ In the normal mode of extraction, the following information will \fInot\fR be 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] @@ -79,7 +80,7 @@ empty for the intended use cases. A new NTFS filesystem can be created using 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 @@ -171,7 +172,7 @@ included in the glob (but the first part MUST be specified as \fIWIMFILE\fR as well). Here's an example. The names for the split WIMs usually go something like: - + .RS .PP .nf @@ -214,6 +215,14 @@ extracted, and some additional informational messages. \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 diff --git a/doc/imagex-capture.1.in b/doc/imagex-capture.1.in index b664cdee..bf47b834 100644 --- a/doc/imagex-capture.1.in +++ b/doc/imagex-capture.1.in @@ -56,7 +56,9 @@ information from the directory tree: .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 @@ -187,6 +189,14 @@ used: .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. @@ -229,8 +239,8 @@ imagex capture somedir mywim.wim --compress=maximum --check 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 diff --git a/doc/imagex-export.1.in b/doc/imagex-export.1.in index 191a41c7..52729a55 100644 --- a/doc/imagex-export.1.in +++ b/doc/imagex-export.1.in @@ -92,7 +92,7 @@ included in the glob (but the first part MUST be specified as \fISRC_WIMFILE\fR well). Here's an example. The names for the split WIMs usually go something like: - + .RS .PP .nf @@ -113,12 +113,12 @@ imagex export mywim.swm 1 other.wim --ref="mywim*.swm" .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 diff --git a/doc/imagex-mount.1.in b/doc/imagex-mount.1.in index 82078d50..5a9928e6 100644 --- a/doc/imagex-mount.1.in +++ b/doc/imagex-mount.1.in @@ -3,11 +3,9 @@ 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] @@ -43,7 +41,7 @@ included in the glob (but the first part MUST be specified as \fIWIMFILE\fR as well). Here's an example. The names for the split WIMs usually go something like: - + .RS .PP .nf @@ -63,7 +61,7 @@ imagex mount mywim.swm 1 dir --ref="mywim*.swm" .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 @@ -124,6 +122,24 @@ mountrw\fR. See \fBSPLIT_WIMS\fR. \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 @@ -134,15 +150,15 @@ mount is read-only. .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 diff --git a/programs/imagex.c b/programs/imagex.c index 2a55a4e8..e7ebc2eb 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -67,16 +67,16 @@ static const char *usage_strings[] = { "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] = @@ -95,11 +95,11 @@ static const char *usage_strings[] = { [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] = @@ -115,11 +115,12 @@ static const struct option common_options[] = { }; 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[] = { @@ -132,6 +133,7 @@ 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[] = { @@ -172,6 +174,8 @@ static const struct option mount_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}, }; @@ -575,6 +579,9 @@ static int imagex_apply(int argc, const char **argv) case 'r': swm_glob = optarg; break; + case 'U': + extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA; + break; default: usage(APPLY); return -1; @@ -707,6 +714,9 @@ static int imagex_capture_or_append(int argc, const char **argv) 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; @@ -1418,6 +1428,9 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) 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; @@ -1442,6 +1455,9 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv) case 'D': staging_dir = optarg; break; + case 'U': + mount_flags |= WIMLIB_MOUNT_FLAG_UNIX_DATA; + break; default: goto mount_usage; } diff --git a/src/add_image.c b/src/add_image.c index 62fbdfb3..3e604e3a 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -230,10 +230,17 @@ static int build_dentry_tree(struct wim_dentry **root_ret, 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; @@ -635,10 +642,15 @@ WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source, 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 diff --git a/src/dentry.c b/src/dentry.c index 35a89d11..d7a684dc 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -1022,7 +1022,6 @@ bool dentry_add_child(struct wim_dentry * restrict parent, return true; } -#ifdef WITH_FUSE /* Unlink a WIM dentry from the directory entry tree. */ void unlink_dentry(struct wim_dentry *dentry) { @@ -1031,10 +1030,8 @@ 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. */ @@ -1057,9 +1054,7 @@ struct wim_ads_entry *inode_get_ads_entry(struct wim_inode *inode, } 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. @@ -1094,9 +1089,55 @@ struct wim_ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_ 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) @@ -1122,9 +1163,76 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx, (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. diff --git a/src/dentry.h b/src/dentry.h index 99de40af..5517c92e 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -396,10 +396,41 @@ extern struct wim_ads_entry *inode_get_ads_entry(struct wim_inode *inode, 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); diff --git a/src/extract_image.c b/src/extract_image.c index c2021563..96c92945 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -114,6 +114,63 @@ static int extract_regular_file_linked(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, @@ -171,7 +228,7 @@ static int extract_regular_file_unlinked(struct wim_dentry *dentry, /* 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)); @@ -179,11 +236,27 @@ static int extract_regular_file_unlinked(struct wim_dentry *dentry, 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; } @@ -232,20 +305,35 @@ static int extract_symlink(struct wim_dentry *dentry, 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; @@ -262,7 +350,20 @@ static int extract_directory(const char *output_path, bool is_root) 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. */ @@ -281,7 +382,9 @@ static int apply_dentry_normal(struct wim_dentry *dentry, void *arg) 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); } @@ -702,7 +805,7 @@ static int extract_all_images(WIMStruct *w, const char *target, int image; const char *image_name; - ret = extract_directory(target, true); + ret = extract_directory(NULL, target, true); if (ret != 0) return ret; @@ -758,6 +861,10 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, "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"); diff --git a/src/mount_image.c b/src/mount_image.c index af392461..b9b63450 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -106,6 +106,9 @@ struct wimfs_context { 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) @@ -116,9 +119,11 @@ 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() @@ -280,20 +285,18 @@ static int close_wimfs_fd(struct wimfs_fd *fd) /* * 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; @@ -309,10 +312,25 @@ static int create_dentry(struct wimfs_context *ctx, const char *path, 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; } @@ -344,6 +362,16 @@ static void remove_dentry(struct wim_dentry *dentry, 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. @@ -353,18 +381,22 @@ static int inode_to_stbuf(const struct wim_inode *inode, 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; @@ -381,10 +413,10 @@ static int inode_to_stbuf(const struct wim_inode *inode, 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; } @@ -896,31 +928,44 @@ static int open_message_queues(struct wimfs_context *ctx, bool daemon) { 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 @@ -1458,31 +1503,52 @@ static int execute_fusermount(const char *dir) 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. */ @@ -1679,26 +1745,24 @@ static int wimfs_listxattr(const char *path, char *list, size_t size) #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; @@ -1708,7 +1772,7 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) 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 & @@ -1721,14 +1785,9 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) 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); } } @@ -2010,7 +2069,7 @@ static int wimfs_rename(const char *from, const char *to) /* 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); @@ -2033,13 +2092,10 @@ static int wimfs_setxattr(const char *path, const char *name, 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; @@ -2061,56 +2117,28 @@ static int wimfs_setxattr(const char *path, const char *name, 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; } } @@ -2263,8 +2291,11 @@ static int wimfs_write(const char *path, const char *buf, size_t size, } 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, @@ -2409,7 +2440,8 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, 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; @@ -2446,6 +2478,7 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, #if FUSE_MAJOR_VERSION > 2 || (FUSE_MAJOR_VERSION == 2 && FUSE_MINOR_VERSION >= 8) ",hard_remove" #endif + ",default_permissions" ; argv[argc++] = "-o"; argv[argc++] = optstring; @@ -2458,6 +2491,8 @@ WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, /* Read-only mount */ strcat(optstring, ",ro"); } + if (mount_flags & WIMLIB_MOUNT_FLAG_ALLOW_OTHER) + strcat(optstring, ",allow_other"); argv[argc] = NULL; #ifdef ENABLE_DEBUG diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index fcf141f5..fc71b9b5 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -88,6 +88,7 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent 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; @@ -99,6 +100,15 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent 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); @@ -148,11 +158,13 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent * 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++; diff --git a/src/verify.c b/src/verify.c index 777a6e0c..bfb3577b 100644 --- a/src/verify.c +++ b/src/verify.c @@ -57,7 +57,7 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w) /* 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) { diff --git a/src/wimlib.h b/src/wimlib.h index 55289fe9..294ea197 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -117,9 +117,14 @@ * 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(). * @@ -216,8 +221,13 @@ #include #include +/** 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 /** @@ -547,7 +557,9 @@ typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type, * 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 @@ -562,6 +574,14 @@ typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type, /** 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_* * ******************************/ @@ -594,6 +614,10 @@ typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type, /** 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_* * ******************************/ @@ -615,6 +639,14 @@ typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type, * 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_* * ******************************/ @@ -1090,11 +1122,13 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image, * 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. @@ -1293,8 +1327,8 @@ extern int wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret); * @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 @@ -1385,9 +1419,8 @@ extern int wimlib_join(const char **swms, unsigned num_swms, /** * 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. @@ -1457,7 +1490,7 @@ extern int wimlib_join(const char **swms, unsigned num_swms, * @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 @@ -2077,9 +2110,9 @@ extern int wimlib_unmount_image(const char *dir, int unmount_flags, * @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 diff --git a/tests/test-imagex-mount b/tests/test-imagex-mount index 6e04673a..088e08b5 100755 --- a/tests/test-imagex-mount +++ b/tests/test-imagex-mount @@ -209,12 +209,12 @@ do_test() { 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 .. @@ -229,7 +229,7 @@ do_test() { 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 ..