Win32: Add untested support for encryted capture
authorEric Biggers <ebiggers3@gmail.com>
Wed, 10 Apr 2013 06:01:59 +0000 (01:01 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Wed, 10 Apr 2013 06:01:59 +0000 (01:01 -0500)
src/extract_image.c
src/lookup_table.c
src/lookup_table.h
src/resource.c
src/win32.c
src/win32.h

index 9534f4d..8941b0e 100644 (file)
@@ -492,7 +492,6 @@ apply_dentry_normal(struct wim_dentry *dentry, void *arg)
        struct apply_args *args = arg;
        tchar *output_path;
        size_t len;
-       int ret;
 
        len = tstrlen(args->target);
        if (dentry_is_root(dentry)) {
index 432fca4..f22bfaf 100644 (file)
@@ -89,8 +89,9 @@ clone_lookup_table_entry(const struct wim_lookup_table_entry *old)
 #ifdef __WIN32__
        case RESOURCE_WIN32:
        case RESOURCE_WIN32_ENCRYPTED:
-#endif
+#else
        case RESOURCE_IN_FILE_ON_DISK:
+#endif
 #ifdef WITH_FUSE
        case RESOURCE_IN_STAGING_FILE:
                BUILD_BUG_ON((void*)&old->file_on_disk !=
@@ -147,13 +148,14 @@ free_lookup_table_entry(struct wim_lookup_table_entry *lte)
        #ifdef __WIN32__
                case RESOURCE_WIN32:
                case RESOURCE_WIN32_ENCRYPTED:
+       #else
+               case RESOURCE_IN_FILE_ON_DISK:
        #endif
        #ifdef WITH_FUSE
                case RESOURCE_IN_STAGING_FILE:
                        BUILD_BUG_ON((void*)&lte->file_on_disk !=
                                     (void*)&lte->staging_file_name);
        #endif
-               case RESOURCE_IN_FILE_ON_DISK:
                case RESOURCE_IN_ATTACHED_BUFFER:
                        BUILD_BUG_ON((void*)&lte->file_on_disk !=
                                     (void*)&lte->attached_buffer);
@@ -671,8 +673,9 @@ print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out)
 #ifdef __WIN32__
        case RESOURCE_WIN32:
        case RESOURCE_WIN32_ENCRYPTED:
-#endif
+#else
        case RESOURCE_IN_FILE_ON_DISK:
+#endif
                tfprintf(out, T("File on Disk      = `%"TS"'\n"),
                         lte->file_on_disk);
                break;
index e5241f8..2a6bf89 100644 (file)
@@ -67,7 +67,9 @@ enum resource_location {
         * file will be provided by @file_on_disk member.  In addition, if
         * @file_on_disk_fp is not NULL, it will be an open FILE * to the file.
         * */
+#ifndef __WIN32__
        RESOURCE_IN_FILE_ON_DISK,
+#endif
 
        /* The stream resource is directly attached in an in-memory buffer
         * pointed to by @attached_buffer. */
@@ -283,10 +285,12 @@ wim_resource_compression_type(const struct wim_lookup_table_entry *lte)
 static inline bool
 lte_filename_valid(const struct wim_lookup_table_entry *lte)
 {
-       return lte->resource_location == RESOURCE_IN_FILE_ON_DISK
+       return 0
        #ifdef __WIN32__
                || lte->resource_location == RESOURCE_WIN32
                || lte->resource_location == RESOURCE_WIN32_ENCRYPTED
+       #else
+               || lte->resource_location == RESOURCE_IN_FILE_ON_DISK
        #endif
        #ifdef WITH_FUSE
                || lte->resource_location == RESOURCE_IN_STAGING_FILE
index 1b53ee4..ea62b59 100644 (file)
@@ -630,6 +630,7 @@ read_wim_resource_prefix(const struct wim_lookup_table_entry *lte,
 }
 
 
+#ifndef __WIN32__
 static int
 read_file_on_disk_prefix(const struct wim_lookup_table_entry *lte,
                         u64 size,
@@ -676,6 +677,7 @@ out_close:
        close(fd);
        return ret;
 }
+#endif /* !__WIN32__ */
 
 static int
 read_buffer_prefix(const struct wim_lookup_table_entry *lte,
@@ -732,7 +734,9 @@ read_resource_prefix(const struct wim_lookup_table_entry *lte,
 {
        static const read_resource_prefix_handler_t handlers[] = {
                [RESOURCE_IN_WIM]             = read_wim_resource_prefix,
+       #ifndef __WIN32__
                [RESOURCE_IN_FILE_ON_DISK]    = read_file_on_disk_prefix,
+       #endif
                [RESOURCE_IN_ATTACHED_BUFFER] = read_buffer_prefix,
        #ifdef WITH_FUSE
                [RESOURCE_IN_STAGING_FILE]    = read_file_on_disk_prefix,
index f2e7eeb..37bada1 100644 (file)
@@ -170,13 +170,13 @@ win32_open_file_data_only(const wchar_t *path)
 }
 
 int
-read_win32_file_prefix(const struct lookup_table_entry *lte,
+read_win32_file_prefix(const struct wim_lookup_table_entry *lte,
                       u64 size,
                       consume_data_callback_t cb,
                       void *ctx_or_buf,
                       int _ignored_flags)
 {
-       int ret;
+       int ret = 0;
        void *out_buf;
        DWORD err;
        u64 bytes_remaining;
@@ -186,8 +186,7 @@ read_win32_file_prefix(const struct lookup_table_entry *lte,
                err = GetLastError();
                ERROR("Failed to open \"%ls\"", lte->file_on_disk);
                win32_error(err);
-               ret = WIMLIB_ERR_OPEN;
-               goto out;
+               return WIMLIB_ERR_OPEN;
        }
 
        if (cb)
@@ -200,27 +199,142 @@ read_win32_file_prefix(const struct lookup_table_entry *lte,
                DWORD bytesToRead, bytesRead;
 
                bytesToRead = min(WIM_CHUNK_SIZE, bytes_remaining);
-               if (!ReadFile(h, out_buf, bytesToRead, &bytesRead, NULL) ||
+               if (!ReadFile(hFile, out_buf, bytesToRead, &bytesRead, NULL) ||
                    bytesRead != bytesToRead)
                {
                        err = GetLastError();
                        ERROR("Failed to read data from \"%ls\"", lte->file_on_disk);
                        win32_error(err);
                        ret = WIMLIB_ERR_READ;
-                       goto out_close_handle;
+                       break;
                }
                bytes_remaining -= bytesRead;
                if (cb) {
-                       ret = cb(out_buf, bytesRead, ctx_or_buf);
+                       ret = (*cb)(out_buf, bytesRead, ctx_or_buf);
                        if (ret)
-                               goto out_close_handle;
+                               break;
                } else {
                        out_buf += bytesRead;
                }
        }
-out_close_handle:
        CloseHandle(hFile);
-out:
+       return ret;
+}
+
+struct win32_encrypted_read_ctx {
+       consume_data_callback_t read_prefix_cb;
+       void *read_prefix_ctx_or_buf;
+       int wimlib_err_code;
+       void *buf;
+       size_t buf_filled;
+       u64 bytes_remaining;
+};
+
+static DWORD WINAPI
+win32_encrypted_export_cb(unsigned char *_data, void *_ctx, unsigned long len)
+{
+       const void *data = _data;
+       struct win32_encrypted_read_ctx *ctx = _ctx;
+       int ret;
+
+       DEBUG("len = %lu", len);
+       if (ctx->read_prefix_cb) {
+               /* The length of the buffer passed to the ReadEncryptedFileRaw()
+                * export callback is undocumented, so we assume it may be of
+                * arbitrary size. */
+               size_t bytes_to_buffer = min(ctx->bytes_remaining - ctx->buf_filled,
+                                            len);
+               while (bytes_to_buffer) {
+                       size_t bytes_to_copy_to_buf =
+                               min(bytes_to_buffer, WIM_CHUNK_SIZE - ctx->buf_filled);
+
+                       memcpy(ctx->buf + ctx->buf_filled, data,
+                              bytes_to_copy_to_buf);
+                       ctx->buf_filled += bytes_to_copy_to_buf;
+                       data += bytes_to_copy_to_buf;
+                       bytes_to_buffer -= bytes_to_copy_to_buf;
+
+                       if (ctx->buf_filled == WIM_CHUNK_SIZE ||
+                           ctx->buf_filled == ctx->bytes_remaining)
+                       {
+                               ret = (*ctx->read_prefix_cb)(ctx->buf,
+                                                            ctx->buf_filled,
+                                                            ctx->read_prefix_ctx_or_buf);
+                               if (ret) {
+                                       ctx->wimlib_err_code = ret;
+                                       /* Shouldn't matter what error code is returned
+                                        * here, as long as it isn't ERROR_SUCCESS. */
+                                       return ERROR_READ_FAULT;
+                               }
+                               ctx->bytes_remaining -= ctx->buf_filled;
+                               ctx->buf_filled = 0;
+                       }
+               }
+       } else {
+               size_t len_to_copy = min(len, ctx->bytes_remaining);
+               memcpy(ctx->read_prefix_ctx_or_buf, data, len_to_copy);
+               ctx->bytes_remaining -= len_to_copy;
+               ctx->read_prefix_ctx_or_buf += len_to_copy;
+       }
+       return ERROR_SUCCESS;
+}
+
+int
+read_win32_encrypted_file_prefix(const struct wim_lookup_table_entry *lte,
+                                u64 size,
+                                consume_data_callback_t cb,
+                                void *ctx_or_buf,
+                                int _ignored_flags)
+{
+       struct win32_encrypted_read_ctx export_ctx;
+       DWORD err;
+       void *file_ctx;
+       int ret;
+
+       DEBUG("Reading %"PRIu64" bytes from encryted file \"%ls\"",
+             size, lte->file_on_disk);
+
+       export_ctx.read_prefix_cb = cb;
+       export_ctx.read_prefix_ctx_or_buf = ctx_or_buf;
+       export_ctx.wimlib_err_code = 0;
+       if (cb) {
+               export_ctx.buf = MALLOC(WIM_CHUNK_SIZE);
+               if (!export_ctx.buf)
+                       return WIMLIB_ERR_NOMEM;
+       } else {
+               export_ctx.buf = NULL;
+       }
+       export_ctx.bytes_remaining = size;
+
+       err = OpenEncryptedFileRawW(lte->file_on_disk, 0, &file_ctx);
+       if (err != ERROR_SUCCESS) {
+               ERROR("Failed to open encrypted file \"%ls\" for raw read",
+                     lte->file_on_disk);
+               win32_error(err);
+               ret = WIMLIB_ERR_OPEN;
+               goto out_free_buf;
+       }
+       err = ReadEncryptedFileRaw(win32_encrypted_export_cb,
+                                  &export_ctx, file_ctx);
+       if (err != ERROR_SUCCESS) {
+               ERROR("Failed to read encrypted file \"%ls\"",
+                     lte->file_on_disk);
+               win32_error(err);
+               ret = export_ctx.wimlib_err_code;
+               if (ret == 0)
+                       ret = WIMLIB_ERR_READ;
+       } else if (export_ctx.bytes_remaining != 0) {
+               ERROR("Only could read %"PRIu64" of %"PRIu64" bytes from "
+                     "encryted file \"%ls\"",
+                     size - export_ctx.bytes_remaining, size,
+                     lte->file_on_disk);
+               ret = WIMLIB_ERR_READ;
+       } else {
+               ret = 0;
+       }
+       CloseEncryptedFileRaw(file_ctx);
+out_free_buf:
+       FREE(export_ctx.buf);
        return ret;
 }
 
@@ -502,7 +616,6 @@ win32_capture_stream(const wchar_t *path,
                     WIN32_FIND_STREAM_DATA *dat)
 {
        struct wim_ads_entry *ads_entry;
-       u8 hash[SHA1_HASH_SIZE];
        struct wim_lookup_table_entry *lte;
        int ret;
        wchar_t *stream_name, *colon;
@@ -510,7 +623,6 @@ win32_capture_stream(const wchar_t *path,
        bool is_named_stream;
        wchar_t *spath;
        size_t spath_nchars;
-       DWORD err;
        size_t spath_buf_nbytes;
        const wchar_t *relpath_prefix;
        const wchar_t *colonchar;
@@ -583,7 +695,10 @@ win32_capture_stream(const wchar_t *path,
        }
        lte->file_on_disk = spath;
        spath = NULL;
-       lte->resource_location = RESOURCE_WIN32;
+       if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED && !is_named_stream)
+               lte->resource_location = RESOURCE_WIN32_ENCRYPTED;
+       else
+               lte->resource_location = RESOURCE_WIN32;
        lte->resource_entry.original_size = (u64)dat->StreamSize.QuadPart;
 
        u32 stream_id;
@@ -959,7 +1074,7 @@ win32_set_reparse_data(HANDLE h,
         * leave 8 bytes of space for them at the beginning of the buffer, then
         * set them manually. */
        buf = alloca(len + 8);
-       ret = read_full_wim_resource(lte, buf + 8, 0);
+       ret = read_full_resource_into_buf(lte, buf + 8, false);
        if (ret)
                return ret;
        *(u32*)(buf + 0) = cpu_to_le32(reparse_tag);
@@ -1110,7 +1225,7 @@ fail:
 
 
 static int
-win32_extract_chunk(const void *buf, size_t len, u64 offset, void *arg)
+win32_extract_chunk(const void *buf, size_t len, void *arg)
 {
        HANDLE hStream = arg;
 
@@ -1135,6 +1250,14 @@ do_win32_extract_stream(HANDLE hStream, struct wim_lookup_table_entry *lte)
                                    win32_extract_chunk, hStream);
 }
 
+static int
+do_win32_extract_encryted_stream(const wchar_t *path,
+                                const struct wim_lookup_table_entry *lte)
+{
+       ERROR("Extrat encryted streams not implemented");
+       return WIMLIB_ERR_INVALID_PARAM;
+}
+
 static bool
 path_is_root_of_drive(const wchar_t *path)
 {
@@ -1339,7 +1462,13 @@ win32_extract_stream(const struct wim_inode *inode,
                if (lte) {
                        DEBUG("Extracting \"%ls\" (len = %"PRIu64")",
                              stream_path, wim_resource_size(lte));
-                       ret = do_win32_extract_stream(h, lte);
+                       if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED
+                           && stream_name_utf16 == NULL) {
+                               ret = do_win32_extract_encryted_stream(stream_path,
+                                                                      lte);
+                       } else {
+                               ret = do_win32_extract_stream(h, lte);
+                       }
                        if (ret)
                                goto fail_close_handle;
                }
index 0ef410a..b4d5236 100644 (file)
@@ -21,13 +21,18 @@ win32_read_file(const tchar *filename, HANDLE handle,
                u64 offset, size_t size, void *buf);
 
 extern int
-read_win32_file_prefix(const struct lookup_table_entry *lte,
+read_win32_file_prefix(const struct wim_lookup_table_entry *lte,
                       u64 size,
                       consume_data_callback_t cb,
                       void *ctx_or_buf,
-                      int _ignored_flags)
-{
-}
+                      int _ignored_flags);
+
+extern int
+read_win32_encrypted_file_prefix(const struct wim_lookup_table_entry *lte,
+                                u64 size,
+                                consume_data_callback_t cb,
+                                void *ctx_or_buf,
+                                int _ignored_flags);
 
 #define FNM_PATHNAME 0x1
 #define FNM_NOESCAPE 0x2