Rev 12 | Rev 15 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 12 | Rev 14 | ||
---|---|---|---|
Line 18... | Line 18... | ||
18 | 18 | ||
19 | 19 | ||
20 | // compiler-specific glue |
20 | // compiler-specific glue |
21 | #ifdef _MSC_VER |
21 | #ifdef _MSC_VER |
22 | #include <io.h> |
22 | #include <io.h> |
- | 23 | #include <direct.h> |
|
- | 24 | #include <sys/utime.h> |
|
23 | #define __x86_64__ 1 |
25 | #define __x86_64__ 1 |
24 | #define __ORDER_BIG_ENDIAN__ 4321 |
26 | #define __ORDER_BIG_ENDIAN__ 4321 |
25 | #define __ORDER_LITTLE_ENDIAN__ 1234 |
27 | #define __ORDER_LITTLE_ENDIAN__ 1234 |
26 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
28 | #define __BYTE_ORDER__ __ORDER_LITTLE_ENDIAN__ |
27 | #define __attribute__(x) |
29 | #define __attribute__(x) |
Line 35... | Line 37... | ||
35 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) |
37 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) |
36 | #define strdup(s) _strdup ((s)) |
38 | #define strdup(s) _strdup ((s)) |
37 | #define strcasecmp(s1,s2) _stricmp ((s1), (s2)) |
39 | #define strcasecmp(s1,s2) _stricmp ((s1), (s2)) |
38 | #define fseek(fp,off,m) _fseeki64 ((fp), (off), (m)) |
40 | #define fseek(fp,off,m) _fseeki64 ((fp), (off), (m)) |
39 | #define access(p,m) _access ((p), (m)) |
41 | #define access(p,m) _access ((p), (m)) |
- | 42 | #define mkdir(p,m) _mkdir ((p)) |
|
- | 43 | #define chmod(p,m) _chmod ((p), (m)) |
|
- | 44 | #define utimbuf __utimbuf32 |
|
- | 45 | #define utime(p,t) _utime32 ((p), (t)) |
|
40 | #define MAXPATHLEN 1024 |
46 | #define MAXPATHLEN 1024 |
41 | #ifndef thread_local |
47 | #ifndef thread_local |
42 | #define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23 |
48 | #define thread_local __declspec(thread) // the thread_local keyword wasn't defined before C++11 and C23 |
43 | #endif // !thread_local |
49 | #endif // !thread_local |
44 | #define START_OF_PACKED_STRUCT() __pragma(pack(push)) __pragma(pack(1)) |
50 | #define START_OF_PACKED_STRUCT() __pragma(pack(push)) __pragma(pack(1)) |
45 | #define END_OF_PACKED_STRUCT() __pragma(pack(pop)) |
51 | #define END_OF_PACKED_STRUCT() __pragma(pack(pop)) |
46 | #define PACKED(thing) thing |
52 | #define PACKED(thing) thing |
47 | #else // !_MSC_VER |
53 | #else // !_MSC_VER |
48 | #include <sys/param.h> |
54 | #include <sys/param.h> |
49 | #include <unistd.h> |
55 | #include <unistd.h> |
- | 56 | #include <utime.h> |
|
50 | #ifndef thread_local |
57 | #ifndef thread_local |
51 | #define thread_local __thread // the thread_local keyword wasn't defined before C++11 and C23 |
58 | #define thread_local __thread // the thread_local keyword wasn't defined before C++11 and C23 |
52 | #endif // !thread_local |
59 | #endif // !thread_local |
53 | #define START_OF_PACKED_STRUCT() |
60 | #define START_OF_PACKED_STRUCT() |
54 | #define END_OF_PACKED_STRUCT() |
61 | #define END_OF_PACKED_STRUCT() |
Line 106... | Line 113... | ||
106 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \ |
113 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 29 ") ? "29" : \ |
107 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \ |
114 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 30 ") ? "30" : \ |
108 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : \ |
115 | *((uint32_t *) &__DATE__[3]) == *((uint32_t *) " 31 ") ? "31" : \ |
109 | "XX" \ |
116 | "XX" \ |
110 | ) // compiler will optimize this into a const string, e.g. "14" |
117 | ) // compiler will optimize this into a const string, e.g. "14" |
111 | #define VERSION_FMT_YYYYMMDD " |
118 | #define VERSION_FMT_YYYYMMDD "%s%s%s" |
112 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
119 | #define VERSION_ARG_YYYYMMDD BUILDDATE_YEAR, BUILDDATE_MONTH, BUILDDATE_DAY |
113 | #endif // !VERSION_ARG_YYYYMMDD |
120 | #endif // !VERSION_ARG_YYYYMMDD |
114 | 121 | ||
115 | 122 | ||
116 | // macro to bring __FILE_NAME__ support to moronic compilers |
123 | // macro to bring __FILE_NAME__ support to moronic compilers |
Line 739... | Line 746... | ||
739 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
746 | static size_t fwrite_fsentry (const fsentry_t *fsentry, FILE *fp); // writes the given filesystem entry into fp (without its contents) |
740 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry |
747 | static size_t add_fsentry (fsentry_t **fsentries, size_t *fsentry_count, parms_t *entry_parms, const char *stored_pathname, const char *buildhost_pathname); // stack up a new filesystem entry |
741 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
748 | static int fsentry_compare_pathnames_cb (const void *a, const void *b); // qsort() comparison callback that sorts filesystem entries by pathnames |
742 | static void update_MKIFS_PATH (const char *processor); |
749 | static void update_MKIFS_PATH (const char *processor); |
743 | static int dump_ifs_info (const char *ifs_pathname, bool want_everything); // dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error |
750 | static int dump_ifs_info (const char *ifs_pathname, bool want_everything); // dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error |
- | 751 | static int create_intermediate_dirs (const char *file_pathname); // creates all intermediate directories to file_pathname so that fopen(file_pathname, "w") doesn't fail |
|
- | 752 | static int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error |
|
744 | 753 | ||
745 | 754 | ||
746 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data) |
755 | static void sha512_private_transform (SHA512_CTX *context, const uint64_t *data) |
747 | { |
756 | { |
748 | // logical functions used in SHA-384 and SHA-512 |
757 | // logical functions used in SHA-384 and SHA-512 |
Line 1882... | Line 1891... | ||
1882 | int32_t checksum; |
1891 | int32_t checksum; |
1883 | char *specifiedpathname_start; |
1892 | char *specifiedpathname_start; |
1884 | char *directiveblock_start; |
1893 | char *directiveblock_start; |
1885 | char *write_ptr; |
1894 | char *write_ptr; |
1886 | char *line_ptr; |
1895 | char *line_ptr; |
- | 1896 | char *outdir = "."; |
|
1887 | char *token; |
1897 | char *token; |
1888 | char *value; |
1898 | char *value; |
1889 | char *sep; |
1899 | char *sep; |
1890 | //char *ctx; |
1900 | //char *ctx; |
1891 | int arg_index; |
1901 | int arg_index; |
Line 1893... | Line 1903... | ||
1893 | bool is_escaped_char = false; |
1903 | bool is_escaped_char = false; |
1894 | bool should_discard_inline_contents = false; |
1904 | bool should_discard_inline_contents = false; |
1895 | bool want_info = false; |
1905 | bool want_info = false; |
1896 | bool want_everything = false; |
1906 | bool want_everything = false; |
1897 | bool want_help = false; |
1907 | bool want_help = false; |
- | 1908 | bool want_dump = false; |
|
1898 | bool is_foreign_endianness; |
1909 | bool is_foreign_endianness; |
1899 | int string_len; |
1910 | int string_len; |
1900 | int read_char; |
1911 | int read_char; |
1901 | FILE *buildfile_fp; |
1912 | FILE *buildfile_fp; |
1902 | FILE *fp; |
1913 | FILE *fp; |
Line 1935... | Line 1946... | ||
1935 | else if (strcmp (argv[arg_index], "-nn") == 0) |
1946 | else if (strcmp (argv[arg_index], "-nn") == 0) |
1936 | { |
1947 | { |
1937 | default_parms.mtime = 0; // *all* files should have a mtime set to zero |
1948 | default_parms.mtime = 0; // *all* files should have a mtime set to zero |
1938 | default_parms.mtime_for_inline_files = 0; |
1949 | default_parms.mtime_for_inline_files = 0; |
1939 | } |
1950 | } |
- | 1951 | else if ((strcmp (argv[arg_index], "--outdir") == 0) && (arg_index + 1 < argc)) // --outdir path |
|
- | 1952 | outdir = argv[++arg_index]; |
|
1940 | else if (strcmp (argv[arg_index], "--info") == 0) |
1953 | else if (strcmp (argv[arg_index], "--info") == 0) |
1941 | want_info = true; |
1954 | want_info = true; |
- | 1955 | else if (strcmp (argv[arg_index], "--dump") == 0) |
|
- | 1956 | want_dump = true; |
|
1942 | else if (strcmp (argv[arg_index], "--everything") == 0) |
1957 | else if (strcmp (argv[arg_index], "--everything") == 0) |
1943 | want_everything = true; |
1958 | want_everything = true; |
1944 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0)) |
1959 | else if ((strcmp (argv[arg_index], "-?") == 0) || (strcmp (argv[arg_index], "--help") == 0)) |
1945 | want_help = true; |
1960 | want_help = true; |
1946 | else if (buildfile_pathname == NULL) |
1961 | else if (buildfile_pathname == NULL) |
Line 1948... | Line 1963... | ||
1948 | else if (ifs_pathname == NULL) |
1963 | else if (ifs_pathname == NULL) |
1949 | ifs_pathname = argv[arg_index]; |
1964 | ifs_pathname = argv[arg_index]; |
1950 | } |
1965 | } |
1951 | 1966 | ||
1952 | // do we not have enough information to run ? |
1967 | // do we not have enough information to run ? |
1953 | if (want_help || (buildfile_pathname == NULL) || (!want_info && (ifs_pathname == NULL))) |
1968 | if (want_help || (buildfile_pathname == NULL) || (!want_info && !want_dump && (ifs_pathname == NULL))) |
1954 | { |
1969 | { |
1955 | fp = (want_help ? stdout : stderr); // select the right output channel |
1970 | fp = (want_help ? stdout : stderr); // select the right output channel |
1956 | fprintf (fp, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
1971 | fprintf (fp, "ifstool - QNX in-kernel filesystem creation utility by Pierre-Marie Baty <pm@pmbaty.com>\n"); |
1957 | fprintf (fp, " version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
1972 | fprintf (fp, " version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
1958 | if (!want_help) |
1973 | if (!want_help) |
1959 | fprintf (fp, "error: missing parameters\n"); |
1974 | fprintf (fp, "error: missing parameters\n"); |
1960 | fprintf (fp, "usage:\n"); |
1975 | fprintf (fp, "usage:\n"); |
1961 | fprintf (fp, " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] <buildfile> <outfile>\n"); |
1976 | fprintf (fp, " ifstool [--bootfile <pathname>] [--startupfile <pathname>@<EP_from_imgbase>] [--kernelfile <pathname>@<fileoffs>] [-n[n]] <buildfile> <outfile>\n"); |
1962 | fprintf (fp, " ifstool --info [--everything] <ifs file>\n"); |
1977 | fprintf (fp, " ifstool --info [--everything] <ifs file>\n"); |
- | 1978 | fprintf (fp, " ifstool --dump [--outdir <path>] <ifs file>\n"); |
|
1963 | fprintf (fp, " ifstool --help\n"); |
1979 | fprintf (fp, " ifstool --help\n"); |
1964 | fprintf (fp, "NOTE: the compilation feature requires predigested boot, startup and kernel files produced by mkifs.\n"); |
1980 | fprintf (fp, "NOTE: the compilation feature requires predigested boot, startup and kernel files produced by mkifs.\n"); |
1965 | exit (want_help ? 0 : 1); |
1981 | exit (want_help ? 0 : 1); |
1966 | } |
1982 | } |
1967 | 1983 | ||
1968 | // do we want info about a particular IFS ? if so, |
1984 | // do we want info about a particular IFS ? if so, dissecate it |
1969 | if (want_info) |
1985 | if (want_info) |
1970 | exit (dump_ifs_info (buildfile_pathname, want_everything)); // NOTE: the first argument after --info is actually the IFS file, not a build file, but the arguments are collected in this order |
1986 | exit (dump_ifs_info (buildfile_pathname, want_everything)); // NOTE: the first argument after --info is actually the IFS file, not a build file, but the arguments are collected in this order |
- | 1987 | ||
- | 1988 | // else do we want to dump its contents ? if so, do so |
|
- | 1989 | else if (want_dump) |
|
- | 1990 | exit (dump_ifs_contents (buildfile_pathname, outdir)); // NOTE: the first argument after --info is actually the IFS file, not a build file, but the arguments are collected in this order |
|
1971 | 1991 | ||
1972 | // make sure we have ${QNX_TARGET} pointing somewhere |
1992 | // make sure we have ${QNX_TARGET} pointing somewhere |
1973 | QNX_TARGET = getenv ("QNX_TARGET"); |
1993 | QNX_TARGET = getenv ("QNX_TARGET"); |
1974 | if (QNX_TARGET == NULL) |
1994 | if (QNX_TARGET == NULL) |
1975 | { |
1995 | { |
Line 2478... | Line 2498... | ||
2478 | for (table_index = 0; table_index < table_count; table_index++) |
2498 | for (table_index = 0; table_index < table_count; table_index++) |
2479 | { |
2499 | { |
2480 | phdr = (elf_program_header_t *) &fsentries[largest_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header |
2500 | phdr = (elf_program_header_t *) &fsentries[largest_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header |
2481 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
2501 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
2482 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory |
2502 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory |
2483 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + |
2503 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + curr_offset - corrective_offset); // patch the physical address member of the program header table |
2484 | } |
2504 | } |
2485 | } |
2505 | } |
2486 | 2506 | ||
2487 | fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob |
2507 | fwrite_or_die (fsentries[largest_index].u.file.UNSAVED_databuf, 1, fsentries[largest_index].u.file.size, fp); // write file data blob |
2488 | fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2508 | fsentries[largest_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
Line 2519... | Line 2539... | ||
2519 | for (table_index = 0; table_index < table_count; table_index++) |
2539 | for (table_index = 0; table_index < table_count; table_index++) |
2520 | { |
2540 | { |
2521 | phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header |
2541 | phdr = (elf_program_header_t *) &fsentries[fsentry_index].u.file.UNSAVED_databuf[ELF_GET_NUMERIC (elf, elf, program_header_table_offset) + (size_t) ELF_GET_NUMERIC (elf, elf, program_header_item_size) * table_index]; // quick access to program header |
2522 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
2542 | corrective_offset = ELF_GET_NUMERIC (elf, phdr, virtual_addr) - ELF_GET_NUMERIC (elf, phdr, file_offset); |
2523 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory |
2543 | if (ELF_GET_NUMERIC (elf, phdr, size_in_memory) != 0) // only patch the physical address of segments that have an actual size in memory |
2524 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + |
2544 | ELF_SET_NUMERIC (elf, phdr, physical_addr, ELF_GET_NUMERIC (elf, phdr, physical_addr) + image_base + curr_offset - corrective_offset); // patch the physical address member of the program header table |
2525 | } |
2545 | } |
2526 | } |
2546 | } |
2527 | 2547 | ||
2528 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
2548 | fwrite_or_die (fsentries[fsentry_index].u.file.UNSAVED_databuf, 1, fsentries[fsentry_index].u.file.size, fp); // write file data blob |
2529 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
2549 | fsentries[fsentry_index].UNSAVED_was_data_written = true; // and remember this file's data was written |
Line 3029... | Line 3049... | ||
3029 | hex_printf (&file.bytes[current_offset], file.len - current_offset, "\n" "%zd extra bytes at offset %zx (%zd):\n", file.len - current_offset, current_offset, current_offset); |
3049 | hex_printf (&file.bytes[current_offset], file.len - current_offset, "\n" "%zd extra bytes at offset %zx (%zd):\n", file.len - current_offset, current_offset, current_offset); |
3030 | } |
3050 | } |
3031 | 3051 | ||
3032 | printf ("End of file reached at offset 0x%zx (%zd)\n", file.len, file.len); |
3052 | printf ("End of file reached at offset 0x%zx (%zd)\n", file.len, file.len); |
3033 | printf ("IFS dissecation complete.\n"); |
3053 | printf ("IFS dissecation complete.\n"); |
- | 3054 | return (0); |
|
- | 3055 | } |
|
- | 3056 | ||
- | 3057 | ||
- | 3058 | static int create_intermediate_dirs (const char *file_pathname) |
|
- | 3059 | { |
|
- | 3060 | // creates all intermediate directories from root (or cwd) up to file_path |
|
- | 3061 | ||
- | 3062 | char *temp_pathname; |
|
- | 3063 | char *separator; |
|
- | 3064 | size_t string_index; |
|
- | 3065 | size_t length; |
|
- | 3066 | ||
- | 3067 | temp_pathname = strdup (file_pathname); // have a working copy of file_pathname |
|
- | 3068 | if (temp_pathname == NULL) |
|
- | 3069 | return (-1); // on strdup() failure, return an error value (errno is set) |
|
- | 3070 | length = strlen (temp_pathname); |
|
- | 3071 | for (string_index = length - 1; string_index != SIZE_MAX; string_index--) // i.e. loop until it overflows |
|
- | 3072 | if ((temp_pathname[string_index] == '/') || (temp_pathname[string_index] == '\\')) |
|
- | 3073 | break; // look for the last directory separator and stop as soon as we find it |
|
- | 3074 | if (string_index != SIZE_MAX) |
|
- | 3075 | { |
|
- | 3076 | for (; string_index < length; string_index++) |
|
- | 3077 | temp_pathname[string_index] = 0; // if we found one, break there so as to have just the path and clear the rest of the string |
|
- | 3078 | separator = strtok (&temp_pathname[1], "/\\"); // for each separator in the remaining string past the first one... |
|
- | 3079 | while (separator != NULL) |
|
- | 3080 | { |
|
- | 3081 | (void) mkdir (temp_pathname, 0755); // create directories recursively |
|
- | 3082 | temp_pathname[strlen (temp_pathname)] = '/'; // put the separator back |
|
- | 3083 | separator = strtok (NULL, "/\\"); // and look for the next one |
|
- | 3084 | } |
|
- | 3085 | } |
|
- | 3086 | ||
- | 3087 | free (temp_pathname); // release our working copy of file_pathname |
|
- | 3088 | return (0); |
|
- | 3089 | } |
|
- | 3090 | ||
- | 3091 | ||
- | 3092 | static int dump_ifs_contents (const char *ifs_pathname, const char *outdir) |
|
- | 3093 | { |
|
- | 3094 | static char outfile_pathname[MAXPATHLEN] = ""; |
|
- | 3095 | ||
- | 3096 | startup_header_t *startup_header = NULL; |
|
- | 3097 | size_t startupheader_offset = 0; |
|
- | 3098 | image_header_t *image_header = NULL; |
|
- | 3099 | size_t imageheader_offset = 0; |
|
- | 3100 | size_t imagetrailer_offset = 0; |
|
- | 3101 | fsentry_t **fsentries = NULL; // mallocated |
|
- | 3102 | size_t fsentry_count = 0; |
|
- | 3103 | fsentry_t *current_fsentry = NULL; |
|
- | 3104 | size_t startupfile_blobsize = 0; |
|
- | 3105 | struct utimbuf file_times = { 0, 0 }; |
|
- | 3106 | void *reallocated_ptr; |
|
- | 3107 | size_t bootfile_blobsize = 0; |
|
- | 3108 | size_t current_offset; |
|
- | 3109 | size_t fsentry_index; |
|
- | 3110 | size_t nearest_distance; |
|
- | 3111 | size_t nearest_index; |
|
- | 3112 | size_t byte_index; |
|
- | 3113 | buffer_t file; |
|
- | 3114 | FILE *fp; |
|
- | 3115 | ||
- | 3116 | // open and read IFS file |
|
- | 3117 | if (read_filecontents (ifs_pathname, ".", &file) == NULL) |
|
- | 3118 | { |
|
- | 3119 | fprintf (stderr, "error: can't open \"%s\" for reading: %s\n", ifs_pathname, strerror (errno)); |
|
- | 3120 | return (1); |
|
- | 3121 | } |
|
- | 3122 | ||
- | 3123 | // create the output directory |
|
- | 3124 | create_intermediate_dirs (outdir); |
|
- | 3125 | (void) mkdir (outdir, 0755); |
|
- | 3126 | ||
- | 3127 | // parse file from start to end |
|
- | 3128 | current_offset = 0; |
|
- | 3129 | for (;;) |
|
- | 3130 | { |
|
- | 3131 | // does a startup header start here ? |
|
- | 3132 | if ((current_offset + sizeof (startup_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "\xeb\x7e\xff\x00", 4) == 0)) |
|
- | 3133 | { |
|
- | 3134 | startupheader_offset = current_offset; |
|
- | 3135 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; |
|
- | 3136 | ||
- | 3137 | // layout: |
|
- | 3138 | // [STARTUP HEADER] |
|
- | 3139 | // (startup file blob) |
|
- | 3140 | // [STARTUP TRAILER v1 or v2] |
|
- | 3141 | ||
- | 3142 | // validate that the file can contain up to the startup trailer |
|
- | 3143 | if (current_offset + startup_header->startup_size > file.len) |
|
- | 3144 | { |
|
- | 3145 | printf ("WARNING: this IFS file is corrupted (startup trailer extends past end of file)\n"); |
|
- | 3146 | goto endofdata; |
|
- | 3147 | } |
|
- | 3148 | ||
- | 3149 | // locate the right startup trailer at the right offset |
|
- | 3150 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
|
- | 3151 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v2_t); |
|
- | 3152 | else // old V1 trailer |
|
- | 3153 | startupfile_blobsize = startup_header->startup_size - sizeof (startup_header_t) - sizeof (startup_trailer_v1_t); |
|
- | 3154 | ||
- | 3155 | current_offset += sizeof (startup_header_t); // jump over the startup header and reach the startup blob |
|
- | 3156 | ||
- | 3157 | // write startup blob |
|
- | 3158 | sprintf (outfile_pathname, "%s/STARTUP.BLOB", outdir); |
|
- | 3159 | fp = fopen (outfile_pathname, "wb"); |
|
- | 3160 | WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno)); |
|
- | 3161 | fwrite (&file.bytes[current_offset], 1, startupfile_blobsize, fp); |
|
- | 3162 | fclose (fp); |
|
- | 3163 | ||
- | 3164 | current_offset += startupfile_blobsize; // jump over the startup blob and reach the startup trailer |
|
- | 3165 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // jump over the startup trailer and reach the next segment |
|
- | 3166 | } |
|
- | 3167 | ||
- | 3168 | // else does an image header start here ? |
|
- | 3169 | else if ((current_offset + sizeof (image_header_t) < file.len) && (memcmp (&file.bytes[current_offset], "imagefs", 7) == 0)) |
|
- | 3170 | { |
|
- | 3171 | imageheader_offset = current_offset; |
|
- | 3172 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; |
|
- | 3173 | ||
- | 3174 | // layout: |
|
- | 3175 | // [IMAGE HEADER] |
|
- | 3176 | // [image directory entries] |
|
- | 3177 | // [smallest file blobs up to KERNEL] |
|
- | 3178 | // [padding] |
|
- | 3179 | // [KERNEL] |
|
- | 3180 | // [rest of file blobs] |
|
- | 3181 | // [IMAGE FOOTER] |
|
- | 3182 | ||
- | 3183 | // validate that the file can contain up to the image trailer |
|
- | 3184 | if (current_offset + image_header->image_size > file.len) |
|
- | 3185 | { |
|
- | 3186 | printf ("WARNING: this IFS file is corrupted (image trailer extends past end of file)\n"); |
|
- | 3187 | goto endofdata; |
|
- | 3188 | } |
|
- | 3189 | ||
- | 3190 | // locate the image trailer at the right offset |
|
- | 3191 | if (image_header->flags & IMAGE_FLAGS_TRAILER_V2) |
|
- | 3192 | imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v2_t); |
|
- | 3193 | else // old V1 trailer |
|
- | 3194 | imagetrailer_offset = current_offset + image_header->image_size - sizeof (image_trailer_v1_t); |
|
- | 3195 | ||
- | 3196 | current_offset += sizeof (image_header_t); // jump over the image header |
|
- | 3197 | current_offset += image_header->dir_offset - sizeof (image_header_t); // jump over possible padding |
|
- | 3198 | ||
- | 3199 | // dump all directory entries until the last one included |
|
- | 3200 | fsentries = NULL; |
|
- | 3201 | fsentry_count = 0; |
|
- | 3202 | while (current_offset < imageheader_offset + image_header->hdr_dir_size) |
|
- | 3203 | { |
|
- | 3204 | current_fsentry = (fsentry_t *) &file.bytes[current_offset]; |
|
- | 3205 | ||
- | 3206 | if (imageheader_offset + image_header->hdr_dir_size - current_offset < sizeof (current_fsentry->header)) |
|
- | 3207 | break; // end padding reached |
|
- | 3208 | ||
- | 3209 | // stack up the filesystem entry pointers in an array while we read them |
|
- | 3210 | reallocated_ptr = realloc (fsentries, (fsentry_count + 1) * sizeof (fsentry_t *)); |
|
- | 3211 | WELLMANNERED_ASSERT (reallocated_ptr, "out of memory"); |
|
- | 3212 | fsentries = reallocated_ptr; |
|
- | 3213 | fsentries[fsentry_count] = current_fsentry; |
|
- | 3214 | fsentry_count++; |
|
- | 3215 | ||
- | 3216 | if ((current_fsentry->header.size == 0) || (current_offset + current_fsentry->header.size >= file.len)) |
|
- | 3217 | { |
|
- | 3218 | printf ("WARNING: this IFS file is corrupted (the size of this directory entry is invalid)\n"); |
|
- | 3219 | goto endofdata; |
|
- | 3220 | } |
|
- | 3221 | ||
- | 3222 | current_offset += current_fsentry->header.size; |
|
- | 3223 | } |
|
- | 3224 | current_offset += imageheader_offset + image_header->hdr_dir_size - current_offset; // jump over possible padding |
|
- | 3225 | ||
- | 3226 | // at this point we are past the directory entries; what is stored now, up to and until the image trailer, is the files' data |
|
- | 3227 | if (fsentry_count > 0) |
|
- | 3228 | { |
|
- | 3229 | while (current_offset < imagetrailer_offset) // and parse data up to the trailer |
|
- | 3230 | { |
|
- | 3231 | nearest_distance = SIZE_MAX; |
|
- | 3232 | nearest_index = SIZE_MAX; |
|
- | 3233 | for (fsentry_index = 0; fsentry_index < fsentry_count; fsentry_index++) |
|
- | 3234 | if (S_ISREG (fsentries[fsentry_index]->header.mode) // if this directory entry a file (i.e. it has a data blob)... |
|
- | 3235 | && (imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset >= current_offset) // ... AND its data blob is still ahead of our current pointer ... |
|
- | 3236 | && (imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset - current_offset < nearest_distance)) // ... AND it's the closest to us we've found so far |
|
- | 3237 | { |
|
- | 3238 | nearest_distance = imageheader_offset + (size_t) fsentries[fsentry_index]->u.file.offset - current_offset; // then remember it |
|
- | 3239 | nearest_index = fsentry_index; |
|
- | 3240 | } |
|
- | 3241 | if (nearest_index == SIZE_MAX) |
|
- | 3242 | break; // found no file ahead, which means we've parsed the whole file data area, so stop the loop so as to proceed to the image trailer |
|
- | 3243 | ||
- | 3244 | fsentry_index = nearest_index; |
|
- | 3245 | current_fsentry = fsentries[fsentry_index]; // quick access to closest fsentry |
|
- | 3246 | ||
- | 3247 | current_offset += imageheader_offset + (size_t) current_fsentry->u.file.offset - current_offset; // jump over possible padding |
|
- | 3248 | ||
- | 3249 | if (current_offset + current_fsentry->u.file.size >= file.len) |
|
- | 3250 | { |
|
- | 3251 | printf ("WARNING: this IFS file is corrupted (the size of this file data extends past the IFS size)\n"); |
|
- | 3252 | goto endofdata; |
|
- | 3253 | } |
|
- | 3254 | ||
- | 3255 | // write filesystem data entry |
|
- | 3256 | if (S_ISDIR (current_fsentry->header.mode)) |
|
- | 3257 | { |
|
- | 3258 | sprintf (outfile_pathname, "%s/%s", outdir, (char *) ¤t_fsentry->u.dir.path); // convert from pointer to char array |
|
- | 3259 | create_intermediate_dirs (outfile_pathname); |
|
- | 3260 | (void) mkdir (outfile_pathname, current_fsentry->header.mode & 0777); |
|
- | 3261 | } |
|
- | 3262 | else if (S_ISLNK (current_fsentry->header.mode)) |
|
- | 3263 | { |
|
- | 3264 | sprintf (outfile_pathname, "%s/%s", outdir, (char *) ¤t_fsentry->u.symlink.path); // convert from pointer to char array |
|
- | 3265 | create_intermediate_dirs (outfile_pathname); |
|
- | 3266 | #ifdef _WIN32 |
|
- | 3267 | fp = fopen (outfile_pathname, "wb"); // on Windows create symlinks as plain files |
|
- | 3268 | WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno)); |
|
- | 3269 | fwrite ((char *) ¤t_fsentry->u.symlink.path + current_fsentry->u.symlink.sym_offset, 1, current_fsentry->u.symlink.sym_size, fp); // convert from pointer to char array |
|
- | 3270 | fclose (fp); |
|
- | 3271 | #else // !_WIN32, thus POSIX |
|
- | 3272 | symlink (current_fsentry->u.symlink.contents, outfile_pathname); // on UNIX systems, just create the symlink for real |
|
- | 3273 | #endif // _WIN32 |
|
- | 3274 | } |
|
- | 3275 | else if (S_ISREG (current_fsentry->header.mode)) |
|
- | 3276 | { |
|
- | 3277 | sprintf (outfile_pathname, "%s/%s", outdir, (char *) ¤t_fsentry->u.file.path); // convert from pointer to char array |
|
- | 3278 | create_intermediate_dirs (outfile_pathname); |
|
- | 3279 | fp = fopen (outfile_pathname, "wb"); // on Windows create symlinks as plain files |
|
- | 3280 | WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno)); |
|
- | 3281 | fwrite (&file.bytes[current_offset], 1, current_fsentry->u.file.size, fp); |
|
- | 3282 | fclose (fp); |
|
- | 3283 | } |
|
- | 3284 | else // must be a device node. Since we might not be the super-user and/or on Win32, create plain file with "X:Y" as data |
|
- | 3285 | { |
|
- | 3286 | sprintf (outfile_pathname, "%s/%s", outdir, (char *) ¤t_fsentry->u.device.path); // convert from pointer to char array |
|
- | 3287 | create_intermediate_dirs (outfile_pathname); |
|
- | 3288 | fp = fopen (outfile_pathname, "wb"); // on Windows create symlinks as plain files |
|
- | 3289 | WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno)); |
|
- | 3290 | fprintf (fp, "%u:%u", current_fsentry->u.device.dev, current_fsentry->u.device.rdev); |
|
- | 3291 | fclose (fp); |
|
- | 3292 | } |
|
- | 3293 | ||
- | 3294 | // set created file mtime |
|
- | 3295 | file_times.actime = current_fsentry->header.mtime; |
|
- | 3296 | file_times.modtime = current_fsentry->header.mtime; |
|
- | 3297 | utime (outfile_pathname, &file_times); |
|
- | 3298 | ||
- | 3299 | // set created file mode |
|
- | 3300 | (void) chmod (outfile_pathname, current_fsentry->header.mode & 0777); |
|
- | 3301 | ||
- | 3302 | current_offset += current_fsentry->u.file.size; // now jump over this file's data |
|
- | 3303 | } |
|
- | 3304 | } |
|
- | 3305 | ||
- | 3306 | // ad this point we're past the last file data, there may be padding before the image trailer |
|
- | 3307 | current_offset += imagetrailer_offset - current_offset; // jump over possible padding and reach the image trailer |
|
- | 3308 | current_offset += (image_header->flags & IMAGE_FLAGS_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)); // now jump over the image trailer and reach the next segment (typically end of file) |
|
- | 3309 | } |
|
- | 3310 | ||
- | 3311 | // else it has to be a boot blob, of which we don't know the size, except that it has to fit in 0xffff bytes and be immediately followed by a startup header |
|
- | 3312 | else |
|
- | 3313 | { |
|
- | 3314 | // so scan for the first startup header magic and version (which makes us 6 bytes to scan for, i.e. "\xeb\x7e\xff\x00" for the magic and "\x01\x00" (LSB) for the version 1) |
|
- | 3315 | for (byte_index = current_offset; byte_index < file.len - 6; byte_index++) |
|
- | 3316 | if (memcmp (&file.bytes[byte_index], "\xeb\x7e\xff\x00" "\x01\x00", 4 + 2) == 0) |
|
- | 3317 | break; // stop as soon as we find it |
|
- | 3318 | ||
- | 3319 | if (byte_index >= file.len - 6) |
|
- | 3320 | break; // if not found, stop scanning |
|
- | 3321 | ||
- | 3322 | bootfile_blobsize = byte_index - current_offset; |
|
- | 3323 | ||
- | 3324 | // write boot blob |
|
- | 3325 | sprintf (outfile_pathname, "%s/BOOT.BLOB", outdir); |
|
- | 3326 | fp = fopen (outfile_pathname, "wb"); |
|
- | 3327 | WELLMANNERED_ASSERT (fp, "failed to open '%s': %s", outfile_pathname, strerror (errno)); |
|
- | 3328 | fwrite (&file.bytes[current_offset], 1, bootfile_blobsize, fp); |
|
- | 3329 | fclose (fp); |
|
- | 3330 | ||
- | 3331 | current_offset = byte_index; // now reach the next segment |
|
- | 3332 | } |
|
- | 3333 | } |
|
- | 3334 | ||
- | 3335 | endofdata: |
|
3034 | return (0); |
3336 | return (0); |
3035 | } |
3337 | } |