mkfs: drop support for creating non-v3 FSes
[minix.git] / usr.sbin / mkfs.mfs / mkfs.c
blobb06f273edd07bfa15151881ec29b19b7a1e2f6b5
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 size_t block_size;
94 int extra_space_percent;
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 ino_t inocount;
138 zone_t zonecount;
139 block_t blockcount;
141 void detect_fs_size(void);
142 void sizeup_dir(void);
143 void detect_size(void);
144 void size_dir(void);
145 static int bitmapsize(uint32_t nr_bits, size_t block_size);
147 /*================================================================
148 * mkfs - make filesystem
149 *===============================================================*/
150 int main(argc, argv)
151 int argc;
152 char *argv[];
154 int nread, mode, usrid, grpid, ch;
155 block_t blocks, maxblocks;
156 size_t i;
157 ino_t root_inum;
158 ino_t inodes;
159 zone_t zones;
160 char *token[MAX_TOKENS], line[LINE_LEN];
161 struct stat statbuf;
163 /* Get two times, the current time and the mod time of the binary of
164 * mkfs itself. When the -d flag is used, the later time is put into
165 * the i_mtimes of all the files. This feature is useful when
166 * producing a set of file systems, and one wants all the times to be
167 * identical. First you set the time of the mkfs binary to what you
168 * want, then go.
170 current_time = time((time_t *) 0); /* time mkfs is being run */
171 stat(argv[0], &statbuf);
172 bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */
174 /* Process switches. */
175 progname = argv[0];
176 blocks = 0;
177 i = 0;
178 inodes_per_block = 0;
179 block_size = 0;
180 extra_space_percent = 0;
181 while ((ch = getopt(argc, argv, "b:di:lotB:x:")) != EOF)
182 switch (ch) {
183 case 'b':
184 blocks = strtoul(optarg, (char **) NULL, 0);
185 break;
186 case 'd':
187 dflag = 1;
188 current_time = bin_time;
189 break;
190 case 'i':
191 i = strtoul(optarg, (char **) NULL, 0);
192 break;
193 case 'l': print = 1; break;
194 case 'o': override = 1; break;
195 case 't': donttest = 1; break;
196 case 'B': block_size = atoi(optarg); break;
197 case 'x': extra_space_percent = atoi(optarg); break;
198 default: usage();
201 if (argc == optind) usage();
203 /* Percentage of extra size must be nonnegative.
204 * It can legitimately be bigger than 100 but has to make some sort of sense.
206 if(extra_space_percent < 0 || extra_space_percent > 2000) usage();
209 if(!block_size) block_size = _MAX_BLOCK_SIZE; /* V3 default block size */
210 if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
211 fprintf(stderr, "block size must be multiple of sector (%d) "
212 "and at least %d bytes\n",
213 SECTOR_SIZE, _MIN_BLOCK_SIZE);
214 pexit("specified block size illegal");
216 if(block_size%V2_INODE_SIZE) {
217 fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
218 V2_INODE_SIZE);
219 pexit("specified block size illegal");
223 zone_shift = 0; /* for future use */
224 zone_size = 1 << zone_shift; /* nr of blocks per zone */
226 if(!inodes_per_block)
227 inodes_per_block = V2_INODES_PER_BLOCK(block_size);
229 /* now that the block size is known, do buffer allocations where
230 * possible.
232 zero = alloc_block();
233 bzero(zero, block_size);
235 /* Determine the size of the device if not specified as -b or proto. */
236 maxblocks = sizeup(argv[optind]);
237 if (argc - optind == 1 && blocks == 0) {
238 blocks = maxblocks;
239 /* blocks == 0 is checked later, but leads to a funny way of
240 * reporting a 0-sized device (displays usage).
242 if(blocks < 1) {
243 fprintf(stderr, "%s: zero size device.\n", progname);
244 return 1;
248 /* The remaining args must be 'special proto', or just 'special' if the
249 * no. of blocks has already been specified.
251 if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
253 if (blocks > maxblocks) {
254 fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
255 progname, argv[optind]);
256 return 1;
259 /* Check special. */
260 check_mtab(argv[optind]);
262 /* Check and start processing proto. */
263 optarg = argv[++optind];
264 if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
265 /* Prototype file is readable. */
266 lct = 1;
267 getline(line, token); /* skip boot block info */
269 /* Read the line with the block and inode counts. */
270 getline(line, token);
271 blocks = atol(token[0]);
272 inodes = atoi(token[1]);
274 /* Process mode line for root directory. */
275 getline(line, token);
276 mode = mode_con(token[0]);
277 usrid = atoi(token[1]);
278 grpid = atoi(token[2]);
280 if(blocks <= 0 && inodes <= 0){
281 block_t extrablocks = 0;
282 ino_t extrainodes = 0;
283 if(blocks < 0) extrablocks = -blocks;
284 if(inodes < 0) extrainodes = -inodes;
285 detect_fs_size();
286 blocks = blockcount + extrablocks;
287 inodes = inocount + extrainodes;
288 blocks += blocks*extra_space_percent/100;
289 inodes += inodes*extra_space_percent/100;
290 printf("dynamically sized filesystem: %d blocks, %d inodes\n", blocks,
291 (unsigned int) inodes);
293 } else {
294 lct = 0;
295 if (optind < argc) {
296 /* Maybe the prototype file is just a size. Check. */
297 blocks = strtoul(optarg, (char **) NULL, 0);
298 if (blocks == 0) pexit("Can't open prototype file");
300 if (i == 0) {
301 #if defined(__minix)
302 uint32_t kb = div64u(mul64u(blocks, block_size), 1024);
303 #else
304 uint32_t kb = ((unsigned long long) blocks * block_size) / 1024;
305 #endif
306 i = kb / 2;
307 if (kb >= 100000) i = kb / 4;
309 /* round up to fill inode block */
310 i += inodes_per_block - 1;
311 i = i / inodes_per_block * inodes_per_block;
313 if (blocks < 5) pexit("Block count too small");
314 if (i < 1) pexit("Inode count too small");
315 inodes = (ino_t) i;
317 /* Make simple file system of the given size, using defaults. */
318 mode = 040777;
319 usrid = BIN;
320 grpid = BINGRP;
321 simple = 1;
324 nrblocks = blocks;
325 nrinodes = inodes;
328 size_t bytes;
329 bytes = 1 + blocks/8;
330 if(!(umap_array = malloc(bytes))) {
331 fprintf(stderr, "mkfs: can't allocate block bitmap (%u bytes).\n",
332 bytes);
333 exit(1);
335 umap_array_elements = bytes;
338 /* Open special. */
339 special(argv[--optind]);
341 #ifdef UNIX
342 if (!donttest) {
343 short *testb;
344 ssize_t w;
346 testb = (short *) alloc_block();
348 /* Try writing the last block of partition or diskette. */
349 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
350 pexit("couldn't seek to last block to test size (1)");
352 testb[0] = 0x3245;
353 testb[1] = 0x11FF;
354 testb[block_size/2-1] = 0x1F2F;
355 if ((w=write(fd, (char *) testb, block_size)) != block_size) {
356 if(w < 0) perror("write");
357 printf("%d/%u\n", w, block_size);
358 pexit("File system is too big for minor device (write)");
360 sync(); /* flush write, so if error next read fails */
361 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
362 pexit("couldn't seek to last block to test size (2)");
364 testb[0] = 0;
365 testb[1] = 0;
366 nread = read(fd, (char *) testb, block_size);
367 if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
368 testb[block_size/2-1] != 0x1F2F) {
369 if(nread < 0) perror("read");
370 printf("nread = %d\n", nread);
371 printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]);
372 pexit("File system is too big for minor device (read)");
374 lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL);
375 testb[0] = 0;
376 testb[1] = 0;
377 if (write(fd, (char *) testb, block_size) != block_size)
378 pexit("File system is too big for minor device (write2)");
379 lseek(fd, 0L, SEEK_SET);
380 free(testb);
382 #endif
384 /* Make the file-system */
386 cache_init();
388 put_block((block_t) 0, zero); /* Write a null boot block. */
390 zones = nrblocks >> zone_shift;
392 super(zones, inodes);
394 root_inum = alloc_inode(mode, usrid, grpid);
395 rootdir(root_inum);
396 if (simple == 0) eat_dir(root_inum);
398 if (print) print_fs();
399 flush();
400 return(0);
402 /* NOTREACHED */
403 } /* end main */
405 /*================================================================
406 * detect_fs_size - determine image size dynamically
407 *===============================================================*/
408 void detect_fs_size()
410 uint32_t point = ftell(proto);
412 inocount = 1; /* root directory node */
413 zonecount = 0;
414 blockcount = 0;
415 sizeup_dir();
417 uint32_t initb;
419 initb = bitmapsize((uint32_t) (1 + inocount), block_size);
420 initb += bitmapsize((uint32_t) zonecount, block_size);
421 initb += START_BLOCK;
422 initb += (inocount + inodes_per_block - 1) / inodes_per_block;
423 initb = (initb + (1 << zone_shift) - 1) >> zone_shift;
425 blockcount = initb+zonecount*zone_size;
426 fseek(proto, point, SEEK_SET);
429 void sizeup_dir()
431 char *token[MAX_TOKENS], *p;
432 char line[LINE_LEN];
433 FILE *f;
434 size_t size;
435 int dir_entries = 2;
436 zone_t dir_zones = 0;
437 zone_t nr_dzones;
439 nr_dzones = V2_NR_DZONES;
441 while (1) {
442 getline(line, token);
443 p = token[0];
444 if (*p == '$') {
445 dir_zones = (dir_entries / (NR_DIR_ENTRIES(block_size) * zone_size));
446 if(dir_entries % (NR_DIR_ENTRIES(block_size) * zone_size))
447 dir_zones++;
448 /* Assumes directory fits in direct blocks */
449 zonecount += dir_zones;
450 return;
453 p = token[1];
454 inocount++;
455 dir_entries++;
457 if (*p == 'd') {
458 sizeup_dir();
459 } else if (*p == 'b' || *p == 'c') {
461 } else if (*p == 's') {
462 zonecount++; /* Symlink contents is always stored a block */
463 } else {
464 if ((f = fopen(token[4], "r")) == NULL) {
465 fprintf(stderr, "%s: Can't open %s: %s\n",
466 progname, token[4], strerror(errno));
467 pexit("dynamic size detection failed");
468 } else {
469 if (fseek(f, 0, SEEK_END) < 0) {
470 fprintf(stderr, "%s: Can't seek to end of %s\n",
471 progname, token[4]);
472 pexit("dynamic size detection failed");
474 size = ftell(f);
475 fclose(f);
476 zone_t fzones= (size / (zone_size * block_size));
477 if (size % (zone_size * block_size))
478 fzones++;
479 if (fzones > nr_dzones)
480 fzones++; /* Assumes files fit within single indirect */
481 zonecount += fzones;
487 /*================================================================
488 * sizeup - determine device size
489 *===============================================================*/
490 block_t sizeup(device)
491 char *device;
493 block_t d;
494 #if defined(__minix)
495 u64_t bytes, resize;
496 u32_t rem;
497 #else
498 off_t size;
499 #endif
502 if ((fd = open(device, O_RDONLY)) == -1) {
503 if (errno != ENOENT)
504 perror("sizeup open");
505 return 0;
508 #if defined(__minix)
509 if(minix_sizeup(device, &bytes) < 0) {
510 perror("sizeup");
511 return 0;
514 d = div64u(bytes, block_size);
515 rem = rem64u(bytes, block_size);
517 resize = add64u(mul64u(d, block_size), rem);
518 if(cmp64(resize, bytes) != 0) {
519 d = ULONG_MAX;
520 fprintf(stderr, "mkfs: truncating FS at %u blocks\n", d);
522 #else
523 size = lseek(fd, 0, SEEK_END);
524 if (size == (off_t) -1) {
525 fprintf(stderr, "Cannot get device size fd=%d\n", fd);
526 exit(-1);
528 d = size / block_size;
529 #endif
531 return d;
535 * copied from fslib
537 static int bitmapsize(nr_bits, block_size)
538 uint32_t nr_bits;
539 size_t block_size;
541 block_t nr_blocks;
543 nr_blocks = (int) (nr_bits / FS_BITS_PER_BLOCK(block_size));
544 if (((uint32_t) nr_blocks * FS_BITS_PER_BLOCK(block_size)) < nr_bits) ++nr_blocks;
545 return(nr_blocks);
548 /*================================================================
549 * super - construct a superblock
550 *===============================================================*/
552 void super(zones, inodes)
553 zone_t zones;
554 ino_t inodes;
556 unsigned int i;
557 int inodeblks;
558 int initblks;
559 uint32_t nb;
560 zone_t v2sq;
561 zone_t zo;
562 struct super_block *sup;
563 char *buf, *cp;
565 buf = alloc_block();
567 for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
568 sup = (struct super_block *) buf; /* lint - might use a union */
570 /* The assumption is that mkfs will create a clean FS. */
571 sup->s_flags = MFSFLAG_CLEAN;
573 sup->s_ninodes = inodes;
574 sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */
575 sup->s_zones = zones;
577 #define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
578 sup->s_imap_blocks = nb = bitmapsize((uint32_t) (1 + inodes), block_size);
579 if(sup->s_imap_blocks != nb) {
580 fprintf(stderr, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS);
581 exit(1);
583 sup->s_zmap_blocks = nb = bitmapsize((uint32_t) zones, block_size);
584 if(nb != sup->s_zmap_blocks) {
585 fprintf(stderr, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS);
586 exit(1);
588 inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks;
589 inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
590 initblks = inode_offset + inodeblks;
591 sup->s_firstdatazone_old = nb =
592 (initblks + (1 << zone_shift) - 1) >> zone_shift;
593 if(nb >= zones) pexit("bit maps too large");
594 if(nb != sup->s_firstdatazone_old) {
595 /* The field is too small to store the value. Fortunately, the value
596 * can be computed from other fields. We set the on-disk field to zero
597 * to indicate that it must not be used. Eventually, we can always set
598 * the on-disk field to zero, and stop using it.
600 sup->s_firstdatazone_old = 0;
602 sup->s_firstdatazone = nb;
603 zoff = sup->s_firstdatazone - 1;
604 sup->s_log_zone_size = zone_shift;
606 v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
607 zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
609 sup->s_magic = SUPER_V3;
610 sup->s_block_size = block_size;
611 sup->s_disk_version = 0;
612 #define MAX_MAX_SIZE (INT_MAX)
613 if(MAX_MAX_SIZE/block_size < zo) {
614 sup->s_max_size = (int32_t) MAX_MAX_SIZE;
616 else {
617 sup->s_max_size = zo * block_size;
622 if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
623 pexit("super() couldn't seek");
625 if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
626 pexit("super() couldn't write");
629 /* Clear maps and inodes. */
630 for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero);
632 next_zone = sup->s_firstdatazone;
633 next_inode = 1;
635 zone_map = INODE_MAP + sup->s_imap_blocks;
637 insert_bit(zone_map, 0); /* bit zero must always be allocated */
638 insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but
639 * must be allocated */
641 free(buf);
645 /*================================================================
646 * rootdir - install the root directory
647 *===============================================================*/
648 void rootdir(inode)
649 ino_t inode;
651 zone_t z;
653 z = alloc_zone();
654 add_zone(inode, z, 2 * sizeof(struct direct), current_time);
655 enter_dir(inode, ".", inode);
656 enter_dir(inode, "..", inode);
657 incr_link(inode);
658 incr_link(inode);
661 void enter_symlink(ino_t inode, char *link)
663 zone_t z;
664 char *buf;
666 buf = alloc_block();
667 z = alloc_zone();
668 strcpy(buf, link);
669 put_block((z << zone_shift), buf);
671 add_zone(inode, z, (size_t) strlen(link), current_time);
673 free(buf);
677 /*================================================================
678 * eat_dir - recursively install directory
679 *===============================================================*/
680 void eat_dir(parent)
681 ino_t parent;
683 /* Read prototype lines and set up directory. Recurse if need be. */
684 char *token[MAX_TOKENS], *p;
685 char line[LINE_LEN];
686 int mode, usrid, grpid, maj, min, f;
687 ino_t n;
688 zone_t z;
689 size_t size;
691 while (1) {
692 getline(line, token);
693 p = token[0];
694 if (*p == '$') return;
695 p = token[1];
696 mode = mode_con(p);
697 usrid = atoi(token[2]);
698 grpid = atoi(token[3]);
699 n = alloc_inode(mode, usrid, grpid);
701 /* Enter name in directory and update directory's size. */
702 enter_dir(parent, token[0], n);
703 incr_size(parent, sizeof(struct direct));
705 /* Check to see if file is directory or special. */
706 incr_link(n);
707 if (*p == 'd') {
708 /* This is a directory. */
709 z = alloc_zone(); /* zone for new directory */
710 add_zone(n, z, 2 * sizeof(struct direct), current_time);
711 enter_dir(n, ".", n);
712 enter_dir(n, "..", parent);
713 incr_link(parent);
714 incr_link(n);
715 eat_dir(n);
716 } else if (*p == 'b' || *p == 'c') {
717 /* Special file. */
718 maj = atoi(token[4]);
719 min = atoi(token[5]);
720 size = 0;
721 if (token[6]) size = atoi(token[6]);
722 size = block_size * size;
723 add_zone(n, (zone_t) (makedev(maj,min)), size, current_time);
724 } else if (*p == 's') {
725 enter_symlink(n, token[4]);
726 } else {
727 /* Regular file. Go read it. */
728 if ((f = open(token[4], O_RDONLY)) < 0) {
729 fprintf(stderr, "%s: Can't open %s: %s\n",
730 progname, token[4], strerror(errno));
731 } else {
732 eat_file(n, f);
739 /*================================================================
740 * eat_file - copy file to MINIX
741 *===============================================================*/
742 /* Zonesize >= blocksize */
743 void eat_file(inode, f)
744 ino_t inode;
745 int f;
747 int ct, i, j, k;
748 zone_t z;
749 char *buf;
750 uint32_t timeval;
752 buf = alloc_block();
754 do {
755 for (i = 0, j = 0; i < zone_size; i++, j += ct) {
756 for (k = 0; k < block_size; k++) buf[k] = 0;
757 if ((ct = read(f, buf, block_size)) > 0) {
758 if (i == 0) z = alloc_zone();
759 put_block((z << zone_shift) + i, buf);
762 timeval = (dflag ? current_time : file_time(f));
763 if (ct) add_zone(inode, z, (size_t) j, timeval);
764 } while (ct == block_size);
765 close(f);
766 free(buf);
769 /*================================================================
770 * directory & inode management assist group
771 *===============================================================*/
772 void enter_dir(parent, name, child)
773 ino_t parent, child;
774 char *name;
776 /* Enter child in parent directory */
777 /* Works for dir > 1 block and zone > block */
778 unsigned int i, j, k, l, off;
779 block_t b;
780 zone_t z;
781 char *p1, *p2;
782 struct direct *dir_entry;
783 d2_inode *ino2;
784 int nr_dzones;
786 b = ((parent - 1) / inodes_per_block) + inode_offset;
787 off = (parent - 1) % inodes_per_block;
789 if(!(dir_entry = malloc(NR_DIR_ENTRIES(block_size) * sizeof(*dir_entry))))
790 pexit("couldn't allocate directory entry");
792 if(!(ino2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*ino2))))
793 pexit("couldn't allocate block of inodes entry");
795 get_block(b, (char *) ino2);
796 nr_dzones = V2_NR_DZONES;
797 for (k = 0; k < nr_dzones; k++) {
798 z = ino2[off].d2_zone[k];
799 if (z == 0) {
800 z = alloc_zone();
801 ino2[off].d2_zone[k] = z;
804 for (l = 0; l < zone_size; l++) {
805 get_block((z << zone_shift) + l, (char *) dir_entry);
806 for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) {
807 if (dir_entry[i].mfs_d_ino == 0) {
808 dir_entry[i].mfs_d_ino = child;
809 p1 = name;
810 p2 = dir_entry[i].mfs_d_name;
811 j = sizeof(dir_entry[i].mfs_d_name);
812 j = 60;
813 while (j--) {
814 *p2++ = *p1;
815 if (*p1 != 0) p1++;
817 put_block((z << zone_shift) + l, (char *) dir_entry);
818 put_block(b, (char *) ino2);
819 free(dir_entry);
820 free(ino2);
821 return;
827 printf("Directory-inode %lu beyond direct blocks. Could not enter %s\n",
828 parent, name);
829 pexit("Halt");
833 void add_zone(ino_t n, zone_t z, size_t bytes, uint32_t cur_time)
835 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
837 int off, i;
838 block_t b;
839 zone_t indir;
840 zone_t *blk;
841 d2_inode *p;
842 d2_inode *inode;
844 if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
845 pexit("Couldn't allocate indirect block");
847 if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
848 pexit("Couldn't allocate block of inodes");
850 b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
851 off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
852 get_block(b, (char *) inode);
853 p = &inode[off];
854 p->d2_size += bytes;
855 p->d2_mtime = cur_time;
856 for (i = 0; i < V2_NR_DZONES; i++)
857 if (p->d2_zone[i] == 0) {
858 p->d2_zone[i] = z;
859 put_block(b, (char *) inode);
860 free(blk);
861 free(inode);
862 return;
864 put_block(b, (char *) inode);
866 /* File has grown beyond a small file. */
867 if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
868 indir = p->d2_zone[V2_NR_DZONES];
869 put_block(b, (char *) inode);
870 b = indir << zone_shift;
871 get_block(b, (char *) blk);
872 for (i = 0; i < V2_INDIRECTS(block_size); i++)
873 if (blk[i] == 0) {
874 blk[i] = z;
875 put_block(b, (char *) blk);
876 free(blk);
877 free(inode);
878 return;
880 pexit("File has grown beyond single indirect");
884 void incr_link(n)
885 ino_t n;
887 /* Increment the link count to inode n */
888 int off;
889 static int enter = 0;
890 block_t b;
892 if(enter) exit(1);
894 b = ((n - 1) / inodes_per_block) + inode_offset;
895 off = (n - 1) % inodes_per_block;
897 static d2_inode *inode2 = NULL;
898 int n;
900 n = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
901 if(!inode2 && !(inode2 = malloc(n)))
902 pexit("couldn't allocate a block of inodes");
904 get_block(b, (char *) inode2);
905 inode2[off].d2_nlinks++;
906 put_block(b, (char *) inode2);
908 enter = 0;
912 void incr_size(n, count)
913 ino_t n;
914 size_t count;
916 /* Increment the file-size in inode n */
917 block_t b;
918 int off;
920 b = ((n - 1) / inodes_per_block) + inode_offset;
921 off = (n - 1) % inodes_per_block;
923 d2_inode *inode2;
924 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
925 pexit("couldn't allocate a block of inodes");
927 get_block(b, (char *) inode2);
928 inode2[off].d2_size += count;
929 put_block(b, (char *) inode2);
930 free(inode2);
935 /*================================================================
936 * allocation assist group
937 *===============================================================*/
938 static ino_t alloc_inode(mode, usrid, grpid)
939 int mode, usrid, grpid;
941 ino_t num;
942 int off;
943 block_t b;
945 num = next_inode++;
946 if (num > nrinodes) {
947 fprintf(stderr, "have %d inodoes\n", nrinodes);
948 pexit("File system does not have enough inodes");
950 b = ((num - 1) / inodes_per_block) + inode_offset;
951 off = (num - 1) % inodes_per_block;
953 d2_inode *inode2;
955 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
956 pexit("couldn't allocate a block of inodes");
958 get_block(b, (char *) inode2);
959 inode2[off].d2_mode = mode;
960 inode2[off].d2_uid = usrid;
961 inode2[off].d2_gid = grpid;
962 put_block(b, (char *) inode2);
964 free(inode2);
967 /* Set the bit in the bit map. */
968 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
969 insert_bit((block_t) INODE_MAP, (int) num);
970 return(num);
974 static zone_t alloc_zone()
976 /* Allocate a new zone */
977 /* Works for zone > block */
978 block_t b;
979 int i;
980 zone_t z;
982 z = next_zone++;
983 b = z << zone_shift;
984 if ((b + zone_size) > nrblocks)
985 pexit("File system not big enough for all the files");
986 for (i = 0; i < zone_size; i++)
987 put_block(b + i, zero); /* give an empty zone */
988 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
989 insert_bit(zone_map, (int) (z - zoff)); /* lint, NOT OK because
990 * z hasn't been broken
991 * up into block +
992 * offset yet. */
993 return(z);
997 void insert_bit(block, bit)
998 block_t block;
999 int bit;
1001 /* Insert 'count' bits in the bitmap */
1002 int w, s;
1003 #if defined(__minix)
1004 bitchunk_t *buf;
1005 #else
1006 uint32_t *buf;
1007 #endif
1009 #if defined(__minix)
1010 buf = (bitchunk_t *) alloc_block();
1011 #else
1012 buf = (uint32_t *) alloc_block();
1013 #endif
1015 get_block(block, (char *) buf);
1016 #if defined(__minix)
1017 w = bit / (8 * sizeof(bitchunk_t));
1018 s = bit % (8 * sizeof(bitchunk_t));
1019 #else
1020 w = bit / (8 * sizeof(uint32_t));
1021 s = bit % (8 * sizeof(uint32_t));
1022 #endif
1023 buf[w] |= (1 << s);
1024 put_block(block, (char *) buf);
1026 free(buf);
1030 /*================================================================
1031 * proto-file processing assist group
1032 *===============================================================*/
1033 int mode_con(p)
1034 char *p;
1036 /* Convert string to mode */
1037 int o1, o2, o3, mode;
1038 char c1, c2, c3;
1040 c1 = *p++;
1041 c2 = *p++;
1042 c3 = *p++;
1043 o1 = *p++ - '0';
1044 o2 = *p++ - '0';
1045 o3 = *p++ - '0';
1046 mode = (o1 << 6) | (o2 << 3) | o3;
1047 if (c1 == 'd') mode |= S_IFDIR;
1048 if (c1 == 'b') mode |= S_IFBLK;
1049 if (c1 == 'c') mode |= S_IFCHR;
1050 if (c1 == 's') mode |= S_IFLNK;
1051 if (c1 == '-') mode |= S_IFREG;
1052 if (c2 == 'u') mode |= S_ISUID;
1053 if (c3 == 'g') mode |= S_ISGID;
1054 return(mode);
1057 void getline(line, parse)
1058 char *parse[MAX_TOKENS];
1059 char line[LINE_LEN];
1061 /* Read a line and break it up in tokens */
1062 int k;
1063 char c, *p;
1064 int d;
1066 for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
1067 for (k = 0; k < LINE_LEN; k++) line[k] = 0;
1068 k = 0;
1069 parse[0] = 0;
1070 p = line;
1071 while (1) {
1072 if (++k > LINE_LEN) pexit("Line too long");
1073 d = fgetc(proto);
1074 if (d == EOF) pexit("Unexpected end-of-file");
1075 *p = d;
1076 if (*p == '\n') lct++;
1077 if (*p == ' ' || *p == '\t') *p = 0;
1078 if (*p == '\n') {
1079 *p++ = 0;
1080 *p = '\n';
1081 break;
1083 p++;
1086 k = 0;
1087 p = line;
1088 lastp = line;
1089 while (1) {
1090 c = *p++;
1091 if (c == '\n') return;
1092 if (c == 0) continue;
1093 parse[k++] = p - 1;
1094 do {
1095 c = *p++;
1096 } while (c != 0 && c != '\n');
1101 /*================================================================
1102 * other stuff
1103 *===============================================================*/
1104 void check_mtab(device)
1105 char *device; /* /dev/hd1 or whatever */
1107 /* Check to see if the special file named in s is mounted. */
1108 #if defined(__minix)
1109 int n, r;
1110 struct stat sb;
1111 char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
1113 r= stat(device, &sb);
1114 if (r == -1)
1116 if (errno == ENOENT)
1117 return; /* Does not exist, and therefore not mounted. */
1118 fprintf(stderr, "%s: stat %s failed: %s\n",
1119 progname, device, strerror(errno));
1120 exit(1);
1122 if (!S_ISBLK(sb.st_mode))
1124 /* Not a block device and therefore not mounted. */
1125 return;
1128 if (load_mtab("mkfs") < 0) return;
1129 while (1) {
1130 n = get_mtab_entry(special, mounted_on, version, rw_flag);
1131 if (n < 0) return;
1132 if (strcmp(device, special) == 0) {
1133 /* Can't mkfs on top of a mounted file system. */
1134 fprintf(stderr, "%s: %s is mounted on %s\n",
1135 progname, device, mounted_on);
1136 exit(1);
1139 #elif defined(__linux__)
1140 /* XXX: this code is copyright Theodore T'so and distributed under the GPLv2. Rewrite.
1142 struct mntent *mnt;
1143 struct stat st_buf;
1144 dev_t file_dev=0, file_rdev=0;
1145 ino_t file_ino=0;
1146 FILE *f;
1147 int fd;
1148 char *mtab_file = "/proc/mounts";
1150 if ((f = setmntent (mtab_file, "r")) == NULL)
1151 goto error;
1153 if (stat(device, &st_buf) == 0) {
1154 if (S_ISBLK(st_buf.st_mode)) {
1155 file_rdev = st_buf.st_rdev;
1156 } else {
1157 file_dev = st_buf.st_dev;
1158 file_ino = st_buf.st_ino;
1162 while ((mnt = getmntent (f)) != NULL) {
1163 if (strcmp(device, mnt->mnt_fsname) == 0)
1164 break;
1165 if (stat(mnt->mnt_fsname, &st_buf) == 0) {
1166 if (S_ISBLK(st_buf.st_mode)) {
1167 if (file_rdev && (file_rdev == st_buf.st_rdev))
1168 break;
1169 } else {
1170 if (file_dev && ((file_dev == st_buf.st_dev) &&
1171 (file_ino == st_buf.st_ino)))
1172 break;
1177 if (mnt == NULL) {
1179 * Do an extra check to see if this is the root device. We
1180 * can't trust /etc/mtab, and /proc/mounts will only list
1181 * /dev/root for the root filesystem. Argh. Instead we
1182 * check if the given device has the same major/minor number
1183 * as the device that the root directory is on.
1185 if (file_rdev && stat("/", &st_buf) == 0) {
1186 if (st_buf.st_dev == file_rdev) {
1187 goto is_root;
1190 goto test_busy;
1192 /* Validate the entry in case /etc/mtab is out of date */
1194 * We need to be paranoid, because some broken distributions
1195 * (read: Slackware) don't initialize /etc/mtab before checking
1196 * all of the non-root filesystems on the disk.
1198 if (stat(mnt->mnt_dir, &st_buf) < 0) {
1199 if (errno == ENOENT) {
1200 goto test_busy;
1202 goto error;
1204 if (file_rdev && (st_buf.st_dev != file_rdev)) {
1205 goto error;
1208 fprintf(stderr, "Device %s is mounted, exiting\n", device);
1209 exit(-1);
1212 * Check to see if we're referring to the root filesystem.
1213 * If so, do a manual check to see if we can open /etc/mtab
1214 * read/write, since if the root is mounted read/only, the
1215 * contents of /etc/mtab may not be accurate.
1217 if (!strcmp(mnt->mnt_dir, "/")) {
1218 is_root:
1219 fprintf(stderr, "Device %s is mounted as root file system!\n",
1220 device);
1221 exit(-1);
1224 test_busy:
1226 endmntent (f);
1227 if ((stat(device, &st_buf) != 0) ||
1228 !S_ISBLK(st_buf.st_mode))
1229 return;
1230 fd = open(device, O_RDONLY | O_EXCL);
1231 if (fd < 0) {
1232 if (errno == EBUSY) {
1233 fprintf(stderr, "Device %s is used by the system\n", device);
1234 exit(-1);
1236 } else
1237 close(fd);
1239 return;
1241 error:
1242 endmntent (f);
1243 fprintf(stderr, "Error while checking if device %s is mounted\n", device);
1244 exit(-1);
1245 #endif
1249 uint32_t file_time(f)
1250 int f;
1252 #ifdef UNIX
1253 struct stat statbuf;
1254 fstat(f, &statbuf);
1255 return(statbuf.st_mtime);
1256 #else /* fstat not supported by DOS */
1257 return(0L);
1258 #endif
1262 void pexit(s)
1263 char *s;
1265 fprintf(stderr, "%s: %s\n", progname, s);
1266 if (lct != 0)
1267 fprintf(stderr, "Line %d being processed when error detected.\n", lct);
1268 flush();
1269 exit(2);
1273 void copy(from, to, count)
1274 char *from, *to;
1275 size_t count;
1277 while (count--) *to++ = *from++;
1280 char *alloc_block()
1282 char *buf;
1284 if(!(buf = malloc(block_size))) {
1285 pexit("couldn't allocate filesystem buffer");
1287 bzero(buf, block_size);
1289 return buf;
1292 void print_fs()
1294 int i, j;
1295 ino_t k;
1296 d2_inode *inode2;
1297 unsigned short *usbuf;
1298 block_t b;
1299 struct direct *dir;
1301 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
1302 pexit("couldn't allocate a block of inodes");
1304 if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
1305 pexit("malloc of directory entry failed");
1307 usbuf = (unsigned short *) alloc_block();
1309 get_super_block((char *) usbuf);
1310 printf("\nSuperblock: ");
1311 for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
1312 get_block((block_t) 2, (char *) usbuf);
1313 printf("...\nInode map: ");
1314 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1315 get_block((block_t) 3, (char *) usbuf);
1316 printf("...\nZone map: ");
1317 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1318 printf("...\n");
1320 free(usbuf);
1321 usbuf = NULL;
1323 k = 0;
1324 for (b = inode_offset; k < nrinodes; b++) {
1325 get_block(b, (char *) inode2);
1326 for (i = 0; i < inodes_per_block; i++) {
1327 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
1328 /* Lint but OK */
1329 if (k > nrinodes) break;
1331 if (inode2[i].d2_mode != 0) {
1332 printf("Inode %2lu: mode=", k);
1333 printf("%06o", inode2[i].d2_mode);
1334 printf(" uid=%2d gid=%2d size=",
1335 inode2[i].d2_uid, inode2[i].d2_gid);
1336 printf("%6d", inode2[i].d2_size);
1337 printf(" zone[0]=%u\n", inode2[i].d2_zone[0]);
1339 if ((inode2[i].d2_mode & S_IFMT) == S_IFDIR) {
1340 /* This is a directory */
1341 get_block(inode2[i].d2_zone[0], (char *) dir);
1342 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1343 if (dir[j].mfs_d_ino)
1344 printf("\tInode %2u: %s\n", dir[j].mfs_d_ino, dir[j].mfs_d_name);
1350 printf("%d inodes used. %d zones used.\n", next_inode - 1, next_zone);
1351 free(dir);
1352 free(inode2);
1356 int read_and_set(n)
1357 block_t n;
1359 /* The first time a block is read, it returns all 0s, unless there has
1360 * been a write. This routine checks to see if a block has been accessed.
1363 int w, s, mask, r;
1365 w = n / 8;
1366 if(w >= umap_array_elements) {
1367 pexit("umap array too small - this can't happen");
1369 s = n % 8;
1370 mask = 1 << s;
1371 r = (umap_array[w] & mask ? 1 : 0);
1372 umap_array[w] |= mask;
1373 return(r);
1376 void usage()
1378 fprintf(stderr,
1379 "Usage: %s [-12dlot] [-b blocks] [-i inodes]\n"
1380 "\t[-x extra] [-B blocksize] special [proto]\n",
1381 progname);
1382 exit(1);
1385 /*================================================================
1386 * get_block & put_block for MS-DOS
1387 *===============================================================*/
1388 #ifdef DOS
1391 * These are the get_block and put_block routines
1392 * when compiling & running mkfs.c under MS-DOS.
1394 * It requires the (asembler) routines absread & abswrite
1395 * from the file diskio.asm. Since these routines just do
1396 * as they are told (read & write the sector specified),
1397 * a local cache is used to minimize the i/o-overhead for
1398 * frequently used blocks.
1400 * The global variable "file" determines whether the output
1401 * is to a disk-device or to a binary file.
1405 #define PH_SECTSIZE 512 /* size of a physical disk-sector */
1408 char *derrtab[14] = {
1409 "no error",
1410 "disk is read-only",
1411 "unknown unit",
1412 "device not ready",
1413 "bad command",
1414 "data error",
1415 "internal error: bad request structure length",
1416 "seek error",
1417 "unknown media type",
1418 "sector not found",
1419 "printer out of paper (?)",
1420 "write fault",
1421 "read error",
1422 "general error"
1425 #define CACHE_SIZE 20 /* 20 block-buffers */
1428 struct cache {
1429 char blockbuf[BLOCK_SIZE];
1430 block_t blocknum;
1431 int dirty;
1432 int usecnt;
1433 } cache[CACHE_SIZE];
1436 void special(string)
1437 char *string;
1440 if (string[1] == ':' && string[2] == 0) {
1441 /* Format: d: or d:fname */
1442 disk = (string[0] & ~32) - 'A';
1443 if (disk > 1 && !override) /* safety precaution */
1444 pexit("Bad drive specifier for special");
1445 } else {
1446 file = 1;
1447 if ((fd = creat(string, BWRITE)) == 0)
1448 pexit("Can't open special file");
1452 void get_block(n, buf)
1453 block_t n;
1454 char *buf;
1456 /* Get a block to the user */
1457 struct cache *bp, *fp;
1459 /* First access returns a zero block */
1460 if (read_and_set(n) == 0) {
1461 copy(zero, buf, block_size);
1462 return;
1465 /* Look for block in cache */
1466 fp = 0;
1467 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1468 if (bp->blocknum == n) {
1469 copy(bp, buf, block_size);
1470 bp->usecnt++;
1471 return;
1474 /* Remember clean block */
1475 if (bp->dirty == 0)
1476 if (fp) {
1477 if (fp->usecnt > bp->usecnt) fp = bp;
1478 } else
1479 fp = bp;
1482 /* Block not in cache, get it */
1483 if (!fp) {
1484 /* No clean buf, flush one */
1485 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1486 if (fp->usecnt > bp->usecnt) fp = bp;
1487 mx_write(fp->blocknum, fp);
1489 mx_read(n, fp);
1490 fp->dirty = 0;
1491 fp->usecnt = 0;
1492 fp->blocknum = n;
1493 copy(fp, buf, block_size);
1496 void put_block(n, buf)
1497 block_t n;
1498 char *buf;
1500 /* Accept block from user */
1501 struct cache *fp, *bp;
1503 (void) read_and_set(n);
1505 /* Look for block in cache */
1506 fp = 0;
1507 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1508 if (bp->blocknum == n) {
1509 copy(buf, bp, block_size);
1510 bp->dirty = 1;
1511 return;
1514 /* Remember clean block */
1515 if (bp->dirty == 0)
1516 if (fp) {
1517 if (fp->usecnt > bp->usecnt) fp = bp;
1518 } else
1519 fp = bp;
1522 /* Block not in cache */
1523 if (!fp) {
1524 /* No clean buf, flush one */
1525 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1526 if (fp->usecnt > bp->usecnt) fp = bp;
1527 mx_write(fp->blocknum, fp);
1529 fp->dirty = 1;
1530 fp->usecnt = 1;
1531 fp->blocknum = n;
1532 copy(buf, fp, block_size);
1535 void cache_init()
1537 struct cache *bp;
1538 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
1541 void flush()
1543 /* Flush all dirty blocks to disk */
1544 struct cache *bp;
1546 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
1547 if (bp->dirty) {
1548 mx_write(bp->blocknum, bp);
1549 bp->dirty = 0;
1553 /*==================================================================
1554 * hard read & write etc.
1555 *=================================================================*/
1556 #define MAX_RETRIES 5
1559 void mx_read(blocknr, buf)
1560 int blocknr;
1561 char *buf;
1564 /* Read the requested MINIX-block in core */
1565 char (*bp)[PH_SECTSIZE];
1566 int sectnum, retries, err;
1568 if (file) {
1569 lseek(fd, (off_t) blocknr * block_size, 0);
1570 if (read(fd, buf, block_size) != block_size)
1571 pexit("mx_read: error reading file");
1572 } else {
1573 sectnum = blocknr * (block_size / PH_SECTSIZE);
1574 for (bp = buf; bp < &buf[block_size]; bp++) {
1575 retries = MAX_RETRIES;
1577 err = absread(disk, sectnum, bp);
1578 while (err && --retries);
1580 if (retries) {
1581 sectnum++;
1582 } else {
1583 dexit("mx_read", sectnum, err);
1589 void mx_write(blocknr, buf)
1590 int blocknr;
1591 char *buf;
1593 /* Write the MINIX-block to disk */
1594 char (*bp)[PH_SECTSIZE];
1595 int retries, sectnum, err;
1597 if (file) {
1598 lseek(fd, blocknr * block_size, 0);
1599 if (write(fd, buf, block_size) != block_size) {
1600 pexit("mx_write: error writing file");
1602 } else {
1603 sectnum = blocknr * (block_size / PH_SECTSIZE);
1604 for (bp = buf; bp < &buf[block_size]; bp++) {
1605 retries = MAX_RETRIES;
1606 do {
1607 err = abswrite(disk, sectnum, bp);
1608 } while (err && --retries);
1610 if (retries) {
1611 sectnum++;
1612 } else {
1613 dexit("mx_write", sectnum, err);
1620 void dexit(s, sectnum, err)
1621 int sectnum, err;
1622 char *s;
1624 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1625 s, sectnum, err, derrtab[err]);
1626 exit(2);
1629 #endif
1631 /*================================================================
1632 * get_block & put_block for UNIX
1633 *===============================================================*/
1634 #ifdef UNIX
1636 void special(string)
1637 char *string;
1639 fd = creat(string, 0777);
1640 close(fd);
1641 fd = open(string, O_RDWR);
1642 if (fd < 0) pexit("Can't open special file");
1647 void get_block(n, buf)
1648 block_t n;
1649 char *buf;
1651 /* Read a block. */
1653 int k;
1655 /* First access returns a zero block */
1656 if (read_and_set(n) == 0) {
1657 copy(zero, buf, block_size);
1658 return;
1660 lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL);
1661 k = read(fd, buf, block_size);
1662 if (k != block_size) {
1663 pexit("get_block couldn't read");
1667 void get_super_block(buf)
1668 char *buf;
1670 /* Read a block. */
1672 int k;
1674 if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
1675 perror("lseek");
1676 pexit("seek failed");
1678 k = read(fd, buf, _STATIC_BLOCK_SIZE);
1679 if (k != _STATIC_BLOCK_SIZE) {
1680 pexit("get_super_block couldn't read");
1684 void put_block(n, buf)
1685 block_t n;
1686 char *buf;
1688 /* Write a block. */
1690 (void) read_and_set(n);
1692 /* XXX - check other lseeks too. */
1693 if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1) {
1694 pexit("put_block couldn't seek");
1696 if (write(fd, buf, block_size) != block_size) {
1697 pexit("put_block couldn't write");
1702 /* Dummy routines to keep source file clean from #ifdefs */
1704 void flush()
1706 return;
1709 void cache_init()
1711 return;
1714 #endif