• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkh3cvfs.c

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 
  3 #include <stdio.h>
  4 #include <string.h>
  5 #include <stdlib.h>
  6 #include <stdint.h>
  7 #include <sys/types.h>
  8 #include <unistd.h>
  9 #include <byteswap.h>
 10 #include <endian.h>
 11 #include <getopt.h>
 12 
 13 
 14 #if !defined(__BYTE_ORDER)
 15 #error "Unknown byte order"
 16 #endif
 17 
 18 #if __BYTE_ORDER == __BIG_ENDIAN
 19 #define cpu_to_be16(x)  (x)
 20 #define cpu_to_be32(x)  (x)
 21 #define be16_to_cpu(x)  (x)
 22 #define be32_to_cpu(x)  (x)
 23 #elif __BYTE_ORDER == __LITTLE_ENDIAN
 24 #define cpu_to_be16(x)  bswap_16(x)
 25 #define cpu_to_be32(x)  bswap_32(x)
 26 #define be16_to_cpu(x)  bswap_16(x)
 27 #define be32_to_cpu(x)  bswap_32(x)
 28 #else
 29 #error "Unsupported endianness"
 30 #endif
 31 
 32 
 33 #define FAT_PTR_FLAGS_GET(x)     ((be32_to_cpu(x) & 0xff000000) >> 24)
 34 #define FAT_PTR_FLAGS_SET(x, y)  (x = cpu_to_be32((be32_to_cpu(x) & 0x00ffffff) | ((y & 0x000000ff) << 24)))
 35 
 36 #define FAT_PTR_VAL_GET(x)     (be32_to_cpu(x) & 0x00ffffff)
 37 #define FAT_PTR_VAL_SET(x, y)  (x = cpu_to_be32((be32_to_cpu(x) & 0xff000000) | (y & 0x00ffffff)))
 38 
 39 
 40 struct fat_entry {
 41         /* first byte contains flags */
 42         uint32_t previous;
 43 
 44         /* first byte is reserved */
 45         uint32_t next;
 46 } __attribute__ ((packed));
 47 
 48 struct file_entry {
 49         uint8_t flags;
 50 
 51         uint8_t res0[5];
 52 
 53         uint16_t year;
 54         uint8_t month;
 55         uint8_t day;
 56         uint8_t hour;
 57         uint8_t minute;
 58         uint8_t second;
 59 
 60         uint8_t res1[3];
 61 
 62         uint32_t length;
 63 
 64         uint32_t parent_block;
 65         uint16_t parent_index;
 66 
 67         uint8_t res2[2];
 68 
 69         uint32_t data_block;
 70 
 71         char name[96];
 72 } __attribute__ ((packed));
 73 
 74 
 75 #define ERASEBLOCK_SIZE   0x10000
 76 #define BLOCK_SIZE        0x400
 77 
 78 #define BLOCKS_PER_ERASEBLOCK   (ERASEBLOCK_SIZE / BLOCK_SIZE)
 79 #define FILE_ENTRIES_PER_BLOCK  (BLOCK_SIZE / sizeof(struct file_entry))
 80 
 81 
 82 #define FLAG_FREE       0x80
 83 #define FLAG_VALID      0x40
 84 #define FLAG_INVALID    0x20
 85 #define FLAG_HIDE       0x10
 86 #define FLAG_DIRECTORY  0x02
 87 #define FLAG_READONLY   0x01
 88 
 89 
 90 static FILE *f;
 91 static size_t file_size = 0;
 92 
 93 static int dir_block = 1;
 94 static int dir_count = 0;
 95 
 96 static int next_data_block = 2;
 97 
 98 
 99 static inline size_t fat_entry_offset(int block) {
100         return ERASEBLOCK_SIZE * (block / (BLOCKS_PER_ERASEBLOCK-1))
101                 + sizeof(struct fat_entry) * (block % (BLOCKS_PER_ERASEBLOCK-1));
102 }
103 
104 static inline size_t block_offset(int block) {
105         return ERASEBLOCK_SIZE * (block / (BLOCKS_PER_ERASEBLOCK-1))
106                 + BLOCK_SIZE * (1 + (block % (BLOCKS_PER_ERASEBLOCK-1)));
107 }
108 
109 static int init_eraseblock(size_t offset) {
110         size_t end = offset - (offset % ERASEBLOCK_SIZE) + ERASEBLOCK_SIZE;
111         char *fill = "\xff";
112         int i;
113 
114         while (file_size < end) {
115                 if (fseek(f, file_size, SEEK_SET)) {
116                         fprintf(stderr, "failed to seek to end\n");
117                         return -1;
118                 }
119 
120                 for (i = 0; i < ERASEBLOCK_SIZE; i++) {
121                         if (fwrite(fill, 1, 1, f) != 1) {
122                                 fprintf(stderr, "failed to write eraseblock\n");
123                                 return -1;
124                         }
125                 }
126 
127                 file_size += ERASEBLOCK_SIZE;
128         }
129 
130         return 0;
131 }
132 
133 static inline void init_fat_entry(struct fat_entry *out) {
134         memset(out, '\xff', sizeof(struct fat_entry));
135 }
136 
137 static int read_fat_entry(struct fat_entry *out, int block) {
138         size_t offset = fat_entry_offset(block);
139 
140         if (init_eraseblock(offset)) {
141                 return -1;
142         }
143 
144         if (fseek(f, offset, SEEK_SET)) {
145                 fprintf(stderr, "failed to seek to fat entry\n");
146                 return -1;
147         }
148 
149         if (fread(out, sizeof(struct fat_entry), 1, f) != 1) {
150                 fprintf(stderr, "failed to read fat entry\n");
151                 return -1;
152         }
153 
154         return 0;
155 }
156 
157 static int write_fat_entry(struct fat_entry *in, int block) {
158         size_t offset = fat_entry_offset(block);
159 
160         if (init_eraseblock(offset)) {
161                 return -1;
162         }
163 
164         if (fseek(f, offset, SEEK_SET)) {
165                 fprintf(stderr, "failed to seek to fat entry\n");
166                 return -1;
167         }
168 
169         if (fwrite(in, sizeof(struct fat_entry), 1, f) != 1) {
170                 fprintf(stderr, "failed to write fat entry\n");
171                 return -1;
172         }
173 
174         return 0;
175 }
176 
177 static inline void init_file_entry(struct file_entry *out) {
178         memset(out, '\xff', sizeof(struct file_entry));
179 }
180 
181 static int write_file_entry(struct file_entry *in, int block, int index) {
182         size_t offset = block_offset(block) + sizeof(struct file_entry) * index;
183 
184         if (init_eraseblock(offset)) {
185                 return -1;
186         }
187 
188         if (fseek(f, offset, SEEK_SET)) {
189                 fprintf(stderr, "failed to seek to file entry\n");
190                 return -1;
191         }
192 
193         if (fwrite(in, sizeof(struct file_entry), 1, f) != 1) {
194                 fprintf(stderr, "failed to write file entry\n");
195                 return -1;
196         }
197 
198         return 0;
199 }
200 
201 static int write_block(void *in, size_t len, int block) {
202         size_t offset = block_offset(block);
203 
204         if (init_eraseblock(offset)) {
205                 return -1;
206         }
207 
208         if (fseek(f, offset, SEEK_SET)) {
209                 fprintf(stderr, "failed to seek to block\n");
210                 return -1;
211         }
212 
213         if (fwrite(in, len, 1, f) != 1) {
214                 fprintf(stderr, "failed to write block\n");
215                 return -1;
216         }
217 
218         return 0;
219 }
220 
221 static int create_root_directory() {
222         struct fat_entry fat;
223         struct file_entry file;
224 
225         /* write format flag / FAT entry for block 0 (contains root file entry) */
226         init_fat_entry(&fat);
227         fat.previous = cpu_to_be32((ERASEBLOCK_SIZE << 12) | BLOCK_SIZE);
228         if (write_fat_entry(&fat, 0)) {
229                 return -1;
230         }
231 
232         /* write root file entry */
233         init_file_entry(&file);
234         file.flags = ~(FLAG_FREE | FLAG_VALID) & 0xff;
235         file.parent_block = cpu_to_be32(0);
236         file.data_block = cpu_to_be32(1);
237         if (write_file_entry(&file, 0, 0)) {
238                 return -1;
239         }
240 
241         /* write FAT entry for block 1 (contains first file entries of root directory) */
242         init_fat_entry(&fat);
243         FAT_PTR_FLAGS_SET(fat.previous, ~(FLAG_FREE | FLAG_VALID));
244         if (write_fat_entry(&fat, 1)) {
245                 return -1;
246         }
247 
248         return 0;
249 }
250 
251 static int write_file(char *name, char *path) {
252         int ret = -1;
253         struct fat_entry fat;
254         struct file_entry file;
255         FILE *fin;
256         char buf[BLOCK_SIZE];
257         size_t len;
258         size_t total = 0;
259         int first_data_block = next_data_block;
260         int data_block = 0;
261 
262         fin = fopen(path, "r");
263         if (fin == NULL) {
264                 fprintf(stderr, "failed to open input file\n");
265                 return ret;
266         }
267 
268         while ((len = fread(buf, 1, BLOCK_SIZE, fin)) != 0 || !data_block) {
269                 total += len;
270 
271                 /* update next pointer of previous FAT entry */
272                 if (data_block) {
273                         if (read_fat_entry(&fat, data_block)) {
274                                 goto err;
275                         }
276                         FAT_PTR_VAL_SET(fat.next, next_data_block);
277                         if (write_fat_entry(&fat, data_block)) {
278                                 goto err;
279                         }
280                 }
281 
282                 /* write FAT entry for new block */
283                 init_fat_entry(&fat);
284                 FAT_PTR_FLAGS_SET(fat.previous, ~(FLAG_FREE | FLAG_VALID));
285                 if (data_block) {
286                         FAT_PTR_VAL_SET(fat.previous, data_block);
287                 }
288                 if (write_fat_entry(&fat, next_data_block)) {
289                         goto err;
290                 }
291 
292                 /* write data block */
293                 if (write_block(buf, len, next_data_block)) {
294                         goto err;
295                 }
296 
297                 data_block = next_data_block;
298                 next_data_block++;
299         }
300 
301         /* create new file entries block if necessary */
302         if (dir_count == FILE_ENTRIES_PER_BLOCK) {
303                 /* update next pointer of previous FAT entry */
304                 if (read_fat_entry(&fat, dir_block)) {
305                         goto err;
306                 }
307                 FAT_PTR_VAL_SET(fat.next, next_data_block);
308                 if (write_fat_entry(&fat, dir_block)) {
309                         goto err;
310                 }
311 
312                 /* write FAT entry for new block */
313                 init_fat_entry(&fat);
314                 FAT_PTR_FLAGS_SET(fat.previous, ~(FLAG_FREE | FLAG_VALID));
315                 FAT_PTR_VAL_SET(fat.previous, dir_block);
316                 if (write_fat_entry(&fat, next_data_block)) {
317                         goto err;
318                 }
319 
320                 dir_block = next_data_block;
321                 dir_count = 0;
322                 next_data_block++;
323         }
324 
325         /* write file entry */
326         init_file_entry(&file);
327 
328         file.flags = ~(FLAG_FREE | FLAG_VALID) & 0xff;
329 
330         file.year = cpu_to_be16(1970);
331         file.month = 1;
332         file.day = 1;
333         file.hour = 0;
334         file.minute = 0;
335         file.second = 0;
336 
337         file.length = cpu_to_be32(total);
338 
339         file.parent_block = cpu_to_be32(0);
340         file.parent_index = cpu_to_be16(0);
341 
342         file.data_block = cpu_to_be32(first_data_block);
343 
344         snprintf(file.name, sizeof(file.name), "%s", name);
345 
346         if (write_file_entry(&file, dir_block, dir_count)) {
347                 goto err;
348         }
349 
350         dir_count++;
351 
352         ret = 0;
353 err:
354         fclose(fin);
355         return ret;
356 }
357 
358 static void usage(char* argv[]) {
359         printf("Usage: %s [OPTIONS...]\n"
360                "\n"
361                "Options:\n"
362                "  -f <filename>  filename in image\n"
363                "  -i <file>      input filename\n"
364                "  -o <file>      output filename\n"
365                , argv[0]);
366 }
367 
368 int main(int argc, char* argv[]) {
369         int ret = EXIT_FAILURE;
370 
371         static char *filename = NULL;
372         static char *input_filename = NULL;
373         static char *output_filename = NULL;
374 
375         while ( 1 ) {
376                 int c;
377 
378                 c = getopt(argc, argv, "f:i:o:");
379                 if (c == -1)
380                         break;
381 
382                 switch (c) {
383                 case 'f':
384                         filename = optarg;
385                         break;
386                 case 'i':
387                         input_filename = optarg;
388                         break;
389                 case 'o':
390                         output_filename = optarg;
391                         break;
392                 default:
393                         usage(argv);
394                         goto err;
395                 }
396         }
397 
398         if (!filename || strlen(filename) == 0 ||
399                 !input_filename || strlen(input_filename) == 0 ||
400                 !output_filename || strlen(output_filename) == 0) {
401 
402                 usage(argv);
403                 goto err;
404         }
405 
406         f = fopen(output_filename, "w+");
407         if (f == NULL) {
408                 fprintf(stderr, "failed to open output file\n");
409                 goto err;
410         }
411 
412         if (create_root_directory()) {
413                 goto err_close;
414         }
415 
416         if (write_file(filename, input_filename)) {
417                 goto err_close;
418         }
419 
420         ret = EXIT_SUCCESS;
421 
422 err_close:
423         fclose(f);
424 err:
425         return ret;
426 }
427 

This page was automatically generated by LXR 0.3.1.  •  OpenWrt