From 9fb3aaca115429b0af2a623bf20bfceef74f047f Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 20 Mar 2013 14:24:42 -0500 Subject: [PATCH] Win32 fixes --- configure.ac | 18 +- programs/imagex-win32.c | 81 ++++++++- programs/imagex-win32.h | 13 ++ programs/imagex.c | 19 +- src/add_image.c | 116 ++++++------ src/dentry.h | 4 + src/extract_image.c | 6 - src/lookup_table.c | 13 +- src/lookup_table.h | 10 ++ src/sha1.c | 29 +-- src/sha1.h | 10 +- src/util.c | 2 +- src/util.h | 11 +- src/wim.c | 15 +- src/win32.c | 380 ++++++++++++++++++---------------------- src/win32.h | 72 +++++--- src/write.c | 20 ++- 17 files changed, 469 insertions(+), 350 deletions(-) diff --git a/configure.ac b/configure.ac index 1326258c..e30d4554 100644 --- a/configure.ac +++ b/configure.ac @@ -237,22 +237,20 @@ else LIBNTFS_3G_LDADD= LIBNTFS_3G_CFLAGS= - if test "x$WINDOWS_NATIVE_BUILD" != "xyes"; then - AM_ICONV - if test "x$am_cv_func_iconv" != "xyes"; then - AC_MSG_ERROR([Cannot find the iconv() function. - iconv() is used to convert between UTF-8 and UTF-16 encodings of WIM - filenames and XML data. Wimlib cannot be compiled without it. iconv() - is available in the latest version of glibc and sometimes in other - libraries.]) - fi - fi fi AM_CONDITIONAL([WITH_NTFS_3G], [test "x$WITH_NTFS_3G" = "xyes"]) AC_SUBST([LIBNTFS_3G_LDADD], [$LIBNTFS_3G_LDADD]) AC_SUBST([LIBNTFS_3G_CFLAGS], [$LIBNTFS_3G_CFLAGS]) +AM_ICONV +if test "x$am_cv_func_iconv" != "xyes"; then + AC_MSG_ERROR([Cannot find the iconv() function. + iconv() is used to convert between encodings of WIM filenames and XML data. + wimlib cannot be compiled without it. iconv() is available in the latest + version of glibc and sometimes in other libraries.]) +fi + AC_MSG_CHECKING([whether to include support for mounting WIMs]) AC_ARG_WITH([fuse], AS_HELP_STRING([--without-fuse], [build without libfuse. diff --git a/programs/imagex-win32.c b/programs/imagex-win32.c index 3c449a77..3dc51d98 100644 --- a/programs/imagex-win32.c +++ b/programs/imagex-win32.c @@ -1,6 +1,7 @@ /* Replacements for functions needed specifically by the 'imagex' program in - * Windows native builds */ + * Windows native builds; also, Windows-specific code to acquire and release + * privileges needed to backup and restore files */ #ifndef __WIN32__ # error "This file contains Windows code" @@ -11,7 +12,7 @@ #include #include #include - +#include /* Replacement for glob() in Windows native builds. */ int glob(const char *pattern, int flags, @@ -94,3 +95,79 @@ void globfree(glob_t *pglob) free(pglob->gl_pathv[i]); free(pglob->gl_pathv[i]); } + +static bool +win32_modify_privilege(const char *privilege, bool enable) +{ + HANDLE hToken; + LUID luid; + TOKEN_PRIVILEGES newState; + bool ret = false; + + if (!OpenProcessToken(GetCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &hToken)) + { + goto out; + } + + if (!LookupPrivilegeValue(NULL, privilege, &luid)) { + goto out; + } + + newState.PrivilegeCount = 1; + newState.Privileges[0].Luid = luid; + newState.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0); + ret = AdjustTokenPrivileges(hToken, FALSE, &newState, 0, NULL, NULL); + CloseHandle(hToken); +out: + if (!ret) { + fprintf(stderr, "WARNING: Failed to %s privilege %s\n", + enable ? "enable" : "disable", privilege); + fprintf(stderr, + "WARNING: The program will continue, " + "but if permission issues are\n" + "encountered, you may need to run " + "this program as the administrator\n"); + } + return ret; +} + +static void +win32_modify_capture_privileges(bool enable) +{ + win32_modify_privilege(SE_BACKUP_NAME, enable); + win32_modify_privilege(SE_SECURITY_NAME, enable); +} + +static void +win32_modify_restore_privileges(bool enable) +{ + win32_modify_privilege(SE_RESTORE_NAME, enable); + win32_modify_privilege(SE_SECURITY_NAME, enable); + win32_modify_privilege(SE_TAKE_OWNERSHIP_NAME, enable); +} + +void +win32_acquire_capture_privileges() +{ + win32_modify_capture_privileges(true); +} + +void +win32_release_capture_privileges() +{ + win32_modify_capture_privileges(false); +} + +void +win32_acquire_restore_privileges() +{ + win32_modify_restore_privileges(true); +} + +void +win32_release_restore_privileges() +{ + win32_modify_restore_privileges(false); +} diff --git a/programs/imagex-win32.h b/programs/imagex-win32.h index 58441e83..1de8e984 100644 --- a/programs/imagex-win32.h +++ b/programs/imagex-win32.h @@ -2,6 +2,7 @@ #define _IMAGEX_WIN32_H #include +#include typedef struct { size_t gl_pathc; @@ -24,4 +25,16 @@ extern void globfree(glob_t *pglob); #define GLOB_ABORTED 2 /* Read error. */ #define GLOB_NOMATCH 3 /* No matches found. */ +extern void +win32_acquire_capture_privileges(); + +extern void +win32_release_capture_privileges(); + +extern void +win32_acquire_restore_privileges(); + +extern void +win32_release_restore_privileges(); + #endif diff --git a/programs/imagex.c b/programs/imagex.c index 19725058..580e65ac 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -900,11 +900,17 @@ static int imagex_apply(int argc, char **argv) } } +#ifdef __WIN32__ + win32_acquire_restore_privileges(); +#endif ret = wimlib_extract_image(w, image, target, extract_flags, additional_swms, num_additional_swms, imagex_progress_func); if (ret == 0) printf("Done applying WIM image.\n"); +#ifdef __WIN32__ + win32_release_restore_privileges(); +#endif out: wimlib_free(w); if (additional_swms) { @@ -1081,6 +1087,9 @@ static int imagex_capture_or_append(int argc, char **argv) } } } +#ifdef __WIN32__ + win32_acquire_capture_privileges(); +#endif ret = wimlib_add_image_multisource(w, capture_sources, num_sources, name, @@ -1091,17 +1100,17 @@ static int imagex_capture_or_append(int argc, char **argv) add_image_flags, imagex_progress_func); if (ret != 0) - goto out; + goto out_release_privs; cur_image = wimlib_get_num_images(w); if (desc) { ret = wimlib_set_image_descripton(w, cur_image, desc); if (ret != 0) - goto out; + goto out_release_privs; } if (flags_element) { ret = wimlib_set_image_flags(w, cur_image, flags_element); if (ret != 0) - goto out; + goto out_release_privs; } if (cmd == APPEND) { ret = wimlib_overwrite(w, write_flags, num_threads, @@ -1114,6 +1123,10 @@ static int imagex_capture_or_append(int argc, char **argv) ret = 0; if (ret != 0) imagex_error("Failed to write the WIM file `%s'", wimfile); +out_release_privs: +#ifdef __WIN32__ + win32_release_capture_privileges(); +#endif out: wimlib_free(w); free(config_str); diff --git a/src/add_image.c b/src/add_image.c index ab4adc97..7c9199c9 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -784,6 +784,7 @@ new_filler_directory(const mbchar *name, struct wim_dentry **dentry_ret) * will be assigned later by assign_inode_numbers(). */ dentry->d_inode->i_resolved = 1; dentry->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY; + *dentry_ret = dentry; } return ret; } @@ -1009,68 +1010,62 @@ wimlib_add_image_multisource(WIMStruct *w, } DEBUG("Building dentry tree."); - if (num_sources == 0) { - ret = new_filler_directory("", &root_dentry); + root_dentry = NULL; + + for (size_t i = 0; i < num_sources; i++) { + int flags; + union wimlib_progress_info progress; + + DEBUG("Building dentry tree for source %zu of %zu " + "(\"%s\" => \"%s\")", i + 1, num_sources, + sources[i].fs_source_path, + sources[i].wim_target_path); + if (progress_func) { + memset(&progress, 0, sizeof(progress)); + progress.scan.source = sources[i].fs_source_path; + progress.scan.wim_target_path = sources[i].wim_target_path; + progress_func(WIMLIB_PROGRESS_MSG_SCAN_BEGIN, &progress); + } + ret = capture_config_set_prefix(&config, + sources[i].fs_source_path); if (ret) - goto out_free_security_data; - } else { - size_t i; - - #ifdef __WIN32__ - win32_acquire_capture_privileges(); - #endif + goto out_free_dentry_tree; + flags = add_image_flags | WIMLIB_ADD_IMAGE_FLAG_SOURCE; + if (!*sources[i].wim_target_path) + flags |= WIMLIB_ADD_IMAGE_FLAG_ROOT; + ret = (*capture_tree)(&branch, sources[i].fs_source_path, + w->lookup_table, sd, + &config, + flags, + progress_func, extra_arg); + if (ret) { + ERROR("Failed to build dentry tree for `%s'", + sources[i].fs_source_path); + goto out_free_dentry_tree; + } + if (branch) { + /* Use the target name, not the source name, for + * the root of each branch from a capture + * source. (This will also set the root dentry + * of the entire image to be unnamed.) */ + ret = set_dentry_name(branch, + path_basename(sources[i].wim_target_path)); + if (ret) + goto out_free_branch; - root_dentry = NULL; - i = 0; - do { - int flags; - union wimlib_progress_info progress; - - DEBUG("Building dentry tree for source %zu of %zu " - "(\"%s\" => \"%s\")", i + 1, num_sources, - sources[i].fs_source_path, - sources[i].wim_target_path); - if (progress_func) { - memset(&progress, 0, sizeof(progress)); - progress.scan.source = sources[i].fs_source_path; - progress.scan.wim_target_path = sources[i].wim_target_path; - progress_func(WIMLIB_PROGRESS_MSG_SCAN_BEGIN, &progress); - } - ret = capture_config_set_prefix(&config, - sources[i].fs_source_path); + ret = attach_branch(&root_dentry, branch, + sources[i].wim_target_path); if (ret) - goto out_free_dentry_tree; - flags = add_image_flags | WIMLIB_ADD_IMAGE_FLAG_SOURCE; - if (!*sources[i].wim_target_path) - flags |= WIMLIB_ADD_IMAGE_FLAG_ROOT; - ret = (*capture_tree)(&branch, sources[i].fs_source_path, - w->lookup_table, sd, - &config, - flags, - progress_func, extra_arg); - if (ret) { - ERROR("Failed to build dentry tree for `%s'", - sources[i].fs_source_path); - goto out_free_dentry_tree; - } - if (branch) { - /* Use the target name, not the source name, for - * the root of each branch from a capture - * source. (This will also set the root dentry - * of the entire image to be unnamed.) */ - ret = set_dentry_name(branch, - path_basename(sources[i].wim_target_path)); - if (ret) - goto out_free_branch; - - ret = attach_branch(&root_dentry, branch, - sources[i].wim_target_path); - if (ret) - goto out_free_branch; - } - if (progress_func) - progress_func(WIMLIB_PROGRESS_MSG_SCAN_END, &progress); - } while (++i != num_sources); + goto out_free_branch; + } + if (progress_func) + progress_func(WIMLIB_PROGRESS_MSG_SCAN_END, &progress); + } + + if (root_dentry == NULL) { + ret = new_filler_directory("" , &root_dentry); + if (ret) + goto out_free_dentry_tree; } DEBUG("Calculating full paths of dentries."); @@ -1113,9 +1108,6 @@ out_free_security_data: out_destroy_capture_config: destroy_capture_config(&config); out: -#ifdef __WIN32__ - win32_release_capture_privileges(); -#endif return ret; } diff --git a/src/dentry.h b/src/dentry.h index 6442b106..3c59f128 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -271,7 +271,11 @@ struct wim_inode { struct list_head i_lte_inode_list; +#ifdef __WIN32__ + utf16lechar *i_extracted_file; +#else mbchar *i_extracted_file; +#endif /* Root of a red-black tree storing the children of this inode (if * non-empty, implies the inode is a directory, although that is also diff --git a/src/extract_image.c b/src/extract_image.c index 199d20b2..d637a106 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -989,9 +989,6 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, w->lookup_table = joined_tab; } -#ifdef __WIN32__ - win32_acquire_restore_privileges(); -#endif if (image == WIMLIB_ALL_IMAGES) { extract_flags |= WIMLIB_EXTRACT_FLAG_MULTI_IMAGE; ret = extract_all_images(w, target, extract_flags, @@ -1001,9 +998,6 @@ WIMLIBAPI int wimlib_extract_image(WIMStruct *w, ret = extract_single_image(w, image, target, extract_flags, progress_func); } -#ifdef __WIN32__ - win32_release_restore_privileges(); -#endif if (extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) diff --git a/src/lookup_table.c b/src/lookup_table.c index f8a2aef0..393c0d68 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -84,11 +84,20 @@ clone_lookup_table_entry(const struct wim_lookup_table_entry *old) memcpy(new, old, sizeof(*old)); new->extracted_file = NULL; switch (new->resource_location) { - case RESOURCE_IN_STAGING_FILE: - case RESOURCE_IN_FILE_ON_DISK: #ifdef __WIN32__ case RESOURCE_WIN32: + { + size_t nbytes = utf16le_strlen(old->win32_file_on_disk); + new->win32_file_on_disk = MALLOC(nbytes + 2); + if (!new->win32_file_on_disk) + goto out_free; + memcpy(new->win32_file_on_disk, old->win32_file_on_disk, + nbytes + 2); + } + break; #endif + case RESOURCE_IN_STAGING_FILE: + case RESOURCE_IN_FILE_ON_DISK: BUILD_BUG_ON((void*)&old->file_on_disk != (void*)&old->staging_file_name); new->staging_file_name = STRDUP(old->staging_file_name); diff --git a/src/lookup_table.h b/src/lookup_table.h index d172cac9..accc7324 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -11,6 +11,10 @@ #define LOOKUP_FLAG_ADS_OK 0x00000001 #define LOOKUP_FLAG_DIRECTORY_OK 0x00000002 +#ifdef __WIN32__ +#include +#endif + /* The lookup table of a WIM file maps SHA1 message digests to streams of data. * Here, the in-memory structure is implemented as a hash table. @@ -159,6 +163,9 @@ struct wim_lookup_table_entry { WIMStruct *wim; mbchar *file_on_disk; mbchar *staging_file_name; + #ifdef __WIN32__ + wchar_t *win32_file_on_disk; + #endif u8 *attached_buffer; #ifdef WITH_NTFS_3G struct ntfs_location *ntfs_loc; @@ -168,6 +175,7 @@ struct wim_lookup_table_entry { /* @file_on_disk_fp and @attr are both used to cache file/stream * handles so we don't have re-open them on every read */ + /* Valid iff resource_location == RESOURCE_IN_FILE_ON_DISK */ FILE *file_on_disk_fp; #ifdef WITH_NTFS_3G @@ -175,6 +183,8 @@ struct wim_lookup_table_entry { struct _ntfs_attr *attr; #endif + HANDLE win32_file_on_disk_fp; + /* Pointer to inode that contains the opened file descriptors to * this stream (valid iff resource_location == * RESOURCE_IN_STAGING_FILE) */ diff --git a/src/sha1.c b/src/sha1.c index ca1ad0eb..0553b63c 100644 --- a/src/sha1.c +++ b/src/sha1.c @@ -45,7 +45,8 @@ const u8 zero_hash[SHA1_HASH_SIZE] = { #ifndef WITH_LIBCRYPTO /* Initialize new context */ -void sha1_init(SHA_CTX* context) +void +sha1_init(SHA_CTX* context) { /* SHA1 initialization constants */ context->state[0] = 0x67452301; @@ -57,9 +58,11 @@ void sha1_init(SHA_CTX* context) } #ifdef ENABLE_SSSE3_SHA1 -extern void sha1_update_intel(int *hash, const char* input, size_t num_blocks); +extern void +sha1_update_intel(int *hash, const void* input, size_t num_blocks); -void sha1_update(SHA_CTX *context, const u8 data[], size_t len) +void +sha1_update(SHA_CTX *context, const void *data, size_t len) { sha1_update_intel((int*)&context->state, data, len / 64); size_t j = (context->count[0] >> 3) & 63; @@ -67,7 +70,8 @@ void sha1_update(SHA_CTX *context, const u8 data[], size_t len) context->count[1] += (len >> 29); } #include -void ssse3_not_found() +void +ssse3_not_found() { fprintf(stderr, "Cannot calculate SHA1 message digest: CPU does not support SSSE3\n" @@ -99,7 +103,8 @@ void ssse3_not_found() #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); /* Hash a single 512-bit block. This is the core of the algorithm. */ -static void sha1_transform(u32 state[5], const u8 buffer[64]) +static void +sha1_transform(u32 state[5], const u8 buffer[64]) { u32 a, b, c, d, e; typedef union { @@ -149,7 +154,8 @@ static void sha1_transform(u32 state[5], const u8 buffer[64]) state[4] += e; } -void sha1_update(SHA_CTX* context, const u8 data[], const size_t len) +void +sha1_update(SHA_CTX* context, const void *data, const size_t len) { size_t i, j; @@ -167,13 +173,14 @@ void sha1_update(SHA_CTX* context, const u8 data[], const size_t len) } else { i = 0; } - memcpy(&context->buffer[j], &data[i], len - i); + memcpy(&context->buffer[j], data + i, len - i); } #endif /* !ENABLE_SSSE3_SHA1 */ /* Add padding and return the message digest. */ -void sha1_final(u8 md[SHA1_HASH_SIZE], SHA_CTX* context) +void +sha1_final(u8 md[SHA1_HASH_SIZE], SHA_CTX* context) { u32 i; u8 finalcount[8]; @@ -192,7 +199,8 @@ void sha1_final(u8 md[SHA1_HASH_SIZE], SHA_CTX* context) } } -void sha1_buffer(const u8 buffer[], size_t len, u8 md[SHA1_HASH_SIZE]) +void +sha1_buffer(const void *buffer, size_t len, u8 md[SHA1_HASH_SIZE]) { SHA_CTX ctx; sha1_init(&ctx); @@ -202,7 +210,8 @@ void sha1_buffer(const u8 buffer[], size_t len, u8 md[SHA1_HASH_SIZE]) #endif /* !WITH_LIBCRYPTO */ -static int sha1_stream(FILE *fp, u8 md[SHA1_HASH_SIZE]) +static int +sha1_stream(FILE *fp, u8 md[SHA1_HASH_SIZE]) { char buf[BUFFER_SIZE]; size_t bytes_read; diff --git a/src/sha1.h b/src/sha1.h index 5238a92c..c8fe87ff 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -62,7 +62,11 @@ zero_out_hash(u8 hash[SHA1_HASH_SIZE]) #ifdef WITH_LIBCRYPTO #include -#define sha1_buffer SHA1 +static inline void +sha1_buffer(const void *buffer, size_t len, u8 hash[SHA1_HASH_SIZE]) +{ + SHA1(buffer, len, hash); +} #define sha1_init SHA1_Init #define sha1_update SHA1_Update #define sha1_final SHA1_Final @@ -76,13 +80,13 @@ typedef struct { } SHA_CTX; extern void -sha1_buffer(const u8 buffer[], size_t len, u8 hash[SHA1_HASH_SIZE]); +sha1_buffer(const void *buffer, size_t len, u8 hash[SHA1_HASH_SIZE]); extern void sha1_init(SHA_CTX *ctx); extern void -sha1_update(SHA_CTX *ctx, const u8 data[], size_t len); +sha1_update(SHA_CTX *ctx, const void *data, size_t len); extern void sha1_final(u8 hash[SHA1_HASH_SIZE], SHA_CTX *ctx); diff --git a/src/util.c b/src/util.c index d43d8def..20bff959 100644 --- a/src/util.c +++ b/src/util.c @@ -48,7 +48,7 @@ # define strerror_r(errnum, buf, bufsize) strerror_s(buf, bufsize, errnum) #endif -static size_t +size_t utf16le_strlen(const utf16lechar *s) { const utf16lechar *p = s; diff --git a/src/util.h b/src/util.h index 50b78bb9..4fd117df 100644 --- a/src/util.h +++ b/src/util.h @@ -67,6 +67,9 @@ typedef char utf8char; /* A pointer to 'utf16lechar' indicates a UTF-16LE encoded string */ typedef u16 utf16lechar; +extern size_t +utf16le_strlen(const utf16lechar *s); + /* encoding.c */ extern void iconv_global_cleanup(); @@ -272,9 +275,13 @@ bsr32(u32 n) } extern int -wimlib_fprintf(FILE *fp, const char *format, ...) FORMAT(printf, 2, 3); +wimlib_fprintf(FILE *fp, const char *format, ...) + //FORMAT(printf, 2, 3) + ; extern int -wimlib_printf(const char *format, ...) FORMAT(printf, 1, 2); +wimlib_printf(const char *format, ...) + //FORMAT(printf, 1, 2) + ; #endif /* _WIMLIB_UTIL_H */ diff --git a/src/wim.c b/src/wim.c index 45b9fd62..6262a1b7 100644 --- a/src/wim.c +++ b/src/wim.c @@ -27,7 +27,6 @@ #include #include -#include #include #include #include @@ -40,6 +39,8 @@ #ifdef __WIN32__ # include "win32.h" +#else +# include #endif #include "buffer_io.h" @@ -669,6 +670,16 @@ wimlib_free(WIMStruct *w) DEBUG("Freed WIMStruct"); } +static bool test_locale_ctype_utf8() +{ + char *ctype = nl_langinfo(CODESET); + + return (strstr(ctype, "UTF-8") == 0 || + strstr(ctype, "UTF8") == 0 || + strstr(ctype, "utf8") == 0 || + strstr(ctype, "utf-8") == 0); +} + bool wimlib_mbs_is_utf8; /* Get global memory allocations out of the way. Not strictly necessary in @@ -680,7 +691,7 @@ wimlib_global_init() #ifdef WITH_NTFS_3G libntfs3g_global_init(); #endif - wimlib_mbs_is_utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0); + wimlib_mbs_is_utf8 = test_locale_ctype_utf8(); return 0; } diff --git a/src/win32.c b/src/win32.c index 97d0b44a..fb30b5f0 100644 --- a/src/win32.c +++ b/src/win32.c @@ -40,11 +40,13 @@ #include "dentry.h" #include "lookup_table.h" #include "security.h" +#include "endianness.h" #include #ifdef ENABLE_ERROR_MESSAGES -void win32_error(u32 err_code) +void +win32_error(u32 err_code) { char *buffer; DWORD nchars; @@ -59,15 +61,22 @@ void win32_error(u32 err_code) LocalFree(buffer); } } + +void +win32_error_last() +{ + win32_error(GetLastError()); +} #endif -void *win32_open_file_readonly(const void *path) +HANDLE +win32_open_file_readonly(const wchar_t *path, bool data_only) { - return CreateFileW((const wchar_t*)path, - FILE_READ_DATA | - FILE_READ_ATTRIBUTES | - READ_CONTROL | - ACCESS_SYSTEM_SECURITY, + DWORD dwDesiredAccess = FILE_READ_DATA; + if (!data_only) + dwDesiredAccess |= FILE_READ_ATTRIBUTES | READ_CONTROL | ACCESS_SYSTEM_SECURITY; + return CreateFileW(path, + dwDesiredAccess, FILE_SHARE_READ, NULL, /* lpSecurityAttributes */ OPEN_EXISTING, @@ -76,8 +85,9 @@ void *win32_open_file_readonly(const void *path) NULL /* hTemplateFile */); } -int win32_read_file(const char *filename, - void *handle, u64 offset, size_t size, void *buf) +int +win32_read_file(const mbchar *filename, + void *handle, u64 offset, size_t size, void *buf) { HANDLE h = handle; DWORD err; @@ -95,116 +105,41 @@ int win32_read_file(const char *filename, return WIMLIB_ERR_READ; } -void win32_close_file(void *handle) +void +win32_close_file(void *handle) { CloseHandle((HANDLE)handle); } -static bool win32_modify_privilege(const char *privilege, bool enable) -{ - HANDLE hToken; - LUID luid; - TOKEN_PRIVILEGES newState; - bool ret = false; - - DEBUG("%s privilege %s", - enable ? "Enabling" : "Disabling", privilege); - - if (!OpenProcessToken(GetCurrentProcess(), - TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, - &hToken)) - { - DEBUG("OpenProcessToken() failed"); - goto out; - } - - if (!LookupPrivilegeValue(NULL, privilege, &luid)) { - DEBUG("LookupPrivilegeValue() failed"); - goto out; - } - - newState.PrivilegeCount = 1; - newState.Privileges[0].Luid = luid; - newState.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0); - ret = AdjustTokenPrivileges(hToken, FALSE, &newState, 0, NULL, NULL); - if (!ret) - DEBUG("AdjustTokenPrivileges() failed"); - CloseHandle(hToken); -out: - if (!ret) { - DWORD err = GetLastError(); - win32_error(err); - WARNING("Failed to %s privilege %s", - enable ? "enable" : "disable", privilege); - WARNING("The program will continue, but if permission issues are " - "encountered, you may need to run this program as the administrator"); - } - return ret; -} - -static bool win32_acquire_privilege(const char *privilege) -{ - return win32_modify_privilege(privilege, true); -} - -static bool win32_release_privilege(const char *privilege) -{ - return win32_modify_privilege(privilege, false); -} - - -void win32_acquire_capture_privileges() -{ - win32_acquire_privilege(SE_BACKUP_NAME); - win32_acquire_privilege(SE_SECURITY_NAME); -} - -void win32_release_capture_privileges() -{ - win32_release_privilege(SE_BACKUP_NAME); - win32_release_privilege(SE_SECURITY_NAME); -} - -void win32_acquire_restore_privileges() -{ - win32_acquire_privilege(SE_RESTORE_NAME); - win32_acquire_privilege(SE_SECURITY_NAME); - win32_acquire_privilege(SE_TAKE_OWNERSHIP_NAME); -} - -void win32_release_restore_privileges() -{ - win32_release_privilege(SE_RESTORE_NAME); - win32_release_privilege(SE_SECURITY_NAME); - win32_release_privilege(SE_TAKE_OWNERSHIP_NAME); -} - -static u64 FILETIME_to_u64(const FILETIME *ft) +static u64 +FILETIME_to_u64(const FILETIME *ft) { return ((u64)ft->dwHighDateTime << 32) | (u64)ft->dwLowDateTime; } -static int win32_get_short_name(struct wim_dentry *dentry, - const wchar_t *path_utf16) +static int +win32_get_short_name(struct wim_dentry *dentry, + const wchar_t *path_utf16) { WIN32_FIND_DATAW dat; if (FindFirstFileW(path_utf16, &dat) && dat.cAlternateFileName[0] != L'\0') { - size_t short_name_len = wcslen(dat.cAlternateFileName) * 2; - size_t n = short_name_len + sizeof(wchar_t); + size_t short_name_nbytes = wcslen(dat.cAlternateFileName) * 2; + size_t n = short_name_nbytes + sizeof(wchar_t); dentry->short_name = MALLOC(n); if (!dentry->short_name) return WIMLIB_ERR_NOMEM; memcpy(dentry->short_name, dat.cAlternateFileName, n); - dentry->short_name_len = short_name_len; + dentry->short_name_nbytes = short_name_nbytes; } return 0; } -static int win32_get_security_descriptor(struct wim_dentry *dentry, - struct sd_set *sd_set, - const wchar_t *path_utf16) +static int +win32_get_security_descriptor(struct wim_dentry *dentry, + struct sd_set *sd_set, + const wchar_t *path_utf16) { SECURITY_INFORMATION requestedInformation; DWORD lenNeeded = 0; @@ -244,16 +179,17 @@ static int win32_get_security_descriptor(struct wim_dentry *dentry, /* Reads the directory entries of directory using a Win32 API and recursively * calls win32_build_dentry_tree() on them. */ -static int win32_recurse_directory(struct wim_dentry *root, - const char *root_disk_path, - struct wim_lookup_table *lookup_table, - struct wim_security_data *sd, - const struct capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, - struct sd_set *sd_set, - const wchar_t *path_utf16, - size_t path_utf16_nchars) +static int +win32_recurse_directory(struct wim_dentry *root, + const mbchar *root_disk_path, + struct wim_lookup_table *lookup_table, + struct wim_security_data *sd, + const struct capture_config *config, + int add_image_flags, + wimlib_progress_func_t progress_func, + struct sd_set *sd_set, + const wchar_t *path_utf16, + size_t path_utf16_nchars) { WIN32_FIND_DATAW dat; HANDLE hFind; @@ -293,18 +229,18 @@ static int win32_recurse_directory(struct wim_dentry *root, { struct wim_dentry *child; - char *utf8_name; - size_t utf8_name_nbytes; - ret = utf16_to_utf8((const char*)dat.cFileName, - wcslen(dat.cFileName) * sizeof(wchar_t), - &utf8_name, - &utf8_name_nbytes); + char *mbs_name; + size_t mbs_name_nbytes; + ret = utf16le_to_mbs(dat.cFileName, + wcslen(dat.cFileName) * sizeof(wchar_t), + &mbs_name, + &mbs_name_nbytes); if (ret) goto out_find_close; - char name[strlen(root_disk_path) + 1 + utf8_name_nbytes + 1]; - sprintf(name, "%s/%s", root_disk_path, utf8_name); - FREE(utf8_name); + char name[strlen(root_disk_path) + 1 + mbs_name_nbytes + 1]; + sprintf(name, "%s/%s", root_disk_path, mbs_name); + FREE(mbs_name); ret = win32_build_dentry_tree(&child, name, lookup_table, sd, config, add_image_flags, progress_func, sd_set); @@ -341,10 +277,11 @@ out_find_close: * only. * * Returns 0 on success; nonzero on failure. */ -static int win32_capture_reparse_point(HANDLE hFile, - struct wim_inode *inode, - struct wim_lookup_table *lookup_table, - const char *path) +static int +win32_capture_reparse_point(HANDLE hFile, + struct wim_inode *inode, + struct wim_lookup_table *lookup_table, + const char *path) { /* "Reparse point data, including the tag and optional GUID, * cannot exceed 16 kilobytes." - MSDN */ @@ -364,7 +301,7 @@ static int win32_capture_reparse_point(HANDLE hFile, ERROR("Reparse data on \"%s\" is invalid", path); return WIMLIB_ERR_READ; } - inode->i_reparse_tag = *(u32*)reparse_point_buf; + inode->i_reparse_tag = le32_to_cpu(*(u32*)reparse_point_buf); return inode_add_ads_with_data(inode, "", (const u8*)reparse_point_buf + 8, bytesReturned - 8, lookup_table); @@ -381,7 +318,8 @@ static int win32_capture_reparse_point(HANDLE hFile, * * Returns 0 on success; nonzero on failure. */ -static int win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE]) +static int +win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE]) { HANDLE hFile; SHA_CTX ctx; @@ -389,7 +327,7 @@ static int win32_sha1sum(const wchar_t *path, u8 hash[SHA1_HASH_SIZE]) DWORD bytesRead; int ret; - hFile = win32_open_file_readonly(path); + hFile = win32_open_file_readonly(path, false); if (hFile == INVALID_HANDLE_VALUE) return WIMLIB_ERR_OPEN; @@ -428,11 +366,12 @@ out_close_handle: * * Returns 0 on success; nonzero on failure. */ -static int win32_capture_stream(const wchar_t *path_utf16, - size_t path_utf16_nchars, - struct wim_inode *inode, - struct wim_lookup_table *lookup_table, - WIN32_FIND_STREAM_DATA *dat) +static int +win32_capture_stream(const wchar_t *path_utf16, + size_t path_utf16_nchars, + struct wim_inode *inode, + struct wim_lookup_table *lookup_table, + WIN32_FIND_STREAM_DATA *dat) { struct wim_ads_entry *ads_entry; u8 hash[SHA1_HASH_SIZE]; @@ -462,16 +401,16 @@ static int win32_capture_stream(const wchar_t *path_utf16, is_named_stream = (p != colon); if (is_named_stream) { /* Allocate an ADS entry for the named stream. */ - char *utf8_stream_name; - size_t utf8_stream_name_len; - ret = utf16_to_utf8((const char *)p, - (colon - p) * sizeof(wchar_t), - &utf8_stream_name, - &utf8_stream_name_len); + char *mbs_stream_name; + size_t mbs_stream_name_nbytes; + ret = utf16le_to_mbs(p, + (colon - p) * sizeof(wchar_t), + &mbs_stream_name, + &mbs_stream_name_nbytes); if (ret) goto out; - ads_entry = inode_add_ads(inode, utf8_stream_name); - FREE(utf8_stream_name); + ads_entry = inode_add_ads(inode, mbs_stream_name); + FREE(mbs_stream_name); if (!ads_entry) { ret = WIMLIB_ERR_NOMEM; goto out; @@ -516,7 +455,8 @@ static int win32_capture_stream(const wchar_t *path_utf16, ret = WIMLIB_ERR_NOMEM; goto out_free_spath; } - lte->file_on_disk = (char*)spath; + lte->win32_file_on_disk = spath; + lte->file_on_disk_fp = INVALID_HANDLE_VALUE; spath = NULL; lte->resource_location = RESOURCE_WIN32; lte->resource_entry.original_size = (uint64_t)dat->StreamSize.QuadPart; @@ -551,10 +491,11 @@ out_invalid_stream_name: * * Returns 0 on success; nonzero on failure. */ -static int win32_capture_streams(const wchar_t *path_utf16, - size_t path_utf16_nchars, - struct wim_inode *inode, - struct wim_lookup_table *lookup_table) +static int +win32_capture_streams(const wchar_t *path_utf16, + size_t path_utf16_nchars, + struct wim_inode *inode, + struct wim_lookup_table *lookup_table) { WIN32_FIND_STREAM_DATA dat; int ret; @@ -599,20 +540,22 @@ out_find_close: } /* Win32 version of capturing a directory tree */ -int win32_build_dentry_tree(struct wim_dentry **root_ret, - const char *root_disk_path, - struct wim_lookup_table *lookup_table, - struct wim_security_data *sd, - const struct capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, - void *extra_arg) +int +win32_build_dentry_tree(struct wim_dentry **root_ret, + const char *root_disk_path, + struct wim_lookup_table *lookup_table, + struct wim_security_data *sd, + const struct capture_config *config, + int add_image_flags, + wimlib_progress_func_t progress_func, + void *extra_arg) { struct wim_dentry *root = NULL; int ret = 0; struct wim_inode *inode; wchar_t *path_utf16; + size_t path_utf16_nbytes; size_t path_utf16_nchars; struct sd_set *sd_set; DWORD err; @@ -651,13 +594,13 @@ int win32_build_dentry_tree(struct wim_dentry **root_ret, sd_set = extra_arg; } - ret = utf8_to_utf16(root_disk_path, strlen(root_disk_path), - (char**)&path_utf16, &path_utf16_nchars); + ret = mbs_to_utf16le(root_disk_path, strlen(root_disk_path), + &path_utf16, &path_utf16_nbytes); if (ret) goto out_destroy_sd_set; - path_utf16_nchars /= sizeof(wchar_t); + path_utf16_nchars = path_utf16_nbytes / sizeof(wchar_t); - HANDLE hFile = win32_open_file_readonly(path_utf16); + HANDLE hFile = win32_open_file_readonly(path_utf16, false); if (hFile == INVALID_HANDLE_VALUE) { err = GetLastError(); ERROR("Win32 API: Failed to open \"%s\"", root_disk_path); @@ -677,16 +620,9 @@ int win32_build_dentry_tree(struct wim_dentry **root_ret, } /* Create a WIM dentry */ - root = new_dentry_with_timeless_inode(path_basename(root_disk_path)); - if (!root) { - if (errno == EILSEQ) - ret = WIMLIB_ERR_INVALID_UTF8_STRING; - else if (errno == ENOMEM) - ret = WIMLIB_ERR_NOMEM; - else - ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE; + ret = new_dentry_with_timeless_inode(path_basename(root_disk_path), &root); + if (ret) goto out_close_handle; - } /* Start preparing the associated WIM inode */ inode = root->d_inode; @@ -760,7 +696,8 @@ out: } /* Replacement for POSIX fnmatch() (partial functionality only) */ -int fnmatch(const char *pattern, const char *string, int flags) +int +fnmatch(const char *pattern, const char *string, int flags) { if (PathMatchSpecA(string, pattern)) return 0; @@ -768,10 +705,11 @@ int fnmatch(const char *pattern, const char *string, int flags) return FNM_NOMATCH; } -static int win32_set_reparse_data(HANDLE h, - u32 reparse_tag, - const struct wim_lookup_table_entry *lte, - const wchar_t *path) +static int +win32_set_reparse_data(HANDLE h, + u32 reparse_tag, + const struct wim_lookup_table_entry *lte, + const wchar_t *path) { int ret; u8 *buf; @@ -795,8 +733,8 @@ static int win32_set_reparse_data(HANDLE h, ret = read_full_wim_resource(lte, buf + 8, 0); if (ret) return ret; - *(u32*)(buf + 0) = reparse_tag; - *(u16*)(buf + 4) = len; + *(u32*)(buf + 0) = cpu_to_le32(reparse_tag); + *(u16*)(buf + 4) = cpu_to_le16(len); *(u16*)(buf + 6) = 0; /* Set the reparse data on the open file using the @@ -835,7 +773,8 @@ static int win32_set_reparse_data(HANDLE h, } -static int win32_extract_chunk(const u8 *buf, size_t len, u64 offset, void *arg) +static int +win32_extract_chunk(const void *buf, size_t len, u64 offset, void *arg) { HANDLE hStream = arg; @@ -853,16 +792,18 @@ static int win32_extract_chunk(const u8 *buf, size_t len, u64 offset, void *arg) return 0; } -static int do_win32_extract_stream(HANDLE hStream, struct wim_lookup_table_entry *lte) +static int +do_win32_extract_stream(HANDLE hStream, struct wim_lookup_table_entry *lte) { return extract_wim_resource(lte, wim_resource_size(lte), win32_extract_chunk, hStream); } -static int win32_extract_stream(const struct wim_inode *inode, - const wchar_t *path, - const wchar_t *stream_name_utf16, - struct wim_lookup_table_entry *lte) +static int +win32_extract_stream(const struct wim_inode *inode, + const wchar_t *path, + const wchar_t *stream_name_utf16, + struct wim_lookup_table_entry *lte) { wchar_t *stream_path; HANDLE h; @@ -986,8 +927,9 @@ out: * * Returns 0 on success; nonzero on failure. */ -static int win32_extract_streams(const struct wim_inode *inode, - const wchar_t *path, u64 *completed_bytes_p) +static int +win32_extract_streams(const struct wim_inode *inode, + const wchar_t *path, u64 *completed_bytes_p) { struct wim_lookup_table_entry *unnamed_lte; int ret; @@ -1000,17 +942,17 @@ static int win32_extract_streams(const struct wim_inode *inode, *completed_bytes_p += wim_resource_size(unnamed_lte); for (u16 i = 0; i < inode->i_num_ads; i++) { const struct wim_ads_entry *ads_entry = &inode->i_ads_entries[i]; - if (ads_entry->stream_name_len != 0) { + if (ads_entry->stream_name_nbytes != 0) { /* Skip special UNIX data entries (see documentation for * WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */ - if (ads_entry->stream_name_len == WIMLIB_UNIX_DATA_TAG_LEN - && !memcmp(ads_entry->stream_name_utf8, - WIMLIB_UNIX_DATA_TAG, - WIMLIB_UNIX_DATA_TAG_LEN)) + if (ads_entry->stream_name_nbytes == WIMLIB_UNIX_DATA_TAG_UTF16LE_NBYTES + && !memcmp(ads_entry->stream_name, + WIMLIB_UNIX_DATA_TAG_UTF16LE, + WIMLIB_UNIX_DATA_TAG_UTF16LE_NBYTES)) continue; ret = win32_extract_stream(inode, path, - (const wchar_t*)ads_entry->stream_name, + ads_entry->stream_name, ads_entry->lte); if (ret) break; @@ -1053,19 +995,19 @@ static int win32_set_security_data(const struct wim_inode *inode, /* Extract a file, directory, reparse point, or hard link to an * already-extracted file using the Win32 API */ -int win32_do_apply_dentry(const char *output_path, - size_t output_path_len, +int win32_do_apply_dentry(const mbchar *output_path, + size_t output_path_nbytes, struct wim_dentry *dentry, struct apply_args *args) { - char *utf16_path; - size_t utf16_path_len; + wchar_t *utf16le_path; + size_t utf16le_path_nbytes; DWORD err; int ret; struct wim_inode *inode = dentry->d_inode; - ret = utf8_to_utf16(output_path, output_path_len, - &utf16_path, &utf16_path_len); + ret = mbs_to_utf16le(output_path, output_path_nbytes, + &utf16le_path, &utf16le_path_nbytes); if (ret) return ret; @@ -1073,23 +1015,19 @@ int win32_do_apply_dentry(const char *output_path, /* Linked file, with another name already extracted. Create a * hard link. */ DEBUG("Creating hard link \"%ls => %ls\"", - (const wchar_t*)utf16_path, - (const wchar_t*)inode->i_extracted_file); - if (!CreateHardLinkW((const wchar_t*)utf16_path, - (const wchar_t*)inode->i_extracted_file, - NULL)) + utf16le_path, inode->i_extracted_file); + if (!CreateHardLinkW(utf16le_path, inode->i_extracted_file, NULL)) { err = GetLastError(); ERROR("Can't create hard link \"%ls => %ls\"", - (const wchar_t*)utf16_path, - (const wchar_t*)inode->i_extracted_file); + utf16le_path, inode->i_extracted_file); ret = WIMLIB_ERR_LINK; win32_error(err); } } else { /* Create the file, directory, or reparse point, and extract the * data streams. */ - ret = win32_extract_streams(inode, (const wchar_t*)utf16_path, + ret = win32_extract_streams(inode, utf16le_path, &args->progress.extract.completed_bytes); if (ret) goto out_free_utf16_path; @@ -1099,7 +1037,7 @@ int win32_do_apply_dentry(const char *output_path, DEBUG("Setting security descriptor %d on %s", inode->i_security_id, output_path); ret = win32_set_security_data(inode, - (const wchar_t*)utf16_path, + utf16le_path, wim_const_security_data(args->w)); if (ret) goto out_free_utf16_path; @@ -1108,37 +1046,38 @@ int win32_do_apply_dentry(const char *output_path, /* Save extracted path for a later call to * CreateHardLinkW() if this inode has multiple links. * */ - inode->i_extracted_file = utf16_path; + inode->i_extracted_file = utf16le_path; goto out; } } out_free_utf16_path: - FREE(utf16_path); + FREE(utf16le_path); out: return ret; } /* Set timestamps on an extracted file using the Win32 API */ -int win32_do_apply_dentry_timestamps(const char *output_path, - size_t output_path_len, - const struct wim_dentry *dentry, - const struct apply_args *args) +int +win32_do_apply_dentry_timestamps(const mbchar *output_path, + size_t output_path_nbytes, + const struct wim_dentry *dentry, + const struct apply_args *args) { /* Win32 */ - char *utf16_path; - size_t utf16_path_len; + wchar_t *utf16le_path; + size_t utf16le_path_nbytes; DWORD err; HANDLE h; int ret; const struct wim_inode *inode = dentry->d_inode; - ret = utf8_to_utf16(output_path, output_path_len, - &utf16_path, &utf16_path_len); + ret = mbs_to_utf16le(output_path, output_path_nbytes, + &utf16le_path, &utf16le_path_nbytes); if (ret) return ret; DEBUG("Opening \"%s\" to set timestamps", output_path); - h = CreateFileW((const wchar_t*)utf16_path, + h = CreateFileW(utf16le_path, GENERIC_WRITE | WRITE_OWNER | WRITE_DAC | ACCESS_SYSTEM_SECURITY, FILE_SHARE_READ, NULL, @@ -1148,7 +1087,7 @@ int win32_do_apply_dentry_timestamps(const char *output_path, if (h == INVALID_HANDLE_VALUE) err = GetLastError(); - FREE(utf16_path); + FREE(utf16le_path); if (h == INVALID_HANDLE_VALUE) goto fail; @@ -1180,14 +1119,19 @@ out: } /* Replacement for POSIX fsync() */ -int fsync(int fd) +int +fsync(int fd) { HANDLE h = (HANDLE)_get_osfhandle(fd); if (h == INVALID_HANDLE_VALUE) { + ERROR("Could not get Windows handle for file descriptor"); + win32_error(GetLastError()); errno = EBADF; return -1; } if (!FlushFileBuffers(h)) { + ERROR("Could not flush file buffers to disk"); + win32_error(GetLastError()); errno = EIO; return -1; } @@ -1195,7 +1139,8 @@ int fsync(int fd) } /* Use the Win32 API to get the number of processors */ -unsigned win32_get_number_of_processors() +unsigned +win32_get_number_of_processors() { SYSTEM_INFO sysinfo; GetSystemInfo(&sysinfo); @@ -1229,3 +1174,12 @@ fail_win32: fail: return NULL; } + +char * +nl_langinfo(nl_item item) +{ + wimlib_assert(item == CODESET); + static char buf[64]; + strcpy(buf, "Unknown"); + return buf; +} diff --git a/src/win32.h b/src/win32.h index 18513be1..87070a4a 100644 --- a/src/win32.h +++ b/src/win32.h @@ -3,52 +3,61 @@ #include "wimlib_internal.h" #include +#include -extern void win32_release_capture_privileges(); -extern void win32_acquire_capture_privileges(); +extern int +win32_build_dentry_tree(struct wim_dentry **root_ret, + const mbchar *root_disk_path, + struct wim_lookup_table *lookup_table, + struct wim_security_data *sd, + const struct capture_config *config, + int add_image_flags, + wimlib_progress_func_t progress_func, + void *extra_arg); -extern void win32_release_restore_privileges(); -extern void win32_acquire_restore_privileges(); +extern int +win32_read_file(const mbchar *filename, void *handle, u64 offset, + size_t size, void *buf); -extern int win32_build_dentry_tree(struct wim_dentry **root_ret, - const mbchar *root_disk_path, - struct wim_lookup_table *lookup_table, - struct wim_security_data *sd, - const struct capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, - void *extra_arg); +extern HANDLE +win32_open_file_readonly(const wchar_t *path_utf16, bool data_only); -extern int win32_read_file(const mbchar *filename, void *handle, u64 offset, - size_t size, void *buf); -extern void *win32_open_file_readonly(const void *path_utf16); -extern void win32_close_file(void *handle); +extern void +win32_close_file(void *handle); #ifdef ENABLE_ERROR_MESSAGES extern void win32_error(u32 err); +extern void win32_error_last(); #else # define win32_error(err) +# define win32_error_last() #endif #define FNM_PATHNAME 0x1 #define FNM_NOMATCH 1 -extern int fnmatch(const mbchar *pattern, const mbchar *string, int flags); +extern int +fnmatch(const mbchar *pattern, const mbchar *string, int flags); -extern int win32_do_apply_dentry(const mbchar *output_path, - size_t output_path_len, - struct wim_dentry *dentry, - struct apply_args *args); +extern int +win32_do_apply_dentry(const mbchar *output_path, + size_t output_path_len, + struct wim_dentry *dentry, + struct apply_args *args); -extern int win32_do_apply_dentry_timestamps(const mbchar *output_path, - size_t output_path_len, - const struct wim_dentry *dentry, - const struct apply_args *args); +extern int +win32_do_apply_dentry_timestamps(const mbchar *output_path, + size_t output_path_len, + const struct wim_dentry *dentry, + const struct apply_args *args); -extern int fsync(int fd); +extern int +fsync(int fd); -extern unsigned win32_get_number_of_processors(); +extern unsigned +win32_get_number_of_processors(); -extern mbchar *realpath(const mbchar *path, mbchar *resolved_path); +extern mbchar * +realpath(const mbchar *path, mbchar *resolved_path); /* Microsoft's swprintf() violates the C standard and they require programmers * to do this weird define to get the correct function. */ @@ -57,4 +66,11 @@ extern mbchar *realpath(const mbchar *path, mbchar *resolved_path); /* Use Microsoft's weird _mkdir() function instead of mkdir() */ #define mkdir(name, mode) _mkdir(name) +typedef enum { + CODESET +} nl_item; + +extern char * +nl_langinfo(nl_item item); + #endif /* _WIMLIB_WIN32_H */ diff --git a/src/write.c b/src/write.c index bd5b05ef..139ecdab 100644 --- a/src/write.c +++ b/src/write.c @@ -67,6 +67,10 @@ #include +#if defined(__WIN32__) && !defined(INVALID_HANDLE_VALUE) +# define INVALID_HANDLE_VALUE ((HANDLE)(-1)) +#endif + static int fflush_and_ftruncate(FILE *fp, off_t size) { @@ -306,10 +310,14 @@ prepare_resource_for_read(struct wim_lookup_table_entry *lte #endif #ifdef __WIN32__ case RESOURCE_WIN32: - if (!lte->file_on_disk_fp) { - lte->file_on_disk_fp = win32_open_file_readonly(lte->file_on_disk); - if (!lte->file_on_disk_fp) + if (lte->win32_file_on_disk_fp == INVALID_HANDLE_VALUE) { + lte->win32_file_on_disk_fp = + win32_open_file_readonly(lte->win32_file_on_disk, true); + if (lte->win32_file_on_disk_fp == INVALID_HANDLE_VALUE) { + ERROR("Win32 API: Can't open %ls", lte->win32_file_on_disk); + win32_error_last(); return WIMLIB_ERR_OPEN; + } } break; #endif @@ -346,10 +354,10 @@ end_wim_resource_read(struct wim_lookup_table_entry *lte #endif #ifdef __WIN32__ else if (lte->resource_location == RESOURCE_WIN32 - && lte->file_on_disk_fp) + && lte->win32_file_on_disk_fp != INVALID_HANDLE_VALUE) { - win32_close_file(lte->file_on_disk_fp); - lte->file_on_disk_fp = NULL; + win32_close_file(lte->win32_file_on_disk_fp); + lte->win32_file_on_disk_fp = INVALID_HANDLE_VALUE; } #endif } -- 2.43.0