X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fresource.c;h=1871cfcccb8617ba005124652507c555f933f480;hp=43ecc0a8d252c3fbf7e66e836102574807e88f52;hb=051a59e4c6d114fc7abfa14ff78436adab5defb9;hpb=b2897d543df1dfbadcbf50d5c013c24866151de7 diff --git a/src/resource.c b/src/resource.c index 43ecc0a8..1871cfcc 100644 --- a/src/resource.c +++ b/src/resource.c @@ -421,6 +421,57 @@ u8 *put_resource_entry(u8 *p, const struct resource_entry *entry) return p; } +static FILE *wim_get_fp(WIMStruct *w) +{ + pthread_mutex_lock(&w->fp_tab_mutex); + FILE *fp; + + wimlib_assert(w->filename != NULL); + + for (size_t i = 0; i < w->num_allocated_fps; i++) { + if (w->fp_tab[i]) { + fp = w->fp_tab[i]; + w->fp_tab[i] = NULL; + goto out; + } + } + DEBUG("Opening extra file descriptor to `%s'", w->filename); + fp = fopen(w->filename, "rb"); + if (!fp) + ERROR_WITH_ERRNO("Failed to open `%s'", w->filename); +out: + pthread_mutex_unlock(&w->fp_tab_mutex); + return fp; +} + +static int wim_release_fp(WIMStruct *w, FILE *fp) +{ + int ret = 0; + FILE **fp_tab; + + pthread_mutex_lock(&w->fp_tab_mutex); + + for (size_t i = 0; i < w->num_allocated_fps; i++) { + if (w->fp_tab[i] == NULL) { + w->fp_tab[i] = fp; + goto out; + } + } + + fp_tab = REALLOC(w->fp_tab, sizeof(FILE*) * (w->num_allocated_fps + 4)); + if (!fp_tab) { + ret = WIMLIB_ERR_NOMEM; + goto out; + } + w->fp_tab = fp_tab; + memset(&w->fp_tab[w->num_allocated_fps], 0, 4 * sizeof(FILE*)); + w->fp_tab[w->num_allocated_fps] = fp; + w->num_allocated_fps += 4; +out: + pthread_mutex_unlock(&w->fp_tab_mutex); + return ret; +} + /* * Reads some data from the resource corresponding to a WIM lookup table entry. * @@ -428,13 +479,11 @@ u8 *put_resource_entry(u8 *p, const struct resource_entry *entry) * @buf: Buffer into which to write the data. * @size: Number of bytes to read. * @offset: Offset at which to start reading the resource. - * @raw: If %true, compressed data is read literally rather than being - * decompressed first. * * Returns zero on success, nonzero on failure. */ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], - size_t size, u64 offset, bool raw) + size_t size, u64 offset, int flags) { int ctype; int ret = 0; @@ -442,7 +491,7 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], /* We shouldn't be allowing read over-runs in any part of the library. * */ - if (raw) + if (flags & WIMLIB_RESOURCE_FLAG_RAW) wimlib_assert(offset + size <= lte->resource_entry.size); else wimlib_assert(offset + size <= lte->resource_entry.original_size); @@ -453,23 +502,38 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], * the lte->wim member. The resource may be either compressed * or uncompressed. */ wimlib_assert(lte->wim != NULL); - wimlib_assert(lte->wim->fp != NULL); + + if (flags & WIMLIB_RESOURCE_FLAG_MULTITHREADED) { + fp = wim_get_fp(lte->wim); + if (!fp) + return WIMLIB_ERR_OPEN; + } else { + wimlib_assert(lte->wim->fp != NULL); + fp = lte->wim->fp; + } + ctype = wim_resource_compression_type(lte); wimlib_assert(ctype != WIM_COMPRESSION_TYPE_NONE || (lte->resource_entry.original_size == lte->resource_entry.size)); - if (raw || ctype == WIM_COMPRESSION_TYPE_NONE) - ret = read_uncompressed_resource(lte->wim->fp, + if ((flags & WIMLIB_RESOURCE_FLAG_RAW) + || ctype == WIM_COMPRESSION_TYPE_NONE) + ret = read_uncompressed_resource(fp, lte->resource_entry.offset + offset, size, buf); else - ret = read_compressed_resource(lte->wim->fp, + ret = read_compressed_resource(fp, lte->resource_entry.size, lte->resource_entry.original_size, lte->resource_entry.offset, ctype, size, offset, buf); + if (flags & WIMLIB_RESOURCE_FLAG_MULTITHREADED) { + int ret2 = wim_release_fp(lte->wim, fp); + if (ret == 0) + ret = ret2; + } break; case RESOURCE_IN_STAGING_FILE: case RESOURCE_IN_FILE_ON_DISK: @@ -534,9 +598,10 @@ int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[], * * Returns 0 on success; nonzero on failure. */ -int read_full_wim_resource(const struct lookup_table_entry *lte, u8 buf[]) +int read_full_wim_resource(const struct lookup_table_entry *lte, u8 buf[], + int flags) { - return read_wim_resource(lte, buf, wim_resource_size(lte), 0, false); + return read_wim_resource(lte, buf, wim_resource_size(lte), 0, flags); } /* Chunk table that's located at the beginning of each compressed resource in @@ -748,7 +813,8 @@ finish_wim_resource_chunk_tab(struct chunk_table *chunk_tab, */ static int write_wim_resource(struct lookup_table_entry *lte, FILE *out_fp, int out_ctype, - struct resource_entry *out_res_entry) + struct resource_entry *out_res_entry, + int flags) { u64 bytes_remaining; u64 original_size; @@ -783,10 +849,14 @@ static int write_wim_resource(struct lookup_table_entry *lte, * without decompressing and recompressing the data). */ raw = (wim_resource_compression_type(lte) == out_ctype && out_ctype != WIM_COMPRESSION_TYPE_NONE); - if (raw) + + if (raw) { + flags |= WIMLIB_RESOURCE_FLAG_RAW; bytes_remaining = old_compressed_size; - else + } else { + flags &= ~WIMLIB_RESOURCE_FLAG_RAW; bytes_remaining = original_size; + } /* Empty resource; nothing needs to be done, so just return success. */ if (bytes_remaining == 0) @@ -859,7 +929,7 @@ static int write_wim_resource(struct lookup_table_entry *lte, offset = 0; do { u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE); - ret = read_wim_resource(lte, buf, to_read, offset, raw); + ret = read_wim_resource(lte, buf, to_read, offset, flags); if (ret != 0) goto out_fclose; if (!raw) @@ -928,7 +998,7 @@ static int write_wim_resource(struct lookup_table_entry *lte, goto out_fclose; } ret = write_wim_resource(lte, out_fp, WIM_COMPRESSION_TYPE_NONE, - out_res_entry); + out_res_entry, flags); if (ret != 0) goto out_fclose; if (fflush(out_fp) != 0) { @@ -994,7 +1064,7 @@ static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size, lte.attached_buffer = (u8*)buf; zero_out_hash(lte.hash); - ret = write_wim_resource(<e, out_fp, out_ctype, out_res_entry); + ret = write_wim_resource(<e, out_fp, out_ctype, out_res_entry, 0); if (ret != 0) return ret; copy_hash(hash, lte.hash); @@ -1021,7 +1091,7 @@ int extract_wim_resource_to_fd(const struct lookup_table_entry *lte, int fd, while (bytes_remaining) { u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE); - ret = read_wim_resource(lte, buf, to_read, offset, false); + ret = read_wim_resource(lte, buf, to_read, offset, 0); if (ret != 0) break; sha1_update(&ctx, buf, to_read); @@ -1075,7 +1145,7 @@ int copy_resource(struct lookup_table_entry *lte, void *wim) ret = write_wim_resource(lte, w->out_fp, wim_resource_compression_type(lte), - <e->output_resource_entry); + <e->output_resource_entry, 0); if (ret != 0) return ret; lte->out_refcnt = lte->refcnt; @@ -1108,7 +1178,7 @@ int write_dentry_resources(struct dentry *dentry, void *wim_p) lte = inode_stream_lte(dentry->d_inode, i, w->lookup_table); if (lte && ++lte->out_refcnt == 1) { ret = write_wim_resource(lte, w->out_fp, ctype, - <e->output_resource_entry); + <e->output_resource_entry, 0); if (ret != 0) break; } @@ -1179,7 +1249,7 @@ int read_metadata_resource(WIMStruct *w, struct image_metadata *imd) } /* Read the metadata resource into memory. (It may be compressed.) */ - ret = read_full_wim_resource(metadata_lte, buf); + ret = read_full_wim_resource(metadata_lte, buf, 0); if (ret != 0) goto out_free_buf;