]> wimlib.net Git - wimlib/blobdiff - src/mount_image.c
Add more comments
[wimlib] / src / mount_image.c
index 04ecbfefe8d3896810c800ae2a569931c5717f7e..a2e09b435e43a60a72db289e0839c747315ceeaa 100644 (file)
@@ -98,11 +98,8 @@ struct wimfs_context {
         * filesystem anyway. */
        u64 next_ino;
 
-       /* List of lookup table entries for files in the staging directory */
-       struct list_head staging_list;
-
        /* List of inodes in the mounted image */
-       struct hlist_head *image_inode_list;
+       struct list_head *image_inode_list;
 
        /* Name and message queue descriptors for message queues between the
         * filesystem daemon process and the unmount process.  These are used
@@ -128,7 +125,6 @@ init_wimfs_context(struct wimfs_context *ctx)
        memset(ctx, 0, sizeof(*ctx));
        ctx->unmount_to_daemon_mq = (mqd_t)-1;
        ctx->daemon_to_unmount_mq = (mqd_t)-1;
-       INIT_LIST_HEAD(&ctx->staging_list);
 }
 
 #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data)
@@ -296,7 +292,7 @@ close_wimfs_fd(struct wimfs_fd *fd)
              fd->f_inode->i_ino, fd->f_inode->i_num_opened_fds,
              fd->f_inode->i_num_allocated_fds);
        ret = lte_put_fd(fd->f_lte, fd);
-       if (ret != 0)
+       if (ret)
                return ret;
 
        inode_put_fd(fd->f_inode, fd);
@@ -350,7 +346,7 @@ create_dentry(struct fuse_context *fuse_ctx, const char *path,
                }
        }
        dentry_add_child(parent, new);
-       hlist_add_head(&new->d_inode->i_hlist, wimfs_ctx->image_inode_list);
+       list_add_tail(&new->d_inode->i_list, wimfs_ctx->image_inode_list);
        if (dentry_ret)
                *dentry_ret = new;
        return 0;
@@ -382,7 +378,7 @@ remove_dentry(struct wim_dentry *dentry,
                        lte_decrement_refcnt(lte, lookup_table);
        }
        unlink_dentry(dentry);
-       put_dentry(dentry);
+       free_dentry(dentry);
 }
 
 static mode_t
@@ -422,22 +418,10 @@ inode_to_stbuf(const struct wim_inode *inode,
        }
        stbuf->st_ino = (ino_t)inode->i_ino;
        stbuf->st_nlink = inode->i_nlink;
-       if (lte) {
-               if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
-                       struct stat native_stat;
-                       if (stat(lte->staging_file_name, &native_stat) != 0) {
-                               DEBUG("Failed to stat `%s': %m",
-                                     lte->staging_file_name);
-                               return -errno;
-                       }
-                       stbuf->st_size = native_stat.st_size;
-               } else {
-                       stbuf->st_size = wim_resource_size(lte);
-               }
-       } else {
+       if (lte)
+               stbuf->st_size = wim_resource_size(lte);
+       else
                stbuf->st_size = 0;
-       }
-
 #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);
@@ -661,18 +645,10 @@ extract_resource_to_staging_dir(struct wim_inode *inode,
        new_lte->refcnt                       = inode->i_nlink;
        new_lte->resource_location            = RESOURCE_IN_STAGING_FILE;
        new_lte->staging_file_name            = staging_file_name;
-       new_lte->lte_inode                    = inode;
-       random_hash(new_lte->hash);
+       new_lte->resource_entry.original_size = size;
 
-       if (stream_id == 0)
-               inode->i_lte = new_lte;
-       else
-               for (u16 i = 0; i < inode->i_num_ads; i++)
-                       if (inode->i_ads_entries[i].stream_id == stream_id)
-                               inode->i_ads_entries[i].lte = new_lte;
-
-       lookup_table_insert(ctx->wim->lookup_table, new_lte);
-       list_add(&new_lte->staging_list, &ctx->staging_list);
+       lookup_table_insert_unhashed(ctx->wim->lookup_table, new_lte,
+                                    inode, stream_id);
        *lte = new_lte;
        return 0;
 out_revert_fd_changes:
@@ -790,64 +766,6 @@ delete_staging_dir(struct wimfs_context *ctx)
        return ret;
 }
 
-static void
-inode_update_lte_ptr(struct wim_inode *inode,
-                    struct wim_lookup_table_entry *old_lte,
-                    struct wim_lookup_table_entry *new_lte)
-{
-       if (inode->i_lte == old_lte) {
-               inode->i_lte = new_lte;
-       } else {
-               for (unsigned i = 0; i < inode->i_num_ads; i++) {
-                       if (inode->i_ads_entries[i].lte == old_lte) {
-                               inode->i_ads_entries[i].lte = new_lte;
-                               break;
-                       }
-               }
-       }
-}
-
-static int
-update_lte_of_staging_file(struct wim_lookup_table_entry *lte,
-                          struct wim_lookup_table *table)
-{
-       struct wim_lookup_table_entry *duplicate_lte;
-       int ret;
-       u8 hash[SHA1_HASH_SIZE];
-       struct stat stbuf;
-
-       ret = sha1sum(lte->staging_file_name, hash);
-       if (ret != 0)
-               return ret;
-       lookup_table_unlink(table, lte);
-       duplicate_lte = __lookup_resource(table, hash);
-       if (duplicate_lte) {
-               /* Merge duplicate lookup table entries */
-               duplicate_lte->refcnt += lte->refcnt;
-               inode_update_lte_ptr(lte->lte_inode, lte, duplicate_lte);
-               free_lookup_table_entry(lte);
-       } else {
-               if (stat(lte->staging_file_name, &stbuf) != 0) {
-                       ERROR_WITH_ERRNO("Failed to stat `%s'", lte->staging_file_name);
-                       return WIMLIB_ERR_STAT;
-               }
-               if (stbuf.st_size == 0) {
-                       /* Zero-length stream.  No lookup table entry needed. */
-                       inode_update_lte_ptr(lte->lte_inode, lte, NULL);
-                       free_lookup_table_entry(lte);
-               } else {
-                       BUILD_BUG_ON(&lte->file_on_disk != &lte->staging_file_name);
-                       lte->resource_entry.original_size = stbuf.st_size;
-                       lte->resource_entry.size = stbuf.st_size;
-                       lte->resource_location = RESOURCE_IN_FILE_ON_DISK;
-                       lte->file_on_disk_fp = NULL;
-                       copy_hash(lte->hash, hash);
-                       lookup_table_insert(table, lte);
-               }
-       }
-       return 0;
-}
-
 static int
 inode_close_fds(struct wim_inode *inode)
 {
@@ -873,24 +791,31 @@ rebuild_wim(struct wimfs_context *ctx, int write_flags,
        int ret;
        struct wim_lookup_table_entry *lte, *tmp;
        WIMStruct *w = ctx->wim;
+       struct wim_image_metadata *imd = wim_get_current_image_metadata(ctx->wim);
 
        DEBUG("Closing all staging file descriptors.");
-       list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
-               ret = inode_close_fds(lte->lte_inode);
-               if (ret != 0)
+       image_for_each_unhashed_stream_safe(lte, tmp, imd) {
+               ret = inode_close_fds(lte->back_inode);
+               if (ret)
                        return ret;
        }
 
-       DEBUG("Calculating SHA1 checksums for all new staging files.");
-       list_for_each_entry_safe(lte, tmp, &ctx->staging_list, staging_list) {
-               ret = update_lte_of_staging_file(lte, w->lookup_table);
-               if (ret != 0)
-                       return ret;
+       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) {
+                       print_lookup_table_entry(lte, stderr);
+                       struct wim_lookup_table_entry **back_ptr;
+                       back_ptr = retrieve_lte_pointer(lte);
+                       *back_ptr = NULL;
+                       list_del(&lte->unhashed_list);
+                       free_lookup_table_entry(lte);
+               }
        }
 
        xml_update_image_info(w, w->current_image);
        ret = wimlib_overwrite(w, write_flags, 0, progress_func);
-       if (ret != 0)
+       if (ret)
                ERROR("Failed to commit changes to mounted WIM image");
        return ret;
 }
