/* Write a block. */ void put_block(block_t n, void *buf) { (void) read_and_set(n); mkfs_seek(mul64u(n, block_size), SEEK_SET); mkfs_write(buf, block_size); }
/* Write a block. */ void put_block(block_t n, void *buf) { (void) read_and_set(n); mkfs_seek((uint64_t)(n) * block_size, SEEK_SET); mkfs_write(buf, block_size); }
void super(zone_t zones, ino_t inodes) { block_t inodeblks, initblks, i; unsigned long nb; long long ind_per_zone, zo; void *buf; struct super_block *sup; sup = buf = alloc_block(); #ifdef MFSFLAG_CLEAN /* The assumption is that mkfs will create a clean FS. */ sup->s_flags = MFSFLAG_CLEAN; #endif sup->s_ninodes = inodes; /* Check for overflow; cannot happen on V3 file systems */ if(inodes != sup->s_ninodes) errx(1, "Too much inodes for that version of Minix FS."); sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */ sup->s_zones = zones; /* Check for overflow; can only happen on V1 file systems */ if(zones != sup->s_zones) errx(1, "Too much zones (blocks) for that version of Minix FS."); #ifndef MFS_STATIC_BLOCK_SIZE #define BIGGERBLOCKS "Please try a larger block size for an FS of this size." #else #define BIGGERBLOCKS "Please use MinixFS V3 for an FS of this size." #endif sup->s_imap_blocks = nb = bitmapsize(1 + inodes, block_size); /* Checks for an overflow: nb is uint32_t while s_imap_blocks is of type * int16_t */ if(sup->s_imap_blocks != nb) { errx(1, "too many inode bitmap blocks.\n" BIGGERBLOCKS); } sup->s_zmap_blocks = nb = bitmapsize(zones, block_size); /* Idem here check for overflow */ if(nb != sup->s_zmap_blocks) { errx(1, "too many block bitmap blocks.\n" BIGGERBLOCKS); } inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks; inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block; initblks = inode_offset + inodeblks; sup->s_firstdatazone_old = nb = (initblks + (1 << zone_shift) - 1) >> zone_shift; if(nb >= zones) errx(1, "bit maps too large"); if(nb != sup->s_firstdatazone_old) { /* The field is too small to store the value. Fortunately, the value * can be computed from other fields. We set the on-disk field to zero * to indicate that it must not be used. Eventually, we can always set * the on-disk field to zero, and stop using it. */ sup->s_firstdatazone_old = 0; } sup->s_firstdatazone = nb; zoff = sup->s_firstdatazone - 1; sup->s_log_zone_size = zone_shift; sup->s_magic = SUPER_MAGIC; #ifdef MFS_SUPER_BLOCK_SIZE sup->s_block_size = block_size; /* Check for overflow */ if(block_size != sup->MFS_SUPER_BLOCK_SIZE) errx(1, "block_size too large."); sup->s_disk_version = 0; #endif ind_per_zone = (long long) indir_per_zone; zo = NR_DZONES + ind_per_zone + ind_per_zone*ind_per_zone; #ifndef MAX_MAX_SIZE #define MAX_MAX_SIZE (INT32_MAX) #endif if(MAX_MAX_SIZE/block_size < zo) { sup->s_max_size = MAX_MAX_SIZE; } else { sup->s_max_size = zo * block_size; } if (verbose>1) { fprintf(stderr, "Super block values:\n" "\tnumber of inodes\t%12d\n" "\tnumber of zones \t%12d\n" "\tinode bit map blocks\t%12d\n" "\tzone bit map blocks\t%12d\n" "\tfirst data zone \t%12d\n" "\tblocks per zone shift\t%12d\n" "\tmaximum file size\t%12d\n" "\tmagic number\t\t%#12X\n", sup->s_ninodes, sup->s_zones, sup->s_imap_blocks, sup->s_zmap_blocks, sup->s_firstdatazone, sup->s_log_zone_size, sup->s_max_size, sup->s_magic); #ifdef MFS_SUPER_BLOCK_SIZE fprintf(stderr, "\tblock size\t\t%12d\n", sup->s_block_size); #endif } mkfs_seek((off_t) SUPER_BLOCK_BYTES, SEEK_SET); mkfs_write(buf, SUPER_BLOCK_BYTES); /* Clear maps and inodes. */ for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero); next_zone = sup->s_firstdatazone; next_inode = 1; zone_map = INODE_MAP + sup->s_imap_blocks; insert_bit(zone_map, 0); /* bit zero must always be allocated */ insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but * must be allocated */ free(buf); }
/*================================================================ * mkfs - make filesystem *===============================================================*/ int main(int argc, char *argv[]) { int nread, mode, usrid, grpid, ch, extra_space_percent, Tflag = 0; block_t blocks, maxblocks, bblocks; ino_t inodes, root_inum; char *token[MAX_TOKENS], line[LINE_LEN], *sfx; struct fs_size fssize; int insertmode = 0; progname = argv[0]; /* Process switches. */ blocks = 0; inodes = 0; bblocks = 0; #ifndef MFS_STATIC_BLOCK_SIZE block_size = 0; #endif zone_shift = 0; extra_space_percent = 0; while ((ch = getopt(argc, argv, "B:b:di:ltvx:z:I:T:")) != EOF) switch (ch) { #ifndef MFS_STATIC_BLOCK_SIZE case 'B': block_size = strtoul(optarg, &sfx, 0); switch(*sfx) { case 'b': case 'B': /* bytes; NetBSD-compatible */ case '\0': break; case 'K': case 'k': block_size*=1024; break; case 's': block_size*=SECTOR_SIZE; break; default: usage(); } break; #else case 'B': if (block_size != strtoul(optarg, (char **) NULL, 0)) errx(4, "block size must be exactly %d bytes", MFS_STATIC_BLOCK_SIZE); break; (void)sfx; /* shut up warnings about unused variable...*/ #endif case 'I': fs_offset_bytes = strtoul(optarg, (char **) NULL, 0); insertmode = 1; break; case 'b': blocks = bblocks = strtoul(optarg, (char **) NULL, 0); break; case 'T': Tflag = 1; current_time = strtoul(optarg, (char **) NULL, 0); break; case 'd': dflag = 1; break; case 'i': inodes = strtoul(optarg, (char **) NULL, 0); break; case 'l': print = 1; break; case 't': donttest = 1; break; case 'v': ++verbose; break; case 'x': extra_space_percent = atoi(optarg); break; case 'z': zone_shift = atoi(optarg); break; default: usage(); } if (argc == optind) usage(); /* Get the current time, set it to the mod time of the binary of * mkfs itself when the -d flag is used. The 'current' time is put into * the i_mtimes of all the files. This -d feature is useful when * producing a set of file systems, and one wants all the times to be * identical. First you set the time of the mkfs binary to what you * want, then go. */ if(Tflag) { if(dflag) errx(1, "-T and -d both specify a time and so are mutually exclusive"); } else if(dflag) { struct stat statbuf; if (stat(progname, &statbuf)) { err(1, "stat of itself"); } current_time = statbuf.st_mtime; } else { current_time = time((time_t *) 0); /* time mkfs is being run */ } /* Percentage of extra size must be nonnegative. * It can legitimately be bigger than 100 but has to make some sort of sense. */ if(extra_space_percent < 0 || extra_space_percent > 2000) usage(); #ifdef DEFAULT_BLOCK_SIZE if(!block_size) block_size = DEFAULT_BLOCK_SIZE; #endif if (block_size % SECTOR_SIZE) errx(4, "block size must be multiple of sector (%d bytes)", SECTOR_SIZE); #ifdef MIN_BLOCK_SIZE if (block_size < MIN_BLOCK_SIZE) errx(4, "block size must be at least %d bytes", MIN_BLOCK_SIZE); #endif #ifdef MAX_BLOCK_SIZE if (block_size > MAX_BLOCK_SIZE) errx(4, "block size must be at most %d bytes", MAX_BLOCK_SIZE); #endif if(block_size%INODE_SIZE) errx(4, "block size must be a multiple of inode size (%d bytes)", INODE_SIZE); if(zone_shift < 0 || zone_shift > 14) errx(4, "zone_shift must be a small non-negative integer"); zone_per_block = 1 << zone_shift; /* nr of blocks per zone */ inodes_per_block = INODES_PER_BLOCK(block_size); indir_per_block = INDIRECTS(block_size); indir_per_zone = INDIRECTS(block_size) << zone_shift; /* number of file zones we can address directly and with a single indirect*/ nr_indirzones = NR_DZONES + indir_per_zone; zone_size = block_size << zone_shift; /* Checks for an overflow: only with very big block size */ if (zone_size <= 0) errx(4, "Zones are too big for this program; smaller -B or -z, please!"); /* now that the block size is known, do buffer allocations where * possible. */ zero = alloc_block(); fs_offset_blocks = roundup(fs_offset_bytes, block_size) / block_size; /* Determine the size of the device if not specified as -b or proto. */ maxblocks = sizeup(argv[optind]); if (bblocks != 0 && bblocks + fs_offset_blocks > maxblocks && !insertmode) { errx(4, "Given size -b %d exeeds device capacity(%d)\n", bblocks, maxblocks); } if (argc - optind == 1 && bblocks == 0) { blocks = maxblocks; /* blocks == 0 is checked later, but leads to a funny way of * reporting a 0-sized device (displays usage). */ if(blocks < 1) { errx(1, "zero size device."); } } /* The remaining args must be 'special proto', or just 'special' if the * no. of blocks has already been specified. */ if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage(); if (maxblocks && blocks > maxblocks && !insertmode) { errx(1, "%s: number of blocks too large for device.", argv[optind]); } /* Check special. */ check_mtab(argv[optind]); /* Check and start processing proto. */ optarg = argv[++optind]; if (optind < argc && (proto = fopen(optarg, "r")) != NULL) { /* Prototype file is readable. */ lct = 1; get_line(line, token); /* skip boot block info */ /* Read the line with the block and inode counts. */ get_line(line, token); if (bblocks == 0){ blocks = strtol(token[0], (char **) NULL, 10); } else { if(bblocks < strtol(token[0], (char **) NULL, 10)) { errx(1, "%s: number of blocks given as parameter(%d)" " is too small for given proto file(%d).", argv[optind], bblocks, strtol(token[0], (char **) NULL, 10)); }; } inodes = strtol(token[1], (char **) NULL, 10); /* Process mode line for root directory. */ get_line(line, token); mode = mode_con(token[0]); usrid = atoi(token[1]); grpid = atoi(token[2]); if(blocks <= 0 && inodes <= 0){ detect_fs_size(&fssize); blocks = fssize.blockcount; inodes = fssize.inocount; blocks += blocks*extra_space_percent/100; inodes += inodes*extra_space_percent/100; /* XXX is it OK to write on stdout? Use warn() instead? Also consider using verbose */ fprintf(stderr, "dynamically sized filesystem: %u blocks, %u inodes\n", (unsigned int) blocks, (unsigned int) inodes); } } else { lct = 0; if (optind < argc) { /* Maybe the prototype file is just a size. Check. */ blocks = strtoul(optarg, (char **) NULL, 0); if (blocks == 0) errx(2, "Can't open prototype file"); } /* Make simple file system of the given size, using defaults. */ mode = 040777; usrid = BIN; grpid = BINGRP; simple = 1; } if (inodes == 0) { long long kb = ((unsigned long long)blocks*block_size) / 1024; inodes = kb / 2; if (kb >= 100000) inodes = kb / 4; if (kb >= 1000000) inodes = kb / 6; if (kb >= 10000000) inodes = kb / 8; if (kb >= 100000000) inodes = kb / 10; if (kb >= 1000000000) inodes = kb / 12; /* XXX check overflow: with very large number of blocks, this results in insanely large number of inodes */ /* XXX check underflow (if/when ino_t is signed), else the message below will look strange */ /* round up to fill inode block */ inodes += inodes_per_block - 1; inodes = inodes / inodes_per_block * inodes_per_block; } if (blocks < 5) errx(1, "Block count too small"); if (inodes < 1) errx(1, "Inode count too small"); nrblocks = blocks; nrinodes = inodes; umap_array_elements = 1 + blocks/8; if(!(umap_array = malloc(umap_array_elements))) err(1, "can't allocate block bitmap (%u bytes).", (unsigned)umap_array_elements); /* Open special. */ special(argv[--optind], insertmode); if (!donttest) { uint16_t *testb; ssize_t w; testb = alloc_block(); /* Try writing the last block of partition or diskette. */ mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET); testb[0] = 0x3245; testb[1] = 0x11FF; testb[block_size/2-1] = 0x1F2F; w=mkfs_write(testb, block_size); sync(); /* flush write, so if error next read fails */ mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET); testb[0] = 0; testb[1] = 0; testb[block_size/2-1] = 0; nread = read(fd, testb, block_size); if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF || testb[block_size/2-1] != 0x1F2F) { warn("nread = %d\n", nread); warnx("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]); errx(1, "File system is too big for minor device (read)"); } mkfs_seek(mul64u(blocks - 1, block_size), SEEK_SET); testb[0] = 0; testb[1] = 0; testb[block_size/2-1] = 0; mkfs_write(testb, block_size); mkfs_seek(0L, SEEK_SET); free(testb); } /* Make the file-system */ put_block(BOOT_BLOCK, zero); /* Write a null boot block. */ put_block(BOOT_BLOCK+1, zero); /* Write another null block. */ super(nrblocks >> zone_shift, inodes); root_inum = alloc_inode(mode, usrid, grpid); rootdir(root_inum); if (simple == 0) eat_dir(root_inum); if (print) print_fs(); else if (verbose > 1) { if (zone_shift) fprintf(stderr, "%d inodes used. %u zones (%u blocks) used.\n", (int)next_inode-1, next_zone, next_zone*zone_per_block); else fprintf(stderr, "%d inodes used. %u zones used.\n", (int)next_inode-1, next_zone); } if(insertmode) printf("%ld\n", written_fs_size); return(0); /* NOTREACHED */ } /* end main */