X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwin32_common.c;h=30f7d6238c9f8b20835debeebe2171b0491e6548;hp=412421ea28ce1480cb56bcea651c2b6896e038e4;hb=873a86a1a5097f2a161494341d8d962453a30465;hpb=aae154ad67444bc760bedff60bc60fd5b91b8ede diff --git a/src/win32_common.c b/src/win32_common.c index 412421ea..30f7d623 100644 --- a/src/win32_common.c +++ b/src/win32_common.c @@ -3,22 +3,20 @@ */ /* - * Copyright (C) 2013, 2014 Eric Biggers + * Copyright (C) 2013, 2014, 2015 Eric Biggers * - * This file is part of wimlib, a library for working with WIM files. + * This file is free software; you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the Free + * Software Foundation; either version 3 of the License, or (at your option) any + * later version. * - * wimlib is free software; you can redistribute it and/or modify it under the - * terms of the GNU General Public License as published by the Free - * Software Foundation; either version 3 of the License, or (at your option) - * any later version. - * - * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - * A PARTICULAR PURPOSE. See the GNU General Public License for more + * This file is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * - * You should have received a copy of the GNU General Public License - * along with wimlib; if not, see http://www.gnu.org/licenses/. + * You should have received a copy of the GNU Lesser General Public License + * along with this file; if not, see http://www.gnu.org/licenses/. */ #ifdef __WIN32__ @@ -27,299 +25,11 @@ # include "config.h" #endif -#include - #include "wimlib/win32_common.h" + #include "wimlib/error.h" #include "wimlib/util.h" -static int -win32_error_to_errno(DWORD err_code) -{ - /* This mapping is that used in Cygwin. - * Some of these choices are arbitrary. */ - switch (err_code) { - case ERROR_ACCESS_DENIED: - return EACCES; - case ERROR_ACTIVE_CONNECTIONS: - return EAGAIN; - case ERROR_ALREADY_EXISTS: - return EEXIST; - case ERROR_BAD_DEVICE: - return ENODEV; - case ERROR_BAD_EXE_FORMAT: - return ENOEXEC; - case ERROR_BAD_NETPATH: - return ENOENT; - case ERROR_BAD_NET_NAME: - return ENOENT; - case ERROR_BAD_NET_RESP: - return ENOSYS; - case ERROR_BAD_PATHNAME: - return ENOENT; - case ERROR_BAD_PIPE: - return EINVAL; - case ERROR_BAD_UNIT: - return ENODEV; - case ERROR_BAD_USERNAME: - return EINVAL; - case ERROR_BEGINNING_OF_MEDIA: - return EIO; - case ERROR_BROKEN_PIPE: - return EPIPE; - case ERROR_BUSY: - return EBUSY; - case ERROR_BUS_RESET: - return EIO; - case ERROR_CALL_NOT_IMPLEMENTED: - return ENOSYS; - case ERROR_CANNOT_MAKE: - return EPERM; - case ERROR_CHILD_NOT_COMPLETE: - return EBUSY; - case ERROR_COMMITMENT_LIMIT: - return EAGAIN; - case ERROR_CRC: - return EIO; - case ERROR_DEVICE_DOOR_OPEN: - return EIO; - case ERROR_DEVICE_IN_USE: - return EAGAIN; - case ERROR_DEVICE_REQUIRES_CLEANING: - return EIO; - case ERROR_DIRECTORY: - return ENOTDIR; - case ERROR_DIR_NOT_EMPTY: - return ENOTEMPTY; - case ERROR_DISK_CORRUPT: - return EIO; - case ERROR_DISK_FULL: - return ENOSPC; -#ifdef ENOTUNIQ - case ERROR_DUP_NAME: - return ENOTUNIQ; -#endif - case ERROR_EAS_DIDNT_FIT: - return ENOSPC; -#ifdef ENOTSUP - case ERROR_EAS_NOT_SUPPORTED: - return ENOTSUP; -#endif - case ERROR_EA_LIST_INCONSISTENT: - return EINVAL; - case ERROR_EA_TABLE_FULL: - return ENOSPC; - case ERROR_END_OF_MEDIA: - return ENOSPC; - case ERROR_EOM_OVERFLOW: - return EIO; - case ERROR_EXE_MACHINE_TYPE_MISMATCH: - return ENOEXEC; - case ERROR_EXE_MARKED_INVALID: - return ENOEXEC; - case ERROR_FILEMARK_DETECTED: - return EIO; - case ERROR_FILENAME_EXCED_RANGE: - return ENAMETOOLONG; - case ERROR_FILE_CORRUPT: - return EEXIST; - case ERROR_FILE_EXISTS: - return EEXIST; - case ERROR_FILE_INVALID: - return ENXIO; - case ERROR_FILE_NOT_FOUND: - return ENOENT; - case ERROR_HANDLE_DISK_FULL: - return ENOSPC; -#ifdef ENODATA - case ERROR_HANDLE_EOF: - return ENODATA; -#endif - case ERROR_INVALID_ADDRESS: - return EINVAL; - case ERROR_INVALID_AT_INTERRUPT_TIME: - return EINTR; - case ERROR_INVALID_BLOCK_LENGTH: - return EIO; - case ERROR_INVALID_DATA: - return EINVAL; - case ERROR_INVALID_DRIVE: - return ENODEV; - case ERROR_INVALID_EA_NAME: - return EINVAL; - case ERROR_INVALID_EXE_SIGNATURE: - return ENOEXEC; -#ifdef EBADRQC - case ERROR_INVALID_FUNCTION: - return EBADRQC; -#endif - case ERROR_INVALID_HANDLE: - return EBADF; - case ERROR_INVALID_NAME: - return ENOENT; - case ERROR_INVALID_PARAMETER: - return EINVAL; - case ERROR_INVALID_SIGNAL_NUMBER: - return EINVAL; - case ERROR_IOPL_NOT_ENABLED: - return ENOEXEC; - case ERROR_IO_DEVICE: - return EIO; - case ERROR_IO_INCOMPLETE: - return EAGAIN; - case ERROR_IO_PENDING: - return EAGAIN; - case ERROR_LOCK_VIOLATION: - return EBUSY; - case ERROR_MAX_THRDS_REACHED: - return EAGAIN; - case ERROR_META_EXPANSION_TOO_LONG: - return EINVAL; - case ERROR_MOD_NOT_FOUND: - return ENOENT; -#ifdef EMSGSIZE - case ERROR_MORE_DATA: - return EMSGSIZE; -#endif - case ERROR_NEGATIVE_SEEK: - return EINVAL; - case ERROR_NETNAME_DELETED: - return ENOENT; - case ERROR_NOACCESS: - return EFAULT; - case ERROR_NONE_MAPPED: - return EINVAL; - case ERROR_NONPAGED_SYSTEM_RESOURCES: - return EAGAIN; -#ifdef ENOLINK - case ERROR_NOT_CONNECTED: - return ENOLINK; -#endif - case ERROR_NOT_ENOUGH_MEMORY: - return ENOMEM; - case ERROR_NOT_OWNER: - return EPERM; -#ifdef ENOMEDIUM - case ERROR_NOT_READY: - return ENOMEDIUM; -#endif - case ERROR_NOT_SAME_DEVICE: - return EXDEV; - case ERROR_NOT_SUPPORTED: - return ENOSYS; - case ERROR_NO_DATA: - return EPIPE; - case ERROR_NO_DATA_DETECTED: - return EIO; -#ifdef ENOMEDIUM - case ERROR_NO_MEDIA_IN_DRIVE: - return ENOMEDIUM; -#endif -#ifdef ENMFILE - case ERROR_NO_MORE_FILES: - return ENMFILE; -#endif -#ifdef ENMFILE - case ERROR_NO_MORE_ITEMS: - return ENMFILE; -#endif - case ERROR_NO_MORE_SEARCH_HANDLES: - return ENFILE; - case ERROR_NO_PROC_SLOTS: - return EAGAIN; - case ERROR_NO_SIGNAL_SENT: - return EIO; - case ERROR_NO_SYSTEM_RESOURCES: - return EFBIG; - case ERROR_NO_TOKEN: - return EINVAL; - case ERROR_OPEN_FAILED: - return EIO; - case ERROR_OPEN_FILES: - return EAGAIN; - case ERROR_OUTOFMEMORY: - return ENOMEM; - case ERROR_PAGED_SYSTEM_RESOURCES: - return EAGAIN; - case ERROR_PAGEFILE_QUOTA: - return EAGAIN; - case ERROR_PATH_NOT_FOUND: - return ENOENT; - case ERROR_PIPE_BUSY: - return EBUSY; - case ERROR_PIPE_CONNECTED: - return EBUSY; -#ifdef ECOMM - case ERROR_PIPE_LISTENING: - return ECOMM; - case ERROR_PIPE_NOT_CONNECTED: - return ECOMM; -#endif - case ERROR_POSSIBLE_DEADLOCK: - return EDEADLOCK; - case ERROR_PRIVILEGE_NOT_HELD: - return EPERM; - case ERROR_PROCESS_ABORTED: - return EFAULT; - case ERROR_PROC_NOT_FOUND: - return ESRCH; -#ifdef ENONET - case ERROR_REM_NOT_LIST: - return ENONET; -#endif - case ERROR_SECTOR_NOT_FOUND: - return EINVAL; - case ERROR_SEEK: - return EINVAL; - case ERROR_SETMARK_DETECTED: - return EIO; - case ERROR_SHARING_BUFFER_EXCEEDED: - return ENOLCK; - case ERROR_SHARING_VIOLATION: - return EBUSY; - case ERROR_SIGNAL_PENDING: - return EBUSY; - case ERROR_SIGNAL_REFUSED: - return EIO; -#ifdef ELIBBAD - case ERROR_SXS_CANT_GEN_ACTCTX: - return ELIBBAD; -#endif - case ERROR_THREAD_1_INACTIVE: - return EINVAL; - case ERROR_TOO_MANY_LINKS: - return EMLINK; - case ERROR_TOO_MANY_OPEN_FILES: - return EMFILE; - case ERROR_WAIT_NO_CHILDREN: - return ECHILD; - case ERROR_WORKING_SET_QUOTA: - return EAGAIN; - case ERROR_WRITE_PROTECT: - return EROFS; - default: - return -1; - } -} - -void -set_errno_from_win32_error(DWORD err) -{ - errno = win32_error_to_errno(err); -} - -void -set_errno_from_GetLastError(void) -{ - set_errno_from_win32_error(GetLastError()); -} - -void -set_errno_from_nt_status(NTSTATUS status) -{ - set_errno_from_win32_error((*func_RtlNtStatusToDosError)(status)); -} - static bool win32_modify_privilege(const wchar_t *privilege, bool enable) { @@ -352,16 +62,21 @@ out: static bool win32_modify_capture_privileges(bool enable) { - return win32_modify_privilege(SE_BACKUP_NAME, enable) - && win32_modify_privilege(SE_SECURITY_NAME, enable); + bool ok = true; + ok &= win32_modify_privilege(SE_BACKUP_NAME, enable); + ok &= win32_modify_privilege(SE_SECURITY_NAME, enable); + return ok; } static bool win32_modify_apply_privileges(bool enable) { - return win32_modify_privilege(SE_RESTORE_NAME, enable) - && win32_modify_privilege(SE_SECURITY_NAME, enable) - && win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable); + bool ok = true; + ok &= win32_modify_privilege(SE_RESTORE_NAME, enable); + ok &= win32_modify_privilege(SE_SECURITY_NAME, enable); + ok &= win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable); + ok &= win32_modify_privilege(SE_MANAGE_VOLUME_NAME, enable); + return ok; } static void @@ -484,20 +199,8 @@ NTSTATUS (WINAPI *func_RtlDosPathNameToNtPathName_U_WithStatus) NTSTATUS (WINAPI *func_RtlCreateSystemVolumeInformationFolder) (PCUNICODE_STRING VolumeRootPath); -static OSVERSIONINFO windows_version_info = { - .dwOSVersionInfoSize = sizeof(OSVERSIONINFO), -}; - static bool acquired_privileges = false; -bool -windows_version_is_at_least(unsigned major, unsigned minor) -{ - return windows_version_info.dwMajorVersion > major || - (windows_version_info.dwMajorVersion == major && - windows_version_info.dwMinorVersion >= minor); -} - struct dll_sym { void **func_ptr; const char *name; @@ -599,9 +302,6 @@ win32_global_init(int init_flags) acquired_privileges = true; } - /* Get Windows version information. */ - GetVersionEx(&windows_version_info); - ret = init_dll(&ntdll_spec); if (ret) goto out_drop_privs; @@ -655,9 +355,175 @@ win32_path_to_nt_path(const wchar_t *win32_path, UNICODE_STRING *nt_path) if (status == STATUS_NO_MEMORY) return WIMLIB_ERR_NOMEM; - ERROR("\"%ls\": invalid path name (status=0x%08"PRIx32")", - win32_path, (u32)status); + winnt_error(status, L"\"%ls\": invalid path name", win32_path); return WIMLIB_ERR_INVALID_PARAM; } +int +win32_get_drive_path(const wchar_t *file_path, wchar_t drive_path[7]) +{ + tchar *file_abspath; + + file_abspath = realpath(file_path, NULL); + if (!file_abspath) + return WIMLIB_ERR_NOMEM; + + if (file_abspath[0] == L'\0' || file_abspath[1] != L':') { + ERROR("\"%ls\": Path format not recognized", file_abspath); + FREE(file_abspath); + return WIMLIB_ERR_UNSUPPORTED; + } + + wsprintf(drive_path, L"\\\\.\\%lc:", file_abspath[0]); + FREE(file_abspath); + return 0; +} + +/* Try to attach an instance of the Windows Overlay File System Filter Driver to + * the specified drive (such as C:) */ +bool +win32_try_to_attach_wof(const wchar_t *drive) +{ + HMODULE fltlib; + bool retval = false; + + /* Use FilterAttach() from Fltlib.dll. */ + + fltlib = LoadLibrary(L"Fltlib.dll"); + + if (!fltlib) { + WARNING("Failed to load Fltlib.dll"); + return retval; + } + + HRESULT (WINAPI *func_FilterAttach)(LPCWSTR lpFilterName, + LPCWSTR lpVolumeName, + LPCWSTR lpInstanceName, + DWORD dwCreatedInstanceNameLength, + LPWSTR lpCreatedInstanceName); + + func_FilterAttach = (void *)GetProcAddress(fltlib, "FilterAttach"); + + if (func_FilterAttach) { + HRESULT res; + + res = (*func_FilterAttach)(L"wof", drive, NULL, 0, NULL); + + if (res != S_OK) + res = (*func_FilterAttach)(L"wofadk", drive, NULL, 0, NULL); + + if (res == S_OK) + retval = true; + } else { + WARNING("FilterAttach() does not exist in Fltlib.dll"); + } + + FreeLibrary(fltlib); + + return retval; +} + + +static void +windows_msg(u32 code, const wchar_t *format, va_list va, + bool is_ntstatus, bool is_error) +{ + wchar_t _buf[STACK_MAX / 8]; + wchar_t *buf = _buf; + size_t buflen = ARRAY_LEN(_buf); + size_t ret; + size_t n; + +retry: + n = vsnwprintf(buf, buflen, format, va); + + if (n >= buflen) + goto realloc; + + n += snwprintf(&buf[n], buflen - n, + (is_ntstatus ? + L" (status=%08"PRIx32"): " : + L" (err=%"PRIu32"): "), + code); + + if (n >= buflen) + goto realloc; + + ret = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + is_ntstatus ? (*func_RtlNtStatusToDosError)(code) : code, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + &buf[n], + buflen - n, + NULL); + n += ret; + + if (n >= buflen || (ret == 0 && GetLastError() == ERROR_INSUFFICIENT_BUFFER)) + goto realloc; + + if (buf[n - 1] == L'\n') + buf[--n] = L'\0'; + if (buf[n - 1] == L'\r') + buf[--n] = L'\0'; + if (buf[n - 1] == L'.') + buf[--n] = L'\0'; + + if (is_error) + ERROR("%ls", buf); + else + WARNING("%ls", buf); + if (buf != _buf) + FREE(buf); + return; + +realloc: + if (buf != _buf) + FREE(buf); + buflen *= 2; + buf = MALLOC(buflen * sizeof(buf[0])); + if (buf) + goto retry; + ERROR("Ran out of memory while building error message!!!"); +} + +void +win32_warning(DWORD err, const wchar_t *format, ...) +{ + va_list va; + + va_start(va, format); + windows_msg(err, format, va, false, false); + va_end(va); +} + +void +win32_error(DWORD err, const wchar_t *format, ...) +{ + va_list va; + + va_start(va, format); + windows_msg(err, format, va, false, true); + va_end(va); +} + +void +winnt_warning(NTSTATUS status, const wchar_t *format, ...) +{ + va_list va; + + va_start(va, format); + windows_msg(status, format, va, true, false); + va_end(va); +} + +void +winnt_error(NTSTATUS status, const wchar_t *format, ...) +{ + va_list va; + + va_start(va, format); + windows_msg(status, format, va, true, true); + va_end(va); +} + #endif /* __WIN32__ */