00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <sys/types.h>
00012 #include <sys/dir.h>
00013 #include <sys/stat.h>
00014 #include <stdio.h>
00015 #include <errno.h>
00016 #include <fcntl.h>
00017 #include <limits.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #include <time.h>
00021 #include <unistd.h>
00022 #include <minix/config.h>
00023 #include <minix/const.h>
00024 #include <minix/type.h>
00025 #include <minix/minlib.h>
00026 #include "../../servers/fs/const.h"
00027 #if (MACHINE == IBM_PC)
00028 #include <minix/partition.h>
00029 #include <minix/u64.h>
00030 #include <sys/ioctl.h>
00031 #endif
00032 #include <a.out.h>
00033 #include <tools.h>
00034 #include <dirent.h>
00035
00036 #undef EXTERN
00037 #define EXTERN
00038 #include "../../servers/fs/type.h"
00039 #include "../../servers/fs/super.h"
00040 #include <minix/fslib.h>
00041
00042 #ifndef max
00043 #define max(a,b) ((a) > (b) ? (a) : (b))
00044 #endif
00045
00046 #ifndef DOS
00047 #ifndef UNIX
00048 #define UNIX
00049 #endif
00050 #endif
00051
00052 #define INODE_MAP 2
00053 #define MAX_TOKENS 10
00054 #define LINE_LEN 200
00055 #define BIN 2
00056 #define BINGRP 2
00057 #define BIT_MAP_SHIFT 13
00058 #define N_BLOCKS MAX_BLOCK_NR
00059 #define N_BLOCKS16 (128L * 1024)
00060 #define INODE_MAX ((unsigned) 65535)
00061
00062
00063
00064
00065
00066
00067 #define MAX_INIT (sizeof(char *) == 2 ? N_BLOCKS16 : N_BLOCKS)
00068
00069
00070 #ifdef DOS
00071 maybedefine O_RDONLY 4
00072 maybedefine BWRITE 5
00073 #endif
00074
00075 #if (MACHINE == ATARI)
00076 int isdev;
00077 #endif
00078
00079 extern char *optarg;
00080 extern int optind;
00081
00082 int next_zone, next_inode, zone_size, zone_shift = 0, zoff;
00083 block_t nrblocks;
00084 int inode_offset, lct = 0, disk, fd, print = 0, file = 0;
00085 unsigned int nrinodes;
00086 int override = 0, simple = 0, dflag;
00087 int donttest;
00088 char *progname;
00089
00090 long current_time, bin_time;
00091 char *zero, *lastp;
00092 char umap[MAX_INIT / 8];
00093 block_t zone_map;
00094 int inodes_per_block;
00095 int fs_version;
00096 unsigned int block_size;
00097 block_t max_nrblocks;
00098
00099 FILE *proto;
00100
00101 _PROTOTYPE(int main, (int argc, char **argv));
00102 _PROTOTYPE(block_t sizeup, (char *device));
00103 _PROTOTYPE(void super, (zone_t zones, Ino_t inodes));
00104 _PROTOTYPE(void rootdir, (Ino_t inode));
00105 _PROTOTYPE(void eat_dir, (Ino_t parent));
00106 _PROTOTYPE(void eat_file, (Ino_t inode, int f));
00107 _PROTOTYPE(void enter_dir, (Ino_t parent, char *name, Ino_t child));
00108 _PROTOTYPE(void incr_size, (Ino_t n, long count));
00109 _PROTOTYPE(PRIVATE ino_t alloc_inode, (int mode, int usrid, int grpid));
00110 _PROTOTYPE(PRIVATE zone_t alloc_zone, (void));
00111 _PROTOTYPE(void add_zone, (Ino_t n, zone_t z, long bytes, long cur_time));
00112 _PROTOTYPE(void add_z_1, (Ino_t n, zone_t z, long bytes, long cur_time));
00113 _PROTOTYPE(void add_z_2, (Ino_t n, zone_t z, long bytes, long cur_time));
00114 _PROTOTYPE(void incr_link, (Ino_t n));
00115 _PROTOTYPE(void insert_bit, (block_t block, int bit));
00116 _PROTOTYPE(int mode_con, (char *p));
00117 _PROTOTYPE(void getline, (char line[LINE_LEN], char *parse[MAX_TOKENS]));
00118 _PROTOTYPE(void check_mtab, (char *devname));
00119 _PROTOTYPE(long file_time, (int f));
00120 _PROTOTYPE(void pexit, (char *s));
00121 _PROTOTYPE(void copy, (char *from, char *to, int count));
00122 _PROTOTYPE(void print_fs, (void));
00123 _PROTOTYPE(int read_and_set, (block_t n));
00124 _PROTOTYPE(void special, (char *string));
00125 _PROTOTYPE(void get_block, (block_t n, char *buf));
00126 _PROTOTYPE(void get_super_block, (char *buf));
00127 _PROTOTYPE(void put_block, (block_t n, char *buf));
00128 _PROTOTYPE(void cache_init, (void));
00129 _PROTOTYPE(void flush, (void));
00130 _PROTOTYPE(void mx_read, (int blocknr, char *buf));
00131 _PROTOTYPE(void mx_write, (int blocknr, char *buf));
00132 _PROTOTYPE(void dexit, (char *s, int sectnum, int err));
00133 _PROTOTYPE(void usage, (void));
00134 _PROTOTYPE(char *alloc_block, (void));
00135
00136
00137
00138
00139 int main(argc, argv)
00140 int argc;
00141 char *argv[];
00142 {
00143 int nread, mode, usrid, grpid, ch;
00144 block_t blocks, maxblocks;
00145 block_t i;
00146 ino_t root_inum;
00147 ino_t inodes;
00148 zone_t zones;
00149 char *token[MAX_TOKENS], line[LINE_LEN];
00150 struct stat statbuf;
00151
00152
00153
00154
00155
00156
00157
00158
00159 current_time = time((time_t *) 0);
00160 stat(argv[0], &statbuf);
00161 bin_time = statbuf.st_mtime;
00162
00163
00164 progname = argv[0];
00165 blocks = 0;
00166 i = 0;
00167 fs_version = 3;
00168 inodes_per_block = 0;
00169 max_nrblocks = N_BLOCKS;
00170 block_size = 0;
00171 while ((ch = getopt(argc, argv, "12b:di:lotB:")) != EOF)
00172 switch (ch) {
00173 case '1':
00174 fs_version = 1;
00175 inodes_per_block = V1_INODES_PER_BLOCK;
00176 max_nrblocks = 0xFFFF;
00177 break;
00178 case '2':
00179 fs_version = 2;
00180 break;
00181 case 'b':
00182 blocks = strtoul(optarg, (char **) NULL, 0);
00183 break;
00184 case 'd':
00185 dflag = 1;
00186 current_time = bin_time;
00187 break;
00188 case 'i':
00189 i = strtoul(optarg, (char **) NULL, 0);
00190 break;
00191 case 'l': print = 1; break;
00192 case 'o': override = 1; break;
00193 case 't': donttest = 1; break;
00194 case 'B': block_size = atoi(optarg); break;
00195 default: usage();
00196 }
00197
00198 if(fs_version == 3) {
00199 if(!block_size) block_size = _MAX_BLOCK_SIZE;
00200 if(block_size%SECTOR_SIZE || block_size < _MIN_BLOCK_SIZE) {
00201 fprintf(stderr, "block size must be multiple of sector (%d) "
00202 "and at least %d bytes\n",
00203 SECTOR_SIZE, _MIN_BLOCK_SIZE);
00204 pexit("specified block size illegal");
00205 }
00206 if(block_size%V2_INODE_SIZE) {
00207 fprintf(stderr, "block size must be a multiple of inode size (%d bytes)\n",
00208 V2_INODE_SIZE);
00209 pexit("specified block size illegal");
00210 }
00211 } else {
00212 if(block_size) {
00213 pexit("Can't specify a block size if FS version is <3");
00214 }
00215 block_size = _STATIC_BLOCK_SIZE;
00216 }
00217
00218 if(!inodes_per_block)
00219 inodes_per_block = V2_INODES_PER_BLOCK(block_size);
00220
00221
00222
00223
00224 zero = alloc_block();
00225 bzero(zero, block_size);
00226
00227
00228 maxblocks = sizeup(argv[optind]);
00229 if (argc - optind == 1 && blocks == 0) {
00230 blocks = maxblocks;
00231
00232
00233
00234 if(blocks < 1) {
00235 fprintf(stderr, "%s: this device can't hold a filesystem.\n",
00236 progname);
00237 return 1;
00238 }
00239 }
00240
00241
00242
00243
00244 if (argc - optind != 2 && (argc - optind != 1 || blocks == 0)) usage();
00245
00246 if (blocks > maxblocks) {
00247 fprintf(stderr, "%s: %s: number of blocks too large for device.\n",
00248 progname, argv[optind]);
00249 return 1;
00250 }
00251
00252
00253 check_mtab(argv[optind]);
00254
00255
00256 optarg = argv[++optind];
00257 if (optind < argc && (proto = fopen(optarg, "r")) != NULL) {
00258
00259 lct = 1;
00260 getline(line, token);
00261
00262
00263 getline(line, token);
00264 blocks = atol(token[0]);
00265 if (blocks > max_nrblocks) pexit("Block count too large");
00266 if (sizeof(char *) == 2 && blocks > N_BLOCKS16) {
00267 fprintf(stderr,
00268 "%s: warning: FS is larger than the %dM that fsck can check!\n",
00269 progname, (int) (N_BLOCKS16 / (1024L * 1024)));
00270 }
00271 inodes = atoi(token[1]);
00272
00273
00274 getline(line, token);
00275 mode = mode_con(token[0]);
00276 usrid = atoi(token[1]);
00277 grpid = atoi(token[2]);
00278 } else {
00279 lct = 0;
00280 if (optind < argc) {
00281
00282 blocks = strtoul(optarg, (char **) NULL, 0);
00283 if (blocks == 0) pexit("Can't open prototype file");
00284 }
00285 if (i == 0) {
00286 int kb;
00287 kb = blocks * (max(block_size,1024) / 1024);
00288
00289
00290
00291
00292
00293
00294 i = kb / 2;
00295 if (kb >= 20000) i = kb / 3;
00296 if (kb >= 40000) i = kb / 4;
00297 if (kb >= 60000) i = kb / 5;
00298 if (kb >= 80000) i = kb / 6;
00299 if (kb >= 100000) i = kb / 7;
00300
00301
00302 i += inodes_per_block - 1;
00303 i = i / inodes_per_block * inodes_per_block;
00304 if (i > INODE_MAX && fs_version < 3) i = INODE_MAX;
00305
00306 }
00307 if (blocks < 5) pexit("Block count too small");
00308 if (blocks > max_nrblocks) pexit("Block count too large");
00309 if (i < 1) pexit("Inode count too small");
00310 if (i > INODE_MAX && fs_version < 3) pexit("Inode count too large");
00311 inodes = (ino_t) i;
00312
00313
00314 mode = 040777;
00315 usrid = BIN;
00316 grpid = BINGRP;
00317 simple = 1;
00318 }
00319
00320 if(ULONG_MAX / block_size <= blocks-1) {
00321 fprintf(stderr, "Warning: too big for filesystem to currently\n");
00322 fprintf(stderr, "run on (max 4GB), truncating.\n");
00323 blocks = ULONG_MAX / block_size;
00324 }
00325
00326 nrblocks = blocks;
00327 nrinodes = inodes;
00328
00329
00330 special(argv[--optind]);
00331
00332 #ifdef UNIX
00333 if (!donttest) {
00334 short *testb;
00335 ssize_t w;
00336
00337 testb = (short *) alloc_block();
00338
00339
00340 if(lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET) < 0) {
00341 pexit("couldn't seek to last block to test size (1)");
00342 }
00343 testb[0] = 0x3245;
00344 testb[1] = 0x11FF;
00345 testb[block_size-1] = 0x1F2F;
00346 if ((w=write(fd, (char *) testb, block_size)) != block_size) {
00347 if(w < 0) perror("write");
00348 printf("%d/%d\n", w, block_size);
00349 pexit("File system is too big for minor device (write)");
00350 }
00351 sync();
00352 if(lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET) < 0) {
00353 pexit("couldn't seek to last block to test size (2)");
00354 }
00355 testb[0] = 0;
00356 testb[1] = 0;
00357 nread = read(fd, (char *) testb, block_size);
00358 if (nread != block_size || testb[0] != 0x3245 || testb[1] != 0x11FF ||
00359 testb[block_size-1] != 0x1F2F) {
00360 if(nread < 0) perror("read");
00361 pexit("File system is too big for minor device (read)");
00362 }
00363 lseek(fd, (off_t) (blocks - 1) * block_size, SEEK_SET);
00364 testb[0] = 0;
00365 testb[1] = 0;
00366 if (write(fd, (char *) testb, block_size) != block_size)
00367 pexit("File system is too big for minor device (write2)");
00368 lseek(fd, 0L, SEEK_SET);
00369 free(testb);
00370 }
00371 #endif
00372
00373
00374
00375 cache_init();
00376
00377 #if (MACHINE == ATARI)
00378 if (isdev) {
00379 char block0[BLOCK_SIZE];
00380 get_block((block_t) 0, block0);
00381
00382 get_block((block_t) 0, block0);
00383
00384
00385 block0[0] = block0[1] = 0;
00386 strncpy(&block0[2], "MINIX ", (size_t) 6);
00387 block0[16] = 0;
00388 block0[17] = block0[18] = 0;
00389 block0[22] = block0[23] = 0;
00390 bzero(&block0[30], 480);
00391 put_block((block_t) 0, block0);
00392 } else
00393 #endif
00394
00395 put_block((block_t) 0, zero);
00396
00397 zone_shift = 0;
00398 zones = nrblocks >> zone_shift;
00399
00400 super(zones, inodes);
00401
00402 root_inum = alloc_inode(mode, usrid, grpid);
00403 rootdir(root_inum);
00404 if (simple == 0) eat_dir(root_inum);
00405
00406 if (print) print_fs();
00407 flush();
00408 return(0);
00409
00410
00411 }
00412
00413
00414
00415
00416
00417 block_t sizeup(device)
00418 char *device;
00419 {
00420 int fd;
00421 struct partition entry;
00422 block_t d;
00423 struct stat st;
00424
00425 if ((fd = open(device, O_RDONLY)) == -1) {
00426 if (errno != ENOENT)
00427 perror("sizeup open");
00428 return 0;
00429 }
00430 if (ioctl(fd, DIOCGETP, &entry) == -1) {
00431 perror("sizeup ioctl");
00432 if(fstat(fd, &st) < 0) {
00433 perror("fstat");
00434 entry.size = cvu64(0);
00435 } else {
00436 fprintf(stderr, "used fstat instead\n");
00437 entry.size = cvu64(st.st_size);
00438 }
00439 }
00440 close(fd);
00441 d = div64u(entry.size, block_size);
00442 return d;
00443 }
00444
00445
00446
00447
00448
00449
00450 void super(zones, inodes)
00451 zone_t zones;
00452 ino_t inodes;
00453 {
00454 unsigned int i;
00455 int inodeblks;
00456 int initblks;
00457
00458 zone_t initzones, nrzones, v1sq, v2sq;
00459 zone_t zo;
00460 struct super_block *sup;
00461 char *buf, *cp;
00462
00463 buf = alloc_block();
00464
00465 for (cp = buf; cp < &buf[block_size]; cp++) *cp = 0;
00466 sup = (struct super_block *) buf;
00467
00468 sup->s_ninodes = inodes;
00469 if (fs_version == 1) {
00470 sup->s_nzones = zones;
00471 } else {
00472 sup->s_nzones = 0;
00473 sup->s_zones = zones;
00474 }
00475 sup->s_imap_blocks = bitmapsize((bit_t) (1 + inodes), block_size);
00476 sup->s_zmap_blocks = bitmapsize((bit_t) zones, block_size);
00477 inode_offset = sup->s_imap_blocks + sup->s_zmap_blocks + 2;
00478 inodeblks = (inodes + inodes_per_block - 1) / inodes_per_block;
00479 initblks = inode_offset + inodeblks;
00480 initzones = (initblks + (1 << zone_shift) - 1) >> zone_shift;
00481 nrzones = nrblocks >> zone_shift;
00482 sup->s_firstdatazone = (initblks + (1 << zone_shift) - 1) >> zone_shift;
00483 zoff = sup->s_firstdatazone - 1;
00484 sup->s_log_zone_size = zone_shift;
00485 if (fs_version == 1) {
00486 sup->s_magic = SUPER_MAGIC;
00487 v1sq = (zone_t) V1_INDIRECTS * V1_INDIRECTS;
00488 zo = V1_NR_DZONES + (long) V1_INDIRECTS + v1sq;
00489 sup->s_max_size = zo * block_size;
00490 } else {
00491 v2sq = (zone_t) V2_INDIRECTS(block_size) * V2_INDIRECTS(block_size);
00492 zo = V2_NR_DZONES + (zone_t) V2_INDIRECTS(block_size) + v2sq;
00493 if(fs_version == 2) {
00494 sup->s_magic = SUPER_V2;
00495 sup->s_max_size = zo * block_size;
00496 } else {
00497 sup->s_magic = SUPER_V3;
00498 sup->s_block_size = block_size;
00499 sup->s_disk_version = 0;
00500 #define MAX_MAX_SIZE ((unsigned long) 0xffffffff)
00501 if(MAX_MAX_SIZE/block_size < zo) {
00502 sup->s_max_size = MAX_MAX_SIZE;
00503 }
00504 else {
00505 sup->s_max_size = zo * block_size;
00506 }
00507 }
00508 }
00509
00510 zone_size = 1 << zone_shift;
00511
00512 if (lseek(fd, (off_t) _STATIC_BLOCK_SIZE, SEEK_SET) == (off_t) -1) {
00513 pexit("super() couldn't seek");
00514 }
00515 if (write(fd, buf, _STATIC_BLOCK_SIZE) != _STATIC_BLOCK_SIZE) {
00516 pexit("super() couldn't write");
00517 }
00518
00519
00520 for (i = 2; i < initblks; i++) put_block((block_t) i, zero);
00521
00522 next_zone = sup->s_firstdatazone;
00523 next_inode = 1;
00524
00525 zone_map = INODE_MAP + sup->s_imap_blocks;
00526
00527 insert_bit(zone_map, 0);
00528 insert_bit((block_t) INODE_MAP, 0);
00529
00530
00531 free(buf);
00532 }
00533
00534
00535
00536
00537
00538 void rootdir(inode)
00539 ino_t inode;
00540 {
00541 zone_t z;
00542
00543 z = alloc_zone();
00544 add_zone(inode, z, 2 * sizeof(struct direct), current_time);
00545 enter_dir(inode, ".", inode);
00546 enter_dir(inode, "..", inode);
00547 incr_link(inode);
00548 incr_link(inode);
00549 }
00550
00551
00552
00553
00554
00555 void eat_dir(parent)
00556 ino_t parent;
00557 {
00558
00559 char *token[MAX_TOKENS], *p;
00560 char line[LINE_LEN];
00561 int mode, usrid, grpid, maj, min, f;
00562 ino_t n;
00563 zone_t z;
00564 long size;
00565
00566 while (1) {
00567 getline(line, token);
00568 p = token[0];
00569 if (*p == '$') return;
00570 p = token[1];
00571 mode = mode_con(p);
00572 usrid = atoi(token[2]);
00573 grpid = atoi(token[3]);
00574 if (grpid & 0200) fprintf(stderr, "A.S.Tanenbaum\n");
00575 n = alloc_inode(mode, usrid, grpid);
00576
00577
00578 enter_dir(parent, token[0], n);
00579 incr_size(parent, sizeof(struct direct));
00580
00581
00582 incr_link(n);
00583 if (*p == 'd') {
00584
00585 z = alloc_zone();
00586 add_zone(n, z, 2 * sizeof(struct direct), current_time);
00587 enter_dir(n, ".", n);
00588 enter_dir(n, "..", parent);
00589 incr_link(parent);
00590 incr_link(n);
00591 eat_dir(n);
00592 } else if (*p == 'b' || *p == 'c') {
00593
00594 maj = atoi(token[4]);
00595 min = atoi(token[5]);
00596 size = 0;
00597 if (token[6]) size = atoi(token[6]);
00598 size = block_size * size;
00599 add_zone(n, (zone_t) ((maj << 8) | min), size, current_time);
00600 } else {
00601
00602 if ((f = open(token[4], O_RDONLY)) < 0) {
00603 fprintf(stderr, "%s: Can't open %s: %s\n",
00604 progname, token[4], strerror(errno));
00605 } else {
00606 eat_file(n, f);
00607 }
00608 }
00609 }
00610
00611 }
00612
00613
00614
00615
00616
00617 void eat_file(inode, f)
00618 ino_t inode;
00619 int f;
00620 {
00621 int ct, i, j, k;
00622 zone_t z;
00623 char *buf;
00624 long timeval;
00625
00626 buf = alloc_block();
00627
00628 do {
00629 for (i = 0, j = 0; i < zone_size; i++, j += ct) {
00630 for (k = 0; k < block_size; k++) buf[k] = 0;
00631 if ((ct = read(f, buf, block_size)) > 0) {
00632 if (i == 0) z = alloc_zone();
00633 put_block((z << zone_shift) + i, buf);
00634 }
00635 }
00636 timeval = (dflag ? current_time : file_time(f));
00637 if (ct) add_zone(inode, z, (long) j, timeval);
00638 } while (ct == block_size);
00639 close(f);
00640 }
00641
00642
00643
00644
00645
00646
00647 void enter_dir(parent, name, child)
00648 ino_t parent, child;
00649 char *name;
00650 {
00651
00652
00653 int i, j, k, l, off;
00654 block_t b;
00655 zone_t z;
00656 char *p1, *p2;
00657 struct direct *dir_entry;
00658 d1_inode ino1[V1_INODES_PER_BLOCK];
00659 d2_inode *ino2;
00660 int nr_dzones;
00661
00662 b = ((parent - 1) / inodes_per_block) + inode_offset;
00663 off = (parent - 1) % inodes_per_block;
00664
00665 if(!(dir_entry = malloc(NR_DIR_ENTRIES(block_size) * sizeof(*dir_entry))))
00666 pexit("couldn't allocate directory entry");
00667
00668 if(!(ino2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*ino2))))
00669 pexit("couldn't allocate block of inodes entry");
00670
00671 if (fs_version == 1) {
00672 get_block(b, (char *) ino1);
00673 nr_dzones = V1_NR_DZONES;
00674 } else {
00675 get_block(b, (char *) ino2);
00676 nr_dzones = V2_NR_DZONES;
00677 }
00678 for (k = 0; k < nr_dzones; k++) {
00679 if (fs_version == 1) {
00680 z = ino1[off].d1_zone[k];
00681 if (z == 0) {
00682 z = alloc_zone();
00683 ino1[off].d1_zone[k] = z;
00684 }
00685 } else {
00686 z = ino2[off].d2_zone[k];
00687 if (z == 0) {
00688 z = alloc_zone();
00689 ino2[off].d2_zone[k] = z;
00690 }
00691 }
00692 for (l = 0; l < zone_size; l++) {
00693 get_block((z << zone_shift) + l, (char *) dir_entry);
00694 for (i = 0; i < NR_DIR_ENTRIES(block_size); i++) {
00695 if (dir_entry[i].d_ino == 0) {
00696 dir_entry[i].d_ino = child;
00697 p1 = name;
00698 p2 = dir_entry[i].d_name;
00699 j = sizeof(dir_entry[i].d_name);
00700 while (j--) {
00701 *p2++ = *p1;
00702 if (*p1 != 0) p1++;
00703 }
00704 put_block((z << zone_shift) + l, (char *) dir_entry);
00705 if (fs_version == 1) {
00706 put_block(b, (char *) ino1);
00707 } else {
00708 put_block(b, (char *) ino2);
00709 }
00710 free(dir_entry);
00711 free(ino2);
00712 return;
00713 }
00714 }
00715 }
00716 }
00717
00718 printf("Directory-inode %d beyond direct blocks. Could not enter %s\n",
00719 parent, name);
00720 pexit("Halt");
00721 }
00722
00723
00724 void add_zone(n, z, bytes, cur_time)
00725 ino_t n;
00726 zone_t z;
00727 long bytes, cur_time;
00728 {
00729 if (fs_version == 1) {
00730 add_z_1(n, z, bytes, cur_time);
00731 } else {
00732 add_z_2(n, z, bytes, cur_time);
00733 }
00734 }
00735
00736 void add_z_1(n, z, bytes, cur_time)
00737 ino_t n;
00738 zone_t z;
00739 long bytes, cur_time;
00740 {
00741
00742
00743 int off, i;
00744 block_t b;
00745 zone_t indir;
00746 zone1_t blk[V1_INDIRECTS];
00747 d1_inode *p;
00748 d1_inode inode[V1_INODES_PER_BLOCK];
00749
00750 b = ((n - 1) / V1_INODES_PER_BLOCK) + inode_offset;
00751 off = (n - 1) % V1_INODES_PER_BLOCK;
00752 get_block(b, (char *) inode);
00753 p = &inode[off];
00754 p->d1_size += bytes;
00755 p->d1_mtime = cur_time;
00756 for (i = 0; i < V1_NR_DZONES; i++)
00757 if (p->d1_zone[i] == 0) {
00758 p->d1_zone[i] = (zone1_t) z;
00759 put_block(b, (char *) inode);
00760 return;
00761 }
00762 put_block(b, (char *) inode);
00763
00764
00765 if (p->d1_zone[V1_NR_DZONES] == 0)
00766 p->d1_zone[V1_NR_DZONES] = (zone1_t) alloc_zone();
00767 indir = p->d1_zone[V1_NR_DZONES];
00768 put_block(b, (char *) inode);
00769 b = indir << zone_shift;
00770 get_block(b, (char *) blk);
00771 for (i = 0; i < V1_INDIRECTS; i++)
00772 if (blk[i] == 0) {
00773 blk[i] = (zone1_t) z;
00774 put_block(b, (char *) blk);
00775 return;
00776 }
00777 pexit("File has grown beyond single indirect");
00778 }
00779
00780 void add_z_2(n, z, bytes, cur_time)
00781 ino_t n;
00782 zone_t z;
00783 long bytes, cur_time;
00784 {
00785
00786
00787 int off, i;
00788 block_t b;
00789 zone_t indir;
00790 zone_t *blk;
00791 d2_inode *p;
00792 d2_inode *inode;
00793
00794 if(!(blk = malloc(V2_INDIRECTS(block_size)*sizeof(*blk))))
00795 pexit("Couldn't allocate indirect block");
00796
00797 if(!(inode = malloc(V2_INODES_PER_BLOCK(block_size)*sizeof(*inode))))
00798 pexit("Couldn't allocate block of inodes");
00799
00800 b = ((n - 1) / V2_INODES_PER_BLOCK(block_size)) + inode_offset;
00801 off = (n - 1) % V2_INODES_PER_BLOCK(block_size);
00802 get_block(b, (char *) inode);
00803 p = &inode[off];
00804 p->d2_size += bytes;
00805 p->d2_mtime = cur_time;
00806 for (i = 0; i < V2_NR_DZONES; i++)
00807 if (p->d2_zone[i] == 0) {
00808 p->d2_zone[i] = z;
00809 put_block(b, (char *) inode);
00810 free(blk);
00811 free(inode);
00812 return;
00813 }
00814 put_block(b, (char *) inode);
00815
00816
00817 if (p->d2_zone[V2_NR_DZONES] == 0) p->d2_zone[V2_NR_DZONES] = alloc_zone();
00818 indir = p->d2_zone[V2_NR_DZONES];
00819 put_block(b, (char *) inode);
00820 b = indir << zone_shift;
00821 get_block(b, (char *) blk);
00822 for (i = 0; i < V2_INDIRECTS(block_size); i++)
00823 if (blk[i] == 0) {
00824 blk[i] = z;
00825 put_block(b, (char *) blk);
00826 free(blk);
00827 free(inode);
00828 return;
00829 }
00830 pexit("File has grown beyond single indirect");
00831 }
00832
00833
00834 void incr_link(n)
00835 ino_t n;
00836 {
00837
00838 int off;
00839 static int enter = 0;
00840 block_t b;
00841
00842 if(enter) exit(1);
00843
00844 b = ((n - 1) / inodes_per_block) + inode_offset;
00845 off = (n - 1) % inodes_per_block;
00846 if (fs_version == 1) {
00847 d1_inode inode1[V1_INODES_PER_BLOCK];
00848
00849 get_block(b, (char *) inode1);
00850 inode1[off].d1_nlinks++;
00851 put_block(b, (char *) inode1);
00852 } else {
00853 static d2_inode *inode2 = NULL;
00854 int n;
00855
00856 n = sizeof(*inode2) * V2_INODES_PER_BLOCK(block_size);
00857 if(!inode2 && !(inode2 = malloc(n)))
00858 pexit("couldn't allocate a block of inodes");
00859
00860 get_block(b, (char *) inode2);
00861 inode2[off].d2_nlinks++;
00862 put_block(b, (char *) inode2);
00863 }
00864 enter = 0;
00865 }
00866
00867
00868 void incr_size(n, count)
00869 ino_t n;
00870 long count;
00871 {
00872
00873 block_t b;
00874 int off;
00875
00876 b = ((n - 1) / inodes_per_block) + inode_offset;
00877 off = (n - 1) % inodes_per_block;
00878 if (fs_version == 1) {
00879 d1_inode inode1[V1_INODES_PER_BLOCK];
00880
00881 get_block(b, (char *) inode1);
00882 inode1[off].d1_size += count;
00883 put_block(b, (char *) inode1);
00884 } else {
00885 d2_inode *inode2;
00886 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
00887 pexit("couldn't allocate a block of inodes");
00888
00889 get_block(b, (char *) inode2);
00890 inode2[off].d2_size += count;
00891 put_block(b, (char *) inode2);
00892 free(inode2);
00893 }
00894 }
00895
00896
00897
00898
00899
00900 PRIVATE ino_t alloc_inode(mode, usrid, grpid)
00901 int mode, usrid, grpid;
00902 {
00903 ino_t num;
00904 int off;
00905 block_t b;
00906
00907 num = next_inode++;
00908 if (num > nrinodes) {
00909 fprintf(stderr, "have %d inodoes\n", nrinodes);
00910 pexit("File system does not have enough inodes");
00911 }
00912 b = ((num - 1) / inodes_per_block) + inode_offset;
00913 off = (num - 1) % inodes_per_block;
00914 if (fs_version == 1) {
00915 d1_inode inode1[V1_INODES_PER_BLOCK];
00916
00917 get_block(b, (char *) inode1);
00918 inode1[off].d1_mode = mode;
00919 inode1[off].d1_uid = usrid;
00920 inode1[off].d1_gid = grpid;
00921 put_block(b, (char *) inode1);
00922 } else {
00923 d2_inode *inode2;
00924
00925 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
00926 pexit("couldn't allocate a block of inodes");
00927
00928 get_block(b, (char *) inode2);
00929 inode2[off].d2_mode = mode;
00930 inode2[off].d2_uid = usrid;
00931 inode2[off].d2_gid = grpid;
00932 put_block(b, (char *) inode2);
00933
00934 free(inode2);
00935 }
00936
00937
00938
00939 insert_bit((block_t) INODE_MAP, (int) num);
00940 return(num);
00941 }
00942
00943
00944 PRIVATE zone_t alloc_zone()
00945 {
00946
00947
00948 block_t b;
00949 int i;
00950 zone_t z;
00951
00952 z = next_zone++;
00953 b = z << zone_shift;
00954 if ((b + zone_size) > nrblocks)
00955 pexit("File system not big enough for all the files");
00956 for (i = 0; i < zone_size; i++)
00957 put_block(b + i, zero);
00958
00959 insert_bit(zone_map, (int) (z - zoff));
00960
00961
00962
00963 return(z);
00964 }
00965
00966
00967 void insert_bit(block, bit)
00968 block_t block;
00969 int bit;
00970 {
00971
00972 int w, s;
00973 short *buf;
00974
00975 buf = (short *) alloc_block();
00976
00977 if (block < 0) pexit("insert_bit called with negative argument");
00978 get_block(block, (char *) buf);
00979 w = bit / (8 * sizeof(short));
00980 s = bit % (8 * sizeof(short));
00981 buf[w] |= (1 << s);
00982 put_block(block, (char *) buf);
00983
00984 free(buf);
00985 }
00986
00987
00988
00989
00990
00991 int mode_con(p)
00992 char *p;
00993 {
00994
00995 int o1, o2, o3, mode;
00996 char c1, c2, c3;
00997
00998 c1 = *p++;
00999 c2 = *p++;
01000 c3 = *p++;
01001 o1 = *p++ - '0';
01002 o2 = *p++ - '0';
01003 o3 = *p++ - '0';
01004 mode = (o1 << 6) | (o2 << 3) | o3;
01005 if (c1 == 'd') mode += I_DIRECTORY;
01006 if (c1 == 'b') mode += I_BLOCK_SPECIAL;
01007 if (c1 == 'c') mode += I_CHAR_SPECIAL;
01008 if (c1 == '-') mode += I_REGULAR;
01009 if (c2 == 'u') mode += I_SET_UID_BIT;
01010 if (c3 == 'g') mode += I_SET_GID_BIT;
01011 return(mode);
01012 }
01013
01014 void getline(line, parse)
01015 char *parse[MAX_TOKENS];
01016 char line[LINE_LEN];
01017 {
01018
01019 int k;
01020 char c, *p;
01021 int d;
01022
01023 for (k = 0; k < MAX_TOKENS; k++) parse[k] = 0;
01024 for (k = 0; k < LINE_LEN; k++) line[k] = 0;
01025 k = 0;
01026 parse[0] = 0;
01027 p = line;
01028 while (1) {
01029 if (++k > LINE_LEN) pexit("Line too long");
01030 d = fgetc(proto);
01031 if (d == EOF) pexit("Unexpected end-of-file");
01032 *p = d;
01033 if (*p == '\n') lct++;
01034 if (*p == ' ' || *p == '\t') *p = 0;
01035 if (*p == '\n') {
01036 *p++ = 0;
01037 *p = '\n';
01038 break;
01039 }
01040 p++;
01041 }
01042
01043 k = 0;
01044 p = line;
01045 lastp = line;
01046 while (1) {
01047 c = *p++;
01048 if (c == '\n') return;
01049 if (c == 0) continue;
01050 parse[k++] = p - 1;
01051 do {
01052 c = *p++;
01053 } while (c != 0 && c != '\n');
01054 }
01055 }
01056
01057
01058
01059
01060
01061 void check_mtab(devname)
01062 char *devname;
01063 {
01064
01065
01066 int n, r;
01067 struct stat sb;
01068 char special[PATH_MAX + 1], mounted_on[PATH_MAX + 1], version[10], rw_flag[10];
01069
01070 r= stat(devname, &sb);
01071 if (r == -1)
01072 {
01073 if (errno == ENOENT)
01074 return;
01075 fprintf(stderr, "%s: stat %s failed: %s\n",
01076 progname, devname, strerror(errno));
01077 exit(1);
01078 }
01079 if (!S_ISBLK(sb.st_mode))
01080 {
01081
01082 return;
01083 }
01084
01085 if (load_mtab("mkfs") < 0) return;
01086 while (1) {
01087 n = get_mtab_entry(special, mounted_on, version, rw_flag);
01088 if (n < 0) return;
01089 if (strcmp(devname, special) == 0) {
01090
01091 fprintf(stderr, "%s: %s is mounted on %s\n",
01092 progname, devname, mounted_on);
01093 exit(1);
01094 }
01095 }
01096 }
01097
01098
01099 long file_time(f)
01100 int f;
01101 {
01102 #ifdef UNIX
01103 struct stat statbuf;
01104 fstat(f, &statbuf);
01105 return(statbuf.st_mtime);
01106 #else
01107 return(0L);
01108 #endif
01109 }
01110
01111
01112 void pexit(s)
01113 char *s;
01114 {
01115 fprintf(stderr, "%s: %s\n", progname, s);
01116 if (lct != 0)
01117 fprintf(stderr, "Line %d being processed when error detected.\n", lct);
01118 flush();
01119 exit(2);
01120 }
01121
01122
01123 void copy(from, to, count)
01124 char *from, *to;
01125 int count;
01126 {
01127 while (count--) *to++ = *from++;
01128 }
01129
01130 char *alloc_block()
01131 {
01132 char *buf;
01133
01134 if(!(buf = malloc(block_size))) {
01135 pexit("couldn't allocate filesystem buffer");
01136 }
01137 bzero(buf, block_size);
01138
01139 return buf;
01140 }
01141
01142 void print_fs()
01143 {
01144 int i, j;
01145 ino_t k;
01146 d1_inode inode1[V1_INODES_PER_BLOCK];
01147 d2_inode *inode2;
01148 unsigned short *usbuf;
01149 block_t b, inode_limit;
01150 struct direct *dir;
01151
01152 if(!(inode2 = malloc(V2_INODES_PER_BLOCK(block_size) * sizeof(*inode2))))
01153 pexit("couldn't allocate a block of inodes");
01154
01155 if(!(dir = malloc(NR_DIR_ENTRIES(block_size)*sizeof(*dir))))
01156 pexit("malloc of directory entry failed");
01157
01158 usbuf = (unsigned short *) alloc_block();
01159
01160 get_super_block((char *) usbuf);
01161 printf("\nSuperblock: ");
01162 for (i = 0; i < 8; i++) printf("%06o ", usbuf[i]);
01163 get_block((block_t) 2, (char *) usbuf);
01164 printf("...\nInode map: ");
01165 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
01166 get_block((block_t) 3, (char *) usbuf);
01167 printf("...\nZone map: ");
01168 for (i = 0; i < 9; i++) printf("%06o ", usbuf[i]);
01169 printf("...\n");
01170
01171 free(usbuf);
01172 usbuf = NULL;
01173
01174 k = 0;
01175 for (b = inode_offset; k < nrinodes; b++) {
01176 if (fs_version == 1) {
01177 get_block(b, (char *) inode1);
01178 } else {
01179 get_block(b, (char *) inode2);
01180 }
01181 for (i = 0; i < inodes_per_block; i++) {
01182 k = inodes_per_block * (int) (b - inode_offset) + i + 1;
01183
01184 if (k > nrinodes) break;
01185 if (fs_version == 1) {
01186 if (inode1[i].d1_mode != 0) {
01187 printf("Inode %2d: mode=", k);
01188 printf("%06o", inode1[i].d1_mode);
01189 printf(" uid=%2d gid=%2d size=",
01190 inode1[i].d1_uid, inode1[i].d1_gid);
01191 printf("%6ld", inode1[i].d1_size);
01192 printf(" zone[0]=%d\n", inode1[i].d1_zone[0]);
01193 }
01194 if ((inode1[i].d1_mode & I_TYPE) == I_DIRECTORY) {
01195
01196 get_block(inode1[i].d1_zone[0], (char *) dir);
01197 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
01198 if (dir[j].d_ino)
01199 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
01200 }
01201 } else {
01202 if (inode2[i].d2_mode != 0) {
01203 printf("Inode %2d: mode=", k);
01204 printf("%06o", inode2[i].d2_mode);
01205 printf(" uid=%2d gid=%2d size=",
01206 inode2[i].d2_uid, inode2[i].d2_gid);
01207 printf("%6ld", inode2[i].d2_size);
01208 printf(" zone[0]=%ld\n", inode2[i].d2_zone[0]);
01209 }
01210 if ((inode2[i].d2_mode & I_TYPE) == I_DIRECTORY) {
01211
01212 get_block(inode2[i].d2_zone[0], (char *) dir);
01213 for (j = 0; j < NR_DIR_ENTRIES(block_size); j++)
01214 if (dir[j].d_ino)
01215 printf("\tInode %2d: %s\n", dir[j].d_ino, dir[j].d_name);
01216 }
01217 }
01218 }
01219 }
01220
01221 printf("%d inodes used. %d zones used.\n", next_inode - 1, next_zone);
01222 free(dir);
01223 free(inode2);
01224 }
01225
01226
01227 int read_and_set(n)
01228 block_t n;
01229 {
01230
01231
01232
01233
01234 int w, s, mask, r;
01235
01236 if (sizeof(char *) == 2 && n >= MAX_INIT) pexit("can't initialize past 128M");
01237 w = n / 8;
01238 s = n % 8;
01239 mask = 1 << s;
01240 r = (umap[w] & mask ? 1 : 0);
01241 umap[w] |= mask;
01242 return(r);
01243 }
01244
01245 void usage()
01246 {
01247 fprintf(stderr,
01248 "Usage: %s [-12dlot] [-b blocks] [-i inodes] [-B blocksize] special [proto]\n",
01249 progname);
01250 exit(1);
01251 }
01252
01253
01254
01255
01256 #ifdef DOS
01257
01258
01259
01260
01261
01262
01263
01264
01265
01266
01267
01268
01269
01270
01271
01272
01273 #define PH_SECTSIZE 512
01274
01275
01276 char *derrtab[14] = {
01277 "no error",
01278 "disk is read-only",
01279 "unknown unit",
01280 "device not ready",
01281 "bad command",
01282 "data error",
01283 "internal error: bad request structure length",
01284 "seek error",
01285 "unknown media type",
01286 "sector not found",
01287 "printer out of paper (?)",
01288 "write fault",
01289 "read error",
01290 "general error"
01291 };
01292
01293 #define CACHE_SIZE 20
01294
01295
01296 struct cache {
01297 char blockbuf[BLOCK_SIZE];
01298 block_t blocknum;
01299 int dirty;
01300 int usecnt;
01301 } cache[CACHE_SIZE];
01302
01303
01304 void special(string)
01305 char *string;
01306 {
01307
01308 if (string[1] == ':' && string[2] == 0) {
01309
01310 disk = (string[0] & ~32) - 'A';
01311 if (disk > 1 && !override)
01312 pexit("Bad drive specifier for special");
01313 } else {
01314 file = 1;
01315 if ((fd = creat(string, BWRITE)) == 0)
01316 pexit("Can't open special file");
01317 }
01318 }
01319
01320 void get_block(n, buf)
01321 block_t n;
01322 char *buf;
01323 {
01324
01325 struct cache *bp, *fp;
01326
01327
01328 if (read_and_set(n) == 0) {
01329 copy(zero, buf, block_size);
01330 return;
01331 }
01332
01333
01334 fp = 0;
01335 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
01336 if (bp->blocknum == n) {
01337 copy(bp, buf, block_size);
01338 bp->usecnt++;
01339 return;
01340 }
01341
01342
01343 if (bp->dirty == 0)
01344 if (fp) {
01345 if (fp->usecnt > bp->usecnt) fp = bp;
01346 } else
01347 fp = bp;
01348 }
01349
01350
01351 if (!fp) {
01352
01353 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
01354 if (fp->usecnt > bp->usecnt) fp = bp;
01355 mx_write(fp->blocknum, fp);
01356 }
01357 mx_read(n, fp);
01358 fp->dirty = 0;
01359 fp->usecnt = 0;
01360 fp->blocknum = n;
01361 copy(fp, buf, block_size);
01362 }
01363
01364 void put_block(n, buf)
01365 block_t n;
01366 char *buf;
01367 {
01368
01369 struct cache *fp, *bp;
01370
01371 (void) read_and_set(n);
01372
01373
01374 fp = 0;
01375 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) {
01376 if (bp->blocknum == n) {
01377 copy(buf, bp, block_size);
01378 bp->dirty = 1;
01379 return;
01380 }
01381
01382
01383 if (bp->dirty == 0)
01384 if (fp) {
01385 if (fp->usecnt > bp->usecnt) fp = bp;
01386 } else
01387 fp = bp;
01388 }
01389
01390
01391 if (!fp) {
01392
01393 for (bp = cache, fp = cache; bp < &cache[CACHE_SIZE]; bp++)
01394 if (fp->usecnt > bp->usecnt) fp = bp;
01395 mx_write(fp->blocknum, fp);
01396 }
01397 fp->dirty = 1;
01398 fp->usecnt = 1;
01399 fp->blocknum = n;
01400 copy(buf, fp, block_size);
01401 }
01402
01403 void cache_init()
01404 {
01405 struct cache *bp;
01406 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++) bp->blocknum = -1;
01407 }
01408
01409 void flush()
01410 {
01411
01412 struct cache *bp;
01413
01414 for (bp = cache; bp < &cache[CACHE_SIZE]; bp++)
01415 if (bp->dirty) {
01416 mx_write(bp->blocknum, bp);
01417 bp->dirty = 0;
01418 }
01419 }
01420
01421
01422
01423
01424 #define MAX_RETRIES 5
01425
01426
01427 void mx_read(blocknr, buf)
01428 int blocknr;
01429 char *buf;
01430 {
01431
01432
01433 char (*bp)[PH_SECTSIZE];
01434 int sectnum, retries, err;
01435
01436 if (file) {
01437 lseek(fd, (off_t) blocknr * block_size, 0);
01438 if (read(fd, buf, block_size) != block_size)
01439 pexit("mx_read: error reading file");
01440 } else {
01441 sectnum = blocknr * (block_size / PH_SECTSIZE);
01442 for (bp = buf; bp < &buf[block_size]; bp++) {
01443 retries = MAX_RETRIES;
01444 do
01445 err = absread(disk, sectnum, bp);
01446 while (err && --retries);
01447
01448 if (retries) {
01449 sectnum++;
01450 } else {
01451 dexit("mx_read", sectnum, err);
01452 }
01453 }
01454 }
01455 }
01456
01457 void mx_write(blocknr, buf)
01458 int blocknr;
01459 char *buf;
01460 {
01461
01462 char (*bp)[PH_SECTSIZE];
01463 int retries, sectnum, err;
01464
01465 if (file) {
01466 lseek(fd, blocknr * block_size, 0);
01467 if (write(fd, buf, block_size) != block_size) {
01468 pexit("mx_write: error writing file");
01469 }
01470 } else {
01471 sectnum = blocknr * (block_size / PH_SECTSIZE);
01472 for (bp = buf; bp < &buf[block_size]; bp++) {
01473 retries = MAX_RETRIES;
01474 do {
01475 err = abswrite(disk, sectnum, bp);
01476 } while (err && --retries);
01477
01478 if (retries) {
01479 sectnum++;
01480 } else {
01481 dexit("mx_write", sectnum, err);
01482 }
01483 }
01484 }
01485 }
01486
01487
01488 void dexit(s, sectnum, err)
01489 int sectnum, err;
01490 char *s;
01491 {
01492 printf("Error: %s, sector: %d, code: %d, meaning: %s\n",
01493 s, sectnum, err, derrtab[err]);
01494 exit(2);
01495 }
01496
01497 #endif
01498
01499
01500
01501
01502 #ifdef UNIX
01503
01504 void special(string)
01505 char *string;
01506 {
01507 fd = creat(string, 0777);
01508 close(fd);
01509 fd = open(string, O_RDWR);
01510 if (fd < 0) pexit("Can't open special file");
01511 #if (MACHINE == ATARI)
01512 {
01513 struct stat statbuf;
01514
01515 if (fstat(fd, &statbuf) < 0) return;
01516 isdev = (statbuf.st_mode & S_IFMT) == S_IFCHR
01517 ||
01518 (statbuf.st_mode & S_IFMT) == S_IFBLK
01519 ;
01520 }
01521 #endif
01522 }
01523
01524
01525
01526 void get_block(n, buf)
01527 block_t n;
01528 char *buf;
01529 {
01530
01531
01532 int k;
01533
01534
01535 if (read_and_set(n) == 0) {
01536 copy(zero, buf, block_size);
01537 return;
01538 }
01539 lseek(fd, (off_t) n * block_size, SEEK_SET);
01540 k = read(fd, buf, block_size);
01541 if (k != block_size) {
01542 pexit("get_block couldn't read");
01543 }
01544 }
01545
01546 void get_super_block(buf)
01547 char *buf;
01548 {
01549
01550
01551 int k;
01552
01553 if(lseek(fd, (off_t) SUPER_BLOCK_BYTES, SEEK_SET) < 0) {
01554 perror("lseek");
01555 pexit("seek failed");
01556 }
01557 k = read(fd, buf, _STATIC_BLOCK_SIZE);
01558 if (k != _STATIC_BLOCK_SIZE) {
01559 pexit("get_super_block couldn't read");
01560 }
01561 }
01562
01563 void put_block(n, buf)
01564 block_t n;
01565 char *buf;
01566 {
01567
01568
01569 (void) read_and_set(n);
01570
01571
01572 if (lseek(fd, (off_t) n * block_size, SEEK_SET) == (off_t) -1) {
01573 pexit("put_block couldn't seek");
01574 }
01575 if (write(fd, buf, block_size) != block_size) {
01576 pexit("put_block couldn't write");
01577 }
01578 }
01579
01580
01581
01582
01583 void flush()
01584 {
01585 return;
01586 }
01587
01588 void cache_init()
01589 {
01590 return;
01591 }
01592
01593 #endif