From: Eric Biggers Date: Sat, 18 Aug 2012 00:46:24 +0000 (-0500) Subject: Some preparations for supporting NTFS capture and apply. X-Git-Tag: v1.0.0~151 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=ef8f45b98b5c4db398321cd36d052ccbb9c3784a Some preparations for supporting NTFS capture and apply. - 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!) --- diff --git a/config.h.in b/config.h.in index 148c5776..da29bd08 100644 --- a/config.h.in +++ b/config.h.in @@ -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 @@ -103,6 +100,9 @@ /* 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 diff --git a/configure.ac b/configure.ac index 1efb42b3..d79f130f 100644 --- a/configure.ac +++ b/configure.ac @@ -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]) diff --git a/doc/imagex-append.1.in b/doc/imagex-append.1.in index d5fa11ec..027959f7 100644 --- a/doc/imagex-append.1.in +++ b/doc/imagex-append.1.in @@ -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 element of the XML data for the image. -.TP -\fB--verify\fR -This option is currently unsupported. .SH EXAMPLES .IP diff --git a/doc/imagex-apply.1.in b/doc/imagex-apply.1.in index 7e09a949..8012066f 100644 --- a/doc/imagex-apply.1.in +++ b/doc/imagex-apply.1.in @@ -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 diff --git a/doc/imagex-capture.1.in b/doc/imagex-capture.1.in index 3c51ab77..6e3edd42 100644 --- a/doc/imagex-capture.1.in +++ b/doc/imagex-capture.1.in @@ -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 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. diff --git a/doc/imagex-mount.1.in b/doc/imagex-mount.1.in index 6d04c7f9..2b8122f4 100644 --- a/doc/imagex-mount.1.in +++ b/doc/imagex-mount.1.in @@ -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) diff --git a/doc/imagex-mountrw.1.in b/doc/imagex-mountrw.1.in index 821897fd..0cc88986 100644 --- a/doc/imagex-mountrw.1.in +++ b/doc/imagex-mountrw.1.in @@ -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) diff --git a/programs/imagex.c b/programs/imagex.c index a1b9cea2..11becdd2 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -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*/ diff --git a/src/dentry.c b/src/dentry.c index 1c93792f..d3399acb 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -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; } diff --git a/src/dentry.h b/src/dentry.h index 51675295..ac2eeafe 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -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 */ diff --git a/src/extract.c b/src/extract.c index 1d229a16..f3b8da06 100644 --- a/src/extract.c +++ b/src/extract.c @@ -35,6 +35,39 @@ #include #include +#ifdef WITH_NTFS_3G +#include +#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; - } } - diff --git a/src/header.c b/src/header.c index 7cd25b11..c6851432 100644 --- a/src/header.c +++ b/src/header.c @@ -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; } diff --git a/src/integrity.c b/src/integrity.c index 49fe514c..55d950a6 100644 --- a/src/integrity.c +++ b/src/integrity.c @@ -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; } diff --git a/src/lookup_table.c b/src/lookup_table.c index a24b02eb..93580934 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -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; } diff --git a/src/modify.c b/src/modify.c index 4a28e0a4..fde95d09 100644 --- a/src/modify.c +++ b/src/modify.c @@ -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; diff --git a/src/mount.c b/src/mount.c index f3043c2b..bf194da4 100644 --- a/src/mount.c +++ b/src/mount.c @@ -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) { diff --git a/src/resource.c b/src/resource.c index 9349c3ba..5e6707d9 100644 --- a/src/resource.c +++ b/src/resource.c @@ -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); diff --git a/src/security.c b/src/security.c index c6bbf7cb..ccca9624 100644 --- a/src/security.c +++ b/src/security.c @@ -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 diff --git a/src/split.c b/src/split.c index 0c41e1ff..40c861a1 100644 --- a/src/split.c +++ b/src/split.c @@ -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]; diff --git a/src/util.c b/src/util.c index 474c6f10..47b76a82 100644 --- a/src/util.c +++ b/src/util.c @@ -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] diff --git a/src/wim.c b/src/wim.c index 73288788..12b84183 100644 --- 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); } diff --git a/src/wimlib.h b/src/wimlib.h index 15b2d719..dde93c61 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -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 @@ -1178,41 +1215,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. * diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index c1ad1cd4..28edf93f 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -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(); diff --git a/tests/test-imagex b/tests/test-imagex index 94a38516..99f44232 100755 --- a/tests/test-imagex +++ b/tests/test-imagex @@ -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