Win32: Improve restoring of special attributes
authorEric Biggers <ebiggers3@gmail.com>
Fri, 29 Mar 2013 18:06:45 +0000 (13:06 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 29 Mar 2013 18:06:45 +0000 (13:06 -0500)
NEWS
src/extract_image.c
src/lzx-compress.c
src/timestamp.h
src/wim.c
src/win32.c

diff --git a/NEWS b/NEWS
index 4314e77..0dc04f1 100644 (file)
--- 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.
 
index d331dc0..5148ddc 100644 (file)
@@ -864,7 +864,7 @@ out:
        return ret;
 }
 
-static const tchar *filename_forbidden_chars = 
+static const tchar *filename_forbidden_chars =
 T(
 #ifdef __WIN32__
 "<>:\"/\\|?*"
index a811d51..a8e15b2 100644 (file)
@@ -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)
 {
index 0ba6147..91006fc 100644 (file)
@@ -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;
 }
index 9a20cc5..6859d5c 100644 (file)
--- 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()
index 6383809..05f457a 100644 (file)
@@ -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));