]> wimlib.net Git - wimlib/blobdiff - src/write.c
NTFS-3g capture: open inodes by inode number
[wimlib] / src / write.c
index 03f3055929cd5b29b1ec1da5f03876fe4f8dceeb..c19d6fcbfc174a4cab3eb548928f38268776b041 100644 (file)
 #define WRITE_RESOURCE_FLAG_SEND_DONE_WITH_FILE        0x00000008
 #define WRITE_RESOURCE_FLAG_SOLID_SORT         0x00000010
 
-static inline int
+static int
 write_flags_to_resource_flags(int write_flags)
 {
        int write_resource_flags = 0;
 
        if (write_flags & WIMLIB_WRITE_FLAG_RECOMPRESS)
                write_resource_flags |= WRITE_RESOURCE_FLAG_RECOMPRESS;
+
        if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
                write_resource_flags |= WRITE_RESOURCE_FLAG_PIPABLE;
+
        if (write_flags & WIMLIB_WRITE_FLAG_SOLID)
                write_resource_flags |= WRITE_RESOURCE_FLAG_SOLID;
+
        if (write_flags & WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES)
                write_resource_flags |= WRITE_RESOURCE_FLAG_SEND_DONE_WITH_FILE;
+
        if ((write_flags & (WIMLIB_WRITE_FLAG_SOLID |
                            WIMLIB_WRITE_FLAG_NO_SOLID_SORT)) ==
            WIMLIB_WRITE_FLAG_SOLID)
                write_resource_flags |= WRITE_RESOURCE_FLAG_SOLID_SORT;
+
        return write_resource_flags;
 }
 
@@ -212,13 +217,13 @@ can_raw_copy(const struct blob_descriptor *blob,
        return false;
 }
 
-static u8
-filter_resource_flags(u8 flags)
+static u32
+reshdr_flags_for_blob(const struct blob_descriptor *blob)
 {
-       return (flags & ~(WIM_RESHDR_FLAG_SOLID |
-                         WIM_RESHDR_FLAG_COMPRESSED |
-                         WIM_RESHDR_FLAG_SPANNED |
-                         WIM_RESHDR_FLAG_FREE));
+       u32 reshdr_flags = 0;
+       if (blob->is_metadata)
+               reshdr_flags |= WIM_RESHDR_FLAG_METADATA;
+       return reshdr_flags;
 }
 
 static void
@@ -230,9 +235,6 @@ blob_set_out_reshdr_for_reuse(struct blob_descriptor *blob)
        rdesc = blob->rdesc;
 
        if (rdesc->flags & WIM_RESHDR_FLAG_SOLID) {
-
-               wimlib_assert(blob->flags & WIM_RESHDR_FLAG_SOLID);
-
                blob->out_reshdr.offset_in_wim = blob->offset_in_res;
                blob->out_reshdr.uncompressed_size = 0;
                blob->out_reshdr.size_in_wim = blob->size;
@@ -241,36 +243,31 @@ blob_set_out_reshdr_for_reuse(struct blob_descriptor *blob)
                blob->out_res_size_in_wim = rdesc->size_in_wim;
                blob->out_res_uncompressed_size = rdesc->uncompressed_size;
        } else {
-               wimlib_assert(!(blob->flags & WIM_RESHDR_FLAG_SOLID));
-
                blob->out_reshdr.offset_in_wim = rdesc->offset_in_wim;
                blob->out_reshdr.uncompressed_size = rdesc->uncompressed_size;
                blob->out_reshdr.size_in_wim = rdesc->size_in_wim;
        }
-       blob->out_reshdr.flags = blob->flags;
+       blob->out_reshdr.flags = rdesc->flags;
 }
 
 
 /* Write the header for a blob in a pipable WIM.  */
 static int
 write_pwm_blob_header(const struct blob_descriptor *blob,
-                     struct filedes *out_fd, int additional_reshdr_flags)
+                     struct filedes *out_fd, bool compressed)
 {
        struct pwm_blob_hdr blob_hdr;
        u32 reshdr_flags;
        int ret;
 
+       wimlib_assert(!blob->unhashed);
+
        blob_hdr.magic = cpu_to_le64(PWM_BLOB_MAGIC);
        blob_hdr.uncompressed_size = cpu_to_le64(blob->size);
-       if (additional_reshdr_flags & PWM_RESHDR_FLAG_UNHASHED) {
-               zero_out_hash(blob_hdr.hash);
-       } else {
-               wimlib_assert(!blob->unhashed);
-               copy_hash(blob_hdr.hash, blob->hash);
-       }
-
-       reshdr_flags = filter_resource_flags(blob->flags);
-       reshdr_flags |= additional_reshdr_flags;
+       copy_hash(blob_hdr.hash, blob->hash);
+       reshdr_flags = reshdr_flags_for_blob(blob);
+       if (compressed)
+               reshdr_flags |= WIM_RESHDR_FLAG_COMPRESSED;
        blob_hdr.flags = cpu_to_le32(reshdr_flags);
        ret = full_write(out_fd, &blob_hdr, sizeof(blob_hdr));
        if (ret)
@@ -794,8 +791,8 @@ write_blob_begin_read(struct blob_descriptor *blob, void *_ctx)
        return 0;
 }
 