@@ -1660,10 +1585,10 @@ wimfs_ftruncate(const char *path, off_t size, struct fuse_file_info *fi)
 {
        struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
        int ret = ftruncate(fd->staging_fd, size);
-       if (ret != 0)
+       if (ret)
                return -errno;
-       if (fd->f_lte && size < fd->f_lte->resource_entry.original_size)
-               fd->f_lte->resource_entry.original_size = size;
+       touch_inode(fd->f_inode);
+       fd->f_lte->resource_entry.original_size = size;
        return 0;
 }
 
@@ -1723,8 +1648,7 @@ wimfs_getxattr(const char *path, const char *name, char *value,
        if (res_size > size)
                return -ERANGE;
 
-       ret = read_full_wim_resource(lte, (u8*)value,
-                                    WIMLIB_RESOURCE_FLAG_MULTITHREADED);
+       ret = read_full_resource_into_buf(lte, value, true);
        if (ret != 0)
                return -EIO;
 
@@ -1739,9 +1663,7 @@ wimfs_link(const char *to, const char *from)
        struct wim_dentry *from_dentry, *from_dentry_parent;
        const char *link_name;
        struct wim_inode *inode;
-       struct wim_lookup_table_entry *lte;
        WIMStruct *w = wimfs_get_WIMStruct();
-       u16 i;
        int ret;
 
        inode = wim_pathname_to_inode(w, to);
@@ -1766,15 +1688,10 @@ wimfs_link(const char *to, const char *from)
        if (ret)
                return -ENOMEM;
 
-       inode_add_dentry(from_dentry, inode);
-       from_dentry->d_inode = inode;
        inode->i_nlink++;
-
-       for (i = 0; i <= inode->i_num_ads; i++) {
-               lte = inode_stream_lte_resolved(inode, i);
-               if (lte)
-                       lte->refcnt++;
-       }
+       inode_ref_streams(inode);
+       from_dentry->d_inode = inode;
+       inode_add_dentry(from_dentry, inode);
        dentry_add_child(from_dentry_parent, from_dentry);
        return 0;
 }
