From dff049d44d86598d82bf78d3fdcfedc28db83018 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sun, 26 Aug 2012 18:46:47 -0500 Subject: [PATCH] Misc fixes - Remove code pertaining to root permissions. We don't need to be root to do a NTFS apply anymore. - Improve comments on fields of `struct dentry'. - Another fix to hard-link creation in the NTFS apply. We close the directory inode before opening the target inode and re-opening the directory inode, so that we can make sure the directory inode will not be opened twice at the same time. --- src/dentry.h | 39 ++++++++++++++++++++++------------ src/lookup_table.h | 1 + src/ntfs-apply.c | 52 ++++++++++++++++++++++++++++++++++++---------- src/ntfs-capture.c | 13 ++++++++---- src/util.c | 2 -- src/wimlib.h | 1 - 6 files changed, 77 insertions(+), 31 deletions(-) diff --git a/src/dentry.h b/src/dentry.h index e030acf0..d634abcd 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -114,24 +114,33 @@ struct dentry { /* Pointer to a child of this directory entry. */ struct dentry *children; - /* Size of directory entry, in bytes. Typical size is around 104 to 120 - * bytes. */ - /* It is possible for the length field to be 0. This situation, which + /* Size of directory entry on disk, in bytes. Typical size is around + * 104 to 120 bytes. + * + * It is possible for the length field to be 0. This situation, which * is undocumented, indicates the end of a list of sibling nodes in a * directory. It also means the real length is 8, because the dentry - * included only the length field, but that takes up 8 bytes. */ + * included only the length field, but that takes up 8 bytes. + * + * The length here includes the base directory entry on disk as well as + * the long and short filenames. It does NOT include any alternate + * stream entries that may follow the directory entry, even though the + * size of those needs to be considered. + */ u64 length; /* The file attributes associated with this file. */ u32 attributes; - /* 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. */ + /* The index of the security descriptor in the WIM image's table of + * security descriptors that contains this file's security information. + * If -1, no security information exists for this file. */ int32_t security_id; - /* The offset, from the start of the metadata section, of this directory - * entry's child files. 0 if the directory entry has no children. */ + /* The offset, from the start of the WIM metadata resource for this + * image, of this directory entry's child files. 0 if the directory + * entry has no children (as in the case of regular files or reparse + * points). */ u64 subdir_offset; /* Timestamps for the dentry. The timestamps are the number of @@ -142,15 +151,15 @@ struct dentry { u64 last_write_time; /* true if the dentry's lookup table entry has been resolved (i.e. the - * @lte field is invalid, but the @hash field is not valid) */ + * @lte field is valid, but the @hash field is not valid) */ bool resolved; /* A hash of the file's contents, or a pointer to the lookup table entry * for this dentry if the lookup table entries have been resolved. * * More specifically, this is for the un-named default file stream, as - * opposed to the alternate file streams, which may have their own - * lookup table entries. */ + * opposed to the alternate (named) file streams, which may have their + * own lookup table entries. */ union { u8 hash[SHA1_HASH_SIZE]; struct lookup_table_entry *lte; @@ -210,7 +219,11 @@ struct dentry { }; /* If the file is part of a hard link set, all the directory entries in - * the set will share the same value for this field. */ + * the set will share the same value for this field. + * + * Unfortunately, in some WIMs it is NOT the case that all dentries that + * share this field are actually in the same hard link set, although the + * WIMs that wimlib writes maintain this restriction. */ u64 hard_link; enum { diff --git a/src/lookup_table.h b/src/lookup_table.h index 79fdf116..6a07aaa9 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -33,6 +33,7 @@ struct ntfs_location { char *stream_name_utf16; u16 stream_name_utf16_num_chars; ntfs_volume **ntfs_vol_p; + bool is_reparse_point; }; /* diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index c4e09fe5..4118a30a 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -141,6 +141,15 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry, return ret; } +static bool in_same_dir(const char *path1, const char *path2) +{ + const char *p1 = strrchr(path1, '/'); + const char *p2 = strrchr(path2, '/'); + if (p1 - path1 != p2 - path2) + return false; + return memcmp(path1, path2, p1 - path1) == 0; +} + /* * Makes a NTFS hard link * @@ -156,21 +165,52 @@ static int wim_apply_hardlink_ntfs(const struct dentry *from_dentry, ntfs_inode **to_ni_ret) { int ret; + char *p; + char orig; + const char *dir_name; + ntfs_inode *to_ni; + ntfs_volume *vol; wimlib_assert(dentry_is_regular_file(from_dentry) && dentry_is_regular_file(to_dentry)); + if (ntfs_inode_close(dir_ni) != 0) { + ERROR_WITH_ERRNO("Error closing directory"); + return WIMLIB_ERR_NTFS_3G; + } + + vol = dir_ni->vol; + DEBUG("Extracting NTFS hard link `%s' => `%s'", from_dentry->full_path_utf8, to_dentry->extracted_file); - to_ni = ntfs_pathname_to_inode(dir_ni->vol, NULL, + to_ni = ntfs_pathname_to_inode(vol, NULL, to_dentry->extracted_file); if (!to_ni) { ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", to_dentry->extracted_file); return WIMLIB_ERR_NTFS_3G; } + p = from_dentry->full_path_utf8 + from_dentry->full_path_utf8_len; + do { + p--; + } while (*p != '/'); + + orig = *p; + *p = '\0'; + dir_name = from_dentry->full_path_utf8; + + dir_ni = ntfs_pathname_to_inode(vol, NULL, + from_dentry->full_path_utf8); + if (!dir_ni) { + ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", + from_dentry->full_path_utf8); + *p = orig; + return WIMLIB_ERR_NTFS_3G; + } + *p = orig; + ret = ntfs_link(to_ni, dir_ni, (ntfschar*)from_dentry->file_name, from_dentry->file_name_len / 2); @@ -687,16 +727,6 @@ WIMLIBAPI int wimlib_apply_image_to_ntfs_volume(WIMStruct *w, int image, if (ret != 0) return ret; -#if 0 - if (getuid() != 0) { - ERROR("We are not root, but NTFS-3g requires root privileges to set arbitrary"); - ERROR("security data on the NTFS filesystem. Please run this program as root"); - ERROR("if you want to extract a WIM image while preserving NTFS-specific"); - ERROR("information."); - - return WIMLIB_ERR_NOT_ROOT; - } -#endif return do_wim_apply_image_ntfs(w, device, flags); } diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index 08868419..56e1c539 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -127,8 +127,8 @@ static int sd_set_add_sd(struct sd_set *sd_set, const u8 *descriptor, u64 *sizes; u8 *descr_copy; struct wim_security_data *sd; - sha1_buffer(descriptor, size, hash); + sha1_buffer(descriptor, size, hash); security_id = lookup_sd(hash, sd_set->root); if (security_id >= 0) return security_id; @@ -268,7 +268,6 @@ static int capture_ntfs_streams(struct dentry *dentry, ntfs_inode *ni, } else { struct ntfs_location *ntfs_loc; - ntfs_loc = CALLOC(1, sizeof(*ntfs_loc)); if (!ntfs_loc) goto out_put_actx; @@ -285,6 +284,7 @@ static int capture_ntfs_streams(struct dentry *dentry, ntfs_inode *ni, actx->attr->name_length * 2); ntfs_loc->stream_name_utf16_num_chars = actx->attr->name_length; + ntfs_loc->is_reparse_point = (type == AT_REPARSE_POINT); lte = new_lookup_table_entry(); if (!lte) goto out_free_ntfs_loc; @@ -296,7 +296,12 @@ static int capture_ntfs_streams(struct dentry *dentry, ntfs_inode *ni, lookup_table_insert(lookup_table, lte); } if (actx->attr->name_length == 0) { - wimlib_assert(!dentry->lte); + if (dentry->lte) { + ERROR("Found two un-named data streams for " + "`%s'", path); + ret = WIMLIB_ERR_NTFS_3G; + goto out_free_lte; + } dentry->lte = lte; } else { struct ads_entry *new_ads_entry; @@ -305,8 +310,8 @@ static int capture_ntfs_streams(struct dentry *dentry, ntfs_inode *ni, &stream_name_utf16_len); if (!stream_name_utf8) goto out_free_lte; - FREE(stream_name_utf8); new_ads_entry = dentry_add_ads(dentry, stream_name_utf8); + FREE(stream_name_utf8); if (!new_ads_entry) goto out_free_lte; diff --git a/src/util.c b/src/util.c index 1e134f7a..b2d26256 100644 --- a/src/util.c +++ b/src/util.c @@ -165,8 +165,6 @@ static const char *error_strings[] = { "identify a WIM file", [WIMLIB_ERR_NO_FILENAME] = "The WIM is not identified with a filename", - [WIMLIB_ERR_NOT_ROOT] - = "Root privileges are required for this operation", [WIMLIB_ERR_NTFS_3G] = "NTFS-3g encountered an error (check errno)", [WIMLIB_ERR_OPEN] diff --git a/src/wimlib.h b/src/wimlib.h index 928f2401..6d9eef48 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -322,7 +322,6 @@ enum wimlib_error_code { WIMLIB_ERR_NOMEM, WIMLIB_ERR_NOTDIR, WIMLIB_ERR_NOT_A_WIM_FILE, - WIMLIB_ERR_NOT_ROOT, WIMLIB_ERR_NO_FILENAME, WIMLIB_ERR_NTFS_3G, WIMLIB_ERR_OPEN, -- 2.43.0