-/* Rewrite a blob that was just written compressed as uncompressed instead.
- */
+/* Rewrite a blob that was just written compressed (as a non-solid WIM resource)
+ * as uncompressed instead.  */
 static int
 write_blob_uncompressed(struct blob_descriptor *blob, struct filedes *out_fd)
 {
@@ -816,7 +813,7 @@ write_blob_uncompressed(struct blob_descriptor *blob, struct filedes *out_fd)
                         * seeked to the end of the compressed resource, so
                         * don't issue a hard error; just keep the compressed
                         * resource instead.  */
-                       WARNING("Recovered compressed blob of "
+                       WARNING("Recovered compressed resource of "
                                "size %"PRIu64", continuing on.", blob->size);
                        return 0;
                }
@@ -877,8 +874,9 @@ should_rewrite_blob_uncompressed(const struct write_blobs_ctx *ctx,
         * uncompressed data by decompressing the compressed data we wrote to
         * the output file.
         */
-       if ((blob->flags & WIM_RESHDR_FLAG_SOLID) &&
-           (blob->out_reshdr.size_in_wim != blob->out_reshdr.uncompressed_size))
+       if (blob->blob_location == BLOB_IN_WIM &&
+           blob->size != blob->rdesc->uncompressed_size &&
+           blob->size != blob->out_reshdr.size_in_wim)
                return false;
 
        return true;
@@ -926,15 +924,10 @@ write_chunk(struct write_blobs_ctx *ctx, const void *cchunk,
                /* Starting to write a new blob in non-solid mode.  */
 
                if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
-                       int additional_reshdr_flags = 0;
-                       if (ctx->compressor != NULL)
-                               additional_reshdr_flags |= WIM_RESHDR_FLAG_COMPRESSED;
-
                        DEBUG("Writing pipable WIM blob header "
                              "(offset=%"PRIu64")", ctx->out_fd->offset);
-
                        ret = write_pwm_blob_header(blob, ctx->out_fd,
-                                                   additional_reshdr_flags);
+                                                   ctx->compressor != NULL);
                        if (ret)
                                return ret;
                }
@@ -1007,7 +1000,7 @@ write_chunk(struct write_blobs_ctx *ctx, const void *cchunk,
                        if (ret)
                                return ret;
 
-                       blob->out_reshdr.flags = filter_resource_flags(blob->flags);
+                       blob->out_reshdr.flags = reshdr_flags_for_blob(blob);
                        if (ctx->compressor != NULL)
                                blob->out_reshdr.flags |= WIM_RESHDR_FLAG_COMPRESSED;
 
@@ -1365,11 +1358,22 @@ remove_empty_blobs(struct list_head *blob_list)
                        blob->out_reshdr.offset_in_wim = 0;
                        blob->out_reshdr.size_in_wim = 0;
                        blob->out_reshdr.uncompressed_size = 0;
-                       blob->out_reshdr.flags = filter_resource_flags(blob->flags);
+                       blob->out_reshdr.flags = reshdr_flags_for_blob(blob);
                }
        }
 }
 
