mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
4325cdcc78
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.
2065 lines
74 KiB
C
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)¶mRec);
|
|
|
|
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)¶mRec); // 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 ******************************/
|