Some preparations for supporting NTFS capture and apply.
authorEric Biggers <ebiggers3@gmail.com>
Sat, 18 Aug 2012 00:46:24 +0000 (19:46 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 18 Aug 2012 00:55:30 +0000 (19:55 -0500)
- Restore support for reading and writing alternate data streams (this was in
  early versions of wimlib but had been removed for not actually being used...)
- Remove the --disable-security-data option.  I don't think anyone would really
  want this; instead we just copy the existing security data by default.  New
  files will be created without security data except when capturing from NTFS
  (not yet implemented).
- Read and write the reparse tag field.
- Remove --verify, --config, --norpfix from imagex commands.  I'm still not
  planning to do anything with these, so remove them to simplify the commands.
  Who knows, maybe I'll add these back later though...
- wimlib_set_link_type(), wimlib_set_verbose(), wimlib_set_output_dir() removed.
  You now pass flags or the output directory to the relevant functions such as
  wimlib_extract_image().
- --enable-ntfs-3g configure option
- --ntfs options on `imagex capture' and `imagex apply' (Actual operations not
  yet implemented!)

24 files changed:
config.h.in
configure.ac
doc/imagex-append.1.in
doc/imagex-apply.1.in
doc/imagex-capture.1.in
doc/imagex-mount.1.in
doc/imagex-mountrw.1.in
programs/imagex.c
src/dentry.c
src/dentry.h
src/extract.c
src/header.c
src/integrity.c
src/lookup_table.c
src/modify.c
src/mount.c
src/resource.c
src/security.c
src/split.c
src/util.c
src/wim.c
src/wimlib.h
src/wimlib_internal.h
tests/test-imagex

index 148c577..da29bd0 100644 (file)
@@ -18,9 +18,6 @@
 /* Define to 1 if including even more debug messages. */
 #undef ENABLE_MORE_DEBUG
 
-/* Define to 1 to enable support for copying security data */
-#undef ENABLE_SECURITY_DATA
-
 /* Define to 1 if using vectorized implementation of SHA1 */
 #undef ENABLE_SSSE3_SHA1
 
 /* Define to 1 if using libcrypto SHA1 */
 #undef WITH_LIBCRYPTO
 
+/* Define to 1 to enable support for NTFS-specific information */
+#undef WITH_NTFS_3G
+
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
    significant byte first (like Motorola and SPARC, unlike Intel). */
 #if defined AC_APPLE_UNIVERSAL_BUILD
index 1efb42b..d79f130 100644 (file)
@@ -131,18 +131,19 @@ if test "x$ENABLE_VERIFY_COMPRESSION" = "xyes"; then
                   compressed data])
 fi
 
