]> wimlib.net Git - wimlib/blobdiff - src/extract_image.c
extract_image.c: Make NO_ACLS and STRICT_ACLS do something on UNIX
[wimlib] / src / extract_image.c
index 69a4b9e8d0fac4298f376197f69b88c3d4ecf40b..2092cf713521b39709600ae353191ee8f11054cc 100644 (file)
@@ -166,48 +166,57 @@ symlink_apply_unix_data(const char *link,
 
 static int
 fd_apply_unix_data(int fd, const char *path,
-                  const struct wimlib_unix_data *unix_data)
+                  const struct wimlib_unix_data *unix_data,
+                  int extract_flags)
 {
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS)
+               return 0;
+
        if (fchown(fd, unix_data->uid, unix_data->gid)) {
-               if (errno == EPERM) {
+               if (errno == EPERM &&
+                   !(extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
+               {
                        WARNING_WITH_ERRNO("failed to set file UNIX "
                                           "owner/group on \"%s\"", path);
-                       /* Ignore? */
                } else {
                        ERROR_WITH_ERRNO("failed to set file UNIX "
                                         "owner/group on \"%s\"", path);
-                       return WIMLIB_ERR_INVALID_DENTRY;
+                       return (errno == EPERM) ? WIMLIB_ERR_INSUFFICIENT_PRIVILEGES_TO_EXTRACT :
+                               WIMLIB_ERR_WRITE;
                }
        }
 
        if (fchmod(fd, unix_data->mode)) {
-               if (errno == EPERM) {
+               if (errno == EPERM &&
+                   !(extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
+               {
                        WARNING_WITH_ERRNO("failed to set UNIX file mode "
                                           "on \"%s\"", path);
-                       /* Ignore? */
                } else {
                        ERROR_WITH_ERRNO("failed to set UNIX file mode "
                                         "on \"%s\"", path);
-                       return WIMLIB_ERR_INVALID_DENTRY;
+                       return (errno == EPERM) ? WIMLIB_ERR_INSUFFICIENT_PRIVILEGES_TO_EXTRACT :
+                               WIMLIB_ERR_WRITE;
                }
        }
        return 0;
 }
 
 static int
-dir_apply_unix_data(const char *dir, const struct wimlib_unix_data *unix_data)
+dir_apply_unix_data(const char *dir, const struct wimlib_unix_data *unix_data,
+                   int extract_flags)
 {
        int dfd = open(dir, O_RDONLY);
        int ret;
        if (dfd >= 0) {
-               ret = fd_apply_unix_data(dfd, dir, unix_data);
-               if (close(dfd)) {
+               ret = fd_apply_unix_data(dfd, dir, unix_data, extract_flags);
+               if (close(dfd) && ret == 0) {
                        ERROR_WITH_ERRNO("can't close directory `%s'", dir);
-                       ret = WIMLIB_ERR_MKDIR;
+                       ret = WIMLIB_ERR_WRITE;
                }
        } else {
                ERROR_WITH_ERRNO("can't open directory `%s'", dir);
-               ret = WIMLIB_ERR_MKDIR;
+               ret = WIMLIB_ERR_OPENDIR;
        }
        return ret;
 }
@@ -288,7 +297,8 @@ out_extract_unix_data:
                else if (ret < 0)
                        ret = 0;
                else
-                       ret = fd_apply_unix_data(out_fd, output_path, &unix_data);
+                       ret = fd_apply_unix_data(out_fd, output_path, &unix_data,
+                                                args->extract_flags);
                if (ret)
                        goto out;
        }
@@ -387,7 +397,8 @@ extract_symlink(struct wim_dentry *dentry,
 
 static int
 extract_directory(struct wim_dentry *dentry,
-                 const tchar *output_path, bool is_root)
+                 const tchar *output_path, bool is_root,
+                 int extract_flags)
 {
        int ret;
        struct stat stbuf;
@@ -417,7 +428,7 @@ extract_directory(struct wim_dentry *dentry,
 dir_exists:
        ret = 0;
 #ifndef __WIN32__
-       if (dentry) {
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) {
                struct wimlib_unix_data unix_data;
                ret = inode_get_unix_data(dentry->d_inode, &unix_data, NULL);
                if (ret > 0)
@@ -425,7 +436,8 @@ dir_exists:
                else if (ret < 0)
                        ret = 0;
                else
-                       ret = dir_apply_unix_data(output_path, &unix_data);
+                       ret = dir_apply_unix_data(output_path, &unix_data,
+                                                 extract_flags);
        }
 #endif
        return ret;
@@ -443,7 +455,7 @@ unix_do_apply_dentry(const char *output_path, size_t output_path_len,
        else if (inode_is_directory(inode))
                return extract_directory((args->extract_flags &
                                           WIMLIB_EXTRACT_FLAG_UNIX_DATA) ? dentry : NULL,
-                                        output_path, false);
+                                        output_path, false, args->extract_flags);
        else
                return extract_regular_file(dentry, args, output_path);
 }
@@ -863,6 +875,33 @@ sort_stream_list_by_wim_position(struct list_head *stream_list)
        return 0;
 }
 
+/*
+ * Extract a dentry to standard output.
+ *
+ * This obviously doesn't make sense in all cases.  We return an error if the
+ * dentry does not correspond to a regular file.  Otherwise we extract the
+ * unnamed data stream only.
+ */
+static int
+extract_dentry_to_stdout(struct wim_dentry *dentry)
+{
+       int ret = 0;
+       if (!dentry_is_regular_file(dentry)) {
+               ERROR("\"%"TS"\" is not a regular file and therefore cannot be "
+                     "extracted to standard output", dentry->_full_path);
+               ret = WIMLIB_ERR_NOT_A_REGULAR_FILE;
+       } else {
+               struct wim_lookup_table_entry *lte;
+
+               lte = inode_unnamed_lte_resolved(dentry->d_inode);
+               if (lte) {
+                       ret = extract_wim_resource_to_fd(lte, STDOUT_FILENO,
+                                                        wim_resource_size(lte));
+               }
+       }
+       return ret;
+}
+
 /*
  * extract_tree - Extract a file or directory tree from the currently selected
  *               WIM image.
@@ -951,6 +990,11 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
        }
        args.extract_root = root;
 
+       ret = calculate_dentry_tree_full_paths(root);
+       if (ret)
+               goto out_ntfs_umount;
+
+
        /* Build a list of the streams that need to be extracted */
        find_streams_for_extraction(root,
                                    &stream_list,
@@ -960,6 +1004,11 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
        calculate_bytes_to_extract(&stream_list, extract_flags,
                                   &args.progress);
 
+       if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT) {
+               ret = extract_dentry_to_stdout(root);
+               goto out_mark_inodes_unvisited;
+       }
+
        if (progress_func) {
                progress_func(*wim_source_path ? WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN :
                              WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN,
@@ -982,10 +1031,6 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
                              &args.progress);
        }
 
-       ret = calculate_dentry_tree_full_paths(root);
-       if (ret)
-               goto out_mark_inodes_unvisited;
-
        /* Make the directory structure and extract empty files */
        args.extract_flags |= WIMLIB_EXTRACT_FLAG_NO_STREAMS;
        args.apply_dentry = ops->apply_dentry;
@@ -1217,6 +1262,9 @@ wimlib_extract_files(WIMStruct *wim,
        if (ret)
                goto out;
 
+       if (num_cmds == 0)
+               goto out;
+
        if (num_additional_swms) {
                ret = new_joined_lookup_table(wim, additional_swms,
                                              num_additional_swms,
@@ -1345,7 +1393,7 @@ extract_all_images(WIMStruct *wim,
        int image;
        const tchar *image_name;
 
-       ret = extract_directory(NULL, target, true);
+       ret = extract_directory(NULL, target, true, 0);
        if (ret)
                return ret;