X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fwrite.c;h=39e8bd0af5a8c75002cb47c17fbd524e0529e694;hb=27bb04887c1bee17ed06e24a71f3cfc9d51eb3a1;hp=2baba967390bd4cdda51c079c3cb8f66f409449b;hpb=b98b25b85877d1bccdc8673a23576b1fac0ab1c6;p=wimlib diff --git a/src/write.c b/src/write.c index 2baba967..39e8bd0a 100644 --- a/src/write.c +++ b/src/write.c @@ -43,6 +43,7 @@ #include "wimlib/integrity.h" #include "wimlib/lookup_table.h" #include "wimlib/metadata.h" +#include "wimlib/paths.h" #include "wimlib/progress.h" #include "wimlib/resource.h" #ifdef __WIN32__ @@ -64,6 +65,7 @@ #define WRITE_RESOURCE_FLAG_RECOMPRESS 0x00000001 #define WRITE_RESOURCE_FLAG_PIPABLE 0x00000002 #define WRITE_RESOURCE_FLAG_PACK_STREAMS 0x00000004 +#define WRITE_RESOURCE_FLAG_SEND_DONE_WITH_FILE 0x00000008 static inline int write_flags_to_resource_flags(int write_flags) @@ -76,6 +78,8 @@ write_flags_to_resource_flags(int write_flags) write_resource_flags |= WRITE_RESOURCE_FLAG_PIPABLE; if (write_flags & WIMLIB_WRITE_FLAG_PACK_STREAMS) write_resource_flags |= WRITE_RESOURCE_FLAG_PACK_STREAMS; + if (write_flags & WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES) + write_resource_flags |= WRITE_RESOURCE_FLAG_SEND_DONE_WITH_FILE; return write_resource_flags; } @@ -98,12 +102,15 @@ static int stream_filtered(const struct wim_lookup_table_entry *lte, const struct filter_context *ctx) { - int write_flags = ctx->write_flags; - WIMStruct *wim = ctx->wim; + int write_flags; + WIMStruct *wim; if (ctx == NULL) return 0; + write_flags = ctx->write_flags; + wim = ctx->wim; + if (write_flags & WIMLIB_WRITE_FLAG_OVERWRITE && lte->resource_location == RESOURCE_IN_WIM && lte->rspec->wim == wim) @@ -312,10 +319,28 @@ do_write_streams_progress(struct write_streams_progress_data *progress_data, if (progress_data->next_progress == progress->write_streams.total_bytes) { progress_data->next_progress = ~(uint64_t)0; } else { + /* Handle rate-limiting of messages */ + + /* Send new message as soon as another 1/128 of the + * total has been written. (Arbitrary number.) */ progress_data->next_progress = - min(progress->write_streams.total_bytes, - progress->write_streams.completed_bytes + - progress->write_streams.total_bytes / 100); + progress->write_streams.completed_bytes + + progress->write_streams.total_bytes / 128; + + /* ... Unless that would be more than 5000000 bytes, in + * which case send the next after the next 5000000 + * bytes. (Another arbitrary number.) */ + if (progress->write_streams.completed_bytes + 5000000 < + progress_data->next_progress) + progress_data->next_progress = + progress->write_streams.completed_bytes + 5000000; + + /* ... But always send a message as soon as we're + * completely done. */ + if (progress->write_streams.total_bytes < + progress_data->next_progress) + progress_data->next_progress = + progress->write_streams.total_bytes; } } return 0; @@ -372,6 +397,8 @@ struct write_streams_ctx { * pending_streams rather than the entry being read.) */ bool stream_was_duplicate; + struct wim_inode *stream_inode; + /* Current uncompressed offset in the stream being read. */ u64 cur_read_stream_offset; @@ -618,10 +645,77 @@ end_write_resource(struct write_streams_ctx *ctx, struct wim_reshdr *out_reshdr) return 0; } +/* No more data streams of the file at @path are needed. */ +static int +done_with_file(const tchar *path, wimlib_progress_func_t progfunc, void *progctx) +{ + union wimlib_progress_info info; + + info.done_with_file.path_to_file = path; + + return call_progress(progfunc, WIMLIB_PROGRESS_MSG_DONE_WITH_FILE, + &info, progctx); +} + +/* Handle WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES mode. */ +static int +done_with_stream(struct wim_lookup_table_entry *stream, + wimlib_progress_func_t progfunc, void *progctx, + struct wim_inode *inode) +{ + if (stream->resource_location == RESOURCE_IN_FILE_ON_DISK +#ifdef __WIN32__ + || stream->resource_location == RESOURCE_IN_WINNT_FILE_ON_DISK + || stream->resource_location == RESOURCE_WIN32_ENCRYPTED +#endif + ) + { + int ret; + + wimlib_assert(inode->num_unread_streams > 0); + if (--inode->num_unread_streams > 0) + return 0; + + #ifdef __WIN32__ + /* XXX: This logic really should be somewhere else. */ + + /* We want the path to the file, but stream->file_on_disk might + * actually refer to a named data stream. Temporarily strip the + * named data stream from the path. */ + wchar_t *p_colon = NULL; + wchar_t *p_question_mark = NULL; + const wchar_t *p_stream_name; + + p_stream_name = path_stream_name(stream->file_on_disk); + if (unlikely(p_stream_name)) { + p_colon = (wchar_t *)(p_stream_name - 1); + wimlib_assert(*p_colon == L':'); + *p_colon = L'\0'; + } + + /* We also should use a fake Win32 path instead of a NT path */ + if (!wcsncmp(stream->file_on_disk, L"\\??\\", 4)) { + p_question_mark = &stream->file_on_disk[1]; + *p_question_mark = L'\\'; + } + #endif + + ret = done_with_file(stream->file_on_disk, progfunc, progctx); + + #ifdef __WIN32__ + if (p_colon) + *p_colon = L':'; + if (p_question_mark) + *p_question_mark = L'?'; + #endif + return ret; + } + return 0; +} + /* Begin processing a stream for writing. */ static int -write_stream_begin_read(struct wim_lookup_table_entry *lte, - u32 flags, void *_ctx) +write_stream_begin_read(struct wim_lookup_table_entry *lte, void *_ctx) { struct write_streams_ctx *ctx = _ctx; int ret; @@ -631,6 +725,11 @@ write_stream_begin_read(struct wim_lookup_table_entry *lte, ctx->cur_read_stream_offset = 0; ctx->cur_read_stream_size = lte->size; + if (lte->unhashed) + ctx->stream_inode = lte->back_inode; + else + ctx->stream_inode = NULL; + /* As an optimization, we allow some streams to be "unhashed", meaning * their SHA1 message digests are unknown. This is the case with * streams that are added by scanning a directry tree with @@ -645,8 +744,6 @@ write_stream_begin_read(struct wim_lookup_table_entry *lte, ctx->stream_was_duplicate = false; if (ctx->lookup_table != NULL && lte->unhashed && !lte->unique_size) { - wimlib_assert(!(flags & BEGIN_STREAM_FLAG_PARTIAL_RESOURCE)); - struct wim_lookup_table_entry *lte_new; ret = hash_unhashed_stream(lte, ctx->lookup_table, <e_new); @@ -675,6 +772,14 @@ write_stream_begin_read(struct wim_lookup_table_entry *lte, lte_new->out_refcnt += lte->out_refcnt; if (ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PACK_STREAMS) ctx->cur_write_res_size -= lte->size; + if (!ret && unlikely(ctx->write_resource_flags & + WRITE_RESOURCE_FLAG_SEND_DONE_WITH_FILE)) + { + ret = done_with_stream(lte, + ctx->progress_data.progfunc, + ctx->progress_data.progctx, + ctx->stream_inode); + } free_lookup_table_entry(lte); if (ret) return ret; @@ -863,7 +968,8 @@ write_chunk(struct write_streams_ctx *ctx, const void *cchunk, if (ctx->compressor != NULL && lte->out_reshdr.size_in_wim >= lte->out_reshdr.uncompressed_size && - !(ctx->write_resource_flags & WRITE_RESOURCE_FLAG_PIPABLE) && + !(ctx->write_resource_flags & (WRITE_RESOURCE_FLAG_PIPABLE | + WRITE_RESOURCE_FLAG_SEND_DONE_WITH_FILE)) && !(lte->flags & WIM_RESHDR_FLAG_PACKED_STREAMS)) { /* Stream did not compress to less than its original @@ -1006,15 +1112,31 @@ static int write_stream_end_read(struct wim_lookup_table_entry *lte, int status, void *_ctx) { struct write_streams_ctx *ctx = _ctx; - if (status == 0) - wimlib_assert(ctx->cur_read_stream_offset == ctx->cur_read_stream_size); - if (ctx->stream_was_duplicate) { - free_lookup_table_entry(lte); - } else if (lte->unhashed && ctx->lookup_table != NULL) { + if (status) + goto out; + + wimlib_assert(ctx->cur_read_stream_offset == ctx->cur_read_stream_size); + + if (unlikely(ctx->write_resource_flags & + WRITE_RESOURCE_FLAG_SEND_DONE_WITH_FILE) && + ctx->stream_inode != NULL) + { + status = done_with_stream(lte, + ctx->progress_data.progfunc, + ctx->progress_data.progctx, + ctx->stream_inode); + } + + if (!ctx->stream_was_duplicate && lte->unhashed && + ctx->lookup_table != NULL) + { list_del(<e->unhashed_list); lookup_table_insert(ctx->lookup_table, lte); lte->unhashed = 0; } +out: + if (ctx->stream_was_duplicate) + free_lookup_table_entry(lte); return status; } @@ -2050,6 +2172,17 @@ write_wim_streams(WIMStruct *wim, int image, int write_flags, } } + /* If needed, set auxiliary information so that we can detect when + * wimlib has finished using each external file. */ + if (unlikely(write_flags & WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES)) { + list_for_each_entry(lte, stream_list, write_streams_list) + if (lte->unhashed) + lte->back_inode->num_unread_streams = 0; + list_for_each_entry(lte, stream_list, write_streams_list) + if (lte->unhashed) + lte->back_inode->num_unread_streams++; + } + return wim_write_stream_list(wim, stream_list, write_flags,