-AC_MSG_CHECKING([whether to include support for copying security data])
-AC_ARG_ENABLE([security_data],
-             AS_HELP_STRING([--disable-security-data], [disable
-                               the ability to retain the security data of
-                               existing WIMs]),
-       [ENABLE_SECURITY_DATA=$enableval],
-       [ENABLE_SECURITY_DATA=yes]
+AC_MSG_CHECKING([whether to include support for ntfs-3g])
+AC_ARG_WITH([ntfs-3g],
+             AS_HELP_STRING([--without-ntfs-3g], [build without NTFS-3g.
+                             This will disable the ability to use NTFS-specific
+                             information when capturing or applying WIMs to a
+                             NTFS filesystem.])
+       [WITH_NTFS_3G=$enableval],
+       [WITH_NTFS_3G=yes]
        )
-AC_MSG_RESULT([$ENABLE_SECURITY_DATA])
-if test "x$ENABLE_SECURITY_DATA" = "xyes"; then
-       AC_DEFINE([ENABLE_SECURITY_DATA], [1], [Define to 1 to enable support
-                  for copying security data])
+AC_MSG_RESULT([$WITH_NTFS_3G])
+if test "x$WITH_NTFS_3G" = "xyes"; then
+       AC_DEFINE([WITH_NTFS_3G], [1], [Define to 1 to enable support for
+                  NTFS-specific information])
 fi
 
 AC_MSG_CHECKING([whether to include support for mounting WIMs])
index d5fa11e..027959f 100644 (file)
@@ -28,14 +28,8 @@ present; additionally, when writing \fIWIMFILE\fR with the new image added,
 write an integrity table.  If this option is not specified, no integrity table
 is included in the new WIM file, even if there was one before.
 .TP
-\fB--config\fR \fICONFIG_FILE\fR
-This option is currently unsupported.
-.TP
 \fB--flags\fR \fIEDITIONID\fR
 Specify a string to use in the <FLAGS> element of the XML data for the image.
-.TP
-\fB--verify\fR
-This option is currently unsupported.
 
 .SH EXAMPLES
 .IP 
index 7e09a94..8012066 100644 (file)
@@ -39,9 +39,6 @@ WIM to save space.
 .TP
 \fB--verbose\fR
 Print the path to of each file or directory within the WIM image as it is extracted.
-.TP
-\fB--verify\fR
-This option is currently unsupported.
 
 .SH EXAMPLES
 .IP 
index 3c51ab7..6e3edd4 100644 (file)
@@ -32,18 +32,9 @@ Specifies the compression type for the WIM file.  \fITYPE\fR may be "none",
 is specified but \fITYPE\fR is not, the compression type is taken to be
 "maximum", which is LZX compression.  "fast" compression is XPRESS compression.
 .TP
-\fB--config\fR \fICONFIG_FILE\fR
-This option is currently unsupported.
-.TP
 \fB--flags\fR \fIEDITIONID\fR
 Specify a string to use in the <FLAGS> element of the XML data for the image.
 .TP
-\fB--norpfix
-This option is currently unsupported.
-.TP
-\fB--verify\fR
-This option is currently unsupported.
-.TP
 \fB--verbose\fR
 Print the names of files and directories as they are captured.
 
index 6d04c7f..2b8122f 100644 (file)
@@ -4,7 +4,7 @@ imagex mount \- Mount an image from a WIM archive readonly
 
 .SH SYNOPSIS
 \fBimagex mount\fR \fIWIMFILE\fR (\fIIMAGE_NUM\fR | \fIIMAGE_NAME\fR)  \
-\fIDIRECTORY\fR [--check]
+\fIDIRECTORY\fR [--check] [--stream-interface=\fIINTERFACE\fR]
 
 .SH DESCRIPTION
 .PP
@@ -19,7 +19,22 @@ It is permissible to omit the \fIIMAGE_NUM\fR or \fIIMAGE_NAME\fR only if
 .TP 6
 \fB--check\fR
 When reading \fIWIMFILE\fR, verify its integrity if the integrity table is
-present.
+present. 
+.TP
+\fB--stream-interface\fR \fIINTERFACE\fR
+Specify the interface to alternate data streams (ADS) in the WIM that will be
+provided by the mounted filesystem.  These are a NTFS feature that found their
+way into the WIM file format.
+
+If "none", it will be impossible to read or write the ADS.
+
+If "xattr" (default), the ADS will be accessible through extended attributes.
+Each ADS will be an extended attribute named "user.*", where the * is the name
+of the ADS.  See \fBsetfattr\fR (1) and \fBgetfattr\fR (1).
+
+If "windows", the ADS will be accessible by specifing the filename, then a
+colon, then the name of the ADS; for example, "myfile:mystream".
+
 .SH SEE ALSO
 .BR imagex (1)
 
index 821897f..0cc8898 100644 (file)
@@ -4,7 +4,7 @@ imagex mountrw \- Mount an image from a WIM archive read-write
 
 .SH SYNOPSIS
 \fBimagex mountrw\fR \fIWIMFILE\fR (\fIIMAGE_NUM\fR | \fIIMAGE_NAME\fR)  \
-\fIDIRECTORY\fR [--check]
+\fIDIRECTORY\fR [--check] [--stream-interface=\fIINTERFACE\fR]
 
 .SH DESCRIPTION
 .PP
@@ -29,6 +29,20 @@ completely written, the old WIM file is overwritten with it.
 \fB--check\fR
 When reading \fIWIMFILE\fR, verify its integrity if the integrity table is
 present. 
+.TP
+\fB--stream-interface\fR \fIINTERFACE\fR
+Specify the interface to alternate data streams (ADS) in the WIM that will be
+provided by the mounted filesystem.  These are a NTFS feature that found their
+way into the WIM file format.
+
+If "none", it will be impossible to read or write the ADS.
+
+If "xattr" (default), the ADS will be accessible through extended attributes.
+Each ADS will be an extended attribute named "user.*", where the * is the name
+of the ADS.  See \fBsetfattr\fR (1) and \fBgetfattr\fR (1).
+
+If "windows", the ADS will be accessible by specifing the filename, then a
+colon, then the name of the ADS; for example, "myfile:mystream".
 
 .SH SEE ALSO
 .BR imagex (1)
index a1b9cea..11becdd 100644 (file)
@@ -75,14 +75,14 @@ static const char *path_basename(const char *path)
 static const char *usage_strings[] = {
 [APPEND] = 
 "    imagex append DIRECTORY WIMFILE [\"IMAGE_NAME\"] [\"DESCRIPTION\"] [--boot]\n"
-"        [--check] [--config CONFIG_FILE] [--flags EDITIONID] [--verify]\n",
+"                  [--check] [--flags EDITIONID]\n",
 [APPLY] = 
 "    imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all] DIRECTORY [--check]\n"
-"        [--verify] [--hardlink] [--symlink] [--verbose]\n",
+"                 [--hardlink] [--symlink] [--verbose]\n",
 [CAPTURE] = 
 "    imagex capture DIRECTORY WIMFILE [\"IMAGE_NAME\"] [\"DESCRIPTION\"]\n"
-"        [--boot] [--check] [--compress[=TYPE]] [--config CONFIG_FILE]\n"
-"        [--flags \"EditionID\"] [--norpfix] [--verify] [--verbose]\n",
+"       l           [--boot] [--check] [--compress[=TYPE]]\n"
+"                   [--flags \"EditionID\"] [--verbose]\n",
 [DELETE] = 
 "    imagex delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check]\n",
 [DIR] = 
@@ -90,19 +90,19 @@ static const char *usage_strings[] = {
 [EXPORT] = 
 "    imagex export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n"
 "        DEST_WIMFILE [\"DEST_IMAGE_NAME\"] [\"DEST_IMAGE_DESCRIPTION\"]\n"
-"        [--boot] [--check] [--compress[=TYPE]]\n",
+"                  [--boot] [--check] [--compress[=TYPE]]\n",
 [INFO] = 
 "    imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n"
-"        [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
-"        [--xml] [--extract-xml FILE] [--metadata]\n",
+"                [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
+"                [--xml] [--extract-xml FILE] [--metadata]\n",
 [JOIN] = 
 "    imagex join [--check] WIMFILE SPLIT_WIM...\n",
 [MOUNT] = 
 "    imagex mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n"
-"        [--check] [--debug]\n",
+"                 [--check] [--debug] [--stream-interface=INTERFACE]\n",
 [MOUNTRW] = 
 "    imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n"
-"        [--check] [--debug]\n",
+"                   [--check] [--debug] [--stream-interface=INTERFACE]\n",
 [SPLIT] = 
 "    imagex split WIMFILE SPLIT_WIMFILE PART_SIZE [--check]\n",
 [UNMOUNT] = 
@@ -118,28 +118,24 @@ static const struct option common_options[] = {
 static const struct option append_options[] = {
        {"boot",   no_argument,       NULL, 'b'},
        {"check",  no_argument,       NULL, 'c'},
-       {"config", required_argument, NULL, 'C'},
        {"flags",    required_argument, NULL, 'f'},
-       {"verify", no_argument,       NULL, 'V'},
        {NULL, 0, NULL, 0},
 };
 static const struct option apply_options[] = {
        {"check",    no_argument,       NULL, 'c'},
-       {"verify",   no_argument,       NULL, 'V'},
        {"hardlink", no_argument,       NULL, 'h'},
        {"symlink",  no_argument,       NULL, 's'},
        {"verbose",  no_argument,       NULL, 'v'},
+       {"ntfs",     no_argument,       NULL, 'N'},
        {NULL, 0, NULL, 0},
 };
 static const struct option capture_options[] = {
        {"boot",     no_argument,       NULL, 'b'},
        {"check",    no_argument,       NULL, 'c'},
        {"compress", optional_argument, NULL, 'x'},
-       {"config",   required_argument, NULL, 'C'},
        {"flags",    required_argument, NULL, 'f'},
-       {"norpfix",  no_argument,       NULL, 'n'},
-       {"verify",   no_argument,       NULL, 'V'},
-       {"verbose",   no_argument,       NULL, 'v'},
+       {"verbose",  no_argument,       NULL,'v'},
+       {"ntfs",     no_argument,       NULL, 'N'},
        {NULL, 0, NULL, 0},
 };
 static const struct option delete_options[] = {
@@ -173,6 +169,7 @@ static const struct option join_options[] = {
 static const struct option mount_options[] = {
        {"check", no_argument, NULL, 'c'},
        {"debug", no_argument, NULL, 'd'},
+       {"stream-interface", required_argument, NULL, 's'},
        {NULL, 0, NULL, 0},
 };
 
@@ -312,15 +309,9 @@ static int imagex_append(int argc, const char **argv)
                        open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
                        write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
                        break;
-               case 'C':
-                       /*config = optarg;*/
-                       break;
                case 'f':
                        flags_element = optarg;
                        break;
-               case 'V':
-                       /* verify */
-                       break;
                default:
                        usage(APPEND);
                        return -1;
@@ -355,9 +346,7 @@ done:
 static int imagex_apply(int argc, const char **argv)
 {
        int c;
-       int link_type = WIM_LINK_TYPE_NONE;
        int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
-       bool verbose = false;
        int image;
        int num_images;
        WIMStruct *w;
@@ -365,23 +354,24 @@ static int imagex_apply(int argc, const char **argv)
        const char *wimfile;
        const char *dir;
        const char *image_num_or_name;
+       int extract_flags = 0;
 
        for_opt(c, apply_options) {
                switch (c) {
                case 'c':
                        open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
                        break;
-               case 'V':
-                       /* verify */
-                       break;
                case 'h':
-                       link_type = WIM_LINK_TYPE_HARD;
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_HARDLINK;
                        break;
                case 's':
-                       link_type = WIM_LINK_TYPE_SYMBOLIC;
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_SYMLINK;
                        break;
                case 'v':
-                       verbose = true;
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
+                       break;
+               case 'N':
+                       extract_flags |= WIMLIB_EXTRACT_FLAG_NTFS;
                        break;
                default:
                        usage(APPLY);
@@ -421,12 +411,7 @@ static int imagex_apply(int argc, const char **argv)
                ret = -1;
                goto done;
        }
-       ret = wimlib_set_output_dir(w, dir);
-       if (ret != 0)
-               goto done;
-       wimlib_set_verbose(w, verbose);
-       wimlib_set_link_type(w, link_type);
-       ret = wimlib_extract_image(w, image);
+       ret = wimlib_extract_image(w, image, dir, extract_flags);
 done:
        wimlib_free(w);
        return ret;
@@ -440,8 +425,7 @@ static int imagex_capture(int argc, const char **argv)
        int add_image_flags = 0;
        int write_flags = WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
        int compression_type = WIM_COMPRESSION_TYPE_NONE;
-       const char *flags_element    = NULL;
-       bool verbose         = false;
+       const char *flags_element = NULL;
        const char *dir;
        const char *wimfile;
        const char *name;
@@ -462,20 +446,14 @@ static int imagex_capture(int argc, const char **argv)
                        if (compression_type == WIM_COMPRESSION_TYPE_INVALID)
                                return -1;
                        break;
-               case 'C':
-                       /*config = optarg;*/
-                       break;
                case 'f':
                        flags_element = optarg;
                        break;
-               case 'n':
-                       /*norpfix = true;*/
-                       break;
                case 'v':
-                       verbose = true;
+                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
                        break;
-               case 'V':
-                       /*verify = true;*/
+               case 'N':
+                       add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NTFS;
                        break;
                default:
                        usage(CAPTURE);
@@ -498,8 +476,6 @@ static int imagex_capture(int argc, const char **argv)
        if (ret != 0)
                return ret;
 
-       wimlib_set_verbose(w, verbose);
-
        ret = wimlib_add_image(w, dir, name, desc, flags_element, 
                               add_image_flags);
        if (ret != 0) {
@@ -1072,19 +1048,26 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv)
                case 'd':
                        mount_flags |= WIMLIB_MOUNT_FLAG_DEBUG;
                        break;
+               case 's':
+                       if (strcasecmp(optarg, "none") == 0)
+                               mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE;
+                       else if (strcasecmp(optarg, "xattr") == 0)
+                               mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
+                       else if (strcasecmp(optarg, "windows") == 0)
+                               mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS;
+                       else {
+                               imagex_error("Unknown stream interface \"%s\"", optarg);
+                               goto mount_usage;
+                       }
+                       break;
                default:
-                       usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)  
-                                       ? MOUNTRW : MOUNT);
-                       return -1;
+                       goto mount_usage;
                }
        }
        argc -= optind;
        argv += optind;
-       if (argc != 2 && argc != 3) {
-               usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)  
-                               ? MOUNTRW : MOUNT);
-               return -1;
-       }
+       if (argc != 2 && argc != 3)
+               goto mount_usage;
 
        wimfile = argv[0];
 
@@ -1122,6 +1105,10 @@ static int imagex_mount_rw_or_ro(int argc, const char **argv)
 done:
        wimlib_free(w);
        return ret;
+mount_usage:
+       usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)  
+                       ? MOUNTRW : MOUNT);
+       return -1;
 }
 
 /* Split a WIM into a spanned set */
