appletfilealias.c

Go to the documentation of this file.
00001 
00002 /*  $Id: appletfilealias.c 355 2005-01-11 22:48:55Z andreradke $    */
00003 
00004 /* copyright 1991-96 UserLand Software, Inc. All Rights Reserved.*/
00005 
00006 
00007 #include <GestaltEqu.h>
00008 #include <Aliases.h>
00009 #include <Finder.h>
00010 #include <Folders.h>
00011 #include "appletdefs.h"
00012 #include "appletfiles.h"
00013 #include "appletmemory.h"
00014 #include "appletstrings.h"
00015 #include "appletfilesinternal.h"
00016 #include "appletfilealias.h"
00017 
00018 #define usesourcefiletype /*DW 9/6/93 -- inherit file type/creator from source file*/
00019 
00020 #define MAXCHAINS 10 /*maximum number of aliases to resolve before giving up*/
00021 
00022 typedef struct {
00023     OSType      folderType;
00024     OSType      aliasType;
00025 } MappingEntry;
00026 
00027 
00028 #define kNumIconTypes 6
00029 #define kNumFolders 9
00030 
00031 
00032     // Resource ID used for alias file's icon (when needed)
00033     
00034 #define kCustomAliasIconID -16496
00035 
00036 
00037     // Forward declarations
00038     
00039 Boolean FSpIsVolume(const FSSpec* fsSpec);
00040 Boolean FSpIsFolder(const FSSpec* fsSpec, long* dirID, unsigned short* fdFlags);
00041 Boolean CopyCustomIcons(const FSSpec* source, short sourceID,
00042                             short destRefnum, short destID);
00043 Boolean CopyDriverIcon(const FSSpec* volSpec, short destRefnum, short destID);
00044 OSErr DetermineAliasInfo(const FSSpec* fsSpec, OSType* creator, OSType* fType,
00045                             Boolean* gotCustom, FSSpec* iconSpec, short* rsrcID);
00046 
00047 
00048 
00049 static pascal OSErr CreateAliasFile(const FSSpec* targetFile, const FSSpec* aliasFile)
00050 {
00051     OSType      fileCreator, fileType;
00052     FSSpec      iconSpec;
00053     Boolean     gotCustom;
00054     short       rsrcID;
00055     short       aliasRefnum;
00056     AliasHandle alias;
00057     FInfo       finf;
00058     
00059         // Get type/creator for alias file & custom icon file spec
00060     OSErr err = DetermineAliasInfo(targetFile, &fileCreator, &fileType, 
00061                                             &gotCustom, &iconSpec, &rsrcID);
00062     if (err != noErr) return err;
00063     
00064     #ifdef usesourcefiletype /*DW 9/6/93 -- inherit file type/creator from source file*/
00065         {
00066         FSSpec fs = *targetFile;
00067         tyfileinfo info;
00068         
00069         if (filegetinfo (&fs, &info)) {
00070             
00071             fileCreator = info.filecreator;
00072             
00073             fileType = info.filetype;
00074             }
00075         }
00076     #endif
00077     
00078         // Create the alias file (it must not exist already)
00079     FSpCreateResFile(aliasFile, fileCreator, fileType, 0);
00080     err = ResError();
00081     if (err != noErr) return err;
00082 
00083         // Create the alias handle
00084     err = NewAlias(aliasFile, targetFile, &alias);
00085     if (err != noErr || alias == NULL) return err;
00086     
00087     aliasRefnum = FSpOpenResFile(aliasFile, fsRdWrPerm);
00088     // should exist because it was just created
00089     
00090         // Add the alias handle to alias file
00091     AddResource((Handle)alias, rAliasType, 0, "\p");
00092     err = ResError();
00093     
00094         // Copy custom icons (if necessary)
00095     if (gotCustom)
00096         gotCustom = CopyCustomIcons(&iconSpec, rsrcID, aliasRefnum, kCustomAliasIconID);
00097         
00098     if (!gotCustom && FSpIsVolume(targetFile))  // must get icon from disk driver
00099         gotCustom = CopyDriverIcon(targetFile, aliasRefnum, kCustomAliasIconID);
00100         
00101     CloseResFile(aliasRefnum);
00102 
00103     FSpGetFInfo(aliasFile, &finf);
00104     
00105     finf.fdCreator = fileCreator;
00106     finf.fdType = fileType;
00107     finf.fdFlags |= 0x8000;     // set alias bit
00108     if (gotCustom)
00109         finf.fdFlags |= 0x0400; // set custom icon bit
00110     finf.fdFlags &= (~0x0100);  // clear inited
00111     
00112     FSpSetFInfo(aliasFile, &finf);
00113 
00114     return noErr;
00115 }
00116 
00117 
00118     // Returns true if fsSpec refers to a volume
00119     
00120 static Boolean FSpIsVolume(const FSSpec* fsSpec)
00121 {
00122     return fsSpec->parID == 1;
00123 }
00124 
00125     // Returns true if fsSpec refers to a folder; also returns folder's dirID & finder flags
00126     
00127 static Boolean FSpIsFolder(const FSSpec* fsSpec, long* dirID, unsigned short* fdFlags)
00128 {
00129     CInfoPBRec pb;
00130 
00131     if (FSpIsVolume(fsSpec)) return false;
00132     
00133     pb.dirInfo.ioNamePtr = (StringPtr)&fsSpec->name;
00134     pb.dirInfo.ioVRefNum = fsSpec->vRefNum;
00135     pb.dirInfo.ioFDirIndex = 0;
00136     pb.dirInfo.ioDrDirID = fsSpec->parID;
00137     
00138     if (PBGetCatInfoSync(&pb) != noErr) return false;
00139     
00140     *dirID = pb.dirInfo.ioDrDirID;
00141     *fdFlags = pb.dirInfo.ioDrUsrWds.frFlags;
00142     
00143     return (pb.dirInfo.ioFlAttrib & 0x10) != 0;
00144 }
00145 
00146 
00147     // Copies all icon resources from indicated source file (using indicated rsrc ID to (already
00148     // opened) destination file (using destID).  source->vRefNum == 0 implies system resource file
00149     // Returns true if an icon was added to the destination.
00150     // (Doesn't work if source == destination.)
00151     
00152 static Boolean CopyCustomIcons(const FSSpec* source, short sourceID,
00153                             short destRefnum, short destID)
00154 {
00155     short       iconRefnum;
00156     char*       table = "ICN#icl4icl8ics#ics4ics8";
00157     OSType*     p;
00158     Boolean     copiedSomething = false;
00159     int         i;
00160     OSErr       err;
00161     
00162     if (source->vRefNum != 0)
00163         iconRefnum = FSpOpenResFile(source, fsRdPerm);
00164     else
00165         iconRefnum = 0; // system resource file
00166         
00167     if (iconRefnum != -1) {
00168         for (i = 0, p = (OSType*)table; i < kNumIconTypes; i++, p++)
00169         {
00170             Handle h;
00171             
00172             UseResFile(iconRefnum);
00173             h = Get1Resource(*p, sourceID);
00174             
00175             if (h != NULL) {
00176                 DetachResource(h);
00177                 
00178                 UseResFile(destRefnum);
00179                 AddResource(h, *p, destID, "\p");
00180                 err = ResError();
00181 
00182                 if (err != noErr)
00183                     DisposHandle(h);
00184                 else
00185                     copiedSomething = true;
00186             }
00187         }
00188         
00189         if (iconRefnum != 0)
00190             CloseResFile(iconRefnum);
00191     }
00192     
00193     return copiedSomething;
00194 }
00195 
00196 
00197     // Copies all icon resources from indicated source file (using indicated rsrc ID to (already
00198     // opened) destination file (using destID).  source->vRefNum == 0 implies system resource file
00199     // Returns true if an icon was added to the destination.
00200     // (Doesn't work if source == destination.)
00201     
00202 static Boolean CopyDriverIcon(const FSSpec* volSpec, short destRefnum, short destID)
00203 {
00204     HParamBlockRec  pb;
00205     ParamBlockRec   cpb;
00206     OSErr           err;
00207     Handle          h;
00208     
00209     if (!FSpIsVolume(volSpec)) return false;
00210     
00211     pb.volumeParam.ioNamePtr = NULL;
00212     pb.volumeParam.ioVRefNum = volSpec->vRefNum;
00213     pb.volumeParam.ioVolIndex = 0;
00214     
00215     err = PBHGetVInfoSync(&pb);
00216     if (err != noErr) return false;
00217     
00218         // set up for Control call
00219     cpb.cntrlParam.ioCRefNum = pb.volumeParam.ioVDRefNum;
00220     cpb.cntrlParam.ioVRefNum = pb.volumeParam.ioVDrvInfo;
00221     
00222         // first try csCode 22
00223     cpb.cntrlParam.csCode = 22;
00224     err = PBControl(&cpb, false);
00225     
00226     if (err != noErr) {
00227             // try csCode 21;
00228         cpb.cntrlParam.csCode = 21;
00229         err = PBControlSync(&cpb);
00230     }
00231     
00232     if (err != noErr) return false;
00233 
00234     h = appnewhandle(kLargeIconSize);       // size of ICN#
00235     if (h == NULL) return false;
00236     
00237         // copy ICN# into handle
00238     BlockMove(*(Ptr*)&cpb.cntrlParam.csParam, *h, kLargeIconSize);
00239 
00240     UseResFile(destRefnum);
00241     AddResource(h, 'ICN#', destID, "\p");
00242     err = ResError();
00243     
00244     if (err != noErr)
00245         DisposHandle(h);
00246         
00247     return err == noErr;
00248 }
00249 
00250 
00251     // Figures out information about an alias for the indicated file (fsSpec)
00252     // Returns type & creator of file; whether the target has a custom icon (and
00253     //      the file from which to get it, and the resource ID of those icons)
00254     
00255 static OSErr DetermineAliasInfo(const FSSpec* fsSpec, OSType* creator, OSType* fType,
00256                             Boolean* gotCustom, FSSpec* iconSpec, short* rsrcID)
00257 {
00258     OSErr err;
00259     long dirID;
00260     FInfo finderStuff;
00261     
00262     *gotCustom = false;
00263     *rsrcID = kCustomIconResource;  // default value
00264     
00265     if (FSpIsVolume(fsSpec)) {
00266             // temporarily, all volumes are given the same type
00267             
00268         *creator = 'MACS';
00269         *fType = kContainerHardDiskAliasType; 
00270 
00271         err = FSMakeFSSpec(fsSpec->vRefNum, 2, "\pIcon\015", iconSpec);
00272         
00273         if (err == noErr) // volume has a custom icon file (maybe)
00274             *gotCustom = true;
00275     }
00276     
00277     else if (FSpIsFolder(fsSpec, &dirID, &finderStuff.fdFlags)) {
00278             // table mapping special folder ID to alias file type
00279         MappingEntry table[kNumFolders] =
00280         {   { kAppleMenuFolderType,         kAppleMenuFolderAliasType },
00281             { kControlPanelFolderType,      kControlPanelFolderAliasType },
00282             { kExtensionFolderType,         kExtensionFolderAliasType },
00283             { kPreferencesFolderType,       kPreferencesFolderAliasType },
00284             { kPrintMonitorDocsFolderType,  kPrintMonitorDocsFolderAliasType },
00285             { kWhereToEmptyTrashFolderType, kContainerTrashAliasType },
00286             { kTrashFolderType,             kContainerTrashAliasType },
00287             { kStartupFolderType,           kStartupFolderAliasType },
00288             { kSystemFolderType,            kSystemFolderAliasType }
00289         };
00290         MappingEntry* p;
00291         int i;
00292         
00293             // see if original folder has a custom icon
00294         *gotCustom = (finderStuff.fdFlags & 0x0400) != 0;
00295         if (*gotCustom)
00296             FSMakeFSSpec(fsSpec->vRefNum, dirID, "\pIcon\015", iconSpec);
00297         
00298         *creator = 'MACS';
00299         *fType = kContainerFolderAliasType;         // default file type for alias file
00300         
00301                 // see if the folder is one of the special ones; if so, modify the file type
00302         for (i=1, p = table; i<=kNumFolders; i++, p++) {
00303             short foundVRefnum;
00304             long foundDirID;
00305             
00306             err = FindFolder(fsSpec->vRefNum, p->folderType, false, &foundVRefnum, &foundDirID);
00307             if (err == noErr && foundDirID == dirID) {
00308                 *fType = p->aliasType;
00309                 break;
00310             }
00311         }
00312     }
00313     
00314     else {  // alias to a file
00315         err = FSpGetFInfo(fsSpec, &finderStuff);
00316         if (err != noErr) return noErr;
00317         
00318         *creator = finderStuff.fdCreator;
00319         *fType = finderStuff.fdType;
00320         
00321         if (*fType == 'APPL')
00322             *fType = kApplicationAliasType;     // special case for aliases to applications
00323             
00324         *gotCustom = (finderStuff.fdFlags & 0x0400) != 0;
00325         if (*gotCustom)
00326             FSMakeFSSpec(fsSpec->vRefNum, fsSpec->parID, fsSpec->name, iconSpec);
00327     }
00328     
00329     return noErr;
00330 }
00331 
00332 
00333 #if false
00334 
00335 pascal OSErr FollowFinderAlias (const FSSpec *fromFile, AliasHandle alias, Boolean logon, FSSpec *target, Boolean *wasChanged) = {
00336                                    
00337     /*
00338     resolves an alias taken from a Finder alias file,
00339     updating the alias record (but not the alias resource in the file) if
00340     necessary.
00341     */
00342     
00343     0x700F, 0xA823};  /*MOVEQ #$0F,D0; _AliasDispatch;*/
00344     /*FollowFinderAlias*/
00345 
00346 #endif
00347     
00348     
00349 static pascal OSErr IsAliasFile (const FSSpec *pfs, Boolean *flalias, Boolean *flfolder) {
00350                              
00351     CInfoPBRec pb;
00352     OSErr ec;
00353     Str255 fname;
00354       
00355     assert ((pfs != nil) || (flalias != nil) || (flfolder != nil));
00356     
00357     copystring ((void *) (*pfs).name, fname);
00358       
00359     *flalias = *flfolder = false;
00360     
00361     pb.hFileInfo.ioCompletion = nil;
00362 
00363     pb.hFileInfo.ioNamePtr = (StringPtr) &fname;
00364 
00365     pb.hFileInfo.ioVRefNum = pfs->vRefNum;
00366 
00367     pb.hFileInfo.ioDirID = pfs->parID;
00368 
00369     pb.hFileInfo.ioFVersNum = 0;  /* MFS compatibility, see TN #204 */
00370 
00371     pb.hFileInfo.ioFDirIndex = 0;
00372       
00373     ec = PBGetCatInfoSync(&pb);
00374       
00375     /*set flalias if the item is not a directory and the aliasFile bit is set */
00376 
00377     if (ec == noErr) { /*check directory bit*/
00378         
00379         if ((pb.hFileInfo.ioFlAttrib & ioDirMask) != 0)
00380             *flfolder = true;
00381         else if ((pb.hFileInfo.ioFlFndrInfo.fdFlags & 0x8000) != 0)
00382             *flalias = true;
00383         }
00384       
00385     return (ec);
00386     } /*IsAliasFile*/
00387 
00388 
00389 static pascal OSErr ResolveAliasFileMountOption (FSSpec *pfs, Boolean resolvechains, Boolean *targetIsFolder, Boolean *wasAliased, Boolean mountRemoteVols) {
00390 
00391     short resnum;
00392     Handle alisHandle;
00393     FSSpec fsorig;
00394     Boolean updateFlag, foundFlag, wasAliasedTemp, specChangedFlag;
00395     short chainCount;
00396     OSErr ec;
00397       
00398     assert ((pfs != nil) || (targetIsFolder != nil) || (wasAliased != nil));
00399       
00400     fsorig = *pfs; /*so FSSpec can be restored in case of error*/
00401 
00402     chainCount = MAXCHAINS; /*circular alias chain protection*/
00403     
00404     resnum = -1; /*resource file not open*/
00405       
00406     *targetIsFolder = foundFlag = specChangedFlag = false;
00407 
00408     do { /*loop through chain of alias files*/
00409         
00410         chainCount--;
00411         
00412         /*check if FSSpec is an alias file or a directory*/
00413         /*note that targetIsFolder => NOT wasAliased*/
00414         
00415         ec = IsAliasFile (pfs, wasAliased, targetIsFolder);
00416         
00417         if (ec != noErr || !(*wasAliased)) 
00418             break;
00419         
00420         resnum = FSpOpenResFile (pfs, fsCurPerm); /*get the resource file reference number*/
00421         
00422         ec = ResError ();
00423         
00424         if (resnum == -1) 
00425             break;
00426         
00427         alisHandle = Get1IndResource (rAliasType, 1); /*the first 'alis' resource in the file is the appropriate alias*/
00428         
00429         ec = ResError ();
00430         
00431         if (alisHandle == nil) 
00432             break;
00433         
00434         LoadResource (alisHandle); /*load the resource explicitly in case SetResLoad(FALSE)*/
00435         
00436         ec = ResError ();
00437         
00438         if (ec != noErr) 
00439             break;
00440     
00441         ec = FollowFinderAlias (pfs, (AliasHandle) alisHandle, mountRemoteVols, pfs, &updateFlag);
00442         
00443         /*FollowFinderAlias returns nsvErr if volume not mounted*/
00444         
00445         if (ec == noErr) {
00446         
00447             if (updateFlag) { /*the resource in the alias file needs updating*/
00448             
00449                 ChangedResource(alisHandle);
00450                 
00451                 WriteResource(alisHandle);
00452                 }
00453           
00454             specChangedFlag = true; /*in case of error, restore file spec*/
00455           
00456             ec = IsAliasFile (pfs, &wasAliasedTemp, targetIsFolder);
00457             
00458             if (ec == noErr) /*we're done unless it was an alias file and we're following a chain*/
00459                 foundFlag = !(wasAliasedTemp && resolvechains);
00460             }
00461         
00462         CloseResFile (resnum);
00463         
00464         resnum = -1;
00465         } while ((ec == noErr) && (chainCount > 0) && (!foundFlag));
00466 
00467     if (chainCount == 0 && !foundFlag) /*return file not found error for circular alias chains*/
00468         ec = fnfErr; 
00469         
00470     /*if error occurred, close resource file and restore the original FSSpec*/
00471 
00472     if (resnum != -1) 
00473         CloseResFile (resnum);
00474 
00475     if (ec != noErr && specChangedFlag) 
00476         *pfs = fsorig;
00477             
00478     return (ec);
00479     } /*ResolveAliasFileMountOption*/
00480     
00481     
00482 boolean filemakealias (const FSSpec *srcFile, const FSSpec *destFile) {
00483     
00484     return (!fileerror ((ptrfilespec) srcFile, CreateAliasFile (srcFile, destFile)));
00485     } /*filemakealias*/
00486 
00487 
00488 boolean fileresolvealias (FSSpec *fs, boolean flmountvolume) {
00489     
00490     /*
00491     DW 9/15/93: add flmountvolume parameter, include code from Apple technote.
00492     
00493     DW 9/16/93: don't report errors in a dialog. too often it's the wrong thing
00494     to do. if you want to report an error to the user, cook up your own dialog.
00495     */
00496 
00497     Boolean flfolder, flalias;
00498     OSErr ec;
00499     
00500     if (flmountvolume) 
00501         ec = ResolveAliasFile (fs, true, &flfolder, &flalias);
00502     else {
00503         ec = ResolveAliasFileMountOption (fs, true, &flfolder, &flalias, false);
00504         
00505         if (ec == nsvErr) /*no dialog, just return false, the caller must be prepared*/
00506             return (false);
00507         }
00508     
00509     return (ec == noErr);
00510     } /*fileresolvealias*/
00511     
00512     

Generated on Wed May 31 18:19:40 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6