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 int ventoy_try_umount_disk(const char *devpath
)
176 fp
= fopen("/proc/mounts", "r");
182 len
= (int)strlen(devpath
);
183 while (fgets(line
, sizeof(line
), fp
))
185 if (strncmp(line
, devpath
, len
) == 0)
187 pos1
= strchr(line
, ' ');
190 pos2
= strchr(pos1
+ 1, ' ');
196 rc
= umount(pos1
+ 1);
199 vdebug("umount %s %s [ failed ] error:%d\n", devpath
, pos1
+ 1, errno
);
203 vdebug("umount %s %s [ success ]\n", devpath
, pos1
+ 1);
214 int ventoy_read_file_to_buf(const char *FileName
, int ExtLen
, void **Bufer
, int *BufLen
)
220 fp
= fopen(FileName
, "rb");
223 vlog("Failed to open file %s", FileName
);
227 fseek(fp
, 0, SEEK_END
);
228 FileSize
= (int)ftell(fp
);
230 Data
= malloc(FileSize
+ ExtLen
);
237 fseek(fp
, 0, SEEK_SET
);
238 fread(Data
, 1, FileSize
, fp
);
248 const char * ventoy_get_local_version(void)
254 static char LocalVersion
[64] = { 0 };
256 if (LocalVersion
[0] == 0)
258 rc
= ventoy_read_file_to_buf("ventoy/version", 1, (void **)&Buf
, &FileSize
);
265 for (Pos
= Buf
; *Pos
; Pos
++)
267 if (*Pos
== '\r' || *Pos
== '\n')
274 scnprintf(LocalVersion
, "%s", Buf
);
281 int VentoyGetLocalBootImg(MBR_HEAD
*pMBR
)
283 memcpy(pMBR
, g_mbr_template
, 512);
287 static int VentoyFillProtectMBR(uint64_t DiskSizeBytes
, MBR_HEAD
*pMBR
)
290 uint32_t DiskSignature
;
291 uint64_t DiskSectorCount
;
293 VentoyGetLocalBootImg(pMBR
);
295 ventoy_gen_preudo_uuid(&Guid
);
297 memcpy(&DiskSignature
, &Guid
, sizeof(uint32_t));
299 vdebug("Disk signature: 0x%08x\n", DiskSignature
);
301 memcpy(pMBR
->BootCode
+ 0x1B8, &DiskSignature
, 4);
303 DiskSectorCount
= DiskSizeBytes
/ 512 - 1;
304 if (DiskSectorCount
> 0xFFFFFFFF)
306 DiskSectorCount
= 0xFFFFFFFF;
309 memset(pMBR
->PartTbl
, 0, sizeof(pMBR
->PartTbl
));
311 pMBR
->PartTbl
[0].Active
= 0x00;
312 pMBR
->PartTbl
[0].FsFlag
= 0xee; // EE
314 pMBR
->PartTbl
[0].StartHead
= 0;
315 pMBR
->PartTbl
[0].StartSector
= 1;
316 pMBR
->PartTbl
[0].StartCylinder
= 0;
317 pMBR
->PartTbl
[0].EndHead
= 254;
318 pMBR
->PartTbl
[0].EndSector
= 63;
319 pMBR
->PartTbl
[0].EndCylinder
= 1023;
321 pMBR
->PartTbl
[0].StartSectorId
= 1;
322 pMBR
->PartTbl
[0].SectorCount
= (uint32_t)DiskSectorCount
;
327 pMBR
->BootCode
[92] = 0x22;
332 static int ventoy_fill_gpt_partname(uint16_t Name
[36], const char *asciiName
)
337 memset(Name
, 0, 36 * sizeof(uint16_t));
338 len
= (int)strlen(asciiName
);
339 for (i
= 0; i
< 36 && i
< len
; i
++)
341 Name
[i
] = asciiName
[i
];
347 int ventoy_fill_gpt(uint64_t size
, uint64_t reserve
, int align4k
, VTOY_GPT_INFO
*gpt
)
349 uint64_t ReservedSector
= 33;
350 uint64_t ModSectorCount
= 0;
351 uint64_t Part1SectorCount
= 0;
352 uint64_t DiskSectorCount
= size
/ 512;
353 VTOY_GPT_HDR
*Head
= &gpt
->Head
;
354 VTOY_GPT_PART_TBL
*Table
= gpt
->PartTbl
;
355 ventoy_guid WindowsDataPartType
= { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
356 //ventoy_guid EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
357 //ventoy_guid BiosGrubPartType = { 0x21686148, 0x6449, 0x6e6f, { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } };
359 VentoyFillProtectMBR(size
, &gpt
->MBR
);
363 ReservedSector
+= reserve
/ 512;
366 Part1SectorCount
= DiskSectorCount
- ReservedSector
- (VTOYEFI_PART_BYTES
/ 512) - 2048;
368 ModSectorCount
= (Part1SectorCount
% 8);
371 vlog("Part1SectorCount:%llu is not aligned by 4KB (%llu)\n", (_ull
)Part1SectorCount
, (_ull
)ModSectorCount
);
374 // check aligned with 4KB
379 vdebug("Disk need to align with 4KB %u\n", (uint32_t)ModSectorCount
);
380 Part1SectorCount
-= ModSectorCount
;
384 vdebug("no need to align with 4KB\n");
388 memcpy(Head
->Signature
, "EFI PART", 8);
389 Head
->Version
[2] = 0x01;
392 Head
->EfiStartLBA
= 1;
393 Head
->EfiBackupLBA
= DiskSectorCount
- 1;
394 Head
->PartAreaStartLBA
= 34;
395 Head
->PartAreaEndLBA
= DiskSectorCount
- 34;
396 ventoy_gen_preudo_uuid(&Head
->DiskGuid
);
397 Head
->PartTblStartLBA
= 2;
398 Head
->PartTblTotNum
= 128;
399 Head
->PartTblEntryLen
= 128;
402 memcpy(&(Table
[0].PartType
), &WindowsDataPartType
, sizeof(ventoy_guid
));
403 ventoy_gen_preudo_uuid(&(Table
[0].PartGuid
));
404 Table
[0].StartLBA
= 2048;
405 Table
[0].LastLBA
= 2048 + Part1SectorCount
- 1;
407 ventoy_fill_gpt_partname(Table
[0].Name
, "Ventoy");
409 // to fix windows issue
410 //memcpy(&(Table[1].PartType), &EspPartType, sizeof(GUID));
411 memcpy(&(Table
[1].PartType
), &WindowsDataPartType
, sizeof(ventoy_guid
));
412 ventoy_gen_preudo_uuid(&(Table
[1].PartGuid
));
413 Table
[1].StartLBA
= Table
[0].LastLBA
+ 1;
414 Table
[1].LastLBA
= Table
[1].StartLBA
+ VTOYEFI_PART_BYTES
/ 512 - 1;
415 Table
[1].Attr
= 0x8000000000000001ULL
;
416 ventoy_fill_gpt_partname(Table
[1].Name
, "VTOYEFI");
419 memcpy(&(Table
[2].PartType
), &BiosGrubPartType
, sizeof(ventoy_guid
));
420 ventoy_gen_preudo_uuid(&(Table
[2].PartGuid
));
421 Table
[2].StartLBA
= 34;
422 Table
[2].LastLBA
= 2047;
427 Head
->PartTblCrc
= ventoy_crc32(Table
, sizeof(gpt
->PartTbl
));
428 Head
->Crc
= ventoy_crc32(Head
, Head
->Length
);
433 int VentoyFillMBRLocation(uint64_t DiskSizeInBytes
, uint32_t StartSectorId
, uint32_t SectorCount
, PART_TABLE
*Table
)
437 uint8_t nSector
= 63;
440 uint32_t EndSectorId
;
442 while (nHead
!= 0 && (DiskSizeInBytes
/ 512 / nSector
/ nHead
) > 1024)
444 nHead
= (uint8_t)nHead
* 2;
452 Cylinder
= StartSectorId
/ nSector
/ nHead
;
453 Head
= StartSectorId
/ nSector
% nHead
;
454 Sector
= StartSectorId
% nSector
+ 1;
456 Table
->StartHead
= Head
;
457 Table
->StartSector
= Sector
;
458 Table
->StartCylinder
= Cylinder
;
460 EndSectorId
= StartSectorId
+ SectorCount
- 1;
461 Cylinder
= EndSectorId
/ nSector
/ nHead
;
462 Head
= EndSectorId
/ nSector
% nHead
;
463 Sector
= EndSectorId
% nSector
+ 1;
465 Table
->EndHead
= Head
;
466 Table
->EndSector
= Sector
;
467 Table
->EndCylinder
= Cylinder
;
469 Table
->StartSectorId
= StartSectorId
;
470 Table
->SectorCount
= SectorCount
;
475 int ventoy_fill_mbr(uint64_t size
, uint64_t reserve
, int align4k
, MBR_HEAD
*pMBR
)
478 uint32_t DiskSignature
;
479 uint32_t DiskSectorCount
;
480 uint32_t PartSectorCount
;
481 uint32_t PartStartSector
;
482 uint32_t ReservedSector
;
484 VentoyGetLocalBootImg(pMBR
);
486 ventoy_gen_preudo_uuid(&Guid
);
488 memcpy(&DiskSignature
, &Guid
, sizeof(uint32_t));
490 vdebug("Disk signature: 0x%08x\n", DiskSignature
);
492 memcpy(pMBR
->BootCode
+ 0x1B8, &DiskSignature
, 4);
494 if (size
/ 512 > 0xFFFFFFFF)
496 DiskSectorCount
= 0xFFFFFFFF;
500 DiskSectorCount
= (uint32_t)(size
/ 512);
509 ReservedSector
= (uint32_t)(reserve
/ 512);
512 // check aligned with 4KB
515 uint64_t sectors
= size
/ 512;
518 vlog("Disk need to align with 4KB %u\n", (uint32_t)(sectors
% 8));
519 ReservedSector
+= (uint32_t)(sectors
% 8);
523 vdebug("no need to align with 4KB\n");
527 vlog("ReservedSector: %u\n", ReservedSector
);
530 PartStartSector
= VTOYIMG_PART_START_SECTOR
;
531 PartSectorCount
= DiskSectorCount
- ReservedSector
- VTOYEFI_PART_BYTES
/ 512 - PartStartSector
;
532 VentoyFillMBRLocation(size
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
);
534 pMBR
->PartTbl
[0].Active
= 0x80; // bootable
535 pMBR
->PartTbl
[0].FsFlag
= 0x07; // exFAT/NTFS/HPFS
538 PartStartSector
+= PartSectorCount
;
539 PartSectorCount
= VTOYEFI_PART_BYTES
/ 512;
540 VentoyFillMBRLocation(size
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
+ 1);
542 pMBR
->PartTbl
[1].Active
= 0x00;
543 pMBR
->PartTbl
[1].FsFlag
= 0xEF; // EFI System Partition