home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-05 | 9.2 KB | 415 lines | [TEXT/CWIE] |
- /*********************************************************************
- Project : GUSI - Grand Unified Socket Interface
- File : GUSIFileDispatch.cp - Dispatch calls to their correct recipient
- Author : Matthias Neeracher
- Language : MPW C/C++
-
- $Log: GUSIFileDispatch.cp,v $
- Revision 1.1 1994/12/30 19:59:55 neeri
- Initial revision
-
- *********************************************************************/
-
- #include "GUSIFile_P.h"
- #include "GUSIMPW_P.h"
- #include <Errors.h>
- #include <utime.h>
-
- #if GENERATINGCFM
- #include <FragLoad.h>
- #endif
-
- #pragma segment GUSI
-
- /************************ External routines *************************/
-
- int open(const char * filename, int oflag)
- {
- Sockets.InitConsole();
-
- Socket * sock;
- int fd;
- GUSIFileRef ref(filename, FileSocketDomain::willOpen);
-
- if (ref.Domain()) {
- errno = 0;
-
- if (sock = ref.Domain()->open(ref, oflag))
- if ((fd = Sockets.Install(sock)) != -1)
- return fd;
- else
- delete sock;
-
- if (!errno)
- return GUSI_error(ENOMEM);
- else
- return -1;
- } else
- return GUSI_error(EINVAL);
- }
-
- int creat(const char* filename)
- {
- return open(filename, O_WRONLY | O_TRUNC | O_CREAT);
- }
-
- int remove(const char *filename)
- {
- GUSIFileRef ref(filename, FileSocketDomain::willRemove, true);
-
- if (ref.Domain())
- return ref.Domain()->remove(ref);
- else
- return GUSI_error(EINVAL);
- }
-
- int unlink(char* filename)
- {
- GUSIFileRef ref(filename, FileSocketDomain::willRemove, true);
-
- if (ref.Domain())
- return ref.Domain()->remove(ref);
- else
- return GUSI_error(EINVAL);
- }
-
- int rename(const char *oldname, const char *newname)
- {
- GUSIFileRef ref(oldname, FileSocketDomain::willRename, true);
-
- if (ref.Domain())
- return ref.Domain()->rename(ref, newname);
- else
- return GUSI_error(EINVAL);
- }
-
- void fsetfileinfo(char *filename, unsigned long newcreator, unsigned long newtype)
- {
- GUSIFileRef ref(filename, FileSocketDomain::willSetFileInfo);
-
- if (ref.Domain())
- ref.Domain()->fsetfileinfo(ref, newcreator, newtype);
- else
- GUSI_error(EINVAL);
- }
-
- void fgetfileinfo(char *filename, unsigned long * creator, unsigned long * type)
- {
- GUSIFileRef ref(filename, FileSocketDomain::willGetFileInfo);
-
- if (ref.Domain())
- ref.Domain()->fgetfileinfo(ref, creator, type);
- else
- GUSI_error(EINVAL);
- }
-
- int faccess(char* filename, unsigned int cmd, long* arg)
- {
- GUSIFileRef ref(filename, FileSocketDomain::willFAccess);
-
- if (ref.Domain())
- return ref.Domain()->faccess(ref, cmd, arg);
- else
- return GUSI_error(EINVAL);
- }
-
- int truncate(const char* filename, off_t offset)
- {
- int res;
- int fd = open(filename, O_RDWR);
-
- if (fd == -1)
- return -1;
-
- res = ftruncate(fd, offset);
-
- close(fd);
-
- return res;
- }
-
- int stat(const char * path, struct stat * buf)
- {
- GUSIFileRef ref(path, FileSocketDomain::willStat);
-
- if (ref.Domain())
- return ref.Domain()->stat(ref, buf);
- else
- return GUSI_error(EINVAL);
- }
-
- int lstat(const char * path, struct stat * buf)
- {
- GUSIFileRef ref(path, FileSocketDomain::willStat, true);
-
- if (ref.Domain())
- return ref.Domain()->stat(ref, buf);
- else
- return GUSI_error(EINVAL);
- }
-
- int chmod(const char * filename, mode_t mode)
- {
- GUSIFileRef ref(filename, FileSocketDomain::willChmod);
-
- if (ref.Domain())
- return ref.Domain()->chmod(ref, mode);
- else
- return GUSI_error(EINVAL);
- }
-
- int utime(const char * path, const struct utimbuf * times)
- {
- GUSIFileRef ref(path, FileSocketDomain::willUTime);
-
- if (ref.Domain())
- return ref.Domain()->utime(ref, times);
- else
- return GUSI_error(EINVAL);
- }
-
- int access(const char * path, int mode)
- {
- GUSIFileRef ref(path, FileSocketDomain::willAccess);
-
- if (ref.Domain())
- return ref.Domain()->access(ref, mode);
- else
- return GUSI_error(EINVAL);
- }
-
- /************************ class GUSIFileRef *************************/
-
- #ifndef GUSI_DISPATCH
-
- // Identifying a name starting with dev: as a file or a device is
- // a dangerous job. Currently, there is no possibility to entirely
- // disable device interpretation, so we're using the following
- // heuristics in order to minimize conflicts with real file names:
- // - Any name corresponding to an existing file is a file
- // - Any name not recognized by any device domain is a file
-
- GUSIFileRef::GUSIFileRef(const char * name, FileSocketDomain::Request request, Boolean useAlias)
- : hasInfo(false), name(name), file(name, useAlias)
- {
- if (!::IsDevice(name) || (!file.Error() && file.Exists()))
- goto isFile;
-
- spec = nil;
- domain = FileSocketDomain::FindDomain(*this, request);
-
- if (!domain)
- goto isFile;
-
- error = noErr;
-
- return;
-
- isFile:
- spec = &file;
- error = file.Error();
- domain= FileSocketDomain::FindDomain(*this, request);
- }
-
- GUSIFileRef::GUSIFileRef(short fRefNum, FileSocketDomain::Request request)
- : hasInfo(false), name(nil), file(fRefNum)
- {
- spec = &file;
- error = file.Error();
- domain= FileSocketDomain::FindDomain(*this, request);
- }
-
- const CInfoPBRec * GUSIFileRef::Info() const
- {
- if (!hasInfo) {
- if (!spec) {
- ((GUSIFileRef *) this)->error = paramErr;
-
- return nil;
- }
- if (((GUSIFileRef *) this)->error = file.CatInfo(((GUSIFileRef *) this)->info))
- return nil;
-
- ((GUSIFileRef *) this)->hasInfo = true;
- }
-
- return &info;
- }
-
- /************************ class FileSocketDomain *************************/
-
- // Only the domain management part is found here. For the file specific part,
- // see GUSIFile.cp
-
- FileSocketDomain * FileSocketDomain::firstDeviceDomain = nil;
- FileSocketDomain * FileSocketDomain::lastDeviceDomain = nil;
- FileSocketDomain * FileSocketDomain::firstFileDomain = nil;
- FileSocketDomain * FileSocketDomain::lastFileDomain = nil;
-
- void Enqueue(
- FileSocketDomain * current,
- FileSocketDomain * FileSocketDomain::* next,
- FileSocketDomain ** first,
- FileSocketDomain ** last)
- {
- current->*next = FileSockets;
-
- if (*last)
- (*last)->*next = current;
- else
- *first = current;
-
- *last = current;
- }
-
- void Dequeue(
- FileSocketDomain * current,
- FileSocketDomain * FileSocketDomain::* next,
- FileSocketDomain ** first,
- FileSocketDomain ** last)
- {
- FileSocketDomain * pred = nil;
-
- if (!*first)
- return;
-
- if (*first == current)
- *first = current->*next;
- else {
- for (pred = *first; pred->*next && pred->*next != current;)
- pred = pred->*next;
- if (pred->*next == current)
- pred->*next = current->*next;
- else
- return;
- }
-
- if (*last == current)
- *last = pred;
- }
-
- static Boolean HandleFileDispatch = true;
- static FileSocketDomain * NullSockets;
-
- FileSocketDomain::FileSocketDomain(
- int domain,
- Boolean doesDevices,
- Boolean doesFiles)
- : SocketDomain(domain)
- {
- if (!FileSockets && HandleFileDispatch) {
- FileSockets = new FileSocketDomain;
- NullSockets = new NullSocketDomain;
- }
-
- if (doesDevices)
- Enqueue(
- this,
- &FileSocketDomain::nextDeviceDomain, &firstDeviceDomain, &lastDeviceDomain);
- if (doesFiles)
- Enqueue(
- this,
- &FileSocketDomain::nextFileDomain, &firstFileDomain, &lastFileDomain);
- }
-
- FileSocketDomain::~FileSocketDomain()
- {
- if (this == FileSockets) {
- FileSockets = nil;
- HandleFileDispatch = false;
- }
-
- Dequeue(
- this,
- &FileSocketDomain::nextDeviceDomain, &firstDeviceDomain, &lastDeviceDomain);
- Dequeue(
- this,
- &FileSocketDomain::nextFileDomain, &firstFileDomain, &lastFileDomain);
- }
-
- FileSocketDomain * FileSocketDomain::FindDomain(
- const GUSIFileRef & ref, Request request)
- {
- FileSocketDomain * dom;
- FileSocketDomain * FileSocketDomain::* next;
-
- // We are already decomposing
-
- if (!FileSockets)
- if (!HandleFileDispatch)
- return nil;
- else
- FileSockets = new FileSocketDomain;
-
- if (ref.IsDevice()) {
- dom = firstDeviceDomain;
- next = &FileSocketDomain::nextDeviceDomain;
- } else {
- dom = firstFileDomain;
- next = &FileSocketDomain::nextFileDomain;
- }
-
- // FileSockets will handle *everything*, therefore loop guaranteed to terminate
-
- while (dom && !dom->Yours(ref, request))
- dom = dom->*next;
-
- return dom;
- }
-
- // Quod licet Jovi non licet bovi
-
- FileSocketDomain::FileSocketDomain()
- : SocketDomain(AF_FILE)
- {
- firstFileDomain = firstDeviceDomain = this;
- nextFileDomain = nextDeviceDomain = nil;
- }
-
- Boolean FileSocketDomain::Yours(const GUSIFileRef & ref, Request req)
- {
- // We handle all plain files and willOpen/willStat for the console
- if (!ref.IsDevice())
- return true;
- else if (req != willOpen && req != willStat)
- return false;
-
- switch (ref.name[4] | 0x20) {
- case 's':
- if ((ref.name[5] | 0x20) != 't' || (ref.name[6] | 0x20) != 'd')
- return false;
- switch (ref.name[7] | 0x20) {
- case 'i':
- if ((ref.name[8] | 0x20) != 'n' || ref.name[9])
- return false;
- return true;
- case 'o':
- if ((ref.name[8] | 0x20) != 'u' || (ref.name[9] | 0x20) != 't' || ref.name[10])
- return false;
- return true;
- case 'e':
- if ((ref.name[8] | 0x20) != 'r' || (ref.name[9] | 0x20) != 'r' || ref.name[10])
- return false;
- return true;
- default:
- return false;
- }
- case 'c':
- if ( (ref.name[5] | 0x20) != 'o' || (ref.name[6] | 0x20) != 'n'
- || (ref.name[7] | 0x20) != 's' || (ref.name[8] | 0x20) != 'o'
- || (ref.name[9] | 0x20) != 'l' || (ref.name[10] | 0x20) != 'e'
- || ref.name[11])
- return false;
- return true;
- case 'n':
- if ( (ref.name[5] | 0x20) != 'u' || (ref.name[6] | 0x20) != 'l'
- || (ref.name[7] | 0x20) != 'l' || ref.name[8])
- return false;
- return true;
- default:
- return false;
- }
- }
-
- #endif // GUSI_DISPATCH
-