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