home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright 1991,1992 Eric R. Smith. All rights reserved.
- */
-
- /* a simple unified file system */
-
- #include "mint.h"
-
-
- extern FILESYS bios_filesys, proc_filesys, pipe_filesys, shm_filesys;
-
- static long uni_root P_((int drv, fcookie *fc));
- static long uni_lookup P_((fcookie *dir, const char *name, fcookie *fc));
- static long uni_getxattr P_((fcookie *fc, XATTR *xattr));
- static long uni_chattr P_((fcookie *fc, int attrib));
- static long uni_chown P_((fcookie *fc, int uid, int gid));
- static long uni_chmode P_((fcookie *fc, unsigned mode));
- static long uni_rmdir P_((fcookie *dir, const char *name));
- static long uni_remove P_((fcookie *dir, const char *name));
- static long uni_getname P_((fcookie *root, fcookie *dir, char *pathname));
- static long uni_rename P_((fcookie *olddir, char *oldname,
- fcookie *newdir, const char *newname));
- static long uni_opendir P_((DIR *dirh, int flags));
- static long uni_readdir P_((DIR *dirh, char *nm, int nmlen, fcookie *));
- static long uni_rewinddir P_((DIR *dirh));
- static long uni_closedir P_((DIR *dirh));
- static long uni_pathconf P_((fcookie *dir, int which));
- static long uni_dfree P_((fcookie *dir, long *buf));
- static DEVDRV * uni_getdev P_((fcookie *fc, long *devsp));
- static long uni_symlink P_((fcookie *dir, const char *name, const char *to));
- static long uni_readlink P_((fcookie *fc, char *buf, int buflen));
-
- FILESYS uni_filesys = {
- (FILESYS *)0,
- 0,
- uni_root,
- uni_lookup, nocreat, uni_getdev, uni_getxattr,
- uni_chattr, uni_chown, uni_chmode,
- nomkdir, uni_rmdir, uni_remove, uni_getname, uni_rename,
- uni_opendir, uni_readdir, uni_rewinddir, uni_closedir,
- uni_pathconf, uni_dfree, nowritelabel, noreadlabel,
- uni_symlink, uni_readlink, nohardlink, nofscntl, nodskchng
- };
-
- /*
- * structure that holds files
- * if (mode & S_IFMT == S_IFDIR), then this is an alias for a drive:
- * "dev" holds the appropriate BIOS device number, and
- * "data" is meaningless
- * if (mode & S_IFMT == S_IFLNK), then this is a symbolic link:
- * "dev" holds the user id of the owner, and
- * "data" points to the actual link data
- */
-
- typedef struct unifile {
- char name[NAME_MAX+1];
- short mode;
- ushort dev;
- FILESYS *fs;
- void *data;
- struct unifile *next;
- } UNIFILE;
-
- /* the "+1" is for shared memory, which has no BIOS drive */
- #define UNI_DIRS NUM_DRIVES+1
- static UNIFILE u_drvs[UNI_DIRS];
- static UNIFILE *u_root = 0;
-
- void
- unifs_init()
- {
- UNIFILE *u = u_drvs;
- int i;
-
- u_root = u;
- for (i = 0; i < NUM_DRIVES; i++,u++) {
- u->next = u+1;
- u->mode = S_IFDIR|DEFAULT_DIRMODE;
- u->dev = i;
- u->fs = 0;
- if (i == PROCDRV)
- strcpy(u->name, "proc");
- else if (i == PIPEDRV)
- strcpy(u->name, "pipe");
- else if (i == BIOSDRV)
- strcpy(u->name, "dev");
- else if (i == UNIDRV) {
- (u-1)->next = u->next; /* skip this drive */
- } else {
- u->name[0] = i + 'a';
- u->name[1] = 0;
- }
- }
- u->next = 0;
- u->mode = S_IFDIR|DEFAULT_DIRMODE;
- u->dev = SHMDEVICE;
- u->fs = &shm_filesys;
- strcpy(u->name, "shm");
- }
-
- static long
- uni_root(drv, fc)
- int drv;
- fcookie *fc;
- {
- if (drv == UNIDRV) {
- fc->fs = &uni_filesys;
- fc->dev = drv;
- fc->index = 0L;
- return 0;
- }
- fc->fs = 0;
- return EINTRN;
- }
-
- static long
- uni_lookup(dir, name, fc)
- fcookie *dir;
- const char *name;
- fcookie *fc;
- {
- UNIFILE *u;
- long drvs;
- FILESYS *fs;
- extern long dosdrvs;
-
- TRACE("uni_lookup(%s)", name);
-
- if (dir->index != 0) {
- DEBUG("uni_lookup: bad directory");
- return EPTHNF;
- }
- /* special case: an empty name in a directory means that directory */
- /* so do "." and ".." */
-
- if (!*name || !strcmp(name, ".") || !strcmp(name, "..")) {
- *fc = *dir;
- return 0;
- }
- drvs = drvmap() | dosdrvs | PSEUDODRVS;
- /*
- * OK, check the list of aliases and special directories
- */
- for (u = u_root; u; u = u->next) {
- if (!stricmp(name, u->name)) {
- if ( (u->mode & S_IFMT) == S_IFDIR ) {
- if (u->dev >= NUM_DRIVES) {
- fs = u->fs;
- return (*fs->root)(u->dev,fc);
- }
- if ((drvs & (1L << u->dev)) == 0)
- return EPTHNF;
- *fc = curproc->root[u->dev];
- if (!fc->fs) { /* drive changed? */
- changedrv(fc->dev);
- *fc = curproc->root[u->dev];
- if (!fc->fs)
- return EPTHNF;
- }
- } else { /* a symbolic link */
- fc->fs = &uni_filesys;
- fc->dev = UNIDRV;
- fc->index = (long)u;
- }
- return 0;
- }
- }
- DEBUG("uni_lookup: name (%s) not found", name);
- return EFILNF;
- }
-
- static long
- uni_getxattr(fc, xattr)
- fcookie *fc;
- XATTR *xattr;
- {
- UNIFILE *u = (UNIFILE *)fc->index;
-
- if (fc->fs != &uni_filesys) {
- ALERT("ERROR: wrong file system getxattr called");
- return EINTRN;
- }
-
- xattr->index = fc->index;
- xattr->dev = fc->dev;
- xattr->nlink = 1;
- xattr->blksize = 1;
-
- /* If "u" is null, then we have the root directory, otherwise
- * we use the UNIFILE structure to get the info about it
- */
- if (!u || ( (u->mode & S_IFMT) == S_IFDIR )) {
- xattr->uid = xattr->gid = 0;
- xattr->size = xattr->nblocks = 0;
- xattr->mode = S_IFDIR | DEFAULT_DIRMODE;
- xattr->attr = FA_DIR;
- } else {
- xattr->uid = u->dev;
- xattr->gid = 0;
- xattr->size = xattr->nblocks = strlen(u->data) + 1;
- xattr->mode = u->mode;
- xattr->attr = 0;
- }
- xattr->mtime = xattr->atime = xattr->ctime = 0;
- xattr->mdate = xattr->adate = xattr->cdate = 0;
- return 0;
- }
-
- static long
- uni_chattr(dir, attrib)
- fcookie *dir;
- int attrib;
- {
- return EACCDN;
- }
-
- static long
- uni_chown(dir, uid, gid)
- fcookie *dir;
- int uid, gid;
- {
- return EINVFN;
- }
-
- static long
- uni_chmode(dir, mode)
- fcookie *dir;
- unsigned mode;
- {
- return EINVFN;
- }
-
- static long
- uni_rmdir(dir, name)
- fcookie *dir;
- const char *name;
- {
- long r;
-
- r = uni_remove(dir, name);
- if (r == EFILNF) r = EPTHNF;
- return r;
- }
-
- static long
- uni_remove(dir, name)
- fcookie *dir;
- const char *name;
- {
- UNIFILE *u, *lastu;
-
- lastu = 0;
- u = u_root;
- while (u) {
- if (!strncmp(u->name, name, NAME_MAX)) {
- if ( (u->mode & S_IFMT) != S_IFLNK ) return EFILNF;
- kfree(u->data);
- if (lastu)
- lastu->next = u->next;
- else
- u_root = u->next;
- kfree(u);
- return 0;
- }
- lastu = u;
- u = u->next;
- }
- return EFILNF;
- }
-
- static long
- uni_getname(root, dir, pathname)
- fcookie *root, *dir; char *pathname;
- {
- FILESYS *fs;
- UNIFILE *u;
- char *n;
- fcookie relto;
-
- fs = dir->fs;
- if (dir->dev == UNIDRV) {
- *pathname = 0;
- return 0;
- }
-
- for (u = u_root; u; u = u->next) {
- if (dir->dev == u->dev && (u->mode & S_IFMT) == S_IFDIR) {
- *pathname++ = '\\';
- for (n = u->name; *n; )
- *pathname++ = *n++;
- break;
- }
- }
-
- if (!u) {
- ALERT("unifs: couldn't match a drive with a directory");
- return EPTHNF;
- }
-
- if (dir->dev >= NUM_DRIVES) {
- if ((*fs->root)(dir->dev, &relto) == 0) {
- return (*fs->getname)(&relto, dir, pathname);
- } else {
- *pathname++ = 0;
- return EINTRN;
- }
- }
-
- if (curproc->root[dir->dev].fs != fs) {
- ALERT("unifs: drive's file system doesn't match directory's");
- return EINTRN;
- }
-
- return (*fs->getname)(&curproc->root[dir->dev], dir, pathname);
- }
-
- static long
- uni_rename(olddir, oldname, newdir, newname)
- fcookie *olddir;
- char *oldname;
- fcookie *newdir;
- const char *newname;
- {
- UNIFILE *u = 0;
- fcookie fc;
- long r;
-
- for (u = u_root; u; u = u->next) {
- if (!stricmp(u->name, oldname))
- break;
- }
-
- if (!u) {
- DEBUG("uni_rename: old file not found");
- return EFILNF;
- }
-
- /* the new name is not allowed to exist! */
- r = uni_lookup(newdir, newname, &fc);
- if (r != EFILNF) {
- DEBUG("uni_rename: error %ld", r);
- return (r == 0) ? EACCDN : r;
- }
-
- (void)strncpy(u->name, newname, NAME_MAX);
- return 0;
- }
-
- static long
- uni_opendir(dirh, flags)
- DIR *dirh;
- int flags;
- {
- if (dirh->fc.index != 0) {
- DEBUG("uni_opendir: bad directory");
- return EPTHNF;
- }
- dirh->index = 0;
- return 0;
- }
-
-
- static long
- uni_readdir(dirh, name, namelen, fc)
- DIR *dirh;
- char *name;
- int namelen;
- fcookie *fc;
- {
- long map;
- char *dirname;
- int i;
- int giveindex = (dirh->flags == 0);
- UNIFILE *u;
- long index;
- extern long dosdrvs;
- long r;
-
- map = dosdrvs | drvmap() | PSEUDODRVS;
- i = dirh->index++;
- u = u_root;
- while (i > 0) {
- --i;
- u = u->next;
- if (!u)
- break;
- }
- tryagain:
- if (!u) return ENMFIL;
-
- dirname = u->name;
- index = (long)u;
- if ( (u->mode & S_IFMT) == S_IFDIR ) {
- /* make sure the drive really exists */
- if ( u->dev >= NUM_DRIVES) {
- r = (*u->fs->root)(u->dev,fc);
- if (r) {
- fc->fs = &uni_filesys;
- fc->index = 0;
- fc->dev = u->dev;
- }
- } else {
- if ((map & (1L << u->dev)) == 0 ) {
- dirh->index++;
- u = u->next;
- goto tryagain;
- }
- *fc = curproc->root[u->dev];
- if (!fc->fs) { /* drive not yet initialized */
- /* use default attributes */
- fc->fs = &uni_filesys;
- fc->index = 0;
- fc->dev = u->dev;
- }
- }
- } else { /* a symbolic link */
- fc->fs = &uni_filesys;
- fc->dev = UNIDRV;
- fc->index = (long)u;
- }
-
- if (giveindex) {
- namelen -= sizeof(long);
- if (namelen <= 0) return ERANGE;
- *((long *)name) = index;
- name += sizeof(long);
- }
- strncpy(name, dirname, namelen-1);
- if (strlen(name) < strlen(dirname))
- return ENAMETOOLONG;
- return 0;
- }
-
- static long
- uni_rewinddir(dirh)
- DIR *dirh;
- {
- dirh->index = 0;
- return 0;
- }
-
- static long
- uni_closedir(dirh)
- DIR *dirh;
- {
- return 0;
- }
-
- static long
- uni_pathconf(dir, which)
- fcookie *dir;
- int which;
- {
- switch(which) {
- case -1:
- return DP_MAXREQ;
- case DP_IOPEN:
- return 0; /* no files to open */
- case DP_MAXLINKS:
- return 1; /* no hard links available */
- case DP_PATHMAX:
- return PATH_MAX;
- case DP_NAMEMAX:
- return NAME_MAX;
- case DP_ATOMIC:
- return 1; /* no atomic writes */
- case DP_TRUNC:
- return DP_AUTOTRUNC;
- case DP_CASE:
- return DP_CASEINSENS;
- default:
- return EINVFN;
- }
- }
-
- static long
- uni_dfree(dir, buf)
- fcookie *dir;
- long *buf;
- {
- buf[0] = 0; /* number of free clusters */
- buf[1] = 0; /* total number of clusters */
- buf[2] = 1; /* sector size (bytes) */
- buf[3] = 1; /* cluster size (sectors) */
- return 0;
- }
-
- static DEVDRV *
- uni_getdev(fc, devsp)
- fcookie *fc;
- long *devsp;
- {
- *devsp = EACCDN;
- return 0;
- }
-
- static long
- uni_symlink(dir, name, to)
- fcookie *dir;
- const char *name;
- const char *to;
- {
- UNIFILE *u;
- fcookie fc;
- long r;
-
- r = uni_lookup(dir, name, &fc);
- if (r == 0) return EACCDN; /* file already exists */
- if (r != EFILNF) return r; /* some other error */
-
- u = kmalloc(SIZEOF(UNIFILE));
- if (!u) return EACCDN;
-
- strncpy(u->name, name, NAME_MAX);
- u->name[NAME_MAX] = 0;
-
- u->data = kmalloc((long)strlen(to)+1);
- if (!u->data) {
- kfree(u);
- return EACCDN;
- }
- strcpy(u->data, to);
- u->mode = S_IFLNK | DEFAULT_DIRMODE;
- u->dev = curproc->ruid;
- u->next = u_root;
- u->fs = &uni_filesys;
- u_root = u;
- return 0;
- }
-
- static long
- uni_readlink(fc, buf, buflen)
- fcookie *fc;
- char *buf;
- int buflen;
- {
- UNIFILE *u;
-
- u = (UNIFILE *)fc->index;
- assert(u);
- assert((u->mode & S_IFMT) == S_IFLNK);
- assert(u->data);
- strncpy(buf, u->data, buflen);
- if (strlen(u->data) >= buflen)
- return ENAMETOOLONG;
- return 0;
- }
-