]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
Implement soft delete
[wimlib] / programs / imagex.c
index 2ba1a076795e326cbad4ceaa6103937e9b211c55..d047130b20b395983283ce21b5619448954734da 100644 (file)
@@ -34,6 +34,7 @@
 #include <limits.h>
 #include <sys/stat.h>
 #include <unistd.h>
+#include <inttypes.h>
 
 #define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
 
@@ -52,6 +53,7 @@ enum imagex_op_type {
        JOIN,
        MOUNT,
        MOUNTRW,
+       OPTIMIZE,
        SPLIT,
        UNMOUNT,
 };
@@ -64,7 +66,7 @@ static const char *usage_strings[] = {
 "imagex append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
 "                     [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n"
 "                     [--verbose] [--dereference] [--config=FILE]\n"
-"                     [--threads=NUM_THREADS]\n",
+"                     [--threads=NUM_THREADS] [--rebuild]\n",
 [APPLY] =
 "imagex apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n"
 "                    (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n"
@@ -75,14 +77,14 @@ static const char *usage_strings[] = {
 "                      [--flags EDITION_ID] [--verbose] [--dereference]\n"
 "                      [--config=FILE] [--threads=NUM_THREADS]\n",
 [DELETE] =
-"imagex delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check]\n",
+"imagex delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n",
 [DIR] =
 "imagex dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n",
 [EXPORT] =
 "imagex export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n"
 "              DEST_WIMFILE [DEST_IMAGE_NAME] [DEST_IMAGE_DESCRIPTION]\n"
 "              [--boot] [--check] [--compress=TYPE] [--ref=\"GLOB\"]\n"
-"              [--threads=NUM_THREADS]\n",
+"              [--threads=NUM_THREADS] [--rebuild]\n",
 [INFO] =
 "imagex info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n"
 "                   [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
@@ -96,6 +98,8 @@ static const char *usage_strings[] = {
 [MOUNTRW] =
 "imagex mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n"
 "                      [--check] [--debug] [--streams-interface=INTERFACE]\n",
+[OPTIMIZE] =
+"imagex optimize WIMFILE [--check] [--recompress]\n",
 [SPLIT] =
 "imagex split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n",
 [UNMOUNT] =
@@ -125,10 +129,12 @@ static const struct option capture_or_append_options[] = {
        {"flags",       required_argument, NULL, 'f'},
        {"verbose",     no_argument,       NULL, 'v'},
        {"threads",     required_argument, NULL, 't'},
+       {"rebuild",     no_argument,       NULL, 'R'},
        {NULL, 0, NULL, 0},
 };
 static const struct option delete_options[] = {
        {"check", no_argument, NULL, 'c'},
+       {"soft",  no_argument, NULL, 's'},
        {NULL, 0, NULL, 0},
 };
 
@@ -138,6 +144,7 @@ static const struct option export_options[] = {
        {"compress",   required_argument, NULL, 'x'},
        {"ref",        required_argument, NULL, 'r'},
        {"threads",    required_argument, NULL, 't'},
+       {"rebuild",    no_argument,       NULL, 'R'},
        {NULL, 0, NULL, 0},
 };
 
@@ -165,6 +172,12 @@ static const struct option mount_options[] = {
        {NULL, 0, NULL, 0},
 };
 
+static const struct option optimize_options[] = {
+       {"check",      no_argument, NULL, 'c'},
+       {"recompress", no_argument, NULL, 'r'},
+       {NULL, 0, NULL, 0},
+};
+
 static const struct option split_options[] = {
        {"check", no_argument, NULL, 'c'},
        {NULL, 0, NULL, 0},
@@ -250,6 +263,15 @@ static int get_compression_type(const char *optarg)
        }
 }
 
+static off_t file_get_size(const char *filename)
+{
+       struct stat st;
+       if (stat(filename, &st) == 0)
+               return st.st_size;
+       else
+               return (off_t)-1;
+}
+
 static char *file_get_contents(const char *filename, size_t *len_ret)
 {
        struct stat stbuf;
@@ -542,6 +564,9 @@ static int imagex_capture_or_append(int argc, const char **argv)
                        if (num_threads == UINT_MAX)
                                return -1;
                        break;
+               case 'R':
+                       write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
+                       break;
                default:
                        usage(cmd);
                        return -1;
@@ -623,6 +648,8 @@ out_write:
                ret = wimlib_write(w, wimfile, WIM_ALL_IMAGES, write_flags,
                                   num_threads);
        }
+       if (ret == WIMLIB_ERR_REOPEN)
+               ret = 0;
        if (ret != 0)
                imagex_error("Failed to write the WIM file `%s'", wimfile);
 out:
@@ -649,6 +676,9 @@ static int imagex_delete(int argc, const char **argv)
                        open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
                        write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
                        break;
+               case 's':
+                       write_flags |= WIMLIB_WRITE_FLAG_SOFT_DELETE;
+                       break;
                default:
                        usage(DELETE);
                        return -1;
@@ -689,6 +719,8 @@ static int imagex_delete(int argc, const char **argv)
        }
 
        ret = wimlib_overwrite(w, write_flags, 0);
+       if (ret == WIMLIB_ERR_REOPEN)
+               ret = 0;
        if (ret != 0) {
                imagex_error("Failed to write the file `%s' with image "
                             "deleted", wimfile);
@@ -797,6 +829,9 @@ static int imagex_export(int argc, const char **argv)
                        if (num_threads == UINT_MAX)
                                return -1;
                        break;
+               case 'R':
+                       write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
+                       break;
                default:
                        usage(EXPORT);
                        return -1;
@@ -894,6 +929,8 @@ static int imagex_export(int argc, const char **argv)
        else
                ret = wimlib_overwrite(dest_w, write_flags, num_threads);
 out:
+       if (ret == WIMLIB_ERR_REOPEN)
+               ret = 0;
        wimlib_free(src_w);
        wimlib_free(dest_w);
        if (additional_swms) {
@@ -1139,8 +1176,8 @@ static int imagex_info(int argc, const char **argv)
                        }
                }
 
-               /* Only call wimlib_overwrite_xml_and_header() if something
-                * actually needs to be changed. */
+               /* Only call wimlib_overwrite() if something actually needs to
+                * be changed. */
                if (boot || new_name || new_desc ||
                                check != wimlib_has_integrity_table(w)) {
 
@@ -1148,9 +1185,17 @@ static int imagex_info(int argc, const char **argv)
                        if (ret != 0)
                                return ret;
 
-                       ret = wimlib_overwrite_xml_and_header(w, check ?
-                                       WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
-                                       WIMLIB_WRITE_FLAG_SHOW_PROGRESS : 0);
+                       int write_flags;
+                       if (check) {
+                               write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY |
+                                             WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
+                       } else {
+                               write_flags = 0;
+                       }
+
+                       ret = wimlib_overwrite(w, write_flags, 1);
+                       if (ret == WIMLIB_ERR_REOPEN)
+                               ret = 0;
                } else {
                        printf("The file `%s' was not modified because nothing "
                                        "needed to be done.\n", wimfile);
@@ -1158,7 +1203,7 @@ static int imagex_info(int argc, const char **argv)
                }
        }
 out:
