home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * This module handles emulation of Macintosh FSSpecs by maintaining
- * a list of referenced volumes and directories to handle the
- * conversion of full paths to FSSpecs and vice versa.
- *
- * This implementation uses a simple linear counter to generate vRefNums
- * and dirIDs. The directory structure as referenced by the running
- * program is stored as a tree so that for any FSSpec, a trace back
- * through the parID fields will step up this tree to the root.
- *
- * As on the Mac, the root of a volume has parID==2, and the root of the
- * filesystem has parID==1.
- */
-
- #include <stdlib.h>
- #include <string.h>
- #include <stdio.h>
- #include <assert.h>
-
- #include <MacTypes.h>
- #include <Files.h>
-
- #include "OSLib.h"
- #include "StringUtils.h"
- //#include "MacSpecs.h"
-
- #undef DEBUG
-
- #if !defined(MAC_FS)
- #ifdef DEBUG
- static unsigned long memused;
- #define MEMUSED(x) memused+=x
- #else
- #define MEMUSED(x)
- #endif
-
- //static int MacEmulInitialized=0;
-
-
- struct DirNode
- {
- char *name; /* name of directory part */
- unsigned dirID; /* of this directory, as seen by apps */
- union {
- struct DirNode *parent; /* of this directory */
- struct VolNode *volume; /* of this root directory [dirID==2] */
- } p;
- struct DirNode *list; /* list of contained directories */
- struct DirNode *next; /* next directory in parent's list */
- };
-
- struct VolNode
- {
- unsigned short vRefNum; /* number */
- struct DirNode root; /* of volume */
- struct VolNode *next; /* next volume in list */
- };
-
- typedef struct DirNode DirNode;
- typedef struct VolNode VolNode;
-
- static VolNode *vols;
-
- /* The dirID is allocated as-they-come, no matter which
- volume is being referenced.
- */
- static unsigned lastDirID = 3; /* last directory ID; starts at 3 */
- static unsigned lastVolRef = 2; /* last volume ref; starts at 2 */
-
- /* Support for 65536 directories */
- #define MAXDIRMAPROWS 256
- #define DIRMAPROWSIZE 256 /* 256 entries allocated at a time */
- static DirNode **dirIDMap[MAXDIRMAPROWS];
- /* map of maps of dirIDs to DirNodes */
- static unsigned dirMapRows; /* # of allocated rows */
-
- /* Add a reference for a new dirID. */
-
- static int AddDirMapEntry(DirNode *node)
- {
- unsigned row = node->dirID / DIRMAPROWSIZE;
- unsigned col = node->dirID % DIRMAPROWSIZE;
-
- while (row >= dirMapRows)
- {
- if (row >= 256)
- {
- fprintf(stderr, "Fatal error: too many directories referenced, out of memory\n");
- return 0;
- }
-
- dirIDMap[row] = (DirNode **) calloc(sizeof(DirNode *), DIRMAPROWSIZE);
- if (dirIDMap[row] == NULL) return 0;
-
- MEMUSED(sizeof(DirNode *) * DIRMAPROWSIZE);
-
- dirMapRows++;
- }
-
- dirIDMap[row][col] = node;
- return 1;
- }
-
-
- /* Add a volume node in 'list' if necessary;
- return new reference or found reference.
- */
-
- static VolNode *FindOrAddVolRef(VolNode **list, const char *name)
- {
- int sz;
- VolNode *vn;
-
- while (*list != NULL)
- {
- if (OS_EqualPath(name, (*list)->root.name))
- return *list;
- else
- list = &((*list)->next);
- }
-
- /* Cannot support more */
-
- if (lastVolRef >= 256)
- return NULL;
-
- #ifdef DEBUG
- printf("FindOrAddVolRef: adding ref for '%s'\n", name);
- #endif
-
- vn = (VolNode *) malloc(sizeof(VolNode));
- if (vn==NULL) return NULL;
- MEMUSED(sizeof(VolNode));
-
- vn->next = NULL;
- vn->vRefNum = lastVolRef++;
-
- /* Initialize root */
-
- sz = strlen(name)+1;
- vn->root.name = (char *) malloc(sz);
- if (vn->root.name==NULL) return NULL;
- MEMUSED(sz);
- strcpy(vn->root.name, name);
-
- vn->root.dirID = 2;
- vn->root.p.volume = vn;
- vn->root.list = NULL;
- vn->root.next = NULL;
-
- *list = vn; /* add to parent's list */
-
- return vn;
- }
-
-
- /* Look up the DirNode for a given dirID */
-
- static DirNode *FindDirMapEntry(unsigned dirID)
- {
- unsigned row = dirID / DIRMAPROWSIZE;
- unsigned col = dirID % DIRMAPROWSIZE;
-
- assert(dirID != 2);
- if (row >= dirMapRows)
- return NULL; /* illegal */
- else
- return dirIDMap[row][col];
- }
-
-
- /* Add a directory node in 'list' if necessary;
- return new reference or found reference.
-
- For a volume, do the same, except use a different parID.
- */
-
- static DirNode *FindOrAddDirRef(DirNode *parent, const char *name)
- {
- int sz;
- DirNode *dn,**list;
-
- list = &parent->list;
-
- while (*list != NULL)
- {
- if (OS_EqualPath(name, (*list)->name))
- return *list;
- else
- list = &((*list)->next);
- }
-
- /* Cannot support more */
-
- if (lastDirID >= 65536)
- return NULL;
-
- #ifdef DEBUG
- printf("FindOrAddDirRef: adding ref for '%s' [parent '%s']\n",
- name, parent==NULL ? "<none>" : parent->name);
- #endif
-
- /* Make node */
-
- sz = strlen(name)+1;
-
- dn = (DirNode *) malloc(sizeof(DirNode));
- if (dn==NULL) return NULL;
- MEMUSED(sizeof(DirNode));
-
- dn->name = (char *) malloc(sz);
- if (dn->name==NULL) return NULL;
- MEMUSED(sz);
-
- strcpy(dn->name, name);
- dn->list = NULL;
- dn->next = NULL;
-
- dn->dirID = lastDirID++;
-
- if (!AddDirMapEntry(dn))
- return 0;
-
- dn->p.parent = parent;
-
- *list = dn; /* add to parent's list */
-
- return dn;
- }
-
- static int FindOrAdd(const OSPathSpec *path,
- unsigned *vRefNum, unsigned *dirID)
- {
- VolNode *vol;
- DirNode *level;
- char pb[OS_PATHSIZE],voln[OS_VOLSIZE];
- char pathbuf[OS_PATHSIZE];
- char *ptr;
-
- #if defined(WIN32_FS) || defined(POSIX_FS)
- strncpy(pathbuf, path->s, OS_PATHSIZE-1);
- pathbuf[OS_PATHSIZE-1] = 0;
- #else
- if (OS_PathSpecToString(path, pathbuf, OS_PATHSIZE) == NULL)
- return 0;
- #endif
-
- ptr = (char *)OS_GetDirPtr(pathbuf);
- strncpy(voln, pathbuf, ptr-pathbuf);
- voln[ptr-pathbuf] = 0;
- strcpy(pb, ptr);
-
- vol = FindOrAddVolRef(&vols, voln);
- if (vol==NULL) return 0;
-
- *vRefNum = vol->vRefNum;
-
- level = &vol->root;
-
- /* We expect the path to be a full path, which on all current
- non-Mac systems start with OS_PATHSEP. We can't add a blank
- directory as the root, since, given a blank volume, we may
- have "" + OS_PATHSEP + "" + OS_PATHSEP + "dir" which would be
- a network reference on some systems.
- */
- ptr=pb+1;
- assert(*pb == OS_PATHSEP);
-
- while (*ptr)
- {
- const char *st;
-
- st=ptr;
- while (*ptr && *ptr != OS_PATHSEP) ptr++;
-
- *ptr=0;
- level = FindOrAddDirRef(level, st);
- ptr++;
-
- if (level==NULL) return 0;
- }
-
- *dirID = level->dirID;
-
- return 1;
- }
-
-
- /* Look up a vRefNum/dirID pair. */
- static void StepVolDir(unsigned *vRefNum, unsigned *dirID,
- DirNode **node)
- {
- if (*vRefNum == 1)
- {
- *node = NULL;
- }
- else
- {
- if (*dirID == 2)
- {
- VolNode *step;
-
- step = vols;
- while (step && step->vRefNum != *vRefNum)
- step = step->next;
-
- if (step != NULL)
- {
- *node = &step->root;
- *vRefNum = 1;
- *dirID = 1;
- }
- else
- *node = NULL;
- }
- else
- {
- *node = FindDirMapEntry(*dirID);
- if (*node)
- *dirID = (*node)->p.parent->dirID;
-
- }
- }
- }
-
- /* Resolve a path to a vRefNum/dirID. */
- static int ResolvePath(const OSPathSpec *path,
- unsigned *vRefNum, unsigned *dirID)
- {
- // meaningless
- #if 0
- OSSpec full;
-
- /* See if the path exists */
- full.path = *path;
- OS_MakeNameSpec("", &full.name);
- if (OS_Status(&full) != OS_NOERR)
- return 0;
- #endif
-
- if (FindOrAdd(path, vRefNum, dirID))
- {
- *vRefNum = - (*vRefNum);
- #ifdef DEBUG
- printf("ResolvePath: Found ref for '%s' (%d,%d)\n",
- OS_PathSpecToString(path,NULL), *vRefNum, *dirID);
- #endif
- return 1;
- }
- else
- {
- *vRefNum = 0;
- *dirID = 0;
- #ifdef DEBUG
- printf("ResolvePath: could not find '%s' or add it!\n",
- OS_PathSpecToString(path,NULL));
- #endif
- return 0;
- }
- }
-
- /* Resolve vRefNum/dirID to a vol and dir string */
- static int ResolveVolDir(unsigned vRefNum, unsigned dirID,
- char *vol, char *dir)
- {
- DirNode *nodes[256];
- DirNode *cur;
- int idx;
- char *dptr;
-
- vRefNum = -vRefNum;
-
- idx=0;
- do
- {
- StepVolDir(&vRefNum, &dirID, &cur);
- if (cur!=NULL)
- nodes[idx++] = cur;
- } while (cur!=NULL);
-
- if (idx)
- strcpy(vol, nodes[--idx]->name);
- else
- {
- *vol = 0; // totally invalid!
- *dir = 0;
- return 0;
- }
-
- dptr=dir;
- *dptr++ = OS_PATHSEP;
- while (idx--)
- {
- strcpy(dptr, nodes[idx]->name);
- dptr+=strlen(dptr);
- *dptr++ = OS_PATHSEP;
- }
- *dptr=0;
-
- return 1;
- }
-
- /*********************************************************************/
-
- #if 0
- #pragma mark -
- #endif
-
-
- static char stvol[OS_VOLSIZE], stdir[OS_PATHSIZE];
- static char stpath[OS_PATHSIZE];
- static char stname[(OS_NAMESIZE < 256 ? 256 : OS_NAMESIZE)];
-
- /*
- Translate an OSPathSpec into the volume and directory for an FSSpec.
- */
- _DLL _PAS OSError
- OS_OSPathSpec_To_VolDir(const OSPathSpec *spec, short *vRefNum, long *dirID)
- {
- unsigned vol, dir;
- if (ResolvePath(spec, &vol, &dir))
- {
- *vRefNum = vol;
- *dirID = dir;
- return OS_NOERR;
- }
- else
- {
- *vRefNum = 0;
- *dirID = 0;
- return OS_DNFERR;
- }
- }
-
- _DLL _PAS OSError
- OS_OSSpec_To_FSSpec(const OSSpec *spec, FSSpec *fss)
- {
- OSError err;
- short vRefNum;
- long dirID;
- int len;
-
- err = OS_OSPathSpec_To_VolDir(&spec->path, &vRefNum, &dirID);
-
- fss->vRefNum = vRefNum;
- fss->parID = dirID;
-
- if (err != OS_NOERR)
- return err;
-
- // optimize
- #if defined(POSIX_FS) || defined(WIN32_FS)
-
- len = strlen(spec->name.s);
- if (len >= sizeof(fss->name))
- return OS_FNTLERR;
- c2pstrcpy(fss->name, spec->name.s);
-
- #else
-
- OS_NameSpecToString2(&spec->name, stname);
-
- /* Enforce Mac-style limits */
- if (strlen(stname) > sizeof(fss->name))
- return OS_FNTLERR;
-
- c2pstrcpy(fss->name, stname);
- #endif
-
- return OS_NOERR;
- }
-
- /*
- Translate the volume and directory from an FSSpec into an OSNameSpec.
- (same as OS_VolDir_To_OSPathSpec but only goes one level)
- */
- _DLL _PAS OSError
- OS_VolDir_To_OSNameSpec(short vRefNum, long dirID, OSNameSpec *spec, long *parID)
- {
- unsigned int cv,cd;
- DirNode *node;
-
- cv = -vRefNum;
- cd = dirID;
- StepVolDir(&cv, &cd, &node);
- if (node == NULL)
- return OS_DNFERR;
- else
- {
- *parID = cd;
- #if defined(POSIX_FS) || defined(WIN32_FS)
- strcpy(spec->s, node->name);
- return OS_NOERR;
- #else
- return OS_MakeNameSpec(node->name, spec);
- #endif
- }
- }
-
- /*
- Translate the volume and directory from an FSSpec into an OSPathSpec.
- */
- _DLL _PAS OSError
- OS_VolDir_To_OSPathSpec(short vRefNum, long dirID, OSPathSpec *spec)
- {
- OSError err;
-
- /* CWD-local path? */
- if (vRefNum==0 || dirID==0)
- {
- if ((err = OS_GetCWD(spec)) != OS_NOERR)
- return err;
- }
- else
- {
- if (!ResolveVolDir(vRefNum, dirID, stvol, stdir))
- return OS_DNFERR;
-
- #if defined(POSIX_FS) || defined(WIN32_FS)
- {
- int vlen = strlen(stvol);
- int dlen = strlen(stdir);
- if (vlen + dlen < OS_PATHSIZE)
- {
- memcpy(spec->s, stvol, vlen);
- memcpy(spec->s + vlen, stdir, dlen + 1);
- }
- }
- #else
- if ((err = OS_MakePathSpec(stvol, stdir, spec)) != OS_NOERR)
- return err;
- #endif
- }
-
- return OS_NOERR;
- }
-
- /*
- Translate an FSSpec into an OSSpec.
- */
- _DLL _PAS OSError
- OS_FSSpec_To_OSSpec(const FSSpec *fss, OSSpec *spec)
- {
- OSError err;
-
- err = OS_VolDir_To_OSPathSpec(fss->vRefNum, fss->parID, &spec->path);
- if (err != OS_NOERR)
- return err;
-
- #if (defined(POSIX_FS) || defined(WIN32_FS)) && (OS_NAMESIZE >= 64)
- p2cstrcpy(spec->name.s, (ConstStr255Param)fss->name);
- return OS_NOERR;
- #else
- p2cstrcpy(stname, (ConstStr255Param)fss->name);
- return OS_MakeNameSpec(stname, &spec->name);
- #endif
- }
-
- #if defined(WIN32_FS)
- extern __stdcall __declspec(dllimport) unsigned char SetFileAttributesA(const char *, long);
- #define FILE_ATTRIBUTES_HIDDEN 2
- #endif
-
- #if defined(WIN32_FS)
- #define FORK_DIR "RESOURCE.FRK"
- #else
- #warning "Unix still uses resource.frk, although Latitude uses AppleDouble"
- #define FORK_DIR "resource.frk"
- #endif
-
- _DLL _PAS OSError
- OS_GetRsrcOSSpec(const OSSpec *spec, OSSpec *rspec, bool create)
- {
- char dbuffer[OS_PATHSIZE];
- OSError err;
-
- /* Make directory */
- OS_PathSpecToString2(&spec->path, dbuffer);
-
- if ((err = OS_MakeSpec2(dbuffer, FORK_DIR, rspec)) != OS_NOERR)
- return err;
-
- if (OS_Status(rspec) != OS_NOERR)
- {
- /* not found: rspec->name is FORK_DIR */
- if (create)
- {
- //DPRINT(("creating directory %s\n", OS_SpecToString1(rspec)));
- if ((err = OS_Mkdir(rspec)) != OS_NOERR)
- /* can't make dir */
- return err;
- #if defined(WIN32_FS)
- SetFileAttributesA(OS_SpecToString1(rspec), FILE_ATTRIBUTE_HIDDEN);
- #endif
- }
- else
- return err; /* can't do anything else */
-
- /* fixup path spec */
- if ((err = OS_MakeSpec2(dbuffer, FORK_DIR, rspec)) != OS_NOERR)
- return err;
- }
- else
- {
- if (OS_IsFile(rspec)) /* resource.frk is a file */
- return OS_FNIDERR;
- }
-
- if ((err = OS_MakeNameSpec(OS_NameSpecToString1(&spec->name),
- &rspec->name)) != OS_NOERR)
- return err;
-
- //DPRINT(("Filename is %s\n", OS_SpecToString1(rspec)));
-
- return OS_NOERR;
- }
-
- //////////////////////////
- #else // defined(MAC_FS)
- //////////////////////////
-
- #warning This module is redundant!
-
- //void OS_InitMacEmul(void) { }
- //void OS_StopMacEmul(void) { }
-
- _DLL _PAS OSError
- OS_OSPathSpec_To_VolDir(const OSPathSpec *spec, short *vRefNum, long *dirID)
- {
- *vRefNum = spec->vRefNum;
- *parID = spec->dirID;
- return OS_NOERR;
- }
-
- _DLL _PAS OSError
- OS_OSSpec_To_FSSpec(const OSSpec *spec, FSSpec *fss)
- {
- pstrcpy(fss->name,spec->name.name);
- return OS_NOERR;
- }
-
- _DLL _PAS OSError
- OS_VolDir_To_OSPathSpec(short vRefNum, long dirID, OSPathSpec *spec)
- {
- spec->vRefNum = vRefNum;
- spec->dirID = parID;
- return OS_NOERR;
- }
-
- _DLL _PAS OSError
- OS_VolDir_To_OSNameSpec(short vRefNum, long dirID, OSNameSpec *spec, long *parID)
- {
- #error
- }
-
- _DLL _PAS OSError
- OS_FSSpec_To_OSSpec(const FSSpec *fss, OSSpec *spec)
- {
- pstrcpy(spec->name.name, fss->name);
- return OS_NOERR;
- }
-
- _DLL _PAS OSError
- OS_GetRsrcOSSpec(OSSpec *spec, OSSpec *rspec, Boolean create)
- {
- *rspec = *spec;
- return OS_NOERR;
- }
-
- #endif // defined(MAC_FS)
-
- ///////////////////////////////////////
-
-
-
-
-
-
-
-
-