#include <string.h>
#include <errno.h>
+#ifdef WITH_NTFS_3G
+#include <ntfs-3g/volume.h>
+#include <ntfs-3g/security.h>
+#endif
+
+/* Sets and creates the directory to which files are to be extracted when
+ * extracting files from the WIM. */
+static int set_output_dir(WIMStruct *w, const char *dir)
+{
+ char *p;
+ DEBUG("Setting output directory to `%s'", dir);
+
+ p = STRDUP(dir);
+ if (!p) {
+ ERROR("Out of memory");
+ return WIMLIB_ERR_NOMEM;
+ }
+
+ if (mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
+ if (errno == EEXIST) {
+ DEBUG("`%s' already exists", dir);
+ goto done;
+ }
+ ERROR_WITH_ERRNO("Cannot create directory `%s'", dir);
+ FREE(p);
+ return WIMLIB_ERR_MKDIR;
+ } else {
+ DEBUG("Created directory `%s'", dir);
+ }
+done:
+ FREE(w->output_dir);
+ w->output_dir = p;
+ return 0;
+}
/*
* Extracts a regular file from the WIM archive.
*/
static int extract_regular_file(WIMStruct *w,
const struct dentry *dentry,
- const char *output_path)
+ const char *output_path,
+ int extract_flags)
{
- struct lookup_table *lookup_table;
- int link_type;
- bool is_multi_image_extraction;
struct lookup_table_entry *lte;
int ret;
int out_fd;
const struct resource_entry *res_entry;
- lookup_table = w->lookup_table;
- link_type = w->link_type;
- is_multi_image_extraction = w->is_multi_image_extraction;
- lte = lookup_resource(lookup_table, dentry->hash);
+ lte = __lookup_resource(w->lookup_table, dentry_hash(dentry));
/* If we already extracted the same file or a hard link copy of it, we
* may be able to simply create a link. The exact action is specified
* by the current @link_type. */
- if (link_type != WIM_LINK_TYPE_NONE && lte && lte->out_refcnt != 0) {
+ if ((extract_flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK)) &&
+ lte && lte->out_refcnt != 0)
+ {
wimlib_assert(lte->file_on_disk);
- if (link_type == WIM_LINK_TYPE_HARD) {
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
if (link(lte->file_on_disk, output_path) != 0) {
ERROR_WITH_ERRNO("Failed to hard link "
"`%s' to `%s'",
num_output_dir_path_components =
get_num_path_components(w->output_dir);
- if (is_multi_image_extraction) {
+ if (w->is_multi_image_extraction) {
num_path_components++;
num_output_dir_path_components--;
}
return ret;
}
+static int extract_symlink(const struct dentry *dentry, const char *output_path,
+ const WIMStruct *w)
+{
+ char target[4096];
+ ssize_t ret = dentry_readlink(dentry, target, sizeof(target), w);
+ if (ret <= 0) {
+ ERROR("Could not read the symbolic link from dentry `%s'",
+ dentry->full_path_utf8);
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ ret = symlink(target, output_path);
+ if (ret != 0) {
+ ERROR_WITH_ERRNO("Failed to symlink `%s' to `%s'",
+ output_path, target);
+ return WIMLIB_ERR_LINK;
+ }
+ return 0;
+}
+
/*
* Extracts a directory from the WIM archive.
*
return 0;
}
+struct extract_args {
+ WIMStruct *w;
+ int extract_flags;
+#ifdef WITH_NTFS_3G
+ struct SECURITY_API *scapi;
+#endif
+};
/*
* Extracts a file or directory from the WIM archive. For use in
* @dentry: The dentry to extract.
* @arg: A pointer to the WIMStruct for the WIM file.
*/
-static int extract_regular_file_or_directory(struct dentry *dentry, void *arg)
+static int extract_dentry(struct dentry *dentry, void *arg)
{
- WIMStruct *w = (WIMStruct*)arg;
+ struct extract_args *args = arg;
+ WIMStruct *w = args->w;
+ int extract_flags = args->extract_flags;
size_t len = strlen(w->output_dir);
char output_path[len + dentry->full_path_utf8_len + 1];
+ int ret = 0;
- if (w->verbose)
+ if (extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE)
puts(dentry->full_path_utf8);
memcpy(output_path, w->output_dir, len);
memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len);
output_path[len + dentry->full_path_utf8_len] = '\0';
-
- if (dentry_is_regular_file(dentry)) {
- return extract_regular_file(w, dentry, output_path);
+ if (dentry_is_symlink(dentry)) {
+ ret = extract_symlink(dentry, output_path, w);
+ } else if (dentry_is_directory(dentry)) {
+ if (!dentry_is_root(dentry)) /* Root doesn't need to be extracted. */
+ ret = extract_directory(dentry, output_path);
} else {
- if (dentry_is_root(dentry)) /* Root doesn't need to be extracted. */
- return 0;
- else
- return extract_directory(dentry, output_path);
+ ret = extract_regular_file(w, dentry, output_path, extract_flags);
}
}
-static int extract_single_image(WIMStruct *w, int image)
+
+static int extract_single_image(WIMStruct *w, int image, int extract_flags)
{
DEBUG("Extracting image %d", image);
if (ret != 0)
return ret;
- return for_dentry_in_tree(wim_root_dentry(w),
- extract_regular_file_or_directory, w);
+ struct extract_args args = {
+ .w = w,
+ .extract_flags = extract_flags,
+ #ifdef WITH_NTFS_3G
+ .scapi = NULL
+ #endif
+ };
+
+ return for_dentry_in_tree(wim_root_dentry(w), extract_dentry, &args);
}
/* Extracts all images from the WIM to w->output_dir, with the images placed in
* subdirectories named by their image names. */
-static int extract_all_images(WIMStruct *w)
+static int extract_all_images(WIMStruct *w, int extract_flags)
{
size_t image_name_max_len = max(xml_get_max_image_name_len(w), 20);
size_t output_path_len = strlen(w->output_dir);
/* Image name is empty. Use image number instead */
sprintf(buf + output_path_len + 1, "%d", image);
}
- ret = wimlib_set_output_dir(w, buf);
+ ret = set_output_dir(w, buf);
if (ret != 0)
goto done;
- ret = extract_single_image(w, image);
+ ret = extract_single_image(w, image, extract_flags);
if (ret != 0)
goto done;
}
done:
/* Restore original output directory */
buf[output_path_len + 1] = '\0';
- return wimlib_set_output_dir(w, buf);
+ return 0;
}
/* Extracts a single image or all images from a WIM file. */
-WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image)
+WIMLIBAPI int wimlib_extract_image(WIMStruct *w, int image,
+ const char *output_dir, int flags)
{
- if (!w->output_dir) {
- ERROR("No output directory selected.");
- return WIMLIB_ERR_NOTDIR;
+ int ret;
+ if (!output_dir)
+ return WIMLIB_ERR_INVALID_PARAM;
+ if ((flags & (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
+ == (WIMLIB_EXTRACT_FLAG_SYMLINK | WIMLIB_EXTRACT_FLAG_HARDLINK))
+ return WIMLIB_ERR_INVALID_PARAM;
+
+ ret = set_output_dir(w, output_dir);
+ if (ret != 0)
+ return ret;
+
+ if ((flags & WIMLIB_EXTRACT_FLAG_NTFS)) {
+ #ifdef WITH_NTFS_3G
+ unsigned long mnt_flags;
+ ret = ntfs_check_if_mounted(output_dir, &mnt_flags);
+ if (ret != 0) {
+ ERROR_WITH_ERRNO("NTFS-3g: Cannot determine if `%s' "
+ "is mounted", output_dir);
+ return WIMLIB_ERR_NTFS_3G;
+ }
+ if (!(mnt_flags & NTFS_MF_MOUNTED)) {
+ ERROR("NTFS-3g: Filesystem on `%s' is not mounted ",
+ output_dir);
+ }
+ if (mnt_flags & NTFS_MF_READONLY) {
+ ERROR("NTFS-3g: Filesystem on `%s' is mounted "
+ "read-only", output_dir);
+ return WIMLIB_ERR_NTFS_3G;
+ }
+ #else
+ ERROR("wimlib was compiled without support for NTFS-3g, so");
+ ERROR("we cannot extract a WIM image while preserving NTFS-");
+ ERROR("specific information");
+ return WIMLIB_ERR_UNSUPPORTED;
+ #endif
}
if (image == WIM_ALL_IMAGES) {
w->is_multi_image_extraction = true;
- return extract_all_images(w);
+ ret = extract_all_images(w, flags);
} else {
w->is_multi_image_extraction = false;
- return extract_single_image(w, image);
- }
-
-}
-
-/* Set the output directory for WIM extraction. The directory is created using
- * mkdir(). Fails if directory cannot be created or already exists. */
-WIMLIBAPI int wimlib_set_output_dir(WIMStruct *w, const char *dir)
-{
- char *p;
- DEBUG("Setting output directory to `%s'", dir);
-
- if (!dir) {
- ERROR("Must specify a directory!");
- return WIMLIB_ERR_INVALID_PARAM;
- }
- p = STRDUP(dir);
- if (!p) {
- ERROR("Out of memory");
- return WIMLIB_ERR_NOMEM;
- }
-
- if (mkdir(dir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) != 0) {
- if (errno == EEXIST) {
- DEBUG("`%s' already exists", dir);
- goto done;
- }
- ERROR_WITH_ERRNO("Cannot create directory `%s'", dir);
- FREE(p);
- return WIMLIB_ERR_MKDIR;
- } else {
- DEBUG("Created directory `%s'", dir);
+ ret = extract_single_image(w, image, flags);
}
-done:
- FREE(w->output_dir);
- w->output_dir = p;
- return 0;
-}
+ return ret;
-WIMLIBAPI int wimlib_set_link_type(WIMStruct *w, int link_type)
-{
- switch (link_type) {
- case WIM_LINK_TYPE_NONE:
- case WIM_LINK_TYPE_HARD:
- case WIM_LINK_TYPE_SYMBOLIC:
- w->link_type = link_type;
- return 0;
- default:
- return WIMLIB_ERR_INVALID_PARAM;
- }
}
-