static WIMStruct *w;
/* Working directory when `imagex mount' is run. */
-static const char *working_directory;
+static char *working_directory;
/* Name of the staging directory for a read-write mount. Whenever a new file is
* created, it is done so in the staging directory. Furthermore, whenever a
/* Flags passed to wimlib_mount(). */
static int mount_flags;
-/* Name of the directory on which the WIM file is mounted. */
-static const char *mount_dir;
-
/* Next inode number to be assigned. */
static u64 next_ino;
return -EMFILE;
num_new_fds = min(fds_per_alloc,
max_fds - inode->num_allocated_fds);
-
+
fds = REALLOC(inode->fds,
(inode->num_allocated_fds + num_new_fds) *
sizeof(inode->fds[0]));
DEBUG("Creating staging file `%s'", name);
- fd = open(name, open_flags | O_CREAT | O_TRUNC, 0600);
+ fd = open(name, open_flags | O_CREAT | O_TRUNC, 0600);
if (fd == -1) {
errno_save = errno;
FREE(name);
return fd;
}
-/*
+/*
* Extract a WIM resource to the staging directory.
*
* @inode: Inode that contains the stream we are extracting
* 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.
+ * 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
return ret;
}
-/*
+/*
* Creates a randomly named staging directory and returns its name into the
* static variable staging_dir_name.
*
}
-/*
- * Deletes the staging directory and all the files contained in it.
+/*
+ * Deletes the staging directory and all the files contained in it.
*/
static int delete_staging_dir()
{
int ret;
-
+
ret = nftw(staging_dir_name, remove_file_or_directory,10, FTW_DEPTH);
staging_dir_name = NULL;
return ret;
static mqd_t daemon_to_unmount_mq;
/* Simple function that returns the concatenation of 4 strings. */
-static char *strcat_dup(const char *s1, const char *s2, const char *s3,
+static char *strcat_dup(const char *s1, const char *s2, const char *s3,
const char *s4)
{
size_t len = strlen(s1) + strlen(s2) + strlen(s3) + strlen(s4) + 1;
}
}
-/*
- * Opens two POSIX message queue: one for sending messages from the unmount
- * process to the daemon process, and one to go the other way. The names of the
- * message queues, which must be system-wide unique, are be based on the mount
- * point. (There of course is still a possibility of a collision if one were to
- * unmount two identically named directories simultaneously...)
- *
- * @daemon specifies whether the calling process is the filesystem daemon or the
- * unmount process.
- */
-static int open_message_queues(bool daemon)
+static int set_message_queue_names(const char *mount_dir)
{
static const char *slash = "/";
static const char *prefix = "wimlib-";
static const char *d2u_suffix = "daemon-to-unmount-mq";
const char *mount_dir_basename = path_basename(mount_dir);
- int flags;
- int ret;
unmount_to_daemon_mq_name = strcat_dup(slash, mount_dir_basename,
prefix, u2d_suffix);
prefix, d2u_suffix);
if (!daemon_to_unmount_mq_name) {
ERROR("Out of memory");
- ret = WIMLIB_ERR_NOMEM;
- goto err1;
+ FREE(unmount_to_daemon_mq_name);
+ unmount_to_daemon_mq_name = NULL;
+ return WIMLIB_ERR_NOMEM;
}
remove_trailing_slashes(unmount_to_daemon_mq_name);
remove_trailing_slashes(daemon_to_unmount_mq_name);
s_slashes_underscores_g(unmount_to_daemon_mq_name + 1);
s_slashes_underscores_g(daemon_to_unmount_mq_name + 1);
+ return 0;
+}
+
+static void free_message_queue_names()
+{
+ FREE(unmount_to_daemon_mq_name);
+ FREE(daemon_to_unmount_mq_name);
+ unmount_to_daemon_mq_name = NULL;
+ daemon_to_unmount_mq_name = NULL;
+}
+
+/*
+ * Opens two POSIX message queue: one for sending messages from the unmount
+ * process to the daemon process, and one to go the other way. The names of the
+ * message queues, which must be system-wide unique, are be based on the mount
+ * point. (There of course is still a possibility of a collision if one were to
+ * unmount two identically named directories simultaneously...)
+ *
+ * @daemon specifies whether the calling process is the filesystem daemon or the
+ * unmount process.
+ */
+static int open_message_queues(bool daemon)
+{
+ int flags;
+ int ret;
+
+ wimlib_assert(unmount_to_daemon_mq_name != NULL &&
+ daemon_to_unmount_mq_name != NULL);
if (daemon)
flags = O_RDONLY | O_CREAT;
else
flags = O_WRONLY | O_CREAT;
- unmount_to_daemon_mq = mq_open(unmount_to_daemon_mq_name, flags,
+ unmount_to_daemon_mq = mq_open(unmount_to_daemon_mq_name, flags,
0700, NULL);
if (unmount_to_daemon_mq == (mqd_t)-1) {
ERROR_WITH_ERRNO("mq_open()");
ret = WIMLIB_ERR_MQUEUE;
- goto err2;
+ goto out;
}
if (daemon)
else
flags = O_RDONLY | O_CREAT;
- daemon_to_unmount_mq = mq_open(daemon_to_unmount_mq_name, flags,
+ daemon_to_unmount_mq = mq_open(daemon_to_unmount_mq_name, flags,
0700, NULL);
if (daemon_to_unmount_mq == (mqd_t)-1) {
ERROR_WITH_ERRNO("mq_open()");
ret = WIMLIB_ERR_MQUEUE;
- goto err3;
+ goto out_close_unmount_to_daemon_mq;
}
- return 0;
-err3:
+ ret = 0;
+ goto out;
+out_close_unmount_to_daemon_mq:
mq_close(unmount_to_daemon_mq);
mq_unlink(unmount_to_daemon_mq_name);
-err2:
- FREE(daemon_to_unmount_mq_name);
-err1:
- FREE(unmount_to_daemon_mq_name);
+ unmount_to_daemon_mq = (mqd_t)-1;
+out:
return ret;
}
return msgsize;
}
+static void unlink_message_queues()
+{
+ mq_unlink(unmount_to_daemon_mq_name);
+ mq_unlink(daemon_to_unmount_mq_name);
+}
+
/* Closes the message queues, which are allocated in static variables */
static void close_message_queues()
{
mq_close(unmount_to_daemon_mq);
+ unmount_to_daemon_mq = (mqd_t)(-1);
mq_close(daemon_to_unmount_mq);
- mq_unlink(unmount_to_daemon_mq_name);
- mq_unlink(daemon_to_unmount_mq_name);
+ daemon_to_unmount_mq = (mqd_t)(-1);
+ unlink_message_queues();
}
static int wimfs_access(const char *path, int mask)
ret = open_message_queues(true);
if (ret != 0)
- exit(1);
+ return;
msgsize = mq_get_msgsize(unmount_to_daemon_mq);
char msg[msgsize];
DEBUG("Waiting for message telling us whether to commit or not, and "
"whether to include integrity checks.");
- bytes_received = mq_timedreceive(unmount_to_daemon_mq, msg,
+ bytes_received = mq_timedreceive(unmount_to_daemon_mq, msg,
msgsize, NULL, &timeout);
- commit = msg[0];
- check_integrity = msg[1];
if (bytes_received == -1) {
- if (errno == ETIMEDOUT) {
+ if (errno == ETIMEDOUT)
ERROR("Timed out.");
- } else {
+ else
ERROR_WITH_ERRNO("mq_timedreceive()");
- }
ERROR("Not committing.");
+ commit = 0;
+ check_integrity = 0;
} else {
DEBUG("Received message: [%d %d]", msg[0], msg[1]);
+ commit = msg[0];
+ check_integrity = msg[1];
}
status = 0;
if (status != 0) {
ERROR_WITH_ERRNO("chdir()");
status = WIMLIB_ERR_NOTDIR;
- goto done;
+ goto out;
}
status = rebuild_wim(w, (check_integrity != 0));
}
} else {
DEBUG("Read-only mount");
}
-done:
- DEBUG("Sending status %u", status);
+out:
+ DEBUG("Sending status %hhd", status);
ret = mq_send(daemon_to_unmount_mq, &status, 1, 1);
if (ret == -1)
ERROR_WITH_ERRNO("Failed to send status to unmount process");
}
#endif
-/*
- * Create a directory in the WIM.
+/*
+ * Create a directory in the WIM.
* @mode is currently ignored.
*/
static int wimfs_mkdir(const char *path, mode_t mode)
struct dentry *parent;
struct dentry *newdir;
const char *basename;
-
+
parent = get_parent_dentry(w, path);
if (!parent)
return -ENOENT;
struct inode *inode;
int ret;
struct wimlib_fd *fd = NULL;
-
+
inode = wim_pathname_to_inode(w, path);
if (!inode)
return -ENOENT;
/*
- * Read data from a file in the WIM or in the staging directory.
+ * Read data from a file in the WIM or in the staging directory.
*/
-static int wimfs_read(const char *path, char *buf, size_t size,
+static int wimfs_read(const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
/* Read from WIM */
u64 res_size = wim_resource_size(fd->f_lte);
-
+
if (offset > res_size)
return -EOVERFLOW;
/* Fills in the entries of the directory specified by @path using the
* FUSE-provided function @filler. */
-static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *fi)
{
struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
/* This rename() implementation currently only supports actual files
* (not alternate data streams) */
-
+
src = get_dentry(w, from);
if (!src)
return -ENOENT;
static int wimfs_rmdir(const char *path)
{
struct dentry *dentry;
-
+
dentry = get_dentry(w, path);
if (!dentry)
return -ENOENT;
struct dentry *dentry_parent, *dentry;
const char *link_name;
struct inode *inode;
-
+
dentry_parent = get_parent_dentry(w, from);
if (!dentry_parent)
return -ENOENT;
u16 stream_idx;
u32 stream_id;
struct inode *inode;
-
+
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
<e, &stream_idx);
int ret;
u16 stream_idx;
unsigned i;
-
+
ret = lookup_resource(w, path, get_lookup_flags(), &dentry,
<e, &stream_idx);
}
#ifdef HAVE_UTIMENSAT
-/*
- * Change the timestamp on a file dentry.
+/*
+ * Change the timestamp on a file dentry.
*
* Note that alternate data streams do not have their own timestamps.
*/
}
#endif
-/* Writes to a file in the WIM filesystem.
+/* Writes to a file in the WIM filesystem.
* It may be an alternate data stream, but here we don't even notice because we
* just get a lookup table entry. */
-static int wimfs_write(const char *path, const char *buf, size_t size,
+static int wimfs_write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *fi)
{
struct wimlib_fd *fd = (struct wimlib_fd*)(uintptr_t)fi->fh;
/* Mounts a WIM file. */
-WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
+WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir,
int flags, WIMStruct **additional_swms,
unsigned num_additional_swms)
{
int argc = 0;
char *argv[16];
int ret;
- char *p;
+ char *dir_copy;
struct lookup_table *joined_tab, *wim_tab_save;
struct image_metadata *imd;
wim->lookup_table = joined_tab;
}
- ret = wimlib_select_image(wim, image);
+ ret = select_wim_image(wim, image);
if (ret != 0)
goto out;
DEBUG("Selected image %d", image);
- next_ino = assign_inode_numbers(&imd->inode_list);
-
- DEBUG("(next_ino = %"PRIu64")", next_ino);
-
- /* Resolve all the lookup table entries of the dentry tree */
- DEBUG("Resolving lookup table entries");
- for_dentry_in_tree(imd->root_dentry, dentry_resolve_ltes,
- wim->lookup_table);
-
- if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
- imd->modified = true;
+ if (imd->root_dentry->refcnt != 1) {
+ ERROR("Cannot mount image that was just exported with "
+ "wimlib_export()");
+ ret = WIMLIB_ERR_INVALID_PARAM;
+ goto out;
+ }
if (!(flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE |
WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR |
DEBUG("Getting current directory");
- mount_dir = dir;
working_directory = getcwd(NULL, 0);
if (!working_directory) {
ERROR_WITH_ERRNO("Could not determine current directory");
goto out;
}
- DEBUG("Closing POSIX message queues");
- /* XXX hack to get rid of the message queues if they already exist for
- * some reason (maybe left over from a previous mount that wasn't
- * unmounted correctly) */
- ret = open_message_queues(true);
+ DEBUG("Unlinking message queues in case they already exist");
+ ret = set_message_queue_names(dir);
if (ret != 0)
- goto out;
- close_message_queues();
+ goto out_free_working_directory;
+ unlink_message_queues();
DEBUG("Preparing arguments to fuse_main()");
-
- p = STRDUP(dir);
- if (!p) {
- ret = WIMLIB_ERR_NOMEM;
- goto out;
- }
+ dir_copy = STRDUP(dir);
+ if (!dir_copy)
+ goto out_free_message_queue_names;
argv[argc++] = "imagex";
- argv[argc++] = p;
+ argv[argc++] = dir_copy;
argv[argc++] = "-s"; /* disable multi-threaded operation */
if (flags & WIMLIB_MOUNT_FLAG_DEBUG)
argv[argc++] = "-d";
- /*
+ /*
* We provide the use_ino option because we are going to assign inode
- * numbers oursides. We've already numbered the inodes with unique
- * numbers in the assign_inode_numbers() function, and the static
- * variable next_ino is set to the next available inode number.
+ * numbers oursides. The inodes will be given unique numbers in the
+ * assign_inode_numbers() function, and the static variable @next_ino is
+ * set to the next available inode number.
*/
char optstring[256] = "use_ino,subtype=wimfs,attr_timeout=0";
argv[argc++] = "-o";
/* Read-write mount. Make the staging directory */
make_staging_dir();
if (!staging_dir_name) {
- FREE(p);
ret = WIMLIB_ERR_MKDIR;
- goto out;
+ goto out_free_dir_copy;
}
} else {
/* Read-only mount */
}
#endif
+
+ /* Mark dentry tree as modified if read-write mount. */
+ if (flags & WIMLIB_MOUNT_FLAG_READWRITE)
+ imd->modified = true;
+
+ next_ino = assign_inode_numbers(&imd->inode_list);
+
+ DEBUG("(next_ino = %"PRIu64")", next_ino);
+
+ /* Resolve all the lookup table entries of the dentry tree */
+ DEBUG("Resolving lookup table entries");
+ for_dentry_in_tree(imd->root_dentry, dentry_resolve_ltes,
+ wim->lookup_table);
+
/* Set static variables. */
w = wim;
mount_flags = flags;
ret = fuse_main(argc, argv, &wimfs_operations, NULL);
if (ret)
ret = WIMLIB_ERR_FUSE;
+out_free_dir_copy:
+ FREE(dir_copy);
+out_free_message_queue_names:
+ free_message_queue_names();
+out_free_working_directory:
+ FREE(working_directory);
+ working_directory = NULL;
out:
if (num_additional_swms) {
free_lookup_table(wim->lookup_table);
}
-/*
+/*
* Unmounts the WIM file that was previously mounted on @dir by using
* wimlib_mount().
*/
int msgsize;
int errno_save;
- mount_dir = dir;
-
/* Open message queues between the unmount process and the
* filesystem daemon. */
+ ret = set_message_queue_names(dir);
+ if (ret != 0)
+ return ret;
+
ret = open_message_queues(false);
if (ret != 0)
return ret;
msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0;
msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0;
- DEBUG("Sending message: %s, %s",
+ DEBUG("Sending message: %s, %s",
(msg[0] == 0) ? "don't commit" : "commit",
(msg[1] == 0) ? "don't check" : "check");
ret = mq_send(unmount_to_daemon_mq, msg, 2, 1);
* send a message from this process to the filesystem daemon telling
* whether --commit was specified or not. However, after that, the
* unmount process must wait for the filesystem daemon to finish writing
- * the WIM file.
+ * the WIM file.
*/
* filesystem daemon has crashed or failed for some reason.
*
* XXX come up with some method to determine if the filesystem
- * daemon has really crashed or not.
+ * daemon has really crashed or not.
*
* XXX Idea: have mount daemon write its PID into the WIM file header?
* */
return mount_unsupported_error();
}
-WIMLIBAPI int wimlib_mount(WIMStruct *wim_p, int image, const char *dir,
+WIMLIBAPI int wimlib_mount(WIMStruct *wim_p, int image, const char *dir,
int flags, WIMStruct **additional_swms,
unsigned num_additional_swms)
{