@@ -1805,10 +1722,10 @@ wimfs_listxattr(const char *path, char *list, size_t size)
                size_t stream_name_mbs_nbytes;
                int ret;
 
-               ret = utf16le_to_mbs(inode->i_ads_entries[i].stream_name,
-                                    inode->i_ads_entries[i].stream_name_nbytes,
-                                    &stream_name_mbs,
-                                    &stream_name_mbs_nbytes);
+               ret = utf16le_to_tstr(inode->i_ads_entries[i].stream_name,
+                                     inode->i_ads_entries[i].stream_name_nbytes,
+                                     &stream_name_mbs,
+                                     &stream_name_mbs_nbytes);
                if (ret)
                        return -errno;
 
@@ -1861,8 +1778,7 @@ wimfs_mknod(const char *path, mode_t mode, dev_t rdev)
                inode = wim_pathname_to_inode(wimfs_ctx->wim, path);
                if (!inode)
                        return -errno;
-               if (inode->i_attributes &
-                   (FILE_ATTRIBUTE_REPARSE_POINT | FILE_ATTRIBUTE_DIRECTORY))
+               if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT)
                        return -ENOENT;
                if (inode_get_ads_entry(inode, stream_name, NULL))
                        return -EEXIST;
@@ -1889,6 +1805,7 @@ wimfs_open(const char *path, struct fuse_file_info *fi)
        u16 stream_idx;
        u32 stream_id;
        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, &lte, &stream_idx);
@@ -1897,10 +1814,13 @@ wimfs_open(const char *path, struct fuse_file_info *fi)
 
        inode = dentry->d_inode;
 
-       if (stream_idx == 0)
+       if (stream_idx == 0) {
                stream_id = 0;
-       else
+               back_ptr = &inode->i_lte;
+       } else {
                stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
+               back_ptr = &inode->i_ads_entries[stream_idx - 1].lte;
+       }
 
        /* 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
@@ -1916,7 +1836,9 @@ wimfs_open(const char *path, struct fuse_file_info *fi)
                                                      &lte, size, ctx);
                if (ret != 0)
                        return ret;
+               *back_ptr = lte;
        }
+       print_lookup_table_entry(lte, stderr);
 
        ret = alloc_wimfs_fd(inode, stream_id, lte, &fd,
                             wimfs_ctx_readonly(ctx));
@@ -1965,6 +1887,7 @@ wimfs_read(const char *path, char *buf, size_t size,
 {
        struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh;
        ssize_t ret;
+       u64 res_size;
 
        if (!fd)
                return -EBADF;
@@ -1972,32 +1895,34 @@ wimfs_read(const char *path, char *buf, size_t size,
        if (!fd->f_lte) /* Empty stream with no lookup table entry */
                return 0;
 
