X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fntfs-apply.c;h=214ac2d617688a8049852f4dcf8bbd5d71930969;hp=ab46c9179e8dd45f02f477675b070792d440fa3e;hb=89ef4adba6571c53200b0c72852784506670b596;hpb=051e6d3d1c88715d21b422fbcc806ab02d61ab67 diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index ab46c917..214ac2d6 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -75,7 +75,7 @@ extract_wim_resource_to_ntfs_attr(const struct lookup_table_entry *lte, * Returns 0 on success, nonzero on failure. */ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry, - struct apply_args *args) + union wimlib_progress_info *progress_info) { int ret = 0; unsigned stream_idx = 0; @@ -90,7 +90,6 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry, while (1) { struct lookup_table_entry *lte; - ntfs_attr *na; lte = inode_stream_lte_resolved(inode, stream_idx); @@ -112,6 +111,8 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry, * Otherwise, we must open the attribute and extract the data. * */ if (lte) { + ntfs_attr *na; + na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); if (!na) { ERROR_WITH_ERRNO("Failed to open a data stream of " @@ -120,11 +121,17 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry, ret = WIMLIB_ERR_NTFS_3G; break; } + ret = ntfs_attr_truncate_solid(na, wim_resource_size(lte)); + if (ret != 0) { + ntfs_attr_close(na); + break; + } + ret = extract_wim_resource_to_ntfs_attr(lte, na); + ntfs_attr_close(na); if (ret != 0) break; - args->progress.extract.completed_bytes += wim_resource_size(lte); - ntfs_attr_close(na); + progress_info->extract.completed_bytes += wim_resource_size(lte); } if (stream_idx == inode->num_ads) break; @@ -135,6 +142,32 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct dentry *dentry, return ret; } +/* Open the NTFS inode that corresponds to the parent of a WIM dentry. */ +static ntfs_inode *dentry_open_parent_ni(const struct dentry *dentry, + ntfs_volume *vol) +{ + char *p; + const char *dir_name; + ntfs_inode *dir_ni; + char orig; + + p = dentry->full_path_utf8 + dentry->full_path_utf8_len; + do { + p--; + } while (*p != '/'); + + orig = *p; + *p = '\0'; + dir_name = dentry->full_path_utf8; + dir_ni = ntfs_pathname_to_inode(vol, NULL, dir_name); + if (!dir_ni) { + ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", + dir_name); + } + *p = orig; + return dir_ni; +} + /* * Makes a NTFS hard link * @@ -157,9 +190,6 @@ static int apply_hardlink_ntfs(const struct dentry *from_dentry, ntfs_inode *to_ni; ntfs_volume *vol; - wimlib_assert(dentry_is_regular_file(from_dentry) - && inode_is_regular_file(inode)); - if (ntfs_inode_close(dir_ni) != 0) { ERROR_WITH_ERRNO("Error closing directory"); return WIMLIB_ERR_NTFS_3G; @@ -176,23 +206,12 @@ static int apply_hardlink_ntfs(const struct dentry *from_dentry, inode->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; + *to_ni_ret = to_ni; - dir_ni = ntfs_pathname_to_inode(vol, NULL, dir_name); - if (!dir_ni) { - ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", - from_dentry->full_path_utf8); - *p = orig; + dir_ni = dentry_open_parent_ni(from_dentry, vol); + if (!dir_ni) return WIMLIB_ERR_NTFS_3G; - } - *p = orig; ret = ntfs_link(to_ni, dir_ni, (ntfschar*)from_dentry->file_name, @@ -203,7 +222,6 @@ static int apply_hardlink_ntfs(const struct dentry *from_dentry, inode->extracted_file); ret = WIMLIB_ERR_NTFS_3G; } - *to_ni_ret = to_ni; return ret; } @@ -254,7 +272,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, } static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry, - struct apply_args *args) + union wimlib_progress_info *progress_info) { struct lookup_table_entry *lte; int ret = 0; @@ -292,7 +310,7 @@ static int apply_reparse_data(ntfs_inode *ni, const struct dentry *dentry, dentry->full_path_utf8); return WIMLIB_ERR_NTFS_3G; } - args->progress.extract.completed_bytes += wim_resource_size(lte); + progress_info->extract.completed_bytes += wim_resource_size(lte); return 0; } @@ -342,22 +360,10 @@ static int preapply_dentry_with_dos_name(struct dentry *dentry, *dir_ni_p, args); if (ret != 0) return ret; - p = dentry->full_path_utf8 + dentry->full_path_utf8_len; - do { - p--; - } while (*p != '/'); - - orig = *p; - *p = '\0'; - dir_name = dentry->full_path_utf8; - - *dir_ni_p = ntfs_pathname_to_inode(vol, NULL, dir_name); - *p = orig; - if (!*dir_ni_p) { - ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", - dir_name); + + *dir_ni_p = dentry_open_parent_ni(dentry, vol); + if (!*dir_ni_p) return WIMLIB_ERR_NTFS_3G; - } } return 0; } @@ -379,13 +385,15 @@ static int do_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni, bool is_hardlink = false; ntfs_volume *vol = dir_ni->vol; struct inode *inode = dentry->d_inode; - dentry->is_extracted = true; + dentry->is_extracted = 1; if (inode->attributes & FILE_ATTRIBUTE_DIRECTORY) { type = S_IFDIR; } else { - /* Apply hard-linked directory in same directory with DOS name - * (if there is one) before this dentry */ + /* If this dentry is hard-linked to any other dentries in the + * same directory, make sure to apply the one (if any) with a + * DOS name first. Otherwise, NTFS-3g might not assign the file + * names correctly. */ if (dentry->short_name_len == 0) { ret = preapply_dentry_with_dos_name(dentry, &dir_ni, args); @@ -438,7 +446,7 @@ static int do_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni, * */ if (!(inode->attributes & (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))) { - ret = write_ntfs_data_streams(ni, dentry, args); + ret = write_ntfs_data_streams(ni, dentry, &args->progress); if (ret != 0) goto out_close_dir_ni; } @@ -450,7 +458,7 @@ static int do_apply_dentry_ntfs(struct dentry *dentry, ntfs_inode *dir_ni, goto out_close_dir_ni; if (inode->attributes & FILE_ATTR_REPARSE_POINT) { - ret = apply_reparse_data(ni, dentry, args); + ret = apply_reparse_data(ni, dentry, &args->progress); if (ret != 0) goto out_close_dir_ni; } @@ -480,35 +488,29 @@ out_set_dos_name: if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; ERROR_WITH_ERRNO("Failed to close directory inode"); + goto out_close_ni; } if (ntfs_inode_close(ni) != 0) { if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; ERROR_WITH_ERRNO("Failed to close hard link target inode"); + goto out; } - p = dentry->full_path_utf8 + dentry->full_path_utf8_len; - do { - p--; - } while (*p != '/'); - - orig = *p; - *p = '\0'; - dir_name = dentry->full_path_utf8; - dir_ni = ntfs_pathname_to_inode(vol, NULL, dir_name); - *p = orig; + dir_ni = dentry_open_parent_ni(dentry, vol); if (!dir_ni) { - ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", - dir_name); - return WIMLIB_ERR_NTFS_3G; + ret = WIMLIB_ERR_NTFS_3G; + goto out; } + ni = ntfs_pathname_to_inode(vol, dir_ni, dentry->file_name_utf8); if (!ni) { ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", dentry->full_path_utf8); ntfs_inode_close(dir_ni); - return WIMLIB_ERR_NTFS_3G; + ret = WIMLIB_ERR_NTFS_3G; + goto out_close_dir_ni; } } @@ -542,12 +544,14 @@ out_close_dir_ni: ret = WIMLIB_ERR_NTFS_3G; ERROR_WITH_ERRNO("Failed to close directory inode"); } +out_close_ni: if (ni && ntfs_inode_close(ni) != 0) { if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; ERROR_WITH_ERRNO("Failed to close inode for `%s'", dentry->full_path_utf8); } +out: return ret; } @@ -576,51 +580,18 @@ static int apply_root_dentry_ntfs(const struct dentry *dentry, int apply_dentry_ntfs(struct dentry *dentry, void *arg) { struct apply_args *args = arg; - ntfs_volume *vol = args->vol; - int extract_flags = args->extract_flags; - WIMStruct *w = args->w; + ntfs_volume *vol = args->vol; + WIMStruct *w = args->w; ntfs_inode *dir_ni; - char *p; - char orig; - const char *dir_name; - - if (dentry->is_extracted) - return 0; - - if (extract_flags & WIMLIB_EXTRACT_FLAG_NO_STREAMS) - if (inode_unnamed_lte_resolved(dentry->d_inode)) - return 0; - - DEBUG("Applying dentry `%s' to NTFS", dentry->full_path_utf8); - - if ((extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) && - args->progress_func) - { - args->progress.extract.cur_path = dentry->full_path_utf8; - args->progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY, - &args->progress); - } if (dentry_is_root(dentry)) return apply_root_dentry_ntfs(dentry, vol, w); - p = dentry->full_path_utf8 + dentry->full_path_utf8_len; - do { - p--; - } while (*p != '/'); - - orig = *p; - *p = '\0'; - dir_name = dentry->full_path_utf8; - - dir_ni = ntfs_pathname_to_inode(vol, NULL, dir_name); - *p = orig; - if (!dir_ni) { - ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", - dir_name); + dir_ni = dentry_open_parent_ni(dentry, vol); + if (dir_ni) + return do_apply_dentry_ntfs(dentry, dir_ni, arg); + else return WIMLIB_ERR_NTFS_3G; - } - return do_apply_dentry_ntfs(dentry, dir_ni, arg); } int apply_dentry_timestamps_ntfs(struct dentry *dentry, void *arg)