macstuff.c
上传用户:andy_li
上传日期:2007-01-06
资源大小:1019k
文件大小:49k
源码类别:

压缩解压

开发平台:

MultiPlatform

  1. #include <string.h>
  2. #include "macstuff.h"
  3. extern int errno;
  4. static  OSErr   GetCommentFromDesktopFile(short vRefNum,
  5.                                           long dirID,
  6.                                           ConstStr255Param name,
  7.                                           Str255 comment);
  8. static  OSErr   GetCommentID(short vRefNum,
  9.                              long dirID,
  10.                              ConstStr255Param name,
  11.                              short *commentID);
  12. static  OSErr   GetDesktopFileName(short vRefNum,
  13.                                    Str255 desktopName);
  14. enum
  15. {
  16.     kBNDLResType    = 'BNDL',
  17.     kFREFResType    = 'FREF',
  18.     kIconFamResType = 'ICN#',
  19.     kFCMTResType    = 'FCMT',
  20.     kAPPLResType    = 'APPL'
  21. };
  22. /*****************************************************************************/
  23. /*
  24. **  File Manager FSp calls
  25. */
  26. /*****************************************************************************/
  27. pascal  OSErr   FSMakeFSSpecCompat(short vRefNum,
  28.                                    long dirID,
  29.                                    ConstStr255Param fileName,
  30.                                    FSSpec *spec)
  31. {
  32.     OSErr   result;
  33. #if !__MACOSSEVENORLATER
  34.     if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
  35.     {
  36.         Boolean isDirectory;
  37.         result = GetObjectLocation(vRefNum, dirID, fileName,
  38.                                     &(spec->vRefNum), &(spec->parID), spec->name,
  39.                                     &isDirectory);
  40.     }
  41.     else
  42. #endif  /* !__MACOSSEVENORLATER */
  43.     {
  44.      /* Let the file system create the FSSpec if it can since it does the job */
  45.      /* much more efficiently than I can. */
  46.         result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
  47.         /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
  48.         /* returned in the parID field when making an FSSpec to the volume's */
  49.         /* root directory by passing a full pathname in MakeFSSpec's */
  50.         /* fileName parameter. Fixed in Mac OS 8.1 */
  51.         if ( (result == noErr) && (spec->parID == 0) )
  52.             spec->parID = fsRtParID;
  53.     }
  54.     return ( result );
  55. }
  56. /*****************************************************************************/
  57. /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
  58. #if !__MACOSSEVENORLATER
  59. static  Boolean FSHasFSSpecCalls(void)
  60. {
  61.     long            response;
  62. #if !GENERATENODATA
  63.     static Boolean  tested = false;
  64.     static Boolean  result = false;
  65. #else
  66.     Boolean result = false;
  67. #endif
  68. #if !GENERATENODATA
  69.     if ( !tested )
  70.     {
  71.         tested = true;
  72. #endif
  73.         if ( Gestalt(gestaltFSAttr, &response) == noErr )
  74.         {
  75.             result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
  76.         }
  77. #if !GENERATENODATA
  78.     }
  79. #endif
  80.     return ( result );
  81. }
  82. #endif  /* !__MACOSSEVENORLATER */
  83. /*****************************************************************************/
  84. /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
  85. /* except for FSpExchangeFiles. */
  86. #if !__MACOSSEVENORLATER
  87. static  Boolean QTHasFSSpecCalls(void)
  88. {
  89.     long            response;
  90. #if !GENERATENODATA
  91.     static Boolean  tested = false;
  92.     static Boolean  result = false;
  93. #else
  94.     Boolean result = false;
  95. #endif
  96. #if !GENERATENODATA
  97.     if ( !tested )
  98.     {
  99.         tested = true;
  100. #endif
  101.         result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
  102. #if !GENERATENODATA
  103.     }
  104. #endif
  105.     return ( result );
  106. }
  107. #endif  /* !__MACOSSEVENORLATER */
  108. /*
  109.  *----------------------------------------------------------------------
  110.  *
  111.  * FSpGetDefaultDir --
  112.  *
  113.  *  This function gets the current default directory.
  114.  *
  115.  * Results:
  116.  *  The provided FSSpec is changed to point to the "default"
  117.  *  directory.  The function returns what ever errors
  118.  *  FSMakeFSSpecCompat may encounter.
  119.  *
  120.  * Side effects:
  121.  *  None.
  122.  *
  123.  *----------------------------------------------------------------------
  124.  */
  125. int FSpGetDefaultDir(FSSpecPtr dirSpec) /* On return the default directory. */
  126. {
  127.     OSErr err;
  128.     short vRefNum = 0;
  129.     long int dirID = 0;
  130.     err = HGetVol(NULL, &vRefNum, &dirID);
  131.     if (err == noErr) {
  132.     err = FSMakeFSSpecCompat(vRefNum, dirID, (ConstStr255Param) NULL,
  133.         dirSpec);
  134.     }
  135.     return err;
  136. }
  137. /*
  138.  *----------------------------------------------------------------------
  139.  *
  140.  * FSpSetDefaultDir --
  141.  *
  142.  *  This function sets the default directory to the directory
  143.  *  pointed to by the provided FSSpec.
  144.  *
  145.  * Results:
  146.  *  The function returns what ever errors HSetVol may encounter.
  147.  *
  148.  * Side effects:
  149.  *  None.
  150.  *
  151.  *----------------------------------------------------------------------
  152.  */
  153. int FSpSetDefaultDir(FSSpecPtr dirSpec) /* The new default directory. */
  154. {
  155.     OSErr err;
  156.     /*
  157.      * The following special case is needed to work around a bug
  158.      * in the Macintosh OS.  (Acutally PC Exchange.)
  159.      */
  160.     if (dirSpec->parID == fsRtParID) {
  161.     err = HSetVol(NULL, dirSpec->vRefNum, fsRtDirID);
  162.     } else {
  163.     err = HSetVol(dirSpec->name, dirSpec->vRefNum, dirSpec->parID);
  164.     }
  165.     return err;
  166. }
  167. /*
  168.  *----------------------------------------------------------------------
  169.  *
  170.  * FSpFindFolder --
  171.  *
  172.  *  This function is a version of the FindFolder function that
  173.  *  returns the result as a FSSpec rather than a vRefNum and dirID.
  174.  *
  175.  * Results:
  176.  *  Results will be simaler to that of the FindFolder function.
  177.  *
  178.  * Side effects:
  179.  *  None.
  180.  *
  181.  *----------------------------------------------------------------------
  182.  */
  183. OSErr
  184. FSpFindFolder(
  185.     short vRefNum,      /* Volume reference number. */
  186.     OSType folderType,      /* Folder type taken by FindFolder. */
  187.     Boolean createFolder,   /* Should we create it if non-existant. */
  188.     FSSpec *spec)       /* Pointer to resulting directory. */
  189. {
  190.     short foundVRefNum;
  191.     long foundDirID;
  192.     OSErr err;
  193.     err = FindFolder(vRefNum, folderType, createFolder,
  194.         &foundVRefNum, &foundDirID);
  195.     if (err != noErr) {
  196.     return err;
  197.     }
  198.     err = FSMakeFSSpecCompat(foundVRefNum, foundDirID, "p", spec);
  199.     return err;
  200. }
  201. /*
  202.  *----------------------------------------------------------------------
  203.  *
  204.  * FSpPathFromLocation --
  205.  *
  206.  *  This function obtains a full path name for a given macintosh
  207.  *  FSSpec.  Unlike the More Files function FSpGetFullPath, this
  208.  *  function will return a C string in the Handle.  It also will
  209.  *  create paths for FSSpec that do not yet exist.
  210.  *
  211.  * Results:
  212.  *  OSErr code.
  213.  *
  214.  * Side effects:
  215.  *  None.
  216.  *
  217.  *----------------------------------------------------------------------
  218.  */
  219. OSErr
  220. FSpPathFromLocation(
  221.     FSSpec *spec,       /* The location we want a path for. */
  222.     int *length,        /* Length of the resulting path. */
  223.     Handle *fullPath)       /* Handle to path. */
  224. {
  225.     OSErr err;
  226.     FSSpec tempSpec;
  227.     CInfoPBRec pb;
  228.     *fullPath = NULL;
  229.     /*
  230.      * Make a copy of the input FSSpec that can be modified.
  231.      */
  232.     BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
  233.     if (tempSpec.parID == fsRtParID) {
  234.     /*
  235.      * The object is a volume.  Add a colon to make it a full
  236.      * pathname.  Allocate a handle for it and we are done.
  237.      */
  238.     tempSpec.name[0] += 2;
  239.     tempSpec.name[tempSpec.name[0] - 1] = ':';
  240.     tempSpec.name[tempSpec.name[0]] = '';
  241.     err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
  242.     } else {
  243.     /*
  244.      * The object isn't a volume.  Is the object a file or a directory?
  245.      */
  246.     pb.dirInfo.ioNamePtr = tempSpec.name;
  247.     pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
  248.     pb.dirInfo.ioDrDirID = tempSpec.parID;
  249.     pb.dirInfo.ioFDirIndex = 0;
  250.     err = PBGetCatInfoSync(&pb);
  251.     if ((err == noErr) || (err == fnfErr)) {
  252.         /*
  253.          * If the file doesn't currently exist we start over.  If the
  254.          * directory exists everything will work just fine.  Otherwise we
  255.          * will just fail later.  If the object is a directory, append a
  256.          * colon so full pathname ends with colon.
  257.          */
  258.         if (err == fnfErr) {
  259.         BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
  260.         } else if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) {
  261.         tempSpec.name[0] += 1;
  262.         tempSpec.name[tempSpec.name[0]] = ':';
  263.         }
  264.         /*
  265.          * Create a new Handle for the object - make it a C string.
  266.          */
  267.         tempSpec.name[0] += 1;
  268.         tempSpec.name[tempSpec.name[0]] = '';
  269.         err = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
  270.         if (err == noErr) {
  271.         /*
  272.          * Get the ancestor directory names - loop until we have an
  273.          * error or find the root directory.
  274.          */
  275.         pb.dirInfo.ioNamePtr = tempSpec.name;
  276.         pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
  277.         pb.dirInfo.ioDrParID = tempSpec.parID;
  278.         do {
  279.             pb.dirInfo.ioFDirIndex = -1;
  280.             pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  281.             err = PBGetCatInfoSync(&pb);
  282.             if (err == noErr) {
  283.             /*
  284.              * Append colon to directory name and add
  285.              * directory name to beginning of fullPath.
  286.              */
  287.             ++tempSpec.name[0];
  288.             tempSpec.name[tempSpec.name[0]] = ':';
  289.             (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
  290.                 tempSpec.name[0]);
  291.             err = MemError();
  292.             }
  293.         } while ( (err == noErr) &&
  294.             (pb.dirInfo.ioDrDirID != fsRtDirID) );
  295.         }
  296.     }
  297.     }
  298.     /*
  299.      * On error Dispose the handle, set it to NULL & return the err.
  300.      * Otherwise, set the length & return.
  301.      */
  302.     if (err == noErr) {
  303.     *length = GetHandleSize(*fullPath) - 1;
  304.     } else {
  305.     if ( *fullPath != NULL ) {
  306.         DisposeHandle(*fullPath);
  307.     }
  308.     *fullPath = NULL;
  309.     *length = 0;
  310.     }
  311.     return err;
  312. }
  313. /*****************************************************************************/
  314. pascal  OSErr   FSpGetDirectoryID(const FSSpec *spec,
  315.                                   long *theDirID,
  316.                                   Boolean *isDirectory)
  317. {
  318.     return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
  319.              theDirID, isDirectory) );
  320. }
  321. /*****************************************************************************/
  322. pascal  OSErr   GetDirectoryID(short vRefNum,
  323.                                long dirID,
  324.                                ConstStr255Param name,
  325.                                long *theDirID,
  326.                                Boolean *isDirectory)
  327. {
  328.     CInfoPBRec pb;
  329.     OSErr error;
  330.     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
  331.     if ( error == noErr )
  332.     {
  333.         *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
  334.         if ( *isDirectory )
  335.         {
  336.             *theDirID = pb.dirInfo.ioDrDirID;
  337.         }
  338.         else
  339.         {
  340.             *theDirID = pb.hFileInfo.ioFlParID;
  341.         }
  342.     }
  343.     return ( error );
  344. }
  345. /*****************************************************************************/
  346. pascal  OSErr GetCatInfoNoName(short vRefNum,
  347.                                long dirID,
  348.                                ConstStr255Param name,
  349.                                CInfoPBPtr pb)
  350. {
  351.     Str31 tempName;
  352.     OSErr error;
  353.     /* Protection against File Sharing problem */
  354.     if ( (name == NULL) || (name[0] == 0) )
  355.     {
  356.         tempName[0] = 0;
  357.         pb->dirInfo.ioNamePtr = tempName;
  358.         pb->dirInfo.ioFDirIndex = -1;   /* use ioDirID */
  359.     }
  360.     else
  361.     {
  362.         pb->dirInfo.ioNamePtr = (StringPtr)name;
  363.         pb->dirInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
  364.     }
  365.     pb->dirInfo.ioVRefNum = vRefNum;
  366.     pb->dirInfo.ioDrDirID = dirID;
  367.     error = PBGetCatInfoSync(pb);
  368.     pb->dirInfo.ioNamePtr = NULL;
  369.     return ( error );
  370. }
  371. /*****************************************************************************/
  372. pascal  OSErr   GetObjectLocation(short vRefNum,
  373.                                   long dirID,
  374.                                   ConstStr255Param pathname,
  375.                                   short *realVRefNum,
  376.                                   long *realParID,
  377.                                   Str255 realName,
  378.                                   Boolean *isDirectory)
  379. {
  380.     OSErr error;
  381.     CInfoPBRec pb;
  382.     Str255 tempPathname;
  383.     /* clear results */
  384.     *realVRefNum = 0;
  385.     *realParID = 0;
  386.     realName[0] = 0;
  387.     /*
  388.     **  Get the real vRefNum
  389.     */
  390.     error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
  391.     if ( error == noErr )
  392.     {
  393.         /*
  394.         **  Determine if the object already exists and if so,
  395.         **  get the real parent directory ID if it's a file
  396.         */
  397.         /* Protection against File Sharing problem */
  398.         if ( (pathname == NULL) || (pathname[0] == 0) )
  399.         {
  400.             tempPathname[0] = 0;
  401.             pb.hFileInfo.ioNamePtr = tempPathname;
  402.             pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
  403.         }
  404.         else
  405.         {
  406.             pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
  407.             pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
  408.         }
  409.         pb.hFileInfo.ioVRefNum = vRefNum;
  410.         pb.hFileInfo.ioDirID = dirID;
  411.         error = PBGetCatInfoSync(&pb);
  412.         if ( error == noErr )
  413.         {
  414.             /*
  415.             **  The file system object is present and we have the file's
  416.             **  real parID
  417.             */
  418.             /*  Is it a directory or a file? */
  419.             *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
  420.             if ( *isDirectory )
  421.             {
  422.                 /*
  423.                 **  It's a directory, get its name and parent dirID, and then
  424.                 **  we're done
  425.                 */
  426.                 pb.dirInfo.ioNamePtr = realName;
  427.                 pb.dirInfo.ioVRefNum = *realVRefNum;
  428.                 /* pb.dirInfo.ioDrDirID already contains the dirID of the
  429.                    directory object */
  430.                 pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
  431.                 error = PBGetCatInfoSync(&pb);
  432.                 /* get the parent ID here, because the file system can return the */
  433.                 /* wrong parent ID from the last call. */
  434.                 *realParID = pb.dirInfo.ioDrParID;
  435.             }
  436.             else
  437.             {
  438.                 /*
  439.                 **  It's a file - use the parent directory ID from the last call
  440.                 **  to GetCatInfoparse, get the file name, and then we're done
  441.                 */
  442.                 *realParID = pb.hFileInfo.ioFlParID;
  443.                 error = GetFilenameFromPathname(pathname, realName);
  444.             }
  445.         }
  446.         else if ( error == fnfErr )
  447.         {
  448.             /*
  449.             **  The file system object is not present - see if its parent is present
  450.             */
  451.             /*
  452.             **  Parse to get the object name from end of pathname
  453.             */
  454.             error = GetFilenameFromPathname(pathname, realName);
  455.             /* if we can't get the object name from the end, we can't continue */
  456.             if ( error == noErr )
  457.             {
  458.                 /*
  459.                 **  What we want now is the pathname minus the object name
  460.                 **  for example:
  461.                 **  if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
  462.                 **  if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
  463.                 **  if pathname is ':dir:file' tempPathname becomes ':dir:'
  464.                 **  if pathname is ':dir:file:' tempPathname becomes ':dir:'
  465.                 **  if pathname is ':file' tempPathname becomes ':'
  466.                 **  if pathname is 'file or file:' tempPathname becomes ''
  467.                 */
  468.                 /* get a copy of the pathname */
  469.                 BlockMoveData(pathname, tempPathname, pathname[0] + 1);
  470.                 /* remove the object name */
  471.                 tempPathname[0] -= realName[0];
  472.                 /* and the trailing colon (if any) */
  473.                 if ( pathname[pathname[0]] == ':' )
  474.                 {
  475.                     --tempPathname[0];
  476.                 }
  477.                 /* OK, now get the parent's directory ID */
  478.                 /* Protection against File Sharing problem */
  479.                 pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
  480.                 if ( tempPathname[0] != 0 )
  481.                 {
  482.                     pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
  483.                 }
  484.                 else
  485.                 {
  486.                     pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
  487.                 }
  488.                 pb.hFileInfo.ioVRefNum = vRefNum;
  489.                 pb.hFileInfo.ioDirID = dirID;
  490.                 error = PBGetCatInfoSync(&pb);
  491.                 *realParID = pb.dirInfo.ioDrDirID;
  492.                 *isDirectory = false;   /* we don't know what the object is
  493.                                            really going to be */
  494.             }
  495.             if ( error != noErr )
  496.             {
  497.                 error = dirNFErr;   /* couldn't find parent directory */
  498.             }
  499.             else
  500.             {
  501.                 error = fnfErr; /* we found the parent, but not the file */
  502.             }
  503.         }
  504.     }
  505.     return ( error );
  506. }
  507. /*****************************************************************************/
  508. pascal  OSErr   DetermineVRefNum(ConstStr255Param pathname,
  509.                                  short vRefNum,
  510.                                  short *realVRefNum)
  511. {
  512.     HParamBlockRec pb;
  513.     OSErr error;
  514.     error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
  515.     if ( error == noErr )
  516.     {
  517.         *realVRefNum = pb.volumeParam.ioVRefNum;
  518.     }
  519.     return ( error );
  520. }
  521. /*****************************************************************************/
  522. pascal  OSErr   GetFilenameFromPathname(ConstStr255Param pathname,
  523.                                         Str255 filename)
  524. {
  525.     short   index;
  526.     short   nameEnd;
  527.     OSErr   error;
  528.     /* default to no filename */
  529.     filename[0] = 0;
  530.     /* check for no pathname */
  531.     if ( pathname != NULL )
  532.     {
  533.         /* get string length */
  534.         index = pathname[0];
  535.         /* check for empty string */
  536.         if ( index != 0 )
  537.         {
  538.             /* skip over last trailing colon (if any) */
  539.             if ( pathname[index] == ':' )
  540.             {
  541.                 --index;
  542.             }
  543.             /* save the end of the string */
  544.             nameEnd = index;
  545.             /* if pathname ends with multiple colons, then this pathname refers */
  546.             /* to a directory, not a file */
  547.             if ( pathname[index] != ':' )
  548.             {
  549.                 /* parse backwards until we find a colon or hit the beginning
  550.                    of the pathname */
  551.                 while ( (index != 0) && (pathname[index] != ':') )
  552.                 {
  553.                     --index;
  554.                 }
  555.                 /* if we parsed to the beginning of the pathname and the
  556.                    pathname ended */
  557.                 /* with a colon, then pathname is a full pathname to a volume,
  558.                    not a file */
  559.                 if ( (index != 0) || (pathname[pathname[0]] != ':') )
  560.                 {
  561.                     /* get the filename and return noErr */
  562.                     filename[0] = (char)(nameEnd - index);
  563.                     BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
  564.                     error = noErr;
  565.                 }
  566.                 else
  567.                 {
  568.                     /* pathname to a volume, not a file */
  569.                     error = notAFileErr;
  570.                 }
  571.             }
  572.             else
  573.             {
  574.                 /* directory, not a file */
  575.                 error = notAFileErr;
  576.             }
  577.         }
  578.         else
  579.         {
  580.             /* empty string isn't a file */
  581.             error = notAFileErr;
  582.         }
  583.     }
  584.     else
  585.     {
  586.         /* NULL pathname isn't a file */
  587.         error = notAFileErr;
  588.     }
  589.     return ( error );
  590. }
  591. /*****************************************************************************/
  592. /*
  593. **  GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
  594. **  in cases where the returned volume name is not needed by the caller.
  595. **  The pathname and vRefNum parameters are not touched, and the pb
  596. **  parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
  597. **  the parameter block is always returned as NULL (since it might point
  598. **  to the local tempPathname).
  599. **
  600. **  I noticed using this code in several places, so here it is once.
  601. **  This reduces the code size of MoreFiles.
  602. */
  603. pascal  OSErr   GetVolumeInfoNoName(ConstStr255Param pathname,
  604.                                     short vRefNum,
  605.                                     HParmBlkPtr pb)
  606. {
  607.     Str255 tempPathname;
  608.     OSErr error;
  609.     /* Make sure pb parameter is not NULL */
  610.     if ( pb != NULL )
  611.     {
  612.         pb->volumeParam.ioVRefNum = vRefNum;
  613.         if ( pathname == NULL )
  614.         {
  615.             pb->volumeParam.ioNamePtr = NULL;
  616.             pb->volumeParam.ioVolIndex = 0;     /* use ioVRefNum only */
  617.         }
  618.         else
  619.         {                                   /* make a copy of the string and */
  620.             BlockMoveData(pathname, tempPathname, pathname[0] + 1);
  621.                                     /* use the copy so original isn't trashed */
  622.             pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;
  623.                                        /* use ioNamePtr/ioVRefNum combination */
  624.             pb->volumeParam.ioVolIndex = -1;
  625.         }
  626.         error = PBHGetVInfoSync(pb);
  627.         pb->volumeParam.ioNamePtr = NULL;   /* ioNamePtr may point to local
  628.                                             tempPathname, so don't return it */
  629.     }
  630.     else
  631.     {
  632.         error = paramErr;
  633.     }
  634.     return ( error );
  635. }
  636. /*****************************************************************************/
  637. pascal  OSErr   FSpGetFullPath(const FSSpec *spec,
  638.                                short *fullPathLength,
  639.                                Handle *fullPath)
  640. {
  641.     OSErr       result;
  642.     OSErr       realResult;
  643.     FSSpec      tempSpec;
  644.     CInfoPBRec  pb;
  645.     *fullPathLength = 0;
  646.     *fullPath = NULL;
  647.     /* Default to noErr */
  648.     realResult = noErr;
  649.     /* Make a copy of the input FSSpec that can be modified */
  650.     BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
  651.     if ( tempSpec.parID == fsRtParID )
  652.     {
  653.         /* The object is a volume */
  654.         /* Add a colon to make it a full pathname */
  655.         ++tempSpec.name[0];
  656.         tempSpec.name[tempSpec.name[0]] = ':';
  657.         /* We're done */
  658.         result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
  659.     }
  660.     else
  661.     {
  662.         /* The object isn't a volume */
  663.         /* Is the object a file or a directory? */
  664.         pb.dirInfo.ioNamePtr = tempSpec.name;
  665.         pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
  666.         pb.dirInfo.ioDrDirID = tempSpec.parID;
  667.         pb.dirInfo.ioFDirIndex = 0;
  668.         result = PBGetCatInfoSync(&pb);
  669.         /* Allow file/directory name at end of path to not exist. */
  670.         realResult = result;
  671.         if ( (result == noErr) || (result == fnfErr) )
  672.         {
  673.             /* if the object is a directory, append a colon so full pathname
  674.                ends with colon */
  675.             if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  676.             {
  677.                 ++tempSpec.name[0];
  678.                 tempSpec.name[tempSpec.name[0]] = ':';
  679.             }
  680.             /* Put the object name in first */
  681.             result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
  682.             if ( result == noErr )
  683.             {
  684.                 /* Get the ancestor directory names */
  685.                 pb.dirInfo.ioNamePtr = tempSpec.name;
  686.                 pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
  687.                 pb.dirInfo.ioDrParID = tempSpec.parID;
  688.                 do  /* loop until we have an error or find the root directory */
  689.                 {
  690.                     pb.dirInfo.ioFDirIndex = -1;
  691.                     pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
  692.                     result = PBGetCatInfoSync(&pb);
  693.                     if ( result == noErr )
  694.                     {
  695.                         /* Append colon to directory name */
  696.                         ++tempSpec.name[0];
  697.                         tempSpec.name[tempSpec.name[0]] = ':';
  698.                         /* Add directory name to beginning of fullPath */
  699.                         (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1],
  700.                                       tempSpec.name[0]);
  701.                         result = MemError();
  702.                     }
  703.                 } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
  704.             }
  705.         }
  706.     }
  707.     if ( result == noErr )
  708.     {
  709.         /* Return the length */
  710.         *fullPathLength = InlineGetHandleSize(*fullPath);
  711.         result = realResult;    /* return realResult in case it was fnfErr */
  712.     }
  713.     else
  714.     {
  715.         /* Dispose of the handle and return NULL and zero length */
  716.         if ( *fullPath != NULL )
  717.         {
  718.             DisposeHandle(*fullPath);
  719.         }
  720.         *fullPath = NULL;
  721.         *fullPathLength = 0;
  722.     }
  723.     return ( result );
  724. }
  725. /*****************************************************************************/
  726. pascal OSErr FSpLocationFromFullPath(short fullPathLength,
  727.                                      const void *fullPath,
  728.                                      FSSpec *spec)
  729. {
  730.     AliasHandle alias;
  731.     OSErr       result;
  732.     Boolean     wasChanged;
  733.     Str32       nullString;
  734.     /* Create a minimal alias from the full pathname */
  735.     nullString[0] = 0;  /* null string to indicate no zone or server name */
  736.     result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString,
  737.                                          nullString, &alias);
  738.     if ( result == noErr )
  739.     {
  740.         /* Let the Alias Manager resolve the alias. */
  741.         result = ResolveAlias(NULL, alias, spec, &wasChanged);
  742.         DisposeHandle((Handle)alias);   /* Free up memory used */
  743.     }
  744.     return ( result );
  745. }
  746. /*****************************************************************************/
  747. pascal  OSErr   GetFullPath(short vRefNum,
  748.                             long dirID,
  749.                             ConstStr255Param name,
  750.                             short *fullPathLength,
  751.                             Handle *fullPath)
  752. {
  753.     OSErr       result;
  754.     FSSpec      spec;
  755.     *fullPathLength = 0;
  756.     *fullPath = NULL;
  757.     result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
  758.     if ( (result == noErr) || (result == fnfErr) )
  759.     {
  760.         result = FSpGetFullPath(&spec, fullPathLength, fullPath);
  761.     }
  762.     return ( result );
  763. }
  764. /*****************************************************************************/
  765. pascal  OSErr   ChangeCreatorType(short vRefNum,
  766.                                   long dirID,
  767.                                   ConstStr255Param name,
  768.                                   OSType creator,
  769.                                   OSType fileType)
  770. {
  771.     CInfoPBRec pb;
  772.     OSErr error;
  773.     short realVRefNum;
  774.     long parID;
  775.     pb.hFileInfo.ioNamePtr = (StringPtr)name;
  776.     pb.hFileInfo.ioVRefNum = vRefNum;
  777.     pb.hFileInfo.ioDirID = dirID;
  778.     pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
  779.     error = PBGetCatInfoSync(&pb);
  780.     if ( error == noErr )
  781.     {
  782.         if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 )   /* if file */
  783.         {                            /* save parent dirID for BumpDate call */
  784.             parID = pb.hFileInfo.ioFlParID;
  785.             /* If creator not 0x00000000, change creator */
  786.             if ( creator != (OSType)0x00000000 )
  787.             {
  788.                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
  789.             }
  790.             /* If fileType not 0x00000000, change fileType */
  791.             if ( fileType != (OSType)0x00000000 )
  792.             {
  793.                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
  794.             }
  795.             pb.hFileInfo.ioDirID = dirID;
  796.             error = PBSetCatInfoSync(&pb);  /* now, save the new information
  797.                                                back to disk */
  798.             if ( (error == noErr) && (parID != fsRtParID) ) /* can't
  799.                                                             bump fsRtParID */
  800.             {
  801.                 /* get the real vRefNum in case a full pathname was passed */
  802.                 error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  803.                 if ( error == noErr )
  804.                 {
  805.                     error = BumpDate(realVRefNum, parID, NULL);
  806.                         /* and bump the parent directory's mod date to wake
  807.                            up the Finder */
  808.                         /* to the change we just made */
  809.                 }
  810.             }
  811.         }
  812.         else
  813.         {
  814.             /* it was a directory, not a file */
  815.             error = notAFileErr;
  816.         }
  817.     }
  818.     return ( error );
  819. }
  820. /*****************************************************************************/
  821. pascal  OSErr   FSpChangeCreatorType(const FSSpec *spec,
  822.                                      OSType creator,
  823.                                      OSType fileType)
  824. {
  825.     return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name,
  826.              creator, fileType) );
  827. }
  828. /*****************************************************************************/
  829. pascal  OSErr   BumpDate(short vRefNum,
  830.                          long dirID,
  831.                          ConstStr255Param name)
  832. /* Given a file or directory, change its modification date to the
  833.    current date/time. */
  834. {
  835.     CInfoPBRec pb;
  836.     Str31 tempName;
  837.     OSErr error;
  838.     unsigned long secs;
  839.     /* Protection against File Sharing problem */
  840.     if ( (name == NULL) || (name[0] == 0) )
  841.     {
  842.         tempName[0] = 0;
  843.         pb.hFileInfo.ioNamePtr = tempName;
  844.         pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
  845.     }
  846.     else
  847.     {
  848.         pb.hFileInfo.ioNamePtr = (StringPtr)name;
  849.         pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
  850.     }
  851.     pb.hFileInfo.ioVRefNum = vRefNum;
  852.     pb.hFileInfo.ioDirID = dirID;
  853.     error = PBGetCatInfoSync(&pb);
  854.     if ( error == noErr )
  855.     {
  856.         GetDateTime(&secs);
  857.         /* set mod date to current date, or one second into the future
  858.             if mod date = current date */
  859.         pb.hFileInfo.ioFlMdDat =
  860.                           (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
  861.         if ( pb.dirInfo.ioNamePtr == tempName )
  862.         {
  863.             pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
  864.         }
  865.         else
  866.         {
  867.             pb.hFileInfo.ioDirID = dirID;
  868.         }
  869.         error = PBSetCatInfoSync(&pb);
  870.     }
  871.     return ( error );
  872. }
  873. /*****************************************************************************/
  874. pascal  OSErr   FSpBumpDate(const FSSpec *spec)
  875. {
  876.     return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
  877. }
  878. /*****************************************************************************/
  879. pascal  OSErr   OnLine(FSSpecPtr volumes,
  880.                        short reqVolCount,
  881.                        short *actVolCount,
  882.                        short *volIndex)
  883. {
  884.     HParamBlockRec pb;
  885.     OSErr error = noErr;
  886.     FSSpec *endVolArray;
  887.     if ( *volIndex > 0 )
  888.     {
  889.         *actVolCount = 0;
  890.         for ( endVolArray = volumes + reqVolCount;
  891.               (volumes < endVolArray) && (error == noErr); ++volumes )
  892.         {
  893.             pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
  894.             pb.volumeParam.ioVolIndex = *volIndex;
  895.             error = PBHGetVInfoSync(&pb);
  896.             if ( error == noErr )
  897.             {
  898.                 volumes->parID = fsRtParID;     /* the root directory's
  899.                                                    parent is 1 */
  900.                 volumes->vRefNum = pb.volumeParam.ioVRefNum;
  901.                 ++*volIndex;
  902.                 ++*actVolCount;
  903.             }
  904.         }
  905.     }
  906.     else
  907.     {
  908.         error = paramErr;
  909.     }
  910.     return ( error );
  911. }
  912. /*****************************************************************************/
  913. pascal  OSErr   DTGetComment(short vRefNum,
  914.                              long dirID,
  915.                              ConstStr255Param name,
  916.                              Str255 comment)
  917. {
  918.     DTPBRec pb;
  919.     OSErr error;
  920.     short dtRefNum;
  921.     Boolean newDTDatabase;
  922.     if (comment != NULL)
  923.     {
  924.         comment[0] = 0; /* return nothing by default */
  925.         /* attempt to open the desktop database */
  926.         error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  927.         if ( error == noErr )
  928.         {
  929.             /* There was a desktop database and it's now open */
  930.             if ( !newDTDatabase )
  931.             {
  932.                 pb.ioDTRefNum = dtRefNum;
  933.                 pb.ioNamePtr = (StringPtr)name;
  934.                 pb.ioDirID = dirID;
  935.                 pb.ioDTBuffer = (Ptr)&comment[1];
  936.                 /*
  937.                 **  IMPORTANT NOTE #1: Inside Macintosh says that comments
  938.                 **  are up to 200 characters. While that may be correct for
  939.                 **  the HFS file system's Desktop Manager, other file
  940.                 **  systems (such as Apple Photo Access) return up to
  941.                 **  255 characters. Make sure the comment buffer is a Str255
  942.                 **  or you'll regret it.
  943.                 **
  944.                 **  IMPORTANT NOTE #2: Although Inside Macintosh doesn't
  945.                 **  mention it, ioDTReqCount is a input field to
  946.                 **  PBDTGetCommentSync. Some file systems (like HFS) ignore
  947.                 **  ioDTReqCount and always return the full comment --
  948.                 **  others (like AppleShare) respect ioDTReqCount and only
  949.                 **  return up to ioDTReqCount characters of the comment.
  950.                 */
  951.                 pb.ioDTReqCount = sizeof(Str255) - 1;
  952.                 error = PBDTGetCommentSync(&pb);
  953.                 if (error == noErr)
  954.                 {
  955.                     comment[0] = (unsigned char)pb.ioDTActCount;
  956.                 }
  957.             }
  958.         }
  959.         else
  960.         {
  961.             /* There is no desktop database - try the Desktop file */
  962.             error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
  963.             if ( error != noErr )
  964.             {
  965.                 error = afpItemNotFound;    /* return an expected error */
  966.             }
  967.         }
  968.     }
  969.     else
  970.     {
  971.         error = paramErr;
  972.     }
  973.     return (error);
  974. }
  975. /*****************************************************************************/
  976. pascal  OSErr   FSpDTGetComment(const FSSpec *spec,
  977.                               Str255 comment)
  978. {
  979.     return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
  980. }
  981. /*****************************************************************************/
  982. pascal  OSErr   DTSetComment(short vRefNum,
  983.                              long dirID,
  984.                              ConstStr255Param name,
  985.                              ConstStr255Param comment)
  986. {
  987.     DTPBRec pb;
  988.     OSErr error;
  989.     short dtRefNum;
  990.     Boolean newDTDatabase;
  991.     error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
  992.     if ( error == noErr )
  993.     {
  994.         pb.ioDTRefNum = dtRefNum;
  995.         pb.ioNamePtr = (StringPtr)name;
  996.         pb.ioDirID = dirID;
  997.         pb.ioDTBuffer = (Ptr)&comment[1];
  998.         /* Truncate the comment to 200 characters just in case */
  999.         /* some file system doesn't range check */
  1000.         if ( comment[0] <= 200 )
  1001.         {
  1002.             pb.ioDTReqCount = comment[0];
  1003.         }
  1004.         else
  1005.         {
  1006.             pb.ioDTReqCount = 200;
  1007.         }
  1008.         error = PBDTSetCommentSync(&pb);
  1009.     }
  1010.     return (error);
  1011. }
  1012. /*****************************************************************************/
  1013. pascal  OSErr   FSpDTSetComment(const FSSpec *spec,
  1014.                               ConstStr255Param comment)
  1015. {
  1016.     return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
  1017. }
  1018. /*****************************************************************************/
  1019. pascal  OSErr   DTOpen(ConstStr255Param volName,
  1020.                        short vRefNum,
  1021.                        short *dtRefNum,
  1022.                        Boolean *newDTDatabase)
  1023. {
  1024.     OSErr error;
  1025.     GetVolParmsInfoBuffer volParmsInfo;
  1026.     long infoSize;
  1027.     DTPBRec pb;
  1028.     /* Check for volume Desktop Manager support before calling */
  1029.     infoSize = sizeof(GetVolParmsInfoBuffer);
  1030.     error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
  1031.     if ( error == noErr )
  1032.     {
  1033.         if ( hasDesktopMgr(volParmsInfo) )
  1034.         {
  1035.             pb.ioNamePtr = (StringPtr)volName;
  1036.             pb.ioVRefNum = vRefNum;
  1037.             error = PBDTOpenInform(&pb);
  1038.             /* PBDTOpenInform informs us if the desktop was just created */
  1039.             /* by leaving the low bit of ioTagInfo clear (0) */
  1040.             *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
  1041.             if ( error == paramErr )
  1042.             {
  1043.                 error = PBDTGetPath(&pb);
  1044.                 /* PBDTGetPath doesn't tell us if the database is new */
  1045.                 /* so assume it is not new */
  1046.                 *newDTDatabase = false;
  1047.             }
  1048.             *dtRefNum = pb.ioDTRefNum;
  1049.         }
  1050.         else
  1051.         {
  1052.             error = paramErr;
  1053.         }
  1054.     }
  1055.     return ( error );
  1056. }
  1057. /*****************************************************************************/
  1058. /*
  1059. **  GetCommentFromDesktopFile
  1060. **
  1061. **  Get a file or directory's Finder comment field (if any) from the
  1062. **  Desktop file's 'FCMT' resources.
  1063. */
  1064. static  OSErr   GetCommentFromDesktopFile(short vRefNum,
  1065.                                           long dirID,
  1066.                                           ConstStr255Param name,
  1067.                                           Str255 comment)
  1068. {
  1069.     OSErr error;
  1070.     short commentID;
  1071.     short realVRefNum;
  1072.     Str255 desktopName;
  1073.     short savedResFile;
  1074.     short dfRefNum;
  1075.     StringHandle commentHandle;
  1076.     /* Get the comment ID number */
  1077.     error = GetCommentID(vRefNum, dirID, name, &commentID);
  1078.     if ( error == noErr )
  1079.     {
  1080.         if ( commentID != 0 )   /* commentID == 0 means there's no comment */
  1081.         {
  1082.             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
  1083.             if ( error == noErr )
  1084.             {
  1085.                 error = GetDesktopFileName(realVRefNum, desktopName);
  1086.                 if ( error == noErr )
  1087.                 {
  1088.                     savedResFile = CurResFile();
  1089.                     /*
  1090.                     **  Open the 'Desktop' file in the root directory. (because
  1091.                     **  opening the resource file could preload unwanted resources,
  1092.                     **  bracket the call with SetResLoad(s))
  1093.                     */
  1094.                     SetResLoad(false);
  1095.                     dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName,
  1096.                                             fsRdPerm);
  1097.                     SetResLoad(true);
  1098.                     if ( dfRefNum != -1)
  1099.                     {
  1100.                         /* Get the comment resource */
  1101.                         commentHandle = (StringHandle)Get1Resource(kFCMTResType,
  1102.                                                                    commentID);
  1103.                         if ( commentHandle != NULL )
  1104.                         {
  1105.                             if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
  1106.                             {
  1107.                                 BlockMoveData(*commentHandle, comment,
  1108.                                               *commentHandle[0] + 1);
  1109.                             }
  1110.                             else
  1111.                             {                       /* no comment available */
  1112.                                 error = afpItemNotFound;
  1113.                             }
  1114.                         }
  1115.                         else
  1116.                         {                           /* no comment available */
  1117.                             error = afpItemNotFound;
  1118.                         }
  1119.                         /* restore the resource chain and close
  1120.                            the Desktop file */
  1121.                         UseResFile(savedResFile);
  1122.                         CloseResFile(dfRefNum);
  1123.                     }
  1124.                     else
  1125.                     {
  1126.                         error = afpItemNotFound;
  1127.                     }
  1128.                 }
  1129.                 else
  1130.                 {
  1131.                     error = afpItemNotFound;
  1132.                 }
  1133.             }
  1134.         }
  1135.         else
  1136.         {
  1137.             error = afpItemNotFound;    /* no comment available */
  1138.         }
  1139.     }
  1140.     return ( error );
  1141. }
  1142. /*****************************************************************************/
  1143. pascal  OSErr   HGetVolParms(ConstStr255Param volName,
  1144.                              short vRefNum,
  1145.                              GetVolParmsInfoBuffer *volParmsInfo,
  1146.                              long *infoSize)
  1147. {
  1148.     HParamBlockRec pb;
  1149.     OSErr error;
  1150.     pb.ioParam.ioNamePtr = (StringPtr)volName;
  1151.     pb.ioParam.ioVRefNum = vRefNum;
  1152.     pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
  1153.     pb.ioParam.ioReqCount = *infoSize;
  1154.     error = PBHGetVolParmsSync(&pb);
  1155.     if ( error == noErr )
  1156.     {
  1157.         *infoSize = pb.ioParam.ioActCount;
  1158.     }
  1159.     return ( error );
  1160. }
  1161. /*****************************************************************************/
  1162. /*
  1163. **  GetCommentID
  1164. **
  1165. **  Get the comment ID number for the Desktop file's 'FCMT' resource ID from
  1166. **  the file or folders fdComment (frComment) field.
  1167. */
  1168. static  OSErr   GetCommentID(short vRefNum,
  1169.                              long dirID,
  1170.                              ConstStr255Param name,
  1171.                              short *commentID)
  1172. {
  1173.     CInfoPBRec pb;
  1174.     OSErr error;
  1175.     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
  1176.     *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
  1177.     return ( error );
  1178. }
  1179. /*****************************************************************************/
  1180. /*
  1181. **  GetDesktopFileName
  1182. **
  1183. **  Get the name of the Desktop file.
  1184. */
  1185. static  OSErr   GetDesktopFileName(short vRefNum,
  1186.                                    Str255 desktopName)
  1187. {
  1188.     OSErr           error;
  1189.     HParamBlockRec  pb;
  1190.     short           index;
  1191.     Boolean         found;
  1192.     pb.fileParam.ioNamePtr = desktopName;
  1193.     pb.fileParam.ioVRefNum = vRefNum;
  1194.     pb.fileParam.ioFVersNum = 0;
  1195.     index = 1;
  1196.     found = false;
  1197.     do
  1198.     {
  1199.         pb.fileParam.ioDirID = fsRtDirID;
  1200.         pb.fileParam.ioFDirIndex = index;
  1201.         error = PBHGetFInfoSync(&pb);
  1202.         if ( error == noErr )
  1203.         {
  1204.             if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
  1205.                  (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
  1206.             {
  1207.                 found = true;
  1208.             }
  1209.         }
  1210.         ++index;
  1211.     } while ( (error == noErr) && !found );
  1212.     return ( error );
  1213. }
  1214. /*****************************************************************************/
  1215. pascal  OSErr   XGetVInfo(short volReference,
  1216.                           StringPtr volName,
  1217.                           short *vRefNum,
  1218.                           UnsignedWide *freeBytes,
  1219.                           UnsignedWide *totalBytes)
  1220. {
  1221.     OSErr           result;
  1222.     long            response;
  1223.     XVolumeParam    pb;
  1224.     /* See if large volume support is available */
  1225.     if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
  1226.     {
  1227.         /* Large volume support is available */
  1228.         pb.ioVRefNum = volReference;
  1229.         pb.ioNamePtr = volName;
  1230.         pb.ioXVersion = 0;  /* this XVolumeParam version (0) */
  1231.         pb.ioVolIndex = 0;  /* use ioVRefNum only, return volume name */
  1232.         result = PBXGetVolInfoSync(&pb);
  1233.         if ( result == noErr )
  1234.         {
  1235.             /* The volume name was returned in volName (if not NULL) and */
  1236.             /* we have the volume's vRefNum and allocation block size */
  1237.             *vRefNum = pb.ioVRefNum;
  1238.             /* return the freeBytes and totalBytes */
  1239.             *totalBytes = pb.ioVTotalBytes;
  1240.             *freeBytes = pb.ioVFreeBytes;
  1241.         }
  1242.     }
  1243.     else
  1244.     {
  1245.         /* No large volume support */
  1246.         /* Use HGetVInfo to get the results */
  1247.         result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
  1248.         if ( result == noErr )
  1249.         {
  1250.             /* zero the high longs of totalBytes and freeBytes */
  1251.             totalBytes->hi = 0;
  1252.             freeBytes->hi = 0;
  1253.         }
  1254.     }
  1255.     return ( result );
  1256. }
  1257. /*****************************************************************************/
  1258. pascal  OSErr   HGetVInfo(short volReference,
  1259.                           StringPtr volName,
  1260.                           short *vRefNum,
  1261.                           unsigned long *freeBytes,
  1262.                           unsigned long *totalBytes)
  1263. {
  1264.     HParamBlockRec  pb;
  1265.     unsigned long   allocationBlockSize;
  1266.     unsigned short  numAllocationBlocks;
  1267.     unsigned short  numFreeBlocks;
  1268.     VCB             *theVCB;
  1269.     Boolean         vcbFound;
  1270.     OSErr           result;
  1271.     /* Use the File Manager to get the real vRefNum */
  1272.     pb.volumeParam.ioVRefNum = volReference;
  1273.     pb.volumeParam.ioNamePtr = volName;
  1274.     pb.volumeParam.ioVolIndex = 0;  /* use ioVRefNum only, return volume name */
  1275.     result = PBHGetVInfoSync(&pb);
  1276.     if ( result == noErr )
  1277.     {
  1278.         /* The volume name was returned in volName (if not NULL) and */
  1279.         /* we have the volume's vRefNum and allocation block size */
  1280.         *vRefNum = pb.volumeParam.ioVRefNum;
  1281.         allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz;
  1282.         /* System 7.5 (and beyond) pins the number of allocation blocks and */
  1283.         /* the number of free allocation blocks returned by PBHGetVInfo to */
  1284.         /* a value so that when multiplied by the allocation block size, */
  1285.         /* the volume will look like it has $7fffffff bytes or less. This */
  1286.         /* was done so older applications that use signed math or that use */
  1287.         /* the GetVInfo function (which uses signed math) will continue to work. */
  1288.         /* However, the unpinned numbers (which we want) are always available */
  1289.         /* in the volume's VCB so we'll get those values from the VCB if possible. */
  1290.         /* Find the volume's VCB */
  1291.         vcbFound = false;
  1292.         theVCB = (VCB *)(GetVCBQHdr()->qHead);
  1293.         while ( (theVCB != NULL) && !vcbFound )
  1294.         {
  1295.             /* Check VCB signature before using VCB. Don't have to check for */
  1296.             /* MFS (0xd2d7) because they can't get big enough to be pinned */
  1297.             if ( theVCB->vcbSigWord == 0x4244 )
  1298.             {
  1299.                 if ( theVCB->vcbVRefNum == *vRefNum )
  1300.                 {
  1301.                     vcbFound = true;
  1302.                 }
  1303.             }
  1304.             if ( !vcbFound )
  1305.             {
  1306.                 theVCB = (VCB *)(theVCB->qLink);
  1307.             }
  1308.         }
  1309.         if ( theVCB != NULL )
  1310.         {
  1311.             /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
  1312.             /* and the number of free blocks from the VCB. */
  1313.             numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks;
  1314.             numFreeBlocks = (unsigned short)theVCB->vcbFreeBks;
  1315.         }
  1316.         else
  1317.         {
  1318.             /* Didn't find a VCB we can use. Return the number of allocation blocks */
  1319.             /* and the number of free blocks returned by PBHGetVInfoSync. */
  1320.             numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks;
  1321.             numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
  1322.         }
  1323.         /* Now, calculate freeBytes and totalBytes using unsigned values */
  1324.         *freeBytes = numFreeBlocks * allocationBlockSize;
  1325.         *totalBytes = numAllocationBlocks * allocationBlockSize;
  1326.     }
  1327.     return ( result );
  1328. }
  1329. /*
  1330. **  PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
  1331. **  File Manager requests from CFM-based programs. At some point, Apple
  1332. **  will get around to adding this to the standard libraries you link with
  1333. **  and you'll get a duplicate symbol link error. At that time, just delete
  1334. **  this code (or comment it out).
  1335. **
  1336. **  Non-CFM 68K programs don't needs this glue (and won't get it) because
  1337. **  they instead use the inline assembly glue found in the Files.h interface
  1338. **  file.
  1339. */
  1340. #if __WANTPASCALELIMINATION
  1341. #undef  pascal
  1342. #endif
  1343. #if GENERATINGCFM
  1344. pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
  1345. {
  1346.     enum
  1347.     {
  1348.         kXGetVolInfoSelector = 0x0012,  /* Selector for XGetVolInfo */
  1349.         uppFSDispatchProcInfo = kRegisterBased
  1350.              | REGISTER_RESULT_LOCATION(kRegisterD0)
  1351.              | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
  1352.              | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long)))  /* trap word */
  1353.              | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long)))  /* selector */
  1354.              | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
  1355.     };
  1356.     return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
  1357.                                         uppFSDispatchProcInfo,
  1358.                                         _FSDispatch,
  1359.                                         kXGetVolInfoSelector,
  1360.                                         paramBlock) );
  1361. }
  1362. #endif
  1363. #if __WANTPASCALELIMINATION
  1364. #define pascal
  1365. #endif
  1366. /*****************************************************************************/
  1367. pascal  OSErr   GetDirName(short vRefNum,
  1368.                            long dirID,
  1369.                            Str31 name)
  1370. {
  1371.     CInfoPBRec pb;
  1372.     OSErr error;
  1373.     if ( name != NULL )
  1374.     {
  1375.         pb.dirInfo.ioNamePtr = name;
  1376.         pb.dirInfo.ioVRefNum = vRefNum;
  1377.         pb.dirInfo.ioDrDirID = dirID;
  1378.         pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
  1379.         error = PBGetCatInfoSync(&pb);
  1380.     }
  1381.     else
  1382.     {
  1383.         error = paramErr;
  1384.     }
  1385.     return ( error );
  1386. }