+static inline bool
+blob_is_in_file(const struct blob_descriptor *blob)
+{
+       return blob->blob_location == BLOB_IN_FILE_ON_DISK
+#ifdef __WIN32__
+           || blob->blob_location == BLOB_IN_WINNT_FILE_ON_DISK
+           || blob->blob_location == BLOB_WIN32_ENCRYPTED
+#endif
+          ;
+}
+
 static void
 init_done_with_file_info(struct list_head *blob_list)
 {
@@ -1681,8 +1685,8 @@ write_blob_list(struct list_head *blob_list,
                offset_in_res = 0;
                list_for_each_entry(blob, &ctx.blobs_in_solid_resource, write_blobs_list) {
                        blob->out_reshdr.size_in_wim = blob->size;
-                       blob->out_reshdr.flags = filter_resource_flags(blob->flags);
-                       blob->out_reshdr.flags |= WIM_RESHDR_FLAG_SOLID;
+                       blob->out_reshdr.flags = reshdr_flags_for_blob(blob) |
+                                                WIM_RESHDR_FLAG_SOLID;
                        blob->out_reshdr.uncompressed_size = 0;
                        blob->out_reshdr.offset_in_wim = offset_in_res;
                        blob->out_res_offset_in_wim = reshdr.offset_in_wim;
@@ -1707,24 +1711,13 @@ out_destroy_context:
        return ret;
 }
 
-static int
-is_blob_in_solid_resource(struct blob_descriptor *blob, void *_ignore)
-{
-       return blob_is_in_solid_wim_resource(blob);
-}
-
-static bool
-wim_has_solid_resources(WIMStruct *wim)
-{
-       return for_blob_in_table(wim->blob_table, is_blob_in_solid_resource, NULL);
-}
 
 static int
-wim_write_blob_list(WIMStruct *wim,
-                   struct list_head *blob_list,
-                   int write_flags,
-                   unsigned num_threads,
-                   struct filter_context *filter_ctx)
+write_file_data_blobs(WIMStruct *wim,
+                     struct list_head *blob_list,
+                     int write_flags,
+                     unsigned num_threads,
+                     struct filter_context *filter_ctx)
 {
        int out_ctype;
        u32 out_chunk_size;
@@ -1762,6 +1755,7 @@ wim_write_blob_list(WIMStruct *wim,
                               wim->progctx);
 }
 
+/* Write the contents of the specified blob as a WIM resource.  */
 static int
 write_wim_resource(struct blob_descriptor *blob,
                   struct filedes *out_fd,
@@ -1784,51 +1778,36 @@ write_wim_resource(struct blob_descriptor *blob,
                               NULL);
 }
 
+/* Write the contents of the specified buffer as a WIM resource.  */
 int
-write_wim_resource_from_buffer(const void *buf, size_t buf_size,
-                              int reshdr_flags, struct filedes *out_fd,
+write_wim_resource_from_buffer(const void *buf,
+                              size_t buf_size,
+                              bool is_metadata,
+                              struct filedes *out_fd,
                               int out_ctype,
                               u32 out_chunk_size,
                               struct wim_reshdr *out_reshdr,
-                              u8 *hash,
+                              u8 *hash_ret,
                               int write_resource_flags)
 {
        int ret;
-       struct blob_descriptor *blob;
-
-       /* Set up a temporary blob descriptor to provide to
-        * write_wim_resource().  */
+       struct blob_descriptor blob;
 
-       blob = new_blob_descriptor();
-       if (blob == NULL)
-               return WIMLIB_ERR_NOMEM;
-
-       blob->blob_location = BLOB_IN_ATTACHED_BUFFER;
-       blob->attached_buffer = (void*)buf;
-       blob->size = buf_size;
-       blob->flags = reshdr_flags;
-
-       if (write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
-               sha1_buffer(buf, buf_size, blob->hash);
-               blob->unhashed = 0;
-       } else {
-               blob->unhashed = 1;
-       }
+       blob_set_is_located_in_attached_buffer(&blob, (void *)buf, buf_size);
+       sha1_buffer(buf, buf_size, blob.hash);
+       blob.unhashed = 0;
+       blob.is_metadata = is_metadata;
 
-       ret = write_wim_resource(blob, out_fd, out_ctype, out_chunk_size,
+       ret = write_wim_resource(&blob, out_fd, out_ctype, out_chunk_size,
                                 write_resource_flags);
        if (ret)
-               goto out_free_blob;
+               return ret;
 
-       copy_reshdr(out_reshdr, &blob->out_reshdr);
+       copy_reshdr(out_reshdr, &blob.out_reshdr);
 
-       if (hash)
-               copy_hash(hash, blob->hash);
-       ret = 0;
-out_free_blob:
-       blob->blob_location = BLOB_NONEXISTENT;
-       free_blob_descriptor(blob);
-       return ret;
+       if (hash_ret)
+               copy_hash(hash_ret, blob.hash);
+       return 0;
 }
 
 struct blob_size_table {
@@ -1860,11 +1839,10 @@ blob_size_table_insert(struct blob_descriptor *blob, void *_tab)
        struct blob_size_table *tab = _tab;
        size_t pos;
        struct blob_descriptor *same_size_blob;
-       struct hlist_node *tmp;
 
        pos = hash_u64(blob->size) % tab->capacity;
        blob->unique_size = 1;
-       hlist_for_each_entry(same_size_blob, tmp, &tab->array[pos], hash_list_2) {
+       hlist_for_each_entry(same_size_blob, &tab->array[pos], hash_list_2) {
                if (same_size_blob->size == blob->size) {
                        blob->unique_size = 0;
                        same_size_blob->unique_size = 0;
@@ -1914,12 +1892,16 @@ inode_find_blobs_to_reference(const struct wim_inode *inode,
 
        for (unsigned i = 0; i < inode->i_num_streams; i++) {
                struct blob_descriptor *blob;
+               const u8 *hash;
 
                blob = stream_blob(&inode->i_streams[i], table);
-               if (blob)
+               if (blob) {
                        reference_blob_for_write(blob, blob_list, inode->i_nlink);
-               else if (!is_zero_hash(stream_hash(&inode->i_streams[i])))
-                       return WIMLIB_ERR_RESOURCE_NOT_FOUND;
+               } else {
+                       hash = stream_hash(&inode->i_streams[i]);
+                       if (!is_zero_hash(hash))
+                               return blob_not_found_error(inode, hash);
+               }
        }
        return 0;
 }
@@ -2169,10 +2151,10 @@ prepare_blob_list_for_write(WIMStruct *wim, int image,
 }
 
 static int
-write_file_blobs(WIMStruct *wim, int image, int write_flags,
-                unsigned num_threads,
-                struct list_head *blob_list_override,
-                struct list_head *blob_table_list_ret)
+write_file_data(WIMStruct *wim, int image, int write_flags,
+               unsigned num_threads,
+               struct list_head *blob_list_override,
+               struct list_head *blob_table_list_ret)
 {
        int ret;
        struct list_head _blob_list;
@@ -2207,15 +2189,15 @@ write_file_blobs(WIMStruct *wim, int image, int write_flags,
                }
        }
 
-       return wim_write_blob_list(wim,
-                                  blob_list,
-                                  write_flags,
-                                  num_threads,
-                                  filter_ctx);
+       return write_file_data_blobs(wim,
+                                    blob_list,
+                                    write_flags,
+                                    num_threads,
+                                    filter_ctx);
 }
 
 static int
-write_metadata_blobs(WIMStruct *wim, int image, int write_flags)
+write_metadata_resources(WIMStruct *wim, int image, int write_flags)
 {
        int ret;
        int start_image;
@@ -2480,7 +2462,7 @@ finish_write(WIMStruct *wim, int image, int write_flags,
            && wim_has_integrity_table(wim))
        {
                old_blob_table_end = wim->hdr.blob_table_reshdr.offset_in_wim +
-                                      wim->hdr.blob_table_reshdr.size_in_wim;
+                                    wim->hdr.blob_table_reshdr.size_in_wim;
                (void)read_integrity_table(wim,
                                           old_blob_table_end - WIM_HEADER_DISK_SIZE,
                                           &old_integrity_table);
@@ -2633,6 +2615,9 @@ unlock_wim_for_append(WIMStruct *wim)
  *   reading the WIM from a pipe.  This copy of the XML data is ignored if the
  *   WIM is read from a seekable file (not a pipe).
  *
+ * - Solid resources are not allowed.  Each blob is always stored in its own
+ *   resource.
+ *
  * - The format of resources, or blobs, has been modified to allow them to be
  *   used before the "blob table" has been read.  Each blob is prefixed with a
  *   `struct pwm_blob_hdr' that is basically an abbreviated form of `struct
@@ -2694,13 +2679,13 @@ write_pipable_wim(WIMStruct *wim, int image, int write_flags,
 
        WARNING("Creating a pipable WIM, which will "
                "be incompatible\n"
-               "          with Microsoft's software (wimgapi/imagex/Dism).");
+               "          with Microsoft's software (WIMGAPI/ImageX/DISM).");
 
        /* At this point, the header at the beginning of the file has already
         * been written.  */
 
        /* For efficiency, when wimlib adds an image to the WIM with
-        * wimlib_add_image(), the SHA-1 message digests of files is not
+        * wimlib_add_image(), the SHA-1 message digests of files are not
         * calculated; instead, they are calculated while the files are being
         * written.  However, this does not work when writing a pipable WIM,
         * since when writing a blob to a pipable WIM, its SHA-1 message digest
@@ -2719,15 +2704,15 @@ write_pipable_wim(WIMStruct *wim, int image, int write_flags,
 
        /* Write metadata resources for the image(s) being included in the
         * output WIM.  */
-       ret = write_metadata_blobs(wim, image, write_flags);
+       ret = write_metadata_resources(wim, image, write_flags);
        if (ret)
                return ret;
 
-       /* Write blobs needed for the image(s) being included in the output WIM,
-        * or blobs needed for the split WIM part.  */
-       return write_file_blobs(wim, image, write_flags,
-                               num_threads, blob_list_override,
-                               blob_table_list_ret);
+       /* Write file data needed for the image(s) being included in the output
+        * WIM, or file data needed for the split WIM part.  */
+       return write_file_data(wim, image, write_flags,
+                              num_threads, blob_list_override,
+                              blob_table_list_ret);
 
        /* The blob table, XML data, and header at end are handled by
         * finish_write().  */
@@ -2803,6 +2788,12 @@ write_wim_part(WIMStruct *wim,
        if (write_flags & WIMLIB_WRITE_FLAG_SOLID)
                DEBUG("\tSOLID");
 
+       if (write_flags & WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES)
+               DEBUG("\tSEND_DONE_WITH_FILE_MESSAGES");
+
+       if (write_flags & WIMLIB_WRITE_FLAG_NO_SOLID_SORT)
+               DEBUG("\tNO_SOLID_SORT");
+
        if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
                DEBUG("\tFILE_DESCRIPTOR");
 
@@ -2907,13 +2898,8 @@ write_wim_part(WIMStruct *wim,
        wim->hdr.part_number = part_number;
        wim->hdr.total_parts = total_parts;
 
-       /* Set compression type if different.  */
-       if (wim->compression_type != wim->out_compression_type) {
-               ret = set_wim_hdr_cflags(wim->out_compression_type, &wim->hdr);
-               wimlib_assert(ret == 0);
-       }
-
-       /* Set chunk size if different.  */
+       /* Set the compression type and chunk size.  */
+       set_wim_hdr_cflags(wim->out_compression_type, &wim->hdr);
        wim->hdr.chunk_size = wim->out_chunk_size;
 
        /* Set GUID.  */
@@ -2943,14 +2929,12 @@ write_wim_part(WIMStruct *wim,
        if (total_parts != 1)
                wim->hdr.boot_idx = 0;
 
-       /* Initialize output file descriptor.  */
+       /* Set up output file descriptor.  */
        if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR) {
-               /* File descriptor was explicitly provided.  Return error if
-                * file descriptor is not seekable, unless writing a pipable WIM
-                * was requested.  */
-               wim->out_fd.fd = *(const int*)path_or_fd;
-               wim->out_fd.offset = 0;
+               /* File descriptor was explicitly provided.  */
+               filedes_init(&wim->out_fd, *(const int *)path_or_fd);
                if (!filedes_is_seekable(&wim->out_fd)) {
+                       /* The file descriptor is a pipe.  */
                        ret = WIMLIB_ERR_INVALID_PARAM;
                        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
                                goto out_restore_hdr;
@@ -2980,17 +2964,17 @@ write_wim_part(WIMStruct *wim,
        if (ret)
                goto out_restore_hdr;
 
-       /* Write metadata resources and blobs.  */
+       /* Write file data and metadata resources.  */
        if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE)) {
                /* Default case: create a normal (non-pipable) WIM.  */
-               ret = write_file_blobs(wim, image, write_flags,
-                                      num_threads,
-                                      blob_list_override,
-                                      &blob_table_list);
+               ret = write_file_data(wim, image, write_flags,
+                                     num_threads,
+                                     blob_list_override,
+                                     &blob_table_list);
                if (ret)
                        goto out_restore_hdr;
 
-               ret = write_metadata_blobs(wim, image, write_flags);
+               ret = write_metadata_resources(wim, image, write_flags);
                if (ret)
                        goto out_restore_hdr;
        } else {
@@ -3261,12 +3245,12 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads)
                goto out_restore_physical_hdr;
        }
 
-       ret = wim_write_blob_list(wim, &blob_list, write_flags,
-                                 num_threads, &filter_ctx);
+       ret = write_file_data_blobs(wim, &blob_list, write_flags,
+                                   num_threads, &filter_ctx);
        if (ret)
                goto out_truncate;
 
-       ret = write_metadata_blobs(wim, WIMLIB_ALL_IMAGES, write_flags);
+       ret = write_metadata_resources(wim, WIMLIB_ALL_IMAGES, write_flags);
        if (ret)
                goto out_truncate;