]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - VtoyTool/vtoydm.c
experimental support for loongson mips64el uefi
[Ventoy.git] / VtoyTool / vtoydm.c
1 /******************************************************************************
2 * vtoydm.c ---- ventoy device mapper tool
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <errno.h>
25 #include <unistd.h>
26 #include <fcntl.h>
27 #include <sys/types.h>
28 #include <sys/mman.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <linux/fs.h>
33 #include "biso.h"
34 #include "biso_list.h"
35 #include "biso_util.h"
36 #include "biso_plat.h"
37 #include "biso_9660.h"
38
39 #ifndef O_BINARY
40 #define O_BINARY 0
41 #endif
42
43 #ifndef USE_DIET_C
44 #ifndef __mips__
45 typedef unsigned long long uint64_t;
46 #endif
47 typedef unsigned int uint32_t;
48 #endif
49
50 #pragma pack(4)
51 typedef struct ventoy_img_chunk
52 {
53 uint32_t img_start_sector; // sector size: 2KB
54 uint32_t img_end_sector; // included
55
56 uint64_t disk_start_sector; // in disk_sector_size
57 uint64_t disk_end_sector; // included
58 }ventoy_img_chunk;
59 #pragma pack()
60
61 static int verbose = 0;
62 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
63
64 #define CMD_PRINT_TABLE 1
65 #define CMD_CREATE_DM 2
66 #define CMD_DUMP_ISO_INFO 3
67 #define CMD_EXTRACT_ISO_FILE 4
68 #define CMD_PRINT_EXTRACT_ISO_FILE 5
69
70 static uint64_t g_iso_file_size;
71 static char g_disk_name[128];
72 static int g_img_chunk_num = 0;
73 static ventoy_img_chunk *g_img_chunk = NULL;
74 static unsigned char g_iso_sector_buf[2048];
75
76 ventoy_img_chunk * vtoydm_get_img_map_data(const char *img_map_file, int *plen)
77 {
78 int len;
79 int rc = 1;
80 FILE *fp = NULL;
81 ventoy_img_chunk *chunk = NULL;
82
83 fp = fopen(img_map_file, "rb");
84 if (NULL == fp)
85 {
86 fprintf(stderr, "Failed to open file %s err:%d\n", img_map_file, errno);
87 return NULL;
88 }
89
90 fseek(fp, 0, SEEK_END);
91 len = (int)ftell(fp);
92 fseek(fp, 0, SEEK_SET);
93
94 debug("File <%s> len:%d\n", img_map_file, len);
95
96 chunk = (ventoy_img_chunk *)malloc(len);
97 if (NULL == chunk)
98 {
99 fprintf(stderr, "Failed to malloc memory len:%d err:%d\n", len, errno);
100 goto end;
101 }
102
103 if (fread(chunk, 1, len, fp) != len)
104 {
105 fprintf(stderr, "Failed to read file err:%d\n", errno);
106 goto end;
107 }
108
109 if (len % sizeof(ventoy_img_chunk))
110 {
111 fprintf(stderr, "image map file size %d is not aligned with %d\n",
112 len, (int)sizeof(ventoy_img_chunk));
113 goto end;
114 }
115
116 rc = 0;
117 end:
118 fclose(fp);
119
120 if (rc)
121 {
122 if (chunk)
123 {
124 free(chunk);
125 chunk = NULL;
126 }
127 }
128
129 *plen = len;
130 return chunk;
131 }
132
133
134 UINT64 vtoydm_get_file_size(const char *pcFileName)
135 {
136 (void)pcFileName;
137
138 debug("vtoydm_get_file_size %s %lu\n", pcFileName, (unsigned long)g_iso_file_size);
139
140 return g_iso_file_size;
141 }
142
143 BISO_FILE_S * vtoydm_open_file(const char *pcFileName)
144 {
145 BISO_FILE_S *file;
146
147 debug("vtoydm_open_file %s\n", pcFileName);
148
149 file = malloc(sizeof(BISO_FILE_S));
150 if (file)
151 {
152 memset(file, 0, sizeof(BISO_FILE_S));
153
154 file->FileSize = g_iso_file_size;
155 file->CurPos = 0;
156 }
157
158 return file;
159 }
160
161 void vtoydm_close_file(BISO_FILE_S *pstFile)
162 {
163 debug("vtoydm_close_file\n");
164
165 if (pstFile)
166 {
167 free(pstFile);
168 }
169 }
170
171 INT64 vtoydm_seek_file(BISO_FILE_S *pstFile, INT64 i64Offset, INT iFromWhere)
172 {
173 debug("vtoydm_seek_file %d\n", (int)i64Offset);
174
175 if (iFromWhere == SEEK_SET)
176 {
177 pstFile->CurPos = (UINT64)i64Offset;
178 }
179
180 return 0;
181 }
182
183 UINT64 vtoydm_map_iso_sector(UINT64 sector)
184 {
185 int i;
186 UINT64 disk_sector = 0;
187
188 for (i = 0; i < g_img_chunk_num; i++)
189 {
190 if (sector >= g_img_chunk[i].img_start_sector && sector <= g_img_chunk[i].img_end_sector)
191 {
192 disk_sector = ((sector - g_img_chunk[i].img_start_sector) << 2) + g_img_chunk[i].disk_start_sector;
193 break;
194 }
195 }
196
197 return disk_sector;
198 }
199
200 int vtoydm_read_iso_sector(UINT64 sector, void *buf)
201 {
202 int i;
203 int fd;
204 UINT64 disk_sector = 0;
205
206 for (i = 0; i < g_img_chunk_num; i++)
207 {
208 if (sector >= g_img_chunk[i].img_start_sector && sector <= g_img_chunk[i].img_end_sector)
209 {
210 disk_sector = ((sector - g_img_chunk[i].img_start_sector) << 2) + g_img_chunk[i].disk_start_sector;
211 break;
212 }
213 }
214
215 fd = open(g_disk_name, O_RDONLY | O_BINARY);
216 if (fd < 0)
217 {
218 debug("Failed to open %s\n", g_disk_name);
219 return 1;
220 }
221
222 lseek(fd, disk_sector * 512, SEEK_SET);
223
224 read(fd, buf, 2048);
225
226 close(fd);
227 return 0;
228 }
229
230 UINT64 vtoydm_read_file
231 (
232 BISO_FILE_S *pstFile,
233 UINT uiBlkSize,
234 UINT uiBlkNum,
235 VOID *pBuf
236 )
237 {
238 int pos = 0;
239 int align = 0;
240 UINT64 readlen = uiBlkSize * uiBlkNum;
241 char *curbuf = (char *)pBuf;
242
243 debug("vtoydm_read_file length:%u\n", uiBlkSize * uiBlkNum);
244
245 pos = (int)(pstFile->CurPos % 2048);
246 if (pos > 0)
247 {
248 align = 2048 - pos;
249
250 vtoydm_read_iso_sector(pstFile->CurPos / 2048, g_iso_sector_buf);
251 if (readlen > align)
252 {
253 memcpy(curbuf, g_iso_sector_buf + pos, align);
254 curbuf += align;
255 readlen -= align;
256 pstFile->CurPos += align;
257 }
258 else
259 {
260 memcpy(curbuf, g_iso_sector_buf + pos, readlen);
261 pstFile->CurPos += readlen;
262 return readlen;
263 }
264 }
265
266 while (readlen > 2048)
267 {
268 vtoydm_read_iso_sector(pstFile->CurPos / 2048, curbuf);
269 pstFile->CurPos += 2048;
270
271 curbuf += 2048;
272 readlen -= 2048;
273 }
274
275 if (readlen > 0)
276 {
277 vtoydm_read_iso_sector(pstFile->CurPos / 2048, g_iso_sector_buf);
278 memcpy(curbuf, g_iso_sector_buf, readlen);
279 pstFile->CurPos += readlen;
280 }
281
282 return uiBlkSize * uiBlkNum;
283 }
284
285 int vtoydm_dump_iso(const char *img_map_file, const char *diskname)
286 {
287 int i = 0;
288 int len = 0;
289 uint64_t sector_num;
290 unsigned long ret;
291 ventoy_img_chunk *chunk = NULL;
292 BISO_READ_S *iso;
293 BISO_PARSER_S *parser = NULL;
294 char label[64] = {0};
295
296 chunk = vtoydm_get_img_map_data(img_map_file, &len);
297 if (NULL == chunk)
298 {
299 return 1;
300 }
301
302 for (i = 0; i < len / sizeof(ventoy_img_chunk); i++)
303 {
304 sector_num = chunk[i].img_end_sector - chunk[i].img_start_sector + 1;
305 g_iso_file_size += sector_num * 2048;
306 }
307
308 strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
309 g_img_chunk = chunk;
310 g_img_chunk_num = len / sizeof(ventoy_img_chunk);
311
312 debug("iso file size : %llu\n", (unsigned long long)g_iso_file_size);
313
314 iso = BISO_AllocReadHandle();
315 if (iso == NULL)
316 {
317 free(chunk);
318 return 1;
319 }
320
321 ret = BISO_OpenImage("XXX", iso);
322 debug("open iso image ret=0x%lx\n", ret);
323
324 parser = (BISO_PARSER_S *)iso;
325 memcpy(label, parser->pstPVD->szVolumeId, 32);
326 for (i = 32; i >=0; i--)
327 {
328 if (label[i] != 0 && label[i] != ' ')
329 {
330 break;
331 }
332 else
333 {
334 label[i] = 0;
335 }
336 }
337
338 if (label[0])
339 {
340 printf("VENTOY_ISO_LABEL %s\n", label);
341 }
342
343 BISO_DumpFileTree(iso);
344
345 BISO_FreeReadHandle(iso);
346
347 free(chunk);
348 return 0;
349 }
350
351 static int vtoydm_extract_iso
352 (
353 const char *img_map_file,
354 const char *diskname,
355 unsigned long first_sector,
356 unsigned long long file_size,
357 const char *outfile
358 )
359 {
360 int len;
361 FILE *fp = NULL;
362
363 g_img_chunk = vtoydm_get_img_map_data(img_map_file, &len);
364 if (NULL == g_img_chunk)
365 {
366 return 1;
367 }
368
369 strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
370 g_img_chunk_num = len / sizeof(ventoy_img_chunk);
371
372 fp = fopen(outfile, "wb");
373 if (fp == NULL)
374 {
375 fprintf(stderr, "Failed to create file %s err:%d\n", outfile, errno);
376 free(g_img_chunk);
377 return 1;
378 }
379
380 while (file_size > 0)
381 {
382 vtoydm_read_iso_sector(first_sector++, g_iso_sector_buf);
383 if (file_size > 2048)
384 {
385 fwrite(g_iso_sector_buf, 2048, 1, fp);
386 file_size -= 2048;
387 }
388 else
389 {
390 fwrite(g_iso_sector_buf, 1, file_size, fp);
391 file_size = 0;
392 }
393 }
394
395 fclose(fp);
396 free(g_img_chunk);
397 return 0;
398 }
399
400
401 static int vtoydm_print_extract_iso
402 (
403 const char *img_map_file,
404 const char *diskname,
405 unsigned long first_sector,
406 unsigned long long file_size,
407 const char *outfile
408 )
409 {
410 int len;
411 uint32_t last = 0;
412 uint32_t sector = 0;
413 uint32_t disk_first = 0;
414 uint32_t count = 0;
415 uint32_t buf[2];
416 uint64_t size = file_size;
417 FILE *fp = NULL;
418
419 g_img_chunk = vtoydm_get_img_map_data(img_map_file, &len);
420 if (NULL == g_img_chunk)
421 {
422 return 1;
423 }
424
425 strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
426 g_img_chunk_num = len / sizeof(ventoy_img_chunk);
427
428 fp = fopen(outfile, "wb");
429 if (fp == NULL)
430 {
431 fprintf(stderr, "Failed to create file %s err:%d\n", outfile, errno);
432 free(g_img_chunk);
433 return 1;
434 }
435
436 fwrite(g_disk_name, 1, 32, fp);
437 fwrite(&size, 1, 8, fp);
438
439 while (file_size > 0)
440 {
441 sector = vtoydm_map_iso_sector(first_sector++);
442
443 if (count > 0 && sector == last + 4)
444 {
445 last += 4;
446 count += 4;
447 }
448 else
449 {
450 if (count > 0)
451 {
452 buf[0] = disk_first;
453 buf[1] = count;
454 fwrite(buf, 1, sizeof(buf), fp);
455 }
456
457 disk_first = sector;
458 last = sector;
459 count = 4;
460 }
461
462 if (file_size > 2048)
463 {
464 file_size -= 2048;
465 }
466 else
467 {
468 file_size = 0;
469 }
470 }
471
472 if (count > 0)
473 {
474 buf[0] = disk_first;
475 buf[1] = count;
476 fwrite(buf, 1, sizeof(buf), fp);
477 }
478
479 fclose(fp);
480 free(g_img_chunk);
481 return 0;
482 }
483
484
485
486
487 static int vtoydm_print_linear_table(const char *img_map_file, const char *diskname)
488 {
489 int i;
490 int len;
491 uint32_t disk_sector_num;
492 uint32_t sector_start;
493 ventoy_img_chunk *chunk = NULL;
494
495 chunk = vtoydm_get_img_map_data(img_map_file, &len);
496 if (NULL == chunk)
497 {
498 return 1;
499 }
500
501 for (i = 0; i < len / sizeof(ventoy_img_chunk); i++)
502 {
503 sector_start = chunk[i].img_start_sector;
504 disk_sector_num = (uint32_t)(chunk[i].disk_end_sector + 1 - chunk[i].disk_start_sector);
505
506 /* TBD: to be more flexible */
507 #if 0
508 printf("%u %u linear %s %llu\n",
509 (sector_start << 2), disk_sector_num,
510 diskname, (unsigned long long)chunk[i].disk_start_sector);
511 #else
512 if (strstr(diskname, "nvme") || strstr(diskname, "mmc") || strstr(diskname, "nbd"))
513 {
514 printf("%u %u linear %sp1 %llu\n",
515 (sector_start << 2), disk_sector_num,
516 diskname, (unsigned long long)chunk[i].disk_start_sector - 2048);
517 }
518 else
519 {
520 printf("%u %u linear %s1 %llu\n",
521 (sector_start << 2), disk_sector_num,
522 diskname, (unsigned long long)chunk[i].disk_start_sector - 2048);
523 }
524 #endif
525 }
526
527 free(chunk);
528 return 0;
529 }
530
531 static int vtoydm_print_help(FILE *fp)
532 {
533 fprintf(fp, "Usage: \n"
534 " vtoydm -p -f img_map_file -d diskname [ -v ] \n"
535 " vtoydm -c -f img_map_file -d diskname [ -v ] \n"
536 " vtoydm -i -f img_map_file -d diskname [ -v ] \n"
537 " vtoydm -e -f img_map_file -d diskname -s sector -l len -o file [ -v ] \n"
538 );
539 return 0;
540 }
541
542 int vtoydm_main(int argc, char **argv)
543 {
544 int ch;
545 int cmd = 0;
546 unsigned long first_sector = 0;
547 unsigned long long file_size = 0;
548 char diskname[128] = {0};
549 char filepath[300] = {0};
550 char outfile[300] = {0};
551
552 while ((ch = getopt(argc, argv, "s:l:o:d:f:v::i::p::c::h::e::E::")) != -1)
553 {
554 if (ch == 'd')
555 {
556 strncpy(diskname, optarg, sizeof(diskname) - 1);
557 }
558 else if (ch == 'f')
559 {
560 strncpy(filepath, optarg, sizeof(filepath) - 1);
561 }
562 else if (ch == 'p')
563 {
564 cmd = CMD_PRINT_TABLE;
565 }
566 else if (ch == 'c')
567 {
568 cmd = CMD_CREATE_DM;
569 }
570 else if (ch == 'i')
571 {
572 cmd = CMD_DUMP_ISO_INFO;
573 }
574 else if (ch == 'e')
575 {
576 cmd = CMD_EXTRACT_ISO_FILE;
577 }
578 else if (ch == 'E')
579 {
580 cmd = CMD_PRINT_EXTRACT_ISO_FILE;
581 }
582 else if (ch == 's')
583 {
584 first_sector = strtoul(optarg, NULL, 10);
585 }
586 else if (ch == 'l')
587 {
588 file_size = strtoull(optarg, NULL, 10);
589 }
590 else if (ch == 'o')
591 {
592 strncpy(outfile, optarg, sizeof(outfile) - 1);
593 }
594 else if (ch == 'v')
595 {
596 verbose = 1;
597 }
598 else if (ch == 'h')
599 {
600 return vtoydm_print_help(stdout);
601 }
602 else
603 {
604 vtoydm_print_help(stderr);
605 return 1;
606 }
607 }
608
609 if (filepath[0] == 0 || diskname[0] == 0)
610 {
611 fprintf(stderr, "Must input file and disk\n");
612 return 1;
613 }
614
615 debug("cmd=%d file=<%s> disk=<%s> first_sector=%lu file_size=%llu\n",
616 cmd, filepath, diskname, first_sector, file_size);
617
618 switch (cmd)
619 {
620 case CMD_PRINT_TABLE:
621 {
622 return vtoydm_print_linear_table(filepath, diskname);
623 }
624 case CMD_CREATE_DM:
625 {
626 break;
627 }
628 case CMD_DUMP_ISO_INFO:
629 {
630 return vtoydm_dump_iso(filepath, diskname);
631 }
632 case CMD_EXTRACT_ISO_FILE:
633 {
634 return vtoydm_extract_iso(filepath, diskname, first_sector, file_size, outfile);
635 }
636 case CMD_PRINT_EXTRACT_ISO_FILE:
637 {
638 return vtoydm_print_extract_iso(filepath, diskname, first_sector, file_size, outfile);
639 }
640 default :
641 {
642 fprintf(stderr, "Invalid cmd \n");
643 return 1;
644 }
645 }
646
647 return 0;
648 }
649
650 // wrapper main
651 #ifndef BUILD_VTOY_TOOL
652 int main(int argc, char **argv)
653 {
654 return vtoydm_main(argc, argv);
655 }
656 #endif
657