* only allows the Administrator to create symbolic links. */
#define WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS 0x00008000
+/** wimlib_extract_blobs(): extract all data blobs. */
+#define WIMLIB_EXTRACT_FLAG_ALL_DATA_BLOBS 0x00010000
+
+/** wimlib_extract_blobs(): extract all metadata blobs. */
+#define WIMLIB_EXTRACT_FLAG_ALL_METADATA_BLOBS 0x00020000
+
/**
* For wimlib_extract_paths() and wimlib_extract_pathlist() only: Treat the
* paths to extract as wildcard patterns ("globs") which may contain the
wimlib_delete_path(WIMStruct *wim, int image,
const wimlib_tchar *path, int delete_flags);
+/**
+ * @ingroup G_extracting_wims
+ *
+ * Extract blobs identified by SHA-1 message digest.
+ *
+ * This is a special-purpose function usually used for debugging. You may be
+ * looking for wimlib_extract_paths().
+ *
+ * @param wim
+ * The ::WIMStruct for the WIM file from which to extract the blob.
+ *
+ * @param blob_sha1s
+ * An array of SHA-1 message digests of blobs to extract. Each SHA-1
+ * message digest is 20 bytes.
+ *
+ * @param num_blobs
+ * The number of blobs to extract --- that is, the number of SHA-1 message
+ * digests specified in @p blob_sha1s.
+ *
+ * @param target
+ * The directory to which to extract the blobs. Each blob will be
+ * extracted to a file in this directory named after the hexadecimal
+ * representation of its SHA-1 message digest.
+ *
+ * @param extract_flags
+ * Reserved; must be 0.
+ *
+ * @return 0 on success; nonzero on failure. Some of the possible error codes
+ * are:
+ *
+ * @retval ::WIMLIB_ERR_DECOMPRESSION
+ * The compressed data of one of the blobs was invalid.
+ * @retval ::WIMLIB_ERR_INVALID_RESOURCE_HASH
+ * One of the blobs was corrupted.
+ * @retval ::WIMLIB_ERR_RESOURCE_NOT_FOUND
+ * One of the specified blobs could not be found in the WIM.
+ * @retval ::WIMLIB_ERR_WRITE
+ * Failed to write data to one of the files.
+ */
+extern int
+wimlib_extract_blobs(WIMStruct *wim,
+ const uint8_t *blob_sha1s, size_t num_blobs,
+ const wimlib_tchar *target, int extract_flags);
+
/**
* @ingroup G_modifying_wims
*
IMAGEX_DEREFERENCE_OPTION,
IMAGEX_DEST_DIR_OPTION,
IMAGEX_DETAILED_OPTION,
+ IMAGEX_DUMP_BLOB_OPTION,
+ IMAGEX_DUMP_DATA_BLOBS_OPTION,
+ IMAGEX_DUMP_METADATA_BLOBS_OPTION,
+ IMAGEX_DUMP_ALL_BLOBS_OPTION,
IMAGEX_EXTRACT_XML_OPTION,
IMAGEX_FLAGS_OPTION,
IMAGEX_FORCE_OPTION,
{T("preserve-dir-structure"), no_argument, NULL, IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION},
{T("wimboot"), no_argument, NULL, IMAGEX_WIMBOOT_OPTION},
{T("compact"), required_argument, NULL, IMAGEX_COMPACT_OPTION},
+ {T("dump-blob"), required_argument, NULL, IMAGEX_DUMP_BLOB_OPTION},
+ {T("dump-data-blobs"), no_argument, NULL, IMAGEX_DUMP_DATA_BLOBS_OPTION},
+ {T("dump-metadata-blobs"), no_argument, NULL, IMAGEX_DUMP_METADATA_BLOBS_OPTION},
+ {T("dump-all-blobs"), no_argument, NULL, IMAGEX_DUMP_ALL_BLOBS_OPTION},
{NULL, 0, NULL, 0},
};
return translate_text_to_tstr(contents, num_bytes, num_tchars_ret);
}
+static int
+parse_sha1(const tchar *hashstr, uint8_t hash[20])
+{
+ if (tstrlen(hashstr) != 40)
+ goto invalid;
+
+ for (int i = 0; i < 20; i++) {
+ tchar high = totlower(hashstr[i * 2 + 0]);
+ tchar low = totlower(hashstr[i * 2 + 1]);
+ uint8_t byte = 0;
+
+ if (high >= '0' && high <= '9')
+ byte |= (high - '0') << 4;
+ else if (high >= 'a' && high <= 'f')
+ byte |= (high - 'a' + 10) << 4;
+ else
+ goto invalid;
+
+ if (low >= '0' && low <= '9')
+ byte |= (low - '0');
+ else if (low >= 'a' && low <= 'f')
+ byte |= (low - 'a' + 10);
+ else
+ goto invalid;
+ hash[i] = byte;
+ }
+
+ return 0;
+
+invalid:
+ imagex_error("\"%"TS"\" is not a well-formed SHA-1 message digest!",
+ hashstr);
+ return -1;
+}
+
#define TO_PERCENT(numerator, denominator) \
(((denominator) == 0) ? 0 : ((numerator) * 100 / (denominator)))
WIMLIB_EXTRACT_FLAG_GLOB_PATHS |
WIMLIB_EXTRACT_FLAG_STRICT_GLOB;
int notlist_extract_flags = WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE;
+ const tchar *blob_to_dump = NULL;
STRING_LIST(refglobs);
if (ret)
goto out_free_refglobs;
break;
+ case IMAGEX_DUMP_DATA_BLOBS_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_DATA_BLOBS;
+ break;
+ case IMAGEX_DUMP_METADATA_BLOBS_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_METADATA_BLOBS;
+ break;
+ case IMAGEX_DUMP_ALL_BLOBS_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_DATA_BLOBS |
+ WIMLIB_EXTRACT_FLAG_ALL_METADATA_BLOBS;
+ break;
+ case IMAGEX_DUMP_BLOB_OPTION:
+ blob_to_dump = optarg;
+ break;
default:
goto out_usage;
}
argc -= optind;
argv += optind;
+ if (blob_to_dump ||
+ (extract_flags & (WIMLIB_EXTRACT_FLAG_ALL_DATA_BLOBS |
+ WIMLIB_EXTRACT_FLAG_ALL_METADATA_BLOBS)))
+ {
+ uint8_t hash[20];
+ unsigned num_hashes = 0;
+
+ if (argc != 1) {
+ imagex_error(T("Can't specify an image in combination "
+ "with any of the \"dump blobs\" "
+ "options"));
+ goto out_err;
+ }
+
+ ret = wimlib_open_wim_with_progress(argv[0], open_flags, &wim,
+ imagex_progress_func, NULL);
+ if (ret)
+ goto out_free_refglobs;
+
+ if (blob_to_dump) {
+ ret = parse_sha1(blob_to_dump, hash);
+ if (ret)
+ goto out_wimlib_free;
+ num_hashes++;
+ }
+ ret = wimlib_extract_blobs(wim, hash, num_hashes, dest_dir,
+ extract_flags);
+ goto out_wimlib_free;
+ }
+
if (argc < 2)
goto out_usage;
WIMLIB_EXTRACT_FLAG_TO_STDOUT | \
WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES | \
WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS | \
+ WIMLIB_EXTRACT_FLAG_ALL_DATA_BLOBS | \
+ WIMLIB_EXTRACT_FLAG_ALL_METADATA_BLOBS | \
WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS | \
WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES | \
WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS | \
}
}
+static int
+extract_blob_to_stdout(struct blob_descriptor *blob)
+{
+ struct filedes _stdout;
+
+ filedes_init(&_stdout, STDOUT_FILENO);
+ return extract_blob_to_fd(blob, &_stdout);
+}
+
/* Extract a WIM dentry to standard output.
*
* This obviously doesn't make sense in all cases. We return an error if the
{
struct wim_inode *inode = dentry->d_inode;
struct blob_descriptor *blob;
- struct filedes _stdout;
if (inode->i_attributes & (FILE_ATTRIBUTE_REPARSE_POINT |
FILE_ATTRIBUTE_DIRECTORY |
return 0;
}
- filedes_init(&_stdout, STDOUT_FILENO);
- return extract_blob_to_fd(blob, &_stdout);
+ return extract_blob_to_stdout(blob);
}
static int
return WIMLIB_ERR_INVALID_PARAM;
return do_wimlib_extract_image(wim, image, target, extract_flags);
}
+
+/* Extract a list of blobs to the specified directory.
+ *
+ * This is somewhat of a hack: we generate a temporary WIM in memory so that we
+ * can just send it through the regular extraction code. */
+static int
+do_wimlib_extract_blobs(struct list_head *blob_list, const tchar *target,
+ wimlib_progress_func_t progfunc, void *progctx,
+ int extract_flags)
+{
+ WIMStruct *tmp_wim = NULL;
+ int ret;
+ struct blob_descriptor *blob;
+ tchar name_buf[SHA1_HASH_SIZE * 2 + 1];
+ struct wim_dentry *root_dentry;
+ struct wim_dentry *dentry;
+ struct wim_dentry *existing;
+ struct wim_image_metadata *imd;
+ const tchar *root_path = WIMLIB_WIM_ROOT_PATH;
+
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT) {
+ list_for_each_entry(blob, blob_list, extraction_list) {
+ ret = extract_blob_to_stdout(blob);
+ if (ret)
+ goto out;
+ }
+ return 0;
+ }
+
+ ret = wimlib_create_new_wim(WIMLIB_COMPRESSION_TYPE_NONE, &tmp_wim);
+ if (ret)
+ goto out;
+
+ wimlib_register_progress_function(tmp_wim, progfunc, progctx);
+
+ ret = wimlib_add_empty_image(tmp_wim, NULL, NULL);
+ if (ret)
+ goto out;
+
+ ret = select_wim_image(tmp_wim, 1);
+ if (ret)
+ goto out;
+
+ ret = new_filler_directory(&root_dentry);
+ if (ret)
+ goto out;
+
+ imd = wim_get_current_image_metadata(tmp_wim);
+
+ imd->root_dentry = root_dentry;
+
+ list_for_each_entry(blob, blob_list, extraction_list) {
+
+ sprint_hash(blob->hash, name_buf);
+
+ ret = new_dentry_with_new_inode(name_buf, true, &dentry);
+ if (ret)
+ goto out;
+
+ ret = WIMLIB_ERR_NOMEM;
+ if (!inode_add_stream(dentry->d_inode, STREAM_TYPE_DATA,
+ NO_STREAM_NAME, blob))
+ goto out;
+ hlist_add_head(&dentry->d_inode->i_hlist_node, &imd->inode_list);
+
+ existing = dentry_add_child(root_dentry, dentry);
+ wimlib_assert(!existing);
+ }
+
+ ret = do_wimlib_extract_paths(tmp_wim, 1, target, &root_path, 1,
+ extract_flags);
+out:
+ wimlib_free(tmp_wim);
+ return ret;
+}
+
+static struct blob_descriptor *
+lookup_data_or_metadata_blob(WIMStruct *wim, const u8 *hash)
+{
+ struct blob_descriptor *blob;
+
+ blob = lookup_blob(wim->blob_table, hash);
+ if (blob)
+ return blob;
+
+ if (wim_has_metadata(wim))
+ for (int i = 0; i < wim->hdr.image_count; i++)
+ if (hashes_equal(hash, wim->image_metadata[i]-> metadata_blob->hash))
+ return wim->image_metadata[i]->metadata_blob;
+ return NULL;
+}
+
+static int
+add_blob_to_list(struct blob_descriptor *blob, void *_list)
+{
+ list_add(&blob->extraction_list, (struct list_head *)_list);
+ return 0;
+}
+
+/* Extract the specified blobs from a WIM to a directory. */
+WIMLIBAPI int
+wimlib_extract_blobs(WIMStruct *wim, const u8 *blob_sha1s, size_t num_blobs,
+ const tchar *target, int extract_flags)
+{
+ const u8 *hashptr;
+ const u8 *hashend;
+ struct blob_descriptor *blob;
+
+ LIST_HEAD(blob_list);
+
+ if (!wim || !target || !*target)
+ return WIMLIB_ERR_INVALID_PARAM;
+
+ if (num_blobs && !blob_sha1s)
+ return WIMLIB_ERR_INVALID_PARAM;
+
+ if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
+ return WIMLIB_ERR_INVALID_PARAM;
+
+ extract_flags &= ~WIMLIB_EXTRACT_FLAG_GLOB_PATHS;
+
+ if (extract_flags & (WIMLIB_EXTRACT_FLAG_ALL_DATA_BLOBS |
+ WIMLIB_EXTRACT_FLAG_ALL_METADATA_BLOBS))
+ {
+ /* Add all the data blobs. */
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_ALL_DATA_BLOBS)
+ for_blob_in_table(wim->blob_table, add_blob_to_list,
+ &blob_list);
+
+ /* Also add the metadata blobs. */
+ if ((extract_flags & WIMLIB_EXTRACT_FLAG_ALL_METADATA_BLOBS)
+ && wim_has_metadata(wim))
+ for (int i = 0; i < wim->hdr.image_count; i++)
+ add_blob_to_list(wim->image_metadata[i]->metadata_blob,
+ &blob_list);
+ } else {
+ hashptr = blob_sha1s;
+ hashend = hashptr + (num_blobs * SHA1_HASH_SIZE);
+
+ /* Look up each blob requested. */
+ for (; hashptr != hashend; hashptr += SHA1_HASH_SIZE) {
+
+ blob = lookup_data_or_metadata_blob(wim, hashptr);
+ if (!blob) {
+ if (wimlib_print_errors) {
+ tchar hashstr[SHA1_HASH_SIZE * 2 + 1];
+ sprint_hash(hashptr, hashstr);
+ ERROR("Stream SHA1=%"TS" not found",
+ hashstr);
+ }
+ return WIMLIB_ERR_RESOURCE_NOT_FOUND;
+ }
+ add_blob_to_list(blob, &blob_list);
+ }
+ }
+
+ /* Extract the blobs. */
+ return do_wimlib_extract_blobs(&blob_list, target, wim->progfunc,
+ wim->progctx, extract_flags);
+}