1 /******************************************************************************
2 * ventoy_util.c ---- ventoy util
3 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 3 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
28 #include <sys/types.h>
29 #include <sys/ioctl.h>
31 #include <sys/types.h>
32 #include <sys/mount.h>
36 #include <ventoy_define.h>
37 #include <ventoy_util.h>
39 uint8_t g_mbr_template
[512];
41 void ventoy_gen_preudo_uuid(void *uuid
)
46 fd
= open("/dev/urandom", O_RDONLY
| O_BINARY
);
50 for (i
= 0; i
< 8; i
++)
52 *((uint16_t *)uuid
+ i
) = (uint16_t)(rand() & 0xFFFF);
62 uint64_t ventoy_get_human_readable_gb(uint64_t SizeBytes
)
67 double GB
= SizeBytes
* 1.0 / 1000 / 1000 / 1000;
69 if ((SizeBytes
% SIZE_1GB
) == 0)
71 return (uint64_t)(SizeBytes
/ SIZE_1GB
);
74 for (i
= 0; i
< 12; i
++)
78 Delta
= (Pow2
- GB
) / Pow2
;
82 Delta
= (GB
- Pow2
) / Pow2
;
97 int ventoy_get_sys_file_line(char *buffer
, int buflen
, const char *fmt
, ...)
105 vsnprintf(path
, 256, fmt
, arg
);
108 if (access(path
, F_OK
) >= 0)
110 FILE *fp
= fopen(path
, "r");
111 memset(buffer
, 0, buflen
);
112 len
= (int)fread(buffer
, 1, buflen
- 1, fp
);
118 if (c
== '\r' || c
== '\n' || c
== ' ' || c
== '\t')
133 vdebug("%s not exist \n", path
);
138 int ventoy_is_disk_mounted(const char *devpath
)
145 fp
= fopen("/proc/mounts", "r");
151 len
= (int)strlen(devpath
);
152 while (fgets(line
, sizeof(line
), fp
))
154 if (strncmp(line
, devpath
, len
) == 0)
157 vdebug("%s mounted <%s>\n", devpath
, line
);
167 static int ventoy_mount_path_escape(char *src
, char *dst
, int len
)
174 for (i
= 0; i
< len
- 1; i
++)
176 if (src
[i
] == '\\' && src
[i
+ 1] == '0' && src
[i
+ 2] == '4' && src
[i
+ 3] == '0')
195 int ventoy_try_umount_disk(const char *devpath
)
205 fp
= fopen("/proc/mounts", "r");
211 len
= (int)strlen(devpath
);
212 while (fgets(line
, sizeof(line
), fp
))
214 if (strncmp(line
, devpath
, len
) == 0)
216 pos1
= strchr(line
, ' ');
219 pos2
= strchr(pos1
+ 1, ' ');
225 ventoy_mount_path_escape(pos1
+ 1, mntpt
, sizeof(mntpt
));
229 vdebug("umount <%s> <%s> [ failed ] error:%d\n", devpath
, mntpt
, errno
);
233 vdebug("umount <%s> <%s> [ success ]\n", devpath
, mntpt
);
243 int ventoy_read_file_to_buf(const char *FileName
, int ExtLen
, void **Bufer
, int *BufLen
)
249 fp
= fopen(FileName
, "rb");
252 vlog("Failed to open file %s", FileName
);
256 fseek(fp
, 0, SEEK_END
);
257 FileSize
= (int)ftell(fp
);
259 Data
= malloc(FileSize
+ ExtLen
);
266 fseek(fp
, 0, SEEK_SET
);
267 fread(Data
, 1, FileSize
, fp
);
277 const char * ventoy_get_local_version(void)
283 static char LocalVersion
[64] = { 0 };
285 if (LocalVersion
[0] == 0)
287 rc
= ventoy_read_file_to_buf("ventoy/version", 1, (void **)&Buf
, &FileSize
);
294 for (Pos
= Buf
; *Pos
; Pos
++)
296 if (*Pos
== '\r' || *Pos
== '\n')
303 scnprintf(LocalVersion
, "%s", Buf
);
310 int VentoyGetLocalBootImg(MBR_HEAD
*pMBR
)
312 memcpy(pMBR
, g_mbr_template
, 512);
316 static int VentoyFillProtectMBR(uint64_t DiskSizeBytes
, MBR_HEAD
*pMBR
)
319 uint32_t DiskSignature
;
320 uint64_t DiskSectorCount
;
322 VentoyGetLocalBootImg(pMBR
);
324 ventoy_gen_preudo_uuid(&Guid
);
326 memcpy(&DiskSignature
, &Guid
, sizeof(uint32_t));
328 vdebug("Disk signature: 0x%08x\n", DiskSignature
);
330 memcpy(pMBR
->BootCode
+ 0x1B8, &DiskSignature
, 4);
331 memcpy(pMBR
->BootCode
+ 0x180, &Guid
, 16);
333 DiskSectorCount
= DiskSizeBytes
/ 512 - 1;
334 if (DiskSectorCount
> 0xFFFFFFFF)
336 DiskSectorCount
= 0xFFFFFFFF;
339 memset(pMBR
->PartTbl
, 0, sizeof(pMBR
->PartTbl
));
341 pMBR
->PartTbl
[0].Active
= 0x00;
342 pMBR
->PartTbl
[0].FsFlag
= 0xee; // EE
344 pMBR
->PartTbl
[0].StartHead
= 0;
345 pMBR
->PartTbl
[0].StartSector
= 1;
346 pMBR
->PartTbl
[0].StartCylinder
= 0;
347 pMBR
->PartTbl
[0].EndHead
= 254;
348 pMBR
->PartTbl
[0].EndSector
= 63;
349 pMBR
->PartTbl
[0].EndCylinder
= 1023;
351 pMBR
->PartTbl
[0].StartSectorId
= 1;
352 pMBR
->PartTbl
[0].SectorCount
= (uint32_t)DiskSectorCount
;
357 pMBR
->BootCode
[92] = 0x22;
362 static int ventoy_fill_gpt_partname(uint16_t Name
[36], const char *asciiName
)
367 memset(Name
, 0, 36 * sizeof(uint16_t));
368 len
= (int)strlen(asciiName
);
369 for (i
= 0; i
< 36 && i
< len
; i
++)
371 Name
[i
] = asciiName
[i
];
377 int ventoy_fill_gpt(uint64_t size
, uint64_t reserve
, int align4k
, VTOY_GPT_INFO
*gpt
)
379 uint64_t ReservedSector
= 33;
380 uint64_t ModSectorCount
= 0;
381 uint64_t Part1SectorCount
= 0;
382 uint64_t DiskSectorCount
= size
/ 512;
383 VTOY_GPT_HDR
*Head
= &gpt
->Head
;
384 VTOY_GPT_PART_TBL
*Table
= gpt
->PartTbl
;
385 ventoy_guid WindowsDataPartType
= { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
386 //ventoy_guid EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
387 //ventoy_guid BiosGrubPartType = { 0x21686148, 0x6449, 0x6e6f, { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } };
389 VentoyFillProtectMBR(size
, &gpt
->MBR
);
393 ReservedSector
+= reserve
/ 512;
396 Part1SectorCount
= DiskSectorCount
- ReservedSector
- (VTOYEFI_PART_BYTES
/ 512) - 2048;
398 ModSectorCount
= (Part1SectorCount
% 8);
401 vlog("Part1SectorCount:%llu is not aligned by 4KB (%llu)\n", (_ull
)Part1SectorCount
, (_ull
)ModSectorCount
);
404 // check aligned with 4KB
409 vdebug("Disk need to align with 4KB %u\n", (uint32_t)ModSectorCount
);
410 Part1SectorCount
-= ModSectorCount
;
414 vdebug("no need to align with 4KB\n");
418 memcpy(Head
->Signature
, "EFI PART", 8);
419 Head
->Version
[2] = 0x01;
422 Head
->EfiStartLBA
= 1;
423 Head
->EfiBackupLBA
= DiskSectorCount
- 1;
424 Head
->PartAreaStartLBA
= 34;
425 Head
->PartAreaEndLBA
= DiskSectorCount
- 34;
426 ventoy_gen_preudo_uuid(&Head
->DiskGuid
);
427 Head
->PartTblStartLBA
= 2;
428 Head
->PartTblTotNum
= 128;
429 Head
->PartTblEntryLen
= 128;
432 memcpy(&(Table
[0].PartType
), &WindowsDataPartType
, sizeof(ventoy_guid
));
433 ventoy_gen_preudo_uuid(&(Table
[0].PartGuid
));
434 Table
[0].StartLBA
= 2048;
435 Table
[0].LastLBA
= 2048 + Part1SectorCount
- 1;
437 ventoy_fill_gpt_partname(Table
[0].Name
, "Ventoy");
439 // to fix windows issue
440 //memcpy(&(Table[1].PartType), &EspPartType, sizeof(GUID));
441 memcpy(&(Table
[1].PartType
), &WindowsDataPartType
, sizeof(ventoy_guid
));
442 ventoy_gen_preudo_uuid(&(Table
[1].PartGuid
));
443 Table
[1].StartLBA
= Table
[0].LastLBA
+ 1;
444 Table
[1].LastLBA
= Table
[1].StartLBA
+ VTOYEFI_PART_BYTES
/ 512 - 1;
445 Table
[1].Attr
= 0xC000000000000001ULL
;
446 ventoy_fill_gpt_partname(Table
[1].Name
, "VTOYEFI");
449 memcpy(&(Table
[2].PartType
), &BiosGrubPartType
, sizeof(ventoy_guid
));
450 ventoy_gen_preudo_uuid(&(Table
[2].PartGuid
));
451 Table
[2].StartLBA
= 34;
452 Table
[2].LastLBA
= 2047;
457 Head
->PartTblCrc
= ventoy_crc32(Table
, sizeof(gpt
->PartTbl
));
458 Head
->Crc
= ventoy_crc32(Head
, Head
->Length
);
463 int VentoyFillMBRLocation(uint64_t DiskSizeInBytes
, uint32_t StartSectorId
, uint32_t SectorCount
, PART_TABLE
*Table
)
467 uint8_t nSector
= 63;
470 uint32_t EndSectorId
;
472 while (nHead
!= 0 && (DiskSizeInBytes
/ 512 / nSector
/ nHead
) > 1024)
474 nHead
= (uint8_t)nHead
* 2;
482 Cylinder
= StartSectorId
/ nSector
/ nHead
;
483 Head
= StartSectorId
/ nSector
% nHead
;
484 Sector
= StartSectorId
% nSector
+ 1;
486 Table
->StartHead
= Head
;
487 Table
->StartSector
= Sector
;
488 Table
->StartCylinder
= Cylinder
;
490 EndSectorId
= StartSectorId
+ SectorCount
- 1;
491 Cylinder
= EndSectorId
/ nSector
/ nHead
;
492 Head
= EndSectorId
/ nSector
% nHead
;
493 Sector
= EndSectorId
% nSector
+ 1;
495 Table
->EndHead
= Head
;
496 Table
->EndSector
= Sector
;
497 Table
->EndCylinder
= Cylinder
;
499 Table
->StartSectorId
= StartSectorId
;
500 Table
->SectorCount
= SectorCount
;
505 int ventoy_fill_mbr(uint64_t size
, uint64_t reserve
, int align4k
, MBR_HEAD
*pMBR
)
508 uint32_t DiskSignature
;
509 uint32_t DiskSectorCount
;
510 uint32_t PartSectorCount
;
511 uint32_t PartStartSector
;
512 uint32_t ReservedSector
;
514 VentoyGetLocalBootImg(pMBR
);
516 ventoy_gen_preudo_uuid(&Guid
);
518 memcpy(&DiskSignature
, &Guid
, sizeof(uint32_t));
520 vdebug("Disk signature: 0x%08x\n", DiskSignature
);
522 memcpy(pMBR
->BootCode
+ 0x1B8, &DiskSignature
, 4);
523 memcpy(pMBR
->BootCode
+ 0x180, &Guid
, 16);
525 if (size
/ 512 > 0xFFFFFFFF)
527 DiskSectorCount
= 0xFFFFFFFF;
531 DiskSectorCount
= (uint32_t)(size
/ 512);
540 ReservedSector
= (uint32_t)(reserve
/ 512);
543 // check aligned with 4KB
546 uint64_t sectors
= size
/ 512;
549 vlog("Disk need to align with 4KB %u\n", (uint32_t)(sectors
% 8));
550 ReservedSector
+= (uint32_t)(sectors
% 8);
554 vdebug("no need to align with 4KB\n");
558 vlog("ReservedSector: %u\n", ReservedSector
);
561 PartStartSector
= VTOYIMG_PART_START_SECTOR
;
562 PartSectorCount
= DiskSectorCount
- ReservedSector
- VTOYEFI_PART_BYTES
/ 512 - PartStartSector
;
563 VentoyFillMBRLocation(size
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
);
565 pMBR
->PartTbl
[0].Active
= 0x80; // bootable
566 pMBR
->PartTbl
[0].FsFlag
= 0x07; // exFAT/NTFS/HPFS
569 PartStartSector
+= PartSectorCount
;
570 PartSectorCount
= VTOYEFI_PART_BYTES
/ 512;
571 VentoyFillMBRLocation(size
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
+ 1);
573 pMBR
->PartTbl
[1].Active
= 0x00;
574 pMBR
->PartTbl
[1].FsFlag
= 0xEF; // EFI System Partition
582 int ventoy_fill_mbr_4k(uint64_t size
, uint64_t reserve
, int align4k
, MBR_HEAD
*pMBR
)
585 uint32_t DiskSignature
;
586 uint32_t DiskSectorCount
;
587 uint32_t PartSectorCount
;
588 uint32_t PartStartSector
;
589 uint32_t ReservedSector
;
591 VentoyGetLocalBootImg(pMBR
);
593 ventoy_gen_preudo_uuid(&Guid
);
595 memcpy(&DiskSignature
, &Guid
, sizeof(uint32_t));
597 vdebug("Disk signature: 0x%08x\n", DiskSignature
);
599 memcpy(pMBR
->BootCode
+ 0x1B8, &DiskSignature
, 4);
600 memcpy(pMBR
->BootCode
+ 0x180, &Guid
, 16);
602 if (size
/ 4096 > 0xFFFFFFFF)
604 DiskSectorCount
= 0xFFFFFFFF;
608 DiskSectorCount
= (uint32_t)(size
/ 4096);
617 ReservedSector
= (uint32_t)(reserve
/ 4096);
620 // check aligned with 4KB
621 vdebug("no need to align with 4KB for 4K native disk\n");
623 vlog("ReservedSector: %u\n", ReservedSector
);
626 PartStartSector
= VTOYIMG_PART_START_SECTOR
>> 3;
627 PartSectorCount
= DiskSectorCount
- ReservedSector
- VTOYEFI_PART_BYTES
/ 4096 - PartStartSector
;
628 VentoyFillMBRLocation(size
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
);
630 pMBR
->PartTbl
[0].Active
= 0x80; // bootable
631 pMBR
->PartTbl
[0].FsFlag
= 0x07; // exFAT/NTFS/HPFS
634 PartStartSector
+= PartSectorCount
;
635 PartSectorCount
= VTOYEFI_PART_BYTES
/ 4096;
636 VentoyFillMBRLocation(size
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
+ 1);
638 pMBR
->PartTbl
[1].Active
= 0x00;
639 pMBR
->PartTbl
[1].FsFlag
= 0xEF; // EFI System Partition