1 /* $NetBSD: mkfs.c,v 1.70 2003/05/02 03:26:11 atatat Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Networks Associates Technology, Inc. 5 * All rights reserved. 6 * 7 * This software was developed for the FreeBSD Project by Marshall 8 * Kirk McKusick and Network Associates Laboratories, the Security 9 * Research Division of Network Associates, Inc. under DARPA/SPAWAR 10 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 11 * research program 12 * 13 * Copyright (c) 1980, 1989, 1993 14 * The Regents of the University of California. All rights reserved. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 */ 44 45 #include <sys/cdefs.h> 46 #ifndef lint 47 #if 0 48 static char sccsid[] = "@(#)mkfs.c 8.11 (Berkeley) 5/3/95"; 49 #else 50 __RCSID("$NetBSD: mkfs.c,v 1.70 2003/05/02 03:26:11 atatat Exp $"); 51 #endif 52 #endif /* not lint */ 53 54 #include <sys/param.h> 55 #include <sys/mman.h> 56 #include <sys/time.h> 57 #include <sys/resource.h> 58 #include <ufs/ufs/dinode.h> 59 #include <ufs/ufs/dir.h> 60 #include <ufs/ufs/ufs_bswap.h> 61 #include <ufs/ffs/fs.h> 62 #include <ufs/ffs/ffs_extern.h> 63 #include <sys/disklabel.h> 64 65 #include <err.h> 66 #include <errno.h> 67 #include <string.h> 68 #include <unistd.h> 69 #include <stdlib.h> 70 71 #ifndef STANDALONE 72 #include <stdio.h> 73 #endif 74 75 #include "extern.h" 76 77 union dinode { 78 struct ufs1_dinode dp1; 79 struct ufs2_dinode dp2; 80 }; 81 82 static void initcg(int, const struct timeval *); 83 static int fsinit(const struct timeval *, mode_t, uid_t, gid_t); 84 static int makedir(struct direct *, int); 85 static daddr_t alloc(int, int); 86 static void iput(union dinode *, ino_t); 87 static void rdfs(daddr_t, int, void *); 88 static void wtfs(daddr_t, int, void *); 89 static int isblock(struct fs *, unsigned char *, int); 90 static void clrblock(struct fs *, unsigned char *, int); 91 static void setblock(struct fs *, unsigned char *, int); 92 static int ilog2(int); 93 #ifdef MFS 94 static void calc_memfree(void); 95 static void *mkfs_malloc(size_t size); 96 #endif 97 98 static int count_digits(int); 99 100 /* 101 * make file system for cylinder-group style file systems 102 */ 103 #define UMASK 0755 104 #define POWEROF2(num) (((num) & ((num) - 1)) == 0) 105 106 union { 107 struct fs fs; 108 char pad[SBLOCKSIZE]; 109 } fsun; 110 #define sblock fsun.fs 111 struct csum *fscs; 112 113 union { 114 struct cg cg; 115 char pad[MAXBSIZE]; 116 } cgun; 117 #define acg cgun.cg 118 119 #define DIP(dp, field) \ 120 ((sblock.fs_magic == FS_UFS1_MAGIC) ? \ 121 (dp)->dp1.di_##field : (dp)->dp2.di_##field) 122 123 char *iobuf; 124 int iobufsize; 125 126 char writebuf[MAXBSIZE]; 127 128 int fsi, fso; 129 130 void 131 mkfs(struct partition *pp, const char *fsys, int fi, int fo, 132 mode_t mfsmode, uid_t mfsuid, gid_t mfsgid) 133 { 134 int fragsperinode, optimalfpg, origdensity, minfpg, lastminfpg; 135 int32_t cylno, i, csfrags; 136 struct timeval tv; 137 long long sizepb; 138 char *writebuf2; /* dynamic buffer */ 139 int nprintcols, printcolwidth; 140 141 #ifndef STANDALONE 142 gettimeofday(&tv, NULL); 143 #endif 144 #ifdef MFS 145 if (mfs) { 146 calc_memfree(); 147 if (fssize * sectorsize > memleft) 148 fssize = memleft / sectorsize; 149 if ((membase = mkfs_malloc(fssize * sectorsize)) == 0) 150 exit(12); 151 } 152 #endif 153 fsi = fi; 154 fso = fo; 155 if (Oflag == 0) { 156 sblock.fs_old_inodefmt = FS_42INODEFMT; 157 sblock.fs_maxsymlinklen = 0; 158 sblock.fs_old_flags = 0; 159 } else { 160 sblock.fs_old_inodefmt = FS_44INODEFMT; 161 sblock.fs_maxsymlinklen = (Oflag == 1 ? MAXSYMLINKLEN_UFS1 : 162 MAXSYMLINKLEN_UFS2); 163 sblock.fs_old_flags = FS_FLAGS_UPDATED; 164 sblock.fs_flags = 0; 165 } 166 /* 167 * Validate the given file system size. 168 * Verify that its last block can actually be accessed. 169 * Convert to file system fragment sized units. 170 */ 171 if (fssize <= 0) { 172 printf("preposterous size %lld\n", (long long)fssize); 173 exit(13); 174 } 175 wtfs(fssize - 1, sectorsize, (char *)&sblock); 176 177 if (isappleufs) { 178 struct appleufslabel appleufs; 179 ffs_appleufs_set(&appleufs,appleufs_volname,tv.tv_sec); 180 wtfs(APPLEUFS_LABEL_OFFSET/sectorsize,APPLEUFS_LABEL_SIZE,&appleufs); 181 } 182 183 /* 184 * collect and verify the filesystem density info 185 */ 186 sblock.fs_avgfilesize = avgfilesize; 187 sblock.fs_avgfpdir = avgfpdir; 188 if (sblock.fs_avgfilesize <= 0) 189 printf("illegal expected average file size %d\n", 190 sblock.fs_avgfilesize), exit(14); 191 if (sblock.fs_avgfpdir <= 0) 192 printf("illegal expected number of files per directory %d\n", 193 sblock.fs_avgfpdir), exit(15); 194 /* 195 * collect and verify the block and fragment sizes 196 */ 197 sblock.fs_bsize = bsize; 198 sblock.fs_fsize = fsize; 199 if (!POWEROF2(sblock.fs_bsize)) { 200 printf("block size must be a power of 2, not %d\n", 201 sblock.fs_bsize); 202 exit(16); 203 } 204 if (!POWEROF2(sblock.fs_fsize)) { 205 printf("fragment size must be a power of 2, not %d\n", 206 sblock.fs_fsize); 207 exit(17); 208 } 209 if (sblock.fs_fsize < sectorsize) { 210 printf("fragment size %d is too small, minimum is %d\n", 211 sblock.fs_fsize, sectorsize); 212 exit(18); 213 } 214 if (sblock.fs_bsize < MINBSIZE) { 215 printf("block size %d is too small, minimum is %d\n", 216 sblock.fs_bsize, MINBSIZE); 217 exit(19); 218 } 219 if (sblock.fs_bsize > MAXBSIZE) { 220 printf("block size %d is too large, maximum is %d\n", 221 sblock.fs_bsize, MAXBSIZE); 222 exit(19); 223 } 224 if (sblock.fs_bsize < sblock.fs_fsize) { 225 printf("block size (%d) cannot be smaller than fragment size (%d)\n", 226 sblock.fs_bsize, sblock.fs_fsize); 227 exit(20); 228 } 229 230 if (maxbsize < bsize || !POWEROF2(maxbsize)) { 231 sblock.fs_maxbsize = sblock.fs_bsize; 232 } else if (sblock.fs_maxbsize > FS_MAXCONTIG * sblock.fs_bsize) { 233 sblock.fs_maxbsize = FS_MAXCONTIG * sblock.fs_bsize; 234 } else { 235 sblock.fs_maxbsize = maxbsize; 236 } 237 sblock.fs_maxcontig = maxcontig; 238 if (sblock.fs_maxcontig < sblock.fs_maxbsize / sblock.fs_bsize) { 239 sblock.fs_maxcontig = sblock.fs_maxbsize / sblock.fs_bsize; 240 printf("Maxcontig raised to %d\n", sblock.fs_maxbsize); 241 } 242 if (sblock.fs_maxcontig > 1) 243 sblock.fs_contigsumsize = MIN(sblock.fs_maxcontig,FS_MAXCONTIG); 244 245 sblock.fs_bmask = ~(sblock.fs_bsize - 1); 246 sblock.fs_fmask = ~(sblock.fs_fsize - 1); 247 sblock.fs_qbmask = ~sblock.fs_bmask; 248 sblock.fs_qfmask = ~sblock.fs_fmask; 249 for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1) 250 sblock.fs_bshift++; 251 for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1) 252 sblock.fs_fshift++; 253 sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize); 254 for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1) 255 sblock.fs_fragshift++; 256 if (sblock.fs_frag > MAXFRAG) { 257 printf("fragment size %d is too small, " 258 "minimum with block size %d is %d\n", 259 sblock.fs_fsize, sblock.fs_bsize, 260 sblock.fs_bsize / MAXFRAG); 261 exit(21); 262 } 263 sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / sectorsize); 264 sblock.fs_size = fssize = dbtofsb(&sblock, fssize); 265 if (Oflag <= 1) { 266 sblock.fs_magic = FS_UFS1_MAGIC; 267 sblock.fs_sblockloc = SBLOCK_UFS1; 268 sblock.fs_nindir = sblock.fs_bsize / sizeof(int32_t); 269 sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode); 270 sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * 271 sizeof (int32_t)); 272 sblock.fs_old_inodefmt = FS_44INODEFMT; 273 sblock.fs_old_cgoffset = 0; 274 sblock.fs_old_cgmask = 0xffffffff; 275 sblock.fs_old_size = sblock.fs_size; 276 sblock.fs_old_rotdelay = 0; 277 sblock.fs_old_rps = 60; 278 sblock.fs_old_nspf = sblock.fs_fsize / sectorsize; 279 sblock.fs_old_cpg = 1; 280 sblock.fs_old_interleave = 1; 281 sblock.fs_old_trackskew = 0; 282 sblock.fs_old_cpc = 0; 283 sblock.fs_old_postblformat = 1; 284 sblock.fs_old_nrpos = 1; 285 } else { 286 sblock.fs_magic = FS_UFS2_MAGIC; 287 sblock.fs_sblockloc = SBLOCK_UFS2; 288 sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t); 289 sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode); 290 sblock.fs_maxsymlinklen = ((NDADDR + NIADDR) * 291 sizeof (int64_t)); 292 } 293 294 sblock.fs_sblkno = 295 roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize), 296 sblock.fs_frag); 297 sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno + 298 roundup(howmany(SBLOCKSIZE, sblock.fs_fsize), sblock.fs_frag)); 299 sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag; 300 sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1; 301 for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) { 302 sizepb *= NINDIR(&sblock); 303 sblock.fs_maxfilesize += sizepb; 304 } 305 306 /* 307 * Calculate the number of blocks to put into each cylinder group. 308 * 309 * This algorithm selects the number of blocks per cylinder 310 * group. The first goal is to have at least enough data blocks 311 * in each cylinder group to meet the density requirement. Once 312 * this goal is achieved we try to expand to have at least 313 * MINCYLGRPS cylinder groups. Once this goal is achieved, we 314 * pack as many blocks into each cylinder group map as will fit. 315 * 316 * We start by calculating the smallest number of blocks that we 317 * can put into each cylinder group. If this is too big, we reduce 318 * the density until it fits. 319 */ 320 origdensity = density; 321 for (;;) { 322 fragsperinode = MAX(numfrags(&sblock, density), 1); 323 minfpg = fragsperinode * INOPB(&sblock); 324 if (minfpg > sblock.fs_size) 325 minfpg = sblock.fs_size; 326 sblock.fs_ipg = INOPB(&sblock); 327 sblock.fs_fpg = roundup(sblock.fs_iblkno + 328 sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); 329 if (sblock.fs_fpg < minfpg) 330 sblock.fs_fpg = minfpg; 331 sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 332 INOPB(&sblock)); 333 sblock.fs_fpg = roundup(sblock.fs_iblkno + 334 sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); 335 if (sblock.fs_fpg < minfpg) 336 sblock.fs_fpg = minfpg; 337 sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 338 INOPB(&sblock)); 339 if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) 340 break; 341 density -= sblock.fs_fsize; 342 } 343 if (density != origdensity) 344 printf("density reduced from %d to %d\n", origdensity, density); 345 /* 346 * Start packing more blocks into the cylinder group until 347 * it cannot grow any larger, the number of cylinder groups 348 * drops below MINCYLGRPS, or we reach the size requested. 349 */ 350 for ( ; sblock.fs_fpg < maxblkspercg; sblock.fs_fpg += sblock.fs_frag) { 351 sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 352 INOPB(&sblock)); 353 if (sblock.fs_size / sblock.fs_fpg < MINCYLGRPS) 354 break; 355 if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize) 356 continue; 357 if (CGSIZE(&sblock) == (unsigned long)sblock.fs_bsize) 358 break; 359 sblock.fs_fpg -= sblock.fs_frag; 360 sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 361 INOPB(&sblock)); 362 break; 363 } 364 /* 365 * Check to be sure that the last cylinder group has enough blocks 366 * to be viable. If it is too small, reduce the number of blocks 367 * per cylinder group which will have the effect of moving more 368 * blocks into the last cylinder group. 369 */ 370 optimalfpg = sblock.fs_fpg; 371 for (;;) { 372 sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg); 373 lastminfpg = roundup(sblock.fs_iblkno + 374 sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag); 375 if (sblock.fs_size < lastminfpg) { 376 printf("Filesystem size %lld < minimum size of %d\n", 377 (long long)sblock.fs_size, lastminfpg); 378 exit(28); 379 } 380 if (sblock.fs_size % sblock.fs_fpg >= lastminfpg || 381 sblock.fs_size % sblock.fs_fpg == 0) 382 break; 383 sblock.fs_fpg -= sblock.fs_frag; 384 sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode), 385 INOPB(&sblock)); 386 } 387 if (optimalfpg != sblock.fs_fpg) 388 printf("Reduced frags per cylinder group from %d to %d %s\n", 389 optimalfpg, sblock.fs_fpg, "to enlarge last cyl group"); 390 sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock)); 391 sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock); 392 if (Oflag <= 1) { 393 sblock.fs_old_spc = sblock.fs_fpg * sblock.fs_old_nspf; 394 sblock.fs_old_nsect = sblock.fs_old_spc; 395 sblock.fs_old_npsect = sblock.fs_old_spc; 396 sblock.fs_old_ncyl = sblock.fs_ncg; 397 } 398 399 /* 400 * fill in remaining fields of the super block 401 */ 402 sblock.fs_csaddr = cgdmin(&sblock, 0); 403 sblock.fs_cssize = 404 fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum)); 405 fscs = (struct csum *)calloc(1, sblock.fs_cssize); 406 if (fscs == NULL) 407 exit(39); 408 sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs)); 409 if (sblock.fs_sbsize > SBLOCKSIZE) 410 sblock.fs_sbsize = SBLOCKSIZE; 411 sblock.fs_minfree = minfree; 412 sblock.fs_maxcontig = maxcontig; 413 sblock.fs_maxbpg = maxbpg; 414 sblock.fs_optim = opt; 415 sblock.fs_cgrotor = 0; 416 sblock.fs_pendingblocks = 0; 417 sblock.fs_pendinginodes = 0; 418 sblock.fs_cstotal.cs_ndir = 0; 419 sblock.fs_cstotal.cs_nbfree = 0; 420 sblock.fs_cstotal.cs_nifree = 0; 421 sblock.fs_cstotal.cs_nffree = 0; 422 sblock.fs_fmod = 0; 423 sblock.fs_ronly = 0; 424 sblock.fs_state = 0; 425 sblock.fs_clean = FS_ISCLEAN; 426 sblock.fs_ronly = 0; 427 sblock.fs_id[0] = (long)tv.tv_sec; /* XXXfvdl huh? */ 428 sblock.fs_id[1] = random(); 429 sblock.fs_fsmnt[0] = '\0'; 430 csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize); 431 sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno - 432 sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno); 433 sblock.fs_cstotal.cs_nbfree = 434 fragstoblks(&sblock, sblock.fs_dsize) - 435 howmany(csfrags, sblock.fs_frag); 436 sblock.fs_cstotal.cs_nffree = 437 fragnum(&sblock, sblock.fs_size) + 438 (fragnum(&sblock, csfrags) > 0 ? 439 sblock.fs_frag - fragnum(&sblock, csfrags) : 0); 440 sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO; 441 sblock.fs_cstotal.cs_ndir = 0; 442 sblock.fs_dsize -= csfrags; 443 sblock.fs_time = tv.tv_sec; 444 if (Oflag <= 1) { 445 sblock.fs_old_time = tv.tv_sec; 446 sblock.fs_old_dsize = sblock.fs_dsize; 447 sblock.fs_old_csaddr = sblock.fs_csaddr; 448 sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; 449 sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; 450 sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; 451 sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; 452 } 453 /* 454 * Dump out summary information about file system. 455 */ 456 if (!mfs) { 457 #define B2MBFACTOR (1 / (1024.0 * 1024.0)) 458 printf("%s: %.1fMB (%lld sectors) block size %d, " 459 "fragment size %d\n", 460 fsys, (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR, 461 (long long)fsbtodb(&sblock, sblock.fs_size), 462 sblock.fs_bsize, sblock.fs_fsize); 463 printf("\tusing %d cylinder groups of %.2fMB, %d blks, " 464 "%d inodes.\n", 465 sblock.fs_ncg, 466 (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR, 467 sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg); 468 #undef B2MBFACTOR 469 } 470 /* 471 * Now determine how wide each column will be, and calculate how 472 * many columns will fit in a 76 char line. 76 is the width of the 473 * subwindows in sysinst. 474 */ 475 printcolwidth = count_digits( 476 fsbtodb(&sblock, cgsblock(&sblock, sblock.fs_ncg -1))); 477 nprintcols = 76 / (printcolwidth + 2); 478 479 /* 480 * allocate space for superblock, cylinder group map, and 481 * two sets of inode blocks. 482 */ 483 if (sblock.fs_bsize < SBLOCKSIZE) 484 iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize; 485 else 486 iobufsize = 4 * sblock.fs_bsize; 487 if ((iobuf = malloc(iobufsize)) == 0) { 488 printf("Cannot allocate I/O buffer\n"); 489 exit(38); 490 } 491 memset(iobuf, 0, iobufsize); 492 /* 493 * Make a copy of the superblock into the buffer that we will be 494 * writing out in each cylinder group. 495 */ 496 memcpy(writebuf, &sblock, sbsize); 497 if (needswap) 498 ffs_sb_swap(&sblock, (struct fs*)writebuf); 499 memcpy(iobuf, writebuf, SBLOCKSIZE); 500 501 if (!mfs) 502 printf("super-block backups (for fsck -b #) at:"); 503 for (cylno = 0; cylno < sblock.fs_ncg; cylno++) { 504 initcg(cylno, &tv); 505 if (mfs) 506 continue; 507 if (cylno % nprintcols == 0) 508 printf("\n"); 509 printf(" %*lld,", printcolwidth, 510 (long long)fsbtodb(&sblock, cgsblock(&sblock, cylno))); 511 fflush(stdout); 512 } 513 if (!mfs) 514 printf("\n"); 515 if (Nflag && !mfs) 516 exit(0); 517 518 /* 519 * Now construct the initial file system, 520 * then write out the super-block. 521 */ 522 if (fsinit(&tv, mfsmode, mfsuid, mfsgid) == 0 && mfs) 523 errx(1, "Error making filesystem"); 524 sblock.fs_time = tv.tv_sec; 525 if (Oflag <= 1) { 526 sblock.fs_old_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir; 527 sblock.fs_old_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree; 528 sblock.fs_old_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree; 529 sblock.fs_old_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree; 530 } 531 memcpy(writebuf, &sblock, sbsize); 532 if (needswap) 533 ffs_sb_swap(&sblock, (struct fs*)writebuf); 534 wtfs(sblock.fs_sblockloc / sectorsize, sbsize, writebuf); 535 536 /* 537 * if we need to swap, create a buffer for the cylinder summaries 538 * to get swapped to. 539 */ 540 if (needswap) { 541 if ((writebuf2 = malloc(sblock.fs_cssize)) == NULL) 542 exit(12); 543 ffs_csum_swap(fscs, (struct csum*)writebuf2, sblock.fs_cssize); 544 } else 545 writebuf2 = (char *)fscs; 546 547 for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize) 548 wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)), 549 sblock.fs_cssize - i < sblock.fs_bsize ? 550 sblock.fs_cssize - i : sblock.fs_bsize, 551 ((char *)writebuf2) + i); 552 if (writebuf2 != (char *)fscs) 553 free(writebuf2); 554 555 /* 556 * Update information about this partion in pack 557 * label, to that it may be updated on disk. 558 */ 559 if (isappleufs) 560 pp->p_fstype = FS_APPLEUFS; 561 else 562 pp->p_fstype = FS_BSDFFS; 563 pp->p_fsize = sblock.fs_fsize; 564 pp->p_frag = sblock.fs_frag; 565 pp->p_cpg = sblock.fs_fpg; 566 } 567 568 /* 569 * Initialize a cylinder group. 570 */ 571 void 572 initcg(int cylno, const struct timeval *tv) 573 { 574 daddr_t cbase, dmax; 575 int32_t i, j, d, dlower, dupper, blkno; 576 struct csum *cs; 577 struct ufs1_dinode *dp1; 578 struct ufs2_dinode *dp2; 579 int start; 580 581 /* 582 * Determine block bounds for cylinder group. 583 * Allow space for super block summary information in first 584 * cylinder group. 585 */ 586 cbase = cgbase(&sblock, cylno); 587 dmax = cbase + sblock.fs_fpg; 588 if (dmax > sblock.fs_size) 589 dmax = sblock.fs_size; 590 dlower = cgsblock(&sblock, cylno) - cbase; 591 dupper = cgdmin(&sblock, cylno) - cbase; 592 if (cylno == 0) 593 dupper += howmany(sblock.fs_cssize, sblock.fs_fsize); 594 cs = fscs + cylno; 595 memset(&acg, 0, sblock.fs_cgsize); 596 acg.cg_time = tv->tv_sec; 597 acg.cg_magic = CG_MAGIC; 598 acg.cg_cgx = cylno; 599 acg.cg_niblk = sblock.fs_ipg; 600 acg.cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ? 601 sblock.fs_ipg : 2 * INOPB(&sblock); 602 acg.cg_ndblk = dmax - cbase; 603 if (sblock.fs_contigsumsize > 0) 604 acg.cg_nclusterblks = acg.cg_ndblk >> sblock.fs_fragshift; 605 start = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield); 606 if (Oflag == 2) { 607 acg.cg_iusedoff = start; 608 } else { 609 acg.cg_old_ncyl = sblock.fs_old_cpg; 610 acg.cg_old_time = acg.cg_time; 611 acg.cg_time = 0; 612 acg.cg_old_niblk = acg.cg_niblk; 613 acg.cg_niblk = 0; 614 acg.cg_initediblk = 0; 615 acg.cg_old_btotoff = start; 616 acg.cg_old_boff = acg.cg_old_btotoff + 617 sblock.fs_old_cpg * sizeof(int32_t); 618 acg.cg_iusedoff = acg.cg_old_boff + 619 sblock.fs_old_cpg * sizeof(u_int16_t); 620 } 621 acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT); 622 if (sblock.fs_contigsumsize <= 0) { 623 acg.cg_nextfreeoff = acg.cg_freeoff + 624 howmany(sblock.fs_fpg, CHAR_BIT); 625 } else { 626 acg.cg_clustersumoff = acg.cg_freeoff + 627 howmany(sblock.fs_fpg, CHAR_BIT) - sizeof(int32_t); 628 if (isappleufs) { 629 /* Apple PR2216969 gives rationale for this change. 630 * I believe they were mistaken, but we need to 631 * duplicate it for compatibility. -- dbj@NetBSD.org 632 */ 633 acg.cg_clustersumoff += sizeof(int32_t); 634 } 635 acg.cg_clustersumoff = 636 roundup(acg.cg_clustersumoff, sizeof(int32_t)); 637 acg.cg_clusteroff = acg.cg_clustersumoff + 638 (sblock.fs_contigsumsize + 1) * sizeof(int32_t); 639 acg.cg_nextfreeoff = acg.cg_clusteroff + 640 howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT); 641 } 642 if (acg.cg_nextfreeoff > sblock.fs_cgsize) { 643 printf("Panic: cylinder group too big\n"); 644 exit(37); 645 } 646 acg.cg_cs.cs_nifree += sblock.fs_ipg; 647 if (cylno == 0) 648 for (i = 0; i < ROOTINO; i++) { 649 setbit(cg_inosused(&acg, 0), i); 650 acg.cg_cs.cs_nifree--; 651 } 652 if (cylno > 0) { 653 /* 654 * In cylno 0, beginning space is reserved 655 * for boot and super blocks. 656 */ 657 for (d = 0, blkno = 0; d < dlower;) { 658 setblock(&sblock, cg_blksfree(&acg, 0), blkno); 659 if (sblock.fs_contigsumsize > 0) 660 setbit(cg_clustersfree(&acg, 0), blkno); 661 acg.cg_cs.cs_nbfree++; 662 d += sblock.fs_frag; 663 blkno++; 664 } 665 } 666 if ((i = (dupper & (sblock.fs_frag - 1))) != 0) { 667 acg.cg_frsum[sblock.fs_frag - i]++; 668 for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) { 669 setbit(cg_blksfree(&acg, 0), dupper); 670 acg.cg_cs.cs_nffree++; 671 } 672 } 673 for (d = dupper, blkno = dupper >> sblock.fs_fragshift; 674 d + sblock.fs_frag <= acg.cg_ndblk; ) { 675 setblock(&sblock, cg_blksfree(&acg, 0), blkno); 676 if (sblock.fs_contigsumsize > 0) 677 setbit(cg_clustersfree(&acg, 0), blkno); 678 acg.cg_cs.cs_nbfree++; 679 d += sblock.fs_frag; 680 blkno++; 681 } 682 if (d < acg.cg_ndblk) { 683 acg.cg_frsum[acg.cg_ndblk - d]++; 684 for (; d < acg.cg_ndblk; d++) { 685 setbit(cg_blksfree(&acg, 0), d); 686 acg.cg_cs.cs_nffree++; 687 } 688 } 689 if (sblock.fs_contigsumsize > 0) { 690 int32_t *sump = cg_clustersum(&acg, 0); 691 u_char *mapp = cg_clustersfree(&acg, 0); 692 int map = *mapp++; 693 int bit = 1; 694 int run = 0; 695 696 for (i = 0; i < acg.cg_nclusterblks; i++) { 697 if ((map & bit) != 0) { 698 run++; 699 } else if (run != 0) { 700 if (run > sblock.fs_contigsumsize) 701 run = sblock.fs_contigsumsize; 702 sump[run]++; 703 run = 0; 704 } 705 if ((i & (CHAR_BIT - 1)) != (CHAR_BIT - 1)) { 706 bit <<= 1; 707 } else { 708 map = *mapp++; 709 bit = 1; 710 } 711 } 712 if (run != 0) { 713 if (run > sblock.fs_contigsumsize) 714 run = sblock.fs_contigsumsize; 715 sump[run]++; 716 } 717 } 718 *cs = acg.cg_cs; 719 /* 720 * Write out the duplicate super block, the cylinder group map 721 * and two blocks worth of inodes in a single write. 722 */ 723 start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE; 724 memcpy(&iobuf[start], &acg, sblock.fs_cgsize); 725 if (needswap) 726 ffs_cg_swap(&acg, (struct cg*)&iobuf[start], &sblock); 727 start += sblock.fs_bsize; 728 dp1 = (struct ufs1_dinode *)(&iobuf[start]); 729 dp2 = (struct ufs2_dinode *)(&iobuf[start]); 730 for (i = 0; i < acg.cg_initediblk; i++) { 731 if (sblock.fs_magic == FS_UFS1_MAGIC) { 732 /* No need to swap, it'll stay random */ 733 dp1->di_gen = random(); 734 dp1++; 735 } else { 736 dp2->di_gen = random(); 737 dp2++; 738 } 739 } 740 wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf); 741 /* 742 * For the old file system, we have to initialize all the inodes. 743 */ 744 if (Oflag <= 1) { 745 for (i = 2 * sblock.fs_frag; 746 i < sblock.fs_ipg / INOPF(&sblock); 747 i += sblock.fs_frag) { 748 dp1 = (struct ufs1_dinode *)(&iobuf[start]); 749 for (j = 0; j < INOPB(&sblock); j++) { 750 dp1->di_gen = random(); 751 dp1++; 752 } 753 wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i), 754 sblock.fs_bsize, &iobuf[start]); 755 } 756 } 757 } 758 759 /* 760 * initialize the file system 761 */ 762 union dinode node; 763 764 #ifdef LOSTDIR 765 #define PREDEFDIR 3 766 #else 767 #define PREDEFDIR 2 768 #endif 769 770 struct direct root_dir[] = { 771 { ROOTINO, sizeof(struct direct), DT_DIR, 1, "." }, 772 { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." }, 773 #ifdef LOSTDIR 774 { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 10, "lost+found" }, 775 #endif 776 }; 777 struct odirect { 778 u_int32_t d_ino; 779 u_int16_t d_reclen; 780 u_int16_t d_namlen; 781 u_char d_name[MAXNAMLEN + 1]; 782 } oroot_dir[] = { 783 { ROOTINO, sizeof(struct direct), 1, "." }, 784 { ROOTINO, sizeof(struct direct), 2, ".." }, 785 #ifdef LOSTDIR 786 { LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" }, 787 #endif 788 }; 789 #ifdef LOSTDIR 790 struct direct lost_found_dir[] = { 791 { LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 1, "." }, 792 { ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." }, 793 { 0, DIRBLKSIZ, 0, 0, 0 }, 794 }; 795 struct odirect olost_found_dir[] = { 796 { LOSTFOUNDINO, sizeof(struct direct), 1, "." }, 797 { ROOTINO, sizeof(struct direct), 2, ".." }, 798 { 0, DIRBLKSIZ, 0, 0 }, 799 }; 800 #endif 801 char buf[MAXBSIZE]; 802 static void copy_dir(struct direct *, struct direct *); 803 804 int 805 fsinit(const struct timeval *tv, mode_t mfsmode, uid_t mfsuid, gid_t mfsgid) 806 { 807 #ifdef LOSTDIR 808 int i; 809 int dirblksiz = DIRBLKSIZ; 810 if (isappleufs) 811 dirblksiz = APPLEUFS_DIRBLKSIZ; 812 #endif 813 814 /* 815 * initialize the node 816 */ 817 memset(&node, 0, sizeof(node)); 818 819 #ifdef LOSTDIR 820 /* 821 * create the lost+found directory 822 */ 823 if (Oflag == 0) { 824 (void)makedir((struct direct *)olost_found_dir, 2); 825 for (i = dirblksiz; i < sblock.fs_bsize; i += dirblksiz) 826 copy_dir((struct direct*)&olost_found_dir[2], 827 (struct direct*)&buf[i]); 828 } else { 829 (void)makedir(lost_found_dir, 2); 830 for (i = dirblksiz; i < sblock.fs_bsize; i += dirblksiz) 831 copy_dir(&lost_found_dir[2], (struct direct*)&buf[i]); 832 } 833 if (sblock.fs_magic == FS_UFS1_MAGIC) { 834 node.dp1.di_atime = tv->tv_sec; 835 node.dp1.di_atimensec = tv->tv_usec * 1000; 836 node.dp1.di_mtime = tv->tv_sec; 837 node.dp1.di_mtimensec = tv->tv_usec * 1000; 838 node.dp1.di_ctime = tv->tv_sec; 839 node.dp1.di_ctimensec = tv->tv_usec * 1000; 840 node.dp1.di_mode = IFDIR | UMASK; 841 node.dp1.di_nlink = 2; 842 node.dp1.di_size = sblock.fs_bsize; 843 node.dp1.di_db[0] = alloc(node.dp1.di_size, node.dp1.di_mode); 844 if (node.dp1.di_db[0] == 0) 845 return (0); 846 node.dp1.di_blocks = btodb(fragroundup(&sblock, 847 node.dp1.di_size)); 848 node.dp1.di_uid = geteuid(); 849 node.dp1.di_gid = getegid(); 850 wtfs(fsbtodb(&sblock, node.dp1.di_db[0]), node.dp1.di_size, 851 buf); 852 } else { 853 node.dp2.di_atime = tv->tv_sec; 854 node.dp2.di_atimensec = tv->tv_usec * 1000; 855 node.dp2.di_mtime = tv->tv_sec; 856 node.dp2.di_mtimensec = tv->tv_usec * 1000; 857 node.dp2.di_ctime = tv->tv_sec; 858 node.dp2.di_ctimensec = tv->tv_usec * 1000; 859 node.dp2.di_birthtime = tv->tv_sec; 860 node.dp2.di_birthnsec = tv->tv_usec * 1000; 861 node.dp2.di_mode = IFDIR | UMASK; 862 node.dp2.di_nlink = 2; 863 node.dp2.di_size = sblock.fs_bsize; 864 node.dp2.di_db[0] = alloc(node.dp2.di_size, node.dp2.di_mode); 865 if (node.dp2.di_db[0] == 0) 866 return (0); 867 node.dp2.di_blocks = btodb(fragroundup(&sblock, 868 node.dp2.di_size)); 869 node.dp2.di_uid = geteuid(); 870 node.dp2.di_gid = getegid(); 871 wtfs(fsbtodb(&sblock, node.dp2.di_db[0]), node.dp2.di_size, 872 buf); 873 } 874 iput(&node, LOSTFOUNDINO); 875 #endif 876 /* 877 * create the root directory 878 */ 879 if (Oflag <= 1) { 880 if (mfs) { 881 node.dp1.di_mode = IFDIR | mfsmode; 882 node.dp1.di_uid = mfsuid; 883 node.dp1.di_gid = mfsgid; 884 } else { 885 node.dp1.di_mode = IFDIR | UMASK; 886 node.dp1.di_uid = geteuid(); 887 node.dp1.di_gid = getegid(); 888 } 889 node.dp1.di_nlink = PREDEFDIR; 890 if (Oflag == 0) 891 node.dp1.di_size = makedir((struct direct *)oroot_dir, 892 PREDEFDIR); 893 else 894 node.dp1.di_size = makedir(root_dir, PREDEFDIR); 895 node.dp1.di_db[0] = alloc(sblock.fs_fsize, node.dp1.di_mode); 896 if (node.dp1.di_db[0] == 0) 897 return (0); 898 node.dp1.di_blocks = btodb(fragroundup(&sblock, 899 node.dp1.di_size)); 900 wtfs(fsbtodb(&sblock, node.dp1.di_db[0]), sblock.fs_fsize, buf); 901 } else { 902 if (mfs) { 903 node.dp2.di_mode = IFDIR | mfsmode; 904 node.dp2.di_uid = mfsuid; 905 node.dp2.di_gid = mfsgid; 906 } else { 907 node.dp2.di_mode = IFDIR | UMASK; 908 node.dp2.di_uid = geteuid(); 909 node.dp2.di_gid = getegid(); 910 } 911 node.dp2.di_atime = tv->tv_sec; 912 node.dp2.di_atimensec = tv->tv_usec * 1000; 913 node.dp2.di_mtime = tv->tv_sec; 914 node.dp2.di_mtimensec = tv->tv_usec * 1000; 915 node.dp2.di_ctime = tv->tv_sec; 916 node.dp2.di_ctimensec = tv->tv_usec * 1000; 917 node.dp2.di_birthtime = tv->tv_sec; 918 node.dp2.di_birthnsec = tv->tv_usec * 1000; 919 node.dp2.di_nlink = PREDEFDIR; 920 node.dp2.di_size = makedir(root_dir, PREDEFDIR); 921 node.dp2.di_db[0] = alloc(sblock.fs_fsize, node.dp2.di_mode); 922 if (node.dp2.di_db[0] == 0) 923 return (0); 924 node.dp2.di_blocks = btodb(fragroundup(&sblock, 925 node.dp2.di_size)); 926 wtfs(fsbtodb(&sblock, node.dp2.di_db[0]), sblock.fs_fsize, buf); 927 } 928 iput(&node, ROOTINO); 929 return (1); 930 } 931 932 /* 933 * construct a set of directory entries in "buf". 934 * return size of directory. 935 */ 936 int 937 makedir(struct direct *protodir, int entries) 938 { 939 char *cp; 940 int i, spcleft; 941 int dirblksiz = DIRBLKSIZ; 942 if (isappleufs) 943 dirblksiz = APPLEUFS_DIRBLKSIZ; 944 945 memset(buf, 0, DIRBLKSIZ); 946 spcleft = dirblksiz; 947 for (cp = buf, i = 0; i < entries - 1; i++) { 948 protodir[i].d_reclen = DIRSIZ(Oflag == 0, &protodir[i], 0); 949 copy_dir(&protodir[i], (struct direct*)cp); 950 cp += protodir[i].d_reclen; 951 spcleft -= protodir[i].d_reclen; 952 } 953 protodir[i].d_reclen = spcleft; 954 copy_dir(&protodir[i], (struct direct*)cp); 955 return (dirblksiz); 956 } 957 958 /* 959 * allocate a block or frag 960 */ 961 daddr_t 962 alloc(int size, int mode) 963 { 964 int i, frag; 965 daddr_t d, blkno; 966 967 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, &acg); 968 /* fs -> host byte order */ 969 if (needswap) 970 ffs_cg_swap(&acg, &acg, &sblock); 971 if (acg.cg_magic != CG_MAGIC) { 972 printf("cg 0: bad magic number\n"); 973 return (0); 974 } 975 if (acg.cg_cs.cs_nbfree == 0) { 976 printf("first cylinder group ran out of space\n"); 977 return (0); 978 } 979 for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag) 980 if (isblock(&sblock, cg_blksfree(&acg, 0), 981 d >> sblock.fs_fragshift)) 982 goto goth; 983 printf("internal error: can't find block in cyl 0\n"); 984 return (0); 985 goth: 986 blkno = fragstoblks(&sblock, d); 987 clrblock(&sblock, cg_blksfree(&acg, 0), blkno); 988 if (sblock.fs_contigsumsize > 0) 989 clrbit(cg_clustersfree(&acg, 0), blkno); 990 acg.cg_cs.cs_nbfree--; 991 sblock.fs_cstotal.cs_nbfree--; 992 fscs[0].cs_nbfree--; 993 if (mode & IFDIR) { 994 acg.cg_cs.cs_ndir++; 995 sblock.fs_cstotal.cs_ndir++; 996 fscs[0].cs_ndir++; 997 } 998 if (size != sblock.fs_bsize) { 999 frag = howmany(size, sblock.fs_fsize); 1000 fscs[0].cs_nffree += sblock.fs_frag - frag; 1001 sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag; 1002 acg.cg_cs.cs_nffree += sblock.fs_frag - frag; 1003 acg.cg_frsum[sblock.fs_frag - frag]++; 1004 for (i = frag; i < sblock.fs_frag; i++) 1005 setbit(cg_blksfree(&acg, 0), d + i); 1006 } 1007 /* host -> fs byte order */ 1008 if (needswap) 1009 ffs_cg_swap(&acg, &acg, &sblock); 1010 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 1011 (char *)&acg); 1012 return (d); 1013 } 1014 1015 /* 1016 * Allocate an inode on the disk 1017 */ 1018 static void 1019 iput(union dinode *ip, ino_t ino) 1020 { 1021 daddr_t d; 1022 int c, i; 1023 struct ufs1_dinode *dp1; 1024 struct ufs2_dinode *dp2; 1025 1026 c = ino_to_cg(&sblock, ino); 1027 rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, &acg); 1028 /* fs -> host byte order */ 1029 if (needswap) 1030 ffs_cg_swap(&acg, &acg, &sblock); 1031 if (acg.cg_magic != CG_MAGIC) { 1032 printf("cg 0: bad magic number\n"); 1033 exit(31); 1034 } 1035 acg.cg_cs.cs_nifree--; 1036 setbit(cg_inosused(&acg, 0), ino); 1037 /* host -> fs byte order */ 1038 if (needswap) 1039 ffs_cg_swap(&acg, &acg, &sblock); 1040 wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize, 1041 (char *)&acg); 1042 sblock.fs_cstotal.cs_nifree--; 1043 fscs[0].cs_nifree--; 1044 if (ino >= sblock.fs_ipg * sblock.fs_ncg) { 1045 printf("fsinit: inode value out of range (%d).\n", ino); 1046 exit(32); 1047 } 1048 d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino)); 1049 rdfs(d, sblock.fs_bsize, (char *)iobuf); 1050 if (sblock.fs_magic == FS_UFS1_MAGIC) { 1051 dp1 = (struct ufs1_dinode *)iobuf; 1052 if (needswap) { 1053 ffs_dinode1_swap(&ip->dp1, 1054 &dp1[ino_to_fsbo(&sblock, ino)]); 1055 /* ffs_dinode1_swap() doesn't swap blocks addrs */ 1056 for (i=0; i<NDADDR + NIADDR; i++) 1057 (&dp1[ino_to_fsbo(&sblock, ino)])->di_db[i] = 1058 bswap32(ip->dp1.di_db[i]); 1059 } else 1060 dp1[ino_to_fsbo(&sblock, ino)] = ip->dp1; 1061 } else { 1062 dp2 = (struct ufs2_dinode *)iobuf; 1063 if (needswap) { 1064 ffs_dinode2_swap(&ip->dp2, 1065 &dp2[ino_to_fsbo(&sblock, ino)]); 1066 for (i=0; i<NDADDR + NIADDR; i++) 1067 (&dp2[ino_to_fsbo(&sblock, ino)])->di_db[i] = 1068 bswap32(ip->dp2.di_db[i]); 1069 } else 1070 dp2[ino_to_fsbo(&sblock, ino)] = ip->dp2; 1071 } 1072 wtfs(d, sblock.fs_bsize, iobuf); 1073 } 1074 1075 /* 1076 * read a block from the file system 1077 */ 1078 void 1079 rdfs(daddr_t bno, int size, void *bf) 1080 { 1081 int n; 1082 off_t offset; 1083 1084 #ifdef MFS 1085 if (mfs) { 1086 memmove(bf, membase + bno * sectorsize, size); 1087 return; 1088 } 1089 #endif 1090 offset = bno; 1091 offset *= sectorsize; 1092 if (lseek(fsi, offset, SEEK_SET) < 0) { 1093 printf("rdfs: seek error for sector %lld: %s\n", 1094 (long long)bno, strerror(errno)); 1095 exit(33); 1096 } 1097 n = read(fsi, bf, size); 1098 if (n != size) { 1099 printf("rdfs: read error for sector %lld: %s\n", 1100 (long long)bno, strerror(errno)); 1101 exit(34); 1102 } 1103 } 1104 1105 /* 1106 * write a block to the file system 1107 */ 1108 void 1109 wtfs(daddr_t bno, int size, void *bf) 1110 { 1111 int n; 1112 off_t offset; 1113 1114 #ifdef MFS 1115 if (mfs) { 1116 memmove(membase + bno * sectorsize, bf, size); 1117 return; 1118 } 1119 #endif 1120 if (Nflag) 1121 return; 1122 offset = bno; 1123 offset *= sectorsize; 1124 if (lseek(fso, offset, SEEK_SET) < 0) { 1125 printf("wtfs: seek error for sector %lld: %s\n", 1126 (long long)bno, strerror(errno)); 1127 exit(35); 1128 } 1129 n = write(fso, bf, size); 1130 if (n != size) { 1131 printf("wtfs: write error for sector %lld: %s\n", 1132 (long long)bno, strerror(errno)); 1133 exit(36); 1134 } 1135 } 1136 1137 /* 1138 * check if a block is available 1139 */ 1140 int 1141 isblock(struct fs *fs, unsigned char *cp, int h) 1142 { 1143 unsigned char mask; 1144 1145 switch (fs->fs_fragshift) { 1146 case 3: 1147 return (cp[h] == 0xff); 1148 case 2: 1149 mask = 0x0f << ((h & 0x1) << 2); 1150 return ((cp[h >> 1] & mask) == mask); 1151 case 1: 1152 mask = 0x03 << ((h & 0x3) << 1); 1153 return ((cp[h >> 2] & mask) == mask); 1154 case 0: 1155 mask = 0x01 << (h & 0x7); 1156 return ((cp[h >> 3] & mask) == mask); 1157 default: 1158 #ifdef STANDALONE 1159 printf("isblock bad fs_fragshift %d\n", fs->fs_fragshift); 1160 #else 1161 fprintf(stderr, "isblock bad fs_fragshift %d\n", 1162 fs->fs_fragshift); 1163 #endif 1164 return (0); 1165 } 1166 } 1167 1168 /* 1169 * take a block out of the map 1170 */ 1171 void 1172 clrblock(struct fs *fs, unsigned char *cp, int h) 1173 { 1174 switch ((fs)->fs_fragshift) { 1175 case 3: 1176 cp[h] = 0; 1177 return; 1178 case 2: 1179 cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2)); 1180 return; 1181 case 1: 1182 cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1)); 1183 return; 1184 case 0: 1185 cp[h >> 3] &= ~(0x01 << (h & 0x7)); 1186 return; 1187 default: 1188 #ifdef STANDALONE 1189 printf("clrblock bad fs_fragshift %d\n", fs->fs_fragshift); 1190 #else 1191 fprintf(stderr, "clrblock bad fs_fragshift %d\n", 1192 fs->fs_fragshift); 1193 #endif 1194 return; 1195 } 1196 } 1197 1198 /* 1199 * put a block into the map 1200 */ 1201 void 1202 setblock(struct fs *fs, unsigned char *cp, int h) 1203 { 1204 switch (fs->fs_fragshift) { 1205 case 3: 1206 cp[h] = 0xff; 1207 return; 1208 case 2: 1209 cp[h >> 1] |= (0x0f << ((h & 0x1) << 2)); 1210 return; 1211 case 1: 1212 cp[h >> 2] |= (0x03 << ((h & 0x3) << 1)); 1213 return; 1214 case 0: 1215 cp[h >> 3] |= (0x01 << (h & 0x7)); 1216 return; 1217 default: 1218 #ifdef STANDALONE 1219 printf("setblock bad fs_frag %d\n", fs->fs_fragshift); 1220 #else 1221 fprintf(stderr, "setblock bad fs_fragshift %d\n", 1222 fs->fs_fragshift); 1223 #endif 1224 return; 1225 } 1226 } 1227 1228 /* copy a direntry to a buffer, in fs byte order */ 1229 static void 1230 copy_dir(struct direct *dir, struct direct *dbuf) 1231 { 1232 memcpy(dbuf, dir, DIRSIZ(Oflag == 0, dir, 0)); 1233 if (needswap) { 1234 dbuf->d_ino = bswap32(dir->d_ino); 1235 dbuf->d_reclen = bswap16(dir->d_reclen); 1236 if (Oflag == 0) 1237 ((struct odirect*)dbuf)->d_namlen = 1238 bswap16(((struct odirect*)dir)->d_namlen); 1239 } 1240 } 1241 1242 /* Determine how many digits are needed to print a given integer */ 1243 static int 1244 count_digits(int num) 1245 { 1246 int ndig; 1247 1248 for(ndig = 1; num > 9; num /=10, ndig++); 1249 1250 return (ndig); 1251 } 1252 1253 static int 1254 ilog2(int val) 1255 { 1256 u_int n; 1257 1258 for (n = 0; n < sizeof(n) * CHAR_BIT; n++) 1259 if (1 << n == val) 1260 return (n); 1261 errx(1, "ilog2: %d is not a power of 2\n", val); 1262 } 1263 1264 1265 #ifdef MFS 1266 /* 1267 * XXX! 1268 * Attempt to guess how much more space is available for process data. The 1269 * heuristic we use is 1270 * 1271 * max_data_limit - (sbrk(0) - etext) - 128kB 1272 * 1273 * etext approximates that start address of the data segment, and the 128kB 1274 * allows some slop for both segment gap between text and data, and for other 1275 * (libc) malloc usage. 1276 */ 1277 static void 1278 calc_memfree(void) 1279 { 1280 extern char etext; 1281 struct rlimit rlp; 1282 u_long base; 1283 1284 base = (u_long)sbrk(0) - (u_long)&etext; 1285 if (getrlimit(RLIMIT_DATA, &rlp) < 0) 1286 perror("getrlimit"); 1287 rlp.rlim_cur = rlp.rlim_max; 1288 if (setrlimit(RLIMIT_DATA, &rlp) < 0) 1289 perror("setrlimit"); 1290 memleft = rlp.rlim_max - base - (128 * 1024); 1291 } 1292 1293 /* 1294 * Internal version of malloc that trims the requested size if not enough 1295 * memory is available. 1296 */ 1297 static void * 1298 mkfs_malloc(size_t size) 1299 { 1300 u_long pgsz; 1301 1302 if (size == 0) 1303 return (NULL); 1304 if (memleft == 0) 1305 calc_memfree(); 1306 1307 pgsz = getpagesize() - 1; 1308 size = (size + pgsz) &~ pgsz; 1309 if (size > memleft) 1310 size = memleft; 1311 memleft -= size; 1312 return (mmap(0, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 1313 -1, 0)); 1314 } 1315 #endif /* MFS */ 1316