2 * Copyright (c) 1999-2015 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
38 #include <sys/ioctl.h>
39 #include <sys/mount.h>
40 #include <sys/param.h>
43 #include <IOKit/storage/IOMediaBSDClient.h>
45 #include <hfs/hfs_format.h>
46 #include "newfs_hfs.h"
56 #define ACCESSMASK (0777)
59 * The maximum HFS volume size is calculated thusly:
61 * The maximum allocation block size (which must be a power of 2 value),
62 * is 2GB, or 2^31 bytes
64 * The maximum number of allocation blocks is 2^32 -1.
66 * Multiplying that out yields 2GB * ( 4GB - 1 ) == 2GB*4GB - 2GB.
67 * More explicitly, 8 exabytes - 2 gigabytes,
68 * or 0x7FFFFFFF80000000 bytes. That gives us our value below.
71 #define MAXHFSVOLSIZE (0x7FFFFFFF80000000ULL)
73 #define ROUNDUP(x,y) (((x)+(y)-1)/(y)*(y))
75 static void getnodeopts
__P((char* optlist
));
76 static void getinitialopts
__P((char* optlist
));
77 static void getclumpopts
__P((char* optlist
));
79 static void getstartopts
__P((char *optlist
));
80 static void getextsopts
__P((char* optlist
));
82 static gid_t a_gid
__P((char *));
83 static uid_t a_uid
__P((char *));
84 static mode_t a_mask
__P((char *));
85 static int hfs_newfs
__P((char *device
));
86 static void validate_hfsplus_block_size
__P((UInt64 sectorCount
, UInt32 sectorSize
));
87 static void hfsplus_params
__P((const DriveInfo
* dip
, hfsparams_t
*defaults
));
88 static UInt32 initialsizecalc
__P((UInt32 initialblocks
));
89 static UInt32 clumpsizecalc
__P((UInt32 clumpblocks
));
90 static UInt32 CalcHFSPlusBTreeClumpSize
__P((UInt32 blockSize
, UInt32 nodeSize
, UInt64 sectors
, int fileID
));
91 static void usage
__P((void));
92 static int get_high_bit (u_int64_t bitstring
);
93 static int bad_disk_size (u_int64_t numsectors
, u_int64_t sectorsize
);
98 char *gVolumeName
= kDefaultVolumeNameStr
;
99 char rawdevice
[MAXPATHLEN
];
100 char blkdevice
[MAXPATHLEN
];
101 uint32_t gBlockSize
= 0;
102 UInt32 gNextCNID
= kHFSFirstUserCatalogNodeID
;
106 int gNoCreate
= FALSE
;
107 int gUserCatNodeSize
= FALSE
;
108 int gCaseSensitive
= FALSE
;
109 int gUserAttrSize
= FALSE
;
110 int gUserAttrInitialSize
= FALSE
;
111 int gUserCatInitialSize
= FALSE
;
112 int gUserExtInitialSize
= FALSE
;
113 int gContentProtect
= FALSE
;
115 static UInt32 attrExtCount
= 1, blkallocExtCount
= 1, catExtCount
= 1, extExtCount
= 1;
116 static UInt32 attrExtStart
= 0, blkallocExtStart
= 0, catExtStart
= 0, extExtStart
= 0;
117 static UInt32 jibStart
= 0, jnlStart
= 0, allocStart
= 0;
120 uint16_t gProtectLevel
= 0;
123 #define JOURNAL_DEFAULT_SIZE (8*1024*1024)
124 int gJournaled
= FALSE
;
125 char *gJournalDevice
= NULL
;
126 UInt64 gJournalSize
= 0;
128 uid_t gUserID
= (uid_t
)NOVAL
;
129 gid_t gGroupID
= (gid_t
)NOVAL
;
130 mode_t gModeMask
= (mode_t
)NOVAL
;
132 /* Starting allocation block number for the file system,
133 * all btrees, including journal will be laid down at this
134 * alloation block offset.
136 UInt32 gFSStartBlock
= 0;
138 UInt64 gPartitionSize
= 0;
140 UInt32 catnodesiz
= 8192;
141 UInt32 extnodesiz
= 4096;
142 UInt32 atrnodesiz
= 8192;
144 UInt32 catinitialblks
= 0;
145 UInt32 extinitialblks
= 0;
146 UInt32 atrinitialblks
= 0;
148 UInt32 catclumpblks
= 0;
149 UInt32 extclumpblks
= 0;
150 UInt32 atrclumpblks
= 0;
151 UInt32 bmclumpblks
= 0;
152 UInt32 rsrclumpblks
= 0;
153 UInt32 datclumpblks
= 0;
154 uint32_t hfsgrowblks
= 0; /* maximum growable size of wrapper */
163 num
= strtoull(str
, &ptr
, 0);
166 char scale
= tolower(*ptr
);
209 if ((progname
= strrchr(*argv
, '/')))
214 // No semicolon at end of line deliberately!
216 static const char *options
= "G:J:D:M:N:PU:hsb:c:i:I:n:v:"
222 while ((ch
= getopt(argc
, argv
, options
)) != -1)
225 gGroupID
= a_gid(optarg
);
230 if (isdigit(optarg
[0])) {
231 gJournalSize
= get_num(optarg
);
232 if (gJournalSize
< 512*1024) {
233 printf("%s: journal size %lldk too small. Reset to %dk.\n",
234 progname
, gJournalSize
/1024, JOURNAL_DEFAULT_SIZE
/1024);
235 gJournalSize
= JOURNAL_DEFAULT_SIZE
;
238 /* back up because there was no size argument */
244 gJournalDevice
= (char *)optarg
;
249 if (isdigit(optarg
[0])) {
250 gPartitionSize
= get_num(optarg
);
252 /* back up because there was no size argument */
258 gContentProtect
= TRUE
;
263 if (isdigit (optarg
[0])) {
264 uint64_t level
= get_num (optarg
);
265 gProtectLevel
= (uint16_t) level
;
268 /* back up because no level was provided */
275 gModeMask
= a_mask(optarg
);
279 gUserID
= a_uid(optarg
);
284 getstartopts(optarg
);
295 UInt64 tempBlockSize
;
297 tempBlockSize
= get_num(optarg
);
298 if (tempBlockSize
< HFSMINBSIZE
)
299 fatal("%s: bad allocation block size (too small)", optarg
);
300 if (tempBlockSize
> HFSMAXBSIZE
)
301 fatal("%s: bad allocation block size (too large)", optarg
);
302 gBlockSize
= (uint32_t)tempBlockSize
;
307 getclumpopts(optarg
);
311 gNextCNID
= atoi(optarg
);
313 * make sure its at least kHFSFirstUserCatalogNodeID
315 if (gNextCNID
< kHFSFirstUserCatalogNodeID
)
316 fatal("%s: starting catalog node id too small (must be > 15)", optarg
);
320 getinitialopts(optarg
);
328 gCaseSensitive
= TRUE
;
332 if ((gVolumeName
= strdup(optarg
)) == NULL
) {
333 fatal("Could not copy volume name %s", optarg
);
346 if ((gProtectLevel
) && !(gContentProtect
)) {
347 fatal ("content protection must be specified to set a protection level");
351 if (gPartitionSize
!= 0) {
353 * If we are given -N, a size, and a device, that's a usage error.
358 rawdevice
[0] = blkdevice
[0] = 0;
364 cp
= strrchr(special
, '/');
369 (void) snprintf(rawdevice
, sizeof(rawdevice
), "%sr%s", _PATH_DEV
, special
);
370 (void) snprintf(blkdevice
, sizeof(blkdevice
), "%s%s", _PATH_DEV
, special
);
373 if (gPartitionSize
== 0) {
375 * Check if target device is aready mounted
377 n
= getmntinfo(&mp
, MNT_NOWAIT
);
379 fatal("%s: getmntinfo: %s", blkdevice
, strerror(errno
));
382 if (strcmp(blkdevice
, mp
->f_mntfromname
) == 0)
383 fatal("%s is mounted on %s", blkdevice
, mp
->f_mntonname
);
388 if (hfs_newfs(rawdevice
) < 0) {
389 err(1, "cannot create filesystem on %s", rawdevice
);
396 static void getnodeopts(char* optlist
)
398 char *strp
= optlist
;
403 while((ndarg
= strsep(&strp
, ",")) != NULL
&& *ndarg
!= '\0') {
405 p
= strchr(ndarg
, '=');
413 if (ndsize
< 4096 || ndsize
> 32768 || (ndsize
& (ndsize
-1)) != 0)
414 fatal("%s: invalid catalog b-tree node size", ndarg
);
416 gUserCatNodeSize
= TRUE
;
420 if (ndsize
< 1024 || ndsize
> 32768 || (ndsize
& (ndsize
-1)) != 0)
421 fatal("%s: invalid extents b-tree node size", ndarg
);
426 if (ndsize
< 4096 || ndsize
> 32768 || (ndsize
& (ndsize
-1)) != 0)
427 fatal("%s: invalid atrribute b-tree node size", ndarg
);
438 static void getinitialopts(char* optlist
)
440 char *strp
= optlist
;
445 while((ndarg
= strsep(&strp
, ",")) != NULL
&& *ndarg
!= '\0') {
447 p
= strchr(ndarg
, '=');
451 inblocks
= atoi(p
+1);
455 atrinitialblks
= inblocks
;
456 gUserAttrInitialSize
= TRUE
;
457 gUserAttrSize
= TRUE
;
460 catinitialblks
= inblocks
;
461 gUserCatInitialSize
= TRUE
;
464 extinitialblks
= inblocks
;
465 gUserExtInitialSize
= TRUE
;
475 static void getclumpopts(char* optlist
)
477 char *strp
= optlist
;
482 while((ndarg
= strsep(&strp
, ",")) != NULL
&& *ndarg
!= '\0') {
484 p
= strchr(ndarg
, '=');
488 clpblocks
= atoi(p
+1);
492 atrclumpblks
= clpblocks
;
493 if (!gUserAttrInitialSize
) {
494 atrinitialblks
= atrclumpblks
;
496 gUserAttrSize
= TRUE
;
499 bmclumpblks
= clpblocks
;
502 catclumpblks
= clpblocks
;
503 if (!gUserCatInitialSize
) {
504 catinitialblks
= catclumpblks
;
508 datclumpblks
= clpblocks
;
511 extclumpblks
= clpblocks
;
512 if (!gUserExtInitialSize
) {
513 extinitialblks
= extclumpblks
;
517 rsrclumpblks
= clpblocks
;
527 static void getextsopts(char* optlist
)
529 char *strp
= optlist
;
534 while((ndarg
= strsep(&strp
, ",")) != NULL
&& *ndarg
!= '\0') {
536 p
= strchr(ndarg
, '=');
544 attrExtCount
= numexts
;
547 blkallocExtCount
= numexts
;
550 catExtCount
= numexts
;
553 extExtCount
= numexts
;
561 static void getstartopts(char* optlist
)
566 unsigned long startat
= 0;
570 startat
= strtoul(optlist
, &strp
, 0);
571 if (startat
== ULONG_MAX
&& errno
!= 0) {
572 err(1, "invalid allocation start block string %s", optlist
);
574 if (startat
> UINT_MAX
) {
575 errx(1, "Allocation block %lu larger than max", startat
);
577 if (strp
&& *strp
== ',')
580 gFSStartBlock
= (UInt32
)startat
;
582 while((ndarg
= strsep(&strp
, ",")) != NULL
&& *ndarg
!= '\0') {
584 startat
= strtoul(optlist
, NULL
, 0);
585 p
= strchr(ndarg
, '=');
590 if (pos
< 0 || pos
> UINT32_MAX
) {
591 errx(1, "pos=%d is invalid", pos
);
600 blkallocExtStart
= upos
;
625 static a_gid(char *s
)
631 if ((gr
= getgrnam(s
)) != NULL
)
634 for (gname
= s
; *s
&& isdigit(*s
); ++s
);
638 errx(1, "unknown group id: %s", gname
);
650 if ((pw
= getpwnam(s
)) != NULL
)
653 for (uname
= s
; *s
&& isdigit(*s
); ++s
);
657 errx(1, "unknown user id: %s", uname
);
671 if (*s
>= '0' && *s
<= '7') {
673 rv
= strtol(s
, &ep
, 8);
675 if (!done
|| rv
< 0 || rv
> INT_MAX
|| *ep
)
676 errx(1, "invalid access mask: %s", s
);
681 * Check to see if the volume is too big.
684 * 0 if it is appropriately sized.
685 * 1 if HFS+ cannot be formatted onto the disk.
688 static int bad_disk_size (u_int64_t numsectors
, u_int64_t sectorsize
) {
690 u_int32_t maxSectorBits
= 0;
691 u_int32_t maxSectorSizeBits
= 0;
692 u_int32_t maxBits
= 0;
696 * The essential problem here is that we cannot simply multiply the sector size by the
697 * number of sectors because the product could overflow a 64 bit integer. We do a cursory
698 * check and then a longer check once we know the product will not overflow.
701 maxSectorBits
= get_high_bit (numsectors
);
702 maxSectorSizeBits
= get_high_bit (sectorsize
);
705 * We get the number of bits to represent the number of sectors and the sector size.
706 * Adding the two numbers gives us the number of bits required to represent the product.
707 * If the product is > 63 then it must be too big.
710 maxBits
= maxSectorBits
+ maxSectorSizeBits
;
715 /* Well, now we know that the two values won't overflow. Time to multiply */
716 bytes
= numsectors
* sectorsize
;
718 if (bytes
> MAXHFSVOLSIZE
) {
723 /* Otherwise, it looks good */
729 * The allocation block size must be defined as a power of 2 value, with a floor of
730 * 512 bytes. However, we never default to anything less than 4096 bytes, so that
731 * gives us 20 block size values from 4kb -> 2GB block size.
733 * See inline comments for how this table is used to determine the minimum fs size that
734 * will use a specified allocation block size.
736 * The growth boundary is used to figure out if we need a bigger block size than the
737 * 4 KB default. We get the index of the highest bit set in the FS size, then subtract the
738 * growth boundary to index into the block allocation size array.
740 * Note that 8K appears twice in table since we want to use it for the range 2 TB < 8 TB FS size.
741 * This means that when the 2TB bit or the 4TB bit is the high bit set, we prefer the 8K block size.
743 #define NUM_ALLOC_BLOCKSIZES 21
744 #define GROWTH_BOUNDARY 41
746 u_int64_t alloc_blocksize
[NUM_ALLOC_BLOCKSIZES
] = {
747 /* Block Size*/ /* Min Dflt FS Size */ /* Max FS Size */
748 4096, /* 0 bytes */ /* 16 TB */
749 8192, /* 2 TB */ /* 32 TB */ /* Note that 8K appears twice in table ! */
750 8192, /* 4 TB */ /* 32 TB */ /* Note that 8K appears twice in table ! */
751 16384, /* 8 TB */ /* 64 TB */
752 32768, /* 16 TB */ /* 128 TB */
753 65536, /* 32 TB */ /* 256 TB */
754 131072, /* 64 TB */ /* 512 TB */
755 262144, /* 128 TB */ /* 1 PB */
756 524288, /* 256 TB */ /* 2 PB */
757 1048576, /* 512 TB */ /* 4 PB */
758 2097152, /* 1 PB */ /* 8 PB */
759 4194304, /* 2 PB */ /* 16 PB */
760 8388608, /* 4 PB */ /* 32 PB */
761 16777216, /* 8 PB */ /* 64 PB */
762 33554432, /* 16 PB */ /* 128 PB */
763 67108864, /* 32 PB */ /* 256 PB */
764 134217728, /* 64 PB */ /* 512 PB */
765 268435456, /* 128 PB */ /* 1 EB */
766 536870912, /* 256 PB */ /* 2 EB */
767 1073741824, /* 512 PB */ /* 4 EB */
768 2147483648ULL /* 1 EB */ /* 8 EB */
771 static int get_high_bit (u_int64_t bitstring
) {
772 u_int64_t bits
= bitstring
;
783 * Validate the HFS Plus allocation block size in gBlockSize. If none was
784 * specified, then calculate a suitable default.
786 * Modifies the global variable gBlockSize.
788 static void validate_hfsplus_block_size(UInt64 sectorCount
, UInt32 sectorSize
)
790 if (gBlockSize
== 0) {
792 /* Start by calculating the fs size */
793 u_int64_t fs_size
= sectorCount
* sectorSize
;
796 * Determine the default based on a sliding scale. The maximum number of
797 * allocation blocks is always 4294967295 == (32 bits worth). At 1 bit per
798 * allocation block, that yields 512 MB of bitmap no matter what size we use
799 * for the allocation block.
801 * The general default policy is to allow the filesystem to grow up to 8x the
802 * current maximum size. So for a 1.5TB filesystem, an 8x multiplier would be
803 * 12TB. That means we can use the default size of 4096 bytes. The boundary begins
804 * at 2TB, since at that point, we can no longer use the default 4096 block size to
805 * extend the filesystem by 8x. For a 16KB block size, the max is 64 TB, but the 8x
806 * multiplier begins at 8 TB. Thereafter, we increase for every power of 2 that
807 * the current filesystem size grows.
810 gBlockSize
= DFL_BLKSIZE
; /* Prefer the default of 4K */
812 int bit_index
= get_high_bit (fs_size
);
813 bit_index
-= GROWTH_BOUNDARY
;
816 * After subtracting the GROWTH_BOUNDARY to index into the array, we'll
817 * use the values in the static array if we have a non-negative index.
818 * That means that if the filesystem is >= 1 TB, then we'll use the index
819 * value. At 2TB, we grow to the 8K block size.
821 if ((bit_index
>= 0) && (bit_index
< 22)) {
822 gBlockSize
= (uint32_t)alloc_blocksize
[bit_index
];
825 if (bit_index
>= 22) {
826 fatal("Error: Disk Device is too big (%llu sectors, %d bytes per sector", sectorCount
, sectorSize
);
830 /* Make sure a user-specified block size is reasonable */
831 if ((gBlockSize
& (gBlockSize
-1)) != 0) {
832 fatal("%s: bad HFS Plus allocation block size (must be a power of two)", optarg
);
835 if ((sectorCount
/ (gBlockSize
/ sectorSize
)) > 0xFFFFFFFF) {
836 fatal("%s: block size is too small for %lld sectors", optarg
, gBlockSize
, sectorCount
);
839 if (gBlockSize
< HFSOPTIMALBLKSIZE
) {
840 warnx("Warning: %u is a non-optimal block size (4096 would be a better choice)", (unsigned int)gBlockSize
);
845 u_int64_t fs_size
= sectorCount
* sectorSize
;
846 u_int32_t totalBlocks
= (u_int32_t
)(fs_size
/gBlockSize
);
848 if (gFSStartBlock
>= totalBlocks
) {
849 warnx("Warning: %u is invalid file system start allocation block number, must be less than total allocation blocks (%u)", (unsigned int)gFSStartBlock
, (unsigned int)totalBlocks
);
850 warnx("Warning: Resetting file system start block to zero");
859 hfs_newfs(char *device
)
862 DriveInfo dip
= { 0 };
865 hfsparams_t defaults
= {0};
866 UInt64 maxPhysPerIO
= 0;
868 if (gPartitionSize
) {
869 dip
.sectorSize
= kBytesPerSector
;
870 dip
.physTotalSectors
= dip
.totalSectors
= gPartitionSize
/ kBytesPerSector
;
871 dip
.physSectorSize
= kBytesPerSector
; /* 512-byte sectors */
875 fso
= open( device
, O_RDONLY
| O_NDELAY
, 0 );
877 fso
= open( device
, O_RDWR
| O_NDELAY
, 0 );
884 fcntl(fso
, F_NOCACHE
, 1);
887 fatal("%s: %s", device
, strerror(errno
));
889 if (fstat( fso
, &stbuf
) < 0)
890 fatal("%s: %s", device
, strerror(errno
));
892 if (ioctl(fso
, DKIOCGETBLOCKSIZE
, &dip
.physSectorSize
) < 0)
893 fatal("%s: %s", device
, strerror(errno
));
895 if ((dip
.physSectorSize
% kBytesPerSector
) != 0)
896 fatal("%d is an unsupported sector size\n", dip
.physSectorSize
);
898 if (ioctl(fso
, DKIOCGETBLOCKCOUNT
, &dip
.physTotalSectors
) < 0)
899 fatal("%s: %s", device
, strerror(errno
));
903 dip
.physSectorsPerIO
= (1024 * 1024) / dip
.physSectorSize
; /* use 1M as default */
905 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBLOCKCOUNTREAD
, &maxPhysPerIO
) < 0)
906 fatal("%s: %s", device
, strerror(errno
));
909 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
);
911 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBLOCKCOUNTWRITE
, &maxPhysPerIO
) < 0)
912 fatal("%s: %s", device
, strerror(errno
));
915 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
);
917 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBYTECOUNTREAD
, &maxPhysPerIO
) < 0)
918 fatal("%s: %s", device
, strerror(errno
));
921 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
/ dip
.physSectorSize
);
923 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBYTECOUNTWRITE
, &maxPhysPerIO
) < 0)
924 fatal("%s: %s", device
, strerror(errno
));
927 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
/ dip
.physSectorSize
);
929 dip
.sectorSize
= kBytesPerSector
;
930 dip
.totalSectors
= dip
.physTotalSectors
* dip
.physSectorSize
/ dip
.sectorSize
;
932 dip
.sectorOffset
= 0;
935 /* Check to see if the disk is too big */
936 u_int64_t secsize
= (u_int64_t
) dip
.sectorSize
;
937 if (bad_disk_size(dip
.totalSectors
, secsize
)) {
938 fatal("%s: partition is too big (maximum is %llu KB)", device
, MAXHFSVOLSIZE
/1024);
942 * If we're going to make an HFS Plus disk (with or without a wrapper), validate the
943 * HFS Plus allocation block size. This will also calculate a default allocation
944 * block size if none (or zero) was specified.
946 validate_hfsplus_block_size(dip
.totalSectors
, dip
.sectorSize
);
948 /* Make an HFS Plus disk */
950 if ((dip
.totalSectors
* dip
.sectorSize
) < kMinHFSPlusVolumeSize
)
951 fatal("%s: partition is too small (minimum is %d KB)", device
, kMinHFSPlusVolumeSize
/1024);
953 hfsplus_params(&dip
, &defaults
);
954 if (gNoCreate
== 0) {
955 retval
= make_hfsplus(&dip
, &defaults
);
957 printf("Initialized %s as a ", device
);
958 if (dip
.totalSectors
> 2048ULL*1024*1024)
960 (long)((dip
.totalSectors
+ (1024ULL*1024*1024))/(2048ULL*1024*1024)));
961 else if (dip
.totalSectors
> 2048*1024)
963 (long)((dip
.totalSectors
+ (1024*1024))/(2048*1024)));
964 else if (dip
.totalSectors
> 2048)
966 (long)((dip
.totalSectors
+ 1024)/2048));
969 (long)((dip
.totalSectors
+ 1)/2));
971 if (gCaseSensitive
) {
972 printf(" case-sensitive");
975 printf(" case-insensitive");
978 printf(" HFS Plus volume with a %uk journal\n",
979 (u_int32_t
)defaults
.journalSize
/1024);
981 printf(" HFS Plus volume\n");
986 fatal("%s: %s", device
, strerror(errno
));
996 typedef struct block_info {
999 _blk_info bi; //64 bit
1000 struct buf *bp; //64 bit on K64, 32 bit on K32
1002 }__attribute__((__packed__)) block_info;
1004 total size == 16 bytes
1007 #define BLOCK_INFO_SIZE 16
1009 static void hfsplus_params (const DriveInfo
* dip
, hfsparams_t
*defaults
)
1011 UInt64 sectorCount
= dip
->totalSectors
;
1012 UInt32 sectorSize
= dip
->sectorSize
;
1013 uint32_t totalBlocks
;
1014 UInt32 minClumpSize
;
1017 UInt32 oddBitmapBytes
;
1019 defaults
->flags
= 0;
1020 defaults
->blockSize
= gBlockSize
;
1021 defaults
->fsStartBlock
= gFSStartBlock
;
1022 defaults
->nextFreeFileID
= gNextCNID
;
1023 // Value will be bigger than UIN32_MAX in 2040
1024 defaults
->createDate
= (uint32_t)(createtime
+ MAC_GMT_FACTOR
); /* Mac OS GMT time */
1025 defaults
->hfsAlignment
= 0;
1026 defaults
->journaledHFS
= gJournaled
;
1027 defaults
->journalDevice
= gJournalDevice
;
1031 * Always set kUseAccessPerms now; this also
1032 * means we have to always have an owner, group,
1035 defaults
->owner
= (gUserID
== (uid_t
)NOVAL
) ? geteuid() : gUserID
;
1036 defaults
->group
= (gGroupID
== (gid_t
)NOVAL
) ? getegid() : gGroupID
;
1037 defaults
->mask
= (gModeMask
== (mode_t
)NOVAL
) ? UMASK
: (gModeMask
& ACCESSMASK
);
1038 defaults
->flags
|= kUseAccessPerms
;
1041 * We want at least 8 megs of journal for each 100 gigs of
1042 * disk space. We cap the size at 512 megs (64x default), unless
1043 * the allocation block size is larger, in which case we use one
1046 * Only scale if it's the default, otherwise just take what
1047 * the user specified, with the caveat below.
1050 uint32_t min_size
= 0;
1053 * Check to ensure the journal size is not too small relative to the
1054 * sector size of the device. This is the check in the kernel:
1055 if (tr->blhdr && (tr->blhdr->max_blocks <= 0 ||
1056 tr->blhdr->max_blocks > (tr->jnl->jhdr->size/tr->jnl->jhdr->jhdr_size)))
1057 * We assume that there will be a block header and that there will be a
1058 * non-negative max_blocks value.
1060 * The 2nd check is the problematic one. We cannot have a journal that's too
1061 * small relative to the sector size. max_blocks == (blhdr_size / 16). However,
1062 * this only matters where the current block header size is smaller than the current
1063 * sector size. So, assume that the blhdr_size == sector size for now. We look
1064 * at the condition above to get the rest of the equation -- (journal size / sector size).
1065 * Then, it's simple algebra to figure out what the new minimum journal size
1068 * (sector_size / 16) > (journal_size / sector_size)
1069 * (sector_size / 16) = (journal_size / sector_size)
1070 * (sector_size / 16) * sector_size = (journal_size / sector_size) * sector_size
1071 * (sector_size / 16) * sector_size = journal_size
1073 * This becomes our new _floor_ for the journal_size.
1076 if (dip
->physSectorSize
!= 0) {
1077 min_size
= dip
->physSectorSize
* (dip
->physSectorSize
/ BLOCK_INFO_SIZE
);
1080 if (gJournalSize
!= 0) {
1082 /* Was the supplied journal size at least the minimum computed above? */
1083 if (gJournalSize
< min_size
) {
1084 printf("%s: journal size %lldk too small. Reset to %dk.\n",
1085 progname
, gJournalSize
/1024, JOURNAL_DEFAULT_SIZE
/1024);
1089 /* defaults->journalSize will get reset below if it is 0 */
1090 defaults
->journalSize
= (uint32_t)gJournalSize
;
1093 if ((gJournalSize
== 0) || (defaults
->journalSize
== 0)) {
1095 uint32_t target_size
;
1096 /* Figure out how many 100's of GBs this filesystem represents */
1097 jscale
= (sectorCount
* sectorSize
) / ((UInt64
)100 * 1024 * 1024 * 1024);
1102 target_size
= JOURNAL_DEFAULT_SIZE
* (jscale
+ 1);
1103 /* Is the target size at least the min_size computed above? */
1104 if (target_size
< min_size
) {
1105 target_size
= min_size
;
1108 defaults
->journalSize
= target_size
;
1113 // volumes that are 128 megs or less in size have such
1114 // a small bitmap (one 4k-block) and inherhently such
1115 // a small btree that we can get by with a much smaller
1116 // journal. even in a worst case scenario of a catalog
1117 // filled with very long korean file names we should
1118 // never touch more than 256k of meta-data for a single
1119 // transaction. therefore we'll make the journal 512k,
1120 // or as small as possible, given the sector size,
1121 // which is safe and doesn't waste much space.
1122 // However, be careful not to let the journal size drop BELOW
1123 // 512k, since the min_size computations can create an artificially
1124 // tiny journal (16k or so) with 512byte sectors.
1126 if (sectorCount
* sectorSize
< 128*1024*1024) {
1127 /* This is a small (<128MB) FS */
1128 uint32_t small_default
= (512 * 1024);
1130 if (small_default
<= min_size
) {
1132 * If 512k is too small given the sector size,
1133 * then use the larger sector size
1135 defaults
->journalSize
= min_size
;
1138 /* 512k was bigger than the min size; we can use it */
1139 defaults
->journalSize
= small_default
;
1144 if (defaults
->journalSize
> 512 * 1024 * 1024) {
1145 defaults
->journalSize
= 512 * 1024 * 1024;
1148 if (defaults
->journalSize
< defaults
->blockSize
) {
1149 defaults
->journalSize
= defaults
->blockSize
;
1153 defaults
->volumeName
= (unsigned char*)gVolumeName
;
1155 if (rsrclumpblks
== 0) {
1156 if (gBlockSize
> DFL_BLKSIZE
)
1157 defaults
->rsrcClumpSize
= ROUNDUP(kHFSPlusRsrcClumpFactor
* DFL_BLKSIZE
, gBlockSize
);
1159 defaults
->rsrcClumpSize
= kHFSPlusRsrcClumpFactor
* gBlockSize
;
1161 defaults
->rsrcClumpSize
= clumpsizecalc(rsrclumpblks
);
1163 if (datclumpblks
== 0) {
1164 if (gBlockSize
> DFL_BLKSIZE
)
1165 defaults
->dataClumpSize
= ROUNDUP(kHFSPlusDataClumpFactor
* DFL_BLKSIZE
, gBlockSize
);
1167 defaults
->dataClumpSize
= kHFSPlusDataClumpFactor
* gBlockSize
;
1169 defaults
->dataClumpSize
= clumpsizecalc(datclumpblks
);
1172 * The default b-tree node size is 8K. However, if the
1173 * volume is small (< 1 GB) we use 4K instead.
1175 if (!gUserCatNodeSize
) {
1176 if ((gBlockSize
< HFSOPTIMALBLKSIZE
) ||
1177 ((UInt64
)(sectorCount
* sectorSize
) < (UInt64
)0x40000000))
1181 if (catclumpblks
== 0) {
1182 clumpSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, catnodesiz
, sectorCount
, kHFSCatalogFileID
);
1185 clumpSize
= clumpsizecalc(catclumpblks
);
1186 if (clumpSize
% catnodesiz
!= 0)
1187 fatal("c=%ld: clump size is not a multiple of node size\n", clumpSize
/gBlockSize
);
1189 if (catinitialblks
== 0) {
1190 initialSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, catnodesiz
, sectorCount
, kHFSCatalogFileID
);
1193 initialSize
= initialsizecalc(catinitialblks
);
1194 if (initialSize
% catnodesiz
!= 0)
1195 fatal("c=%ld: initial size is not a multiple of node size\n", initialSize
/gBlockSize
);
1197 if (initialSize
< clumpSize
) {
1198 fatal("c=%ld: initial size is less than clump size\n", initialSize
/gBlockSize
);
1200 defaults
->catalogClumpSize
= clumpSize
;
1201 defaults
->catalogInitialSize
= initialSize
;
1202 defaults
->catalogNodeSize
= catnodesiz
;
1203 defaults
->catalogExtsCount
= catExtCount
;
1204 defaults
->catalogStartBlock
= catExtStart
;
1206 if (gBlockSize
< 4096 && gBlockSize
< catnodesiz
)
1207 warnx("Warning: block size %u is less than catalog b-tree node size %u", (unsigned int)gBlockSize
, (unsigned int)catnodesiz
);
1209 if (extclumpblks
== 0) {
1210 clumpSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, extnodesiz
, sectorCount
, kHFSExtentsFileID
);
1213 clumpSize
= clumpsizecalc(extclumpblks
);
1214 if (clumpSize
% extnodesiz
!= 0)
1215 fatal("e=%ld: clump size is not a multiple of node size\n", clumpSize
/gBlockSize
);
1217 if (extinitialblks
== 0) {
1218 initialSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, extnodesiz
, sectorCount
, kHFSExtentsFileID
);
1221 initialSize
= initialsizecalc(extinitialblks
);
1222 if (initialSize
% extnodesiz
!= 0)
1223 fatal("e=%ld: initial size is not a multiple of node size\n", initialSize
/gBlockSize
);
1225 if (initialSize
< clumpSize
) {
1226 fatal("e=%ld: initial size is less than clump size\n", initialSize
/gBlockSize
);
1228 defaults
->extentsClumpSize
= clumpSize
;
1229 defaults
->extentsInitialSize
= initialSize
;
1230 defaults
->extentsNodeSize
= extnodesiz
;
1231 defaults
->extentsExtsCount
= extExtCount
;
1232 defaults
->extentsStartBlock
= extExtStart
;
1234 if (gBlockSize
< extnodesiz
)
1235 warnx("Warning: block size %u is less than extents b-tree node size %u", (unsigned int)gBlockSize
, (unsigned int)extnodesiz
);
1236 if (defaults
->extentsExtsCount
> 8) {
1237 warnx("Warning: extents overflow extent requested count %u exceeds maximum 8, capping at 8\n", defaults
->extentsExtsCount
);
1238 defaults
->extentsExtsCount
= 8;
1241 if (atrclumpblks
== 0) {
1242 clumpSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, atrnodesiz
, sectorCount
, kHFSAttributesFileID
);
1245 clumpSize
= clumpsizecalc(atrclumpblks
);
1246 if (clumpSize
% atrnodesiz
!= 0)
1247 fatal("a=%ld: clump size is not a multiple of node size\n", clumpSize
/gBlockSize
);
1249 if (atrinitialblks
== 0) {
1250 if (gUserAttrSize
) {
1254 initialSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, atrnodesiz
, sectorCount
, kHFSAttributesFileID
);
1258 initialSize
= initialsizecalc(atrinitialblks
);
1259 if (initialSize
% atrnodesiz
!= 0)
1260 fatal("a=%ld: initial size is not a multiple of node size\n", initialSize
/gBlockSize
);
1263 if (initialSize
< clumpSize
) {
1264 fatal("a=%ld: initial size is less than clump size\n", initialSize
/gBlockSize
);
1267 defaults
->attributesClumpSize
= clumpSize
;
1268 defaults
->attributesInitialSize
= initialSize
;
1269 defaults
->attributesNodeSize
= atrnodesiz
;
1270 defaults
->attributesExtsCount
= attrExtCount
;
1271 defaults
->attributesStartBlock
= attrExtStart
;
1274 * Calculate the number of blocks needed for bitmap (rounded up to a multiple of the block size).
1278 * Figure out how many bytes we need for the given totalBlocks
1279 * Note: this minimum value may be too large when it counts the
1280 * space used by the wrapper
1282 totalBlocks
= (uint32_t)(sectorCount
/ (gBlockSize
/ sectorSize
));
1284 minClumpSize
= totalBlocks
>> 3; /* convert bits to bytes by dividing by 8 */
1285 if (totalBlocks
& 7)
1286 ++minClumpSize
; /* round up to whole bytes */
1288 /* Round up to a multiple of blockSize */
1289 if ((oddBitmapBytes
= minClumpSize
% gBlockSize
))
1290 minClumpSize
= minClumpSize
- oddBitmapBytes
+ gBlockSize
;
1292 if (bmclumpblks
== 0) {
1293 clumpSize
= minClumpSize
;
1296 clumpSize
= clumpsizecalc(bmclumpblks
);
1298 if (clumpSize
< minClumpSize
)
1299 fatal("b=%ld: bitmap clump size is too small\n", clumpSize
/gBlockSize
);
1301 defaults
->allocationClumpSize
= clumpSize
;
1302 defaults
->allocationExtsCount
= blkallocExtCount
;
1303 defaults
->allocationStartBlock
= blkallocExtStart
;
1305 defaults
->journalInfoBlock
= jibStart
;
1306 defaults
->journalBlock
= jnlStart
;
1307 defaults
->nextAllocBlock
= allocStart
;
1310 defaults
->flags
|= kMakeCaseSensitive
;
1312 if (gContentProtect
)
1313 defaults
->flags
|= kMakeContentProtect
;
1317 defaults
->protectlevel
= gProtectLevel
;
1321 if (gPartitionSize
== 0)
1322 printf("%llu sectors (%u bytes per sector)\n", dip
->physTotalSectors
, dip
->physSectorSize
);
1323 printf("HFS Plus format parameters:\n");
1324 printf("\tvolume name: \"%s\"\n", gVolumeName
);
1325 printf("\tblock-size: %u\n", defaults
->blockSize
);
1326 printf("\ttotal blocks: %u\n", totalBlocks
);
1328 printf("\tjournal-size: %uk\n", defaults
->journalSize
/1024);
1329 printf("\tfirst free catalog node id: %u\n", defaults
->nextFreeFileID
);
1330 printf("\tcatalog b-tree node size: %u\n", defaults
->catalogNodeSize
);
1331 printf("\tcatalog clump size: %u\n", defaults
->catalogClumpSize
);
1332 printf("\tinitial catalog file size: %u\n", defaults
->catalogInitialSize
);
1333 printf("\textents b-tree node size: %u\n", defaults
->extentsNodeSize
);
1334 printf("\textents clump size: %u\n", defaults
->extentsClumpSize
);
1335 printf("\tinitial extents file size: %u\n", defaults
->extentsInitialSize
);
1336 printf("\tattributes b-tree node size: %u\n", defaults
->attributesNodeSize
);
1337 printf("\tattributes clump size: %u\n", defaults
->attributesClumpSize
);
1338 printf("\tinitial attributes file size: %u\n", defaults
->attributesInitialSize
);
1339 printf("\tinitial allocation file size: %u (%u blocks)\n",
1340 defaults
->allocationClumpSize
, defaults
->allocationClumpSize
/ gBlockSize
);
1341 printf("\tdata fork clump size: %u\n", defaults
->dataClumpSize
);
1342 printf("\tresource fork clump size: %u\n", defaults
->rsrcClumpSize
);
1343 if (defaults
->flags
& kUseAccessPerms
) {
1344 printf("\tuser ID: %d\n", (int)defaults
->owner
);
1345 printf("\tgroup ID: %d\n", (int)defaults
->group
);
1346 printf("\taccess mask: %o\n", (int)defaults
->mask
);
1348 printf("\tfile system start block: %u\n", defaults
->fsStartBlock
);
1354 initialsizecalc(UInt32 initialblocks
)
1358 initialsize
= (UInt64
)initialblocks
* (UInt64
)gBlockSize
;
1360 if (initialsize
& (UInt64
)(0xFFFFFFFF00000000ULL
))
1361 fatal("=%ld: too many blocks for initial size!", initialblocks
);
1363 return ((UInt32
)initialsize
);
1368 clumpsizecalc(UInt32 clumpblocks
)
1372 clumpsize
= (UInt64
)clumpblocks
* (UInt64
)gBlockSize
;
1374 if (clumpsize
& (UInt64
)(0xFFFFFFFF00000000ULL
))
1375 fatal("=%ld: too many blocks for clump size!", clumpblocks
);
1377 return ((UInt32
)clumpsize
);
1381 #define CLUMP_ENTRIES 15
1383 short clumptbl
[CLUMP_ENTRIES
* 3] = {
1385 * Volume Attributes Catalog Extents
1386 * Size Clump (MB) Clump (MB) Clump (MB)
1391 /* 8GB */ 11, 11, 5,
1393 * For volumes 16GB and larger, we want to make sure that a full OS
1394 * install won't require fragmentation of the Catalog or Attributes
1395 * B-trees. We do this by making the clump sizes sufficiently large,
1396 * and by leaving a gap after the B-trees for them to grow into.
1398 * For SnowLeopard 10A298, a FullNetInstall with all packages selected
1400 * Catalog B-tree Header
1404 * (used = 231.55 MB)
1405 * Attributes B-tree Header
1409 * (used = 486.52 MB)
1411 * We also want Time Machine backup volumes to have a sufficiently
1412 * large clump size to reduce fragmentation.
1414 * The series of numbers for Catalog and Attribute form a geometric series.
1415 * For Catalog (16GB to 512GB), each term is 8**(1/5) times the previous
1416 * term. For Attributes (16GB to 512GB), each term is 4**(1/5) times
1417 * the previous term. For 1TB to 16TB, each term is 2**(1/5) times the
1420 /* 16GB */ 64, 32, 5,
1421 /* 32GB */ 84, 49, 6,
1422 /* 64GB */ 111, 74, 7,
1423 /* 128GB */ 147, 111, 8,
1424 /* 256GB */ 194, 169, 9,
1425 /* 512GB */ 256, 256, 11,
1426 /* 1TB */ 294, 294, 14,
1427 /* 2TB */ 338, 338, 16,
1428 /* 4TB */ 388, 388, 20,
1429 /* 8TB */ 446, 446, 25,
1430 /* 16TB */ 512, 512, 32
1434 * CalcHFSPlusBTreeClumpSize
1436 * This routine calculates the file clump size for either
1437 * the catalog file or the extents overflow file.
1440 CalcHFSPlusBTreeClumpSize(UInt32 blockSize
, UInt32 nodeSize
, UInt64 sectors
, int fileID
)
1442 UInt32 mod
= MAX(nodeSize
, blockSize
);
1447 /* Figure out which column of the above table to use for this file. */
1449 case kHFSAttributesFileID
:
1452 case kHFSCatalogFileID
:
1461 * The default clump size is 0.8% of the volume size. And
1462 * it must also be a multiple of the node and block size.
1464 if (sectors
< 0x200000) {
1465 clumpSize
= (UInt32
)(sectors
<< 2); /* 0.8 % */
1466 if (clumpSize
< (8 * nodeSize
))
1467 clumpSize
= 8 * nodeSize
;
1470 * XXX This should scale more smoothly!
1472 /* turn exponent into table index... */
1473 for (i
= 0, sectors
= sectors
>> 22;
1474 sectors
&& (i
< CLUMP_ENTRIES
-1);
1475 ++i
, sectors
= sectors
>> 1);
1477 clumpSize
= clumptbl
[column
+ (i
) * 3] * 1024 * 1024;
1481 * Round the clump size to a multiple of node and block size.
1482 * NOTE: This rounds down.
1488 * Rounding down could have rounded down to 0 if the block size was
1489 * greater than the clump size. If so, just use one block or node.
1501 fatal(const char *fmt
, ...)
1503 fatal(fmt
, va_alist
)
1515 if (fcntl(STDERR_FILENO
, F_GETFL
) < 0) {
1516 openlog(progname
, LOG_CONS
, LOG_DAEMON
);
1517 vsyslog(LOG_ERR
, fmt
, ap
);
1530 fprintf(stderr
, "usage: %s [-N [partition-size]] [hfsplus-options] special-device\n", progname
);
1532 fprintf(stderr
, " options:\n");
1533 fprintf(stderr
, "\t-N do not create file system, just print out parameters\n");
1534 fprintf(stderr
, "\t-s use case-sensitive filenames (default is case-insensitive)\n");
1536 fprintf(stderr
, " where hfsplus-options are:\n");
1537 fprintf(stderr
, "\t-J [journal-size] make this HFS+ volume journaled\n");
1538 fprintf(stderr
, "\t-D journal-dev use 'journal-dev' for an external journal\n");
1539 fprintf(stderr
, "\t-G group-id (for root directory)\n");
1540 fprintf(stderr
, "\t-U user-id (for root directory)\n");
1541 fprintf(stderr
, "\t-M octal access-mask (for root directory)\n");
1542 fprintf(stderr
, "\t-b allocation block size (4096 optimal)\n");
1543 fprintf(stderr
, "\t-c clump size list (comma separated)\n");
1544 fprintf(stderr
, "\t\ta=blocks (attributes file)\n");
1545 fprintf(stderr
, "\t\tb=blocks (bitmap file)\n");
1546 fprintf(stderr
, "\t\tc=blocks (catalog file)\n");
1547 fprintf(stderr
, "\t\td=blocks (user data fork)\n");
1548 fprintf(stderr
, "\t\te=blocks (extents file)\n");
1549 fprintf(stderr
, "\t\tr=blocks (user resource fork)\n");
1550 fprintf(stderr
, "\t-i starting catalog node id\n");
1551 fprintf(stderr
, "\t-I initial size list (comma separated)\n");
1552 fprintf(stderr
, "\t\ta=size (attributes b-tree)\n");
1553 fprintf(stderr
, "\t\tc=size (catalog b-tree)\n");
1554 fprintf(stderr
, "\t\te=size (extents b-tree)\n");
1555 fprintf(stderr
, "\t-n b-tree node size list (comma separated)\n");
1556 fprintf(stderr
, "\t\ta=size (attributes b-tree)\n");
1557 fprintf(stderr
, "\t\tc=size (catalog b-tree)\n");
1558 fprintf(stderr
, "\t\te=size (extents b-tree)\n");
1559 fprintf(stderr
, "\t-v volume name (in ascii or UTF-8)\n");
1561 fprintf(stderr
, "\t-E extent count list (comma separated)\n");
1562 fprintf(stderr
, "\t\ta=count (attributes file)\n");
1563 fprintf(stderr
, "\t\tb=count (bitmap file)\n");
1564 fprintf(stderr
, "\t\tc=count (catalog file)\n");
1565 fprintf(stderr
, "\t\te=count (extents file)\n");
1566 fprintf(stderr
, "\t-a <num>[,list] metadata start allocation block, all btrees and journal will be created starting at this allocation block offset\n");
1567 fprintf(stderr
, "\t\tlist is as with -E above, plus:\n");
1568 fprintf(stderr
, "\t\tj=addr (JournalInfoBlock)\n");
1569 fprintf(stderr
, "\t\tJ=addr (Journal)\n");
1570 fprintf(stderr
, "\t\tN=addr (Next Allocation Block)\n");
1571 fprintf(stderr
, "\t\tExample: -a 100,e=200,c=500\n");
1574 fprintf(stderr
, " examples:\n");
1575 fprintf(stderr
, "\t%s -v Untitled /dev/rdisk0s7 \n", progname
);
1576 fprintf(stderr
, "\t%s -v Untitled -n c=4096,e=1024 /dev/rdisk0s7 \n", progname
);
1577 fprintf(stderr
, "\t%s -v Untitled -c b=64,c=1024 /dev/rdisk0s7 \n\n", progname
);