home *** CD-ROM | disk | FTP | other *** search
/ ftp.whtech.com / ftp.whtech.com.7z / ftp.whtech.com / emulators / v9t9 / linux / sources / V9t9 / source / OSLib / MacSpecs.c < prev    next >
Encoding:
C/C++ Source or Header  |  2006-10-19  |  13.3 KB  |  682 lines

  1.  
  2. /*
  3.  *    This module handles emulation of Macintosh FSSpecs by maintaining
  4.  *    a list of referenced volumes and directories to handle the
  5.  *    conversion of full paths to FSSpecs and vice versa.
  6.  *
  7.  *    This implementation uses a simple linear counter to generate vRefNums
  8.  *    and dirIDs.  The directory structure as referenced by the running
  9.  *    program is stored as a tree so that for any FSSpec, a trace back
  10.  *    through the parID fields will step up this tree to the root.
  11.  *
  12.  *    As on the Mac, the root of a volume has parID==2, and the root of the
  13.  *    filesystem has parID==1.
  14.  */
  15.  
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <stdio.h>
  19. #include <assert.h>
  20.  
  21. #include <MacTypes.h>
  22. #include <Files.h>
  23.  
  24. #include "OSLib.h"
  25. #include "StringUtils.h"
  26. //#include "MacSpecs.h"
  27.  
  28. #undef DEBUG
  29.  
  30. #if !defined(MAC_FS)
  31. #ifdef DEBUG
  32. static unsigned long memused;
  33. #define MEMUSED(x)      memused+=x
  34. #else
  35. #define MEMUSED(x)    
  36. #endif
  37.  
  38. //static int MacEmulInitialized=0;
  39.  
  40.  
  41. struct    DirNode
  42. {
  43.     char                *name;        /* name of directory part */
  44.     unsigned             dirID;        /* of this directory, as seen by apps */
  45.     union {
  46.         struct DirNode        *parent;    /* of this directory */
  47.         struct VolNode        *volume;    /* of this root directory [dirID==2] */
  48.     }                    p;
  49.     struct DirNode        *list;        /* list of contained directories */
  50.     struct DirNode         *next;        /* next directory in parent's list */
  51. };
  52.  
  53. struct    VolNode
  54. {
  55.     unsigned short        vRefNum;    /* number */
  56.     struct DirNode        root;        /* of volume */
  57.     struct VolNode        *next;        /* next volume in list */
  58. };
  59.  
  60. typedef struct DirNode DirNode;
  61. typedef struct VolNode VolNode;
  62.  
  63. static VolNode             *vols;
  64.  
  65. /*  The dirID is allocated as-they-come, no matter which
  66.     volume is being referenced.
  67. */
  68. static unsigned    lastDirID = 3;        /* last directory ID; starts at 3 */
  69. static unsigned lastVolRef = 2;        /* last volume ref; starts at 2 */
  70.  
  71. /*    Support for 65536 directories  */
  72. #define MAXDIRMAPROWS    256
  73. #define DIRMAPROWSIZE    256            /* 256 entries allocated at a time */
  74. static DirNode    **dirIDMap[MAXDIRMAPROWS];    
  75.                                     /* map of maps of dirIDs to DirNodes */
  76. static unsigned    dirMapRows;            /* # of allocated rows */
  77.  
  78. /*    Add a reference for a new dirID.  */
  79.  
  80. static int    AddDirMapEntry(DirNode *node)
  81. {
  82.     unsigned row = node->dirID / DIRMAPROWSIZE;
  83.     unsigned col = node->dirID % DIRMAPROWSIZE;
  84.     
  85.     while (row >= dirMapRows)
  86.     {
  87.         if (row >= 256)
  88.         {
  89.             fprintf(stderr, "Fatal error:  too many directories referenced, out of memory\n");
  90.             return 0;
  91.         }
  92.             
  93.         dirIDMap[row] = (DirNode **) calloc(sizeof(DirNode *), DIRMAPROWSIZE);
  94.         if (dirIDMap[row] == NULL)    return 0;
  95.             
  96.         MEMUSED(sizeof(DirNode *) * DIRMAPROWSIZE);
  97.         
  98.         dirMapRows++;
  99.     }
  100.     
  101.     dirIDMap[row][col] = node;
  102.     return 1;
  103. }
  104.  
  105.  
  106. /*  Add a volume node in 'list' if necessary;
  107.     return new reference or found reference.
  108.  */
  109.     
  110. static VolNode *FindOrAddVolRef(VolNode **list, const char *name)
  111. {
  112.     int sz;
  113.     VolNode *vn;
  114.  
  115.     while (*list != NULL)    
  116.     {
  117.         if (OS_EqualPath(name, (*list)->root.name))
  118.             return *list;
  119.         else
  120.             list = &((*list)->next);
  121.     }
  122.     
  123.     /*    Cannot support more  */
  124.     
  125.     if (lastVolRef >= 256)
  126.         return NULL;
  127.  
  128. #ifdef DEBUG
  129.     printf("FindOrAddVolRef: adding ref for '%s'\n", name);
  130. #endif
  131.             
  132.     vn = (VolNode *) malloc(sizeof(VolNode));
  133.     if (vn==NULL)         return NULL;
  134.     MEMUSED(sizeof(VolNode));
  135.             
  136.     vn->next = NULL;
  137.     vn->vRefNum = lastVolRef++;
  138.     
  139.     /* Initialize root */
  140.     
  141.     sz = strlen(name)+1;
  142.     vn->root.name = (char *) malloc(sz);
  143.     if (vn->root.name==NULL)    return NULL;
  144.     MEMUSED(sz);    
  145.     strcpy(vn->root.name, name);
  146.     
  147.     vn->root.dirID = 2;
  148.     vn->root.p.volume = vn;
  149.     vn->root.list = NULL;
  150.     vn->root.next = NULL;
  151.         
  152.     *list = vn;            /* add to parent's list */
  153.     
  154.     return vn;
  155. }
  156.  
  157.  
  158. /*    Look up the DirNode for a given dirID */
  159.  
  160. static DirNode    *FindDirMapEntry(unsigned dirID)
  161. {
  162.     unsigned row = dirID / DIRMAPROWSIZE;
  163.     unsigned col = dirID % DIRMAPROWSIZE;
  164.     
  165.     assert(dirID != 2);
  166.     if (row >= dirMapRows)
  167.         return NULL;            /* illegal */
  168.     else
  169.         return dirIDMap[row][col];    
  170. }
  171.  
  172.  
  173. /*  Add a directory node in 'list' if necessary; 
  174.     return new reference or found reference.
  175.     
  176.     For a volume, do the same, except use a different parID.
  177.  */
  178.     
  179. static DirNode *FindOrAddDirRef(DirNode *parent, const char *name)
  180. {
  181.     int sz;
  182.     DirNode *dn,**list;
  183.     
  184.     list = &parent->list;
  185.     
  186.     while (*list != NULL)
  187.     {
  188.         if (OS_EqualPath(name, (*list)->name))
  189.             return *list;
  190.         else
  191.             list = &((*list)->next);
  192.     }
  193.     
  194.     /*    Cannot support more  */
  195.     
  196.     if (lastDirID >= 65536)
  197.         return NULL;
  198.         
  199. #ifdef DEBUG
  200.     printf("FindOrAddDirRef:  adding ref for '%s' [parent '%s']\n",
  201.         name, parent==NULL ? "<none>" : parent->name);
  202. #endif
  203.     
  204.     /*  Make node  */
  205.     
  206.     sz = strlen(name)+1;
  207.             
  208.     dn = (DirNode *) malloc(sizeof(DirNode));
  209.     if (dn==NULL)     return NULL;
  210.     MEMUSED(sizeof(DirNode));
  211.             
  212.     dn->name = (char *) malloc(sz);
  213.     if (dn->name==NULL)    return NULL;
  214.     MEMUSED(sz);    
  215.             
  216.     strcpy(dn->name, name);
  217.     dn->list = NULL;
  218.     dn->next = NULL;
  219.         
  220.     dn->dirID = lastDirID++;
  221.         
  222.     if (!AddDirMapEntry(dn))
  223.         return 0;
  224.             
  225.     dn->p.parent = parent;    
  226.  
  227.     *list = dn;            /* add to parent's list */
  228.     
  229.     return dn;
  230. }
  231.  
  232. static int    FindOrAdd(const OSPathSpec *path, 
  233.                     unsigned *vRefNum, unsigned *dirID)
  234. {
  235.     VolNode *vol;
  236.     DirNode *level;
  237.     char pb[OS_PATHSIZE],voln[OS_VOLSIZE];
  238.     char pathbuf[OS_PATHSIZE];
  239.     char *ptr;
  240.  
  241. #if defined(WIN32_FS) || defined(POSIX_FS)
  242.     strncpy(pathbuf, path->s, OS_PATHSIZE-1);    
  243.     pathbuf[OS_PATHSIZE-1] = 0;
  244. #else
  245.     if (OS_PathSpecToString(path, pathbuf, OS_PATHSIZE) == NULL)
  246.         return 0;
  247. #endif
  248.         
  249.     ptr = (char *)OS_GetDirPtr(pathbuf);
  250.     strncpy(voln, pathbuf, ptr-pathbuf);
  251.     voln[ptr-pathbuf] = 0;
  252.     strcpy(pb, ptr);
  253.     
  254.     vol = FindOrAddVolRef(&vols, voln);
  255.     if (vol==NULL)    return 0;
  256.  
  257.     *vRefNum = vol->vRefNum;
  258.     
  259.     level = &vol->root;
  260.     
  261.     /*  We expect the path to be a full path, which on all current
  262.         non-Mac systems start with OS_PATHSEP.  We can't add a blank
  263.         directory as the root, since, given a blank volume, we may
  264.         have "" + OS_PATHSEP + "" + OS_PATHSEP + "dir" which would be
  265.         a network reference on some systems.
  266.     */
  267.     ptr=pb+1;
  268.     assert(*pb == OS_PATHSEP);
  269.     
  270.     while (*ptr)
  271.     {
  272.         const char *st;
  273.         
  274.         st=ptr;
  275.         while (*ptr && *ptr != OS_PATHSEP)    ptr++;
  276.         
  277.         *ptr=0;
  278.         level = FindOrAddDirRef(level, st);
  279.         ptr++;
  280.  
  281.         if (level==NULL)    return 0;
  282.     }
  283.  
  284.     *dirID = level->dirID;
  285.     
  286.     return 1;
  287. }
  288.  
  289.  
  290. /*    Look up a vRefNum/dirID pair. */
  291. static void StepVolDir(unsigned *vRefNum, unsigned *dirID, 
  292.                         DirNode **node)
  293. {
  294.     if (*vRefNum == 1)
  295.     {
  296.         *node = NULL;
  297.     }
  298.     else
  299.     {
  300.         if (*dirID == 2)
  301.         {
  302.             VolNode *step;
  303.             
  304.             step = vols;
  305.             while (step && step->vRefNum != *vRefNum)
  306.                 step = step->next;
  307.                 
  308.             if (step != NULL)
  309.             {
  310.                 *node = &step->root;
  311.                 *vRefNum = 1;
  312.                 *dirID = 1;
  313.             }
  314.             else
  315.                 *node = NULL;
  316.         }
  317.         else
  318.         {
  319.             *node = FindDirMapEntry(*dirID);
  320.             if (*node)
  321.                 *dirID = (*node)->p.parent->dirID;
  322.             
  323.         }
  324.     }
  325. }
  326.  
  327. /*    Resolve a path to a vRefNum/dirID.  */
  328. static int    ResolvePath(const OSPathSpec *path, 
  329.                         unsigned *vRefNum, unsigned *dirID)
  330. {
  331. // meaningless
  332. #if 0
  333.     OSSpec full;
  334.     
  335.     /* See if the path exists */
  336.     full.path = *path;
  337.     OS_MakeNameSpec("", &full.name);
  338.     if (OS_Status(&full) != OS_NOERR)
  339.         return 0;
  340. #endif
  341.         
  342.     if (FindOrAdd(path, vRefNum, dirID))
  343.     {
  344.         *vRefNum = - (*vRefNum);
  345. #ifdef DEBUG
  346.         printf("ResolvePath: Found ref for '%s' (%d,%d)\n",
  347.             OS_PathSpecToString(path,NULL), *vRefNum, *dirID);
  348. #endif
  349.         return 1;
  350.     }
  351.     else
  352.     {
  353.         *vRefNum = 0;
  354.         *dirID = 0;
  355. #ifdef DEBUG
  356.         printf("ResolvePath: could not find '%s' or add it!\n",
  357.             OS_PathSpecToString(path,NULL));
  358. #endif
  359.         return 0;
  360.     }
  361. }
  362.  
  363. /*    Resolve vRefNum/dirID to a vol and dir string */
  364. static    int    ResolveVolDir(unsigned vRefNum, unsigned dirID, 
  365.                         char *vol, char *dir)
  366. {
  367.     DirNode *nodes[256];
  368.     DirNode *cur;
  369.     int        idx;
  370.     char    *dptr;
  371.         
  372.     vRefNum = -vRefNum;
  373.     
  374.     idx=0;
  375.     do
  376.     {
  377.         StepVolDir(&vRefNum, &dirID, &cur);
  378.         if (cur!=NULL)
  379.             nodes[idx++] = cur;
  380.     }    while (cur!=NULL);
  381.  
  382.     if (idx)
  383.         strcpy(vol, nodes[--idx]->name);
  384.     else
  385.     {
  386.         *vol = 0;        // totally invalid!
  387.         *dir = 0;
  388.         return 0;
  389.     }
  390.     
  391.     dptr=dir;
  392.     *dptr++ = OS_PATHSEP;
  393.     while (idx--)
  394.     {
  395.         strcpy(dptr, nodes[idx]->name);
  396.         dptr+=strlen(dptr);
  397.         *dptr++ = OS_PATHSEP;
  398.     }
  399.     *dptr=0;
  400.  
  401.     return 1;
  402. }
  403.  
  404. /*********************************************************************/
  405.  
  406. #if 0
  407. #pragma mark -
  408. #endif
  409.  
  410.  
  411. static char    stvol[OS_VOLSIZE], stdir[OS_PATHSIZE];
  412. static char    stpath[OS_PATHSIZE];
  413. static char stname[(OS_NAMESIZE < 256 ? 256 : OS_NAMESIZE)];
  414.  
  415. /*
  416.     Translate an OSPathSpec into the volume and directory for an FSSpec.
  417. */
  418. _DLL _PAS OSError    
  419. OS_OSPathSpec_To_VolDir(const OSPathSpec *spec, short *vRefNum, long *dirID)
  420. {
  421.     unsigned vol, dir;
  422.     if (ResolvePath(spec, &vol, &dir))
  423.     {
  424.         *vRefNum = vol;
  425.         *dirID = dir;
  426.         return OS_NOERR;
  427.     }
  428.     else
  429.     {
  430.         *vRefNum = 0;
  431.         *dirID = 0;
  432.         return OS_DNFERR;
  433.     }
  434. }
  435.  
  436. _DLL _PAS OSError    
  437. OS_OSSpec_To_FSSpec(const OSSpec *spec, FSSpec *fss)
  438. {
  439.     OSError err;
  440.     short vRefNum;
  441.     long dirID;
  442.     int len;
  443.     
  444.     err = OS_OSPathSpec_To_VolDir(&spec->path, &vRefNum, &dirID);
  445.  
  446.     fss->vRefNum = vRefNum;
  447.     fss->parID = dirID;
  448.  
  449.     if (err != OS_NOERR)
  450.         return err;
  451.  
  452.     // optimize
  453. #if defined(POSIX_FS) || defined(WIN32_FS)
  454.  
  455.     len = strlen(spec->name.s);
  456.     if (len >= sizeof(fss->name))
  457.         return OS_FNTLERR;
  458.     c2pstrcpy(fss->name, spec->name.s);
  459.         
  460. #else        
  461.  
  462.     OS_NameSpecToString2(&spec->name, stname);
  463.  
  464.     /*  Enforce Mac-style limits */
  465.     if (strlen(stname) > sizeof(fss->name))
  466.         return OS_FNTLERR;
  467.  
  468.     c2pstrcpy(fss->name, stname);
  469. #endif
  470.  
  471.     return OS_NOERR;
  472. }
  473.  
  474. /*
  475.     Translate the volume and directory from an FSSpec into an OSNameSpec.
  476.     (same as OS_VolDir_To_OSPathSpec but only goes one level)
  477. */
  478. _DLL _PAS OSError    
  479. OS_VolDir_To_OSNameSpec(short vRefNum, long dirID, OSNameSpec *spec, long *parID)
  480. {
  481.     unsigned int cv,cd;
  482.     DirNode *node;
  483.     
  484.     cv = -vRefNum;
  485.     cd = dirID;
  486.     StepVolDir(&cv, &cd, &node);
  487.     if (node == NULL)
  488.         return OS_DNFERR;
  489.     else
  490.     {
  491.         *parID = cd;
  492.     #if defined(POSIX_FS) || defined(WIN32_FS)
  493.         strcpy(spec->s, node->name);
  494.         return OS_NOERR;
  495.     #else
  496.         return OS_MakeNameSpec(node->name, spec);
  497.     #endif
  498.     }
  499. }
  500.  
  501. /*
  502.     Translate the volume and directory from an FSSpec into an OSPathSpec.
  503. */
  504. _DLL _PAS OSError    
  505. OS_VolDir_To_OSPathSpec(short vRefNum, long dirID, OSPathSpec *spec)
  506. {
  507.     OSError err;
  508.  
  509.     /*  CWD-local path? */
  510.     if (vRefNum==0 || dirID==0)
  511.     {
  512.         if ((err = OS_GetCWD(spec)) != OS_NOERR)
  513.             return err;
  514.     }
  515.     else
  516.     {
  517.         if (!ResolveVolDir(vRefNum, dirID, stvol, stdir))
  518.             return OS_DNFERR;
  519.             
  520.     #if defined(POSIX_FS) || defined(WIN32_FS)
  521.         {
  522.         int vlen = strlen(stvol);
  523.         int dlen = strlen(stdir);
  524.         if (vlen + dlen < OS_PATHSIZE)
  525.         {
  526.             memcpy(spec->s, stvol, vlen);
  527.             memcpy(spec->s + vlen, stdir, dlen + 1);
  528.         }
  529.         }
  530.     #else
  531.         if ((err = OS_MakePathSpec(stvol, stdir, spec)) != OS_NOERR)
  532.             return err;
  533.     #endif
  534.     }
  535.  
  536.     return OS_NOERR;
  537. }
  538.  
  539. /*
  540.     Translate an FSSpec into an OSSpec.
  541. */
  542. _DLL _PAS OSError    
  543. OS_FSSpec_To_OSSpec(const FSSpec *fss, OSSpec *spec)
  544. {
  545.     OSError err;
  546.  
  547.     err = OS_VolDir_To_OSPathSpec(fss->vRefNum, fss->parID, &spec->path);
  548.     if (err != OS_NOERR)
  549.         return err;
  550.  
  551. #if (defined(POSIX_FS) || defined(WIN32_FS)) && (OS_NAMESIZE >= 64)
  552.     p2cstrcpy(spec->name.s, (ConstStr255Param)fss->name);
  553.     return OS_NOERR;
  554. #else
  555.     p2cstrcpy(stname, (ConstStr255Param)fss->name);
  556.     return OS_MakeNameSpec(stname, &spec->name);
  557. #endif
  558. }
  559.  
  560. #if defined(WIN32_FS)
  561. extern __stdcall __declspec(dllimport) unsigned char SetFileAttributesA(const char *, long);
  562. #define FILE_ATTRIBUTES_HIDDEN    2
  563. #endif
  564.  
  565. #if defined(WIN32_FS)
  566. #define FORK_DIR    "RESOURCE.FRK"
  567. #else
  568. #warning "Unix still uses resource.frk, although Latitude uses AppleDouble"
  569. #define FORK_DIR    "resource.frk"
  570. #endif
  571.  
  572. _DLL _PAS OSError
  573. OS_GetRsrcOSSpec(const OSSpec *spec, OSSpec *rspec, bool create)
  574. {
  575.     char     dbuffer[OS_PATHSIZE];
  576.     OSError err;
  577.     
  578.     /*  Make directory  */
  579.     OS_PathSpecToString2(&spec->path, dbuffer);
  580.     
  581.     if ((err = OS_MakeSpec2(dbuffer, FORK_DIR, rspec)) != OS_NOERR)
  582.         return err;
  583.     
  584.     if (OS_Status(rspec) != OS_NOERR)
  585.     {
  586.         /*  not found:  rspec->name is FORK_DIR */
  587.         if (create)
  588.         {
  589.             //DPRINT(("creating directory %s\n", OS_SpecToString1(rspec)));
  590.             if ((err = OS_Mkdir(rspec)) != OS_NOERR)    
  591.                 /* can't make dir */
  592.                 return err;
  593.         #if defined(WIN32_FS)
  594.             SetFileAttributesA(OS_SpecToString1(rspec), FILE_ATTRIBUTE_HIDDEN);
  595.         #endif
  596.         }
  597.         else
  598.             return err;            /* can't do anything else */
  599.             
  600.         /*  fixup path spec */
  601.         if ((err = OS_MakeSpec2(dbuffer, FORK_DIR, rspec)) != OS_NOERR)
  602.             return err;
  603.     }
  604.     else
  605.     {
  606.         if (OS_IsFile(rspec))    /* resource.frk is a file */
  607.             return OS_FNIDERR;
  608.     }
  609.     
  610.     if ((err = OS_MakeNameSpec(OS_NameSpecToString1(&spec->name), 
  611.                                 &rspec->name)) != OS_NOERR)
  612.         return err;
  613.         
  614.     //DPRINT(("Filename is %s\n", OS_SpecToString1(rspec)));
  615.     
  616.     return OS_NOERR;
  617. }
  618.  
  619. //////////////////////////
  620. #else    // defined(MAC_FS)
  621. //////////////////////////
  622.  
  623. #warning This module is redundant!
  624.  
  625. //void    OS_InitMacEmul(void) { }
  626. //void    OS_StopMacEmul(void) { }
  627.  
  628. _DLL _PAS OSError    
  629. OS_OSPathSpec_To_VolDir(const OSPathSpec *spec, short *vRefNum, long *dirID)
  630. {
  631.     *vRefNum = spec->vRefNum;
  632.     *parID = spec->dirID;
  633.     return OS_NOERR;
  634. }
  635.  
  636. _DLL _PAS OSError    
  637. OS_OSSpec_To_FSSpec(const OSSpec *spec, FSSpec *fss)
  638. {
  639.     pstrcpy(fss->name,spec->name.name);
  640.     return OS_NOERR;
  641. }
  642.  
  643. _DLL _PAS OSError    
  644. OS_VolDir_To_OSPathSpec(short vRefNum, long dirID, OSPathSpec *spec)
  645. {
  646.     spec->vRefNum = vRefNum;
  647.     spec->dirID = parID;
  648.     return OS_NOERR;
  649. }
  650.  
  651. _DLL _PAS OSError    
  652. OS_VolDir_To_OSNameSpec(short vRefNum, long dirID, OSNameSpec *spec, long *parID)
  653. {
  654.     #error
  655. }
  656.  
  657. _DLL _PAS OSError    
  658. OS_FSSpec_To_OSSpec(const FSSpec *fss, OSSpec *spec)
  659. {
  660.     pstrcpy(spec->name.name, fss->name);
  661.     return OS_NOERR;
  662. }
  663.  
  664. _DLL _PAS OSError
  665. OS_GetRsrcOSSpec(OSSpec *spec, OSSpec *rspec, Boolean create)
  666. {
  667.     *rspec = *spec;
  668.     return OS_NOERR;
  669. }
  670.  
  671. #endif    // defined(MAC_FS)
  672.  
  673. ///////////////////////////////////////
  674.  
  675.  
  676.  
  677.  
  678.  
  679.  
  680.  
  681.  
  682.