#include "lzx.h"
#include "xpress.h"
#include <unistd.h>
+
+#ifdef ENABLE_MULTITHREADED_COMPRESSION
#include <semaphore.h>
#include <pthread.h>
#include <errno.h>
+#endif
#ifdef WITH_NTFS_3G
#include <time.h>
#ifdef HAVE_ALLOCA_H
#include <alloca.h>
+#else
+#include <stdlib.h>
#endif
-
/* Reopens the FILE* for a WIM read-write. */
static int reopen_rw(WIMStruct *w)
{
WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int write_flags,
unsigned num_threads)
{
- const char *wimfile_name;
size_t wim_name_len;
int ret;
return WIMLIB_ERR_INVALID_PARAM;
write_flags &= ~WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE;
-
- wimfile_name = w->filename;
-
- DEBUG("Replacing WIM file `%s'.", wimfile_name);
-
- if (!wimfile_name)
+ if (!w->filename)
return WIMLIB_ERR_NO_FILENAME;
+ DEBUG("Replacing WIM file `%s'.", w->filename);
+
/* Write the WIM to a temporary file. */
/* XXX should the temporary file be somewhere else? */
- wim_name_len = strlen(wimfile_name);
+ wim_name_len = strlen(w->filename);
char tmpfile[wim_name_len + 10];
- memcpy(tmpfile, wimfile_name, wim_name_len);
+ memcpy(tmpfile, w->filename, wim_name_len);
randomize_char_array_with_alnum(tmpfile + wim_name_len, 9);
tmpfile[wim_name_len + 9] = '\0';
- ret = wimlib_write(w, tmpfile, WIM_ALL_IMAGES, write_flags,
+ ret = wimlib_write(w, tmpfile, WIM_ALL_IMAGES,
+ write_flags | WIMLIB_WRITE_FLAG_FSYNC,
num_threads);
if (ret != 0) {
ERROR("Failed to write the WIM file `%s'", tmpfile);
/* Close the original WIM file that was opened for reading. */
if (w->fp) {
if (fclose(w->fp) != 0) {
- WARNING("Failed to close the file `%s'", wimfile_name);
+ WARNING("Failed to close the file `%s'", w->filename);
}
w->fp = NULL;
}
- DEBUG("Renaming `%s' to `%s'", tmpfile, wimfile_name);
+ DEBUG("Renaming `%s' to `%s'", tmpfile, w->filename);
/* Rename the new file to the old file .*/
- if (rename(tmpfile, wimfile_name) != 0) {
+ if (rename(tmpfile, w->filename) != 0) {
ERROR_WITH_ERRNO("Failed to rename `%s' to `%s'",
- tmpfile, wimfile_name);
- /* Remove temporary file. */
- if (unlink(tmpfile) != 0)
- ERROR_WITH_ERRNO("Failed to remove `%s'", tmpfile);
- return WIMLIB_ERR_RENAME;
+ tmpfile, w->filename);
+ ret = WIMLIB_ERR_RENAME;
+ goto err;
}
- if (write_flags & WIMLIB_WRITE_FLAG_VERBOSE)
- printf("Successfully renamed `%s' to `%s'\n", tmpfile, wimfile_name);
+ if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
+ printf("Successfully renamed `%s' to `%s'\n", tmpfile, w->filename);
return 0;
+err:
+ /* Remove temporary file. */
+ if (unlink(tmpfile) != 0)
+ ERROR_WITH_ERRNO("Failed to remove `%s'", tmpfile);
+ return ret;
}
static int check_resource_offset(struct lookup_table_entry *lte, void *arg)
}
+#ifdef ENABLE_MULTITHREADED_COMPRESSION
struct shared_queue {
sem_t filled_slots;
sem_t empty_slots;
}
DEBUG("Compressor thread terminating");
}
+#endif
static void show_stream_write_progress(u64 *cur_size, u64 *next_size,
u64 total_size, u64 one_percent,
return 0;
}
+#ifdef ENABLE_MULTITHREADED_COMPRESSION
static int write_wim_chunks(struct message *msg, FILE *out_fp,
struct chunk_table *chunk_tab)
{
return 0;
}
-
/*
* This function is executed by the main thread when the resources are being
* compressed in parallel. The main thread is in change of all reading of the
#else
ret = prepare_resource_for_read(next_lte);
#endif
+ if (ret != 0)
+ goto out;
DEBUG("Initializing buffers for uncompressed "
"and compressed data (%zu bytes needed)",
}
}
+ // This loop is executed until all resources have been written, except
+ // possibly a few that have been added to the @my_resources list for
+ // writing later.
while (1) {
// Send chunks to the compressor threads until either (a) there
// are no more messages available since they were all sent off,
DEBUG2("Complete msg (begin_chunk=%"PRIu64")", msg->begin_chunk);
if (msg->begin_chunk == 0) {
DEBUG2("Begin chunk tab");
-
-
-
if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
show_stream_write_progress(&cur_size,
&next_size,
#endif
if (ret == 0) {
list_for_each_entry(lte, &my_resources, staging_list) {
- ret = write_wim_resource(lte, out_fp,
- out_ctype,
- <e->output_resource_entry,
- 0);
- if (ret != 0)
- break;
if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
show_stream_write_progress(&cur_size,
&next_size,
&cur_percent,
lte);
}
+ ret = write_wim_resource(lte, out_fp,
+ out_ctype,
+ <e->output_resource_entry,
+ 0);
+ if (ret != 0)
+ break;
}
if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
finish_stream_write_progress(total_size);
return ret;
}
+
+static const char *get_data_type(int ctype)
+{
+ switch (ctype) {
+ case WIM_COMPRESSION_TYPE_NONE:
+ return "uncompressed";
+ case WIM_COMPRESSION_TYPE_LZX:
+ return "LZX-compressed";
+ case WIM_COMPRESSION_TYPE_XPRESS:
+ return "XPRESS-compressed";
+ }
+}
+
static int write_stream_list_parallel(struct list_head *stream_list,
FILE *out_fp, int out_ctype,
int write_flags, u64 total_size,
int ret;
struct shared_queue res_to_compress_queue;
struct shared_queue compressed_res_queue;
+ pthread_t *compressor_threads = NULL;
if (num_threads == 0) {
long nthreads = sysconf(_SC_NPROCESSORS_ONLN);
wimlib_assert(stream_list->next != stream_list);
- {
- pthread_t compressor_threads[num_threads];
- static const double MESSAGES_PER_THREAD = 2.0;
- size_t queue_size = (size_t)(num_threads * MESSAGES_PER_THREAD);
+ static const double MESSAGES_PER_THREAD = 2.0;
+ size_t queue_size = (size_t)(num_threads * MESSAGES_PER_THREAD);
- DEBUG("Initializing shared queues (queue_size=%zu)", queue_size);
+ DEBUG("Initializing shared queues (queue_size=%zu)", queue_size);
- ret = shared_queue_init(&res_to_compress_queue, queue_size);
- if (ret != 0)
- goto out_serial;
+ ret = shared_queue_init(&res_to_compress_queue, queue_size);
+ if (ret != 0)
+ goto out_serial;
- ret = shared_queue_init(&compressed_res_queue, queue_size);
- if (ret != 0)
- goto out_destroy_res_to_compress_queue;
-
- struct compressor_thread_params params;
- params.res_to_compress_queue = &res_to_compress_queue;
- params.compressed_res_queue = &compressed_res_queue;
- params.compress = get_compress_func(out_ctype);
-
- for (unsigned i = 0; i < num_threads; i++) {
- DEBUG("pthread_create thread %u", i);
- ret = pthread_create(&compressor_threads[i], NULL,
- compressor_thread_proc, ¶ms);
- if (ret != 0) {
- ERROR_WITH_ERRNO("Failed to create compressor "
- "thread %u", i);
- num_threads = i;
- goto out_join;
- }
+ ret = shared_queue_init(&compressed_res_queue, queue_size);
+ if (ret != 0)
+ goto out_destroy_res_to_compress_queue;
+
+ struct compressor_thread_params params;
+ params.res_to_compress_queue = &res_to_compress_queue;
+ params.compressed_res_queue = &compressed_res_queue;
+ params.compress = get_compress_func(out_ctype);
+
+ compressor_threads = MALLOC(num_threads * sizeof(pthread_t));
+
+ for (unsigned i = 0; i < num_threads; i++) {
+ DEBUG("pthread_create thread %u", i);
+ ret = pthread_create(&compressor_threads[i], NULL,
+ compressor_thread_proc, ¶ms);
+ if (ret != 0) {
+ ret = -1;
+ ERROR_WITH_ERRNO("Failed to create compressor "
+ "thread %u", i);
+ num_threads = i;
+ goto out_join;
}
+ }
- if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
- printf("Writing compressed data using %u threads...\n",
- num_threads);
- }
+ if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
+ printf("Writing %s compressed data using %u threads...\n",
+ get_data_type(out_ctype), num_threads);
+ }
- ret = main_writer_thread_proc(stream_list,
- out_fp,
- out_ctype,
- &res_to_compress_queue,
- &compressed_res_queue,
- queue_size,
- write_flags,
- total_size);
-
- out_join:
- for (unsigned i = 0; i < num_threads; i++)
- shared_queue_put(&res_to_compress_queue, NULL);
-
- for (unsigned i = 0; i < num_threads; i++) {
- if (pthread_join(compressor_threads[i], NULL)) {
- WARNING("Failed to join compressor thread %u: %s",
- i, strerror(errno));
- }
+ ret = main_writer_thread_proc(stream_list,
+ out_fp,
+ out_ctype,
+ &res_to_compress_queue,
+ &compressed_res_queue,
+ queue_size,
+ write_flags,
+ total_size);
+
+out_join:
+ for (unsigned i = 0; i < num_threads; i++)
+ shared_queue_put(&res_to_compress_queue, NULL);
+
+ for (unsigned i = 0; i < num_threads; i++) {
+ if (pthread_join(compressor_threads[i], NULL)) {
+ WARNING("Failed to join compressor thread %u: %s",
+ i, strerror(errno));
}
}
+ FREE(compressor_threads);
shared_queue_destroy(&compressed_res_queue);
out_destroy_res_to_compress_queue:
shared_queue_destroy(&res_to_compress_queue);
return write_stream_list_serial(stream_list, out_fp,
out_ctype, write_flags, total_size);
}
+#endif
static int write_stream_list(struct list_head *stream_list, FILE *out_fp,
int out_ctype, int write_flags,
wimlib_get_compression_type_string(out_ctype));
}
+#ifdef ENABLE_MULTITHREADED_COMPRESSION
if (compression_needed && total_size >= 1000000 && num_threads != 1) {
return write_stream_list_parallel(stream_list, out_fp,
out_ctype, write_flags,
total_size, num_threads);
- } else {
+ }
+ else
+#endif
+ {
if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS) {
const char *reason = "";
- if (num_threads != 1)
+ if (!compression_needed)
reason = " (no compression needed)";
- printf("Writing data using 1 thread%s\n", reason);
+ printf("Writing %s data using 1 thread%s\n",
+ get_data_type(out_ctype), reason);
}
return write_stream_list_serial(stream_list, out_fp,
return WIMLIB_ERR_WRITE;
xml_data_size = integrity_offset - xml_data_offset;
- hdr.xml_res_entry.offset = xml_data_offset;
- hdr.xml_res_entry.size = xml_data_size;
- hdr.xml_res_entry.original_size = xml_data_size;
- hdr.xml_res_entry.flags = 0;
+ hdr.xml_res_entry.offset = xml_data_offset;
+ hdr.xml_res_entry.size = xml_data_size;
+ hdr.xml_res_entry.original_size = xml_data_size;
+ hdr.xml_res_entry.flags = WIM_RESHDR_FLAG_METADATA;
if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) {
ret = write_integrity_table(out, WIM_HEADER_DISK_SIZE,
if (ret != 0)
return ret;
- DEBUG("Closing output file.");
- wimlib_assert(w->out_fp != NULL);
- if (fclose(w->out_fp) != 0) {
+ if (write_flags & WIMLIB_WRITE_FLAG_FSYNC) {
+ DEBUG("fsync output WIM file");
+ if (fflush(out) != 0
+ || fsync(fileno(out)) != 0)
+ {
+ ERROR_WITH_ERRNO("Error flushing data to WIM file");
+ ret = WIMLIB_ERR_WRITE;
+ }
+ }
+
+ DEBUG("Closing output WIM file.");
+
+ if (fclose(out) != 0) {
ERROR_WITH_ERRNO("Failed to close the WIM file");
ret = WIMLIB_ERR_WRITE;
}
return WIMLIB_ERR_INVALID_IMAGE;
+
if (w->hdr.total_parts != 1) {
ERROR("Cannot call wimlib_write() on part of a split WIM");
return WIMLIB_ERR_SPLIT_UNSUPPORTED;
return ret;
}
+ if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
+ printf("Writing image metadata...\n");
+
ret = for_image(w, image, write_metadata_resource);
if (ret != 0) {
if (ret != 0)
return ret;
- if (write_flags & WIMLIB_WRITE_FLAG_VERBOSE)
+ if (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS)
printf("Successfully wrote `%s'\n", path);
return 0;
}