@@ -1274,3 +1261,10 @@ int main(int argc, const char **argv)
        usage_all();
        return 1;
 }
+/*#ifndef WITH_NTFS_3G*/
+               /*ERROR("wimlib was not compiled with support for NTFS-3g, so we cannot extract");*/
+               /*ERROR("a WIM to a NTFS filesystem while preserving NTFS-specific metadata.");*/
+               /*ERROR("Please apply the WIM to a directory rather than a block device, ");*/
+               /*ERROR("and without the NTFS flag; or compile in support for NTFS-3g.");*/
+               /*return WIMLIB_ERR_UNSUPPORTED;*/
+/*#endif*/
index 1c93792..d3399ac 100644 (file)
@@ -345,9 +345,7 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
                if (file_attr_flags[i].flag & dentry->attributes)
                        printf("    WIM_FILE_ATTRIBUTE_%s is set\n",
                                file_attr_flags[i].name);
-#ifdef ENABLE_SECURITY_DATA
        printf("Security ID       = %d\n", dentry->security_id);
-#endif
        printf("Subdir offset     = %"PRIu64"\n", dentry->subdir_offset);
        /*printf("Unused1           = %"PRIu64"\n", dentry->unused1);*/
        /*printf("Unused2           = %"PRIu64"\n", dentry->unused2);*/
@@ -358,9 +356,9 @@ int print_dentry(struct dentry *dentry, void *lookup_table)
        printf("Hash              = "); 
        print_hash(dentry->hash); 
        putchar('\n');
-       /*printf("Reparse Tag       = %u\n", dentry->reparse_tag);*/
+       printf("Reparse Tag       = %u\n", dentry->reparse_tag);
        printf("Hard Link Group   = %"PRIu64"\n", dentry->hard_link);
-       /*printf("Number of Streams = %hu\n", dentry->streams);*/
+       printf("Number of Alternate Data Streams = %hu\n", dentry->num_ads);
        printf("Filename          = \"");
        print_string(dentry->file_name, dentry->file_name_len);
        puts("\"");
@@ -388,6 +386,7 @@ static inline void dentry_common_init(struct dentry *dentry)
 {
        memset(dentry, 0, sizeof(struct dentry));
        dentry->refcnt = 1;
+       dentry->security_id = -1;
 }
 
 /* 
@@ -523,8 +522,10 @@ static inline void recalculate_dentry_size(struct dentry *dentry)
 {
        dentry->length = WIM_DENTRY_DISK_SIZE + dentry->file_name_len + 
                         2 + dentry->short_name_len;
+       for (u16 i = 0; i < dentry->num_ads; i++)
+               dentry->length += ads_entry_length(&dentry->ads_entries[i]);
        /* Must be multiple of 8. */
-       dentry->length += (8 - dentry->length % 8) % 8;
+       dentry->length = (dentry->length + 7) & ~7;
 }
 
 /* Changes the name of a dentry to @new_name.  Only changes the file_name and
@@ -609,6 +610,70 @@ void calculate_dir_tree_statistics(struct dentry *root, struct lookup_table *tab
        for_dentry_in_tree(root, calculate_dentry_statistics, &stats);
 }
 
+static int read_ads_entries(const u8 *p, struct dentry *dentry,
+                           unsigned remaining_size)
+{
+       u16 num_ads = dentry->num_ads;
+       struct ads_entry *ads_entries = CALLOC(num_ads, sizeof(struct ads_entry));
+       int ret;
+       if (!ads_entries) {
+               ERROR("Could not allocate memory for %u alternate data stream "
+                     "entries", num_ads);
+               return WIMLIB_ERR_NOMEM;
+       }
+       for (u16 i = 0; i < num_ads; i++) {
+               struct ads_entry *cur_entry = &ads_entries[i];
+               u64 length;
+               size_t utf8_len;
+               /* Read the base stream entry, excluding the stream name. */
+               if (remaining_size < WIM_ADS_ENTRY_DISK_SIZE) {
+                       ERROR("Stream entries go past end of directory entry");
+                       ret = WIMLIB_ERR_INVALID_DENTRY;
+                       goto out_free_ads_entries;
+               }
+               remaining_size -= WIM_ADS_ENTRY_DISK_SIZE;
+
+               p = get_u64(p, &length); /* ADS entry length */
+               p += 8; /* Unused */
+               p = get_bytes(p, WIM_HASH_SIZE, (u8*)cur_entry->hash);
+               p = get_u16(p, &cur_entry->stream_name_len);
+               cur_entry->stream_name = NULL;
+               cur_entry->stream_name_utf8 = NULL;
+
+               if (remaining_size < cur_entry->stream_name_len) {
+                       ERROR("Stream entries go past end of directory entry");
+                       ret = WIMLIB_ERR_INVALID_DENTRY;
+                       goto out_free_ads_entries;
+               }
+
+               cur_entry->stream_name = MALLOC(cur_entry->stream_name_len);
+               if (!cur_entry->stream_name) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out_free_ads_entries;
+               }
+               p = get_bytes(p, cur_entry->stream_name_len,
+                             (u8*)cur_entry->stream_name);
+               cur_entry->stream_name_utf8 = utf16_to_utf8(cur_entry->stream_name,
+                                                           cur_entry->stream_name_len,
+                                                           &utf8_len);
+               cur_entry->stream_name_len_utf8 = utf8_len;
+
+               if (!cur_entry->stream_name_utf8) {
+                       ret = WIMLIB_ERR_NOMEM;
+                       goto out_free_ads_entries;
+               }
+       }
+       dentry->ads_entries = ads_entries;
+       return 0;
+out_free_ads_entries:
+       for (u16 i = 0; i < num_ads; i++) {
+               FREE(ads_entries[i].stream_name);
+               FREE(ads_entries[i].stream_name_utf8);
+       }
+       FREE(ads_entries);
+       return ret;
+}
+
 /* 
  * Reads a directory entry from the metadata resource.
  */
