mkfs: separate inode retrieval function
[minix.git] / usr.sbin / mkfs.mfs / mkfs.c
blobecbb56f3593f724b9aacbb3113377bf216ce635b
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 <assert.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 <stdint.h>
25 #include "const.h"
26 #include "type.h"
27 #include "mfsdir.h"
28 #if defined(__minix)
29 #include <minix/partition.h>
30 #include <minix/u64.h>
31 #include <minix/minlib.h>
32 #include <sys/ioctl.h>
33 #endif
34 #include <dirent.h>
36 #undef EXTERN
37 #define EXTERN /* get rid of EXTERN by making it null */
38 #include "super.h"
40 #ifndef max
41 #define max(a,b) ((a) > (b) ? (a) : (b))
42 #endif
44 #ifndef DOS
45 #ifndef UNIX
46 #define UNIX
47 #endif
48 #endif
50 #define INODE_MAP 2
51 #define MAX_TOKENS 10
52 #define LINE_LEN 200
53 #define BIN 2
54 #define BINGRP 2
55 #define BIT_MAP_SHIFT 13
56 #define INODE_MAX ((unsigned) 65535)
57 #define SECTOR_SIZE 512
60 #ifdef DOS
61 maybedefine O_RDONLY 4 /* O_RDONLY | BINARY_BIT */
62 maybedefine BWRITE 5 /* O_WRONLY | BINARY_BIT */
63 #endif
65 #if !defined(__minix)
66 #define mul64u(a,b) ((a) * (b))
67 #define lseek64(a,b,c,d) lseek(a,b,c)
68 #ifdef __linux__
69 #include <mntent.h>
70 #endif
71 #endif
73 #if !defined(__minix)
74 typedef uint32_t block_t;
75 typedef uint32_t zone_t;
76 #endif
78 extern char *optarg;
79 extern int optind;
81 int next_zone, next_inode, zone_size, zone_shift = 0, zoff;
82 block_t nrblocks;
83 int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
84 unsigned int nrinodes;
85 int override = 0, simple = 0, dflag;
86 int donttest; /* skip test if it fits on medium */
87 char *progname;
89 uint32_t current_time, bin_time;
90 char *zero, *lastp;
91 char *umap_array; /* bit map tells if block read yet */
92 int umap_array_elements = 0;
93 block_t zone_map; /* where is zone map? (depends on # inodes) */
94 int inodes_per_block;
95 size_t block_size;
96 int extra_space_percent;
98 FILE *proto;
100 #if defined(__NBSD_LIBC) || !defined(__minix)
101 #define getline _mkfs_getline
102 #endif
104 int main(int argc, char **argv);
105 block_t sizeup(char *device);
106 void super(zone_t zones, ino_t inodes);
107 void rootdir(ino_t inode);
108 void eat_dir(ino_t parent);
109 void eat_file(ino_t inode, int f);
110 void enter_dir(ino_t parent, char *name, ino_t child);
111 void incr_size(ino_t n, size_t count);
112 static ino_t alloc_inode(int mode, int usrid, int grpid);
113 static zone_t alloc_zone(void);
114 void add_zone(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
115 void add_z_1(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
116 void add_z_2(ino_t n, zone_t z, size_t bytes, uint32_t cur_time);
117 void incr_link(ino_t n);
118 void insert_bit(block_t block, int bit);
119 int mode_con(char *p);
120 void getline(char line[LINE_LEN], char *parse[MAX_TOKENS]);
121 void check_mtab(char *devname);
122 uint32_t file_time(int f);
123 void pexit(char *s);
124 void copy(char *from, char *to, size_t count);
125 void print_fs(void);
126 int read_and_set(block_t n);
127 void special(char *string);
128 void get_block(block_t n, char *buf);
129 void get_super_block(char *buf);
130 void put_block(block_t n, char *buf);
131 void cache_init(void);
132 void flush(void);
133 void mx_read(int blocknr, char *buf);
134 void mx_write(int blocknr, char *buf);
135 void dexit(char *s, int sectnum, int err);
136 void usage(void);
137 void *alloc_block(void);
139 ino_t inocount;
140 zone_t zonecount;
141 block_t blockcount;
143 void detect_fs_size(void);
144 void sizeup_dir(void);
145 void detect_size(void);
146 void size_dir(void);
147 static int bitmapsize(uint32_t nr_bits, size_t block_size);
149 /*================================================================
150 * mkfs - make filesystem
151 *===============================================================*/
152 int main(argc, argv)
153 int argc;
154 char *argv[];
156 int nread, mode, usrid, grpid, ch;
157 block_t blocks, maxblocks;
158 size_t i;
159 ino_t root_inum;
160 ino_t inodes;
161 zone_t zones;
162 char *token[MAX_TOKENS], line[LINE_LEN];
163 struct stat statbuf;
165 /* Get two times, the current time and the mod time of the binary of
166 * mkfs itself. When the -d flag is used, the later time is put into
167 * the i_mtimes of all the files. This feature is useful when
168 * producing a set of file systems, and one wants all the times to be
169 * identical. First you set the time of the mkfs binary to what you
170 * want, then go.
172 current_time = time((time_t *) 0); /* time mkfs is being run */
173 stat(argv[0], &statbuf);
174 bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */
176 /* Process switches. */
177 progname = argv[0];
178 blocks = 0;
179 i = 0;
180 inodes_per_block = 0;
181 block_size = 0;
182 extra_space_percent = 0;
183 while ((ch = getopt(argc, argv, "b:di:lotB:x:")) != EOF)
184 switch (ch) {
185 case 'b':
186 blocks = strtoul(optarg, (char **) NULL, 0);
187 break;
188 case 'd':
189 dflag = 1;
190 current_time = bin_time;
191 break;
192 case 'i':
193 i = strtoul(optarg, (char **) NULL, 0);
194 break;
195 case 'l': print = 1; break;
196 case 'o': override = 1; break;
197 case 't': donttest = 1; break;
198 case 'B': block_size = atoi(optarg); break;
199 case 'x': extra_space_percent = atoi(optarg); break;
200 default: usage();
203 if (argc == optind) usage();
205 /* Percentage of extra size must be nonnegative.
206 * It can legitimately be bigger than 100 but has to make some sort of sense.
208 if(extra_space_percent < 0 || extra_space_percent > 2000) usage();
211 if(!block_size) block_size = _MAX_BLOCK_SIZE; /* V3 default block size */
212 if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
213 fprintf(stderr, "block size must be multiple of sector (%d) "
214 "and at least %d bytes\n",
215 SECTOR_SIZE, _MIN_BLOCK_SIZE);
216 pexit("specified block size illegal");
218 if(block_size%V2_INODE_SIZE) {
219 fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
220 V2_INODE_SIZE);
221 pexit("specified block size illegal");
225 zone_shift = 0; /* for future use */
226 zone_size = 1 << zone_shift; /* nr of blocks per zone */
228 if(!inodes_per_block)
229 inodes_per_block = V2_INODES_PER_BLOCK(block_size);
231 /* now that the block size is known, do buffer allocations where
232 * possible.
234 zero = alloc_block();
235 bzero(zero, block_size);
237 /* Determine the size of the device if not specified as -b or proto. */
238 maxblocks = sizeup(argv[optind]);
239 if (argc - optind == 1 && blocks == 0) {
240 blocks = maxblocks;
241 /* blocks == 0 is checked later, but leads to a funny way of
242 * reporting a 0-sized device (displays usage).
244 if(blocks < 1) {
245 fprintf(stderr, "%s: zero size device.\n", progname);
246 return 1;
250 /* The remaining args must be 'special proto', or just 'special' if the
251 * no. of blocks has already been specified.
253 if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
255 if (blocks > maxblocks) {
256 fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
257 progname, argv[optind]);
258 return 1;
261 /* Check special. */
262 check_mtab(argv[optind]);
264 /* Check and start processing proto. */
265 optarg = argv[++optind];
266 if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
267 /* Prototype file is readable. */
268 lct = 1;
269 getline(line, token); /* skip boot block info */
271 /* Read the line with the block and inode counts. */
272 getline(line, token);
273 blocks = atol(token[0]);
274 inodes = atoi(token[1]);
276 /* Process mode line for root directory. */
277 getline(line, token);
278 mode = mode_con(token[0]);
279 usrid = atoi(token[1]);
280 grpid = atoi(token[2]);
282 if(blocks <= 0 && inodes <= 0){
283 detect_fs_size();
284 blocks = blockcount;
285 inodes = inocount;
286 blocks += blocks*extra_space_percent/100;
287 inodes += inodes*extra_space_percent/100;
288 printf("dynamically sized filesystem: %d blocks, %d inodes\n", blocks,
289 (unsigned int) inodes);
291 } else {
292 lct = 0;
293 if (optind < argc) {
294 /* Maybe the prototype file is just a size. Check. */
295 blocks = strtoul(optarg, (char **) NULL, 0);
296 if (blocks == 0) pexit("Can't open prototype file");
298 if (i == 0) {
299 #if defined(__minix)
300 uint32_t kb = div64u(mul64u(blocks, block_size), 1024);
301 #else
302 uint32_t kb = ((unsigned long long) blocks * block_size) / 1024;
303 #endif
304 i = kb / 2;
305 if (kb >= 100000) i = kb / 4;
307 /* round up to fill inode block */
308 i += inodes_per_block - 1;
309 i = i / inodes_per_block * inodes_per_block;
311 if (blocks < 5) pexit("Block count too small");
312 if (i < 1) pexit("Inode count too small");
313 inodes = (ino_t) i;
315 /* Make simple file system of the given size, using defaults. */
316 mode = 040777;
317 usrid = BIN;
318 grpid = BINGRP;
319 simple = 1;
322 nrblocks = blocks;
323 nrinodes = inodes;
326 size_t bytes;
327 bytes = 1 + blocks/8;
328 if(!(umap_array = malloc(bytes))) {
329 fprintf(stderr, "mkfs: can't allocate block bitmap (%u bytes).\n",
330 bytes);
331 exit(1);
333 umap_array_elements = bytes;
336 /* Open special. */
337 special(argv[--optind]);
339 #ifdef UNIX
340 if (!donttest) {
341 short *testb;
342 ssize_t w;
344 testb = (short *) alloc_block();
346 /* Try writing the last block of partition or diskette. */
347 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
348 pexit("couldn't seek to last block to test size (1)");
350 testb[0] = 0x3245;
351 testb[1] = 0x11FF;
352 testb[block_size/2-1] = 0x1F2F;
353 if ((w=write(fd, (char *) testb, block_size)) != block_size) {
354 if(w < 0) perror("write");
355 printf("%d/%u\n", w, block_size);
356 pexit("File system is too big for minor device (write)");
358 sync(); /* flush write, so if error next read fails */
359 if(lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL) < 0) {
360 pexit("couldn't seek to last block to test size (2)");
362 testb[0] = 0;
363 testb[1] = 0;
364 nread = read(fd, (char *) testb, block_size);
365 if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
366 testb[block_size/2-1] != 0x1F2F) {
367 if(nread < 0) perror("read");
368 printf("nread = %d\n", nread);
369 printf("testb = 0x%x 0x%x 0x%x\n", testb[0], testb[1], testb[block_size-1]);
370 pexit("File system is too big for minor device (read)");
372 lseek64(fd, mul64u(blocks - 1, block_size), SEEK_SET, NULL);
373 testb[0] = 0;
374 testb[1] = 0;
375 if (write(fd, (char *) testb, block_size) != block_size)
376 pexit("File system is too big for minor device (write2)");
377 lseek(fd, 0L, SEEK_SET);
378 free(testb);
380 #endif
382 /* Make the file-system */
384 cache_init();
386 put_block((block_t) 0, zero); /* Write a null boot block. */
388 zones = nrblocks >> zone_shift;
390 super(zones, inodes);
392 root_inum = alloc_inode(mode, usrid, grpid);
393 rootdir(root_inum);
394 if (simple == 0) eat_dir(root_inum);
396 if (print) print_fs();
397 flush();
398 return(0);
400 /* NOTREACHED */
401 } /* end main */
403 /*================================================================
404 * detect_fs_size - determine image size dynamically
405 *===============================================================*/
406 void detect_fs_size()
408 uint32_t point = ftell(proto);
410 inocount = 1; /* root directory node */
411 zonecount = 0;
412 blockcount = 0;
413 sizeup_dir();
415 uint32_t initb;
417 initb = bitmapsize((uint32_t) (1 + inocount), block_size);
418 initb += bitmapsize((uint32_t) zonecount, block_size);
419 initb += START_BLOCK;
420 initb += (inocount + inodes_per_block - 1) / inodes_per_block;
421 initb = (initb + (1 << zone_shift) - 1) >> zone_shift;
423 blockcount = initb+zonecount*zone_size;
424 fseek(proto, point, SEEK_SET);
427 void sizeup_dir()
429 char *token[MAX_TOKENS], *p;
430 char line[LINE_LEN];
431 FILE *f;
432 size_t size;
433 int dir_entries = 2;
434 zone_t dir_zones = 0;
435 zone_t nr_dzones;
437 nr_dzones = V2_NR_DZONES;
439 while (1) {
440 getline(line, token);
441 p = token[0];
442 if (*p == '$') {
443 dir_zones = (dir_entries / (NR_DIR_ENTRIES(block_size) * zone_size));
444 if(dir_entries % (NR_DIR_ENTRIES(block_size) * zone_size))
445 dir_zones++;
446 /* Assumes directory fits in direct blocks */
447 zonecount += dir_zones;
448 return;
451 p = token[1];
452 inocount++;
453 dir_entries++;
455 if (*p == 'd') {
456 sizeup_dir();
457 } else if (*p == 'b' || *p == 'c') {
459 } else if (*p == 's') {
460 zonecount++; /* Symlink contents is always stored a block */
461 } else {
462 if ((f = fopen(token[4], "r")) == NULL) {
463 fprintf(stderr, "%s: Can't open %s: %s\n",
464 progname, token[4], strerror(errno));
465 pexit("dynamic size detection failed");
466 } else {
467 if (fseek(f, 0, SEEK_END) < 0) {
468 fprintf(stderr, "%s: Can't seek to end of %s\n",
469 progname, token[4]);
470 pexit("dynamic size detection failed");
472 size = ftell(f);
473 fclose(f);
474 zone_t fzones= (size / (zone_size * block_size));
475 if (size % (zone_size * block_size))
476 fzones++;
477 if (fzones > nr_dzones)
478 fzones++; /* Assumes files fit within single indirect */
479 zonecount += fzones;
485 /*================================================================
486 * sizeup - determine device size
487 *===============================================================*/
488 block_t sizeup(device)
489 char *device;
491 block_t d;
492 #if defined(__minix)
493 u64_t bytes, resize;
494 u32_t rem;
495 #else
496 off_t size;
497 #endif
500 if ((fd = open(device, O_RDONLY)) == -1) {
501 if (errno != ENOENT)
502 perror("sizeup open");
503 return 0;
506 #if defined(__minix)
507 if(minix_sizeup(device, &bytes) < 0) {
508 perror("sizeup");
509 return 0;
512 d = div64u(bytes, block_size);
513 rem = rem64u(bytes, block_size);
515 resize = add64u(mul64u(d, block_size), rem);
516 if(cmp64(resize, bytes) != 0) {
517 d = ULONG_MAX;
518 fprintf(stderr, "mkfs: truncating FS at %u blocks\n", d);
520 #else
521 size = lseek(fd, 0, SEEK_END);
522 if (size == (off_t) -1) {
523 fprintf(stderr, "Cannot get device size fd=%d\n", fd);
524 exit(-1);
526 d = size / block_size;
527 #endif
529 return d;
533 * copied from fslib
535 static int bitmapsize(nr_bits, block_size)
536 uint32_t nr_bits;
537 size_t block_size;
539 block_t nr_blocks;
541 nr_blocks = (int) (nr_bits / FS_BITS_PER_BLOCK(block_size));
542 if (((uint32_t) nr_blocks * FS_BITS_PER_BLOCK(block_size)) < nr_bits) ++nr_blocks;
543 return(nr_blocks);
546 /*================================================================
547 * super - construct a superblock
548 *===============================================================*/
550 void super(zones, inodes)
551 zone_t zones;
552 ino_t inodes;
554 unsigned int i;
555 int inodeblks;
556 int initblks;
557 uint32_t nb;
558 zone_t v2sq;
559 zone_t zo;
560 struct super_block *sup;
561 char *buf, *cp;
563 buf = alloc_block();
565 for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
566 sup = (struct super_block *) buf; /* lint - might use a union */
568 /* The assumption is that mkfs will create a clean FS. */
569 sup->s_flags = MFSFLAG_CLEAN;
571 sup->s_ninodes = inodes;
572 sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */
573 sup->s_zones = zones;
575 #define BIGGERBLOCKS "Please try a larger block size for an FS of this size.\n"
576 sup->s_imap_blocks = nb = bitmapsize((uint32_t) (1 + inodes), block_size);
577 if(sup->s_imap_blocks != nb) {
578 fprintf(stderr, "mkfs: too many inode bitmap blocks.\n" BIGGERBLOCKS);
579 exit(1);
581 sup->s_zmap_blocks = nb = bitmapsize((uint32_t) zones, block_size);
582 if(nb != sup->s_zmap_blocks) {
583 fprintf(stderr, "mkfs: too many block bitmap blocks.\n" BIGGERBLOCKS);
584 exit(1);
586 inode_offset = START_BLOCK + sup->s_imap_blocks + sup->s_zmap_blocks;
587 inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
588 initblks = inode_offset + inodeblks;
589 sup->s_firstdatazone_old = nb =
590 (initblks + (1 << zone_shift) - 1) >> zone_shift;
591 if(nb >= zones) pexit("bit maps too large");
592 if(nb != sup->s_firstdatazone_old) {
593 /* The field is too small to store the value. Fortunately, the value
594 * can be computed from other fields. We set the on-disk field to zero
595 * to indicate that it must not be used. Eventually, we can always set
596 * the on-disk field to zero, and stop using it.
598 sup->s_firstdatazone_old = 0;
600 sup->s_firstdatazone = nb;
601 zoff = sup->s_firstdatazone - 1;
602 sup->s_log_zone_size = zone_shift;
604 v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
605 zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
607 sup->s_magic = SUPER_V3;
608 sup->s_block_size = block_size;
609 sup->s_disk_version = 0;
610 #define MAX_MAX_SIZE (INT_MAX)
611 if(MAX_MAX_SIZE/block_size < zo) {
612 sup->s_max_size = (int32_t) MAX_MAX_SIZE;
614 else {
615 sup->s_max_size = zo * block_size;
620 if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
621 pexit("super() couldn't seek");
623 if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
624 pexit("super() couldn't write");
627 /* Clear maps and inodes. */
628 for (i = START_BLOCK; i < initblks; i++) put_block((block_t) i, zero);
630 next_zone = sup->s_firstdatazone;
631 next_inode = 1;
633 zone_map = INODE_MAP + sup->s_imap_blocks;
635 insert_bit(zone_map, 0); /* bit zero must always be allocated */
636 insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but
637 * must be allocated */
639 free(buf);
643 /*================================================================
644 * rootdir - install the root directory
645 *===============================================================*/
646 void rootdir(inode)
647 ino_t inode;
649 zone_t z;
651 z = alloc_zone();
652 add_zone(inode, z, 2 * sizeof(struct direct), current_time);
653 enter_dir(inode, ".", inode);
654 enter_dir(inode, "..", inode);
655 incr_link(inode);
656 incr_link(inode);
659 void enter_symlink(ino_t inode, char *link)
661 zone_t z;
662 char *buf;
664 buf = alloc_block();
665 z = alloc_zone();
666 strcpy(buf, link);
667 put_block((z << zone_shift), buf);
669 add_zone(inode, z, (size_t) strlen(link), current_time);
671 free(buf);
675 /*================================================================
676 * eat_dir - recursively install directory
677 *===============================================================*/
678 void eat_dir(parent)
679 ino_t parent;
681 /* Read prototype lines and set up directory. Recurse if need be. */
682 char *token[MAX_TOKENS], *p;
683 char line[LINE_LEN];
684 int mode, usrid, grpid, maj, min, f;
685 ino_t n;
686 zone_t z;
687 size_t size;
689 while (1) {
690 getline(line, token);
691 p = token[0];
692 if (*p == '$') return;
693 p = token[1];
694 mode = mode_con(p);
695 usrid = atoi(token[2]);
696 grpid = atoi(token[3]);
697 n = alloc_inode(mode, usrid, grpid);
699 /* Enter name in directory and update directory's size. */
700 enter_dir(parent, token[0], n);
701 incr_size(parent, sizeof(struct direct));
703 /* Check to see if file is directory or special. */
704 incr_link(n);
705 if (*p == 'd') {
706 /* This is a directory. */
707 z = alloc_zone(); /* zone for new directory */
708 add_zone(n, z, 2 * sizeof(struct direct), current_time);
709 enter_dir(n, ".", n);
710 enter_dir(n, "..", parent);
711 incr_link(parent);
712 incr_link(n);
713 eat_dir(n);
714 } else if (*p == 'b' || *p == 'c') {
715 /* Special file. */
716 maj = atoi(token[4]);
717 min = atoi(token[5]);
718 size = 0;
719 if (token[6]) size = atoi(token[6]);
720 size = block_size * size;
721 add_zone(n, (zone_t) (makedev(maj,min)), size, current_time);
722 } else if (*p == 's') {
723 enter_symlink(n, token[4]);
724 } else {
725 /* Regular file. Go read it. */
726 if ((f = open(token[4], O_RDONLY)) < 0) {
727 fprintf(stderr, "%s: Can't open %s: %s\n",
728 progname, token[4], strerror(errno));
729 } else {
730 eat_file(n, f);
737 /*================================================================
738 * eat_file - copy file to MINIX
739 *===============================================================*/
740 /* Zonesize >= blocksize */
741 void eat_file(inode, f)
742 ino_t inode;
743 int f;
745 int ct, i, j, k;
746 zone_t z;
747 char *buf;
748 uint32_t timeval;
750 buf = alloc_block();
752 do {
753 for (i = 0, j = 0; i < zone_size; i++, j += ct) {
754 for (k = 0; k < block_size; k++) buf[k] = 0;
755 if ((ct = read(f, buf, block_size)) > 0) {
756 if (i == 0) z = alloc_zone();
757 put_block((z << zone_shift) + i, buf);
760 timeval = (dflag ? current_time : file_time(f));
761 if (ct) add_zone(inode, z, (size_t) j, timeval);
762 } while (ct == block_size);
763 close(f);
764 free(buf);
767 d2_inode *get_inoblock(ino_t i, block_t *blockno, d2_inode **ino)
769 int off;
770 d2_inode *inoblock = alloc_block();
771 *blockno = ((i - 1) / inodes_per_block) + inode_offset;
772 off = (i - 1) % inodes_per_block;
773 get_block(*blockno, (char *) inoblock);
774 *ino = inoblock + off;
775 return inoblock;
778 /*================================================================
779 * directory & inode management assist group
780 *===============================================================*/
781 void enter_dir(parent, name, child)
782 ino_t parent, child;
783 char *name;
785 /* Enter child in parent directory */
786 /* Works for dir > 1 block and zone > block */
787 unsigned int i, j, k, l;
788 block_t b;
789 zone_t z;
790 char *p1, *p2;
791 struct direct *dir_entry = alloc_block();
792 d2_inode *ino;
793 d2_inode *inoblock = get_inoblock(parent, &b, &ino);
794 int nr_dzones;
796 assert(!(block_size % sizeof(struct direct)));
798 nr_dzones = V2_NR_DZONES;
799 for (k = 0; k < nr_dzones; k++) {
800 z = ino->d2_zone[k];
801 if (z == 0) {
802 z = alloc_zone();
803 ino->d2_zone[k] = z;
806 for (l = 0; l < zone_size; l++) {
807 get_block((z << zone_shift) + l, (char *) dir_entry);
808 for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) {
809 if (dir_entry[i].mfs_d_ino == 0) {
810 dir_entry[i].mfs_d_ino = child;
811 p1 = name;
812 p2 = dir_entry[i].mfs_d_name;
813 j = sizeof(dir_entry[i].mfs_d_name);
814 j = 60;
815 while (j--) {
816 *p2++ = *p1;
817 if (*p1 != 0) p1++;
819 put_block((z << zone_shift) + l, (char *) dir_entry);
820 put_block(b, (char *) inoblock);
821 free(dir_entry);
822 free(inoblock);
823 return;
829 printf("Directory-inode %lu beyond direct blocks. Could not enter %s\n",
830 parent, name);
831 pexit("Halt");
835 void add_zone(ino_t n, zone_t z, size_t bytes, uint32_t cur_time)
837 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
839 int off, i;
840 block_t b;
841 zone_t indir;
842 zone_t *blk;
843 d2_inode *p;
844 d2_inode *inode;
846 if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
847 pexit("Couldn't allocate indirect block");
849 if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
850 pexit("Couldn't allocate block of inodes");
852 b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
853 off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
854 get_block(b, (char *) inode);
855 p = &inode[off];
856 p->d2_size += bytes;
857 p->d2_mtime = cur_time;
858 for (i = 0; i < V2_NR_DZONES; i++)
859 if (p->d2_zone[i] == 0) {
860 p->d2_zone[i] = z;
861 put_block(b, (char *) inode);
862 free(blk);
863 free(inode);
864 return;
866 put_block(b, (char *) inode);
868 /* File has grown beyond a small file. */
869 if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
870 indir = p->d2_zone[V2_NR_DZONES];
871 put_block(b, (char *) inode);
872 b = indir << zone_shift;
873 get_block(b, (char *) blk);
874 for (i = 0; i < V2_INDIRECTS(block_size); i++)
875 if (blk[i] == 0) {
876 blk[i] = z;
877 put_block(b, (char *) blk);
878 free(blk);
879 free(inode);
880 return;
882 pexit("File has grown beyond single indirect");
886 void incr_link(n)
887 ino_t n;
889 /* Increment the link count to inode n */
890 int off;
891 static int enter = 0;
892 block_t b;
894 if(enter) exit(1);
896 b = ((n - 1) / inodes_per_block) + inode_offset;
897 off = (n - 1) % inodes_per_block;
899 static d2_inode *inode2 = NULL;
900 int n;
902 n = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
903 if(!inode2 && !(inode2 = malloc(n)))
904 pexit("couldn't allocate a block of inodes");
906 get_block(b, (char *) inode2);
907 inode2[off].d2_nlinks++;
908 put_block(b, (char *) inode2);
910 enter = 0;
914 void incr_size(n, count)
915 ino_t n;
916 size_t count;
918 /* Increment the file-size in inode n */
919 block_t b;
920 int off;
922 b = ((n - 1) / inodes_per_block) + inode_offset;
923 off = (n - 1) % inodes_per_block;
925 d2_inode *inode2;
926 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
927 pexit("couldn't allocate a block of inodes");
929 get_block(b, (char *) inode2);
930 inode2[off].d2_size += count;
931 put_block(b, (char *) inode2);
932 free(inode2);
937 /*================================================================
938 * allocation assist group
939 *===============================================================*/
940 static ino_t alloc_inode(mode, usrid, grpid)
941 int mode, usrid, grpid;
943 ino_t num;
944 int off;
945 block_t b;
947 num = next_inode++;
948 if (num > nrinodes) {
949 fprintf(stderr, "have %d inodoes\n", nrinodes);
950 pexit("File system does not have enough inodes");
952 b = ((num - 1) / inodes_per_block) + inode_offset;
953 off = (num - 1) % inodes_per_block;
955 d2_inode *inode2;
957 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
958 pexit("couldn't allocate a block of inodes");
960 get_block(b, (char *) inode2);
961 inode2[off].d2_mode = mode;
962 inode2[off].d2_uid = usrid;
963 inode2[off].d2_gid = grpid;
964 put_block(b, (char *) inode2);
966 free(inode2);
969 /* Set the bit in the bit map. */
970 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
971 insert_bit((block_t) INODE_MAP, (int) num);
972 return(num);
976 static zone_t alloc_zone()
978 /* Allocate a new zone */
979 /* Works for zone > block */
980 block_t b;
981 int i;
982 zone_t z;
984 z = next_zone++;
985 b = z << zone_shift;
986 if ((b + zone_size) > nrblocks)
987 pexit("File system not big enough for all the files");
988 for (i = 0; i < zone_size; i++)
989 put_block(b + i, zero); /* give an empty zone */
990 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
991 insert_bit(zone_map, (int) (z - zoff)); /* lint, NOT OK because
992 * z hasn't been broken
993 * up into block +
994 * offset yet. */
995 return(z);
999 void insert_bit(block, bit)
1000 block_t block;
1001 int bit;
1003 /* Insert 'count' bits in the bitmap */
1004 int w, s;
1005 #if defined(__minix)
1006 bitchunk_t *buf;
1007 #else
1008 uint32_t *buf;
1009 #endif
1011 #if defined(__minix)
1012 buf = (bitchunk_t *) alloc_block();
1013 #else
1014 buf = (uint32_t *) alloc_block();
1015 #endif
1017 get_block(block, (char *) buf);
1018 #if defined(__minix)
1019 w = bit / (8 * sizeof(bitchunk_t));
1020 s = bit % (8 * sizeof(bitchunk_t));
1021 #else
1022 w = bit / (8 * sizeof(uint32_t));
1023 s = bit % (8 * sizeof(uint32_t));
1024 #endif
1025 buf[w] |= (1 << s);
1026 put_block(block, (char *) buf);
1028 free(buf);
1032 /*================================================================
1033 * proto-file processing assist group
1034 *===============================================================*/
1035 int mode_con(p)
1036 char *p;
1038 /* Convert string to mode */
1039 int o1, o2, o3, mode;
1040 char c1, c2, c3;
1042 c1 = *p++;
1043 c2 = *p++;
1044 c3 = *p++;
1045 o1 = *p++ - '0';
1046 o2 = *p++ - '0';
1047 o3 = *p++ - '0';
1048 mode = (o1 << 6) | (o2 << 3) | o3;
1049 if (c1 == 'd') mode |= S_IFDIR;
1050 if (c1 == 'b') mode |= S_IFBLK;
1051 if (c1 == 'c') mode |= S_IFCHR;
1052 if (c1 == 's') mode |= S_IFLNK;
1053 if (c1 == '-') mode |= S_IFREG;
1054 if (c2 == 'u') mode |= S_ISUID;
1055 if (c3 == 'g') mode |= S_ISGID;
1056 return(mode);
1059 void getline(line, parse)
1060 char *parse[MAX_TOKENS];
1061 char line[LINE_LEN];
1063 /* Read a line and break it up in tokens */
1064 int k;
1065 char c, *p;
1066 int d;
1068 for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
1069 for (k = 0; k < LINE_LEN; k++) line[k] = 0;
1070 k = 0;
1071 parse[0] = 0;
1072 p = line;
1073 while (1) {
1074 if (++k > LINE_LEN) pexit("Line too long");
1075 d = fgetc(proto);
1076 if (d == EOF) pexit("Unexpected end-of-file");
1077 *p = d;
1078 if (*p == '\n') lct++;
1079 if (*p == ' ' || *p == '\t') *p = 0;
1080 if (*p == '\n') {
1081 *p++ = 0;
1082 *p = '\n';
1083 break;
1085 p++;
1088 k = 0;
1089 p = line;
1090 lastp = line;
1091 while (1) {
1092 c = *p++;
1093 if (c == '\n') return;
1094 if (c == 0) continue;
1095 parse[k++] = p - 1;
1096 do {
1097 c = *p++;
1098 } while (c != 0 && c != '\n');
1103 /*================================================================
1104 * other stuff
1105 *===============================================================*/
1106 void check_mtab(device)
1107 char *device; /* /dev/hd1 or whatever */
1109 /* Check to see if the special file named in s is mounted. */
1110 #if defined(__minix)
1111 int n, r;
1112 struct stat sb;
1113 char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
1115 r= stat(device, &sb);
1116 if (r == -1)
1118 if (errno == ENOENT)
1119 return; /* Does not exist, and therefore not mounted. */
1120 fprintf(stderr, "%s: stat %s failed: %s\n",
1121 progname, device, strerror(errno));
1122 exit(1);
1124 if (!S_ISBLK(sb.st_mode))
1126 /* Not a block device and therefore not mounted. */
1127 return;
1130 if (load_mtab("mkfs") < 0) return;
1131 while (1) {
1132 n = get_mtab_entry(special, mounted_on, version, rw_flag);
1133 if (n < 0) return;
1134 if (strcmp(device, special) == 0) {
1135 /* Can't mkfs on top of a mounted file system. */
1136 fprintf(stderr, "%s: %s is mounted on %s\n",
1137 progname, device, mounted_on);
1138 exit(1);
1141 #elif defined(__linux__)
1142 /* XXX: this code is copyright Theodore T'so and distributed under the GPLv2. Rewrite.
1144 struct mntent *mnt;
1145 struct stat st_buf;
1146 dev_t file_dev=0, file_rdev=0;
1147 ino_t file_ino=0;
1148 FILE *f;
1149 int fd;
1150 char *mtab_file = "/proc/mounts";
1152 if ((f = setmntent (mtab_file, "r")) == NULL)
1153 goto error;
1155 if (stat(device, &st_buf) == 0) {
1156 if (S_ISBLK(st_buf.st_mode)) {
1157 file_rdev = st_buf.st_rdev;
1158 } else {
1159 file_dev = st_buf.st_dev;
1160 file_ino = st_buf.st_ino;
1164 while ((mnt = getmntent (f)) != NULL) {
1165 if (strcmp(device, mnt->mnt_fsname) == 0)
1166 break;
1167 if (stat(mnt->mnt_fsname, &st_buf) == 0) {
1168 if (S_ISBLK(st_buf.st_mode)) {
1169 if (file_rdev && (file_rdev == st_buf.st_rdev))
1170 break;
1171 } else {
1172 if (file_dev && ((file_dev == st_buf.st_dev) &&
1173 (file_ino == st_buf.st_ino)))
1174 break;
1179 if (mnt == NULL) {
1181 * Do an extra check to see if this is the root device. We
1182 * can't trust /etc/mtab, and /proc/mounts will only list
1183 * /dev/root for the root filesystem. Argh. Instead we
1184 * check if the given device has the same major/minor number
1185 * as the device that the root directory is on.
1187 if (file_rdev && stat("/", &st_buf) == 0) {
1188 if (st_buf.st_dev == file_rdev) {
1189 goto is_root;
1192 goto test_busy;
1194 /* Validate the entry in case /etc/mtab is out of date */
1196 * We need to be paranoid, because some broken distributions
1197 * (read: Slackware) don't initialize /etc/mtab before checking
1198 * all of the non-root filesystems on the disk.
1200 if (stat(mnt->mnt_dir, &st_buf) < 0) {
1201 if (errno == ENOENT) {
1202 goto test_busy;
1204 goto error;
1206 if (file_rdev && (st_buf.st_dev != file_rdev)) {
1207 goto error;
1210 fprintf(stderr, "Device %s is mounted, exiting\n", device);
1211 exit(-1);
1214 * Check to see if we're referring to the root filesystem.
1215 * If so, do a manual check to see if we can open /etc/mtab
1216 * read/write, since if the root is mounted read/only, the
1217 * contents of /etc/mtab may not be accurate.
1219 if (!strcmp(mnt->mnt_dir, "/")) {
1220 is_root:
1221 fprintf(stderr, "Device %s is mounted as root file system!\n",
1222 device);
1223 exit(-1);
1226 test_busy:
1228 endmntent (f);
1229 if ((stat(device, &st_buf) != 0) ||
1230 !S_ISBLK(st_buf.st_mode))
1231 return;
1232 fd = open(device, O_RDONLY | O_EXCL);
1233 if (fd < 0) {
1234 if (errno == EBUSY) {
1235 fprintf(stderr, "Device %s is used by the system\n", device);
1236 exit(-1);
1238 } else
1239 close(fd);
1241 return;
1243 error:
1244 endmntent (f);
1245 fprintf(stderr, "Error while checking if device %s is mounted\n", device);
1246 exit(-1);
1247 #endif
1251 uint32_t file_time(f)
1252 int f;
1254 #ifdef UNIX
1255 struct stat statbuf;
1256 fstat(f, &statbuf);
1257 return(statbuf.st_mtime);
1258 #else /* fstat not supported by DOS */
1259 return(0L);
1260 #endif
1264 void pexit(s)
1265 char *s;
1267 fprintf(stderr, "%s: %s\n", progname, s);
1268 if (lct != 0)
1269 fprintf(stderr, "Line %d being processed when error detected.\n", lct);
1270 flush();
1271 exit(2);
1275 void copy(from, to, count)
1276 char *from, *to;
1277 size_t count;
1279 while (count--) *to++ = *from++;
1282 void *alloc_block()
1284 char *buf;
1286 if(!(buf = malloc(block_size))) {
1287 pexit("couldn't allocate filesystem buffer");
1289 bzero(buf, block_size);
1291 return buf;
1294 void print_fs()
1296 int i, j;
1297 ino_t k;
1298 d2_inode *inode2;
1299 unsigned short *usbuf;
1300 block_t b;
1301 struct direct *dir;
1303 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
1304 pexit("couldn't allocate a block of inodes");
1306 if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
1307 pexit("malloc of directory entry failed");
1309 usbuf = (unsigned short *) alloc_block();
1311 get_super_block((char *) usbuf);
1312 printf("\nSuperblock: ");
1313 for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
1314 get_block((block_t) 2, (char *) usbuf);
1315 printf("...\nInode map: ");
1316 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1317 get_block((block_t) 3, (char *) usbuf);
1318 printf("...\nZone map: ");
1319 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1320 printf("...\n");
1322 free(usbuf);
1323 usbuf = NULL;
1325 k = 0;
1326 for (b = inode_offset; k < nrinodes; b++) {
1327 get_block(b, (char *) inode2);
1328 for (i = 0; i < inodes_per_block; i++) {
1329 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
1330 /* Lint but OK */
1331 if (k > nrinodes) break;
1333 if (inode2[i].d2_mode != 0) {
1334 printf("Inode %2lu: mode=", k);
1335 printf("%06o", inode2[i].d2_mode);
1336 printf(" uid=%2d gid=%2d size=",
1337 inode2[i].d2_uid, inode2[i].d2_gid);
1338 printf("%6d", inode2[i].d2_size);
1339 printf(" zone[0]=%u\n", inode2[i].d2_zone[0]);
1341 if ((inode2[i].d2_mode & S_IFMT) == S_IFDIR) {
1342 /* This is a directory */
1343 get_block(inode2[i].d2_zone[0], (char *) dir);
1344 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1345 if (dir[j].mfs_d_ino)
1346 printf("\tInode %2u: %s\n", dir[j].mfs_d_ino, dir[j].mfs_d_name);
1352 printf("%d inodes used. %d zones used.\n", next_inode - 1, next_zone);
1353 free(dir);
1354 free(inode2);
1358 int read_and_set(n)
1359 block_t n;
1361 /* The first time a block is read, it returns all 0s, unless there has
1362 * been a write. This routine checks to see if a block has been accessed.
1365 int w, s, mask, r;
1367 w = n / 8;
1368 if(w >= umap_array_elements) {
1369 pexit("umap array too small - this can't happen");
1371 s = n % 8;
1372 mask = 1 << s;
1373 r = (umap_array[w] & mask ? 1 : 0);
1374 umap_array[w] |= mask;
1375 return(r);
1378 void usage()
1380 fprintf(stderr,
1381 "Usage: %s [-12dlot] [-b blocks] [-i inodes]\n"
1382 "\t[-x extra] [-B blocksize] special [proto]\n",
1383 progname);
1384 exit(1);
1387 /*================================================================
1388 * get_block & put_block for MS-DOS
1389 *===============================================================*/
1390 #ifdef DOS
1393 * These are the get_block and put_block routines
1394 * when compiling & running mkfs.c under MS-DOS.
1396 * It requires the (asembler) routines absread & abswrite
1397 * from the file diskio.asm. Since these routines just do
1398 * as they are told (read & write the sector specified),
1399 * a local cache is used to minimize the i/o-overhead for
1400 * frequently used blocks.
1402 * The global variable "file" determines whether the output
1403 * is to a disk-device or to a binary file.
1407 #define PH_SECTSIZE 512 /* size of a physical disk-sector */
1410 char *derrtab[14] = {
1411 "no error",
1412 "disk is read-only",
1413 "unknown unit",
1414 "device not ready",
1415 "bad command",
1416 "data error",
1417 "internal error: bad request structure length",
1418 "seek error",
1419 "unknown media type",
1420 "sector not found",
1421 "printer out of paper (?)",
1422 "write fault",
1423 "read error",
1424 "general error"
1427 #define CACHE_SIZE 20 /* 20 block-buffers */
1430 struct cache {
1431 char blockbuf[BLOCK_SIZE];
1432 block_t blocknum;
1433 int dirty;
1434 int usecnt;
1435 } cache[CACHE_SIZE];
1438 void special(string)
1439 char *string;
1442 if (string[1] == ':' && string[2] == 0) {
1443 /* Format: d: or d:fname */
1444 disk = (string[0] & ~32) - 'A';
1445 if (disk > 1 && !override) /* safety precaution */
1446 pexit("Bad drive specifier for special");
1447 } else {
1448 file = 1;
1449 if ((fd = creat(string, BWRITE)) == 0)
1450 pexit("Can't open special file");
1454 void get_block(n, buf)
1455 block_t n;
1456 char *buf;
1458 /* Get a block to the user */
1459 struct cache *bp, *fp;
1461 /* First access returns a zero block */
1462 if (read_and_set(n) == 0) {
1463 copy(zero, buf, block_size);
1464 return;
1467 /* Look for block in cache */
1468 fp = 0;
1469 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1470 if (bp->blocknum == n) {
1471 copy(bp, buf, block_size);
1472 bp->usecnt++;
1473 return;
1476 /* Remember clean block */
1477 if (bp->dirty == 0)
1478 if (fp) {
1479 if (fp->usecnt > bp->usecnt) fp = bp;
1480 } else
1481 fp = bp;
1484 /* Block not in cache, get it */
1485 if (!fp) {
1486 /* No clean buf, flush one */
1487 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1488 if (fp->usecnt > bp->usecnt) fp = bp;
1489 mx_write(fp->blocknum, fp);
1491 mx_read(n, fp);
1492 fp->dirty = 0;
1493 fp->usecnt = 0;
1494 fp->blocknum = n;
1495 copy(fp, buf, block_size);
1498 void put_block(n, buf)
1499 block_t n;
1500 char *buf;
1502 /* Accept block from user */
1503 struct cache *fp, *bp;
1505 (void) read_and_set(n);
1507 /* Look for block in cache */
1508 fp = 0;
1509 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1510 if (bp->blocknum == n) {
1511 copy(buf, bp, block_size);
1512 bp->dirty = 1;
1513 return;
1516 /* Remember clean block */
1517 if (bp->dirty == 0)
1518 if (fp) {
1519 if (fp->usecnt > bp->usecnt) fp = bp;
1520 } else
1521 fp = bp;
1524 /* Block not in cache */
1525 if (!fp) {
1526 /* No clean buf, flush one */
1527 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1528 if (fp->usecnt > bp->usecnt) fp = bp;
1529 mx_write(fp->blocknum, fp);
1531 fp->dirty = 1;
1532 fp->usecnt = 1;
1533 fp->blocknum = n;
1534 copy(buf, fp, block_size);
1537 void cache_init()
1539 struct cache *bp;
1540 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
1543 void flush()
1545 /* Flush all dirty blocks to disk */
1546 struct cache *bp;
1548 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
1549 if (bp->dirty) {
1550 mx_write(bp->blocknum, bp);
1551 bp->dirty = 0;
1555 /*==================================================================
1556 * hard read & write etc.
1557 *=================================================================*/
1558 #define MAX_RETRIES 5
1561 void mx_read(blocknr, buf)
1562 int blocknr;
1563 char *buf;
1566 /* Read the requested MINIX-block in core */
1567 char (*bp)[PH_SECTSIZE];
1568 int sectnum, retries, err;
1570 if (file) {
1571 lseek(fd, (off_t) blocknr * block_size, 0);
1572 if (read(fd, buf, block_size) != block_size)
1573 pexit("mx_read: error reading file");
1574 } else {
1575 sectnum = blocknr * (block_size / PH_SECTSIZE);
1576 for (bp = buf; bp < &buf[block_size]; bp++) {
1577 retries = MAX_RETRIES;
1579 err = absread(disk, sectnum, bp);
1580 while (err && --retries);
1582 if (retries) {
1583 sectnum++;
1584 } else {
1585 dexit("mx_read", sectnum, err);
1591 void mx_write(blocknr, buf)
1592 int blocknr;
1593 char *buf;
1595 /* Write the MINIX-block to disk */
1596 char (*bp)[PH_SECTSIZE];
1597 int retries, sectnum, err;
1599 if (file) {
1600 lseek(fd, blocknr * block_size, 0);
1601 if (write(fd, buf, block_size) != block_size) {
1602 pexit("mx_write: error writing file");
1604 } else {
1605 sectnum = blocknr * (block_size / PH_SECTSIZE);
1606 for (bp = buf; bp < &buf[block_size]; bp++) {
1607 retries = MAX_RETRIES;
1608 do {
1609 err = abswrite(disk, sectnum, bp);
1610 } while (err && --retries);
1612 if (retries) {
1613 sectnum++;
1614 } else {
1615 dexit("mx_write", sectnum, err);
1622 void dexit(s, sectnum, err)
1623 int sectnum, err;
1624 char *s;
1626 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1627 s, sectnum, err, derrtab[err]);
1628 exit(2);
1631 #endif
1633 /*================================================================
1634 * get_block & put_block for UNIX
1635 *===============================================================*/
1636 #ifdef UNIX
1638 void special(string)
1639 char *string;
1641 fd = creat(string, 0777);
1642 close(fd);
1643 fd = open(string, O_RDWR);
1644 if (fd < 0) pexit("Can't open special file");
1649 void get_block(n, buf)
1650 block_t n;
1651 char *buf;
1653 /* Read a block. */
1655 int k;
1657 /* First access returns a zero block */
1658 if (read_and_set(n) == 0) {
1659 copy(zero, buf, block_size);
1660 return;
1662 lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL);
1663 k = read(fd, buf, block_size);
1664 if (k != block_size) {
1665 pexit("get_block couldn't read");
1669 void get_super_block(buf)
1670 char *buf;
1672 /* Read a block. */
1674 int k;
1676 if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
1677 perror("lseek");
1678 pexit("seek failed");
1680 k = read(fd, buf, _STATIC_BLOCK_SIZE);
1681 if (k != _STATIC_BLOCK_SIZE) {
1682 pexit("get_super_block couldn't read");
1686 void put_block(n, buf)
1687 block_t n;
1688 char *buf;
1690 /* Write a block. */
1692 (void) read_and_set(n);
1694 /* XXX - check other lseeks too. */
1695 if (lseek64(fd, mul64u(n, block_size), SEEK_SET, NULL) == (off_t) -1) {
1696 pexit("put_block couldn't seek");
1698 if (write(fd, buf, block_size) != block_size) {
1699 pexit("put_block couldn't write");
1704 /* Dummy routines to keep source file clean from #ifdefs */
1706 void flush()
1708 return;
1711 void cache_init()
1713 return;
1716 #endif