mirror of
https://github.com/ventoy/Ventoy.git
synced 2025-08-27 16:01:14 +00:00
initial commit
This commit is contained in:
639
VtoyTool/vtoydm.c
Normal file
639
VtoyTool/vtoydm.c
Normal file
@@ -0,0 +1,639 @@
|
||||
/******************************************************************************
|
||||
* vtoydm.c ---- ventoy device mapper tool
|
||||
*
|
||||
* Copyright (c) 2020, longpanda <admin@ventoy.net>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation; either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <linux/fs.h>
|
||||
#include "biso.h"
|
||||
#include "biso_list.h"
|
||||
#include "biso_util.h"
|
||||
#include "biso_plat.h"
|
||||
#include "biso_9660.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef USE_DIET_C
|
||||
typedef unsigned long long uint64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
#endif
|
||||
|
||||
#pragma pack(4)
|
||||
typedef struct ventoy_img_chunk
|
||||
{
|
||||
uint32_t img_start_sector; // sector size: 2KB
|
||||
uint32_t img_end_sector; // included
|
||||
|
||||
uint64_t disk_start_sector; // in disk_sector_size
|
||||
uint64_t disk_end_sector; // included
|
||||
}ventoy_img_chunk;
|
||||
#pragma pack()
|
||||
|
||||
static int verbose = 0;
|
||||
#define debug(fmt, ...) if(verbose) printf(fmt, ##__VA_ARGS__)
|
||||
|
||||
#define CMD_PRINT_TABLE 1
|
||||
#define CMD_CREATE_DM 2
|
||||
#define CMD_DUMP_ISO_INFO 3
|
||||
#define CMD_EXTRACT_ISO_FILE 4
|
||||
#define CMD_PRINT_EXTRACT_ISO_FILE 5
|
||||
|
||||
static uint64_t g_iso_file_size;
|
||||
static char g_disk_name[128];
|
||||
static int g_img_chunk_num = 0;
|
||||
static ventoy_img_chunk *g_img_chunk = NULL;
|
||||
static unsigned char g_iso_sector_buf[2048];
|
||||
|
||||
ventoy_img_chunk * vtoydm_get_img_map_data(const char *img_map_file, int *plen)
|
||||
{
|
||||
int len;
|
||||
int rc = 1;
|
||||
FILE *fp = NULL;
|
||||
ventoy_img_chunk *chunk = NULL;
|
||||
|
||||
fp = fopen(img_map_file, "rb");
|
||||
if (NULL == fp)
|
||||
{
|
||||
fprintf(stderr, "Failed to open file %s err:%d\n", img_map_file, errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fseek(fp, 0, SEEK_END);
|
||||
len = (int)ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
debug("File <%s> len:%d\n", img_map_file, len);
|
||||
|
||||
chunk = (ventoy_img_chunk *)malloc(len);
|
||||
if (NULL == chunk)
|
||||
{
|
||||
fprintf(stderr, "Failed to malloc memory len:%d err:%d\n", len, errno);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (fread(chunk, 1, len, fp) != len)
|
||||
{
|
||||
fprintf(stderr, "Failed to read file err:%d\n", errno);
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (len % sizeof(ventoy_img_chunk))
|
||||
{
|
||||
fprintf(stderr, "image map file size %d is not aligned with %d\n",
|
||||
len, (int)sizeof(ventoy_img_chunk));
|
||||
goto end;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
end:
|
||||
fclose(fp);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
if (chunk)
|
||||
{
|
||||
free(chunk);
|
||||
chunk = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
*plen = len;
|
||||
return chunk;
|
||||
}
|
||||
|
||||
|
||||
UINT64 vtoydm_get_file_size(const char *pcFileName)
|
||||
{
|
||||
(void)pcFileName;
|
||||
|
||||
debug("vtoydm_get_file_size %s %lu\n", pcFileName, (unsigned long)g_iso_file_size);
|
||||
|
||||
return g_iso_file_size;
|
||||
}
|
||||
|
||||
BISO_FILE_S * vtoydm_open_file(const char *pcFileName)
|
||||
{
|
||||
BISO_FILE_S *file;
|
||||
|
||||
debug("vtoydm_open_file %s\n", pcFileName);
|
||||
|
||||
file = malloc(sizeof(BISO_FILE_S));
|
||||
if (file)
|
||||
{
|
||||
memset(file, 0, sizeof(BISO_FILE_S));
|
||||
|
||||
file->FileSize = g_iso_file_size;
|
||||
file->CurPos = 0;
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
|
||||
void vtoydm_close_file(BISO_FILE_S *pstFile)
|
||||
{
|
||||
debug("vtoydm_close_file\n");
|
||||
|
||||
if (pstFile)
|
||||
{
|
||||
free(pstFile);
|
||||
}
|
||||
}
|
||||
|
||||
INT64 vtoydm_seek_file(BISO_FILE_S *pstFile, INT64 i64Offset, INT iFromWhere)
|
||||
{
|
||||
debug("vtoydm_seek_file %d\n", (int)i64Offset);
|
||||
|
||||
if (iFromWhere == SEEK_SET)
|
||||
{
|
||||
pstFile->CurPos = (UINT64)i64Offset;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT64 vtoydm_map_iso_sector(UINT64 sector)
|
||||
{
|
||||
int i;
|
||||
UINT64 disk_sector = 0;
|
||||
|
||||
for (i = 0; i < g_img_chunk_num; i++)
|
||||
{
|
||||
if (sector >= g_img_chunk[i].img_start_sector && sector <= g_img_chunk[i].img_end_sector)
|
||||
{
|
||||
disk_sector = ((sector - g_img_chunk[i].img_start_sector) << 2) + g_img_chunk[i].disk_start_sector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return disk_sector;
|
||||
}
|
||||
|
||||
int vtoydm_read_iso_sector(UINT64 sector, void *buf)
|
||||
{
|
||||
int i;
|
||||
int fd;
|
||||
UINT64 disk_sector = 0;
|
||||
|
||||
for (i = 0; i < g_img_chunk_num; i++)
|
||||
{
|
||||
if (sector >= g_img_chunk[i].img_start_sector && sector <= g_img_chunk[i].img_end_sector)
|
||||
{
|
||||
disk_sector = ((sector - g_img_chunk[i].img_start_sector) << 2) + g_img_chunk[i].disk_start_sector;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fd = open(g_disk_name, O_RDONLY | O_BINARY);
|
||||
if (fd < 0)
|
||||
{
|
||||
debug("Failed to open %s\n", g_disk_name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
lseek(fd, disk_sector * 512, SEEK_SET);
|
||||
|
||||
read(fd, buf, 2048);
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT64 vtoydm_read_file
|
||||
(
|
||||
BISO_FILE_S *pstFile,
|
||||
UINT uiBlkSize,
|
||||
UINT uiBlkNum,
|
||||
VOID *pBuf
|
||||
)
|
||||
{
|
||||
int pos = 0;
|
||||
int align = 0;
|
||||
UINT64 readlen = uiBlkSize * uiBlkNum;
|
||||
char *curbuf = (char *)pBuf;
|
||||
|
||||
debug("vtoydm_read_file length:%u\n", uiBlkSize * uiBlkNum);
|
||||
|
||||
pos = (int)(pstFile->CurPos % 2048);
|
||||
if (pos > 0)
|
||||
{
|
||||
align = 2048 - pos;
|
||||
|
||||
vtoydm_read_iso_sector(pstFile->CurPos / 2048, g_iso_sector_buf);
|
||||
if (readlen > align)
|
||||
{
|
||||
memcpy(curbuf, g_iso_sector_buf + pos, align);
|
||||
curbuf += align;
|
||||
readlen -= align;
|
||||
pstFile->CurPos += align;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(curbuf, g_iso_sector_buf + pos, readlen);
|
||||
pstFile->CurPos += readlen;
|
||||
return readlen;
|
||||
}
|
||||
}
|
||||
|
||||
while (readlen > 2048)
|
||||
{
|
||||
vtoydm_read_iso_sector(pstFile->CurPos / 2048, curbuf);
|
||||
pstFile->CurPos += 2048;
|
||||
|
||||
curbuf += 2048;
|
||||
readlen -= 2048;
|
||||
}
|
||||
|
||||
if (readlen > 0)
|
||||
{
|
||||
vtoydm_read_iso_sector(pstFile->CurPos / 2048, g_iso_sector_buf);
|
||||
memcpy(curbuf, g_iso_sector_buf, readlen);
|
||||
pstFile->CurPos += readlen;
|
||||
}
|
||||
|
||||
return uiBlkSize * uiBlkNum;
|
||||
}
|
||||
|
||||
int vtoydm_dump_iso(const char *img_map_file, const char *diskname)
|
||||
{
|
||||
int i = 0;
|
||||
int len = 0;
|
||||
uint64_t sector_num;
|
||||
unsigned long ret;
|
||||
ventoy_img_chunk *chunk = NULL;
|
||||
BISO_READ_S *iso;
|
||||
BISO_PARSER_S *parser = NULL;
|
||||
char label[64] = {0};
|
||||
|
||||
chunk = vtoydm_get_img_map_data(img_map_file, &len);
|
||||
if (NULL == chunk)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < len / sizeof(ventoy_img_chunk); i++)
|
||||
{
|
||||
sector_num = chunk[i].img_end_sector - chunk[i].img_start_sector + 1;
|
||||
g_iso_file_size += sector_num * 2048;
|
||||
}
|
||||
|
||||
strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
|
||||
g_img_chunk = chunk;
|
||||
g_img_chunk_num = len / sizeof(ventoy_img_chunk);
|
||||
|
||||
debug("iso file size : %llu\n", (unsigned long long)g_iso_file_size);
|
||||
|
||||
iso = BISO_AllocReadHandle();
|
||||
if (iso == NULL)
|
||||
{
|
||||
free(chunk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = BISO_OpenImage("XXX", iso);
|
||||
debug("open iso image ret=0x%lx\n", ret);
|
||||
|
||||
parser = (BISO_PARSER_S *)iso;
|
||||
memcpy(label, parser->pstPVD->szVolumeId, 32);
|
||||
for (i = 32; i >=0; i--)
|
||||
{
|
||||
if (label[i] != 0 && label[i] != ' ')
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
label[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (label[0])
|
||||
{
|
||||
printf("VENTOY_ISO_LABEL %s\n", label);
|
||||
}
|
||||
|
||||
BISO_DumpFileTree(iso);
|
||||
|
||||
BISO_FreeReadHandle(iso);
|
||||
|
||||
free(chunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vtoydm_extract_iso
|
||||
(
|
||||
const char *img_map_file,
|
||||
const char *diskname,
|
||||
unsigned long first_sector,
|
||||
unsigned long long file_size,
|
||||
const char *outfile
|
||||
)
|
||||
{
|
||||
int len;
|
||||
FILE *fp = NULL;
|
||||
|
||||
g_img_chunk = vtoydm_get_img_map_data(img_map_file, &len);
|
||||
if (NULL == g_img_chunk)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
|
||||
g_img_chunk_num = len / sizeof(ventoy_img_chunk);
|
||||
|
||||
fp = fopen(outfile, "wb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to create file %s err:%d\n", outfile, errno);
|
||||
free(g_img_chunk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (file_size > 0)
|
||||
{
|
||||
vtoydm_read_iso_sector(first_sector++, g_iso_sector_buf);
|
||||
if (file_size > 2048)
|
||||
{
|
||||
fwrite(g_iso_sector_buf, 2048, 1, fp);
|
||||
file_size -= 2048;
|
||||
}
|
||||
else
|
||||
{
|
||||
fwrite(g_iso_sector_buf, 1, file_size, fp);
|
||||
file_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
free(g_img_chunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int vtoydm_print_extract_iso
|
||||
(
|
||||
const char *img_map_file,
|
||||
const char *diskname,
|
||||
unsigned long first_sector,
|
||||
unsigned long long file_size,
|
||||
const char *outfile
|
||||
)
|
||||
{
|
||||
int len;
|
||||
uint32_t last = 0;
|
||||
uint32_t sector = 0;
|
||||
uint32_t disk_first = 0;
|
||||
uint32_t count = 0;
|
||||
uint32_t buf[2];
|
||||
uint64_t size = file_size;
|
||||
FILE *fp = NULL;
|
||||
|
||||
g_img_chunk = vtoydm_get_img_map_data(img_map_file, &len);
|
||||
if (NULL == g_img_chunk)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
strncpy(g_disk_name, diskname, sizeof(g_disk_name) - 1);
|
||||
g_img_chunk_num = len / sizeof(ventoy_img_chunk);
|
||||
|
||||
fp = fopen(outfile, "wb");
|
||||
if (fp == NULL)
|
||||
{
|
||||
fprintf(stderr, "Failed to create file %s err:%d\n", outfile, errno);
|
||||
free(g_img_chunk);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fwrite(g_disk_name, 1, 32, fp);
|
||||
fwrite(&size, 1, 8, fp);
|
||||
|
||||
while (file_size > 0)
|
||||
{
|
||||
sector = vtoydm_map_iso_sector(first_sector++);
|
||||
|
||||
if (count > 0 && sector == last + 4)
|
||||
{
|
||||
last += 4;
|
||||
count += 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (count > 0)
|
||||
{
|
||||
buf[0] = disk_first;
|
||||
buf[1] = count;
|
||||
fwrite(buf, 1, sizeof(buf), fp);
|
||||
}
|
||||
|
||||
disk_first = sector;
|
||||
last = sector;
|
||||
count = 4;
|
||||
}
|
||||
|
||||
if (file_size > 2048)
|
||||
{
|
||||
file_size -= 2048;
|
||||
}
|
||||
else
|
||||
{
|
||||
file_size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0)
|
||||
{
|
||||
buf[0] = disk_first;
|
||||
buf[1] = count;
|
||||
fwrite(buf, 1, sizeof(buf), fp);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
free(g_img_chunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int vtoydm_print_linear_table(const char *img_map_file, const char *diskname)
|
||||
{
|
||||
int i;
|
||||
int len;
|
||||
uint32_t sector_start;
|
||||
uint32_t sector_num;
|
||||
ventoy_img_chunk *chunk = NULL;
|
||||
|
||||
chunk = vtoydm_get_img_map_data(img_map_file, &len);
|
||||
if (NULL == chunk)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0; i < len / sizeof(ventoy_img_chunk); i++)
|
||||
{
|
||||
sector_start = chunk[i].img_start_sector;
|
||||
sector_num = chunk[i].img_end_sector - chunk[i].img_start_sector + 1;
|
||||
|
||||
printf("%u %u linear %s %llu\n",
|
||||
(sector_start << 2), (sector_num << 2),
|
||||
diskname, (unsigned long long)chunk[i].disk_start_sector);
|
||||
}
|
||||
|
||||
free(chunk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vtoydm_print_help(FILE *fp)
|
||||
{
|
||||
fprintf(fp, "Usage: \n"
|
||||
" vtoydm -p -f img_map_file -d diskname [ -v ] \n"
|
||||
" vtoydm -c -f img_map_file -d diskname [ -v ] \n"
|
||||
" vtoydm -i -f img_map_file -d diskname [ -v ] \n"
|
||||
" vtoydm -e -f img_map_file -d diskname -s sector -l len -o file [ -v ] \n"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vtoydm_main(int argc, char **argv)
|
||||
{
|
||||
int ch;
|
||||
int cmd = 0;
|
||||
unsigned long first_sector = 0;
|
||||
unsigned long long file_size = 0;
|
||||
char diskname[128] = {0};
|
||||
char filepath[300] = {0};
|
||||
char outfile[300] = {0};
|
||||
|
||||
while ((ch = getopt(argc, argv, "s:l:o:d:f:v::i::p::c::h::e::E::")) != -1)
|
||||
{
|
||||
if (ch == 'd')
|
||||
{
|
||||
strncpy(diskname, optarg, sizeof(diskname) - 1);
|
||||
}
|
||||
else if (ch == 'f')
|
||||
{
|
||||
strncpy(filepath, optarg, sizeof(filepath) - 1);
|
||||
}
|
||||
else if (ch == 'p')
|
||||
{
|
||||
cmd = CMD_PRINT_TABLE;
|
||||
}
|
||||
else if (ch == 'c')
|
||||
{
|
||||
cmd = CMD_CREATE_DM;
|
||||
}
|
||||
else if (ch == 'i')
|
||||
{
|
||||
cmd = CMD_DUMP_ISO_INFO;
|
||||
}
|
||||
else if (ch == 'e')
|
||||
{
|
||||
cmd = CMD_EXTRACT_ISO_FILE;
|
||||
}
|
||||
else if (ch == 'E')
|
||||
{
|
||||
cmd = CMD_PRINT_EXTRACT_ISO_FILE;
|
||||
}
|
||||
else if (ch == 's')
|
||||
{
|
||||
first_sector = strtoul(optarg, NULL, 10);
|
||||
}
|
||||
else if (ch == 'l')
|
||||
{
|
||||
file_size = strtoull(optarg, NULL, 10);
|
||||
}
|
||||
else if (ch == 'o')
|
||||
{
|
||||
strncpy(outfile, optarg, sizeof(outfile) - 1);
|
||||
}
|
||||
else if (ch == 'v')
|
||||
{
|
||||
verbose = 1;
|
||||
}
|
||||
else if (ch == 'h')
|
||||
{
|
||||
return vtoydm_print_help(stdout);
|
||||
}
|
||||
else
|
||||
{
|
||||
vtoydm_print_help(stderr);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (filepath[0] == 0 || diskname[0] == 0)
|
||||
{
|
||||
fprintf(stderr, "Must input file and disk\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
debug("cmd=%d file=<%s> disk=<%s> first_sector=%lu file_size=%llu\n",
|
||||
cmd, filepath, diskname, first_sector, file_size);
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case CMD_PRINT_TABLE:
|
||||
{
|
||||
return vtoydm_print_linear_table(filepath, diskname);
|
||||
}
|
||||
case CMD_CREATE_DM:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CMD_DUMP_ISO_INFO:
|
||||
{
|
||||
return vtoydm_dump_iso(filepath, diskname);
|
||||
}
|
||||
case CMD_EXTRACT_ISO_FILE:
|
||||
{
|
||||
return vtoydm_extract_iso(filepath, diskname, first_sector, file_size, outfile);
|
||||
}
|
||||
case CMD_PRINT_EXTRACT_ISO_FILE:
|
||||
{
|
||||
return vtoydm_print_extract_iso(filepath, diskname, first_sector, file_size, outfile);
|
||||
}
|
||||
default :
|
||||
{
|
||||
fprintf(stderr, "Invalid cmd \n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// wrapper main
|
||||
#ifndef BUILD_VTOY_TOOL
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return vtoydm_main(argc, argv);
|
||||
}
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user