home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
GEMini Atari
/
GEMini_Atari_CD-ROM_Walnut_Creek_December_1993.iso
/
files
/
mint
/
mint095s
/
unifs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-08-03
|
11KB
|
548 lines
/*
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;
}