--- MiNT/src/unifs.c 2018/04/24 17:55:36 1.1 +++ MiNT/src/unifs.c 2018/04/24 17:58:54 1.1.1.6 @@ -1,6 +1,10 @@ /* -Copyright 1991,1992 Eric R. Smith. All rights reserved. +Copyright 1991,1992 Eric R. Smith. + +Copyright 1992,1993,1994 Atari Corporation. + +All rights reserved. */ @@ -20,45 +24,49 @@ extern FILESYS bios_filesys, proc_filesy -static long uni_root P_((int drv, fcookie *fc)); +static long ARGS_ON_STACK uni_root P_((int drv, fcookie *fc)); + +static long ARGS_ON_STACK uni_lookup P_((fcookie *dir, const char *name, fcookie *fc)); -static long uni_lookup P_((fcookie *dir, const char *name, fcookie *fc)); +static long ARGS_ON_STACK uni_getxattr P_((fcookie *fc, XATTR *xattr)); -static long uni_getxattr P_((fcookie *fc, XATTR *xattr)); +static long ARGS_ON_STACK uni_chattr P_((fcookie *fc, int attrib)); -static long uni_chattr P_((fcookie *fc, int attrib)); +static long ARGS_ON_STACK uni_chown P_((fcookie *fc, int uid, int gid)); -static long uni_chown P_((fcookie *fc, int uid, int gid)); +static long ARGS_ON_STACK uni_chmode P_((fcookie *fc, unsigned mode)); -static long uni_chmode P_((fcookie *fc, unsigned mode)); +static long ARGS_ON_STACK uni_rmdir P_((fcookie *dir, const char *name)); -static long uni_rmdir P_((fcookie *dir, const char *name)); +static long ARGS_ON_STACK uni_remove P_((fcookie *dir, const char *name)); -static long uni_remove P_((fcookie *dir, const char *name)); +static long ARGS_ON_STACK uni_getname P_((fcookie *root, fcookie *dir, -static long uni_getname P_((fcookie *root, fcookie *dir, char *pathname)); + char *pathname, int size)); -static long uni_rename P_((fcookie *olddir, char *oldname, +static long ARGS_ON_STACK uni_rename P_((fcookie *olddir, char *oldname, fcookie *newdir, const char *newname)); -static long uni_opendir P_((DIR *dirh, int flags)); +static long ARGS_ON_STACK uni_opendir P_((DIR *dirh, int flags)); -static long uni_readdir P_((DIR *dirh, char *nm, int nmlen, fcookie *)); +static long ARGS_ON_STACK uni_readdir P_((DIR *dirh, char *nm, int nmlen, fcookie *)); -static long uni_rewinddir P_((DIR *dirh)); +static long ARGS_ON_STACK uni_rewinddir P_((DIR *dirh)); -static long uni_closedir P_((DIR *dirh)); +static long ARGS_ON_STACK uni_closedir P_((DIR *dirh)); -static long uni_pathconf P_((fcookie *dir, int which)); +static long ARGS_ON_STACK uni_pathconf P_((fcookie *dir, int which)); -static long uni_dfree P_((fcookie *dir, long *buf)); +static long ARGS_ON_STACK uni_dfree P_((fcookie *dir, long *buf)); -static DEVDRV * uni_getdev P_((fcookie *fc, long *devsp)); +static DEVDRV * ARGS_ON_STACK uni_getdev P_((fcookie *fc, long *devsp)); -static long uni_symlink P_((fcookie *dir, const char *name, const char *to)); +static long ARGS_ON_STACK uni_symlink P_((fcookie *dir, const char *name, const char *to)); -static long uni_readlink P_((fcookie *fc, char *buf, int buflen)); +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)); @@ -66,7 +74,7 @@ FILESYS uni_filesys = { (FILESYS *)0, - 0, + FS_LONGPATH, uni_root, @@ -80,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 }; @@ -110,7 +118,7 @@ typedef struct unifile { char name[NAME_MAX+1]; - short mode; + ushort mode; ushort dev; @@ -120,17 +128,43 @@ typedef struct unifile { struct unifile *next; + short cdate, ctime; + } UNIFILE; -/* the "+1" is for shared memory, which has no BIOS drive */ +static UNIFILE u_drvs[UNI_NUM_DRVS]; + +static UNIFILE *u_root = 0; -#define UNI_DIRS NUM_DRIVES+1 -static UNIFILE u_drvs[UNI_DIRS]; -static UNIFILE *u_root = 0; +static long do_ulookup P_((fcookie *, const char *, fcookie *, UNIFILE **)); + + + +FILESYS * + +get_filesys (dev) + + int dev; + +{ + + UNIFILE *u; + + + + for (u = u_root; u; u = u->next) + + if (u->dev == dev) + + return u->fs; + + return (FILESYS *) 0L; + +} @@ -148,7 +182,7 @@ unifs_init() u_root = u; - for (i = 0; i < NUM_DRIVES; i++,u++) { + for (i = 0; i < UNI_NUM_DRVS; i++,u++) { u->next = u+1; @@ -156,49 +190,59 @@ unifs_init() u->dev = i; - u->fs = 0; + u->cdate = datestamp; - if (i == PROCDRV) + u->ctime = timestamp; + + if (i == PROCDRV) { strcpy(u->name, "proc"); - else if (i == PIPEDRV) + u->fs = &proc_filesys; + + } else if (i == PIPEDRV) { strcpy(u->name, "pipe"); - else if (i == BIOSDRV) + u->fs = &pipe_filesys; + + } else if (i == BIOSDRV) { strcpy(u->name, "dev"); - else if (i == UNIDRV) { + u->fs = &bios_filesys; + + } else if (i == UNIDRV) { (u-1)->next = u->next; /* skip this drive */ + } else if (i == SHMDRV) { + + strcpy(u->name, "shm"); + + u->fs = &shm_filesys; + } else { u->name[0] = i + 'a'; u->name[1] = 0; + u->fs = 0; + } } - u->next = 0; - - u->mode = S_IFDIR|DEFAULT_DIRMODE; - - u->dev = SHMDEVICE; - - u->fs = &shm_filesys; + --u; /* oops, we went too far */ - strcpy(u->name, "shm"); + u->next = 0; } -static long +static long ARGS_ON_STACK uni_root(drv, fc) @@ -228,7 +272,7 @@ uni_root(drv, fc) -static long +static long ARGS_ON_STACK uni_lookup(dir, name, fc) @@ -240,23 +284,51 @@ uni_lookup(dir, name, fc) { + return do_ulookup(dir, name, fc, (UNIFILE **)0); + +} + + + +/* worker function for uni_lookup; can also return the UNIFILE + + * pointer for the root directory + + */ + +static long + +do_ulookup(dir, name, fc, up) + + fcookie *dir; + + const char *name; + + fcookie *fc; + + UNIFILE **up; + +{ + UNIFILE *u; long drvs; FILESYS *fs; + fcookie *tmp; + extern long dosdrvs; - TRACE("uni_lookup(%s)", name); + TRACE(("uni_lookup(%s)", name)); if (dir->index != 0) { - DEBUG("uni_lookup: bad directory"); + DEBUG(("uni_lookup: bad directory")); return EPTHNF; @@ -270,7 +342,7 @@ uni_lookup(dir, name, fc) if (!*name || !strcmp(name, ".") || !strcmp(name, "..")) { - *fc = *dir; + dup_cookie(fc, dir); return 0; @@ -286,7 +358,7 @@ uni_lookup(dir, name, fc) for (u = u_root; u; u = u->next) { - if (!stricmp(name, u->name)) { + if (!strnicmp(name, u->name, NAME_MAX)) { if ( (u->mode & S_IFMT) == S_IFDIR ) { @@ -294,6 +366,8 @@ uni_lookup(dir, name, fc) fs = u->fs; + if (up) *up = u; + return (*fs->root)(u->dev,fc); } @@ -302,20 +376,22 @@ uni_lookup(dir, name, fc) return EPTHNF; - *fc = curproc->root[u->dev]; + tmp = &curproc->root[u->dev]; - if (!fc->fs) { /* drive changed? */ + if (!tmp->fs) { /* drive changed? */ - changedrv(fc->dev); + changedrv(tmp->dev); - *fc = curproc->root[u->dev]; + tmp = &curproc->root[u->dev]; - if (!fc->fs) + if (!tmp->fs) return EPTHNF; } + dup_cookie(fc, tmp); + } else { /* a symbolic link */ fc->fs = &uni_filesys; @@ -326,13 +402,15 @@ uni_lookup(dir, name, fc) } + if (up) *up = u; + return 0; } } - DEBUG("uni_lookup: name (%s) not found", name); + DEBUG(("uni_lookup: name (%s) not found", name)); return EFILNF; @@ -340,7 +418,7 @@ uni_lookup(dir, name, fc) -static long +static long ARGS_ON_STACK uni_getxattr(fc, xattr) @@ -366,7 +444,7 @@ uni_getxattr(fc, xattr) xattr->index = fc->index; - xattr->dev = fc->dev; + xattr->dev = xattr->rdev = fc->dev; xattr->nlink = 1; @@ -404,9 +482,9 @@ uni_getxattr(fc, xattr) } - xattr->mtime = xattr->atime = xattr->ctime = 0; + xattr->mtime = xattr->atime = xattr->ctime = u->ctime; - xattr->mdate = xattr->adate = xattr->cdate = 0; + xattr->mdate = xattr->adate = xattr->cdate = u->cdate; return 0; @@ -414,7 +492,7 @@ uni_getxattr(fc, xattr) -static long +static long ARGS_ON_STACK uni_chattr(dir, attrib) @@ -424,13 +502,15 @@ uni_chattr(dir, attrib) { + UNUSED(dir); UNUSED(attrib); + return EACCDN; } -static long +static long ARGS_ON_STACK uni_chown(dir, uid, gid) @@ -440,13 +520,17 @@ uni_chown(dir, uid, gid) { + UNUSED(dir); UNUSED(uid); + + UNUSED(gid); + return EINVFN; } -static long +static long ARGS_ON_STACK uni_chmode(dir, mode) @@ -456,13 +540,17 @@ uni_chmode(dir, mode) { + UNUSED(dir); + + UNUSED(mode); + return EINVFN; } -static long +static long ARGS_ON_STACK uni_rmdir(dir, name) @@ -486,7 +574,7 @@ uni_rmdir(dir, name) -static long +static long ARGS_ON_STACK uni_remove(dir, name) @@ -500,16 +588,24 @@ uni_remove(dir, name) + UNUSED(dir); + + + lastu = 0; u = u_root; while (u) { - if (!strncmp(u->name, name, NAME_MAX)) { + if (!strnicmp(u->name, name, NAME_MAX)) { if ( (u->mode & S_IFMT) != S_IFLNK ) return EFILNF; + if (curproc->euid && (u->dev != curproc->euid)) + + return EACCDN; + kfree(u->data); if (lastu) @@ -538,12 +634,14 @@ uni_remove(dir, name) -static long +static long ARGS_ON_STACK -uni_getname(root, dir, pathname) +uni_getname(root, dir, pathname, size) fcookie *root, *dir; char *pathname; + int size; + { FILESYS *fs; @@ -554,6 +652,18 @@ uni_getname(root, dir, pathname) fcookie relto; + char tmppath[PATH_MAX]; + + long r; + + + + UNUSED(root); + + + + if (size <= 0) return ERANGE; + fs = dir->fs; @@ -574,10 +684,16 @@ uni_getname(root, dir, pathname) *pathname++ = '\\'; - for (n = u->name; *n; ) + if (--size <= 0) return ERANGE; + + for (n = u->name; *n; ) { *pathname++ = *n++; + if (--size <= 0) return ERANGE; + + } + break; } @@ -600,11 +716,41 @@ uni_getname(root, dir, pathname) if ((*fs->root)(dir->dev, &relto) == 0) { - return (*fs->getname)(&relto, dir, pathname); + if (!(fs->fsflags & FS_LONGPATH)) { + + r = (*fs->getname)(&relto, dir, tmppath, PATH_MAX); + + release_cookie(&relto); + + if (r) { + + return r; + + } + + if (strlen(tmppath) < size) { + + strcpy(pathname, tmppath); + + return 0; + + } else { + + return ERANGE; + + } + + } + + r = (*fs->getname)(&relto, dir, pathname, size); + + release_cookie(&relto); + + return r; } else { - *pathname++ = 0; + *pathname = 0; return EINTRN; @@ -624,13 +770,41 @@ uni_getname(root, dir, pathname) - return (*fs->getname)(&curproc->root[dir->dev], dir, pathname); + if (!fs) { + + *pathname = 0; + + return 0; + + } + + if (!(fs->fsflags & FS_LONGPATH)) { + + r = (*fs->getname)(&curproc->root[dir->dev], dir, tmppath, PATH_MAX); + + if (r) return r; + + if (strlen(tmppath) < size) { + + strcpy(pathname, tmppath); + + return 0; + + } else { + + return ERANGE; + + } + + } + + return (*fs->getname)(&curproc->root[dir->dev], dir, pathname, size); } -static long +static long ARGS_ON_STACK uni_rename(olddir, oldname, newdir, newname) @@ -644,7 +818,7 @@ uni_rename(olddir, oldname, newdir, newn { - UNIFILE *u = 0; + UNIFILE *u; fcookie fc; @@ -652,9 +826,13 @@ uni_rename(olddir, oldname, newdir, newn + UNUSED(olddir); + + + for (u = u_root; u; u = u->next) { - if (!stricmp(u->name, oldname)) + if (!strnicmp(u->name, oldname, NAME_MAX)) break; @@ -664,7 +842,7 @@ uni_rename(olddir, oldname, newdir, newn if (!u) { - DEBUG("uni_rename: old file not found"); + DEBUG(("uni_rename: old file not found")); return EFILNF; @@ -676,9 +854,15 @@ uni_rename(olddir, oldname, newdir, newn r = uni_lookup(newdir, newname, &fc); + if (r == 0) + + release_cookie(&fc); + + + if (r != EFILNF) { - DEBUG("uni_rename: error %ld", r); + DEBUG(("uni_rename: error %ld", r)); return (r == 0) ? EACCDN : r; @@ -694,7 +878,7 @@ uni_rename(olddir, oldname, newdir, newn -static long +static long ARGS_ON_STACK uni_opendir(dirh, flags) @@ -704,9 +888,13 @@ uni_opendir(dirh, flags) { + UNUSED(flags); + + + if (dirh->fc.index != 0) { - DEBUG("uni_opendir: bad directory"); + DEBUG(("uni_opendir: bad directory")); return EPTHNF; @@ -722,7 +910,7 @@ uni_opendir(dirh, flags) -static long +static long ARGS_ON_STACK uni_readdir(dirh, name, namelen, fc) @@ -812,7 +1000,7 @@ tryagain: } - *fc = curproc->root[u->dev]; + dup_cookie(fc, &curproc->root[u->dev]); if (!fc->fs) { /* drive not yet initialized */ @@ -842,9 +1030,15 @@ tryagain: if (giveindex) { - namelen -= sizeof(long); + namelen -= (int)sizeof(long); - if (namelen <= 0) return ERANGE; + if (namelen <= 0) { + + release_cookie(fc); + + return ERANGE; + + } *((long *)name) = index; @@ -854,17 +1048,21 @@ tryagain: strncpy(name, dirname, namelen-1); - if (strlen(name) < strlen(dirname)) + if (strlen(name) < strlen(dirname)) { + + release_cookie(fc); return ENAMETOOLONG; + } + return 0; } -static long +static long ARGS_ON_STACK uni_rewinddir(dirh) @@ -880,7 +1078,7 @@ uni_rewinddir(dirh) -static long +static long ARGS_ON_STACK uni_closedir(dirh) @@ -888,13 +1086,15 @@ uni_closedir(dirh) { + UNUSED(dirh); + return 0; } -static long +static long ARGS_ON_STACK uni_pathconf(dir, which) @@ -904,6 +1104,10 @@ uni_pathconf(dir, which) { + UNUSED(dir); + + + switch(which) { case -1: @@ -938,6 +1142,14 @@ uni_pathconf(dir, which) return DP_CASEINSENS; + case DP_MODEATTR: + + return DP_FT_DIR|DP_FT_LNK; + + case DP_XATTRFIELDS: + + return DP_INDEX|DP_DEV|DP_NLINK|DP_SIZE; + default: return EINVFN; @@ -948,7 +1160,7 @@ uni_pathconf(dir, which) -static long +static long ARGS_ON_STACK uni_dfree(dir, buf) @@ -958,6 +1170,10 @@ uni_dfree(dir, buf) { + UNUSED(dir); + + + buf[0] = 0; /* number of free clusters */ buf[1] = 0; /* total number of clusters */ @@ -972,7 +1188,7 @@ uni_dfree(dir, buf) -static DEVDRV * +static DEVDRV * ARGS_ON_STACK uni_getdev(fc, devsp) @@ -982,6 +1198,10 @@ uni_getdev(fc, devsp) { + UNUSED(fc); + + + *devsp = EACCDN; return 0; @@ -990,7 +1210,7 @@ uni_getdev(fc, devsp) -static long +static long ARGS_ON_STACK uni_symlink(dir, name, to) @@ -1012,12 +1232,24 @@ uni_symlink(dir, name, to) r = uni_lookup(dir, name, &fc); - if (r == 0) return EACCDN; /* file already exists */ + if (r == 0) { + + release_cookie(&fc); + + return EACCDN; /* file already exists */ + + } if (r != EFILNF) return r; /* some other error */ + if (curproc->egid) + + return EACCDN; /* only members of admin group may do that */ + + + u = kmalloc(SIZEOF(UNIFILE)); if (!u) return EACCDN; @@ -1044,12 +1276,16 @@ uni_symlink(dir, name, to) u->mode = S_IFLNK | DEFAULT_DIRMODE; - u->dev = curproc->ruid; + u->dev = curproc->euid; u->next = u_root; u->fs = &uni_filesys; + u->cdate = datestamp; + + u->ctime = timestamp; + u_root = u; return 0; @@ -1058,7 +1294,7 @@ uni_symlink(dir, name, to) -static long +static long ARGS_ON_STACK uni_readlink(fc, buf, buflen) @@ -1092,3 +1328,323 @@ 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 == (int)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 == (int)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 == (int)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 */ + + /* use special uni_lookup mode to get the unifile entry */ + + r = do_ulookup(dir, name, &fc, &u); + + 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! */ + + 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 == (int)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; + +} +