]> wimlib.net Git - wimlib/blobdiff - src/win32_capture.c
Disallow empty blobs from being read
[wimlib] / src / win32_capture.c
index c7a1d4a407feeae5fa6c4921d287bc0ce46638e3..ba9937cfb1982363aca8cd67137ed0196c63faaa 100644 (file)
@@ -824,7 +824,7 @@ win32_get_encrypted_file_size(const wchar_t *path, bool is_dir, u64 *size_ret)
 }
 
 static int
-winnt_load_efsrpc_raw_data(struct wim_inode *inode, const wchar_t *nt_path,
+winnt_scan_efsrpc_raw_data(struct wim_inode *inode, const wchar_t *nt_path,
                           struct list_head *unhashed_blobs)
 {
        struct blob_descriptor *blob;
@@ -852,6 +852,9 @@ winnt_load_efsrpc_raw_data(struct wim_inode *inode, const wchar_t *nt_path,
        if (ret)
                goto err;
 
+       /* Empty EFSRPC data does not make sense  */
+       wimlib_assert(blob->size != 0);
+
        strm = inode_add_stream(inode, STREAM_TYPE_EFSRPC_RAW_DATA,
                                NO_STREAM_NAME, blob);
        if (!strm)
@@ -900,12 +903,12 @@ get_data_stream_name(wchar_t *raw_stream_name, size_t raw_stream_name_nchars,
        return true;
 }
 
-/* Build the path to the stream.  For unnamed streams, this is simply the path
- * to the file.  For named streams, this is the path to the file, followed by a
- * colon, followed by the stream name.  */
+/* Build the path to the data stream.  For unnamed streams, this is simply the
+ * path to the file.  For named streams, this is the path to the file, followed
+ * by a colon, followed by the stream name.  */
 static wchar_t *
-build_stream_path(const wchar_t *path, size_t path_nchars,
-                 const wchar_t *stream_name, size_t stream_name_nchars)
+build_data_stream_path(const wchar_t *path, size_t path_nchars,
+                      const wchar_t *stream_name, size_t stream_name_nchars)
 {
        size_t stream_path_nchars;
        wchar_t *stream_path;
@@ -952,10 +955,10 @@ winnt_scan_data_stream(const wchar_t *path, size_t path_nchars,
                blob = new_blob_descriptor();
                if (!blob)
                        goto err_nomem;
-               blob->file_on_disk = build_stream_path(path,
-                                                      path_nchars,
-                                                      stream_name,
-                                                      stream_name_nchars);
+               blob->file_on_disk = build_data_stream_path(path,
+                                                           path_nchars,
+                                                           stream_name,
+                                                           stream_name_nchars);
                if (!blob->file_on_disk)
                        goto err_nomem;
                blob->blob_location = BLOB_IN_WINNT_FILE_ON_DISK;
@@ -1087,8 +1090,11 @@ unnamed_only:
                goto out_free_buf;
        }
 
-       ret = winnt_scan_data_stream(path, path_nchars, L"::$DATA", 7,
-                                    file_size, inode, unhashed_blobs);
+       {
+               wchar_t stream_name[] = L"::$DATA";
+               ret = winnt_scan_data_stream(path, path_nchars, stream_name, 7,
+                                            file_size, inode, unhashed_blobs);
+       }
 out_free_buf:
        /* Free buffer if allocated on heap.  */
        if (unlikely(buf != _buf))
@@ -1096,6 +1102,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,
@@ -1114,6 +1151,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? */
@@ -1338,6 +1376,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
@@ -1349,7 +1389,7 @@ retry_open:
                 * needed.  */
                (*func_NtClose)(h);
                h = NULL;
-               ret = winnt_load_efsrpc_raw_data(inode, full_path,
+               ret = winnt_scan_efsrpc_raw_data(inode, full_path,
                                                 params->unhashed_blobs);
                if (ret)
                        goto out;
@@ -1375,6 +1415,8 @@ retry_open:
                        goto out;
        }
 
+       set_sort_key(inode, sort_key);
+
        if (inode_is_directory(inode)) {
 
                /* Directory: recurse to children.  */