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