1 /******************************************************************************
2 * vtoydm.c ---- ventoy device mapper tool
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
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.
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.
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/>.
27 #include <sys/types.h>
29 #include <sys/ioctl.h>
31 #include <sys/types.h>
35 #include "biso_list.h"
36 #include "biso_util.h"
37 #include "biso_plat.h"
38 #include "biso_9660.h"
47 typedef unsigned long long uint64_t;
49 typedef unsigned int uint32_t;
53 typedef struct ventoy_img_chunk
55 uint32_t img_start_sector
; // sector size: 2KB
56 uint32_t img_end_sector
; // included
58 uint64_t disk_start_sector
; // in disk_sector_size
59 uint64_t disk_end_sector
; // included
63 static int verbose
= 0;
64 #define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
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
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];
79 ventoy_img_chunk
* vtoydm_get_img_map_data(const char *img_map_file
, int *plen
)
84 ventoy_img_chunk
*chunk
= NULL
;
86 fp
= fopen(img_map_file
, "rb");
89 fprintf(stderr
, "Failed to open file %s err:%d\n", img_map_file
, errno
);
93 fseek(fp
, 0, SEEK_END
);
95 fseek(fp
, 0, SEEK_SET
);
97 debug("File <%s> len:%d\n", img_map_file
, len
);
99 chunk
= (ventoy_img_chunk
*)malloc(len
);
102 fprintf(stderr
, "Failed to malloc memory len:%d err:%d\n", len
, errno
);
106 if (fread(chunk
, 1, len
, fp
) != len
)
108 fprintf(stderr
, "Failed to read file err:%d\n", errno
);
112 if (len
% sizeof(ventoy_img_chunk
))
114 fprintf(stderr
, "image map file size %d is not aligned with %d\n",
115 len
, (int)sizeof(ventoy_img_chunk
));
137 UINT64
vtoydm_get_file_size(const char *pcFileName
)
141 debug("vtoydm_get_file_size %s %lu\n", pcFileName
, (unsigned long)g_iso_file_size
);
143 return g_iso_file_size
;
146 BISO_FILE_S
* vtoydm_open_file(const char *pcFileName
)
150 debug("vtoydm_open_file %s\n", pcFileName
);
152 file
= malloc(sizeof(BISO_FILE_S
));
155 memset(file
, 0, sizeof(BISO_FILE_S
));
157 file
->FileSize
= g_iso_file_size
;
164 void vtoydm_close_file(BISO_FILE_S
*pstFile
)
166 debug("vtoydm_close_file\n");
174 INT64
vtoydm_seek_file(BISO_FILE_S
*pstFile
, INT64 i64Offset
, INT iFromWhere
)
176 debug("vtoydm_seek_file %d\n", (int)i64Offset
);
178 if (iFromWhere
== SEEK_SET
)
180 pstFile
->CurPos
= (UINT64
)i64Offset
;
186 UINT64
vtoydm_map_iso_sector(UINT64 sector
)
189 UINT64 disk_sector
= 0;
191 for (i
= 0; i
< g_img_chunk_num
; i
++)
193 if (sector
>= g_img_chunk
[i
].img_start_sector
&& sector
<= g_img_chunk
[i
].img_end_sector
)
195 disk_sector
= ((sector
- g_img_chunk
[i
].img_start_sector
) << 2) + g_img_chunk
[i
].disk_start_sector
;
203 int vtoydm_read_iso_sector(UINT64 sector
, void *buf
)
207 UINT64 disk_sector
= 0;
209 for (i
= 0; i
< g_img_chunk_num
; i
++)
211 if (sector
>= g_img_chunk
[i
].img_start_sector
&& sector
<= g_img_chunk
[i
].img_end_sector
)
213 disk_sector
= ((sector
- g_img_chunk
[i
].img_start_sector
) << 2) + g_img_chunk
[i
].disk_start_sector
;
218 fd
= open(g_disk_name
, O_RDONLY
| O_BINARY
);
221 debug("Failed to open %s\n", g_disk_name
);
225 lseek(fd
, disk_sector
* 512, SEEK_SET
);
233 UINT64 vtoydm_read_file
235 BISO_FILE_S
*pstFile
,
243 UINT64 readlen
= uiBlkSize
* uiBlkNum
;
244 char *curbuf
= (char *)pBuf
;
246 debug("vtoydm_read_file length:%u\n", uiBlkSize
* uiBlkNum
);
248 pos
= (int)(pstFile
->CurPos
% 2048);
253 vtoydm_read_iso_sector(pstFile
->CurPos
/ 2048, g_iso_sector_buf
);
256 memcpy(curbuf
, g_iso_sector_buf
+ pos
, align
);
259 pstFile
->CurPos
+= align
;
263 memcpy(curbuf
, g_iso_sector_buf
+ pos
, readlen
);
264 pstFile
->CurPos
+= readlen
;
269 while (readlen
> 2048)
271 vtoydm_read_iso_sector(pstFile
->CurPos
/ 2048, curbuf
);
272 pstFile
->CurPos
+= 2048;
280 vtoydm_read_iso_sector(pstFile
->CurPos
/ 2048, g_iso_sector_buf
);
281 memcpy(curbuf
, g_iso_sector_buf
, readlen
);
282 pstFile
->CurPos
+= readlen
;
285 return uiBlkSize
* uiBlkNum
;
288 int vtoydm_dump_iso(const char *img_map_file
, const char *diskname
)
294 ventoy_img_chunk
*chunk
= NULL
;
296 BISO_PARSER_S
*parser
= NULL
;
297 char label
[64] = {0};
299 chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
305 for (i
= 0; i
< len
/ sizeof(ventoy_img_chunk
); i
++)
307 sector_num
= chunk
[i
].img_end_sector
- chunk
[i
].img_start_sector
+ 1;
308 g_iso_file_size
+= sector_num
* 2048;
311 strncpy(g_disk_name
, diskname
, sizeof(g_disk_name
) - 1);
313 g_img_chunk_num
= len
/ sizeof(ventoy_img_chunk
);
315 debug("iso file size : %llu\n", (unsigned long long)g_iso_file_size
);
317 iso
= BISO_AllocReadHandle();
324 ret
= BISO_OpenImage("XXX", iso
);
325 debug("open iso image ret=0x%lx\n", ret
);
327 parser
= (BISO_PARSER_S
*)iso
;
328 memcpy(label
, parser
->pstPVD
->szVolumeId
, 32);
329 for (i
= 32; i
>=0; i
--)
331 if (label
[i
] != 0 && label
[i
] != ' ')
343 printf("VENTOY_ISO_LABEL %s\n", label
);
346 BISO_DumpFileTree(iso
);
348 BISO_FreeReadHandle(iso
);
354 static int vtoydm_extract_iso
356 const char *img_map_file
,
357 const char *diskname
,
358 unsigned long first_sector
,
359 unsigned long long file_size
,
366 g_img_chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
367 if (NULL
== g_img_chunk
)
372 strncpy(g_disk_name
, diskname
, sizeof(g_disk_name
) - 1);
373 g_img_chunk_num
= len
/ sizeof(ventoy_img_chunk
);
375 fp
= fopen(outfile
, "wb");
378 fprintf(stderr
, "Failed to create file %s err:%d\n", outfile
, errno
);
383 while (file_size
> 0)
385 vtoydm_read_iso_sector(first_sector
++, g_iso_sector_buf
);
386 if (file_size
> 2048)
388 fwrite(g_iso_sector_buf
, 2048, 1, fp
);
393 fwrite(g_iso_sector_buf
, 1, file_size
, fp
);
404 static int vtoydm_print_extract_iso
406 const char *img_map_file
,
407 const char *diskname
,
408 unsigned long first_sector
,
409 unsigned long long file_size
,
416 uint32_t disk_first
= 0;
419 uint64_t size
= file_size
;
422 g_img_chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
423 if (NULL
== g_img_chunk
)
428 strncpy(g_disk_name
, diskname
, sizeof(g_disk_name
) - 1);
429 g_img_chunk_num
= len
/ sizeof(ventoy_img_chunk
);
431 fp
= fopen(outfile
, "wb");
434 fprintf(stderr
, "Failed to create file %s err:%d\n", outfile
, errno
);
439 fwrite(g_disk_name
, 1, 32, fp
);
440 fwrite(&size
, 1, 8, fp
);
442 while (file_size
> 0)
444 sector
= vtoydm_map_iso_sector(first_sector
++);
446 if (count
> 0 && sector
== last
+ 4)
457 fwrite(buf
, 1, sizeof(buf
), fp
);
465 if (file_size
> 2048)
479 fwrite(buf
, 1, sizeof(buf
), fp
);
490 static int vtoydm_print_linear_table(const char *img_map_file
, const char *diskname
, int part
, uint64_t offset
)
494 uint32_t disk_sector_num
;
495 uint32_t sector_start
;
496 ventoy_img_chunk
*chunk
= NULL
;
498 chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
504 for (i
= 0; i
< len
/ sizeof(ventoy_img_chunk
); i
++)
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
);
509 /* TBD: to be more flexible */
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
);
515 if (strstr(diskname
, "nvme") || strstr(diskname
, "mmc") || strstr(diskname
, "nbd"))
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
);
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
);
534 static int vtoydm_print_help(FILE *fp
)
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"
545 static uint64_t vtoydm_get_part_start(const char *diskname
, int part
)
548 unsigned long long size
= 0;
549 char diskpath
[256] = {0};
550 char sizebuf
[64] = {0};
552 if (strstr(diskname
, "nvme") || strstr(diskname
, "mmc") || strstr(diskname
, "nbd"))
554 snprintf(diskpath
, sizeof(diskpath
) - 1, "/sys/class/block/%sp%d/start", diskname
, part
);
558 snprintf(diskpath
, sizeof(diskpath
) - 1, "/sys/class/block/%s%d/start", diskname
, part
);
561 if (access(diskpath
, F_OK
) >= 0)
563 debug("get part start from sysfs for %s %d\n", diskname
, part
);
565 fd
= open(diskpath
, O_RDONLY
| O_BINARY
);
568 read(fd
, sizebuf
, sizeof(sizebuf
));
569 size
= strtoull(sizebuf
, NULL
, 10);
576 debug("%s not exist \n", diskpath
);
582 static uint64_t vtoydm_get_part_secnum(const char *diskname
, int part
)
585 unsigned long long size
= 0;
586 char diskpath
[256] = {0};
587 char sizebuf
[64] = {0};
589 diskname
+= 5; /* skip /dev/ */
591 if (strstr(diskname
, "nvme") || strstr(diskname
, "mmc") || strstr(diskname
, "nbd"))
593 snprintf(diskpath
, sizeof(diskpath
) - 1, "/sys/class/block/%sp%d/size", diskname
, part
);
597 snprintf(diskpath
, sizeof(diskpath
) - 1, "/sys/class/block/%s%d/size", diskname
, part
);
600 if (access(diskpath
, F_OK
) >= 0)
602 debug("get part size from sysfs for %s %d\n", diskname
, part
);
604 fd
= open(diskpath
, O_RDONLY
| O_BINARY
);
607 read(fd
, sizebuf
, sizeof(sizebuf
));
608 size
= strtoull(sizebuf
, NULL
, 10);
615 debug("%s not exist \n", diskpath
);
621 static int vtoydm_vlnk_convert(char *disk
, int len
, int *part
, uint64_t *offset
)
627 ventoy_os_param param
;
628 char diskname
[128] = {0};
630 fp
= fopen("/ventoy/ventoy_os_param", "rb");
633 debug("dm vlnk convert not exist %d\n", errno
);
637 memset(¶m
, 0, sizeof(param
));
638 rdlen
= (int)fread(¶m
, 1, sizeof(param
), fp
);
639 if (rdlen
!= (int)sizeof(param
))
641 debug("fread failed %d %d\n", rdlen
, errno
);
645 debug("dm vlnk convert vtoy_reserved=%d\n", param
.vtoy_reserved
[6]);
647 if (param
.vtoy_reserved
[6])
649 cnt
= vtoy_find_disk_by_guid(¶m
, diskname
);
650 debug("vtoy_find_disk_by_guid cnt=%d\n", cnt
);
653 *part
= param
.vtoy_disk_part_id
;
654 *offset
= vtoydm_get_part_start(diskname
, *part
);
656 debug("VLNK <%s> <%s> <P%d> <%llu>\n", disk
, diskname
, *part
, (unsigned long long)(*offset
));
658 snprintf(disk
, len
, "/dev/%s", diskname
);
670 static int vtoydm_print_raw_linear_table(const char *img_map_file
, const char *diskname
, int part
)
672 uint64_t disk_sector_num
;
674 disk_sector_num
= vtoydm_get_part_secnum(diskname
, part
);
676 if (strstr(diskname
, "nvme") || strstr(diskname
, "mmc") || strstr(diskname
, "nbd"))
678 printf("0 %lu linear %sp%d 0\n", (unsigned long)disk_sector_num
, diskname
, part
);
682 printf("0 %lu linear %s%d 0\n", (unsigned long)disk_sector_num
, diskname
, part
);
688 int vtoydm_main(int argc
, char **argv
)
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};
700 while ((ch
= getopt(argc
, argv
, "s:l:o:d:f:v::i::p::r::c::h::e::E::")) != -1)
704 strncpy(diskname
, optarg
, sizeof(diskname
) - 1);
708 strncpy(filepath
, optarg
, sizeof(filepath
) - 1);
712 cmd
= CMD_PRINT_TABLE
;
716 cmd
= CMD_PRINT_RAW_TABLE
;
724 cmd
= CMD_DUMP_ISO_INFO
;
728 cmd
= CMD_EXTRACT_ISO_FILE
;
732 cmd
= CMD_PRINT_EXTRACT_ISO_FILE
;
736 first_sector
= strtoul(optarg
, NULL
, 10);
740 file_size
= strtoull(optarg
, NULL
, 10);
744 strncpy(outfile
, optarg
, sizeof(outfile
) - 1);
752 return vtoydm_print_help(stdout
);
756 vtoydm_print_help(stderr
);
761 if (filepath
[0] == 0 || diskname
[0] == 0)
763 fprintf(stderr
, "Must input file and disk\n");
767 debug("cmd=%d file=<%s> disk=<%s> first_sector=%lu file_size=%llu\n",
768 cmd
, filepath
, diskname
, first_sector
, file_size
);
770 vtoydm_vlnk_convert(diskname
, sizeof(diskname
), &part
, &offset
);
774 case CMD_PRINT_TABLE
:
776 return vtoydm_print_linear_table(filepath
, diskname
, part
, offset
);
778 case CMD_PRINT_RAW_TABLE
:
780 return vtoydm_print_raw_linear_table(filepath
, diskname
, part
);
786 case CMD_DUMP_ISO_INFO
:
788 return vtoydm_dump_iso(filepath
, diskname
);
790 case CMD_EXTRACT_ISO_FILE
:
792 return vtoydm_extract_iso(filepath
, diskname
, first_sector
, file_size
, outfile
);
794 case CMD_PRINT_EXTRACT_ISO_FILE
:
796 return vtoydm_print_extract_iso(filepath
, diskname
, first_sector
, file_size
, outfile
);
800 fprintf(stderr
, "Invalid cmd \n");
809 #ifndef BUILD_VTOY_TOOL
810 int main(int argc
, char **argv
)
812 return vtoydm_main(argc
, argv
);