]> git.saurik.com Git - hfs.git/blob - newfs_hfs/makehfs.c
Separate dataExtents / rsrcExtents (gcc noticed).
[hfs.git] / newfs_hfs / makehfs.c
1 /*
2 * Copyright (c) 1999-2011 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 File: makehfs.c
25
26 Contains: Initialization code for HFS and HFS Plus volumes.
27
28 Copyright: � 1984-1999 by Apple Computer, Inc., all rights reserved.
29
30 */
31
32 #include <sys/param.h>
33 #include <sys/types.h>
34 #include <sys/time.h>
35 #include <err.h>
36 #include <sys/errno.h>
37 #include <sys/stat.h>
38 #include <sys/sysctl.h>
39 #include <sys/vmmeter.h>
40
41 #include <err.h>
42 #include <errno.h>
43 #include <fcntl.h>
44 #include <paths.h>
45 #include <pwd.h>
46 #include <stdlib.h>
47 #include <stdio.h>
48 #include <string.h>
49 #include <unistd.h>
50 #include <wipefs.h>
51
52 /*
53 * CommonCrypto is meant to be a more stable API than OpenSSL.
54 * Defining COMMON_DIGEST_FOR_OPENSSL gives API-compatibility
55 * with OpenSSL, so we don't have to change the code.
56 */
57 #define COMMON_DIGEST_FOR_OPENSSL
58 #include <CommonCrypto/CommonDigest.h>
59
60 #include <libkern/OSByteOrder.h>
61
62 #include <CoreFoundation/CFString.h>
63 #include <CoreFoundation/CFStringEncodingExt.h>
64 #include <IOKit/IOKitLib.h>
65 #include <IOKit/storage/IOMedia.h>
66
67 #include <TargetConditionals.h>
68
69 extern Boolean _CFStringGetFileSystemRepresentation(CFStringRef string, UInt8 *buffer, CFIndex maxBufLen);
70
71
72 #include <hfs/hfs_format.h>
73 #include <hfs/hfs_mount.h>
74 #include "hfs_endian.h"
75
76 #include "newfs_hfs.h"
77
78 #ifndef NEWFS_HFS_DEBUG
79 # ifdef DEBUG_BUILD
80 # define NEWFS_HFS_DEBUG 1
81 # else
82 # define NEWFS_HFS_DEBUG 0
83 # endif
84 #endif
85
86 #define HFS_BOOT_DATA "/usr/share/misc/hfsbootdata"
87
88 #define HFS_JOURNAL_FILE ".journal"
89 #define HFS_JOURNAL_INFO ".journal_info_block"
90
91 #define kJournalFileType 0x6a726e6c /* 'jrnl' */
92
93
94 typedef HFSMasterDirectoryBlock HFS_MDB;
95
96 struct filefork {
97 UInt16 startBlock;
98 UInt16 blockCount;
99 UInt32 logicalSize;
100 UInt32 physicalSize;
101 };
102
103 struct ExtentRecord {
104 HFSPlusExtentKey key;
105 HFSPlusExtentRecord record;
106 } __attribute__((aligned(2), packed));
107 static size_t numOverflowExtents = 0;
108 static struct ExtentRecord *overflowExtents = NULL;
109
110 struct filefork gDTDBFork, gSystemFork, gReadMeFork;
111
112 static void WriteVH __P((const DriveInfo *driveInfo, HFSPlusVolumeHeader *hp));
113 static void InitVH __P((hfsparams_t *defaults, UInt64 sectors,
114 HFSPlusVolumeHeader *header));
115
116 static int AllocateExtent(UInt8 *buffer, UInt32 startBlock, UInt32 blockCount);
117 static int MarkExtentUsed(const DriveInfo *, HFSPlusVolumeHeader *, UInt32, UInt32);
118
119 static void WriteExtentsFile __P((const DriveInfo *dip, UInt64 startingSector,
120 const hfsparams_t *dp, HFSExtentDescriptor *bbextp, void *buffer,
121 UInt32 *bytesUsed, UInt32 *mapNodes));
122
123 static void WriteAttributesFile(const DriveInfo *driveInfo, UInt64 startingSector,
124 const hfsparams_t *dp, HFSExtentDescriptor *bbextp, void *buffer,
125 UInt32 *bytesUsed, UInt32 *mapNodes);
126
127 static void WriteCatalogFile __P((const DriveInfo *dip, UInt64 startingSector,
128 const hfsparams_t *dp, HFSPlusVolumeHeader *header, void *buffer,
129 UInt32 *bytesUsed, UInt32 *mapNodes));
130 static int WriteJournalInfo(const DriveInfo *driveInfo, UInt64 startingSector,
131 const hfsparams_t *dp, HFSPlusVolumeHeader *header,
132 void *buffer);
133 static void InitCatalogRoot_HFSPlus __P((const hfsparams_t *dp, const HFSPlusVolumeHeader *header, void * buffer));
134
135 static void WriteMapNodes __P((const DriveInfo *driveInfo, UInt64 diskStart,
136 UInt32 firstMapNode, UInt32 mapNodes, UInt16 btNodeSize, void *buffer));
137 static void WriteBuffer __P((const DriveInfo *driveInfo, UInt64 startingSector,
138 UInt64 byteCount, const void *buffer));
139 static UInt32 Largest __P((UInt32 a, UInt32 b, UInt32 c, UInt32 d ));
140
141 static UInt32 GetDefaultEncoding();
142
143 static UInt32 UTCToLocal __P((UInt32 utcTime));
144
145 static int ConvertUTF8toUnicode __P((const UInt8* source, size_t bufsize,
146 UniChar* unibuf, UInt16 *charcount));
147
148 static int getencodinghint(unsigned char *name);
149
150 #define VOLUMEUUIDVALUESIZE 2
151 typedef union VolumeUUID {
152 UInt32 value[VOLUMEUUIDVALUESIZE];
153 struct {
154 UInt32 high;
155 UInt32 low;
156 } v;
157 } VolumeUUID;
158 void GenerateVolumeUUID(VolumeUUID *newVolumeID);
159
160 void SETOFFSET (void *buffer, UInt16 btNodeSize, SInt16 recOffset, SInt16 vecOffset);
161 #define SETOFFSET(buf,ndsiz,offset,rec) \
162 (*(SInt16 *)((UInt8 *)(buf) + (ndsiz) + (-2 * (rec))) = (SWAP_BE16 (offset)))
163
164 #define BYTESTOBLKS(bytes,blks) DivideAndRoundUp((bytes),(blks))
165
166 #define ROUNDUP(x, u) (((x) % (u) == 0) ? (x) : ((x)/(u) + 1) * (u))
167
168 #if TARGET_OS_EMBEDDED
169 #define ENCODING_TO_BIT(e) \
170 ((e) < 48 ? (e) : 0)
171 #else
172 #define ENCODING_TO_BIT(e) \
173 ((e) < 48 ? (e) : \
174 ((e) == kCFStringEncodingMacUkrainian ? 48 : \
175 ((e) == kCFStringEncodingMacFarsi ? 49 : 0)))
176 #endif
177
178
179 #ifdef DEBUG_BUILD
180 struct cp_root_xattr {
181 u_int16_t vers;
182 u_int16_t reserved1;
183 u_int64_t reserved2;
184 u_int8_t reserved3[16];
185 } __attribute__((aligned(2), packed));
186 #endif
187
188 /*
189 * Create a series of (sequential!) extents for the
190 * requested file. It tries to create the requested
191 * number, but may be stymied by the file size, and
192 * the number of minimum blocks.
193 */
194 static void
195 createExtents(HFSPlusForkData *file,
196 UInt32 fileID,
197 UInt32 startBlock,
198 size_t numExtents,
199 int minBlocks)
200 {
201 if (NEWFS_HFS_DEBUG == 0) {
202 /*
203 * The common case, for non-debug.
204 */
205 file->extents[0].startBlock = startBlock;
206 file->extents[0].blockCount = file->totalBlocks;
207 } else {
208 UInt32 blocksLeft, blocksTotal = 0, blockStep;
209 int i;
210 int firstAdjust = 0;
211
212 if (numExtents == 1) {
213 // The common case, no need to do any math
214 file->extents[0].startBlock = startBlock;
215 file->extents[0].blockCount = file->totalBlocks;
216 return;
217 }
218 if (file->totalBlocks < numExtents)
219 numExtents = file->totalBlocks;
220
221 blocksLeft = file->totalBlocks;
222
223 /*
224 * The intent here is to split the number of blocks into the
225 * requested number of extents. So first we determine how
226 * many blocks should go in each extent -- that's blockStep.
227 * If we have been giving minBlocks, we need to make sure it's
228 * a multiple of that. (In general, the values are going to be
229 * 1 or 2 for minBlocks.)
230 *
231 * If there are more requested extents than blocks, the division
232 * works out to zero... so we limit blockStep to minBlocks.
233 *
234 */
235 blockStep = blocksLeft / numExtents;
236
237 /*
238 * To allow invalid extent lengths, set minBlocks to 1, and
239 * comment out the next two if statements.
240 */
241 if ((blockStep % minBlocks) != 0)
242 blockStep = (blockStep / minBlocks) * minBlocks;
243 if (blockStep == 0)
244 blockStep = minBlocks;
245
246 /*
247 * Now, after that, we may still not have the right number, since
248 * the math may not work out properly. So we can work around that
249 * by making the first extent have all the spares.
250 */
251 if ((blockStep * numExtents) < blocksLeft) {
252 // Need to adjust the first one.
253 firstAdjust = blocksLeft - (blockStep * numExtents);
254 if ((firstAdjust % minBlocks) != 0)
255 firstAdjust = ROUNDUP(firstAdjust, minBlocks);
256 }
257
258 /*
259 * Now, at this point, start handing out blocks to each extent.
260 * First to the 8 extents in the fork descriptor.
261 */
262 for (i = 0; i < 8 && blocksLeft > 0; i++) {
263 int n = MIN(blockStep + firstAdjust, blocksLeft);
264 file->extents[i].startBlock = startBlock + blocksTotal;
265 file->extents[i].blockCount = n;
266 blocksLeft -= n;
267 blocksTotal += n;
268 firstAdjust = 0;
269 }
270 /*
271 * Then, if there are any left, to the overflow extents.
272 */
273 while (blocksLeft > 0) {
274 struct ExtentRecord tmp;
275 UInt32 bcount = 0;
276 memset(&tmp, 0, sizeof(tmp));
277 tmp.key.keyLength = SWAP_BE16(sizeof(HFSPlusExtentKey) - sizeof(uint16_t));
278 tmp.key.forkType = 0;
279 tmp.key.fileID = SWAP_BE32(fileID);
280 tmp.key.startBlock = SWAP_BE32(blocksTotal);
281 for (i = 0; i < 8 && blocksLeft > 0; i++) {
282 int n = MIN(blockStep, blocksLeft);
283 tmp.record[i].startBlock = SWAP_BE32(blocksTotal + bcount + startBlock);
284 tmp.record[i].blockCount = SWAP_BE32(n);
285 bcount += n;
286 blocksLeft -= n;
287 }
288 blocksTotal += bcount;
289 overflowExtents = realloc(overflowExtents, (numOverflowExtents+1) * sizeof(*overflowExtents));
290 overflowExtents[numOverflowExtents++] = tmp;
291 }
292 }
293 return;
294 }
295
296 /*
297 * wipefs() in -lutil knows about multiple filesystem formats.
298 * This replaces the code:
299 * WriteBuffer(driveInfo, 0, diskBlocksUsed * kBytesPerSector, NULL);
300 * WriteBuffer(driveInfo, driveInfo->totalSectors - 8, 4 * 1024, NULL);
301 * which was used to erase the beginning and end of the filesystem.
302 *
303 */
304 static int
305 dowipefs(int fd)
306 {
307 int err;
308 wipefs_ctx handle;
309
310 err = wipefs_alloc(fd, 0/*sectorSize*/, &handle);
311 if (err == 0) {
312 err = wipefs_wipe(handle);
313 }
314 wipefs_free(&handle);
315 return err;
316 }
317
318
319 /*
320 * make_hfsplus
321 *
322 * This routine writes an initial HFS Plus volume structure onto a volume.
323 * It is assumed that the disk has already been formatted and verified.
324 *
325 */
326 int
327 make_hfsplus(const DriveInfo *driveInfo, hfsparams_t *defaults)
328 {
329 UInt16 btNodeSize;
330 UInt32 sectorsPerBlock;
331 UInt32 mapNodes;
332 UInt32 sectorsPerNode;
333 UInt32 temp;
334 UInt32 bytesUsed;
335 UInt32 endOfAttributes;
336 UInt32 startOfAllocation;
337 UInt64 bytesToZero;
338 void *nodeBuffer = NULL;
339 HFSPlusVolumeHeader *header = NULL;
340 UInt64 sector;
341
342 /* Use wipefs() API to clear old metadata from the device.
343 * This should be done before we start writing anything on the
344 * device as wipefs will internally call ioctl(DKIOCDISCARD) on the
345 * entire device.
346 */
347 (void) dowipefs(driveInfo->fd);
348
349 /* --- Create an HFS Plus header: */
350
351 header = (HFSPlusVolumeHeader*)malloc((size_t)kBytesPerSector);
352 if (header == NULL)
353 err(1, NULL);
354
355 defaults->encodingHint = getencodinghint(defaults->volumeName);
356
357 /* VH Initialized in native byte order */
358 InitVH(defaults, driveInfo->totalSectors, header);
359
360 sectorsPerBlock = header->blockSize / kBytesPerSector;
361
362
363 /*--- ZERO OUT BEGINNING OF DISK: */
364 /*
365 * Clear out the space to be occupied by the bitmap and B-Trees.
366 * The first chunk is the boot sectors, volume header, allocation bitmap,
367 * journal, Extents B-tree, and Attributes B-tree (if any).
368 * The second chunk is the Catalog B-tree.
369 */
370
371 /* Zero out first 1M (to be safe) for volume header */
372 WriteBuffer(driveInfo, 0, 1024*1024, NULL);
373
374 if (NEWFS_HFS_DEBUG) {
375 /*
376 * Mark each file extent as used individually, rather than doing it all at once.
377 * Also zero out the entire file.
378 */
379 # define MFU(f) \
380 do { \
381 WriteBuffer(driveInfo, \
382 header->f.extents[0].startBlock * sectorsPerBlock, \
383 header->f.totalBlocks * header->blockSize, \
384 NULL); \
385 if (MarkExtentUsed(driveInfo, header, header->f.extents[0].startBlock, header->f.totalBlocks) == -1) { \
386 errx(1, #f " extent overlap <%u, %u>", header->f.extents[0].startBlock, header->f.totalBlocks); \
387 } \
388 } while (0)
389 MFU(allocationFile);
390 MFU(attributesFile);
391 MFU(extentsFile);
392 # undef MFU
393 } else {
394 /* Zero out from start of allocation file to end of attribute file;
395 * will include allocation bitmap, journal, extents btree, and
396 * attribute btree
397 */
398 sector = header->allocationFile.extents[0].startBlock * sectorsPerBlock;
399 endOfAttributes = header->attributesFile.extents[0].startBlock + header->attributesFile.totalBlocks;
400 startOfAllocation = header->allocationFile.extents[0].startBlock;
401 bytesToZero = (UInt64) (endOfAttributes - startOfAllocation + 1) * header->blockSize;
402 WriteBuffer(driveInfo, sector, bytesToZero, NULL);
403
404 bytesToZero = (UInt64) header->catalogFile.totalBlocks * header->blockSize;
405 sector = header->catalogFile.extents[0].startBlock * sectorsPerBlock;
406 WriteBuffer(driveInfo, sector, bytesToZero, NULL);
407 }
408 /*
409 * Allocate a buffer for the rest of our IO.
410 * Note that in some cases we may need to initialize an EA, so we
411 * need to use the attribute B-Tree node size in this calculation.
412 */
413
414 temp = Largest( defaults->catalogNodeSize * 2,
415 (defaults->attributesNodeSize * 2),
416 header->blockSize,
417 (header->catalogFile.extents[0].startBlock + header->catalogFile.totalBlocks + 7) / 8 );
418 /*
419 * If size is not a mutiple of 512, round up to nearest sector
420 */
421 if ( (temp & 0x01FF) != 0 )
422 temp = (temp + kBytesPerSector) & 0xFFFFFE00;
423
424 nodeBuffer = valloc((size_t)temp);
425 if (nodeBuffer == NULL)
426 err(1, NULL);
427
428
429
430 /*--- WRITE ALLOCATION BITMAP BITS TO DISK: */
431
432 /*
433 * XXX - this doesn't work well with using arbitrary extents.
434 *
435 * To do this, we need to find the appropriate area in the file, and
436 * pass that in to AllocateExtent, which is just a bitmap manipulation
437 * routine. Then we need to write it out at the right place. Note that
438 * we may have to read it in first, as well, which may mean zeroing out
439 * the entirety of the allocation file first.
440 *
441 * Possible solution:
442 * New function to mark extent as used.
443 * Function should figure out which block(s) for an extent.
444 * Read it in. Mark the bits used. Return.
445 * For now, it can assume the allocation extents are contiguous, but
446 * should be extensible to not do that.
447 */
448 sector = header->allocationFile.extents[0].startBlock * sectorsPerBlock;
449 bzero(nodeBuffer, temp);
450 /* Mark volume header as allocated */
451 if (header->blockSize == 512) {
452 if (MarkExtentUsed(driveInfo, header, 0, 4) == -1) {
453 errx(1, "Overlapped extent at <0, 4> (%d)", __LINE__);
454 }
455 } else if (header->blockSize == 1024) {
456 if (MarkExtentUsed(driveInfo, header, 0, 2) == -1) {
457 errx(1, "Overlapped extent at <0, 2> (%d)", __LINE__);
458 }
459 } else {
460 if (MarkExtentUsed(driveInfo, header, 0, 1) == -1) {
461 errx(1, "Overlapped extent at <0, 1> (%d)", __LINE__);
462 }
463 }
464 if (NEWFS_HFS_DEBUG == 0) {
465 /* Mark area from bitmap to end of attributes as allocated */
466 if (MarkExtentUsed(driveInfo, header, startOfAllocation, (endOfAttributes - startOfAllocation)) == -1) {
467 errx(1, "Overlapped extent at <%u, %u> (%d)\n", startOfAllocation, endOfAttributes - startOfAllocation, __LINE__);
468 }
469 }
470
471 /* Mark catalog btree blocks as allocated */
472 if (NEWFS_HFS_DEBUG) {
473 /* Erase the catalog file first */
474 WriteBuffer(driveInfo,
475 header->catalogFile.extents[0].startBlock * sectorsPerBlock,
476 header->catalogFile.totalBlocks * header->blockSize,
477 NULL);
478 }
479 if (MarkExtentUsed(driveInfo, header,
480 header->catalogFile.extents[0].startBlock,
481 header->catalogFile.totalBlocks) == -1) {
482 errx(1, "Overlapped catalog extent at <%u, %u>\n", header->catalogFile.extents[0].startBlock, header->catalogFile.totalBlocks);
483 }
484
485 /*
486 * Write alternate Volume Header bitmap bit to allocations file at
487 * 2nd to last sector on HFS+ volume
488 */
489 if (MarkExtentUsed(driveInfo, header, header->totalBlocks - 1, 1) == -1) {
490 errx(1, "Overlapped extent for header at <%u, %u>\n", header->totalBlocks - 1, 1);
491 }
492
493 /*
494 * If the blockSize is 512 bytes, then the last 1kbyte has to be marked
495 * used via two bits.
496 */
497 if ( header->blockSize == 512 ) {
498 if (MarkExtentUsed(driveInfo, header, header->totalBlocks - 2, 1) == -1) {
499 errx(1, "Overlapped extent for AVH at <%u, %u>\n", header->totalBlocks - 2, 1);
500 }
501
502 }
503
504 /*--- WRITE FILE EXTENTS B-TREE TO DISK: */
505
506 btNodeSize = defaults->extentsNodeSize;
507 sectorsPerNode = btNodeSize/kBytesPerSector;
508
509 sector = header->extentsFile.extents[0].startBlock * sectorsPerBlock;
510 WriteExtentsFile(driveInfo, sector, defaults, NULL, nodeBuffer, &bytesUsed, &mapNodes);
511
512 if (mapNodes > 0) {
513 WriteMapNodes(driveInfo, (sector + bytesUsed/kBytesPerSector),
514 bytesUsed/btNodeSize, mapNodes, btNodeSize, nodeBuffer);
515 }
516
517
518
519 /*--- WRITE FILE ATTRIBUTES B-TREE TO DISK: */
520 if (defaults->attributesClumpSize) {
521
522 btNodeSize = defaults->attributesNodeSize;
523 sectorsPerNode = btNodeSize/kBytesPerSector;
524
525 sector = header->attributesFile.extents[0].startBlock * sectorsPerBlock;
526 WriteAttributesFile(driveInfo, sector, defaults, NULL, nodeBuffer, &bytesUsed, &mapNodes);
527 if (mapNodes > 0) {
528 WriteMapNodes(driveInfo, (sector + bytesUsed/kBytesPerSector),
529 bytesUsed/btNodeSize, mapNodes, btNodeSize, nodeBuffer);
530 }
531 }
532
533 /*--- WRITE CATALOG B-TREE TO DISK: */
534
535 btNodeSize = defaults->catalogNodeSize;
536 sectorsPerNode = btNodeSize/kBytesPerSector;
537
538 sector = header->catalogFile.extents[0].startBlock * sectorsPerBlock;
539 WriteCatalogFile(driveInfo, sector, defaults, header, nodeBuffer, &bytesUsed, &mapNodes);
540
541 if (mapNodes > 0) {
542 WriteMapNodes(driveInfo, (sector + bytesUsed/kBytesPerSector),
543 bytesUsed/btNodeSize, mapNodes, btNodeSize, nodeBuffer);
544 }
545
546 /*--- JOURNALING SETUP */
547 if (defaults->journaledHFS) {
548 sector = header->journalInfoBlock * sectorsPerBlock;
549 if (NEWFS_HFS_DEBUG) {
550 /*
551 * For debug build, the journal may be located somewhere other
552 * than right after the journalInfoBlock.
553 */
554 if (MarkExtentUsed(driveInfo, header, header->journalInfoBlock, 1) == -1) {
555 errx(1, "Extent overlap for journalInfoBlock <%u, 1>", header->journalInfoBlock);
556 }
557
558 if (!defaults->journalDevice) {
559 UInt32 jStart = defaults->journalBlock ? defaults->journalBlock : (header->journalInfoBlock + 1);
560 UInt32 jCount = (UInt32)(defaults->journalSize / header->blockSize);
561 if (MarkExtentUsed(driveInfo, header, jStart, jCount) == -1) {
562 errx(1, "Extent overlap for journal <%u, %u>", jStart, jCount);
563 }
564 }
565 }
566 if (WriteJournalInfo(driveInfo, sector, defaults, header, nodeBuffer) != 0) {
567 err(EINVAL, "Failed to create the journal");
568 }
569 }
570
571 /*--- WRITE VOLUME HEADER TO DISK: */
572
573 /* write header last in case we fail along the way */
574
575 /* Writes both copies of the volume header */
576 WriteVH (driveInfo, header);
577 /* VH is now big-endian */
578
579 free(nodeBuffer);
580 free(header);
581
582 return (0);
583 }
584
585 /*
586 * WriteVH
587 *
588 * Writes the Volume Header (VH) to disk.
589 *
590 * The VH is byte-swapped if necessary to big endian. Since this
591 * is always the last operation, there's no point in unswapping it.
592 */
593 static void
594 WriteVH (const DriveInfo *driveInfo, HFSPlusVolumeHeader *hp)
595 {
596 SWAP_HFSPLUSVH (hp);
597
598 WriteBuffer(driveInfo, 2, kBytesPerSector, hp);
599 WriteBuffer(driveInfo, driveInfo->totalSectors - 2, kBytesPerSector, hp);
600 }
601
602
603 /*
604 * InitVH
605 *
606 * Initialize a Volume Header record.
607 */
608 static void
609 InitVH(hfsparams_t *defaults, UInt64 sectors, HFSPlusVolumeHeader *hp)
610 {
611 UInt32 blockSize;
612 UInt32 blockCount;
613 UInt32 blocksUsed;
614 UInt32 bitmapBlocks;
615 UInt16 burnedBlocksBeforeVH = 0;
616 UInt16 burnedBlocksAfterAltVH = 0;
617 UInt32 nextBlock;
618 UInt32 allocateBlock;
619 VolumeUUID newVolumeUUID;
620 VolumeUUID* finderInfoUUIDPtr;
621 UInt64 hotFileBandSize;
622 UInt64 volsize;
623
624 /*
625 * 2 MB is the minimum size for the new behavior with
626 * space after the attr b-tree, and hotfile stuff.
627 */
628 #define MINVOLSIZE_WITHSPACE 2097152
629
630 bzero(hp, kBytesPerSector);
631
632 blockSize = defaults->blockSize;
633 blockCount = sectors / (blockSize >> kLog2SectorSize);
634
635 /*
636 * HFSPlusVolumeHeader is located at sector 2, so we may need
637 * to invalidate blocks before HFSPlusVolumeHeader.
638 */
639 if ( blockSize == 512 ) {
640 burnedBlocksBeforeVH = 2; /* 2 before VH */
641 burnedBlocksAfterAltVH = 1; /* 1 after altVH */
642 } else if ( blockSize == 1024 ) {
643 burnedBlocksBeforeVH = 1;
644 }
645 nextBlock = burnedBlocksBeforeVH + 1; /* +1 for VH itself */
646 if (defaults->fsStartBlock) {
647 if (NEWFS_HFS_DEBUG)
648 printf ("Laying down metadata starting at allocation block=%u (totalBlocks=%u)\n", (unsigned int)defaults->fsStartBlock, (unsigned int)blockCount);
649 nextBlock += defaults->fsStartBlock; /* lay down file system after this allocation block */
650 }
651
652 bitmapBlocks = defaults->allocationClumpSize / blockSize;
653
654 /* note: add 2 for the Alternate VH, and VH */
655 blocksUsed = 2 + burnedBlocksBeforeVH + burnedBlocksAfterAltVH + bitmapBlocks;
656
657 if (defaults->flags & kMakeCaseSensitive) {
658 hp->signature = kHFSXSigWord;
659 hp->version = kHFSXVersion;
660 } else {
661 hp->signature = kHFSPlusSigWord;
662 hp->version = kHFSPlusVersion;
663 }
664 hp->attributes = kHFSVolumeUnmountedMask | kHFSUnusedNodeFixMask;
665 if (defaults->flags & kMakeContentProtect) {
666 hp->attributes |= kHFSContentProtectionMask;
667 }
668 hp->lastMountedVersion = kHFSPlusMountVersion;
669
670 /* NOTE: create date is in local time, not GMT! */
671 hp->createDate = UTCToLocal(defaults->createDate);
672 hp->modifyDate = defaults->createDate;
673 hp->backupDate = 0;
674 hp->checkedDate = defaults->createDate;
675
676 // hp->fileCount = 0;
677 // hp->folderCount = 0;
678
679 hp->blockSize = blockSize;
680 hp->totalBlocks = blockCount;
681 hp->freeBlocks = blockCount; /* will be adjusted at the end */
682
683 volsize = (UInt64) blockCount * (UInt64) blockSize;
684
685 hp->rsrcClumpSize = defaults->rsrcClumpSize;
686 hp->dataClumpSize = defaults->dataClumpSize;
687 hp->nextCatalogID = defaults->nextFreeFileID;
688 hp->encodingsBitmap = 1 | (1 << ENCODING_TO_BIT(defaults->encodingHint));
689
690 /* set up allocation bitmap file */
691 hp->allocationFile.clumpSize = defaults->allocationClumpSize;
692 hp->allocationFile.logicalSize = defaults->allocationClumpSize;
693 hp->allocationFile.totalBlocks = bitmapBlocks;
694
695 if (NEWFS_HFS_DEBUG && defaults->allocationStartBlock)
696 allocateBlock = defaults->allocationStartBlock;
697 else {
698 allocateBlock = nextBlock;
699 nextBlock += bitmapBlocks;
700 }
701
702 createExtents(&hp->allocationFile, kHFSAllocationFileID, allocateBlock, defaults->allocationExtsCount, 1);
703
704 // This works because the files are contiguous for now
705 if (NEWFS_HFS_DEBUG)
706 printf ("allocationFile: (%10u, %10u)\n", hp->allocationFile.extents[0].startBlock, hp->allocationFile.totalBlocks);
707
708 /* set up journal files */
709 if (defaults->journaledHFS) {
710 UInt32 journalBlock;
711 hp->fileCount = 2;
712 hp->attributes |= kHFSVolumeJournaledMask;
713 hp->nextCatalogID += 2;
714
715 /*
716 * Allocate 1 block for the journalInfoBlock. The
717 * journal file size is passed in hfsparams_t.
718 */
719 if (NEWFS_HFS_DEBUG && defaults->journalInfoBlock)
720 hp->journalInfoBlock = defaults->journalInfoBlock;
721 else
722 hp->journalInfoBlock = nextBlock++;
723 if (NEWFS_HFS_DEBUG && defaults->journalBlock)
724 journalBlock = defaults->journalBlock;
725 else {
726 journalBlock = hp->journalInfoBlock + 1;
727 nextBlock += ((defaults->journalSize+blockSize-1) / blockSize);
728 }
729
730 if (NEWFS_HFS_DEBUG) {
731 printf ("journalInfo : (%10u, %10u)\n", (u_int32_t)hp->journalInfoBlock, 1);
732 printf ("journal : (%10u, %10u)\n", (u_int32_t)journalBlock, (u_int32_t)((defaults->journalSize + (blockSize-1)) / blockSize));
733 }
734 /* XXX What if journal is on a different device? */
735 blocksUsed += 1 + ((defaults->journalSize+blockSize-1) / blockSize);
736 } else {
737 hp->journalInfoBlock = 0;
738 }
739
740 /* set up extents b-tree file */
741 hp->extentsFile.clumpSize = defaults->extentsClumpSize;
742 hp->extentsFile.logicalSize = defaults->extentsClumpSize;
743 hp->extentsFile.totalBlocks = defaults->extentsClumpSize / blockSize;
744 if (NEWFS_HFS_DEBUG && defaults->extentsStartBlock)
745 allocateBlock = defaults->extentsStartBlock;
746 else {
747 allocateBlock = nextBlock;
748 nextBlock += hp->extentsFile.totalBlocks;
749 }
750 createExtents(&hp->extentsFile, kHFSExtentsFileID, allocateBlock, defaults->extentsExtsCount, (defaults->journaledHFS && defaults->extentsNodeSize > hp->blockSize) ? defaults->extentsNodeSize / hp->blockSize : 1);
751
752 blocksUsed += hp->extentsFile.totalBlocks;
753
754 if (NEWFS_HFS_DEBUG)
755 printf ("extentsFile : (%10u, %10u)\n", hp->extentsFile.extents[0].startBlock, hp->extentsFile.totalBlocks);
756
757 /* set up attributes b-tree file */
758 if (defaults->attributesClumpSize) {
759 hp->attributesFile.clumpSize = defaults->attributesClumpSize;
760 hp->attributesFile.logicalSize = defaults->attributesClumpSize;
761 hp->attributesFile.totalBlocks = defaults->attributesClumpSize / blockSize;
762 if (NEWFS_HFS_DEBUG && defaults->attributesStartBlock)
763 allocateBlock = defaults->attributesStartBlock;
764 else {
765 allocateBlock = nextBlock;
766 nextBlock += hp->attributesFile.totalBlocks;
767 }
768 createExtents(&hp->attributesFile, kHFSAttributesFileID, allocateBlock, defaults->attributesExtsCount, (defaults->journaledHFS && defaults->attributesNodeSize > hp->blockSize) ? defaults->attributesNodeSize / hp->blockSize : 1);
769 blocksUsed += hp->attributesFile.totalBlocks;
770
771 if (NEWFS_HFS_DEBUG) {
772 printf ("attributesFile: (%10u, %10u)\n", hp->attributesFile.extents[0].startBlock, hp->attributesFile.totalBlocks);
773 }
774 /*
775 * Leave some room for the Attributes B-tree to grow, if the volsize >= 2MB
776 */
777 if (volsize >= MINVOLSIZE_WITHSPACE && defaults->attributesStartBlock == 0) {
778 nextBlock += 10 * (hp->attributesFile.clumpSize / blockSize);
779 }
780 }
781
782 /* set up catalog b-tree file */
783 hp->catalogFile.clumpSize = defaults->catalogClumpSize;
784 hp->catalogFile.logicalSize = defaults->catalogClumpSize;
785 hp->catalogFile.totalBlocks = defaults->catalogClumpSize / blockSize;
786 if (NEWFS_HFS_DEBUG && defaults->catalogStartBlock)
787 allocateBlock = defaults->catalogStartBlock;
788 else {
789 allocateBlock = nextBlock;
790 nextBlock += hp->catalogFile.totalBlocks;
791 }
792 createExtents(&hp->catalogFile, kHFSCatalogFileID, allocateBlock, defaults->catalogExtsCount, (defaults->journaledHFS && defaults->catalogNodeSize > hp->blockSize) ? defaults->catalogNodeSize / hp->blockSize : 1);
793 blocksUsed += hp->catalogFile.totalBlocks;
794
795 if (NEWFS_HFS_DEBUG)
796 printf ("catalogFile : (%10u, %10u)\n\n", hp->catalogFile.extents[0].startBlock, hp->catalogFile.totalBlocks);
797
798 if ((numOverflowExtents * sizeof(struct ExtentRecord)) >
799 (defaults->extentsNodeSize - sizeof(BTNodeDescriptor) - (sizeof(uint16_t) * numOverflowExtents))) {
800 errx(1, "Too many overflow extent records to fit into a single extent node");
801 }
802
803 /*
804 * Add some room for the catalog file to grow...
805 */
806 nextBlock += 10 * (hp->catalogFile.clumpSize / hp->blockSize);
807
808 /*
809 * Add some room for the hot file band. This uses the same 5MB per GB
810 * as the kernel. The kernel only uses hotfiles if the volume is larger
811 * than 10GBytes, so do the same here.
812 */
813 #define METADATAZONE_MINIMUM_VOLSIZE (10ULL * 1024ULL * 1024ULL * 1024ULL)
814 #define HOTBAND_MINIMUM_SIZE (10*1024*1024)
815 #define HOTBAND_MAXIMUM_SIZE (512*1024*1024)
816 if (volsize >= METADATAZONE_MINIMUM_VOLSIZE) {
817 hotFileBandSize = (UInt64) blockCount * blockSize / 1024 * 5;
818 if (hotFileBandSize > HOTBAND_MAXIMUM_SIZE)
819 hotFileBandSize = HOTBAND_MAXIMUM_SIZE;
820 else if (hotFileBandSize < HOTBAND_MINIMUM_SIZE)
821 hotFileBandSize = HOTBAND_MINIMUM_SIZE;
822 nextBlock += hotFileBandSize / blockSize;
823 }
824 if (NEWFS_HFS_DEBUG && defaults->nextAllocBlock)
825 hp->nextAllocation = defaults->nextAllocBlock;
826 else
827 hp->nextAllocation = nextBlock;
828
829 /* Adjust free blocks to reflect everything we have allocated. */
830 hp->freeBlocks -= blocksUsed;
831
832 /* Generate and write UUID for the HFS+ disk */
833 GenerateVolumeUUID(&newVolumeUUID);
834 finderInfoUUIDPtr = (VolumeUUID *)(&hp->finderInfo[24]);
835 finderInfoUUIDPtr->v.high = OSSwapHostToBigInt32(newVolumeUUID.v.high);
836 finderInfoUUIDPtr->v.low = OSSwapHostToBigInt32(newVolumeUUID.v.low);
837 }
838
839 /*
840 * AllocateExtent
841 *
842 * Mark the given extent as in-use in the given bitmap buffer.
843 */
844 static int AllocateExtent(UInt8 *buffer, UInt32 startBlock, UInt32 blockCount)
845 {
846 UInt8 *p;
847
848 /* Point to start of extent in bitmap buffer */
849 p = buffer + (startBlock / 8);
850
851 /*
852 * Important to remember: block 0 is (1 << 7);
853 * block 7 is (1 << 0).
854 */
855 /* Partial byte at start of extent */
856 if (startBlock & 7)
857 {
858 UInt8 mask = 0xff;
859 unsigned int lShift = 0;
860 unsigned int startBit = startBlock & 7;
861
862 /*
863 * Is startBlock + blockCount entirely in
864 * p[0]?
865 */
866 if (blockCount < (8 - startBit)) {
867 lShift = 8 - (startBit + blockCount);
868 }
869 mask = (0xff >> startBit) & (0xff << lShift);
870 if (NEWFS_HFS_DEBUG && (*p & mask)) {
871 fprintf(stderr, "%s(%d): expected 0, got %x\n", __FUNCTION__, __LINE__, *p & mask);
872 return -1;
873 }
874 *(p++) |= mask;
875 /*
876 * We have either set <lShift> or <startBlock & 7> bits.
877 */
878 blockCount -= 8 - (lShift + startBit);
879 // blockCount -= lShift ? blockCount : (8 - startBit);
880 // blockCount -= __builtin_popcount(mask);
881 }
882
883 /* Fill in whole bytes */
884 if (blockCount >= 8)
885 {
886 if (NEWFS_HFS_DEBUG) {
887 /*
888 * Put this in ifdef because it'll slow things down.
889 * For non-debug case, we shouldn't have to worry about
890 * an overlap, anyway.
891 */
892 size_t indx;
893 for (indx = 0; indx < blockCount / 8; indx++) {
894 if (p[indx] != 0) {
895 fprintf(stderr, "%s(%d): Expected 0 at %zu, got 0x%x\n", __FUNCTION__, __LINE__, indx, p[indx]);
896 return -1;
897 }
898 p[indx] = 0xff;
899 }
900 } else {
901 memset(p, 0xFF, blockCount / 8);
902 }
903 p += blockCount / 8;
904 blockCount &= 7;
905 }
906
907 /* Partial byte at end of extent */
908 if (blockCount)
909 {
910 UInt8 mask = 0xff << (8 - blockCount);
911 if (NEWFS_HFS_DEBUG && (*p & mask)) {
912 fprintf(stderr, "%s(%d): Expected 0, got %x\n", __FUNCTION__, __LINE__, *p & mask);
913 return -1;
914 }
915 *(p++) |= mask;
916 }
917 return 0;
918 }
919
920 /*
921 * Mark an extent as being used.
922 * This involves finding out where the allocations file is,
923 * where in the allocations file the extent starts, and how
924 * long it runs.
925 *
926 * One downside to this implementation is that this does
927 * more I/O than the old mechanism, a cost to the flexibility.
928 * May have to consider doing caching of some sort.
929 */
930
931 static int
932 MarkExtentUsed(const DriveInfo *driveInfo,
933 HFSPlusVolumeHeader *header,
934 UInt32 startBlock,
935 UInt32 blockCount)
936 {
937 size_t bufSize = driveInfo->physSectorSize;
938 uint8_t buf[bufSize];
939 uint32_t blocksLeft = blockCount;
940 uint32_t curBlock = startBlock;
941 static const int kBitsPerByte = 8;
942
943 /*
944 * We loop through physSectorSize blocks.
945 * This allows us to set as many bits as we need.
946 */
947 while (blocksLeft > 0) {
948 off_t secNum;
949 uint32_t numBlocks; // The number of blocks to mark as used in this pass.
950 uint32_t blockOffset; // This is the block number of the current range, which starts at curBlock
951
952 memset(buf, 0, sizeof(buf));
953 secNum = curBlock / (bufSize * kBitsPerByte);
954 blockOffset = curBlock % (bufSize * kBitsPerByte);
955 numBlocks = MIN((bufSize * kBitsPerByte) - blockOffset, blocksLeft);
956
957 /*
958 * Okay, now we've got the block number to read,
959 * the offset into the block, and the number of blocks
960 * to set.
961 *
962 * First we read in the buffer. To do that, we need to
963 * know where to read.
964 */
965 ssize_t nbytes;
966 ssize_t nwritten;
967 off_t offset;
968
969 /*
970 * XXX
971 * This needs to be changed if/when we support non-contiguous multiple
972 * extents. At that point, it'll probably have to be a function to search
973 * for the requested offset. (How many times must MapFileC be written?)
974 * For now, though, the offset is the physical sector offset from the
975 * start of the allocations file.
976 */
977 offset = (header->allocationFile.extents[0].startBlock * header->blockSize) +
978 (secNum * bufSize);
979
980 nbytes = pread(driveInfo->fd, buf, bufSize, offset);
981
982 if (nbytes < (ssize_t)bufSize) {
983 if (nbytes == -1)
984 err(1, "%s::pread(%d, %p, %zu, %lld)", __FUNCTION__, driveInfo->fd, buf, bufSize, offset);
985 return -1;
986 }
987
988 if (AllocateExtent(buf, blockOffset, numBlocks) == -1) {
989 warnx("In-use allocation block in <%u, %u>", blockOffset, numBlocks);
990 return -1;
991 }
992 nwritten = pwrite(driveInfo->fd, buf, bufSize, offset);
993 /*
994 * Normally I'd check for nwritten to be less than bufSize, but since bufSize is
995 * the physical sector size, we shouldn't be able to get less. So that most likely
996 * means a return value of 0 or -1, neither of which I could do anything about.
997 */
998 if (nwritten != (ssize_t)bufSize)
999 return -1;
1000
1001 // And go get the next set, if needed
1002 blocksLeft -= numBlocks;
1003 curBlock += numBlocks;
1004 }
1005
1006 return 0;
1007 }
1008 /*
1009 * WriteExtentsFile
1010 *
1011 * Initializes and writes out the extents b-tree file.
1012 *
1013 * Byte swapping is performed in place. The buffer should not be
1014 * accessed through direct casting once it leaves this function.
1015 */
1016 static void
1017 WriteExtentsFile(const DriveInfo *driveInfo, UInt64 startingSector,
1018 const hfsparams_t *dp, HFSExtentDescriptor *bbextp __unused , void *buffer,
1019 UInt32 *bytesUsed, UInt32 *mapNodes)
1020 {
1021 BTNodeDescriptor *ndp;
1022 BTHeaderRec *bthp;
1023 UInt8 *bmp;
1024 UInt32 nodeBitsInHeader;
1025 UInt32 fileSize;
1026 UInt32 nodeSize;
1027 UInt32 temp;
1028 SInt16 offset;
1029
1030 *mapNodes = 0;
1031 fileSize = dp->extentsClumpSize;
1032 nodeSize = dp->extentsNodeSize;
1033
1034 bzero(buffer, nodeSize);
1035
1036
1037 /* FILL IN THE NODE DESCRIPTOR: */
1038 ndp = (BTNodeDescriptor *)buffer;
1039 ndp->kind = kBTHeaderNode;
1040 ndp->numRecords = SWAP_BE16 (3);
1041 offset = sizeof(BTNodeDescriptor);
1042
1043 SETOFFSET(buffer, nodeSize, offset, 1);
1044
1045
1046 /* FILL IN THE HEADER RECORD: */
1047 bthp = (BTHeaderRec *)((UInt8 *)buffer + offset);
1048 if (numOverflowExtents) {
1049 bthp->treeDepth = SWAP_BE16(1);
1050 bthp->rootNode = SWAP_BE32(1);
1051 bthp->firstLeafNode = SWAP_BE32(1);
1052 bthp->lastLeafNode = SWAP_BE32(1);
1053 bthp->leafRecords = SWAP_BE32(numOverflowExtents);
1054 } else {
1055 bthp->treeDepth = 0;
1056 bthp->rootNode = 0;
1057 bthp->firstLeafNode = 0;
1058 bthp->lastLeafNode = 0;
1059 bthp->leafRecords = 0;
1060 }
1061
1062 bthp->nodeSize = SWAP_BE16 (nodeSize);
1063 bthp->totalNodes = SWAP_BE32 (fileSize / nodeSize);
1064 bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->totalNodes) - (numOverflowExtents ? 2 : 1)); /* header */
1065 bthp->clumpSize = SWAP_BE32 (fileSize);
1066
1067 bthp->attributes |= SWAP_BE32 (kBTBigKeysMask);
1068 bthp->maxKeyLength = SWAP_BE16 (kHFSPlusExtentKeyMaximumLength);
1069 offset += sizeof(BTHeaderRec);
1070
1071 SETOFFSET(buffer, nodeSize, offset, 2);
1072
1073 offset += kBTreeHeaderUserBytes;
1074
1075 SETOFFSET(buffer, nodeSize, offset, 3);
1076
1077
1078 /* FIGURE OUT HOW MANY MAP NODES (IF ANY): */
1079 nodeBitsInHeader = 8 * (nodeSize
1080 - sizeof(BTNodeDescriptor)
1081 - sizeof(BTHeaderRec)
1082 - kBTreeHeaderUserBytes
1083 - (4 * sizeof(SInt16)) );
1084
1085 if (SWAP_BE32 (bthp->totalNodes) > nodeBitsInHeader) {
1086 UInt32 nodeBitsInMapNode;
1087
1088 ndp->fLink = SWAP_BE32 (SWAP_BE32 (bthp->lastLeafNode) + 1);
1089 nodeBitsInMapNode = 8 * (nodeSize
1090 - sizeof(BTNodeDescriptor)
1091 - (2 * sizeof(SInt16))
1092 - 2 );
1093 *mapNodes = (SWAP_BE32 (bthp->totalNodes) - nodeBitsInHeader +
1094 (nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
1095 bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->freeNodes) - *mapNodes);
1096 }
1097
1098
1099 /*
1100 * FILL IN THE MAP RECORD, MARKING NODES THAT ARE IN USE.
1101 * Note - worst case (32MB alloc blk) will have only 18 nodes in use.
1102 */
1103 bmp = ((UInt8 *)buffer + offset);
1104 temp = SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes);
1105
1106 /* Working a byte at a time is endian safe */
1107 while (temp >= 8) { *bmp = 0xFF; temp -= 8; bmp++; }
1108 *bmp = ~(0xFF >> temp);
1109 offset += nodeBitsInHeader/8;
1110
1111 SETOFFSET(buffer, nodeSize, offset, 4);
1112
1113 if (NEWFS_HFS_DEBUG && numOverflowExtents) {
1114 void *node2 = (uint8_t*)buffer + nodeSize;
1115 size_t i;
1116 int (^keyCompare)(const void *l, const void *r) = ^(const void *l, const void *r) {
1117 const struct ExtentRecord *left = (const struct ExtentRecord*)l;
1118 const struct ExtentRecord *right = (const struct ExtentRecord*)r;
1119 if (SWAP_BE32(left->key.fileID) != SWAP_BE32(right->key.fileID)) {
1120 return (SWAP_BE32(left->key.fileID) > SWAP_BE32(right->key.fileID)) ? 1 : -1;
1121 }
1122 // forkType will always be 0 for us
1123 if (SWAP_BE32(left->key.startBlock) != SWAP_BE32(right->key.startBlock)) {
1124 return (SWAP_BE32(left->key.startBlock) > SWAP_BE32(right->key.startBlock)) ? 1 : -1;
1125 }
1126 return 0;
1127 };
1128
1129 if (numOverflowExtents > 1) {
1130 qsort_b(overflowExtents, numOverflowExtents, sizeof(*overflowExtents), keyCompare);
1131 }
1132 bzero(node2, nodeSize);
1133 ndp = (BTNodeDescriptor*)node2;
1134 ndp->kind = kBTLeafNode;
1135 ndp->numRecords = SWAP_BE16(numOverflowExtents);
1136 ndp->height = 1;
1137
1138 offset = sizeof(BTNodeDescriptor);
1139 for (i = 0; i < numOverflowExtents; i++) {
1140 SETOFFSET(node2, nodeSize, offset, 1 + i);
1141 memcpy(node2 + offset, &overflowExtents[i], sizeof(*overflowExtents));
1142 offset += sizeof(*overflowExtents);
1143 }
1144 SETOFFSET(node2, nodeSize, offset, numOverflowExtents + 1);
1145 }
1146
1147 *bytesUsed = (SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes) - *mapNodes) * nodeSize;
1148
1149 WriteBuffer(driveInfo, startingSector, *bytesUsed, buffer);
1150
1151 }
1152
1153 /*
1154 * WriteAttributesFile
1155 *
1156 * Initializes and writes out the attributes b-tree file.
1157 *
1158 * Byte swapping is performed in place. The buffer should not be
1159 * accessed through direct casting once it leaves this function.
1160 */
1161 static void
1162 WriteAttributesFile(const DriveInfo *driveInfo, UInt64 startingSector,
1163 const hfsparams_t *dp, HFSExtentDescriptor *bbextp __unused, void *buffer,
1164 UInt32 *bytesUsed, UInt32 *mapNodes)
1165 {
1166 BTNodeDescriptor *ndp;
1167 BTHeaderRec *bthp;
1168 UInt8 *bmp;
1169 UInt32 nodeBitsInHeader;
1170 UInt32 fileSize;
1171 UInt32 nodeSize;
1172 UInt32 temp;
1173 SInt16 offset;
1174 int set_cp_level = 0;
1175
1176 *mapNodes = 0;
1177 fileSize = dp->attributesClumpSize;
1178 nodeSize = dp->attributesNodeSize;
1179
1180 #ifdef DEBUG_BUILD
1181 /*
1182 * If user specified content protection and a protection level,
1183 * then verify the protection level is sane.
1184 */
1185 if ((dp->flags & kMakeContentProtect) && (dp->protectlevel != 0)) {
1186 if ((dp->protectlevel >= 2 ) && (dp->protectlevel <= 4)) {
1187 set_cp_level = 1;
1188 }
1189 }
1190 #endif
1191
1192
1193 bzero(buffer, nodeSize);
1194
1195
1196 /* FILL IN THE NODE DESCRIPTOR: */
1197 ndp = (BTNodeDescriptor *)buffer;
1198 ndp->kind = kBTHeaderNode;
1199 ndp->numRecords = SWAP_BE16 (3);
1200 offset = sizeof(BTNodeDescriptor);
1201
1202 SETOFFSET(buffer, nodeSize, offset, 1);
1203
1204
1205 /* FILL IN THE HEADER RECORD: */
1206 bthp = (BTHeaderRec *)((UInt8 *)buffer + offset);
1207 if (set_cp_level) {
1208 bthp->treeDepth = SWAP_BE16(1);
1209 bthp->rootNode = SWAP_BE32(1);
1210 bthp->firstLeafNode = SWAP_BE32(1);
1211 bthp->lastLeafNode = SWAP_BE32(1);
1212 bthp->leafRecords = SWAP_BE32(1);
1213 }
1214 else {
1215 bthp->treeDepth = 0;
1216 bthp->rootNode = 0;
1217 bthp->firstLeafNode = 0;
1218 bthp->lastLeafNode = 0;
1219 bthp->leafRecords = 0;
1220 }
1221
1222 bthp->nodeSize = SWAP_BE16 (nodeSize);
1223 bthp->totalNodes = SWAP_BE32 (fileSize / nodeSize);
1224 if (set_cp_level) {
1225 /* Add 1 node for the first record */
1226 bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->totalNodes) - 2);
1227 }
1228 else {
1229 /* Take the header into account */
1230 bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->totalNodes) - 1);
1231 }
1232 bthp->clumpSize = SWAP_BE32 (fileSize);
1233
1234 bthp->attributes |= SWAP_BE32 (kBTBigKeysMask | kBTVariableIndexKeysMask);
1235 bthp->maxKeyLength = SWAP_BE16 (kHFSPlusAttrKeyMaximumLength);
1236
1237 offset += sizeof(BTHeaderRec);
1238
1239 SETOFFSET(buffer, nodeSize, offset, 2);
1240
1241 offset += kBTreeHeaderUserBytes;
1242
1243 SETOFFSET(buffer, nodeSize, offset, 3);
1244
1245
1246 /* FIGURE OUT HOW MANY MAP NODES (IF ANY): */
1247 nodeBitsInHeader = 8 * (nodeSize
1248 - sizeof(BTNodeDescriptor)
1249 - sizeof(BTHeaderRec)
1250 - kBTreeHeaderUserBytes
1251 - (4 * sizeof(SInt16)) );
1252 if (SWAP_BE32 (bthp->totalNodes) > nodeBitsInHeader) {
1253 UInt32 nodeBitsInMapNode;
1254
1255 ndp->fLink = SWAP_BE32 (SWAP_BE32 (bthp->lastLeafNode) + 1);
1256 nodeBitsInMapNode = 8 * (nodeSize
1257 - sizeof(BTNodeDescriptor)
1258 - (2 * sizeof(SInt16))
1259 - 2 );
1260 *mapNodes = (SWAP_BE32 (bthp->totalNodes) - nodeBitsInHeader +
1261 (nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
1262 bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->freeNodes) - *mapNodes);
1263 }
1264
1265
1266 /*
1267 * FILL IN THE MAP RECORD, MARKING NODES THAT ARE IN USE.
1268 * Note - worst case (32MB alloc blk) will have only 18 nodes in use.
1269 */
1270 bmp = ((UInt8 *)buffer + offset);
1271 temp = SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes);
1272
1273 /* Working a byte at a time is endian safe */
1274 while (temp >= 8) { *bmp = 0xFF; temp -= 8; bmp++; }
1275 *bmp = ~(0xFF >> temp);
1276 offset += nodeBitsInHeader/8;
1277
1278 SETOFFSET(buffer, nodeSize, offset, 4);
1279
1280 #ifdef DEBUG_BUILD
1281 if (set_cp_level) {
1282 /* Stuff in the EA on the root folder */
1283 void *node2 = (uint8_t*)buffer + nodeSize;
1284
1285 struct cp_root_xattr ea;
1286
1287 uint8_t canonicalName[256];
1288 CFStringRef cfstr;
1289
1290 HFSPlusAttrData *attrData;
1291 HFSPlusAttrKey *attrKey;
1292 bzero(node2, nodeSize);
1293 ndp = (BTNodeDescriptor*)node2;
1294
1295 ndp->kind = kBTLeafNode;
1296 ndp->numRecords = SWAP_BE16(1);
1297 ndp->height = 1;
1298
1299 offset = sizeof(BTNodeDescriptor);
1300 SETOFFSET(node2, nodeSize, offset, 1);
1301
1302 attrKey = (HFSPlusAttrKey*)((uint8_t*)node2 + offset);
1303 attrKey->fileID = SWAP_BE32(1);
1304 attrKey->startBlock = 0;
1305 attrKey->keyLength = SWAP_BE16(sizeof(*attrKey) - sizeof(attrKey->keyLength));
1306
1307 cfstr = CFStringCreateWithCString(kCFAllocatorDefault, "com.apple.system.cprotect", kCFStringEncodingUTF8);
1308 if (_CFStringGetFileSystemRepresentation(cfstr, canonicalName, sizeof(canonicalName)) &&
1309 ConvertUTF8toUnicode(canonicalName,
1310 sizeof(attrKey->attrName),
1311 attrKey->attrName, &attrKey->attrNameLen) == 0) {
1312 attrKey->attrNameLen = SWAP_BE16(attrKey->attrNameLen);
1313 offset += sizeof(*attrKey);
1314
1315 /* If the offset is odd, move up to the next even value */
1316 if (offset & 1) {
1317 offset++;
1318 }
1319
1320 attrData = (HFSPlusAttrData*)((uint8_t*)node2 + offset);
1321 bzero(&ea, sizeof(ea));
1322 ea.vers = OSSwapHostToLittleInt16(dp->protectlevel); //(leave in LittleEndian)
1323 attrData->recordType = SWAP_BE32(kHFSPlusAttrInlineData);
1324 attrData->attrSize = SWAP_BE32(sizeof(ea));
1325 memcpy(attrData->attrData, &ea, sizeof(ea));
1326 offset += sizeof (HFSPlusAttrData) + sizeof(ea) - sizeof(attrData->attrData);
1327 }
1328 SETOFFSET (node2, nodeSize, offset, 2);
1329 CFRelease(cfstr);
1330 }
1331 #endif
1332
1333 *bytesUsed = (SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes) - *mapNodes) * nodeSize;
1334 WriteBuffer(driveInfo, startingSector, *bytesUsed, buffer);
1335 }
1336
1337 #if !TARGET_OS_EMBEDDED
1338 static int
1339 get_dev_uuid(const char *disk_name, char *dev_uuid_str, int dev_uuid_len)
1340 {
1341 io_service_t service;
1342 CFStringRef uuid_str;
1343 int ret = EINVAL;
1344
1345 if (strncmp(disk_name, _PATH_DEV, strlen(_PATH_DEV)) == 0) {
1346 disk_name += strlen(_PATH_DEV);
1347 }
1348
1349 dev_uuid_str[0] = '\0';
1350
1351 service = IOServiceGetMatchingService(kIOMasterPortDefault, IOBSDNameMatching(kIOMasterPortDefault, 0, disk_name));
1352 if (service != IO_OBJECT_NULL) {
1353 uuid_str = IORegistryEntryCreateCFProperty(service, CFSTR(kIOMediaUUIDKey), kCFAllocatorDefault, 0);
1354 if (uuid_str) {
1355 if (CFStringGetFileSystemRepresentation(uuid_str, dev_uuid_str, dev_uuid_len) != 0) {
1356 ret = 0;
1357 }
1358 CFRelease(uuid_str);
1359 }
1360 IOObjectRelease(service);
1361 }
1362
1363 return ret;
1364 }
1365
1366 static int
1367 clear_journal_dev(const char *dev_name)
1368 {
1369 int fd;
1370
1371 fd = open(dev_name, O_RDWR);
1372 if (fd < 0) {
1373 printf("Failed to open the journal device %s (%s)\n", dev_name, strerror(errno));
1374 return -1;
1375 }
1376
1377 dowipefs(fd);
1378
1379 close(fd);
1380 return 0;
1381 }
1382 #endif /* !TARGET_OS_EMBEDDED */
1383
1384
1385 static int
1386 WriteJournalInfo(const DriveInfo *driveInfo, UInt64 startingSector,
1387 const hfsparams_t *dp, HFSPlusVolumeHeader *header,
1388 void *buffer)
1389 {
1390 JournalInfoBlock *jibp = buffer;
1391 UInt32 journalBlock;
1392
1393 memset(buffer, 0xdb, driveInfo->physSectorSize);
1394 memset(jibp, 0, sizeof(JournalInfoBlock));
1395
1396 #if !TARGET_OS_EMBEDDED
1397 if (dp->journalDevice) {
1398 char uuid_str[64];
1399
1400 if (get_dev_uuid(dp->journalDevice, uuid_str, sizeof(uuid_str)) == 0) {
1401 strlcpy((char *)&jibp->reserved[0], uuid_str, sizeof(jibp->reserved));
1402
1403 // we also need to blast out some zeros to the journal device
1404 // in case it had a file system on it previously. that way
1405 // it's "initialized" in the sense that the previous contents
1406 // won't get mounted accidently. if this fails we'll bail out.
1407 if (clear_journal_dev(dp->journalDevice) != 0) {
1408 return -1;
1409 }
1410 } else {
1411 printf("FAILED to get the device uuid for device %s\n", dp->journalDevice);
1412 strlcpy((char *)&jibp->reserved[0], "NO-DEV-UUID", sizeof(jibp->reserved));
1413 return -1;
1414 }
1415 } else {
1416 #endif
1417 jibp->flags = kJIJournalInFSMask;
1418 #if !TARGET_OS_EMBEDDED
1419 }
1420 #endif
1421 jibp->flags |= kJIJournalNeedInitMask;
1422 if (NEWFS_HFS_DEBUG && dp->journalBlock)
1423 journalBlock = dp->journalBlock;
1424 else
1425 journalBlock = header->journalInfoBlock + 1;
1426 jibp->offset = ((UInt64) journalBlock) * header->blockSize;
1427 jibp->size = dp->journalSize;
1428
1429 jibp->flags = SWAP_BE32(jibp->flags);
1430 jibp->offset = SWAP_BE64(jibp->offset);
1431 jibp->size = SWAP_BE64(jibp->size);
1432
1433 WriteBuffer(driveInfo, startingSector, driveInfo->physSectorSize, buffer);
1434
1435 jibp->flags = SWAP_BE32(jibp->flags);
1436 jibp->offset = SWAP_BE64(jibp->offset);
1437 jibp->size = SWAP_BE64(jibp->size);
1438
1439 return 0;
1440 }
1441
1442
1443 /*
1444 * WriteCatalogFile
1445 *
1446 * This routine initializes a Catalog B-Tree.
1447 *
1448 * Note: Since large volumes can have bigger b-trees they
1449 * might need to have map nodes setup.
1450 */
1451 static void
1452 WriteCatalogFile(const DriveInfo *driveInfo, UInt64 startingSector,
1453 const hfsparams_t *dp, HFSPlusVolumeHeader *header, void *buffer,
1454 UInt32 *bytesUsed, UInt32 *mapNodes)
1455 {
1456 BTNodeDescriptor *ndp;
1457 BTHeaderRec *bthp;
1458 UInt8 *bmp;
1459 UInt32 nodeBitsInHeader;
1460 UInt32 fileSize;
1461 UInt32 nodeSize;
1462 UInt32 temp;
1463 SInt16 offset;
1464
1465 *mapNodes = 0;
1466 fileSize = dp->catalogClumpSize;
1467 nodeSize = dp->catalogNodeSize;
1468
1469 bzero(buffer, nodeSize);
1470
1471
1472 /* FILL IN THE NODE DESCRIPTOR: */
1473 ndp = (BTNodeDescriptor *)buffer;
1474 ndp->kind = kBTHeaderNode;
1475 ndp->numRecords = SWAP_BE16 (3);
1476 offset = sizeof(BTNodeDescriptor);
1477
1478 SETOFFSET(buffer, nodeSize, offset, 1);
1479
1480
1481 /* FILL IN THE HEADER RECORD: */
1482 bthp = (BTHeaderRec *)((UInt8 *)buffer + offset);
1483 bthp->treeDepth = SWAP_BE16 (1);
1484 bthp->rootNode = SWAP_BE32 (1);
1485 bthp->firstLeafNode = SWAP_BE32 (1);
1486 bthp->lastLeafNode = SWAP_BE32 (1);
1487 bthp->leafRecords = SWAP_BE32 (dp->journaledHFS ? 6 : 2);
1488 bthp->nodeSize = SWAP_BE16 (nodeSize);
1489 bthp->totalNodes = SWAP_BE32 (fileSize / nodeSize);
1490 bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->totalNodes) - 2); /* header and root */
1491 bthp->clumpSize = SWAP_BE32 (fileSize);
1492
1493
1494 bthp->attributes |= SWAP_BE32 (kBTVariableIndexKeysMask + kBTBigKeysMask);
1495 bthp->maxKeyLength = SWAP_BE16 (kHFSPlusCatalogKeyMaximumLength);
1496 if (dp->flags & kMakeCaseSensitive)
1497 bthp->keyCompareType = kHFSBinaryCompare;
1498 else
1499 bthp->keyCompareType = kHFSCaseFolding;
1500
1501 offset += sizeof(BTHeaderRec);
1502
1503 SETOFFSET(buffer, nodeSize, offset, 2);
1504
1505 offset += kBTreeHeaderUserBytes;
1506
1507 SETOFFSET(buffer, nodeSize, offset, 3);
1508
1509 /* FIGURE OUT HOW MANY MAP NODES (IF ANY): */
1510 nodeBitsInHeader = 8 * (nodeSize
1511 - sizeof(BTNodeDescriptor)
1512 - sizeof(BTHeaderRec)
1513 - kBTreeHeaderUserBytes
1514 - (4 * sizeof(SInt16)) );
1515
1516 if (SWAP_BE32 (bthp->totalNodes) > nodeBitsInHeader) {
1517 UInt32 nodeBitsInMapNode;
1518
1519 ndp->fLink = SWAP_BE32 (SWAP_BE32 (bthp->lastLeafNode) + 1);
1520 nodeBitsInMapNode = 8 * (nodeSize
1521 - sizeof(BTNodeDescriptor)
1522 - (2 * sizeof(SInt16))
1523 - 2 );
1524 *mapNodes = (SWAP_BE32 (bthp->totalNodes) - nodeBitsInHeader +
1525 (nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
1526 bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->freeNodes) - *mapNodes);
1527 }
1528
1529 /*
1530 * FILL IN THE MAP RECORD, MARKING NODES THAT ARE IN USE.
1531 * Note - worst case (32MB alloc blk) will have only 18 nodes in use.
1532 */
1533 bmp = ((UInt8 *)buffer + offset);
1534 temp = SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes);
1535
1536 /* Working a byte at a time is endian safe */
1537 while (temp >= 8) { *bmp = 0xFF; temp -= 8; bmp++; }
1538 *bmp = ~(0xFF >> temp);
1539 offset += nodeBitsInHeader/8;
1540
1541 SETOFFSET(buffer, nodeSize, offset, 4);
1542
1543 InitCatalogRoot_HFSPlus(dp, header, buffer + nodeSize);
1544
1545 *bytesUsed = (SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes) - *mapNodes) * nodeSize;
1546
1547 WriteBuffer(driveInfo, startingSector, *bytesUsed, buffer);
1548 }
1549
1550
1551 static void
1552 InitCatalogRoot_HFSPlus(const hfsparams_t *dp, const HFSPlusVolumeHeader *header, void * buffer)
1553 {
1554 BTNodeDescriptor *ndp;
1555 HFSPlusCatalogKey *ckp;
1556 HFSPlusCatalogKey *tkp;
1557 HFSPlusCatalogFolder *cdp;
1558 HFSPlusCatalogFile *cfp;
1559 HFSPlusCatalogThread *ctp;
1560 UInt16 nodeSize;
1561 SInt16 offset;
1562 size_t unicodeBytes;
1563 UInt8 canonicalName[256];
1564 CFStringRef cfstr;
1565 Boolean cfOK;
1566 int index = 0;
1567
1568 nodeSize = dp->catalogNodeSize;
1569 bzero(buffer, nodeSize);
1570
1571 /*
1572 * All nodes have a node descriptor...
1573 */
1574 ndp = (BTNodeDescriptor *)buffer;
1575 ndp->kind = kBTLeafNode;
1576 ndp->height = 1;
1577 ndp->numRecords = SWAP_BE16 (dp->journaledHFS ? 6 : 2);
1578 offset = sizeof(BTNodeDescriptor);
1579 SETOFFSET(buffer, nodeSize, offset, ++index);
1580
1581 /*
1582 * First record is always the root directory...
1583 */
1584 ckp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1585
1586 /* Use CFString functions to get a HFSPlus Canonical name */
1587 cfstr = CFStringCreateWithCString(kCFAllocatorDefault, (char *)dp->volumeName, kCFStringEncodingUTF8);
1588 cfOK = _CFStringGetFileSystemRepresentation(cfstr, canonicalName, sizeof(canonicalName));
1589
1590 if (!cfOK || ConvertUTF8toUnicode(canonicalName, sizeof(ckp->nodeName.unicode),
1591 ckp->nodeName.unicode, &ckp->nodeName.length)) {
1592
1593 /* On conversion errors "untitled" is used as a fallback. */
1594 (void) ConvertUTF8toUnicode((UInt8 *)kDefaultVolumeNameStr,
1595 sizeof(ckp->nodeName.unicode),
1596 ckp->nodeName.unicode,
1597 &ckp->nodeName.length);
1598 warnx("invalid HFS+ name: \"%s\", using \"%s\" instead",
1599 dp->volumeName, kDefaultVolumeNameStr);
1600 }
1601 CFRelease(cfstr);
1602 ckp->nodeName.length = SWAP_BE16 (ckp->nodeName.length);
1603
1604 unicodeBytes = sizeof(UniChar) * SWAP_BE16 (ckp->nodeName.length);
1605
1606 ckp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength + unicodeBytes);
1607 ckp->parentID = SWAP_BE32 (kHFSRootParentID);
1608 offset += SWAP_BE16 (ckp->keyLength) + 2;
1609
1610 cdp = (HFSPlusCatalogFolder *)((UInt8 *)buffer + offset);
1611 cdp->recordType = SWAP_BE16 (kHFSPlusFolderRecord);
1612 /* folder count is only supported on HFSX volumes */
1613 if (dp->flags & kMakeCaseSensitive) {
1614 cdp->flags = SWAP_BE16 (kHFSHasFolderCountMask);
1615 }
1616 cdp->valence = SWAP_BE32 (dp->journaledHFS ? 2 : 0);
1617 cdp->folderID = SWAP_BE32 (kHFSRootFolderID);
1618 cdp->createDate = SWAP_BE32 (dp->createDate);
1619 cdp->contentModDate = SWAP_BE32 (dp->createDate);
1620 cdp->textEncoding = SWAP_BE32 (dp->encodingHint);
1621 if (dp->flags & kUseAccessPerms) {
1622 cdp->bsdInfo.ownerID = SWAP_BE32 (dp->owner);
1623 cdp->bsdInfo.groupID = SWAP_BE32 (dp->group);
1624 cdp->bsdInfo.fileMode = SWAP_BE16 (dp->mask | S_IFDIR);
1625 }
1626 offset += sizeof(HFSPlusCatalogFolder);
1627 SETOFFSET(buffer, nodeSize, offset, ++index);
1628
1629 /*
1630 * Second record is always the root directory thread...
1631 */
1632 tkp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1633 tkp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength);
1634 tkp->parentID = SWAP_BE32 (kHFSRootFolderID);
1635 // tkp->nodeName.length = 0;
1636
1637 offset += SWAP_BE16 (tkp->keyLength) + 2;
1638
1639 ctp = (HFSPlusCatalogThread *)((UInt8 *)buffer + offset);
1640 ctp->recordType = SWAP_BE16 (kHFSPlusFolderThreadRecord);
1641 ctp->parentID = SWAP_BE32 (kHFSRootParentID);
1642 bcopy(&ckp->nodeName, &ctp->nodeName, sizeof(UInt16) + unicodeBytes);
1643 offset += (sizeof(HFSPlusCatalogThread)
1644 - (sizeof(ctp->nodeName.unicode) - unicodeBytes) );
1645
1646 SETOFFSET(buffer, nodeSize, offset, ++index);
1647
1648 /*
1649 * Add records for ".journal" and ".journal_info_block" files:
1650 */
1651 if (dp->journaledHFS) {
1652 struct HFSUniStr255 *nodename1, *nodename2;
1653 size_t uBytes1, uBytes2;
1654 UInt32 journalBlock;
1655
1656 /* File record #1 */
1657 ckp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1658 (void) ConvertUTF8toUnicode((UInt8 *)HFS_JOURNAL_FILE, sizeof(ckp->nodeName.unicode),
1659 ckp->nodeName.unicode, &ckp->nodeName.length);
1660 ckp->nodeName.length = SWAP_BE16 (ckp->nodeName.length);
1661 uBytes1 = sizeof(UniChar) * SWAP_BE16 (ckp->nodeName.length);
1662 ckp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength + uBytes1);
1663 ckp->parentID = SWAP_BE32 (kHFSRootFolderID);
1664 offset += SWAP_BE16 (ckp->keyLength) + 2;
1665
1666 cfp = (HFSPlusCatalogFile *)((UInt8 *)buffer + offset);
1667 cfp->recordType = SWAP_BE16 (kHFSPlusFileRecord);
1668 cfp->flags = SWAP_BE16 (kHFSThreadExistsMask);
1669 cfp->fileID = SWAP_BE32 (dp->nextFreeFileID);
1670 cfp->createDate = SWAP_BE32 (dp->createDate + 1);
1671 cfp->contentModDate = SWAP_BE32 (dp->createDate + 1);
1672 cfp->textEncoding = 0;
1673
1674 cfp->bsdInfo.fileMode = SWAP_BE16 (S_IFREG);
1675 cfp->bsdInfo.ownerFlags = (uint8_t) SWAP_BE16 (((uint16_t)UF_NODUMP));
1676 cfp->bsdInfo.special.linkCount = SWAP_BE32(1);
1677 cfp->userInfo.fdType = SWAP_BE32 (kJournalFileType);
1678 cfp->userInfo.fdCreator = SWAP_BE32 (kHFSPlusCreator);
1679 cfp->userInfo.fdFlags = SWAP_BE16 (kIsInvisible + kNameLocked);
1680 cfp->dataFork.logicalSize = SWAP_BE64 (dp->journalSize);
1681 cfp->dataFork.totalBlocks = SWAP_BE32 ((dp->journalSize+dp->blockSize-1) / dp->blockSize);
1682
1683 if (NEWFS_HFS_DEBUG && dp->journalBlock)
1684 journalBlock = dp->journalBlock;
1685 else
1686 journalBlock = header->journalInfoBlock + 1;
1687 cfp->dataFork.extents[0].startBlock = SWAP_BE32 (journalBlock);
1688 cfp->dataFork.extents[0].blockCount = cfp->dataFork.totalBlocks;
1689
1690 offset += sizeof(HFSPlusCatalogFile);
1691 SETOFFSET(buffer, nodeSize, offset, ++index);
1692 nodename1 = &ckp->nodeName;
1693
1694 /* File record #2 */
1695 ckp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1696 (void) ConvertUTF8toUnicode((UInt8 *)HFS_JOURNAL_INFO, sizeof(ckp->nodeName.unicode),
1697 ckp->nodeName.unicode, &ckp->nodeName.length);
1698 ckp->nodeName.length = SWAP_BE16 (ckp->nodeName.length);
1699 uBytes2 = sizeof(UniChar) * SWAP_BE16 (ckp->nodeName.length);
1700 ckp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength + uBytes2);
1701 ckp->parentID = SWAP_BE32 (kHFSRootFolderID);
1702 offset += SWAP_BE16 (ckp->keyLength) + 2;
1703
1704 cfp = (HFSPlusCatalogFile *)((UInt8 *)buffer + offset);
1705 cfp->recordType = SWAP_BE16 (kHFSPlusFileRecord);
1706 cfp->flags = SWAP_BE16 (kHFSThreadExistsMask);
1707 cfp->fileID = SWAP_BE32 (dp->nextFreeFileID + 1);
1708 cfp->createDate = SWAP_BE32 (dp->createDate);
1709 cfp->contentModDate = SWAP_BE32 (dp->createDate);
1710 cfp->textEncoding = 0;
1711
1712 cfp->bsdInfo.fileMode = SWAP_BE16 (S_IFREG);
1713 cfp->bsdInfo.ownerFlags = (uint8_t) SWAP_BE16 (((uint16_t)UF_NODUMP));
1714 cfp->bsdInfo.special.linkCount = SWAP_BE32(1);
1715 cfp->userInfo.fdType = SWAP_BE32 (kJournalFileType);
1716 cfp->userInfo.fdCreator = SWAP_BE32 (kHFSPlusCreator);
1717 cfp->userInfo.fdFlags = SWAP_BE16 (kIsInvisible + kNameLocked);
1718 cfp->dataFork.logicalSize = SWAP_BE64(dp->blockSize);;
1719 cfp->dataFork.totalBlocks = SWAP_BE32(1);
1720
1721 cfp->dataFork.extents[0].startBlock = SWAP_BE32 (header->journalInfoBlock);
1722 cfp->dataFork.extents[0].blockCount = cfp->dataFork.totalBlocks;
1723
1724 offset += sizeof(HFSPlusCatalogFile);
1725 SETOFFSET(buffer, nodeSize, offset, ++index);
1726 nodename2 = &ckp->nodeName;
1727
1728 /* Thread record for file #1 */
1729 tkp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1730 tkp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength);
1731 tkp->parentID = SWAP_BE32 (dp->nextFreeFileID);
1732 tkp->nodeName.length = 0;
1733 offset += SWAP_BE16 (tkp->keyLength) + 2;
1734
1735 ctp = (HFSPlusCatalogThread *)((UInt8 *)buffer + offset);
1736 ctp->recordType = SWAP_BE16 (kHFSPlusFileThreadRecord);
1737 ctp->parentID = SWAP_BE32 (kHFSRootFolderID);
1738 bcopy(nodename1, &ctp->nodeName, sizeof(UInt16) + uBytes1);
1739 offset += (sizeof(HFSPlusCatalogThread)
1740 - (sizeof(ctp->nodeName.unicode) - uBytes1) );
1741 SETOFFSET(buffer, nodeSize, offset, ++index);
1742
1743 /* Thread record for file #2 */
1744 tkp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1745 tkp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength);
1746 tkp->parentID = SWAP_BE32 (dp->nextFreeFileID + 1);
1747 tkp->nodeName.length = 0;
1748 offset += SWAP_BE16 (tkp->keyLength) + 2;
1749
1750 ctp = (HFSPlusCatalogThread *)((UInt8 *)buffer + offset);
1751 ctp->recordType = SWAP_BE16 (kHFSPlusFileThreadRecord);
1752 ctp->parentID = SWAP_BE32 (kHFSRootFolderID);
1753 bcopy(nodename2, &ctp->nodeName, sizeof(UInt16) + uBytes2);
1754 offset += (sizeof(HFSPlusCatalogThread)
1755 - (sizeof(ctp->nodeName.unicode) - uBytes2) );
1756 SETOFFSET(buffer, nodeSize, offset, ++index);
1757 }
1758 }
1759
1760 /*
1761 * WriteMapNodes
1762 *
1763 * Initializes a B-tree map node and writes it out to disk.
1764 */
1765 static void
1766 WriteMapNodes(const DriveInfo *driveInfo, UInt64 diskStart, UInt32 firstMapNode,
1767 UInt32 mapNodes, UInt16 btNodeSize, void *buffer)
1768 {
1769 UInt32 sectorsPerNode;
1770 UInt32 mapRecordBytes;
1771 UInt16 i;
1772 BTNodeDescriptor *nd = (BTNodeDescriptor *)buffer;
1773
1774 bzero(buffer, btNodeSize);
1775
1776 nd->kind = kBTMapNode;
1777 nd->numRecords = SWAP_BE16 (1);
1778
1779 /* note: must belong word aligned (hence the extra -2) */
1780 mapRecordBytes = btNodeSize - sizeof(BTNodeDescriptor) - 2*sizeof(SInt16) - 2;
1781
1782 SETOFFSET(buffer, btNodeSize, sizeof(BTNodeDescriptor), 1);
1783 SETOFFSET(buffer, btNodeSize, sizeof(BTNodeDescriptor) + mapRecordBytes, 2);
1784
1785 sectorsPerNode = btNodeSize/kBytesPerSector;
1786
1787 /*
1788 * Note - worst case (32MB alloc blk) will have
1789 * only 18 map nodes. So don't bother optimizing
1790 * this section to do multiblock writes!
1791 */
1792 for (i = 0; i < mapNodes; i++) {
1793 if ((i + 1) < mapNodes)
1794 nd->fLink = SWAP_BE32 (++firstMapNode); /* point to next map node */
1795 else
1796 nd->fLink = 0; /* this is the last map node */
1797
1798 WriteBuffer(driveInfo, diskStart, btNodeSize, buffer);
1799
1800 diskStart += sectorsPerNode;
1801 }
1802 }
1803
1804 /*
1805 * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1806 * NOTE: IF buffer IS NULL, THIS FUNCTION WILL WRITE ZERO'S.
1807 *
1808 * startingSector is in terms of 512-byte sectors.
1809 * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1810 */
1811 static void
1812 WriteBuffer(const DriveInfo *driveInfo, UInt64 startingSector, UInt64 byteCount,
1813 const void *buffer)
1814 {
1815 off_t sector;
1816 off_t physSector = 0;
1817 off_t byteOffsetInPhysSector;
1818 UInt32 numBytesToIO;
1819 UInt32 numPhysSectorsToIO;
1820 UInt32 tempbufSizeInPhysSectors;
1821 UInt32 tempbufSize;
1822 UInt32 fd = driveInfo->fd;
1823 UInt32 physSectorSize = driveInfo->physSectorSize;
1824 void *tempbuf = NULL;
1825 int sectorSizeRatio = driveInfo->physSectorSize / kBytesPerSector;
1826 int status = 0; /* 0: no error; 1: alloc; 2: read; 3: write */
1827
1828 if (0 == byteCount) {
1829 goto exit;
1830 }
1831
1832 /*@@@@@@@@@@ buffer allocation @@@@@@@@@@*/
1833 /* try a buffer size for optimal IO, __UP TO 4MB__. if that
1834 fails, then try with the minimum allowed buffer size, which
1835 is equal to physSectorSize */
1836 tempbufSizeInPhysSectors = MIN ( (byteCount - 1 + physSectorSize) / physSectorSize,
1837 driveInfo->physSectorsPerIO );
1838 /* limit at 4MB */
1839 tempbufSizeInPhysSectors = MIN ( tempbufSizeInPhysSectors, (4 * 1024 * 1024) / physSectorSize );
1840 tempbufSize = tempbufSizeInPhysSectors * physSectorSize;
1841
1842 if ((tempbuf = valloc(tempbufSize)) == NULL) {
1843 /* try allocation of smallest allowed size: one
1844 physical sector.
1845 NOTE: the previous valloc tempbufSize might have
1846 already been one physical sector. we don't want to
1847 check if that was the case, so just try again.
1848 */
1849 tempbufSizeInPhysSectors = 1;
1850 tempbufSize = physSectorSize;
1851 if ((tempbuf = valloc(tempbufSize)) == NULL) {
1852 status = 1;
1853 goto exit;
1854 }
1855 }
1856
1857 /*@@@@@@@@@@ io @@@@@@@@@@*/
1858 sector = driveInfo->sectorOffset + startingSector;
1859 physSector = sector / sectorSizeRatio;
1860 byteOffsetInPhysSector = (sector % sectorSizeRatio) * kBytesPerSector;
1861
1862 while (byteCount > 0) {
1863 numPhysSectorsToIO = MIN ( (byteCount - 1 + physSectorSize) / physSectorSize,
1864 tempbufSizeInPhysSectors );
1865 numBytesToIO = MIN(byteCount, (unsigned)((numPhysSectorsToIO * physSectorSize) - byteOffsetInPhysSector));
1866
1867 /* if IO does not align with physical sector boundaries */
1868 if ((0 != byteOffsetInPhysSector) || ((numBytesToIO % physSectorSize) != 0)) {
1869 if (pread(fd, tempbuf, numPhysSectorsToIO * physSectorSize, physSector * physSectorSize) < 0) {
1870 status = 2;
1871 goto exit;
1872 }
1873 }
1874
1875 if (NULL != buffer) {
1876 memcpy(tempbuf + byteOffsetInPhysSector, buffer, numBytesToIO);
1877 }
1878 else {
1879 bzero(tempbuf + byteOffsetInPhysSector, numBytesToIO);
1880 }
1881
1882 if (pwrite(fd, tempbuf, numPhysSectorsToIO * physSectorSize, physSector * physSectorSize) < 0) {
1883 warn("%s: pwrite(%d, %p, %zu, %lld)", __FUNCTION__, fd, tempbuf, (size_t)(numPhysSectorsToIO * physSectorSize), (long long)(physSector * physSectorSize));
1884 status = 3;
1885 goto exit;
1886 }
1887
1888 byteOffsetInPhysSector = 0;
1889 byteCount -= numBytesToIO;
1890 physSector += numPhysSectorsToIO;
1891 if (NULL != buffer) {
1892 buffer += numBytesToIO;
1893 }
1894 }
1895
1896 exit:
1897 if (tempbuf) {
1898 free(tempbuf);
1899 tempbuf = NULL;
1900 }
1901
1902 if (1 == status) {
1903 err(1, NULL);
1904 }
1905 else if (2 == status) {
1906 err(1, "read (sector %llu)", physSector);
1907 }
1908 else if (3 == status) {
1909 err(1, "write (sector %llu)", physSector);
1910 }
1911
1912 return;
1913 }
1914
1915
1916 static UInt32 Largest( UInt32 a, UInt32 b, UInt32 c, UInt32 d )
1917 {
1918 /* a := max(a,b) */
1919 if (a < b)
1920 a = b;
1921 /* c := max(c,d) */
1922 if (c < d)
1923 c = d;
1924
1925 /* return max(a,c) */
1926 if (a > c)
1927 return a;
1928 else
1929 return c;
1930 }
1931
1932 /*
1933 * UTCToLocal - convert from Mac OS GMT time to Mac OS local time
1934 */
1935 static UInt32 UTCToLocal(UInt32 utcTime)
1936 {
1937 UInt32 localTime = utcTime;
1938 struct timezone timeZone;
1939 struct timeval timeVal;
1940
1941 if (localTime != 0) {
1942
1943 /* HFS volumes need timezone info to convert local to GMT */
1944 (void)gettimeofday( &timeVal, &timeZone );
1945
1946
1947 localTime -= (timeZone.tz_minuteswest * 60);
1948 if (timeZone.tz_dsttime)
1949 localTime += 3600;
1950 }
1951
1952 return (localTime);
1953 }
1954
1955 #define __kCFUserEncodingFileName ("/.CFUserTextEncoding")
1956
1957 static UInt32
1958 GetDefaultEncoding()
1959 {
1960 struct passwd *passwdp;
1961
1962 if ((passwdp = getpwuid(0))) { // root account
1963 char buffer[MAXPATHLEN + 1];
1964 int fd;
1965
1966 strlcpy(buffer, passwdp->pw_dir, sizeof(buffer));
1967 strlcat(buffer, __kCFUserEncodingFileName, sizeof(buffer));
1968
1969 if ((fd = open(buffer, O_RDONLY, 0)) > 0) {
1970 ssize_t readSize;
1971
1972 readSize = read(fd, buffer, MAXPATHLEN);
1973 buffer[(readSize < 0 ? 0 : readSize)] = '\0';
1974 close(fd);
1975 return strtol(buffer, NULL, 0);
1976 }
1977 }
1978 return 0;
1979 }
1980
1981
1982 static int
1983 ConvertUTF8toUnicode(const UInt8* source, size_t bufsize, UniChar* unibuf,
1984 UInt16 *charcount)
1985 {
1986 UInt8 byte;
1987 UniChar* target;
1988 UniChar* targetEnd;
1989
1990 *charcount = 0;
1991 target = unibuf;
1992 targetEnd = (UniChar *)((UInt8 *)unibuf + bufsize);
1993
1994 while ((byte = *source++)) {
1995
1996 /* check for single-byte ascii */
1997 if (byte < 128) {
1998 if (byte == ':') /* ':' is mapped to '/' */
1999 byte = '/';
2000
2001 *target++ = SWAP_BE16 (byte);
2002 } else {
2003 UniChar ch;
2004 UInt8 seq = (byte >> 4);
2005
2006 switch (seq) {
2007 case 0xc: /* double-byte sequence (1100 and 1101) */
2008 case 0xd:
2009 ch = (byte & 0x1F) << 6; /* get 5 bits */
2010 if (((byte = *source++) >> 6) != 2)
2011 return (EINVAL);
2012 break;
2013
2014 case 0xe: /* triple-byte sequence (1110) */
2015 ch = (byte & 0x0F) << 6; /* get 4 bits */
2016 if (((byte = *source++) >> 6) != 2)
2017 return (EINVAL);
2018 ch += (byte & 0x3F); ch <<= 6; /* get 6 bits */
2019 if (((byte = *source++) >> 6) != 2)
2020 return (EINVAL);
2021 break;
2022
2023 default:
2024 return (EINVAL); /* malformed sequence */
2025 }
2026
2027 ch += (byte & 0x3F); /* get last 6 bits */
2028
2029 if (target >= targetEnd)
2030 return (ENOBUFS);
2031
2032 *target++ = SWAP_BE16 (ch);
2033 }
2034 }
2035
2036 *charcount = target - unibuf;
2037
2038 return (0);
2039 }
2040
2041 /*
2042 * Derive the encoding hint for the given name.
2043 */
2044 static int
2045 getencodinghint(unsigned char *name)
2046 {
2047 int mib[3];
2048 size_t buflen = sizeof(int);
2049 struct vfsconf vfc;
2050 int hint = 0;
2051
2052 if (getvfsbyname("hfs", &vfc) < 0)
2053 goto error;
2054
2055 mib[0] = CTL_VFS;
2056 mib[1] = vfc.vfc_typenum;
2057 mib[2] = HFS_ENCODINGHINT;
2058
2059 if (sysctl(mib, 3, &hint, &buflen, name, strlen((char *)name) + 1) < 0)
2060 goto error;
2061 return (hint);
2062 error:
2063 hint = GetDefaultEncoding();
2064 return (hint);
2065 }
2066
2067
2068 /* Generate Volume UUID - similar to code existing in hfs_util */
2069 void GenerateVolumeUUID(VolumeUUID *newVolumeID) {
2070 SHA_CTX context;
2071 char randomInputBuffer[26];
2072 unsigned char digest[20];
2073 time_t now;
2074 clock_t uptime;
2075 int mib[2];
2076 int sysdata;
2077 char sysctlstring[128];
2078 size_t datalen;
2079 double sysloadavg[3];
2080 struct vmtotal sysvmtotal;
2081
2082 do {
2083 /* Initialize the SHA-1 context for processing: */
2084 SHA1_Init(&context);
2085
2086 /* Now process successive bits of "random" input to seed the process: */
2087
2088 /* The current system's uptime: */
2089 uptime = clock();
2090 SHA1_Update(&context, &uptime, sizeof(uptime));
2091
2092 /* The kernel's boot time: */
2093 mib[0] = CTL_KERN;
2094 mib[1] = KERN_BOOTTIME;
2095 datalen = sizeof(sysdata);
2096 sysctl(mib, 2, &sysdata, &datalen, NULL, 0);
2097 SHA1_Update(&context, &sysdata, datalen);
2098
2099 /* The system's host id: */
2100 mib[0] = CTL_KERN;
2101 mib[1] = KERN_HOSTID;
2102 datalen = sizeof(sysdata);
2103 sysctl(mib, 2, &sysdata, &datalen, NULL, 0);
2104 SHA1_Update(&context, &sysdata, datalen);
2105
2106 /* The system's host name: */
2107 mib[0] = CTL_KERN;
2108 mib[1] = KERN_HOSTNAME;
2109 datalen = sizeof(sysctlstring);
2110 sysctl(mib, 2, sysctlstring, &datalen, NULL, 0);
2111 SHA1_Update(&context, sysctlstring, datalen);
2112
2113 /* The running kernel's OS release string: */
2114 mib[0] = CTL_KERN;
2115 mib[1] = KERN_OSRELEASE;
2116 datalen = sizeof(sysctlstring);
2117 sysctl(mib, 2, sysctlstring, &datalen, NULL, 0);
2118 SHA1_Update(&context, sysctlstring, datalen);
2119
2120 /* The running kernel's version string: */
2121 mib[0] = CTL_KERN;
2122 mib[1] = KERN_VERSION;
2123 datalen = sizeof(sysctlstring);
2124 sysctl(mib, 2, sysctlstring, &datalen, NULL, 0);
2125 SHA1_Update(&context, sysctlstring, datalen);
2126
2127 /* The system's load average: */
2128 datalen = sizeof(sysloadavg);
2129 getloadavg(sysloadavg, 3);
2130 SHA1_Update(&context, &sysloadavg, datalen);
2131
2132 /* The system's VM statistics: */
2133 mib[0] = CTL_VM;
2134 mib[1] = VM_METER;
2135 datalen = sizeof(sysvmtotal);
2136 sysctl(mib, 2, &sysvmtotal, &datalen, NULL, 0);
2137 SHA1_Update(&context, &sysvmtotal, datalen);
2138
2139 /* The current GMT (26 ASCII characters): */
2140 time(&now);
2141 strncpy(randomInputBuffer, asctime(gmtime(&now)), 26); /* "Mon Mar 27 13:46:26 2000" */
2142 SHA1_Update(&context, randomInputBuffer, 26);
2143
2144 /* Pad the accumulated input and extract the final digest hash: */
2145 SHA1_Final(digest, &context);
2146
2147 memcpy(newVolumeID, digest, sizeof(*newVolumeID));
2148 } while ((newVolumeID->v.high == 0) || (newVolumeID->v.low == 0));
2149 }
2150
2151