]> git.saurik.com Git - apple/hfs.git/blob - newfs_hfs/newfs_hfs.c
hfs-304.tar.gz
[apple/hfs.git] / newfs_hfs / newfs_hfs.c
1 /*
2 * Copyright (c) 1999-2015 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
25 #include <err.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <grp.h>
29 #include <paths.h>
30 #include <pwd.h>
31 #include <stdlib.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <syslog.h>
36 #include <unistd.h>
37
38 #include <sys/ioctl.h>
39 #include <sys/mount.h>
40 #include <sys/param.h>
41 #include <sys/stat.h>
42
43 #include <IOKit/storage/IOMediaBSDClient.h>
44
45 #include <hfs/hfs_format.h>
46 #include "newfs_hfs.h"
47
48 #if __STDC__
49 #include <stdarg.h>
50 #else
51 #include <varargs.h>
52 #endif
53
54 #define NOVAL (-1)
55 #define UMASK (0755)
56 #define ACCESSMASK (0777)
57
58 /*
59 * The maximum HFS volume size is calculated thusly:
60 *
61 * The maximum allocation block size (which must be a power of 2 value),
62 * is 2GB, or 2^31 bytes
63 *
64 * The maximum number of allocation blocks is 2^32 -1.
65 *
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.
69 */
70
71 #define MAXHFSVOLSIZE (0x7FFFFFFF80000000ULL)
72
73 #define ROUNDUP(x,y) (((x)+(y)-1)/(y)*(y))
74
75 static void getnodeopts __P((char* optlist));
76 static void getinitialopts __P((char* optlist));
77 static void getclumpopts __P((char* optlist));
78 #ifdef DEBUG_BUILD
79 static void getstartopts __P((char *optlist));
80 static void getextsopts __P((char* optlist));
81 #endif
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);
94
95
96
97 char *progname;
98 char *gVolumeName = kDefaultVolumeNameStr;
99 char rawdevice[MAXPATHLEN];
100 char blkdevice[MAXPATHLEN];
101 uint32_t gBlockSize = 0;
102 UInt32 gNextCNID = kHFSFirstUserCatalogNodeID;
103
104 time_t createtime;
105
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;
114
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;
118
119 #ifdef DEBUG_BUILD
120 uint16_t gProtectLevel = 0;
121 #endif
122
123 #define JOURNAL_DEFAULT_SIZE (8*1024*1024)
124 int gJournaled = FALSE;
125 char *gJournalDevice = NULL;
126 UInt64 gJournalSize = 0;
127
128 uid_t gUserID = (uid_t)NOVAL;
129 gid_t gGroupID = (gid_t)NOVAL;
130 mode_t gModeMask = (mode_t)NOVAL;
131
132 /* Starting allocation block number for the file system,
133 * all btrees, including journal will be laid down at this
134 * alloation block offset.
135 */
136 UInt32 gFSStartBlock = 0;
137
138 UInt64 gPartitionSize = 0;
139
140 UInt32 catnodesiz = 8192;
141 UInt32 extnodesiz = 4096;
142 UInt32 atrnodesiz = 8192;
143
144 UInt32 catinitialblks = 0;
145 UInt32 extinitialblks = 0;
146 UInt32 atrinitialblks = 0;
147
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 */
155
156
157 UInt64
158 get_num(char *str)
159 {
160 UInt64 num;
161 char *ptr;
162
163 num = strtoull(str, &ptr, 0);
164
165 if (*ptr) {
166 char scale = tolower(*ptr);
167
168 switch(scale) {
169 case 'b':
170 num *= 512ULL;
171 break;
172 case 'p':
173 num *= 1024ULL;
174 /* fall through */
175 case 't':
176 num *= 1024ULL;
177 /* fall through */
178 case 'g':
179 num *= 1024ULL;
180 /* fall through */
181 case 'm':
182 num *= 1024ULL;
183 /* fall through */
184 case 'k':
185 num *= 1024ULL;
186 break;
187
188 default:
189 num = 0ULL;
190 break;
191 }
192 }
193 return num;
194 }
195
196
197 int
198 main(argc, argv)
199 int argc;
200 char **argv;
201 {
202 extern char *optarg;
203 extern int optind;
204 int ch;
205 char *cp, *special;
206 struct statfs *mp;
207 int n;
208
209 if ((progname = strrchr(*argv, '/')))
210 ++progname;
211 else
212 progname = *argv;
213
214 // No semicolon at end of line deliberately!
215
216 static const char *options = "G:J:D:M:N:PU:hsb:c:i:I:n:v:"
217 #ifdef DEBUG_BUILD
218 "p:a:E:"
219 #endif
220 ;
221
222 while ((ch = getopt(argc, argv, options)) != -1)
223 switch (ch) {
224 case 'G':
225 gGroupID = a_gid(optarg);
226 break;
227
228 case 'J':
229 gJournaled = TRUE;
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;
236 }
237 } else {
238 /* back up because there was no size argument */
239 optind--;
240 }
241 break;
242
243 case 'D':
244 gJournalDevice = (char *)optarg;
245 break;
246
247 case 'N':
248 gNoCreate = TRUE;
249 if (isdigit(optarg[0])) {
250 gPartitionSize = get_num(optarg);
251 } else {
252 /* back up because there was no size argument */
253 optind--;
254 }
255 break;
256
257 case 'P':
258 gContentProtect = TRUE;
259 break;
260
261 #ifdef DEBUG_BUILD
262 case 'p':
263 if (isdigit (optarg[0])) {
264 uint64_t level = get_num (optarg);
265 gProtectLevel = (uint16_t) level;
266 }
267 else {
268 /* back up because no level was provided */
269 optind--;
270 }
271 break;
272 #endif
273
274 case 'M':
275 gModeMask = a_mask(optarg);
276 break;
277
278 case 'U':
279 gUserID = a_uid(optarg);
280 break;
281
282 #ifdef DEBUG_BUILD
283 case 'a':
284 getstartopts(optarg);
285 break;
286 #endif
287
288 #ifdef DEBUG_BUILD
289 case 'E':
290 getextsopts(optarg);
291 break;
292 #endif
293 case 'b':
294 {
295 UInt64 tempBlockSize;
296
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;
303 break;
304 }
305
306 case 'c':
307 getclumpopts(optarg);
308 break;
309
310 case 'i':
311 gNextCNID = atoi(optarg);
312 /*
313 * make sure its at least kHFSFirstUserCatalogNodeID
314 */
315 if (gNextCNID < kHFSFirstUserCatalogNodeID)
316 fatal("%s: starting catalog node id too small (must be > 15)", optarg);
317 break;
318
319 case 'I':
320 getinitialopts(optarg);
321 break;
322
323 case 'n':
324 getnodeopts(optarg);
325 break;
326
327 case 's':
328 gCaseSensitive = TRUE;
329 break;
330
331 case 'v':
332 if ((gVolumeName = strdup(optarg)) == NULL) {
333 fatal("Could not copy volume name %s", optarg);
334 }
335 break;
336
337 case '?':
338 default:
339 usage();
340 }
341
342 argc -= optind;
343 argv += optind;
344
345 #ifdef DEBUG_BUILD
346 if ((gProtectLevel) && !(gContentProtect)) {
347 fatal ("content protection must be specified to set a protection level");
348 }
349 #endif
350
351 if (gPartitionSize != 0) {
352 /*
353 * If we are given -N, a size, and a device, that's a usage error.
354 */
355 if (argc != 0)
356 usage();
357
358 rawdevice[0] = blkdevice[0] = 0;
359 } else {
360 if (argc != 1)
361 usage();
362
363 special = argv[0];
364 cp = strrchr(special, '/');
365 if (cp != 0)
366 special = cp + 1;
367 if (*special == 'r')
368 special++;
369 (void) snprintf(rawdevice, sizeof(rawdevice), "%sr%s", _PATH_DEV, special);
370 (void) snprintf(blkdevice, sizeof(blkdevice), "%s%s", _PATH_DEV, special);
371 }
372
373 if (gPartitionSize == 0) {
374 /*
375 * Check if target device is aready mounted
376 */
377 n = getmntinfo(&mp, MNT_NOWAIT);
378 if (n == 0)
379 fatal("%s: getmntinfo: %s", blkdevice, strerror(errno));
380
381 while (--n >= 0) {
382 if (strcmp(blkdevice, mp->f_mntfromname) == 0)
383 fatal("%s is mounted on %s", blkdevice, mp->f_mntonname);
384 ++mp;
385 }
386 }
387
388 if (hfs_newfs(rawdevice) < 0) {
389 err(1, "cannot create filesystem on %s", rawdevice);
390 }
391
392 exit(0);
393 }
394
395
396 static void getnodeopts(char* optlist)
397 {
398 char *strp = optlist;
399 char *ndarg;
400 char *p;
401 UInt32 ndsize;
402
403 while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
404
405 p = strchr(ndarg, '=');
406 if (p == NULL)
407 usage();
408
409 ndsize = atoi(p+1);
410
411 switch (*ndarg) {
412 case 'c':
413 if (ndsize < 4096 || ndsize > 32768 || (ndsize & (ndsize-1)) != 0)
414 fatal("%s: invalid catalog b-tree node size", ndarg);
415 catnodesiz = ndsize;
416 gUserCatNodeSize = TRUE;
417 break;
418
419 case 'e':
420 if (ndsize < 1024 || ndsize > 32768 || (ndsize & (ndsize-1)) != 0)
421 fatal("%s: invalid extents b-tree node size", ndarg);
422 extnodesiz = ndsize;
423 break;
424
425 case 'a':
426 if (ndsize < 4096 || ndsize > 32768 || (ndsize & (ndsize-1)) != 0)
427 fatal("%s: invalid atrribute b-tree node size", ndarg);
428 atrnodesiz = ndsize;
429 break;
430
431 default:
432 usage();
433 }
434 }
435 }
436
437
438 static void getinitialopts(char* optlist)
439 {
440 char *strp = optlist;
441 char *ndarg;
442 char *p;
443 UInt32 inblocks;
444
445 while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
446
447 p = strchr(ndarg, '=');
448 if (p == NULL)
449 usage();
450
451 inblocks = atoi(p+1);
452
453 switch (*ndarg) {
454 case 'a':
455 atrinitialblks = inblocks;
456 gUserAttrInitialSize = TRUE;
457 gUserAttrSize = TRUE;
458 break;
459 case 'c':
460 catinitialblks = inblocks;
461 gUserCatInitialSize = TRUE;
462 break;
463 case 'e':
464 extinitialblks = inblocks;
465 gUserExtInitialSize = TRUE;
466 break;
467
468 default:
469 usage();
470 }
471 }
472 }
473
474
475 static void getclumpopts(char* optlist)
476 {
477 char *strp = optlist;
478 char *ndarg;
479 char *p;
480 UInt32 clpblocks;
481
482 while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
483
484 p = strchr(ndarg, '=');
485 if (p == NULL)
486 usage();
487
488 clpblocks = atoi(p+1);
489
490 switch (*ndarg) {
491 case 'a':
492 atrclumpblks = clpblocks;
493 if (!gUserAttrInitialSize) {
494 atrinitialblks = atrclumpblks;
495 }
496 gUserAttrSize = TRUE;
497 break;
498 case 'b':
499 bmclumpblks = clpblocks;
500 break;
501 case 'c':
502 catclumpblks = clpblocks;
503 if (!gUserCatInitialSize) {
504 catinitialblks = catclumpblks;
505 }
506 break;
507 case 'd':
508 datclumpblks = clpblocks;
509 break;
510 case 'e':
511 extclumpblks = clpblocks;
512 if (!gUserExtInitialSize) {
513 extinitialblks = extclumpblks;
514 }
515 break;
516 case 'r':
517 rsrclumpblks = clpblocks;
518 break;
519
520 default:
521 usage();
522 }
523 }
524 }
525
526 #ifdef DEBUG_BUILD
527 static void getextsopts(char* optlist)
528 {
529 char *strp = optlist;
530 char *ndarg;
531 char *p;
532 UInt32 numexts;
533
534 while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
535
536 p = strchr(ndarg, '=');
537 if (p == NULL)
538 usage();
539
540 numexts = atoi(p+1);
541
542 switch (*ndarg) {
543 case 'a':
544 attrExtCount = numexts;
545 break;
546 case 'b':
547 blkallocExtCount = numexts;
548 break;
549 case 'c':
550 catExtCount = numexts;
551 break;
552 case 'e':
553 extExtCount = numexts;
554 break;
555 default:
556 usage();
557 }
558 }
559 }
560
561 static void getstartopts(char* optlist)
562 {
563 char *strp;
564 char *ndarg;
565 char *p;
566 unsigned long startat = 0;
567
568 startat = strtoul(optlist, &strp, 0);
569 if (startat == ULONG_MAX && errno != 0) {
570 err(1, "invalid allocation start block string %s", optlist);
571 }
572 if (startat > UINT_MAX) {
573 errx(1, "Allocation block %lu larger than max", startat);
574 }
575 if (strp && *strp == ',')
576 strp++;
577
578 gFSStartBlock = startat;
579
580 while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
581
582 startat = strtoul(optlist, NULL, 0);
583 p = strchr(ndarg, '=');
584 if (p == NULL)
585 usage();
586
587 startat = atoi(p+1);
588
589 switch (*ndarg) {
590 case 'a':
591 attrExtStart = startat;
592 break;
593 case 'b':
594 blkallocExtStart = startat;
595 break;
596 case 'c':
597 catExtStart = startat;
598 break;
599 case 'e':
600 extExtStart = startat;
601 break;
602 case 'j':
603 jibStart = startat;
604 break;
605 case 'J':
606 jnlStart = startat;
607 break;
608 case 'N':
609 allocStart = startat;
610 break;
611 default:
612 usage();
613 }
614 }
615 }
616 #endif
617
618 gid_t
619 static a_gid(char *s)
620 {
621 struct group *gr;
622 char *gname;
623 gid_t gid = 0;
624
625 if ((gr = getgrnam(s)) != NULL)
626 gid = gr->gr_gid;
627 else {
628 for (gname = s; *s && isdigit(*s); ++s);
629 if (!*s)
630 gid = atoi(gname);
631 else
632 errx(1, "unknown group id: %s", gname);
633 }
634 return (gid);
635 }
636
637 static uid_t
638 a_uid(char *s)
639 {
640 struct passwd *pw;
641 char *uname;
642 uid_t uid = 0;
643
644 if ((pw = getpwnam(s)) != NULL)
645 uid = pw->pw_uid;
646 else {
647 for (uname = s; *s && isdigit(*s); ++s);
648 if (!*s)
649 uid = atoi(uname);
650 else
651 errx(1, "unknown user id: %s", uname);
652 }
653 return (uid);
654 }
655
656 static mode_t
657 a_mask(char *s)
658 {
659 int done, rv;
660 char *ep;
661
662 done = 0;
663 rv = -1;
664 if (*s >= '0' && *s <= '7') {
665 done = 1;
666 rv = strtol(s, &ep, 8);
667 }
668 if (!done || rv < 0 || *ep)
669 errx(1, "invalid access mask: %s", s);
670 return (rv);
671 }
672
673 /*
674 * Check to see if the volume is too big.
675 *
676 * Returns:
677 * 0 if it is appropriately sized.
678 * 1 if HFS+ cannot be formatted onto the disk.
679 */
680
681 static int bad_disk_size (u_int64_t numsectors, u_int64_t sectorsize) {
682
683 u_int32_t maxSectorBits = 0;
684 u_int32_t maxSectorSizeBits = 0;
685 u_int32_t maxBits = 0;
686 u_int64_t bytes;
687
688 /*
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.
692 */
693
694 maxSectorBits = get_high_bit (numsectors);
695 maxSectorSizeBits = get_high_bit (sectorsize);
696
697 /*
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.
701 */
702
703 maxBits = maxSectorBits + maxSectorSizeBits;
704 if (maxBits > 63) {
705 return 1;
706 }
707
708 /* Well, now we know that the two values won't overflow. Time to multiply */
709 bytes = numsectors * sectorsize;
710
711 if (bytes > MAXHFSVOLSIZE) {
712 /* Too big! */
713 return 1;
714 }
715
716 /* Otherwise, it looks good */
717 return 0;
718
719 }
720
721 /*
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.
725 *
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.
728 *
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.
732 *
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.
735 */
736 #define NUM_ALLOC_BLOCKSIZES 21
737 #define GROWTH_BOUNDARY 41
738
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 */
762 };
763
764 static int get_high_bit (u_int64_t bitstring) {
765 u_int64_t bits = bitstring;
766 int counter = 0;
767 while (bits) {
768 bits = (bits >> 1);
769 counter++;
770 }
771 return counter;
772 }
773
774
775 /*
776 * Validate the HFS Plus allocation block size in gBlockSize. If none was
777 * specified, then calculate a suitable default.
778 *
779 * Modifies the global variable gBlockSize.
780 */
781 static void validate_hfsplus_block_size(UInt64 sectorCount, UInt32 sectorSize)
782 {
783 if (gBlockSize == 0) {
784
785 /* Start by calculating the fs size */
786 u_int64_t fs_size = sectorCount * sectorSize;
787
788 /*
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.
793 *
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.
801 */
802
803 gBlockSize = DFL_BLKSIZE; /* Prefer the default of 4K */
804
805 int bit_index = get_high_bit (fs_size);
806 bit_index -= GROWTH_BOUNDARY;
807
808 /*
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.
813 */
814 if ((bit_index >= 0) && (bit_index < 22)) {
815 gBlockSize = alloc_blocksize[bit_index];
816 }
817
818 if (bit_index >= 22) {
819 fatal("Error: Disk Device is too big (%llu sectors, %d bytes per sector", sectorCount, sectorSize);
820 }
821 }
822 else {
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);
826 }
827
828 if ((sectorCount / (gBlockSize / sectorSize)) > 0xFFFFFFFF) {
829 fatal("%s: block size is too small for %lld sectors", optarg, gBlockSize, sectorCount);
830 }
831
832 if (gBlockSize < HFSOPTIMALBLKSIZE) {
833 warnx("Warning: %u is a non-optimal block size (4096 would be a better choice)", (unsigned int)gBlockSize);
834 }
835 }
836
837 if (gFSStartBlock) {
838 u_int64_t fs_size = sectorCount * sectorSize;
839 u_int32_t totalBlocks = fs_size/gBlockSize;
840
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");
844 gFSStartBlock = 0;
845 }
846 }
847 }
848
849
850
851 static int
852 hfs_newfs(char *device)
853 {
854 struct stat stbuf;
855 DriveInfo dip = { 0 };
856 int fso = -1;
857 int retval = 0;
858 hfsparams_t defaults = {0};
859 UInt64 maxPhysPerIO = 0;
860
861 if (gPartitionSize) {
862 dip.sectorSize = kBytesPerSector;
863 dip.physTotalSectors = dip.totalSectors = gPartitionSize / kBytesPerSector;
864 dip.physSectorSize = kBytesPerSector; /* 512-byte sectors */
865 dip.fd = 0;
866 } else {
867 if (gNoCreate) {
868 fso = open( device, O_RDONLY | O_NDELAY, 0 );
869 } else {
870 fso = open( device, O_RDWR | O_NDELAY, 0 );
871 }
872 if (fso == -1) {
873 return -1;
874 }
875
876 dip.fd = fso;
877 fcntl(fso, F_NOCACHE, 1);
878
879 if (fso < 0)
880 fatal("%s: %s", device, strerror(errno));
881
882 if (fstat( fso, &stbuf) < 0)
883 fatal("%s: %s", device, strerror(errno));
884
885 if (ioctl(fso, DKIOCGETBLOCKSIZE, &dip.physSectorSize) < 0)
886 fatal("%s: %s", device, strerror(errno));
887
888 if ((dip.physSectorSize % kBytesPerSector) != 0)
889 fatal("%d is an unsupported sector size\n", dip.physSectorSize);
890
891 if (ioctl(fso, DKIOCGETBLOCKCOUNT, &dip.physTotalSectors) < 0)
892 fatal("%s: %s", device, strerror(errno));
893
894 }
895
896 dip.physSectorsPerIO = (1024 * 1024) / dip.physSectorSize; /* use 1M as default */
897
898 if (fso != -1 && ioctl(fso, DKIOCGETMAXBLOCKCOUNTREAD, &maxPhysPerIO) < 0)
899 fatal("%s: %s", device, strerror(errno));
900
901 if (maxPhysPerIO)
902 dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO);
903
904 if (fso != -1 && ioctl(fso, DKIOCGETMAXBLOCKCOUNTWRITE, &maxPhysPerIO) < 0)
905 fatal("%s: %s", device, strerror(errno));
906
907 if (maxPhysPerIO)
908 dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO);
909
910 if (fso != -1 && ioctl(fso, DKIOCGETMAXBYTECOUNTREAD, &maxPhysPerIO) < 0)
911 fatal("%s: %s", device, strerror(errno));
912
913 if (maxPhysPerIO)
914 dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO / dip.physSectorSize);
915
916 if (fso != -1 && ioctl(fso, DKIOCGETMAXBYTECOUNTWRITE, &maxPhysPerIO) < 0)
917 fatal("%s: %s", device, strerror(errno));
918
919 if (maxPhysPerIO)
920 dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO / dip.physSectorSize);
921
922 dip.sectorSize = kBytesPerSector;
923 dip.totalSectors = dip.physTotalSectors * dip.physSectorSize / dip.sectorSize;
924
925 dip.sectorOffset = 0;
926 time(&createtime);
927
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);
932 }
933
934 /*
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.
938 */
939 validate_hfsplus_block_size(dip.totalSectors, dip.sectorSize);
940
941 /* Make an HFS Plus disk */
942
943 if ((dip.totalSectors * dip.sectorSize ) < kMinHFSPlusVolumeSize)
944 fatal("%s: partition is too small (minimum is %d KB)", device, kMinHFSPlusVolumeSize/1024);
945
946 hfsplus_params(&dip, &defaults);
947 if (gNoCreate == 0) {
948 retval = make_hfsplus(&dip, &defaults);
949 if (retval == 0) {
950 printf("Initialized %s as a ", device);
951 if (dip.totalSectors > 2048ULL*1024*1024)
952 printf("%ld TB",
953 (long)((dip.totalSectors + (1024ULL*1024*1024))/(2048ULL*1024*1024)));
954 else if (dip.totalSectors > 2048*1024)
955 printf("%ld GB",
956 (long)((dip.totalSectors + (1024*1024))/(2048*1024)));
957 else if (dip.totalSectors > 2048)
958 printf("%ld MB",
959 (long)((dip.totalSectors + 1024)/2048));
960 else
961 printf("%ld KB",
962 (long)((dip.totalSectors + 1)/2));
963
964 if (gCaseSensitive) {
965 printf(" case-sensitive");
966 }
967 else {
968 printf(" case-insensitive");
969 }
970 if (gJournaled)
971 printf(" HFS Plus volume with a %uk journal\n",
972 (u_int32_t)defaults.journalSize/1024);
973 else
974 printf(" HFS Plus volume\n");
975 }
976 }
977
978 if (retval)
979 fatal("%s: %s", device, strerror(errno));
980
981 if ( fso > 0 ) {
982 close(fso);
983 }
984
985 return retval;
986 }
987
988 /*
989 typedef struct block_info {
990 off_t bnum; //64 bit
991 union {
992 _blk_info bi; //64 bit
993 struct buf *bp; //64 bit on K64, 32 bit on K32
994 } u;
995 }__attribute__((__packed__)) block_info;
996
997 total size == 16 bytes
998 */
999
1000 #define BLOCK_INFO_SIZE 16
1001
1002 static void hfsplus_params (const DriveInfo* dip, hfsparams_t *defaults)
1003 {
1004 UInt64 sectorCount = dip->totalSectors;
1005 UInt32 sectorSize = dip->sectorSize;
1006 uint32_t totalBlocks;
1007 UInt32 minClumpSize;
1008 UInt32 clumpSize;
1009 UInt32 initialSize;
1010 UInt32 oddBitmapBytes;
1011
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;
1020
1021 /*
1022 * 8429818
1023 * Always set kUseAccessPerms now; this also
1024 * means we have to always have an owner, group,
1025 * and mask.
1026 */
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;
1031
1032 /*
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
1036 * allocation block.
1037 *
1038 * Only scale if it's the default, otherwise just take what
1039 * the user specified, with the caveat below.
1040 */
1041 if (gJournaled) {
1042 uint32_t min_size = 0;
1043
1044 /*
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.
1051 *
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
1058 * should be:
1059 *
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
1064 *
1065 * This becomes our new _floor_ for the journal_size.
1066 */
1067
1068 if (dip->physSectorSize != 0) {
1069 min_size = dip->physSectorSize * (dip->physSectorSize / BLOCK_INFO_SIZE);
1070 }
1071
1072 if (gJournalSize != 0) {
1073
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);
1078 gJournalSize = 0;
1079
1080 }
1081 /* defaults->journalSize will get reset below if it is 0 */
1082 defaults->journalSize = gJournalSize;
1083 }
1084
1085 if ((gJournalSize == 0) || (defaults->journalSize == 0)) {
1086 UInt32 jscale;
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);
1090 if (jscale > 64) {
1091 jscale = 64;
1092 }
1093
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;
1098 }
1099
1100 defaults->journalSize = target_size;
1101 }
1102
1103
1104 #ifndef DEBUG_BUILD
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.
1117 //
1118 if (sectorCount * sectorSize < 128*1024*1024) {
1119 /* This is a small (<128MB) FS */
1120 uint32_t small_default = (512 * 1024);
1121
1122 if (small_default <= min_size) {
1123 /*
1124 * If 512k is too small given the sector size,
1125 * then use the larger sector size
1126 */
1127 defaults->journalSize = min_size;
1128 }
1129 else {
1130 /* 512k was bigger than the min size; we can use it */
1131 defaults->journalSize = small_default;
1132 }
1133 }
1134 #endif
1135
1136 if (defaults->journalSize > 512 * 1024 * 1024) {
1137 defaults->journalSize = 512 * 1024 * 1024;
1138 }
1139
1140 if (defaults->journalSize < defaults->blockSize) {
1141 defaults->journalSize = defaults->blockSize;
1142 }
1143 }
1144
1145 defaults->volumeName = (unsigned char*)gVolumeName;
1146
1147 if (rsrclumpblks == 0) {
1148 if (gBlockSize > DFL_BLKSIZE)
1149 defaults->rsrcClumpSize = ROUNDUP(kHFSPlusRsrcClumpFactor * DFL_BLKSIZE, gBlockSize);
1150 else
1151 defaults->rsrcClumpSize = kHFSPlusRsrcClumpFactor * gBlockSize;
1152 } else
1153 defaults->rsrcClumpSize = clumpsizecalc(rsrclumpblks);
1154
1155 if (datclumpblks == 0) {
1156 if (gBlockSize > DFL_BLKSIZE)
1157 defaults->dataClumpSize = ROUNDUP(kHFSPlusDataClumpFactor * DFL_BLKSIZE, gBlockSize);
1158 else
1159 defaults->dataClumpSize = kHFSPlusDataClumpFactor * gBlockSize;
1160 } else
1161 defaults->dataClumpSize = clumpsizecalc(datclumpblks);
1162
1163 /*
1164 * The default b-tree node size is 8K. However, if the
1165 * volume is small (< 1 GB) we use 4K instead.
1166 */
1167 if (!gUserCatNodeSize) {
1168 if ((gBlockSize < HFSOPTIMALBLKSIZE) ||
1169 ((UInt64)(sectorCount * sectorSize) < (UInt64)0x40000000))
1170 catnodesiz = 4096;
1171 }
1172
1173 if (catclumpblks == 0) {
1174 clumpSize = CalcHFSPlusBTreeClumpSize(gBlockSize, catnodesiz, sectorCount, kHFSCatalogFileID);
1175 }
1176 else {
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);
1180 }
1181 if (catinitialblks == 0) {
1182 initialSize = CalcHFSPlusBTreeClumpSize(gBlockSize, catnodesiz, sectorCount, kHFSCatalogFileID);
1183 }
1184 else {
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);
1188 }
1189 if (initialSize < clumpSize) {
1190 fatal("c=%ld: initial size is less than clump size\n", initialSize/gBlockSize);
1191 }
1192 defaults->catalogClumpSize = clumpSize;
1193 defaults->catalogInitialSize = initialSize;
1194 defaults->catalogNodeSize = catnodesiz;
1195 defaults->catalogExtsCount = catExtCount;
1196 defaults->catalogStartBlock = catExtStart;
1197
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);
1200
1201 if (extclumpblks == 0) {
1202 clumpSize = CalcHFSPlusBTreeClumpSize(gBlockSize, extnodesiz, sectorCount, kHFSExtentsFileID);
1203 }
1204 else {
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);
1208 }
1209 if (extinitialblks == 0) {
1210 initialSize = CalcHFSPlusBTreeClumpSize(gBlockSize, extnodesiz, sectorCount, kHFSExtentsFileID);
1211 }
1212 else {
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);
1216 }
1217 if (initialSize < clumpSize) {
1218 fatal("e=%ld: initial size is less than clump size\n", initialSize/gBlockSize);
1219 }
1220 defaults->extentsClumpSize = clumpSize;
1221 defaults->extentsInitialSize = initialSize;
1222 defaults->extentsNodeSize = extnodesiz;
1223 defaults->extentsExtsCount = extExtCount;
1224 defaults->extentsStartBlock = extExtStart;
1225
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;
1231 }
1232
1233 if (atrclumpblks == 0) {
1234 clumpSize = CalcHFSPlusBTreeClumpSize(gBlockSize, atrnodesiz, sectorCount, kHFSAttributesFileID);
1235 }
1236 else {
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);
1240 }
1241 if (atrinitialblks == 0) {
1242 if (gUserAttrSize) {
1243 initialSize = 0;
1244 }
1245 else {
1246 initialSize = CalcHFSPlusBTreeClumpSize(gBlockSize, atrnodesiz, sectorCount, kHFSAttributesFileID);
1247 }
1248 }
1249 else {
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);
1253 }
1254 if (initialSize) {
1255 if (initialSize < clumpSize) {
1256 fatal("a=%ld: initial size is less than clump size\n", initialSize/gBlockSize);
1257 }
1258 }
1259 defaults->attributesClumpSize = clumpSize;
1260 defaults->attributesInitialSize = initialSize;
1261 defaults->attributesNodeSize = atrnodesiz;
1262 defaults->attributesExtsCount = attrExtCount;
1263 defaults->attributesStartBlock = attrExtStart;
1264
1265 /*
1266 * Calculate the number of blocks needed for bitmap (rounded up to a multiple of the block size).
1267 */
1268
1269 /*
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
1273 */
1274 totalBlocks = sectorCount / (gBlockSize / sectorSize);
1275
1276 minClumpSize = totalBlocks >> 3; /* convert bits to bytes by dividing by 8 */
1277 if (totalBlocks & 7)
1278 ++minClumpSize; /* round up to whole bytes */
1279
1280 /* Round up to a multiple of blockSize */
1281 if ((oddBitmapBytes = minClumpSize % gBlockSize))
1282 minClumpSize = minClumpSize - oddBitmapBytes + gBlockSize;
1283
1284 if (bmclumpblks == 0) {
1285 clumpSize = minClumpSize;
1286 }
1287 else {
1288 clumpSize = clumpsizecalc(bmclumpblks);
1289
1290 if (clumpSize < minClumpSize)
1291 fatal("b=%ld: bitmap clump size is too small\n", clumpSize/gBlockSize);
1292 }
1293 defaults->allocationClumpSize = clumpSize;
1294 defaults->allocationExtsCount = blkallocExtCount;
1295 defaults->allocationStartBlock = blkallocExtStart;
1296
1297 defaults->journalInfoBlock = jibStart;
1298 defaults->journalBlock = jnlStart;
1299 defaults->nextAllocBlock = allocStart;
1300
1301 if (gCaseSensitive)
1302 defaults->flags |= kMakeCaseSensitive;
1303
1304 if (gContentProtect)
1305 defaults->flags |= kMakeContentProtect;
1306
1307 #ifdef DEBUG_BUILD
1308 if (gProtectLevel)
1309 defaults->protectlevel = gProtectLevel;
1310 #endif
1311
1312 if (gNoCreate) {
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);
1319 if (gJournaled)
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);
1339 }
1340 printf("\tfile system start block: %u\n", defaults->fsStartBlock);
1341 }
1342 }
1343
1344
1345 static UInt32
1346 initialsizecalc(UInt32 initialblocks)
1347 {
1348 UInt64 initialsize;
1349
1350 initialsize = (UInt64)initialblocks * (UInt64)gBlockSize;
1351
1352 if (initialsize & (UInt64)(0xFFFFFFFF00000000ULL))
1353 fatal("=%ld: too many blocks for initial size!", initialblocks);
1354
1355 return ((UInt32)initialsize);
1356 }
1357
1358
1359 static UInt32
1360 clumpsizecalc(UInt32 clumpblocks)
1361 {
1362 UInt64 clumpsize;
1363
1364 clumpsize = (UInt64)clumpblocks * (UInt64)gBlockSize;
1365
1366 if (clumpsize & (UInt64)(0xFFFFFFFF00000000ULL))
1367 fatal("=%ld: too many blocks for clump size!", clumpblocks);
1368
1369 return ((UInt32)clumpsize);
1370 }
1371
1372
1373 #define CLUMP_ENTRIES 15
1374
1375 short clumptbl[CLUMP_ENTRIES * 3] = {
1376 /*
1377 * Volume Attributes Catalog Extents
1378 * Size Clump (MB) Clump (MB) Clump (MB)
1379 */
1380 /* 1GB */ 4, 4, 4,
1381 /* 2GB */ 6, 6, 4,
1382 /* 4GB */ 8, 8, 4,
1383 /* 8GB */ 11, 11, 5,
1384 /*
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.
1389 *
1390 * For SnowLeopard 10A298, a FullNetInstall with all packages selected
1391 * results in:
1392 * Catalog B-tree Header
1393 * nodeSize: 8192
1394 * totalNodes: 31616
1395 * freeNodes: 1978
1396 * (used = 231.55 MB)
1397 * Attributes B-tree Header
1398 * nodeSize: 8192
1399 * totalNodes: 63232
1400 * freeNodes: 958
1401 * (used = 486.52 MB)
1402 *
1403 * We also want Time Machine backup volumes to have a sufficiently
1404 * large clump size to reduce fragmentation.
1405 *
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
1410 * previous term.
1411 */
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
1423 };
1424
1425 /*
1426 * CalcHFSPlusBTreeClumpSize
1427 *
1428 * This routine calculates the file clump size for either
1429 * the catalog file or the extents overflow file.
1430 */
1431 static UInt32
1432 CalcHFSPlusBTreeClumpSize(UInt32 blockSize, UInt32 nodeSize, UInt64 sectors, int fileID)
1433 {
1434 UInt32 mod = MAX(nodeSize, blockSize);
1435 UInt32 clumpSize;
1436 int column;
1437 int i;
1438
1439 /* Figure out which column of the above table to use for this file. */
1440 switch (fileID) {
1441 case kHFSAttributesFileID:
1442 column = 0;
1443 break;
1444 case kHFSCatalogFileID:
1445 column = 1;
1446 break;
1447 default:
1448 column = 2;
1449 break;
1450 }
1451
1452 /*
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.
1455 */
1456 if (sectors < 0x200000) {
1457 clumpSize = sectors << 2; /* 0.8 % */
1458 if (clumpSize < (8 * nodeSize))
1459 clumpSize = 8 * nodeSize;
1460 } else {
1461 /*
1462 * XXX This should scale more smoothly!
1463 */
1464 /* turn exponent into table index... */
1465 for (i = 0, sectors = sectors >> 22;
1466 sectors && (i < CLUMP_ENTRIES-1);
1467 ++i, sectors = sectors >> 1);
1468
1469 clumpSize = clumptbl[column + (i) * 3] * 1024 * 1024;
1470 }
1471
1472 /*
1473 * Round the clump size to a multiple of node and block size.
1474 * NOTE: This rounds down.
1475 */
1476 clumpSize /= mod;
1477 clumpSize *= mod;
1478
1479 /*
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.
1482 */
1483 if (clumpSize == 0)
1484 clumpSize = mod;
1485
1486 return (clumpSize);
1487 }
1488
1489
1490 /* VARARGS */
1491 void
1492 #if __STDC__
1493 fatal(const char *fmt, ...)
1494 #else
1495 fatal(fmt, va_alist)
1496 char *fmt;
1497 va_dcl
1498 #endif
1499 {
1500 va_list ap;
1501
1502 #if __STDC__
1503 va_start(ap, fmt);
1504 #else
1505 va_start(ap);
1506 #endif
1507 if (fcntl(STDERR_FILENO, F_GETFL) < 0) {
1508 openlog(progname, LOG_CONS, LOG_DAEMON);
1509 vsyslog(LOG_ERR, fmt, ap);
1510 closelog();
1511 } else {
1512 vwarnx(fmt, ap);
1513 }
1514 va_end(ap);
1515 exit(1);
1516 /* NOTREACHED */
1517 }
1518
1519
1520 void usage()
1521 {
1522 fprintf(stderr, "usage: %s [-N [partition-size]] [hfsplus-options] special-device\n", progname);
1523
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");
1527
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");
1552 #ifdef DEBUG_BUILD
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");
1564 #endif
1565
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);
1570
1571 exit(1);
1572 }