X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fmount.c;h=640b27c686176559d262a9235acb804637c6f4b7;hp=bd02cec6ae3f1168cb853d779dca38462c06cd42;hb=815ad485b8ce48db48a3137d73e511f6c9af868c;hpb=46987f6ff2d27b0224f0ccab1b1e91164cae1d86 diff --git a/src/mount.c b/src/mount.c index bd02cec6..640b27c6 100644 --- a/src/mount.c +++ b/src/mount.c @@ -5,30 +5,35 @@ * Filesystem in Userspace. FUSE allows a filesystem to be implemented in a * userspace process by implementing the filesystem primitives--- read(), * write(), readdir(), etc. - * + */ + +/* * Copyright (C) 2012 Eric Biggers * - * wimlib - Library for working with WIM files + * This file is part of wimlib, a library for working with WIM files. * - * This library 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 - * Software Foundation; either version 2.1 of the License, or (at your option) any - * later version. + * wimlib 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 + * Software Foundation; either version 2.1 of the License, or (at your option) + * any later version. * - * This library is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more + * details. * - * You should have received a copy of the GNU Lesser General Public License along - * with this library; if not, write to the Free Software Foundation, Inc., 59 - * Temple Place, Suite 330, Boston, MA 02111-1307 USA + * You should have received a copy of the GNU Lesser General Public License + * along with wimlib; if not, see http://www.gnu.org/licenses/. */ #include "wimlib_internal.h" #ifdef WITH_FUSE +#include "sha1.h" #include "lookup_table.h" #include "xml.h" +#include "io.h" +#include "timestamp.h" #include #include #include @@ -81,7 +86,7 @@ static void make_staging_dir() staging_dir_name = MALLOC(staging_dir_name_len + 1); if (!staging_dir_name) { - ERROR("Out of memory!\n"); + ERROR("Out of memory"); return; } @@ -93,8 +98,8 @@ static void make_staging_dir() staging_dir_name[staging_dir_name_len] = '\0'; if (mkdir(staging_dir_name, 0700) != 0) { - ERROR("Failed to create temporary directory `%s': %m\n", - staging_dir_name); + ERROR_WITH_ERRNO("Failed to create temporary directory `%s'", + staging_dir_name); FREE(staging_dir_name); staging_dir_name = NULL; } @@ -115,7 +120,11 @@ static int remove_file_or_directory(const char *fpath, const struct stat *sb, */ static inline int delete_staging_dir() { - return nftw(staging_dir_name, remove_file_or_directory, 10, FTW_DEPTH); + int ret; + + ret = nftw(staging_dir_name, remove_file_or_directory,10, FTW_DEPTH); + staging_dir_name = NULL; + return ret; } /* Name and message queue descriptors for message queues between the filesystem @@ -191,13 +200,13 @@ static int open_message_queues(bool daemon) unmount_to_daemon_mq_name = strcat_dup(slash, mount_dir_basename, prefix, u2d_suffix); if (!unmount_to_daemon_mq_name) { - ERROR("Out of memory!\n"); + ERROR("Out of memory"); return WIMLIB_ERR_NOMEM; } daemon_to_unmount_mq_name = strcat_dup(slash, mount_dir_basename, prefix, d2u_suffix); if (!daemon_to_unmount_mq_name) { - ERROR("Out of memory!\n"); + ERROR("Out of memory"); ret = WIMLIB_ERR_NOMEM; goto err1; } @@ -216,7 +225,7 @@ static int open_message_queues(bool daemon) 0700, NULL); if (unmount_to_daemon_mq == -1) { - ERROR("mq_open(): %m\n"); + ERROR_WITH_ERRNO("mq_open()"); ret = WIMLIB_ERR_MQUEUE; goto err2; } @@ -230,7 +239,7 @@ static int open_message_queues(bool daemon) 0700, NULL); if (daemon_to_unmount_mq == -1) { - ERROR("mq_open(): %m\n"); + ERROR_WITH_ERRNO("mq_open()"); ret = WIMLIB_ERR_MQUEUE; goto err3; } @@ -255,19 +264,19 @@ static int mq_get_msgsize(mqd_t mq) if (mq_getattr(unmount_to_daemon_mq, &attr) == 0) { msgsize = attr.mq_msgsize; } else { - ERROR("mq_getattr(): %m\n"); - ERROR("Attempting to read %s\n", msgsize_max_file); + ERROR_WITH_ERRNO("mq_getattr()"); + ERROR("Attempting to read %s", msgsize_max_file); fp = fopen(msgsize_max_file, "rb"); if (fp) { if (fscanf(fp, "%d", &msgsize) != 1) { - ERROR("Assuming message size of 8192\n"); + ERROR("Assuming message size of 8192"); msgsize = 8192; } fclose(fp); } else { - ERROR("Failed to open file %s: %m\n", - msgsize_max_file); - ERROR("Assuming message size of 8192\n"); + ERROR_WITH_ERRNO("Failed to open the file `%s'", + msgsize_max_file); + ERROR("Assuming message size of 8192"); msgsize = 8192; } } @@ -295,8 +304,8 @@ static int close_staging_file(struct lookup_table_entry *lte, void *ignore) { if (lte->staging_file_name && lte->staging_num_times_opened) { if (close(lte->staging_fd) != 0) { - ERROR("Failed close file `%s': %m\n", - lte->staging_file_name); + ERROR_WITH_ERRNO("Failed close file `%s'", + lte->staging_file_name); return WIMLIB_ERR_WRITE; } } @@ -320,7 +329,8 @@ static int calculate_sha1sum_for_staging_file(struct dentry *dentry, void *looku if (lte && lte->staging_file_name) { - DEBUG("Calculating SHA1 hash for file `%s'\n", dentry->file_name_utf8); + DEBUG("Calculating SHA1 hash for file `%s'", + dentry->file_name_utf8); ret = sha1sum(lte->staging_file_name, dentry->hash); if (ret != 0) return ret; @@ -329,8 +339,8 @@ static int calculate_sha1sum_for_staging_file(struct dentry *dentry, void *looku memcpy(lte->hash, dentry->hash, WIM_HASH_SIZE); existing = lookup_resource(table, dentry->hash); if (existing) { - DEBUG("Merging duplicate lookup table entries for " - "file `%s'\n", dentry->file_name_utf8); + DEBUG("Merging duplicate lookup table entries for file " + "`%s'", dentry->file_name_utf8); free_lookup_table_entry(lte); existing->refcnt++; } else { @@ -348,22 +358,21 @@ static int rebuild_wim(WIMStruct *w, bool check_integrity) root = wim_root_dentry(w); - DEBUG("Closing all staging file descriptors.\n"); + DEBUG("Closing all staging file descriptors."); /* Close all the staging file descriptors. */ - ret = for_lookup_table_entry(w->lookup_table, - close_staging_file, NULL); + ret = for_lookup_table_entry(w->lookup_table, close_staging_file, NULL); if (ret != 0) { - ERROR("Failed to close all staging files!\n"); + ERROR("Failed to close all staging files"); return ret; } - DEBUG("Calculating SHA1 checksums for all new staging files.\n"); + DEBUG("Calculating SHA1 checksums for all new staging files."); /* Calculate SHA1 checksums for all staging files, and merge unnecessary * lookup table entries. */ ret = for_dentry_in_tree(root, calculate_sha1sum_for_staging_file, w->lookup_table); if (ret != 0) { - ERROR("Failed to calculate new SHA1 checksums!\n"); + ERROR("Failed to calculate new SHA1 checksums"); return ret; } @@ -371,7 +380,7 @@ static int rebuild_wim(WIMStruct *w, bool check_integrity) ret = wimlib_overwrite(w, check_integrity); if (ret != 0) { - ERROR("Failed to commit changes\n"); + ERROR("Failed to commit changes"); return ret; } return ret; @@ -409,8 +418,8 @@ static void wimfs_destroy(void *p) gettimeofday(&now, NULL); timeout.tv_sec = now.tv_sec + 3; timeout.tv_nsec = now.tv_usec * 1000; - DEBUG("Waiting for message telling us whether to commit or not, " - "and whether to include integrity checks.\n"); + 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, msgsize, NULL, &timeout); @@ -418,13 +427,13 @@ static void wimfs_destroy(void *p) check_integrity = msg[1]; if (bytes_received == -1) { if (errno == ETIMEDOUT) { - ERROR("Timed out.\n"); + ERROR("Timed out."); } else { - ERROR("mq_timedreceive(): %m\n"); + ERROR_WITH_ERRNO("mq_timedreceive()"); } - ERROR("Not committing.\n"); + ERROR("Not committing."); } else { - DEBUG("Received message: [%d %d]\n", msg[0], msg[1]); + DEBUG("Received message: [%d %d]", msg[0], msg[1]); } status = 0; @@ -432,7 +441,7 @@ static void wimfs_destroy(void *p) if (commit) { status = chdir(working_directory); if (status != 0) { - ERROR("chdir(): %m\n"); + ERROR_WITH_ERRNO("chdir()"); status = WIMLIB_ERR_NOTDIR; goto done; } @@ -440,7 +449,8 @@ static void wimfs_destroy(void *p) } ret = delete_staging_dir(); if (ret != 0) { - ERROR("Failed to delete the staging directory: %m\n"); + ERROR_WITH_ERRNO("Failed to delete the staging " + "directory"); if (status == 0) status = ret; } @@ -448,7 +458,7 @@ static void wimfs_destroy(void *p) done: ret = mq_send(daemon_to_unmount_mq, &status, 1, 1); if (ret == -1) - ERROR("Failed to send status to unmount process: %m\n"); + ERROR_WITH_ERRNO("Failed to send status to unmount process"); close_message_queues(); } @@ -486,7 +496,7 @@ static int wimfs_mkdir(const char *path, mode_t mode) return -EEXIST; newdir = new_dentry(basename); - newdir->attributes |= WIM_FILE_ATTRIBUTE_DIRECTORY; + newdir->attributes |= FILE_ATTRIBUTE_DIRECTORY; link_dentry(newdir, parent); return 0; } @@ -534,7 +544,7 @@ static int create_staging_file(char **name_ret) /* doesn't exist--- ok */ } - DEBUG("Creating staging file '%s'\n", name); + DEBUG("Creating staging file '%s'", name); fd = creat(name, 0600); if (fd == -1) { @@ -576,8 +586,6 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) /* Create a lookup table entry having the same hash value */ lte = new_lookup_table_entry(); - lte->staging_num_times_opened = 0; - lte->resource_entry.original_size = 0; memcpy(lte->hash, dentry->hash, WIM_HASH_SIZE); fd = create_staging_file(&tmpfile_name); @@ -610,7 +618,7 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi) dentry = get_dentry(w, path); if (!dentry) - return -EEXIST; + return -ENOENT; if (dentry_is_directory(dentry)) return -EISDIR; lte = wim_lookup_resource(w, dentry); @@ -626,11 +634,14 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi) } } else { /* no lookup table entry, so the file must be empty. Create a - * lookup table entry for the file. */ + * lookup table entry for the file, unless it's a read-only + * filesystem. */ char *tmpfile_name; - int err; int fd; + if (!staging_dir_name) /* Read-only filesystem */ + return 0; + lte = new_lookup_table_entry(); if (!lte) return -ENOMEM; @@ -638,9 +649,9 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi) fd = create_staging_file(&tmpfile_name); if (fd == -1) { - err = errno; + int err = errno; free(lte); - return -errno; + return -err; } lte->resource_entry.original_size = 0; randomize_byte_array(lte->hash, WIM_HASH_SIZE); @@ -762,14 +773,29 @@ static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, return 0; do { - memset(&st, 0, sizeof(st)); - if (filler(buf, child->file_name_utf8, &st, 0)) + if (filler(buf, child->file_name_utf8, NULL, 0)) return 0; child = child->next; } while (child != parent->children); return 0; } + +static int wimfs_readlink(const char *path, char *buf, size_t buf_len) +{ + struct dentry *dentry = get_dentry(w, path); + int ret; + if (!dentry) + return -ENOENT; + if (!dentry_is_symlink(dentry)) + return -EINVAL; + + ret = dentry_readlink(dentry, buf, buf_len, w); + if (ret > 0) + ret = 0; + return ret; +} + /* Close a file. */ static int wimfs_release(const char *path, struct fuse_file_info *fi) { @@ -870,7 +896,7 @@ static int extract_resource_to_staging_dir(struct dentry *dentry, struct lookup_table_entry *lte, u64 size) { - int err, fd; + int fd; bool ret; char *staging_file_name; struct lookup_table_entry *new_lte; @@ -978,6 +1004,20 @@ static int wimfs_unlink(const char *path) return 0; } +static int wimfs_utimens(const char *path, const struct timespec tv[2]) +{ + struct dentry *dentry = get_dentry(w, path); + if (!dentry) + return -ENOENT; + time_t last_access_t = (tv[0].tv_nsec == UTIME_NOW) ? + time(NULL) : tv[0].tv_sec; + dentry->last_access_time = unix_timestamp_to_ms(last_access_t); + time_t last_mod_t = (tv[1].tv_nsec == UTIME_NOW) ? + time(NULL) : tv[1].tv_sec; + dentry->last_write_time = unix_timestamp_to_ms(last_mod_t); + return 0; +} + /* Writes to a file in the WIM filesystem. */ static int wimfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) @@ -1046,11 +1086,13 @@ static struct fuse_operations wimfs_oper = { .opendir = wimfs_opendir, .read = wimfs_read, .readdir = wimfs_readdir, + .readlink = wimfs_readlink, .release = wimfs_release, .rename = wimfs_rename, .rmdir = wimfs_rmdir, .truncate = wimfs_truncate, .unlink = wimfs_unlink, + .utimens = wimfs_utimens, .write = wimfs_write, }; @@ -1078,10 +1120,15 @@ WIMLIBAPI int wimlib_mount(WIMStruct *wim, int image, const char *dir, if (flags & WIMLIB_MOUNT_FLAG_READWRITE) wim_get_current_image_metadata(wim)->modified = true; + if (!(flags & (WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE | + WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR | + WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS))) + flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR; + mount_dir = dir; working_directory = getcwd(NULL, 0); if (!working_directory) { - ERROR("Could not determine current directory: %m\n"); + ERROR_WITH_ERRNO("Could not determine current directory"); return WIMLIB_ERR_NOTDIR; } @@ -1160,24 +1207,24 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) mount_dir = dir; pid = fork(); if (pid == -1) { - ERROR("Failed to fork(): %m\n"); + ERROR_WITH_ERRNO("Failed to fork()"); return WIMLIB_ERR_FORK; } if (pid == 0) { execlp("fusermount", "fusermount", "-u", dir, NULL); - ERROR("Failed to execute `fusermount': %m\n"); + ERROR_WITH_ERRNO("Failed to execute `fusermount'"); return WIMLIB_ERR_FUSERMOUNT; } ret = waitpid(pid, &status, 0); if (ret == -1) { - ERROR("Failed to wait for fusermount process to " - "terminate: %m\n"); + ERROR_WITH_ERRNO("Failed to wait for fusermount process to " + "terminate"); return WIMLIB_ERR_FUSERMOUNT; } if (status != 0) { - ERROR("fusermount exited with status %d!\n", status); + ERROR("fusermount exited with status %d", status); return WIMLIB_ERR_FUSERMOUNT; } @@ -1192,13 +1239,13 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) msg[0] = (flags & WIMLIB_UNMOUNT_FLAG_COMMIT) ? 1 : 0; msg[1] = (flags & WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY) ? 1 : 0; - DEBUG("Sending message: %s, %s\n", + 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); if (ret == -1) { - ERROR("Failed to notify filesystem daemon whether " - "we want to commit changes or not!\n"); + ERROR("Failed to notify filesystem daemon whether we want to " + "commit changes or not"); close_message_queues(); return WIMLIB_ERR_MQUEUE; } @@ -1223,28 +1270,27 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) mailbox[0] = 0; DEBUG("Waiting for message telling us whether the unmount was " - "successful or not.\n"); + "successful or not."); ret = mq_timedreceive(daemon_to_unmount_mq, mailbox, msgsize, NULL, &timeout); errno_save = errno; close_message_queues(); if (ret == -1) { if (errno_save == ETIMEDOUT) { - ERROR("Timed out- probably the filesystem " - "daemon crashed and the WIM was not " - "written successfully.\n"); + ERROR("Timed out- probably the filesystem daemon " + "crashed and the WIM was not written " + "successfully."); return WIMLIB_ERR_TIMEOUT; } else { - ERROR("mq_receive(): %s\n", - strerror(errno_save)); + ERROR("mq_receive(): %s", strerror(errno_save)); return WIMLIB_ERR_MQUEUE; } } - DEBUG("Received message: %s\n", (mailbox[0] == 0) ? - "Unmount OK" : "Unmount Failed"); + DEBUG("Received message: %s", + (mailbox[0] == 0) ? "Unmount OK" : "Unmount Failed"); if (mailbox[0] != 0) - ERROR("Unmount failed\n"); + ERROR("Unmount failed"); return mailbox[0]; } @@ -1253,8 +1299,8 @@ WIMLIBAPI int wimlib_unmount(const char *dir, int flags) static inline int mount_unsupported_error() { - ERROR("WIMLIB was compiled with --without-fuse, which " - "disables support for mounting WIMs.\n"); + ERROR("WIMLIB was compiled with --without-fuse, which disables support " + "for mounting WIMs."); return WIMLIB_ERR_UNSUPPORTED; }