X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Funix_apply.c;h=25b28f9d368d3b792eda7832e69fbe9af0e99ad7;hb=57318a10de8d50cd338fa4c0e4e0b9f60e7c0143;hp=bf9c2911d57630ed2f847f68e4a35df9e00d92bb;hpb=71d3401258fb14dcfc921f53452ba972e27e8b8b;p=wimlib diff --git a/src/unix_apply.c b/src/unix_apply.c index bf9c2911..25b28f9d 100644 --- a/src/unix_apply.c +++ b/src/unix_apply.c @@ -31,6 +31,7 @@ #include "wimlib/file_io.h" #include "wimlib/reparse.h" #include "wimlib/timestamp.h" +#include "wimlib/unix_data.h" #include #include @@ -95,6 +96,9 @@ struct unix_apply_ctx { /* Number of characters in target_abspath. */ size_t target_abspath_nchars; + + /* Number of special files we couldn't create due to EPERM */ + unsigned long num_special_files_ignored; }; /* Returns the number of characters needed to represent the path to the @@ -109,7 +113,7 @@ unix_dentry_path_length(const struct wim_dentry *dentry) d = dentry; do { len += d->d_extraction_name_nchars + 1; - d = d->parent; + d = d->d_parent; } while (!dentry_is_root(d) && will_extract_dentry(d)); return len; @@ -157,7 +161,7 @@ unix_build_extraction_path(const struct wim_dentry *dentry, p -= d->d_extraction_name_nchars; memcpy(p, d->d_extraction_name, d->d_extraction_name_nchars); *--p = '/'; - d = d->parent; + d = d->d_parent; } while (!dentry_is_root(d) && will_extract_dentry(d)); return pathbuf; @@ -252,16 +256,17 @@ unix_set_metadata(int fd, const struct wim_inode *inode, const char *path, struct unix_apply_ctx *ctx) { int ret; + struct wimlib_unix_data unix_data; if (fd < 0 && !path) path = unix_build_inode_extraction_path(inode, ctx); if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) - && inode_has_unix_data(inode)) + && inode_get_unix_data(inode, &unix_data)) { - u32 uid = inode->i_unix_data.uid; - u32 gid = inode->i_unix_data.gid; - u32 mode = inode->i_unix_data.mode; + u32 uid = unix_data.uid; + u32 gid = unix_data.gid; + u32 mode = unix_data.mode; ret = unix_set_owner_and_group(fd, path, uid, gid); if (ret) { @@ -371,15 +376,15 @@ unix_create_if_directory(const struct wim_dentry *dentry, return 0; } -/* If @dentry represents an empty regular file, create it, set its metadata, and - * create any needed hard links. */ +/* If @dentry represents an empty regular file or a special file, create it, set + * its metadata, and create any needed hard links. */ static int unix_extract_if_empty_file(const struct wim_dentry *dentry, struct unix_apply_ctx *ctx) { const struct wim_inode *inode; + struct wimlib_unix_data unix_data; const char *path; - int fd; int ret; inode = dentry->d_inode; @@ -388,26 +393,54 @@ unix_extract_if_empty_file(const struct wim_dentry *dentry, if (dentry != inode_first_extraction_dentry(inode)) return 0; - /* Not an empty regular file? */ + /* Is this a directory, a symbolic link, or any type of nonempty file? + */ if (inode_is_directory(inode) || inode_is_symlink(inode) || inode_unnamed_lte_resolved(inode)) return 0; - path = unix_build_extraction_path(dentry, ctx); -retry_create: - fd = open(path, O_TRUNC | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644); - if (fd < 0) { - if (errno == EEXIST && !unlink(path)) - goto retry_create; - ERROR_WITH_ERRNO("Can't create regular file \"%s\"", path); - return WIMLIB_ERR_OPEN; - } - /* On empty files, we can set timestamps immediately because we don't - * need to write any data to them. */ - ret = unix_set_metadata(fd, inode, path, ctx); - if (close(fd) && !ret) { - ERROR_WITH_ERRNO("Error closing \"%s\"", path); - ret = WIMLIB_ERR_WRITE; + /* Recognize special files in UNIX_DATA mode */ + if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) && + inode_get_unix_data(inode, &unix_data) && + !S_ISREG(unix_data.mode)) + { + path = unix_build_extraction_path(dentry, ctx); + retry_mknod: + if (mknod(path, unix_data.mode, unix_data.rdev)) { + if (errno == EPERM) { + WARNING_WITH_ERRNO("Can't create special " + "file \"%s\"", path); + ctx->num_special_files_ignored++; + return 0; + } + if (errno == EEXIST && !unlink(path)) + goto retry_mknod; + ERROR_WITH_ERRNO("Can't create special file \"%s\"", + path); + return WIMLIB_ERR_MKNOD; + } + /* On special files, we can set timestamps immediately because + * we don't need to write any data to them. */ + ret = unix_set_metadata(-1, inode, path, ctx); + } else { + int fd; + + path = unix_build_extraction_path(dentry, ctx); + retry_create: + fd = open(path, O_TRUNC | O_CREAT | O_WRONLY | O_NOFOLLOW, 0644); + if (fd < 0) { + if (errno == EEXIST && !unlink(path)) + goto retry_create; + ERROR_WITH_ERRNO("Can't create regular file \"%s\"", path); + return WIMLIB_ERR_OPEN; + } + /* On empty files, we can set timestamps immediately because we + * don't need to write any data to them. */ + ret = unix_set_metadata(fd, inode, path, ctx); + if (close(fd) && !ret) { + ERROR_WITH_ERRNO("Error closing \"%s\"", path); + ret = WIMLIB_ERR_WRITE; + } } if (ret) return ret; @@ -707,6 +740,12 @@ unix_extract(struct list_head *dentry_list, struct apply_ctx *_ctx) /* Set directory metadata. We do this last so that we get the right * directory timestamps. */ ret = unix_set_dir_metadata(dentry_list, ctx); + if (ret) + goto out; + if (ctx->num_special_files_ignored) { + WARNING("%lu special files were not extracted due to EPERM!", + ctx->num_special_files_ignored); + } out: for (unsigned i = 0; i < NUM_PATHBUFS; i++) FREE(ctx->pathbufs[i]);