#include "wimlib/paths.h"
#include "wimlib/reparse.h"
-#ifdef WITH_NTDLL
-# include <winternl.h>
-# include <ntstatus.h>
-
-NTSTATUS WINAPI
-NtQuerySecurityObject(HANDLE handle,
- SECURITY_INFORMATION SecurityInformation,
- PSECURITY_DESCRIPTOR SecurityDescriptor,
- ULONG Length,
- PULONG LengthNeeded);
-NTSTATUS WINAPI
-NtQueryDirectoryFile(HANDLE FileHandle,
- HANDLE Event,
- PIO_APC_ROUTINE ApcRoutine,
- PVOID ApcContext,
- PIO_STATUS_BLOCK IoStatusBlock,
- PVOID FileInformation,
- ULONG Length,
- FILE_INFORMATION_CLASS FileInformationClass,
- BOOLEAN ReturnSingleEntry,
- PUNICODE_STRING FileName,
- BOOLEAN RestartScan);
-#endif
-
#define MAX_GET_SD_ACCESS_DENIED_WARNINGS 1
#define MAX_GET_SACL_PRIV_NOTHELD_WARNINGS 1
#define MAX_CAPTURE_LONG_PATH_WARNINGS 5
{
int ret = 0;
void *out_buf;
- DWORD err;
u64 bytes_remaining;
HANDLE hFile = win32_open_existing_file(lte->file_on_disk,
* call ourselves, and it saves a dumb call to FindFirstFile() which of
* course has to create its own handle. */
#ifdef WITH_NTDLL
- NTSTATUS status;
- IO_STATUS_BLOCK io_status;
- u8 buf[128] _aligned_attribute(8);
- const FILE_NAME_INFORMATION *info;
-
- status = NtQueryInformationFile(hFile, &io_status, buf, sizeof(buf),
- FileAlternateNameInformation);
- info = (const FILE_NAME_INFORMATION*)buf;
- if (status == STATUS_SUCCESS && info->FileNameLength != 0) {
- dentry->short_name = MALLOC(info->FileNameLength + 2);
- if (!dentry->short_name)
- return WIMLIB_ERR_NOMEM;
- memcpy(dentry->short_name, info->FileName,
- info->FileNameLength);
- dentry->short_name[info->FileNameLength / 2] = L'\0';
- dentry->short_name_nbytes = info->FileNameLength;
+ if (func_NtQueryInformationFile) {
+ NTSTATUS status;
+ IO_STATUS_BLOCK io_status;
+ u8 buf[128] _aligned_attribute(8);
+ const FILE_NAME_INFORMATION *info;
+
+ status = (*func_NtQueryInformationFile)(hFile, &io_status, buf, sizeof(buf),
+ FileAlternateNameInformation);
+ info = (const FILE_NAME_INFORMATION*)buf;
+ if (status == STATUS_SUCCESS && info->FileNameLength != 0) {
+ dentry->short_name = MALLOC(info->FileNameLength + 2);
+ if (!dentry->short_name)
+ return WIMLIB_ERR_NOMEM;
+ memcpy(dentry->short_name, info->FileName,
+ info->FileNameLength);
+ dentry->short_name[info->FileNameLength / 2] = L'\0';
+ dentry->short_name_nbytes = info->FileNameLength;
+ }
+ return 0;
}
- return 0;
-#else
+#endif
+
WIN32_FIND_DATAW dat;
HANDLE hFind;
int ret = 0;
FindClose(hFind);
}
return ret;
-#endif
}
/*
DWORD bufsize, DWORD *lengthNeeded)
{
#ifdef WITH_NTDLL
- NTSTATUS status;
-
- status = NtQuerySecurityObject(hFile, requestedInformation, buf,
- bufsize, lengthNeeded);
- /* Since it queries an already-open handle, NtQuerySecurityObject()
- * apparently returns STATUS_ACCESS_DENIED rather than
- * STATUS_PRIVILEGE_NOT_HELD. */
- if (status == STATUS_ACCESS_DENIED)
- return ERROR_PRIVILEGE_NOT_HELD;
- else
- return RtlNtStatusToDosError(status);
-#else
+ if (func_NtQuerySecurityObject) {
+ NTSTATUS status;
+
+ status = (*func_NtQuerySecurityObject)(hFile,
+ requestedInformation, buf,
+ bufsize, lengthNeeded);
+ /* Since it queries an already-open handle, NtQuerySecurityObject()
+ * apparently returns STATUS_ACCESS_DENIED rather than
+ * STATUS_PRIVILEGE_NOT_HELD. */
+ if (status == STATUS_ACCESS_DENIED)
+ return ERROR_PRIVILEGE_NOT_HELD;
+ else
+ return (*func_RtlNtStatusToDosError)(status);
+ }
+#endif
if (GetFileSecurity(path, requestedInformation, buf,
bufsize, lengthNeeded))
return ERROR_SUCCESS;
else
return GetLastError();
-#endif
}
static int
default:
fail:
set_errno_from_win32_error(err);
- ERROR("Failed to read security descriptor of \"%ls\"", path);
+ ERROR_WITH_ERRNO("Failed to read security descriptor of \"%ls\"", path);
ret = WIMLIB_ERR_READ;
goto out_free_buf;
}
* which we opened with FILE_FLAG_BACKUP_SEMANTICS (probably not the
* case for the FindFirstFile() API; it's not documented). */
#ifdef WITH_NTDLL
+ if (!func_NtQueryDirectoryFile)
+ goto use_FindFirstFile;
+
NTSTATUS status;
IO_STATUS_BLOCK io_status;
const size_t bufsize = 8192;
if (!buf)
return WIMLIB_ERR_NOMEM;
for (;;) {
- status = NtQueryDirectoryFile(hDir, NULL, NULL, NULL,
- &io_status, buf, bufsize,
- FileNamesInformation,
- FALSE, NULL, restartScan);
+ status = (*func_NtQueryDirectoryFile)(hDir, NULL, NULL, NULL,
+ &io_status, buf, bufsize,
+ FileNamesInformation,
+ FALSE, NULL, restartScan);
restartScan = FALSE;
if (status != STATUS_SUCCESS) {
if (status == STATUS_NO_MORE_FILES ||
status == STATUS_NO_MORE_ENTRIES ||
status == STATUS_NO_MORE_MATCHES) {
ret = 0;
+ } else if (status == STATUS_NOT_IMPLEMENTED ||
+ status == STATUS_NOT_SUPPORTED ||
+ status == STATUS_INVALID_INFO_CLASS) {
+ FREE(buf);
+ goto use_FindFirstFile;
} else {
set_errno_from_nt_status(status);
ERROR_WITH_ERRNO("Failed to read directory "
out_free_buf:
FREE(buf);
return ret;
-#else
+#endif
+
+use_FindFirstFile:
+ ;
WIN32_FIND_DATAW dat;
HANDLE hFind;
DWORD err;
out_find_close:
FindClose(hFind);
return ret;
-#endif
}
/* Reparse point fixup status code */
spath_buf_nbytes = (spath_nchars + 1) * sizeof(wchar_t);
spath = MALLOC(spath_buf_nbytes);
- swprintf(spath, L"%ls%ls%ls%ls",
+ tsprintf(spath, L"%ls%ls%ls%ls",
relpath_prefix, path, colonchar, stream_name);
/* Make a new wim_lookup_table_entry */
IO_STATUS_BLOCK io_status;
NTSTATUS status;
const FILE_STREAM_INFORMATION *info;
-#else
+#endif
HANDLE hFind;
DWORD err;
-#endif
DEBUG("Capturing streams from \"%ls\"", path);
if (!(vol_flags & FILE_NAMED_STREAMS))
goto unnamed_only;
-#ifndef WITH_NTDLL
- if (win32func_FindFirstStreamW == NULL)
- goto unnamed_only;
-#endif
#ifdef WITH_NTDLL
+ if (!func_NtQueryInformationFile)
+ goto use_FindFirstStream;
+
buf = _buf;
bufsize = sizeof(_buf);
/* Get a buffer containing the stream information. */
for (;;) {
- status = NtQueryInformationFile(*hFile_p, &io_status, buf, bufsize,
- FileStreamInformation);
+ status = (*func_NtQueryInformationFile)(*hFile_p, &io_status,
+ buf, bufsize,
+ FileStreamInformation);
if (status == STATUS_SUCCESS) {
break;
} else if (status == STATUS_BUFFER_OVERFLOW) {
goto out_free_buf;
}
buf = newbuf;
+ } else if (status == STATUS_NOT_IMPLEMENTED ||
+ status == STATUS_NOT_SUPPORTED ||
+ status == STATUS_INVALID_INFO_CLASS) {
+ goto use_FindFirstStream;
} else {
set_errno_from_nt_status(status);
ERROR_WITH_ERRNO("Failed to read streams of %ls", path);
if (buf != _buf)
FREE(buf);
return ret;
+#endif /* WITH_NTDLL */
-#else /* WITH_NTDLL */
+use_FindFirstStream:
+ if (win32func_FindFirstStreamW == NULL)
+ goto unnamed_only;
hFind = win32func_FindFirstStreamW(path, FindStreamInfoStandard, &dat, 0);
if (hFind == INVALID_HANDLE_VALUE) {
err = GetLastError();
- if (err == ERROR_CALL_NOT_IMPLEMENTED)
+ if (err == ERROR_CALL_NOT_IMPLEMENTED ||
+ err == ERROR_NOT_SUPPORTED ||
+ err == ERROR_INVALID_FUNCTION ||
+ err == ERROR_INVALID_PARAMETER)
goto unnamed_only;
/* Seems legal for this to return ERROR_HANDLE_EOF on reparse
out_find_close:
FindClose(hFind);
return ret;
-#endif /* !WITH_NTDLL */
unnamed_only:
/* FindFirstStream() API is not available, or the volume does not
* support named streams. Only capture the unnamed data stream. */
DEBUG("Only capturing unnamed data stream");
- if (!(inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
- FILE_ATTRIBUTE_REPARSE_POINT)))
- {
- wcscpy(dat.cStreamName, L"::$DATA");
- dat.StreamSize.QuadPart = file_size;
- ret = win32_capture_stream(path,
- path_num_chars,
- inode, lookup_table,
- &dat);
- if (ret)
- return ret;
- }
- return ret;
+ if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_REPARSE_POINT))
+ return 0;
+
+ wcscpy(dat.cStreamName, L"::$DATA");
+ dat.StreamSize.QuadPart = file_size;
+ return win32_capture_stream(path, path_num_chars,
+ inode, lookup_table, &dat);
}
static int
DWORD dret;
bool need_prefix_free = false;
-#ifndef WITH_NTDLL
- if (!win32func_FindFirstStreamW) {
+ if (!win32func_FindFirstStreamW
+#ifdef WITH_NTDLL
+ && !func_NtQueryInformationFile
+#endif
+ )
+ {
WARNING("Running on Windows XP or earlier; "
"alternate data streams will not be captured.");
}
-#endif
path_nchars = wcslen(root_disk_path);
if (path_nchars > WINDOWS_NT_MAX_PATH)