]> wimlib.net Git - wimlib/commitdiff
Support for UNIX-specific data
authorEric Biggers <ebiggers3@gmail.com>
Tue, 5 Mar 2013 20:22:04 +0000 (14:22 -0600)
committerEric Biggers <ebiggers3@gmail.com>
Tue, 5 Mar 2013 20:22:04 +0000 (14:22 -0600)
14 files changed:
doc/imagex-apply.1.in
doc/imagex-capture.1.in
doc/imagex-export.1.in
doc/imagex-mount.1.in
programs/imagex.c
src/add_image.c
src/dentry.c
src/dentry.h
src/extract_image.c
src/mount_image.c
src/ntfs-apply.c
src/verify.c
src/wimlib.h
tests/test-imagex-mount

index 7621ef73f7294ef5335e6730d7a9387c548c285b..5d83d857543ec18be3926a4c453f6195cd331372 100644 (file)
@@ -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
 
index b664cdee728ee70b7878039980ba20a3330034a4..bf47b8347159fa14b37b5c2e7fbd21f6d0a410d5 100644 (file)
@@ -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
index 191a41c7812b36bc38a346e7be0fe867e8fa26d2..52729a55affe0fbd1d8a2a7ec744a824ef8d7e69 100644 (file)
@@ -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
index 82078d50e5d3eddfad8b3abcb3f89ddcdd1bdd15..5a9928e6e515bef66e8a4933bb64da0ac9fe8ea2 100644 (file)
@@ -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
 
index 2a55a4e84be3db640831f7cc0be4c39d2c41cdef..e7ebc2eb33e54b80ae54c237a25cde213daacf88 100644 (file)
@@ -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;
                }
index 62fbdfb3141bc2647696117fcb26ada96efb4a69..3e604e3afc6a2d08c52b68ce5a31987a622195f2 100644 (file)
@@ -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
index 35a89d11e06238f98a8c5e68584dc0c291091062..d7a684dcd7f4d98fb48beec2047dc78556352ff2 100644 (file)
@@ -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.
index 99de40af7224b7324a4335f0457dd44f86a6e85d..5517c92ebf59ecc26dfa7051cf6684a42c67e1bb 100644 (file)
@@ -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);
 
index c2021563d11289edcc04ba8eb5ddaf54757e9b4c..96c929453f152fcd09c763e31016c626b4a7a578 100644 (file)
@@ -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");
index af39246128e2fdffa04fe256c49bb6f507abbd03..b9b63450868866832b3a24b5f10254c7057f12b4 100644 (file)
@@ -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
index fcf141f5b89e3cfdea469aa70cdda66ecd9d2689..fc71b9b5aa2055c80eb92a9a155edb63849f8c86 100644 (file)
@@ -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++;
index 777a6e0c7f06ff6f9165391e8d4d66985a0320ef..bfb3577b9db1e0ce0b0a934c3bc897187fb365fb 100644 (file)
@@ -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) {
index 55289fe91dda2e2073f31403e306b7e9b91f9552..294ea19734fcfc6123574ed2cc1853e13a806194 100644 (file)
  * 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
 
 /**
@@ -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
index 6e04673a71823822e5d2e2533ee7713a4f6a8beb..088e08b544bff64285a45d09cce418403f691738 100755 (executable)
@@ -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 ..