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
= 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;
568 startat
= strtoul(optlist
, &strp
, 0);
569 if (startat
== ULONG_MAX
&& errno
!= 0) {
570 err(1, "invalid allocation start block string %s", optlist
);
572 if (startat
> UINT_MAX
) {
573 errx(1, "Allocation block %lu larger than max", startat
);
575 if (strp
&& *strp
== ',')
578 gFSStartBlock
= startat
;
580 while((ndarg
= strsep(&strp
, ",")) != NULL
&& *ndarg
!= '\0') {
582 startat
= strtoul(optlist
, NULL
, 0);
583 p
= strchr(ndarg
, '=');
591 attrExtStart
= startat
;
594 blkallocExtStart
= startat
;
597 catExtStart
= startat
;
600 extExtStart
= startat
;
609 allocStart
= startat
;
619 static a_gid(char *s
)
625 if ((gr
= getgrnam(s
)) != NULL
)
628 for (gname
= s
; *s
&& isdigit(*s
); ++s
);
632 errx(1, "unknown group id: %s", gname
);
644 if ((pw
= getpwnam(s
)) != NULL
)
647 for (uname
= s
; *s
&& isdigit(*s
); ++s
);
651 errx(1, "unknown user id: %s", uname
);
664 if (*s
>= '0' && *s
<= '7') {
666 rv
= strtol(s
, &ep
, 8);
668 if (!done
|| rv
< 0 || *ep
)
669 errx(1, "invalid access mask: %s", s
);
674 * Check to see if the volume is too big.
677 * 0 if it is appropriately sized.
678 * 1 if HFS+ cannot be formatted onto the disk.
681 static int bad_disk_size (u_int64_t numsectors
, u_int64_t sectorsize
) {
683 u_int32_t maxSectorBits
= 0;
684 u_int32_t maxSectorSizeBits
= 0;
685 u_int32_t maxBits
= 0;
689 * The essential problem here is that we cannot simply multiply the sector size by the
690 * number of sectors because the product could overflow a 64 bit integer. We do a cursory
691 * check and then a longer check once we know the product will not overflow.
694 maxSectorBits
= get_high_bit (numsectors
);
695 maxSectorSizeBits
= get_high_bit (sectorsize
);
698 * We get the number of bits to represent the number of sectors and the sector size.
699 * Adding the two numbers gives us the number of bits required to represent the product.
700 * If the product is > 63 then it must be too big.
703 maxBits
= maxSectorBits
+ maxSectorSizeBits
;
708 /* Well, now we know that the two values won't overflow. Time to multiply */
709 bytes
= numsectors
* sectorsize
;
711 if (bytes
> MAXHFSVOLSIZE
) {
716 /* Otherwise, it looks good */
722 * The allocation block size must be defined as a power of 2 value, with a floor of
723 * 512 bytes. However, we never default to anything less than 4096 bytes, so that
724 * gives us 20 block size values from 4kb -> 2GB block size.
726 * See inline comments for how this table is used to determine the minimum fs size that
727 * will use a specified allocation block size.
729 * The growth boundary is used to figure out if we need a bigger block size than the
730 * 4 KB default. We get the index of the highest bit set in the FS size, then subtract the
731 * growth boundary to index into the block allocation size array.
733 * Note that 8K appears twice in table since we want to use it for the range 2 TB < 8 TB FS size.
734 * This means that when the 2TB bit or the 4TB bit is the high bit set, we prefer the 8K block size.
736 #define NUM_ALLOC_BLOCKSIZES 21
737 #define GROWTH_BOUNDARY 41
739 u_int64_t alloc_blocksize
[NUM_ALLOC_BLOCKSIZES
] = {
740 /* Block Size*/ /* Min Dflt FS Size */ /* Max FS Size */
741 4096, /* 0 bytes */ /* 16 TB */
742 8192, /* 2 TB */ /* 32 TB */ /* Note that 8K appears twice in table ! */
743 8192, /* 4 TB */ /* 32 TB */ /* Note that 8K appears twice in table ! */
744 16384, /* 8 TB */ /* 64 TB */
745 32768, /* 16 TB */ /* 128 TB */
746 65536, /* 32 TB */ /* 256 TB */
747 131072, /* 64 TB */ /* 512 TB */
748 262144, /* 128 TB */ /* 1 PB */
749 524288, /* 256 TB */ /* 2 PB */
750 1048576, /* 512 TB */ /* 4 PB */
751 2097152, /* 1 PB */ /* 8 PB */
752 4194304, /* 2 PB */ /* 16 PB */
753 8388608, /* 4 PB */ /* 32 PB */
754 16777216, /* 8 PB */ /* 64 PB */
755 33554432, /* 16 PB */ /* 128 PB */
756 67108864, /* 32 PB */ /* 256 PB */
757 134217728, /* 64 PB */ /* 512 PB */
758 268435456, /* 128 PB */ /* 1 EB */
759 536870912, /* 256 PB */ /* 2 EB */
760 1073741824, /* 512 PB */ /* 4 EB */
761 2147483648ULL /* 1 EB */ /* 8 EB */
764 static int get_high_bit (u_int64_t bitstring
) {
765 u_int64_t bits
= bitstring
;
776 * Validate the HFS Plus allocation block size in gBlockSize. If none was
777 * specified, then calculate a suitable default.
779 * Modifies the global variable gBlockSize.
781 static void validate_hfsplus_block_size(UInt64 sectorCount
, UInt32 sectorSize
)
783 if (gBlockSize
== 0) {
785 /* Start by calculating the fs size */
786 u_int64_t fs_size
= sectorCount
* sectorSize
;
789 * Determine the default based on a sliding scale. The maximum number of
790 * allocation blocks is always 4294967295 == (32 bits worth). At 1 bit per
791 * allocation block, that yields 512 MB of bitmap no matter what size we use
792 * for the allocation block.
794 * The general default policy is to allow the filesystem to grow up to 8x the
795 * current maximum size. So for a 1.5TB filesystem, an 8x multiplier would be
796 * 12TB. That means we can use the default size of 4096 bytes. The boundary begins
797 * at 2TB, since at that point, we can no longer use the default 4096 block size to
798 * extend the filesystem by 8x. For a 16KB block size, the max is 64 TB, but the 8x
799 * multiplier begins at 8 TB. Thereafter, we increase for every power of 2 that
800 * the current filesystem size grows.
803 gBlockSize
= DFL_BLKSIZE
; /* Prefer the default of 4K */
805 int bit_index
= get_high_bit (fs_size
);
806 bit_index
-= GROWTH_BOUNDARY
;
809 * After subtracting the GROWTH_BOUNDARY to index into the array, we'll
810 * use the values in the static array if we have a non-negative index.
811 * That means that if the filesystem is >= 1 TB, then we'll use the index
812 * value. At 2TB, we grow to the 8K block size.
814 if ((bit_index
>= 0) && (bit_index
< 22)) {
815 gBlockSize
= alloc_blocksize
[bit_index
];
818 if (bit_index
>= 22) {
819 fatal("Error: Disk Device is too big (%llu sectors, %d bytes per sector", sectorCount
, sectorSize
);
823 /* Make sure a user-specified block size is reasonable */
824 if ((gBlockSize
& (gBlockSize
-1)) != 0) {
825 fatal("%s: bad HFS Plus allocation block size (must be a power of two)", optarg
);
828 if ((sectorCount
/ (gBlockSize
/ sectorSize
)) > 0xFFFFFFFF) {
829 fatal("%s: block size is too small for %lld sectors", optarg
, gBlockSize
, sectorCount
);
832 if (gBlockSize
< HFSOPTIMALBLKSIZE
) {
833 warnx("Warning: %u is a non-optimal block size (4096 would be a better choice)", (unsigned int)gBlockSize
);
838 u_int64_t fs_size
= sectorCount
* sectorSize
;
839 u_int32_t totalBlocks
= fs_size
/gBlockSize
;
841 if (gFSStartBlock
>= totalBlocks
) {
842 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
);
843 warnx("Warning: Resetting file system start block to zero");
852 hfs_newfs(char *device
)
855 DriveInfo dip
= { 0 };
858 hfsparams_t defaults
= {0};
859 UInt64 maxPhysPerIO
= 0;
861 if (gPartitionSize
) {
862 dip
.sectorSize
= kBytesPerSector
;
863 dip
.physTotalSectors
= dip
.totalSectors
= gPartitionSize
/ kBytesPerSector
;
864 dip
.physSectorSize
= kBytesPerSector
; /* 512-byte sectors */
868 fso
= open( device
, O_RDONLY
| O_NDELAY
, 0 );
870 fso
= open( device
, O_RDWR
| O_NDELAY
, 0 );
877 fcntl(fso
, F_NOCACHE
, 1);
880 fatal("%s: %s", device
, strerror(errno
));
882 if (fstat( fso
, &stbuf
) < 0)
883 fatal("%s: %s", device
, strerror(errno
));
885 if (ioctl(fso
, DKIOCGETBLOCKSIZE
, &dip
.physSectorSize
) < 0)
886 fatal("%s: %s", device
, strerror(errno
));
888 if ((dip
.physSectorSize
% kBytesPerSector
) != 0)
889 fatal("%d is an unsupported sector size\n", dip
.physSectorSize
);
891 if (ioctl(fso
, DKIOCGETBLOCKCOUNT
, &dip
.physTotalSectors
) < 0)
892 fatal("%s: %s", device
, strerror(errno
));
896 dip
.physSectorsPerIO
= (1024 * 1024) / dip
.physSectorSize
; /* use 1M as default */
898 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBLOCKCOUNTREAD
, &maxPhysPerIO
) < 0)
899 fatal("%s: %s", device
, strerror(errno
));
902 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
);
904 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBLOCKCOUNTWRITE
, &maxPhysPerIO
) < 0)
905 fatal("%s: %s", device
, strerror(errno
));
908 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
);
910 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBYTECOUNTREAD
, &maxPhysPerIO
) < 0)
911 fatal("%s: %s", device
, strerror(errno
));
914 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
/ dip
.physSectorSize
);
916 if (fso
!= -1 && ioctl(fso
, DKIOCGETMAXBYTECOUNTWRITE
, &maxPhysPerIO
) < 0)
917 fatal("%s: %s", device
, strerror(errno
));
920 dip
.physSectorsPerIO
= MIN(dip
.physSectorsPerIO
, maxPhysPerIO
/ dip
.physSectorSize
);
922 dip
.sectorSize
= kBytesPerSector
;
923 dip
.totalSectors
= dip
.physTotalSectors
* dip
.physSectorSize
/ dip
.sectorSize
;
925 dip
.sectorOffset
= 0;
928 /* Check to see if the disk is too big */
929 u_int64_t secsize
= (u_int64_t
) dip
.sectorSize
;
930 if (bad_disk_size(dip
.totalSectors
, secsize
)) {
931 fatal("%s: partition is too big (maximum is %llu KB)", device
, MAXHFSVOLSIZE
/1024);
935 * If we're going to make an HFS Plus disk (with or without a wrapper), validate the
936 * HFS Plus allocation block size. This will also calculate a default allocation
937 * block size if none (or zero) was specified.
939 validate_hfsplus_block_size(dip
.totalSectors
, dip
.sectorSize
);
941 /* Make an HFS Plus disk */
943 if ((dip
.totalSectors
* dip
.sectorSize
) < kMinHFSPlusVolumeSize
)
944 fatal("%s: partition is too small (minimum is %d KB)", device
, kMinHFSPlusVolumeSize
/1024);
946 hfsplus_params(&dip
, &defaults
);
947 if (gNoCreate
== 0) {
948 retval
= make_hfsplus(&dip
, &defaults
);
950 printf("Initialized %s as a ", device
);
951 if (dip
.totalSectors
> 2048ULL*1024*1024)
953 (long)((dip
.totalSectors
+ (1024ULL*1024*1024))/(2048ULL*1024*1024)));
954 else if (dip
.totalSectors
> 2048*1024)
956 (long)((dip
.totalSectors
+ (1024*1024))/(2048*1024)));
957 else if (dip
.totalSectors
> 2048)
959 (long)((dip
.totalSectors
+ 1024)/2048));
962 (long)((dip
.totalSectors
+ 1)/2));
964 if (gCaseSensitive
) {
965 printf(" case-sensitive");
968 printf(" case-insensitive");
971 printf(" HFS Plus volume with a %uk journal\n",
972 (u_int32_t
)defaults
.journalSize
/1024);
974 printf(" HFS Plus volume\n");
979 fatal("%s: %s", device
, strerror(errno
));
989 typedef struct block_info {
992 _blk_info bi; //64 bit
993 struct buf *bp; //64 bit on K64, 32 bit on K32
995 }__attribute__((__packed__)) block_info;
997 total size == 16 bytes
1000 #define BLOCK_INFO_SIZE 16
1002 static void hfsplus_params (const DriveInfo
* dip
, hfsparams_t
*defaults
)
1004 UInt64 sectorCount
= dip
->totalSectors
;
1005 UInt32 sectorSize
= dip
->sectorSize
;
1006 uint32_t totalBlocks
;
1007 UInt32 minClumpSize
;
1010 UInt32 oddBitmapBytes
;
1012 defaults
->flags
= 0;
1013 defaults
->blockSize
= gBlockSize
;
1014 defaults
->fsStartBlock
= gFSStartBlock
;
1015 defaults
->nextFreeFileID
= gNextCNID
;
1016 defaults
->createDate
= createtime
+ MAC_GMT_FACTOR
; /* Mac OS GMT time */
1017 defaults
->hfsAlignment
= 0;
1018 defaults
->journaledHFS
= gJournaled
;
1019 defaults
->journalDevice
= gJournalDevice
;
1023 * Always set kUseAccessPerms now; this also
1024 * means we have to always have an owner, group,
1027 defaults
->owner
= (gUserID
== (uid_t
)NOVAL
) ? geteuid() : gUserID
;
1028 defaults
->group
= (gGroupID
== (gid_t
)NOVAL
) ? getegid() : gGroupID
;
1029 defaults
->mask
= (gModeMask
== (mode_t
)NOVAL
) ? UMASK
: (gModeMask
& ACCESSMASK
);
1030 defaults
->flags
|= kUseAccessPerms
;
1033 * We want at least 8 megs of journal for each 100 gigs of
1034 * disk space. We cap the size at 512 megs (64x default), unless
1035 * the allocation block size is larger, in which case we use one
1038 * Only scale if it's the default, otherwise just take what
1039 * the user specified, with the caveat below.
1042 uint32_t min_size
= 0;
1045 * Check to ensure the journal size is not too small relative to the
1046 * sector size of the device. This is the check in the kernel:
1047 if (tr->blhdr && (tr->blhdr->max_blocks <= 0 ||
1048 tr->blhdr->max_blocks > (tr->jnl->jhdr->size/tr->jnl->jhdr->jhdr_size)))
1049 * We assume that there will be a block header and that there will be a
1050 * non-negative max_blocks value.
1052 * The 2nd check is the problematic one. We cannot have a journal that's too
1053 * small relative to the sector size. max_blocks == (blhdr_size / 16). However,
1054 * this only matters where the current block header size is smaller than the current
1055 * sector size. So, assume that the blhdr_size == sector size for now. We look
1056 * at the condition above to get the rest of the equation -- (journal size / sector size).
1057 * Then, it's simple algebra to figure out what the new minimum journal size
1060 * (sector_size / 16) > (journal_size / sector_size)
1061 * (sector_size / 16) = (journal_size / sector_size)
1062 * (sector_size / 16) * sector_size = (journal_size / sector_size) * sector_size
1063 * (sector_size / 16) * sector_size = journal_size
1065 * This becomes our new _floor_ for the journal_size.
1068 if (dip
->physSectorSize
!= 0) {
1069 min_size
= dip
->physSectorSize
* (dip
->physSectorSize
/ BLOCK_INFO_SIZE
);
1072 if (gJournalSize
!= 0) {
1074 /* Was the supplied journal size at least the minimum computed above? */
1075 if (gJournalSize
< min_size
) {
1076 printf("%s: journal size %lldk too small. Reset to %dk.\n",
1077 progname
, gJournalSize
/1024, JOURNAL_DEFAULT_SIZE
/1024);
1081 /* defaults->journalSize will get reset below if it is 0 */
1082 defaults
->journalSize
= gJournalSize
;
1085 if ((gJournalSize
== 0) || (defaults
->journalSize
== 0)) {
1087 uint32_t target_size
;
1088 /* Figure out how many 100's of GBs this filesystem represents */
1089 jscale
= (sectorCount
* sectorSize
) / ((UInt64
)100 * 1024 * 1024 * 1024);
1094 target_size
= JOURNAL_DEFAULT_SIZE
* (jscale
+ 1);
1095 /* Is the target size at least the min_size computed above? */
1096 if (target_size
< min_size
) {
1097 target_size
= min_size
;
1100 defaults
->journalSize
= target_size
;
1105 // volumes that are 128 megs or less in size have such
1106 // a small bitmap (one 4k-block) and inherhently such
1107 // a small btree that we can get by with a much smaller
1108 // journal. even in a worst case scenario of a catalog
1109 // filled with very long korean file names we should
1110 // never touch more than 256k of meta-data for a single
1111 // transaction. therefore we'll make the journal 512k,
1112 // or as small as possible, given the sector size,
1113 // which is safe and doesn't waste much space.
1114 // However, be careful not to let the journal size drop BELOW
1115 // 512k, since the min_size computations can create an artificially
1116 // tiny journal (16k or so) with 512byte sectors.
1118 if (sectorCount
* sectorSize
< 128*1024*1024) {
1119 /* This is a small (<128MB) FS */
1120 uint32_t small_default
= (512 * 1024);
1122 if (small_default
<= min_size
) {
1124 * If 512k is too small given the sector size,
1125 * then use the larger sector size
1127 defaults
->journalSize
= min_size
;
1130 /* 512k was bigger than the min size; we can use it */
1131 defaults
->journalSize
= small_default
;
1136 if (defaults
->journalSize
> 512 * 1024 * 1024) {
1137 defaults
->journalSize
= 512 * 1024 * 1024;
1140 if (defaults
->journalSize
< defaults
->blockSize
) {
1141 defaults
->journalSize
= defaults
->blockSize
;
1145 defaults
->volumeName
= (unsigned char*)gVolumeName
;
1147 if (rsrclumpblks
== 0) {
1148 if (gBlockSize
> DFL_BLKSIZE
)
1149 defaults
->rsrcClumpSize
= ROUNDUP(kHFSPlusRsrcClumpFactor
* DFL_BLKSIZE
, gBlockSize
);
1151 defaults
->rsrcClumpSize
= kHFSPlusRsrcClumpFactor
* gBlockSize
;
1153 defaults
->rsrcClumpSize
= clumpsizecalc(rsrclumpblks
);
1155 if (datclumpblks
== 0) {
1156 if (gBlockSize
> DFL_BLKSIZE
)
1157 defaults
->dataClumpSize
= ROUNDUP(kHFSPlusDataClumpFactor
* DFL_BLKSIZE
, gBlockSize
);
1159 defaults
->dataClumpSize
= kHFSPlusDataClumpFactor
* gBlockSize
;
1161 defaults
->dataClumpSize
= clumpsizecalc(datclumpblks
);
1164 * The default b-tree node size is 8K. However, if the
1165 * volume is small (< 1 GB) we use 4K instead.
1167 if (!gUserCatNodeSize
) {
1168 if ((gBlockSize
< HFSOPTIMALBLKSIZE
) ||
1169 ((UInt64
)(sectorCount
* sectorSize
) < (UInt64
)0x40000000))
1173 if (catclumpblks
== 0) {
1174 clumpSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, catnodesiz
, sectorCount
, kHFSCatalogFileID
);
1177 clumpSize
= clumpsizecalc(catclumpblks
);
1178 if (clumpSize
% catnodesiz
!= 0)
1179 fatal("c=%ld: clump size is not a multiple of node size\n", clumpSize
/gBlockSize
);
1181 if (catinitialblks
== 0) {
1182 initialSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, catnodesiz
, sectorCount
, kHFSCatalogFileID
);
1185 initialSize
= initialsizecalc(catinitialblks
);
1186 if (initialSize
% catnodesiz
!= 0)
1187 fatal("c=%ld: initial size is not a multiple of node size\n", initialSize
/gBlockSize
);
1189 if (initialSize
< clumpSize
) {
1190 fatal("c=%ld: initial size is less than clump size\n", initialSize
/gBlockSize
);
1192 defaults
->catalogClumpSize
= clumpSize
;
1193 defaults
->catalogInitialSize
= initialSize
;
1194 defaults
->catalogNodeSize
= catnodesiz
;
1195 defaults
->catalogExtsCount
= catExtCount
;
1196 defaults
->catalogStartBlock
= catExtStart
;
1198 if (gBlockSize
< 4096 && gBlockSize
< catnodesiz
)
1199 warnx("Warning: block size %u is less than catalog b-tree node size %u", (unsigned int)gBlockSize
, (unsigned int)catnodesiz
);
1201 if (extclumpblks
== 0) {
1202 clumpSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, extnodesiz
, sectorCount
, kHFSExtentsFileID
);
1205 clumpSize
= clumpsizecalc(extclumpblks
);
1206 if (clumpSize
% extnodesiz
!= 0)
1207 fatal("e=%ld: clump size is not a multiple of node size\n", clumpSize
/gBlockSize
);
1209 if (extinitialblks
== 0) {
1210 initialSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, extnodesiz
, sectorCount
, kHFSExtentsFileID
);
1213 initialSize
= initialsizecalc(extinitialblks
);
1214 if (initialSize
% extnodesiz
!= 0)
1215 fatal("e=%ld: initial size is not a multiple of node size\n", initialSize
/gBlockSize
);
1217 if (initialSize
< clumpSize
) {
1218 fatal("e=%ld: initial size is less than clump size\n", initialSize
/gBlockSize
);
1220 defaults
->extentsClumpSize
= clumpSize
;
1221 defaults
->extentsInitialSize
= initialSize
;
1222 defaults
->extentsNodeSize
= extnodesiz
;
1223 defaults
->extentsExtsCount
= extExtCount
;
1224 defaults
->extentsStartBlock
= extExtStart
;
1226 if (gBlockSize
< extnodesiz
)
1227 warnx("Warning: block size %u is less than extents b-tree node size %u", (unsigned int)gBlockSize
, (unsigned int)extnodesiz
);
1228 if (defaults
->extentsExtsCount
> 8) {
1229 warnx("Warning: extents overflow extent requested count %u exceeds maximum 8, capping at 8\n", defaults
->extentsExtsCount
);
1230 defaults
->extentsExtsCount
= 8;
1233 if (atrclumpblks
== 0) {
1234 clumpSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, atrnodesiz
, sectorCount
, kHFSAttributesFileID
);
1237 clumpSize
= clumpsizecalc(atrclumpblks
);
1238 if (clumpSize
% atrnodesiz
!= 0)
1239 fatal("a=%ld: clump size is not a multiple of node size\n", clumpSize
/gBlockSize
);
1241 if (atrinitialblks
== 0) {
1242 if (gUserAttrSize
) {
1246 initialSize
= CalcHFSPlusBTreeClumpSize(gBlockSize
, atrnodesiz
, sectorCount
, kHFSAttributesFileID
);
1250 initialSize
= initialsizecalc(atrinitialblks
);
1251 if (initialSize
% atrnodesiz
!= 0)
1252 fatal("a=%ld: initial size is not a multiple of node size\n", initialSize
/gBlockSize
);
1255 if (initialSize
< clumpSize
) {
1256 fatal("a=%ld: initial size is less than clump size\n", initialSize
/gBlockSize
);
1259 defaults
->attributesClumpSize
= clumpSize
;
1260 defaults
->attributesInitialSize
= initialSize
;
1261 defaults
->attributesNodeSize
= atrnodesiz
;
1262 defaults
->attributesExtsCount
= attrExtCount
;
1263 defaults
->attributesStartBlock
= attrExtStart
;
1266 * Calculate the number of blocks needed for bitmap (rounded up to a multiple of the block size).
1270 * Figure out how many bytes we need for the given totalBlocks
1271 * Note: this minimum value may be too large when it counts the
1272 * space used by the wrapper
1274 totalBlocks
= sectorCount
/ (gBlockSize
/ sectorSize
);
1276 minClumpSize
= totalBlocks
>> 3; /* convert bits to bytes by dividing by 8 */
1277 if (totalBlocks
& 7)
1278 ++minClumpSize
; /* round up to whole bytes */
1280 /* Round up to a multiple of blockSize */
1281 if ((oddBitmapBytes
= minClumpSize
% gBlockSize
))
1282 minClumpSize
= minClumpSize
- oddBitmapBytes
+ gBlockSize
;
1284 if (bmclumpblks
== 0) {
1285 clumpSize
= minClumpSize
;
1288 clumpSize
= clumpsizecalc(bmclumpblks
);
1290 if (clumpSize
< minClumpSize
)
1291 fatal("b=%ld: bitmap clump size is too small\n", clumpSize
/gBlockSize
);
1293 defaults
->allocationClumpSize
= clumpSize
;
1294 defaults
->allocationExtsCount
= blkallocExtCount
;
1295 defaults
->allocationStartBlock
= blkallocExtStart
;
1297 defaults
->journalInfoBlock
= jibStart
;
1298 defaults
->journalBlock
= jnlStart
;
1299 defaults
->nextAllocBlock
= allocStart
;
1302 defaults
->flags
|= kMakeCaseSensitive
;
1304 if (gContentProtect
)
1305 defaults
->flags
|= kMakeContentProtect
;
1309 defaults
->protectlevel
= gProtectLevel
;
1313 if (gPartitionSize
== 0)
1314 printf("%llu sectors (%u bytes per sector)\n", dip
->physTotalSectors
, dip
->physSectorSize
);
1315 printf("HFS Plus format parameters:\n");
1316 printf("\tvolume name: \"%s\"\n", gVolumeName
);
1317 printf("\tblock-size: %u\n", defaults
->blockSize
);
1318 printf("\ttotal blocks: %u\n", totalBlocks
);
1320 printf("\tjournal-size: %uk\n", defaults
->journalSize
/1024);
1321 printf("\tfirst free catalog node id: %u\n", defaults
->nextFreeFileID
);
1322 printf("\tcatalog b-tree node size: %u\n", defaults
->catalogNodeSize
);
1323 printf("\tcatalog clump size: %u\n", defaults
->catalogClumpSize
);
1324 printf("\tinitial catalog file size: %u\n", defaults
->catalogInitialSize
);
1325 printf("\textents b-tree node size: %u\n", defaults
->extentsNodeSize
);
1326 printf("\textents clump size: %u\n", defaults
->extentsClumpSize
);
1327 printf("\tinitial extents file size: %u\n", defaults
->extentsInitialSize
);
1328 printf("\tattributes b-tree node size: %u\n", defaults
->attributesNodeSize
);
1329 printf("\tattributes clump size: %u\n", defaults
->attributesClumpSize
);
1330 printf("\tinitial attributes file size: %u\n", defaults
->attributesInitialSize
);
1331 printf("\tinitial allocation file size: %u (%u blocks)\n",
1332 defaults
->allocationClumpSize
, defaults
->allocationClumpSize
/ gBlockSize
);
1333 printf("\tdata fork clump size: %u\n", defaults
->dataClumpSize
);
1334 printf("\tresource fork clump size: %u\n", defaults
->rsrcClumpSize
);
1335 if (defaults
->flags
& kUseAccessPerms
) {
1336 printf("\tuser ID: %d\n", (int)defaults
->owner
);
1337 printf("\tgroup ID: %d\n", (int)defaults
->group
);
1338 printf("\taccess mask: %o\n", (int)defaults
->mask
);
1340 printf("\tfile system start block: %u\n", defaults
->fsStartBlock
);
1346 initialsizecalc(UInt32 initialblocks
)
1350 initialsize
= (UInt64
)initialblocks
* (UInt64
)gBlockSize
;
1352 if (initialsize
& (UInt64
)(0xFFFFFFFF00000000ULL
))
1353 fatal("=%ld: too many blocks for initial size!", initialblocks
);
1355 return ((UInt32
)initialsize
);
1360 clumpsizecalc(UInt32 clumpblocks
)
1364 clumpsize
= (UInt64
)clumpblocks
* (UInt64
)gBlockSize
;
1366 if (clumpsize
& (UInt64
)(0xFFFFFFFF00000000ULL
))
1367 fatal("=%ld: too many blocks for clump size!", clumpblocks
);
1369 return ((UInt32
)clumpsize
);
1373 #define CLUMP_ENTRIES 15
1375 short clumptbl
[CLUMP_ENTRIES
* 3] = {
1377 * Volume Attributes Catalog Extents
1378 * Size Clump (MB) Clump (MB) Clump (MB)
1383 /* 8GB */ 11, 11, 5,
1385 * For volumes 16GB and larger, we want to make sure that a full OS
1386 * install won't require fragmentation of the Catalog or Attributes
1387 * B-trees. We do this by making the clump sizes sufficiently large,
1388 * and by leaving a gap after the B-trees for them to grow into.
1390 * For SnowLeopard 10A298, a FullNetInstall with all packages selected
1392 * Catalog B-tree Header
1396 * (used = 231.55 MB)
1397 * Attributes B-tree Header
1401 * (used = 486.52 MB)
1403 * We also want Time Machine backup volumes to have a sufficiently
1404 * large clump size to reduce fragmentation.
1406 * The series of numbers for Catalog and Attribute form a geometric series.
1407 * For Catalog (16GB to 512GB), each term is 8**(1/5) times the previous
1408 * term. For Attributes (16GB to 512GB), each term is 4**(1/5) times
1409 * the previous term. For 1TB to 16TB, each term is 2**(1/5) times the
1412 /* 16GB */ 64, 32, 5,
1413 /* 32GB */ 84, 49, 6,
1414 /* 64GB */ 111, 74, 7,
1415 /* 128GB */ 147, 111, 8,
1416 /* 256GB */ 194, 169, 9,
1417 /* 512GB */ 256, 256, 11,
1418 /* 1TB */ 294, 294, 14,
1419 /* 2TB */ 338, 338, 16,
1420 /* 4TB */ 388, 388, 20,
1421 /* 8TB */ 446, 446, 25,
1422 /* 16TB */ 512, 512, 32
1426 * CalcHFSPlusBTreeClumpSize
1428 * This routine calculates the file clump size for either
1429 * the catalog file or the extents overflow file.
1432 CalcHFSPlusBTreeClumpSize(UInt32 blockSize
, UInt32 nodeSize
, UInt64 sectors
, int fileID
)
1434 UInt32 mod
= MAX(nodeSize
, blockSize
);
1439 /* Figure out which column of the above table to use for this file. */
1441 case kHFSAttributesFileID
:
1444 case kHFSCatalogFileID
:
1453 * The default clump size is 0.8% of the volume size. And
1454 * it must also be a multiple of the node and block size.
1456 if (sectors
< 0x200000) {
1457 clumpSize
= sectors
<< 2; /* 0.8 % */
1458 if (clumpSize
< (8 * nodeSize
))
1459 clumpSize
= 8 * nodeSize
;
1462 * XXX This should scale more smoothly!
1464 /* turn exponent into table index... */
1465 for (i
= 0, sectors
= sectors
>> 22;
1466 sectors
&& (i
< CLUMP_ENTRIES
-1);
1467 ++i
, sectors
= sectors
>> 1);
1469 clumpSize
= clumptbl
[column
+ (i
) * 3] * 1024 * 1024;
1473 * Round the clump size to a multiple of node and block size.
1474 * NOTE: This rounds down.
1480 * Rounding down could have rounded down to 0 if the block size was
1481 * greater than the clump size. If so, just use one block or node.
1493 fatal(const char *fmt
, ...)
1495 fatal(fmt
, va_alist
)
1507 if (fcntl(STDERR_FILENO
, F_GETFL
) < 0) {
1508 openlog(progname
, LOG_CONS
, LOG_DAEMON
);
1509 vsyslog(LOG_ERR
, fmt
, ap
);
1522 fprintf(stderr
, "usage: %s [-N [partition-size]] [hfsplus-options] special-device\n", progname
);
1524 fprintf(stderr
, " options:\n");
1525 fprintf(stderr
, "\t-N do not create file system, just print out parameters\n");
1526 fprintf(stderr
, "\t-s use case-sensitive filenames (default is case-insensitive)\n");
1528 fprintf(stderr
, " where hfsplus-options are:\n");
1529 fprintf(stderr
, "\t-J [journal-size] make this HFS+ volume journaled\n");
1530 fprintf(stderr
, "\t-D journal-dev use 'journal-dev' for an external journal\n");
1531 fprintf(stderr
, "\t-G group-id (for root directory)\n");
1532 fprintf(stderr
, "\t-U user-id (for root directory)\n");
1533 fprintf(stderr
, "\t-M octal access-mask (for root directory)\n");
1534 fprintf(stderr
, "\t-b allocation block size (4096 optimal)\n");
1535 fprintf(stderr
, "\t-c clump size list (comma separated)\n");
1536 fprintf(stderr
, "\t\ta=blocks (attributes file)\n");
1537 fprintf(stderr
, "\t\tb=blocks (bitmap file)\n");
1538 fprintf(stderr
, "\t\tc=blocks (catalog file)\n");
1539 fprintf(stderr
, "\t\td=blocks (user data fork)\n");
1540 fprintf(stderr
, "\t\te=blocks (extents file)\n");
1541 fprintf(stderr
, "\t\tr=blocks (user resource fork)\n");
1542 fprintf(stderr
, "\t-i starting catalog node id\n");
1543 fprintf(stderr
, "\t-I initial size list (comma separated)\n");
1544 fprintf(stderr
, "\t\ta=size (attributes b-tree)\n");
1545 fprintf(stderr
, "\t\tc=size (catalog b-tree)\n");
1546 fprintf(stderr
, "\t\te=size (extents b-tree)\n");
1547 fprintf(stderr
, "\t-n b-tree node size list (comma separated)\n");
1548 fprintf(stderr
, "\t\ta=size (attributes b-tree)\n");
1549 fprintf(stderr
, "\t\tc=size (catalog b-tree)\n");
1550 fprintf(stderr
, "\t\te=size (extents b-tree)\n");
1551 fprintf(stderr
, "\t-v volume name (in ascii or UTF-8)\n");
1553 fprintf(stderr
, "\t-E extent count list (comma separated)\n");
1554 fprintf(stderr
, "\t\ta=count (attributes file)\n");
1555 fprintf(stderr
, "\t\tb=count (bitmap file)\n");
1556 fprintf(stderr
, "\t\tc=count (catalog file)\n");
1557 fprintf(stderr
, "\t\te=count (extents file)\n");
1558 fprintf(stderr
, "\t-a <num>[,list] metadata start allocation block, all btrees and journal will be created starting at this allocation block offset\n");
1559 fprintf(stderr
, "\t\tlist is as with -E above, plus:\n");
1560 fprintf(stderr
, "\t\tj=addr (JournalInfoBlock)\n");
1561 fprintf(stderr
, "\t\tJ=addr (Journal)\n");
1562 fprintf(stderr
, "\t\tN=addr (Next Allocation Block)\n");
1563 fprintf(stderr
, "\t\tExample: -a 100,e=200,c=500\n");
1566 fprintf(stderr
, " examples:\n");
1567 fprintf(stderr
, "\t%s -v Untitled /dev/rdisk0s7 \n", progname
);
1568 fprintf(stderr
, "\t%s -v Untitled -n c=4096,e=1024 /dev/rdisk0s7 \n", progname
);
1569 fprintf(stderr
, "\t%s -v Untitled -c b=64,c=1024 /dev/rdisk0s7 \n\n", progname
);