+ list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
+ ret = unix_create_if_directory(dentry, ctx);
+ if (ret)
+ return ret;
+ }
+ list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
+ ret = unix_extract_if_empty_file(dentry, ctx);
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static void
+unix_count_dentries(const struct list_head *dentry_list,
+ u64 *dir_count_ret, u64 *empty_file_count_ret)
+{
+ const struct wim_dentry *dentry;
+ u64 dir_count = 0;
+ u64 empty_file_count = 0;
+
+ list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
+
+ const struct wim_inode *inode = dentry->d_inode;
+
+ if (inode_is_directory(inode))
+ dir_count++;
+ else if ((dentry == inode_first_extraction_dentry(inode)) &&
+ !inode_is_symlink(inode) &&
+ !inode_get_blob_for_unnamed_data_stream_resolved(inode))
+ empty_file_count++;
+ }
+
+ *dir_count_ret = dir_count;
+ *empty_file_count_ret = empty_file_count;
+}
+
+static int
+unix_create_symlink(const struct wim_inode *inode, const char *path,
+ size_t rpdatalen, struct unix_apply_ctx *ctx)
+{
+ char target[REPARSE_POINT_MAX_SIZE];
+ struct blob_descriptor blob_override;
+ int ret;
+
+ blob_set_is_located_in_attached_buffer(&blob_override,
+ ctx->reparse_data, rpdatalen);
+
+ ret = wim_inode_readlink(inode, target, sizeof(target) - 1,
+ &blob_override,
+ ctx->target_abspath,
+ ctx->target_abspath_nchars);
+ if (unlikely(ret < 0)) {
+ errno = -ret;
+ return WIMLIB_ERR_READLINK;
+ }
+ target[ret] = '\0';
+
+retry_symlink:
+ if (symlink(target, path)) {
+ if (errno == EEXIST && !unlink(path))
+ goto retry_symlink;
+ return WIMLIB_ERR_LINK;
+ }
+ return 0;
+}
+
+static void
+unix_cleanup_open_fds(struct unix_apply_ctx *ctx, unsigned offset)
+{
+ for (unsigned i = offset; i < ctx->num_open_fds; i++)
+ filedes_close(&ctx->open_fds[i]);
+ ctx->num_open_fds = 0;
+}
+
+static int
+unix_begin_extract_blob_instance(const struct blob_descriptor *blob,
+ const struct wim_inode *inode,
+ const struct wim_inode_stream *strm,
+ struct unix_apply_ctx *ctx)
+{
+ const struct wim_dentry *first_dentry;
+ const char *first_path;
+ int fd;
+
+ if (unlikely(strm->stream_type == STREAM_TYPE_REPARSE_POINT)) {
+ /* On UNIX, symbolic links must be created with symlink(), which
+ * requires that the full link target be available. */
+ 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),
+ blob->size, REPARSE_DATA_MAX_SIZE);
+ return WIMLIB_ERR_INVALID_REPARSE_DATA;
+ }
+ ctx->reparse_ptr = ctx->reparse_data;
+ return 0;
+ }
+
+ wimlib_assert(stream_is_unnamed_data_stream(strm));
+
+ /* Unnamed data stream of "regular" file */
+
+ /* This should be ensured by extract_blob_list() */
+ wimlib_assert(ctx->num_open_fds < MAX_OPEN_FILES);
+
+ 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);
+ if (fd < 0) {
+ if (errno == EEXIST && !unlink(first_path))
+ goto retry_create;
+ ERROR_WITH_ERRNO("Can't create regular file \"%s\"", first_path);