X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fmount_image.c;h=bca9e4390e473c7987ae04f0522ccf6ab91901c7;hp=1133ad7d36ec71e037d97ac712746604fcd07ba7;hb=52c44c6a506cdfae17fd5fd5c6611622d342c128;hpb=3071e89c11d1be71cf45b694432e5908e0c4ded9 diff --git a/src/mount_image.c b/src/mount_image.c index 1133ad7d..bca9e439 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -8,7 +8,7 @@ */ /* - * Copyright (C) 2012, 2013, 2014 Eric Biggers + * Copyright (C) 2012, 2013, 2014, 2015 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 @@ -37,19 +37,14 @@ # error "FUSE mount not supported on Windows! Please configure --without-fuse" #endif -#include "wimlib/dentry.h" -#include "wimlib/encoding.h" -#include "wimlib/metadata.h" -#include "wimlib/paths.h" -#include "wimlib/progress.h" -#include "wimlib/reparse.h" -#include "wimlib/timestamp.h" -#include "wimlib/unix_data.h" -#include "wimlib/write.h" -#include "wimlib/xml.h" +#define FUSE_USE_VERSION 26 + +#include /* sometimes required before */ +#include #include #include +#include #include #include #include @@ -57,13 +52,20 @@ #include #include #include -#include #include #include -#define FUSE_USE_VERSION 26 -#include -#include +#include "wimlib/blob_table.h" +#include "wimlib/dentry.h" +#include "wimlib/encoding.h" +#include "wimlib/metadata.h" +#include "wimlib/paths.h" +#include "wimlib/progress.h" +#include "wimlib/reparse.h" +#include "wimlib/timestamp.h" +#include "wimlib/unix_data.h" +#include "wimlib/write.h" +#include "wimlib/xml.h" #ifndef O_NOFOLLOW # define O_NOFOLLOW 0 /* Security only... */ @@ -96,12 +98,12 @@ struct wimfs_fd { * that reference it. */ struct wim_inode *f_inode; - /* Pointer to the lookup table entry for the data stream that has been - * opened. 'num_opened_fds' of the lookup table entry tracks the number - * of file descriptors that reference it. Or, this value may be NULL, + /* Pointer to the blob descriptor for the data stream that has been + * opened. 'num_opened_fds' of the blob descriptor tracks the number of + * file descriptors that reference it. Or, this value may be NULL, * which indicates that the opened stream is empty and consequently does - * not have a lookup table entry. */ - struct wim_lookup_table_entry *f_lte; + * not have a blob descriptor. */ + struct blob_descriptor *f_blob; /* If valid (filedes_valid(&f_staging_fd)), this contains the * corresponding native file descriptor for the staging file that has @@ -120,8 +122,8 @@ struct wimfs_fd { u16 f_idx; /* Unique ID of the opened stream in the inode. This will stay the same - * even if the indices of the inode's alternate data streams are changed - * by a deletion. */ + * even if the indices of the inode's streams are changed by a deletion. + */ u32 f_stream_id; }; @@ -143,6 +145,11 @@ struct wimfs_context { uid_t owner_uid; gid_t owner_gid; + /* Absolute path to the mountpoint directory (may be needed for absolute + * symbolic link fixups) */ + char *mountpoint_abspath; + size_t mountpoint_abspath_nchars; + /* Information about the staging directory for a read-write mount. */ int parent_dir_fd; int staging_dir_fd; @@ -157,9 +164,9 @@ struct wimfs_context { /* Number of file descriptors open to the mounted WIM image. */ unsigned long num_open_fds; - /* Original list of single-instance streams in the mounted image, linked - * by 'struct wim_lookup_table_entry'.orig_stream_list. */ - struct list_head orig_stream_list; + /* Original list of blobs in the mounted image, linked by + * 'struct blob_descriptor'.orig_blob_list. */ + struct list_head orig_blob_list; /* Parameters for unmounting the image (can be set via extended * attribute "wimfs.unmount_info"). */ @@ -219,12 +226,9 @@ fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx) * Allocate a file descriptor to a data stream in the mounted WIM image. * * @inode - * A pointer to the inode containing the stream being opened. - * @stream_id - * The ID of the data stream being opened within the inode. - * @lte - * A pointer to the lookup table entry for the stream data. Or, for a - * 0-byte stream, this may be NULL. + * The inode containing the stream being opened + * @strm + * The stream of the inode being opened * @fd_ret * On success, a pointer to the new file descriptor will be stored here. * @@ -232,8 +236,7 @@ fuse_mask_mode(mode_t mode, const struct fuse_context *fuse_ctx) */ static int alloc_wimfs_fd(struct wim_inode *inode, - u32 stream_id, - struct wim_lookup_table_entry *lte, + struct wim_inode_stream *strm, struct wimfs_fd **fd_ret) { static const u16 min_fds_per_alloc = 8; @@ -281,15 +284,15 @@ alloc_wimfs_fd(struct wim_inode *inode, return -ENOMEM; fd->f_inode = inode; - fd->f_lte = lte; + fd->f_blob = stream_blob_resolved(strm); filedes_invalidate(&fd->f_staging_fd); fd->f_idx = i; - fd->f_stream_id = stream_id; + fd->f_stream_id = strm->stream_id; *fd_ret = fd; inode->i_fds[i] = fd; inode->i_num_opened_fds++; - if (lte) - lte->num_opened_fds++; + if (fd->f_blob) + fd->f_blob->num_opened_fds++; wimfs_inc_num_open_fds(); inode->i_next_fd = i + 1; return 0; @@ -311,9 +314,9 @@ close_wimfs_fd(struct wimfs_fd *fd) if (filedes_close(&fd->f_staging_fd)) ret = -errno; - /* Release this file descriptor from its lookup table entry. */ - if (fd->f_lte) - lte_decrement_num_opened_fds(fd->f_lte); + /* Release this file descriptor from its blob descriptor. */ + if (fd->f_blob) + blob_decrement_num_opened_fds(fd->f_blob); wimfs_dec_num_open_fds(); @@ -323,15 +326,7 @@ close_wimfs_fd(struct wimfs_fd *fd) if (fd->f_idx < inode->i_next_fd) inode->i_next_fd = fd->f_idx; FREE(fd); - if (--inode->i_num_opened_fds == 0) { - /* The last file descriptor to this inode was closed. */ - FREE(inode->i_fds); - inode->i_fds = NULL; - inode->i_num_allocated_fds = 0; - if (inode->i_nlink == 0) - /* No links to this inode remain. Get rid of it. */ - free_inode(inode); - } + inode_dec_num_opened_fds(inode); return ret; } @@ -359,26 +354,47 @@ wim_pathname_to_inode(WIMStruct *wim, const char *path) /* Can look up directory (otherwise get -ENOTDIR) */ #define LOOKUP_FLAG_DIRECTORY_OK 0x02 +/* Get the data stream of the specified name from the specified inode. Returns + * NULL with errno set if not found. */ +static struct wim_inode_stream * +inode_get_data_stream_tstr(const struct wim_inode *inode, + const char *stream_name) +{ + struct wim_inode_stream *strm; + + if (!stream_name || !*stream_name) { + strm = inode_get_unnamed_data_stream(inode); + } else { + const utf16lechar *uname; + + if (tstr_get_utf16le(stream_name, &uname)) + return NULL; + strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname); + tstr_put_utf16le(uname); + } + if (!strm) + errno = ENOENT; + return strm; +} + /* - * Translate a path into the corresponding dentry, lookup table entry, and - * stream index in the mounted WIM image. + * Translate a path into the corresponding dentry and stream in the mounted WIM + * image. * - * Returns 0 or a -errno code. All of @dentry_ret, @lte_ret, and - * @stream_idx_ret are optional. + * Returns 0 or a -errno code. @dentry_ret and @strm_ret are both optional. */ static int -wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path, +wim_pathname_to_stream(const struct wimfs_context *ctx, + const char *path, int lookup_flags, struct wim_dentry **dentry_ret, - struct wim_lookup_table_entry **lte_ret, - u16 *stream_idx_ret) + struct wim_inode_stream **strm_ret) { WIMStruct *wim = ctx->wim; struct wim_dentry *dentry; - struct wim_lookup_table_entry *lte; - u16 stream_idx; - const char *stream_name = NULL; struct wim_inode *inode; + struct wim_inode_stream *strm; + const char *stream_name = NULL; char *p = NULL; lookup_flags |= ctx->default_lookup_flags; @@ -399,31 +415,27 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path, inode = dentry->d_inode; - if (inode_resolve_streams(inode, wim->lookup_table, false)) + if (inode_resolve_streams(inode, wim->blob_table, false)) return -EIO; if (!(lookup_flags & LOOKUP_FLAG_DIRECTORY_OK) && inode_is_directory(inode)) return -EISDIR; - if (stream_name) { - struct wim_ads_entry *ads_entry; - - ads_entry = inode_get_ads_entry(inode, stream_name); - if (!ads_entry) + strm = inode_get_data_stream_tstr(inode, stream_name); + if (!strm) { + /* Force creation of an unnamed data stream */ + if (!stream_name) + strm = inode_add_stream(inode, STREAM_TYPE_DATA, + NO_STREAM_NAME, NULL); + if (!strm) return -errno; - - stream_idx = ads_entry - inode->i_ads_entries + 1; - lte = ads_entry->lte; - } else { - lte = inode_unnamed_stream_resolved(inode, &stream_idx); } + if (dentry_ret) *dentry_ret = dentry; - if (lte_ret) - *lte_ret = lte; - if (stream_idx_ret) - *stream_idx_ret = stream_idx; + if (strm_ret) + *strm_ret = strm; return 0; } @@ -436,14 +448,12 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path, * The path at which to create the first link to the new file. If a file * already exists at this path, -EEXIST is returned. * @mode - * The UNIX mode for the new file. This is only honored if + * The UNIX mode for the new file. This is only fully honored if * WIMLIB_MOUNT_FLAG_UNIX_DATA was passed to wimlib_mount_image(). * @rdev * The device ID for the new file, encoding the major and minor device * numbers. This is only honored if WIMLIB_MOUNT_FLAG_UNIX_DATA was passed * to wimlib_mount_image(). - * @attributes - * Windows file attributes to use for the new file. * @dentry_ret * On success, a pointer to the new dentry is returned here. Its d_inode * member will point to the new inode that was created for it and added to @@ -452,15 +462,14 @@ wim_pathname_to_stream(const struct wimfs_context *ctx, const char *path, * Returns 0 or a -errno code. */ static int -create_dentry(struct fuse_context *fuse_ctx, const char *path, - mode_t mode, dev_t rdev, u32 attributes, - struct wim_dentry **dentry_ret) +create_file(struct fuse_context *fuse_ctx, const char *path, + mode_t mode, dev_t rdev, struct wim_dentry **dentry_ret) { struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx); struct wim_dentry *parent; const char *basename; - struct wim_dentry *new_dentry; - struct wim_inode *new_inode; + struct wim_dentry *dentry; + struct wim_inode *inode; parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE); if (!parent) @@ -474,14 +483,19 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path, if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE)) return -EEXIST; - if (new_dentry_with_inode(basename, &new_dentry)) + if (new_dentry_with_new_inode(basename, true, &dentry)) return -ENOMEM; - new_inode = new_dentry->d_inode; + inode = dentry->d_inode; - new_inode->i_resolved = 1; - new_inode->i_ino = wimfs_ctx->next_ino++; - new_inode->i_attributes = attributes; + inode->i_ino = wimfs_ctx->next_ino++; + + /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes, named + * pipes, and sockets. The real mode is in the UNIX metadata. */ + if (S_ISDIR(mode)) + inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY; + else + inode->i_attributes = FILE_ATTRIBUTE_NORMAL; if (wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA) { struct wimlib_unix_data unix_data; @@ -490,19 +504,19 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path, 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_inode, &unix_data, UNIX_DATA_ALL)) + if (!inode_set_unix_data(inode, &unix_data, UNIX_DATA_ALL)) { - free_dentry(new_dentry); + free_dentry(dentry); return -ENOMEM; } } - list_add_tail(&new_inode->i_list, - &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list); + hlist_add_head(&inode->i_hlist_node, + &wim_get_current_image_metadata(wimfs_ctx->wim)->inode_list); - dentry_add_child(parent, new_dentry); + dentry_add_child(parent, dentry); - *dentry_ret = new_dentry; + *dentry_ret = dentry; return 0; } @@ -511,11 +525,10 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path, * inode. */ static void -remove_dentry(struct wim_dentry *dentry, - struct wim_lookup_table *lookup_table) +remove_dentry(struct wim_dentry *dentry, struct blob_table *blob_table) { - /* Drop the reference to each stream the inode contains. */ - inode_unref_streams(dentry->d_inode, lookup_table); + /* Drop blob references. */ + inode_unref_blobs(dentry->d_inode, blob_table); /* Unlink the dentry from the image's dentry tree. */ unlink_dentry(dentry); @@ -545,19 +558,37 @@ inode_default_unix_mode(const struct wim_inode *inode) return inode_unix_file_type(inode) | 0777; } +static u64 +blob_size(const struct blob_descriptor *blob) +{ + if (!blob) + return 0; + return blob->size; +} + +static u64 +blob_stored_size(const struct blob_descriptor *blob) +{ + if (!blob) + return 0; + if (blob->blob_location == BLOB_IN_WIM && + blob->size == blob->rdesc->uncompressed_size) + return blob->rdesc->size_in_wim; + return blob->size; +} + /* * Retrieve standard UNIX metadata ('struct stat') for a WIM inode. * - * @lte specifies the stream of the inode that is being queried. We mostly - * return the same information for all streams, but st_size and st_blocks may be - * different for different streams. + * @blob is the blob descriptor for the stream of the inode that is being + * queried, or NULL. We mostly return the same information for all streams, but + * st_size and st_blocks may be different for different streams. * * This always returns 0. */ static int inode_to_stbuf(const struct wim_inode *inode, - const struct wim_lookup_table_entry *lte, - struct stat *stbuf) + const struct blob_descriptor *blob, struct stat *stbuf) { const struct wimfs_context *ctx = wimfs_get_context(); struct wimlib_unix_data unix_data; @@ -583,18 +614,17 @@ inode_to_stbuf(const struct wim_inode *inode, } stbuf->st_ino = inode->i_ino; stbuf->st_nlink = inode->i_nlink; - if (lte) - stbuf->st_size = lte->size; + stbuf->st_size = blob_size(blob); #ifdef HAVE_STAT_NANOSECOND_PRECISION stbuf->st_atim = wim_timestamp_to_timespec(inode->i_last_access_time); stbuf->st_mtim = wim_timestamp_to_timespec(inode->i_last_write_time); stbuf->st_ctim = stbuf->st_mtim; #else - stbuf->st_atime = wim_timestamp_to_unix(inode->i_last_access_time); - stbuf->st_mtime = wim_timestamp_to_unix(inode->i_last_write_time); + stbuf->st_atime = wim_timestamp_to_time_t(inode->i_last_access_time); + stbuf->st_mtime = wim_timestamp_to_time_t(inode->i_last_write_time); stbuf->st_ctime = stbuf->st_mtime; #endif - stbuf->st_blocks = (stbuf->st_size + 511) / 512; + stbuf->st_blocks = DIV_ROUND_UP(blob_stored_size(blob), 512); return 0; } @@ -602,7 +632,7 @@ inode_to_stbuf(const struct wim_inode *inode, static void touch_inode(struct wim_inode *inode) { - u64 now = get_wim_timestamp(); + u64 now = now_as_wim_timestamp(); inode->i_last_access_time = now; inode->i_last_write_time = now; } @@ -651,49 +681,37 @@ retry: } /* - * Extract a WIM resource to the staging directory. - * This is necessary if a stream using the resource is being opened for writing. + * Extract a blob to the staging directory. This is necessary when a stream + * using the blob is being opened for writing and the blob has not already been + * extracted to the staging directory. * * @inode * The inode containing the stream being opened for writing. - * - * @stream_idx - * The index of the stream in @inode being opened for writing. - * - * @lte_ptr - * *lte_ptr is the lookup table entry for the stream being extracted, or - * NULL if the stream does not have a lookup table entry (which is possible - * if the stream is empty). On success, *lte_ptr will be set to point to a - * lookup table entry that represents the resource in its new location in a - * staging file. This may be the same as the old entry in the case that it - * was reused, or it may be a new entry. - * + * @strm + * The stream being opened for writing. The blob descriptor to which the + * stream refers will be changed by this function. * @size - * Number of bytes of the stream to extract and include in the staging file - * resource. It may be less than the actual stream length, in which case - * only a prefix of the resource will be extracted. It may also be more - * than the actual stream length, in which case the extra space will be - * zero-filled. + * Number of bytes of the blob to extract and include in the staging file. + * It may be less than the actual blob length, in which case only a prefix + * of the blob will be extracted. It may also be more than the actual blob + * length, in which case the extra space will be zero-filled. * * Returns 0 or a -errno code. */ static int -extract_resource_to_staging_dir(struct wim_inode *inode, - u16 stream_idx, - struct wim_lookup_table_entry **lte_ptr, - off_t size, - const struct wimfs_context *ctx) -{ - struct wim_lookup_table_entry *old_lte; - struct wim_lookup_table_entry *new_lte; +extract_blob_to_staging_dir(struct wim_inode *inode, + struct wim_inode_stream *strm, + off_t size, const struct wimfs_context *ctx) +{ + struct blob_descriptor *old_blob; + struct blob_descriptor *new_blob; char *staging_file_name; int staging_fd; off_t extract_size; int result; - u32 stream_id; int ret; - old_lte = *lte_ptr; + old_blob = stream_blob_resolved(strm); /* Create the staging file. */ staging_fd = create_staging_file(ctx, &staging_file_name); @@ -701,13 +719,13 @@ extract_resource_to_staging_dir(struct wim_inode *inode, return -errno; /* Extract the stream to the staging file (possibly truncated). */ - if (old_lte) { + if (old_blob) { struct filedes fd; filedes_init(&fd, staging_fd); errno = 0; - extract_size = min(old_lte->size, size); - result = extract_stream_to_fd(old_lte, &fd, extract_size); + extract_size = min(old_blob->size, size); + result = extract_blob_prefix_to_fd(old_blob, extract_size, &fd); } else { extract_size = 0; result = 0; @@ -724,106 +742,74 @@ extract_resource_to_staging_dir(struct wim_inode *inode, /* If an error occurred, unlink the staging file. */ if (unlikely(result)) { - /* extract_stream_to_fd() should set errno, but if it didn't, + /* extract_blob_to_fd() should set errno, but if it didn't, * set a default value. */ ret = errno ? -errno : -EIO; goto out_delete_staging_file; } - /* Now deal with the lookup table entries. We may be able to re-use the - * existing entry, but we may have to create a new one instead. */ + /* Create a blob descriptor for the staging file. */ + new_blob = new_blob_descriptor(); + if (unlikely(!new_blob)) { + ret = -ENOMEM; + goto out_delete_staging_file; + } - stream_id = inode_stream_idx_to_id(inode, stream_idx); + /* There may already be open file descriptors to this stream if it's + * previously been opened read-only, but just now we're opening it + * read-write. Identify those file descriptors, update them to use the + * new blob descriptor, and open staging file descriptors for them. */ + for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) { + struct wimfs_fd *fd; + int raw_fd; - if (old_lte && inode->i_nlink == old_lte->refcnt) { - /* The reference count of the existing lookup table entry is the - * same as the link count of the inode that contains the stream - * we're opening. Therefore, all the references to the lookup - * table entry correspond to the stream we're trying to extract, - * so the lookup table entry can be re-used. */ - lookup_table_unlink(ctx->wim->lookup_table, old_lte); - lte_put_resource(old_lte); - new_lte = old_lte; - } else { - /* We need to split the old lookup table entry because it also - * has other references. Or, there was no old lookup table - * entry, so we need to create a new one anyway. */ + fd = inode->i_fds[i]; + if (!fd) + continue; - new_lte = new_lookup_table_entry(); - if (unlikely(!new_lte)) { - ret = -ENOMEM; - goto out_delete_staging_file; - } + j++; - /* There may already be open file descriptors to this stream if - * it's previously been opened read-only, but just now we're - * opening it read-write. Identify those file descriptors and - * change their lookup table entry pointers to point to the new - * lookup table entry, and open staging file descriptors for - * them. - * - * At the same time, we need to count the number of these opened - * file descriptors to the new lookup table entry. If there's - * an old lookup table entry, this number needs to be subtracted - * from the fd's opened to the old entry. */ - for (u16 i = 0, j = 0; j < inode->i_num_opened_fds; i++) { - struct wimfs_fd *fd; - int raw_fd; - - fd = inode->i_fds[i]; - if (!fd) - continue; - - j++; - - if (fd->f_stream_id != stream_id) - continue; - - /* This is a readonly fd for the same stream. */ - fd->f_lte = new_lte; - new_lte->num_opened_fds++; - raw_fd = openat(ctx->staging_dir_fd, staging_file_name, - O_RDONLY | O_NOFOLLOW); - if (unlikely(raw_fd < 0)) { - ret = -errno; - goto out_revert_fd_changes; - } - filedes_init(&fd->f_staging_fd, raw_fd); - } - if (old_lte) { - old_lte->num_opened_fds -= new_lte->num_opened_fds; - old_lte->refcnt -= inode->i_nlink; + if (fd->f_stream_id != strm->stream_id) + continue; + + /* This is a readonly fd for the same stream. */ + fd->f_blob = new_blob; + new_blob->num_opened_fds++; + raw_fd = openat(ctx->staging_dir_fd, staging_file_name, + O_RDONLY | O_NOFOLLOW); + if (unlikely(raw_fd < 0)) { + ret = -errno; + goto out_revert_fd_changes; } + filedes_init(&fd->f_staging_fd, raw_fd); } - new_lte->refcnt = inode->i_nlink; - new_lte->resource_location = RESOURCE_IN_STAGING_FILE; - new_lte->staging_file_name = staging_file_name; - new_lte->staging_dir_fd = ctx->staging_dir_fd; - new_lte->size = size; + if (old_blob) + old_blob->num_opened_fds -= new_blob->num_opened_fds; - add_unhashed_stream(new_lte, inode, stream_id, - &wim_get_current_image_metadata(ctx->wim)->unhashed_streams); - if (stream_idx == 0) - inode->i_lte = new_lte; - else - inode->i_ads_entries[stream_idx - 1].lte = new_lte; - *lte_ptr = new_lte; + new_blob->blob_location = BLOB_IN_STAGING_FILE; + new_blob->staging_file_name = staging_file_name; + new_blob->staging_dir_fd = ctx->staging_dir_fd; + new_blob->size = size; + + prepare_unhashed_blob(new_blob, inode, strm->stream_id, + &wim_get_current_image_metadata(ctx->wim)->unhashed_blobs); + inode_replace_stream_blob(inode, strm, new_blob, ctx->wim->blob_table); return 0; out_revert_fd_changes: - for (u16 i = 0; new_lte->num_opened_fds; i++) { + for (u16 i = 0; new_blob->num_opened_fds; i++) { struct wimfs_fd *fd = inode->i_fds[i]; - if (fd && fd->f_stream_id == stream_id) { - fd->f_lte = old_lte; + if (fd && fd->f_stream_id == strm->stream_id) { + fd->f_blob = old_blob; if (filedes_valid(&fd->f_staging_fd)) { filedes_close(&fd->f_staging_fd); filedes_invalidate(&fd->f_staging_fd); } - new_lte->num_opened_fds--; + new_blob->num_opened_fds--; } } - free_lookup_table_entry(new_lte); + free_blob_descriptor(new_blob); out_delete_staging_file: unlinkat(ctx->staging_dir_fd, staging_file_name, 0); FREE(staging_file_name); @@ -962,50 +948,50 @@ delete_staging_dir(struct wimfs_context *ctx) close(ctx->parent_dir_fd); } -/* Number the inodes in the mounted image sequentially. */ static void -reassign_inode_numbers(struct wimfs_context *ctx) +prepare_inodes(struct wimfs_context *ctx) { struct wim_image_metadata *imd; struct wim_inode *inode; ctx->next_ino = 1; imd = wim_get_current_image_metadata(ctx->wim); - image_for_each_inode(inode, imd) + image_for_each_inode(inode, imd) { inode->i_ino = ctx->next_ino++; + inode->i_num_opened_fds = 0; + inode->i_num_allocated_fds = 0; + inode->i_fds = NULL; + } } static void release_extra_refcnts(struct wimfs_context *ctx) { - struct list_head *list = &ctx->orig_stream_list; - struct wim_lookup_table *lookup_table = ctx->wim->lookup_table; - struct wim_lookup_table_entry *lte, *tmp; + struct list_head *list = &ctx->orig_blob_list; + struct blob_table *blob_table = ctx->wim->blob_table; + struct blob_descriptor *blob, *tmp; - list_for_each_entry_safe(lte, tmp, list, orig_stream_list) { - u32 n = lte->out_refcnt; - while (n--) - lte_decrement_refcnt(lte, lookup_table); - } + list_for_each_entry_safe(blob, tmp, list, orig_blob_list) + blob_subtract_refcnt(blob, blob_table, blob->out_refcnt); } -/* Delete the 'struct wim_lookup_table_entry' for any stream that was modified +/* Delete the 'struct blob_descriptor' for any stream that was modified * or created in the read-write mounted image and had a final size of 0. */ static void -delete_empty_streams(struct wimfs_context *ctx) +delete_empty_blobs(struct wimfs_context *ctx) { - struct wim_lookup_table_entry *lte, *tmp; + struct blob_descriptor *blob, *tmp; struct wim_image_metadata *imd; imd = wim_get_current_image_metadata(ctx->wim); - image_for_each_unhashed_stream_safe(lte, tmp, imd) { - if (!lte->size) { - *retrieve_lte_pointer(lte) = NULL; - list_del(<e->unhashed_list); - free_lookup_table_entry(lte); - } - } + image_for_each_unhashed_blob_safe(blob, tmp, imd) { + if (!blob->size) { + *retrieve_pointer_to_unhashed_blob(blob) = NULL; + list_del(&blob->unhashed_list); + free_blob_descriptor(blob); + } + } } /* Close all file descriptors open to the specified inode. @@ -1027,12 +1013,13 @@ inode_close_fds(struct wim_inode *inode) static void close_all_fds(struct wimfs_context *ctx) { - struct wim_inode *inode, *tmp; + struct wim_inode *inode; + struct hlist_node *tmp; struct wim_image_metadata *imd; imd = wim_get_current_image_metadata(ctx->wim); - list_for_each_entry_safe(inode, tmp, &imd->inode_list, i_list) + image_for_each_inode_safe(inode, tmp, imd) inode_close_fds(inode); } @@ -1046,7 +1033,7 @@ renew_current_image(struct wimfs_context *ctx) int idx = wim->current_image - 1; struct wim_image_metadata *imd = wim->image_metadata[idx]; struct wim_image_metadata *replace_imd; - struct wim_lookup_table_entry *new_lte; + struct blob_descriptor *new_blob; int ret; /* Create 'replace_imd' structure to use for the reset original, @@ -1056,36 +1043,37 @@ renew_current_image(struct wimfs_context *ctx) if (!replace_imd) goto err; - /* Create new stream reference for the modified image's metadata + /* Create new blob descriptor for the modified image's metadata * resource, which doesn't exist yet. */ ret = WIMLIB_ERR_NOMEM; - new_lte = new_lookup_table_entry(); - if (!new_lte) + new_blob = new_blob_descriptor(); + if (!new_blob) goto err_put_replace_imd; - new_lte->flags = WIM_RESHDR_FLAG_METADATA; - new_lte->unhashed = 1; + + new_blob->refcnt = 1; + new_blob->is_metadata = 1; /* Make the image being moved available at a new index. Increments the * WIM's image count, but does not increment the reference count of the * 'struct image_metadata'. */ ret = append_image_metadata(wim, imd); if (ret) - goto err_free_new_lte; + goto err_free_new_blob; - ret = xml_add_image(wim, ""); + ret = xml_add_image(wim->xml_info, NULL); if (ret) goto err_undo_append; - replace_imd->metadata_lte = imd->metadata_lte; - imd->metadata_lte = new_lte; + replace_imd->metadata_blob = imd->metadata_blob; + imd->metadata_blob = new_blob; wim->image_metadata[idx] = replace_imd; wim->current_image = wim->hdr.image_count; return 0; err_undo_append: wim->hdr.image_count--; -err_free_new_lte: - free_lookup_table_entry(new_lte); +err_free_new_blob: + free_blob_descriptor(new_blob); err_put_replace_imd: put_image_metadata(replace_imd, NULL); err: @@ -1126,9 +1114,9 @@ commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq) } else { release_extra_refcnts(ctx); } - INIT_LIST_HEAD(&ctx->orig_stream_list); - delete_empty_streams(ctx); - xml_update_image_info(ctx->wim, ctx->wim->current_image); + INIT_LIST_HEAD(&ctx->orig_blob_list); + delete_empty_blobs(ctx); + mark_image_dirty(wim_get_current_image_metadata(ctx->wim)); write_flags = 0; @@ -1144,7 +1132,7 @@ commit_image(struct wimfs_context *ctx, int unmount_flags, mqd_t mq) return wimlib_overwrite(ctx->wim, write_flags, 0); } -/* In the case of an allow_other mount, only the owner and root should be +/* In the case of an allow_other mount, only the mount owner and root are * allowed to unmount the filesystem. */ static bool may_unmount_wimfs(void) @@ -1283,7 +1271,7 @@ static int wimfs_fgetattr(const char *path, struct stat *stbuf, struct fuse_file_info *fi) { struct wimfs_fd *fd = WIMFS_FD(fi); - return inode_to_stbuf(fd->f_inode, fd->f_lte, stbuf); + return inode_to_stbuf(fd->f_inode, fd->f_blob, stbuf); } static int @@ -1293,7 +1281,7 @@ wimfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi) if (ftruncate(fd->f_staging_fd.fd, size)) return -errno; touch_inode(fd->f_inode); - fd->f_lte->size = size; + fd->f_blob->size = size; return 0; } @@ -1302,14 +1290,16 @@ wimfs_getattr(const char *path, struct stat *stbuf) { const struct wimfs_context *ctx = wimfs_get_context(); struct wim_dentry *dentry; - struct wim_lookup_table_entry *lte; + struct wim_inode_stream *strm; int ret; ret = wim_pathname_to_stream(ctx, path, LOOKUP_FLAG_DIRECTORY_OK, - &dentry, <e, NULL); + &dentry, &strm); if (ret) return ret; - return inode_to_stbuf(dentry->d_inode, lte, stbuf); + + return inode_to_stbuf(dentry->d_inode, + stream_blob_resolved(strm), stbuf); } static int @@ -1328,9 +1318,9 @@ wimfs_getxattr(const char *path, const char *name, char *value, size_t size) { const struct wimfs_context *ctx = wimfs_get_context(); - struct wim_inode *inode; - struct wim_ads_entry *ads_entry; - struct wim_lookup_table_entry *lte; + const struct wim_inode *inode; + const struct wim_inode_stream *strm; + const struct blob_descriptor *blob; if (!strncmp(name, "wimfs.", 6)) { /* Handle some magical extended attributes. These really should @@ -1379,31 +1369,34 @@ wimfs_getxattr(const char *path, const char *name, char *value, return -ENOATTR; name += 5; + if (!*name) + return -ENOATTR; + /* Querying a named data stream */ inode = wim_pathname_to_inode(ctx->wim, path); if (!inode) return -errno; - ads_entry = inode_get_ads_entry(inode, name); - if (!ads_entry) + strm = inode_get_data_stream_tstr(inode, name); + if (!strm) return (errno == ENOENT) ? -ENOATTR : -errno; - lte = ads_entry->lte; - if (!lte) + blob = stream_blob_resolved(strm); + if (!blob) return 0; - if (unlikely(lte->size > INT_MAX)) + if (unlikely(blob->size > INT_MAX)) return -EFBIG; if (size) { - if (size < lte->size) + if (size < blob->size) return -ERANGE; - if (read_full_stream_into_buf(lte, value)) + if (read_blob_into_buf(blob, value)) return errno ? -errno : -EIO; } - return lte->size; + return blob->size; } static int @@ -1435,15 +1428,11 @@ wimfs_link(const char *existing_path, const char *new_path) if (get_dentry_child_with_name(dir, new_name, WIMLIB_CASE_SENSITIVE)) return -EEXIST; - if (new_dentry(new_name, &new_alias)) + if (new_dentry_with_existing_inode(new_name, inode, &new_alias)) return -ENOMEM; - new_alias->d_inode = inode; - inode_add_dentry(new_alias, inode); dentry_add_child(dir, new_alias); touch_inode(dir->d_inode); - inode->i_nlink++; - inode_ref_streams(inode); return 0; } @@ -1466,18 +1455,18 @@ wimfs_listxattr(const char *path, char *list, size_t size) if (!inode) return -errno; - for (u16 i = 0; i < inode->i_num_ads; i++) { - const struct wim_ads_entry *entry; + for (unsigned i = 0; i < inode->i_num_streams; i++) { + const struct wim_inode_stream *strm; char *stream_name_mbs; size_t stream_name_mbs_nbytes; - entry = &inode->i_ads_entries[i]; + strm = &inode->i_streams[i]; - if (!entry->stream_name_nbytes) + if (!stream_is_named_data_stream(strm)) continue; - if (utf16le_to_tstr(entry->stream_name, - entry->stream_name_nbytes, + if (utf16le_to_tstr(strm->stream_name, + utf16le_len_bytes(strm->stream_name), &stream_name_mbs, &stream_name_mbs_nbytes)) return -errno; @@ -1509,8 +1498,7 @@ wimfs_mkdir(const char *path, mode_t mode) int ret; /* Note: according to fuse.h, mode may not include S_IFDIR */ - ret = create_dentry(fuse_get_context(), path, mode | S_IFDIR, 0, - FILE_ATTRIBUTE_DIRECTORY, &dentry); + ret = create_file(fuse_get_context(), path, mode | S_IFDIR, 0, &dentry); if (ret) return ret; touch_parent(dentry); @@ -1527,10 +1515,11 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) if ((wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS) && (stream_name = path_stream_name(path))) { - struct wim_ads_entry *old_entry; - struct wim_ads_entry *new_entry; struct wim_inode *inode; + struct wim_inode_stream *existing_strm; + struct wim_inode_stream *new_strm; char *p; + const utf16lechar *uname; /* Create a named data stream. */ @@ -1545,14 +1534,20 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) if (!inode) return -errno; - old_entry = inode_get_ads_entry(inode, stream_name); - if (old_entry) - return -EEXIST; - if (errno != ENOENT) + if (tstr_get_utf16le(stream_name, &uname)) return -errno; - new_entry = inode_add_ads(inode, stream_name); - if (!new_entry) + existing_strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname); + if (existing_strm) { + tstr_put_utf16le(uname); + return -EEXIST; + } + + new_strm = inode_add_stream(inode, STREAM_TYPE_DATA, uname, NULL); + + tstr_put_utf16le(uname); + + if (!new_strm) return -errno; return 0; } else { @@ -1565,11 +1560,7 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev) !(wimfs_ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA)) return -EPERM; - /* Note: we still use FILE_ATTRIBUTE_NORMAL for device nodes, - * named pipes, and sockets. The real mode is in the UNIX - * metadata. */ - ret = create_dentry(fuse_ctx, path, mode, rdev, - FILE_ATTRIBUTE_NORMAL, &dentry); + ret = create_file(fuse_ctx, path, mode, rdev, &dentry); if (ret) return ret; touch_parent(dentry); @@ -1583,44 +1574,45 @@ wimfs_open(const char *path, struct fuse_file_info *fi) struct wimfs_context *ctx = wimfs_get_context(); struct wim_dentry *dentry; struct wim_inode *inode; - struct wim_lookup_table_entry *lte; - u16 stream_idx; + struct wim_inode_stream *strm; + struct blob_descriptor *blob; struct wimfs_fd *fd; int ret; - ret = wim_pathname_to_stream(ctx, path, 0, &dentry, <e, &stream_idx); + ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm); if (ret) return ret; inode = dentry->d_inode; + blob = stream_blob_resolved(strm); - /* The file resource may be in the staging directory (read-write mounts - * only) or in the WIM. If it's in the staging directory, we need to - * open a native file descriptor for the corresponding file. Otherwise, - * we can read the file resource directly from the WIM file if we are - * opening it read-only, but we need to extract the resource to the - * staging directory if we are opening it writable. */ + /* The data of the file being opened may be in the staging directory + * (read-write mounts only) or in the WIM. If it's in the staging + * directory, we need to open a native file descriptor for the + * corresponding file. Otherwise, we can read the file data directly + * from the WIM file if we are opening it read-only, but we need to + * extract the data to the staging directory if we are opening it + * writable. */ if (flags_writable(fi->flags) && - (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE)) { - ret = extract_resource_to_staging_dir(inode, - stream_idx, - <e, - lte ? lte->size : 0, - ctx); + (!blob || blob->blob_location != BLOB_IN_STAGING_FILE)) { + ret = extract_blob_to_staging_dir(inode, + strm, + blob_size(blob), + ctx); if (ret) return ret; + blob = stream_blob_resolved(strm); } - ret = alloc_wimfs_fd(inode, inode_stream_idx_to_id(inode, stream_idx), - lte, &fd); + ret = alloc_wimfs_fd(inode, strm, &fd); if (ret) return ret; - if (lte && lte->resource_location == RESOURCE_IN_STAGING_FILE) { + if (blob && blob->blob_location == BLOB_IN_STAGING_FILE) { int raw_fd; - raw_fd = openat(lte->staging_dir_fd, lte->staging_file_name, + raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name, (fi->flags & O_ACCMODE) | O_NOFOLLOW); if (raw_fd < 0) { close_wimfs_fd(fd); @@ -1637,6 +1629,7 @@ wimfs_opendir(const char *path, struct fuse_file_info *fi) { WIMStruct *wim = wimfs_get_WIMStruct(); struct wim_inode *inode; + struct wim_inode_stream *strm; struct wimfs_fd *fd; int ret; @@ -1645,7 +1638,10 @@ wimfs_opendir(const char *path, struct fuse_file_info *fi) return -errno; if (!inode_is_directory(inode)) return -ENOTDIR; - ret = alloc_wimfs_fd(inode, 0, NULL, &fd); + strm = inode_get_unnamed_data_stream(inode); + if (!strm) + return -ENOTDIR; + ret = alloc_wimfs_fd(inode, strm, &fd); if (ret) return ret; fi->fh = (uintptr_t)fd; @@ -1657,36 +1653,36 @@ wimfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { struct wimfs_fd *fd = WIMFS_FD(fi); - const struct wim_lookup_table_entry *lte; + const struct blob_descriptor *blob; ssize_t ret; - lte = fd->f_lte; - if (!lte) + blob = fd->f_blob; + if (!blob) return 0; - if (offset >= lte->size) + if (offset >= blob->size) return 0; - if (size > lte->size - offset) - size = lte->size - offset; + if (size > blob->size - offset) + size = blob->size - offset; if (!size) return 0; - switch (lte->resource_location) { - case RESOURCE_IN_WIM: - if (read_partial_wim_stream_into_buf(lte, size, offset, buf)) + switch (blob->blob_location) { + case BLOB_IN_WIM: + if (read_partial_wim_blob_into_buf(blob, offset, size, buf)) ret = errno ? -errno : -EIO; else ret = size; break; - case RESOURCE_IN_STAGING_FILE: - ret = raw_pread(&fd->f_staging_fd, buf, size, offset); + case BLOB_IN_STAGING_FILE: + ret = pread(fd->f_staging_fd.fd, buf, size, offset); if (ret < 0) ret = -errno; break; - case RESOURCE_IN_ATTACHED_BUFFER: - memcpy(buf, lte->attached_buffer + offset, size); + case BLOB_IN_ATTACHED_BUFFER: + memcpy(buf, blob->attached_buffer + offset, size); ret = size; break; default: @@ -1715,18 +1711,15 @@ wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, return ret; for_inode_child(child, inode) { - char *file_name_mbs; - size_t file_name_mbs_nbytes; + char *name; + size_t name_nbytes; - ret = utf16le_to_tstr(child->file_name, - child->file_name_nbytes, - &file_name_mbs, - &file_name_mbs_nbytes); - if (ret) + if (utf16le_to_tstr(child->d_name, child->d_name_nbytes, + &name, &name_nbytes)) return -errno; - ret = filler(buf, file_name_mbs, NULL, 0); - FREE(file_name_mbs); + ret = filler(buf, name, NULL, 0); + FREE(name); if (ret) return ret; } @@ -1734,27 +1727,24 @@ wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, } static int -wimfs_readlink(const char *path, char *buf, size_t buf_len) +wimfs_readlink(const char *path, char *buf, size_t bufsize) { - WIMStruct *wim = wimfs_get_WIMStruct(); + struct wimfs_context *ctx = wimfs_get_context(); const struct wim_inode *inode; - ssize_t ret; + int ret; - inode = wim_pathname_to_inode(wim, path); + inode = wim_pathname_to_inode(ctx->wim, path); if (!inode) return -errno; - if (!inode_is_symlink(inode)) + if (bufsize <= 0) return -EINVAL; - if (buf_len == 0) - return -EINVAL; - ret = wim_inode_readlink(inode, buf, buf_len - 1, NULL); - if (ret >= 0) { - buf[ret] = '\0'; - ret = 0; - } else if (ret == -ENAMETOOLONG) { - buf[buf_len - 1] = '\0'; - } - return ret; + ret = wim_inode_readlink(inode, buf, bufsize - 1, NULL, + ctx->mountpoint_abspath, + ctx->mountpoint_abspath_nchars); + if (ret < 0) + return ret; + buf[ret] = '\0'; + return 0; } /* We use this for both release() and releasedir(), since in both cases we @@ -1770,7 +1760,7 @@ wimfs_removexattr(const char *path, const char *name) { struct wimfs_context *ctx = wimfs_get_context(); struct wim_inode *inode; - struct wim_ads_entry *ads_entry; + struct wim_inode_stream *strm; if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR)) return -ENOTSUP; @@ -1779,17 +1769,20 @@ wimfs_removexattr(const char *path, const char *name) return -ENOATTR; name += 5; + if (!*name) + return -ENOATTR; + /* Removing a named data stream. */ inode = wim_pathname_to_inode(ctx->wim, path); if (!inode) return -errno; - ads_entry = inode_get_ads_entry(inode, name); - if (!ads_entry) + strm = inode_get_data_stream_tstr(inode, name); + if (!strm) return (errno == ENOENT) ? -ENOATTR : -errno; - inode_remove_ads(inode, ads_entry, ctx->wim->lookup_table); + inode_remove_stream(inode, strm, ctx->wim->blob_table); return 0; } @@ -1817,7 +1810,7 @@ wimfs_rmdir(const char *path) return -ENOTEMPTY; touch_parent(dentry); - remove_dentry(dentry, wim->lookup_table); + remove_dentry(dentry, wim->blob_table); return 0; } @@ -1827,7 +1820,9 @@ wimfs_setxattr(const char *path, const char *name, { struct wimfs_context *ctx = wimfs_get_context(); struct wim_inode *inode; - struct wim_ads_entry *existing_entry; + struct wim_inode_stream *strm; + const utf16lechar *uname; + int ret; if (!strncmp(name, "wimfs.", 6)) { /* Handle some magical extended attributes. These really should @@ -1854,29 +1849,50 @@ wimfs_setxattr(const char *path, const char *name, return -ENOATTR; name += 5; + if (!*name) + return -ENOATTR; + /* Setting the contents of a named data stream. */ inode = wim_pathname_to_inode(ctx->wim, path); if (!inode) return -errno; - existing_entry = inode_get_ads_entry(inode, name); - if (existing_entry) { + ret = tstr_get_utf16le(name, &uname); + if (ret) + return -errno; + + strm = inode_get_stream(inode, STREAM_TYPE_DATA, uname); + if (strm) { + ret = -EEXIST; if (flags & XATTR_CREATE) - return -EEXIST; + goto out_put_uname; } else { - if (errno != ENOENT) - return -errno; + ret = -ENOATTR; if (flags & XATTR_REPLACE) - return -ENOATTR; + goto out_put_uname; } - if (!inode_add_ads_with_data(inode, name, value, - size, ctx->wim->lookup_table)) - return -errno; - if (existing_entry) - inode_remove_ads(inode, existing_entry, ctx->wim->lookup_table); - return 0; + if (strm) { + if (!inode_replace_stream_data(inode, strm, value, size, + ctx->wim->blob_table)) + { + ret = -errno; + goto out_put_uname; + } + } else { + if (!inode_add_stream_with_data(inode, STREAM_TYPE_DATA, uname, + value, size, ctx->wim->blob_table)) + { + ret = -errno; + goto out_put_uname; + } + } + + ret = 0; +out_put_uname: + tstr_put_utf16le(uname); + return ret; } static int @@ -1887,15 +1903,13 @@ wimfs_symlink(const char *to, const char *from) struct wim_dentry *dentry; int ret; - ret = create_dentry(fuse_ctx, from, S_IFLNK | 0777, 0, - FILE_ATTRIBUTE_REPARSE_POINT, &dentry); + ret = create_file(fuse_ctx, from, S_IFLNK | 0777, 0, &dentry); if (ret) return ret; - dentry->d_inode->i_reparse_tag = WIM_IO_REPARSE_TAG_SYMLINK; ret = wim_inode_set_symlink(dentry->d_inode, to, - wimfs_ctx->wim->lookup_table); + wimfs_ctx->wim->blob_table); if (ret) { - remove_dentry(dentry, wimfs_ctx->wim->lookup_table); + remove_dentry(dentry, wimfs_ctx->wim->blob_table); if (ret == WIMLIB_ERR_NOMEM) ret = -ENOMEM; else @@ -1911,33 +1925,35 @@ wimfs_truncate(const char *path, off_t size) { const struct wimfs_context *ctx = wimfs_get_context(); struct wim_dentry *dentry; - struct wim_lookup_table_entry *lte; - u16 stream_idx; + struct wim_inode_stream *strm; + struct blob_descriptor *blob; int ret; int fd; - ret = wim_pathname_to_stream(ctx, path, 0, &dentry, <e, &stream_idx); + ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm); if (ret) return ret; - if (!lte && !size) + blob = stream_blob_resolved(strm); + + if (!blob && !size) return 0; - if (!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE) { - return extract_resource_to_staging_dir(dentry->d_inode, - stream_idx, <e, - size, ctx); + if (!blob || blob->blob_location != BLOB_IN_STAGING_FILE) { + return extract_blob_to_staging_dir(dentry->d_inode, + strm, size, ctx); } /* Truncate the staging file. */ - fd = openat(lte->staging_dir_fd, lte->staging_file_name, + fd = openat(blob->staging_dir_fd, blob->staging_file_name, O_WRONLY | O_NOFOLLOW); if (fd < 0) return -errno; ret = ftruncate(fd, size); if (close(fd) || ret) return -errno; - lte->size = size; + blob->size = size; + touch_inode(dentry->d_inode); return 0; } @@ -1946,20 +1962,19 @@ wimfs_unlink(const char *path) { const struct wimfs_context *ctx = wimfs_get_context(); struct wim_dentry *dentry; - u16 stream_idx; + struct wim_inode_stream *strm; int ret; - ret = wim_pathname_to_stream(ctx, path, 0, &dentry, NULL, &stream_idx); + ret = wim_pathname_to_stream(ctx, path, 0, &dentry, &strm); if (ret) return ret; - if (inode_stream_name_nbytes(dentry->d_inode, stream_idx) == 0) { - touch_parent(dentry); - remove_dentry(dentry, ctx->wim->lookup_table); + if (stream_is_named(strm)) { + inode_remove_stream(dentry->d_inode, strm, + ctx->wim->blob_table); } else { - inode_remove_ads(dentry->d_inode, - &dentry->d_inode->i_ads_entries[stream_idx - 1], - ctx->wim->lookup_table); + touch_parent(dentry); + remove_dentry(dentry, ctx->wim->blob_table); } return 0; } @@ -1982,15 +1997,15 @@ wimfs_utimens(const char *path, const struct timespec tv[2]) if (tv[0].tv_nsec != UTIME_OMIT) { if (tv[0].tv_nsec == UTIME_NOW) - inode->i_last_access_time = get_wim_timestamp(); + inode->i_last_access_time = now_as_wim_timestamp(); else - inode->i_last_access_time = timespec_to_wim_timestamp(tv[0]); + inode->i_last_access_time = timespec_to_wim_timestamp(&tv[0]); } if (tv[1].tv_nsec != UTIME_OMIT) { if (tv[1].tv_nsec == UTIME_NOW) - inode->i_last_write_time = get_wim_timestamp(); + inode->i_last_write_time = now_as_wim_timestamp(); else - inode->i_last_write_time = timespec_to_wim_timestamp(tv[1]); + inode->i_last_write_time = timespec_to_wim_timestamp(&tv[1]); } return 0; } @@ -2005,8 +2020,8 @@ wimfs_utime(const char *path, struct utimbuf *times) if (!inode) return -errno; - inode->i_last_access_time = unix_timestamp_to_wim(times->actime); - inode->i_last_write_time = unix_timestamp_to_wim(times->modtime); + inode->i_last_access_time = time_t_to_wim_timestamp(times->actime); + inode->i_last_write_time = time_t_to_wim_timestamp(times->modtime); return 0; } #endif /* !HAVE_UTIMENSAT */ @@ -2018,12 +2033,12 @@ wimfs_write(const char *path, const char *buf, size_t size, struct wimfs_fd *fd = WIMFS_FD(fi); ssize_t ret; - ret = raw_pwrite(&fd->f_staging_fd, buf, size, offset); + ret = pwrite(fd->f_staging_fd.fd, buf, size, offset); if (ret < 0) return -errno; - if (offset + size > fd->f_lte->size) - fd->f_lte->size = offset + size; + if (offset + size > fd->f_blob->size) + fd->f_blob->size = offset + size; touch_inode(fd->f_inode); return ret; @@ -2100,7 +2115,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { if (!wim->filename) return WIMLIB_ERR_NO_FILENAME; - ret = can_delete_from_wim(wim); + ret = can_modify_wim(wim); if (ret) return ret; } @@ -2113,20 +2128,26 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, /* Get the metadata for the image to mount. */ imd = wim_get_current_image_metadata(wim); - if (imd->modified) { - /* To avoid complicating things, we don't support mounting - * images to which in-memory modifications have already been - * made. */ + /* To avoid complicating things, we don't support mounting images to + * which in-memory modifications have already been made. */ + if (is_image_dirty(imd)) { ERROR("Cannot mount a modified WIM image!"); return WIMLIB_ERR_INVALID_PARAM; } if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { + if (imd->refcnt > 1) + return WIMLIB_ERR_IMAGE_HAS_MULTIPLE_REFERENCES; ret = lock_wim_for_append(wim); if (ret) return ret; } + if (wim_has_solid_resources(wim)) { + WARNING("Mounting a WIM file containing solid-compressed data; " + "file access may be slow."); + } + /* If the user did not specify an interface for accessing named * data streams, use the default (extended attributes). */ if (!(mount_flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE | @@ -2149,46 +2170,48 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, ctx.owner_uid = getuid(); ctx.owner_gid = getgid(); - /* Add each stream referenced by files in the image to a list and + /* Add each blob referenced by files in the image to a list and * preemptively double the number of references to each. This is done * to allow implementing the WIMLIB_UNMOUNT_FLAG_NEW_IMAGE semantics. */ - INIT_LIST_HEAD(&ctx.orig_stream_list); + INIT_LIST_HEAD(&ctx.orig_blob_list); if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { unsigned i; struct wim_inode *inode; - struct wim_lookup_table_entry *lte; + struct blob_descriptor *blob; image_for_each_inode(inode, imd) { - for (i = 0; i <= inode->i_num_ads; i++) { - lte = inode_stream_lte(inode, i, - wim->lookup_table); - if (lte) - lte->out_refcnt = 0; + for (i = 0; i < inode->i_num_streams; i++) { + blob = stream_blob(&inode->i_streams[i], + wim->blob_table); + if (blob) + blob->out_refcnt = 0; } } image_for_each_inode(inode, imd) { - for (i = 0; i <= inode->i_num_ads; i++) { - lte = inode_stream_lte(inode, i, - wim->lookup_table); - if (lte) { - if (lte->out_refcnt == 0) - list_add(<e->orig_stream_list, - &ctx.orig_stream_list); - lte->out_refcnt += inode->i_nlink; - lte->refcnt += inode->i_nlink; + for (i = 0; i < inode->i_num_streams; i++) { + blob = stream_blob(&inode->i_streams[i], + wim->blob_table); + if (blob) { + if (blob->out_refcnt == 0) + list_add(&blob->orig_blob_list, + &ctx.orig_blob_list); + blob->out_refcnt += inode->i_nlink; + blob->refcnt += inode->i_nlink; } } } } - /* Assign new inode numbers. */ - reassign_inode_numbers(&ctx); + /* Number the inodes in the mounted image sequentially and initialize + * the file descriptor arrays */ + prepare_inodes(&ctx); - /* If a read-write mount, mark the image as modified. */ - if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) - imd->modified = 1; + /* Save the absolute path to the mountpoint directory. */ + ctx.mountpoint_abspath = realpath(dir, NULL); + if (ctx.mountpoint_abspath) + ctx.mountpoint_abspath_nchars = strlen(ctx.mountpoint_abspath); /* Build the FUSE command line. */ @@ -2275,6 +2298,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir, /* Cleanup and return. */ if (ret) ret = WIMLIB_ERR_FUSE; + FREE(ctx.mountpoint_abspath); release_extra_refcnts(&ctx); if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) delete_staging_dir(&ctx); @@ -2435,7 +2459,7 @@ do_unmount_commit(const char *dir, int unmount_flags, ret = do_unmount(dir); if (progfunc) { /* Terminate the progress thread. */ - char empty[0]; + char empty[1]; mq_send(mq, empty, 0, 1); pthread_join(commit_progress_tid, NULL); }