1.0.66 release

This commit is contained in:
longpanda
2022-02-13 17:00:39 +08:00
parent c57717aea2
commit ba5978d298
287 changed files with 3349 additions and 226 deletions

77
Vlnk/src/crc32.c Normal file
View File

@@ -0,0 +1,77 @@
/******************************************************************************
* crc32.c ----
*
* Copyright (c) 2022, 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 <stdint.h>
#include <string.h>
#include "vlnk.h"
static uint32_t crc32c_table [256];
/* Helper for init_crc32c_table. */
static uint32_t reflect (uint32_t ref, int len)
{
uint32_t result = 0;
int i;
for (i = 1; i <= len; i++)
{
if (ref & 1)
result |= 1 << (len - i);
ref >>= 1;
}
return result;
}
static void init_crc32c_table (void)
{
uint32_t polynomial = 0x1edc6f41;
int i, j;
for(i = 0; i < 256; i++)
{
crc32c_table[i] = reflect(i, 8) << 24;
for (j = 0; j < 8; j++)
crc32c_table[i] = (crc32c_table[i] << 1) ^
(crc32c_table[i] & (1 << 31) ? polynomial : 0);
crc32c_table[i] = reflect(crc32c_table[i], 32);
}
}
uint32_t ventoy_getcrc32c (uint32_t crc, const void *buf, int size)
{
int i;
const uint8_t *data = buf;
if (! crc32c_table[1])
init_crc32c_table ();
crc^= 0xffffffff;
for (i = 0; i < size; i++)
{
crc = (crc >> 8) ^ crc32c_table[(crc & 0xFF) ^ *data];
data++;
}
return crc ^ 0xffffffff;
}

457
Vlnk/src/main_linux.c Normal file
View File

