1 #include <assert.h> // Nick
11 struct oft of_tab[OFTSIZE]; /* Open File Table */
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];
21 static void fs_init(void)
27 void xfs_init(int bootdev)
34 /* User's file table */
35 for (j = udata.u_files; j < (udata.u_files + UFTSIZE); ++j)
38 /* Mount the root device */
39 if (fmount(ROOTDEV, NULLINODE))
42 ifnot(root = i_open(ROOTDEV, ROOTINODE))
45 i_ref(udata.u_cwd = root);
54 for (j = 0; j < UFTSIZE; ++j) {
55 ifnot(udata.u_files[j] & 0x80) /* Portable equivalent of == -1 */
61 int fuzix_open(char *name, int16_t flag)
64 register int16_t oftindex;
69 if (flag < 0 || flag > 2) {
70 udata.u_error = EINVAL;
73 if ((uindex = uf_alloc()) == -1)
76 if ((oftindex = oft_alloc()) == -1)
79 ifnot(ino = n_open(name, NULLINOPTR))
82 of_tab[oftindex].o_inode = ino;
84 if (fuzix_getmode(ino) == F_DIR &&
85 (flag == FO_WRONLY || flag == FO_RDWR)) {
86 udata.u_error = EISDIR;
90 if (isdevice(ino)) /* && d_open((int)ino->c_node.i_addr[0]) != 0) */
92 udata.u_error = ENXIO;
96 udata.u_files[uindex] = oftindex;
98 of_tab[oftindex].o_ptr = 0;
99 of_tab[oftindex].o_access = flag;
104 oft_deref(oftindex); /* This will call i_deref() */
106 udata.u_files[uindex] = -1;
110 int doclose(int16_t uindex)
112 register int16_t oftindex;
116 ifnot(ino = getinode(uindex))
118 oftindex = udata.u_files[uindex];
122 /* && ino->c_refs == 1 && of_tab[oftindex].o_refs == 1 */ )
123 d_close((int)(ino->c_node.i_addr[0]));
126 udata.u_files[uindex] = -1;
132 int fuzix_close(int16_t uindex)
135 return (doclose(uindex));
138 int fuzix_creat(char *name, int16_t mode)
141 register int16_t uindex;
142 register int16_t oftindex;
149 if ((uindex = uf_alloc()) == -1)
151 if ((oftindex = oft_alloc()) == -1)
154 ino = n_open(name, &parent);
157 if (fuzix_getmode(ino) == F_DIR) {
159 udata.u_error = EISDIR;
162 if (fuzix_getmode(ino) == F_REG) {
163 /* Truncate the file to zero length */
166 /* Reset any oft pointers */
167 for (j = 0; j < OFTSIZE; ++j)
168 if (of_tab[j].o_inode == ino)
172 if (parent && (ino = newfile(parent, name)))
173 /* Parent was derefed in newfile */
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() */
182 /* Doesn't exist and can't make it */
186 udata.u_files[uindex] = oftindex;
188 of_tab[oftindex].o_ptr = 0;
189 of_tab[oftindex].o_inode = ino;
190 of_tab[oftindex].o_access = FO_WRONLY;
199 int fuzix_link(char *name1, char *name2)
202 register inoptr ino2;
206 ifnot(ino = n_open(name1, NULLINOPTR))
209 /* Make sure file2 doesn't exist, and get its parent */
210 if ((ino2 = n_open(name2, &parent2))) {
213 udata.u_error = EEXIST;
220 if (ino->c_dev != parent2->c_dev) {
222 udata.u_error = EXDEV;
226 if (ch_link(parent2, "", filename(name2), ino) == 0)
229 /* Update the link count. */
230 ino->c_node.i_nlink =
231 swizzle16(swizzle16(ino->c_node.i_nlink) + 1);
233 setftime(ino, C_TIME);
244 int fuzix_unlink(char *path)
250 ino = n_open(path, &pino);
253 udata.u_error = ENOENT;
257 /* Remove the directory entry */
259 if (ch_link(pino, filename(path), "", NULLINODE) == 0)
262 /* Decrease the link count of the inode */
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");
269 ino->c_node.i_nlink =
270 swizzle16(swizzle16(ino->c_node.i_nlink) - 1);
271 setftime(ino, C_TIME);
281 uint16_t fuzix_read(int16_t d, char *buf, uint16_t nbytes)
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 */
296 uint16_t fuzix_write(int16_t d, char *buf, uint16_t nbytes)
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 */
312 inoptr rwsetup(int rwflag, int d, char *buf, int nbytes)
315 register struct oft *oftp;
318 udata.u_count = nbytes;
320 if ((ino = getinode(d)) == NULLINODE)
323 oftp = of_tab + udata.u_files[d];
324 if (oftp->o_access == (rwflag ? FO_WRONLY : FO_RDONLY)) {
325 udata.u_error = EBADF;
329 setftime(ino, rwflag ? A_TIME : (A_TIME | M_TIME | C_TIME));
331 /* Initialize u_offset from file pointer */
332 udata.u_offset = oftp->o_ptr;
338 uint16_t readi(inoptr ino)
340 register uint16_t amount;
341 register uint16_t toread;
342 register blkno_t pblk;
345 switch (fuzix_getmode(ino)) {
350 /* See of end of file will limit read */
351 toread = udata.u_count =
353 swizzle32(ino->c_node.i_size) - udata.u_offset);
356 bmap(ino, udata.u_offset >> 9, 1)) != NULLBLK)
357 bp = bread(0, pblk, 0);
361 bcopy(bp + (udata.u_offset & 511), udata.u_base,
363 min(toread, 512 - (udata.u_offset & 511))));
366 udata.u_base += amount;
367 udata.u_offset += amount;
370 return udata.u_count - toread;
373 udata.u_error = ENODEV;
380 /* Writei (and readi) need more i/o error handling */
382 uint16_t writei(inoptr ino)
384 register uint16_t amount;
385 register uint16_t towrite;
389 switch (fuzix_getmode(ino)) {
393 towrite = udata.u_count;
396 min(towrite, 512 - (udata.u_offset & 511));
399 bmap(ino, udata.u_offset >> 9, 0)) == NULLBLK)
400 break; /* No space to make more blocks */
402 /* If we are writing an entire block, we don't care
403 about its previous contents */
404 bp = bread(0, pblk, (amount == 512));
406 bcopy(udata.u_base, bp + (udata.u_offset & 511),
408 bawrite((bufptr) bp);
410 udata.u_base += amount;
411 udata.u_offset += amount;
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);
421 return udata.u_count - towrite; // Nick bugfix
424 udata.u_error = ENODEV;
426 return udata.u_count;
434 /* Update current file pointer */
435 of_tab[(int)udata.u_files[d]].o_ptr = udata.u_offset;
438 static int valadr(char *base, uint16_t size)
444 int fuzix_mknod(char *name, int16_t mode, int16_t dev)
451 if ((ino = n_open(name, &parent))) {
452 udata.u_error = EEXIST;
457 udata.u_error = ENOENT;
461 ifnot(ino = newfile(parent, name))
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);
481 void fuzix_sync(void)
487 /* Write out modified inodes */
490 for (ino = i_tab; ino < i_tab + ITABSIZE; ++ino)
491 if ((ino->c_refs) > 0 && ino->c_dirty != 0) {
496 /* Write out modified super blocks */
497 /* This fills the rest of the super block with garbage. */
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);
508 bufsync(); /* Clear buffer pool */
512 int fuzix_chdir(char *dir)
514 register inoptr newcwd;
517 ifnot(newcwd = n_open(dir, NULLINOPTR))
520 if (fuzix_getmode(newcwd) != F_DIR) {
521 udata.u_error = ENOTDIR;
525 i_deref(udata.u_cwd);
526 udata.u_cwd = newcwd;
531 int min(int a, int b)
533 return (a < b ? a : b);
537 int fuzix_chmod(char *path, int16_t mode)
542 ifnot(ino = n_open(path, NULLINOPTR))
546 swizzle16((mode & MODE_MASK) |
547 (swizzle16(ino->c_node.i_mode) & F_MASK));
548 setftime(ino, C_TIME);
553 int fuzix_stat(char *path, struct uzi_stat *buf)
558 ifnot(valadr((char *) buf, sizeof(struct uzi_stat))
559 && (ino = n_open(path, NULLINOPTR))) {
567 /* Utility for stat and fstat */
568 void stcpy(inoptr ino, struct uzi_stat *buf)
570 struct uzi_stat *b = (struct uzi_stat *) buf;
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);
579 b->st_rdev = swizzle16(ino->c_node.i_addr[0]);
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);
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.
592 int fuzix_getfsys(int dev, char *buf)
595 if (dev < 0 || dev >= NDEVS
596 || swizzle16(fs_tab[dev].s_mounted) != SMOUNTED) {
597 udata.u_error = ENXIO;
601 /* FIXME: endiam swapping here */
602 bcopy((char *) &fs_tab[dev], (char *) buf, sizeof(struct filesys));
606 int fuzix_mkdir(char *name, int mode)
610 char fname[FILENAME_LEN + 1];
612 if ((ino = n_open(name, &parent)) != NULL) {
613 udata.u_error = EEXIST;
618 udata.u_error = ENOENT;
622 if (swizzle16(parent->c_node.i_nlink) == 0xFFFF) {
623 udata.u_error = EMLINK;
627 filename_2(name, fname);
629 i_ref(parent); /* We need it again in a minute */
630 if (!(ino = newfile(parent, fname))) {
632 goto nogood2; /* parent inode is derefed in newfile. */
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)
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);
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;
666 inoptr n_open(register char *name, register inoptr * parent)
668 register inoptr wd; /* the directory we are currently searching. */
669 register inoptr ninode;
683 /* See if we are at a mount point */
685 ninode = srch_mt(ninode);
687 while (*name == '/') /* Skip (possibly repeated) slashes */
689 ifnot(*name) /* No more components of path? */
692 udata.u_error = ENOENT;
697 if (fuzix_getmode(wd) != F_DIR) {
698 udata.u_error = ENOTDIR;
702 ninode = srch_dir(wd, name);
704 while (*name != '/' && *name)
712 ifnot(parent || ninode)
713 udata.u_error = ENOENT;
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
734 inoptr srch_dir(inoptr wd, register char *compname)
736 register int curentry;
737 register blkno_t curblock;
738 register struct direct *buf;
739 register int nblocks;
742 nblocks = (swizzle32(wd->c_node.i_size) + 511) >> 9;
744 for (curblock = 0; curblock < nblocks; ++curblock) {
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)) {
751 swizzle16(buf[curentry & 0x0f].d_ino);
752 brelse((bufptr) buf);
753 return (i_open(wd->c_dev, inum));
756 brelse((bufptr) buf);
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.
767 inoptr srch_mt(inoptr ino)
771 for (j = 0; j < NDEVS; ++j)
772 if (swizzle16(fs_tab[j].s_mounted) == SMOUNTED
773 && fs_tab[j].s_mntpt == ino) {
775 return (i_open(j, ROOTINODE));
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.
789 inoptr i_open(register int dev, register unsigned ino)
793 register inoptr nindex;
797 static inoptr nexti = i_tab; /* added inoptr. 26.12.97 HFB */
799 if (dev < 0 || dev >= NDEVS)
800 panic("i_open: Bad dev");
803 ifnot(ino) { /* Want a new one */
805 ifnot(ino = i_alloc(dev)) {
806 udata.u_error = ENOSPC;
811 if (ino < ROOTINODE || ino >= (swizzle16(fs_tab[dev].s_isize) - 2) * 8) {
812 printf("i_open: bad inode number\n");
819 for (i = 0; i < ITABSIZE; ++i) {
821 if (++j >= i_tab + ITABSIZE)
827 if (j->c_dev == dev && j->c_num == ino) {
833 /* Not already in table. */
835 ifnot(nindex) { /* No unrefed slots in inode table */
836 udata.u_error = ENFILE;
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);
846 nindex->c_magic = CMAGIC;
850 if (nindex->c_node.i_nlink
851 || swizzle16(nindex->c_node.i_mode) & F_MASK)
854 ifnot(nindex->c_node.i_nlink
855 && swizzle16(nindex->c_node.i_mode) & F_MASK)
863 printf("i_open: bad disk inode\n");
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.
879 int ch_link(inoptr wd, char *oldname, char *newname, inoptr nindex)
881 struct direct curentry;
883 /* Search the directory for the desired slot. */
889 udata.u_base = (char *) &curentry;
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))
899 if (udata.u_count == 0 && *oldname)
900 return (0); /* Entry not found */
902 bcopy(newname, curentry.d_name, 30);
907 for (i = 0; i < 30; ++i)
908 if (curentry.d_name[i] == '\0')
911 curentry.d_name[i] = '\0';
915 curentry.d_ino = swizzle16(nindex->c_num);
919 /* If an existing slot is being used, we must back up the file offset */
921 udata.u_offset -= 32;
924 udata.u_base = (char *) &curentry;
925 udata.u_sysio = 1; /*280 */
930 setftime(wd, A_TIME | M_TIME | C_TIME); /* Sets c_dirty */
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));
943 /* Filename is given a path name, and returns a pointer to the
944 * final component of it.
947 char *filename(char *path)
954 while (*ptr != '/' && ptr-- > path);
958 void filename_2(char *path, char *name)
965 while (*ptr != '/' && ptr-- > path);
966 memcpy(name, ptr + 1, FILENAME_LEN);
967 name[FILENAME_LEN] = 0;
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.
975 int namecomp(char *n1, char *n2)
980 while (*n1 && *n1 != '/') {
986 return (*n2 == '\0' || *n2 == '/');
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.
999 inoptr newfile(inoptr pino, char *name)
1001 register inoptr nindex;
1004 ifnot(nindex = i_open(pino->c_dev, 0))
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 */
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;
1018 ifnot(ch_link(pino, "", filename(name), nindex)) {
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.
1038 fsptr getdev(int devno)
1042 dev = fs_tab + devno;
1043 if (devno < 0 || devno >= NDEVS || !dev->s_mounted)
1044 panic("getdev: bad dev");
1050 /* Returns true if the magic number of a superblock is corrupt.
1053 static int baddev(fsptr dev)
1055 return (swizzle16(dev->s_mounted) != SMOUNTED);
1059 /* I_alloc finds an unused inode number, and returns it, or 0
1060 * if there are no more inodes available.
1063 unsigned i_alloc(int devno)
1072 if (baddev(dev = getdev(devno)))
1076 if (dev->s_ninode) {
1079 ifnot(dev->s_tinode)
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)
1086 dev->s_tinode = swizzle16(swizzle16(dev->s_tinode) - 1);
1090 /* We must scan the inodes, and fill up the table */
1092 fuzix_sync(); /* Make on-disk inodes consistent */
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)
1099 swizzle16(8 * (blk - 2) + j);
1101 brelse((bufptr) buf);
1105 brelse((bufptr) buf);
1112 udata.u_error = ENOSPC;
1116 dev->s_ninode = swizzle16(k);
1120 printf("i_alloc: corrupt superblock\n");
1121 dev->s_mounted = swizzle16(1);
1122 udata.u_error = ENOSPC;
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.
1132 void i_free(int devno, unsigned ino)
1136 if (baddev(dev = getdev(devno)))
1139 if (ino < 2 || ino >= (swizzle16(dev->s_isize) - 2) * 8)
1140 panic("i_free: bad ino");
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);
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.
1155 blkno_t blk_alloc(int devno)
1158 register blkno_t newno;
1159 blkno_t *buf; /*, *bread(); -- HP */
1163 if (baddev(dev = getdev(devno)))
1166 if (swizzle16(dev->s_nfree) <= 0 || swizzle16(dev->s_nfree) > 50)
1169 i = swizzle16(dev->s_nfree);
1170 newno = swizzle16(dev->s_free[--i]);
1171 dev->s_nfree = swizzle16(i);
1173 if (dev->s_tfree != 0)
1175 udata.u_error = ENOSPC;
1176 dev->s_nfree = swizzle16(swizzle16(dev->s_nfree) + 1);
1180 /* See if we must refill the s_free array */
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];
1188 brelse((bufptr) buf);
1191 validblk(devno, newno);
1195 dev->s_tfree = swizzle16(swizzle16(dev->s_tfree) - 1);
1197 /* Zero out the new block */
1198 buf = (blkno_t *) bread(devno, newno, 2);
1200 bawrite((bufptr) buf);
1204 printf("blk_alloc: corrupt\n");
1205 dev->s_mounted = swizzle16(1);
1207 udata.u_error = ENOSPC;
1212 /* Blk_free is given a device number and a block number,
1213 and frees the block. */
1215 void blk_free(int devno, blkno_t blk)
1224 if (baddev(dev = getdev(devno)))
1227 validblk(devno, blk);
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);
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);
1244 /* Oft_alloc and oft_deref allocate and dereference (and possibly free)
1245 * entries in the open file table.
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;
1259 udata.u_error = ENFILE;
1264 void oft_deref(int of)
1266 register struct oft *ofptr;
1268 ofptr = of_tab + of;
1269 if (!(--ofptr->o_refs) && ofptr->o_inode) {
1270 i_deref(ofptr->o_inode);
1271 ofptr->o_inode = NULLINODE;
1276 /* Uf_alloc finds an unused slot in the user file table.
1283 for (j = 0; j < UFTSIZE; ++j) {
1284 if (udata.u_files[j] & 0x80) { /* Portable, unlike == -1 */
1288 udata.u_error = ENFILE;
1294 /* I_ref increases the reference count of the given inode table entry.
1297 void i_ref(inoptr ino)
1299 if (++(ino->c_refs) == 2 * ITABSIZE) { /* Arbitrary limit. *//*280 */
1300 printf("inode %u,", ino->c_num); /*280 */
1301 panic("too many i-refs");
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.
1311 void i_deref(inoptr ino)
1318 panic("inode freed.");
1320 ifnot(--ino->c_refs) {
1321 /* If the inode has no links and no refs, it must have
1322 its blocks freed. */
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)) {
1332 ino->c_node.i_mode = 0;
1333 i_free(ino->c_dev, ino->c_num);
1336 /* If the inode was modified, we must write it to disk. */
1343 /* Wr_inode writes out the given inode in the inode table out to disk,
1344 * and resets its dirty bit.
1347 void wr_inode(inoptr ino)
1350 register blkno_t blkno;
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);
1363 /* isdevice(ino) returns true if ino points to a device */
1364 int isdevice(inoptr ino)
1366 return (swizzle16(ino->c_node.i_mode) & 020000);
1370 /* F_trunc frees all the blocks associated with the file, if it
1374 void f_trunc(inoptr ino)
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
1385 if (udata.u_offset >= ino->c_node.i_size)
1388 ino->c_node.i_size = udata.u_offset;
1392 blocks = (int32_t)((udata.u_offset + 511) >> 9);
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));
1400 freeblk(dev, blk, 2);
1401 ino->c_node.i_addr[19] = 0;
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);
1409 freeblk(dev, blk, 1);
1410 ino->c_node.i_addr[18] = 0;
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;
1419 /* Companion functions to f_trunc(). */
1420 void freeblk_partial2(int dev, blkno_t blk, int32_t blocks)
1425 if (!blk || blocks >= 65536)
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);
1434 freeblk_partial1(dev, swizzle16(buf[j]), (((int)blocks - 1) & 0xff) + 1);
1435 bawrite((bufptr) buf);
1438 void freeblk_partial1(int dev, blkno_t blk, int blocks)
1443 if (!blk || blocks >= 256)
1446 buf = (blkno_t *) bread(dev, blk, 0);
1447 for (j = 255; j >= blocks; --j) {
1448 freeblk(dev, swizzle16(buf[j]), 0);
1451 bawrite((bufptr) buf);
1454 void freeblk(int dev, blkno_t blk, int 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);
1472 /* Changes: blk_alloc zeroes block it allocates */
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.
1478 blkno_t bmap(inoptr ip, blkno_t bn, int rwflg)
1483 register blkno_t nb;
1487 if (fuzix_getmode(ip) == F_BDEV)
1493 * blocks 0..17 are direct blocks
1496 nb = swizzle16(ip->c_node.i_addr[bn]);
1498 if (rwflg || (nb = blk_alloc(dev)) == 0)
1500 ip->c_node.i_addr[bn] = swizzle16(nb);
1507 * addresses 18 and 19 have single and double indirect blocks.
1508 * the first step is to determine how many levels of indirection.
1513 if (bn & 0xff00) { /* bn > 255 so double indirect */
1520 * fetch the address from the inode
1521 * Create the first indirect block if needed.
1523 ifnot(nb = swizzle16(ip->c_node.i_addr[20 - j])) {
1524 if (rwflg || !(nb = blk_alloc(dev)))
1526 ip->c_node.i_addr[20 - j] = swizzle16(nb);
1531 * fetch through the indirect blocks
1533 for (; j <= 2; j++) {
1534 bp = (bufptr) bread(dev, nb, 0);
1541 i = (bn >> sh) & 0xff;
1542 if ((nb = swizzle16(((blkno_t *) bp)[i])) != 0)
1545 if (rwflg || !(nb = blk_alloc(dev))) {
1549 ((blkno_t *) bp)[i] = swizzle16(nb);
1559 /* Validblk panics if the given block number is not a valid
1560 * data block for the given device.
1562 void validblk(int dev, blkno_t num)
1564 register fsptr devptr;
1566 devptr = fs_tab + dev;
1568 if (devptr->s_mounted == 0)
1569 panic("validblk: not mounted");
1571 if (num < swizzle16(devptr->s_isize)
1572 || num >= swizzle16(devptr->s_fsize))
1573 panic("validblk: invalid blk");
1578 /* This returns the inode pointer associated with a user's file
1579 * descriptor, checking for valid data structures.
1581 inoptr getinode(int uindex)
1583 register int oftindex;
1584 register inoptr inoindex;
1586 if (uindex < 0 || uindex >= UFTSIZE
1587 || udata.u_files[uindex] & 0x80) {
1588 udata.u_error = EBADF;
1592 if ((oftindex = udata.u_files[uindex]) < 0 || oftindex >= OFTSIZE)
1593 panic("Getinode: bad desc table");
1595 if ((inoindex = of_tab[oftindex].o_inode) < i_tab ||
1596 inoindex >= i_tab + ITABSIZE)
1597 panic("Getinode: bad OFT");
1604 /* This sets the times of the given inode, according to the flags.
1606 void setftime(inoptr ino, int flag)
1614 ino->c_node.i_atime = swizzle32(now);
1616 ino->c_node.i_mtime = swizzle32(now);
1618 ino->c_node.i_ctime = swizzle32(now);
1623 int fuzix_getmode(inoptr ino)
1625 return (swizzle16(ino->c_node.i_mode) & F_MASK);
1629 /* Fmount places the given device in the mount table with mount point ino.
1631 int fmount(int dev, inoptr ino)
1634 register struct filesys *fp;
1638 buf = bread(dev, 1, 0);
1639 bcopy(buf, (char *) fp, sizeof(struct filesys));
1640 brelse((bufptr) buf);
1642 /* See if there really is a filesystem on the device */
1643 if (fp->s_mounted == SMOUNTED_WRONGENDIAN)
1645 if (swizzle16(fp->s_mounted) != SMOUNTED ||
1646 swizzle16(fp->s_isize) >= swizzle16(fp->s_fsize))
1656 void magic(inoptr ino)
1658 if (ino->c_magic != CMAGIC)
1659 panic("Corrupt inode");
1662 char *bread(int dev, blkno_t blk, int rewrite)
1666 /*printf("Reading block %d\n", blk);*/
1668 bp = bfind(dev, blk);
1671 panic("want busy block");
1678 /* If rewrite is set, we are about to write over the entire block,
1679 so we don't need the previous contents */
1682 if (bdread(bp) == -1) {
1683 udata.u_error = EIO;
1689 //printf("bread %d\n", (int)(bp - bufpool));
1690 bp->bf_time = ++bufclock; /* Time stamp it */
1691 return (bp->bf_data);
1695 void brelse(bufptr bp)
1697 /*printf("Releasing block %d (0)\n", bp->bf_blk);*/
1701 void bawrite(bufptr bp)
1703 /*printf("Releasing block %d (1)\n", bp->bf_blk);*/
1707 int bfree(bufptr bp, int dirty)
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;
1715 if (dirty == 2) { /* Extra dirty */
1716 if (bdwrite(bp) == -1)
1717 udata.u_error = EIO;
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()!
1734 /*printf("Allocating temp block\n");*/
1738 //printf("tmpbuf %d\n", (int)(bp - bufpool));
1739 bp->bf_time = ++bufclock; /* Time stamp it */
1740 return (bp->bf_data);
1759 for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
1760 if (bp->bf_dev != -1 && bp->bf_dirty) {
1768 bufptr bfind(int dev, blkno_t blk)
1772 for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
1773 if (bp->bf_dev == dev && bp->bf_blk == blk)
1780 bufptr freebuf(void)
1783 register bufptr oldest;
1784 register int oldtime;
1786 /* Try to find a non-busy buffer and write out the data if it is dirty */
1789 //printf("nonbusy");
1790 for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
1792 // printf(" %d(%lld)", (int)(bp -bufpool), bufclock - bp->bf_time);
1793 if (bufclock - bp->bf_time >= oldtime && !bp->bf_busy) {
1795 oldtime = bufclock - bp->bf_time;
1800 panic("no free buffers");
1802 if (oldest->bf_dirty) {
1803 if (bdwrite(oldest) == -1)
1804 udata.u_error = EIO;
1805 oldest->bf_dirty = 0;
1814 for (bp = bufpool; bp < bufpool + NBUFS; ++bp) {
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
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 **********************************************************************/
1831 int bdread(bufptr bp)
1833 /* printf("bdread(fd=%d, block %d)\n", dev_fd, bp->bf_blk); */
1837 (dev_fd, dev_offset + (((int) bp->bf_blk) * 512),
1840 if (read(dev_fd, bp->bf_data, 512) != 512)
1841 panic("read() failed");
1847 int bdwrite(bufptr bp)
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");