sizeof(wchar_t));
if (!ads_entry)
return WIMLIB_ERR_NOMEM;
+ } else if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ /* Ignore unnamed data stream of reparse point */
+ return 0;
} else {
ads_entry = NULL;
}
u16 rpbuflen;
u16 not_rpfixed;
- if (should_exclude_path(full_path + params->capture_root_nchars,
- full_path_nchars - params->capture_root_nchars,
- params->config))
+ ret = try_exclude(full_path, full_path_nchars, params);
+ if (ret < 0) /* Excluded? */
goto out_progress;
+ if (ret > 0) /* Error? */
+ goto out;
/* Open the file. */
status = winnt_openat(cur_dir,
SYNCHRONIZE,
&h);
if (unlikely(!NT_SUCCESS(status))) {
- set_errno_from_nt_status(status);
- ERROR_WITH_ERRNO("\"%ls\": Can't open file "
- "(status=0x%08"PRIx32")",
- printable_path(full_path), (u32)status);
- ret = WIMLIB_ERR_OPEN;
+ if (status == STATUS_DELETE_PENDING) {
+ WARNING("\"%ls\": Deletion pending; skipping file",
+ printable_path(full_path));
+ ret = 0;
+ } else {
+ set_errno_from_nt_status(status);
+ ERROR_WITH_ERRNO("\"%ls\": Can't open file "
+ "(status=0x%08"PRIx32")",
+ printable_path(full_path), (u32)status);
+ if (status == STATUS_FVE_LOCKED_VOLUME)
+ ret = WIMLIB_ERR_FVE_LOCKED_VOLUME;
+ else
+ ret = WIMLIB_ERR_OPEN;
+ }
+ /* XXX: Provide option to exclude files that fail with
+ * STATUS_SHARING_VIOLATION? */
goto out;
}
* However, we need to explicitly check for directories and files with
* only 1 link and refuse to hard link them. This is because Windows
* has a bug where it can return duplicate File IDs for files and
- * directories on the FAT filesystem. */
+ * directories on the FAT filesystem.
+ *
+ * Since we don't follow mount points on Windows, we don't need to query
+ * the volume ID per-file. Just once, for the root, is enough. But we
+ * can't simply pass 0, because then there could be inode collisions
+ * among multiple calls to win32_build_dentry_tree() that are scanning
+ * files on different volumes. */
ret = inode_table_new_dentry(params->inode_table,
filename,
file_info.InternalInformation.IndexNumber.QuadPart,
- 0, /* We don't follow mount points, so we
- currently don't need to get the
- volume ID / device number. */
+ params->capture_root_dev,
(file_info.StandardInformation.NumberOfLinks <= 1 ||
(file_info.BasicInformation.FileAttributes &
FILE_ATTRIBUTE_DIRECTORY)),
struct add_image_params *params)
{
wchar_t *path;
- DWORD dret;
- size_t path_nchars;
int ret;
+ UNICODE_STRING ntpath;
struct winnt_scan_stats stats;
+ size_t ntpath_nchars;
/* 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
if (!path)
return WIMLIB_ERR_NOMEM;
- /* Translate into full path. */
- dret = GetFullPathName(root_disk_path, WINDOWS_NT_MAX_PATH - 3,
- &path[4], NULL);
-
- 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;
- }
-
- /* Add \??\ prefix to form the NT namespace path. */
- wmemcpy(path, L"\\??\\", 4);
- path_nchars = dret + 4;
+ ret = win32_path_to_nt_path(root_disk_path, &ntpath);
+ if (ret)
+ goto out_free_path;
- /* 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';
+ 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;
+ } else {
+ ntpath_nchars = ntpath.Length / sizeof(wchar_t);
+ wmemcpy(path, ntpath.Buffer, ntpath_nchars);
+ path[ntpath_nchars] = L'\0';
- params->capture_root_nchars = path_nchars;
+ params->capture_root_nchars = ntpath_nchars;
+ if (path[ntpath_nchars - 1] == L'\\')
+ params->capture_root_nchars--;
+ ret = 0;
+ }
+ HeapFree(GetProcessHeap(), 0, ntpath.Buffer);
+ if (ret)
+ goto out_free_path;
memset(&stats, 0, sizeof(stats));
ret = winnt_build_dentry_tree_recursive(root_ret, NULL,
- path, path_nchars, L"", 0,
- params, &stats, 0);
+ path, ntpath_nchars,
+ L"", 0, params, &stats, 0);
+out_free_path:
FREE(path);
if (ret == 0)
winnt_do_scan_warnings(root_disk_path, &stats);