From f7d48eea9e1a6a9620ee7d8e883a6505939c7777 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 25 Aug 2012 13:58:11 -0500 Subject: [PATCH 1/1] NTFS apply updates - Hard link creation code fixed and uncommented. We need to close the source directory inode before the target inode. - Code to set DOS filenames added but commented out due to a problem. - New function wim_apply_dentry_timestamps() to apply timestamps to dentry, run in a depth-first traversal of the directory tree following the main WIM application. --- programs/imagex.c | 3 - src/ntfs-apply.c | 152 ++++++++++++++++++++++++++++++++++++++-------- src/util.c | 2 +- src/wimlib.h | 46 ++------------ 4 files changed, 131 insertions(+), 72 deletions(-) diff --git a/programs/imagex.c b/programs/imagex.c index 998378da..1fce776b 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -480,9 +480,6 @@ static int imagex_capture(int argc, const char **argv) add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE; write_flags |= WIMLIB_WRITE_FLAG_VERBOSE; break; - case 'N': - add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NTFS; - break; case 'L': add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE; break; diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index bf290143..2857fc57 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -152,11 +152,15 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry, */ static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry, const struct dentry *to_dentry, - ntfs_inode *dir_ni) + ntfs_inode *dir_ni, + ntfs_inode **to_ni_ret) { int ret; ntfs_inode *to_ni; + wimlib_assert(dentry_is_regular_file(from_dentry) + && dentry_is_regular_file(to_dentry)); + DEBUG("Extracting NTFS hard link `%s' => `%s'", from_dentry->full_path_utf8, to_dentry->extracted_file); @@ -176,11 +180,7 @@ static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry, to_dentry->extracted_file); ret = WIMLIB_ERR_NTFS_3G; } - if (ntfs_inode_close(to_ni) != 0) { - ERROR_WITH_ERRNO("Failed to close NTFS inode for `%s'", - to_dentry->extracted_file); - ret = WIMLIB_ERR_NTFS_3G; - } + *to_ni_ret = to_ni; return ret; } @@ -274,29 +274,34 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry, static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni, WIMStruct *w) { - ntfs_inode *ni; int ret = 0; mode_t type; + ntfs_inode *ni = NULL; + ntfs_inode *hardlink_target_ni = NULL; if (dentry->attributes & FILE_ATTRIBUTE_DIRECTORY) { type = S_IFDIR; } else { type = S_IFREG; -#if 0 const struct list_head *head = &dentry->link_group_list; if (head->next != head) { /* This dentry is one of a hard link set of at least 2 * dentries. If one of the other dentries has already - * been extracted, make a hard link to the file - * corresponding to this already-extracted directory. - * Otherwise, extract the file, and set the - * dentry->extracted_file field so that other dentries - * in the hard link group can link to it. */ + * been extracted, make a hard link to it. Otherwise, + * extract the file, and set the dentry->extracted_file + * field so that other dentries in the hard link group + * can link to it. */ struct dentry *other; list_for_each_entry(other, head, link_group_list) { if (other->extracted_file) { - return wim_apply_hardlink_ntfs( - dentry, other, dir_ni); + ret = wim_apply_hardlink_ntfs(dentry, + other, + dir_ni, + &hardlink_target_ni); + if (ret != 0) + goto out_close_dir; + else + goto out_set_dos_name; } } } @@ -306,7 +311,6 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni, ERROR("Failed to allocate memory for filename"); return WIMLIB_ERR_NOMEM; } -#endif } /* @@ -322,7 +326,7 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni, ERROR_WITH_ERRNO("Could not create NTFS object for `%s'", dentry->full_path_utf8); ret = WIMLIB_ERR_NTFS_3G; - goto out; + goto out_close_new; } /* Write the data streams, unless this is a directory or reparse point @@ -331,26 +335,79 @@ static int do_wim_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni, !(dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT)) { ret = write_ntfs_data_streams(ni, dentry, w); if (ret != 0) - goto out; + goto out_close_new; } ret = apply_file_attributes_and_security_data(ni, dentry, w); if (ret != 0) - goto out; + goto out_close_new; if (dentry->attributes & FILE_ATTR_REPARSE_POINT) { ret = apply_reparse_data(ni, dentry, w); if (ret != 0) - goto out; + goto out_close_new; + } + +out_set_dos_name: +#if 0 + /* Set DOS (short) name if given */ + if (dentry->short_name_len != 0) { + char *short_name_utf8; + size_t short_name_utf8_len; + short_name_utf8 = utf16_to_utf8(dentry->short_name, + dentry->short_name_len, + &short_name_utf8_len); + if (!short_name_utf8) { + ERROR("Out of memory"); + ret = WIMLIB_ERR_NOMEM; + goto out_close_new; + } + + if (!ni) { + ni = ntfs_pathname_to_inode(dir_ni->vol, NULL, + dentry->full_path_utf8); + if (!ni) { + ERROR_WITH_ERRNO("Failed to find inode for `%s'", + dentry->full_path_utf8); + goto out_close_dir; + } + } + + DEBUG("Setting short (DOS) name of `%s' to %s", + dentry->full_path_utf8, short_name_utf8); + + ret = ntfs_set_ntfs_dos_name(ni, dir_ni, short_name_utf8, + short_name_utf8_len, 0); + FREE(short_name_utf8); + if (ret != 0) { + ERROR_WITH_ERRNO("Could not set DOS (short) name for `%s'", + dentry->full_path_utf8); + ret = WIMLIB_ERR_NTFS_3G; + } + goto out_close_hardlink_target; } +#endif - if (ntfs_inode_close_in_dir(ni, dir_ni) != 0) { +out_close_new: + if (ni && ntfs_inode_close_in_dir(ni, dir_ni) != 0) { ERROR_WITH_ERRNO("Failed to close new inode"); ret = WIMLIB_ERR_NTFS_3G; - goto out; } -out: +out_close_dir: + if (ntfs_inode_close(dir_ni) != 0) { + if (ret == 0) + ret = WIMLIB_ERR_NTFS_3G; + ERROR_WITH_ERRNO("Failed to close directory inode"); + } +out_close_hardlink_target: + if (hardlink_target_ni) { + if (ntfs_inode_close(hardlink_target_ni) != 0) { + if (ret == 0) + ret = WIMLIB_ERR_NTFS_3G; + ERROR_WITH_ERRNO("Failed to close hardlink target inode"); + } + } return ret; } @@ -387,6 +444,7 @@ static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg) int ret; char *p; char orig; + ntfs_inode *close_after_dir; const char *dir_name; wimlib_assert(dentry->full_path_utf8); @@ -416,16 +474,48 @@ static int wim_apply_dentry_ntfs(struct dentry *dentry, void *arg) return WIMLIB_ERR_NTFS_3G; } DEBUG("Found NTFS inode for `%s'", dir_name); + return do_wim_apply_dentry_ntfs(dentry, dir_ni, w); +} + +static int wim_apply_dentry_timestamps(struct dentry *dentry, void *arg) +{ + struct ntfs_apply_args *args = arg; + ntfs_volume *vol = args->vol; + int extract_flags = args->extract_flags; + WIMStruct *w = args->w; + char *p; + char buf[24]; + ntfs_inode *ni; + int ret = 0; - ret = do_wim_apply_dentry_ntfs(dentry, dir_ni, w); - if (ntfs_inode_close(dir_ni) != 0) { + DEBUG("Setting timestamps on `%s'", dentry->full_path_utf8); + + ni = ntfs_pathname_to_inode(vol, NULL, dentry->full_path_utf8); + if (!ni) { + ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", + dentry->full_path_utf8); + return WIMLIB_ERR_NTFS_3G; + } + + p = buf; + p = put_u64(p, dentry->creation_time); + p = put_u64(p, dentry->last_write_time); + p = put_u64(p, dentry->last_access_time); + ret = ntfs_inode_set_times(ni, buf, 3 * sizeof(u64), 0); + if (ret != 0) { + ERROR_WITH_ERRNO("Failed to set NTFS timestamps on `%s'", + dentry->full_path_utf8); + ret = WIMLIB_ERR_NTFS_3G; + } + + if (ntfs_inode_close(ni) != 0) { if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; - ERROR_WITH_ERRNO("Failed to close directory inode"); + ERROR_WITH_ERRNO("Failed to close NTFS inode for `%s'", + dentry->full_path_utf8); } return ret; - } static int do_wim_apply_image_ntfs(WIMStruct *w, const char *device, int extract_flags) @@ -445,6 +535,14 @@ static int do_wim_apply_image_ntfs(WIMStruct *w, const char *device, int extract }; ret = for_dentry_in_tree(wim_root_dentry(w), wim_apply_dentry_ntfs, &args); + + if (ret != 0) + goto out; + DEBUG("Setting NTFS timestamps"); + ret = for_dentry_in_tree_depth(wim_root_dentry(w), + wim_apply_dentry_timestamps, + &args); +out: if (ntfs_umount(vol, FALSE) != 0) { ERROR_WITH_ERRNO("Failed to unmount NTFS volume `%s'", device); if (ret == 0) diff --git a/src/util.c b/src/util.c index 985d11b8..1e134f7a 100644 --- a/src/util.c +++ b/src/util.c @@ -267,7 +267,7 @@ static iconv_t cd_utf16_to_utf8 = (iconv_t)(-1); /* Converts a string in the UTF-16 encoding to a newly allocated string in the * UTF-8 encoding. */ char *utf16_to_utf8(const char *utf16_str, size_t utf16_len, - size_t *utf8_len_ret) + size_t *utf8_len_ret) { if (cd_utf16_to_utf8 == (iconv_t)(-1)) { cd_utf16_to_utf8 = iconv_open("UTF-8", "UTF-16LE"); diff --git a/src/wimlib.h b/src/wimlib.h index 9aa8a05a..a379a42f 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -201,20 +201,6 @@ typedef struct WIMStruct WIMStruct; #endif -/** - * Specifies the way in which identical files are linked when extracting - * image(s) from the WIM. - */ -enum wim_link_type { -/** Hard link identical files when extracting files from the WIM. */ - WIM_LINK_TYPE_HARD = 0, -/** Symbolic link identical files when extracting files from the WIM. */ - WIM_LINK_TYPE_SYMBOLIC = 1, -/** Do not create links when extracting identical files from the WIM (default). - * */ - WIM_LINK_TYPE_NONE = 2, -}; - /** * Specifies the compression type of a WIM file. */ @@ -274,13 +260,8 @@ enum wim_compression_type { * 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 - /** Follow symlinks; archive and dump the files they point to. */ -#define WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE 0x00000008 +#define WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE 0x00000004 /** See documentation for wimlib_export_image(). */ #define WIMLIB_EXPORT_FLAG_BOOT 0x00000001 @@ -296,10 +277,12 @@ enum wim_compression_type { #define WIMLIB_OPEN_FLAG_SPLIT_OK 0x00000004 -/** When identical files are extracted from the WIM, hard link them together. */ +/** When identical files are extracted from the WIM, always hard link them + * together. */ #define WIMLIB_EXTRACT_FLAG_HARDLINK 0x00000001 -/** When identical files are extracted from the WIM, symlink them together. */ +/** When identical files are extracted from the WIM, always symlink them + * together. */ #define WIMLIB_EXTRACT_FLAG_SYMLINK 0x00000002 /** Print the name of each file as it is extracted from the WIM image. */ @@ -1155,25 +1138,6 @@ extern int wimlib_set_image_descripton(WIMStruct *wim, int image, */ extern int wimlib_set_image_name(WIMStruct *wim, int image, const char *name); -/** - * Sets the link type to use when extracting files from a WIM. This applies - * when extracting one image as well as when extracting all images. Cross-image - * links may save a lot of space because it is common for files to be referenced - * multiple times in WIM files. By default, the link type used for extraction - * is ::WIM_LINK_TYPE_NONE, meaning that links are not created. - * - * @param wim - * Pointer to the ::WIMStruct for a WIM file - * @param link_type - * ::WIM_LINK_TYPE_NONE, ::WIM_LINK_TYPE_SYMBOLIC, or ::WIM_LINK_TYPE_HARD. - * - * @return 0 on success; nonzero on error. - * @retval ::WIMLIB_ERR_INVALID_PARAM - * @a link_type was not ::WIM_LINK_TYPE_NONE, ::WIM_LINK_TYPE_SYMBOLIC, - * or ::WIM_LINK_TYPE_HARD. - */ -extern int wimlib_set_link_type(WIMStruct *wim, int link_type); - /** * Set the functions that wimlib uses to allocate and free memory. * -- 2.43.0