]> wimlib.net Git - wimlib/blobdiff - src/write.c
Initial imagex_update functionality
[wimlib] / src / write.c
index 9965f5c06bf2d21f853bb6d1bfedda0cbf3d98a3..d24362bb746ac441883961bf0d7c169750381c23 100644 (file)
@@ -48,6 +48,7 @@
 #endif
 
 #include <unistd.h>
+#include <fcntl.h>
 #include <errno.h>
 
 #ifdef WITH_NTFS_3G
@@ -65,7 +66,9 @@
 
 #include <limits.h>
 
-#include <sys/uio.h> /* writev() */
+#ifndef __WIN32__
+#  include <sys/uio.h> /* for `struct iovec' */
+#endif
 
 /* Chunk table that's located at the beginning of each compressed resource in
  * the WIM.  (This is not the on-disk format; the on-disk format just has an
@@ -164,7 +167,7 @@ get_compress_func(int out_ctype)
  *
  * @chunk:       Uncompressed data of the chunk.
  * @chunk_size:          Size of the chunk (<= WIM_CHUNK_SIZE)
- * @out_fd:      FILE descriptor to write the chunk to.
+ * @out_fd:      File descriptor to write the chunk to.
  * @compress:     Compression function to use (NULL if writing uncompressed
  *                     data).
  * @chunk_tab:   Pointer to chunk table being created.  It is updated with the
@@ -175,7 +178,7 @@ get_compress_func(int out_ctype)
 static int
 write_wim_resource_chunk(const void * restrict chunk,
                         unsigned chunk_size,
-                        filedes_t out_fd,
+                        int out_fd,
                         compress_func_t compress,
                         struct chunk_table * restrict chunk_tab)
 {
@@ -216,7 +219,7 @@ write_wim_resource_chunk(const void * restrict chunk,
  */
 static int
 finish_wim_resource_chunk_tab(struct chunk_table *chunk_tab,
-                             filedes_t out_fd, u64 *compressed_size_p)
+                             int out_fd, u64 *compressed_size_p)
 {
        size_t bytes_written;
 
@@ -241,7 +244,7 @@ finish_wim_resource_chunk_tab(struct chunk_table *chunk_tab,
 }
 
 static int
-seek_and_truncate(filedes_t out_fd, off_t offset)
+seek_and_truncate(int out_fd, off_t offset)
 {
        if (lseek(out_fd, offset, SEEK_SET) == -1 ||
            ftruncate(out_fd, offset))
@@ -277,7 +280,7 @@ finalize_and_check_sha1(SHA_CTX * restrict sha_ctx,
 struct write_resource_ctx {
        compress_func_t compress;
        struct chunk_table *chunk_tab;
-       filedes_t out_fd;
+       int out_fd;
        SHA_CTX sha_ctx;
        bool doing_sha;
 };
@@ -301,7 +304,7 @@ write_resource_cb(const void *restrict chunk, size_t chunk_size,
  * @lte:  Lookup table entry for the resource, which could be in another WIM,
  *        in an external file, or in another location.
  *
- * @out_fp:  File descriptor opened to the output WIM.
+ * @out_fd:  File descriptor opened to the output WIM.
  *
  * @out_ctype:  One of the WIMLIB_COMPRESSION_TYPE_* constants to indicate
  *              which compression algorithm to use.
@@ -321,7 +324,7 @@ write_resource_cb(const void *restrict chunk, size_t chunk_size,
  */
 int
 write_wim_resource(struct wim_lookup_table_entry *lte,
-                  filedes_t out_fd, int out_ctype,
+                  int out_fd, int out_ctype,
                   struct resource_entry *out_res_entry,
                   int flags)
 {
@@ -596,9 +599,19 @@ compressor_thread_proc(void *arg)
 static void
 do_write_streams_progress(union wimlib_progress_info *progress,
                          wimlib_progress_func_t progress_func,
-                         uint64_t size_added)
+                         uint64_t size_added,
+                         bool stream_discarded)
 {
-       progress->write_streams.completed_bytes += size_added;
+       if (stream_discarded) {
+               progress->write_streams.total_bytes -= size_added;
+               if (progress->write_streams._private != ~(uint64_t)0 &&
+                   progress->write_streams._private > progress->write_streams.total_bytes)
+               {
+                       progress->write_streams._private = progress->write_streams.total_bytes;
+               }
+       } else {
+               progress->write_streams.completed_bytes += size_added;
+       }
        progress->write_streams.completed_streams++;
        if (progress_func &&
            progress->write_streams.completed_bytes >= progress->write_streams._private)
@@ -606,7 +619,7 @@ do_write_streams_progress(union wimlib_progress_info *progress,
                progress_func(WIMLIB_PROGRESS_MSG_WRITE_STREAMS,
                              progress);
                if (progress->write_streams._private == progress->write_streams.total_bytes) {
-                       progress->write_streams._private = ~0;
+                       progress->write_streams._private = ~(uint64_t)0;
                } else {
                        progress->write_streams._private =
                                min(progress->write_streams.total_bytes,
@@ -617,7 +630,7 @@ do_write_streams_progress(union wimlib_progress_info *progress,
 }
 
 struct serial_write_stream_ctx {
-       filedes_t out_fd;
+       int out_fd;
        int out_ctype;
        int write_resource_flags;
 };
@@ -645,9 +658,11 @@ do_write_stream_list(struct list_head *stream_list,
 {
        int ret = 0;
        struct wim_lookup_table_entry *lte;
+       bool stream_discarded;
 
        /* For each stream in @stream_list ... */
        while (!list_empty(stream_list)) {
+               stream_discarded = false;
                lte = container_of(stream_list->next,
                                   struct wim_lookup_table_entry,
                                   write_streams_list);
@@ -672,6 +687,7 @@ do_write_stream_list(struct list_head *stream_list,
                                        DEBUG("Discarding duplicate stream of length %"PRIu64,
                                              wim_resource_size(lte));
                                        lte->no_progress = 0;
+                                       stream_discarded = true;
                                        goto skip_to_progress;
                                }
                        }
@@ -703,7 +719,8 @@ do_write_stream_list(struct list_head *stream_list,
                if (!lte->no_progress) {
                        do_write_streams_progress(progress,
                                                  progress_func,
-                                                 wim_resource_size(lte));
+                                                 wim_resource_size(lte),
+                                                 stream_discarded);
                }
        }
        return ret;
@@ -712,7 +729,7 @@ do_write_stream_list(struct list_head *stream_list,
 static int
 do_write_stream_list_serial(struct list_head *stream_list,
                            struct wim_lookup_table *lookup_table,
-                           filedes_t out_fd,
+                           int out_fd,
                            int out_ctype,
                            int write_resource_flags,
                            wimlib_progress_func_t progress_func,
@@ -744,7 +761,7 @@ write_flags_to_resource_flags(int write_flags)
 static int
 write_stream_list_serial(struct list_head *stream_list,
                         struct wim_lookup_table *lookup_table,
-                        filedes_t out_fd,
+                        int out_fd,
                         int out_ctype,
                         int write_resource_flags,
                         wimlib_progress_func_t progress_func,
@@ -765,59 +782,26 @@ write_stream_list_serial(struct list_head *stream_list,
 
 #ifdef ENABLE_MULTITHREADED_COMPRESSION
 static int
-write_wim_chunks(struct message *msg, filedes_t out_fd,
+write_wim_chunks(struct message *msg, int out_fd,
                 struct chunk_table *chunk_tab)
 {
-       ssize_t bytes_remaining = msg->total_out_bytes;
-       struct iovec *vecs = msg->out_chunks;
-       unsigned nvecs = msg->num_chunks;
-       int ret;
-
-       wimlib_assert(nvecs != 0);
-       wimlib_assert(msg->total_out_bytes != 0);
-
        for (unsigned i = 0; i < msg->num_chunks; i++) {
                *chunk_tab->cur_offset_p++ = chunk_tab->cur_offset;
-               chunk_tab->cur_offset += vecs[i].iov_len;
-       }
-       for (;;) {
-               ssize_t bytes_written;
-
-               bytes_written = writev(out_fd, vecs, nvecs);
-               if (bytes_written <= 0) {
-                       if (bytes_written < 0 && errno == EINTR)
-                               continue;
-                       else if (bytes_written == 0)
-                               errno = EIO;
-                       ERROR_WITH_ERRNO("Failed to write WIM chunks");
-                       ret = WIMLIB_ERR_WRITE;
-                       break;
-               }
-               bytes_remaining -= bytes_written;
-               if (bytes_remaining <= 0) {
-                       ret = 0;
-                       break;
-               }
-               while (bytes_written >= 0) {
-                       wimlib_assert(nvecs != 0);
-                       if (bytes_written >= vecs[0].iov_len) {
-                               vecs++;
-                               nvecs--;
-                               bytes_written -= vecs[0].iov_len;
-                       } else {
-                               vecs[0].iov_base += bytes_written;
-                               vecs[0].iov_len -= bytes_written;
-                               bytes_written = 0;
-                       }
-               }
+               chunk_tab->cur_offset += msg->out_chunks[i].iov_len;
        }
-       return ret;
+       if (full_writev(out_fd, msg->out_chunks,
+                       msg->num_chunks) != msg->total_out_bytes)
+       {
+               ERROR_WITH_ERRNO("Failed to write WIM chunks");
+               return WIMLIB_ERR_WRITE;
+       }
+       return 0;
 }
 
 struct main_writer_thread_ctx {
        struct list_head *stream_list;
        struct wim_lookup_table *lookup_table;
-       filedes_t out_fd;
+       int out_fd;
        int out_ctype;
        int write_resource_flags;
        struct shared_queue *res_to_compress_queue;
@@ -1046,7 +1030,8 @@ receive_compressed_chunks(struct main_writer_thread_ctx *ctx)
 
                        do_write_streams_progress(ctx->progress,
                                                  ctx->progress_func,
-                                                 wim_resource_size(cur_lte));
+                                                 wim_resource_size(cur_lte),
+                                                 false);
 
                        /* Since we just finished writing a stream, write any
                         * streams that have been added to the serial_streams
@@ -1253,7 +1238,7 @@ get_default_num_threads()
 static int
 write_stream_list_parallel(struct list_head *stream_list,
                           struct wim_lookup_table *lookup_table,
-                          filedes_t out_fd,
+                          int out_fd,
                           int out_ctype,
                           int write_resource_flags,
                           wimlib_progress_func_t progress_func,
@@ -1391,7 +1376,7 @@ out_serial_quiet:
 static int
 write_stream_list(struct list_head *stream_list,
                  struct wim_lookup_table *lookup_table,
-                 filedes_t out_fd, int out_ctype, int write_flags,
+                 int out_fd, int out_ctype, int write_flags,
                  unsigned num_threads, wimlib_progress_func_t progress_func)
 {
        struct wim_lookup_table_entry *lte;
@@ -1688,7 +1673,7 @@ prepare_stream_list(WIMStruct *wim, int image, struct list_head *stream_list)
        return ret;
 }
 
-/* Writes the streams for the specified @image in @wim to @wim->out_fp.
+/* Writes the streams for the specified @image in @wim to @wim->out_fd.
  */
 static int
 write_wim_streams(WIMStruct *wim, int image, int write_flags,
@@ -1719,9 +1704,6 @@ write_wim_streams(WIMStruct *wim, int image, int write_flags,
  *     (public)  WIMLIB_WRITE_FLAG_CHECK_INTEGRITY:
  *             Include an integrity table.
  *
- *     (public)  WIMLIB_WRITE_FLAG_SHOW_PROGRESS:
- *             Show progress information when (if) writing the integrity table.
- *
  *     (private) WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE:
  *             Don't write the lookup table.
  *
@@ -1835,16 +1817,16 @@ out_close_wim:
                if (ret == 0)
                        ret = WIMLIB_ERR_WRITE;
        }
-       w->out_fd = INVALID_FILEDES;
+       w->out_fd = -1;
        return ret;
 }
 
 #if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK)
 int
-lock_wim(WIMStruct *w, filedes_t fd)
+lock_wim(WIMStruct *w, int fd)
 {
        int ret = 0;
-       if (fd != INVALID_FILEDES && !w->wim_locked) {
+       if (fd != -1 && !w->wim_locked) {
                ret = flock(fd, LOCK_EX | LOCK_NB);
                if (ret != 0) {
                        if (errno == EWOULDBLOCK) {
@@ -1868,9 +1850,8 @@ lock_wim(WIMStruct *w, filedes_t fd)
 static int
 open_wim_writable(WIMStruct *w, const tchar *path, int open_flags)
 {
-       wimlib_assert(w->out_fd == INVALID_FILEDES);
-       w->out_fd = open(path, open_flags, 0644);
-       if (w->out_fd == INVALID_FILEDES) {
+       w->out_fd = topen(path, open_flags | O_BINARY, 0644);
+       if (w->out_fd == -1) {
                ERROR_WITH_ERRNO("Failed to open `%"TS"' for writing", path);
                return WIMLIB_ERR_OPEN;
        }
@@ -1881,10 +1862,10 @@ open_wim_writable(WIMStruct *w, const tchar *path, int open_flags)
 void
 close_wim_writable(WIMStruct *w)
 {
-       if (w->out_fd != INVALID_FILEDES) {
+       if (w->out_fd != -1) {
                if (close(w->out_fd))
                        WARNING_WITH_ERRNO("Failed to close output WIM");
-               w->out_fd = INVALID_FILEDES;
+               w->out_fd = -1;
        }
 }
 
@@ -1905,8 +1886,8 @@ begin_write(WIMStruct *w, const tchar *path, int write_flags)
        ret = write_header(&w->hdr, w->out_fd);
        if (ret)
                return ret;
-       if (lseek(w->out_fd, 0, SEEK_END) == -1) {
-               ERROR_WITH_ERRNO("Failed to seek to end of WIM");
+       if (lseek(w->out_fd, WIM_HEADER_DISK_SIZE, SEEK_SET) == -1) {
+               ERROR_WITH_ERRNO("Failed to seek to end of WIM header");
                return WIMLIB_ERR_WRITE;
        }
        return 0;
@@ -2173,19 +2154,9 @@ overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags,
                goto out_unlink;
        }
 
-       DEBUG("Renaming `%"TS"' to `%"TS"'", tmpfile, w->filename);
-
-#ifdef __WIN32__
-       /* Windows won't let you delete open files unless FILE_SHARE_DELETE was
-        * specified to CreateFile().  The WIM was opened with fopen(), which
-        * didn't provided this flag to CreateFile, so the handle must be closed
-        * before executing the rename(). */
-       if (w->fp != NULL) {
-               fclose(w->fp);
-               w->fp = NULL;
-       }
-#endif
+       close_wim(w);
 
+       DEBUG("Renaming `%"TS"' to `%"TS"'", tmpfile, w->filename);
        /* Rename the new file to the old file .*/
        if (trename(tmpfile, w->filename) != 0) {
                ERROR_WITH_ERRNO("Failed to rename `%"TS"' to `%"TS"'",