1/*
2 * Copyright (c) 1999-2014 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
69extern 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
94typedef HFSMasterDirectoryBlock HFS_MDB;
95
96struct filefork {
97	UInt16	startBlock;
98	UInt16	blockCount;
99	UInt32	logicalSize;
100	UInt32	physicalSize;
101};
102
103struct ExtentRecord {
104	HFSPlusExtentKey	key;
105	HFSPlusExtentRecord	record;
106} __attribute__((aligned(2), packed));
107static size_t numOverflowExtents = 0;
108static struct ExtentRecord *overflowExtents = NULL;
109
110struct filefork	gDTDBFork, gSystemFork, gReadMeFork;
111
112static void WriteVH __P((const DriveInfo *driveInfo, HFSPlusVolumeHeader *hp));
113static void InitVH __P((hfsparams_t *defaults, UInt64 sectors,
114		HFSPlusVolumeHeader *header));
115
116static int AllocateExtent(UInt8 *buffer, UInt32 startBlock, UInt32 blockCount);
117static int MarkExtentUsed(const DriveInfo *, HFSPlusVolumeHeader *, UInt32, UInt32);
118
119static void WriteExtentsFile __P((const DriveInfo *dip, UInt64 startingSector,
120        const hfsparams_t *dp, HFSExtentDescriptor *bbextp, void *buffer,
121        UInt32 *bytesUsed, UInt32 *mapNodes));
122
123static void WriteAttributesFile(const DriveInfo *driveInfo, UInt64 startingSector,
124        const hfsparams_t *dp, HFSExtentDescriptor *bbextp, void *buffer,
125        UInt32 *bytesUsed, UInt32 *mapNodes);
126
127static void WriteCatalogFile __P((const DriveInfo *dip, UInt64 startingSector,
128        const hfsparams_t *dp, HFSPlusVolumeHeader *header, void *buffer,
129        UInt32 *bytesUsed, UInt32 *mapNodes));
130static int  WriteJournalInfo(const DriveInfo *driveInfo, UInt64 startingSector,
131			     const hfsparams_t *dp, HFSPlusVolumeHeader *header,
132			     void *buffer);
133static void InitCatalogRoot_HFSPlus __P((const hfsparams_t *dp, const HFSPlusVolumeHeader *header, void * buffer));
134
135static void WriteMapNodes __P((const DriveInfo *driveInfo, UInt64 diskStart,
136		UInt32 firstMapNode, UInt32 mapNodes, UInt16 btNodeSize, void *buffer));
137static void WriteBuffer __P((const DriveInfo *driveInfo, UInt64 startingSector,
138		UInt64 byteCount, const void *buffer));
139static UInt32 Largest __P((UInt32 a, UInt32 b, UInt32 c, UInt32 d ));
140
141static UInt32 GetDefaultEncoding();
142
143static UInt32 UTCToLocal __P((UInt32 utcTime));
144
145static int ConvertUTF8toUnicode __P((const UInt8* source, size_t bufsize,
146		UniChar* unibuf, UInt16 *charcount));
147
148static int getencodinghint(unsigned char *name);
149
150#define VOLUMEUUIDVALUESIZE 2
151typedef union VolumeUUID {
152	UInt32 value[VOLUMEUUIDVALUESIZE];
153	struct {
154		UInt32 high;
155		UInt32 low;
156	} v;
157} VolumeUUID;
158void GenerateVolumeUUID(VolumeUUID *newVolumeID);
159
160void 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
180struct 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 */
194static void
195createExtents(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 */
304static int
305dowipefs(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 */
326int
327make_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 */
593static void
594WriteVH (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 */
608static void
609InitVH(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 */
844static 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
931static int
932MarkExtentUsed(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 */
1016static void
1017WriteExtentsFile(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 */
1161static void
1162WriteAttributesFile(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
1338static int
1339get_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
1366static int
1367clear_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
1385static int
1386WriteJournalInfo(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	if (jibp->flags & kJIJournalInFSMask) {
1440		/*
1441		 * Zero out the on-disk content of the journal file.
1442		 *
1443		 * This is a really ugly hack.  Right now, all of the logic in the code
1444		 * that calls us (make_hfsplus), uses the value 'sectorsPerBlock' but it
1445		 * is really hardcoded to assume the sector size is 512 bytes.  The code
1446		 * in WriteBuffer will massage the I/O to use the actual physical sector
1447		 * size.   Since WriteBuffer takes a sector # relative to 512 byte sectors,
1448		 * We need to convert the journal offset in bytes to value that represents
1449		 * its start LBA in 512 byte sectors.
1450		 *
1451		 * Note further that we swapped to big endian prior to the WriteBuffer call,
1452		 * but we have swapped back to native after the call.
1453		 */
1454		WriteBuffer(driveInfo, jibp->offset / kBytesPerSector, jibp->size, NULL);
1455	}
1456
1457    return 0;
1458}
1459
1460
1461/*
1462 * WriteCatalogFile
1463 *
1464 * This routine initializes a Catalog B-Tree.
1465 *
1466 * Note: Since large volumes can have bigger b-trees they
1467 * might need to have map nodes setup.
1468 */
1469static void
1470WriteCatalogFile(const DriveInfo *driveInfo, UInt64 startingSector,
1471        const hfsparams_t *dp, HFSPlusVolumeHeader *header, void *buffer,
1472        UInt32 *bytesUsed, UInt32 *mapNodes)
1473{
1474	BTNodeDescriptor	*ndp;
1475	BTHeaderRec		*bthp;
1476	UInt8			*bmp;
1477	UInt32			nodeBitsInHeader;
1478	UInt32			fileSize;
1479	UInt32			nodeSize;
1480	UInt32			temp;
1481	SInt16			offset;
1482
1483	*mapNodes = 0;
1484	fileSize = dp->catalogClumpSize;
1485	nodeSize = dp->catalogNodeSize;
1486
1487	bzero(buffer, nodeSize);
1488
1489
1490	/* FILL IN THE NODE DESCRIPTOR:  */
1491	ndp = (BTNodeDescriptor *)buffer;
1492	ndp->kind			= kBTHeaderNode;
1493	ndp->numRecords		= SWAP_BE16 (3);
1494	offset = sizeof(BTNodeDescriptor);
1495
1496	SETOFFSET(buffer, nodeSize, offset, 1);
1497
1498
1499	/* FILL IN THE HEADER RECORD:  */
1500	bthp = (BTHeaderRec *)((UInt8 *)buffer + offset);
1501	bthp->treeDepth		= SWAP_BE16 (1);
1502	bthp->rootNode		= SWAP_BE32 (1);
1503	bthp->firstLeafNode	= SWAP_BE32 (1);
1504	bthp->lastLeafNode	= SWAP_BE32 (1);
1505	bthp->leafRecords	= SWAP_BE32 (dp->journaledHFS ? 6 : 2);
1506	bthp->nodeSize		= SWAP_BE16 (nodeSize);
1507	bthp->totalNodes	= SWAP_BE32 (fileSize / nodeSize);
1508	bthp->freeNodes		= SWAP_BE32 (SWAP_BE32 (bthp->totalNodes) - 2);  /* header and root */
1509	bthp->clumpSize		= SWAP_BE32 (fileSize);
1510
1511
1512	bthp->attributes	|= SWAP_BE32 (kBTVariableIndexKeysMask + kBTBigKeysMask);
1513	bthp->maxKeyLength	=  SWAP_BE16 (kHFSPlusCatalogKeyMaximumLength);
1514	if (dp->flags & kMakeCaseSensitive)
1515		bthp->keyCompareType = kHFSBinaryCompare;
1516	else
1517		bthp->keyCompareType = kHFSCaseFolding;
1518
1519	offset += sizeof(BTHeaderRec);
1520
1521	SETOFFSET(buffer, nodeSize, offset, 2);
1522
1523	offset += kBTreeHeaderUserBytes;
1524
1525	SETOFFSET(buffer, nodeSize, offset, 3);
1526
1527	/* FIGURE OUT HOW MANY MAP NODES (IF ANY):  */
1528	nodeBitsInHeader = 8 * (nodeSize
1529					- sizeof(BTNodeDescriptor)
1530					- sizeof(BTHeaderRec)
1531					- kBTreeHeaderUserBytes
1532					- (4 * sizeof(SInt16)) );
1533
1534	if (SWAP_BE32 (bthp->totalNodes) > nodeBitsInHeader) {
1535		UInt32	nodeBitsInMapNode;
1536
1537		ndp->fLink = SWAP_BE32 (SWAP_BE32 (bthp->lastLeafNode) + 1);
1538		nodeBitsInMapNode = 8 * (nodeSize
1539						- sizeof(BTNodeDescriptor)
1540						- (2 * sizeof(SInt16))
1541						- 2 );
1542		*mapNodes = (SWAP_BE32 (bthp->totalNodes) - nodeBitsInHeader +
1543			(nodeBitsInMapNode - 1)) / nodeBitsInMapNode;
1544		bthp->freeNodes = SWAP_BE32 (SWAP_BE32 (bthp->freeNodes) - *mapNodes);
1545	}
1546
1547	/*
1548	 * FILL IN THE MAP RECORD, MARKING NODES THAT ARE IN USE.
1549	 * Note - worst case (32MB alloc blk) will have only 18 nodes in use.
1550	 */
1551	bmp = ((UInt8 *)buffer + offset);
1552	temp = SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes);
1553
1554	/* Working a byte at a time is endian safe */
1555	while (temp >= 8) { *bmp = 0xFF; temp -= 8; bmp++; }
1556	*bmp = ~(0xFF >> temp);
1557	offset += nodeBitsInHeader/8;
1558
1559	SETOFFSET(buffer, nodeSize, offset, 4);
1560
1561	InitCatalogRoot_HFSPlus(dp, header, buffer + nodeSize);
1562
1563	*bytesUsed = (SWAP_BE32 (bthp->totalNodes) - SWAP_BE32 (bthp->freeNodes) - *mapNodes) * nodeSize;
1564
1565	WriteBuffer(driveInfo, startingSector, *bytesUsed, buffer);
1566}
1567
1568
1569static void
1570InitCatalogRoot_HFSPlus(const hfsparams_t *dp, const HFSPlusVolumeHeader *header, void * buffer)
1571{
1572	BTNodeDescriptor		*ndp;
1573	HFSPlusCatalogKey		*ckp;
1574	HFSPlusCatalogKey		*tkp;
1575	HFSPlusCatalogFolder	*cdp;
1576	HFSPlusCatalogFile		*cfp;
1577	HFSPlusCatalogThread	*ctp;
1578	UInt16					nodeSize;
1579	SInt16					offset;
1580	size_t					unicodeBytes;
1581	UInt8 canonicalName[kHFSPlusMaxFileNameBytes];	// UTF8 character may convert to three bytes, plus a NUL
1582	CFStringRef cfstr;
1583	Boolean	cfOK;
1584	int index = 0;
1585
1586	nodeSize = dp->catalogNodeSize;
1587	bzero(buffer, nodeSize);
1588
1589	/*
1590	 * All nodes have a node descriptor...
1591	 */
1592	ndp = (BTNodeDescriptor *)buffer;
1593	ndp->kind   = kBTLeafNode;
1594	ndp->height = 1;
1595	ndp->numRecords = SWAP_BE16 (dp->journaledHFS ? 6 : 2);
1596	offset = sizeof(BTNodeDescriptor);
1597	SETOFFSET(buffer, nodeSize, offset, ++index);
1598
1599	/*
1600	 * First record is always the root directory...
1601	 */
1602	ckp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1603
1604	/* Use CFString functions to get a HFSPlus Canonical name */
1605	cfstr = CFStringCreateWithCString(kCFAllocatorDefault, (char *)dp->volumeName, kCFStringEncodingUTF8);
1606	cfOK = _CFStringGetFileSystemRepresentation(cfstr, canonicalName, sizeof(canonicalName));
1607
1608	if (!cfOK || ConvertUTF8toUnicode(canonicalName, sizeof(ckp->nodeName.unicode),
1609		ckp->nodeName.unicode, &ckp->nodeName.length)) {
1610
1611		/* On conversion errors "untitled" is used as a fallback. */
1612		(void) ConvertUTF8toUnicode((UInt8 *)kDefaultVolumeNameStr,
1613									sizeof(ckp->nodeName.unicode),
1614									ckp->nodeName.unicode,
1615									&ckp->nodeName.length);
1616		warnx("invalid HFS+ name: \"%s\", using \"%s\" instead",
1617		      dp->volumeName, kDefaultVolumeNameStr);
1618	}
1619	CFRelease(cfstr);
1620	ckp->nodeName.length = SWAP_BE16 (ckp->nodeName.length);
1621
1622	unicodeBytes = sizeof(UniChar) * SWAP_BE16 (ckp->nodeName.length);
1623
1624	ckp->keyLength		= SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength + unicodeBytes);
1625	ckp->parentID		= SWAP_BE32 (kHFSRootParentID);
1626	offset += SWAP_BE16 (ckp->keyLength) + 2;
1627
1628	cdp = (HFSPlusCatalogFolder *)((UInt8 *)buffer + offset);
1629	cdp->recordType		= SWAP_BE16 (kHFSPlusFolderRecord);
1630	/* folder count is only supported on HFSX volumes */
1631	if (dp->flags & kMakeCaseSensitive) {
1632		cdp->flags 		= SWAP_BE16 (kHFSHasFolderCountMask);
1633	}
1634	cdp->valence        = SWAP_BE32 (dp->journaledHFS ? 2 : 0);
1635	cdp->folderID		= SWAP_BE32 (kHFSRootFolderID);
1636	cdp->createDate		= SWAP_BE32 (dp->createDate);
1637	cdp->contentModDate	= SWAP_BE32 (dp->createDate);
1638	cdp->textEncoding	= SWAP_BE32 (dp->encodingHint);
1639	if (dp->flags & kUseAccessPerms) {
1640		cdp->bsdInfo.ownerID  = SWAP_BE32 (dp->owner);
1641		cdp->bsdInfo.groupID  = SWAP_BE32 (dp->group);
1642		cdp->bsdInfo.fileMode = SWAP_BE16 (dp->mask | S_IFDIR);
1643	}
1644	offset += sizeof(HFSPlusCatalogFolder);
1645	SETOFFSET(buffer, nodeSize, offset, ++index);
1646
1647	/*
1648	 * Second record is always the root directory thread...
1649	 */
1650	tkp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1651	tkp->keyLength		= SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength);
1652	tkp->parentID		= SWAP_BE32 (kHFSRootFolderID);
1653	// tkp->nodeName.length = 0;
1654
1655	offset += SWAP_BE16 (tkp->keyLength) + 2;
1656
1657	ctp = (HFSPlusCatalogThread *)((UInt8 *)buffer + offset);
1658	ctp->recordType		= SWAP_BE16 (kHFSPlusFolderThreadRecord);
1659	ctp->parentID		= SWAP_BE32 (kHFSRootParentID);
1660	bcopy(&ckp->nodeName, &ctp->nodeName, sizeof(UInt16) + unicodeBytes);
1661	offset += (sizeof(HFSPlusCatalogThread)
1662			- (sizeof(ctp->nodeName.unicode) - unicodeBytes) );
1663
1664	SETOFFSET(buffer, nodeSize, offset, ++index);
1665
1666	/*
1667	 * Add records for ".journal" and ".journal_info_block" files:
1668	 */
1669	if (dp->journaledHFS) {
1670		struct HFSUniStr255 *nodename1, *nodename2;
1671		size_t uBytes1, uBytes2;
1672		UInt32 journalBlock;
1673
1674		/* File record #1 */
1675		ckp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1676		(void) ConvertUTF8toUnicode((UInt8 *)HFS_JOURNAL_FILE, sizeof(ckp->nodeName.unicode),
1677		                            ckp->nodeName.unicode, &ckp->nodeName.length);
1678		ckp->nodeName.length = SWAP_BE16 (ckp->nodeName.length);
1679		uBytes1 = sizeof(UniChar) * SWAP_BE16 (ckp->nodeName.length);
1680		ckp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength + uBytes1);
1681		ckp->parentID  = SWAP_BE32 (kHFSRootFolderID);
1682		offset += SWAP_BE16 (ckp->keyLength) + 2;
1683
1684		cfp = (HFSPlusCatalogFile *)((UInt8 *)buffer + offset);
1685		cfp->recordType     = SWAP_BE16 (kHFSPlusFileRecord);
1686		cfp->flags          = SWAP_BE16 (kHFSThreadExistsMask);
1687		cfp->fileID         = SWAP_BE32 (dp->nextFreeFileID);
1688		cfp->createDate     = SWAP_BE32 (dp->createDate + 1);
1689		cfp->contentModDate = SWAP_BE32 (dp->createDate + 1);
1690		cfp->textEncoding   = 0;
1691
1692		cfp->bsdInfo.fileMode     = SWAP_BE16 (S_IFREG);
1693		cfp->bsdInfo.ownerFlags   = (uint8_t) SWAP_BE16 (((uint16_t)UF_NODUMP));
1694		cfp->bsdInfo.special.linkCount	= SWAP_BE32(1);
1695		cfp->userInfo.fdType	  = SWAP_BE32 (kJournalFileType);
1696		cfp->userInfo.fdCreator	  = SWAP_BE32 (kHFSPlusCreator);
1697		cfp->userInfo.fdFlags     = SWAP_BE16 (kIsInvisible + kNameLocked);
1698		cfp->dataFork.logicalSize = SWAP_BE64 (dp->journalSize);
1699		cfp->dataFork.totalBlocks = SWAP_BE32 ((dp->journalSize+dp->blockSize-1) / dp->blockSize);
1700
1701		if (NEWFS_HFS_DEBUG && dp->journalBlock)
1702			journalBlock = dp->journalBlock;
1703		else
1704			journalBlock = header->journalInfoBlock + 1;
1705		cfp->dataFork.extents[0].startBlock = SWAP_BE32 (journalBlock);
1706		cfp->dataFork.extents[0].blockCount = cfp->dataFork.totalBlocks;
1707
1708		offset += sizeof(HFSPlusCatalogFile);
1709		SETOFFSET(buffer, nodeSize, offset, ++index);
1710		nodename1 = &ckp->nodeName;
1711
1712		/* File record #2 */
1713		ckp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1714		(void) ConvertUTF8toUnicode((UInt8 *)HFS_JOURNAL_INFO, sizeof(ckp->nodeName.unicode),
1715		                            ckp->nodeName.unicode, &ckp->nodeName.length);
1716		ckp->nodeName.length = SWAP_BE16 (ckp->nodeName.length);
1717		uBytes2 = sizeof(UniChar) * SWAP_BE16 (ckp->nodeName.length);
1718		ckp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength + uBytes2);
1719		ckp->parentID  = SWAP_BE32 (kHFSRootFolderID);
1720		offset += SWAP_BE16 (ckp->keyLength) + 2;
1721
1722		cfp = (HFSPlusCatalogFile *)((UInt8 *)buffer + offset);
1723		cfp->recordType     = SWAP_BE16 (kHFSPlusFileRecord);
1724		cfp->flags          = SWAP_BE16 (kHFSThreadExistsMask);
1725		cfp->fileID         = SWAP_BE32 (dp->nextFreeFileID + 1);
1726		cfp->createDate     = SWAP_BE32 (dp->createDate);
1727		cfp->contentModDate = SWAP_BE32 (dp->createDate);
1728		cfp->textEncoding   = 0;
1729
1730		cfp->bsdInfo.fileMode     = SWAP_BE16 (S_IFREG);
1731		cfp->bsdInfo.ownerFlags   = (uint8_t) SWAP_BE16 (((uint16_t)UF_NODUMP));
1732		cfp->bsdInfo.special.linkCount	= SWAP_BE32(1);
1733		cfp->userInfo.fdType	  = SWAP_BE32 (kJournalFileType);
1734		cfp->userInfo.fdCreator	  = SWAP_BE32 (kHFSPlusCreator);
1735		cfp->userInfo.fdFlags     = SWAP_BE16 (kIsInvisible + kNameLocked);
1736		cfp->dataFork.logicalSize = SWAP_BE64(dp->blockSize);;
1737		cfp->dataFork.totalBlocks = SWAP_BE32(1);
1738
1739		cfp->dataFork.extents[0].startBlock = SWAP_BE32 (header->journalInfoBlock);
1740		cfp->dataFork.extents[0].blockCount = cfp->dataFork.totalBlocks;
1741
1742		offset += sizeof(HFSPlusCatalogFile);
1743		SETOFFSET(buffer, nodeSize, offset, ++index);
1744		nodename2 = &ckp->nodeName;
1745
1746		/* Thread record for file #1 */
1747		tkp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1748		tkp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength);
1749		tkp->parentID  = SWAP_BE32 (dp->nextFreeFileID);
1750		tkp->nodeName.length = 0;
1751		offset += SWAP_BE16 (tkp->keyLength) + 2;
1752
1753		ctp = (HFSPlusCatalogThread *)((UInt8 *)buffer + offset);
1754		ctp->recordType = SWAP_BE16 (kHFSPlusFileThreadRecord);
1755		ctp->parentID   = SWAP_BE32 (kHFSRootFolderID);
1756		bcopy(nodename1, &ctp->nodeName, sizeof(UInt16) + uBytes1);
1757		offset += (sizeof(HFSPlusCatalogThread)
1758				- (sizeof(ctp->nodeName.unicode) - uBytes1) );
1759		SETOFFSET(buffer, nodeSize, offset, ++index);
1760
1761		/* Thread record for file #2 */
1762		tkp = (HFSPlusCatalogKey *)((UInt8 *)buffer + offset);
1763		tkp->keyLength = SWAP_BE16 (kHFSPlusCatalogKeyMinimumLength);
1764		tkp->parentID  = SWAP_BE32 (dp->nextFreeFileID + 1);
1765		tkp->nodeName.length = 0;
1766		offset += SWAP_BE16 (tkp->keyLength) + 2;
1767
1768		ctp = (HFSPlusCatalogThread *)((UInt8 *)buffer + offset);
1769		ctp->recordType = SWAP_BE16 (kHFSPlusFileThreadRecord);
1770		ctp->parentID   = SWAP_BE32 (kHFSRootFolderID);
1771		bcopy(nodename2, &ctp->nodeName, sizeof(UInt16) + uBytes2);
1772		offset += (sizeof(HFSPlusCatalogThread)
1773				- (sizeof(ctp->nodeName.unicode) - uBytes2) );
1774		SETOFFSET(buffer, nodeSize, offset, ++index);
1775	}
1776}
1777
1778/*
1779 * WriteMapNodes
1780 *
1781 * Initializes a B-tree map node and writes it out to disk.
1782 */
1783static void
1784WriteMapNodes(const DriveInfo *driveInfo, UInt64 diskStart, UInt32 firstMapNode,
1785	UInt32 mapNodes, UInt16 btNodeSize, void *buffer)
1786{
1787	UInt32	sectorsPerNode;
1788	UInt32	mapRecordBytes;
1789	UInt16	i;
1790	BTNodeDescriptor *nd = (BTNodeDescriptor *)buffer;
1791
1792	bzero(buffer, btNodeSize);
1793
1794	nd->kind		= kBTMapNode;
1795	nd->numRecords	= SWAP_BE16 (1);
1796
1797	/* note: must belong word aligned (hence the extra -2) */
1798	mapRecordBytes = btNodeSize - sizeof(BTNodeDescriptor) - 2*sizeof(SInt16) - 2;
1799
1800	SETOFFSET(buffer, btNodeSize, sizeof(BTNodeDescriptor), 1);
1801	SETOFFSET(buffer, btNodeSize, sizeof(BTNodeDescriptor) + mapRecordBytes, 2);
1802
1803	sectorsPerNode = btNodeSize/kBytesPerSector;
1804
1805	/*
1806	 * Note - worst case (32MB alloc blk) will have
1807	 * only 18 map nodes. So don't bother optimizing
1808	 * this section to do multiblock writes!
1809	 */
1810	for (i = 0; i < mapNodes; i++) {
1811		if ((i + 1) < mapNodes)
1812			nd->fLink = SWAP_BE32 (++firstMapNode);  /* point to next map node */
1813		else
1814			nd->fLink = 0;  /* this is the last map node */
1815
1816		WriteBuffer(driveInfo, diskStart, btNodeSize, buffer);
1817
1818		diskStart += sectorsPerNode;
1819	}
1820}
1821
1822/*
1823 * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1824 * NOTE: IF buffer IS NULL, THIS FUNCTION WILL WRITE ZERO'S.
1825 *
1826 * startingSector is in terms of 512-byte sectors.
1827 * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
1828 */
1829static void
1830WriteBuffer(const DriveInfo *driveInfo, UInt64 startingSector, UInt64 byteCount,
1831	const void *buffer)
1832{
1833	off_t sector;
1834	off_t physSector = 0;
1835	off_t byteOffsetInPhysSector;
1836	UInt32 numBytesToIO;
1837	UInt32 numPhysSectorsToIO;
1838	UInt32 tempbufSizeInPhysSectors;
1839	UInt32 tempbufSize;
1840	UInt32 fd = driveInfo->fd;
1841	UInt32 physSectorSize = driveInfo->physSectorSize;
1842	void *tempbuf = NULL;
1843	int sectorSizeRatio = driveInfo->physSectorSize / kBytesPerSector;
1844	int status = 0; /* 0: no error; 1: alloc; 2: read; 3: write */
1845
1846	if (0 == byteCount) {
1847		goto exit;
1848	}
1849
1850	/*@@@@@@@@@@ buffer allocation @@@@@@@@@@*/
1851	/* try a buffer size for optimal IO, __UP TO 4MB__. if that
1852	   fails, then try with the minimum allowed buffer size, which
1853	   is equal to physSectorSize */
1854	tempbufSizeInPhysSectors = MIN ( (byteCount - 1 + physSectorSize) / physSectorSize,
1855					     driveInfo->physSectorsPerIO );
1856	/* limit at 4MB */
1857	tempbufSizeInPhysSectors = MIN ( tempbufSizeInPhysSectors, (4 * 1024 * 1024) / physSectorSize );
1858	tempbufSize = tempbufSizeInPhysSectors * physSectorSize;
1859
1860	if ((tempbuf = valloc(tempbufSize)) == NULL) {
1861		/* try allocation of smallest allowed size: one
1862		   physical sector.
1863		   NOTE: the previous valloc tempbufSize might have
1864		   already been one physical sector. we don't want to
1865		   check if that was the case, so just try again.
1866		*/
1867		tempbufSizeInPhysSectors = 1;
1868		tempbufSize = physSectorSize;
1869		if ((tempbuf = valloc(tempbufSize)) == NULL) {
1870			status = 1;
1871			goto exit;
1872		}
1873	}
1874
1875	/*@@@@@@@@@@ io @@@@@@@@@@*/
1876	sector = driveInfo->sectorOffset + startingSector;
1877	physSector = sector / sectorSizeRatio;
1878	byteOffsetInPhysSector =  (sector % sectorSizeRatio) * kBytesPerSector;
1879
1880	while (byteCount > 0) {
1881		numPhysSectorsToIO = MIN ( (byteCount - 1 + physSectorSize) / physSectorSize,
1882				       tempbufSizeInPhysSectors );
1883		numBytesToIO = MIN(byteCount, (unsigned)((numPhysSectorsToIO * physSectorSize) - byteOffsetInPhysSector));
1884
1885		/* if IO does not align with physical sector boundaries */
1886		if ((0 != byteOffsetInPhysSector) || ((numBytesToIO % physSectorSize) != 0)) {
1887			if (pread(fd, tempbuf, numPhysSectorsToIO * physSectorSize, physSector * physSectorSize) < 0) {
1888				status = 2;
1889				goto exit;
1890			}
1891		}
1892
1893		if (NULL != buffer) {
1894			memcpy(tempbuf + byteOffsetInPhysSector, buffer, numBytesToIO);
1895		}
1896		else {
1897			bzero(tempbuf + byteOffsetInPhysSector, numBytesToIO);
1898		}
1899
1900		if (pwrite(fd, tempbuf, numPhysSectorsToIO * physSectorSize, physSector * physSectorSize) < 0) {
1901			warn("%s:  pwrite(%d, %p, %zu, %lld)", __FUNCTION__, fd, tempbuf, (size_t)(numPhysSectorsToIO * physSectorSize), (long long)(physSector * physSectorSize));
1902			status = 3;
1903			goto exit;
1904		}
1905
1906		byteOffsetInPhysSector = 0;
1907		byteCount -= numBytesToIO;
1908		physSector += numPhysSectorsToIO;
1909		if (NULL != buffer) {
1910			buffer += numBytesToIO;
1911		}
1912	}
1913
1914exit:
1915	if (tempbuf) {
1916		free(tempbuf);
1917		tempbuf = NULL;
1918	}
1919
1920	if (1 == status) {
1921		err(1, NULL);
1922	}
1923	else if (2 == status) {
1924		err(1, "read (sector %llu)", physSector);
1925	}
1926	else if (3 == status) {
1927		err(1, "write (sector %llu)", physSector);
1928	}
1929
1930	return;
1931}
1932
1933
1934static UInt32 Largest( UInt32 a, UInt32 b, UInt32 c, UInt32 d )
1935{
1936	/* a := max(a,b) */
1937	if (a < b)
1938		a = b;
1939	/* c := max(c,d) */
1940	if (c < d)
1941		c = d;
1942
1943	/* return max(a,c) */
1944	if (a > c)
1945		return a;
1946	else
1947		return c;
1948}
1949
1950/*
1951 * UTCToLocal - convert from Mac OS GMT time to Mac OS local time
1952 */
1953static UInt32 UTCToLocal(UInt32 utcTime)
1954{
1955	UInt32 localTime = utcTime;
1956	struct timezone timeZone;
1957	struct timeval	timeVal;
1958
1959	if (localTime != 0) {
1960
1961                /* HFS volumes need timezone info to convert local to GMT */
1962                (void)gettimeofday( &timeVal, &timeZone );
1963
1964
1965		localTime -= (timeZone.tz_minuteswest * 60);
1966		if (timeZone.tz_dsttime)
1967			localTime += 3600;
1968	}
1969
1970        return (localTime);
1971}
1972
1973#define __kCFUserEncodingFileName ("/.CFUserTextEncoding")
1974
1975static UInt32
1976GetDefaultEncoding()
1977{
1978    struct passwd *passwdp;
1979
1980    if ((passwdp = getpwuid(0))) { // root account
1981        char buffer[MAXPATHLEN + 1];
1982        int fd;
1983
1984        strlcpy(buffer, passwdp->pw_dir, sizeof(buffer));
1985        strlcat(buffer, __kCFUserEncodingFileName, sizeof(buffer));
1986
1987        if ((fd = open(buffer, O_RDONLY, 0)) > 0) {
1988            ssize_t readSize;
1989
1990            readSize = read(fd, buffer, MAXPATHLEN);
1991            buffer[(readSize < 0 ? 0 : readSize)] = '\0';
1992            close(fd);
1993            return strtol(buffer, NULL, 0);
1994        }
1995    }
1996    return 0;
1997}
1998
1999
2000static int
2001ConvertUTF8toUnicode(const UInt8* source, size_t bufsize, UniChar* unibuf,
2002	UInt16 *charcount)
2003{
2004	UInt8 byte;
2005	UniChar* target;
2006	UniChar* targetEnd;
2007
2008	*charcount = 0;
2009	target = unibuf;
2010	targetEnd = (UniChar *)((UInt8 *)unibuf + bufsize);
2011
2012	while ((byte = *source++)) {
2013
2014		/* check for single-byte ascii */
2015		if (byte < 128) {
2016			if (byte == ':')	/* ':' is mapped to '/' */
2017				byte = '/';
2018
2019			*target++ = SWAP_BE16 (byte);
2020		} else {
2021			UniChar ch;
2022			UInt8 seq = (byte >> 4);
2023
2024			switch (seq) {
2025			case 0xc: /* double-byte sequence (1100 and 1101) */
2026			case 0xd:
2027				ch = (byte & 0x1F) << 6;  /* get 5 bits */
2028				if (((byte = *source++) >> 6) != 2)
2029					return (EINVAL);
2030				break;
2031
2032			case 0xe: /* triple-byte sequence (1110) */
2033				ch = (byte & 0x0F) << 6;  /* get 4 bits */
2034				if (((byte = *source++) >> 6) != 2)
2035					return (EINVAL);
2036				ch += (byte & 0x3F); ch <<= 6;  /* get 6 bits */
2037				if (((byte = *source++) >> 6) != 2)
2038					return (EINVAL);
2039				break;
2040
2041			default:
2042				return (EINVAL);  /* malformed sequence */
2043			}
2044
2045			ch += (byte & 0x3F);  /* get last 6 bits */
2046
2047			if (target >= targetEnd)
2048				return (ENOBUFS);
2049
2050			*target++ = SWAP_BE16 (ch);
2051		}
2052	}
2053
2054	*charcount = target - unibuf;
2055
2056	return (0);
2057}
2058
2059/*
2060 * Derive the encoding hint for the given name.
2061 */
2062static int
2063getencodinghint(unsigned char *name)
2064{
2065        int mib[3];
2066        size_t buflen = sizeof(int);
2067        struct vfsconf vfc;
2068        int hint = 0;
2069
2070        if (getvfsbyname("hfs", &vfc) < 0)
2071		goto error;
2072
2073        mib[0] = CTL_VFS;
2074        mib[1] = vfc.vfc_typenum;
2075        mib[2] = HFS_ENCODINGHINT;
2076
2077	if (sysctl(mib, 3, &hint, &buflen, name, strlen((char *)name) + 1) < 0)
2078 		goto error;
2079	return (hint);
2080error:
2081	hint = GetDefaultEncoding();
2082	return (hint);
2083}
2084
2085
2086/* Generate Volume UUID - similar to code existing in hfs_util */
2087void GenerateVolumeUUID(VolumeUUID *newVolumeID) {
2088	SHA_CTX context;
2089	char randomInputBuffer[26];
2090	unsigned char digest[20];
2091	time_t now;
2092	clock_t uptime;
2093	int mib[2];
2094	int sysdata;
2095	char sysctlstring[128];
2096	size_t datalen;
2097	double sysloadavg[3];
2098	struct vmtotal sysvmtotal;
2099
2100	do {
2101		/* Initialize the SHA-1 context for processing: */
2102		SHA1_Init(&context);
2103
2104		/* Now process successive bits of "random" input to seed the process: */
2105
2106		/* The current system's uptime: */
2107		uptime = clock();
2108		SHA1_Update(&context, &uptime, sizeof(uptime));
2109
2110		/* The kernel's boot time: */
2111		mib[0] = CTL_KERN;
2112		mib[1] = KERN_BOOTTIME;
2113		datalen = sizeof(sysdata);
2114		sysctl(mib, 2, &sysdata, &datalen, NULL, 0);
2115		SHA1_Update(&context, &sysdata, datalen);
2116
2117		/* The system's host id: */
2118		mib[0] = CTL_KERN;
2119		mib[1] = KERN_HOSTID;
2120		datalen = sizeof(sysdata);
2121		sysctl(mib, 2, &sysdata, &datalen, NULL, 0);
2122		SHA1_Update(&context, &sysdata, datalen);
2123
2124		/* The system's host name: */
2125		mib[0] = CTL_KERN;
2126		mib[1] = KERN_HOSTNAME;
2127		datalen = sizeof(sysctlstring);
2128		sysctl(mib, 2, sysctlstring, &datalen, NULL, 0);
2129		SHA1_Update(&context, sysctlstring, datalen);
2130
2131		/* The running kernel's OS release string: */
2132		mib[0] = CTL_KERN;
2133		mib[1] = KERN_OSRELEASE;
2134		datalen = sizeof(sysctlstring);
2135		sysctl(mib, 2, sysctlstring, &datalen, NULL, 0);
2136		SHA1_Update(&context, sysctlstring, datalen);
2137
2138		/* The running kernel's version string: */
2139		mib[0] = CTL_KERN;
2140		mib[1] = KERN_VERSION;
2141		datalen = sizeof(sysctlstring);
2142		sysctl(mib, 2, sysctlstring, &datalen, NULL, 0);
2143		SHA1_Update(&context, sysctlstring, datalen);
2144
2145		/* The system's load average: */
2146		datalen = sizeof(sysloadavg);
2147		getloadavg(sysloadavg, 3);
2148		SHA1_Update(&context, &sysloadavg, datalen);
2149
2150		/* The system's VM statistics: */
2151		mib[0] = CTL_VM;
2152		mib[1] = VM_METER;
2153		datalen = sizeof(sysvmtotal);
2154		sysctl(mib, 2, &sysvmtotal, &datalen, NULL, 0);
2155		SHA1_Update(&context, &sysvmtotal, datalen);
2156
2157		/* The current GMT (26 ASCII characters): */
2158		time(&now);
2159		strncpy(randomInputBuffer, asctime(gmtime(&now)), 26);	/* "Mon Mar 27 13:46:26 2000" */
2160		SHA1_Update(&context, randomInputBuffer, 26);
2161
2162		/* Pad the accumulated input and extract the final digest hash: */
2163		SHA1_Final(digest, &context);
2164
2165		memcpy(newVolumeID, digest, sizeof(*newVolumeID));
2166	} while ((newVolumeID->v.high == 0) || (newVolumeID->v.low == 0));
2167}
2168
2169
2170