]> wimlib.net Git - wimlib/blobdiff - src/unix_apply.c
unix_apply.c: fix overwriting existing readonly files
[wimlib] / src / unix_apply.c
index 5dcb38641c2ea03d61057bf99b5d430327ad38d4..3746f504a3695954e9de7c0126872d151075681e 100644 (file)
@@ -3,7 +3,7 @@
  */
 
 /*
- * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
  *
  * This file 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
@@ -156,7 +156,9 @@ unix_build_extraction_path(const struct wim_dentry *dentry,
        d = dentry;
        do {
                p -= d->d_extraction_name_nchars;
-               memcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
+               if (d->d_extraction_name_nchars)
+                       memcpy(p, d->d_extraction_name,
+                              d->d_extraction_name_nchars);
                *--p = '/';
                d = d->d_parent;
        } while (!dentry_is_root(d) && will_extract_dentry(d));
@@ -181,6 +183,17 @@ unix_build_inode_extraction_path(const struct wim_inode *inode,
        return unix_build_extraction_path(inode_first_extraction_dentry(inode), ctx);
 }
 
+/* Should the specified file be extracted as a directory on UNIX?  We extract
+ * the file as a directory if FILE_ATTRIBUTE_DIRECTORY is set and the file does
+ * not have a symlink or junction reparse point.  It *may* have a different type
+ * of reparse point.  */
+static inline bool
+should_extract_as_directory(const struct wim_inode *inode)
+{
+       return (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) &&
+               !inode_is_symlink(inode);
+}
+
 /* Sets the timestamps on a file being extracted.
  *
  * Either @fd or @path must be specified (not -1 and not NULL, respectively).
@@ -356,7 +369,7 @@ unix_create_if_directory(const struct wim_dentry *dentry,
        const char *path;
        struct stat stbuf;
 
-       if (!dentry_is_directory(dentry))
+       if (!should_extract_as_directory(dentry->d_inode))
                return 0;
 
        path = unix_build_extraction_path(dentry, ctx);
@@ -391,7 +404,7 @@ unix_extract_if_empty_file(const struct wim_dentry *dentry,
 
        /* Is this a directory, a symbolic link, or any type of nonempty file?
         */
-       if (inode_is_directory(inode) || inode_is_symlink(inode) ||
+       if (should_extract_as_directory(inode) || inode_is_symlink(inode) ||
            inode_get_blob_for_unnamed_data_stream_resolved(inode))
                return 0;
 
@@ -423,7 +436,7 @@ unix_extract_if_empty_file(const struct wim_dentry *dentry,
 
                path = unix_build_extraction_path(dentry, ctx);
        retry_create:
-               fd = open(path, O_TRUNC | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
+               fd = open(path, O_EXCL | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
                if (fd < 0) {
                        if (errno == EEXIST && !unlink(path))
                                goto retry_create;
@@ -480,7 +493,7 @@ unix_count_dentries(const struct list_head *dentry_list,
 
                const struct wim_inode *inode = dentry->d_inode;
 
-               if (inode_is_directory(inode))
+               if (should_extract_as_directory(inode))
                        dir_count++;
                else if ((dentry == inode_first_extraction_dentry(inode)) &&
                         !inode_is_symlink(inode) &&
@@ -546,7 +559,7 @@ unix_begin_extract_blob_instance(const struct blob_descriptor *blob,
                if (blob->size > REPARSE_DATA_MAX_SIZE) {
                        ERROR_WITH_ERRNO("Reparse data of \"%s\" has size "
                                         "%"PRIu64" bytes (exceeds %u bytes)",
-                                        inode_first_full_path(inode),
+                                        inode_any_full_path(inode),
                                         blob->size, REPARSE_DATA_MAX_SIZE);
                        return WIMLIB_ERR_INVALID_REPARSE_DATA;
                }
@@ -564,7 +577,7 @@ unix_begin_extract_blob_instance(const struct blob_descriptor *blob,
        first_dentry = inode_first_extraction_dentry(inode);
        first_path = unix_build_extraction_path(first_dentry, ctx);
 retry_create:
-       fd = open(first_path, O_TRUNC | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
+       fd = open(first_path, O_EXCL | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644);
        if (fd < 0) {
                if (errno == EEXIST && !unlink(first_path))
                        goto retry_create;
@@ -680,7 +693,7 @@ unix_set_dir_metadata(struct list_head *dentry_list, struct unix_apply_ctx *ctx)
        int ret;
 
        list_for_each_entry_reverse(dentry, dentry_list, d_extraction_list_node) {
-               if (dentry_is_directory(dentry)) {
+               if (should_extract_as_directory(dentry->d_inode)) {
                        ret = unix_set_metadata(-1, dentry->d_inode, NULL, ctx);
                        if (ret)
                                return ret;