1/*
2 * Copyright (c) 2001-2007 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 *  handleFolder.c
25 *  bless
26 *
27 *  Created by Shantonu Sen <ssen@apple.com> on Thu Dec 6 2001.
28 *  Copyright (c) 2001-2007 Apple Inc. All Rights Reserved.
29 *
30 *  $Id: handleFolder.c,v 1.79 2006/07/21 14:59:24 ssen Exp $
31 *
32 */
33
34#include <CoreFoundation/CoreFoundation.h>
35
36#include <stdlib.h>
37#include <stdio.h>
38#include <unistd.h>
39#include <sys/stat.h>
40#include <sys/mount.h>
41#include <sys/param.h>
42
43#include "enums.h"
44#include "structs.h"
45
46#include "bless.h"
47#include "bless_private.h"
48#include "protos.h"
49
50enum {
51  kIsInvisible                  = 0x4000, /* Files and folders */
52};
53
54
55static int isOFLabel(const char *data, int labelsize);
56static int WriteLabelFile(BLContextPtr context, const char *path, CFDataRef labeldata, int doTypeCreator, int scale);
57
58int modeFolder(BLContextPtr context, struct clarg actargs[klast]) {
59
60    int ret;
61    int isHFS, shouldBless;
62
63    uint32_t folderXid = 0;                   // The directory ID specified by folderXpath
64
65	CFDataRef bootXdata = NULL;
66	CFDataRef bootEFIdata = NULL;
67	CFDataRef labeldata = NULL;
68	CFDataRef labeldata2 = NULL;
69	struct statfs sb;
70
71    BLPreBootEnvType	preboot;
72
73	ret = BLGetPreBootEnvironmentType(context, &preboot);
74	if(ret) {
75		blesscontextprintf(context, kBLLogLevelError,  "Could not determine preboot environment\n");
76		return 1;
77	}
78
79
80    if(actargs[kmount].present) {
81		ret = BLGetCommonMountPoint(context, actargs[kmount].argument, "", actargs[kmount].argument);
82		if(ret) {
83			blesscontextprintf(context, kBLLogLevelError,  "Can't determine mount point of '%s'\n", actargs[kmount].argument );
84		} else {
85			blesscontextprintf(context, kBLLogLevelVerbose,  "Mount point is '%s'\n", actargs[kmount].argument );
86		}
87
88		// if -mount was specified, it implies we want to preserve what exists
89		actargs[ksaveX].present = 1;
90
91    } else if(actargs[kfolder].present || actargs[kfolder9].present) {
92		/* We know that at least one folder has been specified */
93		ret = BLGetCommonMountPoint(context, actargs[kfolder].argument, actargs[kfolder9].argument, actargs[kmount].argument);
94		if(ret) {
95			blesscontextprintf(context, kBLLogLevelError, "Can't determine mount point of '%s' and '%s'\n",
96							   actargs[kfolder].argument, actargs[kfolder9].argument);
97			return 1;
98		} else {
99			blesscontextprintf(context, kBLLogLevelVerbose, "Common mount point of '%s' and '%s' is %s\n",
100							   actargs[kfolder].argument,
101							   actargs[kfolder9].argument, actargs[kmount].argument );
102		}
103    } else if(actargs[kopenfolder].present) {
104		// didn't give a -folder or -mount
105		ret = BLGetCommonMountPoint(context, actargs[kopenfolder].argument, actargs[kopenfolder].argument, actargs[kmount].argument);
106		if(ret) {
107			blesscontextprintf(context, kBLLogLevelError, "Can't determine mount point of '%s'\n",
108							   actargs[kopenfolder].argument);
109			return 1;
110		} else {
111			blesscontextprintf(context, kBLLogLevelVerbose, "Common mount point of '%s' is %s\n",
112							   actargs[kopenfolder].argument, actargs[kmount].argument );
113		}
114    } else if(actargs[kalternateos].present) {
115		// didn't give a -folder or -mount
116		ret = BLGetCommonMountPoint(context, actargs[kalternateos].argument, actargs[kalternateos].argument, actargs[kmount].argument);
117		if(ret) {
118			blesscontextprintf(context, kBLLogLevelError, "Can't determine mount point of '%s'\n",
119							   actargs[kalternateos].argument);
120			return 1;
121		} else {
122			blesscontextprintf(context, kBLLogLevelVerbose, "Common mount point of '%s' is %s\n",
123							   actargs[kalternateos].argument, actargs[kmount].argument );
124		}
125    } else {
126		blesscontextprintf(context, kBLLogLevelError, "No volume specified\n" );
127		return 1;
128    }
129
130	/*
131	 * actargs[kmount].argument will always be filled in as the volume we are
132	 * operating. Look at actargs[kfolder].present to see if the user wanted
133	 * to bless something specifically, or just wanted to use -setBoot
134	 * or something
135	 */
136	if( actargs[kfolder].present || actargs[kfolder9].present
137		|| actargs[kopenfolder].present || actargs[kalternateos].present) {
138		shouldBless = 1;
139	} else {
140		shouldBless = 0;
141	}
142
143	if(shouldBless) {
144		// if we're blessing the volume, we need something for
145		// finderinfo[1]. If you didn't provide a file, but we're
146		// planning on generating one, fill in the path now
147
148		if(!actargs[kfile].present && actargs[kbootefi].present) {
149            // you didn't give a booter file explicitly, so we have to guess
150            // based on the system folder.
151            snprintf(actargs[kfile].argument, sizeof(actargs[kfile].argument),
152                     "%s/boot.efi", actargs[kfolder].argument);
153            actargs[kfile].present = 1;
154        }
155    }
156
157    /* If user gave options that require BootX creation, do it now. */
158    if(actargs[kbootinfo].present) {
159        char bootxpath[MAXPATHLEN];
160
161        if(!actargs[kbootinfo].hasArg) {
162            snprintf(actargs[kbootinfo].argument, kMaxArgLength-1, "%s/%s", actargs[kmount].argument, kBL_PATH_PPC_BOOTX_BOOTINFO);
163        }
164
165		ret = BLLoadFile(context, actargs[kbootinfo].argument, 0, &bootXdata);
166		if(ret) {
167			blesscontextprintf(context, kBLLogLevelVerbose,  "Could not load BootX data from %s\n",
168							   actargs[kbootinfo].argument);
169		}
170
171        if(actargs[kfolder].present && bootXdata) {
172            // check to see if needed
173            CFDataRef oldBootXdata = NULL;
174            struct stat oldPresence;
175
176            snprintf(bootxpath, sizeof(bootxpath), "%s/BootX", actargs[kfolder].argument);
177
178            ret = lstat(bootxpath, &oldPresence);
179
180            if(ret == 0 && S_ISREG(oldPresence.st_mode)) {
181                ret = BLLoadFile(context, bootxpath, 0, &oldBootXdata);
182            }
183            if((ret == 0) && oldBootXdata && CFEqual(oldBootXdata, bootXdata)) {
184				blesscontextprintf(context, kBLLogLevelVerbose,  "BootX unchanged at %s. Skipping update...\n",
185                    bootxpath );
186            } else {
187                ret = BLCreateFile(context, bootXdata, bootxpath, 1, kBL_OSTYPE_PPC_TYPE_BOOTX, kBL_OSTYPE_PPC_CREATOR_CHRP);
188                if(ret) {
189                    blesscontextprintf(context, kBLLogLevelError,  "Could not create BootX at %s\n", bootxpath );
190                    return 2;
191                } else {
192                    blesscontextprintf(context, kBLLogLevelVerbose,  "BootX created successfully at %s\n",
193                    bootxpath );
194                }
195            }
196
197            if (oldBootXdata) CFRelease(oldBootXdata);
198        } else {
199            blesscontextprintf(context, kBLLogLevelVerbose,  "Could not create BootX, no X folder specified\n" );
200        }
201    } else {
202        blesscontextprintf(context, kBLLogLevelVerbose,  "No BootX creation requested\n" );
203    }
204
205	/* If user gave options that require boot.efi creation, do it now. */
206    if(actargs[kbootefi].present) {
207        if(!actargs[kbootefi].hasArg) {
208
209            snprintf(actargs[kbootefi].argument, kMaxArgLength-1, "%s/%s", actargs[kmount].argument, kBL_PATH_I386_BOOT_EFI);
210
211        }
212
213		ret = BLLoadFile(context, actargs[kbootefi].argument, 0, &bootEFIdata);
214		if(ret) {
215			blesscontextprintf(context, kBLLogLevelVerbose,  "Could not load boot.efi data from %s\n",
216							   actargs[kbootefi].argument);
217		}
218
219        if(actargs[kfile].present && bootEFIdata) {
220
221            // check to see if needed
222            CFDataRef oldEFIdata = NULL;
223            struct stat oldPresence;
224
225            ret = lstat(actargs[kfile].argument, &oldPresence);
226
227            if(ret == 0 && S_ISREG(oldPresence.st_mode)) {
228                ret = BLLoadFile(context, actargs[kfile].argument, 0, &oldEFIdata);
229            }
230            if((ret == 0) && oldEFIdata && CFEqual(oldEFIdata, bootEFIdata)) {
231				blesscontextprintf(context, kBLLogLevelVerbose,  "boot.efi unchanged at %s. Skipping update...\n",
232                actargs[kfile].argument );
233            } else {
234                ret = BLCreateFile(context, bootEFIdata, actargs[kfile].argument, 1, 0, 0);
235                if(ret) {
236                    blesscontextprintf(context, kBLLogLevelError,  "Could not create boot.efi at %s\n", actargs[kfile].argument );
237                    return 2;
238                } else {
239                    blesscontextprintf(context, kBLLogLevelVerbose,  "boot.efi created successfully at %s\n",
240                        actargs[kfile].argument );
241                }
242            }
243
244            if(oldEFIdata) CFRelease(oldEFIdata);
245
246        } else {
247            blesscontextprintf(context, kBLLogLevelVerbose,  "Could not create boot.efi, no X folder specified\n" );
248        }
249    } else {
250        blesscontextprintf(context, kBLLogLevelVerbose,  "No boot.efi creation requested\n" );
251    }
252
253
254    ret = BLIsMountHFS(context, actargs[kmount].argument, &isHFS);
255    if(ret) {
256		blesscontextprintf(context, kBLLogLevelError,  "Could not determine filesystem of %s\n", actargs[kmount].argument );
257		return 1;
258    }
259
260    if(0 != statfs(actargs[kmount].argument, &sb)) {
261        blesscontextprintf(context, kBLLogLevelError,  "Can't statfs %s\n" ,
262                           actargs[kmount].argument);
263        return 1;
264    }
265
266
267    if(isHFS && shouldBless) {
268		uint32_t oldwords[8];
269		int useX = 1;
270		uint32_t openfolder = 0;
271		uint32_t bootfile = 0;
272		uint32_t alternateosid = 0; /* aliased with folder9 */
273
274		ret = BLGetVolumeFinderInfo(context, actargs[kmount].argument, oldwords);
275		if(ret) {
276			blesscontextprintf(context, kBLLogLevelError,  "Error getting old Finder info words for %s\n", actargs[kmount].argument );
277			return 1;
278		}
279
280		if(!actargs[kfolder].present && !actargs[kfolder9].present) {
281			// if no blessed folder, preserve what's there already
282			actargs[ksaveX].present = 1;
283		}
284
285		if(actargs[ksaveX].present) {
286			folderXid = oldwords[5];
287			blesscontextprintf(context, kBLLogLevelVerbose,  "Saved folder X\n" );
288		}
289
290		/* always save boot file */
291		bootfile = oldwords[1];
292		alternateosid = oldwords[3];
293
294		/* bless! bless */
295
296		/* First get any directory IDs we need */
297		if(actargs[kfolder].present) {
298			ret = BLGetFileID(context, actargs[kfolder].argument, &folderXid);
299			if(ret) {
300				blesscontextprintf(context, kBLLogLevelError,  "Error while getting directory ID of %s\n", actargs[kfolder].argument );
301			} else {
302				blesscontextprintf(context, kBLLogLevelVerbose,  "Got directory ID of %u for %s\n",
303								   folderXid, actargs[kfolder].argument );
304			}
305		}
306
307		if(actargs[kfolder9].present) {
308			ret = BLGetFileID(context, actargs[kfolder9].argument, &alternateosid);
309			if(ret) {
310				blesscontextprintf(context, kBLLogLevelError,  "Error while getting directory ID of %s\n", actargs[kfolder9].argument );
311			} else {
312				blesscontextprintf(context, kBLLogLevelVerbose,  "Got directory ID of %u for %s\n",
313								   alternateosid, actargs[kfolder9].argument );
314			}
315		}
316
317		if(actargs[kfile].present) {
318			ret = BLGetFileID(context, actargs[kfile].argument, &bootfile);
319			if(ret) {
320				blesscontextprintf(context, kBLLogLevelError,  "Error while getting file ID of %s. Ignoring...\n", actargs[kfile].argument );
321				bootfile = 0;
322			} else {
323				struct stat checkForFile;
324
325				ret = lstat(actargs[kfile].argument, &checkForFile);
326				if(ret || !S_ISREG(checkForFile.st_mode)) {
327					blesscontextprintf(context, kBLLogLevelError,  "%s cannot be accessed, or is not a regular file. Ignoring...\n", actargs[kfile].argument );
328					bootfile = 0;
329				} else {
330					blesscontextprintf(context, kBLLogLevelVerbose,  "Got file ID of %u for %s\n",
331									   bootfile, actargs[kfile].argument );
332				}
333			}
334
335		} else {
336            // no file given. we should try to verify the existing booter
337            if(bootfile) {
338                ret = BLLookupFileIDOnMount(context, actargs[kmount].argument, bootfile, actargs[kfile].argument);
339                if(ret) {
340                    blesscontextprintf(context, kBLLogLevelVerbose,  "Invalid EFI blessed file ID %u. Zeroing...\n",
341                                       bootfile );
342                    bootfile = 0;
343                } else {
344					struct stat checkForFile;
345
346					ret = lstat(actargs[kfile].argument, &checkForFile);
347					if(ret || !S_ISREG(checkForFile.st_mode)) {
348						blesscontextprintf(context, kBLLogLevelError,  "%s cannot be accessed, or is not a regular file. Ignoring...\n", actargs[kfile].argument );
349						bootfile = 0;
350					} else {
351						blesscontextprintf(context, kBLLogLevelVerbose,
352										   "Preserving EFI blessed file ID %u for %s\n",
353										   bootfile, actargs[kfile].argument );
354					}
355                }
356            }
357
358        }
359
360		if(actargs[kalternateos].present) {
361			ret = BLGetFileID(context, actargs[kalternateos].argument, &alternateosid);
362			if(ret) {
363				blesscontextprintf(context, kBLLogLevelError,  "Error while getting file ID of %s. Ignoring...\n", actargs[kalternateos].argument );
364				alternateosid = 0;
365			} else {
366				struct stat checkForFile;
367
368				ret = lstat(actargs[kalternateos].argument, &checkForFile);
369				if(ret || (!S_ISREG(checkForFile.st_mode) && !S_ISDIR(checkForFile.st_mode))) {
370					blesscontextprintf(context, kBLLogLevelError,  "%s cannot be accessed, or is not a regular file or directory. Ignoring...\n", actargs[kalternateos].argument );
371					alternateosid = 0;
372				} else {
373					blesscontextprintf(context, kBLLogLevelVerbose,  "Got file/directory ID of %u for %s\n",
374									   alternateosid, actargs[kalternateos].argument );
375				}
376			}
377
378		} else {
379            // no file/directory given. we should try to verify the existing ID
380            if(alternateosid) {
381                ret = BLLookupFileIDOnMount(context, actargs[kmount].argument, alternateosid, actargs[kalternateos].argument);
382                if(ret) {
383                    blesscontextprintf(context, kBLLogLevelVerbose,  "Invalid EFI alternate OS file/dir ID %u. Zeroing...\n",
384                                       alternateosid );
385                    alternateosid = 0;
386                } else {
387					struct stat checkForFile;
388
389					ret = lstat(actargs[kalternateos].argument, &checkForFile);
390					if(ret || (!S_ISREG(checkForFile.st_mode) && !S_ISDIR(checkForFile.st_mode))) {
391						blesscontextprintf(context, kBLLogLevelError,  "%s cannot be accessed, or is not a regular file. Ignoring...\n", actargs[kalternateos].argument );
392						alternateosid = 0;
393					} else {
394						blesscontextprintf(context, kBLLogLevelVerbose,
395										   "Preserving EFI alternate OS file/dir ID %u for %s\n",
396										   alternateosid, actargs[kalternateos].argument );
397					}
398                }
399            }
400
401        }
402
403		if(actargs[kopenfolder].present) {
404			char openmount[kMaxArgLength];
405
406			openmount[0] = '\0';
407
408			ret = BLGetCommonMountPoint(context, actargs[kopenfolder].argument,
409										actargs[kmount].argument, openmount);
410
411			if(ret || strcmp(actargs[kmount].argument, openmount)) {
412				// if there's an error with the openfolder, or it's
413				// not on the target volume, abort
414				blesscontextprintf(context, kBLLogLevelError,  "Error determining mountpoint of %s\n", actargs[kopenfolder].argument );
415			}
416
417			ret = BLGetFileID(context, actargs[kopenfolder].argument, &openfolder);
418			if(ret) {
419				blesscontextprintf(context, kBLLogLevelError,  "Error while get directory ID of %s\n", actargs[kopenfolder].argument );
420			} else {
421				blesscontextprintf(context, kBLLogLevelVerbose,  "Got directory ID of %u for %s\n",
422								   openfolder, actargs[kopenfolder].argument );
423			}
424		}
425
426		if(actargs[kuse9].present) {
427			useX = 0;
428		}
429
430		/* If either directory was not specified, the dirID
431			* variables will be 0, so we can use that to initialize
432			* the FI fields */
433
434		/* Set Finder info words 3 & 5 + 2 + 1*/
435		oldwords[1] = bootfile;
436		oldwords[2] = openfolder;
437		oldwords[3] = alternateosid;
438		oldwords[5] = folderXid;
439
440        // reserved1 returns the f_fssubtype attribute. Right now, 0 == HFS+,
441        // 1 == HFS+J. Anything else is either HFS plain, or some form
442        // of HFSX. These filesystems we don't want blessed, because we don't
443        // want future versions of OF to list them as bootable, but rather
444        // prefer the Apple_Boot partition
445        //
446        // For EFI-based systems, it's OK to set finderinfo[0], and indeed
447        // a better user experience so that the EFI label shows up
448
449        if(actargs[ksetboot].present &&
450           (preboot == kBLPreBootEnvType_OpenFirmware) &&
451#if _DARWIN_FEATURE_64_BIT_INODE
452           (sb.f_fssubtype & ~1)
453#else
454           (sb.f_reserved1 & ~1)
455#endif
456           ) {
457            blesscontextprintf(context, kBLLogLevelVerbose,  "%s is not HFS+ or Journaled HFS+. Not setting finderinfo[0]...\n", actargs[kmount].argument );
458            oldwords[0] = 0;
459        } else {
460            if(!folderXid || !useX) {
461                /* The 9 folder is what we really want */
462                oldwords[0] = alternateosid;
463            } else {
464                /* X */
465                oldwords[0] = folderXid;
466            }
467        }
468
469		blesscontextprintf(context, kBLLogLevelVerbose,  "finderinfo[0] = %d\n", oldwords[0] );
470		blesscontextprintf(context, kBLLogLevelVerbose,  "finderinfo[1] = %d\n", oldwords[1] );
471		blesscontextprintf(context, kBLLogLevelVerbose,  "finderinfo[2] = %d\n", oldwords[2] );
472		blesscontextprintf(context, kBLLogLevelVerbose,  "finderinfo[3] = %d\n", oldwords[3] );
473		blesscontextprintf(context, kBLLogLevelVerbose,  "finderinfo[5] = %d\n", oldwords[5] );
474
475
476		if(geteuid() != 0 && geteuid() != sb.f_owner) {
477		    blesscontextprintf(context, kBLLogLevelError,  "Authorization required\n" );
478			return 1;
479		}
480
481		ret = BLSetVolumeFinderInfo(context,  actargs[kmount].argument, oldwords);
482		if(ret) {
483			blesscontextprintf(context, kBLLogLevelError,  "Can't set Finder info fields for volume mounted at %s: %s\n", actargs[kmount].argument , strerror(errno));
484			return 2;
485		}
486
487    }
488
489	if(actargs[klabel].present||actargs[klabelfile].present) {
490		int isLabel = 0;
491
492		if(actargs[klabelfile].present) {
493			ret = BLLoadFile(context, actargs[klabelfile].argument, 0, &labeldata);
494			if(ret) {
495				blesscontextprintf(context, kBLLogLevelError, "Can't load label '%s'\n",
496								   actargs[klabelfile].argument);
497				return 2;
498			}
499		} else {
500			ret = BLGenerateLabelData(context, actargs[klabel].argument, kBitmapScale_1x, &labeldata);
501			if (ret) {
502				blesscontextprintf(context, kBLLogLevelError, "Can't render label '%s'\n",
503								   actargs[klabel].argument);
504				return 3;
505			}
506			ret = BLGenerateLabelData(context, actargs[klabel].argument, kBitmapScale_2x, &labeldata2);
507			if (ret) {
508				blesscontextprintf(context, kBLLogLevelError, "Can't render label '%s'\n",
509								   actargs[klabel].argument);
510				return 3;
511			}
512		}
513
514		isLabel = isOFLabel((const char *)CFDataGetBytePtr(labeldata), CFDataGetLength(labeldata));
515		blesscontextprintf(context, kBLLogLevelVerbose,  "Scale 1 label data is valid: %s\n",
516                           isLabel ? "YES" : "NO");
517
518		if (actargs[kfolder].present) {
519			char sysfolder[MAXPATHLEN];
520
521			sprintf(sysfolder, "%s/.disk_label", actargs[kfolder].argument);
522			ret = WriteLabelFile(context, sysfolder, labeldata, isLabel, kBitmapScale_1x);
523			if (ret) return 1;
524
525			if (labeldata2) {
526				sprintf(sysfolder, "%s/.disk_label_2x", actargs[kfolder].argument);
527				ret = WriteLabelFile(context, sysfolder, labeldata2, 0, kBitmapScale_2x);
528				if (ret) return 1;
529			}
530		}
531	}
532
533    /* Set Open Firmware to boot off the specified volume*/
534    if(actargs[ksetboot].present) {
535        if(preboot == kBLPreBootEnvType_EFI) {
536			// if you blessed the volume, then just point EFI at the volume.
537			// only if you didn't bless, but you have something interesting
538			// to point at, should you use actargs[kfile]
539
540
541            if (actargs[klegacy].present) {
542                ret = setefilegacypath(context, actargs[kmount].argument, actargs[knextonly].present,
543									   actargs[klegacydrivehint].present ? actargs[klegacydrivehint].argument : NULL,
544									   actargs[koptions].present ? actargs[koptions].argument : NULL);
545
546            } else {
547                ret = setefifilepath(context, ( !shouldBless && actargs[kfile].present ?
548											actargs[kfile].argument :
549											actargs[kmount].argument),
550                                 actargs[knextonly].present,
551                                 actargs[koptions].present ? actargs[koptions].argument : NULL,
552                                 actargs[kshortform].present ? true : false);
553            }
554            if(ret) {
555                return 3;
556            }
557        } else {
558            struct statfs sb;
559
560            ret = blsustatfs(actargs[kmount].argument, &sb);
561            if(ret) {
562                blesscontextprintf(context, kBLLogLevelError,  "Can't statfs: %s\n",
563                                   strerror(errno));
564                return 2;
565            }
566
567            ret = setboot(context, sb.f_mntfromname, bootXdata, labeldata);
568            if(ret) {
569                return 3;
570            }
571        }
572    }
573
574	if (bootXdata) CFRelease(bootXdata);
575	if (bootEFIdata) CFRelease(bootEFIdata);
576	if (labeldata) CFRelease(labeldata);
577	if (labeldata2) CFRelease(labeldata2);
578
579
580	return 0;
581}
582
583static int isOFLabel(const char *data, int labelsize)
584{
585    uint16_t width, height;
586
587    if(data[0] != 1) return 0;
588
589    width = CFSwapInt16BigToHost(*(uint16_t *)&data[1]);
590    height = CFSwapInt16BigToHost(*(uint16_t *)&data[3]);
591
592    if(labelsize != (width*height+5)) return 0;
593
594    // basic sanity checks for version and dimensions were satisfied
595    return 1;
596}
597
598
599
600static int WriteLabelFile(BLContextPtr context, const char *path, CFDataRef labeldata, int doTypeCreator, int scale)
601{
602    int ret;
603
604    blesscontextprintf(context, kBLLogLevelVerbose,  "Putting scale %d label bitmap in %s\n", scale, path);
605
606    ret = BLCreateFile(context, labeldata, path,
607                       0,
608                       doTypeCreator ? kBL_OSTYPE_PPC_TYPE_OFLABEL : 0,
609                       doTypeCreator ? kBL_OSTYPE_PPC_CREATOR_CHRP : 0);
610    if (ret) {
611        blesscontextprintf(context, kBLLogLevelError,  "Could not write scale %d bitmap label file\n", scale);
612    } else {
613        blesscontextprintf(context, kBLLogLevelVerbose, "Scale %d label written\n", scale);
614    }
615
616    if (!ret) {
617        ret = BLSetFinderFlag(context, path, kIsInvisible, 1);
618        if (ret) {
619            blesscontextprintf(context, kBLLogLevelError,  "Could not set invisibility for %s\n", path);
620        } else {
621            blesscontextprintf(context, kBLLogLevelVerbose,  "Invisibility set for %s\n", path);
622        }
623    }
624    return ret;
625}
626