-       /*wimlib_free(w);*/
+       wimlib_free(w);
        return ret;
 }
 
@@ -1306,6 +1351,74 @@ mount_usage:
        return -1;
 }
 
+static int imagex_optimize(int argc, const char **argv)
+{
+       int c;
+       int open_flags = WIMLIB_OPEN_FLAG_SHOW_PROGRESS;
+       int write_flags = WIMLIB_WRITE_FLAG_REBUILD |
+                         WIMLIB_WRITE_FLAG_SHOW_PROGRESS;
+       int ret;
+       WIMStruct *w;
+       const char *wimfile;
+       off_t old_size;
+       off_t new_size;
+
+       for_opt(c, optimize_options) {
+               switch (c) {
+               case 'c':
+                       open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
+                       write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
+                       break;
+               case 'r':
+                       write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
+                       break;
+               default:
+                       usage(OPTIMIZE);
+                       return -1;
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (argc != 1) {
+               usage(OPTIMIZE);
+               return -1;
+       }
+
+       wimfile = argv[0];
+
+       ret = wimlib_open_wim(wimfile, open_flags, &w);
+       if (ret != 0)
+               return ret;
+
+       old_size = file_get_size(argv[0]);
+       printf("`%s' original size: ", wimfile);
+       if (old_size == -1)
+               puts("Unknown");
+       else
+               printf("%"PRIu64" KiB\n", old_size >> 10);
+
+       ret = wimlib_overwrite(w, write_flags, 0);
+
+       new_size = file_get_size(argv[0]);
+       printf("`%s' optimized size: ", wimfile);
+       if (new_size == -1)
+               puts("Unknown");
+       else
+               printf("%"PRIu64" KiB\n", new_size >> 10);
+
+       fputs("Space saved: ", stdout);
+       if (new_size != -1 && old_size != -1) {
+               printf("%lld KiB\n",
+                      ((long long)old_size - (long long)new_size) >> 10);
+       } else {
+               puts("Unknown");
+       }
+
+       wimlib_free(w);
+       return ret;
+}
+
 /* Split a WIM into a spanned set */
 static int imagex_split(int argc, const char **argv)
 {
@@ -1394,6 +1507,7 @@ static const struct imagex_command imagex_commands[] = {
        {"join",    imagex_join,              JOIN},
        {"mount",   imagex_mount_rw_or_ro,    MOUNT},
        {"mountrw", imagex_mount_rw_or_ro,    MOUNTRW},
+       {"optimize",imagex_optimize,          OPTIMIZE},
        {"split",   imagex_split,             SPLIT},
        {"unmount", imagex_unmount,           UNMOUNT},
 };
@@ -1459,7 +1573,7 @@ static void usage_all()
 {
        puts("IMAGEX: Usage:");
        for (int i = 0; i < ARRAY_LEN(usage_strings); i++)
-               fputs(usage_strings[i], stdout);
+               printf("    %s", usage_strings[i]);
        static const char *extra =
 "    imagex --help\n"
 "    imagex --version\n"