]> wimlib.net Git - wimlib/blobdiff - programs/imagex.c
wimlib-imagex: fix recommendation to read PDF documentation
[wimlib] / programs / imagex.c
index 48e7d31a0a20c573836a433dc50ceb7972c68165..f149d642302525ba672e89f1811d5c1aceac60a7 100644 (file)
@@ -6,7 +6,7 @@
  */
 
 /*
- * Copyright (C) 2012-2016 Eric Biggers
+ * Copyright (C) 2012-2017 Eric Biggers
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -131,7 +131,7 @@ enum {
 static void usage(int cmd, FILE *fp);
 static void usage_all(FILE *fp);
 static void recommend_man_page(int cmd, FILE *fp);
-static const tchar *get_cmd_string(int cmd, bool nospace);
+static const tchar *get_cmd_string(int cmd, bool only_short_form);
 
 static bool imagex_be_quiet = false;
 static FILE *imagex_info_file;
@@ -331,6 +331,7 @@ static const struct option join_options[] = {
        {NULL, 0, NULL, 0},
 };
 
+#if WIM_MOUNTING_SUPPORTED
 static const struct option mount_options[] = {
        {T("check"),             no_argument,       NULL, IMAGEX_CHECK_OPTION},
        {T("debug"),             no_argument,       NULL, IMAGEX_DEBUG_OPTION},
@@ -341,6 +342,7 @@ static const struct option mount_options[] = {
        {T("allow-other"),       no_argument,       NULL, IMAGEX_ALLOW_OTHER_OPTION},
        {NULL, 0, NULL, 0},
 };
+#endif
 
 static const struct option optimize_options[] = {
        {T("check"),       no_argument,       NULL, IMAGEX_CHECK_OPTION},
@@ -365,6 +367,7 @@ static const struct option split_options[] = {
        {NULL, 0, NULL, 0},
 };
 
+#if WIM_MOUNTING_SUPPORTED
 static const struct option unmount_options[] = {
        {T("commit"),  no_argument, NULL, IMAGEX_COMMIT_OPTION},
        {T("check"),   no_argument, NULL, IMAGEX_CHECK_OPTION},
@@ -374,6 +377,7 @@ static const struct option unmount_options[] = {
        {T("new-image"), no_argument, NULL, IMAGEX_NEW_IMAGE_OPTION},
        {NULL, 0, NULL, 0},
 };
+#endif
 
 static const struct option update_options[] = {
        /* Careful: some of the options here set the defaults for update
@@ -486,7 +490,7 @@ verify_image_exists_and_is_single(int image, const tchar *image_name,
 static void
 print_available_compression_types(FILE *fp)
 {
-       static const tchar *s =
+       static const tchar * const s =
        T(
        "Available compression types:\n"
        "\n"
@@ -586,68 +590,68 @@ set_compact_mode(const tchar *arg, int *extract_flags)
 }
 
 
-struct string_set {
+struct string_list {
        tchar **strings;
        unsigned num_strings;
        unsigned num_alloc_strings;
 };
 
-#define STRING_SET_INITIALIZER \
+#define STRING_LIST_INITIALIZER \
        { .strings = NULL, .num_strings = 0, .num_alloc_strings = 0, }
 
-#define STRING_SET(_strings) \
-       struct string_set _strings = STRING_SET_INITIALIZER
+#define STRING_LIST(_strings) \
+       struct string_list _strings = STRING_LIST_INITIALIZER
 
 static int
-string_set_append(struct string_set *set, tchar *glob)
+string_list_append(struct string_list *list, tchar *glob)
 {
-       unsigned num_alloc_strings = set->num_alloc_strings;
+       unsigned num_alloc_strings = list->num_alloc_strings;
 
-       if (set->num_strings == num_alloc_strings) {
+       if (list->num_strings == num_alloc_strings) {
                tchar **new_strings;
 
                num_alloc_strings += 4;
-               new_strings = realloc(set->strings,
-                                     sizeof(set->strings[0]) * num_alloc_strings);
+               new_strings = realloc(list->strings,
+                                     sizeof(list->strings[0]) * num_alloc_strings);
                if (!new_strings) {
                        imagex_error(T("Out of memory!"));
                        return -1;
                }
-               set->strings = new_strings;
-               set->num_alloc_strings = num_alloc_strings;
+               list->strings = new_strings;
+               list->num_alloc_strings = num_alloc_strings;
        }
-       set->strings[set->num_strings++] = glob;
+       list->strings[list->num_strings++] = glob;
        return 0;
 }
 
 static void
-string_set_destroy(struct string_set *set)
+string_list_destroy(struct string_list *list)
 {
-       free(set->strings);
+       free(list->strings);
 }
 
 static int
-wim_reference_globs(WIMStruct *wim, struct string_set *set, int open_flags)
+wim_reference_globs(WIMStruct *wim, struct string_list *list, int open_flags)
 {
-       return wimlib_reference_resource_files(wim, (const tchar **)set->strings,
-                                              set->num_strings,
+       return wimlib_reference_resource_files(wim, (const tchar **)list->strings,
+                                              list->num_strings,
                                               WIMLIB_REF_FLAG_GLOB_ENABLE,
                                               open_flags);
 }
 
 static int
-append_image_property_argument(struct string_set *image_properties)
+append_image_property_argument(struct string_list *image_properties)
 {
        if (!tstrchr(optarg, '=')) {
                imagex_error(T("'--image-property' argument "
                               "must be in the form NAME=VALUE"));
                return -1;
        }
-       return string_set_append(image_properties, optarg);
+       return string_list_append(image_properties, optarg);
 }
 
 static int
-apply_image_properties(struct string_set *image_properties,
+apply_image_properties(struct string_list *image_properties,
                       WIMStruct *wim, int image, bool *any_changes_ret)
 {
        bool any_changes = false;
@@ -683,7 +687,7 @@ apply_image_properties(struct string_set *image_properties,
 static void
 do_resource_not_found_warning(const tchar *wimfile,
                              const struct wimlib_wim_info *info,
-                             const struct string_set *refglobs)
+                             const struct string_list *refglobs)
 {
        if (info->total_parts > 1) {
                if (refglobs->num_strings == 0) {
@@ -1654,7 +1658,7 @@ imagex_apply(int argc, tchar **argv, int cmd)
        const tchar *image_num_or_name = NULL;
        int extract_flags = 0;
 
-       STRING_SET(refglobs);
+       STRING_LIST(refglobs);
 
        for_opt(c, apply_options) {
                switch (c) {
@@ -1665,7 +1669,7 @@ imagex_apply(int argc, tchar **argv, int cmd)
                        /* No longer does anything.  */
                        break;
                case IMAGEX_REF_OPTION:
-                       ret = string_set_append(&refglobs, optarg);
+                       ret = string_list_append(&refglobs, optarg);
                        if (ret)
                                goto out_free_refglobs;
                        break;
@@ -1812,7 +1816,7 @@ imagex_apply(int argc, tchar **argv, int cmd)
 out_wimlib_free:
        wimlib_free(wim);
 out_free_refglobs:
-       string_set_destroy(&refglobs);
+       string_list_destroy(&refglobs);
        return ret;
 
 out_usage:
@@ -1842,10 +1846,10 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        const tchar *wimfile;
        int wim_fd;
        const tchar *name;
-       STRING_SET(image_properties);
+       STRING_LIST(image_properties);
 
        WIMStruct *wim;
-       STRING_SET(base_wimfiles);
+       STRING_LIST(base_wimfiles);
        WIMStruct **base_wims;
 
        WIMStruct *template_wim;
@@ -1914,7 +1918,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                case IMAGEX_FLAGS_OPTION: {
                        tchar *p = alloca((6 + tstrlen(optarg) + 1) * sizeof(tchar));
                        tsprintf(p, T("FLAGS=%"TS), optarg);
-                       ret = string_set_append(&image_properties, p);
+                       ret = string_list_append(&image_properties, p);
                        if (ret)
                                goto out;
                        break;
@@ -1987,7 +1991,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
                                               "valid for capture!"));
                                goto out_usage;
                        }
