improve behaviour under VPC, fixes from nicolas tittley.
[minix.git] / commands / simple / mkfs.c
blobdcac038a6a4382e02abd74c402654bf72283a78b
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/dir.h>
15 #include <sys/stat.h>
16 #include <stdio.h>
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <limits.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <minix/config.h>
25 #include <minix/const.h>
26 #include <minix/type.h>
27 #include <minix/minlib.h>
28 #include "../../servers/mfs/const.h"
29 #if (MACHINE == IBM_PC)
30 #include <minix/partition.h>
31 #include <minix/u64.h>
32 #include <sys/ioctl.h>
33 #endif
34 #include <a.out.h>
35 #include <tools.h>
36 #include <dirent.h>
38 #undef EXTERN
39 #define EXTERN /* get rid of EXTERN by making it null */
40 #include "../../servers/mfs/super.h"
41 #include "../../servers/mfs/type.h"
42 #include "../../servers/mfs/inode.h"
43 #include <minix/fslib.h>
45 #ifndef max
46 #define max(a,b) ((a) > (b) ? (a) : (b))
47 #endif
49 #ifndef DOS
50 #ifndef UNIX
51 #define UNIX
52 #endif
53 #endif
55 #define INODE_MAP 2
56 #define MAX_TOKENS 10
57 #define LINE_LEN 200
58 #define BIN 2
59 #define BINGRP 2
60 #define BIT_MAP_SHIFT 13
61 #define INODE_MAX ((unsigned) 65535)
64 #ifdef DOS
65 maybedefine O_RDONLY 4 /* O_RDONLY | BINARY_BIT */
66 maybedefine BWRITE 5 /* O_WRONLY | BINARY_BIT */
67 #endif
69 #if (MACHINE == ATARI)
70 int isdev;
71 #endif
73 extern char *optarg;
74 extern int optind;
76 int next_zone, next_inode, zone_size, zone_shift = 0, zoff;
77 block_t nrblocks;
78 int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
79 unsigned int nrinodes;
80 int override = 0, simple = 0, dflag;
81 int donttest; /* skip test if it fits on medium */
82 char *progname;
84 long current_time, bin_time;
85 char *zero, *lastp;
86 char *umap_array; /* bit map tells if block read yet */
87 int umap_array_elements = 0;
88 block_t zone_map; /* where is zone map? (depends on # inodes) */
89 int inodes_per_block;
90 int fs_version;
91 unsigned int block_size;
93 FILE *proto;
95 _PROTOTYPE(int main, (int argc, char **argv));
96 _PROTOTYPE(block_t sizeup, (char *device));
97 _PROTOTYPE(void super, (zone_t zones, Ino_t inodes));
98 _PROTOTYPE(void rootdir, (Ino_t inode));
99 _PROTOTYPE(void eat_dir, (Ino_t parent));
100 _PROTOTYPE(void eat_file, (Ino_t inode, int f));
101 _PROTOTYPE(void enter_dir, (Ino_t parent, char *name, Ino_t child));
102 _PROTOTYPE(void incr_size, (Ino_t n, long count));
103 _PROTOTYPE(PRIVATE ino_t alloc_inode, (int mode, int usrid, int grpid));
104 _PROTOTYPE(PRIVATE zone_t alloc_zone, (void));
105 _PROTOTYPE(void add_zone, (Ino_t n, zone_t z, long bytes, long cur_time));
106 _PROTOTYPE(void add_z_1, (Ino_t n, zone_t z, long bytes, long cur_time));
107 _PROTOTYPE(void add_z_2, (Ino_t n, zone_t z, long bytes, long cur_time));
108 _PROTOTYPE(void incr_link, (Ino_t n));
109 _PROTOTYPE(void insert_bit, (block_t block, int bit));
110 _PROTOTYPE(int mode_con, (char *p));
111 _PROTOTYPE(void getline, (char line[LINE_LEN], char *parse[MAX_TOKENS]));
112 _PROTOTYPE(void check_mtab, (char *devname));
113 _PROTOTYPE(long file_time, (int f));
114 _PROTOTYPE(void pexit, (char *s));
115 _PROTOTYPE(void copy, (char *from, char *to, int count));
116 _PROTOTYPE(void print_fs, (void));
117 _PROTOTYPE(int read_and_set, (block_t n));
118 _PROTOTYPE(void special, (char *string));
119 _PROTOTYPE(void get_block, (block_t n, char *buf));
120 _PROTOTYPE(void get_super_block, (char *buf));
121 _PROTOTYPE(void put_block, (block_t n, char *buf));
122 _PROTOTYPE(void cache_init, (void));
123 _PROTOTYPE(void flush, (void));
124 _PROTOTYPE(void mx_read, (int blocknr, char *buf));
125 _PROTOTYPE(void mx_write, (int blocknr, char *buf));
126 _PROTOTYPE(void dexit, (char *s, int sectnum, int err));
127 _PROTOTYPE(void usage, (void));
128 _PROTOTYPE(char *alloc_block, (void));
130 /*================================================================
131 * mkfs - make filesystem
132 *===============================================================*/
133 int main(argc, argv)
134 int argc;
135 char *argv[];
137 int nread, mode, usrid, grpid, ch;
138 block_t blocks, maxblocks;
139 block_t i;
140 ino_t root_inum;
141 ino_t inodes;
142 zone_t zones;
143 char *token[MAX_TOKENS], line[LINE_LEN];
144 struct stat statbuf;
146 /* Get two times, the current time and the mod time of the binary of
147 * mkfs itself. When the -d flag is used, the later time is put into
148 * the i_mtimes of all the files. This feature is useful when
149 * producing a set of file systems, and one wants all the times to be
150 * identical. First you set the time of the mkfs binary to what you
151 * want, then go.
153 current_time = time((time_t *) 0); /* time mkfs is being run */
154 stat(argv[0], &statbuf);
155 bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */
157 /* Process switches. */
158 progname = argv[0];
159 blocks = 0;
160 i = 0;
161 fs_version = 3;
162 inodes_per_block = 0;
163 block_size = 0;
164 while ((ch = getopt(argc, argv, "12b:di:lotB:")) != EOF)
165 switch (ch) {
166 case '1':
167 fs_version = 1;
168 inodes_per_block = V1_INODES_PER_BLOCK;
169 break;
170 case '2':
171 fs_version = 2;
172 break;
173 case 'b':
174 blocks = strtoul(optarg, (char **) NULL, 0);
175 break;
176 case 'd':
177 dflag = 1;
178 current_time = bin_time;
179 break;
180 case 'i':
181 i = strtoul(optarg, (char **) NULL, 0);
182 break;
183 case 'l': print = 1; break;
184 case 'o': override = 1; break;
185 case 't': donttest = 1; break;
186 case 'B': block_size = atoi(optarg); break;
187 default: usage();
190 if (argc == optind) usage();
192 if(fs_version == 3) {
193 if(!block_size) block_size = _MAX_BLOCK_SIZE; /* V3 default block size */
194 if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
195 fprintf(stderr, "block size must be multiple of sector (%d) "
196 "and at least %d bytes\n",
197 SECTOR_SIZE, _MIN_BLOCK_SIZE);
198 pexit("specified block size illegal");
200 if(block_size%V2_INODE_SIZE) {
201 fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
202 V2_INODE_SIZE);
203 pexit("specified block size illegal");
205 } else {
206 if(block_size) {
207 pexit("Can't specify a block size if FS version is <3");
209 block_size = _STATIC_BLOCK_SIZE; /* V1/V2 block size */
212 if(!inodes_per_block)
213 inodes_per_block = V2_INODES_PER_BLOCK(block_size);
215 /* now that the block size is known, do buffer allocations where
216 * possible.
218 zero = alloc_block();
219 bzero(zero, block_size);
221 /* Determine the size of the device if not specified as -b or proto. */
222 maxblocks = sizeup(argv[optind]);
223 if (argc - optind == 1 && blocks == 0) {
224 blocks = maxblocks;
225 /* blocks == 0 is checked later, but leads to a funny way of
226 * reporting a 0-sized device (displays usage).
228 if(blocks < 1) {
229 fprintf(stderr, "%s: zero size device.\n", progname);
230 return 1;
234 /* The remaining args must be 'special proto', or just 'special' if the
235 * no. of blocks has already been specified.
237 if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
239 if (blocks > maxblocks) {
240 fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
241 progname, argv[optind]);
242 return 1;
245 /* Check special. */
246 check_mtab(argv[optind]);
248 /* Check and start processing proto. */
249 optarg = argv[++optind];
250 if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
251 /* Prototype file is readable. */
252 lct = 1;
253 getline(line, token); /* skip boot block info */
255 /* Read the line with the block and inode counts. */
256 getline(line, token);
257 blocks = atol(token[0]);
258 inodes = atoi(token[1]);
260 /* Process mode line for root directory. */
261 getline(line, token);
262 mode = mode_con(token[0]);
263 usrid = atoi(token[1]);
264 grpid = atoi(token[2]);
265 } else {
266 lct = 0;
267 if (optind < argc) {
268 /* Maybe the prototype file is just a size. Check. */
269 blocks = strtoul(optarg, (char **) NULL, 0);
270 if (blocks == 0) pexit("Can't open prototype file");
272 if (i == 0) {
273 u32_t kb = div64u(mul64u(blocks, block_size), 1024);
274 i = kb / 2;
275 if (kb >= 100000) i = kb / 4;
277 /* round up to fill inode block */
278 i += inodes_per_block - 1;
279 i = i / inodes_per_block * inodes_per_block;
280 if (i > INODE_MAX && fs_version < 3) i = INODE_MAX;
283 if (blocks < 5) pexit("Block count too small");
284 if (i < 1) pexit("Inode count too small");
285 if (i > INODE_MAX && fs_version < 3) pexit("Inode count too large");
286 inodes = (ino_t) i;
288 /* Make simple file system of the given size, using defaults. */
289 mode = 040777;
290 usrid = BIN;
291 grpid = BINGRP;
292 simple = 1;
295 nrblocks = blocks;
296 nrinodes = inodes;
299 size_t bytes;
300 bytes = 1 + blocks/8;
301 if(!(umap_array = malloc(bytes))) {
302 fprintf(stderr, "mkfs: can't allocate block bitmap (%d bytes).\n",
303 bytes);
304 exit(1);
306 umap_array_elements = bytes;
309 /* Open special. */
310 special(argv[--optind]);
312 #ifdef UNIX
313 if (!donttest) {
314 short *testb;
315 ssize_t w;
317 testb = (short *) alloc_block();
319 /* Try writing the last block of partition or diskette. */
320 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
321 pexit("couldn't seek to last block to test size (1)");
323 testb[0] = 0x3245;
324 testb[1] = 0x11FF;
325 testb[block_size/2-1] = 0x1F2F;
326 if ((w=write(fd, (char *) testb, block_size)) != block_size) {
327 if(w < 0) perror("write");
328 printf("%d/%d\n", w, block_size);
329 pexit("File system is too big for minor device (write)");
331 sync(); /* flush write, so if error next read fails */
332 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
333 pexit("couldn't seek to last block to test size (2)");
335 testb[0] = 0;
336 testb[1] = 0;
337 nread = read(fd, (char *) testb, block_size);
338 if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
339 testb[block_size/2-1] != 0x1F2F) {
340 if(nread < 0) perror("read");
341 printf("nread = %d\n", nread);
342 printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]);
343 pexit("File system is too big for minor device (read)");
345 lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL);
346 testb[0] = 0;
347 testb[1] = 0;
348 if (write(fd, (char *) testb, block_size) != block_size)
349 pexit("File system is too big for minor device (write2)");
350 lseek(fd, 0L, SEEK_SET);
351 free(testb);
353 #endif
355 /* Make the file-system */
357 cache_init();
359 put_block((block_t) 0, zero); /* Write a null boot block. */
361 zone_shift = 0; /* for future use */
362 zones = nrblocks >> zone_shift;
364 super(zones, inodes);
366 root_inum = alloc_inode(mode, usrid, grpid);
367 rootdir(root_inum);
368 if (simple == 0) eat_dir(root_inum);
370 if (print) print_fs();
371 flush();
372 return(0);
374 /* NOTREACHED */
375 } /* end main */
378 /*================================================================
379 * sizeup - determine device size
380 *===============================================================*/
381 block_t sizeup(device)
382 char *device;
384 int fd;
385 struct partition entry;
386 block_t d;
387 struct stat st;
388 unsigned int rem;
389 u64_t resize;
391 if ((fd = open(device, O_RDONLY)) == -1) {
392 if (errno != ENOENT)
393 perror("sizeup open");
394 return 0;
396 if (ioctl(fd, DIOCGETP, &entry) == -1) {
397 perror("sizeup ioctl");
398 if(fstat(fd, &st) < 0) {
399 perror("fstat");
400 entry.size = cvu64(0);
401 } else {
402 fprintf(stderr, "used fstat instead\n");
403 entry.size = cvu64(st.st_size);
406 close(fd);
407 d = div64u(entry.size, block_size);
408 rem = rem64u(entry.size, block_size);
410 resize = add64u(mul64u(d, block_size), rem);
411 if(cmp64(resize, entry.size) != 0) {
412 d = ULONG_MAX;
413 fprintf(stderr, "mkfs: truncating FS at %lu blocks\n", d);
416 return d;
420 /*================================================================
421 * super - construct a superblock
422 *===============================================================*/
424 void super(zones, inodes)
425 zone_t zones;
426 ino_t inodes;
428 unsigned int i;
429 int inodeblks;
430 int initblks;
431 u32_t nb;
432 zone_t v1sq, v2sq;
433 zone_t zo;
434 struct super_block *sup;
435 char *buf, *cp;
437 buf = alloc_block();
439 for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
440 sup = (struct super_block *) buf; /* lint - might use a union */
442 sup->s_ninodes = inodes;
443 if (fs_version == 1) {
444 sup->s_nzones = zones;
445 if (sup->s_nzones != zones) pexit("too many zones");
446 } else {
447 sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */
448 sup->s_zones = zones;
451 #define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
452 sup->s_imap_blocks = nb = bitmapsize((bit_t) (1 + inodes), block_size);
453 if(sup->s_imap_blocks != nb) {
454 fprintf(stderr, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS);
455 exit(1);
457 sup->s_zmap_blocks = nb = bitmapsize((bit_t) zones, block_size);
458 if(nb != sup->s_zmap_blocks) {
459 fprintf(stderr, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS);
460 exit(1);
462 inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks;
463 inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
464 initblks = inode_offset + inodeblks;
465 sup->s_firstdatazone_old = nb =
466 (initblks + (1 << zone_shift) - 1) >> zone_shift;
467 if(nb >= zones) pexit("bit maps too large");
468 if(nb != sup->s_firstdatazone_old) {
469 /* The field is too small to store the value. Fortunately, the value
470 * can be computed from other fields. We set the on-disk field to zero
471 * to indicate that it must not be used. Eventually, we can always set
472 * the on-disk field to zero, and stop using it.
474 sup->s_firstdatazone_old = 0;
476 sup->s_firstdatazone = nb;
477 zoff = sup->s_firstdatazone - 1;
478 sup->s_log_zone_size = zone_shift;
479 if (fs_version == 1) {
480 sup->s_magic = SUPER_MAGIC; /* identify super blocks */
481 v1sq = (zone_t) V1_INDIRECTS * V1_INDIRECTS;
482 zo = V1_NR_DZONES + (long) V1_INDIRECTS + v1sq;
483 sup->s_max_size = zo * block_size;
484 } else {
485 v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
486 zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
487 if(fs_version == 2) {
488 sup->s_magic = SUPER_V2;/* identify super blocks */
489 sup->s_max_size = zo * block_size;
490 } else {
491 sup->s_magic = SUPER_V3;
492 sup->s_block_size = block_size;
493 sup->s_disk_version = 0;
494 #define MAX_MAX_SIZE ((unsigned long) LONG_MAX)
495 if(MAX_MAX_SIZE/block_size < zo) {
496 sup->s_max_size = MAX_MAX_SIZE;
498 else {
499 sup->s_max_size = zo * block_size;
504 zone_size = 1 << zone_shift; /* nr of blocks per zone */
506 if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
507 pexit("super() couldn't seek");
509 if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
510 pexit("super() couldn't write");
513 /* Clear maps and inodes. */
514 for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero);
516 next_zone = sup->s_firstdatazone;
517 next_inode = 1;
519 zone_map = INODE_MAP + sup->s_imap_blocks;
521 insert_bit(zone_map, 0); /* bit zero must always be allocated */
522 insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but
523 * must be allocated */
525 free(buf);
529 /*================================================================
530 * rootdir - install the root directory
531 *===============================================================*/
532 void rootdir(inode)
533 ino_t inode;
535 zone_t z;
537 z = alloc_zone();
538 add_zone(inode, z, 2 * sizeof(struct direct), current_time);
539 enter_dir(inode, ".", inode);
540 enter_dir(inode, "..", inode);
541 incr_link(inode);
542 incr_link(inode);
546 /*================================================================
547 * eat_dir - recursively install directory
548 *===============================================================*/
549 void eat_dir(parent)
550 ino_t parent;
552 /* Read prototype lines and set up directory. Recurse if need be. */
553 char *token[MAX_TOKENS], *p;
554 char line[LINE_LEN];
555 int mode, usrid, grpid, maj, min, f;
556 ino_t n;
557 zone_t z;
558 long size;
560 while (1) {
561 getline(line, token);
562 p = token[0];
563 if (*p == '$') return;
564 p = token[1];
565 mode = mode_con(p);
566 usrid = atoi(token[2]);
567 grpid = atoi(token[3]);
568 if (grpid & 0200) fprintf(stderr, "A.S.Tanenbaum\n");
569 n = alloc_inode(mode, usrid, grpid);
571 /* Enter name in directory and update directory's size. */
572 enter_dir(parent, token[0], n);
573 incr_size(parent, sizeof(struct direct));
575 /* Check to see if file is directory or special. */
576 incr_link(n);
577 if (*p == 'd') {
578 /* This is a directory. */
579 z = alloc_zone(); /* zone for new directory */
580 add_zone(n, z, 2 * sizeof(struct direct), current_time);
581 enter_dir(n, ".", n);
582 enter_dir(n, "..", parent);
583 incr_link(parent);
584 incr_link(n);
585 eat_dir(n);
586 } else if (*p == 'b' || *p == 'c') {
587 /* Special file. */
588 maj = atoi(token[4]);
589 min = atoi(token[5]);
590 size = 0;
591 if (token[6]) size = atoi(token[6]);
592 size = block_size * size;
593 add_zone(n, (zone_t) ((maj << 8) | min), size, current_time);
594 } else {
595 /* Regular file. Go read it. */
596 if ((f = open(token[4], O_RDONLY)) < 0) {
597 fprintf(stderr, "%s: Can't open %s: %s\n",
598 progname, token[4], strerror(errno));
599 } else {
600 eat_file(n, f);
607 /*================================================================
608 * eat_file - copy file to MINIX
609 *===============================================================*/
610 /* Zonesize >= blocksize */
611 void eat_file(inode, f)
612 ino_t inode;
613 int f;
615 int ct, i, j, k;
616 zone_t z;
617 char *buf;
618 long timeval;
620 buf = alloc_block();
622 do {
623 for (i = 0, j = 0; i < zone_size; i++, j += ct) {
624 for (k = 0; k < block_size; k++) buf[k] = 0;
625 if ((ct = read(f, buf, block_size)) > 0) {
626 if (i == 0) z = alloc_zone();
627 put_block((z << zone_shift) + i, buf);
630 timeval = (dflag ? current_time : file_time(f));
631 if (ct) add_zone(inode, z, (long) j, timeval);
632 } while (ct == block_size);
633 close(f);
638 /*================================================================
639 * directory & inode management assist group
640 *===============================================================*/
641 void enter_dir(parent, name, child)
642 ino_t parent, child;
643 char *name;
645 /* Enter child in parent directory */
646 /* Works for dir > 1 block and zone > block */
647 int i, j, k, l, off;
648 block_t b;
649 zone_t z;
650 char *p1, *p2;
651 struct direct *dir_entry;
652 d1_inode ino1[V1_INODES_PER_BLOCK];
653 d2_inode *ino2;
654 int nr_dzones;
656 b = ((parent - 1) / inodes_per_block) + inode_offset;
657 off = (parent - 1) % inodes_per_block;
659 if(!(dir_entry = malloc(NR_DIR_ENTRIES(block_size) * sizeof(*dir_entry))))
660 pexit("couldn't allocate directory entry");
662 if(!(ino2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*ino2))))
663 pexit("couldn't allocate block of inodes entry");
665 if (fs_version == 1) {
666 get_block(b, (char *) ino1);
667 nr_dzones = V1_NR_DZONES;
668 } else {
669 get_block(b, (char *) ino2);
670 nr_dzones = V2_NR_DZONES;
672 for (k = 0; k < nr_dzones; k++) {
673 if (fs_version == 1) {
674 z = ino1[off].d1_zone[k];
675 if (z == 0) {
676 z = alloc_zone();
677 ino1[off].d1_zone[k] = z;
679 } else {
680 z = ino2[off].d2_zone[k];
681 if (z == 0) {
682 z = alloc_zone();
683 ino2[off].d2_zone[k] = z;
686 for (l = 0; l < zone_size; l++) {
687 get_block((z << zone_shift) + l, (char *) dir_entry);
688 for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) {
689 if (dir_entry[i].d_ino == 0) {
690 dir_entry[i].d_ino = child;
691 p1 = name;
692 p2 = dir_entry[i].d_name;
693 j = sizeof(dir_entry[i].d_name);
694 while (j--) {
695 *p2++ = *p1;
696 if (*p1 != 0) p1++;
698 put_block((z << zone_shift) + l, (char *) dir_entry);
699 if (fs_version == 1) {
700 put_block(b, (char *) ino1);
701 } else {
702 put_block(b, (char *) ino2);
704 free(dir_entry);
705 free(ino2);
706 return;
712 printf("Directory-inode %d beyond direct blocks. Could not enter %s\n",
713 parent, name);
714 pexit("Halt");
718 void add_zone(n, z, bytes, cur_time)
719 ino_t n;
720 zone_t z;
721 long bytes, cur_time;
723 if (fs_version == 1) {
724 add_z_1(n, z, bytes, cur_time);
725 } else {
726 add_z_2(n, z, bytes, cur_time);
730 void add_z_1(n, z, bytes, cur_time)
731 ino_t n;
732 zone_t z;
733 long bytes, cur_time;
735 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
737 int off, i;
738 block_t b;
739 zone_t indir;
740 zone1_t blk[V1_INDIRECTS];
741 d1_inode *p;
742 d1_inode inode[V1_INODES_PER_BLOCK];
744 b = ((n - 1) / V1_INODES_PER_BLOCK) + inode_offset;
745 off = (n - 1) % V1_INODES_PER_BLOCK;
746 get_block(b, (char *) inode);
747 p = &inode[off];
748 p->d1_size += bytes;
749 p->d1_mtime = cur_time;
750 for (i = 0; i < V1_NR_DZONES; i++)
751 if (p->d1_zone[i] == 0) {
752 p->d1_zone[i] = (zone1_t) z;
753 put_block(b, (char *) inode);
754 return;
756 put_block(b, (char *) inode);
758 /* File has grown beyond a small file. */
759 if (p->d1_zone[V1_NR_DZONES] == 0)
760 p->d1_zone[V1_NR_DZONES] = (zone1_t) alloc_zone();
761 indir = p->d1_zone[V1_NR_DZONES];
762 put_block(b, (char *) inode);
763 b = indir << zone_shift;
764 get_block(b, (char *) blk);
765 for (i = 0; i < V1_INDIRECTS; i++)
766 if (blk[i] == 0) {
767 blk[i] = (zone1_t) z;
768 put_block(b, (char *) blk);
769 return;
771 pexit("File has grown beyond single indirect");
774 void add_z_2(n, z, bytes, cur_time)
775 ino_t n;
776 zone_t z;
777 long bytes, cur_time;
779 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
781 int off, i;
782 block_t b;
783 zone_t indir;
784 zone_t *blk;
785 d2_inode *p;
786 d2_inode *inode;
788 if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
789 pexit("Couldn't allocate indirect block");
791 if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
792 pexit("Couldn't allocate block of inodes");
794 b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
795 off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
796 get_block(b, (char *) inode);
797 p = &inode[off];
798 p->d2_size += bytes;
799 p->d2_mtime = cur_time;
800 for (i = 0; i < V2_NR_DZONES; i++)
801 if (p->d2_zone[i] == 0) {
802 p->d2_zone[i] = z;
803 put_block(b, (char *) inode);
804 free(blk);
805 free(inode);
806 return;
808 put_block(b, (char *) inode);
810 /* File has grown beyond a small file. */
811 if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
812 indir = p->d2_zone[V2_NR_DZONES];
813 put_block(b, (char *) inode);
814 b = indir << zone_shift;
815 get_block(b, (char *) blk);
816 for (i = 0; i < V2_INDIRECTS(block_size); i++)
817 if (blk[i] == 0) {
818 blk[i] = z;
819 put_block(b, (char *) blk);
820 free(blk);
821 free(inode);
822 return;
824 pexit("File has grown beyond single indirect");
828 void incr_link(n)
829 ino_t n;
831 /* Increment the link count to inode n */
832 int off;
833 static int enter = 0;
834 block_t b;
836 if(enter) exit(1);
838 b = ((n - 1) / inodes_per_block) + inode_offset;
839 off = (n - 1) % inodes_per_block;
840 if (fs_version == 1) {
841 d1_inode inode1[V1_INODES_PER_BLOCK];
843 get_block(b, (char *) inode1);
844 inode1[off].d1_nlinks++;
845 put_block(b, (char *) inode1);
846 } else {
847 static d2_inode *inode2 = NULL;
848 int n;
850 n = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
851 if(!inode2 && !(inode2 = malloc(n)))
852 pexit("couldn't allocate a block of inodes");
854 get_block(b, (char *) inode2);
855 inode2[off].d2_nlinks++;
856 put_block(b, (char *) inode2);
858 enter = 0;
862 void incr_size(n, count)
863 ino_t n;
864 long count;
866 /* Increment the file-size in inode n */
867 block_t b;
868 int off;
870 b = ((n - 1) / inodes_per_block) + inode_offset;
871 off = (n - 1) % inodes_per_block;
872 if (fs_version == 1) {
873 d1_inode inode1[V1_INODES_PER_BLOCK];
875 get_block(b, (char *) inode1);
876 inode1[off].d1_size += count;
877 put_block(b, (char *) inode1);
878 } else {
879 d2_inode *inode2;
880 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
881 pexit("couldn't allocate a block of inodes");
883 get_block(b, (char *) inode2);
884 inode2[off].d2_size += count;
885 put_block(b, (char *) inode2);
886 free(inode2);
891 /*================================================================
892 * allocation assist group
893 *===============================================================*/
894 PRIVATE ino_t alloc_inode(mode, usrid, grpid)
895 int mode, usrid, grpid;
897 ino_t num;
898 int off;
899 block_t b;
901 num = next_inode++;
902 if (num > nrinodes) {
903 fprintf(stderr, "have %d inodoes\n", nrinodes);
904 pexit("File system does not have enough inodes");
906 b = ((num - 1) / inodes_per_block) + inode_offset;
907 off = (num - 1) % inodes_per_block;
908 if (fs_version == 1) {
909 d1_inode inode1[V1_INODES_PER_BLOCK];
911 get_block(b, (char *) inode1);
912 inode1[off].d1_mode = mode;
913 inode1[off].d1_uid = usrid;
914 inode1[off].d1_gid = grpid;
915 put_block(b, (char *) inode1);
916 } else {
917 d2_inode *inode2;
919 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
920 pexit("couldn't allocate a block of inodes");
922 get_block(b, (char *) inode2);
923 inode2[off].d2_mode = mode;
924 inode2[off].d2_uid = usrid;
925 inode2[off].d2_gid = grpid;
926 put_block(b, (char *) inode2);
928 free(inode2);
931 /* Set the bit in the bit map. */
932 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
933 insert_bit((block_t) INODE_MAP, (int) num);
934 return(num);
938 PRIVATE zone_t alloc_zone()
940 /* Allocate a new zone */
941 /* Works for zone > block */
942 block_t b;
943 int i;
944 zone_t z;
946 z = next_zone++;
947 b = z << zone_shift;
948 if ((b + zone_size) > nrblocks)
949 pexit("File system not big enough for all the files");
950 for (i = 0; i < zone_size; i++)
951 put_block(b + i, zero); /* give an empty zone */
952 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
953 insert_bit(zone_map, (int) (z - zoff)); /* lint, NOT OK because
954 * z hasn't been broken
955 * up into block +
956 * offset yet. */
957 return(z);
961 void insert_bit(block, bit)
962 block_t block;
963 int bit;
965 /* Insert 'count' bits in the bitmap */
966 int w, s;
967 short *buf;
969 buf = (short *) alloc_block();
971 if (block < 0) pexit("insert_bit called with negative argument");
972 get_block(block, (char *) buf);
973 w = bit / (8 * sizeof(short));
974 s = bit % (8 * sizeof(short));
975 buf[w] |= (1 << s);
976 put_block(block, (char *) buf);
978 free(buf);
982 /*================================================================
983 * proto-file processing assist group
984 *===============================================================*/
985 int mode_con(p)
986 char *p;
988 /* Convert string to mode */
989 int o1, o2, o3, mode;
990 char c1, c2, c3;
992 c1 = *p++;
993 c2 = *p++;
994 c3 = *p++;
995 o1 = *p++ - '0';
996 o2 = *p++ - '0';
997 o3 = *p++ - '0';
998 mode = (o1 << 6) | (o2 << 3) | o3;
999 if (c1 == 'd') mode += I_DIRECTORY;
1000 if (c1 == 'b') mode += I_BLOCK_SPECIAL;
1001 if (c1 == 'c') mode += I_CHAR_SPECIAL;
1002 if (c1 == '-') mode += I_REGULAR;
1003 if (c2 == 'u') mode += I_SET_UID_BIT;
1004 if (c3 == 'g') mode += I_SET_GID_BIT;
1005 return(mode);
1008 void getline(line, parse)
1009 char *parse[MAX_TOKENS];
1010 char line[LINE_LEN];
1012 /* Read a line and break it up in tokens */
1013 int k;
1014 char c, *p;
1015 int d;
1017 for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
1018 for (k = 0; k < LINE_LEN; k++) line[k] = 0;
1019 k = 0;
1020 parse[0] = 0;
1021 p = line;
1022 while (1) {
1023 if (++k > LINE_LEN) pexit("Line too long");
1024 d = fgetc(proto);
1025 if (d == EOF) pexit("Unexpected end-of-file");
1026 *p = d;
1027 if (*p == '\n') lct++;
1028 if (*p == ' ' || *p == '\t') *p = 0;
1029 if (*p == '\n') {
1030 *p++ = 0;
1031 *p = '\n';
1032 break;
1034 p++;
1037 k = 0;
1038 p = line;
1039 lastp = line;
1040 while (1) {
1041 c = *p++;
1042 if (c == '\n') return;
1043 if (c == 0) continue;
1044 parse[k++] = p - 1;
1045 do {
1046 c = *p++;
1047 } while (c != 0 && c != '\n');
1052 /*================================================================
1053 * other stuff
1054 *===============================================================*/
1055 void check_mtab(devname)
1056 char *devname; /* /dev/hd1 or whatever */
1058 /* Check to see if the special file named in s is mounted. */
1060 int n, r;
1061 struct stat sb;
1062 char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
1064 r= stat(devname, &sb);
1065 if (r == -1)
1067 if (errno == ENOENT)
1068 return; /* Does not exist, and therefore not mounted. */
1069 fprintf(stderr, "%s: stat %s failed: %s\n",
1070 progname, devname, strerror(errno));
1071 exit(1);
1073 if (!S_ISBLK(sb.st_mode))
1075 /* Not a block device and therefore not mounted. */
1076 return;
1079 if (load_mtab("mkfs") < 0) return;
1080 while (1) {
1081 n = get_mtab_entry(special, mounted_on, version, rw_flag);
1082 if (n < 0) return;
1083 if (strcmp(devname, special) == 0) {
1084 /* Can't mkfs on top of a mounted file system. */
1085 fprintf(stderr, "%s: %s is mounted on %s\n",
1086 progname, devname, mounted_on);
1087 exit(1);
1093 long file_time(f)
1094 int f;
1096 #ifdef UNIX
1097 struct stat statbuf;
1098 fstat(f, &statbuf);
1099 return(statbuf.st_mtime);
1100 #else /* fstat not supported by DOS */
1101 return(0L);
1102 #endif
1106 void pexit(s)
1107 char *s;
1109 fprintf(stderr, "%s: %s\n", progname, s);
1110 if (lct != 0)
1111 fprintf(stderr, "Line %d being processed when error detected.\n", lct);
1112 flush();
1113 exit(2);
1117 void copy(from, to, count)
1118 char *from, *to;
1119 int count;
1121 while (count--) *to++ = *from++;
1124 char *alloc_block()
1126 char *buf;
1128 if(!(buf = malloc(block_size))) {
1129 pexit("couldn't allocate filesystem buffer");
1131 bzero(buf, block_size);
1133 return buf;
1136 void print_fs()
1138 int i, j;
1139 ino_t k;
1140 d1_inode inode1[V1_INODES_PER_BLOCK];
1141 d2_inode *inode2;
1142 unsigned short *usbuf;
1143 block_t b, inode_limit;
1144 struct direct *dir;
1146 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
1147 pexit("couldn't allocate a block of inodes");
1149 if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
1150 pexit("malloc of directory entry failed");
1152 usbuf = (unsigned short *) alloc_block();
1154 get_super_block((char *) usbuf);
1155 printf("\nSuperblock: ");
1156 for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
1157 get_block((block_t) 2, (char *) usbuf);
1158 printf("...\nInode map: ");
1159 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1160 get_block((block_t) 3, (char *) usbuf);
1161 printf("...\nZone map: ");
1162 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1163 printf("...\n");
1165 free(usbuf);
1166 usbuf = NULL;
1168 k = 0;
1169 for (b = inode_offset; k < nrinodes; b++) {
1170 if (fs_version == 1) {
1171 get_block(b, (char *) inode1);
1172 } else {
1173 get_block(b, (char *) inode2);
1175 for (i = 0; i < inodes_per_block; i++) {
1176 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
1177 /* Lint but OK */
1178 if (k > nrinodes) break;
1179 if (fs_version == 1) {
1180 if (inode1[i].d1_mode != 0) {
1181 printf("Inode %2d: mode=", k);
1182 printf("%06o", inode1[i].d1_mode);
1183 printf(" uid=%2d gid=%2d size=",
1184 inode1[i].d1_uid, inode1[i].d1_gid);
1185 printf("%6ld", inode1[i].d1_size);
1186 printf(" zone[0]=%d\n", inode1[i].d1_zone[0]);
1188 if ((inode1[i].d1_mode & I_TYPE) == I_DIRECTORY) {
1189 /* This is a directory */
1190 get_block(inode1[i].d1_zone[0], (char *) dir);
1191 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1192 if (dir[j].d_ino)
1193 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
1195 } else {
1196 if (inode2[i].d2_mode != 0) {
1197 printf("Inode %2d: mode=", k);
1198 printf("%06o", inode2[i].d2_mode);
1199 printf(" uid=%2d gid=%2d size=",
1200 inode2[i].d2_uid, inode2[i].d2_gid);
1201 printf("%6ld", inode2[i].d2_size);
1202 printf(" zone[0]=%ld\n", inode2[i].d2_zone[0]);
1204 if ((inode2[i].d2_mode & I_TYPE) == I_DIRECTORY) {
1205 /* This is a directory */
1206 get_block(inode2[i].d2_zone[0], (char *) dir);
1207 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1208 if (dir[j].d_ino)
1209 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
1215 printf("%d inodes used. %d zones used.\n", next_inode - 1, next_zone);
1216 free(dir);
1217 free(inode2);
1221 int read_and_set(n)
1222 block_t n;
1224 /* The first time a block is read, it returns all 0s, unless there has
1225 * been a write. This routine checks to see if a block has been accessed.
1228 int w, s, mask, r;
1230 w = n / 8;
1231 if(w >= umap_array_elements) {
1232 pexit("umap array too small - this can't happen");
1234 s = n % 8;
1235 mask = 1 << s;
1236 r = (umap_array[w] & mask ? 1 : 0);
1237 umap_array[w] |= mask;
1238 return(r);
1241 void usage()
1243 fprintf(stderr,
1244 "Usage: %s [-12dlot] [-b blocks] [-i inodes] [-B blocksize] special [proto]\n",
1245 progname);
1246 exit(1);
1249 /*================================================================
1250 * get_block & put_block for MS-DOS
1251 *===============================================================*/
1252 #ifdef DOS
1255 * These are the get_block and put_block routines
1256 * when compiling & running mkfs.c under MS-DOS.
1258 * It requires the (asembler) routines absread & abswrite
1259 * from the file diskio.asm. Since these routines just do
1260 * as they are told (read & write the sector specified),
1261 * a local cache is used to minimize the i/o-overhead for
1262 * frequently used blocks.
1264 * The global variable "file" determines whether the output
1265 * is to a disk-device or to a binary file.
1269 #define PH_SECTSIZE 512 /* size of a physical disk-sector */
1272 char *derrtab[14] = {
1273 "no error",
1274 "disk is read-only",
1275 "unknown unit",
1276 "device not ready",
1277 "bad command",
1278 "data error",
1279 "internal error: bad request structure length",
1280 "seek error",
1281 "unknown media type",
1282 "sector not found",
1283 "printer out of paper (?)",
1284 "write fault",
1285 "read error",
1286 "general error"
1289 #define CACHE_SIZE 20 /* 20 block-buffers */
1292 struct cache {
1293 char blockbuf[BLOCK_SIZE];
1294 block_t blocknum;
1295 int dirty;
1296 int usecnt;
1297 } cache[CACHE_SIZE];
1300 void special(string)
1301 char *string;
1304 if (string[1] == ':' && string[2] == 0) {
1305 /* Format: d: or d:fname */
1306 disk = (string[0] & ~32) - 'A';
1307 if (disk > 1 && !override) /* safety precaution */
1308 pexit("Bad drive specifier for special");
1309 } else {
1310 file = 1;
1311 if ((fd = creat(string, BWRITE)) == 0)
1312 pexit("Can't open special file");
1316 void get_block(n, buf)
1317 block_t n;
1318 char *buf;
1320 /* Get a block to the user */
1321 struct cache *bp, *fp;
1323 /* First access returns a zero block */
1324 if (read_and_set(n) == 0) {
1325 copy(zero, buf, block_size);
1326 return;
1329 /* Look for block in cache */
1330 fp = 0;
1331 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1332 if (bp->blocknum == n) {
1333 copy(bp, buf, block_size);
1334 bp->usecnt++;
1335 return;
1338 /* Remember clean block */
1339 if (bp->dirty == 0)
1340 if (fp) {
1341 if (fp->usecnt > bp->usecnt) fp = bp;
1342 } else
1343 fp = bp;
1346 /* Block not in cache, get it */
1347 if (!fp) {
1348 /* No clean buf, flush one */
1349 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1350 if (fp->usecnt > bp->usecnt) fp = bp;
1351 mx_write(fp->blocknum, fp);
1353 mx_read(n, fp);
1354 fp->dirty = 0;
1355 fp->usecnt = 0;
1356 fp->blocknum = n;
1357 copy(fp, buf, block_size);
1360 void put_block(n, buf)
1361 block_t n;
1362 char *buf;
1364 /* Accept block from user */
1365 struct cache *fp, *bp;
1367 (void) read_and_set(n);
1369 /* Look for block in cache */
1370 fp = 0;
1371 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1372 if (bp->blocknum == n) {
1373 copy(buf, bp, block_size);
1374 bp->dirty = 1;
1375 return;
1378 /* Remember clean block */
1379 if (bp->dirty == 0)
1380 if (fp) {
1381 if (fp->usecnt > bp->usecnt) fp = bp;
1382 } else
1383 fp = bp;
1386 /* Block not in cache */
1387 if (!fp) {
1388 /* No clean buf, flush one */
1389 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1390 if (fp->usecnt > bp->usecnt) fp = bp;
1391 mx_write(fp->blocknum, fp);
1393 fp->dirty = 1;
1394 fp->usecnt = 1;
1395 fp->blocknum = n;
1396 copy(buf, fp, block_size);
1399 void cache_init()
1401 struct cache *bp;
1402 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
1405 void flush()
1407 /* Flush all dirty blocks to disk */
1408 struct cache *bp;
1410 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
1411 if (bp->dirty) {
1412 mx_write(bp->blocknum, bp);
1413 bp->dirty = 0;
1417 /*==================================================================
1418 * hard read & write etc.
1419 *=================================================================*/
1420 #define MAX_RETRIES 5
1423 void mx_read(blocknr, buf)
1424 int blocknr;
1425 char *buf;
1428 /* Read the requested MINIX-block in core */
1429 char (*bp)[PH_SECTSIZE];
1430 int sectnum, retries, err;
1432 if (file) {
1433 lseek(fd, (off_t) blocknr * block_size, 0);
1434 if (read(fd, buf, block_size) != block_size)
1435 pexit("mx_read: error reading file");
1436 } else {
1437 sectnum = blocknr * (block_size / PH_SECTSIZE);
1438 for (bp = buf; bp < &buf[block_size]; bp++) {
1439 retries = MAX_RETRIES;
1441 err = absread(disk, sectnum, bp);
1442 while (err && --retries);
1444 if (retries) {
1445 sectnum++;
1446 } else {
1447 dexit("mx_read", sectnum, err);
1453 void mx_write(blocknr, buf)
1454 int blocknr;
1455 char *buf;
1457 /* Write the MINIX-block to disk */
1458 char (*bp)[PH_SECTSIZE];
1459 int retries, sectnum, err;
1461 if (file) {
1462 lseek(fd, blocknr * block_size, 0);
1463 if (write(fd, buf, block_size) != block_size) {
1464 pexit("mx_write: error writing file");
1466 } else {
1467 sectnum = blocknr * (block_size / PH_SECTSIZE);
1468 for (bp = buf; bp < &buf[block_size]; bp++) {
1469 retries = MAX_RETRIES;
1470 do {
1471 err = abswrite(disk, sectnum, bp);
1472 } while (err && --retries);
1474 if (retries) {
1475 sectnum++;
1476 } else {
1477 dexit("mx_write", sectnum, err);
1484 void dexit(s, sectnum, err)
1485 int sectnum, err;
1486 char *s;
1488 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1489 s, sectnum, err, derrtab[err]);
1490 exit(2);
1493 #endif
1495 /*================================================================
1496 * get_block & put_block for UNIX
1497 *===============================================================*/
1498 #ifdef UNIX
1500 void special(string)
1501 char *string;
1503 fd = creat(string, 0777);
1504 close(fd);
1505 fd = open(string, O_RDWR);
1506 if (fd < 0) pexit("Can't open special file");
1507 #if (MACHINE == ATARI)
1509 struct stat statbuf;
1511 if (fstat(fd, &statbuf) < 0) return;
1512 isdev = (statbuf.st_mode & S_IFMT) == S_IFCHR
1514 (statbuf.st_mode & S_IFMT) == S_IFBLK
1517 #endif
1522 void get_block(n, buf)
1523 block_t n;
1524 char *buf;
1526 /* Read a block. */
1528 int k;
1530 /* First access returns a zero block */
1531 if (read_and_set(n) == 0) {
1532 copy(zero, buf, block_size);
1533 return;
1535 lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL);
1536 k = read(fd, buf, block_size);
1537 if (k != block_size) {
1538 pexit("get_block couldn't read");
1542 void get_super_block(buf)
1543 char *buf;
1545 /* Read a block. */
1547 int k;
1549 if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
1550 perror("lseek");
1551 pexit("seek failed");
1553 k = read(fd, buf, _STATIC_BLOCK_SIZE);
1554 if (k != _STATIC_BLOCK_SIZE) {
1555 pexit("get_super_block couldn't read");
1559 void put_block(n, buf)
1560 block_t n;
1561 char *buf;
1563 /* Write a block. */
1565 (void) read_and_set(n);
1567 /* XXX - check other lseeks too. */
1568 if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1) {
1569 pexit("put_block couldn't seek");
1571 if (write(fd, buf, block_size) != block_size) {
1572 pexit("put_block couldn't write");
1577 /* Dummy routines to keep source file clean from #ifdefs */
1579 void flush()
1581 return;
1584 void cache_init()
1586 return;
1589 #endif