#include "wimlib/encoding.h"
#include "wimlib/file_io.h"
+#include "wimlib/dentry.h"
+#include "wimlib/inode.h"
#include "wimlib/lookup_table.h"
#include "wimlib/metadata.h"
#include "wimlib/paths.h"
#include "wimlib/reparse.h"
#include "wimlib/resource.h"
-#include "wimlib/swm.h"
#include "wimlib/timestamp.h"
#include "wimlib/version.h"
#include "wimlib/write.h"
return wimfs_get_context()->wim;
}
-static inline bool
-wimfs_ctx_readonly(const struct wimfs_context *ctx)
-{
- return (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) == 0;
-}
-
static inline int
get_lookup_flags(const struct wimfs_context *ctx)
{
* @stream_id: ID of the stream we're opening
* @lte: Lookup table entry for the stream (may be NULL)
* @fd_ret: Return the allocated file descriptor if successful.
- * @readonly: True if this is a read-only mount.
*
* Return 0 iff successful or error code if unsuccessful.
*/
alloc_wimfs_fd(struct wim_inode *inode,
u32 stream_id,
struct wim_lookup_table_entry *lte,
- struct wimfs_fd **fd_ret,
- bool readonly)
+ struct wimfs_fd **fd_ret)
{
static const u16 fds_per_alloc = 8;
static const u16 max_fds = 0xffff;
*fd_ret = fd;
inode->i_fds[i] = fd;
inode->i_num_opened_fds++;
- if (lte && !readonly)
+ if (lte)
lte->num_opened_fds++;
DEBUG("Allocated fd (idx = %u)", fd->idx);
ret = 0;
struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
int ret;
- parent = get_parent_dentry(wimfs_ctx->wim, path);
+ parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
if (!parent)
return -errno;
return -ENOTDIR;
basename = path_basename(path);
- if (get_dentry_child_with_name(parent, basename))
+ if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
return -EEXIST;
ret = new_dentry_with_inode(basename, &new);
return 0;
}
+static struct wim_inode *
+wim_pathname_to_inode(WIMStruct *wim, const tchar *path)
+{
+ struct wim_dentry *dentry;
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
+ if (dentry)
+ return dentry->d_inode;
+ else
+ return NULL;
+}
+
/* Remove a dentry from a mounted WIM image; i.e. remove an alias for the
* corresponding inode.
*
stbuf->st_ino = (ino_t)inode->i_ino;
stbuf->st_nlink = inode->i_nlink;
if (lte)
- stbuf->st_size = wim_resource_size(lte);
+ stbuf->st_size = lte->size;
else
stbuf->st_size = 0;
#ifdef HAVE_STAT_NANOSECOND_PRECISION
static const size_t STAGING_FILE_NAME_LEN = 20;
name_len = ctx->staging_dir_name_len + 1 + STAGING_FILE_NAME_LEN;
- name = MALLOC(name_len + 1);
+ name = MALLOC(name_len + 1);
if (!name) {
errno = ENOMEM;
return -1;
/* Extract the stream to the staging file (possibly truncated) */
if (old_lte) {
- struct filedes wimlib_fd = {.fd = fd};
- extract_size = min(wim_resource_size(old_lte), size);
- ret = extract_wim_resource_to_fd(old_lte, &wimlib_fd,
- extract_size);
+ struct filedes wimlib_fd;
+ filedes_init(&wimlib_fd, fd);
+ extract_size = min(old_lte->size, size);
+ ret = extract_stream_to_fd(old_lte, &wimlib_fd, extract_size);
} else {
ret = 0;
extract_size = 0;
}
}
- new_lte->refcnt = inode->i_nlink;
- new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
- new_lte->staging_file_name = staging_file_name;
- new_lte->resource_entry.original_size = size;
+ new_lte->refcnt = inode->i_nlink;
+ new_lte->resource_location = RESOURCE_IN_STAGING_FILE;
+ new_lte->staging_file_name = staging_file_name;
+ new_lte->size = size;
- lookup_table_insert_unhashed(ctx->wim->lookup_table, new_lte,
- inode, stream_id);
+ add_unhashed_stream(new_lte, inode, stream_id,
+ &wim_get_current_image_metadata(ctx->wim)->unhashed_streams);
*retrieve_lte_pointer(new_lte) = new_lte;
*lte = new_lte;
return 0;
DEBUG("Freeing entries for zero-length streams");
image_for_each_unhashed_stream_safe(lte, tmp, imd) {
wimlib_assert(lte->unhashed);
- if (wim_resource_size(lte) == 0) {
+ if (lte->size == 0) {
struct wim_lookup_table_entry **back_ptr;
back_ptr = retrieve_lte_pointer(lte);
*back_ptr = NULL;
char *p;
int ret;
- dir_path = realpath(mount_dir, NULL);
+ dir_path = realpath(mount_dir, NULL);
if (!dir_path) {
ERROR_WITH_ERRNO("Failed to resolve path \"%s\"", mount_dir);
if (errno == ENOMEM)
static int
unmount_timed_out_cb(void *_handler_ctx)
{
- struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
+ const struct unmount_msg_handler_context *handler_ctx = _handler_ctx;
- if (handler_ctx->daemon_pid == 0) {
- goto out_crashed;
- } else {
- kill(handler_ctx->daemon_pid, 0);
- if (errno == ESRCH) {
- goto out_crashed;
- } else {
- DEBUG("Filesystem daemon is still alive... "
- "Waiting another %d seconds\n",
- handler_ctx->hdr.timeout_seconds);
- return 0;
- }
+ if (handler_ctx->daemon_pid == 0 ||
+ (kill(handler_ctx->daemon_pid, 0) != 0 && errno == ESRCH))
+ {
+ ERROR("The filesystem daemon has crashed! Changes to the "
+ "WIM may not have been commited.");
+ return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED;
}
-out_crashed:
- ERROR("The filesystem daemon has crashed! Changes to the "
- "WIM may not have been commited.");
- return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED;
+
+ DEBUG("Filesystem daemon is still alive... "
+ "Waiting another %d seconds", handler_ctx->hdr.timeout_seconds);
+ return 0;
}
static int
"terminate");
return WIMLIB_ERR_FUSERMOUNT;
}
- if (status != 0) {
+
+ if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
ERROR("`umount' did not successfully complete");
return WIMLIB_ERR_FUSERMOUNT;
}
+
return 0;
}
if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
return -EPERM;
- ret = lookup_resource(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
- &dentry, NULL, NULL);
+ ret = wim_pathname_to_stream(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
+ &dentry, NULL, NULL);
if (ret)
return ret;
if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_UNIX_DATA))
return -EPERM;
- ret = lookup_resource(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
- &dentry, NULL, NULL);
+ ret = wim_pathname_to_stream(ctx->wim, path, LOOKUP_FLAG_DIRECTORY_OK,
+ &dentry, NULL, NULL);
if (ret)
return ret;
if (ret)
return -errno;
touch_inode(fd->f_inode);
- fd->f_lte->resource_entry.original_size = size;
+ fd->f_lte->size = size;
return 0;
}
int ret;
struct wimfs_context *ctx = wimfs_get_context();
- ret = lookup_resource(ctx->wim, path,
- get_lookup_flags(ctx) | LOOKUP_FLAG_DIRECTORY_OK,
- &dentry, <e, NULL);
+ ret = wim_pathname_to_stream(ctx->wim, path,
+ get_lookup_flags(ctx) |
+ LOOKUP_FLAG_DIRECTORY_OK,
+ &dentry, <e, NULL);
if (ret != 0)
return ret;
return inode_to_stbuf(dentry->d_inode, lte, stbuf);
int ret;
struct wim_inode *inode;
struct wim_ads_entry *ads_entry;
- size_t res_size;
+ u64 stream_size;
struct wim_lookup_table_entry *lte;
struct wimfs_context *ctx = wimfs_get_context();
if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
return -ENOTSUP;
- if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
+ if (strlen(name) <= 5 || memcmp(name, "user.", 5) != 0)
return -ENOATTR;
name += 5;
return -ENOATTR;
lte = ads_entry->lte;
- res_size = wim_resource_size(lte);
+ stream_size = lte->size;
if (size == 0)
- return res_size;
+ return stream_size;
- if (res_size > size)
+ if (stream_size > size)
return -ERANGE;
- ret = read_full_resource_into_buf(lte, value);
- if (ret)
- return -errno;
-
- return res_size;
+ ret = read_full_stream_into_buf(lte, value);
+ if (ret) {
+ if (errno)
+ return -errno;
+ else
+ return -EIO;
+ }
+ return stream_size;
}
#endif
FILE_ATTRIBUTE_REPARSE_POINT))
return -EPERM;
- from_dentry_parent = get_parent_dentry(wim, from);
+ from_dentry_parent = get_parent_dentry(wim, from, WIMLIB_CASE_SENSITIVE);
if (!from_dentry_parent)
return -errno;
if (!dentry_is_directory(from_dentry_parent))
return -ENOTDIR;
link_name = path_basename(from);
- if (get_dentry_child_with_name(from_dentry_parent, link_name))
+ if (get_dentry_child_with_name(from_dentry_parent, link_name,
+ WIMLIB_CASE_SENSITIVE))
return -EEXIST;
ret = new_dentry(link_name, &from_dentry);
p = list;
for (i = 0; i < inode->i_num_ads; i++) {
+
+ if (!ads_entry_is_named_stream(&inode->i_ads_entries[i]))
+ continue;
+
char *stream_name_mbs;
size_t stream_name_mbs_nbytes;
int ret;
struct wimfs_context *ctx = wimfs_get_context();
struct wim_lookup_table_entry **back_ptr;
- ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
- &dentry, <e, &stream_idx);
+ ret = wim_pathname_to_stream(ctx->wim, path, get_lookup_flags(ctx),
+ &dentry, <e, &stream_idx);
if (ret)
return ret;
if (flags_writable(fi->flags) &&
(!lte || lte->resource_location != RESOURCE_IN_STAGING_FILE)) {
- u64 size = (lte) ? wim_resource_size(lte) : 0;
+ u64 size = (lte) ? lte->size : 0;
ret = extract_resource_to_staging_dir(inode, stream_id,
<e, size, ctx);
if (ret)
*back_ptr = lte;
}
- ret = alloc_wimfs_fd(inode, stream_id, lte, &fd,
- wimfs_ctx_readonly(ctx));
+ ret = alloc_wimfs_fd(inode, stream_id, lte, &fd);
if (ret)
return ret;
return -errno;
if (!inode_is_directory(inode))
return -ENOTDIR;
- ret = alloc_wimfs_fd(inode, 0, NULL, &fd, wimfs_ctx_readonly(ctx));
+ ret = alloc_wimfs_fd(inode, 0, NULL, &fd);
fi->fh = (uintptr_t)fd;
return ret;
}
{
struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
ssize_t ret;
- u64 res_size;
+ u64 stream_size;
if (!fd)
return -EBADF;
return 0;
if (fd->f_lte)
- res_size = wim_resource_size(fd->f_lte);
+ stream_size = fd->f_lte->size;
else
- res_size = 0;
+ stream_size = 0;
- if (offset > res_size)
+ if (offset > stream_size)
return -EOVERFLOW;
- size = min(size, res_size - offset);
+ size = min(size, stream_size - offset);
if (size == 0)
return 0;
ret = -errno;
break;
case RESOURCE_IN_WIM:
- if (read_partial_wim_resource_into_buf(fd->f_lte, size,
- offset, buf))
- ret = -errno;
+ if (read_partial_wim_stream_into_buf(fd->f_lte, size,
+ offset, buf))
+ ret = errno ? -errno : -EIO;
else
ret = size;
break;
if (!inode_is_symlink(inode))
return -EINVAL;
if (buf_len == 0)
- return -ENAMETOOLONG;
+ return -EINVAL;
ret = wim_inode_readlink(inode, buf, buf_len - 1, NULL);
if (ret >= 0) {
wimlib_assert(ret <= buf_len - 1);
static int
wimfs_rename(const char *from, const char *to)
{
- return rename_wim_path(wimfs_get_WIMStruct(), from, to);
+ return rename_wim_path(wimfs_get_WIMStruct(), from, to,
+ WIMLIB_CASE_SENSITIVE);
}
/* Remove a directory */
struct wim_dentry *dentry;
WIMStruct *wim = wimfs_get_WIMStruct();
- dentry = get_dentry(wim, path);
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
if (!dentry)
return -errno;
if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR))
return -ENOTSUP;
- if (strlen(name) < 5 || memcmp(name, "user.", 5) != 0)
+ if (strlen(name) <= 5 || memcmp(name, "user.", 5) != 0)
return -ENOATTR;
name += 5;
struct wim_inode *inode;
struct wimfs_context *ctx = wimfs_get_context();
- ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
- &dentry, <e, &stream_idx);
+ ret = wim_pathname_to_stream(ctx->wim, path, get_lookup_flags(ctx),
+ &dentry, <e, &stream_idx);
if (ret != 0)
return ret;
if (lte == NULL && size == 0)
return 0;
- if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
+ if (lte != NULL && lte->resource_location == RESOURCE_IN_STAGING_FILE) {
ret = truncate(lte->staging_file_name, size);
if (ret)
ret = -errno;
else
- lte->resource_entry.original_size = size;
+ lte->size = size;
} else {
/* File in WIM. Extract it to the staging directory, but only
* the first @size bytes of it. */
u16 stream_idx;
struct wimfs_context *ctx = wimfs_get_context();
- ret = lookup_resource(ctx->wim, path, get_lookup_flags(ctx),
- &dentry, <e, &stream_idx);
+ ret = wim_pathname_to_stream(ctx->wim, path, get_lookup_flags(ctx),
+ &dentry, <e, &stream_idx);
if (ret != 0)
return ret;
- if (stream_idx == 0)
+ if (inode_stream_name_nbytes(dentry->d_inode, stream_idx) == 0)
remove_dentry(dentry, ctx->wim->lookup_table);
else
inode_remove_ads(dentry->d_inode, stream_idx - 1,
struct wim_inode *inode;
WIMStruct *wim = wimfs_get_WIMStruct();
- dentry = get_dentry(wim, path);
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
if (!dentry)
return -errno;
inode = dentry->d_inode;
struct wim_inode *inode;
WIMStruct *wim = wimfs_get_WIMStruct();
- dentry = get_dentry(wim, path);
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
if (!dentry)
return -errno;
inode = dentry->d_inode;
return -errno;
/* Update file size */
- if (offset + size > fd->f_lte->resource_entry.original_size) {
+ if (offset + size > fd->f_lte->size) {
DEBUG("Update file size %"PRIu64 " => %"PRIu64"",
- fd->f_lte->resource_entry.original_size,
- offset + size);
- fd->f_lte->resource_entry.original_size = offset + size;
+ fd->f_lte->size, offset + size);
+ fd->f_lte->size = offset + size;
}
/* Update timestamps */
/* API function documented in wimlib.h */
WIMLIBAPI int
wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
- int mount_flags, WIMStruct **additional_swms,
- unsigned num_additional_swms,
- const char *staging_dir)
+ int mount_flags, const char *staging_dir)
{
int argc;
char *argv[16];
DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
wim, image, dir, mount_flags);
- if (!wim || !dir) {
- ret = WIMLIB_ERR_INVALID_PARAM;
- goto out;
- }
+ if (!wim || !dir)
+ return WIMLIB_ERR_INVALID_PARAM;
- ret = verify_swm_set(wim, additional_swms, num_additional_swms);
- if (ret)
- goto out;
+ if (mount_flags & ~(WIMLIB_MOUNT_FLAG_READWRITE |
+ WIMLIB_MOUNT_FLAG_DEBUG |
+ WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
+ WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
+ WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS |
+ WIMLIB_MOUNT_FLAG_UNIX_DATA |
+ WIMLIB_MOUNT_FLAG_ALLOW_OTHER))
+ return WIMLIB_ERR_INVALID_PARAM;
if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
ret = can_delete_from_wim(wim);
if (ret)
- goto out;
+ return ret;
}
- if (num_additional_swms)
- merge_lookup_tables(wim, additional_swms, num_additional_swms);
-
ret = select_wim_image(wim, image);
if (ret)
- goto out_restore_lookup_table;
+ return ret;
DEBUG("Selected image %d", image);
imd = wim_get_current_image_metadata(wim);
- if (imd->refcnt != 1) {
- ERROR("Cannot mount image that was just exported with "
- "wimlib_export_image()");
- ret = WIMLIB_ERR_INVALID_PARAM;
- goto out_restore_lookup_table;
- }
-
if (imd->modified) {
- ERROR("Cannot mount image that was added "
- "with wimlib_add_image()");
- ret = WIMLIB_ERR_INVALID_PARAM;
- goto out_restore_lookup_table;
+ /* wimfs_read() only supports a limited number of stream
+ * locations, not including RESOURCE_IN_FILE_ON_DISK,
+ * RESOURCE_IN_NTFS_VOLUME, etc. that might appear if files were
+ * added to the WIM image. */
+ ERROR("Cannot mount an image with newly added files!");
+ return WIMLIB_ERR_INVALID_PARAM;
}
if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
ret = lock_wim(wim, wim->in_fd.fd);
if (ret)
- goto out_restore_lookup_table;
+ return ret;
}
/* Use default stream interface if one was not specified */
ctx.default_uid = getuid();
ctx.default_gid = getgid();
wimlib_assert(list_empty(&imd->unhashed_streams));
- ctx.wim->lookup_table->unhashed_streams = &imd->unhashed_streams;
if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
wim->wim_locked = 0;
out_free_message_queue_names:
free_message_queue_names(&ctx);
-out_restore_lookup_table:
- if (num_additional_swms)
- unmerge_lookup_table(wim);
-out:
return ret;
}
int ret;
struct wimfs_context wimfs_ctx;
+ if (unmount_flags & ~(WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY |
+ WIMLIB_UNMOUNT_FLAG_COMMIT |
+ WIMLIB_UNMOUNT_FLAG_REBUILD |
+ WIMLIB_UNMOUNT_FLAG_RECOMPRESS |
+ WIMLIB_UNMOUNT_FLAG_LAZY))
+ return WIMLIB_ERR_INVALID_PARAM;
+
init_wimfs_context(&wimfs_ctx);
ret = set_message_queue_names(&wimfs_ctx, dir);
WIMLIBAPI int
wimlib_mount_image(WIMStruct *wim, int image, const tchar *dir,
- int mount_flags, WIMStruct **additional_swms,
- unsigned num_additional_swms,
- const tchar *staging_dir)
+ int mount_flags, const tchar *staging_dir)
{
return mount_unsupported_error();
}