-                       ret = string_set_append(&base_wimfiles, optarg);
+                       ret = string_list_append(&base_wimfiles, optarg);
                        if (ret)
                                goto out;
                        write_flags |= WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS;
@@ -2111,7 +2115,7 @@ imagex_capture_or_append(int argc, tchar **argv, int cmd)
        if (argc >= 4) {
                tchar *p = alloca((12 + tstrlen(argv[3]) + 1) * sizeof(tchar));
                tsprintf(p, T("DESCRIPTION=%"TS), argv[3]);
-               ret = string_set_append(&image_properties, p);
+               ret = string_list_append(&image_properties, p);
                if (ret)
                        goto out;
        }
@@ -2379,8 +2383,8 @@ out_free_capture_sources:
 out_free_source_list_contents:
        free(source_list_contents);
 out:
-       string_set_destroy(&image_properties);
-       string_set_destroy(&base_wimfiles);
+       string_list_destroy(&image_properties);
+       string_list_destroy(&base_wimfiles);
        return ret;
 
 out_usage:
@@ -2628,6 +2632,7 @@ print_blobs(WIMStruct *wim)
        wimlib_iterate_lookup_table(wim, 0, print_resource, NULL);
 }
 
+#ifndef __WIN32__
 static void
 default_print_security_descriptor(const uint8_t *sd, size_t size)
 {
@@ -2635,11 +2640,29 @@ default_print_security_descriptor(const uint8_t *sd, size_t size)
        print_byte_field(sd, size);
        tputchar(T('\n'));
 }
+#endif
+
+static bool
+is_null_guid(const uint8_t *guid)
+{
+       static const uint8_t null_guid[WIMLIB_GUID_LEN];
+
+       return !memcmp(guid, null_guid, WIMLIB_GUID_LEN);
+}
+
+static void
+print_guid(const tchar *label, const uint8_t *guid)
+{
+       if (is_null_guid(guid))
+               return;
+       tprintf(T("%-20"TS"= 0x"), label);
+       print_byte_field(guid, WIMLIB_GUID_LEN);
+       tputchar(T('\n'));
+}
 
 static void
 print_dentry_detailed(const struct wimlib_dir_entry *dentry)
 {
-
        tprintf(T(
 "----------------------------------------------------------------------------\n"));
        tprintf(T("Full Path           = \"%"TS"\"\n"), dentry->full_path);
@@ -2674,6 +2697,13 @@ print_dentry_detailed(const struct wimlib_dir_entry *dentry)
                        dentry->unix_mode, dentry->unix_rdev);
        }
 
