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
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];
78 ventoy_img_chunk
* vtoydm_get_img_map_data(const char *img_map_file
, int *plen
)
83 ventoy_img_chunk
*chunk
= NULL
;
85 fp
= fopen(img_map_file
, "rb");
88 fprintf(stderr
, "Failed to open file %s err:%d\n", img_map_file
, errno
);
92 fseek(fp
, 0, SEEK_END
);
94 fseek(fp
, 0, SEEK_SET
);
96 debug("File <%s> len:%d\n", img_map_file
, len
);
98 chunk
= (ventoy_img_chunk
*)malloc(len
);
101 fprintf(stderr
, "Failed to malloc memory len:%d err:%d\n", len
, errno
);
105 if (fread(chunk
, 1, len
, fp
) != len
)
107 fprintf(stderr
, "Failed to read file err:%d\n", errno
);
111 if (len
% sizeof(ventoy_img_chunk
))
113 fprintf(stderr
, "image map file size %d is not aligned with %d\n",
114 len
, (int)sizeof(ventoy_img_chunk
));
136 UINT64
vtoydm_get_file_size(const char *pcFileName
)
140 debug("vtoydm_get_file_size %s %lu\n", pcFileName
, (unsigned long)g_iso_file_size
);
142 return g_iso_file_size
;
145 BISO_FILE_S
* vtoydm_open_file(const char *pcFileName
)
149 debug("vtoydm_open_file %s\n", pcFileName
);
151 file
= malloc(sizeof(BISO_FILE_S
));
154 memset(file
, 0, sizeof(BISO_FILE_S
));
156 file
->FileSize
= g_iso_file_size
;
163 void vtoydm_close_file(BISO_FILE_S
*pstFile
)
165 debug("vtoydm_close_file\n");
173 INT64
vtoydm_seek_file(BISO_FILE_S
*pstFile
, INT64 i64Offset
, INT iFromWhere
)
175 debug("vtoydm_seek_file %d\n", (int)i64Offset
);
177 if (iFromWhere
== SEEK_SET
)
179 pstFile
->CurPos
= (UINT64
)i64Offset
;
185 UINT64
vtoydm_map_iso_sector(UINT64 sector
)
188 UINT64 disk_sector
= 0;
190 for (i
= 0; i
< g_img_chunk_num
; i
++)
192 if (sector
>= g_img_chunk
[i
].img_start_sector
&& sector
<= g_img_chunk
[i
].img_end_sector
)
194 disk_sector
= ((sector
- g_img_chunk
[i
].img_start_sector
) << 2) + g_img_chunk
[i
].disk_start_sector
;
202 int vtoydm_read_iso_sector(UINT64 sector
, void *buf
)
206 UINT64 disk_sector
= 0;
208 for (i
= 0; i
< g_img_chunk_num
; i
++)
210 if (sector
>= g_img_chunk
[i
].img_start_sector
&& sector
<= g_img_chunk
[i
].img_end_sector
)
212 disk_sector
= ((sector
- g_img_chunk
[i
].img_start_sector
) << 2) + g_img_chunk
[i
].disk_start_sector
;
217 fd
= open(g_disk_name
, O_RDONLY
| O_BINARY
);
220 debug("Failed to open %s\n", g_disk_name
);
224 lseek(fd
, disk_sector
* 512, SEEK_SET
);
232 UINT64 vtoydm_read_file
234 BISO_FILE_S
*pstFile
,
242 UINT64 readlen
= uiBlkSize
* uiBlkNum
;
243 char *curbuf
= (char *)pBuf
;
245 debug("vtoydm_read_file length:%u\n", uiBlkSize
* uiBlkNum
);
247 pos
= (int)(pstFile
->CurPos
% 2048);
252 vtoydm_read_iso_sector(pstFile
->CurPos
/ 2048, g_iso_sector_buf
);
255 memcpy(curbuf
, g_iso_sector_buf
+ pos
, align
);
258 pstFile
->CurPos
+= align
;
262 memcpy(curbuf
, g_iso_sector_buf
+ pos
, readlen
);
263 pstFile
->CurPos
+= readlen
;
268 while (readlen
> 2048)
270 vtoydm_read_iso_sector(pstFile
->CurPos
/ 2048, curbuf
);
271 pstFile
->CurPos
+= 2048;
279 vtoydm_read_iso_sector(pstFile
->CurPos
/ 2048, g_iso_sector_buf
);
280 memcpy(curbuf
, g_iso_sector_buf
, readlen
);
281 pstFile
->CurPos
+= readlen
;
284 return uiBlkSize
* uiBlkNum
;
287 int vtoydm_dump_iso(const char *img_map_file
, const char *diskname
)
293 ventoy_img_chunk
*chunk
= NULL
;
295 BISO_PARSER_S
*parser
= NULL
;
296 char label
[64] = {0};
298 chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
304 for (i
= 0; i
< len
/ sizeof(ventoy_img_chunk
); i
++)
306 sector_num
= chunk
[i
].img_end_sector
- chunk
[i
].img_start_sector
+ 1;
307 g_iso_file_size
+= sector_num
* 2048;
310 strncpy(g_disk_name
, diskname
, sizeof(g_disk_name
) - 1);
312 g_img_chunk_num
= len
/ sizeof(ventoy_img_chunk
);
314 debug("iso file size : %llu\n", (unsigned long long)g_iso_file_size
);
316 iso
= BISO_AllocReadHandle();
323 ret
= BISO_OpenImage("XXX", iso
);
324 debug("open iso image ret=0x%lx\n", ret
);
326 parser
= (BISO_PARSER_S
*)iso
;
327 memcpy(label
, parser
->pstPVD
->szVolumeId
, 32);
328 for (i
= 32; i
>=0; i
--)
330 if (label
[i
] != 0 && label
[i
] != ' ')
342 printf("VENTOY_ISO_LABEL %s\n", label
);
345 BISO_DumpFileTree(iso
);
347 BISO_FreeReadHandle(iso
);
353 static int vtoydm_extract_iso
355 const char *img_map_file
,
356 const char *diskname
,
357 unsigned long first_sector
,
358 unsigned long long file_size
,
365 g_img_chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
366 if (NULL
== g_img_chunk
)
371 strncpy(g_disk_name
, diskname
, sizeof(g_disk_name
) - 1);
372 g_img_chunk_num
= len
/ sizeof(ventoy_img_chunk
);
374 fp
= fopen(outfile
, "wb");
377 fprintf(stderr
, "Failed to create file %s err:%d\n", outfile
, errno
);
382 while (file_size
> 0)
384 vtoydm_read_iso_sector(first_sector
++, g_iso_sector_buf
);
385 if (file_size
> 2048)
387 fwrite(g_iso_sector_buf
, 2048, 1, fp
);
392 fwrite(g_iso_sector_buf
, 1, file_size
, fp
);
403 static int vtoydm_print_extract_iso
405 const char *img_map_file
,
406 const char *diskname
,
407 unsigned long first_sector
,
408 unsigned long long file_size
,
415 uint32_t disk_first
= 0;
418 uint64_t size
= file_size
;
421 g_img_chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
422 if (NULL
== g_img_chunk
)
427 strncpy(g_disk_name
, diskname
, sizeof(g_disk_name
) - 1);
428 g_img_chunk_num
= len
/ sizeof(ventoy_img_chunk
);
430 fp
= fopen(outfile
, "wb");
433 fprintf(stderr
, "Failed to create file %s err:%d\n", outfile
, errno
);
438 fwrite(g_disk_name
, 1, 32, fp
);
439 fwrite(&size
, 1, 8, fp
);
441 while (file_size
> 0)
443 sector
= vtoydm_map_iso_sector(first_sector
++);
445 if (count
> 0 && sector
== last
+ 4)
456 fwrite(buf
, 1, sizeof(buf
), fp
);
464 if (file_size
> 2048)
478 fwrite(buf
, 1, sizeof(buf
), fp
);
489 static int vtoydm_print_linear_table(const char *img_map_file
, const char *diskname
, int part
, uint64_t offset
)
493 uint32_t disk_sector_num
;
494 uint32_t sector_start
;
495 ventoy_img_chunk
*chunk
= NULL
;
497 chunk
= vtoydm_get_img_map_data(img_map_file
, &len
);
503 for (i
= 0; i
< len
/ sizeof(ventoy_img_chunk
); i
++)
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
);
508 /* TBD: to be more flexible */
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
);
514 if (strstr(diskname
, "nvme") || strstr(diskname
, "mmc") || strstr(diskname
, "nbd"))
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
);
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
);
533 static int vtoydm_print_help(FILE *fp
)
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"
544 static uint64_t vtoydm_get_part_start(const char *diskname
, int part
)
547 unsigned long long size
= 0;
548 char diskpath
[256] = {0};
549 char sizebuf
[64] = {0};
551 if (strstr(diskname
, "nvme") || strstr(diskname
, "mmc") || strstr(diskname
, "nbd"))
553 snprintf(diskpath
, sizeof(diskpath
) - 1, "/sys/class/block/%sp%d/start", diskname
, part
);
557 snprintf(diskpath
, sizeof(diskpath
) - 1, "/sys/class/block/%s%d/start", diskname
, part
);
560 if (access(diskpath
, F_OK
) >= 0)
562 debug("get part start from sysfs for %s %d\n", diskname
, part
);
564 fd
= open(diskpath
, O_RDONLY
| O_BINARY
);
567 read(fd
, sizebuf
, sizeof(sizebuf
));
568 size
= strtoull(sizebuf
, NULL
, 10);
575 debug("%s not exist \n", diskpath
);
581 static int vtoydm_vlnk_convert(char *disk
, int len
, int *part
, uint64_t *offset
)
587 ventoy_os_param param
;
588 char diskname
[128] = {0};
590 fp
= fopen("/ventoy/ventoy_os_param", "rb");
593 debug("dm vlnk convert not exist %d\n", errno
);
597 memset(¶m
, 0, sizeof(param
));
598 rdlen
= (int)fread(¶m
, 1, sizeof(param
), fp
);
599 if (rdlen
!= (int)sizeof(param
))
601 debug("fread failed %d %d\n", rdlen
, errno
);
605 debug("dm vlnk convert vtoy_reserved=%d\n", param
.vtoy_reserved
[6]);
607 if (param
.vtoy_reserved
[6])
609 cnt
= vtoy_find_disk_by_guid(¶m
, diskname
);
610 debug("vtoy_find_disk_by_guid cnt=%d\n", cnt
);
613 *part
= param
.vtoy_disk_part_id
;
614 *offset
= vtoydm_get_part_start(diskname
, *part
);
616 debug("VLNK <%s> <%s> <P%d> <%llu>\n", disk
, diskname
, *part
, (unsigned long long)(*offset
));
618 snprintf(disk
, len
, "/dev/%s", diskname
);
630 int vtoydm_main(int argc
, char **argv
)
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};
642 while ((ch
= getopt(argc
, argv
, "s:l:o:d:f:v::i::p::c::h::e::E::")) != -1)
646 strncpy(diskname
, optarg
, sizeof(diskname
) - 1);
650 strncpy(filepath
, optarg
, sizeof(filepath
) - 1);
654 cmd
= CMD_PRINT_TABLE
;
662 cmd
= CMD_DUMP_ISO_INFO
;
666 cmd
= CMD_EXTRACT_ISO_FILE
;
670 cmd
= CMD_PRINT_EXTRACT_ISO_FILE
;
674 first_sector
= strtoul(optarg
, NULL
, 10);
678 file_size
= strtoull(optarg
, NULL
, 10);
682 strncpy(outfile
, optarg
, sizeof(outfile
) - 1);
690 return vtoydm_print_help(stdout
);
694 vtoydm_print_help(stderr
);
699 if (filepath
[0] == 0 || diskname
[0] == 0)
701 fprintf(stderr
, "Must input file and disk\n");
705 debug("cmd=%d file=<%s> disk=<%s> first_sector=%lu file_size=%llu\n",
706 cmd
, filepath
, diskname
, first_sector
, file_size
);
708 vtoydm_vlnk_convert(diskname
, sizeof(diskname
), &part
, &offset
);
712 case CMD_PRINT_TABLE
:
714 return vtoydm_print_linear_table(filepath
, diskname
, part
, offset
);
720 case CMD_DUMP_ISO_INFO
:
722 return vtoydm_dump_iso(filepath
, diskname
);
724 case CMD_EXTRACT_ISO_FILE
:
726 return vtoydm_extract_iso(filepath
, diskname
, first_sector
, file_size
, outfile
);
728 case CMD_PRINT_EXTRACT_ISO_FILE
:
730 return vtoydm_print_extract_iso(filepath
, diskname
, first_sector
, file_size
, outfile
);
734 fprintf(stderr
, "Invalid cmd \n");
743 #ifndef BUILD_VTOY_TOOL
744 int main(int argc
, char **argv
)
746 return vtoydm_main(argc
, argv
);