From 9024010515ca562dd8730d4ca846b5335ff6e48a Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Fri, 29 Mar 2013 13:06:45 -0500 Subject: [PATCH] Win32: Improve restoring of special attributes --- NEWS | 16 +++++ src/extract_image.c | 2 +- src/lzx-compress.c | 2 +- src/timestamp.h | 2 +- src/wim.c | 2 +- src/win32.c | 139 ++++++++++++++++++++++++++++++++++++++++---- 6 files changed, 148 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 4314e77e..0dc04f18 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,21 @@ Only the most important changes more recent than version 0.6 are noted here. +Version 1.3.3: + Windows build now works on Windows XP. + + On the Windows build, hidden directories are now correctly restored as + hidden. Also compressed, encrypted, and sparse files are now restored + as such. + + Performance improvements when capturing hard-linked files (both UNIX and + Windows). Now, each file is only checksummed once total, rather than + once per link. + + Performance of splitting and joining WIMs should be slightly improved. + + Compression and decompression functions are now exported from the + library. + Version 1.3.2: Improvements and bugfixes for the Windows build. diff --git a/src/extract_image.c b/src/extract_image.c index d331dc0d..5148ddcc 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -864,7 +864,7 @@ out: return ret; } -static const tchar *filename_forbidden_chars = +static const tchar *filename_forbidden_chars = T( #ifdef __WIN32__ "<>:\"/\\|?*" diff --git a/src/lzx-compress.c b/src/lzx-compress.c index a811d51c..a8e15b24 100644 --- a/src/lzx-compress.c +++ b/src/lzx-compress.c @@ -567,7 +567,7 @@ lzx_write_compressed_tree(struct output_bitstream *out, /* Builds the canonical Huffman code for the main tree, the length tree, and the * aligned offset tree. */ -static void +static void lzx_make_huffman_codes(const struct lzx_freq_tables *freq_tabs, struct lzx_codes *codes) { diff --git a/src/timestamp.h b/src/timestamp.h index 0ba61472..91006fc0 100644 --- a/src/timestamp.h +++ b/src/timestamp.h @@ -63,7 +63,7 @@ wim_timestamp_to_timespec(u64 timestamp) { struct timespec ts; ts.tv_sec = (timestamp - intervals_1601_to_1970) / intervals_per_second; - ts.tv_nsec = ((timestamp - intervals_1601_to_1970) % intervals_per_second) * + ts.tv_nsec = ((timestamp - intervals_1601_to_1970) % intervals_per_second) * nanoseconds_per_interval; return ts; } diff --git a/src/wim.c b/src/wim.c index 9a20cc57..6859d5c7 100644 --- a/src/wim.c +++ b/src/wim.c @@ -608,7 +608,7 @@ test_locale_ctype_utf8() #endif } -/* Get global memory allocations out of the way, +/* Get global memory allocations out of the way, * single-threaded programs like 'imagex'. */ WIMLIBAPI int wimlib_global_init() diff --git a/src/win32.c b/src/win32.c index 63838090..05f457a8 100644 --- a/src/win32.c +++ b/src/win32.c @@ -1029,6 +1029,41 @@ win32_set_reparse_data(HANDLE h, return 0; } +static int +win32_set_compressed(HANDLE hFile, const wchar_t *path) +{ + USHORT format = COMPRESSION_FORMAT_DEFAULT; + DWORD bytesReturned = 0; + if (!DeviceIoControl(hFile, FSCTL_SET_COMPRESSION, + &format, sizeof(USHORT), + NULL, 0, + &bytesReturned, NULL)) + { + /* Warning only */ + DWORD err = GetLastError(); + WARNING("Failed to set compression flag on \"%ls\"", path); + win32_error(err); + } + return 0; +} + +static int +win32_set_sparse(HANDLE hFile, const wchar_t *path) +{ + DWORD bytesReturned = 0; + if (!DeviceIoControl(hFile, FSCTL_SET_SPARSE, + NULL, 0, + NULL, 0, + &bytesReturned, NULL)) + { + /* Warning only */ + DWORD err = GetLastError(); + WARNING("Failed to set sparse flag on \"%ls\"", path); + win32_error(err); + } + return 0; +} + /* * Sets the security descriptor on an extracted file. */ @@ -1145,6 +1180,91 @@ path_is_root_of_drive(const wchar_t *path) return (*path == L'\0'); } +static DWORD +win32_get_create_flags_and_attributes(DWORD i_attributes) +{ + DWORD attributes; + + /* + * Some attributes cannot be set by passing them to CreateFile(). In + * particular: + * + * FILE_ATTRIBUTE_DIRECTORY: + * CreateDirectory() must be called instead of CreateFile(). + * + * FILE_ATTRIBUTE_SPARSE_FILE: + * Needs an ioctl. + * See: win32_set_sparse(). + * + * FILE_ATTRIBUTE_COMPRESSED: + * Not clear from the documentation, but apparently this needs an + * ioctl as well. + * See: win32_set_compressed(). + * + * FILE_ATTRIBUTE_REPARSE_POINT: + * Needs an ioctl, with the reparse data specified. + * See: win32_set_reparse_data(). + * + * In addition, clear any file flags in the attributes that we don't + * want, but also specify FILE_FLAG_OPEN_REPARSE_POINT and + * FILE_FLAG_BACKUP_SEMANTICS as we are a backup application. + */ + attributes = i_attributes & ~(FILE_ATTRIBUTE_SPARSE_FILE | + FILE_ATTRIBUTE_COMPRESSED | + FILE_ATTRIBUTE_REPARSE_POINT | + FILE_ATTRIBUTE_DIRECTORY | + FILE_FLAG_DELETE_ON_CLOSE | + FILE_FLAG_NO_BUFFERING | + FILE_FLAG_OPEN_NO_RECALL | + FILE_FLAG_OVERLAPPED | + FILE_FLAG_RANDOM_ACCESS | + /*FILE_FLAG_SESSION_AWARE |*/ + FILE_FLAG_SEQUENTIAL_SCAN | + FILE_FLAG_WRITE_THROUGH); + return attributes | + FILE_FLAG_OPEN_REPARSE_POINT | + FILE_FLAG_BACKUP_SEMANTICS; +} + +static bool +inode_has_special_attributes(const struct wim_inode *inode) +{ + return (inode->i_attributes & (FILE_ATTRIBUTE_COMPRESSED | + FILE_ATTRIBUTE_REPARSE_POINT | + FILE_ATTRIBUTE_SPARSE_FILE)) != 0; +} + +static int +win32_set_special_attributes(HANDLE hFile, const struct wim_inode *inode, + struct wim_lookup_table_entry *unnamed_stream_lte, + const wchar_t *path) +{ + int ret; + + if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) { + DEBUG("Setting reparse data on \"%ls\"", path); + ret = win32_set_reparse_data(hFile, inode->i_reparse_tag, + unnamed_stream_lte, path); + if (ret) + return ret; + } + + if (inode->i_attributes & FILE_ATTRIBUTE_COMPRESSED) { + DEBUG("Setting compression flag on \"%ls\"", path); + ret = win32_set_compressed(hFile, path); + if (ret) + return ret; + } + + if (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE) { + DEBUG("Setting sparse flag on \"%ls\"", path); + ret = win32_set_sparse(hFile, path); + if (ret) + return ret; + } + return 0; +} + static int win32_extract_stream(const struct wim_inode *inode, const wchar_t *path, @@ -1213,7 +1333,7 @@ win32_extract_stream(const struct wim_inode *inode, } } DEBUG("Created directory \"%ls\"", stream_path); - if (!(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + if (!inode_has_special_attributes(inode)) { ret = 0; goto out; } @@ -1223,13 +1343,11 @@ win32_extract_stream(const struct wim_inode *inode, DEBUG("Opening \"%ls\"", stream_path); h = CreateFileW(stream_path, - GENERIC_WRITE, + GENERIC_READ | GENERIC_WRITE, 0, NULL, creationDisposition, - FILE_FLAG_OPEN_REPARSE_POINT | - FILE_FLAG_BACKUP_SEMANTICS | - inode->i_attributes, + win32_get_create_flags_and_attributes(inode->i_attributes), NULL); if (h == INVALID_HANDLE_VALUE) { err = GetLastError(); @@ -1239,14 +1357,13 @@ win32_extract_stream(const struct wim_inode *inode, goto fail; } - if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT && - stream_name_utf16 == NULL) - { - DEBUG("Setting reparse data on \"%ls\"", path); - ret = win32_set_reparse_data(h, inode->i_reparse_tag, lte, path); + if (stream_name_utf16 == NULL && inode_has_special_attributes(inode)) { + ret = win32_set_special_attributes(h, inode, lte, path); if (ret) goto fail_close_handle; - } else { + } + + if (!(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)) { if (lte) { DEBUG("Extracting \"%ls\" (len = %"PRIu64")", stream_path, wim_resource_size(lte)); -- 2.43.0