-       if (fd->f_lte->resource_location == RESOURCE_IN_STAGING_FILE) {
-               /* Read from staging file */
+       res_size = wim_resource_size(fd->f_lte);
+       if (offset > res_size)
+               return -EOVERFLOW;
+       size = min(size, INT_MAX);
+       size = min(size, res_size - offset);
 
-               wimlib_assert(fd->f_lte->staging_file_name);
-               wimlib_assert(fd->staging_fd != -1);
-
-               DEBUG("Seek to offset %"PRIu64, offset);
-
-               if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
-                       return -errno;
-               ret = read(fd->staging_fd, buf, size);
-               if (ret == -1)
-                       return -errno;
-               return ret;
-       } else {
-               /* Read from WIM */
-               u64 res_size = wim_resource_size(fd->f_lte);
-               if (offset > res_size)
-                       return -EOVERFLOW;
-               size = min(size, res_size - offset);
-               if (read_wim_resource(fd->f_lte, buf,
-                                     size, offset,
-                                     WIMLIB_RESOURCE_FLAG_MULTITHREADED) != 0)
-                       return -EIO;
-               return size;
+       switch (fd->f_lte->resource_location) {
+       case RESOURCE_IN_STAGING_FILE:
+               ret = pread(fd->staging_fd, buf, size, offset);
+               if (ret < 0)
+                       ret = -errno;
+               break;
+       case RESOURCE_IN_WIM:
+               if (read_partial_wim_resource_into_buf(fd->f_lte, size,
+                                                      offset, buf, true))
+                       ret = -errno;
+               ret = size;
+               break;
+       case RESOURCE_IN_ATTACHED_BUFFER:
+               memcpy(buf, fd->f_lte->attached_buffer + offset, size);
+               ret = size;
+               break;
+       default:
+               ERROR("Invalid resource location");
+               ret = -EIO;
+               break;
        }
+       return ret;
 }
 
 struct fill_params {
@@ -2014,10 +1939,10 @@ dentry_fuse_fill(struct wim_dentry *dentry, void *arg)
        size_t file_name_mbs_nbytes;
        int ret;
 
-       ret = utf16le_to_mbs(dentry->file_name,
-                            dentry->file_name_nbytes,
-                            &file_name_mbs,
-                            &file_name_mbs_nbytes);
+       ret = utf16le_to_tstr(dentry->file_name,
+                             dentry->file_name_nbytes,
+                             &file_name_mbs,
+                             &file_name_mbs_nbytes);
        if (ret)
                return -errno;
 
@@ -2064,8 +1989,7 @@ wimfs_readlink(const char *path, char *buf, size_t buf_len)
        if (!inode_is_symlink(inode))
                return -EINVAL;
 
-       ret = inode_readlink(inode, buf, buf_len, ctx->wim,
-                            WIMLIB_RESOURCE_FLAG_MULTITHREADED);
+       ret = inode_readlink(inode, buf, buf_len, ctx->wim, true);
        if (ret > 0)
                ret = 0;
        return ret;
@@ -2283,19 +2207,20 @@ wimfs_truncate(const char *path, off_t size)
        if (lte == NULL && size == 0)
                return 0;
 
-       inode = dentry->d_inode;
-       if (stream_idx == 0)
-               stream_id = 0;
-       else
-               stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
-
        if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
                ret = truncate(lte->staging_file_name, size);
-               if (ret != 0)
+               if (ret)
                        ret = -errno;
+               else
+                       lte->resource_entry.original_size = size;
        } else {
                /* File in WIM.  Extract it to the staging directory, but only
                 * the first @size bytes of it. */
+               inode = dentry->d_inode;
+               if (stream_idx == 0)
+                       stream_id = 0;
+               else
+                       stream_id = inode->i_ads_entries[stream_idx - 1].stream_id;
                ret = extract_resource_to_staging_dir(inode, stream_id,
                                                      &lte, size, ctx);
        }
