mac-rom/Toolbox/AliasMgr/alUtil.c
Elliot Nunn 4325cdcc78 Bring in CubeE sources
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included.

The Tools directory, containing mostly junk, is also excluded.
2017-12-26 09:52:23 +08:00

2065 lines
74 KiB
C

/*
File: alUtil.c
Contains: Sundry utility routines.
Written by: Prashant Patel
Copyright: © 1990, 1993 by Apple Computer, Inc., all rights reserved.
This file is used in these builds: BigBang
Change History (most recent first):
<SM4> 10/6/93 SAM Fixed Cyclone roll in <LW2>. AL_GetMyServer was not taking the
length byte of the server name into account when copying the
string.
<SM3> 6/14/93 kc Roll in Ludwig.
<LW2> 4/9/93 fau In AL_GetMyServer, changed the BlockMove call's size parameter
to use Length(..) instead of GetHandleSize(..), fixing a NetBoot
problem.
<SM2> 10/8/92 PN Add 4meg Typhoon floppy drive for Cyclone
<41> 6/17/91 PP ich, dba, Post GM, Fix System Heap trashing bug that was
introduced in the AL_getCatInfo routine during last workaround.
<40> 4/12/91 PP pm,#86781:Workaround a FileShare bug that prevents doing a
GetCatInfo on a > 27 character volume name which appears upto 27
characters in VCB.
<39> 3/7/91 PP ich,#iWS b5-mtm-010:Call GetMyZone correctly with timeout and
retry count set properly. Return a boolean correctly in
AL_isAFPmedia routine.
<38> 2/27/91 PP ich,#ich-AMgr-0095:Make AL_mountForeign external.
<37> 1/31/91 PP ich,#b4q4 WhiteBoard:In AL_stripFileName, use Str255 name so it
could work for bad input.
<36> 1/25/91 PP sad,#80663:Detect driveNum and driver ref num correctly for
ejected off-line volumes. Make AL_getDriverName more secure.
<35> 1/21/91 PP (ich) Detect AppleTalk active or inactive correctly.
<34> 1/10/91 PP (ich) Do not bring up auto log-in dialog if AppleTalk is
inactive. During change to aux info, clear out volume name
before copying it. For ejectable volumes, return nsDrvErr
correctly.
<33> 1/2/91 PP (ich) StripFilename routine handles case where input and output
are pointers to same string.
<32> 12/20/90 PP (ich) Added BlockInit routine. Move AL_filterFile and
AL_updateAList to alExt.c to save on paramter passing.
<31> 12/13/90 PP (ich) On client side, do not match FileShare volumes who may
have the same creation date (e.g. duplicate of a folder).
<30> 12/13/90 PP (ich) Do not set needsUpdate for Audio CD volumes since it is
useless and later on it causes volume to be made fuzzy. Restrict
returned names for GetVolName and GetFileName to 255 chars. In
ValidateHandle, test for filename and volume name length is now
correct. In GetCatINfo, set versNum to 0 to keep MFS happy.
<29> 11/29/90 PP (prp/ich) In Filename ÒEqualStringÓ comparisons, do not ignore
diacritical marks in the name. Get in sync with VolumeMount
equates in Files.h
<28> 11/14/90 PP (PP/ich) In CheckIfAnyMatchesCriterion, the name check should be
for entire length of volume name in the alias record.
<27> 10/30/90 PP If MountEjectable returns userCanceledError, do not attempt
MountForeign and return the error to the caller.
<26> 10/30/90 PP In AL_mountAFP, if a switch to root volume occurs, also switch
data in alias record back to original data so the data is valid
for FindTarget. In AL_mountVolume, order for mounting is hard
disk, ejectable volumes followed by foreign volumes. Relax type
matching criterion when creation date for a volume matches and
if the network info matches.
<25> 10/21/90 gbm Change hfileInfo to hFileInfo for the last time (plus one!).
<25> 10/10/90 JL Change hfileInfo to hFileInfo for the last time.
<24> 10/10/90 PP For audio CDs, recognize any inserted disk as the correct target
disk. Handle AppleShare alias time difference. Preflight already
logged on server and Guest disabled. Bring up correct alert for
zero length name and password for mount dialog. Get rid of
xCallParam defs because new AppleTalk.h now has them. Do not
force update of registered user alias used as a Guest alias.
<23> 9/7/90 PP Optimize determination of CheckIfMounted for foreign volumes.
<22> 9/1/90 PP Relax driver name matching for ejectable volumes. Do not do
VolTypeMatch check until other criterion such as name and/or
creation date has matched.
<21> 8/17/90 PP Relax volume type match for foreign volumes (either mounted or
ones identified by alias record) when name and creation date
matches.
<20> 8/10/90 PP Relax volume type matching when name and creation date match and
matching volume is a foreign volume.
<19> 8/6/90 PP Support auto volume mount for foreign file systems other than
AppleShare.
<18> 7/19/90 PP Remove AlreadyConnected dialog.
<17> 7/10/90 dba get rid of warning
<16> 6/28/90 PP Convert CanonicalFileSpec to FSSpec. Invalid username alert has
username as part of the message.
<15> 6/15/90 PP Special Traps to support dialog code are no longer traps. Fix
bug related to getting current zone name if there are no
bridges.
<14> 5/31/90 PP Recognize ejectable off-line volumes.
<13> 5/16/90 PP On client side, super user with "see entire volume" privilege
should try to auto mount SharePoint as well as real volume.
<12> 5/3/90 PP Closer integration of FileShare and aliases. Incorporate Diet
Clinic tips.
<11> 4/10/90 PP Change once more hFileInfo to hfileInfo to stay consistent with
Files.h
<10> 4/10/90 PP Add support for kARMnoUI bit in rules mask.
<9> 4/5/90 PP Code size optimization.
<8> 3/20/90 PP Guard against current implemenation of VolumeMount.
<7> 3/8/90 PP Add support for minimal aliases. Change "hfileInfo" to
"hFileInfo'" to match Files.h change.
<6> 2/27/90 PP EjectableFilter recognizes a floppy of same name or same
creation date. Same name floppies will be fuzzy for more
stringent checks later on. Fix bugs in getting the driver name
for RAM based drivers.
<5> 2/6/90 PP Return nsvErr if neither empty nor occupied floppy drive is
found for floppy aliases.
<4> 1/22/90 PP PromptForUser has different interface.
To Do:
** 2.0 prp 12/15/1989 FindVolume uses different heuristics.
** 1.9 prp 11/30/1989 PromptForUser call forces to provide a bogus
** STARTCALLBACK routine. Take this out when PromptForUser is fixed
** correctly.
** 1.8 prp 11/27/1989 Add SwitchDisk dialog for Ejectable floppies.
** 1.7 prp 10/30/1989 ¥ Handle 'paramErr' returned by _VolumeMount differently
** in AL_mountVol
** 1.6 prp 10/17/1989 Aliases did not work on 68000 machines. Fixed odd
** addressing in variable length info structure.
** 1.5 prp 10/13/1989 Add routines 'AL_appendPString' and 'AL_displayAlert'.
** Also, Appleshare volume auto mount uses 'PromptForUser' routine
** instead of old code.
** 1.4 prp 10/02/1989 AL_filterFile routine has additional param that fixes
** bug in filtering.
** 1.3 prp 09/18/1989 Added AL_filterFile routine to do client filtering of
** alias matches.
** 1.2 prp 09/06/1989 Changes from CodeReview.
** 1.1 prp 08/07/1989 Add automatic volume mount support.
** 1.0 prp 06/12/1989 Initial release.
***/
/*********************************************************************
*
* File: alUtil.c
* Project: Alias Manager
* Contains: utility routines
* Written by: Prashant Patel
*
* Copyright 1989, 1992 by Apple Computer, Inc.
* All Rights Reserved.
*
**********************************************************************/
/**********************************************************************
*************** Public Include files *******************
*********************************************************************/
#include "Aliases.h"
/**********************************************************************
*************** Private Include files *******************
*********************************************************************/
#include "aliasPriv.h"
#include "aliasDlogPriv.h"
/**********************************************************************
*************** External C Include files ***************
*********************************************************************/
#ifndef __MEMORY__
#include <Memory.h>
#endif
#ifndef __ERRORS__
#include <Errors.h>
#endif
#ifndef __DIALOGS__
#include <Dialogs.h>
#endif
#ifndef __TOOLUTILS__
#include <ToolUtils.h>
#endif
#ifndef __RESOURCES__
#include <Resources.h>
#endif
#ifndef __SCRPIT__
#include <Script.h>
#endif
#ifndef __DISKS__
#include <Disks.h>
#endif
#ifndef __DEVICES__
#include <Devices.h>
#endif
#ifndef __PPCTOOLBOX__
#include <PPCToolbox.h>
#endif
#ifndef __GESTALTEQU__
#include <GestaltEqu.h>
#endif
/*********************************************************************
******** private type definitions ***********************************
*********************************************************************/
typedef struct {
AliasPtrPriv aptr; // pointer to locked AliasRecord
short vRefNum; // volume ref num of mounted volume
Boolean needsUpdate; // did any info about volume change?
} EjectableFilterParams;
typedef struct {
VolumeLocation *vinfoPtr; // pointer to volume mount info data
OSErr errFromVolMount; // error from volume mount
short vRefNum; // volume ref num of mounted volume
} PromptFilterParams;
/* Reply buffer for ASPGetStatus (mapped to FPGetServerInfo) call as described in
AFP Engineering Tech Notes. */
typedef struct {
short machineTypeOffset;
short AFPversOffset;
short UAMStringsOffset;
short iconMaskOffset;
short flags;
Str31 serverName;
Str15 machineType;
char variableData[128+256];
} ASPGetStatusReplyBuf;
/*********************************************************************
*************** Is it a full pathname? ************************
*********************************************************************/
pascal Boolean ALI_isFullpath(const unsigned char *path, // I pointer to a path name
register short len) // I length of the pathname
// If the first character of a pathname is a colon, or if the pathname contains
// no colons, it must be a partial pathname; otherwise it's a full pathname.
{
register short i = 0; // for loop index
register unsigned char *s = path; // pointer to input full or partial filename
if (*s == kChrSeparator) // it is a partial pathname
return (FALSE);
else {
while (++i <= len) { // any colon in the pathname?
if (*s++ == kChrSeparator)
return (TRUE);
}
}
return (FALSE);
} // end of AL_isFullpath routine
/*********************************************************************
*************** parse volumename ****************************
*********************************************************************/
pascal void AL_getVolname(const unsigned char *fname, //I pointer to a file specification
register short len, //I length of the pathname
StringPtr vname) //O string pointer to returned volume name
{
register short i = 0; // for loop index
register unsigned char *s = fname; // pointer to input file specification
register unsigned char *d = vname+1; // pointer to output volumename
if (len > (sizeof(Str255)-1)) // maximum length of returned volumename can't exceed!
len = sizeof(Str255) - 1;
while (++i <= len) // locate volume name separator char
if ((*d++ = *s++) == kChrSeparator) // copy all chars including separator
break;
Length(vname) = i-1; // length of the volume name minus the separator char
} // end of AL_getVolname routine
/*********************************************************************
*************** parse filename ******************************
*********************************************************************/
pascal void ALI_getFilename(const unsigned char *path, //I pointer to a path specification
register short len, //I length of the pathname
StringPtr fname) //O string pointer to returned filename
{
// given a full pathname or a partial pathname, return the filename
// component.
register short i = 0; // loop index
register unsigned char *s = path; // pointer to input full or partial filename
s += len; // point beyond the last character
while (i < len) {
if (*--s == kChrSeparator) {
len = i; // don't count it in filename
++s; // do not copy the separator character
break;
}
i++;
}
if (len > (sizeof(Str255)-1)) // maximum length of returned filename can't exceed!
len = sizeof(Str255) - 1;
Length(fname) = len; // length of returned filename
BlockMove (s, fname+1, len); // store resultant string
} // end of AL_getFilename routine
/*********************************************************************
*************** strip filename ******************************
*********************************************************************/
pascal void ALI_stripFilename(const unsigned char *path, //I pointer to a path specification
register short len, //I length of the pathname
StringPtr fname) //O string pointer to returned stripped pathname
{
Str255 name;
// given a full pathname or a partial pathname, strip the filename
// component.
AL_getFilename (path, len, name);
Length(fname) = len - Length(name);
BlockMove ((Ptr)path, fname+1, Length(fname)); // store resultant string
} // end of AL_stripFilename routine
/*********************************************************************
*************** copy pascal string ***************************
*********************************************************************/
pascal void ALI_copyPString(const StringPtr source, //I string pointer to source string
StringPtr dest) //O string pointer to destination string
{
BlockMove ((Ptr)source, (Ptr)dest, Length(source)+1); // store resultant string
} // end of AL_copyPString routine
/*********************************************************************
*************** append pascal string *************************
*********************************************************************/
pascal void ALI_appendPString(const StringPtr source,//I string pointer to source string
StringPtr dest) //O string pointer to destination string
{
BlockMove ((Ptr)(source+1), (Ptr)(dest + (Length(dest)+1)),
Length(source)); // store resultant string
Length(dest) += Length(source);
} // end of AL_appendPString routine
/*********************************************************************
*************** comapare FileSystem fileName string *******
*********************************************************************/
pascal Boolean ALI_FSEqualString(const Str255 str1, //I string pointer to string one
const Str255 str2) //I string pointer to string two
{
return (EqualString (str1, str2, FALSE, TRUE));
} // end of AL_FSEqualString routine
/*********************************************************************
*************** comapare FileSystem string data by length **
*********************************************************************/
pascal Boolean AL_FSEqualStringByLength(const StringPtr s1,//I pointer to string one
const StringPtr s2, //I pointer to string two
register short len) //I length of name data block
{
Str255 str1; // store data 1 in string 1
Str255 str2; // store data 2 in string 2
if (len > (sizeof(Str255)-1)) // is it something we can pass to EqualString?
return (FALSE); // we can't, just be safe and say not equal
else if (len == 0) // empty strings are equal
return (TRUE);
Length(str1) = Length(str2) = len;
BlockMove ((Ptr)s1, (Ptr)(str1+1), len);
BlockMove ((Ptr)s2, (Ptr)(str2+1), len);
return (ALI_FSEqualString (str1, str2));
} // end of AL_FSEqualStringByLength routine
/*********************************************************************
*************** init a block with given char *****************
*********************************************************************/
pascal void ALI_BlockInit (const Ptr source, //I pointer to source block
const char withThisCh, //I init it with this char
register int len) //I length of block
{
register Ptr s = source;
while (len--)
*s++ = withThisCh;
} // end of AL_BlockInit routine
/*********************************************************************
*************** comapare two blocks *************************
*********************************************************************/
pascal Boolean ALI_BlockCompare(const Ptr block1, //I pointer to block one
const Ptr block2, //I pointer to block two
register int len) //I length of blocks
{
register Ptr s1 = block1;
register Ptr s2 = block2;
while (len--)
if (*s1++ != *s2++)
return (FALSE);
return (TRUE);
} // end of AL_BlockCompare routine
/*********************************************************************
*************** Display an alert message *****************************
*********************************************************************/
pascal void AL_displayAlert(short strIdx) //I index into STR# resource
{
Str255 localStr; // local string to be displayed in alert
GetIndString (localStr, kAliasResID, strIdx); // get the display string
ParamText (localStr, '', '', ''); // display our message
(void) StopAlert (kAlAlertID, NULL); // use our alert box
} // end of AL_displayAlert routine
/*********************************************************************
************** Do GetCatInfo from given parameters *****************
*********************************************************************/
pascal OSErr AL_getCatInfo(short vref, //I
long dir, //I
const StringPtr nam, //I
CInfoPBPtr thisCPBPtr) //I/O
{
OSErr error;
/* It is assumed that the ioFDirIndex field is set appropriately before calling
this routine. That field controls whether the info is obtained by name mode,
for a particular directory or by directory index. */
thisCPBPtr->hFileInfo.ioVRefNum = vref; // volume ref #
thisCPBPtr->hFileInfo.ioFVersNum = 0; // keep MFS happy!!!!
/* Because of a FileShare bug, whenever doing a GetCatInfo by name for a volume
which could be greater than 27 characters long, always do it instead by dirID and hence
longer than 27 character volume names work correctly. */
/* Be really paranoid about the bug fix because it already caused System heap trash in certain
circumstances. When a relative path was being looked in dirID 1, the name pointer points to
partial path in the alias record and the GetCatInfo will return the name of the volume when
lookup is changed to by dirID mode. This could cause data to be overwritten in heap.
Make this test really tight so that it is only for the particular bug fix. */
if (thisCPBPtr->hFileInfo.ioFDirIndex == 0 && dir == kVolRootDirID &&
nam != NULL && (Length(nam) >= (sizeof(Str27)-1)) && (*(nam+1) != kChrSeparator)) {
thisCPBPtr->hFileInfo.ioNamePtr = NULL; // donÕt use name pointer at all
thisCPBPtr->hFileInfo.ioDirID = kRootDirID; // look for the root dirID
thisCPBPtr->hFileInfo.ioFDirIndex = -1; // -1 index indicates dirID mode
error = PBGetCatInfoSync(thisCPBPtr);
thisCPBPtr->hFileInfo.ioNamePtr = nam; // set up PB as if we did by name
thisCPBPtr->hFileInfo.ioDirID = kVolRootDirID; // the directory we were told
thisCPBPtr->hFileInfo.ioFDirIndex = 0; // 0 index indicates by name mode
}
else {
thisCPBPtr->hFileInfo.ioNamePtr = nam; // passed name pointer
thisCPBPtr->hFileInfo.ioDirID = dir; // look in this directory
error = PBGetCatInfoSync(thisCPBPtr);
}
return error;
} // end of AL_getCatInfo routine
/*********************************************************************
*************** Validate an alias record handle *************
*********************************************************************/
OSErr AL_validateHandle(const AliasHandlePriv alias)
{
register AliasPtrPriv aptr;
if (alias == NULL)
return (paramErr);
aptr = *alias;
if ( (aptr->aliasSize < sizeof(AliasRecordPriv)) || // minimum number of bytes in the record?
(aptr->aliasVersion < kOldestSupportedAliasVersion) ||
(aptr->thisAliasKind < kFileAlias || aptr->thisAliasKind > kDirAlias) || // correct alias kind?
(aptr->volumeType < kInvalidValue || aptr->volumeType > kVolOtherEjectable) || // correct volume type?
(Length(aptr->volumeName) == 0 || Length(aptr->volumeName) > (sizeof(Str27)-1)) || // volume name reasonable length?
(Length(aptr->fileName) > (sizeof(Str63)-1)) // file name reasonable length?
)
return (paramErr); // Is corrupt handle error better?
else
return (noErr);
} // end of routine AL_validateHandle
/*********************************************************************
** Get pointer and length for various variable info in alias record **
*********************************************************************/
pascal char *AL_getVarPtr (const AliasPtrPriv aptr, //I alias record pointer
short which, //I which variable info
short *len) //O length of data
{
register varInfo *vptr; // pointer in variable length structure
register short i; // for loop index
vptr = (varInfo *) &aptr->vdata; // start at the beginning of variable info
for (i=kMaxMark-kFolderNm-1; i>=0; --i) {
if (vptr->what == which || vptr->what == kEndMark) // found a match or reached end, return data pointer
break;
else // point to the next variable entry
vptr = (varInfo *)((char *)vptr + ((vptr->len+1) & ~1) + sizeof(varInfo));
}
*len = vptr->len; // return length of data
return (vptr->data); // if not found, return end pointer
} // end of AL_getVarPtr routine
/*********************************************************************
**** Add an entry of variable length info of alias record **********
*********************************************************************/
pascal char *AL_addVarEntry (const AliasPtrPriv aptr, //I alias record pointer
short which, //I which variable info
short len, //I length of this varInfo entry
Ptr data) //I ptr to data to be stuffed, if any
{
register varInfo *vptr; // pointer in variable length structure
char *returnedDataPtr = NULL; // pointer to data area of added entry
/* this routine adds an entry at the end of other varInfo entries. If an endMarker is
being added, it means wiping out all entries. */
vptr = (varInfo *) &aptr->vdata; // start at the beginning of variable info
if (which != kEndMark) { // adding an endMarker means wipe out all entries
while (vptr->what != kEndMark) // look until the end marker is reached
vptr = (varInfo *)((char *)vptr + ((vptr->len+1) & ~1) + sizeof(varInfo)); // point to the next variable entry
// vptr now points to the place where a new entry should be added.
vptr->what = which; // added this kind of entry
vptr->len = len; // this is its length
if (data != NULL) // move data if it was given
BlockMove (data, vptr->data, len);
returnedDataPtr = vptr->data;
vptr = (varInfo *)((char *)vptr + ((vptr->len+1) & ~1) + sizeof(varInfo)); // point to the next variable entry
}
vptr->what = kEndMark;
vptr->len = 0; // no datalength for endMarker
return (returnedDataPtr); // return a pointer to the added entry's data area, null for end mark
} // end of AL_addVarEntry routine
/*********************************************************************
*************** Return a Drive Q Entry for a given drive num ********
*********************************************************************/
static DrvQElPtr GetDrvQForDrive(short driveNum) //I drive number
{
register DrvQElPtr drvQEntry; // drive queue entry
drvQEntry = (DrvQElPtr) GetDrvQHdr()->qHead; // get the header of the queue
while (drvQEntry != NULL) { // look at all drive queue entries
if (drvQEntry->dQDrive == driveNum) // driver entry we are looking for
break;
drvQEntry = (DrvQElPtr) drvQEntry->qLink; // next entry in the drive queue
}
return (drvQEntry);
} // end of GetDrvQForDrive routine
/*********************************************************************
*************** Does given drive support ejectable media? ***********
*********************************************************************/
static OSErr IsEjectable(short driveNum, //I drive number
Boolean *ejectable) //O supports ejectable media or not?
{
register DrvQElPtr drvQEntry; // drive queue entry
register long fourBytesFlag; // four bytes of flags preceding each drive queue entry
*ejectable = TRUE; // assume its ejectable
drvQEntry = GetDrvQForDrive(driveNum); // get the drive queue entry for this drive
if (drvQEntry != NULL) {
// four bytes of flags preceding each drive queue entry
fourBytesFlag = (*((long *)drvQEntry -1));
/* value 8 in byte 1 means nonejetctable disk in drive.
value $FC-$FF in byte 1 means disk was ejected within last 1.5 seconds. */
if ((fourBytesFlag & kNonEjectable) && (!(fourBytesFlag & kDiskWasEjected)))
*ejectable = FALSE;
return (noErr);
}
return (nsDrvErr);
} // end of IsEjectable routine
/*********************************************************************
******* Return real drive number and driver ref num for a volume ****
*********************************************************************/
pascal void AL_getDriveInfo(register HVolumeParam *vpbPtr, //I mounted volume's param block
short *dRefNum, //O driver reference number
short *driveNum) //O drive number
{
DrvQElPtr drvQEntry; // drive queue entry for this drive
*dRefNum = vpbPtr->ioVDRefNum;
*driveNum = vpbPtr->ioVDrvInfo;
/* Detect ejectable off-line volumes correctly. For ejectable off-line volumes,
ioVDrvInfo is 0 indicating an off-line volume and ioVDRefNum is the real drive number.
*/
if (*driveNum == 0) {
*driveNum = vpbPtr->ioVDRefNum;
drvQEntry = GetDrvQForDrive(*driveNum);
if (drvQEntry != NULL)
*dRefNum = drvQEntry->dQRefNum;
}
} // end of AL_getDriveInfo routine
/*********************************************************************
*************** Return driver name for a given driver ref num ******
*********************************************************************/
pascal void AL_getDriverName( short DRefNum, //I driver reference number
StringPtr drvrName) //O driver name
{
register DCtlPtr DCtlEntryPtr; // device control entry pointer
register Ptr driverPtr = NULL; // pointer to ROM driver or handle to RAM driver
DCtlHandle DCtlHandle; // device control entry handle
DCtlHandle = GetDCtlEntry (DRefNum);
if (DCtlHandle) {
DCtlEntryPtr = *DCtlHandle;
driverPtr = DCtlEntryPtr->dCtlDriver;
if (driverPtr && (DCtlEntryPtr->dCtlFlags & kRAMbasedDriver)) // driver is RAM-based
driverPtr = *((Ptr *)driverPtr);
}
if (driverPtr)
AL_copyPString((char *) (driverPtr+18), drvrName);
else
Length(drvrName)=0;
} // end of AL_getDriverName routine
/*********************************************************************
**** Convert numeric values into spaces of a given string ***********
*********************************************************************/
static void ConvertNumericToSpace(register StringPtr s, //I/O string converted in place
register short slen) //I length of string
{
register short i=0; // loop index
short whichByte; // which byte of the character
while (++i <= slen) {
whichByte = CharByte(s, 0);
if (whichByte == smSingleByte || whichByte == smLastByte) {
if ((CharType(s, 0) & (smcTypeMask | smcClassMask)) == (smCharPunct + smPunctNumber))
*s = ' '; // convert it to a blank
}
++s;
}
} // end of ConvertNumericToSpace routine
/*********************************************************************
**** Do driver names match for alias record and given DRefNum *******
*********************************************************************/
static Boolean DoDriversMatch(const AliasPtrPriv aptr, //I alias record pointer,
short DRefNum) //I driver reference number
{
Str255 drefDrvrName; // driver name from DRefNum
Str255 aliasDrvrName; // driver name from alias record
register short dlen; // length of driver name from DRefNum
short len; // length of driver name from alias record
char *s; // pointer to driver name in alias record
/* While comparing driver names, convert all numeric digits to spaces. This is to
correctly compare drivers that change their names dynamically depending upon
scsiID (e.g. DataPakDriver4 to DataPakDriver4 for Mass Micro Systems). Also,
even after conversion, just compare first 8 bytes of names. In all cases, this
should be sufficient to locate the correct driver in cases where Driver version
numbers may be appended at the end.
*/
AL_getDriverName (DRefNum, drefDrvrName);
dlen = Length(drefDrvrName);
ConvertNumericToSpace (drefDrvrName+1, dlen);
s = AL_getVarPtr(aptr, kDrvrNm, &len);
Length(aliasDrvrName) = len;
BlockMove (s, aliasDrvrName+1, len);
ConvertNumericToSpace (aliasDrvrName+1, len);
if (len > dlen)
len = dlen;
return (AL_FSEqualStringByLength (drefDrvrName+1, aliasDrvrName+1, len <= 8 ? len : 8));
} // end of DoDriversMatch routine
/*********************************************************************
**** Is It an alias for a AFP media volume? *************************
*********************************************************************/
Boolean AL_isAFPmedia(const AliasPtrPriv aptr) //I alias record pointer
{
return ((aptr->volumeAttributes & kVolAFPmedia) ? TRUE : FALSE);
} // end of AL_isAFPmedia routine
/*********************************************************************
**** Is Mounted volume an AppleShare volume ? ************************
*********************************************************************/
static Boolean IsAppleShare(short FSID) //I from given FSID
{
/*
Is the following the right way to do this? DTS Tech note #66 of June 1990 says so.
Actually, better way may be doing GetVolMountInfo on the volume and comparing the
media type to be 'afpm'. But this is expensive.
*/
return (FSID >= 0x0001 && FSID <= 0x0016);
} // end of IsAppleShare routine
/*********************************************************************
**** Compute volume type from given vpb ****************************
*********************************************************************/
AliasVolType AL_getVolType (register HVolumeParam *vpbPtr) //I mounted volume's param block
{
register AliasVolType vpbVolType; // volume type derived from vpb
long diskSize; // disk size in # of bytes
OSErr err; // return code
Boolean ejectable; // Does drive support ejectable media or not?
short dRefNum; // driver reference number
short driveNum; // drive number
vpbVolType = kVolHD; // assume local hard disk
AL_getDriveInfo(vpbPtr, &dRefNum, &driveNum);
/**** the following code is not the best way to determine if a volume is floppy
or not. It should be replaced with a precise way of determining this. ****/
if (dRefNum == kSONYRefNum && vpbPtr->ioVFSID == kFileManagerID) {
diskSize = vpbPtr->ioVNmAlBlks * vpbPtr->ioVAlBlkSiz; // compute size in bytes
if (diskSize <= k400K)
vpbVolType = kVolFloppy400K; // <= 400K of storage, assume a 400K floppy
else if (diskSize <= k800K)
vpbVolType = kVolFloppy800K; // <= 800K of storage, assume a 800K floppy
else if (diskSize < kMinHDSize)
vpbVolType = kVolFloppy1400K; // less than 2 Mb of storage, assume a 1.4Mb floppy
} else { // Is it Apple CDRom drive or other ejectable non-floppy?
err = IsEjectable(driveNum, &ejectable);
if (err == noErr && ejectable) // it is ejectable, but not a floppy, CDROM or HD
vpbVolType = kVolOtherEjectable;
else if (vpbPtr->ioVFSID != kFileManagerID) // handled by an external file system
vpbVolType = kVolForeign;
}
return (vpbVolType);
} // end of AL_getVolType routine
/*********************************************************************
**** Return correct data pointer from AFP volume mount info *******
*********************************************************************/
static char *GetAFPdataPointer (VolumeLocation *vloc, //I volume location pointer
short kind) // what kind of data? zoneName, serverName, userName etc.
{
AFPVolMountInfo *afp; // afp vol mount info block pointer
short offset=0;
afp = (AFPVolMountInfo *) vloc;
switch (kind) {
case asiZoneName:
offset = afp->zoneNameOffset;
break;
case asiServerName:
offset = afp->serverNameOffset;
break;
case asiVolumeName:
offset = afp->volNameOffset;
break;
case asiUserName:
offset = afp->userNameOffset;
break;
case asiUserPswd:
offset = afp->userPasswordOffset;
break;
case asiVolumePswd:
offset = afp->volPasswordOffset;
break;
}
return (((char *) vloc) + offset);
} // end of GetAFPdataPointer routine
/*********************************************************************
**** Return zone/server/user name from alias record ***************
*********************************************************************/
char *AL_getAFPinfo (const AliasPtrPriv aptr, //I alias record pointer
short kind) // what kind of info? zoneName, serverName or userName
{
short len; // length of variable info data
return (GetAFPdataPointer((VolumeLocation *) AL_getVarPtr (aptr, kVolMntInfo, &len), kind));
} // end of AL_getAFPinfo routine
/*********************************************************************
*************** Get my zone name ******************************
*********************************************************************/
/* .XPP driver call for getting my current zone name using GetMyZone as described
in tech note #250.
*/
void AL_GetMyZonePhs2 (StringPtr zoneName) //I zone name pointer
{
XCallParam xpb;
xpb.ioRefNum = xppRefNum;
xpb.csCode = xCall;
xpb.xppSubCode = zipGetMyZone;
xpb.xppTimeout = 3; // timeout period for .XPP
xpb.xppRetry = 4; // retry count
xpb.zipBuffPtr = (Ptr) zoneName;
xpb.zipInfoField[0] = 0; /* always 0 */
xpb.zipInfoField[1] = 0; /* always 0 */
if ((!GetBridgeAddress()) || (PBControl((ParmBlkPtr)&xpb, FALSE) != noErr)) {
Length(zoneName) = 1; // always return local zone named '*' if zone name can't be got
zoneName[1] = '*'; // local zone
}
} // end of AL_GetMyZonePhs2 routine
/*********************************************************************
*************** Get my server name ******************************
*********************************************************************/
void AL_GetMyServer (StringPtr serverName) //I server name pointer
{
StringHandle strH; // server name string handle
Length(serverName) = 0; // return null string if server name can't be gotten
strH = GetString(kServerNameID);
if (strH != NULL)
BlockMove ((*strH), serverName, Length(*strH)+1); //<SM4>
} // end of AL_GetMyServer routine
/*********************************************************************
*************** Change alias record to auxiliary info ************
*********************************************************************/
void AL_changeToAuxInfo (register AliasPtrPriv aptr, //I pointer to locked AliasRecord
register AuxAliasInfo *auxPtr) //I pointer to auxiliary data
{
AL_BlockInit ((Ptr)aptr->volumeName, '\0', sizeof(Str27));
AL_copyPString (auxPtr->auxVolName, aptr->volumeName);
aptr->volumeCrDate = auxPtr->auxVolCrDate;
aptr->volumeType = auxPtr->auxVolType;
aptr->parDirID = auxPtr->auxDirIDs.auxParDirID;
aptr->fileNum = auxPtr->auxDirIDs.auxFileNum;
} // end of ChangeToAuxInfo routine
/**********************************************************************
*************** Get volume mount info ***********************
*********************************************************************/
pascal OSErr AL_getVolMountInfo(short vRefNum, //I volume reference number
VolumeLocationHandle *vloc) //I/O volume location record handle
{
OSErr err; // result code, assume failure
short vmntInfoSize; // volume mount info size
err = GetVolMountInfoSize(vRefNum, &vmntInfoSize);
if (err == noErr && vmntInfoSize > 0) {
*vloc = (VolumeLocationHandle) NewHandleClear(vmntInfoSize);
if (*vloc == NULL) // no heap space
return (MemError());
HLock((Handle)(*vloc)); // lock the newly created volume location record
err = GetVolMountInfo (vRefNum, (**vloc));
HUnlock((Handle)(*vloc)); // lock the newly created volume location record
if (err != noErr) {
DisposHandle((Handle)(*vloc)); // fatal error, return NULL
*vloc = NULL;
}
}
return (err);
} // end of AL_getVolMountInfo routine
/*********************************************************************
**** Does volume mount info match to the one stored in alias ? *****
*********************************************************************/
static Boolean ZoneAndServerMatches (const AliasPtrPriv aptr, //I alias record pointer
short vRefNum) //I volume reference number
{
VolumeLocationHandle vloc=NULL; // volume location data handle
Boolean answer = TRUE; // assume they match
if (aptr->volumeAttributes & kVolMntExists) {
if (AL_getVolMountInfo (vRefNum, &vloc) == noErr &&
(*vloc)->media == kAFPmedia)
answer = (FSEqualString(AL_getAFPinfo (aptr, asiZoneName),
GetAFPdataPointer((*vloc), asiZoneName)) &&
FSEqualString(AL_getAFPinfo (aptr, asiServerName),
GetAFPdataPointer((*vloc), asiServerName)));
else
answer = FALSE;
} // if no volume mount info was stored, assume that it matches
if (vloc != NULL)
DisposHandle((Handle)vloc);
return (answer);
} // end of ZoneAndServerMatches routine
/*********************************************************************
**** Find a VCB entry that matches a drive number ***************
*********************************************************************/
static VCB* FindVCB(short drvNum)
{
register VCB* vcbp;
for (vcbp = (VCB*)(GetVCBQHdr()->qHead);
vcbp && vcbp->vcbDrvNum != drvNum;
vcbp = (VCB*)vcbp->qLink)
;
return vcbp;
}
/*********************************************************************
**** Get AppleShare time difference for the mounted volume *******
*********************************************************************/
static long AL_getAppleShareTimeDiff (VCB* vcbp) //I mounted volume's param block
{
return (vcbp == nil ? 0 :
*((long *) (((Ptr)vcbp) + kVCBsrvrTimeOffset)) - kSrvrTimeBase);
} // end of AL_getAppleShareTimeOffset routine
/*********************************************************************
**** Fix a creation date if it comes from AppleSgare volume *******
**** and the alias is for an AppleShare volume. *******
*********************************************************************/
unsigned long AL_fixedCreationDate (HVolumeParam *vpbPtr, //I mounted volume's param block (if nil, use passed vRefNum)
short vref, //I volume reference number/WD ref
unsigned long dateToFix) //I date needing adjustment
{
HVolumeParam vpb; //I mounted volume's param block
unsigned long answer = dateToFix;
// Is the volume an AppleShare Volume?
// In such a case, adjust the creation date so that is the real creation date on server.
if (vpbPtr == nil && AL_findVolByVRefNum (vref, &vpb) == noErr)
vpbPtr = &vpb;
if (vpbPtr != nil && IsAppleShare(vpbPtr->ioVFSID))
answer = (long)dateToFix + AL_getAppleShareTimeDiff (FindVCB(vpbPtr->ioVDrvInfo));
return (answer);
} // end of AL_fixedCreationDate routine
/*********************************************************************
**** Check if given volume type matches given vpb derived volType **
*********************************************************************/
static Boolean AL_volTypeMatches (register const AliasPtrPriv aptr, //I alias record pointer
HVolumeParam *vpbPtr, //I mounted volume's param block
register AliasVolType *vpbVolTypePtr)
{
short dRefNum; // driver reference number
short driveNum; // drive number
*vpbVolTypePtr = AL_getVolType(vpbPtr); // get derived volume type from given vpb
if (aptr->volumeType == (*vpbVolTypePtr)) { // type matches, continue matching other criterion
if ((*vpbVolTypePtr) == kVolForeign) { // for HFS File System ID, no other criterion
if ((!AL_isAFPmedia(aptr)) || ZoneAndServerMatches(aptr, vpbPtr->ioVRefNum)) // zone and server matches
return (TRUE);
}
else if (aptr->volumeType == kVolOtherEjectable) { // make sure the drivers match
AL_getDriveInfo(vpbPtr, &dRefNum, &driveNum);
return (DoDriversMatch(aptr, dRefNum));
}
else
return (TRUE);
}
return (FALSE);
} // end of AL_volTypeMatches routine
/*********************************************************************
**** Check if given volume's real dirID matches ********************
*********************************************************************/
static Boolean SharePointCopy (register const AliasPtrPriv aptr, //I alias record pointer
HVolumeParam *vpbPtr) //I mounted volume's param block
{
short auxLen; // length of auxiliary real parent dirID
AuxAliasDirIDs *realDirPtr; // pointer to real directory ID info
FIDParam hpb; // H parameter block for fileIDs
if (AL_isAFPmedia(aptr) && aptr->volumeType == kVolForeign &&
(aptr->volumeAttributes & kAuxRealDirID)) { // real dirID info exists
realDirPtr = (AuxAliasDirIDs *) AL_getVarPtr(aptr, kAuxRealDirID, &auxLen);
if (realDirPtr->auxRealRootDirID != kInvalidValue &&
auxLen == sizeof(AuxAliasDirIDs)) { // catch old version incompatibility
hpb.ioNamePtr = NULL; // get the real parent dirID for this shared volume
hpb.ioVRefNum = vpbPtr->ioVRefNum; // setup fileID call parameters
hpb.ioSrcDirID = kRootDirID;
if (PBCreateFileIDRef ((HParmBlkPtr)&hpb, FALSE) == noErr &&
realDirPtr->auxRealRootDirID != hpb.ioFileID) // does not match with value in alias
return (TRUE); // Not the real thing, a duplicate of original Shared folder
}
}
return (FALSE);
} // end of SharePointCopy routine
/*********************************************************************
**** Check if any mounted volume matches given criterion *******
*********************************************************************/
static pascal OSErr AL_checkIfAnyMatchesCriterion (const AliasPtrPriv aptr, //I alias record pointer
short matchMask, // match criterion
HVolumeParam *vpbPtr) //I/O mounted volume's param block if matches criterion
{
OSErr err; // result code
Str27 localName; // temporary local volume name
AliasVolType vpbVolType; // vpb derived volume type
Boolean needsUpdate; // to satisfy the call, it is ignored
Boolean volTypeMatches; // Do volume types match?
vpbPtr->ioVolIndex = 1;
vpbPtr->ioNamePtr = localName; // return name
while ((err = PBHGetVInfo ((HParmBlkPtr)vpbPtr, FALSE)) == noErr) {
++(vpbPtr->ioVolIndex); // next mounted volume
/* Audio CDs have dynamically assigned names and creation dates. Hence, recognize
any audio CD that is mounted as the correct one.
*/
if (vpbPtr->ioVFSID == kAudioFSID && aptr->volumeFSID == kAudioFSID)
break;
if ((matchMask & kMatchCrDate) && (aptr->volumeCrDate != AL_fixedCreationDate(vpbPtr, vpbPtr->ioVRefNum, vpbPtr->ioVCrDate)))
continue;
if ((matchMask & kMatchName) &&
(!FSEqualString (localName, aptr->volumeName)))
continue;
volTypeMatches = AL_volTypeMatches (aptr, vpbPtr, &vpbVolType); // Is it the right type?
if (volTypeMatches && (!SharePointCopy (aptr, vpbPtr))) // Make sure it is not a FileShare share point copy
break;
/* For FileShare aliases, relax type match failure if creation date and Network
info matches.
*/
if ((matchMask & kMatchCrDate) && AL_isAFPmedia(aptr) && (!volTypeMatches)) {
/* On local server, resoving an alias created from client. */
if (aptr->volumeType == kVolForeign && AL_isItSelf(aptr, &needsUpdate))
break;
/* On client, resoving an alias created on local server. */
if (aptr->volumeType != kVolForeign && vpbPtr->ioVFSID != kFileManagerID &&
ZoneAndServerMatches(aptr, vpbPtr->ioVRefNum))
break;
}
}
return (err);
} // end of AL_checkIfAnyMatchesCriterion routine
/*********************************************************************
**** Check if a particular volume is mounted or not ***************
*********************************************************************/
OSErr AL_checkIfMounted (const AliasPtrPriv aptr, //I alias record pointer
short *vref, //O mounted volume's vref number
Boolean *needsUpdate) //O does VolMount info need updating? Set onlyif needs updating
{
OSErr err; // result code
HVolumeParam vpb; // volume parameter block
AliasVolType vpbVolType; // vpb derived volume type
Boolean volTypeMatch=false; // Does the volume type match with alias record?
err = AL_findVolByName (aptr->volumeName, &vpb);
// for fullpath minimal aliases, either a volume by same name found or no such volume
if ((err != noErr && err != nsvErr) || aptr->volumeType == kInvalidValue)
goto EXIT;
/* If volume types do not match but creation date and name matches and if the derived volume
type is foreign, assume it is a FileShare case where the owner is accessing the alias from
a remote machine and hence set it to true.
*/
/* If volume types do not match but creation date and name matches and if the original volume
type is foreign, assume it is a FileShare case where the remote auxiliary info switch has occurred
assuming that it is not the same node. The server name has probably changed from the
FileShare by the user. So, eventhough the alias is for a foreign volume and current matching
disk is non-foreign, assume a match.
*/
if (err == noErr) {
volTypeMatch = AL_volTypeMatches(aptr, &vpb, &vpbVolType);
vpb.ioVCrDate = AL_fixedCreationDate(&vpb, vpb.ioVRefNum, vpb.ioVCrDate); // fix vol CrDate for AppleShare volumes
if (vpb.ioVCrDate == aptr->volumeCrDate &&
(aptr->volumeType == kVolForeign || vpbVolType == kVolForeign)) {
*needsUpdate = (!volTypeMatch);
volTypeMatch = TRUE;
}
}
/* If the creation date and type matches, found the volume we are looking for. */
if (err != noErr || (!volTypeMatch) || vpb.ioVCrDate != aptr->volumeCrDate) {
/* Try to find another by same name and matching creation date and type. */
err = AL_checkIfAnyMatchesCriterion (aptr, kMatchCrDate + kMatchName, &vpb);
if (err == nsvErr) {
/* Try to find another by same creation date and matching type. */
err = AL_checkIfAnyMatchesCriterion (aptr, kMatchCrDate, &vpb);
if (err == nsvErr)
/* Try to find another by same name and matching type. */
err = AL_checkIfAnyMatchesCriterion (aptr, kMatchName, &vpb);
if (err == noErr) // yes, we found it, but name or creation date are different
*needsUpdate = TRUE; // set the update needed flag
}
}
EXIT:
if (err == noErr)
*vref = vpb.ioVRefNum;
return (err);
} // end of AL_checkIfMounted routine
/*********************************************************************
**** Callback routine for PromptForUser call *******************
*********************************************************************/
static OSErr PromptForUserFilter (StringPtr password, //I
StringPtr name, //I
short method, //I
Ptr yourDataPtr) //I
{
OSErr err=noErr; // result code
PromptFilterParams *paramRecPtr; // parameters passed to prompt filter
Str127 localStr; // local string to be displayed in alert
Str31 localStr2; // local string to be displayed in alert
/* Validate the input. */
if (method == kScrambledPswdLogin && Length(name) == 0) // zero length name for a registered user is invalid
err = afpParmErr;
if (err == noErr) {
paramRecPtr = (PromptFilterParams *) yourDataPtr;
AL_copyPString (name, GetAFPdataPointer(paramRecPtr->vinfoPtr, asiUserName));
AL_copyPString (password, GetAFPdataPointer(paramRecPtr->vinfoPtr, asiUserPswd));
paramRecPtr->errFromVolMount = err = VolumeMount(paramRecPtr->vinfoPtr, &(paramRecPtr->vRefNum));
}
if (err == afpUserNotAuth) // ask for the password again
AL_displayAlert(kBadPswdIdx);
else if (err == afpParmErr) { // unknown user
GetIndString (localStr, kAliasResID, kUnknownUsrIdx); // get the display string
AL_appendPString (name, localStr); // append the typed user name
GetIndString (localStr2, kAliasResID, kUnknownUsrIdx2); // get trailing part of display message
AL_appendPString (localStr2, localStr);
ParamText (localStr, '', '', ''); // display our message
(void) StopAlert (kAlAlertID, NULL); // use our alert box
}
else // any other fatal error or no err, get out of prompt dialog and return the error
err = noErr;
return (err == afpUserNotAuth ? kSelectPswdItem :
err == afpParmErr ? kSelectUserNameItem : err);
} // end of PromptForUserFilter routine
/*********************************************************************
**** Lookup the given server and return its address ***************
*********************************************************************/
static OSErr LookupServer (const AliasPtrPriv aptr, //I alias record pointer
AddrBlock *entityAddr) //O entity address
{
MPPParamBlock checkNBP; // use NBP to confirm the name
EntityName entity; // packed entity name, (server name, "AFPServer", zone name)
char rbuf[128]; // return buffer (at least sizeof (EntityName) + sizeof (AddrBlock) + 4)
GetIndString (&rbuf[0], kAliasResID, kAFPServerIdx); // entityType is "AFPServer"
NBPSetEntity ((Ptr) &entity, AL_getAFPinfo (aptr, asiServerName), // zone and server name from alias record
rbuf, AL_getAFPinfo (aptr, asiZoneName));
checkNBP.NBPentityPtr = (Ptr) &entity;
checkNBP.NBPretBuffSize = sizeof (EntityName) + sizeof (AddrBlock) + 4; // as dictated by NBP
checkNBP.NBPretBuffPtr = &rbuf;
checkNBP.NBPmaxToGet = 1; // just this particular server
checkNBP.NBPinterval = 1; // allow 8 ticks before looking up again
checkNBP.NBPcount = 2; // allow 2 max retries
if (PLookupName ((MPPPBPtr) &checkNBP, FALSE) == noErr && checkNBP.NBPnumGotten == 1) {
(void) NBPExtract (rbuf, 1, 1, &entity, entityAddr);
return (noErr);
} else
return (afpNoServer);
} // end of LookupServer routine
/*********************************************************************
**** Return info about server ***********************************
*********************************************************************/
static void GetServerInfo (const AliasPtrPriv aptr, //I alias record pointer
Boolean *guestLoginAllowed, //O Does it allow guest login?
Boolean *IsItSelf) //O Is it ourself?
{
XPPPrmBlk getStatus; // param block for ASPGetStatus call
AddrBlock entityAddr; // entity address
short myNode; // caller's node ID
short myNet; // caller's network #
ASPGetStatusReplyBuf rbuf; // reply buffer for GetStatus call
Ptr UAMStrPtr; // pointer into UAM strings
unsigned char cntOfUAMStrs; // count of UAM strings
unsigned char index; // loop index
Str15 NoUserAuthent; // string represting "No User Authent"
*IsItSelf = FALSE; // assume it is not self
*guestLoginAllowed = TRUE; // assume guest login is allowed
if (LookupServer (aptr, &entityAddr) == noErr) {
(void) GetNodeAddress (&myNode, &myNet);
if (myNet == entityAddr.aNet && myNode == entityAddr.aNode) {
*IsItSelf = TRUE;
return;
}
getStatus.ioRefNum = xppRefNum;
getStatus.aspTimeout = 1; // allow 8 ticks before getting server info again
getStatus.aspRetry = 2; // allow 2 max retries
*(AddrBlock *)(&getStatus.cbSize) = entityAddr; // lookup info for this server
getStatus.rbSize = sizeof(ASPGetStatusReplyBuf);
getStatus.rbPtr = (Ptr) &rbuf;
if (ASPGetStatus((XPPParmBlkPtr) &getStatus, FALSE) == noErr) {
UAMStrPtr = ((Ptr) &rbuf) + rbuf.UAMStringsOffset;
cntOfUAMStrs = *UAMStrPtr++;
GetIndString (NoUserAuthent, kAliasResID, kNoUserAuthentIdx); // "No User Authent" string
for (index=1; index<=cntOfUAMStrs; ++index)
if (FSEqualString(NoUserAuthent, UAMStrPtr))
break;
else
UAMStrPtr += (Length(UAMStrPtr) +1); // point to the next UAM string
if (index > cntOfUAMStrs) // guest login is disallowed
*guestLoginAllowed = FALSE;
}
}
} // end of GetServerInfo routine
/*********************************************************************
**** Is any user currently logged on to server? *******************
*********************************************************************/
static Boolean AlreadyLoggedOnServer (const AliasPtrPriv aptr) //I alias record pointer
{
register VCB* vcbp; // volume control block pointer
vcbp = (VCB*)(GetVCBQHdr()->qHead);
while (vcbp) {
if (IsAppleShare(vcbp->vcbFSID) && ZoneAndServerMatches(aptr, vcbp->vcbVRefNum))
return(TRUE);
vcbp = (VCB*)vcbp->qLink;
}
return(FALSE);
} // end of AlreadyLoggedOnServer routine
/********************************************************************
**** Is AppleTalk active or not ? ******************************
*********************************************************************/
static Boolean AppleTalkActive ()
{
OSErr err; // result code
long appletalk; // gestalt result
// Check if appletalk is active (gestalt returns 0 if it isn't)
err = Gestalt(gestaltAppleTalkVersion, &appletalk);
return (err == noErr && appletalk != 0);
} // end of AppleTalkActive routine
/*********************************************************************
*** Get copied volume location data from alias record **********
*********************************************************************/
static OSErr GetVolumeLocation (const AliasPtrPriv aptr, //I alias record pointer
VolumeLocationHandle *vloc) //I/O volume location record handle
{
VolumeLocation *vlocInAlias; // volume location data pointer in alias record
short vlocSize; // volume location info size
vlocInAlias = (VolumeLocation *) AL_getVarPtr (aptr, kVolMntInfo, &vlocSize);
return (PtrToHand((Ptr)vlocInAlias, (Handle *)vloc, vlocSize));
} // end of GetVolumeLocation routine
/*********************************************************************
*** Auto mount a volume that supports AFP media (e.g. APPleShare)*****
*********************************************************************/
static OSErr AL_mountAFP (const AliasPtrPriv aptr, //I alias record pointer
short *vref, //O mounted volume's vref number
Boolean *needsUpdate, //O does VolMount info need updating?
Boolean UIallowed, //I Is user interface allowed or not?
AuxAliasInfo *auxInfo) //I auxiliary alias record info
{
OSErr err, err2; // result code
char *userPtr; // user name pointer
char *volNamePtr; // volume name pointer
Str127 titleStr; // title string for PromptForUser dialog
Str31 titleStr2; // a portion of the title string (also used to save user name)
short loginMethod; // authentication method used to 'login'
Handle iconHndl; // handle to displayed icon
PromptFilterParams paramRec; // parameters passed to prompt filter
VolumeLocationHandle vlocH=NULL; // copied volume location data handle
VolumeLocation *vloc; // volume location data pointer in copied handle
Boolean wasAlreadyMounted; // was volume already mounted?
Boolean guestLoginAllowed; // Guest login allowed on this server?
Boolean isItSelf; // Is the caller's server same as the one in alias record?
if (GetVolumeLocation(aptr, &vlocH) != noErr)
return (memFullErr);
HLock((Handle)(vlocH)); // lock the newly created volume location record
vloc = *vlocH; // get the volume location record pointer
/* Put possibly switched volume name(e.g. shared folder name vs. the real volume name)
in the volume location record for the VolumeMount call.
*/
volNamePtr = GetAFPdataPointer(vloc, asiVolumeName);
AL_copyPString (aptr->volumeName, volNamePtr);
userPtr = GetAFPdataPointer(vloc, asiUserName);
if (Length(userPtr) > 0 && (!AlreadyLoggedOnServer(aptr))) { // bring up the PromptForUser dialog
char *userPswdPtr; // user password pointer
if (AppleTalkActive())
GetServerInfo (aptr, &guestLoginAllowed, &isItSelf);
else
isItSelf = TRUE; // force a failure if AppleTalk inactive
/* can't do mounting of yourself OR if no user interface allowed. */
if (isItSelf || (!UIallowed) || AL_isItSelf(aptr, needsUpdate)) {
err = nsvErr;
goto EXIT;
}
GetIndString (titleStr, kAliasResID, kMountVolIdx);
AL_appendPString (volNamePtr, titleStr);
GetIndString (titleStr2, kAliasResID, kMountVolAsIdx);
AL_appendPString (titleStr2, titleStr);
iconHndl = GetResource ('ICON', kAppleShareICONID);
loginMethod = kScrambledPswdLogin; // scrambled password
AL_copyPString (userPtr, titleStr2); // save original user name
userPswdPtr = GetAFPdataPointer(vloc, asiUserPswd);
Length(userPswdPtr) = 0; // no input password
paramRec.vinfoPtr = vloc; // set up the parameter block for promptFilter
err2 = PromptForUser(titleStr, iconHndl, userPtr, userPswdPtr,
kSelectPswdItem, guestLoginAllowed, &loginMethod,
(ProcPtr)PromptForUserFilter, (Ptr)&paramRec);
if (err2 == noErr) { // user supplied a password and volume mount was successful
err = paramRec.errFromVolMount; // error from volume mount
if (err == noErr) {
*vref = paramRec.vRefNum; // volume ref number from volume mount
/* Do not update change from registered user to a guest. */
if (Length(userPtr) != 0 && (!FSEqualString (titleStr2, userPtr)))
*needsUpdate = TRUE;
}
} else { // user canceled out of PromptForUser dialog
err = userCanceledErr;
goto EXIT;
}
}
else // It was a Guest Login alias
err = VolumeMount(vloc, vref);
/* For FileShare, if we are on the client side as a Super User who can see "entire
volume", we need to try to mount the real volume also. Just copy the real volume
name in the VolMountInfo record, keep the same password and do VolumeMount.
*/
if (err == paramErr && auxInfo != NULL) {
AL_copyPString (auxInfo->auxVolName, volNamePtr);
AL_changeToAuxInfo(aptr, auxInfo); // from now on, resolve from real data that was in alias record
err = VolumeMount(vloc, vref);
}
/* If try to login as Guest wehere there is no Guest login is allowed, VolumeMount returns
paramErr and the user name length is zero. Map the error to afpAccessDenied.
*/
if (err == paramErr && Length(userPtr) == 0)
err = afpAccessDenied;
wasAlreadyMounted = (err == afpAlreadyMounted);
if (wasAlreadyMounted) { // volume was already mounted (VolumeMount says so)
HVolumeParam vpb; // volume parameter block
err = AL_findVolByName (volNamePtr, &vpb); // VolumeMount did not return the VRefNum
*vref = vpb.ioVRefNum;
}
if (err == noErr) {
CInfoPBRec cpb; // catalog info parameter block
/*
Has user's privileges been revoked since the alias was last used? If so, unmount
the volume and return afpAccessDenied error.
*/
cpb.hFileInfo.ioFDirIndex = 0; // find by name mode
err = AL_getCatInfo (*vref, kVolRootDirID, volNamePtr, &cpb);
if (err == noErr &&
/* this is bad. Files.h does not have a nice way to access this field (byte #31) */
(cpb.dirInfo.filler2 /*ioACUser*/ & kServerVolNoPrivs) == kServerVolNoPrivs) { // no privileges for that volume
if (!wasAlreadyMounted) // we mounted it, unmount it.
(void) UnmountVol (NULL, *vref); // no privileges for that volume
err = afpAccessDenied;
*vref = 0; // do not return a valid volume ref num in such a case
}
}
/*
If the auto mounted volume's creation date has changed,
set the needsUpdate flag to get the alias record updated.
*/
if (err == noErr) {
HVolumeParam vpb; // volume parameter block
err = AL_findVolByVRefNum (*vref, &vpb);
if (err == noErr && aptr->volumeCrDate != AL_fixedCreationDate(&vpb, vpb.ioVRefNum, vpb.ioVCrDate))
*needsUpdate = TRUE; // the creation date needs updating
}
EXIT:
if (vlocH != NULL) { // get rid of volume location data handle
HUnlock((Handle)vlocH);
DisposHandle((Handle)vlocH);
}
// some other serious error occurred during VolumeMount. Currently, paramErr
// is returned by VolumeMount for the case when Server is not reachable.
return ((err == paramErr) ? nsvErr : err);
} // end of AL_mountAFP routine
/*********************************************************************
*********************** Auto mount a foreign volume ***************
*********************************************************************/
OSErr AL_mountForeign (const AliasPtrPriv aptr, //I alias record pointer
short *vref, //O mounted volume's vref number
Boolean *needsUpdate, //O does VolMount info need updating?
Boolean UIallowed, //I Is user interface allowed or not?
AuxAliasInfo *auxInfo) //I auxiliary alias record info
{
OSErr err=nsvErr; // result code
short len; // length of variable vol mount info
/* If the alias record says that there is no volume mount info available, return nsvErr. */
if (aptr->volumeAttributes & kVolMntExists) {
if (AL_isAFPmedia(aptr))
err = AL_mountAFP(aptr, vref, needsUpdate, UIallowed, auxInfo);
else
err = AliasVolumeMount((VolumeLocation *) AL_getVarPtr (aptr, kVolMntInfo, &len),
UIallowed, vref, needsUpdate);
}
return (err);
} // end of AL_mountForeign routine
/*********************************************************************
**** Auto mount a hard disk volume that is dragged to trash *******
*********************************************************************/
static OSErr AL_mountHD (const AliasPtrPriv aptr, //I alias record pointer
short *vref, //O mounted volume's vref number
Boolean *needsUpdate) //O does VolMount info need updating?
{
OSErr err = nsvErr; // result code
VolumeParam vpb; // volume parameter block
register DrvQElPtr drvQEntry; // drive queue entry
register long fourBytesFlag; // four bytes of flags preceding each drive queue entry
drvQEntry = (DrvQElPtr) GetDrvQHdr()->qHead; // get the header of the queue
while (drvQEntry != NULL) { // look at all drive queue entries
// byte 1 of four bytes of flags preceding each drive queue entry
fourBytesFlag = (*((long *)drvQEntry -1));
if ((fourBytesFlag & kNonEjectable) && (!(fourBytesFlag & kDiskWasEjected))) {
if (!(FindVCB(drvQEntry->dQDrive))) { // it is also unmounted
vpb.ioVRefNum = drvQEntry->dQDrive; // mount the volume in this drive
err = PBMountVol((ParmBlkPtr)&vpb);
if (err == noErr) {
err = AL_checkIfMounted(aptr, vref, needsUpdate);
if (err == noErr)
break;
else
(void) UnmountVol (NULL, vpb.ioVRefNum); // unmount and eject it
}
}
}
drvQEntry = (DrvQElPtr) drvQEntry->qLink; // next entry in the drive queue
}
return (err);
} // end of AL_mountHD routine
/**********************************************************************
*************** Is the volume type a floppy? *********************
**********************************************************************/
Boolean AL_isItAFloppy (AliasVolType thisVol) //I for this volume type
{
return ((thisVol == kVolFloppy400K || thisVol == kVolFloppy800K ||
thisVol == kVolFloppy1400K)
? TRUE : FALSE);
} // end of AL_isItAFloppy routine
/**********************************************************************
*************** Is size of the disk compatible? ******************
**********************************************************************/
static Boolean SizeCompatible (AliasVolType thisVol, //I for this volume type
DrvQElPtr drvQEntry) //I try to match against this drive Q entry
{
CntrlParam cpb; // control parameter block
short drvType; // drive type
DrvSts status; // drive status (if control code 23 is not implemented)
if (thisVol == kVolOtherEjectable) // for CDROM and other ejectable non-floppy disks, assume compatible size
return (TRUE);
cpb.ioVRefNum = drvQEntry->dQDrive; // drive number
cpb.ioCRefNum = drvQEntry->dQRefNum;// driver reference number
cpb.csCode = 23; // control code, hard coded because can relate to the manual
if (PBControl((ParmBlkPtr) &cpb, FALSE) == noErr) {
drvType = cpb.csParam[1] & kDriveTypeMask;
if ((drvType == 5) || // 4-Meg Typhoon
(drvType == 4) || // means super drive, all floppies will fit
(drvType == 3 && thisVol != kVolFloppy1400K) || // 800K drive, only 1.4Mb won't fit
(drvType == 2 && thisVol == kVolFloppy400K)) // 400K drive, only 400K will fit
return (TRUE);
} else { // try getting device status
if (DriveStatus(drvQEntry->dQDrive, &status) == noErr) {
if (status.sides & kDoubleSided) { // double-sided drive, assume 800K drive
if (thisVol != kVolFloppy1400K)
return (TRUE); // will support 400K and 800K volumes
} else { // single-sided drive, assume 400K drive
if (thisVol == kVolFloppy400K)
return (TRUE); // will support 400K volume only
}
}
}
return (FALSE); // size is not compatible
} // end of SizeCompatible routine
/**********************************************************************
*************** Is there a free drive for a given ejectable media? **
**********************************************************************/
static Boolean DriveAvailable (const AliasPtrPriv aptr, //I alias record pointer
Boolean searchFlag, //I find an empty or occupied drive?
short *drvNum) //O drive number of the available drive
{
register DrvQElPtr drvQEntry; // drive queue entry
register long fourBytesFlag; // four bytes of flags preceding each drive queue entry
drvQEntry = (DrvQElPtr) GetDrvQHdr()->qHead; // get the header of the queue
while (drvQEntry != NULL) { // look at all drive queue entries
if (((drvQEntry->dQRefNum == kSONYRefNum) && (AL_isItAFloppy(aptr->volumeType))) ||
(aptr->volumeType == kVolOtherEjectable)) { // disk driver we are looking for
// byte 1 of four bytes of flags preceding each drive queue entry
fourBytesFlag = (*((long *)drvQEntry -1));
/* value 8 in byte 1 means nonejetctable disk in drive.
value $FC-$FF in byte 1 means disk was ejected within last 1.5 seconds. */
if ((!(fourBytesFlag & kNonEjectable)) || (fourBytesFlag & kDiskWasEjected)) {
if (AL_isItAFloppy(aptr->volumeType) || DoDriversMatch(aptr, drvQEntry->dQRefNum)) {
/* Are we looking for an empty drive or an occupied drive? Test the input parameter
flag against the diskInDriveByte value. */
if (((searchFlag == kFindEmptyDrive) && ((fourBytesFlag & kDiskInDriveByteMask) == 0)) ||
((searchFlag != kFindEmptyDrive) && (fourBytesFlag & kDiskInDriveMask))) {
if (SizeCompatible (aptr->volumeType, drvQEntry)) { // Is size compatible with this drive?
*drvNum = drvQEntry->dQDrive;
return (TRUE);
}
}
}
}
}
drvQEntry = (DrvQElPtr) drvQEntry->qLink; // next entry in the drive queue
}
return (FALSE); // no matching drive available
} // end of DriveAvailable routine
/**********************************************************************
*************** Filter for SwitchDisk ModalDialog call ***********
**********************************************************************/
static pascal Boolean EjectableFilter (DialogPtr theDialog, //I dialog record pointer
EventRecord * /*theEvent*/, //I event record pointer
short *itemHit) //O item hit
{
EventRecord diskEvent; // disk-inserted event
OSErr result; // result from disk-inserted volume mount
short drvNum; // drive number from disk-inserted volume mount
EjectableFilterParams *paramRecPtr; // pointer to param rec passed as RefCon
AliasPtrPriv aptr; // alias record pointer from RefCon
HVolumeParam vpb; // volume parameter block
Str27 volName; // disk-inserted volume name
AliasVolType vpbVolType; // vpb derived volume type
Boolean nameMatches; // inserted volume name matches alias record volume name
Boolean volTypeMatches; // inserted volume type matches alias record volume name
Boolean volTypeAudioCD; // both inserted volume and alias record volumes are Audio CD
if (GetNextEvent (diskMask, &diskEvent)) {
result = (diskEvent.message & kResultCodeMask) >> 16;
drvNum = diskEvent.message & kDrvNumMask;
*itemHit = kI_BadEjectable; // assume right one is not mounted
if (result == noErr) { // volume was mounted successfully
vpb.ioNamePtr = volName; // return volume name
vpb.ioVolIndex = 0; // by refNum only mode
vpb.ioVRefNum = drvNum; // pass the drive number
result = PBHGetVInfo ((HParmBlkPtr) &vpb, FALSE);
if (result == noErr) {
paramRecPtr = (EjectableFilterParams *) (GetWRefCon (theDialog)); // get our param record pointer
aptr = paramRecPtr->aptr; // get our alias record pointer
volTypeMatches = AL_volTypeMatches (aptr, &vpb, &vpbVolType);
if (volTypeMatches || (vpbVolType != kVolOtherEjectable && aptr->volumeType != kVolOtherEjectable)) { // found the right kind of volume
/* Ignore colon at end of name in alias record if there is one and match volume name */
nameMatches = AL_FSEqualStringByLength (volName+1, aptr->volumeName+1, Length(volName));
/* Audio CDs have dynamically assigned names and creation dates. Hence, recognize
any audio CD that is inserted as the correct one. Do not set needsUpdate for such
volumes because it is useless and may lead volume to become fuzzy. */
volTypeAudioCD = ((vpb.ioVFSID == kAudioFSID) && (aptr->volumeFSID == kAudioFSID));
if (volTypeMatches && ((nameMatches) || (vpb.ioVCrDate == aptr->volumeCrDate) || // either the name or creation date should match
(volTypeAudioCD))) { // assume it is our volume
*itemHit = kI_MountedEjectable; // our ejectable volume was mounted
paramRecPtr->vRefNum = vpb.ioVRefNum; // returned mounted volume's refrence number
paramRecPtr->needsUpdate = ((!volTypeAudioCD) && ((!nameMatches) || (vpb.ioVCrDate != aptr->volumeCrDate)));
} else { // not the volume we are looking for
(void) UnmountVol (NULL, vpb.ioVRefNum); // unmount and eject it
(void) Eject (NULL, drvNum);
}
}
} else
(void) Eject (NULL, drvNum);
} else
(void) Eject (NULL, drvNum);
return (TRUE); // we handled the event
}
return (FALSE); // Let ModalDialog handle the event
} // end of EjectableFilter routine
/*********************************************************************
**** Bring up switch disk dialog to mount an ejectable volume ***
*********************************************************************/
static OSErr AL_mountEjectable (const AliasPtrPriv aptr, //I alias record pointer
short *vref, //O mounted volume's vref number
Boolean *needsUpdate, //O does VolMount info need updating?
Boolean UIallowed) //I Is user interface allowed or not?
{
OSErr err = nsvErr; // result code
DialogPtr switchDiskDialog; // Pointer to SwitchDisk dialog
short itemHit; // Get selection from ModalDialog
short drvNum=1; // drive number where disk could be inserted
Boolean ExitDialog; // Flag used to exit the Dialog
EjectableFilterParams paramRec; // local param rec on stack passed to filter routine via RefCon
GrafPtr savePort; // save current port for restoring later
if (!UIallowed)
return (err);
/* Try to find an empty compatible drive where the disk could be inserted. If such drive is
available, there is no need to auto eject any volume. If no such drive is available, find a
compatible drive and auto eject the volume. */
if (! DriveAvailable (aptr, kFindEmptyDrive, &drvNum)) {
if (DriveAvailable (aptr, (!kFindEmptyDrive), &drvNum))
(void) Eject (NULL, drvNum);
else
return (nsDrvErr);
}
GetPort (&savePort); // save the current port
switchDiskDialog = GetNewDialog(kAlSwitchDiskID, NULL, (WindowPtr)-1);// Bring in the dialog resource
paramRec.aptr = aptr; // pass alias record pointer in param record
SetWRefCon (switchDiskDialog, (long)&paramRec); // store address of our local param storage
AL_setArrowCursor(); // arrow cursor
SetPort(switchDiskDialog);
// display the name of the ejectable volume.
ParamText (aptr->volumeName,'','','');
do { // Start of dialog handle loop
ModalDialog(EjectableFilter, &itemHit); // Wait until an item is hit
ExitDialog = TRUE; // assume that correct action was taken
switch (itemHit) {
case kI_CancelSwitchDisk: // Canceling out of switch disk dialog
err = userCanceledErr;
break;
case kI_MountedEjectable: // mounted a correct ejectable volume. Did any info change?
err = noErr;
*vref = paramRec.vRefNum; // from filter routine
if (paramRec.needsUpdate) // from filter routine, if info changed
*needsUpdate = TRUE;
break;
case kI_BadEjectable: // disk-inserted volume mount was unsuccessful or wrong volume
ExitDialog = FALSE; // keep the dialog box up and ask for disk again
break;
default: // what was it?
break;
} // end of switch statement
} while (! ExitDialog); // Handle dialog items until exit selected
// release resources, dispose of handles and dialogs.
if (switchDiskDialog != NULL) {
DisposDialog(switchDiskDialog); // dispose of our dialog
SetPort(savePort); // restore the original port
}
return (err);
} // end of AL_mountEjectable routine
/*********************************************************************
*************** Mount a volume ********************************
*********************************************************************/
OSErr AL_mountVolume (const AliasPtrPriv aptr, //I alias record pointer
short *vref, //O volume reference number
Boolean *needsUpdate, //O did anything about volume change?
Boolean UIallowed, //I Is user interface allowed or not?
AuxAliasInfo *auxInfo) //I auxiliary alias record info
{
OSErr err = nsvErr; // result code
if (aptr->volumeType == kVolHD) // auto-mount of hard disks
/* if non-ejectable hard disk, then scan driveQ for unmounted volumes. Mount it and
call AL_checkIfMounted. If the right one found, OK else unmount it. */
err = AL_mountHD(aptr, vref, needsUpdate);
else if (aptr->volumeAttributes & kVolEjectable) // handle ejectable volumes here
err = AL_mountEjectable (aptr, vref, needsUpdate, UIallowed); // bring up switch disk dialog
if (err != noErr && err != userCanceledErr && err != nsDrvErr) // try mounting as foreign volume if the alias record has vol mount info
err = AL_mountForeign(aptr, vref, needsUpdate, UIallowed, auxInfo);
return (err);
} // end of AL_mountVolume routine
/*********************** end of alUtil.c file ******************************/