home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Vectronix 2
/
VECTRONIX2.iso
/
FILES_01
/
MIDICOM.LZH
/
MC_UTILS
/
MC_XFS
/
MCXFS.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-10-05
|
42KB
|
1,828 lines
#define NEWWAY
#include <string.h>
#include <ctype.h>
#include "atarierr.h"
#include "osbind.h"
#define DTABUF DTA
#define NUM_DRIVES 1
#include "filesys.h"
#include "mcxfs.h"
typedef long cdecl (*Func)();
#define NULL (void *)0L
#define UNUSED(x) (void)x
#define READY_Q 1
#define IO_Q 3
#define F_SETLKW 7
/* search mask for anything OTHER THAN a volume label */
#define FILEORDIR 0x37
int MCDRIVE =13;
static char tmpbuf[PATH_MAX+1];
int flk = 0;
static long cdecl mc_root (int drv, fcookie *fc);
static long cdecl mc_lookup (fcookie *dir, const char *name, fcookie *fc);
static long cdecl mc_getxattr (fcookie *fc, XATTR *xattr);
static long cdecl mc_chattr (fcookie *fc, int attrib);
static long cdecl mc_chown (fcookie *fc, int uid, int gid);
static long cdecl mc_chmode (fcookie *fc, unsigned mode);
static long cdecl mc_mkdir (fcookie *dir, const char *name, unsigned mode);
static long cdecl mc_rmdir (fcookie *dir, const char *name);
static long cdecl mc_remove (fcookie *dir, const char *name);
static long cdecl mc_getname (fcookie *root, fcookie *dir,char *pathname,int size);
static long cdecl mc_rename (fcookie *olddir, char *oldname,fcookie *newdir, const char *newname);
static long cdecl mc_opendir (DIR *dirh, int flags);
static long cdecl mc_readdir (DIR *dirh, char *nm, int nmlen, fcookie *);
static long cdecl mc_rewinddir (DIR *dirh);
static long cdecl mc_closedir (DIR *dirh);
static long cdecl mc_pathconf (fcookie *dir, int which);
static long cdecl mc_dfree (fcookie *dir, long *buf);
static long cdecl mc_writelabel (fcookie *dir, const char *name);
static long cdecl mc_readlabel (fcookie *dir, char *name, int namelen);
static long cdecl nodskchng(int drv);
static long cdecl nofscntl(fcookie *dir,const char *name,int cmd,long arg);
static long cdecl nosymlink(fcookie *dir,const char *name,const char *to);
static long cdecl noreadlink(fcookie *dir,char *buf,int buflen);
static long cdecl nohardlink(fcookie *fromdir,fcookie *todir,const char *fromname, const char *toname);
static long cdecl mc_release (fcookie *fc);
static long cdecl mc_dupcookie(fcookie *dest,fcookie *src);
long cdecl mc_creat (fcookie *dir,const char *name, unsigned mode,int attrib, fcookie *fc);
DEVDRV * cdecl mc_getdev (fcookie *fc, long *devsp);
long cdecl mc_open (FILEPTR *f);
long cdecl mc_read (FILEPTR *f, char *buf, long bytes);
long cdecl mc_lseek (FILEPTR *f, long where, int whence);
long cdecl mc_write (FILEPTR *f, const char *buf, long bytes);
long cdecl mc_ioctl (FILEPTR *f, int mode, void *buf);
long cdecl mc_datime (FILEPTR *f, int *time, int rwflag);
long cdecl mc_close (FILEPTR *f, int pid);
/*long cdecl mc_dskchng (int drv);*/
/* some routines from biosfs.c */
long cdecl null_select (FILEPTR *f, long p, int mode);
void cdecl null_unselect (FILEPTR *f, long p, int mode);
DEVDRV mc_device = {
mc_open,mc_write,mc_read,mc_lseek,mc_ioctl,
mc_datime,mc_close,null_select, null_unselect};
FILESYS mc_filesys = {
(FILESYS *)0,FS_NOXBIT | FS_KNOPARSE,
mc_root,mc_lookup,mc_creat,mc_getdev,mc_getxattr,mc_chattr,
mc_chown,mc_chmode,mc_mkdir,mc_rmdir,mc_remove,mc_getname,
mc_rename,mc_opendir,mc_readdir,mc_rewinddir,mc_closedir,
mc_pathconf,mc_dfree,mc_writelabel,mc_readlabel,
nosymlink,noreadlink,nohardlink,nofscntl,nodskchng,
#ifdef NEWWAY
mc_release,
mc_dupcookie
#else
0,0
#endif
};
struct kerinfo *kernel;
#define CCONWS (void)(*kernel->dos_tab[0x09])
#define Timestamp() (*kernel->dos_tab[0x2c])
#define Datestamp() (*kernel->dos_tab[0x2a])
#define Domain() (*kernel->dos_tab[0x119])(-1)
#define Getpid() (*kernel->dos_tab[0x10b])
#define Getuid() (*kernel->dos_tab[0x10f])
#define Getgid() (*kernel->dos_tab[0x114])
#define Nap (*kernel->nap)
#define Sleep (*kernel->sleep)
#define Yield() Sleep(READY_Q, 0L)
#define Wake (*kernel->wake)
#define DEBUG (*kernel->debug)
#define ALERT (*kernel->alert)
#define TRACE (*kernel->trace)
#define FATAL (*kernel->fatal)
#define Kmalloc (*kernel->kmalloc)
#define Kfree (*kernel->kfree)
#define Stricmp (*kernel->stricmp)
#define Sprintf (*kernel->sprintf)
#define Strlwr (*kernel->strlwr)
#define Unixtime (*kernel->unixtim)
#define Dostime (*kernel->dostim)
#define Denyshare (*kernel->denyshare)
#define Denylock (*kernel->denylock)
#define Changedrive (*kernel->drvchng)
static long install_cookies(void);
/*
* this must be the first function; it is called by the kernel when the
* file system is being loaded, and should return the file system
* structure
*/
FILESYS * cdecl mc_init(struct kerinfo *k)
{
kernel = k;
Cconws("MiNT Filesystem\r\n");
Cconws(" für MIDI_COM\r\n");
instmedia();
Cconws("Drive N: only\r\n");
(void)install_cookies();
return (&mc_filesys);
}
/* some utility functions and variables: see end of file */
static DTABUF *lastdta; /* last DTA buffer we asked TOS about */
static DTABUF foo;
static void do_setdta (DTABUF *dta);
static int executable_extension (char *);
/* this array keeps track of which drives have been changed */
/* a nonzero entry means that the corresponding drive has been changed,
* but GEMDOS doesn't know it yet
*/
#ifdef NEWWAY
#define NUM_INDICES 64
#else
#define NUM_INDICES 128
#define MIN_AGE 8
#endif
struct tindex {
char *name; /* full path name */
FILEPTR *open; /* fileptrs for this file; OR
* count of number of open directories
*/
LOCK *locks; /* locks on this file */
/* file status */
long size;
int time;
int date;
int attr;
int valid; /* 1 if the above status is still valid */
#ifdef NEWWAY
int links; /* how many times index is in use */
#else
int stamp; /* age of this index, for garbage collection */
#endif
}gl_ti[NUM_INDICES];
/* temporary index for files found by readdir */
static struct tindex tmpindex;
static char tmpiname[PATH_MAX];
static struct tindex *tstrindex (char *s);
static int tfullpath (char *result, struct tindex *base, const char *name);
static struct tindex *garbage_collect(void);
static para * getmc_cookie(void);
#ifndef NEWWAY
static int tclock; /* #calls to tfullpath since last garbage
collection */
#endif
/* some extra flags for the attr field */
/*
* is a string the name of a file with executable extension?
*/
#define FA_EXEC 0x4000
/*
* should the file be deleted when it is closed?
*/
#define FA_DELETE 0x2000
/*
* NOTE: call executable_extension only on a DTA name returned from
* Fsfirst(), not on an arbitrary path, for two reasons: (1) it
* expects only upper case, and (2) it looks only for the 1st extension,
* so a folder with a '.' in its name would confuse it.
*/
static int executable_extension(char *s)
{
while (*s && *s != '.') s++;
if (!*s) return 0;
s++;
if (s[0] == 'T') {
return ((s[1] == 'T' && s[2] == 'P') ||
(s[1] == 'O' && s[2] == 'S'));
}
if (s[0] == 'P')
return (s[1] == 'R' && s[2] == 'G');
if (s[0] == 'A')
return (s[1] == 'P' && s[2] == 'P');
if (s[0] == 'G')
return (s[1] == 'T' && s[2] == 'P');
return 0;
}
/*
* Look in the table of tos indices to see if an index corresponding
* to this file name already exists. If so, mark it as being used
* and return it. If not, find an empty slot and make an index for
* this string. If no empty slots exist, garbage collect and
* try again.
*
* This routine is pretty dumb; we really should use a hash table
* of some sort
*/
static struct tindex *tstrindex(char *s)
{
int i;
char *r;
struct tindex *t, *free = NULL;
t = gl_ti;
for (i = 0; i < NUM_INDICES; i++, t++) {
if (t->name && !stricmp(t->name, s)) {
#ifndef NEWWAY
t->stamp = tclock; /* update use time */
#endif
return t;
}
else if (!t->name && !free)
free = t;
}
if (!free) {
free = garbage_collect();
}
#ifdef NEWWAY
if (!free) {
t = gl_ti;
FATAL("tosfs: unable to get a file name index");
}
#else
if (!free) {
FATAL("tosfs: unable to get a file name index");
}
#endif
r = Kmalloc((long)strlen(s)+1);
if (!r) {
FATAL("MCfs: unable to allocate space for a file name");
}
strcpy(r, s);
free->name = r;
#ifdef NEWWAY
free->links = 0;
#else
free->stamp = tclock;
#endif
free->open = 0;
free->locks = 0;
/* check to see if this file was recently returned by opendir() */
#ifndef NEWWAY
if (tmpindex.valid && tclock - tmpindex.stamp < MIN_AGE &&
!stricmp(free->name, tmpindex.name)) {
free->size = tmpindex.size;
free->time = tmpindex.time;
free->date = tmpindex.date;
free->attr = tmpindex.attr;
free->valid = 1;
tmpindex.valid = 0;
} else
#endif
free->valid = 0;
return free;
}
/*
* garbage collection routine: for any TOS index older than MIN_AGE,
* check through all current processes to see if it's in use. If
* not, free the corresponding string.
* Returns: a pointer to a newly freed index, or NULL.
*/
/* it's unlikely that the kernel would need to hold onto a file cookie
for longer than this many calls to tstrindex() without first
saving the cookie in a directory or file pointer
*/
static struct tindex * garbage_collect()
{
struct tindex *free, *t;
int i;
#ifndef NEWWAY
fcookie *fc, *gc;
PROC *p;
int j;
int age;
#endif
free = 0;
t = gl_ti;
for (i = 0; i < NUM_INDICES; i++,t++) {
if (!t->name) continue;
#ifdef NEWWAY
if (t->links == 0) {
Kfree(t->name);
t->name = 0;
if (!free) free = t;
}
#else
age = tclock - t->stamp;
t->stamp = 0;
if (age > MIN_AGE) {
/* see if any process is using this index */
if (t->open)
goto found_index;
for (p = proclist; p; p = p->gl_next) {
fc = p->curdir;
gc = p->root;
for (j = 0; j < NUM_DRIVES; j++,fc++,gc++) {
if (( fc->fs == &mc_filesys &&
fc->index == (long)t ) ||
( gc->fs == &mc_filesys &&
gc->index == (long)t ) )
goto found_index;
}
}
/* here, we couldn't find the index in use by any proc. */
Kfree(t->name);
t->name = 0;
if (!free)
free = t;
found_index:
;
} else {
/* make sure that future garbage collections might look at this file */
t->stamp = -age;
}
#endif
}
#ifndef NEWWAY
tclock = 0; /* reset the clock */
tmpindex.valid = 0; /* expire the temporary Fsfirst buffer */
#endif
return free;
}
#define DIRSEP(c) ((c) == '\\')
static int tfullpath(char *result,struct tindex *basei, const char *path)
{
#define TNMTEMP 32
static char name[TNMTEMP+1];
char *n;
int namelen, pathlen;
char *base = basei->name;
int r;
#ifndef NEWWAY
basei->stamp = ++tclock;
if (tclock > 10000) {
/* garbage collect every so often whether we need it or not */
(void)garbage_collect();
}
#endif
r=0;
if (!*path) {
strncpy(result, base, PATH_MAX-1);
return r;
}
strncpy(result, base, PATH_MAX-1);
pathlen = (int) strlen(result);
/* now path is relative to what's currently in "result" */
while(*path) {
/* get next name in path */
n = name; namelen = 0;
while (*path && !DIRSEP(*path)) {
/* BUG: we really should to the translation to DOS 8.3
* format *here*, so that really long names are truncated
* correctly.
*/
if (namelen < TNMTEMP) {
*n++ = toupper(*path); path++; namelen++;
}
else
path++;
}
*n = 0;
while (DIRSEP(*path)) path++;
/* check for "." and ".." */
if (!strcmp(name, ".")) continue;
if (!strcmp(name, "..")) {
n = strrchr(result, '\\');
if (n) {
*n = 0;
pathlen = (int)(n - result);
}
else r = EMOUNT;
continue;
}
if (pathlen + namelen < PATH_MAX - 1) {
strcat(result, "\\");
pathlen++;
/* make sure the name is restricted to DOS 8.3 format */
for (base = result; *base; base++)
;
n = name;
namelen = 0;
while (*n && *n != '.' && namelen++ < 8) {
*base++ = *n++;
pathlen++;
}
while (*n && *n != '.') n++;
if (*n == '.' && *(n+1) != 0) {
*base++ = *n++;
pathlen++;
namelen = 0;
while (*n && namelen++ < 3) {
*base++ = *n++;
pathlen++;
}
}
*base = 0;
}
}
return r;
}
static long cdecl mc_root(int drv,fcookie *fc)
{
struct tindex *ti;
DEBUG(" mc_root");
if (drv==MCDRIVE)
{
Sprintf(tmpbuf, "%c:", drv+'A');
fc->fs = &mc_filesys;
fc->dev = drv;
ti = tstrindex(tmpbuf);
ti->size = ti->date = ti->time = 0;
ti->attr = FA_DIR;
ti->valid = 1;
fc->index = (long)ti;
#ifdef NEWWAY
ti->links++;
#endif
return (0);
}
return(EDRIVE);
}
long MC_Fsfirst(char *filename, int attr,DTABUF *dta );
long MC_Fsnext(DTABUF *dta);
long MC_Fopen(char *name,int tosmode );
long MC_Fread( int handle, long count, void *buf );
long MC_Fcreate(char *name,int tosmode );
long MC_Fclose(int handle);
long MC_Dcreate(char *path );
long MC_Ddelete(char *path );
long MC_Dfree(long *buf, int driveno);
long MC_Fseek( long offset, int handle, int seekmode );
long MC_Fattrib(char *filename, int wflag, int attrib );
long MC_Fdelete(char *filename );
long MC_Frename( int zero,char *oldname,char *newname );
long MC_Fwrite( int handle, long count, void *buf );
long MC_Fdatime( int *timeptr, int handle, int wflag );
static long cdecl mc_lookup(fcookie *dir,const char *name,fcookie *fc)
{
long r;
struct tindex *ti = (struct tindex *)dir->index;
DEBUG(" mc_lookup(dir=%s name=%s",ti->name,name);
r = tfullpath(tmpbuf, ti, name);
/* if the name is empty or otherwise trivial, just return the directory */
if (!strcmp(ti->name, tmpbuf)) {
*fc = *dir;
#ifdef NEWWAY
ti->links++;
#endif
return r;
}
/* is there already an index for this file?? If so, is it up to date?? */
ti = tstrindex(tmpbuf);
if (!ti->valid) {
if (tmpbuf[1] == ':' && tmpbuf[2] == 0) {
/* a root directory -- lookup always succeeds */
foo.d_length = 0;
foo.d_date = foo.d_time = 0;
foo.d_attrib = FA_DIR;
foo.d_fname[0] = 0;
} else {
do_setdta(&foo);
r = MC_Fsfirst(tmpbuf, FILEORDIR,&foo);
if (r) {
return (r);
}
}
ti->size = foo.d_length;
ti->date = foo.d_date;
ti->time = foo.d_time;
ti->attr = foo.d_attrib;
if (executable_extension(foo.d_fname))
ti->attr |= FA_EXEC;
ti->valid = 1;
}
fc->fs = &mc_filesys;
fc->index = (long)ti;
fc->dev = dir->dev;
#ifdef NEWWAY
ti->links++;
DEBUG(" mc_lookup neu: %s links=%d",ti->name,ti->links);
#endif
return r;
}
static long cdecl mc_getxattr(fcookie *fc,XATTR *xattr)
{
struct tindex *ti = (struct tindex *)fc->index;
long r;
static long junkindex = 0;
DEBUG(" mc_getxattr %s links=%d",ti->name,ti->links);
xattr->index = junkindex++;
xattr->dev = fc->dev;
xattr->nlink = 1;
xattr->uid = xattr->gid = 0;
#ifndef NEWWAY
ti->stamp = ++tclock;
#endif
if (!ti->valid) {
do_setdta(&foo);
if (ti->name[2] == 0) { /* a root directory */
/* actually, this can also happen if a program tries to open a file
* with an empty name... so we should fail gracefully
*/
ti->attr = FA_DIR;
ti->size = 0;
ti->date = ti->time = 0;
goto around;
}
r = MC_Fsfirst(ti->name, FILEORDIR,&foo);
if (r) {
return r;
}
ti->size = foo.d_length;
ti->date = foo.d_date;
ti->time = foo.d_time;
ti->attr = foo.d_attrib;
if (executable_extension(foo.d_fname))
ti->attr |= FA_EXEC;
around:
ti->valid = 1;
}
xattr->size = ti->size;
/* BUG: blksize isn't accurate if the sector size is not 512 */
xattr->blksize = 1024;
xattr->nblocks = (xattr->size + 1023) / 1024;
xattr->mdate = xattr->cdate = xattr->adate = ti->date;
xattr->mtime = xattr->ctime = xattr->atime = ti->time;
xattr->mode = (ti->attr & FA_DIR) ? (S_IFDIR | DEFAULT_DIRMODE) :
(S_IFREG | DEFAULT_MODE);
if (ti->attr & FA_RDONLY) {
xattr->mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
}
if (ti->attr & FA_EXEC) {
xattr->mode |= (S_IXUSR|S_IXGRP|S_IXOTH);
}
xattr->attr = ti->attr & 0xff;
return 0;
}
static long cdecl mc_chattr(fcookie *fc,int attrib)
{
struct tindex *ti = (struct tindex *)fc->index;
DEBUG(" mc_chattr");
if (ti->attr & FA_DIR) {
DEBUG("error: attempt to change attributes of a directory");
return EACCDN;
}
ti->valid = 0;
(void)tfullpath(tmpbuf, ti, "");
return MC_Fattrib(tmpbuf, 1, attrib);
}
static long cdecl
mc_chown(dir, uid, gid)
fcookie *dir;
int uid, gid;
{
UNUSED(dir); UNUSED(uid); UNUSED(gid);
DEBUG(" mc_chown returns %ld",EINVFN);
return EINVFN;
}
static long cdecl mc_chmode(fcookie *fc,unsigned mode)
{
int oldattr, newattr;
long r;
struct tindex *ti = (struct tindex *)fc->index;
DEBUG(" mc_chmode");
oldattr =(int) MC_Fattrib(ti->name, 0, 0);
if (oldattr < 0)
return oldattr;
ti->valid = 0;
if (!(mode & S_IWUSR))
newattr = oldattr | FA_RDONLY;
else
newattr = oldattr & ~FA_RDONLY;
if (newattr != oldattr)
r = MC_Fattrib(ti->name, 1, newattr);
else
r = 0;
return (r < 0) ? r : 0;
}
static long cdecl mc_mkdir(fcookie *dir,const char *name,unsigned mode)
/* ignored under TOS */
{
UNUSED(mode);
DEBUG(" mc_mkdir");
(void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
tmpindex.valid = 0;
return MC_Dcreate(tmpbuf);
}
static long cdecl mc_rmdir(fcookie *dir,const char *name)
{
struct tindex *ti;
DEBUG(" mc_rmdir");
(void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
ti = tstrindex(tmpbuf);
ti->valid = 0;
return MC_Ddelete(tmpbuf);
}
static long cdecl mc_remove(fcookie *dir,const char *name)
{
struct tindex *ti;
DEBUG(" mc_remove");
(void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
ti = tstrindex(tmpbuf);
if (ti->open) {
DEBUG("mc_remove: file is open, will be deleted later");
if (ti->attr & FA_RDONLY)
return EACCDN;
ti->attr |= FA_DELETE;
return 0;
}
ti->valid = 0;
return MC_Fdelete(tmpbuf);
}
static long cdecl
mc_getname(fcookie *root,fcookie *dir,char *pathname,int size)
{
char *rootnam = ((struct tindex *)root->index)->name;
char *dirnam = ((struct tindex *)dir->index)->name;
int i;
DEBUG(" mc_getname");
i = (int) strlen(rootnam);
if (strlen(dirnam) < i) {
return (EINTRN);
}
if (strlen(dirnam+i) < size) {
strcpy(pathname, dirnam + i);
return(0);
}
return(ERANGE);
}
static long cdecl mc_rename(fcookie *olddir,char *oldname,fcookie *newdir,const char *newname)
{
static char newbuf[128];
struct tindex *ti;
long r;
DEBUG(" mc_rename");
(void)tfullpath(tmpbuf, (struct tindex *)olddir->index, oldname);
(void)tfullpath(newbuf, (struct tindex *)newdir->index, newname);
r = MC_Frename(0, tmpbuf, newbuf);
if (r == 0) {
ti = tstrindex(tmpbuf);
Kfree(ti->name);
ti->name = Kmalloc((long)strlen(newbuf)+1);
if (!ti->name) {
FATAL("tosfs: unable to allocate space for a name");
}
strcpy(ti->name, newbuf);
ti->valid = 0;
}
return r;
}
#define DIR_FLAG(x) (x->fsstuff[0])
#define STARTSEARCH 0 /* opendir() was just called */
#define INSEARCH 1 /* readdir() has been called at least once */
#define NMFILE 2 /* no more files to read */
#define DIR_DTA(x) ((DTABUF *)(x->fsstuff + 2))
#define DIR_NAME(x) (x->fsstuff + 32)
/*
* The directory functions are a bit tricky. What we do is have
* opendir() do Fsfirst; the first readdir() picks up this name,
* subsequent readdir()'s have to do Fsnext
*/
static long cdecl
mc_opendir(DIR *dirh,int flags)
{
long r;
struct tindex *t = (struct tindex *)dirh->fc.index;
UNUSED(flags);
DEBUG(" mc_opendir");
(void)tfullpath(tmpbuf, t, "*.*");
do_setdta(DIR_DTA(dirh));
r = MC_Fsfirst(tmpbuf, FILEORDIR,DIR_DTA(dirh));
if (r == 0) {
t->open++;
DIR_FLAG(dirh) = STARTSEARCH;
return 0;
} else if (r == EFILNF) {
t->open++;
DIR_FLAG(dirh) = NMFILE;
return 0;
}
return (r);
}
static long cdecl
mc_readdir(dirh, name, namelen, fc)
DIR *dirh;
char *name;
int namelen;
fcookie *fc;
{
static long index = 0;
long ret;
int giveindex = dirh->flags == 0;
struct tindex *ti;
DTABUF *dta = DIR_DTA(dirh);
DEBUG(" mc_readdir");
again:
if (DIR_FLAG(dirh) == NMFILE)
return ENMFIL;
if (DIR_FLAG(dirh) == STARTSEARCH) {
DIR_FLAG(dirh) = INSEARCH;
} else {
do_setdta(dta);
ret = MC_Fsnext(dta);
if (ret) {
DIR_FLAG(dirh) = NMFILE;
return ret;
}
}
/* don't return volume labels from readdir */
if (dta->d_attrib == FA_LABEL) goto again;
fc->fs = &mc_filesys;
fc->dev = dirh->fc.dev;
(void)tfullpath(tmpiname, (struct tindex *)dirh->fc.index, DIR_NAME(dirh));
ti = &tmpindex;
ti->name = tmpiname;
ti->valid = 1;
ti->size = dta->d_length;
ti->date = dta->d_date;
ti->time = dta->d_time;
ti->attr = dta->d_attrib;
#ifdef NEWWAY
ti->links++;
#else
ti->stamp = tclock;
#endif
if (executable_extension(dta->d_fname))
ti->attr |= FA_EXEC;
fc->index = (long)ti;
if (giveindex) {
namelen -= (int) sizeof(long);
if (namelen <= 0) return ERANGE;
*((long *)name) = index++;
name += sizeof(long);
}
strncpy(name, DIR_NAME(dirh), namelen-1);
name[namelen-1] = 0;
/* BUG: we really should do the "strlwr" operation only
* for Dreaddir (i.e. if giveindex == 0) but
* unfortunately some old programs rely on the behaviour
* below
*/
if (strlen(DIR_NAME(dirh)) >= namelen)
return ENAMETOOLONG;
else
return 0;
}
static long cdecl
mc_rewinddir(dirh)
DIR *dirh;
{
struct tindex *ti = (struct tindex *)dirh->fc.index;
long r;
DEBUG(" mc_rewinddir");
(void)tfullpath(tmpbuf, ti, "*.*");
do_setdta(DIR_DTA(dirh));
r = MC_Fsfirst(tmpbuf, FILEORDIR,DIR_DTA(dirh));
if (r == 0) {
DIR_FLAG(dirh) = STARTSEARCH;
} else {
DIR_FLAG(dirh) = NMFILE;
}
return r;
}
static long cdecl
mc_closedir(dirh)
DIR *dirh;
{
struct tindex *t = (struct tindex *)dirh->fc.index;
DEBUG(" mc_closedir");
if (t->open == 0) {
FATAL("t->open == 0: directory == %s", t->name);
}
--t->open;
DIR_FLAG(dirh) = NMFILE;
return 0;
}
static long cdecl
mc_pathconf(dir, which)
fcookie *dir;
int which;
{
UNUSED(dir);
DEBUG(" mc_pathconf");
switch(which) {
case -1:
return DP_MAXREQ;
case DP_IOPEN:
return 60; /* we can only keep about this many open */
case DP_MAXLINKS:
return 1; /* no hard links */
case DP_PATHMAX:
return PATH_MAX;
case DP_NAMEMAX:
return 8+3+1;
case DP_ATOMIC:
return 512; /* we can write at least a sector atomically */
case DP_TRUNC:
return DP_DOSTRUNC; /* DOS style file names */
/* case DP_CASE:
return DP_CASECONV; /* names converted to upper case */
*/
default:
return EINVFN;
}
}
long cdecl
mc_dfree(dir, buf)
fcookie *dir;
long *buf;
{
DEBUG(" mc_dfree");
return MC_Dfree(buf, (dir->dev)+1);
}
/*
* writelabel: creates a volume label
* readlabel: reads a volume label
* both of these are only guaranteed to work in the root directory
*/
/*
* BUG: this should first delete any old labels, so that it will
* work with TOS <1.4
*/
long cdecl
mc_writelabel(dir, name)
fcookie *dir;
const char *name;
{
long r;
struct tindex *ti;
DEBUG(" mc_writelabel");
(void)tfullpath(tmpbuf, (struct tindex *)dir->index, name);
r = MC_Fcreate(tmpbuf, FA_LABEL);
if (r < 0) return r;
(void)MC_Fclose((int)r);
ti = tstrindex(tmpbuf);
ti->valid = 0;
return 0;
}
long cdecl
mc_readlabel(dir, name, namelen)
fcookie *dir;
char *name;
int namelen;
{
long r;
struct tindex *ti = (struct tindex *)dir->index;
DEBUG(" mc_readlabel");
if (ti->name[2] != 0) /* not a root directory? */
return EFILNF;
(void)tfullpath(tmpbuf, ti, "*.*");
do_setdta(&foo);
r = MC_Fsfirst(tmpbuf, FA_LABEL,&foo);
if (r)
return r;
strncpy(name, foo.d_fname, namelen-1);
return (strlen(foo.d_fname) < namelen) ? 0 : ENAMETOOLONG;
}
/*
* TOS creat: this doesn't actually create the file, rather it
* sets up a (fake) index for the file that will be used by
* the later mc_open call.
*/
static long cdecl
mc_creat(dir, name, mode, attrib, fc)
fcookie *dir;
const char *name;
unsigned mode;
int attrib;
fcookie *fc;
{
struct tindex *ti=(struct tindex *)dir->index;
UNUSED(mode);
DEBUG(" mc_create dir=%ld name=%ld",dir->index,(long)name);
(void)tfullpath(tmpbuf,ti, name);
ti = tstrindex(tmpbuf);
ti->size = 0;
ti->date = (int) Datestamp();
ti->time = (int) Timestamp();
ti->attr = attrib;
ti->valid = 1;
fc->fs = &mc_filesys;
fc->index = (long)ti;
fc->dev = dir->dev;
#ifdef NEWWAY
ti->links++;
#endif
return 0;
}
/*
* TOS device driver
*/
static DEVDRV * cdecl
mc_getdev(fc, devsp)
fcookie *fc;
long *devsp;
{
UNUSED(fc); UNUSED(devsp);
DEBUG(" mc_getdevice");
return &mc_device;
}
static long cdecl mc_open(FILEPTR *f)
{
struct tindex *ti;
int mode = f->flags;
int tosmode;
long r;
extern int flk; /* in main.c, set if _FLK cookie already present */
ti = (struct tindex *)(f->fc.index);
DEBUG(" mc_open");
#ifndef NEWWAY
ti->stamp = ++tclock;
#endif
ti->valid = 0;
#ifndef RO_FASCISM
/* TEMPORARY HACK: change all modes to O_RDWR for files opened in
* compatibility sharing mode. This is silly, but
* allows broken TOS programs that write to read-only handles to continue
* to work (it also helps file sharing, by making the realistic assumption
* that any open TOS file can be written to). Eventually,
* this should be tuneable by the user somehow.
* ALSO: change O_COMPAT opens into O_DENYNONE; again, this may be temporary.
*/
if ( (mode & O_SHMODE) == O_COMPAT ) {
f->flags = (mode & ~(O_RWMODE|O_SHMODE)) | O_RDWR | O_DENYNONE;
}
#endif
/* check to see that nobody has opened this file already in an
* incompatible mode
*/
if (Denyshare(ti->open, f)) {
return EACCDN;
}
/*
* now open the file; if O_TRUNC was specified, actually
* create the file anew.
* BUG: O_TRUNC without O_CREAT doesn't work right. The kernel doesn't
* use this mode, anyways
*/
if (mode & O_TRUNC) {
if (ti->open) {
return EACCDN;
}
r = MC_Fcreate(ti->name, ti->attr);
} else {
if (flk)
tosmode = mode & (O_RWMODE|O_SHMODE);
else
tosmode = (mode & O_RWMODE);
if (tosmode == O_EXEC) tosmode = O_RDONLY;
r = MC_Fopen(ti->name, tosmode );
if (r == EFILNF && (mode & O_CREAT))
{
r = MC_Fcreate(ti->name, ti->attr);
}
}
if (r < 0) {
/* get rid of the index for the file, since it doesn't exist */
Kfree(ti->name);
ti->name = 0;
ti->valid = 0;
return r;
}
f->devinfo = r;
f->next = ti->open;
ti->open = f;
return 0;
}
static long cdecl
mc_write(f, buf, bytes)
FILEPTR *f; const char *buf; long bytes;
{
struct tindex *ti = (struct tindex *)f->fc.index;
ti->valid = 0;
DEBUG(" mc_write");
return MC_Fwrite((int)f->devinfo, bytes, buf);
}
static long cdecl
mc_read(f, buf, bytes)
FILEPTR *f; char *buf; long bytes;
{
DEBUG(" mc_read");
return MC_Fread((int)f->devinfo, bytes, buf);
}
static long cdecl
mc_lseek(f, where, whence)
FILEPTR *f; long where; int whence;
{
long r;
DEBUG(" mc_lseek");
r = MC_Fseek(where, (int)f->devinfo, whence);
return r;
}
static long cdecl
mc_ioctl(f, mode, buf)
FILEPTR *f; int mode; void *buf;
{
LOCK t, *lck, **old;
struct flock *fl;
long r;
struct tindex *ti;
extern int flk; /* set in main.c if _FLK already installed */
DEBUG(" mc_ioctl");
if (mode == FIONREAD || mode == FIONWRITE) {
*((long *)buf) = 1;
return 0;
}
else if (mode == F_SETLK || mode == F_SETLKW || mode == F_GETLK) {
fl = ((struct flock *)buf);
t.l = *fl;
switch(t.l.l_whence) {
case 0:
break;
case 1: /* SEEK_CUR */
r = MC_Fseek(0L, (int)f->devinfo, 1);
t.l.l_start += r;
break;
case 2:
r = MC_Fseek(0L, (int)f->devinfo, 1);
t.l.l_start = MC_Fseek(t.l.l_start, (int)f->devinfo, 2);
(void)MC_Fseek(r, (int)f->devinfo, 0);
break;
default:
return EINVFN;
}
/* BUG: can't lock a file starting at >2gigabytes from the beginning */
if (t.l.l_start < 0) t.l.l_start = 0;
t.l.l_whence = 0;
ti = (struct tindex *)f->fc.index;
if (mode == F_GETLK) {
lck = Denylock(ti->locks, &t);
if (lck)
*fl = lck->l;
else
fl->l_type = F_UNLCK;
return 0;
}
if (t.l.l_type == F_UNLCK) {
/* try to find the lock */
old = &ti->locks;
lck = *old;
while (lck) { /*???*/
if (lck->l.l_start == t.l.l_start &&
lck->l.l_len == t.l.l_len) {
/* found it -- remove the lock */
*old = lck->next;
if (flk)
(void)Flock((int)f->devinfo, 1,
t.l.l_start, t.l.l_len);
/* wake up anyone waiting on the lock */
Wake(IO_Q, (long)lck);
Kfree(lck);
break;
}
old = &lck->next;
lck = lck->next;
}
return lck ? 0 : ENSLOCK;
}
do {
/* see if there's a conflicting lock */
while ((lck = Denylock(ti->locks, &t)) != 0) {
if (mode == F_SETLKW) {
Sleep(IO_Q, (long)lck);
}
else
return ELOCKED;
}
/* if not, add this lock to the list */
lck = Kmalloc(sizeof(LOCK));
if (!lck) return ENSMEM;
/* see if other _FLK code might object */
if (flk) {
r = Flock((int)f->devinfo, 0, t.l.l_start, t.l.l_len);
if (r) {
Kfree(lck);
if (mode == F_SETLKW && r == ELOCKED) {
Yield();
lck = NULL;
}
else
return r;
}
}
} while (!lck);
lck->l = t.l;
lck->l.l_pid = 0;/* ??? */
lck->next = ti->locks;
ti->locks = lck;
/* mark the file as being locked */
f->flags |= O_LOCK;
return 0;
}
return EINVFN;
}
static long cdecl
mc_datime(FILEPTR *f,int *timeptr,int rwflag)
{
DEBUG(" mc_datime");
if (rwflag) {
struct tindex *ti = (struct tindex *)f->fc.index;
ti->valid = 0;
}
return MC_Fdatime(timeptr, (int)f->devinfo, rwflag);
}
static long cdecl
mc_close(f, pid)
FILEPTR *f;
int pid;
{
LOCK *lck, **oldl;
struct tindex *t;
FILEPTR **old, *p;
long r = 0;
extern int flk; /* set in main.c */
t = (struct tindex *)(f->fc.index);
DEBUG(" mc_close");
/* if this handle was locked, remove any locks held by the process
*/
if (f->flags & O_LOCK) {
oldl = &t->locks;
lck = *oldl;
while (lck) {
if (lck->l.l_pid == pid) {
*oldl = lck->next;
if (flk)
(void)Flock((int)f->devinfo, 1,
lck->l.l_start, lck->l.l_len);
Wake(IO_Q, (long)lck);
Kfree(lck);
} else {
oldl = &lck->next;
}
lck = *oldl;
}
}
if (f->links <= 0) {
/* remove f from the list of open file pointers on this index */
t->valid = 0;
old = &t->open;
p = t->open;
while (p && p != f) {
old = &p->next;
p = p->next;
}
*old = f->next;
f->next = 0;
r = MC_Fclose((int)f->devinfo);
/* if the file was marked for deletion, delete it */
if (!t->open) {
if (t->attr & FA_DELETE) {
(void)MC_Fdelete(t->name);
t->name = 0;
}
}
}
return r;
}
/*
* check for disk change: called by the kernel if Mediach returns a
* non-zero value
*/
/*
long cdecl
mc_dskchng(drv)
int drv;
{
char dlet;
int i;
struct tindex *ti;
dlet = 'A' + drv;
DEBUG(" mc_dskchng");
ti = gl_ti;
for (i = 0; i < NUM_INDICES; i++, ti++) {
if (ti->name && ti->name[0] == dlet) {
Kfree(ti->name);
ti->name = 0;
}
}
tmpindex.valid = 0;
/*
* OK, make sure that GEMDOS knows to look for a change if we
* ever use this drive again.
*/
return 1;
}
*/
#ifdef NEWWAY
/* release/copy file cookies; these functions exist to keep
* track of whether or not the kernel is still using a file
*/
long cdecl mc_release(fcookie *fc)
{
struct tindex *ti = (struct tindex *)fc->index;
if (ti->links <= 0) {
FATAL("mc_release: link count of `%s' is %d", ti->name, ti->links);
}
ti->links--;
DEBUG("mc_release: %s now has %d links", ti->name, ti->links);
return 0;
}
long cdecl mc_dupcookie(fcookie *dest,fcookie *src)
{
struct tindex *ti = (struct tindex *)src->index;
if (ti->links <= 0) {
FATAL("mc_dupcookie: link count of %s is %d", ti->name, ti->links);
}
ti->links++;
DEBUG("mc_dupcookie: %s now has %d links", ti->name, ti->links);
*dest=*src;
return 0;
}
#endif
/*
* utility function: sets the TOS DTA, and also records what directory
* this was in. This is just to save us a call into the kernel if the
* correct DTA has already been set.
*/
static void
do_setdta(dta)
DTABUF *dta;
{
if (dta != lastdta) {
/* Fsetdta(dta);*/
lastdta = dta;
}
}
static CINFO infos;
static long install_cookies(void)
{
COOKIE *cokie;
int found=0;
long laenge;
cokie = *CJAR;
if (cokie)
{
while (cokie->tag.aslong != 0)
{
if (!strncmp(cokie->tag.aschar, "MICO",4))
{
cokie->value=(long)&infos;
found=1;
}
cokie++;
}
if (!found)
{
laenge=cokie->value;
strncpy(cokie->tag.aschar,"MICO",4);
cokie->value=(long) &infos;
cokie++;
cokie->tag.aslong = 0;
cokie->value=laenge;
}
infos.LW=MCDRIVE+'A';
infos.params=NULL;
infos.kernel=kernel;
}
return(0);
}
static para * getmc_cookie(void)
{
COOKIE *jar;
if (infos.params) return((para*) infos.params);
jar = *CJAR; /* CJAR defined in cookie.h */
if (jar)
{
while (jar->tag.aslong != 0)
{
if (!strncmp(jar->tag.aschar, "MICO",4))
{
return((para*) infos.params);
}
jar++;
}
} else return(NULL);
return(NULL);
}
long cdecl nosymlink(fcookie *dir,const char *name,const char *to)
{
DEBUG("nosymlink");
UNUSED(dir); UNUSED(name);
UNUSED(to);
return EINVFN;
}
long cdecl noreadlink(fcookie *dir,char *buf,int buflen)
{
DEBUG("noreadlink");
UNUSED(dir); UNUSED(buf);
UNUSED(buflen);
return EINVFN;
}
long cdecl nohardlink(fcookie *fromdir,fcookie *todir,const char *fromname, const char *toname)
{
DEBUG("nohardlink");
UNUSED(fromdir); UNUSED(todir);
UNUSED(fromname); UNUSED(toname);
return EINVFN;
}
/* dummy routine for file systems with no Fscntl commands */
long cdecl nofscntl(fcookie *dir,const char *name,int cmd,long arg)
{
DEBUG("nofscntl");
UNUSED(dir); UNUSED(name);
UNUSED(cmd); UNUSED(arg);
return EINVFN;
}
/*
* Did the disk change? Not on this drive!
* However, we have to do Getbpb anyways, because someone has decided
* to force a media change on our (non-existent) drive.
*/
long cdecl nodskchng(int drv)
{
DEBUG("nodskchng");
UNUSED(drv);
return 0;
}
long cdecl null_select(FILEPTR *f, long p,int mode)
{
FATAL("null_select");
UNUSED(f); UNUSED(p);
UNUSED(mode);
return 1; /* we're always ready to read/write */
}
void cdecl null_unselect(FILEPTR *f,long p,int mode)
{
DEBUG("null_unselect");
UNUSED(f); UNUSED(p);
UNUSED(mode);
/* nothing to do */
}
static int semaphore=0;
void cdecl pausen(int *i)
{
/* while (*i>0) { Sleep(READY_Q,0L);};*/
while (*i>0) { Sleep(IO_Q,1234L);};
}
void set_semaphore(void)
{
while (semaphore>0) {pausen(&semaphore);};
semaphore=1;
};
void free_semaphore(void)
{
semaphore=0;
Wake(IO_Q,1234L);
};
static char h_path[PATH_MAX+1];
long MC_Fsfirst(char *filename, int attr,DTABUF *dta )
{
para *parm=getmc_cookie();
DEBUG("MC_FSFIRST");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=78;
strcpy(h_path,filename);
parm->mix.fu78.PFAD=h_path;
parm->mix.fu78.ATTR=attr;
parm->mix.fu78.dta=dta;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fsnext(DTABUF *dta)
{
para *parm=getmc_cookie();
DEBUG("MC_FSNEXT");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=79;
parm->mix.dta=dta;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fopen(char *name,int tosmode )
{
para *parm=getmc_cookie();
DEBUG("MC_FOPEN");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=61;
strcpy(h_path,name);
parm->mix.fu78.PFAD=h_path;
parm->mix.fu78.ATTR=tosmode;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fread( int handle, long count, void *buf )
{
para *parm=getmc_cookie();
DEBUG("MC_FREAD");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=63;
parm->mix.fu63.handle=handle;
parm->mix.fu63.count=count;
parm->mix.fu63.buffer=buf;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fcreate(char *name,int tosmode )
{
para *parm=getmc_cookie();
DEBUG("MC_FCREATE");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=60;
strcpy(h_path,name);
parm->mix.fu78.PFAD=h_path;
parm->mix.fu78.ATTR=tosmode;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fclose(int handle)
{
para *parm=getmc_cookie();
DEBUG("MC_FCLOSE");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=62;
parm->mix.LEER=handle;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Dcreate(char *path )
{
para *parm=getmc_cookie();
DEBUG("MC_DCREATE");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=57;
strcpy(h_path,path);
parm->mix.fu78.PFAD=h_path;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Dfree(long *buf, int driveno)
{
para *parm=getmc_cookie();
UNUSED(driveno);
DEBUG("MC_FFREE");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=54;
parm->mix.fu54.info=(diskinfo *)buf;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Ddelete(char *path )
{
para *parm=getmc_cookie();
DEBUG("MC_DDELETE");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=58;
strcpy(h_path,path);
parm->mix.fu78.PFAD=h_path;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fseek( long offset, int handle, int seekmode )
{
para *parm=getmc_cookie();
DEBUG("MC_FSEEK");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=66;
parm->mix.fu66.hndl=handle;
parm->mix.fu66.skmod=seekmode;
parm->mix.fu66.offs=offset;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fattrib(char *filename, int wflag, int attrib )
{
para *parm=getmc_cookie();
DEBUG("MC_FATTRIB");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=67;
strcpy(h_path,filename);
parm->mix.fu67.fnm=h_path;
parm->mix.fu67.fattr=attrib;
parm->mix.fu67.wflag=wflag;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fdelete(char *filename )
{
para *parm=getmc_cookie();
DEBUG("MC_FDELETE");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=65;
strcpy(h_path,filename);
parm->mix.fu78.PFAD=h_path;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Frename( int zero,char *oldname,char *newname )
{
para *parm=getmc_cookie();
DEBUG("MC_FRENAME");
UNUSED(zero);
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=86;
strcpy(h_path,oldname);
parm->mix.fu86.pf1=h_path;
parm->mix.fu86.pf2=newname;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fwrite( int handle, long count, void *buf )
{
para *parm=getmc_cookie();
DEBUG("MC_FWRITE");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=64;
parm->mix.fu63.handle=handle;
parm->mix.fu63.count=count;
parm->mix.fu63.buffer=buf;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}
long MC_Fdatime( int *timeptr, int handle, int wflag )
{
para *parm=getmc_cookie();
DEBUG("MC_FDATIME");
if (parm)
{
set_semaphore();
parm->retcode=-4;
parm->fktn=87;
parm->mix.fu87.handl=handle;
parm->mix.fu87.wf=wflag;
parm->mix.fu87.dostme=(long *)timeptr;
while (parm->fktn>=0) { Sleep(IO_Q,1234L);};
free_semaphore();
return(parm->retcode);
}
return(EFILNF); /* file not found */
}