@@ -2390,20 +2315,24 @@ wimfs_write(const char *path, const char *buf, size_t size,
        if (!fd)
                return -EBADF;
 
-       wimlib_assert(fd->f_lte);
-       wimlib_assert(fd->f_lte->staging_file_name);
+       wimlib_assert(fd->f_lte != NULL);
+       wimlib_assert(fd->f_lte->staging_file_name != NULL);
        wimlib_assert(fd->staging_fd != -1);
-       wimlib_assert(fd->f_inode);
-
-       /* Seek to the requested position */
-       if (lseek(fd->staging_fd, offset, SEEK_SET) == -1)
-               return -errno;
+       wimlib_assert(fd->f_inode != NULL);
 
        /* Write the data. */
-       ret = write(fd->staging_fd, buf, size);
+       ret = pwrite(fd->staging_fd, buf, size, offset);
        if (ret == -1)
                return -errno;
 
+       /* Update file size */
+       if (offset + size > fd->f_lte->resource_entry.original_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;
+       }
+
        /* Update timestamps */
        touch_inode(fd->f_inode);
        return ret;
@@ -2483,7 +2412,6 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        struct wim_lookup_table *joined_tab, *wim_tab_save;
        struct wim_image_metadata *imd;
        struct wimfs_context ctx;
-       struct hlist_node *cur_node;
        struct wim_inode *inode;
 
        DEBUG("Mount: wim = %p, image = %d, dir = %s, flags = %d, ",
@@ -2493,7 +2421,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
                return WIMLIB_ERR_INVALID_PARAM;
 
        ret = verify_swm_set(wim, additional_swms, num_additional_swms);
-       if (ret != 0)
+       if (ret)
                return ret;
 
        if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) && (wim->hdr.total_parts != 1)) {
@@ -2505,7 +2433,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
                ret = new_joined_lookup_table(wim, additional_swms,
                                              num_additional_swms,
                                              &joined_tab);
-               if (ret != 0)
+               if (ret)
                        return ret;
                wim_tab_save = wim->lookup_table;
                wim->lookup_table = joined_tab;
@@ -2513,28 +2441,29 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
 
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = wim_run_full_verifications(wim);
-               if (ret != 0)
+               if (ret)
                        goto out;
        }
 
+       ret = wim_checksum_unhashed_streams(wim);
+       if (ret)
+               goto out;
+
        ret = select_wim_image(wim, image);
-       if (ret != 0)
+       if (ret)
                goto out;
 
        DEBUG("Selected image %d", image);
 
        imd = wim_get_current_image_metadata(wim);
 
-       if (imd->root_dentry->refcnt != 1) {
+       if (imd->refcnt != 1) {
                ERROR("Cannot mount image that was just exported with "
                      "wimlib_export_image()");
                ret = WIMLIB_ERR_INVALID_PARAM;
                goto out;
        }
 
-       if (imd->inode_list.first) /* May be unneeded? */
-               imd->inode_list.first->pprev = &imd->inode_list.first;
-
        if (imd->modified) {
                ERROR("Cannot mount image that was added "
                      "with wimlib_add_image()");
@@ -2544,7 +2473,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
 
        if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
                ret = lock_wim(wim, wim->fp);
-               if (ret != 0)
+               if (ret)
                        goto out;
        }
 
@@ -2554,7 +2483,6 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
                       WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)))
                mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
 
-
        DEBUG("Initializing struct wimfs_context");
        init_wimfs_context(&ctx);
        ctx.wim = wim;
@@ -2562,12 +2490,14 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        ctx.image_inode_list = &imd->inode_list;
        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;
 
        DEBUG("Unlinking message queues in case they already exist");
        ret = set_message_queue_names(&ctx, dir);
-       if (ret != 0)
+       if (ret)
                goto out_unlock;
        unlink_message_queues(&ctx);
 
@@ -2605,7 +2535,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        if ((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)) {
                /* Read-write mount.  Make the staging directory */
                ret = make_staging_dir(&ctx, staging_dir);
-               if (ret != 0)
+               if (ret)
                        goto out_free_dir_copy;
        } else {
                /* Read-only mount */
@@ -2638,7 +2568,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
         * assign inode numbers */
        DEBUG("Resolving lookup table entries and assigning inode numbers");
        ctx.next_ino = 1;
-       hlist_for_each_entry(inode, cur_node, &imd->inode_list, i_hlist) {
+       image_for_each_inode(inode, imd) {
                inode_resolve_ltes(inode, wim->lookup_table);
                inode->i_ino = ctx.next_ino++;
        }