+/* Description of where data is located on a Windows filesystem */
+struct windows_file {
+
+ /* Is the data the raw encrypted data of an EFS-encrypted file? */
+ u64 is_encrypted : 1;
+
+ /* The file's LCN (logical cluster number) for sorting, or 0 if unknown.
+ */
+ u64 sort_key : 63;
+
+ /* A reference to the VSS snapshot containing the file, or NULL if none.
+ */
+ struct vss_snapshot *snapshot;
+
+ /* The path to the file. If 'is_encrypted=0' this is an NT namespace
+ * path; if 'is_encrypted=1' this is a Win32 namespace path. */
+ wchar_t path[];
+};
+
+/* Allocate a 'struct windows_file' to describe the location of a data stream.
+ */
+static struct windows_file *
+alloc_windows_file(bool is_encrypted, struct vss_snapshot *snapshot,
+ const wchar_t *path, size_t path_nchars,
+ const wchar_t *stream_name, size_t stream_name_nchars)
+{
+ struct windows_file *file;
+ wchar_t *p;
+
+ file = MALLOC(sizeof(struct windows_file) +
+ (path_nchars + (stream_name_nchars ? 1 : 0) +
+ stream_name_nchars + 1) * sizeof(wchar_t));
+ if (!file)
+ return NULL;
+
+ file->is_encrypted = is_encrypted;
+ file->sort_key = 0;
+ file->snapshot = vss_get_snapshot(snapshot);
+ p = wmempcpy(file->path, path, path_nchars);
+ if (stream_name_nchars) {
+ /* Named data stream */
+ *p++ = L':';
+ p = wmempcpy(p, stream_name, stream_name_nchars);
+ }
+ *p = L'\0';
+ return file;
+}
+
+/* Add a stream, located on a Windows filesystem, to the specified WIM inode.
+ */
+static int
+add_stream(struct wim_inode *inode, bool is_encrypted,
+ struct vss_snapshot *snapshot, u64 size,
+ const wchar_t *path, size_t path_nchars,
+ int stream_type, const utf16lechar *stream_name, size_t stream_name_nchars,
+ struct list_head *unhashed_blobs)
+{
+ struct blob_descriptor *blob = NULL;
+ struct wim_inode_stream *strm;
+
+ /* If the stream is nonempty, create a blob descriptor for it. */
+ if (size) {
+ blob = new_blob_descriptor();
+ if (!blob)
+ goto err_nomem;
+
+ blob->windows_file = alloc_windows_file(is_encrypted, snapshot,
+ path, path_nchars,
+ stream_name,
+ stream_name_nchars);
+ if (!blob->windows_file)
+ goto err_nomem;
+
+ blob->blob_location = BLOB_IN_WINDOWS_FILE;
+ blob->file_inode = inode;
+ blob->size = size;
+ }
+
+ strm = inode_add_stream(inode, stream_type, stream_name, blob);
+ if (!strm)
+ goto err_nomem;
+
+ prepare_unhashed_blob(blob, inode, strm->stream_id, unhashed_blobs);
+ return 0;
+
+err_nomem:
+ free_blob_descriptor(blob);
+ return WIMLIB_ERR_NOMEM;
+}
+
+struct windows_file *
+clone_windows_file(const struct windows_file *file)
+{
+ struct windows_file *new;
+
+ new = memdup(file, sizeof(struct windows_file) +
+ (wcslen(file->path) + 1) * sizeof(wchar_t));
+ if (new)
+ vss_get_snapshot(new->snapshot);
+ return new;
+}
+
+void
+free_windows_file(struct windows_file *file)
+{
+ vss_put_snapshot(file->snapshot);
+ FREE(file);
+}
+
+int
+cmp_windows_files(const struct windows_file *file1,
+ const struct windows_file *file2)
+{
+ /* Compare by starting LCN (logical cluster number) */
+ int v = cmp_u64(file1->sort_key, file2->sort_key);
+ if (v)
+ return v;
+
+ /* Compare files by path: just a heuristic that will place files
+ * in the same directory next to each other. */
+ return wcscmp(file1->path, file2->path);
+}
+
+const wchar_t *
+get_windows_file_path(const struct windows_file *file)
+{
+ return file->path;
+}
+