@@ -0,0 +1,457 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/statfs.h>
#include <dirent.h>
#include <unistd.h>
#include "vlnk.h"
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
#define IS_DIGIT(x) ((x) >= '0' && (x) <= '9')
static int verbose = 0;
#define debug(fmt, args...) if(verbose) printf(fmt, ##args)
static uint8_t g_vlnk_buf[VLNK_FILE_LEN];
static int64_t get_file_size(char *file)
{
struct stat stStat;
if (stat(file, &stStat) < 0)
{
return -1;
}
return (int64_t)(stStat.st_size);
}
static int get_disk_sig(char *diskname, uint32_t *sig)
{
int fd;
uint8_t buf[512] = {0};
fd = open(diskname, O_RDONLY);
if (fd < 0)
{
printf("Failed to open %s\n", diskname);
return 1;
}
read(fd, buf, 512);
close(fd);
memcpy(sig, buf + 0x1b8, 4);
return 0;
}
static int vtoy_get_disk_guid(const char *diskname, uint8_t *vtguid, uint8_t *vtsig)
{
int i = 0;
int fd = 0;
char devdisk[128] = {0};
snprintf(devdisk, sizeof(devdisk) - 1, "/dev/%s", diskname);
fd = open(devdisk, O_RDONLY);
if (fd >= 0)
{
lseek(fd, 0x180, SEEK_SET);
read(fd, vtguid, 16);
lseek(fd, 0x1b8, SEEK_SET);
read(fd, vtsig, 4);
close(fd);
return 0;
}
else
{
debug("failed to open %s %d\n", devdisk, errno);
return errno;
}
}
static int vtoy_is_possible_blkdev(const char *name)
{
if (name[0] == '.')
{
return 0;
}
/* /dev/ramX */
if (name[0] == 'r' && name[1] == 'a' && name[2] == 'm')
{
return 0;
}
/* /dev/loopX */
if (name[0] == 'l' && name[1] == 'o' && name[2] == 'o' && name[3] == 'p')
{
return 0;
}
/* /dev/dm-X */
if (name[0] == 'd' && name[1] == 'm' && name[2] == '-' && IS_DIGIT(name[3]))
{
return 0;
}
/* /dev/srX */
if (name[0] == 's' && name[1] == 'r' && IS_DIGIT(name[2]))
{
return 0;
}
return 1;
}
static int find_disk_by_sig(uint8_t *sig, char *diskname)
{
int rc = 0;
int count = 0;
DIR* dir = NULL;
struct dirent* p = NULL;
uint8_t vtguid[16];
uint8_t vtsig[16];
dir = opendir("/sys/block");
if (!dir)
{
return 0;
}
while ((p = readdir(dir)) != NULL)
{
if (!vtoy_is_possible_blkdev(p->d_name))
{
continue;
}
rc = vtoy_get_disk_guid(p->d_name, vtguid, vtsig);
if (rc == 0 && memcmp(vtsig, sig, 4) == 0)
{
sprintf(diskname, "%s", p->d_name);
count++;
}
}
closedir(dir);
return count;
}
static uint64_t get_part_offset(char *partname)
{
int fd;
uint64_t offset;
char buf[32] = {0};
char path[PATH_MAX];
snprintf(path, PATH_MAX - 1, "/sys/class/block/%s/start", partname);
fd = open(path, O_RDONLY);
if (fd < 0)
{
return 0;
}
read(fd, buf, sizeof(buf));
close(fd);
offset = (uint64_t)strtoull(buf, NULL, 10);
offset *= 512;
return offset;
}
static int create_vlnk(char *infile, char *diskname, uint64_t partoff, char *outfile)
{
FILE *fp;
int len;
uint32_t sig = 0;
debug("create vlnk\n");
if (infile[0] == 0 || outfile[0] == 0 || diskname[0] == 0 || partoff == 0)
{
debug("Invalid parameters: %d %d %d %llu\n", infile[0], outfile[0], diskname[0], (unsigned long long)partoff);
return 1;
}
len = (int)strlen(infile);
if (len >= VLNK_NAME_MAX)
{
printf("File name length %d is too long for vlnk!\n", len);
return 1;
}
if (get_disk_sig(diskname, &sig))
{
printf("Failed to read disk sig\n");
return 1;
}
fp = fopen(outfile, "wb+");
if (!fp)
{
printf("Failed to create file %s\n", outfile);
return 1;
}
memset(g_vlnk_buf, 0, sizeof(g_vlnk_buf));
ventoy_create_vlnk(sig, partoff, infile, (ventoy_vlnk *)g_vlnk_buf);
fwrite(g_vlnk_buf, 1, VLNK_FILE_LEN, fp);
fclose(fp);
return 0;
}
static int get_mount_point(char *partname, char *mntpoint)
{
int i;
int len;
int rc = 1;
FILE *fp = NULL;
char line[PATH_MAX];
fp = fopen("/proc/mounts", "r");
if (!fp)
{
return 1;
}
len = (int)strlen(partname);
while (fgets(line, sizeof(line), fp))
{
if (strncmp(line, partname, len) == 0)
{
for (i = len; i < PATH_MAX && line[i]; i++)
{
if (line[i] == ' ')
{
line[i] = 0;
rc = 0;
strncpy(mntpoint, line + len, PATH_MAX - 1);
break;
}
}
break;
}
}
fclose(fp);
return rc;
}
static int parse_vlnk(char *infile)
{
int i;
int fd;
int cnt;
int pflag = 0;
char diskname[128] = {0};
char partname[128] = {0};
char partpath[256] = {0};
char mntpoint[PATH_MAX];
ventoy_vlnk vlnk;
debug("parse vlnk\n");
if (infile[0] == 0)
{
debug("input file null\n");
return 1;
}
fd = open(infile, O_RDONLY);
if (fd < 0)
{
printf("Failed to open file %s error %d\n", infile, errno);
return 1;
}
memset(&vlnk, 0, sizeof(vlnk));
read(fd, &vlnk, sizeof(vlnk));
close(fd);
debug("disk_signature:%08X\n", vlnk.disk_signature);
debug("file path:<%s>\n", vlnk.filepath);
debug("part offset: %llu\n", (unsigned long long)vlnk.part_offset);
cnt = find_disk_by_sig((uint8_t *)&(vlnk.disk_signature), diskname);
if (cnt != 1)
{
printf("Disk in vlnk not found!\n");
return 1;
}
debug("Disk is <%s>\n", diskname);
if (strstr(diskname, "nvme") || strstr(diskname, "mmc") || strstr(diskname, "nbd"))
{
pflag = 1;
}
for (i = 1; i <= 128; i++)
{
if (pflag)
{
snprintf(partname, sizeof(partname) - 1, "%sp%d", diskname, i);
}
else
{
snprintf(partname, sizeof(partname) - 1, "%s%d", diskname, i);
}
if (get_part_offset(partname) == vlnk.part_offset)
{
debug("Find correct partition </dev/%s>\n", partname);
break;
}
}
if (i > 128)
{
printf("Partition in vlnk not found!");
return 1;
}
snprintf(partpath, sizeof(partpath), "/dev/%s ", partname);
if (get_mount_point(partpath, mntpoint))
{
printf("Mountpoint of %s is not found!\n", partpath);
return 1;
}
debug("moutpoint of %s is <%s>\n", partpath, mntpoint);
strcat(mntpoint, vlnk.filepath);
printf("Vlnk Point: %s\n", mntpoint);
if (access(mntpoint, F_OK) >= 0)
{
printf("File Exist: YES\n");
}
else
{
printf("File Exist: NO\n");
}
return 0;
}
static int check_vlnk(char *infile)
{
int fd;
int64_t size;
ventoy_vlnk vlnk;
debug("check vlnk\n");
if (infile[0] == 0)
{
debug("input file null\n");
return 1;
}
size = get_file_size(infile);
if (size != VLNK_FILE_LEN)
{
debug("file size %lld is not a vlnk file size\n", (long long)size);
return 1;
}
fd = open(infile, O_RDONLY);
if (fd < 0)
{
debug("Failed to open file %s error %d\n", infile, errno);
return 1;
}
memset(&vlnk, 0, sizeof(vlnk));
read(fd, &vlnk, sizeof(vlnk));
close(fd);
if (CheckVlnkData(&vlnk))
{
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
int ch = 0;
int cmd = 0;
uint64_t partoff = 0;
char infile[PATH_MAX] = {0};
char outfile[PATH_MAX] = {0};
char diskname[256] = {0};
while ((ch = getopt(argc, argv, "c:t:l:d:p:o:v::")) != -1)
{
if (ch == 'c')
{
cmd = 1;
strncpy(infile, optarg, sizeof(infile) - 1);
}
else if (ch == 'o')
{
strncpy(outfile, optarg, sizeof(outfile) - 1);
}
else if (ch == 'l')
{
cmd = 2;
strncpy(infile, optarg, sizeof(infile) - 1);
}
else if (ch == 't')
{
cmd = 3;
strncpy(infile, optarg, sizeof(infile) - 1);
}
else if (ch == 'd')
{
strncpy(diskname, optarg, sizeof(diskname) - 1);
}
else if (ch == 'p')
{
partoff = (uint64_t)strtoull(optarg, NULL, 10);
partoff *= 512;
}
else if (ch == 'v')
{
verbose = 1;
}
else
{
return 1;
}
}
if (cmd == 1)
{
return create_vlnk(infile, diskname, partoff, outfile);
}
else if (cmd == 2)
{
return parse_vlnk(infile);
}
else if (cmd == 3)
{
return check_vlnk(infile);
}
else
{
printf("Invalid command %d\n", cmd);
return 1;
}
}

711
Vlnk/src/main_windows.c Normal file
View File

@@ -0,0 +1,711 @@
#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
#include <resource.h>
#include <vlnk.h>
static WCHAR g_CurDirW[MAX_PATH];
static CHAR g_CurDirA[MAX_PATH];
static CHAR g_LogFile[MAX_PATH];
static HWND g_create_button;
static HWND g_parse_button;
typedef enum MSGID
{
MSGID_ERROR = 0,
MSGID_INFO,
MSGID_BTN_CREATE,
MSGID_BTN_PARSE,
MSGID_SRC_UNSUPPORTED,
MSGID_FS_UNSUPPORTED,
MSGID_SUFFIX_UNSUPPORTED,
MSGID_DISK_INFO_ERR,
MSGID_VLNK_SUCCESS,
MSGID_RUNNING_TIP,
MSGID_CREATE_FILE_ERR,
MSGID_ALREADY_VLNK,
MSGID_INVALID_VLNK,
MSGID_VLNK_POINT_TO,
MSGID_VLNK_NO_DST,
MSGID_FILE_NAME_TOO_LONG,
MSGID_BUTT
}MSGID;
const WCHAR *g_msg_cn[MSGID_BUTT] =
{
L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
L"<EFBFBD><EFBFBD>֧<EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>vlnk",
L"<EFBFBD><EFBFBD>֧<EFBFBD>ֵ<EFBFBD><EFBFBD>ļ<EFBFBD>ϵͳ",
L"<EFBFBD><EFBFBD>֧<EFBFBD>ֵ<EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD><EFBFBD>׺<EFBFBD><EFBFBD>",
L"<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϣʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
L"Vlnk <20>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD><C9B9><EFBFBD>",
L"<EFBFBD><EFBFBD><EFBFBD>ȹر<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD> VentoyVlnk <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
L"<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD>ʧ<EFBFBD><EFBFBD>",
L"<EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><EFBFBD>Ѿ<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD>vlnk<EFBFBD>ļ<EFBFBD><EFBFBD>ˣ<EFBFBD>",
L"<EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>vlnk<EFBFBD>ļ<EFBFBD>!",
L"<EFBFBD><EFBFBD> vlnk <20>ļ<EFBFBD>ָ<EFBFBD><D6B8> ",
L"<EFBFBD><EFBFBD> vlnk ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڣ<EFBFBD>",
L"<EFBFBD>ļ<EFBFBD>·<EFBFBD><EFBFBD>̫<EFBFBD><EFBFBD><EFBFBD><EFBFBD>",
};
const WCHAR *g_msg_en[MSGID_BUTT] =
{
L"Error",
L"Info",
L"Create",
L"Parse",
L"This file is not supported for vlnk",
L"Unsupported file system!",
L"Unsupported file suffix!",
L"Error when getting disk info",
L"Vlnk file successfully created!",
L"Please close another running VentoyVlnk instance!",
L"Failed to create file!",
L"This file is already a vlnk file!",
L"Invalid vlnk file!",
L"The vlnk file point to ",
L"The file pointed by the vlnk does NOT exist!",
L"The file full path is too long!",
};
const WCHAR **g_msg_lang = NULL;
HINSTANCE g_hInst;
static void Log2File(const char *log)
{
time_t stamp;
struct tm ttm;
FILE *fp;
time(&stamp);
localtime_s(&ttm, &stamp);
fopen_s(&fp, g_LogFile, "a+");
if (fp)
{
fprintf_s(fp, "[%04u/%02u/%02u %02u:%02u:%02u] %s",
ttm.tm_year + 1900, ttm.tm_mon + 1, ttm.tm_mday,
ttm.tm_hour, ttm.tm_min, ttm.tm_sec, log);
fclose(fp);
}
}
void LogW(const WCHAR *Fmt, ...)
{
WCHAR log[512];
CHAR alog[2048];
va_list arg;
if (g_LogFile[0] == 0)
{
return;
}
va_start(arg, Fmt);
vswprintf_s(log, 512, Fmt, arg);
va_end(arg);
WideCharToMultiByte(CP_UTF8, 0, log, -1, alog, 2048, 0, 0);
Log2File(alog);
}
void LogA(const CHAR *Fmt, ...)
{
CHAR log[512];
va_list arg;
if (g_LogFile[0] == 0)
{
return;
}
va_start(arg, Fmt);
vsprintf_s(log, 512, Fmt, arg);
va_end(arg);
Log2File(log);
}
static int Utf8ToUtf16(const char* src, WCHAR * dst)
{
int size = MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, 0);
return MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size + 1);
}
static BOOL OnDestroyDialog()
{
return TRUE;
}
static BOOL InitDialog(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
HICON hIcon;
g_create_button = GetDlgItem(hWnd, IDC_BUTTON1);
g_parse_button = GetDlgItem(hWnd, IDC_BUTTON2);
hIcon = LoadIcon(g_hInst, MAKEINTRESOURCE(IDI_ICON1));
SendMessage(hWnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
SendMessage(hWnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
SetWindowTextW(g_create_button, g_msg_lang[MSGID_BTN_CREATE]);
SetWindowTextW(g_parse_button, g_msg_lang[MSGID_BTN_PARSE]);
return TRUE;
}
static int GetPhyDiskInfo(const char LogicalDrive, UINT32 *DiskSig, DISK_EXTENT *DiskExtent)
{
BOOL Ret;
DWORD dwSize;
HANDLE Handle;
VOLUME_DISK_EXTENTS DiskExtents;
CHAR PhyPath[128];
UINT8 SectorBuf[512];
LogA("GetPhyDiskInfo %C\n", LogicalDrive);
sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", LogicalDrive);
Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (Handle == INVALID_HANDLE_VALUE)
{
LogA("Could not open the disk %C: error:%u\n", LogicalDrive, GetLastError());
return 1;
}
Ret = DeviceIoControl(Handle,
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
NULL,
0,
&DiskExtents,
(DWORD)(sizeof(DiskExtents)),
(LPDWORD)&dwSize,
NULL);
if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
{
LogA("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error:%u\n", GetLastError());
CloseHandle(Handle);
return 1;
}
CloseHandle(Handle);
memcpy(DiskExtent, DiskExtents.Extents, sizeof(DISK_EXTENT));
LogA("%C: is in PhysicalDrive%d Offset:%llu\n", LogicalDrive, DiskExtents.Extents[0].DiskNumber,
(ULONGLONG)(DiskExtents.Extents[0].StartingOffset.QuadPart));
sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskExtents.Extents[0].DiskNumber);
Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
if (Handle == INVALID_HANDLE_VALUE)
{
LogA("Could not open the disk<PhysicalDrive%d>, error:%u\n", DiskExtents.Extents[0].DiskNumber, GetLastError());
return 1;
}
if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))
{
LogA("ReadFile failed, dwSize:%u error:%u\n", dwSize, GetLastError());
CloseHandle(Handle);
return 1;
}
memcpy(DiskSig, SectorBuf + 0x1B8, 4);
CloseHandle(Handle);
return 0;
}
static int SaveBuffer2File(const WCHAR *Fullpath, void *Buffer, DWORD Length)
{
int rc = 1;
DWORD dwSize;
HANDLE Handle;
LogW(L"SaveBuffer2File <%ls> len:%u\n", Fullpath, Length);
Handle = CreateFileW(Fullpath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
if (Handle == INVALID_HANDLE_VALUE)
{
LogA("Could not create new file, error:%u\n", GetLastError());
goto End;
}
WriteFile(Handle, Buffer, Length, &dwSize, NULL);
rc = 0;
End:
if (Handle != INVALID_HANDLE_VALUE)
{
CloseHandle(Handle);
}
return rc;
}
static int DefaultVlnkDstFullPath(WCHAR *Src, WCHAR *Dir, WCHAR *Dst)
{
int i, j;
int len;
int wrlen;
WCHAR C;
len = (int)lstrlen(Src);
for (i = len - 1; i >= 0; i--)
{
if (Src[i] == '.')
{
C = Src[i];
Src[i] = 0;
wrlen = swprintf_s(Dst, MAX_PATH, L"%ls\\%ls.vlnk.%ls", Dir, Src, Src + i + 1);
Src[i] = C;
for (j = wrlen - (len - i); j < wrlen; j++)
{
if (Dst[j] >= 'A' && Dst[j] <= 'Z')
{
Dst[j] = 'a' + (Dst[j] - 'A');
}
}
break;
}
}
return 0;
}
static BOOL IsVlnkFile(WCHAR *path, ventoy_vlnk *outvlnk)
{
BOOL bRet;
BOOL bVlnk = FALSE;
DWORD dwSize;
LARGE_INTEGER FileSize;
HANDLE Handle;
ventoy_vlnk vlnk;
Handle = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (Handle == INVALID_HANDLE_VALUE)
{
LogA("Could not open this file, error:%u\n", GetLastError());
return FALSE;
}
if (!GetFileSizeEx(Handle, &FileSize))
{
LogA("Failed to get vlnk file size\n");
goto End;
}
if (FileSize.QuadPart != VLNK_FILE_LEN)
{
LogA("Invalid vlnk file length %llu\n", (unsigned long long)FileSize.QuadPart);
goto End;
}
memset(&vlnk, 0, sizeof(vlnk));
bRet = ReadFile(Handle, &vlnk, sizeof(vlnk), &dwSize, NULL);
if (bRet && CheckVlnkData(&vlnk))
{
if (outvlnk)
{
memcpy(outvlnk, &vlnk, sizeof(vlnk));
}
bVlnk = TRUE;
}
End:
if (Handle != INVALID_HANDLE_VALUE)
{
CloseHandle(Handle);
}
return bVlnk;
}
static int CreateVlnk(HWND hWnd, WCHAR *Dir)
{
int i;
int end;
int len;
UINT32 DiskSig;
DISK_EXTENT DiskExtend;
OPENFILENAME ofn = { 0 };
CHAR UTF8Path[MAX_PATH];
WCHAR DstFullPath[MAX_PATH];
WCHAR szFile[MAX_PATH] = { 0 };
CHAR suffix[8] = { 0 };
CHAR Drive[8] = { 0 };
CHAR FsName[64] = { 0 };
CHAR *Buf = NULL;
WCHAR *Pos = NULL;
ventoy_vlnk *vlnk = NULL;
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"Vlnk Source File\0*.iso;*.img;*.wim;*.vhd;*.vhdx;*.vtoy;*.efi;*.dat\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn) != TRUE)
{
return 1;
}
LogW(L"Create vlnk for <%ls>\n", szFile);
len = lstrlen(szFile);
if (len < 5 || szFile[0] == '.' || szFile[1] != ':')
{
MessageBox(hWnd, g_msg_lang[MSGID_SRC_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
Drive[0] = (CHAR)szFile[0];
Drive[1] = ':';
Drive[2] = '\\';
if (0 == GetVolumeInformationA(Drive, NULL, 0, NULL, NULL, NULL, FsName, sizeof(FsName) - 1))
{
LogA("GetVolumeInformationA failed %u\n", GetLastError());
return 1;
}
LogA("Partition filesystem of <%s> is <%s>\n", Drive, FsName);
if (_stricmp(FsName, "NTFS") == 0 ||
_stricmp(FsName, "exFAT") == 0 ||
_stricmp(FsName, "FAT") == 0 ||
_stricmp(FsName, "FAT32") == 0 ||
_stricmp(FsName, "FAT16") == 0 ||
_stricmp(FsName, "FAT12") == 0 ||
_stricmp(FsName, "UDF") == 0)
{
LogA("FS Check OK\n");
}
else
{
MessageBox(hWnd, g_msg_lang[MSGID_FS_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
end = (szFile[len - 5] == '.') ? 5 : 4;
for (i = 0; i < end; i++)
{
suffix[i] = (CHAR)szFile[len - (end - i)];
}
if (!IsSupportedImgSuffix(suffix))
{
MessageBox(hWnd, g_msg_lang[MSGID_SUFFIX_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
if (IsVlnkFile(szFile, NULL))
{
MessageBox(hWnd, g_msg_lang[MSGID_ALREADY_VLNK], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
for (i = 0; i < MAX_PATH && szFile[i]; i++)
{
if (szFile[i] == '\\' || szFile[i] == '/')
{
Pos = szFile + i;
}
}
if (!Pos)
{
LogA("name part not found\n");
return 1;
}
LogW(L"File Name is <%ls>\n", Pos + 1);
memset(UTF8Path, 0, sizeof(UTF8Path));
WideCharToMultiByte(CP_UTF8, 0, szFile + 2, -1, UTF8Path, MAX_PATH, NULL, 0);
for (i = 0; i < MAX_PATH && UTF8Path[i]; i++)
{
if (UTF8Path[i] == '\\')
{
UTF8Path[i] = '/';
}
}
len = (int)strlen(UTF8Path);
if (len >= VLNK_NAME_MAX)
{
LogA("File name length %d overflow\n", len);
MessageBox(hWnd, g_msg_lang[MSGID_FILE_NAME_TOO_LONG], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
DiskExtend.StartingOffset.QuadPart = 0;
if (GetPhyDiskInfo((char)szFile[0], &DiskSig, &DiskExtend))
{
MessageBox(hWnd, g_msg_lang[MSGID_DISK_INFO_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
Buf = malloc(VLNK_FILE_LEN);
if (Buf)
{
memset(Buf, 0, VLNK_FILE_LEN);
vlnk = (ventoy_vlnk *)Buf;
ventoy_create_vlnk(DiskSig, (uint64_t)DiskExtend.StartingOffset.QuadPart, UTF8Path, vlnk);
DefaultVlnkDstFullPath(Pos + 1, Dir, DstFullPath);
LogW(L"vlnk output file path is <%ls>\n", DstFullPath);
if (SaveBuffer2File(DstFullPath, Buf, VLNK_FILE_LEN) == 0)
{
WCHAR Msg[1024];
swprintf_s(Msg, 1024, L"%ls\r\n\r\n%ls", g_msg_lang[MSGID_VLNK_SUCCESS], DstFullPath + lstrlen(Dir) + 1);
LogW(L"Vlnk file create success <%ls>\n", DstFullPath);
MessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
}
else
{
LogA("Vlnk file save failed\n");
MessageBox(hWnd, g_msg_lang[MSGID_CREATE_FILE_ERR], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
}
free(Buf);
}
return 0;
}
static CHAR GetDriveLetter(UINT32 disksig, UINT64 PartOffset)
{
CHAR Letter;
DWORD Drives;
UINT32 Sig;
DISK_EXTENT DiskExtent;
Letter = 'A';
Drives = GetLogicalDrives();
LogA("Logic Drives: 0x%x", Drives);
while (Drives)
{
if (Drives & 0x01)
{
Sig = 0;
DiskExtent.StartingOffset.QuadPart = 0;
if (GetPhyDiskInfo(Letter, &Sig, &DiskExtent) == 0)
{
if (Sig == disksig && DiskExtent.StartingOffset.QuadPart == PartOffset)
{
return Letter;
}
}
}
Drives >>= 1;
Letter++;
}
return 0;
}
static int ParseVlnk(HWND hWnd)
{
int i;
CHAR Letter;
ventoy_vlnk vlnk;
OPENFILENAME ofn = { 0 };
WCHAR szFile[MAX_PATH] = { 0 };
WCHAR szDst[MAX_PATH + 2] = { 0 };
WCHAR Msg[1024];
CHAR *suffix = NULL;
HANDLE hFile;
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFile = szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFilter = L"Vlnk File\0*.vlnk.iso;*.vlnk.img;*.vlnk.wim;*.vlnk.efi;*.vlnk.vhd;*.vlnk.vhdx;*.vlnk.vtoy;*.vlnk.dat\0";
ofn.nFilterIndex = 1;
ofn.lpstrFileTitle = NULL;
ofn.nMaxFileTitle = 0;
ofn.lpstrInitialDir = NULL;
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
if (GetOpenFileName(&ofn) != TRUE)
{
return 1;
}
LogW(L"Parse vlnk for <%ls>\n", szFile);
if (!IsVlnkFile(szFile, &vlnk))
{
MessageBox(hWnd, g_msg_lang[MSGID_INVALID_VLNK], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
for (i = 0; i < sizeof(vlnk.filepath) && vlnk.filepath[i]; i++)
{
if (vlnk.filepath[i] == '.')
{
suffix = vlnk.filepath + i;
}
}
if (!IsSupportedImgSuffix(suffix))
{
MessageBox(hWnd, g_msg_lang[MSGID_SUFFIX_UNSUPPORTED], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
Utf8ToUtf16(vlnk.filepath, szDst + 2);
for (i = 2; i < MAX_PATH && szDst[i]; i++)
{
if (szDst[i] == '/')
{
szDst[i] = '\\';
}
}
Letter = GetDriveLetter(vlnk.disk_signature, vlnk.part_offset);
if (Letter == 0)
{
MessageBox(hWnd, g_msg_lang[MSGID_VLNK_NO_DST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
szDst[0] = toupper(Letter);
szDst[1] = ':';
LogW(L"vlnk dst is %ls\n", szDst);
hFile = CreateFileW(szDst, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (INVALID_HANDLE_VALUE == hFile)
{
MessageBox(hWnd, g_msg_lang[MSGID_VLNK_NO_DST], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
CloseHandle(hFile);
swprintf_s(Msg, 1024, L"%ls %ls", g_msg_lang[MSGID_VLNK_POINT_TO], szDst);
MessageBox(hWnd, Msg, g_msg_lang[MSGID_INFO], MB_OK | MB_ICONINFORMATION);
return 0;
}
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
WORD NotifyCode;
WORD CtrlID;
switch (Message)
{
case WM_COMMAND:
{
NotifyCode = HIWORD(wParam);
CtrlID = LOWORD(wParam);
if (NotifyCode == BN_CLICKED)
{
if (CtrlID == IDC_BUTTON1)
{
EnableWindow(g_create_button, FALSE);
CreateVlnk(hWnd, g_CurDirW);
EnableWindow(g_create_button, TRUE);
}
else if (CtrlID == IDC_BUTTON2)
{
EnableWindow(g_parse_button, FALSE);
ParseVlnk(hWnd);
EnableWindow(g_parse_button, TRUE);
}
}
break;
}
case WM_INITDIALOG:
{
InitDialog(hWnd, wParam, lParam);
break;
}
case WM_CLOSE:
{
OnDestroyDialog();
EndDialog(hWnd, 0);
}
}
return 0;
}
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow)
{
int i;
HANDLE hMutex;
UNREFERENCED_PARAMETER(hPrevInstance);
if (GetUserDefaultUILanguage() == 0x0804)
{
g_msg_lang = g_msg_cn;
}
else
{
g_msg_lang = g_msg_en;
}
hMutex = CreateMutexA(NULL, TRUE, "VtoyVlnkMUTEX");
if ((hMutex != NULL) && (GetLastError() == ERROR_ALREADY_EXISTS))
{
MessageBoxW(NULL, g_msg_lang[MSGID_RUNNING_TIP], g_msg_lang[MSGID_ERROR], MB_OK | MB_ICONERROR);
return 1;
}
GetCurrentDirectoryA(MAX_PATH, g_CurDirA);
GetCurrentDirectoryW(MAX_PATH, g_CurDirW);
sprintf_s(g_LogFile, sizeof(g_LogFile), "%s\\VentoyVlnk.log", g_CurDirA);
for (i = 0; i < __argc; i++)
{
if (strncmp(__argv[i], "-Q", 2) == 0 ||
strncmp(__argv[i], "-q", 2) == 0)
{
g_LogFile[0] = 0;
break;
}
}
LogA("========= VentoyVlnk =========\n");
g_hInst = hInstance;
DialogBoxA(hInstance, MAKEINTRESOURCEA(IDD_DIALOG1), NULL, DialogProc);
return 0;
}

80
Vlnk/src/vlnk.c Normal file
View File

@@ -0,0 +1,80 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include "vlnk.h"
int ventoy_create_vlnk(uint32_t disksig, uint64_t partoffset, const char *path, ventoy_vlnk *vlnk)
{
uint32_t crc;
ventoy_guid guid = VENTOY_GUID;
memcpy(&(vlnk->guid), &guid, sizeof(ventoy_guid));
vlnk->disk_signature = disksig;
vlnk->part_offset = partoffset;
#ifdef WIN32
strcpy_s(vlnk->filepath, sizeof(vlnk->filepath) - 1, path);
#else
strncpy(vlnk->filepath, path, sizeof(vlnk->filepath) - 1);
#endif
crc = ventoy_getcrc32c(0, vlnk, sizeof(ventoy_vlnk));
vlnk->crc32 = crc;
return 0;
}
int CheckVlnkData(ventoy_vlnk *vlnk)
{
uint32_t readcrc, calccrc;
ventoy_guid guid = VENTOY_GUID;
if (memcmp(&vlnk->guid, &guid, sizeof(guid)))
{
return 0;
}
readcrc = vlnk->crc32;
vlnk->crc32 = 0;
calccrc = ventoy_getcrc32c(0, vlnk, sizeof(ventoy_vlnk));
if (readcrc != calccrc)
{
return 0;
}
return 1;
}
int IsSupportedImgSuffix(char *suffix)
{
int i = 0;
const char *suffixs[] =
{
".iso", ".img", ".wim", ".efi", ".vhd", ".vhdx", ".dat", ".vtoy", NULL
};
if (!suffix)
{
return 0;
}
while (suffixs[i])
{
#ifdef WIN32
if (_stricmp(suffixs[i], suffix) == 0)
#else
if (strcasecmp(suffixs[i], suffix) == 0)
#endif
{
return 1;
}
i++;
}
return 0;
}

38
Vlnk/src/vlnk.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef __VLNK_H__
#define __VLNK_H__
#define VLNK_FILE_LEN 32768
#define VLNK_NAME_MAX 384
#define VENTOY_GUID { 0x77772020, 0x2e77, 0x6576, { 0x6e, 0x74, 0x6f, 0x79, 0x2e, 0x6e, 0x65, 0x74 }}
#pragma pack(1)
typedef struct ventoy_guid
{
uint32_t data1;
uint16_t data2;
uint16_t data3;
uint8_t data4[8];
}ventoy_guid;
typedef struct ventoy_vlnk
{
ventoy_guid guid; // VENTOY_GUID
uint32_t crc32; // crc32
uint32_t disk_signature;
uint64_t part_offset; // in bytes
char filepath[VLNK_NAME_MAX];
uint8_t reserverd[96];
}ventoy_vlnk;
#pragma pack()
uint32_t ventoy_getcrc32c (uint32_t crc, const void *buf, int size);
int ventoy_create_vlnk(uint32_t disksig, uint64_t partoffset, const char *path, ventoy_vlnk *vlnk);
int CheckVlnkData(ventoy_vlnk *vlnk);
int IsSupportedImgSuffix(char *suffix);
#endif