mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2025-01-17 09:29:49 +00:00
2065 lines
74 KiB
C
2065 lines
74 KiB
C
|
/*
|
|||
|
File: alUtil.c
|
|||
|
|
|||
|
Contains: Sundry utility routines.
|
|||
|
|
|||
|
Written by: Prashant Patel
|
|||
|
|
|||
|
Copyright: <EFBFBD> 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 <EFBFBD>EqualString<EFBFBD> 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 <EFBFBD> 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<6F>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 ******************************/
|