home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright 1990,1991,1992 Eric R. Smith.
- Copyright 1992,1993,1994 Atari Corp.
- All rights reserved.
- */
-
- /*
- * various file system interface things
- */
-
- #include "mint.h"
-
- #define PATH2COOKIE_DB(x) TRACE(x)
-
- FILESYS *active_fs;
- FILESYS *drives[NUM_DRIVES];
- extern FILESYS tos_filesys; /* declaration needed for debugging only */
-
- /* "aliased" drives are different names
- * for real drives/directories
- * if drive d is an alias for c:\usr,
- * then alias_drv[3] == 2 (the real
- * drive) and aliases has bit (1L << 3)
- * set.
- * NOTE: if aliasdrv[d] is 0, then d is not an aliased drive,
- * otherwise d is aliased to drive aliasdrv[d]-1
- * (e.g. if drive A: is aliased to B:\FOO, then
- * aliasdrv[0] == 'B'-'A'+1 == 2). Always remember to
- * compensate for the extra 1 when dereferencing aliasdrv!
- */
- int aliasdrv[NUM_DRIVES];
-
- FILEPTR *flist; /* a list of free file pointers */
-
- char follow_links[1]; /* dummy "name" used as a parameter to path2cookie */
-
- /* vector of valid drives, according to GEMDOS */
- /* note that this isn't necessarily the same as what the BIOS thinks of
- * as valid
- */
- long dosdrvs;
-
- /*
- * Initialize a specific drive. This is called whenever a new drive
- * is accessed, or when media change occurs on an old drive.
- * Assumption: at this point, active_fs is a valid pointer
- * to a list of file systems.
- */
-
- /* table of processes holding locks on drives */
- extern PROC *dlockproc[]; /* in dosdir.c */
-
- void
- init_drive(i)
- int i;
- {
- long r;
- FILESYS *fs;
- fcookie root_dir;
-
- TRACE(("init_drive(%c)", i+'A'));
-
- drives[i] = 0; /* no file system */
- if (i >= 0 && i < NUM_DRIVES) {
- if (dlockproc[i]) return;
- }
-
- for (fs = active_fs; fs; fs = fs->next) {
- r = (*fs->root)(i, &root_dir);
- if (r == 0) {
- drives[i] = root_dir.fs;
- release_cookie(&root_dir);
- break;
- }
- }
- }
-
- /*
- * initialize the file system
- */
-
- #define NUMFPS 40 /* initial number of file pointers */
-
- void
- init_filesys()
- {
- static FILEPTR initial[NUMFPS+1];
- int i;
- extern FILESYS tos_filesys, bios_filesys, pipe_filesys,
- proc_filesys, uni_filesys;
-
- /* get the vector of connected GEMDOS drives */
- dosdrvs = Dsetdrv(Dgetdrv()) | drvmap();
-
- /* set up some initial file pointers */
- for (i = 0; i < NUMFPS; i++) {
- initial[i].devinfo = (ulong) (&initial[i+1]);
- }
- initial[NUMFPS].devinfo = 0;
- flist = initial;
-
- /* set up the file systems */
- tos_filesys.next = 0;
- bios_filesys.next = &tos_filesys;
- pipe_filesys.next = &bios_filesys;
- proc_filesys.next = &pipe_filesys;
- uni_filesys.next = &proc_filesys;
-
- active_fs = &uni_filesys;
-
- /* initialize the BIOS file system */
- biosfs_init();
-
- /* initialize the unified file system */
- unifs_init();
- }
-
- /*
- * load file systems from disk
- * this routine is called after process 0 is set up, but before any user
- * processes are run
- *
- * NOTE that a number of directory changes take place here: we look first
- * in the current directory, then in the directory \mint.
- */
-
- typedef FILESYS * ARGS_ON_STACK (*FSFUNC) P_((struct kerinfo *));
-
- /* uk: made this lie outside of functions, as load_filesys() and
- * load_devdriver() need access to it.
- */
- #define NPATHS 3
- static const char *ext_paths[NPATHS] = {"", "\\MINT", "\\MULTITOS"};
-
-
- void
- load_filesys()
- {
- long r;
- BASEPAGE *b;
- FILESYS *fs;
- FSFUNC initf;
- static DTABUF dta;
- int i;
- extern struct kerinfo kernelinfo; /* in main.c */
- char curpath[PATH_MAX];
- MEMREGION *xfsreg;
-
- curproc->dta = &dta;
- d_getpath(curpath,0);
-
- for (i = 0; i < NPATHS; i++) {
- if (*ext_paths[i]) {
- /* don't bother checking the current directory twice! */
- if (!stricmp(ext_paths[i],curpath))
- r = -1;
- else
- r = d_setpath(ext_paths[i]);
- }
- else
- r = 0;
-
- if (r == 0)
- r = f_sfirst("*.xfs", 0);
-
- while (r == 0) {
- b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
- if ( ((long)b) < 0 ) {
- DEBUG(("Error loading file system %s", dta.dta_name));
- r = f_snext();
- continue;
- }
- /* we leave a little bit of slop at the end of the loaded stuff */
- m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
- initf = (FSFUNC)b->p_tbase;
- TRACE(("initializing %s", dta.dta_name));
- fs = (*initf)(&kernelinfo);
-
- if (fs) {
- TRACE(("%s loaded OK", dta.dta_name));
- /* put the loaded XFS into super accesible memory */
- xfsreg = addr2region( (long) b );
- mark_region(xfsreg, PROT_S);
-
- /* link it into the list of drivers */
- /* uk: but only if it has not installed itself via Dcntl()
- * after checking if file system is already installed,
- * so we know for sure that each file system in at most
- * once in the chain (important for removal!)
- * also note: this doesn't preclude loading two different
- * instances of the same file system driver, e.g. it's perfectly
- * OK to have a "cdromy1.xfs" and "cdromz2.xfs"; the check below
- * just makes sure that a given instance of a file system is
- * installed at most once. I.e., it prevents cdromy1.xfs from being
- * installed twice.
- */
- if ((FILESYS*)1L != fs) {
- FILESYS *f = active_fs;
- for (; f; f = f->next)
- if (f == fs)
- break;
- if (!f) { /* we ran completly through the list */
- fs->next = active_fs;
- active_fs = fs;
- }
- }
- } else {
- DEBUG(("%s returned null", dta.dta_name));
- m_free((virtaddr)b);
- }
- r = f_snext();
- }
- }
-
- #if 0
- /* here, we invalidate all old drives EXCEPT for ones we're already using (at
- * this point, only the bios devices should be open)
- * this gives newly loaded file systems a chance to replace the
- * default tosfs.c
- */
- for (i = 0; i < NUM_DRIVES; i++) {
- if (d_lock(1, i) == 0) /* lock if possible */
- d_lock(0, i); /* and then unlock */
- }
- #endif
- }
-
-
- /*
- * uk: load device driver in files called *.xdd (external device driver)
- * from disk
- * maybe this should go into biosfs.c ??
- *
- * this routine is called after process 0 is set up, but before any user
- * processes are run, but before the loadable file systems come in,
- * so they can make use of external device drivers
- *
- * NOTE that a number of directory changes take place here: we look first
- * in the current directory, then in the directory \mint, and finally
- * the d_lock() calls force us into the root directory.
- * ??? what d_lock() calls ???
- */
-
- typedef DEVDRV * ARGS_ON_STACK (*DEVFUNC) P_((struct kerinfo *));
-
- #define DEV_SELFINST ((DEVDRV*)1L) /* dev driver did dcntl() already */
-
- void
- load_devdriver()
- {
- long r;
- BASEPAGE *b;
- DEVDRV *dev;
- DEVFUNC initf;
- struct dev_descr the_dev;
- static DTABUF dta;
- int i;
- extern struct kerinfo kernelinfo; /* in main.c */
- char curpath[PATH_MAX];
- char dev_name[PATH_MAX]; /* a bit long, but one never knows... */
- char ch, *p;
- MEMREGION *xddreg;
-
-
- curproc->dta = &dta;
- d_getpath(curpath,0);
-
- for (i = 0; i < NPATHS; i++) {
- if (*ext_paths[i]) {
- /* don't bother checking the current directory twice! */
- if (!stricmp(ext_paths[i],curpath))
- r = -1;
- else
- r = d_setpath(ext_paths[i]);
- }
- else
- r = 0;
-
- if (r == 0)
- r = f_sfirst("*.xdd", 0);
-
- while (r == 0) {
- b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
- if ( ((long)b) < 0 ) {
- DEBUG(("Error loading device driver %s", dta.dta_name));
- r = f_snext();
- continue;
- }
- /* we leave a little bit of slop at the end of the loaded stuff */
- m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
- initf = (DEVFUNC)b->p_tbase;
- TRACE(("initializing %s", dta.dta_name));
- dev = (*initf)(&kernelinfo);
-
- if (dev) {
- if (DEV_SELFINST != dev) {
- /* we need to install the device driver ourselves */
- the_dev.driver = dev;
- the_dev.dinfo = 0;
- the_dev.flags = 0;
- the_dev.tty = (struct tty*)0L;
- the_dev.reserved[0] = the_dev.reserved[1] = 0;
- the_dev.reserved[2] = the_dev.reserved[3] = 0;
- p = dta.dta_name;
- /* copy the dev. driver name, converting to lower case */
- while (*p && *p != '.') {
- *p = tolower(*p);
- p++;
- }
- ch = *p;
- *p = '\0'; /* we dont want the extension */
- strcpy(dev_name, "u:\\dev\\");
- strcat(dev_name, dta.dta_name);
- *p = ch;
- r = d_cntl(DEV_INSTALL, dev_name, (long)&the_dev);
- if (r <= 0) {
- DEBUG(("Error installing device driver %s", dta.dta_name));
- r = f_snext();
- continue;
- }
- }
- TRACE(("%s loaded OK", dta.dta_name));
- /* put the loaded XDD into super accesible memory */
- xddreg = addr2region( (long) b );
- mark_region(xddreg, PROT_S);
- } else {
- DEBUG(("%s returned null", dta.dta_name));
- m_free((virtaddr)b);
- }
- r = f_snext();
- }
- }
- }
-
-
- void
- close_filesys()
- {
- PROC *p;
- FILEPTR *f;
- int i;
-
- TRACE(("close_filesys"));
- /* close every open file */
- for (p = proclist; p; p = p->gl_next) {
- for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
- if ( (f = p->handle[i]) != 0) {
- if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q)
- ALERT("Open file for dead process?");
- do_pclose(p, f);
- }
- }
- }
- }
-
- /*
- * "media change" routine: called when a media change is detected on device
- * d, which may or may not be a BIOS device. All handles associated with
- * the device are closed, and all directories invalidated. This routine
- * does all the dirty work, and is called automatically when
- * disk_changed detects a media change.
- */
-
- void ARGS_ON_STACK
- changedrv(d)
- unsigned d;
- {
- PROC *p;
- int i;
- FILEPTR *f;
- FILESYS *fs;
- SHTEXT *stext;
- extern SHTEXT *text_reg; /* in mem.c */
- DIR *dirh;
- fcookie dir;
- int warned = (d & 0xf000) == PROC_RDEV_BASE;
- long r;
-
- /* if an aliased drive, change the *real* device */
- if (d < NUM_DRIVES && aliasdrv[d]) {
- d = aliasdrv[d] - 1; /* see NOTE above */
- }
-
- /* re-initialize the device, if it was a BIOS device */
- if (d < NUM_DRIVES) {
- fs = drives[d];
- if (fs) {
- (void)(*fs->dskchng)(d);
- }
- init_drive(d);
- }
-
- for (p = proclist; p; p = p->gl_next) {
- /* invalidate all open files on this device */
- for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
- if (((f = p->handle[i]) != 0) && (f->fc.dev == d)) {
- if (!warned) {
- ALERT(
- "Files were open on a changed drive (0x%x)!", d);
- warned++;
- }
-
- /* we set f->dev to NULL to indicate to do_pclose that this is an
- * emergency close, and that it shouldn't try to make any
- * calls to the device driver since the file has gone away
- */
- f->dev = NULL;
- (void)do_pclose(p, f);
- /* we could just zero the handle, but this could lead to confusion if
- * a process doesn't realize that there's been a media change, Fopens
- * a new file, and gets the same handle back. So, we force the
- * handle to point to /dev/null.
- */
- p->handle[i] =
- do_open("U:\\DEV\\NULL", O_RDWR, 0, (XATTR *)0);
- }
- }
-
- /* terminate any active directory searches on the drive */
- for (i = 0; i < NUM_SEARCH; i++) {
- dirh = &p->srchdir[i];
- if (p->srchdta[i] && dirh->fc.fs && dirh->fc.dev == d) {
- TRACE(("closing search for process %d", p->pid));
- release_cookie(&dirh->fc);
- dirh->fc.fs = 0;
- p->srchdta[i] = 0;
- }
- }
-
- for (dirh = p->searches; dirh; dirh = dirh->next) {
- /* If this search is on the changed drive, release
- the cookie, but do *not* free it, since the
- user could later call closedir on it. */
- if (dirh->fc.fs && dirh->fc.dev == d) {
- release_cookie (&dirh->fc);
- dirh->fc.fs = 0;
- }
- }
-
- if (d >= NUM_DRIVES) continue;
-
- /* change any active directories on the device to the (new) root */
- fs = drives[d];
- if (fs) {
- r = (*fs->root)(d, &dir);
- if (r != E_OK) dir.fs = 0;
- } else {
- dir.fs = 0; dir.dev = d;
- }
-
- for (i = 0; i < NUM_DRIVES; i++) {
- if (p->root[i].dev == d) {
- release_cookie(&p->root[i]);
- dup_cookie(&p->root[i], &dir);
- }
- if (p->curdir[i].dev == d) {
- release_cookie(&p->curdir[i]);
- dup_cookie(&p->curdir[i], &dir);
- }
- }
- release_cookie(&dir);
- }
-
- /* free any file descriptors associated with shared text regions */
- for (stext = text_reg; stext; stext = stext->next) {
- f = stext->f;
- if (f->fc.dev == d) {
- f->dev = NULL;
- do_pclose(rootproc, f);
- stext->f = 0;
- }
- }
- }
-
- /*
- * check for media change: if the drive has changed, call changedrv to
- * invalidate any open files and file handles associated with it, and
- * call the file system's media change routine.
- * returns: 0 if no change, 1 if change, negative number for error
- */
-
- int
- disk_changed(d)
- int d;
- {
- short r;
- FILESYS *fs;
- static char tmpbuf[8192];
-
- /* for now, only check BIOS devices */
- if (d < 0 || d >= NUM_DRIVES)
- return 0;
- /* watch out for aliased drives */
- if (aliasdrv[d]) {
- d = aliasdrv[d] - 1;
- if (d < 0 || d >= NUM_DRIVES)
- return 0;
- }
-
- /* has the drive been initialized yet? If not, then initialize it and return
- * "no change"
- */
- fs = drives[d];
- if (!fs) {
- TRACE(("drive %c not yet initialized", d+'A'));
- changedrv(d);
- return 0;
- }
-
- /* We have to do this stuff no matter what, because someone may have installed
- * vectors to force a media change...
- * PROBLEM: AHDI may get upset if the drive isn't valid.
- * SOLUTION: don't change the default PSEUDODRIVES setting!
- */
-
- TRACE(("calling mediach(%d)",d));
- r = (int)mediach(d);
- TRACE(("mediach(%d) == %d", d, r));
-
- if (r < 0) {
- /* KLUDGE: some .XFS drivers don't install BIOS vectors, and so we'll
- * always get EUNDEV back from them. This isn't recommended (since there
- * are other programs than MiNT that may ask for BIOS functions from
- * any installed drives). This is a temporary work-around until those
- * .XFSes are changed to either install BIOS vectors or to use the
- * new U: Dcntl() calls to install themselves.
- * Note that EUNDEV must be tested for drives A-C, or else booting may
- * not work properly.
- */
- if (d > 2 && r == EUNDEV)
- r = 2; /* assume there may be a change */
- else
- return r;
- }
- if (r == 1) { /* drive _may_ have changed */
- r = rwabs(0, tmpbuf, 1, 0, d, 0L); /* check the BIOS */
- if (r != E_CHNG) { /* nope, no change */
- TRACE(("rwabs returned %d", r));
- return (r < 0) ? r : 0;
- }
- r = 2; /* drive was definitely changed */
- }
- if (r == 2) {
- TRACE(("definite media change"));
- fs = drives[d]; /* get filesystem associated with drive */
- if ((*fs->dskchng)(d)) { /* does the fs agree that it changed? */
- drives[d] = 0;
- changedrv(d); /* yes -- do the change */
- return 1;
- }
- }
- return 0;
- }
-
- /*
- * routines for parsing path names
- */
-
- #define DIRSEP(p) ((p) == '\\')
-
- /*
- * relpath2cookie converts a TOS file name into a file cookie representing
- * the directory the file resides in, and a character string representing
- * the name of the file in that directory. The character string is
- * copied into the "lastname" array. If lastname is NULL, then the cookie
- * returned actually represents the file, instead of just the directory
- * the file is in.
- *
- * note that lastname, if non-null, should be big enough to contain all the
- * characters in "path", since if the file system doesn't want the kernel
- * to do path name parsing we may end up just copying path to lastname
- * and returning the current or root directory, as appropriate
- *
- * "relto" is the directory relative to which the search should start.
- * if you just want the current directory, use path2cookie instead.
- *
- */
-
- #define MAX_LINKS 4
-
- long
- relpath2cookie(relto, path, lastname, res, depth)
- fcookie *relto;
- const char *path;
- char *lastname;
- fcookie *res;
- int depth;
- {
- fcookie dir;
- int drv;
- int len;
- char c, *s;
- XATTR xattr;
- static char newpath[16] = "U:\\DEV\\";
- char temp2[PATH_MAX];
- char linkstuff[PATH_MAX];
- long r;
-
- /* dolast: 0 == return a cookie for the directory the file is in
- * 1 == return a cookie for the file itself, don't follow links
- * 2 == return a cookie for whatever the file points at
- */
- int dolast = 0;
- int i = 0;
-
- if (!lastname) {
- dolast = 1;
- lastname = temp2;
- } else if (lastname == follow_links) {
- dolast = 2;
- lastname = temp2;
- }
-
- *lastname = 0;
-
- PATH2COOKIE_DB(("relpath2cookie(%s, dolast=%d, depth=%d)", path, dolast, depth));
-
- if (depth > MAX_LINKS) {
- DEBUG(("Too many symbolic links"));
- return ELOOP;
- }
- /* special cases: CON:, AUX:, etc. should be converted to U:\DEV\CON,
- * U:\DEV\AUX, etc.
- */
- if (strlen(path) == 4 && path[3] == ':') {
- strncpy(newpath+7, path, 3);
- path = newpath;
- }
-
- /* first, check for a drive letter */
- /* BUG: a '\' at the start of a symbolic link is relative to the current
- * drive of the process, not the drive the link is located on
- */
- if (path[1] == ':') {
- c = path[0];
- if (c >= 'a' && c <= 'z')
- drv = c - 'a';
- else if (c >= 'A' && c <= 'Z')
- drv = c - 'A';
- else
- goto nodrive;
- path += 2;
- i = 1; /* remember that we saw a drive letter */
- } else {
- nodrive:
- drv = curproc->curdrv;
- }
-
- /* see if the path is rooted from '\\' */
- if (DIRSEP(*path)) {
- while(DIRSEP(*path))path++;
- dup_cookie(&dir, &curproc->root[drv]);
- } else {
- if (i) { /* an explicit drive letter was given */
- dup_cookie(&dir, &curproc->curdir[drv]);
- }
- else
- dup_cookie(&dir, relto);
- }
-
- if (!dir.fs) {
- changedrv(dir.dev);
- dup_cookie(&dir, &curproc->root[drv]);
- }
-
- if (!dir.fs) {
- DEBUG(("path2cookie: no file system: returning EDRIVE"));
- return EDRIVE;
- }
-
- /* here's where we come when we've gone across a mount point */
-
- restart_mount:
-
- if (!*path) { /* nothing more to do */
- PATH2COOKIE_DB(("relpath2cookie: no more path, returning 0"));
- *res = dir;
- return 0;
- }
-
- /* see if there has been a disk change; if so, return E_CHNG.
- * path2cookie will restart the search automatically; other functions
- * that call relpath2cookie directly will have to fail gracefully
- */
- if ((r = disk_changed(dir.dev)) != 0) {
- release_cookie(&dir);
- if (r > 0) r = E_CHNG;
- PATH2COOKIE_DB(("relpath2cookie: returning %d", r));
- return r;
- }
-
-
- if (dir.fs->fsflags & FS_KNOPARSE) {
- if (!dolast) {
- PATH2COOKIE_DB(("fs is a KNOPARSE, nothing to do"));
- strncpy(lastname, path, PATH_MAX-1);
- lastname[PATH_MAX - 1] = 0;
- r = 0;
- *res = dir;
- } else {
- PATH2COOKIE_DB(("fs is a KNOPARSE, calling lookup"));
- r = (*dir.fs->lookup)(&dir, path, res);
- if (r == EMOUNT) { /* hmmm... a ".." at a mount point, maybe */
- fcookie mounteddir;
- r = (*dir.fs->root)(dir.dev, &mounteddir);
- if (r == 0 && drv == UNIDRV) {
- if (dir.fs == mounteddir.fs &&
- dir.index == mounteddir.index &&
- dir.dev == mounteddir.dev) {
- release_cookie(&dir);
- release_cookie(&mounteddir);
- dup_cookie(&dir, &curproc->root[UNIDRV]);
- TRACE(("path2cookie: restarting from mount point"));
- goto restart_mount;
- }
- } else {
- if (r == 0)
- release_cookie(&mounteddir);
- r = 0;
- }
- }
- release_cookie(&dir);
- }
- PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
- return r;
- }
-
-
- /* parse all but (possibly) the last component of the path name */
- /* rules here: at the top of the loop, &dir is the cookie of
- * the directory we're in now, xattr is its attributes, and res is unset
- * at the end of the loop, &dir is unset, and either r is nonzero
- * (to indicate an error) or res is set to the final result
- */
- r = (dir.fs->getxattr)(&dir, &xattr);
- if (r) {
- DEBUG(("couldn't get directory attributes"));
- release_cookie(&dir);
- return EINTRN;
- }
-
- while (*path) {
-
- /* now we must have a directory, since there are more things in the path */
- if ((xattr.mode & S_IFMT) != S_IFDIR) {
- PATH2COOKIE_DB(("relpath2cookie: not a directory, returning EPTHNF"));
- release_cookie(&dir);
- r = EPTHNF;
- break;
- }
- /* we must also have search permission for the directory */
- if (denyaccess(&xattr, S_IXOTH)) {
- DEBUG(("search permission in directory denied"));
- release_cookie(&dir);
- r = EPTHNF;
- break;
- }
-
- /* if there's nothing left in the path, we can break here */
- if (!*path) {
- PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (1)"));
- *res = dir;
- break;
- }
- /* next, peel off the next name in the path */
- len = 0;
- s = lastname;
- c = *path;
- while (c && !DIRSEP(c)) {
- if (len++ < PATH_MAX)
- *s++ = c;
- c = *++path;
- }
- *s = 0;
-
- /* if there are no more names in the path, and we don't want
- * to actually look up the last name, then we're done
- */
- if (dolast == 0 && !*path) {
- *res = dir;
- PATH2COOKIE_DB(("relpath2cookie: no more path, breaking (2)"));
- break;
- }
-
-
- /*
- * skip trailing slashes
- */
- while (DIRSEP(*path)) path++;
-
- PATH2COOKIE_DB(("relpath2cookie: looking up [%s]", lastname));
-
- r = (*dir.fs->lookup)(&dir, lastname, res);
- if (r == EMOUNT) {
- fcookie mounteddir;
- r = (*dir.fs->root)(dir.dev, &mounteddir);
- if (r == 0 && drv == UNIDRV) {
- if (samefile(&dir, &mounteddir)) {
- release_cookie(&dir);
- release_cookie(&mounteddir);
- dup_cookie(&dir, &curproc->root[UNIDRV]);
- TRACE(("path2cookie: restarting from mount point"));
- goto restart_mount;
- } else if (r == 0) {
- r = EINTRN;
- release_cookie(&mounteddir);
- release_cookie(&dir);
- break;
- }
- } else if (r == 0) {
- release_cookie(&mounteddir);
- } else {
- release_cookie(&dir);
- break;
- }
- } else if (r) {
- if (r == EFILNF && *path) {
- /* the "file" we didn't find was treated as a directory */
- r = EPTHNF;
- }
- release_cookie(&dir);
- break;
- }
-
- /* check for a symbolic link */
- r = (res->fs->getxattr)(res, &xattr);
- if (r != 0) {
- DEBUG(("path2cookie: couldn't get file attributes"));
- release_cookie(&dir);
- release_cookie(res);
- break;
- }
-
- /* if the file is a link, and we're following links, follow it */
- if ( (xattr.mode & S_IFMT) == S_IFLNK && (*path || dolast > 1)) {
- r = (res->fs->readlink)(res, linkstuff, PATH_MAX);
- release_cookie(res);
- if (r) {
- DEBUG(("error reading symbolic link"));
- release_cookie(&dir);
- break;
- }
- r = relpath2cookie(&dir, linkstuff, follow_links, res,
- depth+1);
- release_cookie(&dir);
- if (r) {
- DEBUG(("error following symbolic link"));
- break;
- }
- dir = *res;
- (void)(res->fs->getxattr)(res, &xattr);
- } else {
- release_cookie(&dir);
- dir = *res;
- }
- }
-
- PATH2COOKIE_DB(("relpath2cookie: returning %ld", r));
- return r;
- }
-
- #define MAX_TRYS 8
-
- long
- path2cookie(path, lastname, res)
- const char *path;
- char *lastname;
- fcookie *res;
- {
- fcookie *dir;
- long r;
- /* AHDI sometimes will keep insisting that a media change occured;
- * we limit the number of retrys to avoid hanging the system
- */
- int trycnt = 0;
-
- dir = &curproc->curdir[curproc->curdrv];
-
- do {
- r = relpath2cookie(dir, path, lastname, res, 0);
- if (r == E_CHNG)
- DEBUG(("path2cookie: restarting due to media change"));
- } while (r == E_CHNG && trycnt++ < MAX_TRYS);
-
- return r;
- }
-
- /*
- * release_cookie: tell the file system owner that a cookie is no
- * longer in use by the kernel
- */
- void
- release_cookie(fc)
- fcookie *fc;
- {
- FILESYS *fs;
-
- if (fc) {
- fs = fc->fs;
- if (fs && fs->release) {
- (void)(*fs->release)(fc);
- }
- }
- }
-
- /*
- * Make a new cookie (newc) which is a duplicate of the old cookie
- * (oldc). This may be something the file system is interested in,
- * so we give it a chance to do the duplication; if it doesn't
- * want to, we just copy.
- */
-
- void
- dup_cookie(newc, oldc)
- fcookie *newc, *oldc;
- {
- FILESYS *fs = oldc->fs;
-
- if (fs && fs->release && fs->dupcookie) {
- (void)(*fs->dupcookie)(newc, oldc);
- } else {
- *newc = *oldc;
- }
- }
-
- /*
- * new_fileptr, dispose_fileptr: allocate (deallocate) a file pointer
- */
-
- FILEPTR *
- new_fileptr()
- {
- FILEPTR *f;
-
- if ((f = flist) != 0) {
- flist = f->next;
- f->next = 0;
- return f;
- }
- f = kmalloc(SIZEOF(FILEPTR));
- if (!f) {
- FATAL("new_fileptr: out of memory");
- }
- else {
- f->next = 0;
- }
- return f;
- }
-
- void
- dispose_fileptr(f)
- FILEPTR *f;
- {
- if (f->links != 0) {
- FATAL("dispose_fileptr: f->links == %d", f->links);
- }
- f->next = flist;
- flist = f;
- }
-
- /*
- * denyshare(list, f): "list" points at the first FILEPTR in a
- * chained list of open FILEPTRS referring to the same file;
- * f is a newly opened FILEPTR. Every FILEPTR in the given list is
- * checked to see if its "open" mode (in list->flags) is compatible with
- * the open mode in f->flags. If not (for example, if f was opened with
- * a "read" mode and some other file has the O_DENYREAD share mode),
- * then 1 is returned. If all the open FILEPTRs in the list are
- * compatible with f, then 0 is returned.
- * This is not as complicated as it sounds. In practice, just keep a
- * list of open FILEPTRs attached to each file, and put something like
- * if (denyshare(thisfile->openfileptrlist, newfileptr))
- * return EACCDN;
- * in the device open routine.
- */
-
- int ARGS_ON_STACK
- denyshare(list, f)
- FILEPTR *list, *f;
- {
- int newrm, newsm; /* new read and sharing mode */
- int oldrm, oldsm; /* read and sharing mode of already opened file */
- int i;
-
- newrm = f->flags & O_RWMODE;
- newsm = f->flags & O_SHMODE;
-
- /*
- * O_EXEC gets treated the same as O_RDONLY for our purposes
- */
- if (newrm == O_EXEC) newrm = O_RDONLY;
-
- /* New meaning for O_COMPAT: deny write access to all _other_
- * processes.
- */
-
- for ( ; list; list = list->next) {
- oldrm = list->flags & O_RWMODE;
- if (oldrm == O_EXEC) oldrm = O_RDONLY;
- oldsm = list->flags & O_SHMODE;
- if (oldsm == O_DENYW || oldsm == O_DENYRW) {
- if (newrm != O_RDONLY) {
- DEBUG(("write access denied"));
- return 1;
- }
- }
- if (oldsm == O_DENYR || oldsm == O_DENYRW) {
- if (newrm != O_WRONLY) {
- DEBUG(("read access denied"));
- return 1;
- }
- }
- if (newsm == O_DENYW || newsm == O_DENYRW) {
- if (oldrm != O_RDONLY) {
- DEBUG(("couldn't deny writes"));
- return 1;
- }
- }
- if (newsm == O_DENYR || newsm == O_DENYRW) {
- if (oldrm != O_WRONLY) {
- DEBUG(("couldn't deny reads"));
- return 1;
- }
- }
- /* If either sm == O_COMPAT, then we check to make sure
- that the file pointers are owned by the same process (O_COMPAT means
- "deny writes to any other processes"). This isn't quite the same
- as the Atari spec, which says O_COMPAT means "deny access to other
- processes." We should fix the spec.
- */
- if ((newsm == O_COMPAT && newrm != O_RDONLY && oldrm != O_RDONLY) ||
- (oldsm == O_COMPAT && newrm != O_RDONLY)) {
- for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
- if (curproc->handle[i] == list)
- goto found;
- }
- /* old file pointer is not open by this process */
- DEBUG(("O_COMPAT file was opened for writing by another process"));
- return 1;
- found:
- ; /* everything is OK */
- }
- }
- return 0;
- }
-
- /*
- * denyaccess(XATTR *xattr, unsigned perm): checks to see if the access
- * specified by perm (which must be some combination of S_IROTH, S_IWOTH,
- * and S_IXOTH) should be granted to the current process
- * on a file with the given extended attributes. Returns 0 if access
- * by the current process is OK, 1 if not.
- */
-
- int
- denyaccess(xattr, perm)
- XATTR *xattr;
- unsigned perm;
- {
- unsigned mode;
-
- /* the super-user can do anything! */
- if (curproc->euid == 0)
- return 0;
-
- mode = xattr->mode;
- if (curproc->euid == xattr->uid)
- perm = perm << 6;
- else if (curproc->egid == xattr->gid)
- perm = perm << 3;
- if ((mode & perm) != perm) return 1; /* access denied */
- return 0;
- }
-
- /*
- * Checks a lock against a list of locks to see if there is a conflict.
- * This is a utility to be used by file systems, somewhat like denyshare
- * above. Returns 0 if there is no conflict, or a pointer to the
- * conflicting LOCK structure if there is.
- *
- * Conflicts occur for overlapping locks if the process id's are
- * different and if at least one of the locks is a write lock.
- *
- * NOTE: we assume before being called that the locks have been converted
- * so that l_start is absolute. not relative to the current position or
- * end of file.
- */
-
- LOCK * ARGS_ON_STACK
- denylock(list, lck)
- LOCK *list, *lck;
- {
- LOCK *t;
- unsigned long tstart, tend;
- unsigned long lstart, lend;
- int pid = curproc->pid;
- int ltype;
-
- ltype = lck->l.l_type;
- lstart = lck->l.l_start;
-
- if (lck->l.l_len == 0)
- lend = 0xffffffffL;
- else
- lend = lstart + lck->l.l_len - 1;
-
- for (t = list; t; t = t->next) {
- tstart = t->l.l_start;
- if (t->l.l_len == 0)
- tend = 0xffffffffL;
- else
- tend = tstart + t->l.l_len - 1;
-
- /* look for overlapping locks */
- if (tstart <= lstart && tend >= lstart && t->l.l_pid != pid &&
- (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
- break;
- if (lstart <= tstart && lend >= tstart && t->l.l_pid != pid &&
- (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
- break;
- }
- return t;
- }
-
- /*
- * check to see that a file is a directory, and that write permission
- * is granted; return an error code, or 0 if everything is ok.
- */
- long
- dir_access(dir, perm)
- fcookie *dir;
- unsigned perm;
- {
- XATTR xattr;
- long r;
-
- r = (*dir->fs->getxattr)(dir, &xattr);
- if (r) {
- DEBUG(("dir_access: file system returned %ld", r));
- return r;
- }
- if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
- DEBUG(("file is not a directory"));
- return EPTHNF;
- }
- if (denyaccess(&xattr, perm)) {
- DEBUG(("no permission for directory"));
- return EACCDN;
- }
- return 0;
- }
-
- /*
- * returns 1 if the given name contains a wildcard character
- */
-
- int
- has_wild(name)
- const char *name;
- {
- char c;
-
- while ((c = *name++) != 0) {
- if (c == '*' || c == '?') return 1;
- }
- return 0;
- }
-
- /*
- * void copy8_3(dest, src): convert a file name (src) into DOS 8.3 format
- * (in dest). Note the following things:
- * if a field has less than the required number of characters, it is
- * padded with blanks
- * a '*' means to pad the rest of the field with '?' characters
- * special things to watch for:
- * "." and ".." are more or less left alone
- * "*.*" is recognized as a special pattern, for which dest is set
- * to just "*"
- * Long names are truncated. Any extensions after the first one are
- * ignored, i.e. foo.bar.c -> foo.bar, foo.c.bar->foo.c.
- */
-
- void
- copy8_3(dest, src)
- char *dest;
- const char *src;
- {
- char fill = ' ', c;
- int i;
-
- if (src[0] == '.') {
- if (src[1] == 0) {
- strcpy(dest, ". . ");
- return;
- }
- if (src[1] == '.' && src[2] == 0) {
- strcpy(dest, ".. . ");
- return;
- }
- }
- if (src[0] == '*' && src[1] == '.' && src[2] == '*' && src[3] == 0) {
- dest[0] = '*';
- dest[1] = 0;
- return;
- }
-
- for (i = 0; i < 8; i++) {
- c = *src++;
- if (!c || c == '.') break;
- if (c == '*') {
- fill = c = '?';
- }
- *dest++ = toupper(c);
- }
- while (i++ < 8) {
- *dest++ = fill;
- }
- *dest++ = '.';
- i = 0;
- fill = ' ';
- while (c && c != '.')
- c = *src++;
-
- if (c) {
- for( ;i < 3; i++) {
- c = *src++;
- if (!c || c == '.') break;
- if (c == '*')
- c = fill = '?';
- *dest++ = toupper(c);
- }
- }
- while (i++ < 3)
- *dest++ = fill;
- *dest = 0;
- }
-
- /*
- * int pat_match(name, patrn): returns 1 if "name" matches the template in
- * "patrn", 0 if not. "patrn" is assumed to have been expanded in 8.3
- * format by copy8_3; "name" need not be. Any '?' characters in patrn
- * will match any character in name. Note that if "patrn" has a '*' as
- * the first character, it will always match; this will happen only if
- * the original pattern (before copy8_3 was applied) was "*.*".
- *
- * BUGS: acts a lot like the silly TOS pattern matcher.
- */
-
- int
- pat_match(name, template)
- const char *name, *template;
- {
- register char *s, c;
- char expname[TOS_NAMELEN+1];
-
- if (*template == '*') return 1;
- copy8_3(expname, name);
-
- s = expname;
- while ((c = *template++) != 0) {
- if (c != *s && c != '?')
- return 0;
- s++;
- }
- return 1;
- }
-
- /*
- * int samefile(fcookie *a, fcookie *b): returns 1 if the two cookies
- * refer to the same file or directory, 0 otherwise
- */
-
- int
- samefile(a, b)
- fcookie *a, *b;
- {
- if (a->fs == b->fs && a->dev == b->dev && a->index == b->index)
- return 1;
- return 0;
- }
-