X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwrite.c;h=4c68921cc9164efb926e58325f0e0a99109ec6bc;hp=fde7e939ed57a83d4ef053ff0d69db755d96750d;hb=58daaca96dc8b23e345342e844c58b1972e5fedf;hpb=7bbd03a7f450e59ebd7481cd1af0639131630f42 diff --git a/src/write.c b/src/write.c index fde7e939..4c68921c 100644 --- a/src/write.c +++ b/src/write.c @@ -81,16 +81,19 @@ * array of offsets.) */ struct chunk_table { off_t file_offset; - u64 num_chunks; u64 original_resource_size; - u64 bytes_per_chunk_entry; + u64 num_chunks; u64 table_disk_size; - u64 cur_offset; - u64 *cur_offset_p; + unsigned bytes_per_chunk_entry; + void *cur_offset_p; union { - u64 offsets[0]; - u32 u32_offsets[0]; + u32 cur_offset_u32; + u64 cur_offset_u64; }; + /* Beginning of chunk offsets, in either 32-bit or 64-bit little endian + * integers, including the first offset of 0, which will not be written. + * */ + u8 offsets[] _aligned_attribute(8); }; /* @@ -105,10 +108,11 @@ begin_wim_resource_chunk_tab(const struct wim_lookup_table_entry *lte, { u64 size = wim_resource_size(lte); u64 num_chunks = wim_resource_chunks(lte); + unsigned bytes_per_chunk_entry = (size > (1ULL << 32)) ? 8 : 4; size_t alloc_size = sizeof(struct chunk_table) + num_chunks * sizeof(u64); struct chunk_table *chunk_tab = CALLOC(1, alloc_size); - DEBUG("Begin chunk table for stream with size %"PRIu64, size); + DEBUG("Beginning chunk table for stream with size %"PRIu64, size); if (!chunk_tab) { ERROR("Failed to allocate chunk table for %"PRIu64" byte " @@ -118,13 +122,15 @@ begin_wim_resource_chunk_tab(const struct wim_lookup_table_entry *lte, chunk_tab->file_offset = file_offset; chunk_tab->num_chunks = num_chunks; chunk_tab->original_resource_size = size; - chunk_tab->bytes_per_chunk_entry = (size > (1ULL << 32)) ? 8 : 4; + chunk_tab->bytes_per_chunk_entry = bytes_per_chunk_entry; chunk_tab->table_disk_size = chunk_tab->bytes_per_chunk_entry * (num_chunks - 1); - chunk_tab->cur_offset = 0; chunk_tab->cur_offset_p = chunk_tab->offsets; - if (full_write(out_fd, chunk_tab, + /* We don't know the correct offsets yet; this just writes zeroes to + * reserve space for the table, so we can go back to it later after + * we've written the compressed chunks following it. */ + if (full_write(out_fd, chunk_tab->offsets, chunk_tab->table_disk_size) != chunk_tab->table_disk_size) { ERROR_WITH_ERRNO("Failed to write chunk table in compressed " @@ -136,6 +142,22 @@ begin_wim_resource_chunk_tab(const struct wim_lookup_table_entry *lte, return 0; } +/* Add the offset for the next chunk to the chunk table being constructed for a + * compressed stream. */ +static void +chunk_tab_record_chunk(struct chunk_table *chunk_tab, unsigned out_chunk_size) +{ + if (chunk_tab->bytes_per_chunk_entry == 4) { + *(le32*)chunk_tab->cur_offset_p = cpu_to_le32(chunk_tab->cur_offset_u32); + chunk_tab->cur_offset_p = (le32*)chunk_tab->cur_offset_p + 1; + chunk_tab->cur_offset_u32 += out_chunk_size; + } else { + *(le64*)chunk_tab->cur_offset_p = cpu_to_le64(chunk_tab->cur_offset_u64); + chunk_tab->cur_offset_p = (le64*)chunk_tab->cur_offset_p + 1; + chunk_tab->cur_offset_u64 += out_chunk_size; + } +} + /* * compress_func_t- Pointer to a function to compresses a chunk * of a WIM resource. This may be either @@ -205,8 +227,7 @@ write_wim_resource_chunk(const void * restrict chunk, out_chunk = chunk; out_chunk_size = chunk_size; } - *chunk_tab->cur_offset_p++ = chunk_tab->cur_offset; - chunk_tab->cur_offset += out_chunk_size; + chunk_tab_record_chunk(chunk_tab, out_chunk_size); } else { /* Write uncompressed */ out_chunk = chunk; @@ -232,14 +253,8 @@ finish_wim_resource_chunk_tab(struct chunk_table *chunk_tab, { size_t bytes_written; - if (chunk_tab->bytes_per_chunk_entry == 8) { - array_cpu_to_le64(chunk_tab->offsets, chunk_tab->num_chunks); - } else { - for (u64 i = 0; i < chunk_tab->num_chunks; i++) - chunk_tab->u32_offsets[i] = cpu_to_le32(chunk_tab->offsets[i]); - } bytes_written = full_pwrite(out_fd, - (u8*)chunk_tab->offsets + chunk_tab->bytes_per_chunk_entry, + chunk_tab->offsets + chunk_tab->bytes_per_chunk_entry, chunk_tab->table_disk_size, chunk_tab->file_offset); if (bytes_written != chunk_tab->table_disk_size) { @@ -247,7 +262,10 @@ finish_wim_resource_chunk_tab(struct chunk_table *chunk_tab, "file resource"); return WIMLIB_ERR_WRITE; } - *compressed_size_p = chunk_tab->cur_offset + chunk_tab->table_disk_size; + if (chunk_tab->bytes_per_chunk_entry == 4) + *compressed_size_p = chunk_tab->cur_offset_u32 + chunk_tab->table_disk_size; + else + *compressed_size_p = chunk_tab->cur_offset_u64 + chunk_tab->table_disk_size; return 0; } @@ -359,7 +377,7 @@ write_wim_resource(struct wim_lookup_table_entry *lte, if (!(flags & WIMLIB_RESOURCE_FLAG_RECOMPRESS) && lte->resource_location == RESOURCE_IN_WIM && out_ctype != WIMLIB_COMPRESSION_TYPE_NONE && - wimlib_get_compression_type(lte->wim) == out_ctype) + lte->wim->compression_type == out_ctype) { flags |= WIMLIB_RESOURCE_FLAG_RAW; write_ctx.doing_sha = false; @@ -793,10 +811,8 @@ static int write_wim_chunks(struct message *msg, int out_fd, struct chunk_table *chunk_tab) { - for (unsigned i = 0; i < msg->num_chunks; i++) { - *chunk_tab->cur_offset_p++ = chunk_tab->cur_offset; - chunk_tab->cur_offset += msg->out_chunks[i].iov_len; - } + for (unsigned i = 0; i < msg->num_chunks; i++) + chunk_tab_record_chunk(chunk_tab, msg->out_chunks[i].iov_len); if (full_writev(out_fd, msg->out_chunks, msg->num_chunks) != msg->total_out_bytes) { @@ -1191,7 +1207,7 @@ main_thread_process_next_stream(struct wim_lookup_table_entry *lte, void *_ctx) ctx->out_ctype == WIMLIB_COMPRESSION_TYPE_NONE || (lte->resource_location == RESOURCE_IN_WIM && !(ctx->write_resource_flags & WIMLIB_RESOURCE_FLAG_RECOMPRESS) && - wimlib_get_compression_type(lte->wim) == ctx->out_ctype)) + lte->wim->compression_type == ctx->out_ctype)) { /* Stream is too small or isn't being compressed. Process it by * the main thread when we have a chance. We can't necessarily @@ -1531,10 +1547,10 @@ lte_overwrite_prepare_2(struct wim_lookup_table_entry *lte, void *_args) if (lte->resource_entry.offset + lte->resource_entry.size > args->end_offset) { - #ifdef ENABLE_ERROR_MESSAGES - ERROR("The following resource is after the XML data:"); - print_lookup_table_entry(lte, stderr); - #endif + if (wimlib_print_errors) { + ERROR("The following resource is after the XML data:"); + print_lookup_table_entry(lte, stderr); + } return WIMLIB_ERR_RESOURCE_ORDER; } copy_resource_entry(<e->output_resource_entry, @@ -1697,7 +1713,7 @@ write_wim_streams(WIMStruct *wim, int image, int write_flags, return write_stream_list(&stream_list, wim->lookup_table, wim->out_fd, - wimlib_get_compression_type(wim), + wim->compression_type, write_flags, num_threads, progress_func); @@ -1782,6 +1798,7 @@ finish_write(WIMStruct *w, int image, int write_flags, struct wim_header checkpoint_hdr; memcpy(&checkpoint_hdr, &hdr, sizeof(struct wim_header)); zero_resource_entry(&checkpoint_hdr.integrity); + checkpoint_hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS; ret = write_header(&checkpoint_hdr, w->out_fd); if (ret) goto out_close_wim; @@ -1809,6 +1826,7 @@ finish_write(WIMStruct *w, int image, int write_flags, zero_resource_entry(&hdr.integrity); } + hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS; ret = write_header(&hdr, w->out_fd); if (ret) goto out_close_wim; @@ -1891,7 +1909,9 @@ begin_write(WIMStruct *w, const tchar *path, int write_flags) if (ret) return ret; /* Write dummy header. It will be overwritten later. */ + w->hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS; ret = write_header(&w->hdr, w->out_fd); + w->hdr.flags &= ~WIM_HDR_FLAG_WRITE_IN_PROGRESS; if (ret) return ret; if (lseek(w->out_fd, WIM_HEADER_DISK_SIZE, SEEK_SET) == -1) { @@ -2093,11 +2113,20 @@ overwrite_wim_inplace(WIMStruct *w, int write_flags, return ret; } + /* Set WIM_HDR_FLAG_WRITE_IN_PROGRESS flag in header. */ + ret = write_header_flags(w->hdr.flags | WIM_HDR_FLAG_WRITE_IN_PROGRESS, + w->out_fd); + if (ret) { + ERROR_WITH_ERRNO("Error updating WIM header flags"); + close_wim_writable(w); + goto out_unlock_wim; + } + if (lseek(w->out_fd, old_wim_end, SEEK_SET) == -1) { ERROR_WITH_ERRNO("Can't seek to end of WIM"); close_wim_writable(w); - w->wim_locked = 0; - return WIMLIB_ERR_WRITE; + ret = WIMLIB_ERR_WRITE; + goto out_unlock_wim; } DEBUG("Writing newly added streams (offset = %"PRIu64")", @@ -2105,7 +2134,7 @@ overwrite_wim_inplace(WIMStruct *w, int write_flags, ret = write_stream_list(&stream_list, w->lookup_table, w->out_fd, - wimlib_get_compression_type(w), + w->compression_type, write_flags, num_threads, progress_func); @@ -2132,6 +2161,7 @@ out_truncate: * an error path. */ (void)ttruncate(w->filename, old_wim_end); } +out_unlock_wim: w->wim_locked = 0; return ret; } @@ -2196,15 +2226,16 @@ wimlib_overwrite(WIMStruct *w, int write_flags, unsigned num_threads, wimlib_progress_func_t progress_func) { + int ret; + write_flags &= WIMLIB_WRITE_MASK_PUBLIC; if (!w->filename) return WIMLIB_ERR_NO_FILENAME; - if (w->hdr.total_parts != 1) { - ERROR("Cannot modify a split WIM"); - return WIMLIB_ERR_SPLIT_UNSUPPORTED; - } + ret = can_modify_wim(w); + if (ret) + return ret; if ((!w->deletion_occurred || (write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE)) && !(write_flags & WIMLIB_WRITE_FLAG_REBUILD))