VM: make mapping types explicit
[minix.git] / usr.sbin / mkfs.mfs / mkfs.c
blob9a0fd9fab259524a5748482c84a40c0b29ec6c0a
1 /* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. */
3 /* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
5 * This program can make version 1, 2 and 3 file systems, as follows:
6 * mkfs /dev/fd0 1200 # Version 3 (default)
7 * mkfs -1 /dev/fd0 360 # Version 1
9 * Note that the version 1 and 2 file systems produced by this program are not
10 * compatible with the original version 1 and 2 file system layout.
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <stdio.h>
16 #include <errno.h>
17 #include <fcntl.h>
18 #include <limits.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <time.h>
22 #include <unistd.h>
23 #include <stdint.h>
24 #include "const.h"
25 #include "type.h"
26 #include "mfsdir.h"
27 #if defined(__minix)
28 #include <minix/partition.h>
29 #include <minix/u64.h>
30 #include <sys/ioctl.h>
31 #endif
32 #include <dirent.h>
34 #undef EXTERN
35 #define EXTERN /* get rid of EXTERN by making it null */
36 #include "super.h"
38 #ifndef max
39 #define max(a,b) ((a) > (b) ? (a) : (b))
40 #endif
42 #ifndef DOS
43 #ifndef UNIX
44 #define UNIX
45 #endif
46 #endif
48 #define INODE_MAP 2
49 #define MAX_TOKENS 10
50 #define LINE_LEN 200
51 #define BIN 2
52 #define BINGRP 2
53 #define BIT_MAP_SHIFT 13
54 #define INODE_MAX ((unsigned) 65535)
55 #define SECTOR_SIZE 512
58 #ifdef DOS
59 maybedefine O_RDONLY 4 /* O_RDONLY | BINARY_BIT */
60 maybedefine BWRITE 5 /* O_WRONLY | BINARY_BIT */
61 #endif
63 #if !defined(__minix)
64 #define mul64u(a,b) ((a) * (b))
65 #define lseek64(a,b,c,d) lseek(a,b,c)
66 #ifdef __linux__
67 #include <mntent.h>
68 #endif
69 #endif
71 #if !defined(__minix)
72 typedef uint32_t block_t;
73 typedef uint32_t zone_t;
74 #endif
76 extern char *optarg;
77 extern int optind;
79 int next_zone, next_inode, zone_size, zone_shift = 0, zoff;
80 block_t nrblocks;
81 int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
82 unsigned int nrinodes;
83 int override = 0, simple = 0, dflag;
84 int donttest; /* skip test if it fits on medium */
85 char *progname;
87 uint32_t current_time, bin_time;
88 char *zero, *lastp;
89 char *umap_array; /* bit map tells if block read yet */
90 int umap_array_elements = 0;
91 block_t zone_map; /* where is zone map? (depends on # inodes) */
92 int inodes_per_block;
93 int fs_version;
94 size_t block_size;
96 FILE *proto;
98 #if defined(__NBSD_LIBC) || !defined(__minix)
99 #define getline _mkfs_getline
100 #endif
102 int main(int argc, char **argv);
103 block_t sizeup(char *device);
104 void super(zone_t zones, ino_t inodes);
105 void rootdir(ino_t inode);
106 void eat_dir(ino_t parent);
107 void eat_file(ino_t inode, int f);
108 void enter_dir(ino_t parent, char *name, ino_t child);
109 void incr_size(ino_t n, size_t count);
110 static ino_t alloc_inode(int mode, int usrid, int grpid);
111 static zone_t alloc_zone(void);
112 void add_zone(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
113 void add_z_1(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
114 void add_z_2(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
115 void incr_link(ino_t n);
116 void insert_bit(block_t block, int bit);
117 int mode_con(char *p);
118 void getline(char line[LINE_LEN], char *parse[MAX_TOKENS]);
119 void check_mtab(char *devname);
120 uint32_t file_time(int f);
121 void pexit(char *s);
122 void copy(char *from, char *to, size_t count);
123 void print_fs(void);
124 int read_and_set(block_t n);
125 void special(char *string);
126 void get_block(block_t n, char *buf);
127 void get_super_block(char *buf);
128 void put_block(block_t n, char *buf);
129 void cache_init(void);
130 void flush(void);
131 void mx_read(int blocknr, char *buf);
132 void mx_write(int blocknr, char *buf);
133 void dexit(char *s, int sectnum, int err);
134 void usage(void);
135 char *alloc_block(void);
137 /*================================================================
138 * mkfs - make filesystem
139 *===============================================================*/
140 int main(argc, argv)
141 int argc;
142 char *argv[];
144 int nread, mode, usrid, grpid, ch;
145 block_t blocks, maxblocks;
146 size_t i;
147 ino_t root_inum;
148 ino_t inodes;
149 zone_t zones;
150 char *token[MAX_TOKENS], line[LINE_LEN];
151 struct stat statbuf;
153 /* Get two times, the current time and the mod time of the binary of
154 * mkfs itself. When the -d flag is used, the later time is put into
155 * the i_mtimes of all the files. This feature is useful when
156 * producing a set of file systems, and one wants all the times to be
157 * identical. First you set the time of the mkfs binary to what you
158 * want, then go.
160 current_time = time((time_t *) 0); /* time mkfs is being run */
161 stat(argv[0], &statbuf);
162 bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */
164 /* Process switches. */
165 progname = argv[0];
166 blocks = 0;
167 i = 0;
168 fs_version = 3;
169 inodes_per_block = 0;
170 block_size = 0;
171 while ((ch = getopt(argc, argv, "12b:di:lotB:")) != EOF)
172 switch (ch) {
173 case '1':
174 fs_version = 1;
175 inodes_per_block = V1_INODES_PER_BLOCK;
176 break;
177 case '2':
178 fs_version = 2;
179 break;
180 case 'b':
181 blocks = strtoul(optarg, (char **) NULL, 0);
182 break;
183 case 'd':
184 dflag = 1;
185 current_time = bin_time;
186 break;
187 case 'i':
188 i = strtoul(optarg, (char **) NULL, 0);
189 break;
190 case 'l': print = 1; break;
191 case 'o': override = 1; break;
192 case 't': donttest = 1; break;
193 case 'B': block_size = atoi(optarg); break;
194 default: usage();
197 if (argc == optind) usage();
199 if(fs_version == 3) {
200 if(!block_size) block_size = _MAX_BLOCK_SIZE; /* V3 default block size */
201 if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
202 fprintf(stderr, "block size must be multiple of sector (%d) "
203 "and at least %d bytes\n",
204 SECTOR_SIZE, _MIN_BLOCK_SIZE);
205 pexit("specified block size illegal");
207 if(block_size%V2_INODE_SIZE) {
208 fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
209 V2_INODE_SIZE);
210 pexit("specified block size illegal");
212 } else {
213 if(block_size) {
214 pexit("Can't specify a block size if FS version is <3");
216 block_size = _STATIC_BLOCK_SIZE; /* V1/V2 block size */
219 if(!inodes_per_block)
220 inodes_per_block = V2_INODES_PER_BLOCK(block_size);
222 /* now that the block size is known, do buffer allocations where
223 * possible.
225 zero = alloc_block();
226 bzero(zero, block_size);
228 /* Determine the size of the device if not specified as -b or proto. */
229 maxblocks = sizeup(argv[optind]);
230 if (argc - optind == 1 && blocks == 0) {
231 blocks = maxblocks;
232 /* blocks == 0 is checked later, but leads to a funny way of
233 * reporting a 0-sized device (displays usage).
235 if(blocks < 1) {
236 fprintf(stderr, "%s: zero size device.\n", progname);
237 return 1;
241 /* The remaining args must be 'special proto', or just 'special' if the
242 * no. of blocks has already been specified.
244 if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
246 if (blocks > maxblocks) {
247 fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
248 progname, argv[optind]);
249 return 1;
252 /* Check special. */
253 check_mtab(argv[optind]);
255 /* Check and start processing proto. */
256 optarg = argv[++optind];
257 if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
258 /* Prototype file is readable. */
259 lct = 1;
260 getline(line, token); /* skip boot block info */
262 /* Read the line with the block and inode counts. */
263 getline(line, token);
264 blocks = atol(token[0]);
265 inodes = atoi(token[1]);
267 /* Process mode line for root directory. */
268 getline(line, token);
269 mode = mode_con(token[0]);
270 usrid = atoi(token[1]);
271 grpid = atoi(token[2]);
272 } else {
273 lct = 0;
274 if (optind < argc) {
275 /* Maybe the prototype file is just a size. Check. */
276 blocks = strtoul(optarg, (char **) NULL, 0);
277 if (blocks == 0) pexit("Can't open prototype file");
279 if (i == 0) {
280 #if defined(__minix)
281 uint32_t kb = div64u(mul64u(blocks, block_size), 1024);
282 #else
283 uint32_t kb = ((unsigned long long) blocks * block_size) / 1024;
284 #endif
285 i = kb / 2;
286 if (kb >= 100000) i = kb / 4;
288 /* round up to fill inode block */
289 i += inodes_per_block - 1;
290 i = i / inodes_per_block * inodes_per_block;
291 if (i > INODE_MAX && fs_version < 3) i = INODE_MAX;
294 if (blocks < 5) pexit("Block count too small");
295 if (i < 1) pexit("Inode count too small");
296 if (i > INODE_MAX && fs_version < 3) pexit("Inode count too large");
297 inodes = (ino_t) i;
299 /* Make simple file system of the given size, using defaults. */
300 mode = 040777;
301 usrid = BIN;
302 grpid = BINGRP;
303 simple = 1;
306 nrblocks = blocks;
307 nrinodes = inodes;
310 size_t bytes;
311 bytes = 1 + blocks/8;
312 if(!(umap_array = malloc(bytes))) {
313 fprintf(stderr, "mkfs: can't allocate block bitmap (%u bytes).\n",
314 bytes);
315 exit(1);
317 umap_array_elements = bytes;
320 /* Open special. */
321 special(argv[--optind]);
323 #ifdef UNIX
324 if (!donttest) {
325 short *testb;
326 ssize_t w;
328 testb = (short *) alloc_block();
330 /* Try writing the last block of partition or diskette. */
331 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
332 pexit("couldn't seek to last block to test size (1)");
334 testb[0] = 0x3245;
335 testb[1] = 0x11FF;
336 testb[block_size/2-1] = 0x1F2F;
337 if ((w=write(fd, (char *) testb, block_size)) != block_size) {
338 if(w < 0) perror("write");
339 printf("%d/%u\n", w, block_size);
340 pexit("File system is too big for minor device (write)");
342 sync(); /* flush write, so if error next read fails */
343 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
344 pexit("couldn't seek to last block to test size (2)");
346 testb[0] = 0;
347 testb[1] = 0;
348 nread = read(fd, (char *) testb, block_size);
349 if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
350 testb[block_size/2-1] != 0x1F2F) {
351 if(nread < 0) perror("read");
352 printf("nread = %d\n", nread);
353 printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]);
354 pexit("File system is too big for minor device (read)");
356 lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL);
357 testb[0] = 0;
358 testb[1] = 0;
359 if (write(fd, (char *) testb, block_size) != block_size)
360 pexit("File system is too big for minor device (write2)");
361 lseek(fd, 0L, SEEK_SET);
362 free(testb);
364 #endif
366 /* Make the file-system */
368 cache_init();
370 put_block((block_t) 0, zero); /* Write a null boot block. */
372 zone_shift = 0; /* for future use */
373 zones = nrblocks >> zone_shift;
375 super(zones, inodes);
377 root_inum = alloc_inode(mode, usrid, grpid);
378 rootdir(root_inum);
379 if (simple == 0) eat_dir(root_inum);
381 if (print) print_fs();
382 flush();
383 return(0);
385 /* NOTREACHED */
386 } /* end main */
389 /*================================================================
390 * sizeup - determine device size
391 *===============================================================*/
392 block_t sizeup(device)
393 char *device;
395 block_t d;
396 #if defined(__minix)
397 u64_t bytes, resize;
398 u32_t rem;
399 #else
400 off_t size;
401 #endif
404 if ((fd = open(device, O_RDONLY)) == -1) {
405 if (errno != ENOENT)
406 perror("sizeup open");
407 return 0;
410 #if defined(__minix)
411 if(minix_sizeup(device, &bytes) < 0) {
412 perror("sizeup");
413 return 0;
416 d = div64u(bytes, block_size);
417 rem = rem64u(bytes, block_size);
419 resize = add64u(mul64u(d, block_size), rem);
420 if(cmp64(resize, bytes) != 0) {
421 d = ULONG_MAX;
422 fprintf(stderr, "mkfs: truncating FS at %u blocks\n", d);
424 #else
425 size = lseek(fd, 0, SEEK_END);
426 if (size == (off_t) -1) {
427 fprintf(stderr, "Cannot get device size fd=%d\n", fd);
428 exit(-1);
430 d = size / block_size;
431 #endif
433 return d;
437 * copied from fslib
439 static int bitmapsize(nr_bits, block_size)
440 uint32_t nr_bits;
441 size_t block_size;
443 block_t nr_blocks;
445 nr_blocks = (int) (nr_bits / FS_BITS_PER_BLOCK(block_size));
446 if (((uint32_t) nr_blocks * FS_BITS_PER_BLOCK(block_size)) < nr_bits) ++nr_blocks;
447 return(nr_blocks);
450 /*================================================================
451 * super - construct a superblock
452 *===============================================================*/
454 void super(zones, inodes)
455 zone_t zones;
456 ino_t inodes;
458 unsigned int i;
459 int inodeblks;
460 int initblks;
461 uint32_t nb;
462 zone_t v1sq, v2sq;
463 zone_t zo;
464 struct super_block *sup;
465 char *buf, *cp;
467 buf = alloc_block();
469 for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
470 sup = (struct super_block *) buf; /* lint - might use a union */
472 /* The assumption is that mkfs will create a clean FS. */
473 sup->s_flags = MFSFLAG_CLEAN;
475 sup->s_ninodes = inodes;
476 if (fs_version == 1) {
477 sup->s_nzones = zones;
478 if (sup->s_nzones != zones) pexit("too many zones");
479 } else {
480 sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */
481 sup->s_zones = zones;
484 #define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
485 sup->s_imap_blocks = nb = bitmapsize((uint32_t) (1 + inodes), block_size);
486 if(sup->s_imap_blocks != nb) {
487 fprintf(stderr, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS);
488 exit(1);
490 sup->s_zmap_blocks = nb = bitmapsize((uint32_t) zones, block_size);
491 if(nb != sup->s_zmap_blocks) {
492 fprintf(stderr, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS);
493 exit(1);
495 inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks;
496 inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
497 initblks = inode_offset + inodeblks;
498 sup->s_firstdatazone_old = nb =
499 (initblks + (1 << zone_shift) - 1) >> zone_shift;
500 if(nb >= zones) pexit("bit maps too large");
501 if(nb != sup->s_firstdatazone_old) {
502 /* The field is too small to store the value. Fortunately, the value
503 * can be computed from other fields. We set the on-disk field to zero
504 * to indicate that it must not be used. Eventually, we can always set
505 * the on-disk field to zero, and stop using it.
507 sup->s_firstdatazone_old = 0;
509 sup->s_firstdatazone = nb;
510 zoff = sup->s_firstdatazone - 1;
511 sup->s_log_zone_size = zone_shift;
512 if (fs_version == 1) {
513 sup->s_magic = SUPER_MAGIC; /* identify super blocks */
514 v1sq = (zone_t) V1_INDIRECTS * V1_INDIRECTS;
515 zo = V1_NR_DZONES + (int) V1_INDIRECTS + v1sq;
516 sup->s_max_size = zo * block_size;
517 } else {
518 v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
519 zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
520 if(fs_version == 2) {
521 sup->s_magic = SUPER_V2;/* identify super blocks */
522 sup->s_max_size = zo * block_size;
523 } else {
524 sup->s_magic = SUPER_V3;
525 sup->s_block_size = block_size;
526 sup->s_disk_version = 0;
527 #define MAX_MAX_SIZE (INT_MAX)
528 if(MAX_MAX_SIZE/block_size < zo) {
529 sup->s_max_size = (int32_t) MAX_MAX_SIZE;
531 else {
532 sup->s_max_size = zo * block_size;
537 zone_size = 1 << zone_shift; /* nr of blocks per zone */
539 if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
540 pexit("super() couldn't seek");
542 if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
543 pexit("super() couldn't write");
546 /* Clear maps and inodes. */
547 for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero);
549 next_zone = sup->s_firstdatazone;
550 next_inode = 1;
552 zone_map = INODE_MAP + sup->s_imap_blocks;
554 insert_bit(zone_map, 0); /* bit zero must always be allocated */
555 insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but
556 * must be allocated */
558 free(buf);
562 /*================================================================
563 * rootdir - install the root directory
564 *===============================================================*/
565 void rootdir(inode)
566 ino_t inode;
568 zone_t z;
570 z = alloc_zone();
571 add_zone(inode, z, 2 * sizeof(struct direct), current_time);
572 enter_dir(inode, ".", inode);
573 enter_dir(inode, "..", inode);
574 incr_link(inode);
575 incr_link(inode);
579 /*================================================================
580 * eat_dir - recursively install directory
581 *===============================================================*/
582 void eat_dir(parent)
583 ino_t parent;
585 /* Read prototype lines and set up directory. Recurse if need be. */
586 char *token[MAX_TOKENS], *p;
587 char line[LINE_LEN];
588 int mode, usrid, grpid, maj, min, f;
589 ino_t n;
590 zone_t z;
591 size_t size;
593 while (1) {
594 getline(line, token);
595 p = token[0];
596 if (*p == '$') return;
597 p = token[1];
598 mode = mode_con(p);
599 usrid = atoi(token[2]);
600 grpid = atoi(token[3]);
601 if (grpid & 0200) fprintf(stderr, "A.S.Tanenbaum\n");
602 n = alloc_inode(mode, usrid, grpid);
604 /* Enter name in directory and update directory's size. */
605 enter_dir(parent, token[0], n);
606 incr_size(parent, sizeof(struct direct));
608 /* Check to see if file is directory or special. */
609 incr_link(n);
610 if (*p == 'd') {
611 /* This is a directory. */
612 z = alloc_zone(); /* zone for new directory */
613 add_zone(n, z, 2 * sizeof(struct direct), current_time);
614 enter_dir(n, ".", n);
615 enter_dir(n, "..", parent);
616 incr_link(parent);
617 incr_link(n);
618 eat_dir(n);
619 } else if (*p == 'b' || *p == 'c') {
620 /* Special file. */
621 maj = atoi(token[4]);
622 min = atoi(token[5]);
623 size = 0;
624 if (token[6]) size = atoi(token[6]);
625 size = block_size * size;
626 add_zone(n, (zone_t) (makedev(maj,min)), size, current_time);
627 } else {
628 /* Regular file. Go read it. */
629 if ((f = open(token[4], O_RDONLY)) < 0) {
630 fprintf(stderr, "%s: Can't open %s: %s\n",
631 progname, token[4], strerror(errno));
632 } else {
633 eat_file(n, f);
640 /*================================================================
641 * eat_file - copy file to MINIX
642 *===============================================================*/
643 /* Zonesize >= blocksize */
644 void eat_file(inode, f)
645 ino_t inode;
646 int f;
648 int ct, i, j, k;
649 zone_t z;
650 char *buf;
651 uint32_t timeval;
653 buf = alloc_block();
655 do {
656 for (i = 0, j = 0; i < zone_size; i++, j += ct) {
657 for (k = 0; k < block_size; k++) buf[k] = 0;
658 if ((ct = read(f, buf, block_size)) > 0) {
659 if (i == 0) z = alloc_zone();
660 put_block((z << zone_shift) + i, buf);
663 timeval = (dflag ? current_time : file_time(f));
664 if (ct) add_zone(inode, z, (size_t) j, timeval);
665 } while (ct == block_size);
666 close(f);
667 free(buf);
672 /*================================================================
673 * directory & inode management assist group
674 *===============================================================*/
675 void enter_dir(parent, name, child)
676 ino_t parent, child;
677 char *name;
679 /* Enter child in parent directory */
680 /* Works for dir > 1 block and zone > block */
681 unsigned int i, j, k, l, off;
682 block_t b;
683 zone_t z;
684 char *p1, *p2;
685 struct direct *dir_entry;
686 d1_inode ino1[V1_INODES_PER_BLOCK];
687 d2_inode *ino2;
688 int nr_dzones;
690 b = ((parent - 1) / inodes_per_block) + inode_offset;
691 off = (parent - 1) % inodes_per_block;
693 if(!(dir_entry = malloc(NR_DIR_ENTRIES(block_size) * sizeof(*dir_entry))))
694 pexit("couldn't allocate directory entry");
696 if(!(ino2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*ino2))))
697 pexit("couldn't allocate block of inodes entry");
699 if (fs_version == 1) {
700 get_block(b, (char *) ino1);
701 nr_dzones = V1_NR_DZONES;
702 } else {
703 get_block(b, (char *) ino2);
704 nr_dzones = V2_NR_DZONES;
706 for (k = 0; k < nr_dzones; k++) {
707 if (fs_version == 1) {
708 z = ino1[off].d1_zone[k];
709 if (z == 0) {
710 z = alloc_zone();
711 ino1[off].d1_zone[k] = z;
713 } else {
714 z = ino2[off].d2_zone[k];
715 if (z == 0) {
716 z = alloc_zone();
717 ino2[off].d2_zone[k] = z;
720 for (l = 0; l < zone_size; l++) {
721 get_block((z << zone_shift) + l, (char *) dir_entry);
722 for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) {
723 if (dir_entry[i].mfs_d_ino == 0) {
724 dir_entry[i].mfs_d_ino = child;
725 p1 = name;
726 p2 = dir_entry[i].mfs_d_name;
727 j = sizeof(dir_entry[i].mfs_d_name);
728 j = 60;
729 while (j--) {
730 *p2++ = *p1;
731 if (*p1 != 0) p1++;
733 put_block((z << zone_shift) + l, (char *) dir_entry);
734 if (fs_version == 1) {
735 put_block(b, (char *) ino1);
736 } else {
737 put_block(b, (char *) ino2);
739 free(dir_entry);
740 free(ino2);
741 return;
747 printf("Directory-inode %lu beyond direct blocks. Could not enter %s\n",
748 parent, name);
749 pexit("Halt");
753 void add_zone(ino_t n, zone_t z, size_t bytes, uint32_t cur_time)
755 if (fs_version == 1) {
756 add_z_1(n, z, bytes, cur_time);
757 } else {
758 add_z_2(n, z, bytes, cur_time);
762 void add_z_1(ino_t n, zone_t z, size_t bytes, uint32_t cur_time)
764 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
766 int off, i;
767 block_t b;
768 zone_t indir;
769 uint16_t blk[V1_INDIRECTS];
770 d1_inode *p;
771 d1_inode inode[V1_INODES_PER_BLOCK];
773 b = ((n - 1) / V1_INODES_PER_BLOCK) + inode_offset;
774 off = (n - 1) % V1_INODES_PER_BLOCK;
775 get_block(b, (char *) inode);
776 p = &inode[off];
777 p->d1_size += bytes;
778 p->d1_mtime = cur_time;
779 for (i = 0; i < V1_NR_DZONES; i++)
780 if (p->d1_zone[i] == 0) {
781 p->d1_zone[i] = (uint16_t) z;
782 put_block(b, (char *) inode);
783 return;
785 put_block(b, (char *) inode);
787 /* File has grown beyond a small file. */
788 if (p->d1_zone[V1_NR_DZONES] == 0)
789 p->d1_zone[V1_NR_DZONES] = (uint16_t) alloc_zone();
790 indir = p->d1_zone[V1_NR_DZONES];
791 put_block(b, (char *) inode);
792 b = indir << zone_shift;
793 get_block(b, (char *) blk);
794 for (i = 0; i < V1_INDIRECTS; i++)
795 if (blk[i] == 0) {
796 blk[i] = (uint16_t) z;
797 put_block(b, (char *) blk);
798 return;
800 pexit("File has grown beyond single indirect");
803 void add_z_2(ino_t n, zone_t z, size_t bytes, uint32_t cur_time)
805 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
807 int off, i;
808 block_t b;
809 zone_t indir;
810 zone_t *blk;
811 d2_inode *p;
812 d2_inode *inode;
814 if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
815 pexit("Couldn't allocate indirect block");
817 if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
818 pexit("Couldn't allocate block of inodes");
820 b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
821 off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
822 get_block(b, (char *) inode);
823 p = &inode[off];
824 p->d2_size += bytes;
825 p->d2_mtime = cur_time;
826 for (i = 0; i < V2_NR_DZONES; i++)
827 if (p->d2_zone[i] == 0) {
828 p->d2_zone[i] = z;
829 put_block(b, (char *) inode);
830 free(blk);
831 free(inode);
832 return;
834 put_block(b, (char *) inode);
836 /* File has grown beyond a small file. */
837 if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
838 indir = p->d2_zone[V2_NR_DZONES];
839 put_block(b, (char *) inode);
840 b = indir << zone_shift;
841 get_block(b, (char *) blk);
842 for (i = 0; i < V2_INDIRECTS(block_size); i++)
843 if (blk[i] == 0) {
844 blk[i] = z;
845 put_block(b, (char *) blk);
846 free(blk);
847 free(inode);
848 return;
850 pexit("File has grown beyond single indirect");
854 void incr_link(n)
855 ino_t n;
857 /* Increment the link count to inode n */
858 int off;
859 static int enter = 0;
860 block_t b;
862 if(enter) exit(1);
864 b = ((n - 1) / inodes_per_block) + inode_offset;
865 off = (n - 1) % inodes_per_block;
866 if (fs_version == 1) {
867 d1_inode inode1[V1_INODES_PER_BLOCK];
869 get_block(b, (char *) inode1);
870 inode1[off].d1_nlinks++;
871 put_block(b, (char *) inode1);
872 } else {
873 static d2_inode *inode2 = NULL;
874 int n;
876 n = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
877 if(!inode2 && !(inode2 = malloc(n)))
878 pexit("couldn't allocate a block of inodes");
880 get_block(b, (char *) inode2);
881 inode2[off].d2_nlinks++;
882 put_block(b, (char *) inode2);
884 enter = 0;
888 void incr_size(n, count)
889 ino_t n;
890 size_t count;
892 /* Increment the file-size in inode n */
893 block_t b;
894 int off;
896 b = ((n - 1) / inodes_per_block) + inode_offset;
897 off = (n - 1) % inodes_per_block;
898 if (fs_version == 1) {
899 d1_inode inode1[V1_INODES_PER_BLOCK];
901 get_block(b, (char *) inode1);
902 inode1[off].d1_size += count;
903 put_block(b, (char *) inode1);
904 } else {
905 d2_inode *inode2;
906 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
907 pexit("couldn't allocate a block of inodes");
909 get_block(b, (char *) inode2);
910 inode2[off].d2_size += count;
911 put_block(b, (char *) inode2);
912 free(inode2);
917 /*================================================================
918 * allocation assist group
919 *===============================================================*/
920 static ino_t alloc_inode(mode, usrid, grpid)
921 int mode, usrid, grpid;
923 ino_t num;
924 int off;
925 block_t b;
927 num = next_inode++;
928 if (num > nrinodes) {
929 fprintf(stderr, "have %d inodoes\n", nrinodes);
930 pexit("File system does not have enough inodes");
932 b = ((num - 1) / inodes_per_block) + inode_offset;
933 off = (num - 1) % inodes_per_block;
934 if (fs_version == 1) {
935 d1_inode inode1[V1_INODES_PER_BLOCK];
937 get_block(b, (char *) inode1);
938 inode1[off].d1_mode = mode;
939 inode1[off].d1_uid = usrid;
940 inode1[off].d1_gid = grpid;
941 put_block(b, (char *) inode1);
942 } else {
943 d2_inode *inode2;
945 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
946 pexit("couldn't allocate a block of inodes");
948 get_block(b, (char *) inode2);
949 inode2[off].d2_mode = mode;
950 inode2[off].d2_uid = usrid;
951 inode2[off].d2_gid = grpid;
952 put_block(b, (char *) inode2);
954 free(inode2);
957 /* Set the bit in the bit map. */
958 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
959 insert_bit((block_t) INODE_MAP, (int) num);
960 return(num);
964 static zone_t alloc_zone()
966 /* Allocate a new zone */
967 /* Works for zone > block */
968 block_t b;
969 int i;
970 zone_t z;
972 z = next_zone++;
973 b = z << zone_shift;
974 if ((b + zone_size) > nrblocks)
975 pexit("File system not big enough for all the files");
976 for (i = 0; i < zone_size; i++)
977 put_block(b + i, zero); /* give an empty zone */
978 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
979 insert_bit(zone_map, (int) (z - zoff)); /* lint, NOT OK because
980 * z hasn't been broken
981 * up into block +
982 * offset yet. */
983 return(z);
987 void insert_bit(block, bit)
988 block_t block;
989 int bit;
991 /* Insert 'count' bits in the bitmap */
992 int w, s;
993 #if defined(__minix)
994 bitchunk_t *buf;
995 #else
996 uint32_t *buf;
997 #endif
999 #if defined(__minix)
1000 buf = (bitchunk_t *) alloc_block();
1001 #else
1002 buf = (uint32_t *) alloc_block();
1003 #endif
1005 get_block(block, (char *) buf);
1006 #if defined(__minix)
1007 w = bit / (8 * sizeof(bitchunk_t));
1008 s = bit % (8 * sizeof(bitchunk_t));
1009 #else
1010 w = bit / (8 * sizeof(uint32_t));
1011 s = bit % (8 * sizeof(uint32_t));
1012 #endif
1013 buf[w] |= (1 << s);
1014 put_block(block, (char *) buf);
1016 free(buf);
1020 /*================================================================
1021 * proto-file processing assist group
1022 *===============================================================*/
1023 int mode_con(p)
1024 char *p;
1026 /* Convert string to mode */
1027 int o1, o2, o3, mode;
1028 char c1, c2, c3;
1030 c1 = *p++;
1031 c2 = *p++;
1032 c3 = *p++;
1033 o1 = *p++ - '0';
1034 o2 = *p++ - '0';
1035 o3 = *p++ - '0';
1036 mode = (o1 << 6) | (o2 << 3) | o3;
1037 if (c1 == 'd') mode |= S_IFDIR;
1038 if (c1 == 'b') mode |= S_IFBLK;
1039 if (c1 == 'c') mode |= S_IFCHR;
1040 if (c1 == '-') mode |= S_IFREG;
1041 if (c2 == 'u') mode |= S_ISUID;
1042 if (c3 == 'g') mode |= S_ISGID;
1043 return(mode);
1046 void getline(line, parse)
1047 char *parse[MAX_TOKENS];
1048 char line[LINE_LEN];
1050 /* Read a line and break it up in tokens */
1051 int k;
1052 char c, *p;
1053 int d;
1055 for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
1056 for (k = 0; k < LINE_LEN; k++) line[k] = 0;
1057 k = 0;
1058 parse[0] = 0;
1059 p = line;
1060 while (1) {
1061 if (++k > LINE_LEN) pexit("Line too long");
1062 d = fgetc(proto);
1063 if (d == EOF) pexit("Unexpected end-of-file");
1064 *p = d;
1065 if (*p == '\n') lct++;
1066 if (*p == ' ' || *p == '\t') *p = 0;
1067 if (*p == '\n') {
1068 *p++ = 0;
1069 *p = '\n';
1070 break;
1072 p++;
1075 k = 0;
1076 p = line;
1077 lastp = line;
1078 while (1) {
1079 c = *p++;
1080 if (c == '\n') return;
1081 if (c == 0) continue;
1082 parse[k++] = p - 1;
1083 do {
1084 c = *p++;
1085 } while (c != 0 && c != '\n');
1090 /*================================================================
1091 * other stuff
1092 *===============================================================*/
1093 void check_mtab(device)
1094 char *device; /* /dev/hd1 or whatever */
1096 /* Check to see if the special file named in s is mounted. */
1097 #if defined(__minix)
1098 int n, r;
1099 struct stat sb;
1100 char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
1102 r= stat(device, &sb);
1103 if (r == -1)
1105 if (errno == ENOENT)
1106 return; /* Does not exist, and therefore not mounted. */
1107 fprintf(stderr, "%s: stat %s failed: %s\n",
1108 progname, device, strerror(errno));
1109 exit(1);
1111 if (!S_ISBLK(sb.st_mode))
1113 /* Not a block device and therefore not mounted. */
1114 return;
1117 if (load_mtab("mkfs") < 0) return;
1118 while (1) {
1119 n = get_mtab_entry(special, mounted_on, version, rw_flag);
1120 if (n < 0) return;
1121 if (strcmp(device, special) == 0) {
1122 /* Can't mkfs on top of a mounted file system. */
1123 fprintf(stderr, "%s: %s is mounted on %s\n",
1124 progname, device, mounted_on);
1125 exit(1);
1128 #elif defined(__linux__)
1129 /* XXX: this code is copyright Theodore T'so and distributed under the GPLv2. Rewrite.
1131 struct mntent *mnt;
1132 struct stat st_buf;
1133 dev_t file_dev=0, file_rdev=0;
1134 ino_t file_ino=0;
1135 FILE *f;
1136 int fd;
1137 char *mtab_file = "/proc/mounts";
1139 if ((f = setmntent (mtab_file, "r")) == NULL)
1140 goto error;
1142 if (stat(device, &st_buf) == 0) {
1143 if (S_ISBLK(st_buf.st_mode)) {
1144 file_rdev = st_buf.st_rdev;
1145 } else {
1146 file_dev = st_buf.st_dev;
1147 file_ino = st_buf.st_ino;
1151 while ((mnt = getmntent (f)) != NULL) {
1152 if (strcmp(device, mnt->mnt_fsname) == 0)
1153 break;
1154 if (stat(mnt->mnt_fsname, &st_buf) == 0) {
1155 if (S_ISBLK(st_buf.st_mode)) {
1156 if (file_rdev && (file_rdev == st_buf.st_rdev))
1157 break;
1158 } else {
1159 if (file_dev && ((file_dev == st_buf.st_dev) &&
1160 (file_ino == st_buf.st_ino)))
1161 break;
1166 if (mnt == NULL) {
1168 * Do an extra check to see if this is the root device. We
1169 * can't trust /etc/mtab, and /proc/mounts will only list
1170 * /dev/root for the root filesystem. Argh. Instead we
1171 * check if the given device has the same major/minor number
1172 * as the device that the root directory is on.
1174 if (file_rdev && stat("/", &st_buf) == 0) {
1175 if (st_buf.st_dev == file_rdev) {
1176 goto is_root;
1179 goto test_busy;
1181 /* Validate the entry in case /etc/mtab is out of date */
1183 * We need to be paranoid, because some broken distributions
1184 * (read: Slackware) don't initialize /etc/mtab before checking
1185 * all of the non-root filesystems on the disk.
1187 if (stat(mnt->mnt_dir, &st_buf) < 0) {
1188 if (errno == ENOENT) {
1189 goto test_busy;
1191 goto error;
1193 if (file_rdev && (st_buf.st_dev != file_rdev)) {
1194 goto error;
1197 fprintf(stderr, "Device %s is mounted, exiting\n", device);
1198 exit(-1);
1201 * Check to see if we're referring to the root filesystem.
1202 * If so, do a manual check to see if we can open /etc/mtab
1203 * read/write, since if the root is mounted read/only, the
1204 * contents of /etc/mtab may not be accurate.
1206 if (!strcmp(mnt->mnt_dir, "/")) {
1207 is_root:
1208 fprintf(stderr, "Device %s is mounted as root file system!\n",
1209 device);
1210 exit(-1);
1213 test_busy:
1215 endmntent (f);
1216 if ((stat(device, &st_buf) != 0) ||
1217 !S_ISBLK(st_buf.st_mode))
1218 return;
1219 fd = open(device, O_RDONLY | O_EXCL);
1220 if (fd < 0) {
1221 if (errno == EBUSY) {
1222 fprintf(stderr, "Device %s is used by the system\n", device);
1223 exit(-1);
1225 } else
1226 close(fd);
1228 return;
1230 error:
1231 endmntent (f);
1232 fprintf(stderr, "Error while checking if device %s is mounted\n", device);
1233 exit(-1);
1234 #endif
1238 uint32_t file_time(f)
1239 int f;
1241 #ifdef UNIX
1242 struct stat statbuf;
1243 fstat(f, &statbuf);
1244 return(statbuf.st_mtime);
1245 #else /* fstat not supported by DOS */
1246 return(0L);
1247 #endif
1251 void pexit(s)
1252 char *s;
1254 fprintf(stderr, "%s: %s\n", progname, s);
1255 if (lct != 0)
1256 fprintf(stderr, "Line %d being processed when error detected.\n", lct);
1257 flush();
1258 exit(2);
1262 void copy(from, to, count)
1263 char *from, *to;
1264 size_t count;
1266 while (count--) *to++ = *from++;
1269 char *alloc_block()
1271 char *buf;
1273 if(!(buf = malloc(block_size))) {
1274 pexit("couldn't allocate filesystem buffer");
1276 bzero(buf, block_size);
1278 return buf;
1281 void print_fs()
1283 int i, j;
1284 ino_t k;
1285 d1_inode inode1[V1_INODES_PER_BLOCK];
1286 d2_inode *inode2;
1287 unsigned short *usbuf;
1288 block_t b;
1289 struct direct *dir;
1291 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
1292 pexit("couldn't allocate a block of inodes");
1294 if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
1295 pexit("malloc of directory entry failed");
1297 usbuf = (unsigned short *) alloc_block();
1299 get_super_block((char *) usbuf);
1300 printf("\nSuperblock: ");
1301 for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
1302 get_block((block_t) 2, (char *) usbuf);
1303 printf("...\nInode map: ");
1304 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1305 get_block((block_t) 3, (char *) usbuf);
1306 printf("...\nZone map: ");
1307 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1308 printf("...\n");
1310 free(usbuf);
1311 usbuf = NULL;
1313 k = 0;
1314 for (b = inode_offset; k < nrinodes; b++) {
1315 if (fs_version == 1) {
1316 get_block(b, (char *) inode1);
1317 } else {
1318 get_block(b, (char *) inode2);
1320 for (i = 0; i < inodes_per_block; i++) {
1321 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
1322 /* Lint but OK */
1323 if (k > nrinodes) break;
1324 if (fs_version == 1) {
1325 if (inode1[i].d1_mode != 0) {
1326 printf("Inode %2lu: mode=", k);
1327 printf("%06o", inode1[i].d1_mode);
1328 printf(" uid=%2d gid=%2d size=",
1329 inode1[i].d1_uid, inode1[i].d1_gid);
1330 printf("%6d", inode1[i].d1_size);
1331 printf(" zone[0]=%d\n", inode1[i].d1_zone[0]);
1333 if ((inode1[i].d1_mode & S_IFMT) == S_IFDIR) {
1334 /* This is a directory */
1335 get_block(inode1[i].d1_zone[0], (char *) dir);
1336 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1337 if (dir[j].mfs_d_ino)
1338 printf("\tInode %2u: %s\n", dir[j].mfs_d_ino, dir[j].mfs_d_name);
1340 } else {
1341 if (inode2[i].d2_mode != 0) {
1342 printf("Inode %2lu: mode=", k);
1343 printf("%06o", inode2[i].d2_mode);
1344 printf(" uid=%2d gid=%2d size=",
1345 inode2[i].d2_uid, inode2[i].d2_gid);
1346 printf("%6d", inode2[i].d2_size);
1347 printf(" zone[0]=%u\n", inode2[i].d2_zone[0]);
1349 if ((inode2[i].d2_mode & S_IFMT) == S_IFDIR) {
1350 /* This is a directory */
1351 get_block(inode2[i].d2_zone[0], (char *) dir);
1352 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1353 if (dir[j].mfs_d_ino)
1354 printf("\tInode %2u: %s\n", dir[j].mfs_d_ino, dir[j].mfs_d_name);
1360 printf("%d inodes used. %d zones used.\n", next_inode - 1, next_zone);
1361 free(dir);
1362 free(inode2);
1366 int read_and_set(n)
1367 block_t n;
1369 /* The first time a block is read, it returns all 0s, unless there has
1370 * been a write. This routine checks to see if a block has been accessed.
1373 int w, s, mask, r;
1375 w = n / 8;
1376 if(w >= umap_array_elements) {
1377 pexit("umap array too small - this can't happen");
1379 s = n % 8;
1380 mask = 1 << s;
1381 r = (umap_array[w] & mask ? 1 : 0);
1382 umap_array[w] |= mask;
1383 return(r);
1386 void usage()
1388 fprintf(stderr,
1389 "Usage: %s [-12dlot] [-b blocks] [-i inodes] [-B blocksize] special [proto]\n",
1390 progname);
1391 exit(1);
1394 /*================================================================
1395 * get_block & put_block for MS-DOS
1396 *===============================================================*/
1397 #ifdef DOS
1400 * These are the get_block and put_block routines
1401 * when compiling & running mkfs.c under MS-DOS.
1403 * It requires the (asembler) routines absread & abswrite
1404 * from the file diskio.asm. Since these routines just do
1405 * as they are told (read & write the sector specified),
1406 * a local cache is used to minimize the i/o-overhead for
1407 * frequently used blocks.
1409 * The global variable "file" determines whether the output
1410 * is to a disk-device or to a binary file.
1414 #define PH_SECTSIZE 512 /* size of a physical disk-sector */
1417 char *derrtab[14] = {
1418 "no error",
1419 "disk is read-only",
1420 "unknown unit",
1421 "device not ready",
1422 "bad command",
1423 "data error",
1424 "internal error: bad request structure length",
1425 "seek error",
1426 "unknown media type",
1427 "sector not found",
1428 "printer out of paper (?)",
1429 "write fault",
1430 "read error",
1431 "general error"
1434 #define CACHE_SIZE 20 /* 20 block-buffers */
1437 struct cache {
1438 char blockbuf[BLOCK_SIZE];
1439 block_t blocknum;
1440 int dirty;
1441 int usecnt;
1442 } cache[CACHE_SIZE];
1445 void special(string)
1446 char *string;
1449 if (string[1] == ':' && string[2] == 0) {
1450 /* Format: d: or d:fname */
1451 disk = (string[0] & ~32) - 'A';
1452 if (disk > 1 && !override) /* safety precaution */
1453 pexit("Bad drive specifier for special");
1454 } else {
1455 file = 1;
1456 if ((fd = creat(string, BWRITE)) == 0)
1457 pexit("Can't open special file");
1461 void get_block(n, buf)
1462 block_t n;
1463 char *buf;
1465 /* Get a block to the user */
1466 struct cache *bp, *fp;
1468 /* First access returns a zero block */
1469 if (read_and_set(n) == 0) {
1470 copy(zero, buf, block_size);
1471 return;
1474 /* Look for block in cache */
1475 fp = 0;
1476 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1477 if (bp->blocknum == n) {
1478 copy(bp, buf, block_size);
1479 bp->usecnt++;
1480 return;
1483 /* Remember clean block */
1484 if (bp->dirty == 0)
1485 if (fp) {
1486 if (fp->usecnt > bp->usecnt) fp = bp;
1487 } else
1488 fp = bp;
1491 /* Block not in cache, get it */
1492 if (!fp) {
1493 /* No clean buf, flush one */
1494 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1495 if (fp->usecnt > bp->usecnt) fp = bp;
1496 mx_write(fp->blocknum, fp);
1498 mx_read(n, fp);
1499 fp->dirty = 0;
1500 fp->usecnt = 0;
1501 fp->blocknum = n;
1502 copy(fp, buf, block_size);
1505 void put_block(n, buf)
1506 block_t n;
1507 char *buf;
1509 /* Accept block from user */
1510 struct cache *fp, *bp;
1512 (void) read_and_set(n);
1514 /* Look for block in cache */
1515 fp = 0;
1516 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1517 if (bp->blocknum == n) {
1518 copy(buf, bp, block_size);
1519 bp->dirty = 1;
1520 return;
1523 /* Remember clean block */
1524 if (bp->dirty == 0)
1525 if (fp) {
1526 if (fp->usecnt > bp->usecnt) fp = bp;
1527 } else
1528 fp = bp;
1531 /* Block not in cache */
1532 if (!fp) {
1533 /* No clean buf, flush one */
1534 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1535 if (fp->usecnt > bp->usecnt) fp = bp;
1536 mx_write(fp->blocknum, fp);
1538 fp->dirty = 1;
1539 fp->usecnt = 1;
1540 fp->blocknum = n;
1541 copy(buf, fp, block_size);
1544 void cache_init()
1546 struct cache *bp;
1547 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
1550 void flush()
1552 /* Flush all dirty blocks to disk */
1553 struct cache *bp;
1555 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
1556 if (bp->dirty) {
1557 mx_write(bp->blocknum, bp);
1558 bp->dirty = 0;
1562 /*==================================================================
1563 * hard read & write etc.
1564 *=================================================================*/
1565 #define MAX_RETRIES 5
1568 void mx_read(blocknr, buf)
1569 int blocknr;
1570 char *buf;
1573 /* Read the requested MINIX-block in core */
1574 char (*bp)[PH_SECTSIZE];
1575 int sectnum, retries, err;
1577 if (file) {
1578 lseek(fd, (off_t) blocknr * block_size, 0);
1579 if (read(fd, buf, block_size) != block_size)
1580 pexit("mx_read: error reading file");
1581 } else {
1582 sectnum = blocknr * (block_size / PH_SECTSIZE);
1583 for (bp = buf; bp < &buf[block_size]; bp++) {
1584 retries = MAX_RETRIES;
1586 err = absread(disk, sectnum, bp);
1587 while (err && --retries);
1589 if (retries) {
1590 sectnum++;
1591 } else {
1592 dexit("mx_read", sectnum, err);
1598 void mx_write(blocknr, buf)
1599 int blocknr;
1600 char *buf;
1602 /* Write the MINIX-block to disk */
1603 char (*bp)[PH_SECTSIZE];
1604 int retries, sectnum, err;
1606 if (file) {
1607 lseek(fd, blocknr * block_size, 0);
1608 if (write(fd, buf, block_size) != block_size) {
1609 pexit("mx_write: error writing file");
1611 } else {
1612 sectnum = blocknr * (block_size / PH_SECTSIZE);
1613 for (bp = buf; bp < &buf[block_size]; bp++) {
1614 retries = MAX_RETRIES;
1615 do {
1616 err = abswrite(disk, sectnum, bp);
1617 } while (err && --retries);
1619 if (retries) {
1620 sectnum++;
1621 } else {
1622 dexit("mx_write", sectnum, err);
1629 void dexit(s, sectnum, err)
1630 int sectnum, err;
1631 char *s;
1633 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1634 s, sectnum, err, derrtab[err]);
1635 exit(2);
1638 #endif
1640 /*================================================================
1641 * get_block & put_block for UNIX
1642 *===============================================================*/
1643 #ifdef UNIX
1645 void special(string)
1646 char *string;
1648 fd = creat(string, 0777);
1649 close(fd);
1650 fd = open(string, O_RDWR);
1651 if (fd < 0) pexit("Can't open special file");
1656 void get_block(n, buf)
1657 block_t n;
1658 char *buf;
1660 /* Read a block. */
1662 int k;
1664 /* First access returns a zero block */
1665 if (read_and_set(n) == 0) {
1666 copy(zero, buf, block_size);
1667 return;
1669 lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL);
1670 k = read(fd, buf, block_size);
1671 if (k != block_size) {
1672 pexit("get_block couldn't read");
1676 void get_super_block(buf)
1677 char *buf;
1679 /* Read a block. */
1681 int k;
1683 if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
1684 perror("lseek");
1685 pexit("seek failed");
1687 k = read(fd, buf, _STATIC_BLOCK_SIZE);
1688 if (k != _STATIC_BLOCK_SIZE) {
1689 pexit("get_super_block couldn't read");
1693 void put_block(n, buf)
1694 block_t n;
1695 char *buf;
1697 /* Write a block. */
1699 (void) read_and_set(n);
1701 /* XXX - check other lseeks too. */
1702 if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1) {
1703 pexit("put_block couldn't seek");
1705 if (write(fd, buf, block_size) != block_size) {
1706 pexit("put_block couldn't write");
1711 /* Dummy routines to keep source file clean from #ifdefs */
1713 void flush()
1715 return;
1718 void cache_init()
1720 return;
1723 #endif