+       if (!is_null_guid(dentry->object_id.object_id)) {
+               print_guid(T("Object ID"), dentry->object_id.object_id);
+               print_guid(T("Birth Volume ID"), dentry->object_id.birth_volume_id);
+               print_guid(T("Birth Object ID"), dentry->object_id.birth_object_id);
+               print_guid(T("Domain ID"), dentry->object_id.domain_id);
+       }
+
        for (uint32_t i = 0; i <= dentry->num_named_streams; i++) {
                if (dentry->streams[i].stream_name) {
                        tprintf(T("\tNamed data stream \"%"TS"\":\n"),
@@ -2715,7 +2745,7 @@ imagex_dir(int argc, tchar **argv, int cmd)
        };
        int iterate_flags = WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE;
 
-       STRING_SET(refglobs);
+       STRING_LIST(refglobs);
 
        for_opt(c, dir_options) {
                switch (c) {
@@ -2729,7 +2759,7 @@ imagex_dir(int argc, tchar **argv, int cmd)
                        iterate_flags &= ~WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE;
                        break;
                case IMAGEX_REF_OPTION:
-                       ret = string_set_append(&refglobs, optarg);
+                       ret = string_list_append(&refglobs, optarg);
                        if (ret)
                                goto out_free_refglobs;
                        break;
@@ -2794,7 +2824,7 @@ imagex_dir(int argc, tchar **argv, int cmd)
 out_wimlib_free:
        wimlib_free(wim);
 out_free_refglobs:
-       string_set_destroy(&refglobs);
+       string_list_destroy(&refglobs);
        return ret;
 
 out_usage:
@@ -2826,7 +2856,7 @@ imagex_export(int argc, tchar **argv, int cmd)
        int image;
        struct stat stbuf;
        bool wim_is_new;
-       STRING_SET(refglobs);
+       STRING_LIST(refglobs);
        unsigned num_threads = 0;
        uint32_t chunk_size = UINT32_MAX;
        uint32_t solid_chunk_size = UINT32_MAX;
@@ -2874,7 +2904,7 @@ imagex_export(int argc, tchar **argv, int cmd)
                                goto out_err;
                        break;
                case IMAGEX_REF_OPTION:
-                       ret = string_set_append(&refglobs, optarg);
+                       ret = string_list_append(&refglobs, optarg);
                        if (ret)
                                goto out_free_refglobs;
                        break;
@@ -2946,9 +2976,9 @@ imagex_export(int argc, tchar **argv, int cmd)
                wim_is_new = false;
                /* Destination file exists. */
 
-               if (!S_ISREG(stbuf.st_mode)) {
-                       imagex_error(T("\"%"TS"\" is not a regular file"),
-                                    dest_wimfile);
+               if (!S_ISREG(stbuf.st_mode) && !S_ISBLK(stbuf.st_mode)) {
+                       imagex_error(T("\"%"TS"\" is not a regular file "
+                                      "or block device"), dest_wimfile);
                        ret = -1;
                        goto out_free_src_wim;
                }
@@ -3091,7 +3121,7 @@ out_free_dest_wim:
 out_free_src_wim:
        wimlib_free(src_wim);
 out_free_refglobs:
-       string_set_destroy(&refglobs);
+       string_list_destroy(&refglobs);
        return ret;
 
 out_usage:
@@ -3118,7 +3148,7 @@ imagex_extract(int argc, tchar **argv, int cmd)
                            WIMLIB_EXTRACT_FLAG_STRICT_GLOB;
        int notlist_extract_flags = WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE;
 
-       STRING_SET(refglobs);
+       STRING_LIST(refglobs);
 
        tchar *root_path = WIMLIB_WIM_ROOT_PATH;
 
@@ -3131,7 +3161,7 @@ imagex_extract(int argc, tchar **argv, int cmd)
                        /* No longer does anything.  */
                        break;
                case IMAGEX_REF_OPTION:
-                       ret = string_set_append(&refglobs, optarg);
+                       ret = string_list_append(&refglobs, optarg);
                        if (ret)
                                goto out_free_refglobs;
                        break;
@@ -3279,7 +3309,7 @@ imagex_extract(int argc, tchar **argv, int cmd)
 out_wimlib_free:
        wimlib_free(wim);
 out_free_refglobs:
-       string_set_destroy(&refglobs);
+       string_list_destroy(&refglobs);
        return ret;
 
 out_usage:
@@ -3305,7 +3335,7 @@ imagex_info(int argc, tchar **argv, int cmd)
        const tchar *xml_out_file = NULL;
        const tchar *wimfile;
        const tchar *image_num_or_name;
-       STRING_SET(image_properties);
+       STRING_LIST(image_properties);
        WIMStruct *wim;
        int image;
        int ret;
@@ -3361,7 +3391,7 @@ imagex_info(int argc, tchar **argv, int cmd)
                /* NEW_NAME */
                tchar *p = alloca((5 + tstrlen(argv[2]) + 1) * sizeof(tchar));
                tsprintf(p, T("NAME=%"TS), argv[2]);
-               ret = string_set_append(&image_properties, p);
+               ret = string_list_append(&image_properties, p);
                if (ret)
                        goto out;
        }
@@ -3370,7 +3400,7 @@ imagex_info(int argc, tchar **argv, int cmd)
                /* NEW_DESC */
                tchar *p = alloca((12 + tstrlen(argv[3]) + 1) * sizeof(tchar));
                tsprintf(p, T("DESCRIPTION=%"TS), argv[3]);
-               ret = string_set_append(&image_properties, p);
+               ret = string_list_append(&image_properties, p);
                if (ret)
                        goto out;
        }
@@ -3540,7 +3570,7 @@ imagex_info(int argc, tchar **argv, int cmd)
 out_wimlib_free:
        wimlib_free(wim);
 out:
-       string_set_destroy(&image_properties);
+       string_list_destroy(&image_properties);
        return ret;
 
 out_usage:
@@ -3612,7 +3642,7 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
        int image;
        int ret;
 
-       STRING_SET(refglobs);
+       STRING_LIST(refglobs);
 
        if (cmd == CMD_MOUNTRW) {
                mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
@@ -3644,7 +3674,7 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
                        }
                        break;
                case IMAGEX_REF_OPTION:
-                       ret = string_set_append(&refglobs, optarg);
+                       ret = string_list_append(&refglobs, optarg);
                        if (ret)
                                goto out_free_refglobs;
                        break;
@@ -3712,7 +3742,7 @@ imagex_mount_rw_or_ro(int argc, tchar **argv, int cmd)
 out_free_wim:
        wimlib_free(wim);
 out_free_refglobs:
-       string_set_destroy(&refglobs);
+       string_list_destroy(&refglobs);
        return ret;
 
 out_usage:
@@ -4231,13 +4261,13 @@ imagex_verify(int argc, tchar **argv, int cmd)
        WIMStruct *wim;
        int open_flags = WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
        int verify_flags = 0;
-       STRING_SET(refglobs);
+       STRING_LIST(refglobs);
        int c;
 
        for_opt(c, verify_options) {
                switch (c) {
                case IMAGEX_REF_OPTION:
-                       ret = string_set_append(&refglobs, optarg);
+                       ret = string_list_append(&refglobs, optarg);
                        if (ret)
                                goto out_free_refglobs;
                        break;
@@ -4293,7 +4323,7 @@ imagex_verify(int argc, tchar **argv, int cmd)
 out_wimlib_free:
        wimlib_free(wim);
 out_free_refglobs:
-       string_set_destroy(&refglobs);
+       string_list_destroy(&refglobs);
        return ret;
 
 out_usage:
@@ -4348,7 +4378,7 @@ static const struct imagex_command imagex_commands[] = {
 
 #endif
 
-static const tchar *usage_strings[] = {
+static const tchar * const usage_strings[] = {
 [CMD_APPEND] =
 T(
 "    %"TS" " SOURCE_STR " WIMFILE [IMAGE_NAME [IMAGE_DESC]]\n"
@@ -4459,21 +4489,18 @@ T(
 static const tchar *invocation_name;
 static int invocation_cmd = CMD_NONE;
 
-static const tchar *get_cmd_string(int cmd, bool nospace)
+static const tchar *get_cmd_string(int cmd, bool only_short_form)
 {
        static tchar buf[50];
-       if (cmd == CMD_NONE) {
+
+       if (cmd == CMD_NONE)
                return T("wimlib-imagex");
-       } else if (invocation_cmd != CMD_NONE) {
+
+       if (only_short_form || invocation_cmd != CMD_NONE) {
                tsprintf(buf, T("wim%"TS), imagex_commands[cmd].name);
        } else {
-               const tchar *format;
-
-               if (nospace)
-                       format = T("%"TS"-%"TS"");
-               else
-                       format = T("%"TS" %"TS"");
-               tsprintf(buf, format, invocation_name, imagex_commands[cmd].name);
+               tsprintf(buf, T("%"TS" %"TS), invocation_name,
+                        imagex_commands[cmd].name);
        }
        return buf;
 }
@@ -4481,10 +4508,10 @@ static const tchar *get_cmd_string(int cmd, bool nospace)
 static void
 version(void)
 {
-       static const tchar *s =
+       static const tchar * const s =
        T(
 "wimlib-imagex (distributed with " PACKAGE " " PACKAGE_VERSION ")\n"
-"Copyright (C) 2012-2016 Eric Biggers\n"
+"Copyright (C) 2012-2017 Eric Biggers\n"
 "License GPLv3+; GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
 "This is free software: you are free to change and redistribute it.\n"
 "There is NO WARRANTY, to the extent permitted by law.\n"
@@ -4533,8 +4560,7 @@ recommend_man_page(int cmd, FILE *fp)
        format_str = T("Some uncommon options are not listed;\n"
                       "See %"TS".pdf in the doc directory for more details.\n");
 #else
-       format_str = T("Some uncommon options are not listed;\n"
-                      "Try `man %"TS"' for more details.\n");
+       format_str = T("Some uncommon options are not listed; see `man %"TS"' for more details.\n");
 #endif
        tfprintf(fp, format_str, get_cmd_string(cmd, true));
 }
@@ -4556,7 +4582,7 @@ usage_all(FILE *fp)
                print_usage_string(cmd, fp);
                tfprintf(fp, T("\n"));
        }
-       static const tchar *extra =
+       static const tchar * const extra =
        T(
 "    %"TS" --help\n"
 "    %"TS" --version\n"
@@ -4571,16 +4597,17 @@ usage_all(FILE *fp)
        recommend_man_page(CMD_NONE, fp);
 }
 
+#ifdef __WIN32__
+extern int wmain(int argc, wchar_t **argv);
+#define main wmain
+#endif
+
 /* Entry point for wimlib's ImageX implementation.  On UNIX the command
  * arguments will just be 'char' strings (ideally UTF-8 encoded, but could be
  * something else), while on Windows the command arguments will be UTF-16LE
  * encoded 'wchar_t' strings. */
 int
-#ifdef __WIN32__
-wmain(int argc, wchar_t **argv, wchar_t **envp)
-#else
-main(int argc, char **argv)
-#endif
+main(int argc, tchar **argv)
 {
        int ret;
        int init_flags = 0;
@@ -4589,31 +4616,6 @@ main(int argc, char **argv)
        imagex_info_file = stdout;
        invocation_name = tbasename(argv[0]);
 
-#ifndef __WIN32__
-       if (getenv("WIMLIB_IMAGEX_USE_UTF8")) {
-               init_flags |= WIMLIB_INIT_FLAG_ASSUME_UTF8;
-       } else {
-               char *codeset;
-
-               setlocale(LC_ALL, "");
-               codeset = nl_langinfo(CODESET);
-               if (!strstr(codeset, "UTF-8") &&
-                   !strstr(codeset, "UTF8") &&
-                   !strstr(codeset, "utf-8") &&
-                   !strstr(codeset, "utf8"))
-               {
-                       fprintf(stderr,
-"WARNING: Running %"TS" in a UTF-8 locale is recommended!\n"
-"         Maybe try: `export LANG=en_US.UTF-8'?\n"
-"         Alternatively, set the environmental variable WIMLIB_IMAGEX_USE_UTF8\n"
-"         to any value to force wimlib to use UTF-8.\n",
-                       invocation_name);
-
-               }
-       }
-
-#endif /* !__WIN32__ */
-
        {
                tchar *igcase = tgetenv(T("WIMLIB_IMAGEX_IGNORE_CASE"));
                if (igcase != NULL) {