Chameleon

Chameleon Svn Source Tree

Root/trunk/i386/util/boot1-install/boot1-install.c

1/*
2 * boot1-install.c
3 * boot1-install
4 *
5 * Created by Zenith432 on November 19th, 2014.
6 * Copyright (c) 2014 Zenith432. All rights reserved.
7 */
8
9#include <assert.h>
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13
14#include <errno.h>
15#include <fcntl.h>
16#include <sys/stat.h>
17#include <sys/types.h>
18#include <sys/uio.h>
19#include <unistd.h>
20
21#include <CoreFoundation/CoreFoundation.h>
22#include <DiskArbitration/DiskArbitration.h>
23
24struct buffer_t
25{
26unsigned char* _b;
27size_t _s;
28};
29
30enum volume_kind_t
31{
32_undetected = 0,
33_exfat = 1,
34_hfs = 2,
35_msdos = 3,
36_other = 255
37};
38
39static int isVolumeMounted = 0;
40static int isMediaWhole = 0;
41static int isMediaLeaf = 0;
42static enum volume_kind_t daVolumeKind = _undetected;
43
44static struct buffer_t bpbBlob = { NULL, 0 };
45static struct buffer_t bootBlob = { NULL, 0 };
46static struct buffer_t outputBlob = { NULL, 0 };
47
48static char const UnsupportedMessage[] = "Only exFAT, FAT32 or HFS+ volumes are supported\n";
49static char const exfatID[] = "EXFAT ";
50static char const fat32ID[] = "FAT32 ";
51static char const devrdisk[] = "/dev/rdisk";
52static char const devdisk[] = "/dev/disk";
53static char const defaultBootFile_exfat[] = "./boot1x";
54static char const defaultBootFile_hfs[] = "./boot1h";
55static char const defaultBootFile_fat32[] = "./boot1f32";
56
57static __used char const copyright[] = "Copyright 2014 Zenith432";
58
59static int checkExfat(struct buffer_t const*);
60static int checkFat32(struct buffer_t const*);
61static int loadChunk(char const*, off_t, off_t, struct buffer_t*);
62static void unsupported(void);
63
64#pragma mark -
65#pragma mark Cleaners
66#pragma mark -
67
68static
69void free_buffer(struct buffer_t* pBuffer)
70{
71assert(pBuffer);
72if (pBuffer->_b) {
73free(pBuffer->_b);
74pBuffer->_b = NULL;
75pBuffer->_s = 0;
76}
77}
78
79/*
80 * Uses statics
81 */
82static
83void cleanup(void)
84{
85free_buffer(&outputBlob);
86free_buffer(&bootBlob);
87free_buffer(&bpbBlob);
88}
89
90#pragma mark -
91#pragma mark ExFAT Processor
92#pragma mark -
93
94static
95unsigned VBRChecksum(unsigned char const* octets, size_t NumberOfBytes)
96{
97unsigned Checksum = 0;
98size_t Index;
99for (Index = 0; Index != NumberOfBytes; ++Index)
100{
101if (Index == 106 || Index == 107 || Index == 112)
102continue;
103Checksum = ((Checksum << 31) | (Checksum >> 1)) + (unsigned) octets[Index];
104}
105return Checksum;
106}
107
108static
109int calcSum(struct buffer_t const* pBootBlob,
110struct buffer_t const* pBpbBlob,
111struct buffer_t* pOutputBlob,
112char const* pathName)
113{
114unsigned char *outBuffer, *p, *q;
115size_t outSize, toCopy, leftOver;
116unsigned Checksum;
117
118assert(pBootBlob && pBpbBlob);
119if (pBootBlob->_s > 9U * 512U) {
120fprintf(stderr, "Boot Code must be at most 4608 bytes\n");
121return -1;
122}
123if (pBpbBlob->_s < 113U) {
124fprintf(stderr, "BPB must be at least 113 bytes\n");
125return -1;
126}
127if (!checkExfat(pBpbBlob)) {
128fprintf(stderr, "BPB does not contain proper exFAT signature\n");
129return -1;
130}
131outSize = 12U * 512U;
132outBuffer = malloc(outSize);
133if (!outBuffer) {
134fprintf(stderr, "%s: Memory allocation failed\n", __FUNCTION__);
135return -1;
136}
137memset(outBuffer, 0, outSize);
138memcpy(outBuffer, pBootBlob->_b, pBootBlob->_s);
139memcpy(&outBuffer[3], &pBpbBlob->_b[3], 8);
140memset(&outBuffer[11], 0, 53);
141toCopy = 120;
142if (pBpbBlob->_s < toCopy)
143toCopy = pBpbBlob->_s;
144leftOver = 120 - toCopy;
145memcpy(&outBuffer[64], &pBpbBlob->_b[64], toCopy - 64);
146if (leftOver)
147memset(&outBuffer[120 - leftOver], 0, leftOver);
148for (toCopy = 0; toCopy != 9; ++toCopy) {
149p = outBuffer + toCopy * 512U + 508U;
150p[2] = 0x55U;
151p[3] = 0xAAU;
152if (toCopy) {
153p[0] = 0U;
154p[1] = 0U;
155}
156}
157if (pathName) {
158/*
159 * Copy OEM Parameters record
160 */
161struct buffer_t auxBlob = { NULL, 0 };
162if (loadChunk(pathName, 9 * 512 , 512, &auxBlob) >= 0) {
163memcpy(&outBuffer[9 * 512], &auxBlob._b[0], 512);
164free_buffer(&auxBlob);
165}
166}
167Checksum = VBRChecksum(outBuffer, 11U * 512U);
168p = outBuffer + 11U * 512U;
169q = p + 512U;
170for (; p < q; p += 4) {
171*(unsigned*) p = Checksum;
172}
173if (pOutputBlob) {
174pOutputBlob->_b = outBuffer;
175pOutputBlob->_s = outSize;
176} else
177free(outBuffer);
178return 0;
179}
180
181#pragma mark -
182#pragma mark FAT32 Processor
183#pragma mark -
184
185static
186int fat32Layout(struct buffer_t const* pBootBlob,
187struct buffer_t const* pBpbBlob,
188struct buffer_t* pOutputBlob)
189{
190unsigned char *outBuffer;
191size_t outSize;
192
193assert(pBootBlob && pBpbBlob);
194if (pBootBlob->_s > 512U) {
195fprintf(stderr, "Boot Code must be at most 512 bytes\n");
196return -1;
197}
198if (pBpbBlob->_s < 90U) {
199fprintf(stderr, "BPB must be at least 90 bytes\n");
200return -1;
201}
202if (!checkFat32(pBpbBlob)) {
203fprintf(stderr, "BPB does not contain proper FAT32 signature\n");
204return -1;
205}
206outSize = 512U;
207outBuffer = malloc(outSize);
208if (!outBuffer) {
209fprintf(stderr, "%s: Memory allocation failed\n", __FUNCTION__);
210return -1;
211}
212memset(outBuffer, 0, outSize);
213memcpy(outBuffer, pBootBlob->_b, pBootBlob->_s);
214memcpy(&outBuffer[3], &pBpbBlob->_b[3], 87);
215outBuffer[510] = 0x55U;
216outBuffer[511] = 0xAAU;
217if (pOutputBlob) {
218pOutputBlob->_b = outBuffer;
219pOutputBlob->_s = outSize;
220} else
221free(outBuffer);
222return 0;
223}
224
225#pragma mark -
226#pragma mark File Operations
227#pragma mark -
228
229static
230void writeVBR(char const* pathName,
231 struct buffer_t const* pBuffer,
232 int numCopies,
233 size_t expectedSize,
234 char const* volumeType)
235{
236int fd, j;
237
238assert(pathName && pBuffer && volumeType);
239if (pBuffer->_s != expectedSize) {
240fprintf(stderr, "Unexpected %s VBR size %lu (expected %lu)\n", volumeType, pBuffer->_s, expectedSize);
241return;
242}
243fd = open(pathName, O_WRONLY);
244if (fd < 0) {
245fprintf(stderr, "Unable to write boot record to %s, %s\n", pathName, strerror(errno));
246}
247for (j = 0; j != numCopies; ++j)
248write(fd, pBuffer->_b, pBuffer->_s);
249close(fd);
250}
251
252static
253int loadChunk(char const* pathName, off_t startOffset, off_t bytesToRead, struct buffer_t* pBuffer)
254{
255int fd;
256ssize_t rc;
257unsigned char* p;
258struct stat buf;
259
260assert(pathName);
261fd = open(pathName, O_RDONLY);
262if (fd < 0) {
263fprintf(stderr, "Unable to open %s, %s\n", pathName, strerror(errno));
264return -1;
265}
266if (bytesToRead > 0)
267buf.st_size = bytesToRead;
268else if (fstat(fd, &buf) < 0) {
269fprintf(stderr, "Unable to fstat %s, %s\n", pathName, strerror(errno));
270close(fd);
271return -1;
272}
273if (startOffset > 0) {
274off_t t = lseek(fd, startOffset, SEEK_SET);
275if (t < 0) {
276fprintf(stderr, "Unable to lseek %s, %s\n", pathName, strerror(errno));
277close(fd);
278return -1;
279}
280if (t != startOffset) {
281fprintf(stderr, "lseek %s returned wrong value %lld instead of %lld\n", pathName, t, startOffset);
282close(fd);
283return -1;
284}
285if (bytesToRead <= 0)
286buf.st_size -= t;
287}
288p = malloc((size_t) buf.st_size);
289if (!p) {
290fprintf(stderr, "%s: Memory allocation failed\n", __FUNCTION__);
291close(fd);
292return -1;
293}
294rc = read(fd, p, (size_t) buf.st_size);
295if (rc < 0) {
296fprintf(stderr, "Unable to read from %s, %s\n", pathName, strerror(errno));
297free(p);
298close(fd);
299return -1;
300}
301close(fd);
302if (rc != buf.st_size) {
303fprintf(stderr, "Unable to read entire chunk from %s, read %ld/%lld\n", pathName, rc, buf.st_size);
304free(p);
305return -1;
306}
307if (pBuffer) {
308pBuffer->_b = p;
309pBuffer->_s = (size_t) rc;
310} else
311free(p);
312return 0;
313}
314
315#pragma mark -
316#pragma mark DiskArbitration Helpers
317#pragma mark -
318
319static
320char const* toBSDName(char const* pathName)
321{
322assert(pathName);
323return strncmp(pathName, &devrdisk[0], 10) ? pathName : &pathName[6];
324}
325
326static
327char const* daReturnStr(DAReturn v)
328{
329if (unix_err(err_get_code(v)) == v)
330return strerror(err_get_code(v));
331switch (v) {
332case kDAReturnError:
333return "Error";
334case kDAReturnBusy:
335return "Busy";
336case kDAReturnBadArgument:
337return "Bad Argument";
338case kDAReturnExclusiveAccess:
339return "Exclusive Access";
340case kDAReturnNoResources:
341return "No Resources";
342case kDAReturnNotFound:
343return "Not Found";
344case kDAReturnNotMounted:
345return "Not Mounted";
346case kDAReturnNotPermitted:
347return "Not Permitted";
348case kDAReturnNotPrivileged:
349return "Not Privileged";
350case kDAReturnNotReady:
351return "Not Ready";
352case kDAReturnNotWritable:
353return "Not Writable";
354case kDAReturnUnsupported:
355return "Unsupported";
356default:
357return "Unknown";
358}
359}
360
361static
362int getDASessionAndDisk(char const* pathName, DASessionRef* pSession, DADiskRef* pDisk)
363{
364DASessionRef session;
365DADiskRef disk;
366
367assert(pathName);
368session = DASessionCreate(kCFAllocatorDefault);
369if (!session) {
370fprintf(stderr, "DASessionCreate returned NULL\n");
371return -1;
372}
373disk = DADiskCreateFromBSDName(kCFAllocatorDefault, session, toBSDName(pathName));
374if (!disk) {
375CFRelease(session);
376fprintf(stderr, "DADiskCreateFromBSDName(%s) returned NULL\n", pathName);
377return -1;
378}
379if (pDisk)
380*pDisk = disk;
381else
382CFRelease(disk);
383if (pSession)
384*pSession = session;
385else
386CFRelease(session);
387return 0;
388}
389
390#pragma mark -
391#pragma mark Mount/UMount
392#pragma mark -
393
394static
395void umountCallback(DADiskRef disk __unused,
396DADissenterRef dissenter,
397void *context)
398{
399if (context && dissenter != NULL) {
400*(int*) context = -1;
401fprintf(stderr, "umount unsuccessful, status %s\n", daReturnStr(DADissenterGetStatus(dissenter)));
402}
403CFRunLoopStop(CFRunLoopGetCurrent());
404}
405
406static
407int umount(char const* pathName)
408{
409DASessionRef session;
410DADiskRef disk;
411int rc;
412
413assert(pathName);
414if (getDASessionAndDisk(pathName, &session, &disk) < 0)
415return -1;
416rc = 0;
417DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
418DADiskUnmount(disk, kDADiskUnmountOptionDefault, umountCallback, &rc);
419CFRunLoopRun();
420DASessionUnscheduleFromRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
421CFRelease(disk);
422CFRelease(session);
423return rc;
424}
425
426static
427void mountCallback(DADiskRef disk __unused,
428 DADissenterRef dissenter,
429 void *context)
430{
431if (context && dissenter != NULL) {
432*(int*) context = -1;
433fprintf(stderr, "mount unsuccessful, status %s\n", daReturnStr(DADissenterGetStatus(dissenter)));
434}
435CFRunLoopStop(CFRunLoopGetCurrent());
436}
437
438static
439int mount(char const* pathName)
440{
441DASessionRef session;
442DADiskRef disk;
443int rc;
444
445assert(pathName);
446if (getDASessionAndDisk(pathName, &session, &disk) < 0)
447return -1;
448rc = 0;
449DASessionScheduleWithRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
450DADiskMount(disk, NULL, kDADiskMountOptionDefault, mountCallback, &rc);
451CFRunLoopRun();
452DASessionUnscheduleFromRunLoop(session, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
453CFRelease(disk);
454CFRelease(session);
455return rc;
456}
457
458#pragma mark -
459#pragma mark Analyze Volume
460#pragma mark -
461
462static
463int checkExfat(struct buffer_t const* pBpbBlob)
464{
465assert(pBpbBlob);
466return !memcmp(&pBpbBlob->_b[3], &exfatID[0], 8);
467}
468
469static
470int checkHFS(struct buffer_t const* pBpbBlob)
471{
472uint16_t sig;
473
474assert(pBpbBlob);
475sig = OSSwapBigToHostInt16(*(uint16_t const*)&pBpbBlob->_b[0]);
476return sig == 0x4244 || sig == 0x482B || sig == 0x4858;/* 'BD', 'H+', 'HX' */
477}
478
479static
480int checkFat32(struct buffer_t const* pBpbBlob)
481{
482uint16_t bytesPerSector, rootEntCnt;
483uint8_t sectorsPerCluster;
484
485assert(pBpbBlob);
486bytesPerSector = OSSwapLittleToHostInt16(*(uint16_t const*)&pBpbBlob->_b[11]);
487if ((bytesPerSector & (bytesPerSector - 1U)) ||
488bytesPerSector < 0x200U ||
489bytesPerSector > 0x1000U)
490return 0;
491sectorsPerCluster = pBpbBlob->_b[13];
492if (!sectorsPerCluster ||
493(sectorsPerCluster & (sectorsPerCluster - 1U)))
494return 0;
495rootEntCnt = OSSwapLittleToHostInt16(*(uint16_t const*)&pBpbBlob->_b[17]);
496if (rootEntCnt)
497return 0;
498return !memcmp(&pBpbBlob->_b[82], &fat32ID[0], 8);
499}
500
501static
502int checkSupportedVolume(enum volume_kind_t* pKind, struct buffer_t const* pBpbBlob, char const* pathName)
503{
504int rc;
505
506assert(pKind && pBpbBlob);
507rc = -1;
508switch (*pKind) {
509case _undetected:
510if (checkExfat(pBpbBlob)) {
511*pKind = _exfat;
512rc = 0;
513} else if (checkFat32(pBpbBlob)) {
514*pKind = _msdos;
515rc = 0;
516} else if (pathName) {
517struct buffer_t auxBlob = { NULL, 0 };
518if (loadChunk(pathName, 1024 , 512, &auxBlob) >= 0) {
519if (checkHFS(&auxBlob)) {
520*pKind = _hfs;
521rc = 0;
522}
523free_buffer(&auxBlob);
524}
525}
526break;
527case _exfat:
528if (checkExfat(pBpbBlob))
529rc = 0;
530else
531*pKind = _other;
532break;
533case _hfs:
534if (checkHFS(pBpbBlob))
535rc = 0;
536else
537*pKind = _other;
538break;
539case _msdos:
540if (checkFat32(pBpbBlob))
541rc = 0;
542else
543*pKind = _other;
544break;
545default:
546break;
547}
548if (rc < 0)
549unsupported();
550return rc;
551}
552
553/*
554 * Uses statics
555 */
556static
557int checkDevicePath2(char const* pathName)
558{
559DASessionRef session;
560DADiskRef disk;
561CFDictionaryRef descDict;
562CFStringRef s_ref;
563CFBooleanRef b_ref;
564
565assert(pathName);
566if (getDASessionAndDisk(pathName, &session, &disk) < 0)
567return -1;
568descDict = DADiskCopyDescription(disk);
569if (!descDict) {
570CFRelease(disk);
571CFRelease(session);
572fprintf(stderr, "DADiskCopyDescription(%s) returned NULL\n", pathName);
573return -1;
574}
575if (CFDictionaryGetValueIfPresent(descDict, kDADiskDescriptionMediaWholeKey, (void const**) &b_ref) &&
576CFBooleanGetValue(b_ref))
577isMediaWhole = 1;
578if (CFDictionaryGetValueIfPresent(descDict, kDADiskDescriptionMediaLeafKey, (void const**) &b_ref) &&
579CFBooleanGetValue(b_ref))
580isMediaLeaf = 1;
581if (CFDictionaryContainsKey(descDict, kDADiskDescriptionVolumePathKey))
582isVolumeMounted = 1;
583if (CFDictionaryGetValueIfPresent(descDict, kDADiskDescriptionVolumeKindKey, (void const**) &s_ref)) {
584static char cstr_buffer[64];
585char const* cstr = CFStringGetCStringPtr(s_ref, kCFStringEncodingUTF8);
586if (!cstr) {
587CFStringGetCString(s_ref, &cstr_buffer[0], (CFIndex) sizeof cstr_buffer, kCFStringEncodingUTF8);
588cstr = &cstr_buffer[0];
589}
590#if 0
591printf("DAVolumeKind %s\n", cstr);
592#endif
593if (!strcmp(cstr, "exfat"))
594daVolumeKind = _exfat;
595else if (!strcmp(cstr, "hfs"))
596daVolumeKind = _hfs;
597else if (!strcmp(cstr, "msdos"))
598daVolumeKind = _msdos;
599else
600daVolumeKind = _other;
601}
602#if 0
603printf(stderr, "whole %c, leaf %c, mounted %c\n",
604 isMediaWhole ? 'Y' : 'N',
605 isMediaLeaf ? 'Y' : 'N',
606 isVolumeMounted ? 'Y' : 'N');
607#endif
608#if 0
609CFShow(descDict);
610#endif
611CFRelease(descDict);
612CFRelease(disk);
613CFRelease(session);
614return 0;
615}
616
617static
618int checkDevicePath(char const* pathName)
619{
620struct stat buf;
621
622assert(pathName);
623if (strncmp(pathName, &devdisk[0], 9) != 0 &&
624strncmp(pathName, &devrdisk[0], 10) != 0) {
625fprintf(stderr, "disk must be of form /dev/rdiskUsS or /dev/diskUsS\n");
626return -1;
627}
628if (stat(pathName, &buf) < 0) {
629fprintf(stderr, "stat on %s failed, %s\n", pathName, strerror(errno));
630return -1;
631}
632if (!(buf.st_mode & (S_IFCHR | S_IFBLK))) {
633fprintf(stderr, "%s is not a block or character special device\n", pathName);
634return -1;
635}
636/*
637 * FIXME: milk information from st_rdev - what's in it?
638 */
639#if 0
640printf("size of buf is %lu\n", sizeof buf);
641printf("st_dev %#x\n", buf.st_dev);
642printf("st_ino %llu\n", buf.st_ino);
643printf("st_mode %#o\n", buf.st_mode);
644printf("st_nlink %u\n", buf.st_nlink);
645printf("st_uid %u\n", buf.st_uid);
646printf("st_gid %u\n", buf.st_gid);
647printf("st_rdev %#x\n", buf.st_rdev);
648printf("st_size %llu\n", buf.st_size);
649printf("st_blocks %llu\n", buf.st_blocks);
650printf("st_blksize %u\n", buf.st_blksize);
651printf("st_flags %#x\n", buf.st_flags);
652printf("st_gen %u\n", buf.st_gen);
653#endif
654return 0;
655}
656
657#pragma mark -
658#pragma mark Usage
659#pragma mark -
660
661static
662void usage(char const* self)
663{
664assert(self);
665fprintf(stderr, "Usage: %s [-yM] [-f boot_code_file] disk\n", self);
666fprintf(stderr, " boot_code_file is an optional boot template\n");
667fprintf(stderr, " -y: don't ask any questions\n");
668fprintf(stderr, " -M: keep volume mounted while proceeding (useful for root filesystem)\n");
669fprintf(stderr, "disk is of the form /dev/rdiskUsS or /dev/diskUsS\n");
670fprintf(stderr, "default boot files are\n");
671fprintf(stderr, " boot1h for HFS+\n");
672fprintf(stderr, " boot1f32 for FAT32\n");
673fprintf(stderr, " boot1x for exFAT\n");
674}
675
676static
677void unsupported(void)
678{
679fprintf(stderr, "%s", &UnsupportedMessage[0]);
680}
681
682#pragma mark -
683#pragma mark Main
684#pragma mark -
685
686int main(int argc, char* const argv[])
687{
688int ch;
689char const* bootFile = NULL;
690char const* devicePath = NULL;
691int dontAsk = 0;
692int keepMounted = 0;
693
694while ((ch = getopt(argc, argv, "yMf:")) != -1)
695switch (ch) {
696case 'y':
697dontAsk = 1;
698break;
699case 'M':
700keepMounted = 1;
701break;
702case 'f':
703bootFile = optarg;
704break;
705default:
706goto usage_and_error;
707}
708if (optind + 1 > argc)
709goto usage_and_error;
710devicePath = argv[optind];
711if (geteuid() != 0) {
712fprintf(stderr, "This program must be run as root\n");
713return -1;
714}
715#if 0
716printf("bootFile %s, devicePath %s, dontAsk %d\n", bootFile, devicePath, dontAsk);
717#endif
718if (checkDevicePath(devicePath) < 0)
719return -1;
720if (checkDevicePath2(devicePath) >= 0) {
721if (isMediaWhole && !isMediaLeaf) {
722fprintf(stderr, "%s is a whole disk\n", devicePath);
723return -1;
724}
725switch (daVolumeKind) {
726case _undetected:
727case _exfat:
728case _hfs:
729case _msdos:
730break;
731default:
732unsupported();
733return -1;
734}
735if (isVolumeMounted && keepMounted)
736isVolumeMounted = 0;
737if (isVolumeMounted && umount(devicePath) < 0) {
738fprintf(stderr, "Unable to umount %s, please 'diskutil umount' manually before running this program\n", devicePath);
739return -1;
740}
741}
742/*
743 * Note:
744 * Reading a non-multiple of 512 does not work on /dev/rdisk
745 */
746if (loadChunk(devicePath, daVolumeKind == _hfs ? 1024 : 0, 512, &bpbBlob) < 0)
747goto remount_and_error;
748if (checkSupportedVolume(&daVolumeKind, &bpbBlob, devicePath) < 0)
749goto cleanup_and_error;
750if (!bootFile) {
751switch (daVolumeKind) {
752case _exfat:
753bootFile = &defaultBootFile_exfat[0];
754break;
755case _hfs:
756bootFile = &defaultBootFile_hfs[0];
757break;
758case _msdos:
759bootFile = &defaultBootFile_fat32[0];
760break;
761default:
762assert(0);
763break;
764}
765printf("Using %s as default boot template\n", bootFile);
766}
767if (loadChunk(bootFile, 0, 0, &bootBlob) < 0)
768goto cleanup_and_error;
769switch (daVolumeKind) {
770case _exfat:
771if (calcSum(&bootBlob, &bpbBlob, &outputBlob, devicePath) < 0)
772goto cleanup_and_error;
773break;
774case _hfs:
775free_buffer(&bpbBlob);
776if (bootBlob._s != 1024U) {
777fprintf(stderr, "Boot Code size must be 1024 bytes\n");
778goto cleanup_and_error;
779}
780break;
781case _msdos:
782if (fat32Layout(&bootBlob, &bpbBlob, &outputBlob) < 0)
783goto cleanup_and_error;
784break;
785default:
786assert(0);
787break;
788}
789if (!dontAsk) {
790printf("About to write new boot record on %s, Are You Sure (Y/N)?", devicePath);
791ch = 0;
792while (ch != 'Y' && ch != 'N')
793ch = getchar();
794if (ch != 'Y') {
795printf("Aborted due to user request\n");
796goto cleanup_and_exit;
797}
798}
799switch (daVolumeKind) {
800case _exfat:
801writeVBR(devicePath, &outputBlob, 2, 12U * 512U, "exFAT");
802break;
803case _hfs:
804writeVBR(devicePath, &bootBlob, 1, 1024U, "HFS+");
805break;
806case _msdos:
807writeVBR(devicePath, &outputBlob, 1, 512U, "FAT32");
808break;
809default:
810assert(0);
811break;
812}
813
814cleanup_and_exit:
815cleanup();
816if (isVolumeMounted)
817mount(devicePath);
818return 0;
819
820cleanup_and_error:
821cleanup();
822remount_and_error:
823if (isVolumeMounted)
824mount(devicePath);
825return -1;
826
827usage_and_error:
828usage(argv[0]);
829return -1;
830}
831

Archive Download this file

Revision: 2495