Re: identifying AppleShare mounts
Re: identifying AppleShare mounts
- Subject: Re: identifying AppleShare mounts
- From: Scott Ribe <email@hidden>
- Date: Fri, 01 Aug 2003 12:31:58 -0600
- Resent-date: Mon, 04 Aug 2003 07:14:37 -0600
- Resent-from: Scott Ribe <email@hidden>
- Resent-message-id: <BB500E3E.2FF79%email@hidden>
- Resent-to: <email@hidden>
>
I have a file sync app that automatically mounts remote AppleShare
>
volumes (right now via mount_afp), and sometimes runs unattended on a
>
schedule. Sometimes these are volumes the user might have mounted
>
manually and left mounted, in which case my app fails to mount (since
>
the OS won't let it mount a volume that's already mounted elsewhere).
>
>
Is there any way, before mounting a volume, that my app could check to
>
see if it's already mounted?
>
>
If so, can it find out where the preexisting mount point is, and if
>
there's read/write access?
>
>
And if it uses a preexisting mount point, what's the best way to check
>
periodically that the mount continues to exist?
Ah, good luck ;-) The long and short of it is that the only thing you can do
is look for remote volumes with the same name and hope that you never have
multiple remote mounts named "Macintosh HD". For what it's worth here's a
bug report I submitted to Apple a little over a year ago:
03-Jul-2002 02:50 PM Scott Ribe:
The task: I need my application to auto-mount an AppleShare volume, without
presenting any user interface. I need this to work the same way on OS X and
Classic (from the user's perspective--I don't mind a code branch). I am
trying to use PBMountVolume, by filling in an AFPXVolMountInfo to connect
via TCP/IP. Here are my results.
OS X:
If the volume is not already mounted, PBMountVolume returns noErr and fills
in the ioVRefNum field.
If the volume is already mounted, PBMountVolume returns afpAlreadyMounted
and fills in the ioVRefNum field.
Classic:
If the volume is not already mounted, PBMountVolume returns noErr and fills
in the ioVRefNum field.
If the volume is already mounted, PBMountVolume returns afpAlreadyMounted
and DOES NOT fill in the ioVRefNum field--this is where the fun begins! I
thought I would iterate over the mounted volumes by index, get the volume
refs, get the mount info, check for equivalence to my mount info, and find
the ref num of the mounted volume that way. No such luck.
FSGetVolumeInfo does let me iterate over the drives and get the vol ref nums
for all mounted volumes--no problem there. But PBGetVolMountInfoSize locks
up under Classic. I thought perhaps it was a bad idea to call that on a
local volume. So I tried to use PBHGetVInfoSync to identify remote volumes.
But although it always returns noErr, it does not always return correct info
in the ioVAtrb field. So next I used PBHGetVolParmsSync, and it does
reliably identify the remote volume (vMServerAdr is non-zero, but it's not
the correct address--it is always 0x00000001 for the remote volume). But
PBGetVolMountInfoSize locks up even on a remote volume. So I decided to just
assume a generous size (2k) and skip that call. But then PBGetVolMountInfo
always returns paramErr--and I have tried every imaginable combination of
vol ref num & name parameters, and have set the reqCount field just in
case--nothing makes it work.
Misc:
PBGetVolMountInfoSize and PBGetVolMountInfo work as expected under OS X. All
OS 9 debugging was done under Classic. However, I did reboot into OS 9 and
verify that the program behavior was the same--using PBMountVolume failed to
locate the already mounted volume while using PBGetVolMountInfo locked up.
Request:
It seems to me that the simplest fix for my current problem would be for
PBMountVolume to always fill in the volume reference for an already-mounted
volume. But the problems with getting volume mounting info could be a
serious difficulty in other situations.
Oh, and here's another I filed way back then:
09-Jul-2002 09:52 PM Scott Ribe:
If two applications call PBVolumeMount at about the same time, the volume
can be mounted twice (shows up twice in /Volumes and on the
desktop)--neither call gets afpAlreadyMounted as a return value. Under OS 9
I have never seen this happen, and expected the behavior to be that one
application would get noErr and the other would get afpAlreadyMounted. I'm
using an AFPXVolMountInfo record with an alternate address of
kAFPTagTypeIPPort, and connecting to Mac OS X Server 10.1.4.
Having said that, here's some code I currently use to find a mounted volume
or mount it if I don't find it (the code's ugly as hell because I hope that
someday it will just go away and so don't feel like making it pretty):
bool MountRemote( CFDictionaryRef mount, short * volref )
{
bool status = false;
static CFStringRef ipkey = CFSTR( "ip" ), portkey = CFSTR( "port" ),
userkey = CFSTR( "user" ),
pwdkey = CFSTR( "password" ), volkey = CFSTR(
"volume" );
CFStringRef ip, port, usr, pwd, vol;
ip = (CFStringRef) CFDictionaryGetValue( mount, ipkey );
port = (CFStringRef) CFDictionaryGetValue( mount, portkey );
usr = (CFStringRef) CFDictionaryGetValue( mount, userkey );
pwd = (CFStringRef) CFDictionaryGetValue( mount, pwdkey );
vol = (CFStringRef) CFDictionaryGetValue( mount, volkey );
if( ip && usr && pwd && vol )
status = MountShare( volref, ip, port, vol, usr, pwd );
else
LogErr( "incomplete mount info" );
CheckSuccess( status, "mounting remote volume" );
return status;
}
bool MountShare( short * volref, CFStringRef ipstr, CFStringRef portstr,
CFStringRef vol, CFStringRef usr, CFStringRef pwd )
{
bool status = false;
OSStatus err;
unsigned char ip[6];
AFPXVolMountInfo info;
if( buildip( ipstr, portstr, ip ) )
{
buildafpx( vol, usr, pwd, ip, &info );
ParamBlockRec params;
params.ioParam.ioBuffer = (char *) &info;
err = ::PBVolumeMount( ¶ms );
if( !err )
{
status = true;
*volref = params.ioParam.ioVRefNum; // under Classic this does
not set the volref if the vol was already mounted
}
else if( err == afpAlreadyMounted ) // thus the need to iterate over
mounted volumes looking for the one that matches
{
LogMessage( "volume already mounted, comparing to mounted
volumes: " );
ItemCount nsvcnt = 0;
for( ItemCount i = 1; !status; i++ )
{
FSRef dummyroot;
FSVolumeRefNum refnum;
HFSUniStr255 uniname;
err = ::FSGetVolumeInfo( kFSInvalidVolumeRefNum, i, &refnum,
kFSVolInfoNone, NULL, &uniname, &dummyroot );
if( !err )
{
char cname[256];
uni2c( &uniname, cname );
LogMessage4( " ", i, ": ", cname );
// but it gets worse: under Classic
PBGetVolMountInfoSize hangs and PBGetVolMountInfo always returns paramErr,
// while PBHGetVInfoSync returns incorrect info in
ioVAtrb
HParamBlockRec hparams;
GetVolParmsInfoBuffer gvpib;
hparams.volumeParam.ioNamePtr = NULL;
hparams.volumeParam.ioVRefNum = refnum;
hparams.volumeParam.ioVolIndex = 0;
hparams.ioParam.ioBuffer = (Ptr) &gvpib;
hparams.ioParam.ioReqCount = sizeof( gvpib );
// so we assume that if the volume is remote and has the
same name then it's the right one
err = ::PBHGetVolParmsSync( &hparams );
CheckErr( err, "getting volume parameters" );
LogMessage2( " server address: ", gvpib.vMServerAdr
);
if( !err && gvpib.vMServerAdr != 0 )
{
HFSUniStr255 uniname2;
uniname2.length = ::CFStringGetLength( vol );
CFRange rng = { 0, uniname2.length };
::CFStringGetCharacters( vol, rng, uniname2.unicode
);
if( unieq( &uniname, &uniname2 ) )
{
LogMessage2( " matched by volref ", refnum
);
status = true;
*volref = refnum;
}
}
}
else if( err == nsvErr && nsvcnt < 4 )
nsvcnt++;
else if( err == nsvErr || i >= 255 )
break;
else
CheckErr( err, "getting indexed volume info" );
}
}
else
CheckErr( err, "mounting share" );
}
return status;
}
bool buildip( CFStringRef ipstr, CFStringRef portstr, UInt8 ip[6] )
{
bool ret = false;
CFArrayRef strs = ::CFStringCreateArrayBySeparatingStrings( NULL, ipstr,
CFSTR( "." ) );
if( strs )
{
CFIndex numstrs = ::CFArrayGetCount( strs );
if( numstrs == 4 )
{
long ip0, ip1, ip2, ip3, port;
ip0 = ::CFStringGetIntValue( (CFStringRef)
::CFArrayGetValueAtIndex( strs, 0 ) );
ip1 = ::CFStringGetIntValue( (CFStringRef)
::CFArrayGetValueAtIndex( strs, 1 ) );
ip2 = ::CFStringGetIntValue( (CFStringRef)
::CFArrayGetValueAtIndex( strs, 2 ) );
ip3 = ::CFStringGetIntValue( (CFStringRef)
::CFArrayGetValueAtIndex( strs, 3 ) );
if( portstr )
port = ::CFStringGetIntValue( portstr );
else
port = 548;
if( ip0 >= 0 && ip0 <= 255 &&
ip1 >= 0 && ip1 <= 255 &&
ip2 >= 0 && ip2 <= 255 &&
ip3 >= 0 && ip3 <= 255 &&
port >= 1 && port <= 65535 )
{
ret = true;
ip[0] = ip0;
ip[1] = ip1;
ip[2] = ip2;
ip[3] = ip3;
ip[4] = ( port >> 8 ) & 0x000000FF;
ip[5] = port & 0x000000FF;
}
}
::CFRelease( strs );
}
if( !ret )
LogErr4( "illegal value in ip or port ", ipstr, ":", portstr );
return ret;
}
void buildafpx( CFStringRef vol, CFStringRef usr, CFStringRef pwd, UInt8
ip[4], AFPXVolMountInfo * info )
{
unsigned char * base = (unsigned char *) info, * cur = (unsigned char *)
&info->AFPData[0];
if( (unsigned long) cur % 2 )
cur++;
*cur = 0;
long nulloff = cur - base;
cur++;
if( (unsigned long) cur % 2 )
cur++;
long srvroff = cur - base;
*cur++ = 1;
*cur++ = '*';
if( (unsigned long) cur % 2 )
cur++;
::CFStringGetCString( vol, (char *) cur + 1, 31,
kCFStringEncodingMacRoman );
*cur = strlen( (char *) cur + 1 );
long voloff = cur - base;
cur += *cur + 1;
if( (unsigned long) cur % 2 )
cur++;
::CFStringGetCString( usr, (char *) cur + 1, 31,
kCFStringEncodingMacRoman );
*cur = strlen( (char *) cur + 1 );
long usroff = cur - base;
cur += *cur + 1;
if( (unsigned long) cur % 2 )
cur++;
::CFStringGetCString( pwd, (char *) cur + 1, 31,
kCFStringEncodingMacRoman );
*cur = strlen( (char *) cur + 1 );
long pwdoff = cur - base;
cur += *cur + 1;
if( (unsigned long) cur % 2 )
cur++;
long afpoff = cur - base;
*cur++ = 0;
*cur++ = 1;
*cur++ = kAFPTagLengthIPPort;
*cur++ = kAFPTagTypeIPPort;
*cur++ = ip[0];
*cur++ = ip[1];
*cur++ = ip[2];
*cur++ = ip[3];
*cur++ = ip[4];
*cur++ = ip[5];
info->length = cur - base;
info->media = AppleShareMediaType;
info->flags = volMountNoLoginMsgFlagMask | volMountExtendedFlagsMask;
info->nbpInterval = 0;
info->nbpCount = 0;
info->uamType = kEncryptPassword;
info->zoneNameOffset = nulloff;
info->serverNameOffset = srvroff;
info->volNameOffset = voloff;
info->userNameOffset = usroff;
info->userPasswordOffset = pwdoff;
info->volPasswordOffset = nulloff;
info->extendedFlags = kAFPExtendedFlagsAlternateAddressMask;
info->uamNameOffset = nulloff;
info->alternateAddressOffset = afpoff;
info->AFPData[0] = 0;
}
bool offeq( const AFPXVolMountInfo * info1, short off1, const
AFPXVolMountInfo * info2, short off2 )
{
bool ret = true;
unsigned char * cur1 = ( (unsigned char *) info1 ) + off1;
unsigned char * cur2 = ( (unsigned char *) info2 ) + off2;
unsigned char * end = cur1 + *cur1;
while( cur1 <= end && ret )
ret = *cur1++ == *cur2++;
return ret;
}
bool unieq( const HFSUniStr255 * str1, const HFSUniStr255 * str2 )
{
bool ret;
if( str1->length == str2->length )
{
ret = true;
const UniChar * c1 = str1->unicode, * c2 = str2->unicode, * end =
str1->unicode + str1->length;
while( c1 < end && ret )
ret = *c1++ == *c2++;
}
else
ret = false;
return ret;
}
void uni2c( const HFSUniStr255 * uni, char * c )
{
for( int i = 0; i < uni->length; i++ )
c[i] = uni->unicode[i] & 0x007F;
c[uni->length] = 0;
}
--
Scott Ribe
email@hidden
http://www.killerbytes.com/
(303) 665-7007 voice
_______________________________________________
macnetworkprog mailing list | email@hidden
Help/Unsubscribe/Archives:
http://www.lists.apple.com/mailman/listinfo/macnetworkprog
Do not post admin requests to the list. They will be ignored.