struct winnt_scan_stats {
unsigned long num_get_sd_access_denied;
unsigned long num_get_sacl_priv_notheld;
- unsigned long num_long_path_warnings;
};
static inline const wchar_t *
info->FileName[1] == L'.'))
{
wchar_t *p;
+ wchar_t *filename;
struct wim_dentry *child;
p = full_path + full_path_nchars;
- *p++ = L'\\';
- p = wmempcpy(p, info->FileName,
+ /* Only add a backslash if we don't already have
+ * one. This prevents a duplicate backslash
+ * from being added when the path to the capture
+ * dir had a trailing backslash. */
+ if (*(p - 1) != L'\\')
+ *p++ = L'\\';
+ filename = p;
+ p = wmempcpy(filename, info->FileName,
info->FileNameLength / 2);
*p = '\0';
h,
full_path,
p - full_path,
- full_path + full_path_nchars + 1,
+ filename,
info->FileNameLength / 2,
params,
stats,
/* Reparse point fixup status code */
enum rp_status {
- /* Reparse point should be excluded from capture */
- RP_EXCLUDED = -0,
-
/* Reparse point will be captured literally (no fixup) */
RP_NOT_FIXED = -1,
return p;
}
-static enum rp_status
+static int
+winnt_rpfix_progress(struct add_image_params *params, const wchar_t *path,
+ const struct reparse_data *rpdata,
+ enum wimlib_progress_msg msg)
+{
+ size_t print_name_nchars = rpdata->print_name_nbytes / sizeof(wchar_t);
+ wchar_t print_name0[print_name_nchars + 1];
+
+ wmemcpy(print_name0, rpdata->print_name, print_name_nchars);
+ print_name0[print_name_nchars] = L'\0';
+
+ params->progress.scan.cur_path = printable_path(path);
+ params->progress.scan.symlink_target = print_name0;
+ return do_capture_progress(params, msg, NULL);
+}
+
+static int
winnt_try_rpfix(u8 *rpbuf, u16 *rpbuflen_p,
u64 capture_root_ino, u64 capture_root_dev,
const wchar_t *path, struct add_image_params *params)
{
struct reparse_data rpdata;
const wchar_t *rel_target;
+ int ret;
if (parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata)) {
/* Couldn't even understand the reparse data. Don't try the
capture_root_ino,
capture_root_dev);
if (!rel_target) {
- /* Target points outside of the tree being captured. Exclude
- * this reparse point from the capture (but inform the library
- * user). */
- size_t print_name_nchars = rpdata.print_name_nbytes / sizeof(wchar_t);
- wchar_t print_name0[print_name_nchars + 1];
- print_name0[print_name_nchars] = L'\0';
- wmemcpy(print_name0, rpdata.print_name, print_name_nchars);
-
- params->progress.scan.cur_path = printable_path(path);
- params->progress.scan.symlink_target = print_name0;
- do_capture_progress(params, WIMLIB_SCAN_DENTRY_EXCLUDED_SYMLINK, NULL);
- return RP_EXCLUDED;
+ /* Target points outside of the tree being captured. Don't
+ * adjust it. */
+ ret = winnt_rpfix_progress(params, path, &rpdata,
+ WIMLIB_SCAN_DENTRY_NOT_FIXED_SYMLINK);
+ if (ret)
+ return ret;
+ return RP_NOT_FIXED;
}
if (rel_target == rpdata.substitute_name) {
if (make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p))
return RP_NOT_FIXED;
}
+ ret = winnt_rpfix_progress(params, path, &rpdata,
+ WIMLIB_SCAN_DENTRY_FIXED_SYMLINK);
+ if (ret)
+ return ret;
return RP_FIXED;
}
* Path to the reparse point file.
* @params:
* Capture parameters. add_flags, capture_root_ino, capture_root_dev,
- * progress_func, and progress are used.
+ * progfunc, progctx, and progress are used.
* @rpbuf:
* Buffer of length at least REPARSE_POINT_MAX_SIZE bytes into which the
* reparse point buffer will be loaded.
* On success, the length of the reparse point buffer in bytes is written
* to this location.
*
- * On success, returns a nonpositive `enum rp_status' value.
+ * On success, returns a negative `enum rp_status' value.
* On failure, returns a positive error code.
*/
static int
if (should_exclude_path(full_path + params->capture_root_nchars,
full_path_nchars - params->capture_root_nchars,
params->config))
- {
- ret = 0;
goto out_progress;
- }
/* Open the file. */
status = winnt_openat(cur_dir,
ret = winnt_get_reparse_data(h, full_path, params,
rpbuf, &rpbuflen);
switch (ret) {
- case RP_EXCLUDED:
- ret = 0;
- goto out;
case RP_FIXED:
not_rpfixed = 0;
break;
if (inode->i_nlink > 1) {
/* Shared inode (hard link); skip reading per-inode information.
*/
- ret = 0;
goto out_progress;
}
out_progress:
params->progress.scan.cur_path = printable_path(full_path);
if (likely(root))
- do_capture_progress(params, WIMLIB_SCAN_DENTRY_OK, inode);
+ ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_OK, inode);
else
- do_capture_progress(params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL);
+ ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL);
out:
if (likely(h != INVALID_HANDLE_VALUE))
(*func_NtClose)(h);
struct add_image_params *params)
{
wchar_t *path;
- DWORD dret;
- size_t path_nchars;
int ret;
+ UNICODE_STRING ntpath;
struct winnt_scan_stats stats;
/* WARNING: There is no check for overflow later when this buffer is
if (!path)
return WIMLIB_ERR_NOMEM;
- /* Translate into full path. */
- dret = GetFullPathName(root_disk_path, WINDOWS_NT_MAX_PATH - 3,
- &path[4], NULL);
+ ret = win32_path_to_nt_path(root_disk_path, &ntpath);
+ if (ret)
+ goto out_free_path;
- if (unlikely(dret == 0 || dret >= WINDOWS_NT_MAX_PATH - 3)) {
- ERROR("Can't get full path name for \"%ls\"", root_disk_path);
- return WIMLIB_ERR_UNSUPPORTED;
+ if (ntpath.Length < 4 * sizeof(wchar_t) ||
+ ntpath.Length > WINDOWS_NT_MAX_PATH * sizeof(wchar_t) ||
+ wmemcmp(ntpath.Buffer, L"\\??\\", 4))
+ {
+ ERROR("\"%ls\": unrecognized path format", root_disk_path);
+ ret = WIMLIB_ERR_INVALID_PARAM;
+ goto out_free_path;
}
- /* Add \??\ prefix to form the NT namespace path. */
- wmemcpy(path, L"\\??\\", 4);
- path_nchars = dret + 4;
-
- /* Strip trailing slashes. If we don't do this, we may create a path
- * with multiple consecutive backslashes, which for some reason causes
- * Windows to report that the file cannot be found. */
- while (unlikely(path[path_nchars - 1] == L'\\' &&
- path[path_nchars - 2] != L':'))
- path[--path_nchars] = L'\0';
+ params->capture_root_nchars = ntpath.Length / sizeof(wchar_t);
+ wmemcpy(path, ntpath.Buffer, params->capture_root_nchars);
+ path[params->capture_root_nchars] = L'\0';
- params->capture_root_nchars = path_nchars;
+ HeapFree(GetProcessHeap(), 0, ntpath.Buffer);
memset(&stats, 0, sizeof(stats));
ret = winnt_build_dentry_tree_recursive(root_ret, NULL,
- path, path_nchars, L"", 0,
- params, &stats, 0);
+ path, params->capture_root_nchars,
+ L"", 0, params, &stats, 0);
+out_free_path:
FREE(path);
if (ret == 0)
winnt_do_scan_warnings(root_disk_path, &stats);