*/
/*
- * 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
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));
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).
const struct wim_dentry *dentry;
const char *newpath;
- list_for_each_entry(dentry, &inode->i_extraction_aliases,
- d_extraction_alias_node)
- {
+ inode_for_each_extraction_alias(dentry, inode) {
if (dentry == first_dentry)
continue;
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);
/* 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;
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;
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) &&
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;
}
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;
return WIMLIB_ERR_OPEN;
}
filedes_init(&ctx->open_fds[ctx->num_open_fds++], fd);
+#ifdef HAVE_POSIX_FALLOCATE
+ posix_fallocate(fd, 0, blob->size);
+#endif
return unix_create_hardlinks(inode, first_dentry, first_path, ctx);
}
/* Called when the next chunk of a blob has been read for extraction */
static int
-unix_extract_chunk(const void *chunk, size_t size, void *_ctx)
+unix_extract_chunk(const struct blob_descriptor *blob, u64 offset,
+ const void *chunk, size_t size, void *_ctx)
{
struct unix_apply_ctx *ctx = _ctx;
int ret;
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;
struct read_blob_callbacks cbs = {
.begin_blob = unix_begin_extract_blob,
- .consume_chunk = unix_extract_chunk,
+ .continue_blob = unix_extract_chunk,
.end_blob = unix_end_extract_blob,
.ctx = ctx,
};