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