@@ -623,6 +688,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        u16 short_name_len;
        u16 file_name_len;
        size_t file_name_utf8_len;
+       int ret;
 
        dentry_common_init(dentry);
 
@@ -665,11 +731,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        }
 
        p = get_u32(p, &dentry->attributes);
-#ifdef ENABLE_SECURITY_DATA
        p = get_u32(p, (u32*)&dentry->security_id);
-#else
-       p += sizeof(u32);
-#endif
        p = get_u64(p, &dentry->subdir_offset);
 
        /* 2 unused fields */
@@ -681,15 +743,13 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
 
        p = get_bytes(p, WIM_HASH_SIZE, dentry->hash);
        
-       /* Currently ignoring reparse_tag. */
-       p += sizeof(u32);
+       p = get_u32(p, &dentry->reparse_tag);
 
        /* The reparse_reserved field does not actually exist. */
 
        p = get_u64(p, &dentry->hard_link);
        
-       /* Currently ignoring streams. */
-       p += sizeof(u16);
+       p = get_u16(p, &dentry->num_ads);
 
        p = get_u16(p, &short_name_len);
        p = get_u16(p, &file_name_len);
@@ -722,6 +782,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        if (!file_name_utf8) {
                ERROR("Failed to allocate memory to convert UTF-16 "
                      "filename (%hu bytes) to UTF-8", file_name_len);
+               ret = WIMLIB_ERR_NOMEM;
                goto out_free_file_name;
        }
 
@@ -734,11 +795,19 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        if (!short_name) {
                ERROR("Failed to allocate %hu bytes for short filename",
                      short_name_len);
+               ret = WIMLIB_ERR_NOMEM;
                goto out_free_file_name_utf8;
        }
 
        get_bytes(p, short_name_len, short_name);
 
+       if (dentry->num_ads != 0) {
+               ret = read_ads_entries(p, dentry,
+                                      dentry->length - calculated_size);
+               if (ret != 0)
+                       goto out_free_short_name;
+       }
+
        dentry->file_name          = file_name;
        dentry->file_name_utf8     = file_name_utf8;
        dentry->short_name         = short_name;
@@ -746,11 +815,13 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len,
        dentry->file_name_utf8_len = file_name_utf8_len;
        dentry->short_name_len     = short_name_len;
        return 0;
+out_free_short_name:
+       FREE(short_name);
 out_free_file_name_utf8:
-       FREE(dentry->file_name_utf8);
+       FREE(file_name_utf8);
 out_free_file_name:
-       FREE(dentry->file_name);
-       return WIMLIB_ERR_NOMEM;
+       FREE(file_name);
+       return ret;
 }
 
 /* 
@@ -758,7 +829,8 @@ out_free_file_name:
  *
  * @dentry:  The dentry structure.
  * @p:       The memory location to write the data to.
- * @return:  True on success, false on failure.
+ * @return:  Pointer to the byte after the last byte we wrote as part of the
+ *             dentry.
  */
 static u8 *write_dentry(const struct dentry *dentry, u8 *p)
 {
@@ -766,11 +838,7 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p)
        memset(p, 0, dentry->length);
        p = put_u64(p, dentry->length);
        p = put_u32(p, dentry->attributes);
-#ifdef ENABLE_SECURITY_DATA
        p = put_u32(p, dentry->security_id);
-#else
-       p = put_u32(p, (u32)(-1));
-#endif
        p = put_u64(p, dentry->subdir_offset);
        p = put_u64(p, 0); /* unused1 */
        p = put_u64(p, 0); /* unused2 */
@@ -782,14 +850,22 @@ static u8 *write_dentry(const struct dentry *dentry, u8 *p)
        else
                DEBUG("zero hash for %s\n", dentry->file_name_utf8);
        p += WIM_HASH_SIZE;
-       p = put_u32(p, 0); /* reparse_tag */
+       p = put_u32(p, dentry->reparse_tag);
        p = put_u64(p, dentry->hard_link);
-       p = put_u16(p, 0); /*streams */
+       p = put_u16(p, dentry->num_ads); /*streams */
        p = put_u16(p, dentry->short_name_len);
        p = put_u16(p, dentry->file_name_len);
        p = put_bytes(p, dentry->file_name_len, (u8*)dentry->file_name);
        p = put_u16(p, 0); /* filename padding, 2 bytes. */
        p = put_bytes(p, dentry->short_name_len, (u8*)dentry->short_name);
+       for (u16 i = 0; i < dentry->num_ads; i++) {
+               p = put_u64(p, ads_entry_length(&dentry->ads_entries[i]));
+               p = put_u64(p, 0); /* Unused */
+               p = put_bytes(p, WIM_HASH_SIZE, dentry->ads_entries[i].hash);
+               p = put_u16(p, dentry->ads_entries[i].stream_name_len);
+               p = put_bytes(p, dentry->ads_entries[i].stream_name_len,
+                                (u8*)dentry->ads_entries[i].stream_name);
+       }
        return orig_p + dentry->length;
 }
 
index 5167529..ac2eeaf 100644 (file)
@@ -7,6 +7,31 @@
 /* Size of the struct dentry up to and including the file_name_len. */
 #define WIM_DENTRY_DISK_SIZE 102
 
