]> wimlib.net Git - wimlib/blobdiff - src/extract.c
Some preparations for supporting NTFS capture and apply.
[wimlib] / src / extract.c
index 53dc9ec2d43569e1f0e6b80875a96aac21e91313..f3b8da06ab6e439fa61bc637510e6ab36805cebd 100644 (file)
@@ -2,24 +2,26 @@
  * extract.c
  *
  * Support for extracting WIM files.
- *
+ */
+
+/*
  * Copyright (C) 2010 Carl Thijssen
  * Copyright (C) 2012 Eric Biggers
  *
- * wimlib - Library for working with WIM files 
+ * This file is part of wimlib, a library for working with WIM files.
  *
- * This library is free software; you can redistribute it and/or modify it under
- * the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 2.1 of the License, or (at your option) any
- * later version.
+ * wimlib is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2.1 of the License, or (at your option)
+ * any later version.
  *
- * This library is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
- * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
+ * details.
  *
- * You should have received a copy of the GNU Lesser General Public License along
- * with this library; if not, write to the Free Software Foundation, Inc., 59
- * Temple Place, Suite 330, Boston, MA 02111-1307 USA 
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with wimlib; if not, see http://www.gnu.org/licenses/.
  */
 
 #include "wimlib_internal.h"
 #include <string.h>
 #include <errno.h>
 
+#ifdef WITH_NTFS_3G
+#include <ntfs-3g/volume.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. 
@@ -55,29 +90,26 @@ static int extract_regular_file(WIMStruct *w,
                                const struct dentry *dentry, 
                                const char *output_path)
 {
-       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);
 
        /* 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 ((w->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 (w->extract_flags & WIMLIB_EXTRACT_FLAG_HARDLINK) {
                        if (link(lte->file_on_disk, output_path) != 0) {
-                               ERROR("Failed to hard link `%s' to `%s': %m\n",
-                                               output_path, lte->file_on_disk);
+                               ERROR_WITH_ERRNO("Failed to hard link "
+                                                "`%s' to `%s'",
+                                                output_path, lte->file_on_disk);
                                return WIMLIB_ERR_LINK;
                        }
                } else {
@@ -93,7 +125,7 @@ static int extract_regular_file(WIMStruct *w,
                        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--;
                        }
@@ -114,8 +146,9 @@ static int extract_regular_file(WIMStruct *w,
                                p2 = path_next_part(p2, NULL);
                        strcpy(p, p2);
                        if (symlink(buf, output_path) != 0) {
-                               ERROR("Failed to symlink `%s' to `%s': %m\n",
-                                               buf, lte->file_on_disk);
+                               ERROR_WITH_ERRNO("Failed to symlink `%s' to "
+                                                "`%s'",
+                                                buf, lte->file_on_disk);
                                return WIMLIB_ERR_LINK;
                        }
 
@@ -127,14 +160,14 @@ static int extract_regular_file(WIMStruct *w,
 
        out_fd = open(output_path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        if (out_fd == -1) {
-               ERROR("Failed to open the file `%s' for writing: "
-                               "%m\n", output_path);
+               ERROR_WITH_ERRNO("Failed to open the file `%s' for writing",
+                                output_path);
                return WIMLIB_ERR_OPEN;
        }
 
        /* Extract empty file, with no lookup table entry... */
        if (!lte) {
-               DEBUG("Empty file `%s'\n", output_path);
+               DEBUG("Empty file `%s'.", output_path);
                ret = 0;
                goto done;
        }
@@ -145,7 +178,7 @@ static int extract_regular_file(WIMStruct *w,
                                     res_entry->original_size);
 
        if (ret != 0) {
-               ERROR("Failed to extract resource to `%s'!\n", output_path);
+               ERROR("Failed to extract resource to `%s'", output_path);
                goto done;
        }
 
@@ -181,8 +214,8 @@ static int extract_directory(struct dentry *dentry, const char *output_path)
                                 itself. */
                        return 0;
                default:
-                       ERROR("Cannot create directory `%s': %m\n",
-                                       output_path);
+                       ERROR_WITH_ERRNO("Cannot create directory `%s'",
+                                        output_path);
                        return WIMLIB_ERR_MKDIR;
                }
        }
@@ -203,14 +236,13 @@ static int extract_regular_file_or_directory(struct dentry *dentry, void *arg)
        size_t len = strlen(w->output_dir);
        char output_path[len + dentry->full_path_utf8_len + 1];
 
-       if (w->verbose)
+       if (w->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);
        } else {
@@ -223,7 +255,7 @@ static int extract_regular_file_or_directory(struct dentry *dentry, void *arg)
 
 static int extract_single_image(WIMStruct *w, int image)
 {
-       DEBUG("Extracting image %d\n", image);
+       DEBUG("Extracting image %d", image);
 
        int ret;
        ret = wimlib_select_image(w, image);
@@ -246,96 +278,80 @@ static int extract_all_images(WIMStruct *w)
        int image;
        const char *image_name;
 
-       DEBUG("Attempting to extract all images from `%s'\n", w->filename);
+       DEBUG("Attempting to extract all images from `%s'", w->filename);
 
        memcpy(buf, w->output_dir, output_path_len);
        buf[output_path_len] = '/';
        for (image = 1; image <= w->hdr.image_count; image++) {
-               buf[output_path_len + 1] = '\0';
                
                image_name = wimlib_get_image_name(w, image);
                if (*image_name) {
-                       strncat(buf + output_path_len + 1, image_name, 
-                               image_name_max_len);
+                       strcpy(buf + output_path_len + 1, image_name);
                } else {
                        /* 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);
                if (ret != 0)
                        goto done;
        }
-       ret = 0;
 done:
+       /* Restore original output directory */
        buf[output_path_len + 1] = '\0';
-       wimlib_set_output_dir(w, buf);
-       return ret;
+       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.\n");
-               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
        }
+       w->extract_flags = flags;
        if (image == WIM_ALL_IMAGES) {
                w->is_multi_image_extraction = true;
-               return extract_all_images(w);
+               ret = extract_all_images(w);
        } 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'\n", dir);
-
-       if (!dir) {
-               ERROR("Must specify a directory!\n");
-               return WIMLIB_ERR_INVALID_PARAM;
-       }
-       p = STRDUP(dir);
-       if (!p) {
-               ERROR("Out of memory!\n");
-               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\n", dir);
-                       goto done;
-               }
-               ERROR("Cannot create directory `%s': %m\n", dir);
-               FREE(p);
-               return WIMLIB_ERR_MKDIR;
-       } else {
-               DEBUG("Created directory `%s'\n", dir);
+               ret = extract_single_image(w, image);
        }
-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;
-       }
 }
-