From: Eric Biggers Date: Fri, 23 May 2014 14:58:19 +0000 (-0500) Subject: Add support for special files on UNIX X-Git-Tag: v1.7.0~113 X-Git-Url: https://wimlib.net/git/?p=wimlib;a=commitdiff_plain;h=3a900017c59c26af398f9cf375719dbcda378fb8 Add support for special files on UNIX --- diff --git a/NEWS b/NEWS index f4074bd3..4fef76cd 100644 --- a/NEWS +++ b/NEWS @@ -13,10 +13,14 @@ Version 1.7.0-BETA: documentation for the new '--wimboot' option to wimcapture and wimapply for more information. - The format of UNIX data has been changed. If you captured any WIMs with - the --unix-data option, to upgrade them you'll need to apply them with - --unix-data using wimlib v1.6.2, then re-capture them with --unix-data - using this version. + On UNIX-like systems, you can now backup and restore device nodes, named + pipes, and sockets. In addition, 32-bit user and group IDs are now + supported. + + The way that UNIX data is stored in WIM files has been changed. If you + captured any WIMs with the --unix-data option, to upgrade them you'll + need to apply them with --unix-data using wimlib-imagex v1.6.2, then + re-capture them with --unix-data using this version. wimlib now understands tagged metadata items, such as object IDs, that can be stored in WIM directory entries. diff --git a/doc/man1/imagex-apply.1.in b/doc/man1/imagex-apply.1.in index 5aec9b3f..e3d04381 100644 --- a/doc/man1/imagex-apply.1.in +++ b/doc/man1/imagex-apply.1.in @@ -331,15 +331,12 @@ Reparse point fixups are never done in the NTFS volume extraction mode on UNIX-like systems. .TP \fB--unix-data\fR -(UNIX-like systems only) By default, in the directory extraction mode on UNIX, -\fB@IMAGEX_PROGNAME@ apply\fR will ignore both Windows-style security -descriptors and UNIX-specific file owners, groups, and modes set when using -\fB@IMAGEX_PROGNAME@ capture\fR with the \fB--unix-data\fR flag. By passing -\fB--unix-data\fR to \fB@IMAGEX_PROGNAME@ apply\fR instead, this causes this -UNIX-specific data to be restored when available. However, by default, if -\fB@IMAGEX_PROGNAME@\fR does not have permission to set the UNIX owner, group or -file mode on an extracted file, a warning will be printed and it will not be -considered an error condition; use \fB--strict-acls\fR to get stricter behavior. +(UNIX-like systems only) Restore UNIX owners, groups, modes, and device IDs +(major and minor numbers) that were captured by \fB@IMAGEX_PROGNAME@ capture\fR +with the \fB--unix-data\fR option. As of wimlib v1.7.0, you can backup and +restore not only the standard UNIX file permission information, but also +character device nodes, block device nodes, named pipes (FIFOs), and UNIX domain +sockets. .TP \fB--no-acls\fR Do not restore security descriptors on extracted files and directories. diff --git a/doc/man1/imagex-capture.1.in b/doc/man1/imagex-capture.1.in index b1f72675..a1b6ff2b 100644 --- a/doc/man1/imagex-capture.1.in +++ b/doc/man1/imagex-capture.1.in @@ -57,10 +57,10 @@ the WIM format was designed for Windows, so it cannot store all possible metadata from filesystems used on UNIX-like systems. The main information that will \fInot\fR be stored is: .IP \[bu] 4 -UNIX file owners, groups, and modes. (Exception: see the \fB--unix-data\fR -option.) As a result, file permissions will not be stored, and files that are -neither regular files, directories, nor symbolic links, such as device files and -FIFOs, cannot be captured and will be excluded by default. +UNIX file owners, groups, modes, and device IDs (major and minor numbers), +unless the \fB--unix-data\fR option is specified. By default (without +\fB--unix-data\fR), files that are neither regular files, directories, nor +symbolic links, such as device nodes and FIFOs, will be excluded. .IP \[bu] Extended attributes. This mainly includes extensions to the traditional UNIX security model, such as SELinux security labels, POSIX ACLs, and capabilities @@ -342,11 +342,18 @@ saved in the WIM image as Windows/System32/WimBootCompress.ini, overriding any that may be present on the filesystem. .TP \fB--unix-data\fR -(UNIX-like systems only) Store the UNIX owner, group, and mode of all captured -files. This is done by adding a special tagged metadata item to each directory -entry that contains this information. This information should be ignored by the -Microsoft implementation. (Note: the way that UNIX data is stored was changed -in wimlib v1.7.0 and is not backwards or forward compatible.) +(UNIX-like systems only) Store the UNIX owner, group, mode, and device ID (major +and minor number) of each captured file. As of wimlib v1.7.0, you can backup +and restore not only the standard UNIX file permission information, but also +character device nodes, block device nodes, named pipes (FIFOs), and UNIX domain +sockets. +.IP +wimlib stores UNIX data by adding a special tagged metadata item to each +directory entry of each file that contains this information. This extra +information is ignored by the Microsoft implementation. Note: UNIX data stored +by wimlib before v1.7.0 used a different format that is no longer supported. If +you have old WIM files with UNIX data, apply them with v1.6.2 and recapture them +with v1.7.0 or later. .TP \fB--no-acls\fR Do not capture files' security descriptors. diff --git a/doc/man1/imagex-mount.1.in b/doc/man1/imagex-mount.1.in index 7ebf0598..f475527c 100644 --- a/doc/man1/imagex-mount.1.in +++ b/doc/man1/imagex-mount.1.in @@ -123,17 +123,20 @@ Store temporary staging files in a subdirectory of the directory \fIDIR\fR. Only valid for \fB@IMAGEX_PROGNAME@ mountrw\fR. .TP \fB--unix-data\fR -By default, \fB@IMAGEX_PROGNAME@ mount\fR and \fB@IMAGEX_PROGNAME@ mountrw\fR will ignore both -Windows-style security descriptors (which may have been set either from Windows or by -\fB@IMAGEX_PROGNAME@ capture\fR from an NTFS-volume) and UNIX-specific data (which is from using -\fB@IMAGEX_PROGNAME@ capture\fR with the \fB--unix-data\fR flag). In this default mode, -all files will simply be owned by the user running \fB@IMAGEX_PROGNAME@\fR and will have mode 0777. -(Note: they will still not be accessible to other users unless you also specify -\fB--allow-other\fR.) If you instead provide the \fB--unix-data\fR flag, these -default permissions will be overridden on a per-file basis with the -UNIX-specific data when available, and in the case of \fB@IMAGEX_PROGNAME@ mountrw\fR it -will be possible to change the UNIX permissions using the standard UNIX -tools and functions. +Honor UNIX-specific metadata that was captured by \fB@IMAGEX_PROGNAME@ +capture\fR with the \fB--unix-data option\fR. By default, \fB@IMAGEX_PROGNAME@ +mount\fR and \fB@IMAGEX_PROGNAME@ mountrw\fR will ignore both Windows-style +security descriptors (which may have been set either from Windows or by +\fB@IMAGEX_PROGNAME@ capture\fR from an NTFS-volume) and UNIX-specific metadata. +In this default mode, all files will simply be owned by the user running +\fB@IMAGEX_PROGNAME@\fR and will have mode 0777. (Note: they will still not be +accessible to other users unless you also specify \fB--allow-other\fR.) If you +instead provide the \fB--unix-data\fR option, these default permissions will be +overridden on a per-file basis with the UNIX-specific data when available, and +in the case of \fB@IMAGEX_PROGNAME@ mountrw\fR it will be possible to change the +UNIX permissions using the standard UNIX tools and functions. In addition, with +wimlib v1.7.0 and later, you can create device nodes, named pipes, and sockets +on the mounted filesystem and have them stored in the WIM image. .TP \fB--allow-other\fR Pass the \fBallow_other\fR option to the FUSE mount. See \fBmount.fuse\fR (8). diff --git a/include/wimlib.h b/include/wimlib.h index f28e971f..702c3a63 100644 --- a/include/wimlib.h +++ b/include/wimlib.h @@ -1256,7 +1256,7 @@ struct wimlib_dir_entry { uint32_t unix_uid; uint32_t unix_gid; uint32_t unix_mode; - uint32_t unix_reserved; + uint32_t unix_rdev; uint64_t reserved[14]; @@ -1321,10 +1321,9 @@ typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resour * wimlib_update_image(). */ #define WIMLIB_ADD_FLAG_BOOT 0x00000008 -/** Store the UNIX owner, group, and mode. This is done by adding a special - * alternate data stream to each regular file, symbolic link, and directory to - * contain this information. Please note that this flag is for convenience - * only; Microsoft's implementation will not understand this special +/** UNIX-like systems only: Store the UNIX owner, group, mode, and device ID + * (major and minor number) of each file. See the documentation for the + * --unix-data option to wimlib-imagex capture for more * information. */ #define WIMLIB_ADD_FLAG_UNIX_DATA 0x00000010 @@ -2068,6 +2067,7 @@ enum wimlib_error_code { WIMLIB_ERR_WIMBOOT, WIMLIB_ERR_ABORTED_BY_PROGRESS, WIMLIB_ERR_UNKNOWN_PROGRESS_STATUS, + WIMLIB_ERR_MKNOD, }; diff --git a/include/wimlib/unix_data.h b/include/wimlib/unix_data.h index 64323695..ede0fdce 100644 --- a/include/wimlib/unix_data.h +++ b/include/wimlib/unix_data.h @@ -7,6 +7,7 @@ struct wimlib_unix_data { u32 uid; u32 gid; u32 mode; + u32 rdev; }; struct wim_inode; @@ -21,11 +22,12 @@ inode_get_unix_data(const struct wim_inode *inode, #define UNIX_DATA_UID 0x1 #define UNIX_DATA_GID 0x2 #define UNIX_DATA_MODE 0x4 +#define UNIX_DATA_RDEV 0x8 -#define UNIX_DATA_ALL (UNIX_DATA_UID | UNIX_DATA_GID | UNIX_DATA_MODE) +#define UNIX_DATA_ALL 0xF extern bool -inode_set_unix_data(struct wim_inode *inode, u32 uid, u32 gid, u32 mode, - int which); +inode_set_unix_data(struct wim_inode *inode, + struct wimlib_unix_data *unix_data, int which); #endif /* _WIMLIB_UNIX_DATA_H */ diff --git a/programs/imagex.c b/programs/imagex.c index 41ab646d..059e6d9b 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -2430,8 +2430,10 @@ print_dentry_detailed(const struct wimlib_dir_entry *dentry) tprintf(T("Link Count = %"PRIu32"\n"), dentry->num_links); if (dentry->unix_mode != 0) { - tprintf(T("UNIX Data = uid:%"PRIu32" gid:%"PRIu32" mode:0%"PRIo32"\n"), - dentry->unix_uid, dentry->unix_gid, dentry->unix_mode); + tprintf(T("UNIX Data = uid:%"PRIu32" gid:%"PRIu32" " + "mode:0%"PRIo32" rdev:0x%"PRIx32"\n"), + dentry->unix_uid, dentry->unix_gid, + dentry->unix_mode, dentry->unix_rdev); } for (uint32_t i = 0; i <= dentry->num_named_streams; i++) { diff --git a/src/iterate_dir.c b/src/iterate_dir.c index c295dd18..4e286b15 100644 --- a/src/iterate_dir.c +++ b/src/iterate_dir.c @@ -87,6 +87,7 @@ init_wimlib_dentry(struct wimlib_dir_entry *wdentry, struct wim_dentry *dentry, wdentry->unix_uid = unix_data.uid; wdentry->unix_gid = unix_data.gid; wdentry->unix_mode = unix_data.mode; + wdentry->unix_rdev = unix_data.rdev; } lte = inode_unnamed_lte(inode, wim->lookup_table); diff --git a/src/mount_image.c b/src/mount_image.c index 169f3d3b..168ee852 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -315,7 +315,8 @@ fuse_mask_mode(mode_t mode, struct fuse_context *fuse_ctx) */ static int create_dentry(struct fuse_context *fuse_ctx, const char *path, - mode_t mode, int attributes, struct wim_dentry **dentry_ret) + mode_t mode, dev_t rdev, int attributes, + struct wim_dentry **dentry_ret) { struct wim_dentry *parent; struct wim_dentry *new; @@ -343,10 +344,14 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path, new->d_inode->i_attributes = attributes; if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) { - if (!inode_set_unix_data(new->d_inode, - fuse_ctx->uid, - fuse_ctx->gid, - fuse_mask_mode(mode, fuse_ctx), + struct wimlib_unix_data unix_data; + + unix_data.uid = fuse_ctx->uid; + unix_data.gid = fuse_ctx->gid; + unix_data.mode = fuse_mask_mode(mode, fuse_ctx); + unix_data.rdev = rdev; + + if (!inode_set_unix_data(new->d_inode, &unix_data, UNIX_DATA_ALL)) { free_dentry(new); @@ -426,10 +431,12 @@ inode_to_stbuf(const struct wim_inode *inode, stbuf->st_uid = unix_data.uid; stbuf->st_gid = unix_data.gid; stbuf->st_mode = unix_data.mode; + stbuf->st_rdev = unix_data.rdev; } else { stbuf->st_uid = ctx->default_uid; stbuf->st_gid = ctx->default_gid; stbuf->st_mode = inode_default_unix_mode(inode); + stbuf->st_rdev = 0; } stbuf->st_ino = (ino_t)inode->i_ino; stbuf->st_nlink = inode->i_nlink; @@ -1617,6 +1624,7 @@ wimfs_chmod(const char *path, mode_t mask) struct wim_dentry *dentry; struct wim_inode *inode; struct wimfs_context *ctx = wimfs_get_context(); + struct wimlib_unix_data unix_data; int ret; if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA)) @@ -1629,8 +1637,11 @@ wimfs_chmod(const char *path, mode_t mask) inode = dentry->d_inode; - if (!inode_set_unix_data(inode, ctx->default_uid, - ctx->default_gid, mask, UNIX_DATA_MODE)) + unix_data.uid = ctx->default_uid; + unix_data.gid = ctx->default_gid; + unix_data.mode = mask; + unix_data.rdev = 0; + if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_MODE)) return -ENOMEM; return 0; @@ -1643,6 +1654,7 @@ wimfs_chown(const char *path, uid_t uid, gid_t gid) struct wim_inode *inode; struct wimfs_context *ctx = wimfs_get_context(); int which; + struct wimlib_unix_data unix_data; int ret; if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA)) @@ -1668,8 +1680,11 @@ wimfs_chown(const char *path, uid_t uid, gid_t gid) gid = ctx->default_gid; - if (!inode_set_unix_data(inode, uid, gid, - inode_default_unix_mode(inode), which)) + unix_data.uid = uid; + unix_data.gid = gid; + unix_data.mode = inode_default_unix_mode(inode); + unix_data.rdev = 0; + if (!inode_set_unix_data(inode, &unix_data, which)) return -ENOMEM; return 0; @@ -1880,11 +1895,12 @@ wimfs_listxattr(const char *path, char *list, size_t size) static int wimfs_mkdir(const char *path, mode_t mode) { - return create_dentry(fuse_get_context(), path, mode | S_IFDIR, + return create_dentry(fuse_get_context(), path, mode | S_IFDIR, 0, FILE_ATTRIBUTE_DIRECTORY, NULL); } -/* Create a regular file or alternate data stream in the WIM image. */ +/* Create a non-directory, non-symbolic-link file or alternate data stream in + * the WIM image. */ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) { @@ -1892,11 +1908,12 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) struct fuse_context *fuse_ctx = fuse_get_context(); struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx); - if (!S_ISREG(mode)) - return -EPERM; - if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS) && (stream_name = path_stream_name(path))) { + + if (!S_ISREG(mode)) + return -EPERM; + /* Make an alternate data stream */ struct wim_ads_entry *new_entry; struct wim_inode *inode; @@ -1917,8 +1934,12 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) return -ENOMEM; return 0; } else { - /* Make a normal file (not an alternate data stream) */ - return create_dentry(fuse_ctx, path, mode | S_IFREG, + if (!S_ISREG(mode) && + !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA)) + return -EPERM; + + /* Make a regular file, device node, named pipe, or socket. */ + return create_dentry(fuse_ctx, path, mode, rdev, FILE_ATTRIBUTE_NORMAL, NULL); } } @@ -2255,7 +2276,7 @@ wimfs_symlink(const char *to, const char *from) struct wim_dentry *dentry; int ret; - ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777, + ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777, 0, FILE_ATTRIBUTE_REPARSE_POINT, &dentry); if (ret == 0) { dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK; diff --git a/src/tagged_items.c b/src/tagged_items.c index 3a12974a..6cd897fa 100644 --- a/src/tagged_items.c +++ b/src/tagged_items.c @@ -69,7 +69,7 @@ struct wimlib_unix_data_disk { le32 uid; le32 gid; le32 mode; - le32 reserved; + le32 rdev; }; /* Retrieves the first tagged item with the specified tag and minimum length @@ -178,19 +178,20 @@ inode_get_unix_data(const struct wim_inode *inode, unix_data->uid = le32_to_cpu(p->uid); unix_data->gid = le32_to_cpu(p->gid); unix_data->mode = le32_to_cpu(p->mode); + unix_data->rdev = le32_to_cpu(p->rdev); return true; } /* Sets UNIX data on the specified WIM inode. * This is a wimlib extension. * - * Callers must specify all of @uid, @gid, and @mode. If the inode does not yet + * Callers must specify all members in @unix_data. If the inode does not yet * have UNIX data, it is given these values. Otherwise, only the values that * also have the corresponding flags in @which set are changed. * * Returns %true if successful, %false if failed (out of memory). */ bool -inode_set_unix_data(struct wim_inode *inode, u32 uid, u32 gid, u32 mode, +inode_set_unix_data(struct wim_inode *inode, struct wimlib_unix_data *unix_data, int which) { struct wimlib_unix_data_disk *p; @@ -200,14 +201,15 @@ inode_set_unix_data(struct wim_inode *inode, u32 uid, u32 gid, u32 mode, p = inode_add_unix_data_disk(inode); if (!p) return false; - p->reserved = cpu_to_le32(0); - which = UNIX_DATA_UID | UNIX_DATA_GID | UNIX_DATA_MODE; + which = UNIX_DATA_ALL; } if (which & UNIX_DATA_UID) - p->uid = cpu_to_le32(uid); + p->uid = cpu_to_le32(unix_data->uid); if (which & UNIX_DATA_GID) - p->gid = cpu_to_le32(gid); + p->gid = cpu_to_le32(unix_data->gid); if (which & UNIX_DATA_MODE) - p->mode = cpu_to_le32(mode); + p->mode = cpu_to_le32(unix_data->mode); + if (which & UNIX_DATA_RDEV) + p->rdev = cpu_to_le32(unix_data->rdev); return true; } diff --git a/src/unix_apply.c b/src/unix_apply.c index 40dc9edf..8b8d9bf5 100644 --- a/src/unix_apply.c +++ b/src/unix_apply.c @@ -96,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 @@ -373,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; @@ -390,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; @@ -709,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]); diff --git a/src/unix_capture.c b/src/unix_capture.c index a72d3ad3..ba540c98 100644 --- a/src/unix_capture.c +++ b/src/unix_capture.c @@ -347,19 +347,25 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret, goto out; } - if (unlikely(!S_ISREG(stbuf.st_mode) && - !S_ISDIR(stbuf.st_mode) && - !S_ISLNK(stbuf.st_mode))) - { - if (params->add_flags & WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE) + if (!(params->add_flags & WIMLIB_ADD_FLAG_UNIX_DATA)) { + if (unlikely(!S_ISREG(stbuf.st_mode) && + !S_ISDIR(stbuf.st_mode) && + !S_ISLNK(stbuf.st_mode))) { - ERROR("\"%s\": File type is unsupported", full_path); - ret = WIMLIB_ERR_UNSUPPORTED_FILE; + if (params->add_flags & + WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE) + { + ERROR("\"%s\": File type is unsupported", + full_path); + ret = WIMLIB_ERR_UNSUPPORTED_FILE; + goto out; + } + params->progress.scan.cur_path = full_path; + ret = do_capture_progress(params, + WIMLIB_SCAN_DENTRY_UNSUPPORTED, + NULL); goto out; } - params->progress.scan.cur_path = full_path; - ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_UNSUPPORTED, NULL); - goto out; } ret = inode_table_new_dentry(params->inode_table, relpath, @@ -387,9 +393,13 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret, #endif inode->i_resolved = 1; if (params->add_flags & WIMLIB_ADD_FLAG_UNIX_DATA) { - if (!inode_set_unix_data(inode, stbuf.st_uid, stbuf.st_gid, - stbuf.st_mode, UNIX_DATA_ALL)) - { + struct wimlib_unix_data unix_data; + + unix_data.uid = stbuf.st_uid; + unix_data.gid = stbuf.st_gid; + unix_data.mode = stbuf.st_mode; + unix_data.rdev = stbuf.st_rdev; + if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_ALL)) { ret = WIMLIB_ERR_NOMEM; goto out; } @@ -407,7 +417,7 @@ unix_build_dentry_tree_recursive(struct wim_dentry **tree_ret, } else if (S_ISDIR(stbuf.st_mode)) { ret = unix_scan_directory(tree, full_path, full_path_len, dirfd, relpath, params); - } else { + } else if (S_ISLNK(stbuf.st_mode)) { ret = unix_scan_symlink(&tree, full_path, dirfd, relpath, inode, params); if (!tree) diff --git a/src/util.c b/src/util.c index 02017d03..7916f40a 100644 --- a/src/util.c +++ b/src/util.c @@ -350,6 +350,8 @@ static const tchar *error_strings[] = { = T("The operation was aborted by the library user"), [WIMLIB_ERR_UNKNOWN_PROGRESS_STATUS] = T("The user-provided progress function returned an unrecognized value"), + [WIMLIB_ERR_MKNOD] + = T("Unable to create a special file (e.g. device node or socket)"), }; /* API function documented in wimlib.h */