source: trunk/minix/commands/simple/mkfs.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 38.6 KB
Line 
1/* mkfs - make the MINIX filesystem Authors: Tanenbaum et al. */
2
3/* Authors: Andy Tanenbaum, Paul Ogilvie, Frans Meulenbroeks, Bruce Evans
4 *
5 * This program can make both version 1 and version 2 file systems, as follows:
6 * mkfs /dev/fd0 1200 # Version 2 (default)
7 * mkfs -1 /dev/fd0 360 # Version 1
8 *
9 */
10
11#include <sys/types.h>
12#include <sys/dir.h>
13#include <sys/stat.h>
14#include <stdio.h>
15#include <errno.h>
16#include <fcntl.h>
17#include <limits.h>
18#include <stdlib.h>
19#include <string.h>
20#include <time.h>
21#include <unistd.h>
22#include <minix/config.h>
23#include <minix/const.h>
24#include <minix/type.h>
25#include <minix/minlib.h>
26#include "../../servers/fs/const.h"
27#if (MACHINE == IBM_PC)
28#include <minix/partition.h>
29#include <minix/u64.h>
30#include <sys/ioctl.h>
31#endif
32#include <a.out.h>
33#include <tools.h>
34#include <dirent.h>
35
36#undef EXTERN
37#define EXTERN /* get rid of EXTERN by making it null */
38#include "../../servers/fs/type.h"
39#include "../../servers/fs/super.h"
40#include <minix/fslib.h>
41
42#ifndef max
43#define max(a,b) ((a) > (b) ? (a) : (b))
44#endif
45
46#ifndef DOS
47#ifndef UNIX
48#define UNIX
49#endif
50#endif
51
52#define INODE_MAP 2
53#define MAX_TOKENS 10
54#define LINE_LEN 200
55#define BIN 2
56#define BINGRP 2
57#define BIT_MAP_SHIFT 13
58#define N_BLOCKS MAX_BLOCK_NR
59#define N_BLOCKS16 (128L * 1024)
60#define INODE_MAX ((unsigned) 65535)
61
62/* You can make a really large file system on a 16-bit system, but the array
63 * of bits that get_block()/putblock() needs gets a bit big, so we can only
64 * prefill MAX_INIT blocks. (16-bit fsck can't check a file system larger
65 * than N_BLOCKS16 anyway.)
66 */
67#define MAX_INIT (sizeof(char *) == 2 ? N_BLOCKS16 : N_BLOCKS)
68
69
70#ifdef DOS
71maybedefine O_RDONLY 4 /* O_RDONLY | BINARY_BIT */
72 maybedefine BWRITE 5 /* O_WRONLY | BINARY_BIT */
73#endif
74
75#if (MACHINE == ATARI)
76int isdev;
77#endif
78
79extern char *optarg;
80extern int optind;
81
82int next_zone, next_inode, zone_size, zone_shift = 0, zoff;
83block_t nrblocks;
84int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
85unsigned int nrinodes;
86int override = 0, simple = 0, dflag;
87int donttest; /* skip test if it fits on medium */
88char *progname;
89
90long current_time, bin_time;
91char *zero, *lastp;
92char umap[MAX_INIT / 8]; /* bit map tells if block read yet */
93block_t zone_map; /* where is zone map? (depends on # inodes) */
94int inodes_per_block;
95int fs_version;
96unsigned int block_size;
97block_t max_nrblocks;
98
99FILE *proto;
100
101_PROTOTYPE(int main, (int argc, char **argv));
102_PROTOTYPE(block_t sizeup, (char *device));
103_PROTOTYPE(void super, (zone_t zones, Ino_t inodes));
104_PROTOTYPE(void rootdir, (Ino_t inode));
105_PROTOTYPE(void eat_dir, (Ino_t parent));
106_PROTOTYPE(void eat_file, (Ino_t inode, int f));
107_PROTOTYPE(void enter_dir, (Ino_t parent, char *name, Ino_t child));
108_PROTOTYPE(void incr_size, (Ino_t n, long count));
109_PROTOTYPE(PRIVATE ino_t alloc_inode, (int mode, int usrid, int grpid));
110_PROTOTYPE(PRIVATE zone_t alloc_zone, (void));
111_PROTOTYPE(void add_zone, (Ino_t n, zone_t z, long bytes, long cur_time));
112_PROTOTYPE(void add_z_1, (Ino_t n, zone_t z, long bytes, long cur_time));
113_PROTOTYPE(void add_z_2, (Ino_t n, zone_t z, long bytes, long cur_time));
114_PROTOTYPE(void incr_link, (Ino_t n));
115_PROTOTYPE(void insert_bit, (block_t block, int bit));
116_PROTOTYPE(int mode_con, (char *p));
117_PROTOTYPE(void getline, (char line[LINE_LEN], char *parse[MAX_TOKENS]));
118_PROTOTYPE(void check_mtab, (char *devname));
119_PROTOTYPE(long file_time, (int f));
120_PROTOTYPE(void pexit, (char *s));
121_PROTOTYPE(void copy, (char *from, char *to, int count));
122_PROTOTYPE(void print_fs, (void));
123_PROTOTYPE(int read_and_set, (block_t n));
124_PROTOTYPE(void special, (char *string));
125_PROTOTYPE(void get_block, (block_t n, char *buf));
126_PROTOTYPE(void get_super_block, (char *buf));
127_PROTOTYPE(void put_block, (block_t n, char *buf));
128_PROTOTYPE(void cache_init, (void));
129_PROTOTYPE(void flush, (void));
130_PROTOTYPE(void mx_read, (int blocknr, char *buf));
131_PROTOTYPE(void mx_write, (int blocknr, char *buf));
132_PROTOTYPE(void dexit, (char *s, int sectnum, int err));
133_PROTOTYPE(void usage, (void));
134_PROTOTYPE(char *alloc_block, (void));
135
136/*================================================================
137 * mkfs - make filesystem
138 *===============================================================*/
139int main(argc, argv)
140int argc;
141char *argv[];
142{
143 int nread, mode, usrid, grpid, ch;
144 block_t blocks, maxblocks;
145 block_t i;
146 ino_t root_inum;
147 ino_t inodes;
148 zone_t zones;
149 char *token[MAX_TOKENS], line[LINE_LEN];
150 struct stat statbuf;
151
152 /* Get two times, the current time and the mod time of the binary of
153 * mkfs itself. When the -d flag is used, the later time is put into
154 * the i_mtimes of all the files. This feature is useful when
155 * producing a set of file systems, and one wants all the times to be
156 * identical. First you set the time of the mkfs binary to what you
157 * want, then go.
158 */
159 current_time = time((time_t *) 0); /* time mkfs is being run */
160 stat(argv[0], &statbuf);
161 bin_time = statbuf.st_mtime; /* time when mkfs binary was last modified */
162
163 /* Process switches. */
164 progname = argv[0];
165 blocks = 0;
166 i = 0;
167 fs_version = 3;
168 inodes_per_block = 0;
169 max_nrblocks = N_BLOCKS;
170 block_size = 0;
171 while ((ch = getopt(argc, argv, "12b:di:lotB:")) != EOF)
172 switch (ch) {
173 case '1':
174 fs_version = 1;
175 inodes_per_block = V1_INODES_PER_BLOCK;
176 max_nrblocks = 0xFFFF;
177 break;
178 case '2':
179 fs_version = 2;
180 break;
181 case 'b':
182 blocks = strtoul(optarg, (char **) NULL, 0);
183 break;
184 case 'd':
185 dflag = 1;
186 current_time = bin_time;
187 break;
188 case 'i':
189 i = strtoul(optarg, (char **) NULL, 0);
190 break;
191 case 'l': print = 1; break;
192 case 'o': override = 1; break;
193 case 't': donttest = 1; break;
194 case 'B': block_size = atoi(optarg); break;
195 default: usage();
196 }
197
198 if(fs_version == 3) {
199 if(!block_size) block_size = _MAX_BLOCK_SIZE; /* V3 default block size */
200 if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
201 fprintf(stderr, "block size must be multiple of sector (%d) "
202 "and at least %d bytes\n",
203 SECTOR_SIZE, _MIN_BLOCK_SIZE);
204 pexit("specified block size illegal");
205 }
206 if(block_size%V2_INODE_SIZE) {
207 fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
208 V2_INODE_SIZE);
209 pexit("specified block size illegal");
210 }
211 } else {
212 if(block_size) {
213 pexit("Can't specify a block size if FS version is <3");
214 }
215 block_size = _STATIC_BLOCK_SIZE; /* V1/V2 block size */
216 }
217
218 if(!inodes_per_block)
219 inodes_per_block = V2_INODES_PER_BLOCK(block_size);
220
221 /* now that the block size is known, do buffer allocations where
222 * possible.
223 */
224 zero = alloc_block();
225 bzero(zero, block_size);
226
227 /* Determine the size of the device if not specified as -b or proto. */
228 maxblocks = sizeup(argv[optind]);
229 if (argc - optind == 1 && blocks == 0) {
230 blocks = maxblocks;
231 /* blocks == 0 is checked later, but leads to a funny way of
232 * reporting a 0-sized device (displays usage).
233 */
234 if(blocks < 1) {
235 fprintf(stderr, "%s: this device can't hold a filesystem.\n",
236 progname);
237 return 1;
238 }
239 }
240
241 /* The remaining args must be 'special proto', or just 'special' if the
242 * no. of blocks has already been specified.
243 */
244 if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
245
246 if (blocks > maxblocks) {
247 fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
248 progname, argv[optind]);
249 return 1;
250 }
251
252 /* Check special. */
253 check_mtab(argv[optind]);
254
255 /* Check and start processing proto. */
256 optarg = argv[++optind];
257 if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
258 /* Prototype file is readable. */
259 lct = 1;
260 getline(line, token); /* skip boot block info */
261
262 /* Read the line with the block and inode counts. */
263 getline(line, token);
264 blocks = atol(token[0]);
265 if (blocks > max_nrblocks) pexit("Block count too large");
266 if (sizeof(char *) == 2 && blocks > N_BLOCKS16) {
267 fprintf(stderr,
268 "%s: warning: FS is larger than the %dM that fsck can check!\n",
269 progname, (int) (N_BLOCKS16 / (1024L * 1024)));
270 }
271 inodes = atoi(token[1]);
272
273 /* Process mode line for root directory. */
274 getline(line, token);
275 mode = mode_con(token[0]);
276 usrid = atoi(token[1]);
277 grpid = atoi(token[2]);
278 } else {
279 lct = 0;
280 if (optind < argc) {
281 /* Maybe the prototype file is just a size. Check. */
282 blocks = strtoul(optarg, (char **) NULL, 0);
283 if (blocks == 0) pexit("Can't open prototype file");
284 }
285 if (i == 0) {
286 int kb;
287 kb = blocks * (max(block_size,1024) / 1024);
288 /* The default for inodes is 2 blocks per kb, rounded up
289 * to fill an inode block. Above 20M, the average files are
290 * sure to be larger because it is hard to fill up 20M with
291 * tiny files, so reduce the default number of inodes. This
292 * default can always be overridden by using the '-i option.
293 */
294 i = kb / 2;
295 if (kb >= 20000) i = kb / 3;
296 if (kb >= 40000) i = kb / 4;
297 if (kb >= 60000) i = kb / 5;
298 if (kb >= 80000) i = kb / 6;
299 if (kb >= 100000) i = kb / 7;
300
301 /* round up to fill inode block */
302 i += inodes_per_block - 1;
303 i = i / inodes_per_block * inodes_per_block;
304 if (i > INODE_MAX && fs_version < 3) i = INODE_MAX;
305
306 }
307 if (blocks < 5) pexit("Block count too small");
308 if (blocks > max_nrblocks) pexit("Block count too large");
309 if (i < 1) pexit("Inode count too small");
310 if (i > INODE_MAX && fs_version < 3) pexit("Inode count too large");
311 inodes = (ino_t) i;
312
313 /* Make simple file system of the given size, using defaults. */
314 mode = 040777;
315 usrid = BIN;
316 grpid = BINGRP;
317 simple = 1;
318 }
319
320 if(ULONG_MAX / block_size <= blocks-1) {
321 fprintf(stderr, "Warning: too big for filesystem to currently\n");
322 fprintf(stderr, "run on (max 4GB), truncating.\n");
323 blocks = ULONG_MAX / block_size;
324 }
325
326 nrblocks = blocks;
327 nrinodes = inodes;
328
329 /* Open special. */
330 special(argv[--optind]);
331
332#ifdef UNIX
333 if (!donttest) {
334 short *testb;
335 ssize_t w;
336
337 testb = (short *) alloc_block();
338
339 /* Try writing the last block of partition or diskette. */
340 if(lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET) < 0) {
341 pexit("couldn't seek to last block to test size (1)");
342 }
343 testb[0] = 0x3245;
344 testb[1] = 0x11FF;
345 testb[block_size-1] = 0x1F2F;
346 if ((w=write(fd, (char *) testb, block_size)) != block_size) {
347 if(w < 0) perror("write");
348 printf("%d/%d\n", w, block_size);
349 pexit("File system is too big for minor device (write)");
350 }
351 sync(); /* flush write, so if error next read fails */
352 if(lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET) < 0) {
353 pexit("couldn't seek to last block to test size (2)");
354 }
355 testb[0] = 0;
356 testb[1] = 0;
357 nread = read(fd, (char *) testb, block_size);
358 if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
359 testb[block_size-1] != 0x1F2F) {
360 if(nread < 0) perror("read");
361 pexit("File system is too big for minor device (read)");
362 }
363 lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET);
364 testb[0] = 0;
365 testb[1] = 0;
366 if (write(fd, (char *) testb, block_size) != block_size)
367 pexit("File system is too big for minor device (write2)");
368 lseek(fd, 0L, SEEK_SET);
369 free(testb);
370 }
371#endif
372
373 /* Make the file-system */
374
375 cache_init();
376
377#if (MACHINE == ATARI)
378 if (isdev) {
379 char block0[BLOCK_SIZE];
380 get_block((block_t) 0, block0);
381 /* Need to read twice; first time gets an empty block */
382 get_block((block_t) 0, block0);
383 /* Zero parts of the boot block so the disk won't be
384 * recognized as a tos disk any more. */
385 block0[0] = block0[1] = 0; /* branch code to boot code */
386 strncpy(&block0[2], "MINIX ", (size_t) 6);
387 block0[16] = 0; /* number of FATS */
388 block0[17] = block0[18] = 0; /* number of dir entries */
389 block0[22] = block0[23] = 0; /* sectors/FAT */
390 bzero(&block0[30], 480);/* boot code */
391 put_block((block_t) 0, block0);
392 } else
393#endif
394
395 put_block((block_t) 0, zero); /* Write a null boot block. */
396
397 zone_shift = 0; /* for future use */
398 zones = nrblocks >> zone_shift;
399
400 super(zones, inodes);
401
402 root_inum = alloc_inode(mode, usrid, grpid);
403 rootdir(root_inum);
404 if (simple == 0) eat_dir(root_inum);
405
406 if (print) print_fs();
407 flush();
408 return(0);
409
410 /* NOTREACHED */
411} /* end main */
412
413
414/*================================================================
415 * sizeup - determine device size
416 *===============================================================*/
417block_t sizeup(device)
418char *device;
419{
420 int fd;
421 struct partition entry;
422 block_t d;
423 struct stat st;
424
425 if ((fd = open(device, O_RDONLY)) == -1) {
426 if (errno != ENOENT)
427 perror("sizeup open");
428 return 0;
429 }
430 if (ioctl(fd, DIOCGETP, &entry) == -1) {
431 perror("sizeup ioctl");
432 if(fstat(fd, &st) < 0) {
433 perror("fstat");
434 entry.size = cvu64(0);
435 } else {
436 fprintf(stderr, "used fstat instead\n");
437 entry.size = cvu64(st.st_size);
438 }
439 }
440 close(fd);
441 d = div64u(entry.size, block_size);
442 return d;
443}
444
445
446/*================================================================
447 * super - construct a superblock
448 *===============================================================*/
449
450void super(zones, inodes)
451zone_t zones;
452ino_t inodes;
453{
454 unsigned int i;
455 int inodeblks;
456 int initblks;
457
458 zone_t initzones, nrzones, v1sq, v2sq;
459 zone_t zo;
460 struct super_block *sup;
461 char *buf, *cp;
462
463 buf = alloc_block();
464
465 for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
466 sup = (struct super_block *) buf; /* lint - might use a union */
467
468 sup->s_ninodes = inodes;
469 if (fs_version == 1) {
470 sup->s_nzones = zones;
471 } else {
472 sup->s_nzones = 0; /* not used in V2 - 0 forces errors early */
473 sup->s_zones = zones;
474 }
475 sup->s_imap_blocks = bitmapsize((bit_t) (1 + inodes), block_size);
476 sup->s_zmap_blocks = bitmapsize((bit_t) zones, block_size);
477 inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2;
478 inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
479 initblks = inode_offset + inodeblks;
480 initzones = (initblks + (1 << zone_shift) - 1) >> zone_shift;
481 nrzones = nrblocks >> zone_shift;
482 sup->s_firstdatazone = (initblks + (1 << zone_shift) - 1) >> zone_shift;
483 zoff = sup->s_firstdatazone - 1;
484 sup->s_log_zone_size = zone_shift;
485 if (fs_version == 1) {
486 sup->s_magic = SUPER_MAGIC; /* identify super blocks */
487 v1sq = (zone_t) V1_INDIRECTS * V1_INDIRECTS;
488 zo = V1_NR_DZONES + (long) V1_INDIRECTS + v1sq;
489 sup->s_max_size = zo * block_size;
490 } else {
491 v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
492 zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
493 if(fs_version == 2) {
494 sup->s_magic = SUPER_V2;/* identify super blocks */
495 sup->s_max_size = zo * block_size;
496 } else {
497 sup->s_magic = SUPER_V3;
498 sup->s_block_size = block_size;
499 sup->s_disk_version = 0;
500#define MAX_MAX_SIZE ((unsigned long) 0xffffffff)
501 if(MAX_MAX_SIZE/block_size < zo) {
502 sup->s_max_size = MAX_MAX_SIZE;
503 }
504 else {
505 sup->s_max_size = zo * block_size;
506 }
507 }
508 }
509
510 zone_size = 1 << zone_shift; /* nr of blocks per zone */
511
512 if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
513 pexit("super() couldn't seek");
514 }
515 if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
516 pexit("super() couldn't write");
517 }
518
519 /* Clear maps and inodes. */
520 for (i = 2; i < initblks; i++) put_block((block_t) i, zero);
521
522 next_zone = sup->s_firstdatazone;
523 next_inode = 1;
524
525 zone_map = INODE_MAP + sup->s_imap_blocks;
526
527 insert_bit(zone_map, 0); /* bit zero must always be allocated */
528 insert_bit((block_t) INODE_MAP, 0); /* inode zero not used but
529 * must be allocated */
530
531 free(buf);
532}
533
534
535/*================================================================
536 * rootdir - install the root directory
537 *===============================================================*/
538void rootdir(inode)
539ino_t inode;
540{
541 zone_t z;
542
543 z = alloc_zone();
544 add_zone(inode, z, 2 * sizeof(struct direct), current_time);
545 enter_dir(inode, ".", inode);
546 enter_dir(inode, "..", inode);
547 incr_link(inode);
548 incr_link(inode);
549}
550
551
552/*================================================================
553 * eat_dir - recursively install directory
554 *===============================================================*/
555void eat_dir(parent)
556ino_t parent;
557{
558 /* Read prototype lines and set up directory. Recurse if need be. */
559 char *token[MAX_TOKENS], *p;
560 char line[LINE_LEN];
561 int mode, usrid, grpid, maj, min, f;
562 ino_t n;
563 zone_t z;
564 long size;
565
566 while (1) {
567 getline(line, token);
568 p = token[0];
569 if (*p == '$') return;
570 p = token[1];
571 mode = mode_con(p);
572 usrid = atoi(token[2]);
573 grpid = atoi(token[3]);
574 if (grpid & 0200) fprintf(stderr, "A.S.Tanenbaum\n");
575 n = alloc_inode(mode, usrid, grpid);
576
577 /* Enter name in directory and update directory's size. */
578 enter_dir(parent, token[0], n);
579 incr_size(parent, sizeof(struct direct));
580
581 /* Check to see if file is directory or special. */
582 incr_link(n);
583 if (*p == 'd') {
584 /* This is a directory. */
585 z = alloc_zone(); /* zone for new directory */
586 add_zone(n, z, 2 * sizeof(struct direct), current_time);
587 enter_dir(n, ".", n);
588 enter_dir(n, "..", parent);
589 incr_link(parent);
590 incr_link(n);
591 eat_dir(n);
592 } else if (*p == 'b' || *p == 'c') {
593 /* Special file. */
594 maj = atoi(token[4]);
595 min = atoi(token[5]);
596 size = 0;
597 if (token[6]) size = atoi(token[6]);
598 size = block_size * size;
599 add_zone(n, (zone_t) ((maj << 8) | min), size, current_time);
600 } else {
601 /* Regular file. Go read it. */
602 if ((f = open(token[4], O_RDONLY)) < 0) {
603 fprintf(stderr, "%s: Can't open %s: %s\n",
604 progname, token[4], strerror(errno));
605 } else {
606 eat_file(n, f);
607 }
608 }
609 }
610
611}
612
613/*================================================================
614 * eat_file - copy file to MINIX
615 *===============================================================*/
616/* Zonesize >= blocksize */
617void eat_file(inode, f)
618ino_t inode;
619int f;
620{
621 int ct, i, j, k;
622 zone_t z;
623 char *buf;
624 long timeval;
625
626 buf = alloc_block();
627
628 do {
629 for (i = 0, j = 0; i < zone_size; i++, j += ct) {
630 for (k = 0; k < block_size; k++) buf[k] = 0;
631 if ((ct = read(f, buf, block_size)) > 0) {
632 if (i == 0) z = alloc_zone();
633 put_block((z << zone_shift) + i, buf);
634 }
635 }
636 timeval = (dflag ? current_time : file_time(f));
637 if (ct) add_zone(inode, z, (long) j, timeval);
638 } while (ct == block_size);
639 close(f);
640}
641
642
643
644/*================================================================
645 * directory & inode management assist group
646 *===============================================================*/
647void enter_dir(parent, name, child)
648ino_t parent, child;
649char *name;
650{
651 /* Enter child in parent directory */
652 /* Works for dir > 1 block and zone > block */
653 int i, j, k, l, off;
654 block_t b;
655 zone_t z;
656 char *p1, *p2;
657 struct direct *dir_entry;
658 d1_inode ino1[V1_INODES_PER_BLOCK];
659 d2_inode *ino2;
660 int nr_dzones;
661
662 b = ((parent - 1) / inodes_per_block) + inode_offset;
663 off = (parent - 1) % inodes_per_block;
664
665 if(!(dir_entry = malloc(NR_DIR_ENTRIES(block_size) * sizeof(*dir_entry))))
666 pexit("couldn't allocate directory entry");
667
668 if(!(ino2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*ino2))))
669 pexit("couldn't allocate block of inodes entry");
670
671 if (fs_version == 1) {
672 get_block(b, (char *) ino1);
673 nr_dzones = V1_NR_DZONES;
674 } else {
675 get_block(b, (char *) ino2);
676 nr_dzones = V2_NR_DZONES;
677 }
678 for (k = 0; k < nr_dzones; k++) {
679 if (fs_version == 1) {
680 z = ino1[off].d1_zone[k];
681 if (z == 0) {
682 z = alloc_zone();
683 ino1[off].d1_zone[k] = z;
684 }
685 } else {
686 z = ino2[off].d2_zone[k];
687 if (z == 0) {
688 z = alloc_zone();
689 ino2[off].d2_zone[k] = z;
690 }
691 }
692 for (l = 0; l < zone_size; l++) {
693 get_block((z << zone_shift) + l, (char *) dir_entry);
694 for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) {
695 if (dir_entry[i].d_ino == 0) {
696 dir_entry[i].d_ino = child;
697 p1 = name;
698 p2 = dir_entry[i].d_name;
699 j = sizeof(dir_entry[i].d_name);
700 while (j--) {
701 *p2++ = *p1;
702 if (*p1 != 0) p1++;
703 }
704 put_block((z << zone_shift) + l, (char *) dir_entry);
705 if (fs_version == 1) {
706 put_block(b, (char *) ino1);
707 } else {
708 put_block(b, (char *) ino2);
709 }
710 free(dir_entry);
711 free(ino2);
712 return;
713 }
714 }
715 }
716 }
717
718 printf("Directory-inode %d beyond direct blocks. Could not enter %s\n",
719 parent, name);
720 pexit("Halt");
721}
722
723
724void add_zone(n, z, bytes, cur_time)
725ino_t n;
726zone_t z;
727long bytes, cur_time;
728{
729 if (fs_version == 1) {
730 add_z_1(n, z, bytes, cur_time);
731 } else {
732 add_z_2(n, z, bytes, cur_time);
733 }
734}
735
736void add_z_1(n, z, bytes, cur_time)
737ino_t n;
738zone_t z;
739long bytes, cur_time;
740{
741 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
742
743 int off, i;
744 block_t b;
745 zone_t indir;
746 zone1_t blk[V1_INDIRECTS];
747 d1_inode *p;
748 d1_inode inode[V1_INODES_PER_BLOCK];
749
750 b = ((n - 1) / V1_INODES_PER_BLOCK) + inode_offset;
751 off = (n - 1) % V1_INODES_PER_BLOCK;
752 get_block(b, (char *) inode);
753 p = &inode[off];
754 p->d1_size += bytes;
755 p->d1_mtime = cur_time;
756 for (i = 0; i < V1_NR_DZONES; i++)
757 if (p->d1_zone[i] == 0) {
758 p->d1_zone[i] = (zone1_t) z;
759 put_block(b, (char *) inode);
760 return;
761 }
762 put_block(b, (char *) inode);
763
764 /* File has grown beyond a small file. */
765 if (p->d1_zone[V1_NR_DZONES] == 0)
766 p->d1_zone[V1_NR_DZONES] = (zone1_t) alloc_zone();
767 indir = p->d1_zone[V1_NR_DZONES];
768 put_block(b, (char *) inode);
769 b = indir << zone_shift;
770 get_block(b, (char *) blk);
771 for (i = 0; i < V1_INDIRECTS; i++)
772 if (blk[i] == 0) {
773 blk[i] = (zone1_t) z;
774 put_block(b, (char *) blk);
775 return;
776 }
777 pexit("File has grown beyond single indirect");
778}
779
780void add_z_2(n, z, bytes, cur_time)
781ino_t n;
782zone_t z;
783long bytes, cur_time;
784{
785 /* Add zone z to inode n. The file has grown by 'bytes' bytes. */
786
787 int off, i;
788 block_t b;
789 zone_t indir;
790 zone_t *blk;
791 d2_inode *p;
792 d2_inode *inode;
793
794 if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
795 pexit("Couldn't allocate indirect block");
796
797 if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
798 pexit("Couldn't allocate block of inodes");
799
800 b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
801 off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
802 get_block(b, (char *) inode);
803 p = &inode[off];
804 p->d2_size += bytes;
805 p->d2_mtime = cur_time;
806 for (i = 0; i < V2_NR_DZONES; i++)
807 if (p->d2_zone[i] == 0) {
808 p->d2_zone[i] = z;
809 put_block(b, (char *) inode);
810 free(blk);
811 free(inode);
812 return;
813 }
814 put_block(b, (char *) inode);
815
816 /* File has grown beyond a small file. */
817 if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
818 indir = p->d2_zone[V2_NR_DZONES];
819 put_block(b, (char *) inode);
820 b = indir << zone_shift;
821 get_block(b, (char *) blk);
822 for (i = 0; i < V2_INDIRECTS(block_size); i++)
823 if (blk[i] == 0) {
824 blk[i] = z;
825 put_block(b, (char *) blk);
826 free(blk);
827 free(inode);
828 return;
829 }
830 pexit("File has grown beyond single indirect");
831}
832
833
834void incr_link(n)
835ino_t n;
836{
837 /* Increment the link count to inode n */
838 int off;
839 static int enter = 0;
840 block_t b;
841
842 if(enter) exit(1);
843
844 b = ((n - 1) / inodes_per_block) + inode_offset;
845 off = (n - 1) % inodes_per_block;
846 if (fs_version == 1) {
847 d1_inode inode1[V1_INODES_PER_BLOCK];
848
849 get_block(b, (char *) inode1);
850 inode1[off].d1_nlinks++;
851 put_block(b, (char *) inode1);
852 } else {
853 static d2_inode *inode2 = NULL;
854 int n;
855
856 n = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
857 if(!inode2 && !(inode2 = malloc(n)))
858 pexit("couldn't allocate a block of inodes");
859
860 get_block(b, (char *) inode2);
861 inode2[off].d2_nlinks++;
862 put_block(b, (char *) inode2);
863 }
864 enter = 0;
865}
866
867
868void incr_size(n, count)
869ino_t n;
870long count;
871{
872 /* Increment the file-size in inode n */
873 block_t b;
874 int off;
875
876 b = ((n - 1) / inodes_per_block) + inode_offset;
877 off = (n - 1) % inodes_per_block;
878 if (fs_version == 1) {
879 d1_inode inode1[V1_INODES_PER_BLOCK];
880
881 get_block(b, (char *) inode1);
882 inode1[off].d1_size += count;
883 put_block(b, (char *) inode1);
884 } else {
885 d2_inode *inode2;
886 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
887 pexit("couldn't allocate a block of inodes");
888
889 get_block(b, (char *) inode2);
890 inode2[off].d2_size += count;
891 put_block(b, (char *) inode2);
892 free(inode2);
893 }
894}
895
896
897/*================================================================
898 * allocation assist group
899 *===============================================================*/
900PRIVATE ino_t alloc_inode(mode, usrid, grpid)
901int mode, usrid, grpid;
902{
903 ino_t num;
904 int off;
905 block_t b;
906
907 num = next_inode++;
908 if (num > nrinodes) {
909 fprintf(stderr, "have %d inodoes\n", nrinodes);
910 pexit("File system does not have enough inodes");
911 }
912 b = ((num - 1) / inodes_per_block) + inode_offset;
913 off = (num - 1) % inodes_per_block;
914 if (fs_version == 1) {
915 d1_inode inode1[V1_INODES_PER_BLOCK];
916
917 get_block(b, (char *) inode1);
918 inode1[off].d1_mode = mode;
919 inode1[off].d1_uid = usrid;
920 inode1[off].d1_gid = grpid;
921 put_block(b, (char *) inode1);
922 } else {
923 d2_inode *inode2;
924
925 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
926 pexit("couldn't allocate a block of inodes");
927
928 get_block(b, (char *) inode2);
929 inode2[off].d2_mode = mode;
930 inode2[off].d2_uid = usrid;
931 inode2[off].d2_gid = grpid;
932 put_block(b, (char *) inode2);
933
934 free(inode2);
935 }
936
937 /* Set the bit in the bit map. */
938 /* DEBUG FIXME. This assumes the bit is in the first inode map block. */
939 insert_bit((block_t) INODE_MAP, (int) num);
940 return(num);
941}
942
943
944PRIVATE zone_t alloc_zone()
945{
946 /* Allocate a new zone */
947 /* Works for zone > block */
948 block_t b;
949 int i;
950 zone_t z;
951
952 z = next_zone++;
953 b = z << zone_shift;
954 if ((b + zone_size) > nrblocks)
955 pexit("File system not big enough for all the files");
956 for (i = 0; i < zone_size; i++)
957 put_block(b + i, zero); /* give an empty zone */
958 /* DEBUG FIXME. This assumes the bit is in the first zone map block. */
959 insert_bit(zone_map, (int) (z - zoff)); /* lint, NOT OK because
960 * z hasn't been broken
961 * up into block +
962 * offset yet. */
963 return(z);
964}
965
966
967void insert_bit(block, bit)
968block_t block;
969int bit;
970{
971 /* Insert 'count' bits in the bitmap */
972 int w, s;
973 short *buf;
974
975 buf = (short *) alloc_block();
976
977 if (block < 0) pexit("insert_bit called with negative argument");
978 get_block(block, (char *) buf);
979 w = bit / (8 * sizeof(short));
980 s = bit % (8 * sizeof(short));
981 buf[w] |= (1 << s);
982 put_block(block, (char *) buf);
983
984 free(buf);
985}
986
987
988/*================================================================
989 * proto-file processing assist group
990 *===============================================================*/
991int mode_con(p)
992char *p;
993{
994 /* Convert string to mode */
995 int o1, o2, o3, mode;
996 char c1, c2, c3;
997
998 c1 = *p++;
999 c2 = *p++;
1000 c3 = *p++;
1001 o1 = *p++ - '0';
1002 o2 = *p++ - '0';
1003 o3 = *p++ - '0';
1004 mode = (o1 << 6) | (o2 << 3) | o3;
1005 if (c1 == 'd') mode += I_DIRECTORY;
1006 if (c1 == 'b') mode += I_BLOCK_SPECIAL;
1007 if (c1 == 'c') mode += I_CHAR_SPECIAL;
1008 if (c1 == '-') mode += I_REGULAR;
1009 if (c2 == 'u') mode += I_SET_UID_BIT;
1010 if (c3 == 'g') mode += I_SET_GID_BIT;
1011 return(mode);
1012}
1013
1014void getline(line, parse)
1015char *parse[MAX_TOKENS];
1016char line[LINE_LEN];
1017{
1018 /* Read a line and break it up in tokens */
1019 int k;
1020 char c, *p;
1021 int d;
1022
1023 for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
1024 for (k = 0; k < LINE_LEN; k++) line[k] = 0;
1025 k = 0;
1026 parse[0] = 0;
1027 p = line;
1028 while (1) {
1029 if (++k > LINE_LEN) pexit("Line too long");
1030 d = fgetc(proto);
1031 if (d == EOF) pexit("Unexpected end-of-file");
1032 *p = d;
1033 if (*p == '\n') lct++;
1034 if (*p == ' ' || *p == '\t') *p = 0;
1035 if (*p == '\n') {
1036 *p++ = 0;
1037 *p = '\n';
1038 break;
1039 }
1040 p++;
1041 }
1042
1043 k = 0;
1044 p = line;
1045 lastp = line;
1046 while (1) {
1047 c = *p++;
1048 if (c == '\n') return;
1049 if (c == 0) continue;
1050 parse[k++] = p - 1;
1051 do {
1052 c = *p++;
1053 } while (c != 0 && c != '\n');
1054 }
1055}
1056
1057
1058/*================================================================
1059 * other stuff
1060 *===============================================================*/
1061void check_mtab(devname)
1062char *devname; /* /dev/hd1 or whatever */
1063{
1064/* Check to see if the special file named in s is mounted. */
1065
1066 int n, r;
1067 struct stat sb;
1068 char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
1069
1070 r= stat(devname, &sb);
1071 if (r == -1)
1072 {
1073 if (errno == ENOENT)
1074 return; /* Does not exist, and therefore not mounted. */
1075 fprintf(stderr, "%s: stat %s failed: %s\n",
1076 progname, devname, strerror(errno));
1077 exit(1);
1078 }
1079 if (!S_ISBLK(sb.st_mode))
1080 {
1081 /* Not a block device and therefore not mounted. */
1082 return;
1083 }
1084
1085 if (load_mtab("mkfs") < 0) return;
1086 while (1) {
1087 n = get_mtab_entry(special, mounted_on, version, rw_flag);
1088 if (n < 0) return;
1089 if (strcmp(devname, special) == 0) {
1090 /* Can't mkfs on top of a mounted file system. */
1091 fprintf(stderr, "%s: %s is mounted on %s\n",
1092 progname, devname, mounted_on);
1093 exit(1);
1094 }
1095 }
1096}
1097
1098
1099long file_time(f)
1100int f;
1101{
1102#ifdef UNIX
1103 struct stat statbuf;
1104 fstat(f, &statbuf);
1105 return(statbuf.st_mtime);
1106#else /* fstat not supported by DOS */
1107 return(0L);
1108#endif
1109}
1110
1111
1112void pexit(s)
1113char *s;
1114{
1115 fprintf(stderr, "%s: %s\n", progname, s);
1116 if (lct != 0)
1117 fprintf(stderr, "Line %d being processed when error detected.\n", lct);
1118 flush();
1119 exit(2);
1120}
1121
1122
1123void copy(from, to, count)
1124char *from, *to;
1125int count;
1126{
1127 while (count--) *to++ = *from++;
1128}
1129
1130char *alloc_block()
1131{
1132 char *buf;
1133
1134 if(!(buf = malloc(block_size))) {
1135 pexit("couldn't allocate filesystem buffer");
1136 }
1137 bzero(buf, block_size);
1138
1139 return buf;
1140}
1141
1142void print_fs()
1143{
1144 int i, j;
1145 ino_t k;
1146 d1_inode inode1[V1_INODES_PER_BLOCK];
1147 d2_inode *inode2;
1148 unsigned short *usbuf;
1149 block_t b, inode_limit;
1150 struct direct *dir;
1151
1152 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
1153 pexit("couldn't allocate a block of inodes");
1154
1155 if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
1156 pexit("malloc of directory entry failed");
1157
1158 usbuf = (unsigned short *) alloc_block();
1159
1160 get_super_block((char *) usbuf);
1161 printf("\nSuperblock: ");
1162 for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
1163 get_block((block_t) 2, (char *) usbuf);
1164 printf("...\nInode map: ");
1165 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1166 get_block((block_t) 3, (char *) usbuf);
1167 printf("...\nZone map: ");
1168 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
1169 printf("...\n");
1170
1171 free(usbuf);
1172 usbuf = NULL;
1173
1174 k = 0;
1175 for (b = inode_offset; k < nrinodes; b++) {
1176 if (fs_version == 1) {
1177 get_block(b, (char *) inode1);
1178 } else {
1179 get_block(b, (char *) inode2);
1180 }
1181 for (i = 0; i < inodes_per_block; i++) {
1182 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
1183 /* Lint but OK */
1184 if (k > nrinodes) break;
1185 if (fs_version == 1) {
1186 if (inode1[i].d1_mode != 0) {
1187 printf("Inode %2d: mode=", k);
1188 printf("%06o", inode1[i].d1_mode);
1189 printf(" uid=%2d gid=%2d size=",
1190 inode1[i].d1_uid, inode1[i].d1_gid);
1191 printf("%6ld", inode1[i].d1_size);
1192 printf(" zone[0]=%d\n", inode1[i].d1_zone[0]);
1193 }
1194 if ((inode1[i].d1_mode & I_TYPE) == I_DIRECTORY) {
1195 /* This is a directory */
1196 get_block(inode1[i].d1_zone[0], (char *) dir);
1197 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1198 if (dir[j].d_ino)
1199 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
1200 }
1201 } else {
1202 if (inode2[i].d2_mode != 0) {
1203 printf("Inode %2d: mode=", k);
1204 printf("%06o", inode2[i].d2_mode);
1205 printf(" uid=%2d gid=%2d size=",
1206 inode2[i].d2_uid, inode2[i].d2_gid);
1207 printf("%6ld", inode2[i].d2_size);
1208 printf(" zone[0]=%ld\n", inode2[i].d2_zone[0]);
1209 }
1210 if ((inode2[i].d2_mode & I_TYPE) == I_DIRECTORY) {
1211 /* This is a directory */
1212 get_block(inode2[i].d2_zone[0], (char *) dir);
1213 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
1214 if (dir[j].d_ino)
1215 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
1216 }
1217 }
1218 }
1219 }
1220
1221 printf("%d inodes used. %d zones used.\n", next_inode - 1, next_zone);
1222 free(dir);
1223 free(inode2);
1224}
1225
1226
1227int read_and_set(n)
1228block_t n;
1229{
1230/* The first time a block is read, it returns all 0s, unless there has
1231 * been a write. This routine checks to see if a block has been accessed.
1232 */
1233
1234 int w, s, mask, r;
1235
1236 if (sizeof(char *) == 2 && n >= MAX_INIT) pexit("can't initialize past 128M");
1237 w = n / 8;
1238 s = n % 8;
1239 mask = 1 << s;
1240 r = (umap[w] & mask ? 1 : 0);
1241 umap[w] |= mask;
1242 return(r);
1243}
1244
1245void usage()
1246{
1247 fprintf(stderr,
1248 "Usage: %s [-12dlot] [-b blocks] [-i inodes] [-B blocksize] special [proto]\n",
1249 progname);
1250 exit(1);
1251}
1252
1253/*================================================================
1254 * get_block & put_block for MS-DOS
1255 *===============================================================*/
1256#ifdef DOS
1257
1258/*
1259 * These are the get_block and put_block routines
1260 * when compiling & running mkfs.c under MS-DOS.
1261 *
1262 * It requires the (asembler) routines absread & abswrite
1263 * from the file diskio.asm. Since these routines just do
1264 * as they are told (read & write the sector specified),
1265 * a local cache is used to minimize the i/o-overhead for
1266 * frequently used blocks.
1267 *
1268 * The global variable "file" determines whether the output
1269 * is to a disk-device or to a binary file.
1270 */
1271
1272
1273#define PH_SECTSIZE 512 /* size of a physical disk-sector */
1274
1275
1276char *derrtab[14] = {
1277 "no error",
1278 "disk is read-only",
1279 "unknown unit",
1280 "device not ready",
1281 "bad command",
1282 "data error",
1283 "internal error: bad request structure length",
1284 "seek error",
1285 "unknown media type",
1286 "sector not found",
1287 "printer out of paper (?)",
1288 "write fault",
1289 "read error",
1290 "general error"
1291};
1292
1293#define CACHE_SIZE 20 /* 20 block-buffers */
1294
1295
1296struct cache {
1297 char blockbuf[BLOCK_SIZE];
1298 block_t blocknum;
1299 int dirty;
1300 int usecnt;
1301} cache[CACHE_SIZE];
1302
1303
1304void special(string)
1305char *string;
1306{
1307
1308 if (string[1] == ':' && string[2] == 0) {
1309 /* Format: d: or d:fname */
1310 disk = (string[0] & ~32) - 'A';
1311 if (disk > 1 && !override) /* safety precaution */
1312 pexit("Bad drive specifier for special");
1313 } else {
1314 file = 1;
1315 if ((fd = creat(string, BWRITE)) == 0)
1316 pexit("Can't open special file");
1317 }
1318}
1319
1320void get_block(n, buf)
1321block_t n;
1322char *buf;
1323{
1324 /* Get a block to the user */
1325 struct cache *bp, *fp;
1326
1327 /* First access returns a zero block */
1328 if (read_and_set(n) == 0) {
1329 copy(zero, buf, block_size);
1330 return;
1331 }
1332
1333 /* Look for block in cache */
1334 fp = 0;
1335 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1336 if (bp->blocknum == n) {
1337 copy(bp, buf, block_size);
1338 bp->usecnt++;
1339 return;
1340 }
1341
1342 /* Remember clean block */
1343 if (bp->dirty == 0)
1344 if (fp) {
1345 if (fp->usecnt > bp->usecnt) fp = bp;
1346 } else
1347 fp = bp;
1348 }
1349
1350 /* Block not in cache, get it */
1351 if (!fp) {
1352 /* No clean buf, flush one */
1353 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1354 if (fp->usecnt > bp->usecnt) fp = bp;
1355 mx_write(fp->blocknum, fp);
1356 }
1357 mx_read(n, fp);
1358 fp->dirty = 0;
1359 fp->usecnt = 0;
1360 fp->blocknum = n;
1361 copy(fp, buf, block_size);
1362}
1363
1364void put_block(n, buf)
1365block_t n;
1366char *buf;
1367{
1368 /* Accept block from user */
1369 struct cache *fp, *bp;
1370
1371 (void) read_and_set(n);
1372
1373 /* Look for block in cache */
1374 fp = 0;
1375 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
1376 if (bp->blocknum == n) {
1377 copy(buf, bp, block_size);
1378 bp->dirty = 1;
1379 return;
1380 }
1381
1382 /* Remember clean block */
1383 if (bp->dirty == 0)
1384 if (fp) {
1385 if (fp->usecnt > bp->usecnt) fp = bp;
1386 } else
1387 fp = bp;
1388 }
1389
1390 /* Block not in cache */
1391 if (!fp) {
1392 /* No clean buf, flush one */
1393 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
1394 if (fp->usecnt > bp->usecnt) fp = bp;
1395 mx_write(fp->blocknum, fp);
1396 }
1397 fp->dirty = 1;
1398 fp->usecnt = 1;
1399 fp->blocknum = n;
1400 copy(buf, fp, block_size);
1401}
1402
1403void cache_init()
1404{
1405 struct cache *bp;
1406 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
1407}
1408
1409void flush()
1410{
1411 /* Flush all dirty blocks to disk */
1412 struct cache *bp;
1413
1414 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
1415 if (bp->dirty) {
1416 mx_write(bp->blocknum, bp);
1417 bp->dirty = 0;
1418 }
1419}
1420
1421/*==================================================================
1422 * hard read & write etc.
1423 *=================================================================*/
1424#define MAX_RETRIES 5
1425
1426
1427void mx_read(blocknr, buf)
1428int blocknr;
1429char *buf;
1430{
1431
1432 /* Read the requested MINIX-block in core */
1433 char (*bp)[PH_SECTSIZE];
1434 int sectnum, retries, err;
1435
1436 if (file) {
1437 lseek(fd, (off_t) blocknr * block_size, 0);
1438 if (read(fd, buf, block_size) != block_size)
1439 pexit("mx_read: error reading file");
1440 } else {
1441 sectnum = blocknr * (block_size / PH_SECTSIZE);
1442 for (bp = buf; bp < &buf[block_size]; bp++) {
1443 retries = MAX_RETRIES;
1444 do
1445 err = absread(disk, sectnum, bp);
1446 while (err && --retries);
1447
1448 if (retries) {
1449 sectnum++;
1450 } else {
1451 dexit("mx_read", sectnum, err);
1452 }
1453 }
1454 }
1455}
1456
1457void mx_write(blocknr, buf)
1458int blocknr;
1459char *buf;
1460{
1461 /* Write the MINIX-block to disk */
1462 char (*bp)[PH_SECTSIZE];
1463 int retries, sectnum, err;
1464
1465 if (file) {
1466 lseek(fd, blocknr * block_size, 0);
1467 if (write(fd, buf, block_size) != block_size) {
1468 pexit("mx_write: error writing file");
1469 }
1470 } else {
1471 sectnum = blocknr * (block_size / PH_SECTSIZE);
1472 for (bp = buf; bp < &buf[block_size]; bp++) {
1473 retries = MAX_RETRIES;
1474 do {
1475 err = abswrite(disk, sectnum, bp);
1476 } while (err && --retries);
1477
1478 if (retries) {
1479 sectnum++;
1480 } else {
1481 dexit("mx_write", sectnum, err);
1482 }
1483 }
1484 }
1485}
1486
1487
1488void dexit(s, sectnum, err)
1489int sectnum, err;
1490char *s;
1491{
1492 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
1493 s, sectnum, err, derrtab[err]);
1494 exit(2);
1495}
1496
1497#endif
1498
1499/*================================================================
1500 * get_block & put_block for UNIX
1501 *===============================================================*/
1502#ifdef UNIX
1503
1504void special(string)
1505char *string;
1506{
1507 fd = creat(string, 0777);
1508 close(fd);
1509 fd = open(string, O_RDWR);
1510 if (fd < 0) pexit("Can't open special file");
1511#if (MACHINE == ATARI)
1512 {
1513 struct stat statbuf;
1514
1515 if (fstat(fd, &statbuf) < 0) return;
1516 isdev = (statbuf.st_mode & S_IFMT) == S_IFCHR
1517 ||
1518 (statbuf.st_mode & S_IFMT) == S_IFBLK
1519 ;
1520 }
1521#endif
1522}
1523
1524
1525
1526void get_block(n, buf)
1527block_t n;
1528char *buf;
1529{
1530/* Read a block. */
1531
1532 int k;
1533
1534 /* First access returns a zero block */
1535 if (read_and_set(n) == 0) {
1536 copy(zero, buf, block_size);
1537 return;
1538 }
1539 lseek(fd, (off_t) n * block_size, SEEK_SET);
1540 k = read(fd, buf, block_size);
1541 if (k != block_size) {
1542 pexit("get_block couldn't read");
1543 }
1544}
1545
1546void get_super_block(buf)
1547char *buf;
1548{
1549/* Read a block. */
1550
1551 int k;
1552
1553 if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
1554 perror("lseek");
1555 pexit("seek failed");
1556 }
1557 k = read(fd, buf, _STATIC_BLOCK_SIZE);
1558 if (k != _STATIC_BLOCK_SIZE) {
1559 pexit("get_super_block couldn't read");
1560 }
1561}
1562
1563void put_block(n, buf)
1564block_t n;
1565char *buf;
1566{
1567/* Write a block. */
1568
1569 (void) read_and_set(n);
1570
1571 /* XXX - check other lseeks too. */
1572 if (lseek(fd, (off_t) n * block_size, SEEK_SET) == (off_t) -1) {
1573 pexit("put_block couldn't seek");
1574 }
1575 if (write(fd, buf, block_size) != block_size) {
1576 pexit("put_block couldn't write");
1577 }
1578}
1579
1580
1581/* Dummy routines to keep source file clean from #ifdefs */
1582
1583void flush()
1584{
1585 return;
1586}
1587
1588void cache_init()
1589{
1590 return;
1591}
1592
1593#endif
Note: See TracBrowser for help on using the repository browser.