Re: Mounting AFP Volume using Cocoa
Re: Mounting AFP Volume using Cocoa
- Subject: Re: Mounting AFP Volume using Cocoa
- From: Bill Monk <email@hidden>
- Date: Mon, 21 Apr 2008 18:07:21 -0500
On Apr 19, 2008, on Mon, 21 Apr 2008 10:06:47 +0530, JanakiRam wrote:
This code works fine , but when i try to mount another volume/
account on the same server , this code doesn't seem to work.I'm
always getting -43 error.If i unmount the earlier volume/account on
the same server then i'm able to mount another volume on the server.
What sort of server? Perhaps you should post some code. In general it
should works for any number of volumes on a server.
Now, I have occasionally seen error -43 in a situation where
[[NSWorkspace sharedWorkspace] mountedLocalVolumePaths] (which,
somewhat contrary to its name, returns all mounted volumes including
servers) lists a particular server as being mounted, but that server
is not visible on the Desktop or in Finder window sidebars. Yet the
server is in fact mounted, as can be confirmed with various File
Manager API such as FSPathMakeRef(), reading/writing the volume by
any means, etc. Such volumes can be unmounted in Terminal with
umount, which succeeds without error. After that they can be mounted
again with no problem.
Have only really noticed this under Tiger, with programmatically
mounted idisks. My guess is that it may sometimes fail to display new
volumes if several are mounted in very rapid succession. For my
purposes it didn't matter: if a volume is mounted and accessible,
that was good enough.
Without seeing your code, couldn't say if this applies to your
situation. Possibly, sending
[[NSWorkspace sharedWorkspace]
noteFileSystemChanged:pathOfVolumeToMount];
after a successful mount might help ensure the volume is visible in
Finder. Probably best to first check if a volume is already mounted
via mountedLocalVolumePaths anyway
As Jens notes, logging into AFP servers as multiple users at the same
time may not always do what you'd expect.
With Leopard client, for instance, you -can- programatically mount
the same volume for multiple logged-in accounts (assuming the volumes
are marked as sharable for each account in System prefs, or the
volume is the account's public folder). Doing this will succeed; no
error occurs. The vRefNum returned, however, will be the same for all
of them, and only the first appears in the Finder. This makes sense
from a concurrency standpoint.
Not sure if any of the above addresses your -43 errors; http://
lists.apple.com/mailman/listinfo/filesystem-dev would definitely be a
good place to ask about that.
In any case your question prompted me to rework that old code;
passing a single dictionary for the many params is more
pleasant...perhaps it will be useful to someone.
NSString *kServerNameKey = @"kServerNameKey";
NSString *kVolumeNameKey = @"kVolumeNameKey";
NSString *kTransportNameKey = @"kTransportNameKey";
NSString *kMountDirectoryKey = @"kMountDirectoryKey";
NSString *kUserNameKey = @"kUserNameKey";
NSString *kPasswordKey = @"kPasswordKey";
NSString *kAsyncKey = @"kAsyncKey";
-(void)mountServer:(NSDictionary *)mountDictionary
{
NSString *pathOfVolumeToMount;
#define kNoPasswordInURL 1
#if kNoPasswordInURL
// encode transportName://serverName/volumeName URL for server,
without userName/password
pathOfVolumeToMount = [NSString stringWithFormat:@"%@://%@/%@",
[mountDictionary objectForKey:kTransportNameKey],
[mountDictionary objectForKey:kServerNameKey],
[mountDictionary objectForKey:kVolumeNameKey]];
#else
// It's possible to encode the userName/password into the URL, but
this is undesirable when trying to
// mount a volume quietly, without an authentication dialog
appearing. Instead, pass userName/password
// directly to FSMountServerVolumeSync (see comments below).
// encode transportName://userName:password@serverName/volumeName
URL for server, with userName/password
*pathOfVolumeToMount = [NSString stringWithFormat:@"%@://%@:%@@%@/%@",
[mountDictionary objectForKey:kTransportNameKey],
[mountDictionary objectForKey:kUserNameKey],
[mountDictionary objectForKey:kPasswordKey],
[mountDictionary objectForKey:kServerNameKey],
[mountDictionary objectForKey:kVolumeNameKey]];
#endif // kNoPasswordInURL
// percent-ascape any space characters in the URL string and create URL
pathOfVolumeToMount = [pathOfVolumeToMount
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *urlOfVolumeToMount = [NSURL URLWithString:pathOfVolumeToMount];
// create NSURL for optional directory on server to mount; can also
// just include the subdirectory in server URL (if that path is
share-able).
NSURL *mountDirectoryURL = NULL;
NSString *mountDirectoryPath = [mountDictionary
objectForKey:kMountDirectoryKey];
if ( ![mountDirectoryPath isEqualToString:@""] ) {
mountDirectoryPath = [NSString stringWithFormat:@"/Volumes/%@/%@",
[mountDictionary objectForKey:kVolumeNameKey],
mountDirectoryPath];
mountDirectoryPath = [mountDirectoryPath
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
mountDirectoryURL = [NSURL URLWithString:mountDirectoryPath];
}
// To mount a volume quietly, without an authentication dialog, it's
necessary
// that FSMountServerVolumeSync's userName and password params *not*
be NULL.
// While it -is- possible to pass NULL for these (by encoding them into
// the URL, see above), if the server doesn't exist, passing NULL
for these params
// causes the system to put up a "server is not available or may not
be operational"
// dialog even though the values are already encoded into the URL.
//
// Solution: pass userName and password directly to
FSMountServerVolumeSync,
// and leave them out of the URL. This will mount the volume if it's
possible,
// and if not, will quietly return an error. No authentication
dialog will appear.
OSStatus error;
FSVolumeRefNum refNum;
error = FSMountServerVolumeSync( (CFURLRef)urlOfVolumeToMount,
(CFURLRef)mountDirectoryURL, // if NULL, default location is
mounted.
(CFStringRef)[mountDictionary objectForKey:kUserNameKey],
(CFStringRef)[mountDictionary objectForKey:kPasswordKey],
&refNum,
0L /* OptionBits, currently unused */
);
if ( !error ) {
NSLog( @"Sync-mounted server %@, user == %@, refNum == %d",
[pathOfVolumeToMount
stringByAppendingPathComponent:mountDirectoryPath],
[mountDictionary objectForKey:kUserNameKey],
refNum );
// Experiment: see if -noteFileSystemChanged: has any effect on the
occasional idisk
// which mounts successfully but which is not visible in Finder
window sidebars and,
// sometimes, not even on the Desktop. (noticed with under Tiger)
[[NSWorkspace sharedWorkspace] noteFileSystemChanged:
[pathOfVolumeToMount
stringByAppendingPathComponent:mountDirectoryPath]];
}
else {
NSLog( @"Sync mount failed for server %@, error == %d",
pathOfVolumeToMount, error );
}
}
-(void)mountServers:(NSArray *)array
{
if ( array == NULL ) return;
unsigned int i, count = [array count];
for (i = 0; i < count; i++) {
NSDictionary *thisServer = [array objectAtIndex:i];
[self mountServer:thisServer];
}
}
- (IBAction)mountSomeServers:(id)sender
{
NSMutableArray *mountArray = [NSMutableArray array];
NSDictionary *mountDictionary;
// mount a file-shared volume on machine "MBPLeopard"
mountDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
@"MBPLeopard.local", kServerNameKey,
@"volumeName", kVolumeNameKey,
@"afp", kTransportNameKey,
@"", kMountDirectoryKey,
@"username", kUserNameKey,
@"password", kPasswordKey,
[NSNumber numberWithBool:YES], kAsyncKey, NULL];
[mountArray addObject:mountDictionary];
// also mount user's home directory on the same server
mountDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
@"MBPLeopar.local", kServerNameKey,
@"username", kVolumeNameKey, // home directory
@"afp", kTransportNameKey,
@"", kMountDirectoryKey,
@"username", kUserNameKey,
@"password", kPasswordKey,
[NSNumber numberWithBool:YES], kAsyncKey, NULL];
[mountArray addObject:mountDictionary];
// an idisk
mountDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
@"idisk.mac.com", kServerNameKey,
@"youriDisk-Public", kVolumeNameKey,
@"http", kTransportNameKey,
@"", kMountDirectoryKey,
@"username", kUserNameKey,
@"", kPasswordKey, // assumes no password sort on idisk public folder
[NSNumber numberWithBool:YES], kAsyncKey, NULL];
[mountArray addObject:mountDictionary];
// a subdirectory on the same idisk, without bothering
//with the kMountDirectoryKey key
mountDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
@"idisk.mac.com", kServerNameKey,
@"youriDisk-Public/SomeExistentFolder", kVolumeNameKey,
@"http", kTransportNameKey,
@"", kMountDirectoryKey,
@"username", kUserNameKey,
@"", kPasswordKey,
[NSNumber numberWithBool:YES], kAsyncKey, NULL];
[mountArray addObject:mountDictionary];
// mount servers in array
[self mountServers:mountArray];
}
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden