home *** CD-ROM | disk | FTP | other *** search
- /* lock.c - Lock-related stuff for the cfs file system.
- Copyright (C) 1991, 1992, 1993 Kristian Nielsen.
-
- This file is part of XFH, the compressing file system handler.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program 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 General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "CFS.h"
-
- #include <string.h>
-
- #include <dossupport.h>
-
-
- /*
- * RawCFSLock() is the low-lewel LOCATE_OBJECT function of the CFS file
- * system. It takes a simple filename (that is, no path specification),
- * a lock to the parent directory, and a 'mode' value as arguments. A
- * special case occurs for a null name, in which case it just returns
- * a copy of the passed lock.
- * NOTE: 'directory/' is a valid name iff it's a directory.
- */
-
- struct CFSLock *RawCFSLock(glb glob, struct CFSLock *lock,
- char * name, LONG mode ){
- LONG saveioerr;
-
- if( name && *name ){
-
- /* Here is the place to check whether the lock refers to a
- * directory in the underlying file system, or if it is in fact
- * a directory in an archieve. This code is for the former case: */
-
- if( lock->objtype == XOBJECT ){
- struct FileLock *xlock;
-
- if( !(xlock=xLock(glob,lock->xlock,name,mode)) ){
- debug(("Error: RawCFSLock(): Could not obtain lock: %ld.\n",glob->ioerr));
- return NULL;
- }
- if( !xExamine( glob, xlock, &glob->fib1 ) ){
- debug(("Error: RawCFSLock(): Cannot examine() object: %ld\n",glob->ioerr));
- saveioerr = glob->ioerr;
- xUnLock( glob, xlock );
- glob->ioerr = saveioerr;
- return NULL;
- }
- if( glob->fib1.fib_DirEntryType > 0 ){
- struct CFSLock *newlock;
-
- /* A directory. */
- newlock = XObjMakeLock(glob, xlock, mode);
- if( !newlock ){
- saveioerr = glob->ioerr;
- xUnLock(glob, xlock);
- glob->ioerr = saveioerr;
- }
- return newlock;
- }else{
- struct FileHandle *xfh;
- LONG filetype;
-
- /* A plain file. Determine its type. */
- /* First open the file. If the lock is to be exclusive, */
- /* we need to xUnLock() it while examining the file (BAD!) */
- /* This means that there's an ever so slight change that */
- /* the file will go away inbetween the xClose() and xLock(). */
- /* It might even have come back in a new disguise! sigh... */
-
- if( mode == EXCLUSIVE_LOCK ){
- debug(("RawCFSLock(): Temporarely UnLock()'ing...\n"));
- xUnLock(glob, xlock);
- xlock = NULL;
- xfh = xOpen( glob, lock->xlock, name, MODE_OLDFILE );
- }else{
- xfh = xOpenFromCopyOfLock( glob, xlock );
- }
- if( !xfh ){
- debug(("Error: RawCFSLock(): Cannot Open() file: %ld.\n",glob->ioerr));
- if( xlock ){
- saveioerr = glob->ioerr;
- xUnLock(glob, xlock);
- glob->ioerr = saveioerr;
- }
- return NULL;
- }
- filetype = xFileType(glob, xfh);
- xClose(glob, xfh);
- if(!xlock){
- if( !(xlock=xLock(glob,lock->xlock,name,mode)) ){
- debug(("Error: RawCFSLock(): Could not re-Lock() the file: %ld.\n",glob->ioerr));
- return NULL;
- }
- }
- /* ToDo: this shouldn't be implemented as an ugly switch(). */
- switch(filetype){
- case XOBJECT:{
- struct CFSLock *newlock;
-
- newlock = XObjMakeLock(glob, xlock, mode);
- if( !newlock ){
- saveioerr = glob->ioerr;
- xUnLock( glob, xlock );
- glob->ioerr = saveioerr;
- }
- return newlock;
- }
- case XPKOBJECT:{
- struct XpkLock *newlock;
-
- newlock = XpkMakeLock(glob, xlock, mode);
- if( !newlock ){
- saveioerr = glob->ioerr;
- xUnLock(glob, xlock);
- glob->ioerr = saveioerr;
- }
- return (struct CFSLock *)newlock;
- }
- default:
- debug(("ERROR: RawCFSLock(): unsupported file type %ld.\n",filetype));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return NULL;
- }
- }
- }else{
- debug(("** PANIC **: bad object type in lock: %ld\n",lock->objtype));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return NULL;
- }
- }else{
- /* A Null name was passed. If the parent lock is of the right type,
- * just DupLock() it. Otherwise, signal an error.
- * (Duplock() will catch the case of an exclusive lock).
- */
- if( mode == lock-> mode ){
- return CFSDupLock( glob, lock );
- }else{
- glob->ioerr = ERROR_OBJECT_IN_USE;
- return NULL;
- }
- }
- }
-
-
- /* And DOS said: let there be devices...
- * So hardwire a CFSLock to serve as our root lock.
- */
- struct CFSLock *makerootlockdayone(glb glob){
- return XObjMakeLock(glob, glob->xrootlock, ACCESS_READ);
- }
-
-
- /*
- * Create a struct FileLock around a CFSLock for returning to caller.
- */
- struct FileLock * CreateFileLock( glb glob, struct CFSLock *lock ){
- struct FileLock *xlock;
-
- if( !dalloc(xlock) ){
- OUTOFMEM;
- return NULL;
- }
-
- /* Place any linking of filelocks into a list here. */
- xlock -> fl_Key = (LONG) lock;
- xlock -> fl_Access = lock -> mode;
- xlock -> fl_Task = glob -> dosport;
- xlock -> fl_Volume = c2b(glob -> volnode);
-
- return xlock;
- }
-
-
-
- /*
- * This is the function that does all the main parsing of path strings.
- * It's purpose is to lock the parent directory of a file or dir, and
- * return a pointer to the actual filename. A special case occurs for
- * NULL filenames (either "" or "name:") - here the actual lock is
- * returned, and the name set to "".
- *
- * In case of an error, the name is set to "", and a NULL lock is returned.
- *
- * NOTE: This will fail to correctly handle a path like '...//' - it
- * will lock the directory and return a NULL name. This will present
- * a problem if someone tries to obtain an exclusive lock on such a path.
- */
-
- struct CFSLock *CFSLockParent( glb glob, struct CFSLock *parentlock,
- char **nameptr ){
- char *p,*q,*path,*name;
- struct CFSLock *lock,*childlock;
- int len;
-
-
- /* Watch out for a NULL name. */
- if(!*nameptr) *nameptr = "";
-
- /* Allocate a copy of the path so that we can modify it. */
- len = strlen(*nameptr);
- if( !(name = dosalloc( len+1 )) ){
- OUTOFMEM;
- *nameptr += len; /* Set to empty string. */
- return NULL;
- }
- strcpy( name, *nameptr);
-
- path = name;
-
- /* A NULL parent lock is equal to the rootlock. */
- if(!parentlock) parentlock = glob->rootlock;
-
- /* Now check for an absolute path, ie '...:...' */
- if( p=strchr(name,':') ){
-
- /* Got an absolute path. This is either an assign (or the device /
- * volume name, which is treated the same way), or a root
- * specification (like ':system/cli'). */
-
- if( p==name ){ /* get the root dir. */
- parentlock = glob->rootlock;
- }
- #ifndef NONSTRICT
- else{
- /* The assign/device/volume name was used by dos.library to
- * find our process id and the parent lock. It is of no use
- * to the handler.*/
-
- /* 'Assign' allows silly names like '1/2:', but some other
- * commands have trouble with this. Flag these names as invalid. */
-
- if( q=strchr(name,'/') ){
- if( q<p ){
- debug(("Error: silly device name '%s'/n",name));
- glob->ioerr = ERROR_INVALID_COMPONENT_NAME;
- dosfree( name );
- *nameptr += len;
- return NULL;
- }
- }
- }
- #endif
-
- path = p+1; /* Point past ':'. */
-
- #ifndef NONSTRICT
- /* Disallow more than one ':' char in name. */
- if( strchr(path,':') ){
- debug(("Error: multiple ':' char in name '%s'.\n",name));
- glob->ioerr = ERROR_INVALID_COMPONENT_NAME;
- dosfree( name);
- *nameptr += len;
- return NULL;
- }
- #endif
-
- }
-
- /* Now look through the path specification. */
-
- if( !(lock = CFSDupLock( glob, parentlock )) ){
- /* Couldn't DupLock the parent. Hence we must use a reference. */
- debug(("CFSLockParent(): Cannot DupLock() the passed parent dir: %ld - using reference.\n",glob->ioerr));
- XObjAddReferenceToLock(glob, parentlock);
- lock = parentlock;
- /* NOTE: We now have a dangerous double reference to the
- * lock. Notably, the lock will be CFSUnLock()'ed two
- * times.
- */
- }
-
- for(;;){
- p = path;
- if( !*p ) break; /* If p is the null string, then lock is ok now. */
- path = strchr( p, '/' );
- if( path ){
- *path++ = '\0';
- if( !*path && path != p+1 ){
- break; /* Last component is 'name/'. */
- }
- }else{
- break; /* Last component is 'name'. */
- }
-
- /* At this point, p holds a null-terminated path component. */
-
- childlock = p+1 == path ?
- CFSParentDir(glob,lock) :
- RawCFSLock(glob,lock,p,SHARED_LOCK);
- if( !childlock ){
- LONG saveioerr;
-
- /* Some kind of error happened while locking the path component.
- * Report this error back to caller. */
-
- saveioerr = glob->ioerr; /* Save I/O error code. */
- CFSUnLock( glob, lock);
- if( p+1 == path && !glob->ioerr) /* Attempt to use '/' past root */
- glob->ioerr = ERROR_OBJECT_NOT_FOUND;
- else
- glob->ioerr = saveioerr; /* Restore for IoErr(). */
- dosfree( name );
- *nameptr += len;
- return NULL;
- }
- CFSUnLock( glob, lock);
- lock=childlock;
-
- if( !CFSExamine(glob, childlock, &glob->fib1) ){
- /* Error examining component. */
-
- CFSUnLock(glob, lock);
- dosfree( name );
- *nameptr += len;
- return NULL;
- }
-
- if( glob->fib1.fib_DirEntryType < 0 ){
- /* this component in the path is not a directory, so return
- * an error. */
-
- debug(("Error: CFSLockParent(): Plain file used in path.\n"));
- CFSUnLock(glob, lock);
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- dosfree( name );
- *nameptr += len;
- return NULL;
- }
- }
-
- *nameptr += (p - name); /* Point to equivalent of *p in 'name'. */
- dosfree( name );
- return lock;
- }
-
-
- /*
- * This function handles the ACTION_LOCATE_OBJECT request.
- */
-
- struct CFSLock * CFSLock(glb glob,struct CFSLock * parentlock,
- char * name,LONG mode){
- struct CFSLock *lock,*parent;
- LONG ioerrsave;
-
- /* Lock the parent directory, and set 'name' to point to the actual
- * name. For a path like 'name:', lock the file/dir and point name to
- * "" (RawCFSLock() will handle this case).
- */
- if(!(parent = CFSLockParent(glob, parentlock, &name ))){
- return NULL;
- }
- debug(("CFSLock: parent=%lx, name='%s'\n",parent,name));
- /* Now Lock the file or dir. */
- lock = RawCFSLock( glob, parent, name, mode );
- ioerrsave = glob->ioerr;
- CFSUnLock( glob, parent );
- glob->ioerr = ioerrsave;
- return lock;
- }
-
-
- struct CFSLock *CFSDupLock( glb glob, struct CFSLock *lock ){
-
- if( !lock ) return 0L;
- return (*lock->f->DupLock) (glob,lock);
- }
-
-
- struct CFSLock *CFSParentDir( glb glob, struct CFSLock *lock){
-
- if( !lock ) return NULL;
- else if(!lock->f){
- debug(("** PANIC **: CFSParentDir(): NULL action function.\n"));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }else return (*lock->f->Parent)(glob, lock);
- }
-
-
- struct CFSLock *CFSParentFH( glb glob, struct CFSFH *fh){
-
- if( !fh ) return NULL;
- else if(!fh->f){
- debug(("** PANIC **: CFSParentDir(): NULL action function.\n"));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }else return (*fh->f->ParentOfFH)(glob, fh);
- }
-
-
- BOOL CFSUnLock( glb glob,struct CFSLock *lock){
-
- if( !lock ) return 0L; /* No really sensible error possible. */
- else if(!lock->f){
- debug(("** PANIC **: CFSUnLock(): NULL action function.\n"));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }else return (*lock->f->UnLock)(glob, lock);
- }
-
-
- BOOL CFSExamine(glb glob, struct CFSLock *lock, struct FileInfoBlock *fib){
-
- if( !lock ){
- return DOSFALSE; /* No really sensible error possible. */
- }else if( lock->f ){
- return (*lock->f->Examine)( glob, lock, fib );
- } else {
- debug(("** PANIC **: NULL object action func Examine() in lock.\n"));
- return DOSFALSE;
- }
- }
-
-
- BOOL CFSExamineNext(glb glob, struct CFSLock *lock, struct FileInfoBlock *fib){
-
- if( !lock ){
- return DOSFALSE; /* No really sensible error possible. */
- }else if( lock->f ){
- return (*lock->f->ExNext)( glob, lock, fib );
- } else {
- debug(("** PANIC **: NULL object action func ExNext() in lock.\n"));
- return DOSFALSE;
- }
- }
-
-
- struct CFSLock *CFSCreateDir( glb glob, struct CFSLock *parent, char *name ){
- struct CFSLock *lock;
-
- /* Lock the parent directory, and set 'name' to point to the actual
- * name. For a path like 'name:', lock the file/dir and point name to
- * "" (RawCFSLock() will handle this case).
- */
- if(!(parent = CFSLockParent(glob, parent, &name ))){
- return NULL;
- }else if( parent->f ){
- LONG saveioerr;
-
- lock = (*parent->f->CreateDir)( glob, parent, name );
- if( !lock ) saveioerr = glob->ioerr;
- CFSUnLock( glob, parent );
- if( !lock ) glob->ioerr = saveioerr;
- return lock;
- }else{
- debug(("** PANIC **: NULL object action func CreateDir() in lock.\n"));
- CFSUnLock( glob, parent );
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return NULL;
- }
- }
-
-
- /* CFSDeleteFile(): Delete a file or directory.
- *
- * Just passes control to the appropriate lock-specific call.
- * NOTE: It's up to the lock-specific functions to check that an attempt
- * to delete a non-empty directory is rejected.
- */
- BOOL CFSDeleteFile( glb glob, struct CFSLock *parent, char *name ){
-
- if(!(parent = CFSLockParent(glob, parent, &name ))){
- return DOSFALSE;
- }else if( parent->f ){
- LONG saveioerr;
- BOOL err;
-
- err = (*parent->f->DeleteFile)( glob, parent, name );
- if( !err ) saveioerr = glob->ioerr;
- CFSUnLock( glob, parent );
- if( !err ) glob->ioerr = saveioerr;
- return err;
- }else{
- debug(("** PANIC **: NULL object action func DeleteFile() in lock.\n"));
- CFSUnLock( glob, parent );
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }
- }
-
-
- /* CfsRename(): Rename files within the file system.
- *
- * A problem arises if someone tries to rename between two directory-
- * locks of different types (ie. a lharc-archieve and an UFS directory).
- * This function passes control to the FROM-locktype rename function. It's
- * up to this function to check the type of the destination directory
- * and take an appropriate action.
- */
- BOOL CFSRename( glb glob, struct CFSLock *parent1, char *name1, struct CFSLock *parent2, char *name2 ){
-
- if(!(parent1 = CFSLockParent(glob, parent1, &name1 ))){
- return DOSFALSE;
- }
- if(!(parent2 = CFSLockParent(glob, parent2, &name2 ))){
- LONG saveioerr = glob->ioerr;
- CFSUnLock( glob, parent1 );
- glob->ioerr = saveioerr;
- return DOSFALSE;
- }
-
- if( parent1->f ){
- LONG saveioerr;
- BOOL err;
-
- err = (*parent1->f->Rename)( glob, parent1, name1, parent2, name2 );
- if( !err ) saveioerr = glob->ioerr;
- CFSUnLock( glob, parent1 );
- CFSUnLock( glob, parent2 );
- if( !err ) glob->ioerr = saveioerr;
- return err;
- }else{
- debug(("** PANIC **: NULL object action func Rename() in lock.\n"));
- CFSUnLock( glob, parent1 );
- CFSUnLock( glob, parent2 );
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }
- }
-
-
- BOOL CFSSetProtection( glb glob, struct CFSLock *parent, char *name, LONG bits ){
-
- if(!(parent = CFSLockParent(glob, parent, &name ))){
- return DOSFALSE;
- }else if( parent->f ){
- LONG saveioerr;
- BOOL err;
-
- err = (*parent->f->SetProtection)( glob, parent, name, bits );
- if( !err ) saveioerr = glob->ioerr;
- CFSUnLock( glob, parent );
- if( !err ) glob->ioerr = saveioerr;
- return err;
- }else{
- debug(("** PANIC **: NULL object action func SetProtection() in lock.\n"));
- CFSUnLock( glob, parent );
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }
- }
-
-
- BOOL CFSSetComment( glb glob, struct CFSLock *parent, char *name, char *comment ){
-
- if(!(parent = CFSLockParent(glob, parent, &name ))){
- return DOSFALSE;
- }else if( parent->f ){
- LONG saveioerr;
- BOOL err;
-
- err = (*parent->f->SetComment)( glob, parent, name, comment );
- if( !err ) saveioerr = glob->ioerr;
- CFSUnLock( glob, parent );
- if( !err ) glob->ioerr = saveioerr;
- return err;
- }else{
- debug(("** PANIC **: NULL object action func SetComment() in lock.\n"));
- CFSUnLock( glob, parent );
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }
- }
-
-
- BOOL CFSSetDate( glb glob, struct CFSLock *parent, char *name, struct DateStamp *ds ){
-
- if(!(parent = CFSLockParent(glob, parent, &name ))){
- return DOSFALSE;
- }else if( parent->f ){
- LONG saveioerr;
- BOOL err;
-
- err = (*parent->f->SetFileDate)( glob, parent, name, ds );
- if( !err ) saveioerr = glob->ioerr;
- CFSUnLock( glob, parent );
- if( !err ) glob->ioerr = saveioerr;
- return err;
- }else{
- debug(("** PANIC **: NULL object action func SetDate() in lock.\n"));
- CFSUnLock( glob, parent );
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return DOSFALSE;
- }
- }
-
-
- BOOL CFSSameLock( glb glob, struct CFSLock *l1, struct CFSLock *l2 ){
- if(!l1 || !l2) return (BOOL) (l1==l2 ? TRUE : FALSE);
- if( l1->objtype != l2->objtype ) return FALSE;
- if( !l1->f ){
- debug(("** PANIC **: CFSSameLock(): Bad action func in lock.\n"));
- glob->ioerr = ERROR_OBJECT_WRONG_TYPE;
- return FALSE;
- }else return (*l1->f->SameLock)(glob, l1, l2);
- }
-
-
- /* End of lock.c */
-