Unify process_alloc() and process_realloc() with PROCESS_ALLOC_MODE_REALLOC bit
[moveable_pool.git] / fuzix_fs.c
1 #include <assert.h> // Nick
2 #include <stdio.h>
3 #include <string.h>
4 #include <time.h>
5 #include <unistd.h>
6 #define UCP 1
7 #include "fuzix_fs.h"
8 #include "util.h"
9
10 #if 0
11 struct oft of_tab[OFTSIZE]; /* Open File Table */
12 #endif
13
14 inoptr root;
15 struct cinode i_tab[ITABSIZE];
16 struct filesys fs_tab[1];
17 long/*uint16_t*/ bufclock;              /* Time-stamp counter for LRU */
18 struct blkbuf bufpool[NBUFS];
19 struct u_data udata;
20
21 static void fs_init(void)
22 {
23         udata.u_euid = 0;
24         udata.u_insys = 1;
25 }
26
27 void xfs_init(int bootdev)
28 {
29         register char *j;
30
31         fs_init();
32         bufinit();
33
34         /* User's file table */
35         for (j = udata.u_files; j < (udata.u_files + UFTSIZE); ++j)
36                 *j = -1;
37
38         /* Mount the root device */
39         if (fmount(ROOTDEV, NULLINODE))
40                 panic("no filesys");
41
42         ifnot(root = i_open(ROOTDEV, ROOTINODE))
43             panic("no root");
44
45         i_ref(udata.u_cwd = root);
46 }
47
48
49 #if 0
50 void xfs_end(void)
51 {
52         register int16_t j;
53
54         for (j = 0; j < UFTSIZE; ++j) {
55                 ifnot(udata.u_files[j] & 0x80)  /* Portable equivalent of == -1 */
56                     doclose(j);
57         }
58 }
59
60
61 int fuzix_open(char *name, int16_t flag)
62 {
63         int16_t uindex;
64         register int16_t oftindex;
65         register inoptr ino;
66
67         udata.u_error = 0;
68
69         if (flag < 0 || flag > 2) {
70                 udata.u_error = EINVAL;
71                 return (-1);
72         }
73         if ((uindex = uf_alloc()) == -1)
74                 return (-1);
75
76         if ((oftindex = oft_alloc()) == -1)
77                 goto nooft;
78
79         ifnot(ino = n_open(name, NULLINOPTR))
80             goto cantopen;
81
82         of_tab[oftindex].o_inode = ino;
83
84         if (fuzix_getmode(ino) == F_DIR &&
85             (flag == FO_WRONLY || flag == FO_RDWR)) {
86                 udata.u_error = EISDIR;
87                 goto cantopen;
88         }
89
90         if (isdevice(ino))      /* && d_open((int)ino->c_node.i_addr[0]) != 0) */
91         {
92                 udata.u_error = ENXIO;
93                 goto cantopen;
94         }
95
96         udata.u_files[uindex] = oftindex;
97
98         of_tab[oftindex].o_ptr = 0;
99         of_tab[oftindex].o_access = flag;
100
101         return (uindex);
102
103       cantopen:
104         oft_deref(oftindex);    /* This will call i_deref() */
105       nooft:
106         udata.u_files[uindex] = -1;
107         return (-1);
108 }
109
110 int doclose(int16_t uindex)
111 {
112         register int16_t oftindex;
113         inoptr ino;
114
115         udata.u_error = 0;
116         ifnot(ino = getinode(uindex))
117             return (-1);
118         oftindex = udata.u_files[uindex];
119
120 #if 0
121         if (isdevice(ino)
122             /* && ino->c_refs == 1 && of_tab[oftindex].o_refs == 1 */ )
123             d_close((int)(ino->c_node.i_addr[0]));
124 #endif
125
126         udata.u_files[uindex] = -1;
127         oft_deref(oftindex);
128
129         return (0);
130 }
131
132 int fuzix_close(int16_t uindex)
133 {
134         udata.u_error = 0;
135         return (doclose(uindex));
136 }
137
138 int fuzix_creat(char *name, int16_t mode)
139 {
140         register inoptr ino;
141         register int16_t uindex;
142         register int16_t oftindex;
143         inoptr parent;
144         register int16_t j;
145
146         udata.u_error = 0;
147         parent = NULLINODE;
148
149         if ((uindex = uf_alloc()) == -1)
150                 return (-1);
151         if ((oftindex = oft_alloc()) == -1)
152                 return (-1);
153
154         ino = n_open(name, &parent);
155         if (ino) {
156                 i_deref(parent);
157                 if (fuzix_getmode(ino) == F_DIR) {
158                         i_deref(ino);
159                         udata.u_error = EISDIR;
160                         goto nogood;
161                 }
162                 if (fuzix_getmode(ino) == F_REG) {
163                         /* Truncate the file to zero length */
164                         udata.u_offset = 0;
165                         f_trunc(ino);
166                         /* Reset any oft pointers */
167                         for (j = 0; j < OFTSIZE; ++j)
168                                 if (of_tab[j].o_inode == ino)
169                                         of_tab[j].o_ptr = 0;
170                 }
171         } else {
172                 if (parent && (ino = newfile(parent, name)))
173                         /* Parent was derefed in newfile */
174                 {
175                         ino->c_node.i_mode =
176                             swizzle16(F_REG |
177                                       (mode & MODE_MASK & ~udata.u_mask));
178                         setftime(ino, A_TIME | M_TIME | C_TIME);
179                         /* The rest of the inode is initialized in newfile() */
180                         wr_inode(ino);
181                 } else {
182                         /* Doesn't exist and can't make it */
183                         goto nogood;
184                 }
185         }
186         udata.u_files[uindex] = oftindex;
187
188         of_tab[oftindex].o_ptr = 0;
189         of_tab[oftindex].o_inode = ino;
190         of_tab[oftindex].o_access = FO_WRONLY;
191
192         return (uindex);
193
194       nogood:
195         oft_deref(oftindex);
196         return (-1);
197 }
198
199 int fuzix_link(char *name1, char *name2)
200 {
201         register inoptr ino;
202         register inoptr ino2;
203         inoptr parent2;
204
205         udata.u_error = 0;
206         ifnot(ino = n_open(name1, NULLINOPTR))
207             return (-1);
208
209         /* Make sure file2 doesn't exist, and get its parent */
210         if ((ino2 = n_open(name2, &parent2))) {
211                 i_deref(ino2);
212                 i_deref(parent2);
213                 udata.u_error = EEXIST;
214                 goto nogood;
215         }
216
217         ifnot(parent2)
218             goto nogood;
219
220         if (ino->c_dev != parent2->c_dev) {
221                 i_deref(parent2);
222                 udata.u_error = EXDEV;
223                 goto nogood;
224         }
225
226         if (ch_link(parent2, "", filename(name2), ino) == 0)
227                 goto nogood;
228
229         /* Update the link count. */
230         ino->c_node.i_nlink =
231             swizzle16(swizzle16(ino->c_node.i_nlink) + 1);
232         wr_inode(ino);
233         setftime(ino, C_TIME);
234
235         i_deref(parent2);
236         i_deref(ino);
237         return (0);
238
239       nogood:
240         i_deref(ino);
241         return (-1);
242 }
243
244 int fuzix_unlink(char *path)
245 {
246         register inoptr ino;
247         inoptr pino;
248
249         udata.u_error = 0;
250         ino = n_open(path, &pino);
251
252         ifnot(pino && ino) {
253                 udata.u_error = ENOENT;
254                 return (-1);
255         }
256
257         /* Remove the directory entry */
258
259         if (ch_link(pino, filename(path), "", NULLINODE) == 0)
260                 goto nogood;
261
262         /* Decrease the link count of the inode */
263
264         if (ino->c_node.i_nlink == 0) {
265                 ino->c_node.i_nlink =
266                     swizzle16(swizzle16(ino->c_node.i_nlink) + 2);
267                 printf("fuzix_unlink: bad nlink\n");
268         } else
269                 ino->c_node.i_nlink =
270                     swizzle16(swizzle16(ino->c_node.i_nlink) - 1);
271         setftime(ino, C_TIME);
272         i_deref(pino);
273         i_deref(ino);
274         return (0);
275       nogood:
276         i_deref(pino);
277         i_deref(ino);
278         return (-1);
279 }
280
281 uint16_t fuzix_read(int16_t d, char *buf, uint16_t nbytes)
282 {
283         register inoptr ino;
284         uint16_t r;
285
286         udata.u_error = 0;
287         /* Set up u_base, u_offset, ino; check permissions, file num. */
288         if ((ino = rwsetup(1, d, buf, nbytes)) == NULLINODE)
289                 return (-1);    /* bomb out if error */
290
291         r = readi(ino);
292         updoff(d);
293         return r;
294 }
295
296 uint16_t fuzix_write(int16_t d, char *buf, uint16_t nbytes)
297 {
298         register inoptr ino;
299         uint16_t r;
300
301         udata.u_error = 0;
302         /* Set up u_base, u_offset, ino; check permissions, file num. */
303         if ((ino = rwsetup(0, d, buf, nbytes)) == NULLINODE)
304                 return (-1);    /* bomb out if error */
305
306         r = writei(ino);
307         updoff(d);
308
309         return r;
310 }
311
312 inoptr rwsetup(int rwflag, int d, char *buf, int nbytes)
313 {
314         register inoptr ino;
315         register struct oft *oftp;
316
317         udata.u_base = buf;
318         udata.u_count = nbytes;
319
320         if ((ino = getinode(d)) == NULLINODE)
321                 return (NULLINODE);
322
323         oftp = of_tab + udata.u_files[d];
324         if (oftp->o_access == (rwflag ? FO_WRONLY : FO_RDONLY)) {
325                 udata.u_error = EBADF;
326                 return (NULLINODE);
327         }
328
329         setftime(ino, rwflag ? A_TIME : (A_TIME | M_TIME | C_TIME));
330
331         /* Initialize u_offset from file pointer */
332         udata.u_offset = oftp->o_ptr;
333
334         return (ino);
335 }
336 #endif
337
338 uint16_t readi(inoptr ino)
339 {
340         register uint16_t amount;
341         register uint16_t toread;
342         register blkno_t pblk;
343         register char *bp;
344
345         switch (fuzix_getmode(ino)) {
346
347         case F_DIR:
348         case F_REG:
349
350                 /* See of end of file will limit read */
351                 toread = udata.u_count =
352                     min(udata.u_count,
353                         swizzle32(ino->c_node.i_size) - udata.u_offset);
354                 while (toread) {
355                         if ((pblk =
356                              bmap(ino, udata.u_offset >> 9, 1)) != NULLBLK)
357                                 bp = bread(0, pblk, 0);
358                         else
359                                 bp = zerobuf();
360
361                         bcopy(bp + (udata.u_offset & 511), udata.u_base,
362                               (amount =
363                                min(toread, 512 - (udata.u_offset & 511))));
364                         brelse((bufptr) bp);
365
366                         udata.u_base += amount;
367                         udata.u_offset += amount;
368                         toread -= amount;
369                 }
370                 return udata.u_count - toread;
371
372         default:
373                 udata.u_error = ENODEV;
374         }
375         return 0;
376 }
377
378
379
380 /* Writei (and readi) need more i/o error handling */
381
382 uint16_t writei(inoptr ino)
383 {
384         register uint16_t amount;
385         register uint16_t towrite;
386         register char *bp;
387         blkno_t pblk;
388
389         switch (fuzix_getmode(ino)) {
390
391         case F_DIR:
392         case F_REG:
393                 towrite = udata.u_count;
394                 while (towrite) {
395                         amount =
396                             min(towrite, 512 - (udata.u_offset & 511));
397
398                         if ((pblk =
399                              bmap(ino, udata.u_offset >> 9, 0)) == NULLBLK)
400                                 break;  /* No space to make more blocks */
401
402                         /* If we are writing an entire block, we don't care
403                            about its previous contents */
404                         bp = bread(0, pblk, (amount == 512));
405
406                         bcopy(udata.u_base, bp + (udata.u_offset & 511),
407                               amount);
408                         bawrite((bufptr) bp);
409
410                         udata.u_base += amount;
411                         udata.u_offset += amount;
412                         towrite -= amount;
413                 }
414
415                 /* Update size if file grew */
416                 if (udata.u_offset > swizzle32(ino->c_node.i_size)) {
417                         ino->c_node.i_size = swizzle32(udata.u_offset);
418                         ino->c_dirty = 1;
419                 }
420
421                 return udata.u_count - towrite; // Nick bugfix
422
423         default:
424                 udata.u_error = ENODEV;
425         }
426         return udata.u_count;
427 }
428
429
430
431 #if 0
432 void updoff(int d)
433 {
434         /* Update current file pointer */
435         of_tab[(int)udata.u_files[d]].o_ptr = udata.u_offset;
436 }
437
438 static int valadr(char *base, uint16_t size)
439 {
440         return (1);
441 }
442
443
444 int fuzix_mknod(char *name, int16_t mode, int16_t dev)
445 {
446         register inoptr ino;
447         inoptr parent;
448
449         udata.u_error = 0;
450
451         if ((ino = n_open(name, &parent))) {
452                 udata.u_error = EEXIST;
453                 goto nogood;
454         }
455
456         ifnot(parent) {
457                 udata.u_error = ENOENT;
458                 return (-1);
459         }
460
461         ifnot(ino = newfile(parent, name))
462             goto nogood2;
463
464         /* Initialize mode and dev */
465         ino->c_node.i_mode = swizzle16(mode & ~udata.u_mask);
466         ino->c_node.i_addr[0] = swizzle16(isdevice(ino) ? dev : 0);
467         setftime(ino, A_TIME | M_TIME | C_TIME);
468         wr_inode(ino);
469
470         i_deref(ino);
471         return (0);
472
473       nogood:
474         i_deref(ino);
475       nogood2:
476         i_deref(parent);
477         return (-1);
478 }
479 #endif
480
481 void fuzix_sync(void)
482 {
483         int j;
484         inoptr ino;
485         char *buf;
486
487         /* Write out modified inodes */
488
489         udata.u_error = 0;
490         for (ino = i_tab; ino < i_tab + ITABSIZE; ++ino)
491                 if ((ino->c_refs) > 0 && ino->c_dirty != 0) {
492                         wr_inode(ino);
493                         ino->c_dirty = 0;
494                 }
495
496         /* Write out modified super blocks */
497         /* This fills the rest of the super block with garbage. */
498
499         for (j = 0; j < NDEVS; ++j) {
500                 if (swizzle16(fs_tab[j].s_mounted) == SMOUNTED
501                     && fs_tab[j].s_fmod) {
502                         fs_tab[j].s_fmod = 0;
503                         buf = bread(j, 1, 1);
504                         bcopy((char *) &fs_tab[j], buf, 512);
505                         bfree((bufptr) buf, 2);
506                 }
507         }
508         bufsync();              /* Clear buffer pool */
509 }
510
511 #if 0
512 int fuzix_chdir(char *dir)
513 {
514         register inoptr newcwd;
515
516         udata.u_error = 0;
517         ifnot(newcwd = n_open(dir, NULLINOPTR))
518             return (-1);
519
520         if (fuzix_getmode(newcwd) != F_DIR) {
521                 udata.u_error = ENOTDIR;
522                 i_deref(newcwd);
523                 return (-1);
524         }
525         i_deref(udata.u_cwd);
526         udata.u_cwd = newcwd;
527         return (0);
528 }
529 #endif
530
531 int min(int a, int b)
532 {
533         return (a < b ? a : b);
534 }
535
536 #if 0
537 int fuzix_chmod(char *path, int16_t mode)
538 {
539         inoptr ino;
540
541         udata.u_error = 0;
542         ifnot(ino = n_open(path, NULLINOPTR))
543             return (-1);
544
545         ino->c_node.i_mode =
546             swizzle16((mode & MODE_MASK) |
547                       (swizzle16(ino->c_node.i_mode) & F_MASK));
548         setftime(ino, C_TIME);
549         i_deref(ino);
550         return (0);
551 }
552
553 int fuzix_stat(char *path, struct uzi_stat *buf)
554 {
555         register inoptr ino;
556
557         udata.u_error = 0;
558         ifnot(valadr((char *) buf, sizeof(struct uzi_stat))
559               && (ino = n_open(path, NULLINOPTR))) {
560                 return (-1);
561         }
562         stcpy(ino, buf);
563         i_deref(ino);
564         return (0);
565 }
566
567 /* Utility for stat and fstat */
568 void stcpy(inoptr ino, struct uzi_stat *buf)
569 {
570         struct uzi_stat *b = (struct uzi_stat *) buf;
571
572         b->st_dev = swizzle16(ino->c_dev);
573         b->st_ino = swizzle16(ino->c_num);
574         b->st_mode = swizzle16(ino->c_node.i_mode);
575         b->st_nlink = swizzle16(ino->c_node.i_nlink);
576         b->st_uid = swizzle16(ino->c_node.i_uid);
577         b->st_gid = swizzle16(ino->c_node.i_gid);
578
579         b->st_rdev = swizzle16(ino->c_node.i_addr[0]);
580
581         b->st_size = swizzle32(ino->c_node.i_size);
582         b->fst_atime = swizzle32(ino->c_node.i_atime);
583         b->fst_mtime = swizzle32(ino->c_node.i_mtime);
584         b->fst_ctime = swizzle32(ino->c_node.i_ctime);
585 }
586
587 /* Special system call returns super-block of given filesystem for
588  * users to determine free space, etc.  Should be replaced with a
589  * sync() followed by a read of block 1 of the device.
590  */
591
592 int fuzix_getfsys(int dev, char *buf)
593 {
594         udata.u_error = 0;
595         if (dev < 0 || dev >= NDEVS
596             || swizzle16(fs_tab[dev].s_mounted) != SMOUNTED) {
597                 udata.u_error = ENXIO;
598                 return (-1);
599         }
600
601         /* FIXME: endiam swapping here */
602         bcopy((char *) &fs_tab[dev], (char *) buf, sizeof(struct filesys));
603         return (0);
604 }
605
606 int fuzix_mkdir(char *name, int mode)
607 {
608         inoptr ino;
609         inoptr parent;
610         char fname[FILENAME_LEN + 1];
611
612         if ((ino = n_open(name, &parent)) != NULL) {
613                 udata.u_error = EEXIST;
614                 goto nogood;
615         }
616
617         if (!parent) {
618                 udata.u_error = ENOENT;
619                 return (-1);
620         }
621
622         if (swizzle16(parent->c_node.i_nlink) == 0xFFFF) {
623                 udata.u_error = EMLINK;
624                 goto nogood2;
625         }
626
627         filename_2(name, fname);
628
629         i_ref(parent);          /* We need it again in a minute */
630         if (!(ino = newfile(parent, fname))) {
631                 i_deref(parent);
632                 goto nogood2;   /* parent inode is derefed in newfile. */
633         }
634
635         /* Initialize mode and dev */
636         ino->c_node.i_mode = swizzle16(F_DIR | 0200);   /* so ch_link is allowed */
637         setftime(ino, A_TIME | M_TIME | C_TIME);
638         if (ch_link(ino, "", ".", ino) == 0 ||
639             ch_link(ino, "", "..", parent) == 0)
640                 goto cleanup;
641
642         /* Link counts and permissions */
643         ino->c_node.i_nlink = swizzle16(2);
644         parent->c_node.i_nlink =
645             swizzle16(swizzle16(parent->c_node.i_nlink) + 1);
646         ino->c_node.i_mode = swizzle16(((mode & ~udata.u_mask) & MODE_MASK) | F_DIR);
647         i_deref(parent);
648         wr_inode(ino);
649         i_deref(ino);
650         return (0);
651
652       cleanup:
653         if (!ch_link(parent, fname, "", NULLINODE))
654                 fprintf(stderr, "mkdir: bad rec\n");
655         /* i_deref will put the blocks */
656         ino->c_node.i_nlink = 0;
657         wr_inode(ino);
658       nogood:
659         i_deref(ino);
660       nogood2:
661         i_deref(parent);
662         return (-1);
663
664 }
665
666 inoptr n_open(register char *name, register inoptr * parent)
667 {
668         register inoptr wd;     /* the directory we are currently searching. */
669         register inoptr ninode;
670
671         if (*name == '/')
672                 wd = root;
673         else
674                 wd = udata.u_cwd;
675
676         i_ref(ninode = wd);
677         i_ref(ninode);
678
679         for (;;) {
680                 if (ninode)
681                         magic(ninode);
682
683                 /* See if we are at a mount point */
684                 if (ninode)
685                         ninode = srch_mt(ninode);
686
687                 while (*name == '/')    /* Skip (possibly repeated) slashes */
688                         ++name;
689                 ifnot(*name)    /* No more components of path? */
690                     break;
691                 ifnot(ninode) {
692                         udata.u_error = ENOENT;
693                         goto nodir;
694                 }
695                 i_deref(wd);
696                 wd = ninode;
697                 if (fuzix_getmode(wd) != F_DIR) {
698                         udata.u_error = ENOTDIR;
699                         goto nodir;
700                 }
701
702                 ninode = srch_dir(wd, name);
703
704                 while (*name != '/' && *name)
705                         ++name;
706         }
707
708         if (parent)
709                 *parent = wd;
710         else
711                 i_deref(wd);
712         ifnot(parent || ninode)
713             udata.u_error = ENOENT;
714         return (ninode);
715
716 nodir:
717         if (parent)
718                 *parent = NULLINODE;
719         i_deref(wd);
720         return (NULLINODE);
721
722 }
723
724
725
726 /* Srch_dir is given a inode pointer of an open directory and a string
727  * containing a filename, and searches the directory for the file.  If
728  * it exists, it opens it and returns the inode pointer, otherwise NULL.
729  * This depends on the fact that ba_read will return unallocated blocks
730  * as zero-filled, and a partially allocated block will be padded with
731  * zeroes.
732  */
733
734 inoptr srch_dir(inoptr wd, register char *compname)
735 {
736         register int curentry;
737         register blkno_t curblock;
738         register struct direct *buf;
739         register int nblocks;
740         unsigned inum;
741
742         nblocks = (swizzle32(wd->c_node.i_size) + 511) >> 9;
743
744         for (curblock = 0; curblock < nblocks; ++curblock) {
745                 buf =
746                     (struct direct *) bread(wd->c_dev,
747                                             bmap(wd, curblock, 1), 0);
748                 for (curentry = 0; curentry < 16; ++curentry) {
749                         if (namecomp(compname, buf[curentry].d_name)) {
750                                 inum =
751                                     swizzle16(buf[curentry & 0x0f].d_ino);
752                                 brelse((bufptr) buf);
753                                 return (i_open(wd->c_dev, inum));
754                         }
755                 }
756                 brelse((bufptr) buf);
757         }
758         return (NULLINODE);
759 }
760
761
762 /* Srch_mt sees if the given inode is a mount point. If so it
763  * dereferences it, and references and returns a pointer to the
764  * root of the mounted filesystem.
765  */
766
767 inoptr srch_mt(inoptr ino)
768 {
769         register int j;
770
771         for (j = 0; j < NDEVS; ++j)
772                 if (swizzle16(fs_tab[j].s_mounted) == SMOUNTED
773                     && fs_tab[j].s_mntpt == ino) {
774                         i_deref(ino);
775                         return (i_open(j, ROOTINODE));
776                 }
777
778         return (ino);
779 }
780 #endif
781
782
783 /* I_open is given an inode number and a device number,
784  * and makes an entry in the inode table for them, or
785  * increases it reference count if it is already there.
786  * An inode # of zero means a newly allocated inode.
787  */
788
789 inoptr i_open(register int dev, register unsigned ino)
790 {
791
792         struct dinode *buf;
793         register inoptr nindex;
794         int i;
795         register inoptr j;
796         int new;
797         static inoptr nexti = i_tab;    /* added inoptr. 26.12.97  HFB */
798
799         if (dev < 0 || dev >= NDEVS)
800                 panic("i_open: Bad dev");
801
802         new = 0;
803         ifnot(ino) {            /* Want a new one */
804                 new = 1;
805                 ifnot(ino = i_alloc(dev)) {
806                         udata.u_error = ENOSPC;
807                         return (NULLINODE);
808                 }
809         }
810
811         if (ino < ROOTINODE || ino >= (swizzle16(fs_tab[dev].s_isize) - 2) * 8) {
812                 printf("i_open: bad inode number\n");
813                 return (NULLINODE);
814         }
815
816
817         nindex = NULLINODE;
818         j = (inoptr) nexti;
819         for (i = 0; i < ITABSIZE; ++i) {
820                 nexti = (inoptr) j;
821                 if (++j >= i_tab + ITABSIZE)
822                         j = i_tab;
823
824                 ifnot(j->c_refs)
825                     nindex = j;
826
827                 if (j->c_dev == dev && j->c_num == ino) {
828                         nindex = j;
829                         goto found;
830                 }
831         }
832
833         /* Not already in table. */
834
835         ifnot(nindex) {         /* No unrefed slots in inode table */
836                 udata.u_error = ENFILE;
837                 return (NULLINODE);
838         }
839
840         buf = (struct dinode *) bread(dev, (ino >> 3) + 2, 0);
841         bcopy((char *) &(buf[ino & 0x07]), (char *) &(nindex->c_node), 64);
842         brelse((bufptr) buf);
843
844         nindex->c_dev = dev;
845         nindex->c_num = ino;
846         nindex->c_magic = CMAGIC;
847
848 found:
849         if (new) {
850                 if (nindex->c_node.i_nlink
851                     || swizzle16(nindex->c_node.i_mode) & F_MASK)
852                         goto badino;
853         } else {
854                 ifnot(nindex->c_node.i_nlink
855                       && swizzle16(nindex->c_node.i_mode) & F_MASK)
856                     goto badino;
857         }
858
859         ++nindex->c_refs;
860         return (nindex);
861
862 badino:
863         printf("i_open: bad disk inode\n");
864         return (NULLINODE);
865 }
866
867
868
869 #if 0
870 /* Ch_link modifies or makes a new entry in the directory for the name
871  * and inode pointer given. The directory is searched for oldname.  When
872  * found, it is changed to newname, and it inode # is that of *nindex.
873  * A oldname of "" matches a unused slot, and a nindex of NULLINODE
874  * means an inode # of 0.  A return status of 0 means there was no
875  * space left in the filesystem, or a non-empty oldname was not found,
876  * or the user did not have write permission.
877  */
878
879 int ch_link(inoptr wd, char *oldname, char *newname, inoptr nindex)
880 {
881         struct direct curentry;
882
883         /* Search the directory for the desired slot. */
884
885         udata.u_offset = 0;
886
887         for (;;) {
888                 udata.u_count = 32;
889                 udata.u_base = (char *) &curentry;
890                 readi(wd);
891
892                 /* Read until EOF or name is found */
893                 /* readi() advances udata.u_offset */
894                 if (udata.u_count == 0
895                     || namecomp(oldname, curentry.d_name))
896                         break;
897         }
898
899         if (udata.u_count == 0 && *oldname)
900                 return (0);     /* Entry not found */
901
902         bcopy(newname, curentry.d_name, 30);
903
904         {
905                 int i;
906
907                 for (i = 0; i < 30; ++i)
908                         if (curentry.d_name[i] == '\0')
909                                 break;
910                 for (; i < 30; ++i)
911                         curentry.d_name[i] = '\0';
912         }
913
914         if (nindex)
915                 curentry.d_ino = swizzle16(nindex->c_num);
916         else
917                 curentry.d_ino = 0;
918
919         /* If an existing slot is being used, we must back up the file offset */
920         if (udata.u_count)
921                 udata.u_offset -= 32;
922
923         udata.u_count = 32;
924         udata.u_base = (char *) &curentry;
925         udata.u_sysio = 1;      /*280 */
926         if (writei(wd))
927                 return 0;
928
929
930         setftime(wd, A_TIME | M_TIME | C_TIME); /* Sets c_dirty */
931
932         /* Update file length to next block */
933         if (swizzle32(wd->c_node.i_size) & 511)
934                 wd->c_node.i_size = swizzle32(
935                     swizzle32(wd->c_node.i_size) + 512 -
936                     (swizzle32(wd->c_node.i_size) & 511));
937
938         return (1);
939 }
940
941
942
943 /* Filename is given a path name, and returns a pointer to the
944  * final component of it.
945  */
946
947 char *filename(char *path)
948 {
949         register char *ptr;
950
951         ptr = path;
952         while (*ptr)
953                 ++ptr;
954         while (*ptr != '/' && ptr-- > path);
955         return (ptr + 1);
956 }
957
958 void filename_2(char *path, char *name)
959 {
960         register char *ptr;
961
962         ptr = path;
963         while (*ptr)
964                 ++ptr;
965         while (*ptr != '/' && ptr-- > path);
966         memcpy(name, ptr + 1, FILENAME_LEN);
967         name[FILENAME_LEN] = 0;
968 }
969
970
971 /* Namecomp compares two strings to see if they are the same file name.
972  * It stops at 30 chars or a null or a slash. It returns 0 for difference.
973  */
974
975 int namecomp(char *n1, char *n2)
976 {
977         register int n;
978
979         n = 30;
980         while (*n1 && *n1 != '/') {
981                 if (*n1++ != *n2++)
982                         return (0);
983                 ifnot(--n)
984                     return (-1);
985         }
986         return (*n2 == '\0' || *n2 == '/');
987 }
988
989
990 /* Newfile is given a pointer to a directory and a name, and creates
991  * an entry in the directory for the name, dereferences the parent,
992  * and returns a pointer to the new inode.  It allocates an inode
993  * number, and creates a new entry in the inode table for the new
994  * file, and initializes the inode table entry for the new file.
995  * The new file will have one reference, and 0 links to it.  Better
996  * Better make sure there isn't already an entry with the same name.
997  */
998
999 inoptr newfile(inoptr pino, char *name)
1000 {
1001         register inoptr nindex;
1002         register int j;
1003
1004         ifnot(nindex = i_open(pino->c_dev, 0))
1005             goto nogood;
1006
1007         /* BIG FIX:  user/group setting was missing  SN *//*280 */
1008         nindex->c_node.i_uid = swizzle16(udata.u_euid); /*280 */
1009         nindex->c_node.i_gid = swizzle16(udata.u_egid); /*280 */
1010
1011         nindex->c_node.i_mode = swizzle16(F_REG);       /* For the time being */
1012         nindex->c_node.i_nlink = swizzle16(1);
1013         nindex->c_node.i_size = 0;
1014         for (j = 0; j < 20; j++)
1015                 nindex->c_node.i_addr[j] = 0;
1016         wr_inode(nindex);
1017
1018         ifnot(ch_link(pino, "", filename(name), nindex)) {
1019                 i_deref(nindex);
1020                 goto nogood;
1021         }
1022
1023         i_deref(pino);
1024         return (nindex);
1025
1026 nogood:
1027         i_deref(pino);
1028         return (NULLINODE);
1029 }
1030 #endif
1031
1032
1033 /* Check the given device number, and return its address in the mount
1034  * table.  Also time-stamp the superblock of dev, and mark it modified.
1035  * Used when freeing and allocating blocks and inodes.
1036  */
1037
1038 fsptr getdev(int devno)
1039 {
1040         register fsptr dev;
1041
1042         dev = fs_tab + devno;
1043         if (devno < 0 || devno >= NDEVS || !dev->s_mounted)
1044                 panic("getdev: bad dev");
1045         dev->s_fmod = 1;
1046         return (dev);
1047 }
1048
1049
1050 /* Returns true if the magic number of a superblock is corrupt.
1051  */
1052
1053 static int baddev(fsptr dev)
1054 {
1055         return (swizzle16(dev->s_mounted) != SMOUNTED);
1056 }
1057
1058
1059 /* I_alloc finds an unused inode number, and returns it, or 0
1060  * if there are no more inodes available.
1061  */
1062
1063 unsigned i_alloc(int devno)
1064 {
1065         fsptr dev;
1066         blkno_t blk;
1067         struct dinode *buf;
1068         register int j;
1069         register int k;
1070         unsigned ino;
1071
1072         if (baddev(dev = getdev(devno)))
1073                 goto corrupt;
1074
1075       tryagain:
1076         if (dev->s_ninode) {
1077                 int i;
1078
1079                 ifnot(dev->s_tinode)
1080                     goto corrupt;
1081                 i = swizzle16(dev->s_ninode);
1082                 ino = swizzle16(dev->s_inode[--i]);
1083                 dev->s_ninode = swizzle16(i);
1084                 if (ino < 2 || ino >= (swizzle16(dev->s_isize) - 2) * 8)
1085                         goto corrupt;
1086                 dev->s_tinode = swizzle16(swizzle16(dev->s_tinode) - 1);
1087                 return (ino);
1088         }
1089
1090         /* We must scan the inodes, and fill up the table */
1091
1092         fuzix_sync();           /* Make on-disk inodes consistent */
1093         k = 0;
1094         for (blk = 2; blk < swizzle16(dev->s_isize); blk++) {
1095                 buf = (struct dinode *) bread(devno, blk, 0);
1096                 for (j = 0; j < 8; j++) {
1097                         ifnot(buf[j].i_mode || buf[j].i_nlink)
1098                             dev->s_inode[k++] =
1099                             swizzle16(8 * (blk - 2) + j);
1100                         if (k == 50) {
1101                                 brelse((bufptr) buf);
1102                                 goto done;
1103                         }
1104                 }
1105                 brelse((bufptr) buf);
1106         }
1107
1108       done:
1109         ifnot(k) {
1110                 if (dev->s_tinode)
1111                         goto corrupt;
1112                 udata.u_error = ENOSPC;
1113                 return (0);
1114         }
1115
1116         dev->s_ninode = swizzle16(k);
1117         goto tryagain;
1118
1119       corrupt:
1120         printf("i_alloc: corrupt superblock\n");
1121         dev->s_mounted = swizzle16(1);
1122         udata.u_error = ENOSPC;
1123         return (0);
1124 }
1125
1126
1127 /* I_free is given a device and inode number, and frees the inode.
1128  * It is assumed that there are no references to the inode in the
1129  * inode table or in the filesystem.
1130  */
1131
1132 void i_free(int devno, unsigned ino)
1133 {
1134         register fsptr dev;
1135
1136         if (baddev(dev = getdev(devno)))
1137                 return;
1138
1139         if (ino < 2 || ino >= (swizzle16(dev->s_isize) - 2) * 8)
1140                 panic("i_free: bad ino");
1141
1142         dev->s_tinode = swizzle16(swizzle16(dev->s_tinode) + 1);
1143         if (swizzle16(dev->s_ninode) < 50) {
1144                 int i = swizzle16(dev->s_ninode);
1145                 dev->s_inode[i++] = swizzle16(ino);
1146                 dev->s_ninode = swizzle16(i);
1147         }
1148 }
1149
1150
1151 /* Blk_alloc is given a device number, and allocates an unused block
1152  * from it. A returned block number of zero means no more blocks.
1153  */
1154
1155 blkno_t blk_alloc(int devno)
1156 {
1157         register fsptr dev;
1158         register blkno_t newno;
1159         blkno_t *buf;           /*, *bread(); -- HP */
1160         register int j;
1161         int i;
1162
1163         if (baddev(dev = getdev(devno)))
1164                 goto corrupt2;
1165
1166         if (swizzle16(dev->s_nfree) <= 0 || swizzle16(dev->s_nfree) > 50)
1167                 goto corrupt;
1168
1169         i = swizzle16(dev->s_nfree);
1170         newno = swizzle16(dev->s_free[--i]);
1171         dev->s_nfree = swizzle16(i);
1172         ifnot(newno) {
1173                 if (dev->s_tfree != 0)
1174                         goto corrupt;
1175                 udata.u_error = ENOSPC;
1176                 dev->s_nfree = swizzle16(swizzle16(dev->s_nfree) + 1);
1177                 return (0);
1178         }
1179
1180         /* See if we must refill the s_free array */
1181
1182         ifnot(dev->s_nfree) {
1183                 buf = (blkno_t *) bread(devno, newno, 0);
1184                 dev->s_nfree = buf[0];
1185                 for (j = 0; j < 50; j++) {
1186                         dev->s_free[j] = buf[j + 1];
1187                 }
1188                 brelse((bufptr) buf);
1189         }
1190
1191         validblk(devno, newno);
1192
1193         ifnot(dev->s_tfree)
1194             goto corrupt;
1195         dev->s_tfree = swizzle16(swizzle16(dev->s_tfree) - 1);
1196
1197         /* Zero out the new block */
1198         buf = (blkno_t *) bread(devno, newno, 2);
1199         bzero(buf, 512);
1200         bawrite((bufptr) buf);
1201         return (newno);
1202
1203       corrupt:
1204         printf("blk_alloc: corrupt\n");
1205         dev->s_mounted = swizzle16(1);
1206       corrupt2:
1207         udata.u_error = ENOSPC;
1208         return (0);
1209 }
1210
1211
1212 /* Blk_free is given a device number and a block number,
1213 and frees the block. */
1214
1215 void blk_free(int devno, blkno_t blk)
1216 {
1217         register fsptr dev;
1218         register char *buf;
1219         int b;
1220
1221         ifnot(blk)
1222             return;
1223
1224         if (baddev(dev = getdev(devno)))
1225                 return;
1226
1227         validblk(devno, blk);
1228
1229         if (dev->s_nfree == swizzle16(50) ) {
1230                 buf = bread(devno, blk, 1);
1231                 bcopy((char *) &(dev->s_nfree), buf, 512);
1232                 bawrite((bufptr) buf);
1233                 dev->s_nfree = 0;
1234         }
1235
1236         dev->s_tfree = swizzle16(swizzle16(dev->s_tfree) + 1);
1237         b = swizzle16(dev->s_nfree);
1238         dev->s_free[b++] = swizzle16(blk);
1239         dev->s_nfree = swizzle16(b);
1240 }
1241
1242
1243 #if 0
1244 /* Oft_alloc and oft_deref allocate and dereference (and possibly free)
1245  * entries in the open file table.
1246  */
1247
1248 int oft_alloc(void)
1249 {
1250         register int j;
1251
1252         for (j = 0; j < OFTSIZE; ++j) {
1253                 ifnot(of_tab[j].o_refs) {
1254                         of_tab[j].o_refs = 1;
1255                         of_tab[j].o_inode = NULLINODE;
1256                         return (j);
1257                 }
1258         }
1259         udata.u_error = ENFILE;
1260         return (-1);
1261 }
1262
1263
1264 void oft_deref(int of)
1265 {
1266         register struct oft *ofptr;
1267
1268         ofptr = of_tab + of;
1269         if (!(--ofptr->o_refs) && ofptr->o_inode) {
1270                 i_deref(ofptr->o_inode);
1271                 ofptr->o_inode = NULLINODE;
1272         }
1273 }
1274
1275
1276 /* Uf_alloc finds an unused slot in the user file table.
1277  */
1278
1279 int uf_alloc(void)
1280 {
1281         register int j;
1282
1283         for (j = 0; j < UFTSIZE; ++j) {
1284                 if (udata.u_files[j] & 0x80) {  /* Portable, unlike  == -1 */
1285                         return (j);
1286                 }
1287         }
1288         udata.u_error = ENFILE;
1289         return (-1);
1290 }
1291 #endif
1292
1293
1294 /* I_ref increases the reference count of the given inode table entry.
1295  */
1296
1297 void i_ref(inoptr ino)
1298 {
1299         if (++(ino->c_refs) == 2 * ITABSIZE) {  /* Arbitrary limit. *//*280 */
1300                 printf("inode %u,", ino->c_num);        /*280 */
1301                 panic("too many i-refs");
1302         }                       /*280 */
1303 }
1304
1305
1306 /* I_deref decreases the reference count of an inode, and frees it from
1307  * the table if there are no more references to it.  If it also has no
1308  * links, the inode itself and its blocks (if not a device) is freed.
1309  */
1310
1311 void i_deref(inoptr ino)
1312 {
1313         unsigned int m;
1314
1315         magic(ino);
1316
1317         ifnot(ino->c_refs)
1318             panic("inode freed.");
1319
1320         ifnot(--ino->c_refs) {
1321                 /* If the inode has no links and no refs, it must have
1322                    its blocks freed. */
1323
1324                 ifnot(ino->c_node.i_nlink) {
1325                         m = swizzle16(ino->c_node.i_mode);
1326                         if (((m & F_MASK) == F_REG) ||
1327                             ((m & F_MASK) == F_DIR) ||
1328                             ((m & F_MASK) == F_PIPE)) {
1329                                 udata.u_offset = 0;
1330                                 f_trunc(ino);
1331                         }
1332                         ino->c_node.i_mode = 0;
1333                         i_free(ino->c_dev, ino->c_num);
1334                 }
1335
1336                 /* If the inode was modified, we must write it to disk. */
1337                 if (ino->c_dirty)
1338                         wr_inode(ino);
1339         }
1340 }
1341
1342
1343 /* Wr_inode writes out the given inode in the inode table out to disk,
1344  * and resets its dirty bit.
1345  */
1346
1347 void wr_inode(inoptr ino)
1348 {
1349         struct dinode *buf;
1350         register blkno_t blkno;
1351
1352         magic(ino);
1353
1354         blkno = (ino->c_num >> 3) + 2;
1355         buf = (struct dinode *) bread(ino->c_dev, blkno, 0);
1356         bcopy((char *) (&ino->c_node),
1357               (char *) ((char **) &buf[ino->c_num & 0x07]), 64);
1358         bfree((bufptr) buf, 2);
1359         ino->c_dirty = 0;
1360 }
1361
1362
1363 /* isdevice(ino) returns true if ino points to a device */
1364 int isdevice(inoptr ino)
1365 {
1366         return (swizzle16(ino->c_node.i_mode) & 020000);
1367 }
1368
1369
1370 /* F_trunc frees all the blocks associated with the file, if it
1371  * is a disk file.
1372  */
1373
1374 void f_trunc(inoptr ino)
1375 {
1376         int dev;
1377         blkno_t blk;
1378         int32_t blocks;
1379         int j;
1380
1381         /*
1382          * Note: the previous i_deref() logic relied on f_trunc() always
1383          * dirtying the file, and this is no longer the case, must fix it
1384          */
1385         if (udata.u_offset >= ino->c_node.i_size)
1386                 return;
1387
1388         ino->c_node.i_size = udata.u_offset;
1389         ino->c_dirty = 1;
1390
1391         dev = ino->c_dev;
1392         blocks = (int32_t)((udata.u_offset + 511) >> 9);
1393
1394         /* First deallocate the double indirect blocks */
1395         blk = swizzle16(ino->c_node.i_addr[19]);
1396         if (blocks > 18 + 256) {
1397                 freeblk_partial2(dev, blk, blocks - (18 + 256));
1398                 return;
1399         }
1400         freeblk(dev, blk, 2);
1401         ino->c_node.i_addr[19] = 0;
1402
1403         /* Also deallocate the indirect blocks */
1404         blk = swizzle16(ino->c_node.i_addr[18]);
1405         if ((int)blocks > 18) {
1406                 freeblk_partial1(dev, blk, (int)blocks - 18);
1407                 return;
1408         }
1409         freeblk(dev, blk, 1);
1410         ino->c_node.i_addr[18] = 0;
1411
1412         /* Finally, free the direct blocks */
1413         for (j = 17; j >= (int)blocks; --j) {
1414                 freeblk(dev, swizzle16(ino->c_node.i_addr[j]), 0);
1415                 ino->c_node.i_addr[j] = 0;
1416         }
1417 }
1418
1419 /* Companion functions to f_trunc(). */
1420 void freeblk_partial2(int dev, blkno_t blk, int32_t blocks)
1421 {
1422         blkno_t *buf;
1423         int end, j;
1424
1425         if (!blk || blocks >= 65536)
1426             return;
1427
1428         buf = (blkno_t *) bread(dev, blk, 0);
1429         end = (int)blocks >> 8;
1430         for (j = 255; j > end; --j) {
1431                 freeblk(dev, swizzle16(buf[j]), 1);
1432                 buf[j] = 0;
1433         }
1434         freeblk_partial1(dev, swizzle16(buf[j]), (((int)blocks - 1) & 0xff) + 1);
1435         bawrite((bufptr) buf);
1436 }
1437
1438 void freeblk_partial1(int dev, blkno_t blk, int blocks)
1439 {
1440         blkno_t *buf;
1441         int j;
1442
1443         if (!blk || blocks >= 256)
1444             return;
1445
1446         buf = (blkno_t *) bread(dev, blk, 0);
1447         for (j = 255; j >= blocks; --j) {
1448                 freeblk(dev, swizzle16(buf[j]), 0);
1449                 buf[j] = 0;
1450         }
1451         bawrite((bufptr) buf);
1452 }
1453
1454 void freeblk(int dev, blkno_t blk, int level)
1455 {
1456         blkno_t *buf;
1457         int j;
1458
1459         ifnot(blk)
1460             return;
1461
1462         if (level) {
1463                 buf = (blkno_t *) bread(dev, blk, 0);
1464                 for (j = 255; j >= 0; --j)
1465                         freeblk(dev, swizzle16(buf[j]), level - 1);
1466                 brelse((bufptr) buf);
1467         }
1468
1469         blk_free(dev, blk);
1470 }
1471
1472 /* Changes: blk_alloc zeroes block it allocates */
1473 /*
1474  * Bmap defines the structure of file system storage by returning
1475  * the physical block number on a device given the inode and the
1476  * logical block number in a file.  The block is zeroed if created.
1477  */
1478 blkno_t bmap(inoptr ip, blkno_t bn, int rwflg)
1479 {
1480         register int i;
1481         register bufptr bp;
1482         register int j;
1483         register blkno_t nb;
1484         int sh;
1485         int dev;
1486
1487         if (fuzix_getmode(ip) == F_BDEV)
1488                 return (bn);
1489
1490         dev = ip->c_dev;
1491
1492         /*
1493          * blocks 0..17 are direct blocks
1494          */
1495         if (bn < 18) {
1496                 nb = swizzle16(ip->c_node.i_addr[bn]);
1497                 if (nb == 0) {
1498                         if (rwflg || (nb = blk_alloc(dev)) == 0)
1499                                 return (NULLBLK);
1500                         ip->c_node.i_addr[bn] = swizzle16(nb);
1501                         ip->c_dirty = 1;
1502                 }
1503                 return (nb);
1504         }
1505
1506         /*
1507          * addresses 18 and 19 have single and double indirect blocks.
1508          * the first step is to determine how many levels of indirection.
1509          */
1510         bn -= 18;
1511         sh = 0;
1512         j = 2;
1513         if (bn & 0xff00) {      /* bn > 255  so double indirect */
1514                 sh = 8;
1515                 bn -= 256;
1516                 j = 1;
1517         }
1518
1519         /*
1520          * fetch the address from the inode
1521          * Create the first indirect block if needed.
1522          */
1523         ifnot(nb = swizzle16(ip->c_node.i_addr[20 - j])) {
1524                 if (rwflg || !(nb = blk_alloc(dev)))
1525                         return (NULLBLK);
1526                 ip->c_node.i_addr[20 - j] = swizzle16(nb);
1527                 ip->c_dirty = 1;
1528         }
1529
1530         /*
1531          * fetch through the indirect blocks
1532          */
1533         for (; j <= 2; j++) {
1534                 bp = (bufptr) bread(dev, nb, 0);
1535                 /******
1536                 if(bp->bf_error) {
1537                         brelse(bp);
1538                         return((blkno_t)0);
1539                 }
1540                 ******/
1541                 i = (bn >> sh) & 0xff;
1542                 if ((nb = swizzle16(((blkno_t *) bp)[i])) != 0)
1543                         brelse(bp);
1544                 else {
1545                         if (rwflg || !(nb = blk_alloc(dev))) {
1546                                 brelse(bp);
1547                                 return (NULLBLK);
1548                         }
1549                         ((blkno_t *) bp)[i] = swizzle16(nb);
1550                         bawrite(bp);
1551                 }
1552                 sh -= 8;
1553         }
1554         return (nb);
1555 }
1556
1557
1558
1559 /* Validblk panics if the given block number is not a valid
1560  *  data block for the given device.
1561  */
1562 void validblk(int dev, blkno_t num)
1563 {
1564         register fsptr devptr;
1565
1566         devptr = fs_tab + dev;
1567
1568         if (devptr->s_mounted == 0)
1569                 panic("validblk: not mounted");
1570
1571         if (num < swizzle16(devptr->s_isize)
1572             || num >= swizzle16(devptr->s_fsize))
1573                 panic("validblk: invalid blk");
1574 }
1575
1576
1577 #if 0
1578 /* This returns the inode pointer associated with a user's file
1579  * descriptor, checking for valid data structures.
1580  */
1581 inoptr getinode(int uindex)
1582 {
1583         register int oftindex;
1584         register inoptr inoindex;
1585
1586         if (uindex < 0 || uindex >= UFTSIZE
1587             || udata.u_files[uindex] & 0x80) {
1588                 udata.u_error = EBADF;
1589                 return (NULLINODE);
1590         }
1591
1592         if ((oftindex = udata.u_files[uindex]) < 0 || oftindex >= OFTSIZE)
1593                 panic("Getinode: bad desc table");
1594
1595         if ((inoindex = of_tab[oftindex].o_inode) < i_tab ||
1596             inoindex >= i_tab + ITABSIZE)
1597                 panic("Getinode: bad OFT");
1598
1599         magic(inoindex);
1600
1601         return (inoindex);
1602 }
1603
1604 /* This sets the times of the given inode, according to the flags.
1605  */
1606 void setftime(inoptr ino, int flag)
1607 {
1608         time_t now;
1609         ino->c_dirty = 1;
1610
1611         now = time(NULL);
1612
1613         if (flag & A_TIME)
1614                 ino->c_node.i_atime = swizzle32(now);
1615         if (flag & M_TIME)
1616                 ino->c_node.i_mtime = swizzle32(now);
1617         if (flag & C_TIME)
1618                 ino->c_node.i_ctime = swizzle32(now);
1619 }
1620 #endif
1621
1622
1623 int fuzix_getmode(inoptr ino)
1624 {
1625         return (swizzle16(ino->c_node.i_mode) & F_MASK);
1626 }
1627
1628
1629 /* Fmount places the given device in the mount table with mount point ino.
1630  */
1631 int fmount(int dev, inoptr ino)
1632 {
1633         char *buf;
1634         register struct filesys *fp;
1635
1636         /* Dev 0 blk 1 */
1637         fp = fs_tab + dev;
1638         buf = bread(dev, 1, 0);
1639         bcopy(buf, (char *) fp, sizeof(struct filesys));
1640         brelse((bufptr) buf);
1641
1642         /* See if there really is a filesystem on the device */
1643         if (fp->s_mounted == SMOUNTED_WRONGENDIAN)
1644                 swizzling = 1;
1645         if (swizzle16(fp->s_mounted) != SMOUNTED ||
1646             swizzle16(fp->s_isize) >= swizzle16(fp->s_fsize))
1647                 return (-1);
1648
1649         fp->s_mntpt = ino;
1650         if (ino)
1651                 ++ino->c_refs;
1652
1653         return (0);
1654 }
1655
1656 void magic(inoptr ino)
1657 {
1658         if (ino->c_magic != CMAGIC)
1659                 panic("Corrupt inode");
1660 }
1661
1662 char *bread(int dev, blkno_t blk, int rewrite)
1663 {
1664         register bufptr bp;
1665
1666 /*printf("Reading block %d\n", blk);*/
1667
1668         bp = bfind(dev, blk);
1669         if (bp) {
1670                 if (bp->bf_busy)
1671                         panic("want busy block");
1672                 goto done;
1673         }
1674         bp = freebuf();
1675         bp->bf_dev = dev;
1676         bp->bf_blk = blk;
1677
1678         /* If rewrite is set, we are about to write over the entire block,
1679            so we don't need the previous contents */
1680
1681         ifnot(rewrite)
1682             if (bdread(bp) == -1) {
1683                 udata.u_error = EIO;
1684                 return 0;
1685         }
1686
1687 done:
1688         bp->bf_busy = 1;
1689  //printf("bread %d\n", (int)(bp - bufpool));
1690         bp->bf_time = ++bufclock;       /* Time stamp it */
1691         return (bp->bf_data);
1692 }
1693
1694
1695 void brelse(bufptr bp)
1696 {
1697 /*printf("Releasing block %d (0)\n", bp->bf_blk);*/
1698         bfree(bp, 0);
1699 }
1700
1701 void bawrite(bufptr bp)
1702 {
1703 /*printf("Releasing block %d (1)\n", bp->bf_blk);*/
1704         bfree(bp, 1);
1705 }
1706
1707 int bfree(bufptr bp, int dirty)
1708 {
1709  assert(bp->bf_busy);
1710  //printf("bfree %d %d\n", (int)(bp - bufpool), dirty);
1711 /*printf("Releasing block %d (%d)\n", bp->bf_blk, dirty);*/
1712         bp->bf_dirty |= dirty;
1713         bp->bf_busy = 0;
1714
1715         if (dirty == 2) {       /* Extra dirty */
1716                 if (bdwrite(bp) == -1)
1717                         udata.u_error = EIO;
1718                 bp->bf_dirty = 0;
1719                 return (-1);
1720         }
1721         return (0);
1722 }
1723
1724
1725 /* This returns a busy block not belonging to any device, with
1726  * garbage contents.  It is essentially a malloc for the kernel.
1727  * Free it with brelse()!
1728  */
1729 char *tmpbuf(void)
1730 {
1731         bufptr bp;
1732         //bufptr freebuf();
1733
1734 /*printf("Allocating temp block\n");*/
1735         bp = freebuf();
1736         bp->bf_dev = -1;
1737         bp->bf_busy = 1;
1738  //printf("tmpbuf %d\n", (int)(bp - bufpool));
1739         bp->bf_time = ++bufclock;       /* Time stamp it */
1740         return (bp->bf_data);
1741 }
1742
1743
1744 char *zerobuf(void)
1745 {
1746         char *b;
1747         //char *tmpbuf();
1748
1749         b = tmpbuf();
1750         bzero(b, 512);
1751         return (b);
1752 }
1753
1754
1755 void bufsync(void)
1756 {
1757         register bufptr bp;
1758
1759         for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
1760                 if (bp->bf_dev != -1 && bp->bf_dirty) {
1761                         bdwrite(bp);
1762                         if (!bp->bf_busy)
1763                                 bp->bf_dirty = 0;
1764                 }
1765         }
1766 }
1767
1768 bufptr bfind(int dev, blkno_t blk)
1769 {
1770         register bufptr bp;
1771
1772         for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
1773                 if (bp->bf_dev == dev && bp->bf_blk == blk)
1774                         return (bp);
1775         }
1776         return (NULL);
1777 }
1778
1779
1780 bufptr freebuf(void)
1781 {
1782         register bufptr bp;
1783         register bufptr oldest;
1784         register int oldtime;
1785
1786         /* Try to find a non-busy buffer and write out the data if it is dirty */
1787         oldest = NULL;
1788         oldtime = 0;
1789  //printf("nonbusy");
1790         for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
1791  //if (!bp->bf_busy)
1792  // printf(" %d(%lld)", (int)(bp -bufpool), bufclock - bp->bf_time);
1793                 if (bufclock - bp->bf_time >= oldtime && !bp->bf_busy) {
1794                         oldest = bp;
1795                         oldtime = bufclock - bp->bf_time;
1796                 }
1797         }
1798  //printf("\n");
1799         ifnot(oldest)
1800             panic("no free buffers");
1801
1802         if (oldest->bf_dirty) {
1803                 if (bdwrite(oldest) == -1)
1804                         udata.u_error = EIO;
1805                 oldest->bf_dirty = 0;
1806         }
1807         return (oldest);
1808 }
1809
1810 void bufinit(void)
1811 {
1812         register bufptr bp;
1813
1814         for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
1815                 bp->bf_dev = -1;
1816         }
1817 }
1818
1819
1820 /*********************************************************************
1821 Bdread() and bdwrite() are the block device interface routines.  they
1822 are given a buffer pointer, which contains the device, block number,
1823 and data location.  They basically validate the device and vector the
1824 call.
1825
1826 Cdread() and cdwrite are the same for character (or "raw") devices,
1827 and are handed a device number.  Udata.u_base, count, and offset have
1828 the rest of the data.
1829 **********************************************************************/
1830
1831 int bdread(bufptr bp)
1832 {
1833 /*    printf("bdread(fd=%d, block %d)\n", dev_fd, bp->bf_blk); */
1834
1835         udata.u_buf = bp;
1836         if (lseek
1837             (dev_fd, dev_offset + (((int) bp->bf_blk) * 512),
1838              SEEK_SET) == -1)
1839                 perror("lseek");
1840         if (read(dev_fd, bp->bf_data, 512) != 512)
1841                 panic("read() failed");
1842
1843         return 0;
1844 }
1845
1846
1847 int bdwrite(bufptr bp)
1848 {
1849         udata.u_buf = bp;
1850
1851         lseek(dev_fd, dev_offset + (((int) bp->bf_blk) * 512), SEEK_SET);
1852         if (write(dev_fd, bp->bf_data, 512) != 512)
1853                 panic("write() failed");
1854         return 0;
1855 }