home *** CD-ROM | disk | FTP | other *** search
- head 1.2;
- access;
- symbols
- version39-41:1.1;
- locks;
- comment @ * @;
-
-
- 1.2
- date 92.08.09.20.38.34; author amiga; state Exp;
- branches;
- next 1.1;
-
- 1.1
- date 92.05.14.19.55.40; author mwild; state Exp;
- branches;
- next ;
-
-
- desc
- @lowlevel path expander, used by all functions requiring a path name
- @
-
-
- 1.2
- log
- @change to use 2.x header files by default
- @
- text
- @/*
- * This file is part of ixemul.library for the Amiga.
- * Copyright (C) 1991, 1992 Markus M. Wild
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: __plock.c,v 1.1 1992/05/14 19:55:40 mwild Exp $
- *
- * $Log: __plock.c,v $
- * Revision 1.1 1992/05/14 19:55:40 mwild
- * Initial revision
- *
- */
-
- /* 20-jan-92 -mw- revamped to emulate GetDeviceProc() under 1.3
- * new way to find out whether IsFileSystem(name)
- * 14-mar-92 -mw- limited /sys -> sys: mapping. `/' is now treated
- * as undefined path, to be compatible to a later
- * version, where it will be a virtual directory
- * of devices and logicals
- */
-
- /*
- * Lock() and LLock() emulation. Takes care of expanding paths that contain
- * symlinks.
- * Call __plock() if you need a lock to the parent directory as used in
- * other packets, that way you always get the "right" thing
- */
-
- #define KERNEL
- #include "ixemul.h"
- #include <stdlib.h>
- #include <string.h>
-
- #undef DEBUG
-
- #ifdef DEBUG
- #define DP(a) kprintf a
- #else
- #define DP(a)
- #endif
-
- /* don't need async packets in here, no shared file packets are in use */
- #define __srwport (u.u_sync_mp)
-
- #if __GNUC__ != 2
- #define alloca __builtin_alloca
- #endif
-
- #ifndef ACTION_READ_LINK
- #define ACTION_READ_LINK 1024
- #endif
-
- #ifndef ACTION_IS_FILESYSTEM
- #define ACTION_IS_FILESYSTEM 1027
- #endif
-
-
- #ifndef ERROR_IS_SOFT_LINK
- #define ERROR_IS_SOFT_LINK 233
- #endif
-
- #ifndef DVPF_ASSIGN
- /* structure return by GetDeviceProc() */
- struct DevProc {
- struct MsgPort *dvp_Port;
- BPTR dvp_Lock;
- ULONG dvp_Flags;
- struct DosList *dvp_DevNode; /* DON'T TOUCH OR USE! */
- };
-
- /* definitions for dvp_Flags */
- #define DVPB_UNLOCK 0
- #define DVPF_UNLOCK (1L << DVPB_UNLOCK)
- #define DVPB_ASSIGN 1
- #define DVPF_ASSIGN (1L << DVPB_ASSIGN)
-
- #define BASE_EXT_DECL
- #define BASE_PAR_DECL
- #define BASE_PAR_DECL0
- #define BASE_NAME ix.ix_dos_base
- __inline static struct DevProc* GetDeviceProc(BASE_PAR_DECL UBYTE* name, struct DevProc* dp)
- {
- BASE_EXT_DECL
- register struct DevProc* res __asm("d0");
- register void *a6 __asm ("a6");
- register UBYTE* d1 __asm("d1");
- register struct DevProc* d2 __asm("d2");
-
- a6 = BASE_NAME;
- d1 = name;
- d2 = dp;
- __asm volatile ("
- jsr a6@@(-0x282)"
- : "=r" (res)
- : "r" (a6), "r" (d1), "r" (d2)
- : "d0", "d1", "a0", "a1", "d2");
- *(char*)d2=*(char *)d2;
- return res;
- }
- __inline static void FreeDeviceProc(BASE_PAR_DECL struct DevProc* dp)
- {
- BASE_EXT_DECL
- register void *a6 __asm ("a6");
- register struct DevProc* d1 __asm("d1");
-
- a6 = BASE_NAME;
- d1 = dp;
- __asm volatile ("
- jsr a6@@(-0x288)"
- : /* no output */
- : "r" (a6), "r" (d1)
- : "d0", "d1", "a0", "a1");
- *(char*)d1=*(char *)d1;
- }
- #endif
-
- static struct DevProc *get_device_proc (char *, struct DevProc *, int *);
- static void free_device_proc (struct DevProc *);
- static int unslashify (char *);
-
- extern int _dos20;
-
- BPTR
- __plock (char *file_name, int (*last_func)(), void *last_arg)
- {
- BPTR parent_lock;
- struct MsgPort *handler;
- struct StandardPacket *sp;
- unsigned char *bstr;
- char *sep, *next, *cp;
- int len;
- /* true when we're processing the last element of name */
- int is_last;
- /* true after first pass, we should unlock all locks except the one
- * we get as a sideeffect of DeviceProc */
- int unlock_parent;
- int link_levels;
- int no_error;
- BPTR result;
- int res_res2;
- int omask;
- int split_name;
- struct DevProc *dp;
- char *orig_name, *name;
-
- DP(("__plock: file_name = %s, last_func = $%lx\n",
- file_name ? file_name : "(none)", last_func));
-
- /* ``fix'' until I find the real problem in pdksh.. */
- if (! file_name)
- return 0;
-
- /* need to operate on a backup of the passed name, so I can do
- * /sys -> sys: conversion in place */
- name = alloca (strlen (file_name) + 1);
- strcpy (name, file_name);
- orig_name = name;
-
- /* now get a LONG aligned packet */
- sp = alloca (sizeof(*sp)+2);
- sp = LONG_ALIGN (sp);
- __init_std_packet(sp);
-
- /* allocate one BSTR-buffer. A length of 255 is enough, since a bstr
- * can't address any more ;-) */
- bstr = alloca (256 + 2);
- bstr = LONG_ALIGN (bstr);
-
- /* NOTE: although we don't use any DOS calls here, we have to block
- * any signals, since the locks we obtain in this function have to
- * be freed before anything else can be done. This function is
- * *not* reentrant in the sense that it can be interrupted without
- * being finished */
- omask = syscall (SYS_sigsetmask, ~0);
-
- dp = 0;
-
- retry_multi_assign:
-
- name = orig_name;
- if (ix.ix_translate_slash && unslashify (name) < 0)
- {
- result = 0;
- res_res2 = ERROR_OBJECT_NOT_FOUND;
- dp = 0;
- goto do_return;
- }
-
- if (! strcmp (name, "*") || ! strcasecmp (name, "console:"))
- {
- handler = (struct MsgPort *)(((struct Process *)FindTask (0))->pr_ConsoleTask);
- parent_lock = 0;
- DP(("__plock: console override, handler $%lx.\n", handler));
- name = "*"; /* supports console: under 1.3 */
- if (dp) free_device_proc (dp);
- split_name = 0;
- dp = 0;
- }
- else if (! strcasecmp (name, "nil:") || ! strcasecmp (name, "/nil") ||
- ! strcmp (name, "/dev/null") || ! strcmp (name, "dev:null"))
- {
- result = 0;
- res_res2 = 4242; /* special special ;-)))) */
- dp = 0;
- goto do_return;
- }
- else
- {
- dp = get_device_proc (name, dp, &split_name);
- DP(("__plock: gdp(%s) -> $%lx",name,dp));
-
- handler = dp ? dp->dvp_Port : 0;
- parent_lock = dp ? dp->dvp_Lock : 0;
- if (handler)
- DP((" handler = $%lx, parent_lock = $%lx, is_fs = %ld\n", handler, parent_lock, split_name));
- else
- DP(("\n"));
- }
-
- is_last = 0;
- unlock_parent = 0;
- link_levels = 0;
- result = 0;
-
- if (! handler)
- {
- res_res2 = ERROR_OBJECT_NOT_FOUND;
- goto do_return;
- }
-
- link_levels = 0;
-
- /* this seems logical, doesn't it? don't know ;-)) */
- sep = index (name, ':');
- if (sep) name = sep+1;
-
- do
- {
- DP(("__plock: solving for %s.\n", name));
-
- if (split_name)
- {
- /* fetch the first part of "name", thus stopping at either a : or a /
- * next points at the start of the next directory component to be
- * processed in the next run
- */
-
- sep = index (name, ':');
- if (sep)
- {
- sep++; /* the : is part of the filename */
- next = sep;
- }
- else
- {
- sep = index (name, '/');
-
- /* map foo/bar/ into foo/bar, but keep foo/bar// */
- if (sep && sep[1]==0)
- {
- is_last = 1;
- next = sep;
- }
- else if (! sep)
- {
- sep = name + strlen (name);
- next = sep;
- is_last = 1;
- }
- else
- {
- if (ix.ix_translate_slash)
- for (next = sep + 1; *next == '/'; next ++) ;
- else
- next = sep + 1;
-
- /* if the slash is the first character, it means "parent",
- * so we have to pass it literally to Lock() */
- if (sep == name) sep = next;
- }
- }
- }
- else
- {
- sep = name + strlen (name);
- is_last = 1;
- }
-
- len = sep - name;
- if (len) bcopy (name, bstr + 1, len);
- *bstr = len;
-
- if (ix.ix_translate_dots)
- {
- /* turn a ".." into a "/", and a "." into a "" */
-
- if (bcmp (bstr, "\2..", 3) == 0)
- {
- bstr[0] = 1; bstr[1] = '/';
- }
- else if (bcmp (bstr, "\1.", 2) == 0)
- bstr[0] = 0;
- }
-
- do
- {
- sp->sp_Pkt.dp_Port = __srwport;
- if (! is_last)
- {
- sp->sp_Pkt.dp_Type = ACTION_LOCATE_OBJECT;
- sp->sp_Pkt.dp_Arg1 = parent_lock;
- sp->sp_Pkt.dp_Arg2 = CTOBPTR(bstr);
- sp->sp_Pkt.dp_Arg3 = ACCESS_READ;
-
- PutPacket(handler, sp);
- __wait_sync_packet(sp);
-
- no_error = sp->sp_Pkt.dp_Res1 > 0;
- }
- else
- if (! (*last_func)(sp, handler, parent_lock, CTOBPTR (bstr),
- last_arg, &no_error)) break;
-
- /* if no error, fine */
- if (no_error) break;
-
- /* else check whether ordinary error or really symlink */
- if (sp->sp_Pkt.dp_Res2 != ERROR_IS_SOFT_LINK) break;
-
- /* read the link. temporarily use our bstr as a cstr, thus setting
- * a terminating zero byte and skipping the length byte */
- bstr[*bstr + 1] = 0;
-
- sp->sp_Pkt.dp_Port = __srwport;
- sp->sp_Pkt.dp_Type = ACTION_READ_LINK;
- sp->sp_Pkt.dp_Arg1 = parent_lock;
- sp->sp_Pkt.dp_Arg2 = (long) (bstr + 1); /* read as cstr */
- sp->sp_Pkt.dp_Arg3 = (long) (bstr + 1); /* write as cstr, same place */
- sp->sp_Pkt.dp_Arg4 = 255; /* what a BSTR can address */
-
- PutPacket(handler, sp);
- __wait_sync_packet(sp);
-
- /* error (no matter which...) couldn't read the link */
- if (sp->sp_Pkt.dp_Res1 <= 0)
- {
- /* this is our error-"lock", so make sure it is really zero */
- sp->sp_Pkt.dp_Res1 = 0;
- break;
- }
-
- /* oky, new name. Set up as bstr and retry to lock it */
- *bstr = sp->sp_Pkt.dp_Res1;
-
- /* if the read name is absolute, we may have to change the
- * handler and the parent lock. Check for this */
- bstr[*bstr + 1] = 0;
-
- /* this isn't enabled by default, because it makes normal dos calls
- * fail miserably */
- if (ix.ix_translate_symlinks && unslashify (bstr + 1) < 0)
- {
- sp->sp_Pkt.dp_Res1 = 0;
- sp->sp_Pkt.dp_Res2 = ERROR_OBJECT_NOT_FOUND;
- break;
- }
-
- if (cp = index ((char *)bstr + 1, ':'))
- {
- if (unlock_parent)
- {
- sp->sp_Pkt.dp_Port = __srwport;
- sp->sp_Pkt.dp_Type = ACTION_FREE_LOCK;
- sp->sp_Pkt.dp_Arg1 = parent_lock;
-
- PutPacket(handler, sp);
- __wait_sync_packet(sp);
- }
-
- /* if this is ":foobar", then the handler stays the same, and the
- * parent_lock gets zero. Don't need get_device_proc() to find
- * this out ;-) */
- if (cp == (char *)bstr+1)
- parent_lock = 0;
- else
- /*
- * NOTE: Multiassigns are currently only supported as the first
- * part of a path name. I don't like the idea of setting up
- * another recursion level here just to parse them...
- *
- * This approach also makes symbolic links to non-fs devices
- * limited, which is bad. I'll HAVE to think something up
- * (so you can't for example have dev:tty -> con:0/0/640/100/tty)
- */
- handler = DeviceProc (bstr + 1); /* XXX fix !!! */
- parent_lock = IoErr ();
- unlock_parent = 0;
-
- if (! handler)
- {
- /* interesting bug.. long not noticed... */
-
- sp->sp_Pkt.dp_Res1 = 0;
- if (! strcasecmp (bstr + 1, "nil:"))
- sp->sp_Pkt.dp_Res2 = 4242;
- else
- sp->sp_Pkt.dp_Res2 = ERROR_OBJECT_NOT_FOUND;
- break;
- }
- }
-
- ++link_levels;
- }
- while (link_levels < MAXSYMLINKS);
-
- if (link_levels == MAXSYMLINKS)
- {
- result = 0;
- res_res2 = ERROR_TOO_MANY_LEVELS;
- }
- else
- {
- result = sp->sp_Pkt.dp_Res1;
- res_res2 = sp->sp_Pkt.dp_Res2;
- }
-
- if (unlock_parent)
- {
- sp->sp_Pkt.dp_Port = __srwport;
- sp->sp_Pkt.dp_Type = ACTION_FREE_LOCK;
- sp->sp_Pkt.dp_Arg1 = parent_lock;
-
- PutPacket(handler, sp);
- __wait_sync_packet(sp);
- }
- else
- unlock_parent = 1;
-
- parent_lock = result;
- name = next;
- }
- while (no_error && ! is_last);
-
- /* yes I know it's ugly ... */
- if (!no_error && res_res2 == ERROR_OBJECT_NOT_FOUND
- && dp && (dp->dvp_Flags & DVPF_ASSIGN))
- goto retry_multi_assign;
-
- do_return:
- free_device_proc (dp);
-
- /* set up Result2 so that the IoErr() works */
- ((struct Process *)FindTask (0))->pr_Result2 = res_res2;
-
- syscall (SYS_sigsetmask, omask);
-
- DP(("__plock: returning %ld, res2 = %ld.\n", result, res_res2));
-
- return result;
- }
-
- /*
- * this is somewhat similar to DeviceProc(), but with the difference that it's
- * strictly passive, it won't start the handler, if it doesn't exist. This is
- * vital to be able to deal with stubborn console handlers, that don't answer
- * packets until they're really open..
- * Returns:
- * HAN_UNDEF device doesn't exist
- * HAN_CLONE_DEV device exists, handler zero
- * HAN_FS_DEV device exists, handler non-zero
- * HAN_NOT_A_DEV exists, but is not a device
- */
-
- #define HAN_UNDEF 0
- #define HAN_CLONE_DEV 1
- #define HAN_FS_DEV 2
- #define HAN_NOT_A_DEV 3
-
- static int
- find_handler (char *bstr)
- {
- struct DosLibrary *dl;
- struct RootNode *rn;
- struct DosInfo *di;
- struct DevInfo *dv;
- extern struct ixemul_base *ixemulbase;
- int res = HAN_UNDEF;
-
- /* could probably use less drastic measures under 2.0... */
- Forbid ();
- dl = (struct DosLibrary *) ixemulbase->ix_dos_base;
- rn = (struct RootNode *) dl->dl_Root;
- di = BTOCPTR (rn->rn_Info);
- for (dv = BTOCPTR (di->di_DevInfo); dv; dv = BTOCPTR (dv->dvi_Next))
- {
- #if 0
- /* quite verbose output... */
- {
- char buf[255];
-
- bcopy (BTOCPTR (dv->dvi_Name)+1, buf, *(char *)BTOCPTR (dv->dvi_Name));
- buf[*(char *)BTOCPTR (dv->dvi_Name)] = 0;
- DP(("\t%s(%ld,$%lx)", buf, dv->dvi_Type, dv->dvi_Task));
- }
- #endif
-
- if (! strncasecmp (bstr, BTOCPTR (dv->dvi_Name), bstr[0]+1))
- {
- if (dv->dvi_Type == DLT_DEVICE)
- res = dv->dvi_Task ? HAN_FS_DEV : HAN_CLONE_DEV;
- else
- res = HAN_NOT_A_DEV;
- break;
- }
- }
- Permit ();
- /* DP(("\n")); */
- return res;
- }
-
- /*
- * feels very much like GetDeviceProc(), but works under 1.3 as well. Under
- * 2.0, we're using the dos-library GetDeviceProc(), under 1.3 that is
- * emulated with own structures.
- * is_fs is filled out with a best guess approach, since we can't use the
- * proper packet on a handler that isn't yet fully operating (as after just
- * calling DevProc)
- * if calling with prev!=0, is_fs is not touched.
- */
-
- static struct DevProc *
- get_device_proc (char *name, struct DevProc *prev, int *is_fs)
- {
- char *cp, *f;
- int len;
- struct DevProc *dp;
- int han = HAN_UNDEF;
-
- if (! prev)
- {
- /* have to prove the oposite */
- *is_fs = 1;
-
- cp = index (name, ':');
- if (cp && cp != name) /* ":..." has to be a filesystem */
- {
- len = cp - name;
- f = alloca (len + 1);
- f[0] = len;
- bcopy (name, f + 1, len);
-
- /* try to find it */
- han = find_handler (f);
-
- DP((" find_handler(%s) = %ld\n", name, han));
-
- /* this might be wrong, we'll know more after GetDeviceProc() */
- if (han == HAN_CLONE_DEV)
- *is_fs = 0;
- }
- }
- else
- if (! _dos20)
- {
- /* 1.3 doesn't support multiassigns, and this would be the only reason
- * to call here more than once. */
- kfree (prev);
- return 0;
- }
-
- if (_dos20)
- dp = GetDeviceProc (name, prev);
- else
- {
- dp = (struct DevProc *) kmalloc (sizeof (*dp));
- dp->dvp_Port = DeviceProc (name);
- dp->dvp_Lock = IoErr ();
- dp->dvp_Flags = 0; /* just don't set DVPF_ASSIGN ;-)) */
- dp->dvp_DevNode = 0; /* is private anyway */
- }
-
- /* second approach to verify, if a handler probably is a file system or not.
- * If the device is a filesystem, but didn't contain a volume before, then
- * the GetDeviceProc() call will have popped up the `please insert a disk'
- * requester. If the user obeyed, the handler will now exist. On the other
- * hand, if the device really is a clone device, it will still be one (ie. have
- * its task field zero), so check the device list again. */
-
- /* only for possible clone devices */
- if (han == HAN_CLONE_DEV)
- *is_fs = find_handler (f) != HAN_CLONE_DEV;
-
- return dp;
- }
-
- static void
- free_device_proc (struct DevProc *dp)
- {
- if (_dos20)
- FreeDeviceProc (dp);
- else
- kfree (dp);
- }
-
-
- static int
- unslashify (char *name)
- {
- char *oname = name;
-
- /* if we're here, make sure to return every attempt to use a colon inside
- * a filename as an error. I could at least imagine, that it would be
- * possible for the user to actually generate a file with colons in its
- * name, but he would probably not be able to get rid of it again... */
- if (index (name, ':'))
- return ix.ix_force_translation ? -1 : 0;
-
- while (oname[0] == '/' && oname[1] == '/')
- oname++;
-
- /* don't (!) use strcpy () here, this is an overlapping copy ! */
- if (oname > name)
- bcopy (oname, name, strlen (oname) + 1);
-
- /* This is marked as error, so that the user gets used to use `..' instead of
- * `/' to really mean `parent directory', *iff* he/she enabled ix slash
- * translation (this function is only called if slash translation is enabled) */
- if (name[0] == '/' && name[1] == 0)
- return ix.ix_force_translation ? -1 : 0;
-
- if (name[0] == '/')
- {
- /* get the delimiter */
- char *cp = index (name + 1, '/');
- int shift = 0;
-
- /* if there is a separating (and not terminating) slash, shift a bit ;-) */
- if (cp)
- while (*cp == '/')
- {
- shift ++;
- cp ++;
- }
-
- /* is it a terminator (then discard it) or a separator ? */
- if (! cp || !*cp)
- {
- /* terminator */
- cp = name + strlen (name);
- bcopy (name + 1, name, cp - name);
- cp[-1-shift] = ':';
- cp[-shift] = 0;
- }
- else
- {
- /* separator */
- bcopy (name + 1, name, strlen (name) + 1);
- cp --;
- bcopy (cp, cp - (shift - 1), strlen (cp) + 1);
- cp[-shift] = ':';
- }
- }
-
- return 0;
- }
- @
-
-
- 1.1
- log
- @Initial revision
- @
- text
- @d19 1
- a19 1
- * $Id$
- d21 4
- a24 1
- * $Log$
- a88 1
- #endif
- d128 1
- @
-