mkfs.c

Go to the documentation of this file.
00001 /* mkfs  -  make the MINIX filesystem   Authors: Tanenbaum et al. */
00002 
00003 /*      Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
00004  *
00005  * This program can make both version 1 and version 2 file systems, as follows:
00006  *      mkfs /dev/fd0 1200      # Version 2 (default)
00007  *      mkfs -1 /dev/fd0 360    # Version 1
00008  *
00009  */
00010 
00011 #include <sys/types.h>
00012 #include <sys/dir.h>
00013 #include <sys/stat.h>
00014 #include <stdio.h>
00015 #include <errno.h>
00016 #include <fcntl.h>
00017 #include <limits.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <time.h>
00021 #include <unistd.h>
00022 #include <minix/config.h>
00023 #include <minix/const.h>
00024 #include <minix/type.h>
00025 #include <minix/minlib.h>
00026 #include "../../servers/fs/const.h"
00027 #if (MACHINE == IBM_PC)
00028 #include <minix/partition.h>
00029 #include <minix/u64.h>
00030 #include <sys/ioctl.h>
00031 #endif
00032 #include <a.out.h>
00033 #include <tools.h>
00034 #include <dirent.h>
00035 
00036 #undef EXTERN
00037 #define EXTERN                  /* get rid of EXTERN by making it null */
00038 #include "../../servers/fs/type.h"
00039 #include "../../servers/fs/super.h"
00040 #include <minix/fslib.h>
00041 
00042 #ifndef max
00043 #define max(a,b) ((a) > (b) ? (a) : (b))
00044 #endif
00045 
00046 #ifndef DOS
00047 #ifndef UNIX
00048 #define UNIX
00049 #endif
00050 #endif
00051 
00052 #define INODE_MAP            2
00053 #define MAX_TOKENS          10
00054 #define LINE_LEN           200
00055 #define BIN                  2
00056 #define BINGRP               2
00057 #define BIT_MAP_SHIFT       13
00058 #define N_BLOCKS         MAX_BLOCK_NR
00059 #define N_BLOCKS16        (128L * 1024)
00060 #define INODE_MAX       ((unsigned) 65535)
00061 
00062 /* You can make a really large file system on a 16-bit system, but the array
00063  * of bits that get_block()/putblock() needs gets a bit big, so we can only
00064  * prefill MAX_INIT blocks.  (16-bit fsck can't check a file system larger
00065  * than N_BLOCKS16 anyway.)
00066  */
00067 #define MAX_INIT         (sizeof(char *) == 2 ? N_BLOCKS16 : N_BLOCKS)
00068 
00069 
00070 #ifdef DOS
00071 maybedefine O_RDONLY 4          /* O_RDONLY | BINARY_BIT */
00072  maybedefine BWRITE 5           /* O_WRONLY | BINARY_BIT */
00073 #endif
00074 
00075 #if (MACHINE == ATARI)
00076 int isdev;
00077 #endif
00078 
00079 extern char *optarg;
00080 extern int optind;
00081 
00082 int next_zone, next_inode, zone_size, zone_shift = 0, zoff;
00083 block_t nrblocks;
00084 int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
00085 unsigned int nrinodes;
00086 int override = 0, simple = 0, dflag;
00087 int donttest;                   /* skip test if it fits on medium */
00088 char *progname;
00089 
00090 long current_time, bin_time;
00091 char *zero, *lastp;
00092 char umap[MAX_INIT / 8];        /* bit map tells if block read yet */
00093 block_t zone_map;               /* where is zone map? (depends on # inodes) */
00094 int inodes_per_block;
00095 int fs_version;
00096 unsigned int block_size;
00097 block_t max_nrblocks;
00098 
00099 FILE *proto;
00100 
00101 _PROTOTYPE(int main, (int argc, char **argv));
00102 _PROTOTYPE(block_t sizeup, (char *device));
00103 _PROTOTYPE(void super, (zone_t zones, Ino_t inodes));
00104 _PROTOTYPE(void rootdir, (Ino_t inode));
00105 _PROTOTYPE(void eat_dir, (Ino_t parent));
00106 _PROTOTYPE(void eat_file, (Ino_t inode, int f));
00107 _PROTOTYPE(void enter_dir, (Ino_t parent, char *name, Ino_t child));
00108 _PROTOTYPE(void incr_size, (Ino_t n, long count));
00109 _PROTOTYPE(PRIVATE ino_t alloc_inode, (int mode, int usrid, int grpid));
00110 _PROTOTYPE(PRIVATE zone_t alloc_zone, (void));
00111 _PROTOTYPE(void add_zone, (Ino_t n, zone_t z, long bytes, long cur_time));
00112 _PROTOTYPE(void add_z_1, (Ino_t n, zone_t z, long bytes, long cur_time));
00113 _PROTOTYPE(void add_z_2, (Ino_t n, zone_t z, long bytes, long cur_time));
00114 _PROTOTYPE(void incr_link, (Ino_t n));
00115 _PROTOTYPE(void insert_bit, (block_t block, int bit));
00116 _PROTOTYPE(int mode_con, (char *p));
00117 _PROTOTYPE(void getline, (char line[LINE_LEN], char *parse[MAX_TOKENS]));
00118 _PROTOTYPE(void check_mtab, (char *devname));
00119 _PROTOTYPE(long file_time, (int f));
00120 _PROTOTYPE(void pexit, (char *s));
00121 _PROTOTYPE(void copy, (char *from, char *to, int count));
00122 _PROTOTYPE(void print_fs, (void));
00123 _PROTOTYPE(int read_and_set, (block_t n));
00124 _PROTOTYPE(void special, (char *string));
00125 _PROTOTYPE(void get_block, (block_t n, char *buf));
00126 _PROTOTYPE(void get_super_block, (char *buf));
00127 _PROTOTYPE(void put_block, (block_t n, char *buf));
00128 _PROTOTYPE(void cache_init, (void));
00129 _PROTOTYPE(void flush, (void));
00130 _PROTOTYPE(void mx_read, (int blocknr, char *buf));
00131 _PROTOTYPE(void mx_write, (int blocknr, char *buf));
00132 _PROTOTYPE(void dexit, (char *s, int sectnum, int err));
00133 _PROTOTYPE(void usage, (void));
00134 _PROTOTYPE(char *alloc_block, (void));
00135 
00136 /*================================================================
00137  *                    mkfs  -  make filesystem
00138  *===============================================================*/
00139 int main(argc, argv)
00140 int argc;
00141 char *argv[];
00142 {
00143   int nread, mode, usrid, grpid, ch;
00144   block_t blocks, maxblocks;
00145   block_t i;
00146   ino_t root_inum;
00147   ino_t inodes;
00148   zone_t zones;
00149   char *token[MAX_TOKENS], line[LINE_LEN];
00150   struct stat statbuf;
00151 
00152   /* Get two times, the current time and the mod time of the binary of
00153    * mkfs itself.  When the -d flag is used, the later time is put into
00154    * the i_mtimes of all the files.  This feature is useful when
00155    * producing a set of file systems, and one wants all the times to be
00156    * identical. First you set the time of the mkfs binary to what you
00157    * want, then go.
00158    */
00159   current_time = time((time_t *) 0);    /* time mkfs is being run */
00160   stat(argv[0], &statbuf);
00161   bin_time = statbuf.st_mtime;  /* time when mkfs binary was last modified */
00162 
00163   /* Process switches. */
00164   progname = argv[0];
00165   blocks = 0;
00166   i = 0;
00167   fs_version = 3;
00168   inodes_per_block = 0;
00169   max_nrblocks = N_BLOCKS;
00170   block_size = 0;
00171   while ((ch = getopt(argc, argv, "12b:di:lotB:")) != EOF)
00172         switch (ch) {
00173             case '1':
00174                 fs_version = 1;
00175                 inodes_per_block = V1_INODES_PER_BLOCK;
00176                 max_nrblocks = 0xFFFF;
00177                 break;
00178             case '2':
00179                 fs_version = 2;
00180                 break;
00181             case 'b':
00182                 blocks = strtoul(optarg, (char **) NULL, 0);
00183                 break;
00184             case 'd':
00185                 dflag = 1;
00186                 current_time = bin_time;
00187                 break;
00188             case 'i':
00189                 i = strtoul(optarg, (char **) NULL, 0);
00190                 break;
00191             case 'l':   print = 1;      break;
00192             case 'o':   override = 1;   break;
00193             case 't':   donttest = 1;   break;
00194             case 'B':   block_size = atoi(optarg);      break;
00195             default:    usage();
00196         }
00197 
00198   if(fs_version == 3) {
00199         if(!block_size) block_size = _MAX_BLOCK_SIZE; /* V3 default block size */
00200         if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
00201                 fprintf(stderr, "block size must be multiple of sector (%d) "
00202                         "and at least %d bytes\n",
00203                         SECTOR_SIZE, _MIN_BLOCK_SIZE);
00204                 pexit("specified block size illegal");
00205         }
00206         if(block_size%V2_INODE_SIZE) {
00207                 fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
00208                         V2_INODE_SIZE);
00209                 pexit("specified block size illegal");
00210         }
00211   } else {
00212         if(block_size) {
00213                 pexit("Can't specify a block size if FS version is <3");
00214         }
00215         block_size = _STATIC_BLOCK_SIZE;        /* V1/V2 block size */
00216   }
00217 
00218   if(!inodes_per_block)
00219         inodes_per_block = V2_INODES_PER_BLOCK(block_size);
00220 
00221   /* now that the block size is known, do buffer allocations where
00222    * possible.
00223    */
00224   zero = alloc_block();
00225   bzero(zero, block_size);
00226 
00227   /* Determine the size of the device if not specified as -b or proto. */
00228   maxblocks = sizeup(argv[optind]);
00229   if (argc - optind == 1 && blocks == 0) {
00230         blocks = maxblocks;
00231         /* blocks == 0 is checked later, but leads to a funny way of
00232          * reporting a 0-sized device (displays usage).
00233          */
00234         if(blocks < 1) {
00235                 fprintf(stderr, "%s: this device can't hold a filesystem.\n",
00236                         progname);
00237                 return 1;
00238         }
00239   }
00240 
00241   /* The remaining args must be 'special proto', or just 'special' if the
00242    * no. of blocks has already been specified.
00243    */
00244   if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
00245 
00246   if (blocks > maxblocks) {
00247         fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
00248                 progname, argv[optind]);
00249         return 1;
00250   }
00251 
00252   /* Check special. */
00253   check_mtab(argv[optind]);
00254 
00255   /* Check and start processing proto. */
00256   optarg = argv[++optind];
00257   if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
00258         /* Prototype file is readable. */
00259         lct = 1;
00260         getline(line, token);   /* skip boot block info */
00261 
00262         /* Read the line with the block and inode counts. */
00263         getline(line, token);
00264         blocks = atol(token[0]);
00265         if (blocks > max_nrblocks) pexit("Block count too large");
00266         if (sizeof(char *) == 2 && blocks > N_BLOCKS16) {
00267                 fprintf(stderr,
00268                 "%s: warning: FS is larger than the %dM that fsck can check!\n",
00269                         progname, (int) (N_BLOCKS16 / (1024L * 1024)));
00270         }
00271         inodes = atoi(token[1]);
00272 
00273         /* Process mode line for root directory. */
00274         getline(line, token);
00275         mode = mode_con(token[0]);
00276         usrid = atoi(token[1]);
00277         grpid = atoi(token[2]);
00278   } else {
00279         lct = 0;
00280         if (optind < argc) {
00281                 /* Maybe the prototype file is just a size.  Check. */
00282                 blocks = strtoul(optarg, (char **) NULL, 0);
00283                 if (blocks == 0) pexit("Can't open prototype file");
00284         }
00285         if (i == 0) {
00286                 int kb;
00287                 kb = blocks * (max(block_size,1024) / 1024);
00288                 /* The default for inodes is 2 blocks per kb, rounded up
00289                  * to fill an inode block.  Above 20M, the average files are
00290                  * sure to be larger because it is hard to fill up 20M with
00291                  * tiny files, so reduce the default number of inodes.  This
00292                  * default can always be overridden by using the '-i option.
00293                  */
00294                 i = kb / 2;
00295                 if (kb >= 20000) i = kb / 3;
00296                 if (kb >= 40000) i = kb / 4;
00297                 if (kb >= 60000) i = kb / 5;
00298                 if (kb >= 80000) i = kb / 6;
00299                 if (kb >= 100000) i = kb / 7;
00300 
00301                 /* round up to fill inode block */
00302                 i += inodes_per_block - 1;
00303                 i = i / inodes_per_block * inodes_per_block;
00304                 if (i > INODE_MAX && fs_version < 3) i = INODE_MAX;
00305 
00306         }
00307         if (blocks < 5) pexit("Block count too small");
00308         if (blocks > max_nrblocks) pexit("Block count too large");
00309         if (i < 1) pexit("Inode count too small");
00310         if (i > INODE_MAX && fs_version < 3) pexit("Inode count too large");
00311         inodes = (ino_t) i;
00312 
00313         /* Make simple file system of the given size, using defaults. */
00314         mode = 040777;
00315         usrid = BIN;
00316         grpid = BINGRP;
00317         simple = 1;
00318   }
00319 
00320   if(ULONG_MAX / block_size <= blocks-1) {
00321         fprintf(stderr, "Warning: too big for filesystem to currently\n");
00322         fprintf(stderr, "run on (max 4GB), truncating.\n");
00323         blocks = ULONG_MAX / block_size;
00324   }
00325 
00326   nrblocks = blocks;
00327   nrinodes = inodes;
00328 
00329   /* Open special. */
00330   special(argv[--optind]);
00331 
00332 #ifdef UNIX
00333   if (!donttest) {
00334         short *testb;
00335         ssize_t w;
00336 
00337         testb = (short *) alloc_block();
00338 
00339         /* Try writing the last block of partition or diskette. */
00340         if(lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET) < 0) {
00341                 pexit("couldn't seek to last block to test size (1)");
00342         }
00343         testb[0] = 0x3245;
00344         testb[1] = 0x11FF;
00345         testb[block_size-1] = 0x1F2F;
00346         if ((w=write(fd, (char *) testb, block_size)) != block_size) {
00347                 if(w < 0) perror("write");
00348                 printf("%d/%d\n", w, block_size);
00349                 pexit("File system is too big for minor device (write)");
00350         }
00351         sync();                 /* flush write, so if error next read fails */
00352         if(lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET) < 0) {
00353                 pexit("couldn't seek to last block to test size (2)");
00354         }
00355         testb[0] = 0;
00356         testb[1] = 0;
00357         nread = read(fd, (char *) testb, block_size);
00358         if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
00359                 testb[block_size-1] != 0x1F2F) {
00360                 if(nread < 0) perror("read");
00361                 pexit("File system is too big for minor device (read)");
00362         }
00363         lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET);
00364         testb[0] = 0;
00365         testb[1] = 0;
00366         if (write(fd, (char *) testb, block_size) != block_size)
00367                 pexit("File system is too big for minor device (write2)");
00368         lseek(fd, 0L, SEEK_SET);
00369         free(testb);
00370   }
00371 #endif
00372 
00373   /* Make the file-system */
00374 
00375   cache_init();
00376 
00377 #if (MACHINE == ATARI)
00378   if (isdev) {
00379         char block0[BLOCK_SIZE];
00380         get_block((block_t) 0, block0);
00381         /* Need to read twice; first time gets an empty block */
00382         get_block((block_t) 0, block0);
00383         /* Zero parts of the boot block so the disk won't be
00384          * recognized as a tos disk any more. */
00385         block0[0] = block0[1] = 0;      /* branch code to boot code    */
00386         strncpy(&block0[2], "MINIX ", (size_t) 6);
00387         block0[16] = 0;         /* number of FATS              */
00388         block0[17] = block0[18] = 0;    /* number of dir entries       */
00389         block0[22] = block0[23] = 0;    /* sectors/FAT                 */
00390         bzero(&block0[30], 480);/* boot code                   */
00391         put_block((block_t) 0, block0);
00392   } else
00393 #endif
00394 
00395         put_block((block_t) 0, zero);   /* Write a null boot block. */
00396 
00397   zone_shift = 0;               /* for future use */
00398   zones = nrblocks >> zone_shift;
00399 
00400   super(zones, inodes);
00401 
00402   root_inum = alloc_inode(mode, usrid, grpid);
00403   rootdir(root_inum);
00404   if (simple == 0) eat_dir(root_inum);
00405 
00406   if (print) print_fs();
00407   flush();
00408   return(0);
00409 
00410   /* NOTREACHED */
00411 }                               /* end main */
00412 
00413 
00414 /*================================================================
00415  *                    sizeup  -  determine device size
00416  *===============================================================*/
00417 block_t sizeup(device)
00418 char *device;
00419 {
00420   int fd;
00421   struct partition entry;
00422   block_t d;
00423   struct stat st;
00424 
00425   if ((fd = open(device, O_RDONLY)) == -1) {
00426         if (errno != ENOENT)
00427                 perror("sizeup open");
00428         return 0;
00429   }
00430   if (ioctl(fd, DIOCGETP, &entry) == -1) {
00431         perror("sizeup ioctl");
00432         if(fstat(fd, &st) < 0) {
00433                 perror("fstat");
00434                 entry.size = cvu64(0);
00435         } else {
00436                 fprintf(stderr, "used fstat instead\n");
00437                 entry.size = cvu64(st.st_size);
00438         }
00439   }
00440   close(fd);
00441   d = div64u(entry.size, block_size);
00442   return d;
00443 }
00444 
00445 
00446 /*================================================================
00447  *                 super  -  construct a superblock
00448  *===============================================================*/
00449 
00450 void super(zones, inodes)
00451 zone_t zones;
00452 ino_t inodes;
00453 {
00454   unsigned int i;
00455   int inodeblks;
00456   int initblks;
00457 
00458   zone_t initzones, nrzones, v1sq, v2sq;
00459   zone_t zo;
00460   struct super_block *sup;
00461   char *buf, *cp;
00462 
00463   buf = alloc_block();
00464 
00465   for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
00466   sup = (struct super_block *) buf;     /* lint - might use a union */
00467 
00468   sup->s_ninodes = inodes;
00469   if (fs_version == 1) {
00470         sup->s_nzones = zones;
00471   } else {
00472         sup->s_nzones = 0;      /* not used in V2 - 0 forces errors early */
00473         sup->s_zones = zones;
00474   }
00475   sup->s_imap_blocks = bitmapsize((bit_t) (1 + inodes), block_size);
00476   sup->s_zmap_blocks = bitmapsize((bit_t) zones, block_size);
00477   inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2;
00478   inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
00479   initblks = inode_offset + inodeblks;
00480   initzones = (initblks + (1 << zone_shift) - 1) >> zone_shift;
00481   nrzones = nrblocks >> zone_shift;
00482   sup->s_firstdatazone = (initblks + (1 << zone_shift) - 1) >> zone_shift;
00483   zoff = sup->s_firstdatazone - 1;
00484   sup->s_log_zone_size = zone_shift;
00485   if (fs_version == 1) {
00486         sup->s_magic = SUPER_MAGIC;     /* identify super blocks */
00487         v1sq = (zone_t) V1_INDIRECTS * V1_INDIRECTS;
00488         zo = V1_NR_DZONES + (long) V1_INDIRECTS + v1sq;
00489         sup->s_max_size = zo * block_size;
00490   } else {
00491         v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
00492         zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
00493         if(fs_version == 2) {
00494                 sup->s_magic = SUPER_V2;/* identify super blocks */
00495                 sup->s_max_size = zo * block_size;
00496         } else {
00497                 sup->s_magic = SUPER_V3;
00498                 sup->s_block_size = block_size;
00499                 sup->s_disk_version = 0;
00500 #define MAX_MAX_SIZE    ((unsigned long) 0xffffffff)
00501                 if(MAX_MAX_SIZE/block_size < zo) {
00502                         sup->s_max_size = MAX_MAX_SIZE;
00503                 }
00504                 else {
00505                         sup->s_max_size = zo * block_size;
00506                 }
00507         }
00508   }
00509 
00510   zone_size = 1 << zone_shift;  /* nr of blocks per zone */
00511 
00512   if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
00513         pexit("super() couldn't seek");
00514   }
00515   if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
00516         pexit("super() couldn't write");
00517   }
00518 
00519   /* Clear maps and inodes. */
00520   for (i = 2; i < initblks; i++) put_block((block_t) i, zero);
00521 
00522   next_zone = sup->s_firstdatazone;
00523   next_inode = 1;
00524 
00525   zone_map = INODE_MAP + sup->s_imap_blocks;
00526 
00527   insert_bit(zone_map, 0);      /* bit zero must always be allocated */
00528   insert_bit((block_t) INODE_MAP, 0);   /* inode zero not used but
00529                                          * must be allocated */
00530 
00531   free(buf);
00532 }
00533 
00534 
00535 /*================================================================
00536  *              rootdir  -  install the root directory
00537  *===============================================================*/
00538 void rootdir(inode)
00539 ino_t inode;
00540 {
00541   zone_t z;
00542 
00543   z = alloc_zone();
00544   add_zone(inode, z, 2 * sizeof(struct direct), current_time);
00545   enter_dir(inode, ".", inode);
00546   enter_dir(inode, "..", inode);
00547   incr_link(inode);
00548   incr_link(inode);
00549 }
00550 
00551 
00552 /*================================================================
00553  *          eat_dir  -  recursively install directory
00554  *===============================================================*/
00555 void eat_dir(parent)
00556 ino_t parent;
00557 {
00558   /* Read prototype lines and set up directory. Recurse if need be. */
00559   char *token[MAX_TOKENS], *p;
00560   char line[LINE_LEN];
00561   int mode, usrid, grpid, maj, min, f;
00562   ino_t n;
00563   zone_t z;
00564   long size;
00565 
00566   while (1) {
00567         getline(line, token);
00568         p = token[0];
00569         if (*p == '$') return;
00570         p = token[1];
00571         mode = mode_con(p);
00572         usrid = atoi(token[2]);
00573         grpid = atoi(token[3]);
00574         if (grpid & 0200) fprintf(stderr, "A.S.Tanenbaum\n");
00575         n = alloc_inode(mode, usrid, grpid);
00576 
00577         /* Enter name in directory and update directory's size. */
00578         enter_dir(parent, token[0], n);
00579         incr_size(parent, sizeof(struct direct));
00580 
00581         /* Check to see if file is directory or special. */
00582         incr_link(n);
00583         if (*p == 'd') {
00584                 /* This is a directory. */
00585                 z = alloc_zone();       /* zone for new directory */
00586                 add_zone(n, z, 2 * sizeof(struct direct), current_time);
00587                 enter_dir(n, ".", n);
00588                 enter_dir(n, "..", parent);
00589                 incr_link(parent);
00590                 incr_link(n);
00591                 eat_dir(n);
00592         } else if (*p == 'b' || *p == 'c') {
00593                 /* Special file. */
00594                 maj = atoi(token[4]);
00595                 min = atoi(token[5]);
00596                 size = 0;
00597                 if (token[6]) size = atoi(token[6]);
00598                 size = block_size * size;
00599                 add_zone(n, (zone_t) ((maj << 8) | min), size, current_time);
00600         } else {
00601                 /* Regular file. Go read it. */
00602                 if ((f = open(token[4], O_RDONLY)) < 0) {
00603                         fprintf(stderr, "%s: Can't open %s: %s\n",
00604                                 progname, token[4], strerror(errno));
00605                 } else {
00606                         eat_file(n, f);
00607                 }
00608         }
00609   }
00610 
00611 }
00612 
00613 /*================================================================
00614  *              eat_file  -  copy file to MINIX
00615  *===============================================================*/
00616 /* Zonesize >= blocksize */
00617 void eat_file(inode, f)
00618 ino_t inode;
00619 int f;
00620 {
00621   int ct, i, j, k;
00622   zone_t z;
00623   char *buf;
00624   long timeval;
00625 
00626   buf = alloc_block();
00627 
00628   do {
00629         for (i = 0, j = 0; i < zone_size; i++, j += ct) {
00630                 for (k = 0; k < block_size; k++) buf[k] = 0;
00631                 if ((ct = read(f, buf, block_size)) > 0) {
00632                         if (i == 0) z = alloc_zone();
00633                         put_block((z << zone_shift) + i, buf);
00634                 }
00635         }
00636         timeval = (dflag ? current_time : file_time(f));
00637         if (ct) add_zone(inode, z, (long) j, timeval);
00638   } while (ct == block_size);
00639   close(f);
00640 }
00641 
00642 
00643 
00644 /*================================================================
00645  *          directory & inode management assist group
00646  *===============================================================*/
00647 void enter_dir(parent, name, child)
00648 ino_t parent, child;
00649 char *name;
00650 {
00651   /* Enter child in parent directory */
00652   /* Works for dir > 1 block and zone > block */
00653   int i, j, k, l, off;
00654   block_t b;
00655   zone_t z;
00656   char *p1, *p2;
00657   struct direct *dir_entry;
00658   d1_inode ino1[V1_INODES_PER_BLOCK];
00659   d2_inode *ino2;
00660   int nr_dzones;
00661 
00662   b = ((parent - 1) / inodes_per_block) + inode_offset;
00663   off = (parent - 1) % inodes_per_block;
00664 
00665   if(!(dir_entry = malloc(NR_DIR_ENTRIES(block_size) * sizeof(*dir_entry))))
00666         pexit("couldn't allocate directory entry");
00667 
00668   if(!(ino2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*ino2))))
00669         pexit("couldn't allocate block of inodes entry");
00670 
00671   if (fs_version == 1) {
00672         get_block(b, (char *) ino1);
00673         nr_dzones = V1_NR_DZONES;
00674   } else {
00675         get_block(b, (char *) ino2);
00676         nr_dzones = V2_NR_DZONES;
00677   }
00678   for (k = 0; k < nr_dzones; k++) {
00679         if (fs_version == 1) {
00680                 z = ino1[off].d1_zone[k];
00681                 if (z == 0) {
00682                         z = alloc_zone();
00683                         ino1[off].d1_zone[k] = z;
00684                 }
00685         } else {
00686                 z = ino2[off].d2_zone[k];
00687                 if (z == 0) {
00688                         z = alloc_zone();
00689                         ino2[off].d2_zone[k] = z;
00690                 }
00691         }
00692         for (l = 0; l < zone_size; l++) {
00693                 get_block((z << zone_shift) + l, (char *) dir_entry);
00694                 for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) {
00695                         if (dir_entry[i].d_ino == 0) {
00696                                 dir_entry[i].d_ino = child;
00697                                 p1 = name;
00698                                 p2 = dir_entry[i].d_name;
00699                                 j = sizeof(dir_entry[i].d_name);
00700                                 while (j--) {
00701                                         *p2++ = *p1;
00702                                         if (*p1 != 0) p1++;
00703                                 }
00704                                 put_block((z << zone_shift) + l, (char *) dir_entry);
00705                                 if (fs_version == 1) {
00706                                         put_block(b, (char *) ino1);
00707                                 } else {
00708                                         put_block(b, (char *) ino2);
00709                                 }
00710                                 free(dir_entry);
00711                                 free(ino2);
00712                                 return;
00713                         }
00714                 }
00715         }
00716   }
00717 
00718   printf("Directory-inode %d beyond direct blocks.  Could not enter %s\n",
00719          parent, name);
00720   pexit("Halt");
00721 }
00722 
00723 
00724 void add_zone(n, z, bytes, cur_time)
00725 ino_t n;
00726 zone_t z;
00727 long bytes, cur_time;
00728 {
00729   if (fs_version == 1) {
00730         add_z_1(n, z, bytes, cur_time);
00731   } else {
00732         add_z_2(n, z, bytes, cur_time);
00733   }
00734 }
00735 
00736 void add_z_1(n, z, bytes, cur_time)
00737 ino_t n;
00738 zone_t z;
00739 long bytes, cur_time;
00740 {
00741   /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
00742 
00743   int off, i;
00744   block_t b;
00745   zone_t indir;
00746   zone1_t blk[V1_INDIRECTS];
00747   d1_inode *p;
00748   d1_inode inode[V1_INODES_PER_BLOCK];
00749 
00750   b = ((n - 1) / V1_INODES_PER_BLOCK) + inode_offset;
00751   off = (n - 1) % V1_INODES_PER_BLOCK;
00752   get_block(b, (char *) inode);
00753   p = &inode[off];
00754   p->d1_size += bytes;
00755   p->d1_mtime = cur_time;
00756   for (i = 0; i < V1_NR_DZONES; i++)
00757         if (p->d1_zone[i] == 0) {
00758                 p->d1_zone[i] = (zone1_t) z;
00759                 put_block(b, (char *) inode);
00760                 return;
00761         }
00762   put_block(b, (char *) inode);
00763 
00764   /* File has grown beyond a small file. */
00765   if (p->d1_zone[V1_NR_DZONES] == 0)
00766         p->d1_zone[V1_NR_DZONES] = (zone1_t) alloc_zone();
00767   indir = p->d1_zone[V1_NR_DZONES];
00768   put_block(b, (char *) inode);
00769   b = indir << zone_shift;
00770   get_block(b, (char *) blk);
00771   for (i = 0; i < V1_INDIRECTS; i++)
00772         if (blk[i] == 0) {
00773                 blk[i] = (zone1_t) z;
00774                 put_block(b, (char *) blk);
00775                 return;
00776         }
00777   pexit("File has grown beyond single indirect");
00778 }
00779 
00780 void add_z_2(n, z, bytes, cur_time)
00781 ino_t n;
00782 zone_t z;
00783 long bytes, cur_time;
00784 {
00785   /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
00786 
00787   int off, i;
00788   block_t b;
00789   zone_t indir;
00790   zone_t *blk;
00791   d2_inode *p;
00792   d2_inode *inode;
00793 
00794   if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
00795         pexit("Couldn't allocate indirect block");
00796 
00797   if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
00798         pexit("Couldn't allocate block of inodes");
00799 
00800   b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
00801   off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
00802   get_block(b, (char *) inode);
00803   p = &inode[off];
00804   p->d2_size += bytes;
00805   p->d2_mtime = cur_time;
00806   for (i = 0; i < V2_NR_DZONES; i++)
00807         if (p->d2_zone[i] == 0) {
00808                 p->d2_zone[i] = z;
00809                 put_block(b, (char *) inode);
00810                 free(blk);
00811                 free(inode);
00812                 return;
00813         }
00814   put_block(b, (char *) inode);
00815 
00816   /* File has grown beyond a small file. */
00817   if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
00818   indir = p->d2_zone[V2_NR_DZONES];
00819   put_block(b, (char *) inode);
00820   b = indir << zone_shift;
00821   get_block(b, (char *) blk);
00822   for (i = 0; i < V2_INDIRECTS(block_size); i++)
00823         if (blk[i] == 0) {
00824                 blk[i] = z;
00825                 put_block(b, (char *) blk);
00826                 free(blk);
00827                 free(inode);
00828                 return;
00829         }
00830   pexit("File has grown beyond single indirect");
00831 }
00832 
00833 
00834 void incr_link(n)
00835 ino_t n;
00836 {
00837   /* Increment the link count to inode n */
00838   int off;
00839   static int enter = 0;
00840   block_t b;
00841 
00842   if(enter) exit(1);
00843 
00844   b = ((n - 1) / inodes_per_block) + inode_offset;
00845   off = (n - 1) % inodes_per_block;
00846   if (fs_version == 1) {
00847         d1_inode inode1[V1_INODES_PER_BLOCK];
00848 
00849         get_block(b, (char *) inode1);
00850         inode1[off].d1_nlinks++;
00851         put_block(b, (char *) inode1);
00852   } else {
00853         static d2_inode *inode2 = NULL;
00854         int n;
00855 
00856         n = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
00857         if(!inode2 && !(inode2 = malloc(n)))
00858                 pexit("couldn't allocate a block of inodes");
00859 
00860         get_block(b, (char *) inode2);
00861         inode2[off].d2_nlinks++;
00862         put_block(b, (char *) inode2);
00863   }
00864   enter = 0;
00865 }
00866 
00867 
00868 void incr_size(n, count)
00869 ino_t n;
00870 long count;
00871 {
00872   /* Increment the file-size in inode n */
00873   block_t b;
00874   int off;
00875 
00876   b = ((n - 1) / inodes_per_block) + inode_offset;
00877   off = (n - 1) % inodes_per_block;
00878   if (fs_version == 1) {
00879         d1_inode inode1[V1_INODES_PER_BLOCK];
00880 
00881         get_block(b, (char *) inode1);
00882         inode1[off].d1_size += count;
00883         put_block(b, (char *) inode1);
00884   } else {
00885         d2_inode *inode2;
00886         if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
00887                 pexit("couldn't allocate a block of inodes");
00888 
00889         get_block(b, (char *) inode2);
00890         inode2[off].d2_size += count;
00891         put_block(b, (char *) inode2);
00892         free(inode2);
00893   }
00894 }
00895 
00896 
00897 /*================================================================
00898  *                   allocation assist group
00899  *===============================================================*/
00900 PRIVATE ino_t alloc_inode(mode, usrid, grpid)
00901 int mode, usrid, grpid;
00902 {
00903   ino_t num;
00904   int off;
00905   block_t b;
00906 
00907   num = next_inode++;
00908   if (num > nrinodes) {
00909         fprintf(stderr, "have %d inodoes\n", nrinodes);
00910         pexit("File system does not have enough inodes");
00911   }
00912   b = ((num - 1) / inodes_per_block) + inode_offset;
00913   off = (num - 1) % inodes_per_block;
00914   if (fs_version == 1) {
00915         d1_inode inode1[V1_INODES_PER_BLOCK];
00916 
00917         get_block(b, (char *) inode1);
00918         inode1[off].d1_mode = mode;
00919         inode1[off].d1_uid = usrid;
00920         inode1[off].d1_gid = grpid;
00921         put_block(b, (char *) inode1);
00922   } else {
00923         d2_inode *inode2;
00924 
00925         if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
00926                 pexit("couldn't allocate a block of inodes");
00927 
00928         get_block(b, (char *) inode2);
00929         inode2[off].d2_mode = mode;
00930         inode2[off].d2_uid = usrid;
00931         inode2[off].d2_gid = grpid;
00932         put_block(b, (char *) inode2);
00933 
00934         free(inode2);
00935   }
00936 
00937   /* Set the bit in the bit map. */
00938   /* DEBUG FIXME.  This assumes the bit is in the first inode map block. */
00939   insert_bit((block_t) INODE_MAP, (int) num);
00940   return(num);
00941 }
00942 
00943 
00944 PRIVATE zone_t alloc_zone()
00945 {
00946   /* Allocate a new zone */
00947   /* Works for zone > block */
00948   block_t b;
00949   int i;
00950   zone_t z;
00951 
00952   z = next_zone++;
00953   b = z << zone_shift;
00954   if ((b + zone_size) > nrblocks)
00955         pexit("File system not big enough for all the files");
00956   for (i = 0; i < zone_size; i++)
00957         put_block(b + i, zero); /* give an empty zone */
00958   /* DEBUG FIXME.  This assumes the bit is in the first zone map block. */
00959   insert_bit(zone_map, (int) (z - zoff));       /* lint, NOT OK because
00960                                                  * z hasn't been broken
00961                                                  * up into block +
00962                                                  * offset yet. */
00963   return(z);
00964 }
00965 
00966 
00967 void insert_bit(block, bit)
00968 block_t block;
00969 int bit;
00970 {
00971   /* Insert 'count' bits in the bitmap */
00972   int w, s;
00973   short *buf;
00974 
00975   buf = (short *) alloc_block();
00976 
00977   if (block < 0) pexit("insert_bit called with negative argument");
00978   get_block(block, (char *) buf);
00979   w = bit / (8 * sizeof(short));
00980   s = bit % (8 * sizeof(short));
00981   buf[w] |= (1 << s);
00982   put_block(block, (char *) buf);
00983 
00984   free(buf);
00985 }
00986 
00987 
00988 /*================================================================
00989  *              proto-file processing assist group
00990  *===============================================================*/
00991 int mode_con(p)
00992 char *p;
00993 {
00994   /* Convert string to mode */
00995   int o1, o2, o3, mode;
00996   char c1, c2, c3;
00997 
00998   c1 = *p++;
00999   c2 = *p++;
01000   c3 = *p++;
01001   o1 = *p++ - '0';
01002   o2 = *p++ - '0';
01003   o3 = *p++ - '0';
01004   mode = (o1 << 6) | (o2 << 3) | o3;
01005   if (c1 == 'd') mode += I_DIRECTORY;
01006   if (c1 == 'b') mode += I_BLOCK_SPECIAL;
01007   if (c1 == 'c') mode += I_CHAR_SPECIAL;
01008   if (c1 == '-') mode += I_REGULAR;
01009   if (c2 == 'u') mode += I_SET_UID_BIT;
01010   if (c3 == 'g') mode += I_SET_GID_BIT;
01011   return(mode);
01012 }
01013 
01014 void getline(line, parse)
01015 char *parse[MAX_TOKENS];
01016 char line[LINE_LEN];
01017 {
01018   /* Read a line and break it up in tokens */
01019   int k;
01020   char c, *p;
01021   int d;
01022 
01023   for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
01024   for (k = 0; k < LINE_LEN; k++) line[k] = 0;
01025   k = 0;
01026   parse[0] = 0;
01027   p = line;
01028   while (1) {
01029         if (++k > LINE_LEN) pexit("Line too long");
01030         d = fgetc(proto);
01031         if (d == EOF) pexit("Unexpected end-of-file");
01032         *p = d;
01033         if (*p == '\n') lct++;
01034         if (*p == ' ' || *p == '\t') *p = 0;
01035         if (*p == '\n') {
01036                 *p++ = 0;
01037                 *p = '\n';
01038                 break;
01039         }
01040         p++;
01041   }
01042 
01043   k = 0;
01044   p = line;
01045   lastp = line;
01046   while (1) {
01047         c = *p++;
01048         if (c == '\n') return;
01049         if (c == 0) continue;
01050         parse[k++] = p - 1;
01051         do {
01052                 c = *p++;
01053         } while (c != 0 && c != '\n');
01054   }
01055 }
01056 
01057 
01058 /*================================================================
01059  *                      other stuff
01060  *===============================================================*/
01061 void check_mtab(devname)
01062 char *devname;                  /* /dev/hd1 or whatever */
01063 {
01064 /* Check to see if the special file named in s is mounted. */
01065 
01066   int n, r;
01067   struct stat sb;
01068   char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
01069 
01070   r= stat(devname, &sb);
01071   if (r == -1)
01072   {
01073         if (errno == ENOENT)
01074                 return; /* Does not exist, and therefore not mounted. */
01075         fprintf(stderr, "%s: stat %s failed: %s\n",
01076                 progname, devname, strerror(errno));
01077         exit(1);
01078   }
01079   if (!S_ISBLK(sb.st_mode))
01080   {
01081         /* Not a block device and therefore not mounted. */
01082         return;
01083   }
01084 
01085   if (load_mtab("mkfs") < 0) return;
01086   while (1) {
01087         n = get_mtab_entry(special, mounted_on, version, rw_flag);
01088         if (n < 0) return;
01089         if (strcmp(devname, special) == 0) {
01090                 /* Can't mkfs on top of a mounted file system. */
01091                 fprintf(stderr, "%s: %s is mounted on %s\n",
01092                         progname, devname, mounted_on);
01093                 exit(1);
01094         }
01095   }
01096 }
01097 
01098 
01099 long file_time(f)
01100 int f;
01101 {
01102 #ifdef UNIX
01103   struct stat statbuf;
01104   fstat(f, &statbuf);
01105   return(statbuf.st_mtime);
01106 #else                           /* fstat not supported by DOS */
01107   return(0L);
01108 #endif
01109 }
01110 
01111 
01112 void pexit(s)
01113 char *s;
01114 {
01115   fprintf(stderr, "%s: %s\n", progname, s);
01116   if (lct != 0)
01117         fprintf(stderr, "Line %d being processed when error detected.\n", lct);
01118   flush();
01119   exit(2);
01120 }
01121 
01122 
01123 void copy(from, to, count)
01124 char *from, *to;
01125 int count;
01126 {
01127   while (count--) *to++ = *from++;
01128 }
01129 
01130 char *alloc_block()
01131 {
01132         char *buf;
01133 
01134         if(!(buf = malloc(block_size))) {
01135                 pexit("couldn't allocate filesystem buffer");
01136         }
01137         bzero(buf, block_size);
01138 
01139         return buf;
01140 }
01141 
01142 void print_fs()
01143 {
01144   int i, j;
01145   ino_t k;
01146   d1_inode inode1[V1_INODES_PER_BLOCK];
01147   d2_inode *inode2;
01148   unsigned short *usbuf;
01149   block_t b, inode_limit;
01150   struct direct *dir;
01151 
01152   if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
01153         pexit("couldn't allocate a block of inodes");
01154 
01155   if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
01156         pexit("malloc of directory entry failed");
01157 
01158   usbuf = (unsigned short *) alloc_block();
01159 
01160   get_super_block((char *) usbuf);
01161   printf("\nSuperblock: ");
01162   for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
01163   get_block((block_t) 2, (char *) usbuf);
01164   printf("...\nInode map:  ");
01165   for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
01166   get_block((block_t) 3, (char *) usbuf);
01167   printf("...\nZone  map:  ");
01168   for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
01169   printf("...\n");
01170 
01171   free(usbuf);
01172   usbuf = NULL;
01173 
01174   k = 0;
01175   for (b = inode_offset; k < nrinodes; b++) {
01176         if (fs_version == 1) {
01177                 get_block(b, (char *) inode1);
01178         } else {
01179                 get_block(b, (char *) inode2);
01180         }
01181         for (i = 0; i < inodes_per_block; i++) {
01182                 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
01183                 /* Lint but OK */
01184                 if (k > nrinodes) break;
01185                 if (fs_version == 1) {
01186                         if (inode1[i].d1_mode != 0) {
01187                                 printf("Inode %2d:  mode=", k);
01188                                 printf("%06o", inode1[i].d1_mode);
01189                                 printf("  uid=%2d  gid=%2d  size=",
01190                                 inode1[i].d1_uid, inode1[i].d1_gid);
01191                                 printf("%6ld", inode1[i].d1_size);
01192                                 printf("  zone[0]=%d\n", inode1[i].d1_zone[0]);
01193                         }
01194                         if ((inode1[i].d1_mode & I_TYPE) == I_DIRECTORY) {
01195                                 /* This is a directory */
01196                                 get_block(inode1[i].d1_zone[0], (char *) dir);
01197                                 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
01198                                         if (dir[j].d_ino)
01199                                                 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
01200                         }
01201                 } else {
01202                         if (inode2[i].d2_mode != 0) {
01203                                 printf("Inode %2d:  mode=", k);
01204                                 printf("%06o", inode2[i].d2_mode);
01205                                 printf("  uid=%2d  gid=%2d  size=",
01206                                 inode2[i].d2_uid, inode2[i].d2_gid);
01207                                 printf("%6ld", inode2[i].d2_size);
01208                                 printf("  zone[0]=%ld\n", inode2[i].d2_zone[0]);
01209                         }
01210                         if ((inode2[i].d2_mode & I_TYPE) == I_DIRECTORY) {
01211                                 /* This is a directory */
01212                                 get_block(inode2[i].d2_zone[0], (char *) dir);
01213                                 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
01214                                         if (dir[j].d_ino)
01215                                                 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
01216                         }
01217                 }
01218         }
01219   }
01220 
01221   printf("%d inodes used.     %d zones used.\n", next_inode - 1, next_zone);
01222   free(dir);
01223   free(inode2);
01224 }
01225 
01226 
01227 int read_and_set(n)
01228 block_t n;
01229 {
01230 /* The first time a block is read, it returns all 0s, unless there has
01231  * been a write.  This routine checks to see if a block has been accessed.
01232  */
01233 
01234   int w, s, mask, r;
01235 
01236   if (sizeof(char *) == 2 && n >= MAX_INIT) pexit("can't initialize past 128M");
01237   w = n / 8;
01238   s = n % 8;
01239   mask = 1 << s;
01240   r = (umap[w] & mask ? 1 : 0);
01241   umap[w] |= mask;
01242   return(r);
01243 }
01244 
01245 void usage()
01246 {
01247   fprintf(stderr,
01248           "Usage: %s [-12dlot] [-b blocks] [-i inodes] [-B blocksize] special [proto]\n",
01249           progname);
01250   exit(1);
01251 }
01252 
01253 /*================================================================
01254  *                    get_block & put_block for MS-DOS
01255  *===============================================================*/
01256 #ifdef DOS
01257 
01258 /*
01259  *      These are the get_block and put_block routines
01260  *      when compiling & running mkfs.c under MS-DOS.
01261  *
01262  *      It requires the (asembler) routines absread & abswrite
01263  *      from the file diskio.asm. Since these routines just do
01264  *      as they are told (read & write the sector specified),
01265  *      a local cache is used to minimize the i/o-overhead for
01266  *      frequently used blocks.
01267  *
01268  *      The global variable "file" determines whether the output
01269  *      is to a disk-device or to a binary file.
01270  */
01271 
01272 
01273 #define PH_SECTSIZE        512  /* size of a physical disk-sector */
01274 
01275 
01276 char *derrtab[14] = {
01277              "no error",
01278              "disk is read-only",
01279              "unknown unit",
01280              "device not ready",
01281              "bad command",
01282              "data error",
01283              "internal error: bad request structure length",
01284              "seek error",
01285              "unknown media type",
01286              "sector not found",
01287              "printer out of paper (?)",
01288              "write fault",
01289              "read error",
01290              "general error"
01291 };
01292 
01293 #define CACHE_SIZE      20      /* 20 block-buffers */
01294 
01295 
01296 struct cache {
01297   char blockbuf[BLOCK_SIZE];
01298   block_t blocknum;
01299   int dirty;
01300   int usecnt;
01301 } cache[CACHE_SIZE];
01302 
01303 
01304 void special(string)
01305 char *string;
01306 {
01307 
01308   if (string[1] == ':' && string[2] == 0) {
01309         /* Format: d: or d:fname */
01310         disk = (string[0] & ~32) - 'A';
01311         if (disk > 1 && !override)      /* safety precaution */
01312                 pexit("Bad drive specifier for special");
01313   } else {
01314         file = 1;
01315         if ((fd = creat(string, BWRITE)) == 0)
01316                 pexit("Can't open special file");
01317   }
01318 }
01319 
01320 void get_block(n, buf)
01321 block_t n;
01322 char *buf;
01323 {
01324   /* Get a block to the user */
01325   struct cache *bp, *fp;
01326 
01327   /* First access returns a zero block */
01328   if (read_and_set(n) == 0) {
01329         copy(zero, buf, block_size);
01330         return;
01331   }
01332 
01333   /* Look for block in cache */
01334   fp = 0;
01335   for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
01336         if (bp->blocknum == n) {
01337                 copy(bp, buf, block_size);
01338                 bp->usecnt++;
01339                 return;
01340         }
01341 
01342         /* Remember clean block */
01343         if (bp->dirty == 0)
01344                 if (fp) {
01345                         if (fp->usecnt > bp->usecnt) fp = bp;
01346                 } else
01347                         fp = bp;
01348   }
01349 
01350   /* Block not in cache, get it */
01351   if (!fp) {
01352         /* No clean buf, flush one */
01353         for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
01354                 if (fp->usecnt > bp->usecnt) fp = bp;
01355         mx_write(fp->blocknum, fp);
01356   }
01357   mx_read(n, fp);
01358   fp->dirty = 0;
01359   fp->usecnt = 0;
01360   fp->blocknum = n;
01361   copy(fp, buf, block_size);
01362 }
01363 
01364 void put_block(n, buf)
01365 block_t n;
01366 char *buf;
01367 {   
01368   /* Accept block from user */
01369   struct cache *fp, *bp;
01370 
01371   (void) read_and_set(n);
01372 
01373   /* Look for block in cache */
01374   fp = 0;
01375   for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
01376         if (bp->blocknum == n) {
01377                 copy(buf, bp, block_size);
01378                 bp->dirty = 1;
01379                 return;
01380         }
01381 
01382         /* Remember clean block */
01383         if (bp->dirty == 0)
01384                 if (fp) {
01385                         if (fp->usecnt > bp->usecnt) fp = bp;
01386                 } else
01387                         fp = bp;
01388   }
01389 
01390   /* Block not in cache */
01391   if (!fp) {
01392         /* No clean buf, flush one */
01393         for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
01394                 if (fp->usecnt > bp->usecnt) fp = bp;
01395         mx_write(fp->blocknum, fp);
01396   }
01397   fp->dirty = 1;
01398   fp->usecnt = 1;
01399   fp->blocknum = n;
01400   copy(buf, fp, block_size);
01401 }
01402 
01403 void cache_init()
01404 {
01405   struct cache *bp;
01406   for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
01407 }
01408 
01409 void flush()
01410 {
01411   /* Flush all dirty blocks to disk */
01412   struct cache *bp;
01413 
01414   for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
01415         if (bp->dirty) {
01416                 mx_write(bp->blocknum, bp);
01417                 bp->dirty = 0;
01418         }
01419 }
01420 
01421 /*==================================================================
01422  *                      hard read & write etc.
01423  *=================================================================*/
01424 #define MAX_RETRIES     5
01425 
01426 
01427 void mx_read(blocknr, buf)
01428 int blocknr;
01429 char *buf;
01430 {
01431 
01432   /* Read the requested MINIX-block in core */
01433   char (*bp)[PH_SECTSIZE];
01434   int sectnum, retries, err;
01435 
01436   if (file) {
01437         lseek(fd, (off_t) blocknr * block_size, 0);
01438         if (read(fd, buf, block_size) != block_size)
01439                 pexit("mx_read: error reading file");
01440   } else {
01441         sectnum = blocknr * (block_size / PH_SECTSIZE);
01442         for (bp = buf; bp < &buf[block_size]; bp++) {
01443                 retries = MAX_RETRIES;
01444                 do
01445                         err = absread(disk, sectnum, bp);
01446                 while (err && --retries);
01447 
01448                 if (retries) {
01449                         sectnum++;
01450                 } else {
01451                         dexit("mx_read", sectnum, err);
01452                 }
01453         }
01454   }
01455 }
01456 
01457 void mx_write(blocknr, buf)
01458 int blocknr;
01459 char *buf;
01460 {
01461   /* Write the MINIX-block to disk */
01462   char (*bp)[PH_SECTSIZE];
01463   int retries, sectnum, err;
01464 
01465   if (file) {
01466         lseek(fd, blocknr * block_size, 0);
01467         if (write(fd, buf, block_size) != block_size) {
01468                 pexit("mx_write: error writing file");
01469         }
01470   } else {
01471         sectnum = blocknr * (block_size / PH_SECTSIZE);
01472         for (bp = buf; bp < &buf[block_size]; bp++) {
01473                 retries = MAX_RETRIES;
01474                 do {
01475                         err = abswrite(disk, sectnum, bp);
01476                 } while (err && --retries);
01477 
01478                 if (retries) {
01479                         sectnum++;
01480                 } else {
01481                         dexit("mx_write", sectnum, err);
01482                 }
01483         }
01484   }
01485 }
01486 
01487 
01488 void dexit(s, sectnum, err)
01489 int sectnum, err;
01490 char *s;
01491 {
01492   printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
01493          s, sectnum, err, derrtab[err]);
01494   exit(2);
01495 }
01496 
01497 #endif
01498 
01499 /*================================================================
01500  *                    get_block & put_block for UNIX
01501  *===============================================================*/
01502 #ifdef UNIX
01503 
01504 void special(string)
01505 char *string;
01506 {
01507   fd = creat(string, 0777);
01508   close(fd);
01509   fd = open(string, O_RDWR);
01510   if (fd < 0) pexit("Can't open special file");
01511 #if (MACHINE == ATARI)
01512   {
01513         struct stat statbuf;
01514 
01515         if (fstat(fd, &statbuf) < 0) return;
01516         isdev = (statbuf.st_mode & S_IFMT) == S_IFCHR
01517                 ||
01518                 (statbuf.st_mode & S_IFMT) == S_IFBLK
01519                 ;
01520   }
01521 #endif
01522 }
01523 
01524 
01525 
01526 void get_block(n, buf)
01527 block_t n;
01528 char *buf;
01529 {
01530 /* Read a block. */
01531 
01532   int k;
01533 
01534   /* First access returns a zero block */
01535   if (read_and_set(n) == 0) {
01536         copy(zero, buf, block_size);
01537         return;
01538   }
01539   lseek(fd, (off_t) n * block_size, SEEK_SET);
01540   k = read(fd, buf, block_size);
01541   if (k != block_size) {
01542         pexit("get_block couldn't read");
01543   }
01544 }
01545 
01546 void get_super_block(buf)
01547 char *buf;
01548 {
01549 /* Read a block. */
01550 
01551   int k;
01552 
01553   if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
01554         perror("lseek");
01555         pexit("seek failed");
01556   }
01557   k = read(fd, buf, _STATIC_BLOCK_SIZE);
01558   if (k != _STATIC_BLOCK_SIZE) {
01559         pexit("get_super_block couldn't read");
01560   }
01561 }
01562 
01563 void put_block(n, buf)
01564 block_t n;
01565 char *buf;
01566 {
01567 /* Write a block. */
01568 
01569   (void) read_and_set(n);
01570 
01571   /* XXX - check other lseeks too. */
01572   if (lseek(fd, (off_t) n * block_size, SEEK_SET) == (off_t) -1) {
01573         pexit("put_block couldn't seek");
01574   }
01575   if (write(fd, buf, block_size) != block_size) {
01576         pexit("put_block couldn't write");
01577   }
01578 }
01579 
01580 
01581 /* Dummy routines to keep source file clean from #ifdefs */
01582 
01583 void flush()
01584 {
01585   return;
01586 }
01587 
01588 void cache_init()
01589 {
01590   return;
01591 }
01592 
01593 #endif

Generated on Fri Apr 14 22:57:09 2006 for minix by  doxygen 1.4.6