]> wimlib.net Git - wimlib/blob - src/write.c
New compression/decompression API
[wimlib] / src / write.c
1 /*
2  * write.c
3  *
4  * Support for writing WIM files; write a WIM file, overwrite a WIM file, write
5  * compressed file resources, etc.
6  */
7
8 /*
9  * Copyright (C) 2012, 2013 Eric Biggers
10  *
11  * This file is part of wimlib, a library for working with WIM files.
12  *
13  * wimlib is free software; you can redistribute it and/or modify it under the
14  * terms of the GNU General Public License as published by the Free
15  * Software Foundation; either version 3 of the License, or (at your option)
16  * any later version.
17  *
18  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
19  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
20  * A PARTICULAR PURPOSE. See the GNU General Public License for more
21  * details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with wimlib; if not, see http://www.gnu.org/licenses/.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 #  include "config.h"
29 #endif
30
31 #if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
32 /* On BSD, this should be included before "wimlib/list.h" so that "wimlib/list.h" can
33  * overwrite the LIST_HEAD macro. */
34 #  include <sys/file.h>
35 #endif
36
37 #include "wimlib/chunk_compressor.h"
38 #include "wimlib/endianness.h"
39 #include "wimlib/error.h"
40 #include "wimlib/file_io.h"
41 #include "wimlib/header.h"
42 #include "wimlib/integrity.h"
43 #include "wimlib/lookup_table.h"
44 #include "wimlib/metadata.h"
45 #include "wimlib/resource.h"
46 #ifdef __WIN32__
47 #  include "wimlib/win32.h" /* win32_rename_replacement() */
48 #endif
49 #include "wimlib/write.h"
50 #include "wimlib/xml.h"
51
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <stdlib.h>
55 #include <unistd.h>
56
57 #ifdef HAVE_ALLOCA_H
58 #  include <alloca.h>
59 #endif
60
61 /* wimlib internal flags used when writing resources.  */
62 #define WRITE_RESOURCE_FLAG_RECOMPRESS          0x00000001
63 #define WRITE_RESOURCE_FLAG_PIPABLE             0x00000002
64 #define WRITE_RESOURCE_FLAG_PACK_STREAMS        0x00000004
65
66 static inline int
67 write_flags_to_resource_flags(int write_flags)
68 {
69         int write_resource_flags = 0;
70
71         if (write_flags & WIMLIB_WRITE_FLAG_RECOMPRESS)
72                 write_resource_flags |= WRITE_RESOURCE_FLAG_RECOMPRESS;
73         if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
74                 write_resource_flags |= WRITE_RESOURCE_FLAG_PIPABLE;
75         if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS)
76                 write_resource_flags |= WRITE_RESOURCE_FLAG_PACK_STREAMS;
77         return write_resource_flags;
78 }
79
80 struct filter_context {
81         int write_flags;
82         WIMStruct *wim;
83 };
84
85 /* Determine specified stream should be filtered out from the write.
86  *
87  * Return values:
88  *
89  *  < 0 : The stream should be hard-filtered; that is, not included in the
90  *        output WIM at all.
91  *    0 : The stream should not be filtered out.
92  *  > 0 : The stream should be soft-filtered; that is, it already exists in the
93  *        WIM file and may not need to be written again.
94  */
95 static int
96 stream_filtered(const struct wim_lookup_table_entry *lte,
97                 const struct filter_context *ctx)
98 {
99         int write_flags = ctx->write_flags;
100         WIMStruct *wim = ctx->wim;
101
102         if (ctx == NULL)
103                 return 0;
104
105         if (write_flags & WIMLIB_WRITE_FLAG_OVERWRITE &&
106             lte->resource_location == RESOURCE_IN_WIM &&
107             lte->rspec->wim == wim)
108                 return 1;
109
110         if (write_flags & WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS &&
111             lte->resource_location == RESOURCE_IN_WIM &&
112             lte->rspec->wim != wim)
113                 return -1;
114
115         return 0;
116 }
117
118 static bool
119 stream_hard_filtered(const struct wim_lookup_table_entry *lte,
120                      struct filter_context *ctx)
121 {
122         return stream_filtered(lte, ctx) < 0;
123 }
124
125 static inline int
126 may_soft_filter_streams(const struct filter_context *ctx)
127 {
128         if (ctx == NULL)
129                 return 0;
130         return ctx->write_flags & WIMLIB_WRITE_FLAG_OVERWRITE;
131 }
132
133 static inline int
134 may_hard_filter_streams(const struct filter_context *ctx)
135 {
136         if (ctx == NULL)
137                 return 0;
138         return ctx->write_flags & WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS;
139 }
140
141 static inline int
142 may_filter_streams(const struct filter_context *ctx)
143 {
144         return (may_soft_filter_streams(ctx) ||
145                 may_hard_filter_streams(ctx));
146 }
147
148
149 /* Return true if the specified resource is compressed and the compressed data
150  * can be reused with the specified output parameters.  */
151 static bool
152 can_raw_copy(const struct wim_lookup_table_entry *lte,
153              int write_resource_flags, int out_ctype, u32 out_chunk_size)
154 {
155         const struct wim_resource_spec *rspec;
156
157         if (write_resource_flags & WRITE_RESOURCE_FLAG_RECOMPRESS)
158                 return false;
159
160         if (out_ctype == WIMLIB_COMPRESSION_TYPE_NONE)
161                 return false;
162
163         if (lte->resource_location != RESOURCE_IN_WIM)
164                 return false;
165
166         rspec = lte->rspec;
167
168         if (rspec->is_pipable != !!(write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE))
169                 return false;
170
171
172         if (rspec->flags & WIM_RESHDR_FLAG_COMPRESSED) {
173                 /* Normal compressed resource: Must use same compression type
174                  * and chunk size.  */
175                 return (rspec->wim->compression_type == out_ctype &&
176                         rspec->wim->chunk_size == out_chunk_size);
177         }
178
179         if ((rspec->flags & WIM_RESHDR_FLAG_PACKED_STREAMS) &&
180             (write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS))
181         {
182                 /* Packed resource: Such resources may contain multiple streams,
183                  * and in general only a subset of them need to be written.  As
184                  * a heuristic, re-use the raw data if at least half the
185                  * uncompressed size is being written.  */
186
187                 /* Note: packed resources contain a header that specifies the
188                  * compression type and chunk size; therefore we don't need to
189                  * check if they are compatible with @out_ctype and
190                  * @out_chunk_size.  */
191
192                 struct wim_lookup_table_entry *res_stream;
193                 u64 write_size = 0;
194
195                 list_for_each_entry(res_stream, &rspec->stream_list, rspec_node)
196                         if (res_stream->will_be_in_output_wim)
197                                 write_size += res_stream->size;
198
199                 return (write_size > rspec->uncompressed_size / 2);
200         }
201         return false;
202 }
203
204 static u8
205 filter_resource_flags(u8 flags)
206 {
207         return (flags & ~(WIM_RESHDR_FLAG_PACKED_STREAMS |
208                           WIM_RESHDR_FLAG_COMPRESSED |
209                           WIM_RESHDR_FLAG_SPANNED |
210                           WIM_RESHDR_FLAG_FREE));
211 }
212
213 static void
214 stream_set_out_reshdr_for_reuse(struct wim_lookup_table_entry *lte)
215 {
216         const struct wim_resource_spec *rspec;
217
218         wimlib_assert(lte->resource_location == RESOURCE_IN_WIM);
219         rspec = lte->rspec;
220
221         if (rspec->flags & WIM_RESHDR_FLAG_PACKED_STREAMS) {
222
223                 wimlib_assert(lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS);
224
225                 lte->out_reshdr.offset_in_wim = lte->offset_in_res;
226                 lte->out_reshdr.uncompressed_size = 0;
227                 lte->out_reshdr.size_in_wim = lte->size;
228
229                 lte->out_res_offset_in_wim = rspec->offset_in_wim;
230                 lte->out_res_size_in_wim = rspec->size_in_wim;
231                 /*lte->out_res_uncompressed_size = rspec->uncompressed_size;*/
232         } else {
233                 wimlib_assert(!(lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS));
234
235                 lte->out_reshdr.offset_in_wim = rspec->offset_in_wim;
236                 lte->out_reshdr.uncompressed_size = rspec->uncompressed_size;
237                 lte->out_reshdr.size_in_wim = rspec->size_in_wim;
238         }
239         lte->out_reshdr.flags = lte->flags;
240 }
241
242
243 /* Write the header for a stream in a pipable WIM.  */
244 static int
245 write_pwm_stream_header(const struct wim_lookup_table_entry *lte,
246                         struct filedes *out_fd,
247                         int additional_reshdr_flags)
248 {
249         struct pwm_stream_hdr stream_hdr;
250         u32 reshdr_flags;
251         int ret;
252
253         stream_hdr.magic = cpu_to_le64(PWM_STREAM_MAGIC);
254         stream_hdr.uncompressed_size = cpu_to_le64(lte->size);
255         if (additional_reshdr_flags & PWM_RESHDR_FLAG_UNHASHED) {
256                 zero_out_hash(stream_hdr.hash);
257         } else {
258                 wimlib_assert(!lte->unhashed);
259                 copy_hash(stream_hdr.hash, lte->hash);
260         }
261
262         reshdr_flags = filter_resource_flags(lte->flags);
263         reshdr_flags |= additional_reshdr_flags;
264         stream_hdr.flags = cpu_to_le32(reshdr_flags);
265         ret = full_write(out_fd, &stream_hdr, sizeof(stream_hdr));
266         if (ret)
267                 ERROR_WITH_ERRNO("Write error");
268         return ret;
269 }
270
271 #if 0
272 static int
273 seek_and_truncate(struct filedes *out_fd, off_t offset)
274 {
275         if (filedes_seek(out_fd, offset) == -1 ||
276             ftruncate(out_fd->fd, offset))
277         {
278                 ERROR_WITH_ERRNO("Failed to truncate output WIM file");
279                 return WIMLIB_ERR_WRITE;
280         }
281         return 0;
282 }
283 #endif
284
285 struct write_streams_progress_data {
286         wimlib_progress_func_t progress_func;
287         union wimlib_progress_info progress;
288         uint64_t next_progress;
289         WIMStruct *prev_wim_part;
290 };
291
292 static void
293 do_write_streams_progress(struct write_streams_progress_data *progress_data,
294                           u64 size,
295                           bool discarded,
296                           struct wim_lookup_table_entry *cur_stream)
297 {
298         union wimlib_progress_info *progress = &progress_data->progress;
299         bool new_wim_part;
300
301         if (discarded) {
302                 progress->write_streams.total_bytes -= size;
303                 if (progress_data->next_progress != ~(uint64_t)0 &&
304                     progress_data->next_progress > progress->write_streams.total_bytes)
305                 {
306                         progress_data->next_progress = progress->write_streams.total_bytes;
307                 }
308         } else {
309                 progress->write_streams.completed_bytes += size;
310         }
311         new_wim_part = false;
312         if (cur_stream->resource_location == RESOURCE_IN_WIM &&
313             cur_stream->rspec->wim != progress_data->prev_wim_part)
314         {
315                 if (progress_data->prev_wim_part) {
316                         new_wim_part = true;
317                         progress->write_streams.completed_parts++;
318                 }
319                 progress_data->prev_wim_part = cur_stream->rspec->wim;
320         }
321         progress->write_streams.completed_streams++;
322         if (progress_data->progress_func
323             && (progress->write_streams.completed_bytes >= progress_data->next_progress
324                 || new_wim_part))
325         {
326                 progress_data->progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
327                                              progress);
328                 if (progress_data->next_progress == progress->write_streams.total_bytes) {
329                         progress_data->next_progress = ~(uint64_t)0;
330                 } else {
331                         progress_data->next_progress =
332                                 min(progress->write_streams.total_bytes,
333                                     progress->write_streams.completed_bytes +
334                                         progress->write_streams.total_bytes / 100);
335                 }
336         }
337 }
338
339 struct write_streams_ctx {
340         /* File descriptor the streams are being written to.  */
341         struct filedes *out_fd;
342
343         /* Lookup table for the WIMStruct on whose behalf the streams are being
344          * written.  */
345         struct wim_lookup_table *lookup_table;
346
347         /* Compression format to use.  */
348         int out_ctype;
349
350         /* Maximum uncompressed chunk size in compressed resources to use.  */
351         u32 out_chunk_size;
352
353         /* Flags that affect how the streams will be written.  */
354         int write_resource_flags;
355
356         /* Data used for issuing WRITE_STREAMS progress.  */
357         struct write_streams_progress_data progress_data;
358
359         struct filter_context *filter_ctx;
360
361         /* Upper bound on the total number of bytes that need to be compressed.
362          * */
363         u64 num_bytes_to_compress;
364
365         /* Pointer to the chunk_compressor implementation being used for
366          * compressing chunks of data, or NULL if chunks are being written
367          * uncompressed.  */
368         struct chunk_compressor *compressor;
369
370         /* Buffer for dividing the read data into chunks of size
371          * @out_chunk_size.  */
372         u8 *chunk_buf;
373
374         /* Number of bytes in @chunk_buf that are currently filled.  */
375         size_t chunk_buf_filled;
376
377         /* List of streams that currently have chunks being compressed.  */
378         struct list_head pending_streams;
379
380         /* Set to true if the stream currently being read was a duplicate, and
381          * therefore the corresponding stream entry needs to be freed once the
382          * read finishes.  (In this case we add the duplicate entry to
383          * pending_streams rather than the entry being read.)  */
384         bool stream_was_duplicate;
385
386         /* Current uncompressed offset in the resource being read.  */
387         u64 cur_read_res_offset;
388
389         /* Uncompressed size of the resource currently being read.  */
390         u64 cur_read_res_size;
391
392         /* Current uncompressed offset in the resource being written.  */
393         u64 cur_write_res_offset;
394
395         /* Uncompressed size of resource currently being written.  */
396         u64 cur_write_res_size;
397
398         /* Array that is filled in with compressed chunk sizes as a resource is
399          * being written.  */
400         u64 *chunk_csizes;
401
402         /* Index of next entry in @chunk_csizes to fill in.  */
403         size_t chunk_index;
404
405         /* Number of entries in @chunk_csizes currently allocated.  */
406         size_t num_alloc_chunks;
407
408         /* Offset in the output file of the start of the chunks of the resource
409          * currently being written.  */
410         u64 chunks_start_offset;
411 };
412
413 static u64
414 get_chunk_entry_size(u64 res_size, int write_resource_flags)
415 {
416         if (res_size <= UINT32_MAX ||
417             (write_resource_flags & WIM_RESHDR_FLAG_PACKED_STREAMS))
418                 return 4;
419         else
420                 return 8;
421 }
422
423 /* Reserve space for the chunk table and prepare to accumulate the chunk table
424  * in memory.  */
425 static int
426 begin_chunk_table(struct write_streams_ctx *ctx, u64 res_expected_size)
427 {
428         u64 expected_num_chunks;
429         u64 expected_num_chunk_entries;
430         size_t reserve_size;
431         int ret;
432
433         /* Calculate the number of chunks and chunk entries that should be
434          * needed for the resource.  These normally will be the final values,
435          * but in PACKED_STREAMS mode some of the streams we're planning to
436          * write into the resource may be duplicates, and therefore discarded,
437          * potentially decreasing the number of chunk entries needed.  */
438         expected_num_chunks = DIV_ROUND_UP(res_expected_size, ctx->out_chunk_size);
439         expected_num_chunk_entries = expected_num_chunks;
440         if (!(ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS))
441                 expected_num_chunk_entries--;
442
443         /* Make sure the chunk_csizes array is long enough to store the
444          * compressed size of each chunk.  */
445         if (expected_num_chunks > ctx->num_alloc_chunks) {
446                 u64 new_length = expected_num_chunks + 50;
447
448                 if ((size_t)new_length != new_length) {
449                         ERROR("Resource size too large (%"PRIu64" bytes!",
450                               res_expected_size);
451                         return WIMLIB_ERR_NOMEM;
452                 }
453
454                 FREE(ctx->chunk_csizes);
455                 ctx->chunk_csizes = MALLOC(new_length * sizeof(ctx->chunk_csizes[0]));
456                 if (ctx->chunk_csizes == NULL) {
457                         ctx->num_alloc_chunks = 0;
458                         return WIMLIB_ERR_NOMEM;
459                 }
460                 ctx->num_alloc_chunks = new_length;
461         }
462
463         ctx->chunk_index = 0;
464
465         if (!(ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE)) {
466                 /* Reserve space for the chunk table in the output file.  In the
467                  * case of packed resources this reserves the upper bound for
468                  * the needed space, not necessarily the exact space which will
469                  * prove to be needed.  At this point, we just use @chunk_csizes
470                  * for a buffer of 0's because the actual compressed chunk sizes
471                  * are unknown.  */
472                 reserve_size = expected_num_chunk_entries *
473                                get_chunk_entry_size(res_expected_size,
474                                                     ctx->write_resource_flags);
475                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS)
476                         reserve_size += sizeof(struct alt_chunk_table_header_disk);
477                 memset(ctx->chunk_csizes, 0, reserve_size);
478                 ret = full_write(ctx->out_fd, ctx->chunk_csizes, reserve_size);
479                 if (ret)
480                         return ret;
481         }
482         return 0;
483 }
484
485 static int
486 begin_write_resource(struct write_streams_ctx *ctx, u64 res_expected_size)
487 {
488         int ret;
489
490         wimlib_assert(res_expected_size != 0);
491
492         if (ctx->compressor != NULL) {
493                 ret = begin_chunk_table(ctx, res_expected_size);
494                 if (ret)
495                         return ret;
496         }
497
498         /* Output file descriptor is now positioned at the offset at which to
499          * write the first chunk of the resource.  */
500         ctx->chunks_start_offset = ctx->out_fd->offset;
501         ctx->cur_write_res_offset = 0;
502         ctx->cur_write_res_size = res_expected_size;
503         return 0;
504 }
505
506 static int
507 end_chunk_table(struct write_streams_ctx *ctx, u64 res_actual_size,
508                 u64 *res_start_offset_ret, u64 *res_store_size_ret)
509 {
510         size_t actual_num_chunks;
511         size_t actual_num_chunk_entries;
512         size_t chunk_entry_size;
513         int ret;
514
515         actual_num_chunks = ctx->chunk_index;
516         actual_num_chunk_entries = actual_num_chunks;
517         if (!(ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS))
518                 actual_num_chunk_entries--;
519
520         chunk_entry_size = get_chunk_entry_size(res_actual_size,
521                                                 ctx->write_resource_flags);
522
523         typedef le64 __attribute__((may_alias)) aliased_le64_t;
524         typedef le32 __attribute__((may_alias)) aliased_le32_t;
525
526         if (chunk_entry_size == 4) {
527                 aliased_le32_t *entries = (aliased_le32_t*)ctx->chunk_csizes;
528
529                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
530                         for (size_t i = 0; i < actual_num_chunk_entries; i++)
531                                 entries[i] = cpu_to_le32(ctx->chunk_csizes[i]);
532                 } else {
533                         u32 offset = ctx->chunk_csizes[0];
534                         for (size_t i = 0; i < actual_num_chunk_entries; i++) {
535                                 u32 next_size = ctx->chunk_csizes[i + 1];
536                                 entries[i] = cpu_to_le32(offset);
537                                 offset += next_size;
538                         }
539                 }
540         } else {
541                 aliased_le64_t *entries = (aliased_le64_t*)ctx->chunk_csizes;
542
543                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
544                         for (size_t i = 0; i < actual_num_chunk_entries; i++)
545                                 entries[i] = cpu_to_le64(ctx->chunk_csizes[i]);
546                 } else {
547                         u64 offset = ctx->chunk_csizes[0];
548                         for (size_t i = 0; i < actual_num_chunk_entries; i++) {
549                                 u64 next_size = ctx->chunk_csizes[i + 1];
550                                 entries[i] = cpu_to_le64(offset);
551                                 offset += next_size;
552                         }
553                 }
554         }
555
556         size_t chunk_table_size = actual_num_chunk_entries * chunk_entry_size;
557         u64 res_start_offset;
558         u64 res_end_offset;
559
560         if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
561                 ret = full_write(ctx->out_fd, ctx->chunk_csizes, chunk_table_size);
562                 if (ret)
563                         goto error;
564                 res_end_offset = ctx->out_fd->offset;
565                 res_start_offset = ctx->chunks_start_offset;
566         } else {
567                 res_end_offset = ctx->out_fd->offset;
568
569                 u64 chunk_table_offset;
570
571                 chunk_table_offset = ctx->chunks_start_offset - chunk_table_size;
572
573                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
574                         struct alt_chunk_table_header_disk hdr;
575
576                         hdr.res_usize = cpu_to_le64(res_actual_size);
577                         hdr.chunk_size = cpu_to_le32(ctx->out_chunk_size);
578                         hdr.compression_format = cpu_to_le32(ctx->out_ctype);
579
580                         BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZX != 1);
581                         BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_XPRESS != 2);
582                         BUILD_BUG_ON(WIMLIB_COMPRESSION_TYPE_LZMS != 3);
583
584                         ret = full_pwrite(ctx->out_fd, &hdr, sizeof(hdr),
585                                           chunk_table_offset - sizeof(hdr));
586                         if (ret)
587                                 goto error;
588                         res_start_offset = chunk_table_offset - sizeof(hdr);
589                 } else {
590                         res_start_offset = chunk_table_offset;
591                 }
592
593                 ret = full_pwrite(ctx->out_fd, ctx->chunk_csizes,
594                                   chunk_table_size, chunk_table_offset);
595                 if (ret)
596                         goto error;
597         }
598
599         *res_start_offset_ret = res_start_offset;
600         *res_store_size_ret = res_end_offset - res_start_offset;
601
602         return 0;
603
604 error:
605         ERROR_WITH_ERRNO("Write error");
606         return ret;
607 }
608
609 /* Finish writing a WIM resource by writing or updating the chunk table (if not
610  * writing the data uncompressed) and loading its metadata into @out_reshdr.  */
611 static int
612 end_write_resource(struct write_streams_ctx *ctx, struct wim_reshdr *out_reshdr)
613 {
614         int ret;
615         u64 res_size_in_wim;
616         u64 res_uncompressed_size;
617         u64 res_offset_in_wim;
618
619         wimlib_assert(ctx->cur_write_res_size == ctx->cur_write_res_offset);
620         res_uncompressed_size = ctx->cur_write_res_size;
621
622         if (ctx->compressor) {
623                 ret = end_chunk_table(ctx, res_uncompressed_size,
624                                       &res_offset_in_wim, &res_size_in_wim);
625                 if (ret)
626                         return ret;
627         } else {
628                 res_offset_in_wim = ctx->chunks_start_offset;
629                 res_size_in_wim = ctx->out_fd->offset - res_offset_in_wim;
630         }
631         out_reshdr->uncompressed_size = res_uncompressed_size;
632         out_reshdr->size_in_wim = res_size_in_wim;
633         out_reshdr->offset_in_wim = res_offset_in_wim;
634         DEBUG("Finished writing resource: %"PRIu64" => %"PRIu64" @ %"PRIu64"",
635               res_uncompressed_size, res_size_in_wim, res_offset_in_wim);
636         return 0;
637 }
638
639 /* Begin processing a stream for writing.  */
640 static int
641 write_stream_begin_read(struct wim_lookup_table_entry *lte,
642                         bool is_partial_res, void *_ctx)
643 {
644         struct write_streams_ctx *ctx = _ctx;
645         int ret;
646
647         wimlib_assert(lte->size > 0);
648
649         ctx->cur_read_res_offset = 0;
650         ctx->cur_read_res_size = lte->size;
651
652         /* As an optimization, we allow some streams to be "unhashed", meaning
653          * their SHA1 message digests are unknown.  This is the case with
654          * streams that are added by scanning a directry tree with
655          * wimlib_add_image(), for example.  Since WIM uses single-instance
656          * streams, we don't know whether such each such stream really need to
657          * written until it is actually checksummed, unless it has a unique
658          * size.  In such cases we read and checksum the stream in this
659          * function, thereby advancing ahead of read_stream_list(), which will
660          * still provide the data again to write_stream_process_chunk().  This
661          * is okay because an unhashed stream cannot be in a WIM resource, which
662          * might be costly to decompress.  */
663         ctx->stream_was_duplicate = false;
664         if (ctx->lookup_table != NULL && lte->unhashed && !lte->unique_size) {
665
666                 wimlib_assert(!is_partial_res);
667
668                 struct wim_lookup_table_entry *lte_new;
669
670                 ret = hash_unhashed_stream(lte, ctx->lookup_table, &lte_new);
671                 if (ret)
672                         return ret;
673                 if (lte_new != lte) {
674                         /* Duplicate stream detected.  */
675
676                         if (lte_new->will_be_in_output_wim ||
677                             stream_filtered(lte_new, ctx->filter_ctx))
678                         {
679                                 /* The duplicate stream is already being
680                                  * included in the output WIM, or it would be
681                                  * filtered out if it had been.  Skip writing
682                                  * this stream (and reading it again) entirely,
683                                  * passing its output reference count to the
684                                  * duplicate stream in the former case.  */
685                                 DEBUG("Discarding duplicate stream of "
686                                       "length %"PRIu64, lte->size);
687                                 do_write_streams_progress(&ctx->progress_data,
688                                                           lte->size, true, lte);
689                                 list_del(&lte->write_streams_list);
690                                 list_del(&lte->lookup_table_list);
691                                 if (lte_new->will_be_in_output_wim)
692                                         lte_new->out_refcnt += lte->out_refcnt;
693                                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS)
694                                         ctx->cur_write_res_size -= lte->size;
695                                 free_lookup_table_entry(lte);
696                                 return BEGIN_STREAM_STATUS_SKIP_STREAM;
697                         } else {
698                                 /* The duplicate stream can validly be written,
699                                  * but was not marked as such.  Discard the
700                                  * current stream entry and use the duplicate,
701                                  * but actually freeing the current entry must
702                                  * wait until read_stream_list() has finished
703                                  * reading its data.  */
704                                 DEBUG("Stream duplicate, but not already "
705                                       "selected for writing.");
706                                 list_replace(&lte->write_streams_list,
707                                              &lte_new->write_streams_list);
708                                 list_replace(&lte->lookup_table_list,
709                                              &lte_new->lookup_table_list);
710                                 lte_new->out_refcnt = lte->out_refcnt;
711                                 lte_new->will_be_in_output_wim = 1;
712                                 ctx->stream_was_duplicate = true;
713                                 lte = lte_new;
714                         }
715                 }
716         }
717         list_move_tail(&lte->write_streams_list, &ctx->pending_streams);
718         return 0;
719 }
720
721 /* Write the next chunk of (typically compressed) data to the output WIM,
722  * handling the writing of the chunk table.  */
723 static int
724 write_chunk(struct write_streams_ctx *ctx, const void *cchunk,
725             size_t csize, size_t usize)
726 {
727         int ret;
728
729         struct wim_lookup_table_entry *lte;
730
731         lte = list_entry(ctx->pending_streams.next,
732                          struct wim_lookup_table_entry, write_streams_list);
733
734         if (ctx->cur_write_res_offset == 0 &&
735             !(ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS))
736         {
737                 /* Starting to write a new stream in non-packed mode.  */
738
739                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
740                         int additional_reshdr_flags = 0;
741                         if (ctx->compressor != NULL)
742                                 additional_reshdr_flags |= WIM_RESHDR_FLAG_COMPRESSED;
743
744                         DEBUG("Writing pipable WIM stream header "
745                               "(offset=%"PRIu64")", ctx->out_fd->offset);
746
747                         ret = write_pwm_stream_header(lte, ctx->out_fd,
748                                                       additional_reshdr_flags);
749                         if (ret)
750                                 return ret;
751                 }
752
753                 ret = begin_write_resource(ctx, lte->size);
754                 if (ret)
755                         return ret;
756         }
757
758         if (ctx->compressor != NULL) {
759                 /* Record the compresed chunk size.  */
760                 wimlib_assert(ctx->chunk_index < ctx->num_alloc_chunks);
761                 ctx->chunk_csizes[ctx->chunk_index++] = csize;
762
763                /* If writing a pipable WIM, before the chunk data write a chunk
764                 * header that provides the compressed chunk size.  */
765                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
766                         struct pwm_chunk_hdr chunk_hdr = {
767                                 .compressed_size = cpu_to_le32(csize),
768                         };
769                         ret = full_write(ctx->out_fd, &chunk_hdr,
770                                          sizeof(chunk_hdr));
771                         if (ret)
772                                 goto error;
773                 }
774         }
775
776         /* Write the chunk data.  */
777         ret = full_write(ctx->out_fd, cchunk, csize);
778         if (ret)
779                 goto error;
780
781         ctx->cur_write_res_offset += usize;
782
783         do_write_streams_progress(&ctx->progress_data,
784                                   usize, false, lte);
785
786         if (ctx->cur_write_res_offset == ctx->cur_write_res_size &&
787             !(ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS))
788         {
789                 struct wim_lookup_table_entry *lte;
790
791                 lte = list_entry(ctx->pending_streams.next,
792                                  struct wim_lookup_table_entry, write_streams_list);
793                 wimlib_assert(ctx->cur_write_res_offset == lte->size);
794
795                 /* Finished writing a stream in non-packed mode.  */
796
797                 ret = end_write_resource(ctx, &lte->out_reshdr);
798                 if (ret)
799                         return ret;
800
801                 wimlib_assert(lte->out_reshdr.uncompressed_size == lte->size);
802
803                 lte->out_reshdr.flags = filter_resource_flags(lte->flags);
804                 if (ctx->compressor != NULL)
805                         lte->out_reshdr.flags |= WIM_RESHDR_FLAG_COMPRESSED;
806
807                 list_del(&lte->write_streams_list);
808                 ctx->cur_write_res_offset = 0;
809         }
810
811         return 0;
812
813 error:
814         ERROR_WITH_ERRNO("Write error");
815         return ret;
816 }
817
818 static int
819 submit_chunk_for_compression(struct write_streams_ctx *ctx,
820                              const void *chunk, size_t size)
821 {
822         /* While we are unable to submit the chunk for compression (due to too
823          * many chunks already outstanding), retrieve and write the next
824          * compressed chunk.  */
825         while (!ctx->compressor->submit_chunk(ctx->compressor, chunk, size)) {
826                 const void *cchunk;
827                 unsigned csize;
828                 unsigned usize;
829                 bool bret;
830                 int ret;
831
832                 bret = ctx->compressor->get_chunk(ctx->compressor,
833                                                   &cchunk, &csize, &usize);
834
835                 wimlib_assert(bret);
836
837                 ret = write_chunk(ctx, cchunk, csize, usize);
838                 if (ret)
839                         return ret;
840         }
841         return 0;
842 }
843
844 /* Process the next chunk of data to be written to a WIM resource.  */
845 static int
846 write_stream_process_chunk(const void *chunk, size_t size, void *_ctx)
847 {
848         struct write_streams_ctx *ctx = _ctx;
849         int ret;
850         const u8 *chunkptr, *chunkend;
851
852         wimlib_assert(size != 0);
853
854         if (ctx->compressor == NULL) {
855                 /* Write chunk uncompressed.  */
856                  ret = write_chunk(ctx, chunk, size, size);
857                  if (ret)
858                          return ret;
859                  ctx->cur_read_res_offset += size;
860                  return 0;
861         }
862
863         /* Submit the chunk for compression, but take into account that the
864          * @size the chunk was provided in may not correspond to the
865          * @out_chunk_size being used for compression.  */
866         chunkptr = chunk;
867         chunkend = chunkptr + size;
868         do {
869                 const u8 *resized_chunk;
870                 size_t needed_chunk_size;
871
872                 if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
873                         needed_chunk_size = ctx->out_chunk_size;
874                 } else {
875                         u64 res_bytes_remaining;
876
877                         res_bytes_remaining = ctx->cur_read_res_size -
878                                               ctx->cur_read_res_offset;
879                         needed_chunk_size = min(ctx->out_chunk_size,
880                                                 ctx->chunk_buf_filled +
881                                                         res_bytes_remaining);
882                 }
883
884                 if (ctx->chunk_buf_filled == 0 &&
885                     chunkend - chunkptr >= needed_chunk_size)
886                 {
887                         /* No intermediate buffering needed.  */
888                         resized_chunk = chunkptr;
889                         chunkptr += needed_chunk_size;
890                         ctx->cur_read_res_offset += needed_chunk_size;
891                 } else {
892                         /* Intermediate buffering needed.  */
893                         size_t bytes_consumed;
894
895                         bytes_consumed = min(chunkend - chunkptr,
896                                              needed_chunk_size - ctx->chunk_buf_filled);
897
898                         memcpy(&ctx->chunk_buf[ctx->chunk_buf_filled],
899                                chunkptr, bytes_consumed);
900
901                         resized_chunk = ctx->chunk_buf;
902
903                         chunkptr += bytes_consumed;
904                         ctx->cur_read_res_offset += bytes_consumed;
905                         ctx->chunk_buf_filled += bytes_consumed;
906                         if (ctx->chunk_buf_filled == needed_chunk_size) {
907                                 resized_chunk = ctx->chunk_buf;
908                                 ctx->chunk_buf_filled = 0;
909                         } else {
910                                 break;
911                         }
912
913                 }
914
915                 ret = submit_chunk_for_compression(ctx, resized_chunk,
916                                                    needed_chunk_size);
917                 if (ret)
918                         return ret;
919
920         } while (chunkptr != chunkend);
921         return 0;
922 }
923
924 /* Finish processing a stream for writing.  It may not have been completely
925  * written yet, as the chunk_compressor implementation may still have chunks
926  * buffered or being compressed.  */
927 static int
928 write_stream_end_read(struct wim_lookup_table_entry *lte, int status, void *_ctx)
929 {
930         struct write_streams_ctx *ctx = _ctx;
931         if (status == 0)
932                 wimlib_assert(ctx->cur_read_res_offset == ctx->cur_read_res_size);
933         if (ctx->stream_was_duplicate) {
934                 free_lookup_table_entry(lte);
935         } else if (lte->unhashed && ctx->lookup_table != NULL) {
936                 list_del(&lte->unhashed_list);
937                 lookup_table_insert(ctx->lookup_table, lte);
938                 lte->unhashed = 0;
939         }
940         return status;
941 }
942
943 /* Compute statistics about a list of streams that will be written.
944  *
945  * Assumes the streams are sorted such that all streams located in each distinct
946  * WIM (specified by WIMStruct) are together.  */
947 static void
948 compute_stream_list_stats(struct list_head *stream_list,
949                           struct write_streams_ctx *ctx)
950 {
951         struct wim_lookup_table_entry *lte;
952         u64 total_bytes = 0;
953         u64 num_streams = 0;
954         u64 total_parts = 0;
955         WIMStruct *prev_wim_part = NULL;
956
957         list_for_each_entry(lte, stream_list, write_streams_list) {
958                 num_streams++;
959                 total_bytes += lte->size;
960                 if (lte->resource_location == RESOURCE_IN_WIM) {
961                         if (prev_wim_part != lte->rspec->wim) {
962                                 prev_wim_part = lte->rspec->wim;
963                                 total_parts++;
964                         }
965                 }
966         }
967         ctx->progress_data.progress.write_streams.total_bytes       = total_bytes;
968         ctx->progress_data.progress.write_streams.total_streams     = num_streams;
969         ctx->progress_data.progress.write_streams.completed_bytes   = 0;
970         ctx->progress_data.progress.write_streams.completed_streams = 0;
971         ctx->progress_data.progress.write_streams.compression_type  = ctx->out_ctype;
972         ctx->progress_data.progress.write_streams.total_parts       = total_parts;
973         ctx->progress_data.progress.write_streams.completed_parts   = 0;
974         ctx->progress_data.next_progress = 0;
975         ctx->progress_data.prev_wim_part = NULL;
976 }
977
978 /* Find streams in @stream_list that can be copied to the output WIM in raw form
979  * rather than compressed.  Delete these streams from @stream_list, and move one
980  * per resource to @raw_copy_resources.  Return the total uncompressed size of
981  * the streams that need to be compressed.  */
982 static u64
983 find_raw_copy_resources(struct list_head *stream_list,
984                         int write_resource_flags,
985                         int out_ctype,
986                         u32 out_chunk_size,
987                         struct list_head *raw_copy_resources)
988 {
989         struct wim_lookup_table_entry *lte, *tmp;
990         u64 num_bytes_to_compress = 0;
991
992         INIT_LIST_HEAD(raw_copy_resources);
993
994         /* Initialize temporary raw_copy_ok flag.  */
995         list_for_each_entry(lte, stream_list, write_streams_list)
996                 if (lte->resource_location == RESOURCE_IN_WIM)
997                         lte->rspec->raw_copy_ok = 0;
998
999         list_for_each_entry_safe(lte, tmp, stream_list, write_streams_list) {
1000                 if (lte->resource_location == RESOURCE_IN_WIM &&
1001                     lte->rspec->raw_copy_ok)
1002                 {
1003                         list_del(&lte->write_streams_list);
1004                 } else if (can_raw_copy(lte, write_resource_flags,
1005                                  out_ctype, out_chunk_size))
1006                 {
1007                         lte->rspec->raw_copy_ok = 1;
1008                         list_move_tail(&lte->write_streams_list,
1009                                        raw_copy_resources);
1010                 } else {
1011                         num_bytes_to_compress += lte->size;
1012                 }
1013         }
1014
1015         return num_bytes_to_compress;
1016 }
1017
1018 /* Copy a raw compressed resource located in another WIM file to the WIM file
1019  * being written.  */
1020 static int
1021 write_raw_copy_resource(struct wim_resource_spec *in_rspec,
1022                         struct filedes *out_fd)
1023 {
1024         u64 cur_read_offset;
1025         u64 end_read_offset;
1026         u8 buf[BUFFER_SIZE];
1027         size_t bytes_to_read;
1028         int ret;
1029         struct filedes *in_fd;
1030         struct wim_lookup_table_entry *lte;
1031         u64 out_offset_in_wim;
1032
1033         DEBUG("Copying raw compressed data (size_in_wim=%"PRIu64", "
1034               "uncompressed_size=%"PRIu64")",
1035               in_rspec->size_in_wim, in_rspec->uncompressed_size);
1036
1037         /* Copy the raw data.  */
1038         cur_read_offset = in_rspec->offset_in_wim;
1039         end_read_offset = cur_read_offset + in_rspec->size_in_wim;
1040
1041         out_offset_in_wim = out_fd->offset;
1042
1043         if (in_rspec->is_pipable) {
1044                 if (cur_read_offset < sizeof(struct pwm_stream_hdr))
1045                         return WIMLIB_ERR_INVALID_PIPABLE_WIM;
1046                 cur_read_offset -= sizeof(struct pwm_stream_hdr);
1047                 out_offset_in_wim += sizeof(struct pwm_stream_hdr);
1048         }
1049         in_fd = &in_rspec->wim->in_fd;
1050         wimlib_assert(cur_read_offset != end_read_offset);
1051         do {
1052
1053                 bytes_to_read = min(sizeof(buf), end_read_offset - cur_read_offset);
1054
1055                 ret = full_pread(in_fd, buf, bytes_to_read, cur_read_offset);
1056                 if (ret)
1057                         return ret;
1058
1059                 ret = full_write(out_fd, buf, bytes_to_read);
1060                 if (ret)
1061                         return ret;
1062
1063                 cur_read_offset += bytes_to_read;
1064
1065         } while (cur_read_offset != end_read_offset);
1066
1067         list_for_each_entry(lte, &in_rspec->stream_list, rspec_node) {
1068                 if (lte->will_be_in_output_wim) {
1069                         stream_set_out_reshdr_for_reuse(lte);
1070                         if (in_rspec->flags & WIM_RESHDR_FLAG_PACKED_STREAMS)
1071                                 lte->out_res_offset_in_wim = out_offset_in_wim;
1072                         else
1073                                 lte->out_reshdr.offset_in_wim = out_offset_in_wim;
1074
1075                 }
1076         }
1077         return 0;
1078 }
1079
1080 /* Copy a list of raw compressed resources located other WIM file(s) to the WIM
1081  * file being written.  */
1082 static int
1083 write_raw_copy_resources(struct list_head *raw_copy_resources,
1084                          struct filedes *out_fd,
1085                          struct write_streams_progress_data *progress_data)
1086 {
1087         struct wim_lookup_table_entry *lte;
1088         int ret;
1089
1090         list_for_each_entry(lte, raw_copy_resources, write_streams_list) {
1091                 ret = write_raw_copy_resource(lte->rspec, out_fd);
1092                 if (ret)
1093                         return ret;
1094                 do_write_streams_progress(progress_data, lte->size, false, lte);
1095         }
1096         return 0;
1097 }
1098
1099 /* Wait for and write all chunks pending in the compressor.  */
1100 static int
1101 finish_remaining_chunks(struct write_streams_ctx *ctx)
1102 {
1103         const void *cdata;
1104         unsigned csize;
1105         unsigned usize;
1106         int ret;
1107
1108         if (ctx->compressor == NULL)
1109                 return 0;
1110
1111         if (ctx->chunk_buf_filled != 0) {
1112                 ret = submit_chunk_for_compression(ctx, ctx->chunk_buf,
1113                                                    ctx->chunk_buf_filled);
1114                 if (ret)
1115                         return ret;
1116         }
1117
1118         while (ctx->compressor->get_chunk(ctx->compressor, &cdata, &csize, &usize)) {
1119                 ret = write_chunk(ctx, cdata, csize, usize);
1120                 if (ret)
1121                         return ret;
1122         }
1123         return 0;
1124 }
1125
1126 static void
1127 remove_zero_length_streams(struct list_head *stream_list)
1128 {
1129         struct wim_lookup_table_entry *lte, *tmp;
1130
1131         list_for_each_entry_safe(lte, tmp, stream_list, write_streams_list) {
1132                 wimlib_assert(lte->will_be_in_output_wim);
1133                 if (lte->size == 0) {
1134                         list_del(&lte->write_streams_list);
1135                         lte->out_reshdr.offset_in_wim = 0;
1136                         lte->out_reshdr.size_in_wim = 0;
1137                         lte->out_reshdr.uncompressed_size = 0;
1138                         lte->out_reshdr.flags = filter_resource_flags(lte->flags);
1139                 }
1140         }
1141 }
1142
1143 /*
1144  * Write a list of streams to the output WIM file.
1145  *
1146  * @stream_list
1147  *      The list of streams to write, specifies a list of `struct
1148  *      wim_lookup_table_entry's linked by the 'write_streams_list' member.
1149  *
1150  * @out_fd
1151  *      The file descriptor, opened for writing, to which to write the streams.
1152  *
1153  * @write_resource_flags
1154  *      Flags to modify how the streams are written:
1155  *
1156  *      WRITE_RESOURCE_FLAG_RECOMPRESS:
1157  *              Force compression of all resources, even if they could otherwise
1158  *              be re-used by caping the raw data, due to being located in a WIM
1159  *              file with compatible compression parameters.
1160  *
1161  *      WRITE_RESOURCE_FLAG_PIPABLE:
1162  *              Write the resources in the wimlib-specific pipable format, and
1163  *              furthermore do so in such a way that no seeking backwards in
1164  *              @out_fd will be performed (so it may be a pipe, contrary to the
1165  *              default behavior).
1166  *
1167  *      WRITE_RESOURCE_FLAG_PACK_STREAMS:
1168  *              Pack all the streams into a single resource rather than writing
1169  *              them in separate resources.  This format is only valid if the
1170  *              WIM version number is WIM_VERSION_PACKED_STREAMS.  This flag
1171  *              currently may not be combined with WRITE_RESOURCE_FLAG_PIPABLE.
1172  *
1173  * @out_ctype
1174  *      Compression format to use to write the output streams, specified as one
1175  *      of the WIMLIB_COMPRESSION_TYPE_* constants, excepting
1176  *      WIMLIB_COMPRESSION_TYPE_INVALID but including
1177  *      WIMLIB_COMPRESSION_TYPE_NONE.
1178  *
1179  * @out_chunk_size
1180  *      Chunk size to use to write the streams.  It must be a valid chunk size
1181  *      for the specified compression format @out_ctype, unless @out_ctype is
1182  *      WIMLIB_COMPRESSION_TYPE_NONE, in which case this parameter is ignored.
1183  *
1184  * @num_threads
1185  *      Number of threads to use to compress data.  If 0, a default number of
1186  *      threads will be chosen.  The number of threads still may be decreased
1187  *      from the specified value if insufficient memory is detected.
1188  *
1189  * @lookup_table
1190  *      If on-the-fly deduplication of unhashed streams is desired, this
1191  *      parameter must be pointer to the lookup table for the WIMStruct on whose
1192  *      behalf the streams are being written.  Otherwise, this parameter can be
1193  *      NULL.
1194  *
1195  * @filter_ctx
1196  *      If on-the-fly deduplication of unhashed streams is desired, this
1197  *      parameter can be a pointer to a context for stream filtering used to
1198  *      detect whether the duplicate stream has been hard-filtered or not.  If
1199  *      no streams are hard-filtered or no streams are unhashed, this parameter
1200  *      can be NULL.
1201  *
1202  * @progress_func
1203  *      If non-NULL, a progress function that will be called periodically with
1204  *      WIMLIB_PROGRESS_MSG_WRITE_STREAMS messages.  Note that on-the-fly
1205  *      deduplication of unhashed streams may result in the total bytes provided
1206  *      in the progress data to decrease from one message to the next.
1207  *
1208  * This function will write the streams in @stream_list to resources in
1209  * consecutive positions in the output WIM file, or to a single packed resource
1210  * if WRITE_RESOURCE_FLAG_PACK_STREAMS was specified in @write_resource_flags.
1211  * In both cases, the @out_reshdr of the `struct wim_lookup_table_entry' for
1212  * each stream written will be updated to specify its location, size, and flags
1213  * in the output WIM.  In the packed resource case,
1214  * WIM_RESHDR_FLAG_PACKED_STREAMS shall be set in the @flags field of the
1215  * @out_reshdr, and @out_res_offset_in_wim and @out_res_size_in_wim will also
1216  * be set to the offset and size, respectively, in the output WIM of the full
1217  * packed resource containing the corresponding stream.
1218  *
1219  * Each of the streams to write may be in any location supported by the
1220  * resource-handling code (specifically, read_stream_list()), such as the
1221  * contents of external file that has been logically added to the output WIM, or
1222  * a stream in another WIM file that has been imported, or even stream in the
1223  * "same" WIM file of which a modified copy is being written.  In the case that
1224  * a stream is already in a WIM file and uses compatible compression parameters,
1225  * by default this function will re-use the raw data instead of decompressing
1226  * it, then recompressing it; however, with WRITE_RESOURCE_FLAG_RECOMPRESS
1227  * specified in @write_resource_flags, this is not done.
1228  *
1229  * As a further requirement, this function requires that the
1230  * @will_be_in_output_wim member be set on all streams in @stream_list as well
1231  * as any other streams not in @stream_list that will be in the output WIM file,
1232  * but not on any other streams in the output WIM's lookup table or sharing a
1233  * packed resource with a stream in @stream_list.  Still furthermore, if
1234  * on-the-fly deduplication of streams is possible, then all streams in
1235  * @stream_list must also be linked by @lookup_table_list along with any other
1236  * streams that have @will_be_in_output_wim set.
1237  *
1238  * This function handles on-the-fly deduplication of streams for which SHA1
1239  * message digests have not yet been calculated and it is therefore known
1240  * whether such streams are already in @stream_list or in the WIM's lookup table
1241  * at all.  If @lookup_table is non-NULL, then each stream in @stream_list that
1242  * has @unhashed set but not @unique_size set is checksummed immediately before
1243  * it would otherwise be read for writing in order to determine if it is
1244  * identical to another stream already being written or one that would be
1245  * filtered out of the output WIM using stream_filtered() with the context
1246  * @filter_ctx.  Each such duplicate stream will be removed from @stream_list, its
1247  * reference count transfered to the pre-existing duplicate stream, its memory
1248  * freed, and will not be written.  Alternatively, if a stream in @stream_list
1249  * is a duplicate with any stream in @lookup_table that has not been marked for
1250  * writing or would not be hard-filtered, it is freed and the pre-existing
1251  * duplicate is written instead, taking ownership of the reference count and
1252  * slot in the @lookup_table_list.
1253  *
1254  * Returns 0 if all streams were written successfully (or did not need to be
1255  * written); otherwise a non-zero error code.
1256  */
1257 static int
1258 write_stream_list(struct list_head *stream_list,
1259                   struct filedes *out_fd,
1260                   int write_resource_flags,
1261                   int out_ctype,
1262                   u32 out_chunk_size,
1263                   unsigned num_threads,
1264                   struct wim_lookup_table *lookup_table,
1265                   struct filter_context *filter_ctx,
1266                   wimlib_progress_func_t progress_func)
1267 {
1268         int ret;
1269         struct write_streams_ctx ctx;
1270         struct list_head raw_copy_resources;
1271
1272         wimlib_assert((write_resource_flags &
1273                        (WRITE_RESOURCE_FLAG_PACK_STREAMS |
1274                         WRITE_RESOURCE_FLAG_PIPABLE)) !=
1275                                 (WRITE_RESOURCE_FLAG_PACK_STREAMS |
1276                                  WRITE_RESOURCE_FLAG_PIPABLE));
1277
1278         remove_zero_length_streams(stream_list);
1279
1280         if (list_empty(stream_list)) {
1281                 DEBUG("No streams to write.");
1282                 return 0;
1283         }
1284
1285         memset(&ctx, 0, sizeof(ctx));
1286
1287         /* Pre-sorting the streams is required for compute_stream_list_stats().
1288          * Afterwards, read_stream_list() need not sort them again.  */
1289         ret = sort_stream_list_by_sequential_order(stream_list,
1290                                                    offsetof(struct wim_lookup_table_entry,
1291                                                             write_streams_list));
1292         if (ret)
1293                 return ret;
1294
1295         ctx.out_fd = out_fd;
1296         ctx.lookup_table = lookup_table;
1297         ctx.out_ctype = out_ctype;
1298         ctx.out_chunk_size = out_chunk_size;
1299         ctx.write_resource_flags = write_resource_flags;
1300         ctx.filter_ctx = filter_ctx;
1301
1302         if (out_chunk_size != 0) {
1303                 if (out_chunk_size <= STACK_MAX) {
1304                         ctx.chunk_buf = alloca(out_chunk_size);
1305                 } else {
1306                         ctx.chunk_buf = MALLOC(out_chunk_size);
1307                         if (ctx.chunk_buf == NULL) {
1308                                 ret = WIMLIB_ERR_NOMEM;
1309                                 goto out_destroy_context;
1310                         }
1311                 }
1312         }
1313         ctx.chunk_buf_filled = 0;
1314
1315         compute_stream_list_stats(stream_list, &ctx);
1316
1317         ctx.progress_data.progress_func = progress_func;
1318
1319         ctx.num_bytes_to_compress = find_raw_copy_resources(stream_list,
1320                                                             write_resource_flags,
1321                                                             out_ctype,
1322                                                             out_chunk_size,
1323                                                             &raw_copy_resources);
1324
1325         DEBUG("Writing stream list "
1326               "(offset = %"PRIu64", write_resource_flags=0x%08x, "
1327               "out_ctype=%d, out_chunk_size=%u, num_threads=%u, "
1328               "total_bytes=%"PRIu64", num_bytes_to_compress=%"PRIu64")",
1329               out_fd->offset, write_resource_flags,
1330               out_ctype, out_chunk_size, num_threads,
1331               ctx.progress_data.progress.write_streams.total_bytes,
1332               ctx.num_bytes_to_compress);
1333
1334         if (ctx.num_bytes_to_compress == 0) {
1335                 DEBUG("No compression needed; skipping to raw copy!");
1336                 goto out_write_raw_copy_resources;
1337         }
1338
1339         /* Unless uncompressed output was required, allocate a chunk_compressor
1340          * to do compression.  There are serial and parallel implementations of
1341          * the chunk_compressor interface.  We default to parallel using the
1342          * specified number of threads, unless the upper bound on the number
1343          * bytes needing to be compressed is less 2000000 (heuristic value).  */
1344         if (out_ctype != WIMLIB_COMPRESSION_TYPE_NONE) {
1345
1346                 if (out_ctype == WIMLIB_COMPRESSION_TYPE_LZMS &&
1347                     ctx.lookup_table != NULL) {
1348                         WARNING("LZMS compression not implemented; data will "
1349                                 "actually be written uncompressed.");
1350                 }
1351
1352                 if (ctx.num_bytes_to_compress >= 2000000) {
1353                         ret = new_parallel_chunk_compressor(out_ctype,
1354                                                             out_chunk_size,
1355                                                             num_threads, 0,
1356                                                             &ctx.compressor);
1357                         if (ret) {
1358                                 DEBUG("Couldn't create parallel chunk compressor "
1359                                       "(status %d)", ret);
1360                         }
1361                 }
1362
1363                 if (ctx.compressor == NULL) {
1364                         ret = new_serial_chunk_compressor(out_ctype, out_chunk_size,
1365                                                           &ctx.compressor);
1366                         if (ret)
1367                                 goto out_destroy_context;
1368                 }
1369         }
1370
1371         if (ctx.compressor)
1372                 ctx.progress_data.progress.write_streams.num_threads = ctx.compressor->num_threads;
1373         else
1374                 ctx.progress_data.progress.write_streams.num_threads = 1;
1375
1376         DEBUG("Actually using %u threads",
1377               ctx.progress_data.progress.write_streams.num_threads);
1378
1379         INIT_LIST_HEAD(&ctx.pending_streams);
1380
1381         if (ctx.progress_data.progress_func) {
1382                 (*ctx.progress_data.progress_func)(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
1383                                                    &ctx.progress_data.progress);
1384         }
1385
1386         if (write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
1387                 ret = begin_write_resource(&ctx, ctx.num_bytes_to_compress);
1388                 if (ret)
1389                         goto out_destroy_context;
1390         }
1391
1392         /* Read the list of streams needing to be compressed, using the
1393          * specified callbacks to execute processing of the data.  */
1394
1395         struct read_stream_list_callbacks cbs = {
1396                 .begin_stream           = write_stream_begin_read,
1397                 .begin_stream_ctx       = &ctx,
1398                 .consume_chunk          = write_stream_process_chunk,
1399                 .consume_chunk_ctx      = &ctx,
1400                 .end_stream             = write_stream_end_read,
1401                 .end_stream_ctx         = &ctx,
1402         };
1403
1404         ret = read_stream_list(stream_list,
1405                                offsetof(struct wim_lookup_table_entry, write_streams_list),
1406                                &cbs,
1407                                STREAM_LIST_ALREADY_SORTED |
1408                                         VERIFY_STREAM_HASHES |
1409                                         COMPUTE_MISSING_STREAM_HASHES);
1410
1411         if (ret)
1412                 goto out_destroy_context;
1413
1414         ret = finish_remaining_chunks(&ctx);
1415         if (ret)
1416                 goto out_destroy_context;
1417
1418         if (write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) {
1419                 struct wim_reshdr reshdr;
1420                 struct wim_lookup_table_entry *lte;
1421                 u64 offset_in_res;
1422
1423                 ret = end_write_resource(&ctx, &reshdr);
1424                 if (ret)
1425                         goto out_destroy_context;
1426
1427                 DEBUG("Ending packed resource: %lu %lu %lu.",
1428                       reshdr.offset_in_wim,
1429                       reshdr.size_in_wim,
1430                       reshdr.uncompressed_size);
1431
1432                 offset_in_res = 0;
1433                 list_for_each_entry(lte, &ctx.pending_streams, write_streams_list) {
1434                         lte->out_reshdr.size_in_wim = lte->size;
1435                         lte->out_reshdr.flags = filter_resource_flags(lte->flags);
1436                         lte->out_reshdr.flags |= WIM_RESHDR_FLAG_PACKED_STREAMS;
1437                         lte->out_reshdr.uncompressed_size = 0;
1438                         lte->out_reshdr.offset_in_wim = offset_in_res;
1439                         lte->out_res_offset_in_wim = reshdr.offset_in_wim;
1440                         lte->out_res_size_in_wim = reshdr.size_in_wim;
1441                         /*lte->out_res_uncompressed_size = reshdr.uncompressed_size;*/
1442                         offset_in_res += lte->size;
1443                 }
1444                 wimlib_assert(offset_in_res == reshdr.uncompressed_size);
1445         }
1446
1447 out_write_raw_copy_resources:
1448         /* Copy any compressed resources for which the raw data can be reused
1449          * without decompression.  */
1450         ret = write_raw_copy_resources(&raw_copy_resources, ctx.out_fd,
1451                                        &ctx.progress_data);
1452
1453 out_destroy_context:
1454         if (out_chunk_size > STACK_MAX)
1455                 FREE(ctx.chunk_buf);
1456         FREE(ctx.chunk_csizes);
1457         if (ctx.compressor)
1458                 ctx.compressor->destroy(ctx.compressor);
1459         DEBUG("Done (ret=%d)", ret);
1460         return ret;
1461 }
1462
1463 static int
1464 write_wim_resource(struct wim_lookup_table_entry *lte,
1465                    struct filedes *out_fd,
1466                    int out_ctype,
1467                    u32 out_chunk_size,
1468                    int write_resource_flags)
1469 {
1470         LIST_HEAD(stream_list);
1471         list_add(&lte->write_streams_list, &stream_list);
1472         lte->will_be_in_output_wim = 1;
1473         return write_stream_list(&stream_list,
1474                                  out_fd,
1475                                  write_resource_flags & ~WRITE_RESOURCE_FLAG_PACK_STREAMS,
1476                                  out_ctype,
1477                                  out_chunk_size,
1478                                  1,
1479                                  NULL,
1480                                  NULL,
1481                                  NULL);
1482 }
1483
1484 int
1485 write_wim_resource_from_buffer(const void *buf, size_t buf_size,
1486                                int reshdr_flags, struct filedes *out_fd,
1487                                int out_ctype,
1488                                u32 out_chunk_size,
1489                                struct wim_reshdr *out_reshdr,
1490                                u8 *hash,
1491                                int write_resource_flags)
1492 {
1493         int ret;
1494         struct wim_lookup_table_entry *lte;
1495
1496         /* Set up a temporary lookup table entry to provide to
1497          * write_wim_resource().  */
1498
1499         lte = new_lookup_table_entry();
1500         if (lte == NULL)
1501                 return WIMLIB_ERR_NOMEM;
1502
1503         lte->resource_location  = RESOURCE_IN_ATTACHED_BUFFER;
1504         lte->attached_buffer    = (void*)buf;
1505         lte->size               = buf_size;
1506         lte->flags              = reshdr_flags;
1507
1508         if (write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) {
1509                 sha1_buffer(buf, buf_size, lte->hash);
1510                 lte->unhashed = 0;
1511         } else {
1512                 lte->unhashed = 1;
1513         }
1514
1515         ret = write_wim_resource(lte, out_fd, out_ctype, out_chunk_size,
1516                                  write_resource_flags);
1517         if (ret)
1518                 goto out_free_lte;
1519
1520         copy_reshdr(out_reshdr, &lte->out_reshdr);
1521
1522         if (hash)
1523                 copy_hash(hash, lte->hash);
1524         ret = 0;
1525 out_free_lte:
1526         lte->resource_location = RESOURCE_NONEXISTENT;
1527         free_lookup_table_entry(lte);
1528         return ret;
1529 }
1530
1531 struct stream_size_table {
1532         struct hlist_head *array;
1533         size_t num_entries;
1534         size_t capacity;
1535 };
1536
1537 static int
1538 init_stream_size_table(struct stream_size_table *tab, size_t capacity)
1539 {
1540         tab->array = CALLOC(capacity, sizeof(tab->array[0]));
1541         if (tab->array == NULL)
1542                 return WIMLIB_ERR_NOMEM;
1543         tab->num_entries = 0;
1544         tab->capacity = capacity;
1545         return 0;
1546 }
1547
1548 static void
1549 destroy_stream_size_table(struct stream_size_table *tab)
1550 {
1551         FREE(tab->array);
1552 }
1553
1554 static int
1555 stream_size_table_insert(struct wim_lookup_table_entry *lte, void *_tab)
1556 {
1557         struct stream_size_table *tab = _tab;
1558         size_t pos;
1559         struct wim_lookup_table_entry *same_size_lte;
1560         struct hlist_node *tmp;
1561
1562         pos = hash_u64(lte->size) % tab->capacity;
1563         lte->unique_size = 1;
1564         hlist_for_each_entry(same_size_lte, tmp, &tab->array[pos], hash_list_2) {
1565                 if (same_size_lte->size == lte->size) {
1566                         lte->unique_size = 0;
1567                         same_size_lte->unique_size = 0;
1568                         break;
1569                 }
1570         }
1571
1572         hlist_add_head(&lte->hash_list_2, &tab->array[pos]);
1573         tab->num_entries++;
1574         return 0;
1575 }
1576
1577 struct find_streams_ctx {
1578         WIMStruct *wim;
1579         int write_flags;
1580         struct list_head stream_list;
1581         struct stream_size_table stream_size_tab;
1582 };
1583
1584 static void
1585 reference_stream_for_write(struct wim_lookup_table_entry *lte,
1586                            struct list_head *stream_list, u32 nref)
1587 {
1588         if (!lte->will_be_in_output_wim) {
1589                 lte->out_refcnt = 0;
1590                 list_add_tail(&lte->write_streams_list, stream_list);
1591                 lte->will_be_in_output_wim = 1;
1592         }
1593         lte->out_refcnt += nref;
1594 }
1595
1596 static int
1597 fully_reference_stream_for_write(struct wim_lookup_table_entry *lte,
1598                                  void *_stream_list)
1599 {
1600         struct list_head *stream_list = _stream_list;
1601         lte->will_be_in_output_wim = 0;
1602         reference_stream_for_write(lte, stream_list, lte->refcnt);
1603         return 0;
1604 }
1605
1606 static int
1607 inode_find_streams_to_reference(const struct wim_inode *inode,
1608                                 const struct wim_lookup_table *table,
1609                                 struct list_head *stream_list)
1610 {
1611         struct wim_lookup_table_entry *lte;
1612         unsigned i;
1613
1614         wimlib_assert(inode->i_nlink > 0);
1615
1616         for (i = 0; i <= inode->i_num_ads; i++) {
1617                 lte = inode_stream_lte(inode, i, table);
1618                 if (lte)
1619                         reference_stream_for_write(lte, stream_list,
1620                                                    inode->i_nlink);
1621                 else if (!is_zero_hash(inode_stream_hash(inode, i)))
1622                         return WIMLIB_ERR_RESOURCE_NOT_FOUND;
1623         }
1624         return 0;
1625 }
1626
1627 static int
1628 do_stream_set_not_in_output_wim(struct wim_lookup_table_entry *lte, void *_ignore)
1629 {
1630         lte->will_be_in_output_wim = 0;
1631         return 0;
1632 }
1633
1634 static int
1635 image_find_streams_to_reference(WIMStruct *wim)
1636 {
1637         struct wim_image_metadata *imd;
1638         struct wim_inode *inode;
1639         struct wim_lookup_table_entry *lte;
1640         struct list_head *stream_list;
1641         int ret;
1642
1643         imd = wim_get_current_image_metadata(wim);
1644
1645         image_for_each_unhashed_stream(lte, imd)
1646                 lte->will_be_in_output_wim = 0;
1647
1648         stream_list = wim->private;
1649         image_for_each_inode(inode, imd) {
1650                 ret = inode_find_streams_to_reference(inode,
1651                                                       wim->lookup_table,
1652                                                       stream_list);
1653                 if (ret)
1654                         return ret;
1655         }
1656         return 0;
1657 }
1658
1659 static int
1660 prepare_unfiltered_list_of_streams_in_output_wim(WIMStruct *wim,
1661                                                  int image,
1662                                                  int streams_ok,
1663                                                  struct list_head *stream_list_ret)
1664 {
1665         int ret;
1666
1667         INIT_LIST_HEAD(stream_list_ret);
1668
1669         if (streams_ok && (image == WIMLIB_ALL_IMAGES ||
1670                            (image == 1 && wim->hdr.image_count == 1)))
1671         {
1672                 /* Fast case:  Assume that all streams are being written and
1673                  * that the reference counts are correct.  */
1674                 struct wim_lookup_table_entry *lte;
1675                 struct wim_image_metadata *imd;
1676                 unsigned i;
1677
1678                 for_lookup_table_entry(wim->lookup_table,
1679                                        fully_reference_stream_for_write,
1680                                        stream_list_ret);
1681
1682                 for (i = 0; i < wim->hdr.image_count; i++) {
1683                         imd = wim->image_metadata[i];
1684                         image_for_each_unhashed_stream(lte, imd)
1685                                 fully_reference_stream_for_write(lte, stream_list_ret);
1686                 }
1687         } else {
1688                 /* Slow case:  Walk through the images being written and
1689                  * determine the streams referenced.  */
1690                 for_lookup_table_entry(wim->lookup_table,
1691                                        do_stream_set_not_in_output_wim, NULL);
1692                 wim->private = stream_list_ret;
1693                 ret = for_image(wim, image, image_find_streams_to_reference);
1694                 if (ret)
1695                         return ret;
1696         }
1697
1698         return 0;
1699 }
1700
1701 struct insert_other_if_hard_filtered_ctx {
1702         struct stream_size_table *tab;
1703         struct filter_context *filter_ctx;
1704 };
1705
1706 static int
1707 insert_other_if_hard_filtered(struct wim_lookup_table_entry *lte, void *_ctx)
1708 {
1709         struct insert_other_if_hard_filtered_ctx *ctx = _ctx;
1710
1711         if (!lte->will_be_in_output_wim &&
1712             stream_hard_filtered(lte, ctx->filter_ctx))
1713                 stream_size_table_insert(lte, ctx->tab);
1714         return 0;
1715 }
1716
1717 static int
1718 determine_stream_size_uniquity(struct list_head *stream_list,
1719                                struct wim_lookup_table *lt,
1720                                struct filter_context *filter_ctx)
1721 {
1722         int ret;
1723         struct stream_size_table tab;
1724         struct wim_lookup_table_entry *lte;
1725
1726         ret = init_stream_size_table(&tab, lt->capacity);
1727         if (ret)
1728                 return ret;
1729
1730         if (may_hard_filter_streams(filter_ctx)) {
1731                 struct insert_other_if_hard_filtered_ctx ctx = {
1732                         .tab = &tab,
1733                         .filter_ctx = filter_ctx,
1734                 };
1735                 for_lookup_table_entry(lt, insert_other_if_hard_filtered, &ctx);
1736         }
1737
1738         list_for_each_entry(lte, stream_list, write_streams_list)
1739                 stream_size_table_insert(lte, &tab);
1740
1741         destroy_stream_size_table(&tab);
1742         return 0;
1743 }
1744
1745 static void
1746 filter_stream_list_for_write(struct list_head *stream_list,
1747                              struct filter_context *filter_ctx)
1748 {
1749         struct wim_lookup_table_entry *lte, *tmp;
1750
1751         list_for_each_entry_safe(lte, tmp,
1752                                  stream_list, write_streams_list)
1753         {
1754                 int status = stream_filtered(lte, filter_ctx);
1755
1756                 if (status == 0) {
1757                         /* Not filtered.  */
1758                         continue;
1759                 } else {
1760                         if (status > 0) {
1761                                 /* Soft filtered.  */
1762                         } else {
1763                                 /* Hard filtered.  */
1764                                 lte->will_be_in_output_wim = 0;
1765                                 list_del(&lte->lookup_table_list);
1766                         }
1767                         list_del(&lte->write_streams_list);
1768                 }
1769         }
1770 }
1771
1772 /*
1773  * prepare_stream_list_for_write() -
1774  *
1775  * Prepare the list of streams to write for writing a WIM containing the
1776  * specified image(s) with the specified write flags.
1777  *
1778  * @wim
1779  *      The WIMStruct on whose behalf the write is occurring.
1780  *
1781  * @image
1782  *      Image(s) from the WIM to write; may be WIMLIB_ALL_IMAGES.
1783  *
1784  * @write_flags
1785  *      WIMLIB_WRITE_FLAG_* flags for the write operation:
1786  *
1787  *      STREAMS_OK:  For writes of all images, assume that all streams in the
1788  *      lookup table of @wim and the per-image lists of unhashed streams should
1789  *      be taken as-is, and image metadata should not be searched for
1790  *      references.  This does not exclude filtering with OVERWRITE and
1791  *      SKIP_EXTERNAL_WIMS, below.
1792  *
1793  *      OVERWRITE:  Streams already present in @wim shall not be returned in
1794  *      @stream_list_ret.
1795  *
1796  *      SKIP_EXTERNAL_WIMS:  Streams already present in a WIM file, but not
1797  *      @wim, shall be be returned in neither @stream_list_ret nor
1798  *      @lookup_table_list_ret.
1799  *
1800  * @stream_list_ret
1801  *      List of streams, linked by write_streams_list, that need to be written
1802  *      will be returned here.
1803  *
1804  *      Note that this function assumes that unhashed streams will be written;
1805  *      it does not take into account that they may become duplicates when
1806  *      actually hashed.
1807  *
1808  * @lookup_table_list_ret
1809  *      List of streams, linked by lookup_table_list, that need to be included
1810  *      in the WIM's lookup table will be returned here.  This will be a
1811  *      superset of the streams in @stream_list_ret.
1812  *
1813  *      This list will be a proper superset of @stream_list_ret if and only if
1814  *      WIMLIB_WRITE_FLAG_OVERWRITE was specified in @write_flags and some of
1815  *      the streams that would otherwise need to be written were already located
1816  *      in the WIM file.
1817  *
1818  *      All streams in this list will have @out_refcnt set to the number of
1819  *      references to the stream in the output WIM.  If
1820  *      WIMLIB_WRITE_FLAG_STREAMS_OK was specified in @write_flags, @out_refcnt
1821  *      may be as low as 0.
1822  *
1823  * @filter_ctx_ret
1824  *      A context for queries of stream filter status with stream_filtered() is
1825  *      returned in this location.
1826  *
1827  * In addition, @will_be_in_output_wim will be set to 1 in all stream entries
1828  * inserted into @lookup_table_list_ret and to 0 in all stream entries in the
1829  * lookup table of @wim not inserted into @lookup_table_list_ret.
1830  *
1831  * Still furthermore, @unique_size will be set to 1 on all stream entries in
1832  * @stream_list_ret that have unique size among all stream entries in
1833  * @stream_list_ret and among all stream entries in the lookup table of @wim
1834  * that are ineligible for being written due to filtering.
1835  *
1836  * Returns 0 on success; nonzero on read error, memory allocation error, or
1837  * otherwise.
1838  */
1839 static int
1840 prepare_stream_list_for_write(WIMStruct *wim, int image,
1841                               int write_flags,
1842                               struct list_head *stream_list_ret,
1843                               struct list_head *lookup_table_list_ret,
1844                               struct filter_context *filter_ctx_ret)
1845 {
1846         int ret;
1847         struct wim_lookup_table_entry *lte;
1848
1849         filter_ctx_ret->write_flags = write_flags;
1850         filter_ctx_ret->wim = wim;
1851
1852         ret = prepare_unfiltered_list_of_streams_in_output_wim(
1853                                 wim,
1854                                 image,
1855                                 write_flags & WIMLIB_WRITE_FLAG_STREAMS_OK,
1856                                 stream_list_ret);
1857         if (ret)
1858                 return ret;
1859
1860         INIT_LIST_HEAD(lookup_table_list_ret);
1861         list_for_each_entry(lte, stream_list_ret, write_streams_list)
1862                 list_add_tail(&lte->lookup_table_list, lookup_table_list_ret);
1863
1864         ret = determine_stream_size_uniquity(stream_list_ret, wim->lookup_table,
1865                                              filter_ctx_ret);
1866         if (ret)
1867                 return ret;
1868
1869         if (may_filter_streams(filter_ctx_ret))
1870                 filter_stream_list_for_write(stream_list_ret, filter_ctx_ret);
1871
1872         return 0;
1873 }
1874
1875 static int
1876 write_wim_streams(WIMStruct *wim, int image, int write_flags,
1877                   unsigned num_threads,
1878                   wimlib_progress_func_t progress_func,
1879                   struct list_head *stream_list_override,
1880                   struct list_head *lookup_table_list_ret)
1881 {
1882         int ret;
1883         struct list_head _stream_list;
1884         struct list_head *stream_list;
1885         struct wim_lookup_table_entry *lte;
1886         struct filter_context _filter_ctx;
1887         struct filter_context *filter_ctx;
1888
1889         if (stream_list_override == NULL) {
1890                 /* Normal case: prepare stream list from image(s) being written.
1891                  */
1892                 stream_list = &_stream_list;
1893                 filter_ctx = &_filter_ctx;
1894                 ret = prepare_stream_list_for_write(wim, image, write_flags,
1895                                                     stream_list,
1896                                                     lookup_table_list_ret,
1897                                                     filter_ctx);
1898                 if (ret)
1899                         return ret;
1900         } else {
1901                 /* Currently only as a result of wimlib_split() being called:
1902                  * use stream list already explicitly provided.  Use existing
1903                  * reference counts.  */
1904                 stream_list = stream_list_override;
1905                 filter_ctx = NULL;
1906                 INIT_LIST_HEAD(lookup_table_list_ret);
1907                 list_for_each_entry(lte, stream_list, write_streams_list) {
1908                         lte->out_refcnt = lte->refcnt;
1909                         lte->will_be_in_output_wim = 1;
1910                         lte->unique_size = 0;
1911                         list_add_tail(&lte->lookup_table_list, lookup_table_list_ret);
1912                 }
1913         }
1914
1915         return write_stream_list(stream_list,
1916                                  &wim->out_fd,
1917                                  write_flags_to_resource_flags(write_flags),
1918                                  wim->out_compression_type,
1919                                  wim->out_chunk_size,
1920                                  num_threads,
1921                                  wim->lookup_table,
1922                                  filter_ctx,
1923                                  progress_func);
1924 }
1925
1926 static int
1927 write_wim_metadata_resources(WIMStruct *wim, int image, int write_flags,
1928                              wimlib_progress_func_t progress_func)
1929 {
1930         int ret;
1931         int start_image;
1932         int end_image;
1933         int write_resource_flags;
1934
1935         if (write_flags & WIMLIB_WRITE_FLAG_NO_METADATA) {
1936                 DEBUG("Not writing any metadata resources.");
1937                 return 0;
1938         }
1939
1940         write_resource_flags = write_flags_to_resource_flags(write_flags);
1941
1942         write_resource_flags &= ~WRITE_RESOURCE_FLAG_PACK_STREAMS;
1943
1944         DEBUG("Writing metadata resources (offset=%"PRIu64")",
1945               wim->out_fd.offset);
1946
1947         if (progress_func)
1948                 progress_func(WIMLIB_PROGRESS_MSG_WRITE_METADATA_BEGIN, NULL);
1949
1950         if (image == WIMLIB_ALL_IMAGES) {
1951                 start_image = 1;
1952                 end_image = wim->hdr.image_count;
1953         } else {
1954                 start_image = image;
1955                 end_image = image;
1956         }
1957
1958         for (int i = start_image; i <= end_image; i++) {
1959                 struct wim_image_metadata *imd;
1960
1961                 imd = wim->image_metadata[i - 1];
1962                 /* Build a new metadata resource only if image was modified from
1963                  * the original (or was newly added).  Otherwise just copy the
1964                  * existing one.  */
1965                 if (imd->modified) {
1966                         DEBUG("Image %u was modified; building and writing new "
1967                               "metadata resource", i);
1968                         ret = write_metadata_resource(wim, i,
1969                                                       write_resource_flags);
1970                 } else if (write_flags & WIMLIB_WRITE_FLAG_OVERWRITE) {
1971                         DEBUG("Image %u was not modified; re-using existing "
1972                               "metadata resource.", i);
1973                         stream_set_out_reshdr_for_reuse(imd->metadata_lte);
1974                         ret = 0;
1975                 } else {
1976                         DEBUG("Image %u was not modified; copying existing "
1977                               "metadata resource.", i);
1978                         ret = write_wim_resource(imd->metadata_lte,
1979                                                  &wim->out_fd,
1980                                                  wim->out_compression_type,
1981                                                  wim->out_chunk_size,
1982                                                  write_resource_flags);
1983                 }
1984                 if (ret)
1985                         return ret;
1986         }
1987         if (progress_func)
1988                 progress_func(WIMLIB_PROGRESS_MSG_WRITE_METADATA_END, NULL);
1989         return 0;
1990 }
1991
1992 static int
1993 open_wim_writable(WIMStruct *wim, const tchar *path, int open_flags)
1994 {
1995         int raw_fd;
1996         DEBUG("Opening \"%"TS"\" for writing.", path);
1997
1998         raw_fd = topen(path, open_flags | O_BINARY, 0644);
1999         if (raw_fd < 0) {
2000                 ERROR_WITH_ERRNO("Failed to open \"%"TS"\" for writing", path);
2001                 return WIMLIB_ERR_OPEN;
2002         }
2003         filedes_init(&wim->out_fd, raw_fd);
2004         return 0;
2005 }
2006
2007 static int
2008 close_wim_writable(WIMStruct *wim, int write_flags)
2009 {
2010         int ret = 0;
2011
2012         if (!(write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)) {
2013                 DEBUG("Closing WIM file.");
2014                 if (filedes_valid(&wim->out_fd))
2015                         if (filedes_close(&wim->out_fd))
2016                                 ret = WIMLIB_ERR_WRITE;
2017         }
2018         filedes_invalidate(&wim->out_fd);
2019         return ret;
2020 }
2021
2022 static int
2023 cmp_streams_by_out_rspec(const void *p1, const void *p2)
2024 {
2025         const struct wim_lookup_table_entry *lte1, *lte2;
2026
2027         lte1 = *(const struct wim_lookup_table_entry**)p1;
2028         lte2 = *(const struct wim_lookup_table_entry**)p2;
2029
2030         if (lte1->out_reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) {
2031                 if (lte2->out_reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS) {
2032                         if (lte1->out_res_offset_in_wim != lte2->out_res_offset_in_wim)
2033                                 return cmp_u64(lte1->out_res_offset_in_wim,
2034                                                lte2->out_res_offset_in_wim);
2035                 } else {
2036                         return 1;
2037                 }
2038         } else {
2039                 if (lte2->out_reshdr.flags & WIM_RESHDR_FLAG_PACKED_STREAMS)
2040                         return -1;
2041         }
2042         return cmp_u64(lte1->out_reshdr.offset_in_wim,
2043                        lte2->out_reshdr.offset_in_wim);
2044 }
2045
2046 static int
2047 write_wim_lookup_table(WIMStruct *wim, int image, int write_flags,
2048                        struct wim_reshdr *out_reshdr,
2049                        struct list_head *lookup_table_list)
2050 {
2051         int ret;
2052
2053         /* Set output resource metadata for streams already present in WIM.  */
2054         if (write_flags & WIMLIB_WRITE_FLAG_OVERWRITE) {
2055                 struct wim_lookup_table_entry *lte;
2056                 list_for_each_entry(lte, lookup_table_list, lookup_table_list)
2057                 {
2058                         if (lte->resource_location == RESOURCE_IN_WIM &&
2059                             lte->rspec->wim == wim)
2060                         {
2061                                 stream_set_out_reshdr_for_reuse(lte);
2062                         }
2063                 }
2064         }
2065
2066         ret = sort_stream_list(lookup_table_list,
2067                                offsetof(struct wim_lookup_table_entry, lookup_table_list),
2068                                cmp_streams_by_out_rspec);
2069         if (ret)
2070                 return ret;
2071
2072         /* Add entries for metadata resources.  */
2073         if (!(write_flags & WIMLIB_WRITE_FLAG_NO_METADATA)) {
2074                 int start_image;
2075                 int end_image;
2076
2077                 if (image == WIMLIB_ALL_IMAGES) {
2078                         start_image = 1;
2079                         end_image = wim->hdr.image_count;
2080                 } else {
2081                         start_image = image;
2082                         end_image = image;
2083                 }
2084
2085                 /* Push metadata resource lookup table entries onto the front of
2086                  * the list in reverse order, so that they're written in order.
2087                  */
2088                 for (int i = end_image; i >= start_image; i--) {
2089                         struct wim_lookup_table_entry *metadata_lte;
2090
2091                         metadata_lte = wim->image_metadata[i - 1]->metadata_lte;
2092                         wimlib_assert(metadata_lte->out_reshdr.flags & WIM_RESHDR_FLAG_METADATA);
2093                         metadata_lte->out_refcnt = 1;
2094                         list_add(&metadata_lte->lookup_table_list, lookup_table_list);
2095                 }
2096         }
2097
2098         return write_wim_lookup_table_from_stream_list(lookup_table_list,
2099                                                        &wim->out_fd,
2100                                                        wim->hdr.part_number,
2101                                                        out_reshdr,
2102                                                        write_flags_to_resource_flags(write_flags));
2103 }
2104
2105 /*
2106  * finish_write():
2107  *
2108  * Finish writing a WIM file: write the lookup table, xml data, and integrity
2109  * table, then overwrite the WIM header.  By default, closes the WIM file
2110  * descriptor (@wim->out_fd) if successful.
2111  *
2112  * write_flags is a bitwise OR of the following:
2113  *
2114  *      (public) WIMLIB_WRITE_FLAG_CHECK_INTEGRITY:
2115  *              Include an integrity table.
2116  *
2117  *      (public) WIMLIB_WRITE_FLAG_FSYNC:
2118  *              fsync() the output file before closing it.
2119  *
2120  *      (public) WIMLIB_WRITE_FLAG_PIPABLE:
2121  *              Writing a pipable WIM, possibly to a pipe; include pipable WIM
2122  *              stream headers before the lookup table and XML data, and also
2123  *              write the WIM header at the end instead of seeking to the
2124  *              beginning.  Can't be combined with
2125  *              WIMLIB_WRITE_FLAG_CHECK_INTEGRITY.
2126  *
2127  *      (private) WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE:
2128  *              Don't write the lookup table.
2129  *
2130  *      (private) WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE:
2131  *              When (if) writing the integrity table, re-use entries from the
2132  *              existing integrity table, if possible.
2133  *
2134  *      (private) WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML:
2135  *              After writing the XML data but before writing the integrity
2136  *              table, write a temporary WIM header and flush the stream so that
2137  *              the WIM is less likely to become corrupted upon abrupt program
2138  *              termination.
2139  *      (private) WIMLIB_WRITE_FLAG_HEADER_AT_END:
2140  *              Instead of overwriting the WIM header at the beginning of the
2141  *              file, simply append it to the end of the file.  (Used when
2142  *              writing to pipe.)
2143  *      (private) WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR:
2144  *              Do not close the file descriptor @wim->out_fd on either success
2145  *              on failure.
2146  *      (private) WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES:
2147  *              Use the existing <TOTALBYTES> stored in the in-memory XML
2148  *              information, rather than setting it to the offset of the XML
2149  *              data being written.
2150  */
2151 static int
2152 finish_write(WIMStruct *wim, int image, int write_flags,
2153              wimlib_progress_func_t progress_func,
2154              struct list_head *lookup_table_list)
2155 {
2156         int ret;
2157         off_t hdr_offset;
2158         int write_resource_flags;
2159         off_t old_lookup_table_end;
2160         off_t new_lookup_table_end;
2161         u64 xml_totalbytes;
2162
2163         DEBUG("image=%d, write_flags=%08x", image, write_flags);
2164
2165         write_resource_flags = write_flags_to_resource_flags(write_flags);
2166
2167         /* In the WIM header, there is room for the resource entry for a
2168          * metadata resource labeled as the "boot metadata".  This entry should
2169          * be zeroed out if there is no bootable image (boot_idx 0).  Otherwise,
2170          * it should be a copy of the resource entry for the image that is
2171          * marked as bootable.  This is not well documented...  */
2172         if (wim->hdr.boot_idx == 0) {
2173                 zero_reshdr(&wim->hdr.boot_metadata_reshdr);
2174         } else {
2175                 copy_reshdr(&wim->hdr.boot_metadata_reshdr,
2176                             &wim->image_metadata[
2177                                 wim->hdr.boot_idx - 1]->metadata_lte->out_reshdr);
2178         }
2179
2180         /* Write lookup table.  (Save old position first.)  */
2181         old_lookup_table_end = wim->hdr.lookup_table_reshdr.offset_in_wim +
2182                                wim->hdr.lookup_table_reshdr.size_in_wim;
2183         if (!(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) {
2184                 ret = write_wim_lookup_table(wim, image, write_flags,
2185                                              &wim->hdr.lookup_table_reshdr,
2186                                              lookup_table_list);
2187                 if (ret)
2188                         return ret;
2189         }
2190
2191         /* Write XML data.  */
2192         xml_totalbytes = wim->out_fd.offset;
2193         if (write_flags & WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES)
2194                 xml_totalbytes = WIM_TOTALBYTES_USE_EXISTING;
2195         ret = write_wim_xml_data(wim, image, xml_totalbytes,
2196                                  &wim->hdr.xml_data_reshdr,
2197                                  write_resource_flags);
2198         if (ret)
2199                 return ret;
2200
2201         /* Write integrity table (optional).  */
2202         if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
2203                 if (write_flags & WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML) {
2204                         struct wim_header checkpoint_hdr;
2205                         memcpy(&checkpoint_hdr, &wim->hdr, sizeof(struct wim_header));
2206                         zero_reshdr(&checkpoint_hdr.integrity_table_reshdr);
2207                         checkpoint_hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
2208                         ret = write_wim_header_at_offset(&checkpoint_hdr,
2209                                                          &wim->out_fd, 0);
2210                         if (ret)
2211                                 return ret;
2212                 }
2213
2214                 if (!(write_flags & WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE))
2215                         old_lookup_table_end = 0;
2216
2217                 new_lookup_table_end = wim->hdr.lookup_table_reshdr.offset_in_wim +
2218                                        wim->hdr.lookup_table_reshdr.size_in_wim;
2219
2220                 ret = write_integrity_table(wim,
2221                                             new_lookup_table_end,
2222                                             old_lookup_table_end,
2223                                             progress_func);
2224                 if (ret)
2225                         return ret;
2226         } else {
2227                 /* No integrity table.  */
2228                 zero_reshdr(&wim->hdr.integrity_table_reshdr);
2229         }
2230
2231         /* Now that all information in the WIM header has been determined, the
2232          * preliminary header written earlier can be overwritten, the header of
2233          * the existing WIM file can be overwritten, or the final header can be
2234          * written to the end of the pipable WIM.  */
2235         wim->hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS;
2236         hdr_offset = 0;
2237         if (write_flags & WIMLIB_WRITE_FLAG_HEADER_AT_END)
2238                 hdr_offset = wim->out_fd.offset;
2239         DEBUG("Writing new header @ %"PRIu64".", hdr_offset);
2240         ret = write_wim_header_at_offset(&wim->hdr, &wim->out_fd, hdr_offset);
2241         if (ret)
2242                 return ret;
2243
2244         /* Possibly sync file data to disk before closing.  On POSIX systems, it
2245          * is necessary to do this before using rename() to overwrite an
2246          * existing file with a new file.  Otherwise, data loss would occur if
2247          * the system is abruptly terminated when the metadata for the rename
2248          * operation has been written to disk, but the new file data has not.
2249          */
2250         if (write_flags & WIMLIB_WRITE_FLAG_FSYNC) {
2251                 DEBUG("Syncing WIM file.");
2252                 if (fsync(wim->out_fd.fd)) {
2253                         ERROR_WITH_ERRNO("Error syncing data to WIM file");
2254                         return WIMLIB_ERR_WRITE;
2255                 }
2256         }
2257
2258         if (close_wim_writable(wim, write_flags)) {
2259                 ERROR_WITH_ERRNO("Failed to close the output WIM file");
2260                 return WIMLIB_ERR_WRITE;
2261         }
2262
2263         return 0;
2264 }
2265
2266 #if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
2267 int
2268 lock_wim(WIMStruct *wim, int fd)
2269 {
2270         int ret = 0;
2271         if (fd != -1 && !wim->wim_locked) {
2272                 ret = flock(fd, LOCK_EX | LOCK_NB);
2273                 if (ret != 0) {
2274                         if (errno == EWOULDBLOCK) {
2275                                 ERROR("`%"TS"' is already being modified or has been "
2276                                       "mounted read-write\n"
2277                                       "        by another process!", wim->filename);
2278                                 ret = WIMLIB_ERR_ALREADY_LOCKED;
2279                         } else {
2280                                 WARNING_WITH_ERRNO("Failed to lock `%"TS"'",
2281                                                    wim->filename);
2282                                 ret = 0;
2283                         }
2284                 } else {
2285                         wim->wim_locked = 1;
2286                 }
2287         }
2288         return ret;
2289 }
2290 #endif
2291
2292 /*
2293  * write_pipable_wim():
2294  *
2295  * Perform the intermediate stages of creating a "pipable" WIM (i.e. a WIM
2296  * capable of being applied from a pipe).
2297  *
2298  * Pipable WIMs are a wimlib-specific modification of the WIM format such that
2299  * images can be applied from them sequentially when the file data is sent over
2300  * a pipe.  In addition, a pipable WIM can be written sequentially to a pipe.
2301  * The modifications made to the WIM format for pipable WIMs are:
2302  *
2303  * - Magic characters in header are "WLPWM\0\0\0" (wimlib pipable WIM) instead
2304  *   of "MSWIM\0\0\0".  This lets wimlib know that the WIM is pipable and also
2305  *   stops other software from trying to read the file as a normal WIM.
2306  *
2307  * - The header at the beginning of the file does not contain all the normal
2308  *   information; in particular it will have all 0's for the lookup table and
2309  *   XML data resource entries.  This is because this information cannot be
2310  *   determined until the lookup table and XML data have been written.
2311  *   Consequently, wimlib will write the full header at the very end of the
2312  *   file.  The header at the end, however, is only used when reading the WIM
2313  *   from a seekable file (not a pipe).
2314  *
2315  * - An extra copy of the XML data is placed directly after the header.  This
2316  *   allows image names and sizes to be determined at an appropriate time when
2317  *   reading the WIM from a pipe.  This copy of the XML data is ignored if the
2318  *   WIM is read from a seekable file (not a pipe).
2319  *
2320  * - The format of resources, or streams, has been modified to allow them to be
2321  *   used before the "lookup table" has been read.  Each stream is prefixed with
2322  *   a `struct pwm_stream_hdr' that is basically an abbreviated form of `struct
2323  *   wim_lookup_table_entry_disk' that only contains the SHA1 message digest,
2324  *   uncompressed stream size, and flags that indicate whether the stream is
2325  *   compressed.  The data of uncompressed streams then follows literally, while
2326  *   the data of compressed streams follows in a modified format.  Compressed
2327  *   streams do not begin with a chunk table, since the chunk table cannot be
2328  *   written until all chunks have been compressed.  Instead, each compressed
2329  *   chunk is prefixed by a `struct pwm_chunk_hdr' that gives its size.
2330  *   Furthermore, the chunk table is written at the end of the resource instead
2331  *   of the start.  Note: chunk offsets are given in the chunk table as if the
2332  *   `struct pwm_chunk_hdr's were not present; also, the chunk table is only
2333  *   used if the WIM is being read from a seekable file (not a pipe).
2334  *
2335  * - Metadata resources always come before other file resources (streams).
2336  *   (This does not by itself constitute an incompatibility with normal WIMs,
2337  *   since this is valid in normal WIMs.)
2338  *
2339  * - At least up to the end of the file resources, all components must be packed
2340  *   as tightly as possible; there cannot be any "holes" in the WIM.  (This does
2341  *   not by itself consititute an incompatibility with normal WIMs, since this
2342  *   is valid in normal WIMs.)
2343  *
2344  * Note: the lookup table, XML data, and header at the end are not used when
2345  * applying from a pipe.  They exist to support functionality such as image
2346  * application and export when the WIM is *not* read from a pipe.
2347  *
2348  *   Layout of pipable WIM:
2349  *
2350  * ---------+----------+--------------------+----------------+--------------+-----------+--------+
2351  * | Header | XML data | Metadata resources | File resources | Lookup table | XML data  | Header |
2352  * ---------+----------+--------------------+----------------+--------------+-----------+--------+
2353  *
2354  *   Layout of normal WIM:
2355  *
2356  * +--------+-----------------------------+-------------------------+
2357  * | Header | File and metadata resources | Lookup table | XML data |
2358  * +--------+-----------------------------+-------------------------+
2359  *
2360  * An optional integrity table can follow the final XML data in both normal and
2361  * pipable WIMs.  However, due to implementation details, wimlib currently can
2362  * only include an integrity table in a pipable WIM when writing it to a
2363  * seekable file (not a pipe).
2364  *
2365  * Do note that since pipable WIMs are not supported by Microsoft's software,
2366  * wimlib does not create them unless explicitly requested (with
2367  * WIMLIB_WRITE_FLAG_PIPABLE) and as stated above they use different magic
2368  * characters to identify the file.
2369  */
2370 static int
2371 write_pipable_wim(WIMStruct *wim, int image, int write_flags,
2372                   unsigned num_threads, wimlib_progress_func_t progress_func,
2373                   struct list_head *stream_list_override,
2374                   struct list_head *lookup_table_list_ret)
2375 {
2376         int ret;
2377         struct wim_reshdr xml_reshdr;
2378
2379         WARNING("Creating a pipable WIM, which will "
2380                 "be incompatible\n"
2381                 "          with Microsoft's software (wimgapi/imagex/Dism).");
2382
2383         /* At this point, the header at the beginning of the file has already
2384          * been written.  */
2385
2386         /* For efficiency, when wimlib adds an image to the WIM with
2387          * wimlib_add_image(), the SHA1 message digests of files is not
2388          * calculated; instead, they are calculated while the files are being
2389          * written.  However, this does not work when writing a pipable WIM,
2390          * since when writing a stream to a pipable WIM, its SHA1 message digest
2391          * needs to be known before the stream data is written.  Therefore,
2392          * before getting much farther, we need to pre-calculate the SHA1
2393          * message digests of all streams that will be written.  */
2394         ret = wim_checksum_unhashed_streams(wim);
2395         if (ret)
2396                 return ret;
2397
2398         /* Write extra copy of the XML data.  */
2399         ret = write_wim_xml_data(wim, image, WIM_TOTALBYTES_OMIT,
2400                                  &xml_reshdr,
2401                                  WRITE_RESOURCE_FLAG_PIPABLE);
2402         if (ret)
2403                 return ret;
2404
2405         /* Write metadata resources for the image(s) being included in the
2406          * output WIM.  */
2407         ret = write_wim_metadata_resources(wim, image, write_flags,
2408                                            progress_func);
2409         if (ret)
2410                 return ret;
2411
2412         /* Write streams needed for the image(s) being included in the output
2413          * WIM, or streams needed for the split WIM part.  */
2414         return write_wim_streams(wim, image, write_flags, num_threads,
2415                                  progress_func, stream_list_override,
2416                                  lookup_table_list_ret);
2417
2418         /* The lookup table, XML data, and header at end are handled by
2419          * finish_write().  */
2420 }
2421
2422 /* Write a standalone WIM or split WIM (SWM) part to a new file or to a file
2423  * descriptor.  */
2424 int
2425 write_wim_part(WIMStruct *wim,
2426                const void *path_or_fd,
2427                int image,
2428                int write_flags,
2429                unsigned num_threads,
2430                wimlib_progress_func_t progress_func,
2431                unsigned part_number,
2432                unsigned total_parts,
2433                struct list_head *stream_list_override,
2434                const u8 *guid)
2435 {
2436         int ret;
2437         struct wim_header hdr_save;
2438         struct list_head lookup_table_list;
2439
2440         if (total_parts == 1)
2441                 DEBUG("Writing standalone WIM.");
2442         else
2443                 DEBUG("Writing split WIM part %u/%u", part_number, total_parts);
2444         if (image == WIMLIB_ALL_IMAGES)
2445                 DEBUG("Including all images.");
2446         else
2447                 DEBUG("Including image %d only.", image);
2448         if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
2449                 DEBUG("File descriptor: %d", *(const int*)path_or_fd);
2450         else
2451                 DEBUG("Path: \"%"TS"\"", (const tchar*)path_or_fd);
2452         DEBUG("Write flags: 0x%08x", write_flags);
2453
2454         if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY)
2455                 DEBUG("\tCHECK_INTEGRITY");
2456
2457         if (write_flags & WIMLIB_WRITE_FLAG_REBUILD)
2458                 DEBUG("\tREBUILD");
2459
2460         if (write_flags & WIMLIB_WRITE_FLAG_RECOMPRESS)
2461                 DEBUG("\tRECOMPRESS");
2462
2463         if (write_flags & WIMLIB_WRITE_FLAG_FSYNC)
2464                 DEBUG("\tFSYNC");
2465
2466         if (write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE)
2467                 DEBUG("\tFSYNC");
2468
2469         if (write_flags & WIMLIB_WRITE_FLAG_IGNORE_READONLY_FLAG)
2470                 DEBUG("\tIGNORE_READONLY_FLAG");
2471
2472         if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
2473                 DEBUG("\tPIPABLE");
2474
2475         if (write_flags & WIMLIB_WRITE_FLAG_NOT_PIPABLE)
2476                 DEBUG("\tNOT_PIPABLE");
2477
2478         if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS)
2479                 DEBUG("\tPACK_STREAMS");
2480
2481         if (write_flags & WIMLIB_WRITE_FLAG_NO_PACK_STREAMS)
2482                 DEBUG("\tNO_PACK_STREAMS");
2483
2484         if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
2485                 DEBUG("\tFILE_DESCRIPTOR");
2486
2487         if (write_flags & WIMLIB_WRITE_FLAG_NO_METADATA)
2488                 DEBUG("\tNO_METADATA");
2489
2490         if (write_flags & WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES)
2491                 DEBUG("\tUSE_EXISTING_TOTALBYTES");
2492
2493         if (num_threads == 0)
2494                 DEBUG("Number of threads: autodetect");
2495         else
2496                 DEBUG("Number of threads: %u", num_threads);
2497         DEBUG("Progress function: %s", (progress_func ? "yes" : "no"));
2498         DEBUG("Stream list:       %s", (stream_list_override ? "specified" : "autodetect"));
2499         DEBUG("GUID:              %s", ((guid || wim->guid_set_explicitly) ?
2500                                         "specified" : "generate new"));
2501
2502         /* Internally, this is always called with a valid part number and total
2503          * parts.  */
2504         wimlib_assert(total_parts >= 1);
2505         wimlib_assert(part_number >= 1 && part_number <= total_parts);
2506
2507         /* A valid image (or all images) must be specified.  */
2508         if (image != WIMLIB_ALL_IMAGES &&
2509              (image < 1 || image > wim->hdr.image_count))
2510                 return WIMLIB_ERR_INVALID_IMAGE;
2511
2512         /* If we need to write metadata resources, make sure the ::WIMStruct has
2513          * the needed information attached (e.g. is not a resource-only WIM,
2514          * such as a non-first part of a split WIM).  */
2515         if (!wim_has_metadata(wim) &&
2516             !(write_flags & WIMLIB_WRITE_FLAG_NO_METADATA))
2517                 return WIMLIB_ERR_METADATA_NOT_FOUND;
2518
2519         /* Check for contradictory flags.  */
2520         if ((write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
2521                             WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY))
2522                                 == (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
2523                                     WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY))
2524                 return WIMLIB_ERR_INVALID_PARAM;
2525
2526         if ((write_flags & (WIMLIB_WRITE_FLAG_PIPABLE |
2527                             WIMLIB_WRITE_FLAG_NOT_PIPABLE))
2528                                 == (WIMLIB_WRITE_FLAG_PIPABLE |
2529                                     WIMLIB_WRITE_FLAG_NOT_PIPABLE))
2530                 return WIMLIB_ERR_INVALID_PARAM;
2531
2532         if ((write_flags & (WIMLIB_WRITE_FLAG_PACK_STREAMS |
2533                             WIMLIB_WRITE_FLAG_NO_PACK_STREAMS))
2534                                 == (WIMLIB_WRITE_FLAG_PACK_STREAMS |
2535                                     WIMLIB_WRITE_FLAG_NO_PACK_STREAMS))
2536                 return WIMLIB_ERR_INVALID_PARAM;
2537
2538         /* Save previous header, then start initializing the new one.  */
2539         memcpy(&hdr_save, &wim->hdr, sizeof(struct wim_header));
2540
2541         /* Set default integrity, pipable, and packed stream flags.  */
2542         if (!(write_flags & (WIMLIB_WRITE_FLAG_PIPABLE |
2543                              WIMLIB_WRITE_FLAG_NOT_PIPABLE)))
2544                 if (wim_is_pipable(wim)) {
2545                         DEBUG("WIM is pipable; default to PIPABLE.");
2546                         write_flags |= WIMLIB_WRITE_FLAG_PIPABLE;
2547                 }
2548
2549         if (!(write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
2550                              WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY)))
2551                 if (wim_has_integrity_table(wim)) {
2552                         DEBUG("Integrity table present; default to CHECK_INTEGRITY.");
2553                         write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
2554                 }
2555
2556         if (!(write_flags & (WIMLIB_WRITE_FLAG_PACK_STREAMS |
2557                              WIMLIB_WRITE_FLAG_NO_PACK_STREAMS)))
2558                 if (wim->hdr.wim_version == WIM_VERSION_PACKED_STREAMS) {
2559                         DEBUG("WIM version 3584; default to PACK_STREAMS.");
2560                         write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
2561                 }
2562
2563         if ((write_flags & (WIMLIB_WRITE_FLAG_PIPABLE |
2564                             WIMLIB_WRITE_FLAG_PACK_STREAMS))
2565                                     == (WIMLIB_WRITE_FLAG_PIPABLE |
2566                                         WIMLIB_WRITE_FLAG_PACK_STREAMS))
2567         {
2568                 ERROR("Cannot specify both PIPABLE and PACK_STREAMS!");
2569                 return WIMLIB_ERR_INVALID_PARAM;
2570         }
2571
2572         /* Set appropriate magic number.  */
2573         if (write_flags & WIMLIB_WRITE_FLAG_PIPABLE)
2574                 wim->hdr.magic = PWM_MAGIC;
2575         else
2576                 wim->hdr.magic = WIM_MAGIC;
2577
2578         /* Set appropriate version number.  */
2579         if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS)
2580                 wim->hdr.wim_version = WIM_VERSION_PACKED_STREAMS;
2581         else
2582                 wim->hdr.wim_version = WIM_VERSION_DEFAULT;
2583
2584         /* Clear header flags that will be set automatically.  */
2585         wim->hdr.flags &= ~(WIM_HDR_FLAG_METADATA_ONLY          |
2586                             WIM_HDR_FLAG_RESOURCE_ONLY          |
2587                             WIM_HDR_FLAG_SPANNED                |
2588                             WIM_HDR_FLAG_WRITE_IN_PROGRESS);
2589
2590         /* Set SPANNED header flag if writing part of a split WIM.  */
2591         if (total_parts != 1)
2592                 wim->hdr.flags |= WIM_HDR_FLAG_SPANNED;
2593
2594         /* Set part number and total parts of split WIM.  This will be 1 and 1
2595          * if the WIM is standalone.  */
2596         wim->hdr.part_number = part_number;
2597         wim->hdr.total_parts = total_parts;
2598
2599         /* Set compression type if different.  */
2600         if (wim->compression_type != wim->out_compression_type) {
2601                 ret = set_wim_hdr_cflags(wim->out_compression_type, &wim->hdr);
2602                 wimlib_assert(ret == 0);
2603         }
2604
2605         /* Set chunk size if different.  */
2606         wim->hdr.chunk_size = wim->out_chunk_size;
2607
2608         /* Use GUID if specified; otherwise generate a new one.  */
2609         if (guid)
2610                 memcpy(wim->hdr.guid, guid, WIMLIB_GUID_LEN);
2611         else if (!wim->guid_set_explicitly)
2612                 randomize_byte_array(wim->hdr.guid, WIMLIB_GUID_LEN);
2613
2614         /* Clear references to resources that have not been written yet.  */
2615         zero_reshdr(&wim->hdr.lookup_table_reshdr);
2616         zero_reshdr(&wim->hdr.xml_data_reshdr);
2617         zero_reshdr(&wim->hdr.boot_metadata_reshdr);
2618         zero_reshdr(&wim->hdr.integrity_table_reshdr);
2619
2620         /* Set image count and boot index correctly for single image writes.  */
2621         if (image != WIMLIB_ALL_IMAGES) {
2622                 wim->hdr.image_count = 1;
2623                 if (wim->hdr.boot_idx == image)
2624                         wim->hdr.boot_idx = 1;
2625                 else
2626                         wim->hdr.boot_idx = 0;
2627         }
2628
2629         /* Split WIMs can't be bootable.  */
2630         if (total_parts != 1)
2631                 wim->hdr.boot_idx = 0;
2632
2633         /* Initialize output file descriptor.  */
2634         if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR) {
2635                 /* File descriptor was explicitly provided.  Return error if
2636                  * file descriptor is not seekable, unless writing a pipable WIM
2637                  * was requested.  */
2638                 wim->out_fd.fd = *(const int*)path_or_fd;
2639                 wim->out_fd.offset = 0;
2640                 if (!filedes_is_seekable(&wim->out_fd)) {
2641                         ret = WIMLIB_ERR_INVALID_PARAM;
2642                         if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
2643                                 goto out_restore_hdr;
2644                         if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
2645                                 ERROR("Can't include integrity check when "
2646                                       "writing pipable WIM to pipe!");
2647                                 goto out_restore_hdr;
2648                         }
2649                 }
2650
2651         } else {
2652                 /* Filename of WIM to write was provided; open file descriptor
2653                  * to it.  */
2654                 ret = open_wim_writable(wim, (const tchar*)path_or_fd,
2655                                         O_TRUNC | O_CREAT | O_RDWR);
2656                 if (ret)
2657                         goto out_restore_hdr;
2658         }
2659
2660         /* Write initial header.  This is merely a "dummy" header since it
2661          * doesn't have all the information yet, so it will be overwritten later
2662          * (unless writing a pipable WIM).  */
2663         if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
2664                 wim->hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
2665         ret = write_wim_header(&wim->hdr, &wim->out_fd);
2666         wim->hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS;
2667         if (ret)
2668                 goto out_restore_hdr;
2669
2670         /* Write metadata resources and streams.  */
2671         if (!(write_flags & WIMLIB_WRITE_FLAG_PIPABLE)) {
2672                 /* Default case: create a normal (non-pipable) WIM.  */
2673                 ret = write_wim_streams(wim, image, write_flags, num_threads,
2674                                         progress_func, stream_list_override,
2675                                         &lookup_table_list);
2676                 if (ret)
2677                         goto out_restore_hdr;
2678
2679                 ret = write_wim_metadata_resources(wim, image, write_flags,
2680                                                    progress_func);
2681                 if (ret)
2682                         goto out_restore_hdr;
2683         } else {
2684                 /* Non-default case: create pipable WIM.  */
2685                 ret = write_pipable_wim(wim, image, write_flags, num_threads,
2686                                         progress_func, stream_list_override,
2687                                         &lookup_table_list);
2688                 if (ret)
2689                         goto out_restore_hdr;
2690                 write_flags |= WIMLIB_WRITE_FLAG_HEADER_AT_END;
2691         }
2692
2693
2694         /* Write lookup table, XML data, and (optional) integrity table.  */
2695         ret = finish_write(wim, image, write_flags, progress_func,
2696                            &lookup_table_list);
2697 out_restore_hdr:
2698         memcpy(&wim->hdr, &hdr_save, sizeof(struct wim_header));
2699         (void)close_wim_writable(wim, write_flags);
2700         DEBUG("ret=%d", ret);
2701         return ret;
2702 }
2703
2704 /* Write a standalone WIM to a file or file descriptor.  */
2705 static int
2706 write_standalone_wim(WIMStruct *wim, const void *path_or_fd,
2707                      int image, int write_flags, unsigned num_threads,
2708                      wimlib_progress_func_t progress_func)
2709 {
2710         return write_wim_part(wim, path_or_fd, image, write_flags,
2711                               num_threads, progress_func, 1, 1, NULL, NULL);
2712 }
2713
2714 /* API function documented in wimlib.h  */
2715 WIMLIBAPI int
2716 wimlib_write(WIMStruct *wim, const tchar *path,
2717              int image, int write_flags, unsigned num_threads,
2718              wimlib_progress_func_t progress_func)
2719 {
2720         if (!path)
2721                 return WIMLIB_ERR_INVALID_PARAM;
2722
2723         write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
2724
2725         return write_standalone_wim(wim, path, image, write_flags,
2726                                     num_threads, progress_func);
2727 }
2728
2729 /* API function documented in wimlib.h  */
2730 WIMLIBAPI int
2731 wimlib_write_to_fd(WIMStruct *wim, int fd,
2732                    int image, int write_flags, unsigned num_threads,
2733                    wimlib_progress_func_t progress_func)
2734 {
2735         if (fd < 0)
2736                 return WIMLIB_ERR_INVALID_PARAM;
2737
2738         write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
2739         write_flags |= WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR;
2740
2741         return write_standalone_wim(wim, &fd, image, write_flags,
2742                                     num_threads, progress_func);
2743 }
2744
2745 static bool
2746 any_images_modified(WIMStruct *wim)
2747 {
2748         for (int i = 0; i < wim->hdr.image_count; i++)
2749                 if (wim->image_metadata[i]->modified)
2750                         return true;
2751         return false;
2752 }
2753
2754 static int
2755 check_resource_offset(struct wim_lookup_table_entry *lte, void *_wim)
2756 {
2757         const WIMStruct *wim = _wim;
2758         off_t end_offset = *(const off_t*)wim->private;
2759
2760         if (lte->resource_location == RESOURCE_IN_WIM && lte->rspec->wim == wim &&
2761             lte->rspec->offset_in_wim + lte->rspec->size_in_wim > end_offset)
2762                 return WIMLIB_ERR_RESOURCE_ORDER;
2763         return 0;
2764 }
2765
2766 /* Make sure no file or metadata resources are located after the XML data (or
2767  * integrity table if present)--- otherwise we can't safely overwrite the WIM in
2768  * place and we return WIMLIB_ERR_RESOURCE_ORDER.  */
2769 static int
2770 check_resource_offsets(WIMStruct *wim, off_t end_offset)
2771 {
2772         int ret;
2773         unsigned i;
2774
2775         wim->private = &end_offset;
2776         ret = for_lookup_table_entry(wim->lookup_table, check_resource_offset, wim);
2777         if (ret)
2778                 return ret;
2779
2780         for (i = 0; i < wim->hdr.image_count; i++) {
2781                 ret = check_resource_offset(wim->image_metadata[i]->metadata_lte, wim);
2782                 if (ret)
2783                         return ret;
2784         }
2785         return 0;
2786 }
2787
2788 /*
2789  * Overwrite a WIM, possibly appending streams to it.
2790  *
2791  * A WIM looks like (or is supposed to look like) the following:
2792  *
2793  *                   Header (212 bytes)
2794  *                   Streams and metadata resources (variable size)
2795  *                   Lookup table (variable size)
2796  *                   XML data (variable size)
2797  *                   Integrity table (optional) (variable size)
2798  *
2799  * If we are not adding any streams or metadata resources, the lookup table is
2800  * unchanged--- so we only need to overwrite the XML data, integrity table, and
2801  * header.  This operation is potentially unsafe if the program is abruptly
2802  * terminated while the XML data or integrity table are being overwritten, but
2803  * before the new header has been written.  To partially alleviate this problem,
2804  * a special flag (WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML) is passed to
2805  * finish_write() to cause a temporary WIM header to be written after the XML
2806  * data has been written.  This may prevent the WIM from becoming corrupted if
2807  * the program is terminated while the integrity table is being calculated (but
2808  * no guarantees, due to write re-ordering...).
2809  *
2810  * If we are adding new streams or images (metadata resources), the lookup table
2811  * needs to be changed, and those streams need to be written.  In this case, we
2812  * try to perform a safe update of the WIM file by writing the streams *after*
2813  * the end of the previous WIM, then writing the new lookup table, XML data, and
2814  * (optionally) integrity table following the new streams.  This will produce a
2815  * layout like the following:
2816  *
2817  *                   Header (212 bytes)
2818  *                   (OLD) Streams and metadata resources (variable size)
2819  *                   (OLD) Lookup table (variable size)
2820  *                   (OLD) XML data (variable size)
2821  *                   (OLD) Integrity table (optional) (variable size)
2822  *                   (NEW) Streams and metadata resources (variable size)
2823  *                   (NEW) Lookup table (variable size)
2824  *                   (NEW) XML data (variable size)
2825  *                   (NEW) Integrity table (optional) (variable size)
2826  *
2827  * At all points, the WIM is valid as nothing points to the new data yet.  Then,
2828  * the header is overwritten to point to the new lookup table, XML data, and
2829  * integrity table, to produce the following layout:
2830  *
2831  *                   Header (212 bytes)
2832  *                   Streams and metadata resources (variable size)
2833  *                   Nothing (variable size)
2834  *                   More Streams and metadata resources (variable size)
2835  *                   Lookup table (variable size)
2836  *                   XML data (variable size)
2837  *                   Integrity table (optional) (variable size)
2838  *
2839  * This method allows an image to be appended to a large WIM very quickly, and
2840  * is is crash-safe except in the case of write re-ordering, but the
2841  * disadvantage is that a small hole is left in the WIM where the old lookup
2842  * table, xml data, and integrity table were.  (These usually only take up a
2843  * small amount of space compared to the streams, however.)
2844  */
2845 static int
2846 overwrite_wim_inplace(WIMStruct *wim, int write_flags,
2847                       unsigned num_threads,
2848                       wimlib_progress_func_t progress_func)
2849 {
2850         int ret;
2851         off_t old_wim_end;
2852         u64 old_lookup_table_end, old_xml_begin, old_xml_end;
2853         struct wim_header hdr_save;
2854         struct list_head stream_list;
2855         struct list_head lookup_table_list;
2856         struct filter_context filter_ctx;
2857
2858         DEBUG("Overwriting `%"TS"' in-place", wim->filename);
2859
2860         /* Save original header so it can be restored in case of error  */
2861         memcpy(&hdr_save, &wim->hdr, sizeof(struct wim_header));
2862
2863         /* Set default integrity flag.  */
2864         if (!(write_flags & (WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
2865                              WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY)))
2866                 if (wim_has_integrity_table(wim))
2867                         write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
2868
2869         /* Set default packed flag.  */
2870         if (!(write_flags & (WIMLIB_WRITE_FLAG_PACK_STREAMS |
2871                              WIMLIB_WRITE_FLAG_NO_PACK_STREAMS)))
2872         {
2873         #if 0
2874                 if (wim->hdr.wim_version == WIM_VERSION_PACKED_STREAMS)
2875                         write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
2876         #endif
2877                 /* wimlib allows multiple packs in a single WIM, but they don't
2878                  * seem to be compatible with WIMGAPI.  Write new streams
2879                  * unpacked.  */
2880         } else if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS) {
2881                 wim->hdr.wim_version = WIM_VERSION_PACKED_STREAMS;
2882         }
2883
2884         /* Set additional flags for overwrite.  */
2885         write_flags |= WIMLIB_WRITE_FLAG_OVERWRITE |
2886                        WIMLIB_WRITE_FLAG_STREAMS_OK;
2887
2888         /* Make sure that the integrity table (if present) is after the XML
2889          * data, and that there are no stream resources, metadata resources, or
2890          * lookup tables after the XML data.  Otherwise, these data would be
2891          * overwritten. */
2892         old_xml_begin = wim->hdr.xml_data_reshdr.offset_in_wim;
2893         old_xml_end = old_xml_begin + wim->hdr.xml_data_reshdr.size_in_wim;
2894         old_lookup_table_end = wim->hdr.lookup_table_reshdr.offset_in_wim +
2895                                wim->hdr.lookup_table_reshdr.size_in_wim;
2896         if (wim->hdr.integrity_table_reshdr.offset_in_wim != 0 &&
2897             wim->hdr.integrity_table_reshdr.offset_in_wim < old_xml_end) {
2898                 WARNING("Didn't expect the integrity table to be before the XML data");
2899                 ret = WIMLIB_ERR_RESOURCE_ORDER;
2900                 goto out_restore_memory_hdr;
2901         }
2902
2903         if (old_lookup_table_end > old_xml_begin) {
2904                 WARNING("Didn't expect the lookup table to be after the XML data");
2905                 ret = WIMLIB_ERR_RESOURCE_ORDER;
2906                 goto out_restore_memory_hdr;
2907         }
2908
2909         /* Set @old_wim_end, which indicates the point beyond which we don't
2910          * allow any file and metadata resources to appear without returning
2911          * WIMLIB_ERR_RESOURCE_ORDER (due to the fact that we would otherwise
2912          * overwrite these resources). */
2913         if (!wim->deletion_occurred && !any_images_modified(wim)) {
2914                 /* If no images have been modified and no images have been
2915                  * deleted, a new lookup table does not need to be written.  We
2916                  * shall write the new XML data and optional integrity table
2917                  * immediately after the lookup table.  Note that this may
2918                  * overwrite an existing integrity table. */
2919                 DEBUG("Skipping writing lookup table "
2920                       "(no images modified or deleted)");
2921                 old_wim_end = old_lookup_table_end;
2922                 write_flags |= WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE |
2923                                WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML;
2924         } else if (wim->hdr.integrity_table_reshdr.offset_in_wim != 0) {
2925                 /* Old WIM has an integrity table; begin writing new streams
2926                  * after it. */
2927                 old_wim_end = wim->hdr.integrity_table_reshdr.offset_in_wim +
2928                               wim->hdr.integrity_table_reshdr.size_in_wim;
2929         } else {
2930                 /* No existing integrity table; begin writing new streams after
2931                  * the old XML data. */
2932                 old_wim_end = old_xml_end;
2933         }
2934
2935         ret = check_resource_offsets(wim, old_wim_end);
2936         if (ret)
2937                 goto out_restore_memory_hdr;
2938
2939         ret = prepare_stream_list_for_write(wim, WIMLIB_ALL_IMAGES, write_flags,
2940                                             &stream_list, &lookup_table_list,
2941                                             &filter_ctx);
2942         if (ret)
2943                 goto out_restore_memory_hdr;
2944
2945         ret = open_wim_writable(wim, wim->filename, O_RDWR);
2946         if (ret)
2947                 goto out_restore_memory_hdr;
2948
2949         ret = lock_wim(wim, wim->out_fd.fd);
2950         if (ret)
2951                 goto out_close_wim;
2952
2953         /* Set WIM_HDR_FLAG_WRITE_IN_PROGRESS flag in header. */
2954         wim->hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS;
2955         ret = write_wim_header_flags(wim->hdr.flags, &wim->out_fd);
2956         if (ret) {
2957                 ERROR_WITH_ERRNO("Error updating WIM header flags");
2958                 goto out_unlock_wim;
2959         }
2960
2961         if (filedes_seek(&wim->out_fd, old_wim_end) == -1) {
2962                 ERROR_WITH_ERRNO("Can't seek to end of WIM");
2963                 ret = WIMLIB_ERR_WRITE;
2964                 goto out_restore_physical_hdr;
2965         }
2966
2967         ret = write_stream_list(&stream_list,
2968                                 &wim->out_fd,
2969                                 write_flags_to_resource_flags(write_flags),
2970                                 wim->compression_type,
2971                                 wim->chunk_size,
2972                                 num_threads,
2973                                 wim->lookup_table,
2974                                 &filter_ctx,
2975                                 progress_func);
2976         if (ret)
2977                 goto out_truncate;
2978
2979         ret = write_wim_metadata_resources(wim, WIMLIB_ALL_IMAGES,
2980                                            write_flags, progress_func);
2981         if (ret)
2982                 goto out_truncate;
2983
2984         write_flags |= WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE;
2985         ret = finish_write(wim, WIMLIB_ALL_IMAGES, write_flags,
2986                            progress_func, &lookup_table_list);
2987         if (ret)
2988                 goto out_truncate;
2989
2990         wim->wim_locked = 0;
2991         return 0;
2992
2993 out_truncate:
2994         if (!(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) {
2995                 WARNING("Truncating `%"TS"' to its original size (%"PRIu64" bytes)",
2996                         wim->filename, old_wim_end);
2997                 /* Return value of ftruncate() is ignored because this is
2998                  * already an error path.  */
2999                 (void)ftruncate(wim->out_fd.fd, old_wim_end);
3000         }
3001 out_restore_physical_hdr:
3002         (void)write_wim_header_flags(hdr_save.flags, &wim->out_fd);
3003 out_unlock_wim:
3004         wim->wim_locked = 0;
3005 out_close_wim:
3006         (void)close_wim_writable(wim, write_flags);
3007 out_restore_memory_hdr:
3008         memcpy(&wim->hdr, &hdr_save, sizeof(struct wim_header));
3009         return ret;
3010 }
3011
3012 static int
3013 overwrite_wim_via_tmpfile(WIMStruct *wim, int write_flags,
3014                           unsigned num_threads,
3015                           wimlib_progress_func_t progress_func)
3016 {
3017         size_t wim_name_len;
3018         int ret;
3019
3020         DEBUG("Overwriting `%"TS"' via a temporary file", wim->filename);
3021
3022         /* Write the WIM to a temporary file in the same directory as the
3023          * original WIM. */
3024         wim_name_len = tstrlen(wim->filename);
3025         tchar tmpfile[wim_name_len + 10];
3026         tmemcpy(tmpfile, wim->filename, wim_name_len);
3027         randomize_char_array_with_alnum(tmpfile + wim_name_len, 9);
3028         tmpfile[wim_name_len + 9] = T('\0');
3029
3030         ret = wimlib_write(wim, tmpfile, WIMLIB_ALL_IMAGES,
3031                            write_flags | WIMLIB_WRITE_FLAG_FSYNC,
3032                            num_threads, progress_func);
3033         if (ret) {
3034                 tunlink(tmpfile);
3035                 return ret;
3036         }
3037
3038         close_wim(wim);
3039
3040         /* Rename the new WIM file to the original WIM file.  Note: on Windows
3041          * this actually calls win32_rename_replacement(), not _wrename(), so
3042          * that removing the existing destination file can be handled.  */
3043         DEBUG("Renaming `%"TS"' to `%"TS"'", tmpfile, wim->filename);
3044         ret = trename(tmpfile, wim->filename);
3045         if (ret) {
3046                 ERROR_WITH_ERRNO("Failed to rename `%"TS"' to `%"TS"'",
3047                                  tmpfile, wim->filename);
3048         #ifdef __WIN32__
3049                 if (ret < 0)
3050         #endif
3051                 {
3052                         tunlink(tmpfile);
3053                 }
3054                 return WIMLIB_ERR_RENAME;
3055         }
3056
3057         if (progress_func) {
3058                 union wimlib_progress_info progress;
3059                 progress.rename.from = tmpfile;
3060                 progress.rename.to = wim->filename;
3061                 progress_func(WIMLIB_PROGRESS_MSG_RENAME, &progress);
3062         }
3063         return 0;
3064 }
3065
3066 /* Determine if the specified WIM file may be updated by appending in-place
3067  * rather than writing and replacing it with an entirely new file.  */
3068 static bool
3069 can_overwrite_wim_inplace(const WIMStruct *wim, int write_flags)
3070 {
3071         /* REBUILD flag forces full rebuild.  */
3072         if (write_flags & WIMLIB_WRITE_FLAG_REBUILD)
3073                 return false;
3074
3075         /* Deletions cause full rebuild by default.  */
3076         if (wim->deletion_occurred && !(write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE))
3077                 return false;
3078
3079         /* Pipable WIMs cannot be updated in place, nor can a non-pipable WIM be
3080          * turned into a pipable WIM in-place.  */
3081         if (wim_is_pipable(wim) || (write_flags & WIMLIB_WRITE_FLAG_PIPABLE))
3082                 return false;
3083
3084         /* wimlib allows multiple packs in a single WIM, but they don't seem to
3085          * be compatible with WIMGAPI, so force all streams to be repacked if
3086          * the WIM already may have contained a pack and PACK_STREAMS was
3087          * requested.  */
3088         if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS &&
3089             wim->hdr.wim_version == WIM_VERSION_PACKED_STREAMS)
3090                 return false;
3091
3092         /* The default compression type and compression chunk size selected for
3093          * the output WIM must be the same as those currently used for the WIM.
3094          */
3095         if (wim->compression_type != wim->out_compression_type)
3096                 return false;
3097         if (wim->chunk_size != wim->out_chunk_size)
3098                 return false;
3099
3100         return true;
3101 }
3102
3103 /* API function documented in wimlib.h  */
3104 WIMLIBAPI int
3105 wimlib_overwrite(WIMStruct *wim, int write_flags,
3106                  unsigned num_threads,
3107                  wimlib_progress_func_t progress_func)
3108 {
3109         int ret;
3110         u32 orig_hdr_flags;
3111
3112         write_flags &= WIMLIB_WRITE_MASK_PUBLIC;
3113
3114         if (write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR)
3115                 return WIMLIB_ERR_INVALID_PARAM;
3116
3117         if (!wim->filename)
3118                 return WIMLIB_ERR_NO_FILENAME;
3119
3120         orig_hdr_flags = wim->hdr.flags;
3121         if (write_flags & WIMLIB_WRITE_FLAG_IGNORE_READONLY_FLAG)
3122                 wim->hdr.flags &= ~WIM_HDR_FLAG_READONLY;
3123         ret = can_modify_wim(wim);
3124         wim->hdr.flags = orig_hdr_flags;
3125         if (ret)
3126                 return ret;
3127
3128         if (can_overwrite_wim_inplace(wim, write_flags)) {
3129                 ret = overwrite_wim_inplace(wim, write_flags, num_threads,
3130                                             progress_func);
3131                 if (ret != WIMLIB_ERR_RESOURCE_ORDER)
3132                         return ret;
3133                 WARNING("Falling back to re-building entire WIM");
3134         }
3135         return overwrite_wim_via_tmpfile(wim, write_flags, num_threads,
3136                                          progress_func);
3137 }