Subversion Repositories QNX 8.QNX8 IFS tool

Rev

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 "%04s%02s%02s"
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, dump it
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) + 0x1400000 + curr_offset - corrective_offset); // patch the physical address member of the program header table
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) + 0x1400000 + curr_offset - corrective_offset); // patch the physical address member of the program header table
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 *) &current_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 *) &current_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 *) &current_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 *) &current_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 *) &current_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
}