From: Eric Biggers Date: Mon, 22 Apr 2013 05:58:45 +0000 (-0500) Subject: Windows rpfix capture (in progress) X-Git-Tag: v1.3.3~52 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=ca3f717fa42ec38d85dc020821340e59a15c25df Windows rpfix capture (in progress) --- diff --git a/src/add_image.c b/src/add_image.c index e45bc1c1..8e97a8ec 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -179,53 +179,6 @@ unix_capture_directory(struct wim_dentry *dir_dentry, return ret; } -static char * -fixup_symlink(char *dest, ino_t capture_root_ino, dev_t capture_root_dev) -{ - char *p = dest; - struct stat stbuf; - - for (;;) { - char save; - int ret; - - while (*p == '/') - p++; - - save = *p; - *p = '\0'; - if (stat(dest, &stbuf)) { - WARNING_WITH_ERRNO("Failed to stat \"%s\": %m", dest); - *p = save; - /* Treat as a link pointing outside the capture root (it - * most likely is). */ - return NULL; - } - *p = save; - - if (stbuf.st_ino == capture_root_ino && - stbuf.st_dev == capture_root_dev) - { - /* Link points inside capture root. Return abbreviated - * path. */ - if (*p == '\0') - *(p - 1) = '/'; - while (p - 1 >= dest && *(p - 1) == '/') - p--; - return p; - } - - if (*p == '\0') { - /* Link points outside capture root. */ - return NULL; - } - - do { - p++; - } while (*p != '/' && *p != '\0'); - } -} - static int unix_capture_symlink(struct wim_dentry **root_p, const char *path, @@ -269,6 +222,7 @@ unix_capture_symlink(struct wim_dentry **root_p, *root_p = NULL; return 0; } + inode->i_not_rpfixed = 0; } ret = inode_set_symlink(inode, dest, params->lookup_table, NULL); diff --git a/src/dentry.c b/src/dentry.c index 5b19f6f5..99fb2426 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -702,6 +702,7 @@ new_timeless_inode() inode->i_security_id = -1; inode->i_nlink = 1; inode->i_next_stream_id = 1; + inode->i_not_rpfixed = 1; #ifdef WITH_FUSE if (pthread_mutex_init(&inode->i_mutex, NULL) != 0) { ERROR_WITH_ERRNO("Error initializing mutex"); @@ -1217,8 +1218,9 @@ replace_forbidden_characters(utf16lechar *name) #ifdef __WIN32__ if (wcschr(L"<>:\"/\\|?*", (wchar_t)*p)) #else - if (*p == '/') { + if (*p == '/') #endif + { if (name) { WARNING("File, directory, or stream name \"%"WS"\"\n" " contains forbidden characters; " @@ -1482,7 +1484,8 @@ read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { p += 4; p = get_u32(p, &inode->i_reparse_tag); - p += 4; + p += 2; + p = get_u16(p, &inode->i_not_rpfixed); } else { p += 4; /* i_reparse_tag is irrelevant; just leave it at 0. */ @@ -1754,9 +1757,10 @@ write_dentry(const struct wim_dentry *dentry, u8 *p) hash = inode_stream_hash(inode, 0); p = put_bytes(p, SHA1_HASH_SIZE, hash); if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { - p = put_zeroes(p, 4); + p = put_u32(p, 0); p = put_u32(p, inode->i_reparse_tag); - p = put_zeroes(p, 4); + p = put_u16(p, 0); + p = put_u16(p, inode->i_not_rpfixed); } else { u64 link_group_id; p = put_u32(p, 0); diff --git a/src/dentry.h b/src/dentry.h index 5d12b4b8..042ffe60 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -231,6 +231,8 @@ struct wim_inode { /* Used only in NTFS-mode extraction */ u8 i_dos_name_extracted : 1; + u16 i_not_rpfixed; + /* Number of alternate data streams associated with this inode */ u16 i_num_ads; diff --git a/src/symlink.c b/src/symlink.c index dc365e8c..366e54ed 100644 --- a/src/symlink.c +++ b/src/symlink.c @@ -29,10 +29,11 @@ #include "sha1.h" #include -/* None of this file is ever needed in Win32 builds because the reparse point - * buffers are not parsed. */ +/* UNIX version of getting and setting the data in reparse points */ #if !defined(__WIN32__) +#include + /* * Find the symlink target of a symbolic link or junction point in the WIM. * @@ -54,6 +55,7 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf, u16 print_name_offset; u16 print_name_len; char *link_target; + char *translated_target; size_t link_target_len; ssize_t ret; unsigned header_size; @@ -92,54 +94,55 @@ get_symlink_name(const void *resource, size_t resource_len, char *buf, DEBUG("Interpeting substitute name \"%s\" (ReparseTag=0x%x)", link_target, reparse_tag); translate_slashes = true; + translated_target = link_target; if (link_target_len >= 7 && - link_target[0] == '\\' && - link_target[1] == '?' && - link_target[2] == '?' && - link_target[3] == '\\' && - link_target[4] != '\0' && - link_target[5] == ':' && - link_target[6] == '\\') + translated_target[0] == '\\' && + translated_target[1] == '?' && + translated_target[2] == '?' && + translated_target[3] == '\\' && + translated_target[4] != '\0' && + translated_target[5] == ':' && + translated_target[6] == '\\') { /* "Full" symlink or junction (\??\x:\ prefixed path) */ - link_target += 6; + translated_target += 6; link_target_len -= 6; } else if (reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT && link_target_len >= 12 && - memcmp(link_target, "\\\\?\\Volume{", 11) == 0 && - link_target[link_target_len - 1] == '\\') + memcmp(translated_target, "\\\\?\\Volume{", 11) == 0 && + translated_target[link_target_len - 1] == '\\') { /* Volume junction. Can't really do anything with it. */ translate_slashes = false; } else if (reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK && link_target_len >= 3 && - link_target[0] != '\0' && - link_target[1] == ':' && - link_target[2] == '/') + translated_target[0] != '\0' && + translated_target[1] == ':' && + translated_target[2] == '/') { /* "Absolute" symlink, with drive letter */ - link_target += 2; + translated_target += 2; link_target_len -= 2; } else if (reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK && link_target_len >= 1) { - if (link_target[0] == '/') + if (translated_target[0] == '/') /* "Absolute" symlink, without drive letter */ ; else /* "Relative" symlink, without drive letter */ ; } else { - ERROR("Invalid reparse point: \"%s\"", link_target); + ERROR("Invalid reparse point: \"%s\"", translated_target); ret = -EIO; goto out; } if (translate_slashes) for (size_t i = 0; i < link_target_len; i++) - if (link_target[i] == '\\') - link_target[i] = '/'; - memcpy(buf, link_target, link_target_len + 1); + if (translated_target[i] == '\\') + translated_target[i] = '/'; + memcpy(buf, translated_target, link_target_len + 1); ret = link_target_len; out: FREE(link_target); @@ -156,24 +159,26 @@ make_symlink_reparse_data_buf(const char *symlink_target, ret = tstr_to_utf16le(symlink_target, strlen(symlink_target), &name_utf16le, &name_utf16le_nbytes); - if (ret != 0) + if (ret) return ret; for (size_t i = 0; i < name_utf16le_nbytes / 2; i++) if (name_utf16le[i] == cpu_to_le16('/')) name_utf16le[i] = cpu_to_le16('\\'); - size_t len = 12 + name_utf16le_nbytes * 2; + size_t len = 12 + (name_utf16le_nbytes + 2) * 2; void *buf = MALLOC(len); if (buf) { void *p = buf; - p = put_u16(p, name_utf16le_nbytes); /* Substitute name offset */ + p = put_u16(p, 0); /* Substitute name offset */ p = put_u16(p, name_utf16le_nbytes); /* Substitute name length */ - p = put_u16(p, 0); /* Print name offset */ + p = put_u16(p, name_utf16le_nbytes + 2); /* Print name offset */ p = put_u16(p, name_utf16le_nbytes); /* Print name length */ - p = put_u32(p, 1); /* flags: 0 iff *full* target, including drive letter??? */ + p = put_u32(p, 1); /* flags: 0 if relative link, otherwise 1 */ p = put_bytes(p, name_utf16le_nbytes, name_utf16le); + p = put_u16(p, 0); p = put_bytes(p, name_utf16le_nbytes, name_utf16le); + p = put_u16(p, 0); *len_ret = len; *buf_ret = buf; ret = 0; @@ -284,4 +289,86 @@ out_free_symlink_buf: return ret; } +static int +unix_get_ino_and_dev(const char *path, u64 *ino_ret, u64 *dev_ret) +{ + struct stat stbuf; + if (stat(path, &stbuf)) { + WARNING_WITH_ERRNO("Failed to stat \"%s\"", path); + /* Treat as a link pointing outside the capture root (it + * most likely is). */ + return WIMLIB_ERR_STAT; + } else { + *ino_ret = stbuf.st_ino; + *dev_ret = stbuf.st_dev; + return 0; + } +} + #endif /* !defined(__WIN32__) */ + +#ifdef __WIN32__ +# include "win32.h" +# define RP_PATH_SEPARATOR L'\\' +# define os_get_ino_and_dev win32_get_file_and_vol_ids +#else +# define RP_PATH_SEPARATOR '/' +# define os_get_ino_and_dev unix_get_ino_and_dev +#endif + +/* Fix up reparse points--- mostly shared between UNIX and Windows */ +tchar * +fixup_symlink(tchar *dest, u64 capture_root_ino, u64 capture_root_dev) +{ + tchar *p = dest; + +#ifdef __WIN32__ + /* Skip over drive letter */ + if (*p != RP_PATH_SEPARATOR) + p += 2; +#endif + + DEBUG("Fixing symlink or junction \"%"TS"\"", dest); + for (;;) { + tchar save; + int ret; + u64 ino; + u64 dev; + + while (*p == RP_PATH_SEPARATOR) + p++; + + save = *p; + *p = T('\0'); + ret = os_get_ino_and_dev(dest, &ino, &dev); + *p = save; + + if (ino == capture_root_ino && dev == capture_root_dev) { + /* Link points inside capture root. Return abbreviated + * path. */ + if (*p == T('\0')) + *(p - 1) = RP_PATH_SEPARATOR; + while (p - 1 >= dest && *(p - 1) == RP_PATH_SEPARATOR) + p--; + #ifdef __WIN32__ + /* Add back drive letter */ + if (*dest != RP_PATH_SEPARATOR) { + *--p = *(dest + 1); + *--p = *dest; + } + #endif + wimlib_assert(p >= dest); + return p; + } + + if (*p == T('\0')) { + /* Link points outside capture root. */ + return NULL; + } + + do { + p++; + } while (*p != RP_PATH_SEPARATOR && *p != T('\0')); + } +} + diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 1d3edcd7..bde430f1 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -671,6 +671,8 @@ inode_set_symlink(struct wim_inode *inode, const char *target, struct wim_lookup_table *lookup_table, struct wim_lookup_table_entry **lte_ret); #endif +extern tchar * +fixup_symlink(tchar *dest, u64 capture_root_ino, u64 capture_root_dev); /* verify.c */ diff --git a/src/win32.c b/src/win32.c index 77422249..b10a4058 100644 --- a/src/win32.c +++ b/src/win32.c @@ -39,6 +39,7 @@ #include "lookup_table.h" #include "security.h" #include "endianness.h" +#include "buffer_io.h" #include #include @@ -493,12 +494,7 @@ static int win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, wchar_t *path, size_t path_num_chars, - struct wim_lookup_table *lookup_table, - struct wim_inode_table *inode_table, - struct sd_set *sd_set, - const struct wimlib_capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, + struct add_image_params *params, struct win32_capture_state *state, unsigned vol_flags); @@ -508,12 +504,7 @@ static int win32_recurse_directory(struct wim_dentry *root, wchar_t *dir_path, size_t dir_path_num_chars, - struct wim_lookup_table *lookup_table, - struct wim_inode_table *inode_table, - struct sd_set *sd_set, - const struct wimlib_capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, + struct add_image_params *params, struct win32_capture_state *state, unsigned vol_flags) { @@ -564,12 +555,7 @@ win32_recurse_directory(struct wim_dentry *root, ret = win32_build_dentry_tree_recursive(&child, dir_path, path_len, - lookup_table, - inode_table, - sd_set, - config, - add_image_flags, - progress_func, + params, state, vol_flags); dir_path[dir_path_num_chars] = L'\0'; @@ -590,6 +576,171 @@ out_find_close: return ret; } +int +win32_get_file_and_vol_ids(const wchar_t *path, u64 *ino_ret, u64 *dev_ret) +{ + HANDLE hFile; + DWORD err; + BY_HANDLE_FILE_INFORMATION file_info; + int ret; + + hFile = win32_open_existing_file(path, FILE_READ_ATTRIBUTES); + if (hFile == INVALID_HANDLE_VALUE) { + err = GetLastError(); + WARNING("Failed to open \"%ls\" to get file and volume IDs", + path); + win32_error(err); + return WIMLIB_ERR_OPEN; + } + + if (!GetFileInformationByHandle(hFile, &file_info)) { + err = GetLastError(); + ERROR("Failed to get file information for \"%ls\"", path); + win32_error(err); + ret = WIMLIB_ERR_STAT; + } else { + *ino_ret = ((u64)file_info.nFileIndexHigh << 32) | + (u64)file_info.nFileIndexLow; + *dev_ret = file_info.dwVolumeSerialNumber; + ret = 0; + } + CloseHandle(hFile); + return ret; +} + +enum rp_status { + RP_EXCLUDED = 0x0, + RP_NOT_FIXED = 0x1, + RP_FIXED_FULLPATH = 0x2, + RP_FIXED_ABSPATH = 0x4, + RP_FIXED = RP_FIXED_FULLPATH | RP_FIXED_ABSPATH, +}; + +static enum rp_status +win32_maybe_rpfix_target(wchar_t *target, size_t *target_nchars_p, + u64 capture_root_ino, u64 capture_root_dev) +{ + size_t target_nchars= *target_nchars_p; + size_t stripped_chars; + wchar_t *orig_target; + + if (target_nchars == 0) + return RP_NOT_FIXED; + + if (target[0] == L'\\') { + if (target_nchars >= 2 && target[1] == L'\\') { + /* Probaby a volume. Can't do anything with it. */ + DEBUG("Not fixing target (probably a volume)"); + return RP_NOT_FIXED; + } else if (target_nchars >= 7 && + target[1] == '?' && + target[2] == '?' && + target[3] == '\\' && + target[4] != '\0' && + target[5] == ':' && + target[6] == '\\') + { + DEBUG("Full style path"); + /* Full \??\x:\ style path (may be junction or symlink) + * */ + stripped_chars = 4; + } else { + DEBUG("Absolute target without drive letter"); + /* Absolute target, without drive letter */ + stripped_chars = 0; + } + } else if (target_nchars >= 3 && + target[0] != L'\0' && + target[1] == L':' && + target[2] == L'\\') + { + DEBUG("Absolute target with drive letter"); + /* Absolute target, with drive letter */ + stripped_chars = 0; + } else { + DEBUG("Relative symlink or other link"); + /* Relative symlink or other unexpected format */ + return RP_NOT_FIXED; + } + target[target_nchars] = L'\0'; + orig_target = target; + target = fixup_symlink(target + stripped_chars, capture_root_ino, capture_root_dev); + if (target) { + target_nchars = wcslen(target); + wmemmove(orig_target + stripped_chars, target, target_nchars + 1); + *target_nchars_p = target_nchars + stripped_chars; + DEBUG("Fixed reparse point (new target: \"%ls\")", orig_target); + return stripped_chars ? RP_FIXED_FULLPATH : RP_FIXED_ABSPATH; + } else { + return RP_EXCLUDED; + } +} + +static enum rp_status +win32_do_capture_rpfix(char *rpbuf, DWORD *rpbuflen_p, + u64 capture_root_ino, u64 capture_root_dev) +{ + const char *p_get; + char *p_put; + u16 substitute_name_offset; + u16 substitute_name_len; + wchar_t *target; + size_t target_nchars; + enum rp_status status; + u32 rptag; + DWORD rpbuflen = *rpbuflen_p; + + if (rpbuflen < 16) + return RP_EXCLUDED; + p_get = get_u32(rpbuf, &rptag); + p_get += 4; + p_get = get_u16(p_get, &substitute_name_offset); + p_get = get_u16(p_get, &substitute_name_len); + p_get += 4; + if ((size_t)substitute_name_offset + substitute_name_len > rpbuflen) + return RP_EXCLUDED; + if (rptag == WIM_IO_REPARSE_TAG_SYMLINK) { + if (rpbuflen < 20) + return RP_EXCLUDED; + p_get += 4; + } + + + target = (wchar_t*)&p_get[substitute_name_offset]; + target_nchars = substitute_name_len / 2; + /* Note: target is not necessarily null-terminated */ + + status = win32_maybe_rpfix_target(target, &target_nchars, + capture_root_ino, capture_root_dev); + if (status & RP_FIXED) { + size_t target_nbytes = target_nchars * 2; + size_t print_nbytes = target_nbytes; + wchar_t target_copy[target_nchars]; + wchar_t *print_name = target_copy; + + if (status == RP_FIXED_FULLPATH) { + print_nbytes -= 8; + print_name += 4; + } + wmemcpy(target_copy, target, target_nchars); + p_put = rpbuf + 8; + p_put = put_u16(p_put, 0); /* Substitute name offset */ + p_put = put_u16(p_put, target_nbytes); /* Substitute name length */ + p_put = put_u16(p_put, target_nbytes + 2); /* Print name offset */ + p_put = put_u16(p_put, print_nbytes); /* Print name length */ + if (rptag == WIM_IO_REPARSE_TAG_SYMLINK) + p_put = put_u32(p_put, 1); + p_put = put_bytes(p_put, target_nbytes, target_copy); + p_put = put_u16(p_put, 0); + p_put = put_bytes(p_put, print_nbytes, print_name); + p_put = put_u16(p_put, 0); + rpbuflen = p_put - rpbuf; + put_u16(rpbuf + 4, rpbuflen - 8); + *rpbuflen_p = rpbuflen; + } + return status; +} + /* Load a reparse point into a WIM inode. It is just stored in memory. * * @hFile: Open handle to a reparse point, with permission to read the reparse @@ -605,10 +756,11 @@ out_find_close: * * Returns 0 on success; nonzero on failure. */ static int -win32_capture_reparse_point(HANDLE hFile, +win32_capture_reparse_point(struct wim_dentry **root_p, + HANDLE hFile, struct wim_inode *inode, - struct wim_lookup_table *lookup_table, - const wchar_t *path) + const wchar_t *path, + struct add_image_params *params) { DEBUG("Capturing reparse point \"%ls\"", path); @@ -616,6 +768,8 @@ win32_capture_reparse_point(HANDLE hFile, * cannot exceed 16 kilobytes." - MSDN */ char reparse_point_buf[REPARSE_POINT_MAX_SIZE]; DWORD bytesReturned; + char *fixed_buf; + DWORD fixed_len; if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, /* "Not used with this operation; set to NULL" */ @@ -637,9 +791,26 @@ win32_capture_reparse_point(HANDLE hFile, return WIMLIB_ERR_READ; } inode->i_reparse_tag = le32_to_cpu(*(u32*)reparse_point_buf); - return inode_add_ads_with_data(inode, L"", - reparse_point_buf + 8, - bytesReturned - 8, lookup_table); + + if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_RPFIX && + (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK || + inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT)) + { + enum rp_status status; + status = win32_do_capture_rpfix(reparse_point_buf, + &bytesReturned, + params->capture_root_ino, + params->capture_root_dev); + if (status == RP_EXCLUDED) { + free_dentry(*root_p); + *root_p = NULL; + return 0; + } else if (status & RP_FIXED) { + inode->i_not_rpfixed = 0; + } + } + return inode_add_ads_with_data(inode, L"", reparse_point_buf + 8, + bytesReturned - 8, params->lookup_table); } /* Scans an unnamed or named stream of a Win32 file (not a reparse point @@ -884,12 +1055,7 @@ static int win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, wchar_t *path, size_t path_num_chars, - struct wim_lookup_table *lookup_table, - struct wim_inode_table *inode_table, - struct sd_set *sd_set, - const struct wimlib_capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, + struct add_image_params *params, struct win32_capture_state *state, unsigned vol_flags) { @@ -899,30 +1065,30 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, u64 file_size; int ret = 0; - if (exclude_path(path, path_num_chars, config, true)) { - if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) { + if (exclude_path(path, path_num_chars, params->config, true)) { + if (params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_ROOT) { ERROR("Cannot exclude the root directory from capture"); ret = WIMLIB_ERR_INVALID_CAPTURE_CONFIG; goto out; } - if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE) - && progress_func) + if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE) + && params->progress_func) { union wimlib_progress_info info; info.scan.cur_path = path; info.scan.excluded = true; - progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info); + params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info); } goto out; } - if ((add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) - && progress_func) + if ((params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_VERBOSE) + && params->progress_func) { union wimlib_progress_info info; info.scan.cur_path = path; info.scan.excluded = false; - progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info); + params->progress_func(WIMLIB_PROGRESS_MSG_SCAN_DENTRY, &info); } HANDLE hFile = win32_open_existing_file(path, @@ -946,7 +1112,7 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, } /* Create a WIM dentry with an associated inode, which may be shared */ - ret = inode_table_new_dentry(inode_table, + ret = inode_table_new_dentry(params->inode_table, path_basename_with_len(path, path_num_chars), ((u64)file_info.nFileIndexHigh << 32) | (u64)file_info.nFileIndexLow, @@ -970,13 +1136,14 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, inode->i_last_access_time = FILETIME_to_u64(&file_info.ftLastAccessTime); inode->i_resolved = 1; - add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE); + params->add_image_flags &= ~(WIMLIB_ADD_IMAGE_FLAG_ROOT | WIMLIB_ADD_IMAGE_FLAG_SOURCE); - if (!(add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS) + if (!(params->add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NO_ACLS) && (vol_flags & FILE_PERSISTENT_ACLS)) { - ret = win32_get_security_descriptor(root, sd_set, path, state, - add_image_flags); + ret = win32_get_security_descriptor(root, params->sd_set, + path, state, + params->add_image_flags); if (ret) goto out_close_handle; } @@ -992,7 +1159,7 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, ret = win32_capture_streams(path, path_num_chars, inode, - lookup_table, + params->lookup_table, file_size, vol_flags); if (ret) @@ -1000,29 +1167,21 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, ret = win32_recurse_directory(root, path, path_num_chars, - lookup_table, - inode_table, - sd_set, - config, - add_image_flags, - progress_func, + params, state, vol_flags); } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { /* Reparse point: save the reparse tag and data. Alternate data * streams are not captured, if it's even possible for a reparse * point to have alternate data streams... */ - ret = win32_capture_reparse_point(hFile, - inode, - lookup_table, - path); + ret = win32_capture_reparse_point(&root, hFile, inode, path, params); } else { /* Not a directory, not a reparse point; capture the default * file contents and any alternate data streams. */ ret = win32_capture_streams(path, path_num_chars, inode, - lookup_table, + params->lookup_table, file_size, vol_flags); } @@ -1032,7 +1191,7 @@ out: if (ret == 0) *root_ret = root; else - free_dentry_tree(root, lookup_table); + free_dentry_tree(root, params->lookup_table); return ret; } @@ -1072,13 +1231,7 @@ win32_do_capture_warnings(const struct win32_capture_state *state, int win32_build_dentry_tree(struct wim_dentry **root_ret, const wchar_t *root_disk_path, - struct wim_lookup_table *lookup_table, - struct wim_inode_table *inode_table, - struct sd_set *sd_set, - const struct wimlib_capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, - void *extra_arg) + struct add_image_params *params) { size_t path_nchars; wchar_t *path; @@ -1086,10 +1239,17 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, struct win32_capture_state state; unsigned vol_flags; + path_nchars = wcslen(root_disk_path); if (path_nchars > 32767) return WIMLIB_ERR_INVALID_PARAM; + ret = win32_get_file_and_vol_ids(root_disk_path, + ¶ms->capture_root_ino, + ¶ms->capture_root_dev); + if (ret) + return ret; + win32_get_vol_flags(root_disk_path, &vol_flags); /* There is no check for overflow later when this buffer is being used! @@ -1103,20 +1263,12 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, wmemcpy(path, root_disk_path, path_nchars + 1); memset(&state, 0, sizeof(state)); - ret = win32_build_dentry_tree_recursive(root_ret, - path, - path_nchars, - lookup_table, - inode_table, - sd_set, - config, - add_image_flags, - progress_func, - &state, - vol_flags); + ret = win32_build_dentry_tree_recursive(root_ret, path, + path_nchars, params, + &state, vol_flags); FREE(path); if (ret == 0) - win32_do_capture_warnings(&state, add_image_flags); + win32_do_capture_warnings(&state, params->add_image_flags); return ret; } diff --git a/src/win32.h b/src/win32.h index b4d52361..e525ccb4 100644 --- a/src/win32.h +++ b/src/win32.h @@ -8,13 +8,10 @@ extern int win32_build_dentry_tree(struct wim_dentry **root_ret, const tchar *root_disk_path, - struct wim_lookup_table *lookup_table, - struct wim_inode_table *inode_table, - struct sd_set *sd, - const struct wimlib_capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, - void *extra_arg); + struct add_image_params *params); + +extern int +win32_get_file_and_vol_ids(const wchar_t *path, u64 *ino_ret, u64 *dev_ret); extern int win32_read_file(const tchar *filename, HANDLE handle,