X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwin32_capture.c;h=afb38e30a7ce497a49d2656e770cdaa5c2217613;hp=c05eb192b4105a86c2c90f7652320fe232f056a4;hb=2200ddb2ab85b390daa140de5338ac9f023d3683;hpb=5caa3dfded8e0f590112b59feeb3b55e4fa28420 diff --git a/src/win32_capture.c b/src/win32_capture.c index c05eb192..afb38e30 100644 --- a/src/win32_capture.c +++ b/src/win32_capture.c @@ -38,9 +38,12 @@ #define MAX_GET_SD_ACCESS_DENIED_WARNINGS 1 #define MAX_GET_SACL_PRIV_NOTHELD_WARNINGS 1 +#define MAX_CAPTURE_LONG_PATH_WARNINGS 5 + struct win32_capture_state { unsigned long num_get_sd_access_denied; unsigned long num_get_sacl_priv_notheld; + unsigned long num_long_path_warnings; }; @@ -154,9 +157,10 @@ win32_encrypted_export_cb(unsigned char *_data, void *_ctx, unsigned long len) } } else { size_t len_to_copy = min(len, ctx->bytes_remaining); - memcpy(ctx->read_prefix_ctx_or_buf, data, len_to_copy); + ctx->read_prefix_ctx_or_buf = mempcpy(ctx->read_prefix_ctx_or_buf, + data, + len_to_copy); ctx->bytes_remaining -= len_to_copy; - ctx->read_prefix_ctx_or_buf += len_to_copy; } return ERROR_SUCCESS; } @@ -367,7 +371,7 @@ win32_recurse_directory(struct wim_dentry *root, * opendir(), FindFirstFileW has file globbing built into it. But this * isn't what we actually want, so just add a dummy glob to get all * entries. */ - dir_path[dir_path_num_chars] = L'/'; + dir_path[dir_path_num_chars] = OS_PREFERRED_PATH_SEPARATOR; dir_path[dir_path_num_chars + 1] = L'*'; dir_path[dir_path_num_chars + 2] = L'\0'; hFind = FindFirstFileW(dir_path, &dat); @@ -393,7 +397,7 @@ win32_recurse_directory(struct wim_dentry *root, continue; size_t filename_len = wcslen(dat.cFileName); - dir_path[dir_path_num_chars] = L'/'; + dir_path[dir_path_num_chars] = OS_PREFERRED_PATH_SEPARATOR; wmemcpy(dir_path + dir_path_num_chars + 1, dat.cFileName, filename_len + 1); @@ -506,12 +510,10 @@ win32_capture_try_rpfix(u8 *rpbuf, u16 *rpbuflen_p, const wchar_t *path) { struct reparse_data rpdata; - DWORD rpbuflen; int ret; enum rp_status rp_status; - rpbuflen = *rpbuflen_p; - ret = parse_reparse_data(rpbuf, rpbuflen, &rpdata); + ret = parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata); if (ret) return -ret; @@ -535,7 +537,7 @@ win32_capture_try_rpfix(u8 *rpbuf, u16 *rpbuflen_p, rpdata.print_name += 4; rpdata.print_name_nbytes -= 8; } - ret = make_reparse_buffer(&rpdata, rpbuf); + ret = make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p); if (ret == 0) ret = rp_status; else @@ -755,12 +757,11 @@ win32_capture_stream(const wchar_t *path, if (is_named_stream) { spath_nchars += 1 + stream_name_nchars; colonchar = L":"; - if (path_num_chars == 1 && - path[0] != L'/' && - path[0] != L'\\') - { + if (path_num_chars == 1 && !is_any_path_separator(path[0])) { spath_nchars += 2; - relpath_prefix = L"./"; + static const wchar_t _relpath_prefix[] = + {L'.', OS_PREFERRED_PATH_SEPARATOR, L'\0'}; + relpath_prefix = _relpath_prefix; } } @@ -950,6 +951,18 @@ win32_build_dentry_tree_recursive(struct wim_dentry **root_ret, goto out; } +#if 0 + if (path_num_chars >= 4 && + !wmemcmp(path, L"\\\\?\\", 4) && + path_num_chars + 1 - 4 > MAX_PATH && + state->num_long_path_warnings < MAX_CAPTURE_LONG_PATH_WARNINGS) + { + WARNING("Path \"%ls\" exceeds MAX_PATH", path); + if (++state->num_long_path_warnings == MAX_CAPTURE_LONG_PATH_WARNINGS) + WARNING("Suppressing further warnings about long paths."); + } +#endif + if ((params->add_flags & WIMLIB_ADD_FLAG_VERBOSE) && params->progress_func) { @@ -1115,6 +1128,8 @@ win32_do_capture_warnings(const struct win32_capture_state *state, " descriptors.\n"); } +#define WINDOWS_NT_MAX_PATH 32768 + /* Win32 version of capturing a directory tree */ int win32_build_dentry_tree(struct wim_dentry **root_ret, @@ -1126,6 +1141,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, int ret; struct win32_capture_state state; unsigned vol_flags; + DWORD dret; if (!win32func_FindFirstStreamW) { WARNING("Running on Windows XP or earlier; " @@ -1133,7 +1149,7 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, } path_nchars = wcslen(root_disk_path); - if (path_nchars > 32767) + if (path_nchars > WINDOWS_NT_MAX_PATH) return WIMLIB_ERR_INVALID_PARAM; if (GetFileAttributesW(root_disk_path) == INVALID_FILE_ATTRIBUTES && @@ -1152,15 +1168,31 @@ win32_build_dentry_tree(struct wim_dentry **root_ret, win32_get_vol_flags(root_disk_path, &vol_flags); - /* There is no check for overflow later when this buffer is being used! - * But the max path length on NTFS is 32767 characters, and paths need - * to be written specially to even go past 260 characters, so we should - * be okay with 32770 characters. */ - path = MALLOC(32770 * sizeof(wchar_t)); + /* WARNING: There is no check for overflow later when this buffer is + * being used! But it's as long as the maximum path length understood + * by Windows NT (which is NOT the same as MAX_PATH). */ + path = MALLOC(WINDOWS_NT_MAX_PATH * sizeof(wchar_t)); if (!path) return WIMLIB_ERR_NOMEM; - wmemcpy(path, root_disk_path, path_nchars + 1); + /* Work around defective behavior in Windows where paths longer than 260 + * characters are not supported by default; instead they need to be + * turned into absolute paths and prefixed with "\\?\". */ + + if (wcsncmp(root_disk_path, L"\\\\?\\", 4)) { + dret = GetFullPathName(root_disk_path, WINDOWS_NT_MAX_PATH - 4, + &path[4], NULL); + + if (dret == 0 || dret >= WINDOWS_NT_MAX_PATH - 4) { + WARNING("Can't get full path name for \"%ls\"", root_disk_path); + wmemcpy(path, root_disk_path, path_nchars + 1); + } else { + wmemcpy(path, L"\\\\?\\", 4); + path_nchars = 4 + dret; + } + } else { + wmemcpy(path, root_disk_path, path_nchars + 1); + } memset(&state, 0, sizeof(state)); ret = win32_build_dentry_tree_recursive(root_ret, path,