]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - LinuxGUI/Ventoy2Disk/Core/ventoy_util.c
Update ru_RU.txt (#2120)
[Ventoy.git] / LinuxGUI / Ventoy2Disk / Core / ventoy_util.c
1 /******************************************************************************
2 * ventoy_util.c ---- ventoy util
3 * Copyright (c) 2021, longpanda <admin@ventoy.net>
4 *
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.
9 *
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.
14 *
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/>.
17 *
18 */
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <string.h>
23 #include <stdarg.h>
24 #include <errno.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/types.h>
29 #include <sys/ioctl.h>
30 #include <sys/stat.h>
31 #include <sys/types.h>
32 #include <sys/mount.h>
33 #include <linux/fs.h>
34 #include <dirent.h>
35 #include <time.h>
36 #include <ventoy_define.h>
37 #include <ventoy_util.h>
38
39 uint8_t g_mbr_template[512];
40
41 void ventoy_gen_preudo_uuid(void *uuid)
42 {
43 int i;
44 int fd;
45
46 fd = open("/dev/urandom", O_RDONLY | O_BINARY);
47 if (fd < 0)
48 {
49 srand(time(NULL));
50 for (i = 0; i < 8; i++)
51 {
52 *((uint16_t *)uuid + i) = (uint16_t)(rand() & 0xFFFF);
53 }
54 }
55 else
56 {
57 read(fd, uuid, 16);
58 close(fd);
59 }
60 }
61
62 uint64_t ventoy_get_human_readable_gb(uint64_t SizeBytes)
63 {
64 int i;
65 int Pow2 = 1;
66 double Delta;
67 double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;
68
69 if ((SizeBytes % SIZE_1GB) == 0)
70 {
71 return (uint64_t)(SizeBytes / SIZE_1GB);
72 }
73
74 for (i = 0; i < 12; i++)
75 {
76 if (Pow2 > GB)
77 {
78 Delta = (Pow2 - GB) / Pow2;
79 }
80 else
81 {
82 Delta = (GB - Pow2) / Pow2;
83 }
84
85 if (Delta < 0.05)
86 {
87 return Pow2;
88 }
89
90 Pow2 <<= 1;
91 }
92
93 return (uint64_t)GB;
94 }
95
96
97 int ventoy_get_sys_file_line(char *buffer, int buflen, const char *fmt, ...)
98 {
99 int len;
100 char c;
101 char path[256];
102 va_list arg;
103
104 va_start(arg, fmt);
105 vsnprintf(path, 256, fmt, arg);
106 va_end(arg);
107
108 if (access(path, F_OK) >= 0)
109 {
110 FILE *fp = fopen(path, "r");
111 memset(buffer, 0, buflen);
112 len = (int)fread(buffer, 1, buflen - 1, fp);
113 fclose(fp);
114
115 while (len > 0)
116 {
117 c = buffer[len - 1];
118 if (c == '\r' || c == '\n' || c == ' ' || c == '\t')
119 {
120 buffer[len - 1] = 0;
121 len--;
122 }
123 else
124 {
125 break;
126 }
127 }
128
129 return 0;
130 }
131 else
132 {
133 vdebug("%s not exist \n", path);
134 return 1;
135 }
136 }
137
138 int ventoy_is_disk_mounted(const char *devpath)
139 {
140 int len;
141 int mount = 0;
142 char line[512];
143 FILE *fp = NULL;
144
145 fp = fopen("/proc/mounts", "r");
146 if (!fp)
147 {
148 return 0;
149 }
150
151 len = (int)strlen(devpath);
152 while (fgets(line, sizeof(line), fp))
153 {
154 if (strncmp(line, devpath, len) == 0)
155 {
156 mount = 1;
157 vdebug("%s mounted <%s>\n", devpath, line);
158 goto end;
159 }
160 }
161
162 end:
163 fclose(fp);
164 return mount;
165 }
166
167 static int ventoy_mount_path_escape(char *src, char *dst, int len)
168 {
169 int i = 0;
170 int n = 0;
171
172 dst[len - 1] = 0;
173
174 for (i = 0; i < len - 1; i++)
175 {
176 if (src[i] == '\\' && src[i + 1] == '0' && src[i + 2] == '4' && src[i + 3] == '0')
177 {
178 dst[n++] = ' ';
179 i += 3;
180 }
181 else
182 {
183 dst[n++] = src[i];
184 }
185
186 if (src[i] == 0)
187 {
188 break;
189 }
190 }
191
192 return 0;
193 }
194
195 int ventoy_try_umount_disk(const char *devpath)
196 {
197 int rc;
198 int len;
199 char line[1024];
200 char mntpt[1024];
201 char *pos1 = NULL;
202 char *pos2 = NULL;
203 FILE *fp = NULL;
204
205 fp = fopen("/proc/mounts", "r");
206 if (!fp)
207 {
208 return 0;
209 }
210
211 len = (int)strlen(devpath);
212 while (fgets(line, sizeof(line), fp))
213 {
214 if (strncmp(line, devpath, len) == 0)
215 {
216 pos1 = strchr(line, ' ');
217 if (pos1)
218 {
219 pos2 = strchr(pos1 + 1, ' ');
220 if (pos2)
221 {
222 *pos2 = 0;
223 }
224
225 ventoy_mount_path_escape(pos1 + 1, mntpt, sizeof(mntpt));
226 rc = umount(mntpt);
227 if (rc)
228 {
229 vdebug("umount <%s> <%s> [ failed ] error:%d\n", devpath, mntpt, errno);
230 }
231 else
232 {
233 vdebug("umount <%s> <%s> [ success ]\n", devpath, mntpt);
234 }
235 }
236 }
237 }
238
239 fclose(fp);
240 return 0;
241 }
242
243 int ventoy_read_file_to_buf(const char *FileName, int ExtLen, void **Bufer, int *BufLen)
244 {
245 int FileSize;
246 FILE *fp = NULL;
247 void *Data = NULL;
248
249 fp = fopen(FileName, "rb");
250 if (fp == NULL)
251 {
252 vlog("Failed to open file %s", FileName);
253 return 1;
254 }
255
256 fseek(fp, 0, SEEK_END);
257 FileSize = (int)ftell(fp);
258
259 Data = malloc(FileSize + ExtLen);
260 if (!Data)
261 {
262 fclose(fp);
263 return 1;
264 }
265
266 fseek(fp, 0, SEEK_SET);
267 fread(Data, 1, FileSize, fp);
268
269 fclose(fp);
270
271 *Bufer = Data;
272 *BufLen = FileSize;
273
274 return 0;
275 }
276
277 const char * ventoy_get_local_version(void)
278 {
279 int rc;
280 int FileSize;
281 char *Pos = NULL;
282 char *Buf = NULL;
283 static char LocalVersion[64] = { 0 };
284
285 if (LocalVersion[0] == 0)
286 {
287 rc = ventoy_read_file_to_buf("ventoy/version", 1, (void **)&Buf, &FileSize);
288 if (rc)
289 {
290 return "";
291 }
292 Buf[FileSize] = 0;
293
294 for (Pos = Buf; *Pos; Pos++)
295 {
296 if (*Pos == '\r' || *Pos == '\n')
297 {
298 *Pos = 0;
299 break;
300 }
301 }
302
303 scnprintf(LocalVersion, "%s", Buf);
304 free(Buf);
305 }
306
307 return LocalVersion;
308 }
309
310 int VentoyGetLocalBootImg(MBR_HEAD *pMBR)
311 {
312 memcpy(pMBR, g_mbr_template, 512);
313 return 0;
314 }
315
316 static int VentoyFillProtectMBR(uint64_t DiskSizeBytes, MBR_HEAD *pMBR)
317 {
318 ventoy_guid Guid;
319 uint32_t DiskSignature;
320 uint64_t DiskSectorCount;
321
322 VentoyGetLocalBootImg(pMBR);
323
324 ventoy_gen_preudo_uuid(&Guid);
325
326 memcpy(&DiskSignature, &Guid, sizeof(uint32_t));
327
328 vdebug("Disk signature: 0x%08x\n", DiskSignature);
329
330 memcpy(pMBR->BootCode + 0x1B8, &DiskSignature, 4);
331 memcpy(pMBR->BootCode + 0x180, &Guid, 16);
332
333 DiskSectorCount = DiskSizeBytes / 512 - 1;
334 if (DiskSectorCount > 0xFFFFFFFF)
335 {
336 DiskSectorCount = 0xFFFFFFFF;
337 }
338
339 memset(pMBR->PartTbl, 0, sizeof(pMBR->PartTbl));
340
341 pMBR->PartTbl[0].Active = 0x00;
342 pMBR->PartTbl[0].FsFlag = 0xee; // EE
343
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;
350
351 pMBR->PartTbl[0].StartSectorId = 1;
352 pMBR->PartTbl[0].SectorCount = (uint32_t)DiskSectorCount;
353
354 pMBR->Byte55 = 0x55;
355 pMBR->ByteAA = 0xAA;
356
357 pMBR->BootCode[92] = 0x22;
358
359 return 0;
360 }
361
362 static int ventoy_fill_gpt_partname(uint16_t Name[36], const char *asciiName)
363 {
364 int i;
365 int len;
366
367 memset(Name, 0, 36 * sizeof(uint16_t));
368 len = (int)strlen(asciiName);
369 for (i = 0; i < 36 && i < len; i++)
370 {
371 Name[i] = asciiName[i];
372 }
373
374 return 0;
375 }
376
377 int ventoy_fill_gpt(uint64_t size, uint64_t reserve, int align4k, VTOY_GPT_INFO *gpt)
378 {
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 } };
388
389 VentoyFillProtectMBR(size, &gpt->MBR);
390
391 if (reserve > 0)
392 {
393 ReservedSector += reserve / 512;
394 }
395
396 Part1SectorCount = DiskSectorCount - ReservedSector - (VTOYEFI_PART_BYTES / 512) - 2048;
397
398 ModSectorCount = (Part1SectorCount % 8);
399 if (ModSectorCount)
400 {
401 vlog("Part1SectorCount:%llu is not aligned by 4KB (%llu)\n", (_ull)Part1SectorCount, (_ull)ModSectorCount);
402 }
403
404 // check aligned with 4KB
405 if (align4k)
406 {
407 if (ModSectorCount)
408 {
409 vdebug("Disk need to align with 4KB %u\n", (uint32_t)ModSectorCount);
410 Part1SectorCount -= ModSectorCount;
411 }
412 else
413 {
414 vdebug("no need to align with 4KB\n");
415 }
416 }
417
418 memcpy(Head->Signature, "EFI PART", 8);
419 Head->Version[2] = 0x01;
420 Head->Length = 92;
421 Head->Crc = 0;
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;
430
431
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;
436 Table[0].Attr = 0;
437 ventoy_fill_gpt_partname(Table[0].Name, "Ventoy");
438
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");
447
448 #if 0
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;
453 Table[2].Attr = 0;
454 #endif
455
456 //Update CRC
457 Head->PartTblCrc = ventoy_crc32(Table, sizeof(gpt->PartTbl));
458 Head->Crc = ventoy_crc32(Head, Head->Length);
459
460 return 0;
461 }
462
463 int VentoyFillMBRLocation(uint64_t DiskSizeInBytes, uint32_t StartSectorId, uint32_t SectorCount, PART_TABLE *Table)
464 {
465 uint8_t Head;
466 uint8_t Sector;
467 uint8_t nSector = 63;
468 uint8_t nHead = 8;
469 uint32_t Cylinder;
470 uint32_t EndSectorId;
471
472 while (nHead != 0 && (DiskSizeInBytes / 512 / nSector / nHead) > 1024)
473 {
474 nHead = (uint8_t)nHead * 2;
475 }
476
477 if (nHead == 0)
478 {
479 nHead = 255;
480 }
481
482 Cylinder = StartSectorId / nSector / nHead;
483 Head = StartSectorId / nSector % nHead;
484 Sector = StartSectorId % nSector + 1;
485
486 Table->StartHead = Head;
487 Table->StartSector = Sector;
488 Table->StartCylinder = Cylinder;
489
490 EndSectorId = StartSectorId + SectorCount - 1;
491 Cylinder = EndSectorId / nSector / nHead;
492 Head = EndSectorId / nSector % nHead;
493 Sector = EndSectorId % nSector + 1;
494
495 Table->EndHead = Head;
496 Table->EndSector = Sector;
497 Table->EndCylinder = Cylinder;
498
499 Table->StartSectorId = StartSectorId;
500 Table->SectorCount = SectorCount;
501
502 return 0;
503 }
504
505 int ventoy_fill_mbr(uint64_t size, uint64_t reserve, int align4k, MBR_HEAD *pMBR)
506 {
507 ventoy_guid Guid;
508 uint32_t DiskSignature;
509 uint32_t DiskSectorCount;
510 uint32_t PartSectorCount;
511 uint32_t PartStartSector;
512 uint32_t ReservedSector;
513
514 VentoyGetLocalBootImg(pMBR);
515
516 ventoy_gen_preudo_uuid(&Guid);
517
518 memcpy(&DiskSignature, &Guid, sizeof(uint32_t));
519
520 vdebug("Disk signature: 0x%08x\n", DiskSignature);
521
522 memcpy(pMBR->BootCode + 0x1B8, &DiskSignature, 4);
523 memcpy(pMBR->BootCode + 0x180, &Guid, 16);
524
525 if (size / 512 > 0xFFFFFFFF)
526 {
527 DiskSectorCount = 0xFFFFFFFF;
528 }
529 else
530 {
531 DiskSectorCount = (uint32_t)(size / 512);
532 }
533
534 if (reserve <= 0)
535 {
536 ReservedSector = 0;
537 }
538 else
539 {
540 ReservedSector = (uint32_t)(reserve / 512);
541 }
542
543 // check aligned with 4KB
544 if (align4k)
545 {
546 uint64_t sectors = size / 512;
547 if (sectors % 8)
548 {
549 vlog("Disk need to align with 4KB %u\n", (uint32_t)(sectors % 8));
550 ReservedSector += (uint32_t)(sectors % 8);
551 }
552 else
553 {
554 vdebug("no need to align with 4KB\n");
555 }
556 }
557
558 vlog("ReservedSector: %u\n", ReservedSector);
559
560 //Part1
561 PartStartSector = VTOYIMG_PART_START_SECTOR;
562 PartSectorCount = DiskSectorCount - ReservedSector - VTOYEFI_PART_BYTES / 512 - PartStartSector;
563 VentoyFillMBRLocation(size, PartStartSector, PartSectorCount, pMBR->PartTbl);
564
565 pMBR->PartTbl[0].Active = 0x80; // bootable
566 pMBR->PartTbl[0].FsFlag = 0x07; // exFAT/NTFS/HPFS
567
568 //Part2
569 PartStartSector += PartSectorCount;
570 PartSectorCount = VTOYEFI_PART_BYTES / 512;
571 VentoyFillMBRLocation(size, PartStartSector, PartSectorCount, pMBR->PartTbl + 1);
572
573 pMBR->PartTbl[1].Active = 0x00;
574 pMBR->PartTbl[1].FsFlag = 0xEF; // EFI System Partition
575
576 pMBR->Byte55 = 0x55;
577 pMBR->ByteAA = 0xAA;
578
579 return 0;
580 }
581