Win32 capture: sort streams by starting LCN
authorEric Biggers <ebiggers3@gmail.com>
Sat, 2 May 2015 18:39:17 +0000 (13:39 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Sat, 2 May 2015 19:10:56 +0000 (14:10 -0500)
NEWS
include/wimlib/blob_table.h
src/blob_table.c
src/win32_capture.c

diff --git a/NEWS b/NEWS
index ab71b7c8d9f5ae644f8b568699286057acaf9641..f5703ca4518f83dcdc4aae0d357e2c7d3f5a755d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -28,7 +28,8 @@ Version 1.8.1-BETA:
        In mounted WIM images, the disk usage provided for each file (st_blocks)
        is now the compressed size rather than the uncompressed size.
 
-       The performance of NTFS-3g capture mode has been slightly improved.
+       The performance of the NTFS-3g and Windows capture modes has been
+       slightly improved.
 
 Version 1.8.0:
        Improved the LZX compressor.  It is now 15-20% faster than before and
index 556187e824cc3e4be0fa3be1a2cb56db3d7c0c4e..dcf6af7ffaa2c2a44870b1e3d8eb6bb55e8caf6b 100644 (file)
@@ -174,6 +174,9 @@ struct blob_descriptor {
                                struct {
                                        tchar *file_on_disk;
                                        struct wim_inode *file_inode;
+                               #ifdef __WIN32__
+                                       u64 sort_key;
+                               #endif
                                };
 
                                /* BLOB_IN_ATTACHED_BUFFER */
index 1d87a71761ed219846e5d6395a3f912df83786fa..e93fce1ef2fb91a6f05458c841f3580f84abb756 100644 (file)
@@ -395,7 +395,7 @@ cmp_blobs_by_sequential_order(const void *p1, const void *p2)
 
        v = (int)blob1->blob_location - (int)blob2->blob_location;
 
-       /* Different resource locations?  */
+       /* Different locations?  */
        if (v)
                return v;
 
@@ -429,6 +429,10 @@ cmp_blobs_by_sequential_order(const void *p1, const void *p2)
 #ifdef __WIN32__
        case BLOB_IN_WINNT_FILE_ON_DISK:
        case BLOB_WIN32_ENCRYPTED:
+               /* Windows: compare by starting LCN (logical cluster number)  */
+               v = cmp_u64(blob1->sort_key, blob2->sort_key);
+               if (v)
+                       return v;
 #endif
                /* Compare files by path: just a heuristic that will place files
                 * in the same directory next to each other.  */
index 13f63650e3e46f537696ffbea1614577c0a13227..3061f6ae48a4192b9254eed91d5ce5a69277a6ce 100644 (file)
@@ -1099,6 +1099,37 @@ out_free_buf:
        return ret;
 }
 
+static u64
+get_sort_key(HANDLE h)
+{
+       STARTING_VCN_INPUT_BUFFER in = { .StartingVcn.QuadPart = 0 };
+       RETRIEVAL_POINTERS_BUFFER out;
+       DWORD bytesReturned;
+
+       if (!DeviceIoControl(h, FSCTL_GET_RETRIEVAL_POINTERS,
+                            &in, sizeof(in),
+                            &out, sizeof(out),
+                            &bytesReturned, NULL))
+               return 0;
+
+       if (out.ExtentCount < 1)
+               return 0;
+
+       return out.Extents[0].Lcn.QuadPart;
+}
+
+static void
+set_sort_key(struct wim_inode *inode, u64 sort_key)
+{
+       for (unsigned i = 0; i < inode->i_num_streams; i++) {
+               struct wim_inode_stream *strm = &inode->i_streams[i];
+               struct blob_descriptor *blob = stream_blob_resolved(strm);
+               if (blob && (blob->blob_location == BLOB_IN_WINNT_FILE_ON_DISK ||
+                            blob->blob_location == BLOB_WIN32_ENCRYPTED))
+                       blob->sort_key = sort_key;
+       }
+}
+
 static int
 winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret,
                                  HANDLE cur_dir,
@@ -1117,6 +1148,7 @@ winnt_build_dentry_tree_recursive(struct wim_dentry **root_ret,
        NTSTATUS status;
        FILE_ALL_INFORMATION file_info;
        ACCESS_MASK requestedPerms;
+       u64 sort_key;
 
        ret = try_exclude(full_path, full_path_nchars, params);
        if (ret < 0) /* Excluded? */
@@ -1341,6 +1373,8 @@ retry_open:
                }
        }
 
+       sort_key = get_sort_key(h);
+
        if (unlikely(inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED)) {
                /* Load information about the raw encrypted data.  This is
                 * needed for any directory or non-directory that has
@@ -1378,6 +1412,8 @@ retry_open:
                        goto out;
        }
 
+       set_sort_key(inode, sort_key);
+
        if (inode_is_directory(inode)) {
 
                /* Directory: recurse to children.  */