📄 mkfs.c
字号:
/* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. *//* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans * * This program can make both version 1 and version 2 file systems, as follows: * mkfs /dev/fd0 1200 # Version 2 (default) * mkfs -1 /dev/fd0 360 # Version 1 * */#include <sys/types.h>#include <sys/dir.h>#include <sys/stat.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <minix/config.h>#include <minix/const.h>#include <minix/type.h>#include <minix/minlib.h>#include "../../fs/const.h"#if (MACHINE == IBM_PC)#include <minix/partition.h>#include <sys/ioctl.h>#endif#undef EXTERN#define EXTERN /* get rid of EXTERN by making it null */#include "../../fs/type.h"#include "../../fs/super.h"#include <minix/fslib.h>#ifndef DOS#ifndef UNIX#undef printf /* printf is a macro for printk */#define UNIX#endif#endif#include <stdio.h>#define INODE_MAP 2#define MAX_TOKENS 10#define LINE_LEN 200#define BIN 2#define BINGRP 2#define BIT_MAP_SHIFT 13#define N_BLOCKS (1024L * 1024)#define N_BLOCKS16 (128L * 1024)#define INODE_MAX ((unsigned) 65535)/* You can make a really large file system on a 16-bit system, but the array * of bits that get_block()/putblock() needs gets a bit big, so we can only * prefill MAX_INIT blocks. (16-bit fsck can't check a file system larger * than N_BLOCKS16 anyway.) */#define MAX_INIT (sizeof(char *) == 2 ? N_BLOCKS16 : N_BLOCKS)#ifdef DOSmaybedefine O_RDONLY 4 /* O_RDONLY | BINARY_BIT */ maybedefine BWRITE 5 /* O_WRONLY | BINARY_BIT */#endif#if (MACHINE == ATARI)int isdev;#endifextern char *optarg;extern int optind;int next_zone, next_inode, zone_size, zone_shift = 0, zoff;block_t nrblocks;int inode_offset, lct = 0, disk, fd, print = 0, file = 0;unsigned int nrinodes;int override = 0, simple = 0, dflag;int donttest; /* skip test if it fits on medium */char *progname;long current_time, bin_time;char zero[BLOCK_SIZE], *lastp;char umap[MAX_INIT / 8]; /* bit map tells if block read yet */block_t zone_map; /* where is zone map? (depends on # inodes) */int inodes_per_block;int fs_version;block_t max_nrblocks;FILE *proto;_PROTOTYPE(int main, (int argc, char **argv));_PROTOTYPE(block_t sizeup, (char *device));_PROTOTYPE(void super, (zone_t zones, Ino_t inodes));_PROTOTYPE(void rootdir, (Ino_t inode));_PROTOTYPE(void eat_dir, (Ino_t parent));_PROTOTYPE(void eat_file, (Ino_t inode, int f));_PROTOTYPE(void enter_dir, (Ino_t parent, char *name, Ino_t child));_PROTOTYPE(void incr_size, (Ino_t n, long count));_PROTOTYPE(PRIVATE ino_t alloc_inode, (int mode, int usrid, int grpid));_PROTOTYPE(PRIVATE zone_t alloc_zone, (void));_PROTOTYPE(void add_zone, (Ino_t n, zone_t z, long bytes, long cur_time));_PROTOTYPE(void add_z_1, (Ino_t n, zone_t z, long bytes, long cur_time));_PROTOTYPE(void add_z_2, (Ino_t n, zone_t z, long bytes, long cur_time));_PROTOTYPE(void incr_link, (Ino_t n));_PROTOTYPE(void insert_bit, (block_t block, int bit));_PROTOTYPE(int mode_con, (char *p));_PROTOTYPE(void getline, (char line[LINE_LEN], char *parse[MAX_TOKENS]));_PROTOTYPE(void check_mtab, (char *devname));_PROTOTYPE(long file_time, (int f));_PROTOTYPE(void pexit, (char *s));_PROTOTYPE(void copy, (char *from, char *to, int count));_PROTOTYPE(void print_fs, (void));_PROTOTYPE(int read_and_set, (block_t n));_PROTOTYPE(void special, (char *string));_PROTOTYPE(void get_block, (block_t n, char buf[BLOCK_SIZE]));_PROTOTYPE(void put_block, (block_t n, char buf[BLOCK_SIZE]));_PROTOTYPE(void cache_init, (void));_PROTOTYPE(void flush, (void));_PROTOTYPE(void mx_read, (int blocknr, char buf[BLOCK_SIZE]));_PROTOTYPE(void mx_write, (int blocknr, char buf[BLOCK_SIZE]));_PROTOTYPE(void dexit, (char *s, int sectnum, int err));_PROTOTYPE(void usage, (void));/*================================================================ * mkfs - make filesystem *===============================================================*/int main(argc, argv)int argc;char *argv[];{ int nread, mode, usrid, grpid, ch; block_t blocks; block_t i; ino_t root_inum; ino_t inodes; zone_t zones; char *token[MAX_TOKENS], line[LINE_LEN]; struct stat statbuf; /* Get two times, the current time and the mod time of the binary of * mkfs itself. When the -d flag is used, the later time is put into * the i_mtimes of all the files. This 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. */ current_time = time((time_t *) 0); /* time mkfs is being run */ stat(argv[0], &statbuf); bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */ /* Process switches. */ progname = argv[0]; blocks = 0; i = 0; fs_version = 2; inodes_per_block = V2_INODES_PER_BLOCK; max_nrblocks = N_BLOCKS; while ((ch = getopt(argc, argv, "1b:di:lot")) != EOF) switch (ch) { case '1': fs_version = 1; inodes_per_block = V1_INODES_PER_BLOCK; max_nrblocks = 0xFFFF; break; case 'b': blocks = strtoul(optarg, (char **) NULL, 0); break; case 'd': dflag = 1; current_time = bin_time; break; case 'i': i = strtoul(optarg, (char **) NULL, 0); break; case 'l': print = 1; break; case 'o': override = 1; break; case 't': donttest = 1; break; default: usage(); } /* Determine the size of the device if not specified as -b or proto. */ if (argc - optind == 1 && blocks == 0) blocks = sizeup(argv[optind]); /* The remaining args must be 'special proto', or just 'special' if the * block size has already been specified. */ if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage(); /* 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; getline(line, token); /* skip boot block info */ /* Read the line with the block and inode counts. */ getline(line, token); blocks = atol(token[0]); if (blocks > max_nrblocks) pexit("Block count too large"); if (sizeof(char *) == 2 && blocks > N_BLOCKS16) { fprintf(stderr, "%s: warning: FS is larger than the %dM that fsck can check!\n", progname, (int) (N_BLOCKS16 / (1024L * 1024))); } inodes = atoi(token[1]); /* Process mode line for root directory. */ getline(line, token); mode = mode_con(token[0]); usrid = atoi(token[1]); grpid = atoi(token[2]); } else { lct = 0; if (optind < argc) { /* Maybe the prototype file is just a size. Check. */ blocks = strtoul(optarg, (char **) NULL, 0); if (blocks == 0) pexit("Can't open prototype file"); } if (i == 0) { /* The default for inodes is 3 blocks per inode, rounded up * to fill an inode block. Above 20M, the average files are * sure to be larger because it is hard to fill up 20M with * tiny files, so reduce the default number of inodes. This * default can always be overridden by using the -i option. */ i = blocks / 3; if (blocks >= 20000) i = blocks / 4; if (blocks >= 40000) i = blocks / 5; if (blocks >= 60000) i = blocks / 6; if (blocks >= 80000) i = blocks / 7; if (blocks >= 100000) i = blocks / 8; i += inodes_per_block - 1; i = i / inodes_per_block * inodes_per_block; if (i > INODE_MAX) i = INODE_MAX; } if (blocks < 5) pexit("Block count too small"); if (blocks > max_nrblocks) pexit("Block count too large"); if (i < 1) pexit("Inode count too small"); if (i > INODE_MAX) pexit("Inode count too large"); inodes = (ino_t) i; /* Make simple file system of the given size, using defaults. */ mode = 040777; usrid = BIN; grpid = BINGRP; simple = 1; } nrblocks = blocks; nrinodes = inodes; /* Open special. */ special(argv[--optind]);#ifdef UNIX if (!donttest) { static short testb[BLOCK_SIZE / sizeof(short)]; /* Try writing the last block of partition or diskette. */ lseek(fd, (off_t) (blocks - 1) * BLOCK_SIZE, SEEK_SET); testb[0] = 0x3245; testb[1] = 0x11FF; if (write(fd, (char *) testb, BLOCK_SIZE) != BLOCK_SIZE) pexit("File system is too big for minor device"); sync(); /* flush write, so if error next read fails */ lseek(fd, (off_t) (blocks - 1) * BLOCK_SIZE, SEEK_SET); testb[0] = 0; testb[1] = 0; nread = read(fd, (char *) testb, BLOCK_SIZE); if (nread != BLOCK_SIZE || testb[0] != 0x3245 || testb[1] != 0x11FF) pexit("File system is too big for minor device"); lseek(fd, (off_t) (blocks - 1) * BLOCK_SIZE, SEEK_SET); testb[0] = 0; testb[1] = 0; if (write(fd, (char *) testb, BLOCK_SIZE) != BLOCK_SIZE) pexit("File system is too big for minor device"); lseek(fd, 0L, SEEK_SET); }#endif /* Make the file-system */ cache_init();#if (MACHINE == ATARI) if (isdev) { char block0[BLOCK_SIZE]; get_block((block_t) 0, block0); /* Need to read twice; first time gets an empty block */ get_block((block_t) 0, block0); /* Zero parts of the boot block so the disk won't be * recognized as a tos disk any more. */ block0[0] = block0[1] = 0; /* branch code to boot code */ strncpy(&block0[2], "MINIX ", (size_t) 6); block0[16] = 0; /* number of FATS */ block0[17] = block0[18] = 0; /* number of dir entries */ block0[22] = block0[23] = 0; /* sectors/FAT */ bzero(&block0[30], 480);/* boot code */ put_block((block_t) 0, block0); } else#endif put_block((block_t) 0, zero); /* Write a null boot block. */ zone_shift = 0; /* for future use */ zones = nrblocks >> zone_shift; super(zones, inodes); root_inum = alloc_inode(mode, usrid, grpid); rootdir(root_inum); if (simple == 0) eat_dir(root_inum); if (print) print_fs(); flush(); return(0); /* NOTREACHED */} /* end main *//*================================================================ * sizeup - determine device size *===============================================================*/block_t sizeup(device)char *device;{ int fd; struct partition entry; if ((fd = open(device, O_RDONLY)) == -1) return 0; if (ioctl(fd, DIOCGETP, &entry) == -1) entry.size = 0; close(fd); return entry.size / BLOCK_SIZE;}/*================================================================ * super - construct a superblock *===============================================================*/void super(zones, inodes)zone_t zones;ino_t inodes;{ unsigned int i; int inodeblks; int initblks; zone_t initzones, nrzones, v1sq, v2sq; zone_t zo; struct super_block *sup; char buf[BLOCK_SIZE], *cp; for (cp = buf; cp < &buf[BLOCK_SIZE]; cp++) *cp = 0; sup = (struct super_block *) buf; /* lint - might use a union */ sup->s_ninodes = inodes; if (fs_version == 1) { sup->s_nzones = zones; } else { sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */ sup->s_zones = zones; } sup->s_imap_blocks = bitmapsize((bit_t) (1 + inodes)); sup->s_zmap_blocks = bitmapsize((bit_t) zones); inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2; inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block; initblks = inode_offset + inodeblks; initzones = (initblks + (1 << zone_shift) - 1) >> zone_shift; nrzones = nrblocks >> zone_shift; sup->s_firstdatazone = (initblks + (1 << zone_shift) - 1) >> zone_shift; zoff = sup->s_firstdatazone - 1; sup->s_log_zone_size = zone_shift; if (fs_version == 1) { sup->s_magic = SUPER_MAGIC; /* identify super blocks */ v1sq = (zone_t) V1_INDIRECTS * V1_INDIRECTS; zo = V1_NR_DZONES + (long) V1_INDIRECTS + v1sq; } else { sup->s_magic = SUPER_V2;/* identify super blocks */ v2sq = (zone_t) V2_INDIRECTS * V2_INDIRECTS; zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS + v2sq; } sup->s_max_size = zo * BLOCK_SIZE; zone_size = 1 << zone_shift; /* nr of blocks per zone */ put_block((block_t) 1, buf); /* Clear maps and inodes. */ for (i = 2; 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 */}/*================================================================ * rootdir - install the root directory *===============================================================*/void rootdir(inode)ino_t inode;{ zone_t z; z = alloc_zone(); add_zone(inode, z, 32L, current_time); enter_dir(inode, ".", inode); enter_dir(inode, "..", inode); incr_link(inode); incr_link(inode);}/*================================================================ * eat_dir - recursively install directory *===============================================================*/void eat_dir(parent)ino_t parent;{ /* Read prototype lines and set up directory. Recurse if need be. */ char *token[MAX_TOKENS], *p; char line[LINE_LEN]; int mode, usrid, grpid, maj, min, f; ino_t n; zone_t z; long size; while (1) { getline(line, token); p = token[0]; if (*p == '$') return; p = token[1]; mode = mode_con(p); usrid = atoi(token[2]); grpid = atoi(token[3]); if (grpid & 0200) fprintf(stderr, "A.S.Tanenbaum\n"); n = alloc_inode(mode, usrid, grpid); /* Enter name in directory and update directory's size. */ enter_dir(parent, token[0], n); incr_size(parent, 16L); /* Check to see if file is directory or special. */ incr_link(n);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -