]> wimlib.net Git - wimlib/blobdiff - src/write.c
read_wim_lookup_table(): Make sure all resources get validated (try 2)
[wimlib] / src / write.c
index 411fed9a349baa6f9c1411c9cae0cb8833bc4a14..292aa7d129ec500ad95494384f7f6325d93a7e9a 100644 (file)
@@ -39,6 +39,7 @@
 #include "wimlib/error.h"
 #include "wimlib/file_io.h"
 #include "wimlib/header.h"
+#include "wimlib/inode.h"
 #include "wimlib/integrity.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
@@ -172,8 +173,8 @@ can_raw_copy(const struct wim_lookup_table_entry *lte,
        if (rspec->flags & WIM_RESHDR_FLAG_COMPRESSED) {
                /* Normal compressed resource: Must use same compression type
                 * and chunk size.  */
-               return (rspec->wim->compression_type == out_ctype &&
-                       rspec->wim->chunk_size == out_chunk_size);
+               return (rspec->compression_type == out_ctype &&
+                       rspec->chunk_size == out_chunk_size);
        }
 
        /* XXX: For compatibility, we can't allow multiple packed resources per
@@ -277,7 +278,6 @@ struct write_streams_progress_data {
        wimlib_progress_func_t progress_func;
        union wimlib_progress_info progress;
        uint64_t next_progress;
-       WIMStruct *prev_wim_part;
 };
 
 static void
@@ -288,7 +288,6 @@ do_write_streams_progress(struct write_streams_progress_data *progress_data,
                          bool discarded)
 {
        union wimlib_progress_info *progress = &progress_data->progress;
-       bool new_wim_part;
 
        if (discarded) {
                progress->write_streams.total_bytes -= complete_size;
@@ -303,20 +302,8 @@ do_write_streams_progress(struct write_streams_progress_data *progress_data,
                progress->write_streams.completed_streams += complete_count;
        }
 
-       new_wim_part = false;
-       if (cur_stream->resource_location == RESOURCE_IN_WIM &&
-           cur_stream->rspec->wim != progress_data->prev_wim_part)
-       {
-               if (progress_data->prev_wim_part) {
-                       new_wim_part = true;
-                       progress->write_streams.completed_parts++;
-               }
-               progress_data->prev_wim_part = cur_stream->rspec->wim;
-       }
-
        if (progress_data->progress_func
-           && (progress->write_streams.completed_bytes >= progress_data->next_progress
-               || new_wim_part))
+           && (progress->write_streams.completed_bytes >= progress_data->next_progress))
        {
                progress_data->progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
                                             progress);
@@ -568,8 +555,8 @@ end_chunk_table(struct write_streams_ctx *ctx, u64 res_actual_size,
                        hdr.chunk_size = cpu_to_le32(ctx->out_chunk_size);
                        hdr.compression_format = cpu_to_le32(ctx->out_ctype);
 
-                       BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 1);
-                       BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 2);
+                       BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 1);
+                       BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 2);
                        BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZMS != 3);
 
                        ret = full_pwrite(ctx->out_fd, &hdr, sizeof(hdr),
@@ -1060,7 +1047,6 @@ compute_stream_list_stats(struct list_head *stream_list,
        ctx->progress_data.progress.write_streams.total_parts       = total_parts;
        ctx->progress_data.progress.write_streams.completed_parts   = 0;
        ctx->progress_data.next_progress = 0;
-       ctx->progress_data.prev_wim_part = NULL;
 }
 
 /* Find streams in @stream_list that can be copied to the output WIM in raw form
@@ -1233,7 +1219,7 @@ remove_zero_length_streams(struct list_head *stream_list)
  * Write a list of streams to the output WIM file.
  *
  * @stream_list
- *     The list of streams to write, specifies a list of `struct
+ *     The list of streams to write, specified by a list of `struct
  *     wim_lookup_table_entry's linked by the 'write_streams_list' member.
  *
  * @out_fd
@@ -1244,20 +1230,20 @@ remove_zero_length_streams(struct list_head *stream_list)
  *
  *     WRITE_RESOURCE_FLAG_RECOMPRESS:
  *             Force compression of all resources, even if they could otherwise
- *             be re-used by caping the raw data, due to being located in a WIM
+ *             be re-used by copying the raw data, due to being located in a WIM
  *             file with compatible compression parameters.
  *
  *     WRITE_RESOURCE_FLAG_PIPABLE:
  *             Write the resources in the wimlib-specific pipable format, and
  *             furthermore do so in such a way that no seeking backwards in
- *             @out_fd will be performed (so it may be a pipe, contrary to the
- *             default behavior).
+ *             @out_fd will be performed (so it may be a pipe).
  *
  *     WRITE_RESOURCE_FLAG_PACK_STREAMS:
  *             Pack all the streams into a single resource rather than writing
- *             them in separate resources.  This format is only valid if the
- *             WIM version number is WIM_VERSION_PACKED_STREAMS.  This flag
- *             currently may not be combined with WRITE_RESOURCE_FLAG_PIPABLE.
+ *             them in separate resources.  This flag is only valid if the WIM
+ *             version number has been, or will be, set to
+ *             WIM_VERSION_PACKED_STREAMS.  This flag may not be combined with
+ *             WRITE_RESOURCE_FLAG_PIPABLE.
  *
  * @out_ctype
  *     Compression format to use to write the output streams, specified as one
@@ -1300,15 +1286,15 @@ remove_zero_length_streams(struct list_head *stream_list)
  * In both cases, the @out_reshdr of the `struct wim_lookup_table_entry' for
  * each stream written will be updated to specify its location, size, and flags
  * in the output WIM.  In the packed resource case,
- * WIM_RESHDR_FLAG_PACKED_STREAMS shall be set in the @flags field of the
- * @out_reshdr, and @out_res_offset_in_wim and @out_res_size_in_wim will also
- * be set to the offset and size, respectively, in the output WIM of the full
- * packed resource containing the corresponding stream.
+ * WIM_RESHDR_FLAG_PACKED_STREAMS will be set in the @flags field of each
+ * @out_reshdr, and furthermore @out_res_offset_in_wim and @out_res_size_in_wim
+ * of each @out_reshdr will be set to the offset and size, respectively, in the
+ * output WIM of the packed resource containing the corresponding stream.
  *
  * Each of the streams to write may be in any location supported by the
  * resource-handling code (specifically, read_stream_list()), such as the
  * contents of external file that has been logically added to the output WIM, or
- * a stream in another WIM file that has been imported, or even stream in the
+ * a stream in another WIM file that has been imported, or even stream in the
  * "same" WIM file of which a modified copy is being written.  In the case that
  * a stream is already in a WIM file and uses compatible compression parameters,
  * by default this function will re-use the raw data instead of decompressing
@@ -1316,32 +1302,31 @@ remove_zero_length_streams(struct list_head *stream_list)
  * specified in @write_resource_flags, this is not done.
  *
  * As a further requirement, this function requires that the
- * @will_be_in_output_wim member be set on all streams in @stream_list as well
- * as any other streams not in @stream_list that will be in the output WIM file,
- * but not on any other streams in the output WIM's lookup table or sharing a
- * packed resource with a stream in @stream_list.  Still furthermore, if
- * on-the-fly deduplication of streams is possible, then all streams in
+ * @will_be_in_output_wim member be set to 1 on all streams in @stream_list as
+ * well as any other streams not in @stream_list that will be in the output WIM
+ * file, but set to 0 on any other streams in the output WIM's lookup table or
+ * sharing a packed resource with a stream in @stream_list.  Still furthermore,
+ * if on-the-fly deduplication of streams is possible, then all streams in
  * @stream_list must also be linked by @lookup_table_list along with any other
  * streams that have @will_be_in_output_wim set.
  *
  * This function handles on-the-fly deduplication of streams for which SHA1
- * message digests have not yet been calculated and it is therefore known
- * whether such streams are already in @stream_list or in the WIM's lookup table
- * at all.  If @lookup_table is non-NULL, then each stream in @stream_list that
- * has @unhashed set but not @unique_size set is checksummed immediately before
- * it would otherwise be read for writing in order to determine if it is
- * identical to another stream already being written or one that would be
- * filtered out of the output WIM using stream_filtered() with the context
- * @filter_ctx.  Each such duplicate stream will be removed from @stream_list, its
- * reference count transfered to the pre-existing duplicate stream, its memory
- * freed, and will not be written.  Alternatively, if a stream in @stream_list
- * is a duplicate with any stream in @lookup_table that has not been marked for
- * writing or would not be hard-filtered, it is freed and the pre-existing
- * duplicate is written instead, taking ownership of the reference count and
- * slot in the @lookup_table_list.
- *
- * Returns 0 if all streams were written successfully (or did not need to be
- * written); otherwise a non-zero error code.
+ * message digests have not yet been calculated.  Such streams may or may not
+ * need to be written.  If @lookup_table is non-NULL, then each stream in
+ * @stream_list that has @unhashed set but not @unique_size set is checksummed
+ * immediately before it would otherwise be read for writing in order to
+ * determine if it is identical to another stream already being written or one
+ * that would be filtered out of the output WIM using stream_filtered() with the
+ * context @filter_ctx.  Each such duplicate stream will be removed from
+ * @stream_list, its reference count transfered to the pre-existing duplicate
+ * stream, its memory freed, and will not be written.  Alternatively, if a
+ * stream in @stream_list is a duplicate with any stream in @lookup_table that
+ * has not been marked for writing or would not be hard-filtered, it is freed
+ * and the pre-existing duplicate is written instead, taking ownership of the
+ * reference count and slot in the @lookup_table_list.
+ *
+ * Returns 0 if every stream was either written successfully or did not need to
+ * be written; otherwise returns a non-zero error code.
  */
 static int
 write_stream_list(struct list_head *stream_list,
@@ -1430,11 +1415,11 @@ write_stream_list(struct list_head *stream_list,
         * to do compression.  There are serial and parallel implementations of
         * the chunk_compressor interface.  We default to parallel using the
         * specified number of threads, unless the upper bound on the number
-        * bytes needing to be compressed is less 2000000 (heuristic value).  */
+        * bytes needing to be compressed is less than a heuristic value.  */
        if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE) {
 
        #ifdef ENABLE_MULTITHREADED_COMPRESSION
-               if (ctx.num_bytes_to_compress >= 2000000) {
+               if (ctx.num_bytes_to_compress > max(2000000, out_chunk_size)) {
                        ret = new_parallel_chunk_compressor(out_ctype,
                                                            out_chunk_size,
                                                            num_threads, 0,
@@ -1843,7 +1828,7 @@ determine_stream_size_uniquity(struct list_head *stream_list,
        struct stream_size_table tab;
        struct wim_lookup_table_entry *lte;
 
-       ret = init_stream_size_table(&tab, lt->capacity);
+       ret = init_stream_size_table(&tab, 9001);
        if (ret)
                return ret;
 
@@ -2819,10 +2804,11 @@ wimlib_write(WIMStruct *wim, const tchar *path,
             int image, int write_flags, unsigned num_threads,
             wimlib_progress_func_t progress_func)
 {
-       if (!path)
+       if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
                return WIMLIB_ERR_INVALID_PARAM;
 
-       write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
+       if (path == NULL || path[0] == T('\0'))
+               return WIMLIB_ERR_INVALID_PARAM;
 
        return write_standalone_wim(wim, path, image, write_flags,
                                    num_threads, progress_func);
@@ -2834,10 +2820,12 @@ wimlib_write_to_fd(WIMStruct *wim, int fd,
                   int image, int write_flags, unsigned num_threads,
                   wimlib_progress_func_t progress_func)
 {
+       if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
+               return WIMLIB_ERR_INVALID_PARAM;
+
        if (fd < 0)
                return WIMLIB_ERR_INVALID_PARAM;
 
-       write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
        write_flags |= WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR;
 
        return write_standalone_wim(wim, &fd, image, write_flags,
@@ -3123,7 +3111,10 @@ overwrite_wim_via_tmpfile(WIMStruct *wim, int write_flags,
                return ret;
        }
 
-       close_wim(wim);
+       if (filedes_valid(&wim->in_fd)) {
+               filedes_close(&wim->in_fd);
+               filedes_invalidate(&wim->in_fd);
+       }
 
        /* Rename the new WIM file to the original WIM file.  Note: on Windows
         * this actually calls win32_rename_replacement(), not _wrename(), so
@@ -3197,9 +3188,7 @@ wimlib_overwrite(WIMStruct *wim, int write_flags,
        int ret;
        u32 orig_hdr_flags;
 
-       write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
-
-       if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
+       if (write_flags & ~WIMLIB_WRITE_MASK_PUBLIC)
                return WIMLIB_ERR_INVALID_PARAM;
 
        if (!wim->filename)