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;
static void
unix_count_dentries(const struct list_head *dentry_list,
- uint64_t *dir_count_ret, uint64_t *empty_file_count_ret)
+ u64 *dir_count_ret, u64 *empty_file_count_ret)
{
const struct wim_dentry *dentry;
- uint64_t dir_count = 0;
- uint64_t empty_file_count = 0;
+ 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))
+ if (should_extract_as_directory(inode))
dir_count++;
else if ((dentry == inode_first_extraction_dentry(inode)) &&
!inode_is_symlink(inode) &&
static int
unix_create_symlink(const struct wim_inode *inode, const char *path,
- const u8 *rpdata, u16 rpdatalen, bool rpfix,
- const char *apply_dir, size_t apply_dir_nchars)
+ size_t rpdatalen, struct unix_apply_ctx *ctx)
{
- char link_target[REPARSE_DATA_MAX_SIZE];
- int ret;
+ char target[REPARSE_POINT_MAX_SIZE];
struct blob_descriptor blob_override;
+ int ret;
blob_set_is_located_in_attached_buffer(&blob_override,
- (void *)rpdata, rpdatalen);
+ ctx->reparse_data, rpdatalen);
- ret = wim_inode_readlink(inode, link_target,
- sizeof(link_target) - 1, &blob_override);
- if (ret < 0) {
+ 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';
- link_target[ret] = 0;
-
- if (rpfix && link_target[0] == '/') {
-
- /* "Fix" the absolute symbolic link by prepending the absolute
- * path to the target directory. */
-
- if (sizeof(link_target) - (ret + 1) < apply_dir_nchars) {
- errno = ENAMETOOLONG;
- return WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED;
- }
- memmove(link_target + apply_dir_nchars, link_target,
- ret + 1);
- memcpy(link_target, apply_dir, apply_dir_nchars);
- }
retry_symlink:
- if (symlink(link_target, path)) {
+ if (symlink(target, path)) {
if (errno == EEXIST && !unlink(path))
goto retry_symlink;
return WIMLIB_ERR_LINK;
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;
}
/* We finally have the symlink data, so we can create
* the symlink. */
const char *path;
- bool rpfix;
-
- rpfix = (ctx->common.extract_flags &
- WIMLIB_EXTRACT_FLAG_RPFIX) &&
- !inode->i_not_rpfixed;
path = unix_build_inode_extraction_path(inode, ctx);
- ret = unix_create_symlink(inode, path,
- ctx->reparse_data,
- blob->size,
- rpfix,
- ctx->target_abspath,
- ctx->target_abspath_nchars);
+ ret = unix_create_symlink(inode, path, blob->size, ctx);
if (ret) {
ERROR_WITH_ERRNO("Can't create symbolic link "
"\"%s\"", path);
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;
int ret;
struct unix_apply_ctx *ctx = (struct unix_apply_ctx *)_ctx;
size_t path_max;
- uint64_t dir_count;
- uint64_t empty_file_count;
+ u64 dir_count;
+ u64 empty_file_count;
/* Compute the maximum path length that will be needed, then allocate
* some path buffers. */
/* Extract nonempty regular files and symbolic links. */
- struct read_blob_list_callbacks cbs = {
- .begin_blob = unix_begin_extract_blob,
- .begin_blob_ctx = ctx,
- .consume_chunk = unix_extract_chunk,
- .consume_chunk_ctx = ctx,
- .end_blob = unix_end_extract_blob,
- .end_blob_ctx = ctx,
+ struct read_blob_callbacks cbs = {
+ .begin_blob = unix_begin_extract_blob,
+ .consume_chunk = unix_extract_chunk,
+ .end_blob = unix_end_extract_blob,
+ .ctx = ctx,
};
ret = extract_blob_list(&ctx->common, &cbs);
if (ret)