/* File: alFill.c Contains: Fill an alias record. Written by: Prashant Patel Copyright: © 1989-1990 by Apple Computer, Inc., all rights reserved. This file is used in these builds: BigBang Change History (most recent first): <35> 2/13/91 PP dnf,#go5 Decision:For AFP volume mount, use data structs from Files.h specially since the AFPVolMountInfo record is no longer header only (it includes 144 bytes of data after header) <34> 2/11/91 PP ich,:Return FSMakeFSSpec error to caller. <33> 1/31/91 PP ich,#WS ich-AMgr-0091:Set kAuxRealDirID bit only when CreateIDRef call is successful. For MinFullpath, store chooser username or instead of Guest. <32> 1/25/91 PP sad,#80663:Detect driveNum and driver ref num correctly for ejected off-line volumes. <31> 1/21/91 PP (ich) For FileShare volumes on client side, store auxiliary parent id correctly i.e. not always 1. <30> 1/10/91 PP (ich) While getting minimum fullpath alias volumename, restrict it to Str27. <29> 12/20/90 PP (ich) If alias record grows, clear expanded record before filling it in. <28> 12/13/90 PP (ich) Always do CreateID for root volume of a FileShare volume on the client side and store the real dirID for a tighter volume matching check. <27> 12/13/90 PP (ich) Call to FSMakeFSSpec is now part of AL_canonifyFile. For minimal full path alias, user name is explicit string. <26> 11/29/90 PP (PP/ich) Remove Alias Version 1 compatibility code. Get in sync with Files.h VolumeMount equates. <25> 10/30/90 PP If FileShare is enabled for a target volume, store network info all the time. <24> 10/21/90 gbm Change hfileInfo to hFileInfo for the last time. <24> 10/10/90 JL Change hfileInfo to hFileInfo for the last time. <23> 10/10/90 PP For creation dates on AppleShare volumes, need to store raw data instead of time adjusted to current machine's date. All handles are allocated as NewHandleClear instead of NewHandle to avoid uninitalized data comparison in UpdateAlias. <22> 9/19/90 PP Initialize unused, fileName and volumeName fields to zero so UpdateAlias BlockCompare works correctly. <21> 9/7/90 PP During alias creation, determine whether on client or server side of FileShare by looking at volume attribute bits. <20> 9/1/90 PP FileShare CreateFileID meaning has changed. It now works only for root directory. Now, exported and mounted bits are available for client also. Use these bits for detecting whether creating FileShare object aliases. <19> 8/28/90 dnf Change references to CreateFileID to CreateFileIDRef <18> 8/21/90 PP FileShare's kSharePoint and kInExported bits are now visible from client also. Cannot use them to determine whether creating alias on client or server side. <17> 8/17/90 PP Volume creation date cannot be obtained by GetCatInfo on dirID of 2. <16> 8/6/90 dnf Convert to new name of FSMakeFSSpec <15> 8/6/90 PP New alias record has userType of zero instead of four blanks. Support foreign volume mount other than AppleShare. Support foreign volume mount other than AppleShare. <14> 7/9/90 PP When updating an alias record, preserve userType field. <13> 6/28/90 PP Convert CanonicalFileSpec to FSSpec. <12> 6/15/90 PP GetMyZonePhs2 and GetMyServer are now void functions. <11> 5/31/90 PP For minimal fullpath aliases, check zone and server names for not to be NULL. <10> 5/16/90 PP If target is a FileShare volume, store its real dirID in addition to it's parent's real dirID. <9> 5/3/90 PP Closer integration of FileShare and aliases. Incorporate Diet Clinic tips. <8> 4/10/90 PP Change once more hFileInfo to hfileInfo to stay consistent with Files.h <7> 4/5/90 PP Code Size optimization. <6> 3/8/90 PP Support NewAliasMinimal and NewAliasMinimalFromFullPath. Change "hfileInfo" to "hFileInfo'" to match Files.h change. <5> 2/27/90 PP Ignore GetVolMountInfo error since it is not fatal. <4> 2/6/90 PP PBHCreateID call is now PBCreateFileID. <3> 1/21/90 PP Fiil volumeAttirbutes field. Fill driver name for non-floppy ejectable volumes. <2.2> 12/15/89 prp Handle MFS volume special case for AL_fillFileInfo. <2.1> 11/27/89 prp Now determines whether Floppies are 400K, 800K or 1400K <2.0> 10/30/89 prp • AppleShare volumes return wrgVolTypeErr when CatSearch and FileIDs not supported. <1.9> 10/13/89 prp Fix bug in allocation of variable length for Folder Name. <1.8> 10/2/89 prp FileID and fileNum fields in Alias record are now same since the fileID interpretation has changed. <1.7> 9/18/89 prp Fill folder info and FillVarLen are different to accomodate moving of FolderName field of Alias record to variable info. <1.6> 9/6/89 prp Changes from CodeReview. <1.5> 8/7/89 prp Add automatic volume mount support. <1.4> 7/31/89 prp Since FileIDs.h has now merged with Files.h, remove its inclusion and fix names of fields that have changed in FIDParam. <1.3> 7/6/89 prp FileID calls across AppleShare volumes return noErr but garbage data. Do not use FileIDs if alias is on AppleShare volume. <1.2> 6/12/89 prp Incorporate FileIDs and CatSearch. Added slow search. Cleaned up IFNDEFs. <1.1> 5/31/89 prp Moved Alias Record to private definition file. Changed FileEntity to FileSpec. <1.0> 5/30/89 prp Initial Release To Do: */ /********************************************************************* * * File: alFill.c * Project: Alias Manager * Contains: routines to fill an alias record * Written by: Prashant Patel * * Copyright 1989 by Apple Computer, Inc. * All Rights Reserved. * **********************************************************************/ /********************************************************************** *************** Public Include files ******************* *********************************************************************/ #include "Aliases.h" /********************************************************************** *************** Private Include files ******************* *********************************************************************/ #include "aliasPriv.h" /********************************************************************** *************** External C Include files *************** *********************************************************************/ #ifndef __MEMORY__ #include #endif #ifndef __FILES__ #include #endif #ifndef __ERRORS__ #include #endif #ifndef __TOOLUTILS__ #include #endif /********************************************************************* ******** private definitions **************************************** *********************************************************************/ typedef struct { // GetVolParms buffer short version; long attributes; } VolParmsBuf; /********************************************************************** *************** Allocate AFP mount block ******************* *********************************************************************/ static OSErr AllocAFPMountBlock(VolumeLocationHandle *vloc) //O volume location record handle { *vloc = (VolumeLocationHandle) NewHandleClear(sizeof (AFPVolMountInfo)); return (MemError()); } // end of AllocAFPMountBlock routine /********************************************************************* **** Fill new volume mount record with old info ******************* *********************************************************************/ static void AL_fillAFPmountBlock (VolumeLocation *vloc, //I/O volume mount info if any StringPtr zoneName, //I zone name pointer StringPtr serverName, //I server name pointer StringPtr volName, //I volume name pointer StringPtr userName) //I user name pointer { AFPVolMountInfo *afp; // afp vol mount info block pointer vloc->length = sizeof (AFPVolMountInfo); vloc->media = kAFPmedia; afp = (AFPVolMountInfo *) vloc; afp->flags = 0; afp->nbpInterval = 0; afp->nbpCount = 0; afp->uamType = kScrambledPswdLogin; afp->zoneNameOffset = &afp->AFPData[kAFPzoneNameOffset] - &vloc->length; afp->serverNameOffset = &afp->AFPData[kAFPserverNameOffset] - &vloc->length; afp->volNameOffset = &afp->AFPData[kAFPvolNameOffset] - &vloc->length; afp->userNameOffset = &afp->AFPData[kAFPuserNameOffset] - &vloc->length; afp->userPasswordOffset = &afp->AFPData[kAFPuserPasswordOffset] - &vloc->length; afp->volPasswordOffset = &afp->AFPData[kAFPvolPasswordOffset] - &vloc->length; AL_copyPString (zoneName, &afp->AFPData[kAFPzoneNameOffset]); AL_copyPString (serverName, &afp->AFPData[kAFPserverNameOffset]); AL_copyPString (volName, &afp->AFPData[kAFPvolNameOffset]); AL_copyPString (userName, &afp->AFPData[kAFPuserNameOffset]); Length(&afp->AFPData[kAFPuserPasswordOffset]) = Length(&afp->AFPData[kAFPvolPasswordOffset]) = 0; } // end of AL_fillVmntFromAlias routine /********************************************************************* **** Fill volume information in alias record *************** *********************************************************************/ static OSErr AL_fillVInfo ( short vref, //I volume reference number AliasPtrPriv aptr, //I/O alias record pointer VolumeLocationHandle *vMntInfo, //O volume mount info if any StringPtr drvrName, //O driver name for kVolOtherEjectable NewAliasType type, //I new or update alias is of what type? MinimalFullpathSpec *fullpathSpec) //I fullpath spec { OSErr err = noErr; // result code if (type == kMinimalFromFullpathAlias) { // handle volume info coming from fullpath Str32 userName; // user name for minimal full path alias StringHandle strH; // user name string handle short userNameLen; // length of user name // store volume name from full path name AL_getVolname (fullpathSpec->fullpath, (sizeof(Str27)-1), aptr->volumeName); // get volume name aptr->parDirID = kInvalidValue; aptr->volumeType = kInvalidValue; aptr->volumeAttributes = 0; if (fullpathSpec->zoneName != NULL && fullpathSpec->serverName != NULL && Length(fullpathSpec->zoneName) > 0 && Length(fullpathSpec->serverName) > 0) { // create an AFP mount block err = AllocAFPMountBlock (vMntInfo); if (err != noErr) return (err); // Get user name from "Chooser" string resource or put "Unknown Name" strH = GetString(kChooserUserNameID); userNameLen = (strH != NULL) ? (**strH) : 0; if (userNameLen > (sizeof(userName)-1)) userNameLen = (sizeof(userName)-1); if (userNameLen != 0) // non-empty user name from Chooser BlockMove ((*strH), userName, userNameLen+1); else GetIndString (userName, kAliasResID, kUnknownNameIdx); AL_fillAFPmountBlock((**vMntInfo), fullpathSpec->zoneName, fullpathSpec->serverName, aptr->volumeName, userName); aptr->volumeType = kVolForeign; aptr->volumeAttributes |= (kVolMntExists | kVolAFPmedia); // pretend valid auto VolMount info for AFP media } } else { HVolumeParam vpb; // volume parameter block short dRefNum; // driver reference number short driveNum; // drive number // fill in volume info vpb.ioVRefNum = vref; // lookup volume info vpb.ioVolIndex = 0; // using vrefnum mode vpb.ioNamePtr = aptr->volumeName; // put volume name in alias if ((err = PBHGetVInfo((HParmBlkPtr) &vpb, false)) == noErr) { aptr->volumeCrDate = vpb.ioVCrDate; // put 'volumeID' in alias aptr->volumeSig = vpb.ioVSigWord; // put volume signature aptr->volumeType = AL_getVolType(&vpb); // compute volume type aptr->volumeAttributes = 0; // init it to no attributes aptr->volumeFSID = vpb.ioVFSID; // store file system ID if (aptr->volumeType == kVolOtherEjectable || AL_isItAFloppy(aptr->volumeType)) { // ejectable volumes aptr->volumeAttributes |= kVolEjectable; // it is ejectable if (aptr->volumeType == kVolOtherEjectable) { // for non-floppy ejectables, store driver name AL_getDriveInfo(&vpb, &dRefNum, &driveNum); AL_getDriverName(dRefNum, drvrName); } } // Try to get VolumeMount info for all foreign volumes. if (aptr->volumeType == kVolForeign && AL_getVolMountInfo (vref, vMntInfo) == noErr) { // call does not exist or other error aptr->volumeAttributes |= kVolMntExists; // valid auto VolMount info if ((**vMntInfo)->media == kAFPmedia) { aptr->volumeAttributes |= kVolAFPmedia; // supports AFP media aptr->volumeCrDate = AL_fixedCreationDate(&vpb, vpb.ioVRefNum, aptr->volumeCrDate); // fix vol CrDate for AppleShare volumes } } } } return (err); } // end of AL_fillVInfo routine /********************************************************************* **** Fill folder information in alias record *************** *********************************************************************/ static OSErr AL_fillFldrInfo (const FSSpec *toFile, //I aliased toFile AliasPtrPriv aptr, //I/O alias record pointer NewAliasType type) //I new or update alias is of what type? { OSErr err; // result code long pdir; // parent directory ID Str63 folderNm; // this folder's name // special case for the volume, no parent folder name. // Also, only complete aliases store them. if (type != kCompleteAlias || toFile->parID == kVolRootDirID) return(noErr); if ((err = AL_findDirByID(toFile->vRefNum, toFile->parID, &pdir, folderNm)) == noErr) // get this folder's name // fill in folder name info in alias record varInfo entry. (void) AL_addVarEntry (aptr, kFolderNm, Length(folderNm), folderNm+1); return (err); } // end of AL_fillFldrInfo routine /********************************************************************* **** Fill file information in alias record ******************* *********************************************************************/ static OSErr AL_fillFileInfo (register const FSSpec* toFile, //I alias to file register AliasPtrPriv aptr, //I/O alias record pointer NewAliasType type, //I new or update alias is of what type? register AuxAliasInfo *auxPtr, // auxiliary alias record info VolumeLocationHandle *vMntInfo) //O volume mount info if any { OSErr err=noErr; // result code CInfoPBRec cpb; // catalog info param block FIDParam hpb; // H parameter block for fileIDs Str63 localName; // temporary local name Boolean targetIsSharepoint; // Is target a Sharepoint? Boolean targetIsLocal; // Is target local or remote? Str32 zoneName; // zone name for aux volMnt info for FileShare Str31 serverName; // server name for aux volMnt info for FileShare Str32 userName; // user name for aux volMnt info for FileShare HIOParam vpb; // volume parameter block VolParmsBuf volumeParms; // answer from GetVolParms aptr->thisAliasKind = kFileAlias; // assume a file if (toFile->parID == kInvalidValue) { // for minimal fullpath aliases aptr->fileNum = kInvalidValue; goto EXIT; } cpb.hFileInfo.ioFDirIndex = 0; // want info about this file or dir err = AL_getCatInfo (toFile->vRefNum,toFile->parID,aptr->fileName,&cpb); if (err != noErr) goto EXIT; if (cpb.hFileInfo.ioFlAttrib & kDirMask) aptr->thisAliasKind = kDirAlias; aptr->fileType = cpb.hFileInfo.ioFlFndrInfo.fdType; // file type aptr->fdCreator = cpb.hFileInfo.ioFlFndrInfo.fdCreator; // creator name aptr->fileNum = cpb.hFileInfo.ioDirID; // file number or dirID aptr->fileCrDate = cpb.hFileInfo.ioFlCrDat;// file or dir creation date if (AL_isAFPmedia(aptr)) aptr->fileCrDate = AL_fixedCreationDate(nil, toFile->vRefNum, aptr->fileCrDate); // fix CrDate for AppleShare volumes hpb.ioVRefNum = toFile->vRefNum; // setup fileID call parameters hpb.ioSrcDirID = toFile->parID; hpb.ioNamePtr = aptr->fileName; // return the name if (aptr->thisAliasKind == kFileAlias && type == kCompleteAlias) { // file ID valid only for files and non-minimal aliases err = PBCreateFileIDRef ((HParmBlkPtr)&hpb, FALSE); if (err == noErr || err == fidExists) // call exists and returned valid value aptr->fileNum = hpb.ioFileID; // store the result err = noErr; // if call did not exist and could not store fileID // it is not fatal, continue filling alias record } /* Are we creating an alias for a target that is on a Shared volume (e.g. FileShare)? If so, need to store network info and auxiliary info in the alias record. */ /* Get volume attributes to determine whether on remote client side or local server side. Also, see if FileShare is running but may be nothing is shared. */ vpb.ioVRefNum = toFile->vRefNum; vpb.ioNamePtr = NULL; vpb.ioReqCount = sizeof (VolParmsBuf); vpb.ioBuffer = (Ptr) &volumeParms; if (PBHGetVolParms ((HParmBlkPtr) &vpb, FALSE) == noErr) { targetIsLocal = (volumeParms.attributes & kHasAccesspriv) && (volumeParms.attributes & kHasPersonalAcces); if (targetIsLocal) { // Yes, the target is on a local server volume. Store Network info. AL_GetMyZonePhs2(zoneName); AL_GetMyServer(serverName); hpb.ioDestNamePtr = &userName[0]; (void) PBHGetLogInInfo((HParmBlkPtr)&hpb, FALSE); err = AllocAFPMountBlock (vMntInfo); if (err != noErr) goto EXIT; AL_fillAFPmountBlock((**vMntInfo), zoneName, serverName, aptr->volumeName, userName); aptr->volumeAttributes |= (kVolMntExists | kVolAFPmedia); // valid vol mount info for 'afpm' media } } else targetIsLocal = (aptr->volumeType != kVolForeign); cpb.hFileInfo.ioFDirIndex = -1; // interested in parent directories only targetIsSharepoint = ((cpb.hFileInfo.ioFlAttrib & kSharePoint) != 0); // Is share point the target? if (targetIsSharepoint) // for Sharepoint init localName correctly before using it. AL_copyPString (aptr->fileName, localName); if (aptr->thisAliasKind == kFileAlias) // if file target, start with its parent (void) AL_getCatInfo (toFile->vRefNum,toFile->parID,localName,&cpb); if (cpb.hFileInfo.ioFlAttrib & kSharePoint || cpb.hFileInfo.ioFlAttrib & kInExported) { if (!targetIsLocal) { // on a remote client /* try to do a PBCreateFileIDRef call for root directory. This is for FileShare or shared volumes only. This is supposed to return real root directory ID and not the fake one. Store this real parent dirID to be used later on from server side. This could also be used on client side for tighter volume matching. On server side, no need to get real parent directory ID and hence these calls are not made. */ hpb.ioNamePtr = NULL; // get the real parent dirID for shared volume objects auxPtr->auxDirIDs.auxFileNum = aptr->fileNum; auxPtr->auxDirIDs.auxParDirID = toFile->parID; auxPtr->auxDirIDs.auxRealRootDirID = kInvalidValue; // special case for root directory only hpb.ioSrcDirID = kRootDirID; if (PBCreateFileIDRef ((HParmBlkPtr)&hpb, FALSE) == noErr) { if (toFile->parID == kRootDirID) auxPtr->auxDirIDs.auxParDirID = hpb.ioFileID; else if (toFile->parID == kVolRootDirID) auxPtr->auxDirIDs.auxFileNum = hpb.ioFileID; auxPtr->auxDirIDs.auxRealRootDirID = hpb.ioFileID; aptr->volumeAttributes |= kAuxRealDirID; } if (toFile->parID == kVolRootDirID) { // for volume aliases, store real parent of shared folder hpb.ioSrcDirID = kVolRootDirID; if (PBCreateFileIDRef ((HParmBlkPtr)&hpb, FALSE) == noErr) auxPtr->auxDirIDs.auxParDirID = hpb.ioFileID; } } else { // on local server /* Check if target is on a FileShare server within a shared folder or target is the share point itself. If so, mark the attribute bit and fill the auxiliary remote alias record. Aux volume name is the name of the folder that is the sharpoint. Aux volume creation date is the creation date of the sharepoint. Aux parent directory ID is 2 for targets at root, 1 for root itself and the real one for others. Aux file num is 2 for root itself and real one for others. */ while (!(cpb.hFileInfo.ioFlAttrib & kSharePoint)) { err = AL_getCatInfo (toFile->vRefNum,cpb.hFileInfo.ioFlParID,localName,&cpb); // interested in parent only if (err != noErr) goto EXIT; } AL_copyPString (localName, auxPtr->auxVolName); auxPtr->auxVolCrDate = cpb.hFileInfo.ioFlParID == kVolRootDirID ? aptr->volumeCrDate : cpb.hFileInfo.ioFlCrDat; auxPtr->auxVolType = kVolForeign; // aux info is for a foreign volume auxPtr->auxDirIDs.auxParDirID = targetIsSharepoint ? kVolRootDirID : toFile->parID == cpb.hFileInfo.ioDirID ? kRootDirID : toFile->parID; auxPtr->auxDirIDs.auxFileNum = targetIsSharepoint ? kRootDirID : aptr->fileNum; auxPtr->auxDirIDs.auxRealRootDirID = kInvalidValue; aptr->volumeAttributes |= (kVolAuxRemoteInfo); // valid auxiliary remote alias record info } } EXIT: return (err); } // end of AL_fillFileInfo routine /********************************************************************* * Fill # of chars in Folder name# of dirs, chars in absolute path and* *********************************************************************/ static OSErr AL_fillVarLen (const FSSpec *toFile, //I aliased toFile const AliasPtrPriv aptr,//I alias record pointer short *ndirToRoot, //O # of dirs to root for toFile short *nchInAPath, //O # of chars in abs apth of toFile short *nchInFldrNm, //O # of chars in parent folder name NewAliasType type, //I new or update alias is of what type? MinimalFullpathSpec *fullpathSpec) //I fullpath spec { OSErr err = noErr; // result code Str63 localName; // temporary local name long tdir; // temporary directory num holder Boolean lookingInputDir = TRUE; // will start at the input directory *ndirToRoot = *nchInAPath = *nchInFldrNm = 0; if (type == kMinimalFromFullpathAlias) *nchInAPath = fullpathSpec->fullpathLength; // special case for volumes, already set to return zero length fields // also for minimal aliases, these fields are zero. if (toFile->parID == kVolRootDirID || type != kCompleteAlias) return (noErr); // first get the length of parent folder name err = AL_findDirByID (toFile->vRefNum, toFile->parID, &tdir, localName); if (err != noErr) goto EXIT; *nchInFldrNm = Length(localName); tdir = toFile->parID; // start with input directory while (tdir != kRootDirID) { // trace to root level and get // # of directories and # of char in abs path if ((err = AL_findDirByID (toFile->vRefNum, tdir, &tdir, localName)) == noErr) { ++(*ndirToRoot); // one more dir in the list *nchInAPath += Length(localName) + 1; // add 1 for ':' } else break; } // add volume name, file name length to absolute path if (err == noErr) *nchInAPath += Length(aptr->volumeName) + 1 // 1 for separator character + Length(aptr->fileName); EXIT: return (err); } // end of AL_fillVarLen routine /********************************************************************* ************ Fill # of levels from fromFile and toFile *************** ************ until a common ancestor directory is found ************** *********************************************************************/ static OSErr AL_fillRLvls( const FSSpec *fromFile, //I alias from file const FSSpec *toFile, //I alias to file AliasPtrPriv aptr, //I/O alias record pointer short ndirToRoot) //I # of dirs to root for toFile { OSErr err = noErr; // result code long tdir; // temporary directory num holder long *l; // directory ID array pointer register int i; // for loop index short len; // length of data aptr->nlvlFrom = aptr->nlvlTo = 1; // assume in same folder // detect a simple and common case if (fromFile->parID == toFile->parID) return (noErr); tdir = fromFile->parID; // start with input directory while (tdir != kRootDirID) { // match fromFile path directories to toFile path directories // in order to find a common ancestor directory l = (long *) AL_getVarPtr (aptr, kDirIDs, &len); for (i=0; inlvlTo = i + 1; // these many levels from toFile until a common ancestor break; } if (i < ndirToRoot) // found a common ancestor, no need to look further break; if ((err = AL_findDirByID (fromFile->vRefNum, tdir, &tdir, NULL)) == noErr) ++aptr->nlvlFrom; // one more level up from the fromFile else break; } if (tdir == kRootDirID) aptr->nlvlTo = ndirToRoot + 1; // root is the common ancestor return (err); } // end of AL_fillRLvls routine /********************************************************************* **** Fill variable length absolute path & dirIDs in alias record **** *********************************************************************/ static OSErr AL_fillAbsPath ( short vref, //I volume ref #/ working dir # AliasPtrPriv aptr, //I/O alias record pointer short ndirToRoot, //I # of dirs to root for toFile short nchInAPath, //I # of chars in abs path of toFile NewAliasType type, //I new or update alias is of what type? MinimalFullpathSpec *fullpathSpec) //I fullpath spec { OSErr err = noErr; // result code Str63 localName; // temporary local name long tdir; // temporary directory num holder long *l; // temporary long pointer char *s; // temporary character pointer // add variable infor entries for dirIDS and absolute path if (type == kCompleteAlias && ndirToRoot) // DirIDs stored only for complete aliases l = (long *) AL_addVarEntry (aptr, kDirIDs, ndirToRoot*sizeof(long), NULL); if (type != kMinimalAlias && nchInAPath) { // AbsPath not stored for minimal aliases s = AL_addVarEntry (aptr, kAbsPath, nchInAPath, NULL); if (type == kMinimalFromFullpathAlias) BlockMove (fullpathSpec->fullpath, s, nchInAPath); } // special case for volumes, nothing to put for dirIDs and AbsPath. // Also, MinimalFullPath case is done. if (aptr->parDirID == kVolRootDirID || type != kCompleteAlias || nchInAPath == 0) return (noErr); tdir = aptr->parDirID; // start with input directory s += nchInAPath - Length(aptr->fileName); // point to place where fileName is stored // fill aliased toFile name at end of abs path character array BlockMove (aptr->fileName+1, s, Length(aptr->fileName)); *(--s) = kChrSeparator; // put a colon in front of it while (tdir != kRootDirID) { // trace all directories upto root *l++ = tdir; // store directory IDs upto root if ((err = AL_findDirByID (vref, tdir, &tdir, localName)) == noErr) { // found the directory by its ID s -= Length(localName); // put its name in abs path BlockMove (localName+1, s, Length(localName)); *(--s) = kChrSeparator; // put a colon in front of it } else break; } // end of while if (err == noErr) { // put volume name at the beginning of abs path s -= Length(aptr->volumeName); BlockMove (aptr->volumeName+1, s, Length(aptr->volumeName)); } return (err); } // end of AL_fillAbsPath routine /********************************************************************** ************** Fill in a new alias or update an alias record ****** *********************************************************************/ pascal OSErr AL_fillAlias ( const FSSpec *fromFile, //I aliased from file const FSSpec *target,//I aliased to file Boolean flag, //I update or new? AliasHandlePriv alias, //I/O alias record handle Boolean *wasChanged, //O did alias record change or not? NewAliasType type, // new or update alias is of what type? MinimalFullpathSpec *fullpath) //I fullpath spec { OSErr err; // result code Size oldVarInfoLen=0; // length of varInfo before update register Size newVarInfoLen=0; // length of varInfo after update Size currentLen; // length of alias record before update Size userDataLen=0; // length of user data at the end of alias record unsigned short oldAliasSize=0; // size of old alias record minus any user data unsigned short newAliasSize; // size of newly constructed alias record minus any user data register AliasPtrPriv aptr; // pointer to locked AliasRecord short ndirToRoot; // number of dirs to root for target short nchInAPath; // number of chars in target abs path short nchInFldrNm; // number of chars in parent folder name AliasHandlePriv aliasNew; // handle for newly constructed alias record FSSpec canonicalTarget; // canonical form of target Str255 drvrName; // driver name for kVolOtherEjectable AuxAliasInfo auxAliasRecord; // auxiliary alias record VolumeLocationHandle vloc=NULL; // volume location data handle short vlocSize; // volume location data size *wasChanged = FALSE; // assume that alias record stays the same /* validate passed handle for update call. Also, make sure that the target is a valid canonical form. */ if (target == NULL || (flag != kCreateAlias && (AL_validateHandle(alias) != noErr))) return (paramErr); if (type == kCompleteAlias) { err = AL_canonifyFile (target->vRefNum, target->parID, (Str255 *)target->name, &canonicalTarget); if (err != noErr) return (err); } else canonicalTarget = *target; /* If we are updating the alias record, consturct the updated alias record in a different place then the old one. So, if any errors occur during partially updated alias, old alias record still remains intact. Idea is not to do in-place update so the original record is not damaged until a new update alias is fully constructed. Please note that oldVarInfoLen and userDataLen are meaningful only during updating. */ currentLen = GetHandleSize ((Handle)alias); // current length of old alias record if (flag != kCreateAlias) { // it is update, remember old record aliasNew = (AliasHandlePriv) NewHandleClear(currentLen); if (aliasNew == NULL) // no room for updating return (MemError()); oldAliasSize = (*alias)->aliasSize; userDataLen = currentLen - oldAliasSize; // length of user data oldVarInfoLen = AL_getVarPtr(*alias, kEndMark, &nchInAPath) - &((*alias)->vdata); } else // if creating a new alias record, obviously we have to create it in place aliasNew = alias; HLock((Handle)aliasNew); // lock the alias record, so no one can move us aptr = *aliasNew; // pointer to alias record /* Fill in the alias record. First, fill in fixed length info like volume information, file information etc. Then pre-flight the computation of the length of variable data. Extend or shrink the alias record. Then fill in the variable length information. */ // if it is update, preserve old userType, otherwise init to blanks aptr->userType = flag == kCreateAlias ? 0 : (*alias)->userType; /********* Shipping System 7.0 version has the alias record version 2. From now on, version 2 alias records have to be supported. */ aptr->aliasVersion = 2; // set alias version aptr->unused1 = aptr->unused2 = 0; // unused fields are inited to zero aptr->unused = 0; aptr->parDirID = canonicalTarget.parID; // put parent directory ID in alias AL_copyPString (canonicalTarget.name, aptr->fileName); // put file name in alias rec // fill in volume info if ((err = AL_fillVInfo (canonicalTarget.vRefNum, aptr, &vloc, drvrName, type, fullpath)) != noErr) goto EXIT; // fill in file (or directory) info if ((err = AL_fillFileInfo (&canonicalTarget, aptr, type, &auxAliasRecord, &vloc)) != noErr) goto EXIT; /* pre-flight variable length extension of alias record and do SetHandleSize just once. Make sure all variable length data ends up on an even boundary. */ // get #of directories to root for target and total # of characters // in absolute path of target. if ((err = AL_fillVarLen (&canonicalTarget, aptr, &ndirToRoot, &nchInAPath, &nchInFldrNm, type, fullpath)) != noErr) goto EXIT; if (nchInFldrNm) newVarInfoLen += ((nchInFldrNm+1) & ~1) + sizeof(varInfo); // length of parent folder name if (nchInAPath) newVarInfoLen += ((nchInAPath+1) & ~1) + sizeof(varInfo); // length of absolute path if (ndirToRoot) newVarInfoLen += (ndirToRoot * sizeof (long)) + sizeof(varInfo); // length of directory IDs if (aptr->volumeAttributes & kVolMntExists) { // volume location info vlocSize = GetHandleSize((Handle)vloc); newVarInfoLen += ((vlocSize+1) & ~1) + sizeof(varInfo); } if (aptr->volumeType == kVolOtherEjectable) // driver name length newVarInfoLen += ((Length(drvrName)+1) & ~1) + sizeof(varInfo); // Is any auxiliary info available to be stored in case of FileShare volumes? if (aptr->volumeAttributes & kVolAuxRemoteInfo) // valid auxiliary remote alias record info newVarInfoLen += sizeof(AuxAliasInfo) + sizeof(varInfo); if (aptr->volumeAttributes & kVolAuxRealDirIDs) // valid auxiliary real dirID info newVarInfoLen += sizeof(AuxAliasDirIDs) + sizeof(varInfo); newVarInfoLen += sizeof(varInfo); // leave room for the endMarker /* Extend or shrink the alias record to accomodate new variable length information. If we are growing the record, unlock the handle before growing. This has a better chance for succeding. If success, lock it again so our record pointer is valid again and while we fill the variable info, the record won't be moved on us. If we are updating the alias record, old user data that may have been appended to the alias record has to be adjusted up or down accordingly. */ if (newVarInfoLen != oldVarInfoLen) { // need to expand or shrink the variable length field HUnlock((Handle)aliasNew); // unlock previously allocated alias record SetHandleSize ((Handle)aliasNew, currentLen + (newVarInfoLen-oldVarInfoLen)); // grow alias record if ((err = MemError()) != noErr) // could not extend block goto EXIT; HLock((Handle)aliasNew); aptr = *aliasNew; // lock the pointer to alias record again if (newVarInfoLen > oldVarInfoLen) // clear out expanded record before filling it in AL_BlockInit ((Ptr)aptr + currentLen, '\0', newVarInfoLen-oldVarInfoLen); } // Move user data from old record to new record if doing an update. BlockMove (((char *)(*alias)) + oldAliasSize, ((char *) aptr) + oldAliasSize + (newVarInfoLen - oldVarInfoLen), userDataLen); /* The record is now set to correct size. Now fill in the variable length info like parent folder name, absolute fullpath, zone, server and user name for AppleShare aliases, driver name for non-floppy ejectable volumes and any other future variable length info that needs to be stored. */ // wipe out old variable length data and fill in all variable info (void) AL_addVarEntry (aptr, kEndMark, 0, NULL); // datalength 0 for endMarker // fill in folder name info if ((err = AL_fillFldrInfo (&canonicalTarget, aptr, type)) != noErr) goto EXIT; // store all directory IDs and full absolute pathname of target if ((err = AL_fillAbsPath (canonicalTarget.vRefNum, aptr, ndirToRoot, nchInAPath, type, fullpath)) != noErr) goto EXIT; // fill in zone, server and user name if (aptr->volumeAttributes & kVolMntExists) (void) AL_addVarEntry (aptr, kVolMntInfo, vlocSize, (Ptr)(*vloc)); // fill in driver name for non-floppy ejectable disks if (aptr->volumeType == kVolOtherEjectable) (void) AL_addVarEntry (aptr, kDrvrNm, Length(drvrName), drvrName+1); // Store any auxiliary info available to be stored in case of FileShare volumes? if (aptr->volumeAttributes & kVolAuxRemoteInfo) // valid auxiliary remote alias record info (void) AL_addVarEntry (aptr, kAuxRemoteAlias, sizeof(AuxAliasInfo), (Ptr)&auxAliasRecord); if (aptr->volumeAttributes & kVolAuxRealDirIDs) // valid auxiliary real parent dirID info (void) AL_addVarEntry (aptr, kAuxRealDirID, sizeof(AuxAliasDirIDs), (Ptr)&auxAliasRecord.auxDirIDs); // fill in fromFile-target relative path information. // relative path across volumes does not make sense. // Also, relative path for volume aliases or relative to a volume does not make sense. if (fromFile != NULL && fromFile->vRefNum == canonicalTarget.vRefNum && fromFile->parID != kVolRootDirID && canonicalTarget.parID != kVolRootDirID) { if ((err = AL_fillRLvls (fromFile, &canonicalTarget, aptr, ndirToRoot)) != noErr) goto EXIT; } else aptr->nlvlFrom = aptr->nlvlTo = kNoRelativePath; /* We are done with updating the alias record. Store the size of the new record. Size is our fixed length data plus variable length data. It does not include the length of any user data that may have been there. This size field is available to client to inspect and access his own data that is stored at the end. If we updated the alias (as opposed to creating a new one), copy data from newly constructed alias record to the old handle and dispose of the new handle. Also, update needs to check if the record was really updated or not. If the old record size (our fixed plus variable length) does not match the new record size (newly computed fixed plus variable length), the two records are different. If both lengths are same, comapre both records to determine if the record was updated or not. */ newAliasSize = (currentLen - userDataLen) + (newVarInfoLen - oldVarInfoLen); aptr->aliasSize = newAliasSize; if (flag != kCreateAlias) { // if it was update, copy into old record, compare old and new records currentLen = newAliasSize + userDataLen; // length of new alias record (our data + user data) if (oldAliasSize != newAliasSize) { // need to expand or shrink old alias record SetHandleSize ((Handle)alias, currentLen); if ((err = MemError()) != noErr) goto EXIT; *wasChanged = TRUE; // if different length, they are already different } else *wasChanged = (! AL_BlockCompare((Ptr)aptr, (Ptr)*alias, newAliasSize)); if (*wasChanged) // if it is the same record, no need to copy BlockMove ((Ptr)aptr, (Ptr)*alias, currentLen); } EXIT: HUnlock((Handle)aliasNew); // unlock the allocated alias record if (flag != kCreateAlias) // get rid of newly constructed copy of alias record DisposHandle((Handle)aliasNew); if (vloc != NULL) // get rid of volume location data handle DisposHandle((Handle)vloc); return (err); } // end of AL_fillAlias routine /******************************** end of alFill.c **************************/