]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - VtoyTool/vtoydm.c
Fix the order issue in TreeView mode. (#3218)
[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 <dirent.h>
34 #include "biso.h"
35 #include "biso_list.h"
36 #include "biso_util.h"
37 #include "biso_plat.h"
38 #include "biso_9660.h"
39 #include "vtoytool.h"
40
41 #ifndef O_BINARY
42 #define O_BINARY 0
43 #endif
44
45 #ifndef USE_DIET_C
46 #ifndef __mips__
47 typedef unsigned long long uint64_t;
48 #endif
49 typedef unsigned int uint32_t;
50 #endif
51
52 #pragma pack(4)
53 typedef struct ventoy_img_chunk
54 {
55 uint32_t img_start_sector; // sector size: 2KB
56 uint32_t img_end_sector; // included
57
58 uint64_t disk_start_sector; // in disk_sector_size
59 uint64_t disk_end_sector; // included
60 }ventoy_img_chunk;
61 #pragma pack()
62
63 static int verbose = 0;
64 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
65
66 #define CMD_PRINT_TABLE 1
67 #define CMD_CREATE_DM 2
68 #define CMD_DUMP_ISO_INFO 3
69 #define CMD_EXTRACT_ISO_FILE 4
70 #define CMD_PRINT_EXTRACT_ISO_FILE 5
71 #define CMD_PRINT_RAW_TABLE 6
72
73 static uint64_t g_iso_file_size;
74 static char g_disk_name[128];
75 static int g_img_chunk_num = 0;
76 static ventoy_img_chunk *g_img_chunk = NULL;
77 static unsigned char g_iso_sector_buf[2048];
78
79 ventoy_img_chunk * vtoydm_get_img_map_data(const char *img_map_file, int *plen)
80 {
81 int len;
82 int rc = 1;
83 FILE *fp = NULL;
84 ventoy_img_chunk *chunk = NULL;
85
86 fp = fopen(img_map_file, "rb");
87 if (NULL == fp)
88 {
89 fprintf(stderr, "Failed to open file %s err:%d\n", img_map_file, errno);
90 return NULL;
91 }
92
93 fseek(fp, 0, SEEK_END);
94 len = (int)ftell(fp);
95 fseek(fp, 0, SEEK_SET);
96
97 debug("File <%s> len:%d\n", img_map_file, len);
98
99 chunk = (ventoy_img_chunk *)malloc(len);
100 if (NULL == chunk)
101 {
102 fprintf(stderr, "Failed to malloc memory len:%d err:%d\n", len, errno);
103 goto end;
104 }
105
106 if (fread(chunk, 1, len, fp) != len)
107 {
108 fprintf(stderr, "Failed to read file err:%d\n", errno);
109 goto end;
110 }
111
112 if (len % sizeof(ventoy_img_chunk))
113 {
114 fprintf(stderr, "image map file size %d is not aligned with %d\n",
115 len, (int)sizeof(ventoy_img_chunk));
116 goto end;
117 }
118
119 rc = 0;
120 end:
121 fclose(fp);
122
123 if (rc)
124 {
125 if (chunk)
126 {
127 free(chunk);
128 chunk = NULL;
129 }
130 }
131
132 *plen = len;
133 return chunk;
134 }
135
136
137 UINT64 vtoydm_get_file_size(const char *pcFileName)
138 {
139 (void)pcFileName;
140
141 debug("vtoydm_get_file_size %s %lu\n", pcFileName, (unsigned long)g_iso_file_size);
142
143 return g_iso_file_size;
144 }
145
146 BISO_FILE_S * vtoydm_open_file(const char *pcFileName)
147 {
148 BISO_FILE_S *file;
149
150 debug("vtoydm_open_file %s\n", pcFileName);
151
152 file = malloc(sizeof(BISO_FILE_S));
153 if (file)
154 {
155 memset(file, 0, sizeof(BISO_FILE_S));
156
157 file->FileSize = g_iso_file_size;
158 file->CurPos = 0;
159 }
160
161 return file;
162 }
163
164 void vtoydm_close_file(BISO_FILE_S *pstFile)
165 {
166 debug("vtoydm_close_file\n");
167
168 if (pstFile)
169 {
170 free(pstFile);
171 }
172 }
173
174 INT64 vtoydm_seek_file(BISO_FILE_S *pstFile, INT64 i64Offset, INT iFromWhere)
175 {
176 debug("vtoydm_seek_file %d\n", (int)i64Offset);
177
178 if (iFromWhere == SEEK_SET)
179 {
180 pstFile->CurPos = (UINT64)i64Offset;
181 }
182
183 return 0;
184 }
185
186 UINT64 vtoydm_map_iso_sector(UINT64 sector)
187 {
188 int i;
189 UINT64 disk_sector = 0;
190
191 for (i = 0; i < g_img_chunk_num; i++)
192 {
193 if (sector >= g_img_chunk[i].img_start_sector && sector <= g_img_chunk[i].img_end_sector)
194 {
195 disk_sector = ((sector - g_img_chunk[i].img_start_sector) << 2) + g_img_chunk[i].disk_start_sector;
196 break;
197 }
198 }
199
200 return disk_sector;
201 }
202
203 int vtoydm_read_iso_sector(UINT64 sector, void *buf)
204 {
205 int i;
206 int fd;
207 UINT64 disk_sector = 0;
208
209 for (i = 0; i < g_img_chunk_num; i++)
210 {
211 if (sector >= g_img_chunk[i].img_start_sector && sector <= g_img_chunk[i].img_end_sector)
212 {
213 disk_sector = ((sector - g_img_chunk[i].img_start_sector) << 2) + g_img_chunk[i].disk_start_sector;
214 break;
215 }
216 }
217
218 fd = open(g_disk_name, O_RDONLY | O_BINARY);
219 if (fd < 0)
220 {
221 debug("Failed to open %s\n", g_disk_name);
222 return 1;
223 }
224
225 lseek(fd, disk_sector * 512, SEEK_SET);
226
227 read(fd, buf, 2048);
228
229 close(fd);
230 return 0;
231 }
232
233 UINT64 vtoydm_read_file
234 (
235 BISO_FILE_S *pstFile,
236 UINT uiBlkSize,
237 UINT uiBlkNum,
238 VOID *pBuf
239 )
240 {
241 int pos = 0;
242 int align = 0;
243 UINT64 readlen = uiBlkSize * uiBlkNum;
244 char *curbuf = (char *)pBuf;
245
246 debug("vtoydm_read_file length:%u\n", uiBlkSize * uiBlkNum);
247
248 pos = (int)(pstFile->CurPos % 2048);
249 if (pos > 0)
250 {
251 align = 2048 - pos;
252
253 vtoydm_read_iso_sector(pstFile->CurPos / 2048, g_iso_sector_buf);
254 if (readlen > align)
255 {
256 memcpy(curbuf, g_iso_sector_buf + pos, align);
257 curbuf += align;
258 readlen -= align;
259 pstFile->CurPos += align;
260 }
261 else
262 {
263 memcpy(curbuf, g_iso_sector_buf + pos, readlen);
264 pstFile->CurPos += readlen;
265 return readlen;
266 }
267 }
268
269 while (readlen > 2048)
270 {
271 vtoydm_read_iso_sector(pstFile->CurPos / 2048, curbuf);
272 pstFile->CurPos += 2048;
273
274 curbuf += 2048;
275 readlen -= 2048;
276 }
277
278 if (readlen > 0)
279 {
280 vtoydm_read_iso_sector(pstFile->CurPos / 2048, g_iso_sector_buf);
281 memcpy(curbuf, g_iso_sector_buf, readlen);
282 pstFile->CurPos += readlen;
283 }
284
285 return uiBlkSize * uiBlkNum;
286 }
287
288 int vtoydm_dump_iso(const char *img_map_file, const char *diskname)
289 {
290 int i = 0;
291 int len = 0;
292 uint64_t sector_num;
293 unsigned long ret;
294 ventoy_img_chunk *chunk = NULL;
295 BISO_READ_S *iso;
296 BISO_PARSER_S *parser = NULL;
297 char label[64] = {0};
298
299 chunk = vtoydm_get_img_map_data(img_map_file, &len);
300 if (NULL == chunk)
301 {
302 return 1;
303 }
304
305 for (i = 0; i < len / sizeof(ventoy_img_chunk); i++)
306 {
307 sector_num = chunk[i].img_end_sector - chunk[i].img_start_sector + 1;
308 g_iso_file_size += sector_num * 2048;
309 }
310
311 strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
312 g_img_chunk = chunk;
313 g_img_chunk_num = len / sizeof(ventoy_img_chunk);
314
315 debug("iso file size : %llu\n", (unsigned long long)g_iso_file_size);
316
317 iso = BISO_AllocReadHandle();
318 if (iso == NULL)
319 {
320 free(chunk);
321 return 1;
322 }
323
324 ret = BISO_OpenImage("XXX", iso);
325 debug("open iso image ret=0x%lx\n", ret);
326
327 parser = (BISO_PARSER_S *)iso;
328 memcpy(label, parser->pstPVD->szVolumeId, 32);
329 for (i = 32; i >=0; i--)
330 {
331 if (label[i] != 0 && label[i] != ' ')
332 {
333 break;
334 }
335 else
336 {
337 label[i] = 0;
338 }
339 }
340
341 if (label[0])
342 {
343 printf("VENTOY_ISO_LABEL %s\n", label);
344 }
345
346 BISO_DumpFileTree(iso);
347
348 BISO_FreeReadHandle(iso);
349
350 free(chunk);
351 return 0;
352 }
353
354 static int vtoydm_extract_iso
355 (
356 const char *img_map_file,
357 const char *diskname,
358 unsigned long first_sector,
359 unsigned long long file_size,
360 const char *outfile
361 )
362 {
363 int len;
364 FILE *fp = NULL;
365
366 g_img_chunk = vtoydm_get_img_map_data(img_map_file, &len);
367 if (NULL == g_img_chunk)
368 {
369 return 1;
370 }
371
372 strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
373 g_img_chunk_num = len / sizeof(ventoy_img_chunk);
374
375 fp = fopen(outfile, "wb");
376 if (fp == NULL)
377 {
378 fprintf(stderr, "Failed to create file %s err:%d\n", outfile, errno);
379 free(g_img_chunk);
380 return 1;
381 }
382
383 while (file_size > 0)
384 {
385 vtoydm_read_iso_sector(first_sector++, g_iso_sector_buf);
386 if (file_size > 2048)
387 {
388 fwrite(g_iso_sector_buf, 2048, 1, fp);
389 file_size -= 2048;
390 }
391 else
392 {
393 fwrite(g_iso_sector_buf, 1, file_size, fp);
394 file_size = 0;
395 }
396 }
397
398 fclose(fp);
399 free(g_img_chunk);
400 return 0;
401 }
402
403
404 static int vtoydm_print_extract_iso
405 (
406 const char *img_map_file,
407 const char *diskname,
408 unsigned long first_sector,
409 unsigned long long file_size,
410 const char *outfile
411 )
412 {
413 int len;
414 uint32_t last = 0;
415 uint32_t sector = 0;
416 uint32_t disk_first = 0;
417 uint32_t count = 0;
418 uint32_t buf[2];
419 uint64_t size = file_size;
420 FILE *fp = NULL;
421
422 g_img_chunk = vtoydm_get_img_map_data(img_map_file, &len);
423 if (NULL == g_img_chunk)
424 {
425 return 1;
426 }
427
428 strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
429 g_img_chunk_num = len / sizeof(ventoy_img_chunk);
430
431 fp = fopen(outfile, "wb");
432 if (fp == NULL)
433 {
434 fprintf(stderr, "Failed to create file %s err:%d\n", outfile, errno);
435 free(g_img_chunk);
436 return 1;
437 }
438
439 fwrite(g_disk_name, 1, 32, fp);
440 fwrite(&size, 1, 8, fp);
441
442 while (file_size > 0)
443 {
444 sector = vtoydm_map_iso_sector(first_sector++);
445
446 if (count > 0 && sector == last + 4)
447 {
448 last += 4;
449 count += 4;
450 }
451 else
452 {
453 if (count > 0)
454 {
455 buf[0] = disk_first;
456 buf[1] = count;
457 fwrite(buf, 1, sizeof(buf), fp);
458 }
459
460 disk_first = sector;
461 last = sector;
462 count = 4;
463 }
464
465 if (file_size > 2048)
466 {
467 file_size -= 2048;
468 }
469 else
470 {
471 file_size = 0;
472 }
473 }
474
475 if (count > 0)
476 {
477 buf[0] = disk_first;
478 buf[1] = count;
479 fwrite(buf, 1, sizeof(buf), fp);
480 }
481
482 fclose(fp);
483 free(g_img_chunk);
484 return 0;
485 }
486
487
488
489
490 static int vtoydm_print_linear_table(const char *img_map_file, const char *diskname, int part, uint64_t offset)
491 {
492 int i;
493 int len;
494 uint32_t disk_sector_num;
495 uint32_t sector_start;
496 ventoy_img_chunk *chunk = NULL;
497
498 chunk = vtoydm_get_img_map_data(img_map_file, &len);
499 if (NULL == chunk)
500 {
501 return 1;
502 }
503
504 for (i = 0; i < len / sizeof(ventoy_img_chunk); i++)
505 {
506 sector_start = chunk[i].img_start_sector;
507 disk_sector_num = (uint32_t)(chunk[i].disk_end_sector + 1 - chunk[i].disk_start_sector);
508
509 /* TBD: to be more flexible */
510 #if 0
511 printf("%u %u linear %s %llu\n",
512 (sector_start << 2), disk_sector_num,
513 diskname, (unsigned long long)chunk[i].disk_start_sector);
514 #else
515 if (strstr(diskname, "nvme") || strstr(diskname, "mmc") || strstr(diskname, "nbd"))
516 {
517 printf("%u %u linear %sp%d %llu\n",
518 (sector_start << 2), disk_sector_num,
519 diskname, part, (unsigned long long)chunk[i].disk_start_sector - offset);
520 }
521 else
522 {
523 printf("%u %u linear %s%d %llu\n",
524 (sector_start << 2), disk_sector_num,
525 diskname, part, (unsigned long long)chunk[i].disk_start_sector - offset);
526 }
527 #endif
528 }
529
530 free(chunk);
531 return 0;
532 }
533
534 static int vtoydm_print_help(FILE *fp)
535 {
536 fprintf(fp, "Usage: \n"
537 " vtoydm -p -f img_map_file -d diskname [ -v ] \n"
538 " vtoydm -c -f img_map_file -d diskname [ -v ] \n"
539 " vtoydm -i -f img_map_file -d diskname [ -v ] \n"
540 " vtoydm -e -f img_map_file -d diskname -s sector -l len -o file [ -v ] \n"
541 );
542 return 0;
543 }
544
545 static uint64_t vtoydm_get_part_start(const char *diskname, int part)
546 {
547 int fd;
548 unsigned long long size = 0;
549 char diskpath[256] = {0};
550 char sizebuf[64] = {0};
551
552 if (strstr(diskname, "nvme") || strstr(diskname, "mmc") || strstr(diskname, "nbd"))
553 {
554 snprintf(diskpath, sizeof(diskpath) - 1, "/sys/class/block/%sp%d/start", diskname, part);
555 }
556 else
557 {
558 snprintf(diskpath, sizeof(diskpath) - 1, "/sys/class/block/%s%d/start", diskname, part);
559 }
560
561 if (access(diskpath, F_OK) >= 0)
562 {
563 debug("get part start from sysfs for %s %d\n", diskname, part);
564
565 fd = open(diskpath, O_RDONLY | O_BINARY);
566 if (fd >= 0)
567 {
568 read(fd, sizebuf, sizeof(sizebuf));
569 size = strtoull(sizebuf, NULL, 10);
570 close(fd);
571 return size;
572 }
573 }
574 else
575 {
576 debug("%s not exist \n", diskpath);
577 }
578
579 return size;
580 }
581
582 static uint64_t vtoydm_get_part_secnum(const char *diskname, int part)
583 {
584 int fd;
585 unsigned long long size = 0;
586 char diskpath[256] = {0};
587 char sizebuf[64] = {0};
588
589 diskname += 5; /* skip /dev/ */
590
591 if (strstr(diskname, "nvme") || strstr(diskname, "mmc") || strstr(diskname, "nbd"))
592 {
593 snprintf(diskpath, sizeof(diskpath) - 1, "/sys/class/block/%sp%d/size", diskname, part);
594 }
595 else
596 {
597 snprintf(diskpath, sizeof(diskpath) - 1, "/sys/class/block/%s%d/size", diskname, part);
598 }
599
600 if (access(diskpath, F_OK) >= 0)
601 {
602 debug("get part size from sysfs for %s %d\n", diskname, part);
603
604 fd = open(diskpath, O_RDONLY | O_BINARY);
605 if (fd >= 0)
606 {
607 read(fd, sizebuf, sizeof(sizebuf));
608 size = strtoull(sizebuf, NULL, 10);
609 close(fd);
610 return size;
611 }
612 }
613 else
614 {
615 debug("%s not exist \n", diskpath);
616 }
617
618 return size;
619 }
620
621 static int vtoydm_vlnk_convert(char *disk, int len, int *part, uint64_t *offset)
622 {
623 int rc = 1;
624 int cnt = 0;
625 int rdlen;
626 FILE *fp = NULL;
627 ventoy_os_param param;
628 char diskname[128] = {0};
629
630 fp = fopen("/ventoy/ventoy_os_param", "rb");
631 if (!fp)
632 {
633 debug("dm vlnk convert not exist %d\n", errno);
634 goto end;
635 }
636
637 memset(&param, 0, sizeof(param));
638 rdlen = (int)fread(&param, 1, sizeof(param), fp);
639 if (rdlen != (int)sizeof(param))
640 {
641 debug("fread failed %d %d\n", rdlen, errno);
642 goto end;
643 }
644
645 debug("dm vlnk convert vtoy_reserved=%d\n", param.vtoy_reserved[6]);
646
647 if (param.vtoy_reserved[6])
648 {
649 cnt = vtoy_find_disk_by_guid(&param, diskname);
650 debug("vtoy_find_disk_by_guid cnt=%d\n", cnt);
651 if (cnt == 1)
652 {
653 *part = param.vtoy_disk_part_id;
654 *offset = vtoydm_get_part_start(diskname, *part);
655
656 debug("VLNK <%s> <%s> <P%d> <%llu>\n", disk, diskname, *part, (unsigned long long)(*offset));
657
658 snprintf(disk, len, "/dev/%s", diskname);
659
660 rc = 0;
661 }
662 }
663
664 end:
665 if (fp)
666 fclose(fp);
667 return rc;
668 }
669
670 static int vtoydm_print_raw_linear_table(const char *img_map_file, const char *diskname, int part)
671 {
672 uint64_t disk_sector_num;
673
674 disk_sector_num = vtoydm_get_part_secnum(diskname, part);
675
676 if (strstr(diskname, "nvme") || strstr(diskname, "mmc") || strstr(diskname, "nbd"))
677 {
678 printf("0 %lu linear %sp%d 0\n", (unsigned long)disk_sector_num, diskname, part);
679 }
680 else
681 {
682 printf("0 %lu linear %s%d 0\n", (unsigned long)disk_sector_num, diskname, part);
683 }
684
685 return 0;
686 }
687
688 int vtoydm_main(int argc, char **argv)
689 {
690 int ch;
691 int cmd = 0;
692 int part = 1;
693 uint64_t offset = 2048;
694 unsigned long first_sector = 0;
695 unsigned long long file_size = 0;
696 char diskname[128] = {0};
697 char filepath[300] = {0};
698 char outfile[300] = {0};
699
700 while ((ch = getopt(argc, argv, "s:l:o:d:f:v::i::p::r::c::h::e::E::")) != -1)
701 {
702 if (ch == 'd')
703 {
704 strncpy(diskname, optarg, sizeof(diskname) - 1);
705 }
706 else if (ch == 'f')
707 {
708 strncpy(filepath, optarg, sizeof(filepath) - 1);
709 }
710 else if (ch == 'p')
711 {
712 cmd = CMD_PRINT_TABLE;
713 }
714 else if (ch == 'r')
715 {
716 cmd = CMD_PRINT_RAW_TABLE;
717 }
718 else if (ch == 'c')
719 {
720 cmd = CMD_CREATE_DM;
721 }
722 else if (ch == 'i')
723 {
724 cmd = CMD_DUMP_ISO_INFO;
725 }
726 else if (ch == 'e')
727 {
728 cmd = CMD_EXTRACT_ISO_FILE;
729 }
730 else if (ch == 'E')
731 {
732 cmd = CMD_PRINT_EXTRACT_ISO_FILE;
733 }
734 else if (ch == 's')
735 {
736 first_sector = strtoul(optarg, NULL, 10);
737 }
738 else if (ch == 'l')
739 {
740 file_size = strtoull(optarg, NULL, 10);
741 }
742 else if (ch == 'o')
743 {
744 strncpy(outfile, optarg, sizeof(outfile) - 1);
745 }
746 else if (ch == 'v')
747 {
748 verbose = 1;
749 }
750 else if (ch == 'h')
751 {
752 return vtoydm_print_help(stdout);
753 }
754 else
755 {
756 vtoydm_print_help(stderr);
757 return 1;
758 }
759 }
760
761 if (filepath[0] == 0 || diskname[0] == 0)
762 {
763 fprintf(stderr, "Must input file and disk\n");
764 return 1;
765 }
766
767 debug("cmd=%d file=<%s> disk=<%s> first_sector=%lu file_size=%llu\n",
768 cmd, filepath, diskname, first_sector, file_size);
769
770 vtoydm_vlnk_convert(diskname, sizeof(diskname), &part, &offset);
771
772 switch (cmd)
773 {
774 case CMD_PRINT_TABLE:
775 {
776 return vtoydm_print_linear_table(filepath, diskname, part, offset);
777 }
778 case CMD_PRINT_RAW_TABLE:
779 {
780 return vtoydm_print_raw_linear_table(filepath, diskname, part);
781 }
782 case CMD_CREATE_DM:
783 {
784 break;
785 }
786 case CMD_DUMP_ISO_INFO:
787 {
788 return vtoydm_dump_iso(filepath, diskname);
789 }
790 case CMD_EXTRACT_ISO_FILE:
791 {
792 return vtoydm_extract_iso(filepath, diskname, first_sector, file_size, outfile);
793 }
794 case CMD_PRINT_EXTRACT_ISO_FILE:
795 {
796 return vtoydm_print_extract_iso(filepath, diskname, first_sector, file_size, outfile);
797 }
798 default :
799 {
800 fprintf(stderr, "Invalid cmd \n");
801 return 1;
802 }
803 }
804
805 return 0;
806 }
807
808 // wrapper main
809 #ifndef BUILD_VTOY_TOOL
810 int main(int argc, char **argv)
811 {
812 return vtoydm_main(argc, argv);
813 }
814 #endif
815