+#define WIM_ADS_ENTRY_DISK_SIZE (2 * sizeof(u64) + WIM_HASH_SIZE + sizeof(u16))
+
+/* Alternate data stream entry */
+struct ads_entry {
+       /* SHA-1 message digest of stream contents */
+       u8 hash[WIM_HASH_SIZE];
+
+       /* Length of stream name (UTF-16) */
+       u16 stream_name_len;
+
+       /* Length of stream name (UTF-8) */
+       u16 stream_name_len_utf8;
+
+       /* Stream name (UTF-16) */
+       char *stream_name;
+
+       /* Stream name (UTF-8) */
+       char *stream_name_utf8;
+};
+
+static inline u64 ads_entry_length(const struct ads_entry *entry)
+{
+       return WIM_ADS_ENTRY_DISK_SIZE + entry->stream_name_len;
+}
+
 /* In-memory structure for a directory entry.  There is a directory tree for
  * each image in the WIM.  */
 struct dentry {
@@ -36,9 +61,7 @@ struct dentry {
        /* The index of the node in the security table that contains this file's
         * security information.  If -1, no security information exists for this
         * file.  */
-#ifdef ENABLE_SECURITY_DATA
        int32_t security_id;
-#endif
 
        /* The offset, from the start of the metadata section, of this directory
         * entry's child files.  0 if the directory entry has no children. */
@@ -58,9 +81,10 @@ struct dentry {
        /* A hash of the file's contents. */
        u8 hash[WIM_HASH_SIZE];
 
-       /* Identity of a reparse point (whatever that is).  Currently ignoring
-        * this field*/
-       //u32 reparse_tag;
+       /* Identity of a reparse point.  See
+        * http://msdn.microsoft.com/en-us/library/windows/desktop/aa365503(v=vs.85).aspx
+        * for what a reparse point is. */
+       u32 reparse_tag;
 
        /* Although M$'s documentation does not tell you this, it seems that the
         * reparse_reserved field does not actually exist.  So the hard_link
@@ -75,9 +99,8 @@ struct dentry {
         * the set will share the same value for this field. */
        u64 hard_link;
 
-       /* Number of WIMStreamEntry structures that follow this struct dentry.
-        * Currently ignoring this field. */
-       //u16 streams;
+       /* Number of alternate data streams associated with this file. */
+       u16 num_ads;
 
        /* Length of short filename, in bytes, not including the terminating
         * zero wide-character. */
@@ -104,8 +127,8 @@ struct dentry {
        char *full_path_utf8;
        u32   full_path_utf8_len;
 
-       /* Stream entries for this dentry. Currently being ignored. */
-       //struct WIMStreamEntry *stream_entries;
+       /* Alternate stream entries for this dentry. */
+       struct ads_entry *ads_entries;
 
        /* Number of references to the dentry tree itself, as in multiple
         * WIMStructs */
index 1d229a1..f3b8da0 100644 (file)
 #include <string.h>
 #include <errno.h>
 
+#ifdef WITH_NTFS_3G
+#include <ntfs-3g/volume.h>
+#endif
+
+/* Sets and creates the directory to which files are to be extracted when
+ * extracting files from the WIM. */
+static int set_output_dir(WIMStruct *w, const char *dir)
+{
+       char *p;
+       DEBUG("Setting output directory to `%s'", dir);
+
+       p = STRDUP(dir);
+       if (!p) {
+               ERROR("Out of memory");
+               return WIMLIB_ERR_NOMEM;
+       }
+
+       if (mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
+               if (errno == EEXIST) {
+                       DEBUG("`%s' already exists", dir);
+                       goto done;
+               }
+               ERROR_WITH_ERRNO("Cannot create directory `%s'", dir);
+               FREE(p);
+               return WIMLIB_ERR_MKDIR;
+       } else {
+               DEBUG("Created directory `%s'", dir);
+       }
+done:
+       FREE(w->output_dir);
+       w->output_dir = p;
+       return 0;
+}
 
 /* 
  * Extracts a regular file from the WIM archive. 
@@ -57,26 +90,22 @@ static int extract_regular_file(WIMStruct *w,
                                const struct dentry *dentry, 
                                const char *output_path)
 {
-       struct lookup_table *lookup_table;
-       int link_type;
-       bool is_multi_image_extraction;
        struct lookup_table_entry *lte;
        int ret;
        int out_fd;
        const struct resource_entry *res_entry;
 
-       lookup_table = w->lookup_table;
-       link_type = w->link_type;
-       is_multi_image_extraction = w->is_multi_image_extraction;
-       lte = lookup_resource(lookup_table, dentry->hash);
+       lte = lookup_resource(w->lookup_table, dentry->hash);
 
        /* If we already extracted the same file or a hard link copy of it, we
         * may be able to simply create a link.  The exact action is specified
         * by the current @link_type. */
-       if (link_type != WIM_LINK_TYPE_NONE && lte && lte->out_refcnt != 0) {
+       if ((w->extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) &&
+             lte && lte->out_refcnt != 0)
+       {
                wimlib_assert(lte->file_on_disk);
 
-               if (link_type == WIM_LINK_TYPE_HARD) {
+               if (w->extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
                        if (link(lte->file_on_disk, output_path) != 0) {
                                ERROR_WITH_ERRNO("Failed to hard link "
                                                 "`%s' to `%s'",
@@ -96,7 +125,7 @@ static int extract_regular_file(WIMStruct *w,
                        num_output_dir_path_components =
                                get_num_path_components(w->output_dir);
 
-                       if (is_multi_image_extraction) {
+                       if (w->is_multi_image_extraction) {
                                num_path_components++;
                                num_output_dir_path_components--;
                        }
@@ -207,14 +236,13 @@ static int extract_regular_file_or_directory(struct dentry *dentry, void *arg)
        size_t len = strlen(w->output_dir);
        char output_path[len + dentry->full_path_utf8_len + 1];
 
-       if (w->verbose)
+       if (w->extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE)
                puts(dentry->full_path_utf8);
 
        memcpy(output_path, w->output_dir, len);
        memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
        output_path[len + dentry->full_path_utf8_len] = '\0';
 
-
        if (dentry_is_regular_file(dentry)) {
                return extract_regular_file(w, dentry, output_path);
        } else {
@@ -263,7 +291,7 @@ static int extract_all_images(WIMStruct *w)
                        /* Image name is empty. Use image number instead */
                        sprintf(buf + output_path_len + 1, "%d", image);
                }
-               ret = wimlib_set_output_dir(w, buf);
+               ret = set_output_dir(w, buf);
                if (ret != 0)
                        goto done;
                ret = extract_single_image(w, image);
@@ -273,70 +301,57 @@ static int extract_all_images(WIMStruct *w)
 done:
        /* Restore original output directory */
        buf[output_path_len + 1] = '\0';
-       return wimlib_set_output_dir(w, buf);
+       return 0;
 }
 
 /* Extracts a single image or all images from a WIM file. */
-WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image)
+WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
+                                  const char *output_dir, int flags)
 {
-       if (!w->output_dir) {
-               ERROR("No output directory selected.");
-               return WIMLIB_ERR_NOTDIR;
+       int ret;
+       if (!output_dir)
+               return WIMLIB_ERR_INVALID_PARAM;
+       if ((flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
+                       == (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
+               return WIMLIB_ERR_INVALID_PARAM;
+       
+       ret = set_output_dir(w, output_dir);
+       if (ret != 0)
+               return ret;
+
+       if ((flags & WIMLIB_EXTRACT_FLAG_NTFS)) {
+       #ifdef WITH_NTFS_3G
+               unsigned long mnt_flags;
+               ret = ntfs_check_if_mounted(output_dir, &mnt_flags);
+               if (ret != 0) {
+                       ERROR_WITH_ERRNO("NTFS-3g: Cannot determine if `%s' "
+                                        "is mounted", output_dir);
+                       return WIMLIB_ERR_NTFS_3G;
+               }
+               if (!(mnt_flags & NTFS_MF_MOUNTED)) {
+                       ERROR("NTFS-3g: Filesystem on `%s' is not mounted ",
+                             output_dir);
+               }
+               if (mnt_flags & NTFS_MF_READONLY) {
+                       ERROR("NTFS-3g: Filesystem on `%s' is mounted "
+                             "read-only", output_dir);
+                       return WIMLIB_ERR_NTFS_3G;
+               }
+       #else
+               ERROR("wimlib was compiled without support for NTFS-3g, so");
+               ERROR("we cannot extract a WIM image while preserving NTFS-");
+               ERROR("specific information");
+               return WIMLIB_ERR_UNSUPPORTED;
+       #endif
        }
+       w->extract_flags = flags;
        if (image == WIM_ALL_IMAGES) {
                w->is_multi_image_extraction = true;
-               return extract_all_images(w);
+               ret = extract_all_images(w);
        } else {
                w->is_multi_image_extraction = false;
-               return extract_single_image(w, image);
-       }
-
-}
-
-/* Sets and creates the directory to which files are to be extracted when
- * extracting files from the WIM. */
-WIMLIBAPI int wimlib_set_output_dir(WIMStruct *w, const char *dir)
-{
-       char *p;
-       DEBUG("Setting output directory to `%s'", dir);
-
-       if (!dir) {
-               ERROR("Must specify a directory!");
-               return WIMLIB_ERR_INVALID_PARAM;
-       }
-       p = STRDUP(dir);
-       if (!p) {
-               ERROR("Out of memory");
-               return WIMLIB_ERR_NOMEM;
-       }
-
-       if (mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
-               if (errno == EEXIST) {
-                       DEBUG("`%s' already exists", dir);
-                       goto done;
-               }
-               ERROR_WITH_ERRNO("Cannot create directory `%s'", dir);
-               FREE(p);
-               return WIMLIB_ERR_MKDIR;
-       } else {
-               DEBUG("Created directory `%s'", dir);
+               ret = extract_single_image(w, image);
        }
-done:
-       FREE(w->output_dir);
-       w->output_dir = p;
-       return 0;
-}
+       return ret;
 
-WIMLIBAPI int wimlib_set_link_type(WIMStruct *w, int link_type)
-{
-       switch (link_type) {
-               case WIM_LINK_TYPE_NONE:
-               case WIM_LINK_TYPE_HARD:
-               case WIM_LINK_TYPE_SYMBOLIC:
-                       w->link_type = link_type;
-                       return 0;
-               default:
-                       return WIMLIB_ERR_INVALID_PARAM;
-       }
 }
-
index 7cd25b1..c685143 100644 (file)
@@ -96,8 +96,7 @@ int read_header(FILE *fp, struct wim_header *hdr, int split_ok)
                ERROR("Unexpected chunk size of %u! Ask the author to "
                      "implement support for other chunk sizes.",
                      chunk_size);
-               ERROR("(Or it might just be that the WIM header is "
-                     "invalid.)", chunk_size);
+               ERROR("(Or it might just be that the WIM header is invalid.)");
                return WIMLIB_ERR_INVALID_CHUNK_SIZE;
        }
 
index 49fe514..55d950a 100644 (file)
@@ -209,8 +209,7 @@ int check_wim_integrity(WIMStruct *w, int show_progress, int *status)
                      "the %"PRIu64" bytes from the end of the header to the",
                      expected_num_entries, bytes_to_check);
                ERROR("end of the lookup table with a chunk size of %u, but "
-                     "there were only %u entries", expected_num_entries,
-                     bytes_to_check, chunk_size, num_entries);
+                     "there were only %u entries", chunk_size, num_entries);
                ret = WIMLIB_ERR_INVALID_INTEGRITY_TABLE;
                goto out;
        }
index a24b02e..9358093 100644 (file)
@@ -55,7 +55,7 @@ struct lookup_table_entry *new_lookup_table_entry()
 {
        struct lookup_table_entry *lte;
        
-       lte = MALLOC(sizeof(struct lookup_table_entry));
+       lte = CALLOC(1, sizeof(struct lookup_table_entry));
        if (!lte) {
                ERROR("Out of memory (tried to allocate %zu bytes for "
                      "lookup table entry)",
@@ -63,12 +63,8 @@ struct lookup_table_entry *new_lookup_table_entry()
                return NULL;
        }
 
-       lte->next         = NULL;
-       lte->file_on_disk = NULL;
-       lte->other_wim_fp = NULL;
        lte->part_number  = 1;
        lte->refcnt       = 1;
-       lte->staging_num_times_opened = 0;
        return lte;
 }
 
index 4a28e0a..fde95d0 100644 (file)
@@ -41,9 +41,7 @@ static void destroy_image_metadata(struct image_metadata *imd,
                                   struct lookup_table *lt)
 {
        free_dentry_tree(imd->root_dentry, lt, true);
-#ifdef ENABLE_SECURITY_DATA
        free_security_data(imd->security_data);
-#endif
 
        /* Get rid of the lookup table entry for this image's metadata resource
         * */
@@ -223,9 +221,7 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry)
        struct lookup_table_entry *metadata_lte;
        struct image_metadata *imd;
        struct image_metadata *new_imd;
-#ifdef ENABLE_SECURITY_DATA
        struct wim_security_data *sd;
-#endif
 
        DEBUG("Reallocating image metadata array for image_count = %u",
              w->hdr.image_count + 1);
@@ -242,13 +238,11 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry)
        metadata_lte = new_lookup_table_entry();
        if (!metadata_lte)
                goto out_free_imd;
-#ifdef ENABLE_SECURITY_DATA
        sd = CALLOC(1, sizeof(struct wim_security_data));
        if (!sd)
                goto out_free_metadata_lte;
        sd->refcnt = 1;
        sd->total_length = 8;
-#endif
 
        metadata_lte->resource_entry.flags = WIM_RESHDR_FLAG_METADATA;
        randomize_byte_array(metadata_lte->hash, WIM_HASH_SIZE);
@@ -260,9 +254,7 @@ static int add_new_dentry_tree(WIMStruct *w, struct dentry *root_dentry)
        new_imd->metadata_lte   = metadata_lte;
        new_imd->modified       = true;
        new_imd->root_dentry    = root_dentry;
-#ifdef ENABLE_SECURITY_DATA
        new_imd->security_data  = sd;
-#endif
        FREE(w->image_metadata);
        w->image_metadata       = imd;
 
@@ -372,7 +364,6 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        ret = add_new_dentry_tree(dest_wim, root);
        if (ret != 0)
                return ret;
-#ifdef ENABLE_SECURITY_DATA
        /* Bring over old security data */
        struct wim_security_data *sd = wim_security_data(src_wim);
        struct image_metadata *new_imd = wim_get_current_image_metadata(dest_wim);
@@ -380,7 +371,6 @@ WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
        free_security_data(new_imd->security_data);
        new_imd->security_data = sd;
        sd->refcnt++;
-#endif
 
        if (flags & WIMLIB_EXPORT_FLAG_BOOT) {
                DEBUG("Setting boot_idx to %d", dest_wim->hdr.image_count);
@@ -399,7 +389,6 @@ WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image)
        int num_images;
        int i;
        int ret;
-       struct image_metadata *imd;
 
        if (image == WIM_ALL_IMAGES) {
                num_images = w->hdr.image_count;
index f3043c2..bf194da 100644 (file)
@@ -585,8 +585,6 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
 
        /* Create a lookup table entry having the same hash value */
        lte = new_lookup_table_entry();
-       lte->staging_num_times_opened = 0;
-       lte->resource_entry.original_size = 0;
        memcpy(lte->hash, dentry->hash, WIM_HASH_SIZE);
 
        fd = create_staging_file(&tmpfile_name);
@@ -1105,6 +1103,11 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
        if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
                wim_get_current_image_metadata(wim)->modified = true;
 
+       if (!(flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
+                      WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
+                      WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
+               flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
+
        mount_dir = dir;
        working_directory = getcwd(NULL, 0);
        if (!working_directory) {
index 9349c3b..5e6707d 100644 (file)
@@ -401,7 +401,8 @@ int read_resource(FILE *fp, u64 resource_size, u64 resource_original_size,
                if (resource_size != resource_original_size) {
                        ERROR("Resource with original size %"PRIu64" bytes is "
                              "marked as uncompressed, but its actual size is "
-                             "%"PRIu64" bytes", resource_size);
+                             "%"PRIu64" bytes", 
+                             resource_original_size, resource_size);
                        return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
                }
                return read_uncompressed_resource(fp, 
@@ -923,9 +924,7 @@ int read_metadata_resource(FILE *fp, int wim_ctype, struct image_metadata *imd)
        int ret;
        const struct resource_entry *res_entry;
        struct dentry *dentry;
-#ifdef ENABLE_SECURITY_DATA
        struct wim_security_data *sd;
-#endif
 
        res_entry = &imd->metadata_lte->resource_entry;
 
@@ -965,12 +964,10 @@ int read_metadata_resource(FILE *fp, int wim_ctype, struct image_metadata *imd)
         * The security data starts with a 4-byte integer giving its total
         * length. */
 
-#ifdef ENABLE_SECURITY_DATA
        /* Read the security data into a wim_security_data structure. */
        ret = read_security_data(buf, res_entry->original_size, &sd);
        if (ret != 0)
                goto out_free_buf;
-#endif
 
        dentry = MALLOC(sizeof(struct dentry));
        if (!dentry) {
@@ -1003,15 +1000,11 @@ int read_metadata_resource(FILE *fp, int wim_ctype, struct image_metadata *imd)
        if (ret != 0)
                goto out_free_dentry_tree;
 
-#ifdef ENABLE_SECURITY_DATA
        imd->security_data = sd;
-#endif
        imd->root_dentry = dentry;
        goto out_free_buf;
 out_free_security_data:
-#ifdef ENABLE_SECURITY_DATA
        free_security_data(sd);
-#endif
 out_free_dentry_tree:
        free_dentry_tree(dentry, NULL, false);
 out_free_buf:
@@ -1045,12 +1038,10 @@ int write_metadata_resource(WIMStruct *w)
        if (metadata_offset == -1)
                return WIMLIB_ERR_WRITE;
 
-       #ifdef ENABLE_SECURITY_DATA
        struct wim_security_data *sd = wim_security_data(w);
        if (sd)
                subdir_offset = sd->total_length + root->length + 8;
        else
-       #endif
                subdir_offset = 8 + root->length + 8;
        calculate_subdir_offsets(root, &subdir_offset);
        metadata_original_size = subdir_offset;
@@ -1060,13 +1051,8 @@ int write_metadata_resource(WIMStruct *w)
                      "metadata resource", metadata_original_size);
                return WIMLIB_ERR_NOMEM;
        }
-       #ifdef ENABLE_SECURITY_DATA
-       /* Write the security data. */
+
        p = write_security_data(sd, buf);
-       #else
-       p = put_u32(buf, 8); /* Total length of security data. */
-       p = put_u32(p, 0); /* Number of security data entries. */
-       #endif
 
        DEBUG("Writing dentry tree.");
        p = write_dentry_tree(root, p);
@@ -1165,9 +1151,6 @@ int write_file_resource(struct dentry *dentry, void *wim_p)
                        return WIMLIB_ERR_OPEN;
                }
 
-               if (w->verbose)
-                       puts(lte->file_on_disk);
-
                ret = transfer_file_resource(in_fp, len, len, 0,
                                             WIM_COMPRESSION_TYPE_NONE, out_fp,
                                             out_wim_ctype, output_res_entry);
index c6bbf7c..ccca962 100644 (file)
@@ -28,8 +28,6 @@
 #include "io.h"
 #include "security.h"
 
-#ifdef ENABLE_SECURITY_DATA
-
 /* 
  * Reads the security data from the metadata resource.
  *
@@ -283,5 +281,3 @@ void free_security_data(struct wim_security_data *sd)
                sd->refcnt--;
        }
 }
-
-#endif
index 0c41e1f..40c861a 100644 (file)
@@ -240,7 +240,7 @@ WIMLIBAPI int wimlib_split(const char *wimfile, const char *swm_name,
 
                FILE *fp = fopen(p, "r+b");
                if (!fp) {
-                       ERROR_WITH_ERRNO("Failed to open `%s'");
+                       ERROR_WITH_ERRNO("Failed to open `%s'", p);
                        return WIMLIB_ERR_OPEN;
                }
                u8 buf[4];
index 474c6f1..47b76a8 100644 (file)
@@ -159,6 +159,8 @@ static const char *error_strings[] = {
                        "identify a WIM file",
        [WIMLIB_ERR_NO_FILENAME] 
                = "The WIM is not identified with a filename",
+       [WIMLIB_ERR_NTFS_3G]
+               = "NTFS-3g encountered an error (check errno)",
        [WIMLIB_ERR_OPEN] 
                = "Failed to open a file",
        [WIMLIB_ERR_OPENDIR] 
index 7328878..12b8418 100644 (file)
--- a/src/wim.c
+++ b/src/wim.c
@@ -32,9 +32,7 @@
 
 static int print_metadata(WIMStruct *w)
 {
-#ifdef ENABLE_SECURITY_DATA
        print_security_data(wim_security_data(w));
-#endif
        return for_dentry_in_tree(wim_root_dentry(w), print_dentry, 
                                  w->lookup_table);
 }
@@ -48,14 +46,7 @@ static int print_files(WIMStruct *w)
 
 WIMStruct *new_wim_struct()
 {
-       WIMStruct *w;
-       
-       w = CALLOC(1, sizeof(WIMStruct));
-       if (!w)
-               return NULL;
-       w->link_type     = WIM_LINK_TYPE_NONE;
-       w->current_image = WIM_NO_IMAGE;
-       return w;
+       return CALLOC(1, sizeof(WIMStruct));
 }
 
 /* 
@@ -116,6 +107,7 @@ static int append_metadata_resource_entry(struct lookup_table_entry *lte,
        WIMStruct *w = wim_p;
 
        if (lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) {
+               /*fprintf(stderr, "found mlte at %u\n", lte->resource_entry.offset);*/
                if (w->current_image == w->hdr.image_count) {
                        ERROR("Expected only %u images, but found more",
                              w->hdr.image_count);
@@ -154,11 +146,6 @@ int wim_resource_compression_type(const WIMStruct *w,
        return resource_compression_type(wim_ctype, entry->flags);
 }
 
-WIMLIBAPI void wimlib_set_verbose(WIMStruct *w, bool verbose)
-{
-       w->verbose = verbose;
-}
-
 /*
  * Creates a WIMStruct for a new WIM file.
  */
@@ -222,10 +209,8 @@ int wimlib_select_image(WIMStruct *w, int image)
                        DEBUG("Freeing image %u", w->current_image);
                        free_dentry_tree(imd->root_dentry, NULL, false);
                        imd->root_dentry = NULL;
-#ifdef ENABLE_SECURITY_DATA
                        free_security_data(imd->security_data);
                        imd->security_data = NULL;
-#endif
                }
        }
 
@@ -409,7 +394,8 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int flags)
        w->fp = fopen(in_wim_path, "rb");
 
        if (!w->fp) {
-               ERROR_WITH_ERRNO("Failed to open the file `%s' for reading");
+               ERROR_WITH_ERRNO("Failed to open the file `%s' for reading",
+                                in_wim_path);
                return WIMLIB_ERR_OPEN;
        }
 
@@ -573,9 +559,7 @@ WIMLIBAPI void wimlib_free(WIMStruct *w)
                for (i = 0; i < w->hdr.image_count; i++) {
                        free_dentry_tree(w->image_metadata[i].root_dentry, 
                                         NULL, false);
-                       #ifdef ENABLE_SECURITY_DATA
                        free_security_data(w->image_metadata[i].security_data);
-                       #endif
                }
                FREE(w->image_metadata);
        }
index 15b2d71..dde93c6 100644 (file)
@@ -234,40 +234,75 @@ enum wim_compression_type {
 };
 
 /** Mount the WIM read-write. */
-#define WIMLIB_MOUNT_FLAG_READWRITE            0x1
+#define WIMLIB_MOUNT_FLAG_READWRITE            0x00000001
 
 /** For debugging only. (This passes the @c -d flag to @c fuse_main()).*/
-#define WIMLIB_MOUNT_FLAG_DEBUG                        0x2
+#define WIMLIB_MOUNT_FLAG_DEBUG                        0x00000002
+
+/** Do not allow accessing alternate data streams. */
+#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE                0x00000010
+
+/** Access alternate data streams through extended file attributes.  This is the
+ * default mode. */
+#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR       0x00000020
+
+/** Access alternate data streams by specifying the file name, a colon, then the
+ * alternate file stream name. */
+#define WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS     0x00000040
 
 /** Include an integrity table in the new WIM being written during the unmount. 
  * Ignored for read-only mounts. */
-#define WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY    0x1
+#define WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY    0x00000001
 
 /** Unless this flag is given, changes to a mounted WIM are discarded.  Ignored
  * for read-only mounts. */
-#define WIMLIB_UNMOUNT_FLAG_COMMIT             0x2
+#define WIMLIB_UNMOUNT_FLAG_COMMIT             0x00000002
 
 /** Include an integrity table in the new WIM file. */
-#define WIMLIB_WRITE_FLAG_CHECK_INTEGRITY      0x1
+#define WIMLIB_WRITE_FLAG_CHECK_INTEGRITY      0x00000001
 
 /** Print progress information when writing the integrity table. */
-#define WIMLIB_WRITE_FLAG_SHOW_PROGRESS                0x2
+#define WIMLIB_WRITE_FLAG_SHOW_PROGRESS                0x00000002
 
 /** Mark the image being added as the bootable image of the WIM. */
-#define WIMLIB_ADD_IMAGE_FLAG_BOOT             0x1
+#define WIMLIB_ADD_IMAGE_FLAG_BOOT             0x00000001
+
+/** Print the name of each file or directory as it is scanned to be included in
+ * the WIM image. */
+#define WIMLIB_ADD_IMAGE_FLAG_VERBOSE          0x00000002
+
+/** Apply NTFS-specific information to the captured WIM image.  This flag can
+ * only be specified if the directory being captured is on a NTFS filesystem
+ * mounted with NTFS-3g, and wimlib was compiled with support for NTFS-3g  */
+#define WIMLIB_ADD_IMAGE_FLAG_NTFS             0x00000004
 
 /** See documentation for wimlib_export_image(). */
-#define WIMLIB_EXPORT_FLAG_BOOT                        0x1
+#define WIMLIB_EXPORT_FLAG_BOOT                        0x00000001
 
 /** Verify the integrity of the WIM if an integrity table is present. */
-#define WIMLIB_OPEN_FLAG_CHECK_INTEGRITY       0x1
+#define WIMLIB_OPEN_FLAG_CHECK_INTEGRITY       0x00000001
 
 /** Print progress information when verifying integrity table. */
-#define WIMLIB_OPEN_FLAG_SHOW_PROGRESS         0x2
+#define WIMLIB_OPEN_FLAG_SHOW_PROGRESS         0x00000002
 
 /** If this flag is not given, an error is issued if the WIM is part of a split
  * WIM.  */
-#define WIMLIB_OPEN_FLAG_SPLIT_OK              0x4
+#define WIMLIB_OPEN_FLAG_SPLIT_OK              0x00000004
+
+
+/** When identical files are extracted from the WIM, hard link them together. */
+#define WIMLIB_EXTRACT_FLAG_HARDLINK           0x00000001
+
+/** When identical files are extracted from the WIM, symlink them together. */
+#define WIMLIB_EXTRACT_FLAG_SYMLINK            0x00000002
+
+/** Apply NTFS-specific information when applying the WIM image.  This flag can
+ * only be specified if the output directory is on a NTFS filesystem mounted
+ * with NTFS-3g, and wimlib was compiled with support for NTFS-3g  */
+#define WIMLIB_EXTRACT_FLAG_NTFS               0x00000004
+
+/** Print the name of each file as it is extracted from the WIM image. */
+#define WIMLIB_EXTRACT_FLAG_VERBOSE            0x00000008
 
 /**
  * Possible values of the error code returned by many functions in wimlib.
@@ -302,6 +337,7 @@ enum wimlib_error_code {
        WIMLIB_ERR_NOTDIR,
        WIMLIB_ERR_NOT_A_WIM_FILE,
        WIMLIB_ERR_NO_FILENAME,
+       WIMLIB_ERR_NTFS_3G,
        WIMLIB_ERR_OPEN,
        WIMLIB_ERR_OPENDIR,
        WIMLIB_ERR_READ,
@@ -535,7 +571,8 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image,
  * @retval ::WIMLIB_ERR_WRITE
  *     Failed to write a file being extracted.
  */
-extern int wimlib_extract_image(WIMStruct *wim, int image);
+extern int wimlib_extract_image(WIMStruct *wim, int image,
+                               const char *output_dir, int flags);
 
 /**
  * Extracts the XML data for a WIM file to a file stream.  Every WIM file
@@ -1179,41 +1216,6 @@ int wimlib_set_memory_allocator(void *(*malloc_func)(size_t),
 extern int wimlib_set_print_errors(bool show_messages);
 
 /**
- * Sets whether wimlib is to be verbose when extracting files from a WIM or when
- * creating an image from a directory (i.e. whether it will print all affected
- * files or not.)  This is a per-WIM parameter.
- *
- * @param wim
- *     Pointer to the ::WIMStruct for the WIM file.
- * @param verbose
- *     Whether wimlib is to be verbose when extracting files from @a wim using
- *     wimlib_extract_image() or when adding an image to @a wim using
- *     wimlib_add_image().
- *
- * @return This function has no return value.
- */
-extern void wimlib_set_verbose(WIMStruct *wim, bool verbose);
-
-/**
- * Sets and creates the directory to which files are to be extracted when
- * extracting files from the WIM.
- *
- * @param wim
- *     Pointer to the ::WIMStruct for the WIM file.
- * @param dir
- *     The name of the directory to extract files to.
- *
- * @return 0 on success; nonzero on error.
- * @retval ::WIMLIB_ERR_INVALID_PARAM
- *     @a dir was @c NULL.
- * @retval ::WIMLIB_ERR_MKDIR
- *     @a dir does not already exist and it could not created.
- * @retval ::WIMLIB_ERR_NOMEM
- *     Failed to allocate the memory needed to duplicate the @a dir string.
- */
-extern int wimlib_set_output_dir(WIMStruct *wim, const char *dir);
-
-/**
  * Splits a WIM into multiple parts.
  *
  * @param wimfile
index c1ad1cd..28edf93 100644 (file)
@@ -183,7 +183,6 @@ struct wim_header {
 #define WIM_HDR_FLAG_COMPRESS_LZX       0x00040000
 
 
-#ifdef ENABLE_SECURITY_DATA
 /* Structure for security data.  Each image in the WIM file has its own security
  * data. */
 struct wim_security_data {
@@ -205,17 +204,15 @@ struct wim_security_data {
         * exporting images between WIMs) */
        u32 refcnt;
 } WIMSecurityData;
-#endif
 
 /* Metadata resource for an image. */
 struct image_metadata {
        /* Pointer to the root dentry for the image. */
        struct dentry    *root_dentry;
 
-#ifdef ENABLE_SECURITY_DATA
        /* Pointer to the security data for the image. */
        struct wim_security_data *security_data;
-#endif
+
        /* A pointer to the lookup table entry for this image's metadata
         * resource. */
        struct lookup_table_entry *metadata_lte;
@@ -259,18 +256,17 @@ typedef struct WIMStruct {
        /* The header of the WIM file. */
        struct wim_header    hdr;
 
-       /* The type of links to create when extracting files (hard, symbolic, or
-        * none.) */
-       int    link_type;
+       /* Temporary flags to use when extracting a WIM image or adding a WIM
+        * image. */
+       union {
+               int extract_flags;
+               int add_flags;
+       };
 
        /* The currently selected image, indexed starting at 1.  If not 0,
         * subtract 1 from this to get the index of the current image in the
         * image_metadata array. */
-       int                  current_image;
-
-       /* True if files names are to be printed when doing extraction. 
-        * May be used for other things later. */
-       bool   verbose;
+       int current_image;
 
        union {
                /* Set to true when extracting multiple images */
@@ -293,12 +289,10 @@ static inline struct dentry **wim_root_dentry_p(WIMStruct *w)
        return &w->image_metadata[w->current_image - 1].root_dentry;
 }
 
-#ifdef ENABLE_SECURITY_DATA
 static inline struct wim_security_data *wim_security_data(WIMStruct *w)
 {
        return w->image_metadata[w->current_image - 1].security_data;
 }
-#endif
 
 static inline struct lookup_table_entry*
 wim_metadata_lookup_table_entry(WIMStruct *w)
@@ -381,14 +375,13 @@ extern int write_resource_from_memory(const u8 resource[], int out_ctype,
                                      u64 *resource_size_ret);
 extern int write_metadata_resource(WIMStruct *w);
 
-#ifdef ENABLE_SECURITY_DATA
+/* security.c */
 int read_security_data(const u8 metadata_resource[], 
                u64 metadata_resource_len, struct wim_security_data **sd_p);
 
 void print_security_data(const struct wim_security_data *sd);
 u8 *write_security_data(const struct wim_security_data *sd, u8 *p);
 void free_security_data(struct wim_security_data *sd);
-#endif
 
 /* wim.c */
 extern WIMStruct *new_wim_struct();
index 94a3851..99f4423 100755 (executable)
@@ -31,7 +31,7 @@ imagex() {
 
 
 cleanup() {
-       if [ -d tmp ] && mountpoint tmp; then
+       if [ -d tmp ] && mountpoint tmp > /dev/null; then
                fusermount -u tmp > /dev/null;
        fi
        rm -rf tmp* *.wim *.swm dir3