--- MiNT/src/unifs.c 2018/04/24 17:56:34 1.1.1.3 +++ MiNT/src/unifs.c 2018/04/24 17:57:22 1.1.1.4 @@ -2,7 +2,7 @@ Copyright 1991,1992 Eric R. Smith. -Copyright 1992 Atari Corporation. +Copyright 1992,1993 Atari Corporation. All rights reserved. @@ -66,6 +66,8 @@ static long ARGS_ON_STACK uni_symlink P_ static long ARGS_ON_STACK uni_readlink P_((fcookie *fc, char *buf, int buflen)); +static long ARGS_ON_STACK uni_fscntl P_((fcookie *dir, const char *name, int cmd, long arg)); + FILESYS uni_filesys = { @@ -86,7 +88,7 @@ FILESYS uni_filesys = { uni_pathconf, uni_dfree, nowritelabel, noreadlabel, - uni_symlink, uni_readlink, nohardlink, nofscntl, nodskchng + uni_symlink, uni_readlink, nohardlink, uni_fscntl, nodskchng }; @@ -1232,3 +1234,321 @@ uni_readlink(fc, buf, buflen) } + + + + + + + + +/* uk: use these Dcntl's to install a new filesystem which is only visible + + * on drive u: + + * + + * FS_INSTALL: let the kernel know about the file system; it does NOT + + * get a device number. + + * FS_MOUNT: use Dcntl(FS_MOUNT, "u:\\foo", &descr) to make a directory + + * foo where the filesytem resides in; the file system now + + * gets its device number which is also written into the + + * dev_no field of the fs_descr structure. + + * FS_UNMOUNT: remove a file system's directory; this call closes all + + * open files, directory searches and directories on this + + * device. Make sure that the FS will not recognise any + + * accesses to this device, as fs->root will be called + + * during the reinitalisation! + + * FS_UNINSTALL: remove a file system completely from the kernel list, + + * but that will only be possible if there is no directory + + * associated with this file system. + + * This function allows it to write file systems as demons + + * which stay in memory only as long as needed. + + * + + * BUG: it is not possible yet to lock such a filesystem. + + */ + + + +/* here we start with gemdos only file system device numbers */ + +static curr_dev_no = 0x100; + + + + + + + +static long ARGS_ON_STACK + +uni_fscntl(dir, name, cmd, arg) + + fcookie *dir; + + const char *name; + + int cmd; + + long arg; + +{ + + fcookie fc; + + long r; + + + + extern struct kerinfo kernelinfo; + + extern FILESYS *active_fs; + + + + if (cmd == FS_INSTALL) { /* install a new filesystem */ + + struct fs_descr *d = (struct fs_descr*)arg; + + FILESYS *fs; + + + + /* check if FS is installed already */ + + for (fs = active_fs; fs; fs = fs->next) + + if (d->file_system == fs) return 0L; + + /* include new file system into chain of file systems */ + + d->file_system->next = active_fs; + + active_fs = d->file_system; + + return (long)&kernelinfo; /* return pointer to kernel info as OK */ + + } else if (cmd == FS_MOUNT) { /* install a new gemdos-only device for this FS */ + + struct fs_descr *d = (struct fs_descr*)arg; + + FILESYS *fs; + + UNIFILE *u; + + + + /* first check for existing names */ + + r = uni_lookup(dir, name, &fc); + + if (r == 0) { + + release_cookie(&fc); + + return EACCDN; /* name exists already */ + + } + + if (r != EFILNF) return r; /* some other error */ + + if (!d) return EACCDN; + + if (!d->file_system) return EACCDN; + + /* check if FS is installed */ + + for (fs = active_fs; fs; fs = fs->next) + + if (d->file_system == fs) break; + + if (!fs) return EACCDN; /* not installed, so return an error */ + + u = kmalloc(SIZEOF(UNIFILE)); + + if (!u) return EACCDN; + + strncpy(u->name, name, NAME_MAX); + + u->name[NAME_MAX] = 0; + + u->mode = S_IFDIR|DEFAULT_DIRMODE; + + u->data = 0; + + u->fs = d->file_system; + + /* now get the file system its own device number */ + + u->dev = d->dev_no = curr_dev_no++; + + /* chain new entry into unifile list */ + + u->next = u_root; + + u_root = u; + + return (long)u->dev; + + } else if (cmd == FS_UNMOUNT) { /* remove a file system's directory */ + + struct fs_descr *d = (struct fs_descr*)arg; + + FILESYS *fs; + + UNIFILE *u; + + + + /* first check that directory exists */ + + r = uni_lookup(dir, name, &fc); + + if (r != 0) return EFILNF; /* name does not exist */ + + if (!d) return EFILNF; + + if (!d->file_system) return EFILNF; + + if (d->file_system != fc.fs) + + return EFILNF; /* not the right name! */ + + u = (UNIFILE*)fc.index; + + release_cookie(&fc); + + if (!u || (u->fs != d->file_system)) + + return EFILNF; + + /* check if FS is installed */ + + for (fs = active_fs; fs; fs = fs->next) + + if (d->file_system == fs) break; + + if (!fs) return EACCDN; /* not installed, so return an error */ + + + + /* here comes the difficult part: we have to close all files on that + + * device, so we have to call changedrv(). The file system driver + + * has to make sure that further calls to fs.root() with this device + + * number will fail! + + * + + * Kludge: mark the directory as a link, so uni_remove will remove it. + + */ + + changedrv(u->dev); + + u->mode &= ~S_IFMT; + + u->mode |= S_IFLNK; + + return uni_remove(dir, name); + + } else if (cmd == FS_UNINSTALL) { /* remove file system from kernel list */ + + struct fs_descr *d = (struct fs_descr*)arg; + + FILESYS *fs, *last_fs; + + UNIFILE *u; + + + + /* first check if there are any files or directories associated with + + * this file system + + */ + + for (u = u_root; u; u = u->next) + + if (u->fs == d->file_system) + + return EACCDN; /* we cannot remove it before unmount */ + + last_fs = 0; + + fs = active_fs; + + while (fs) { /* go through the list and remove the file system */ + + if (fs == d->file_system) { + + if (last_fs) + + last_fs->next = fs->next; + + else + + active_fs = fs->next; + + d->file_system->next = 0; + + return 0; + + } + + last_fs = fs; + + fs = fs->next; + + } + + return EFILNF; + + } else { + + /* see if we should just pass this along to another file system */ + + r = uni_lookup(dir, name, &fc); + + if (r == 0) { + + if (fc.fs != &uni_filesys) { + + r = (*fc.fs->fscntl)(&fc, ".", cmd, arg); + + release_cookie(&fc); + + return r; + + } + + release_cookie(&fc); + + } + + } + + return EINVFN; + +} +