diff options
Diffstat (limited to 'macos/source/recurse.c')
-rw-r--r-- | macos/source/recurse.c | 442 |
1 files changed, 442 insertions, 0 deletions
diff --git a/macos/source/recurse.c b/macos/source/recurse.c new file mode 100644 index 0000000..e87db3c --- /dev/null +++ b/macos/source/recurse.c @@ -0,0 +1,442 @@ +/* +These functions are based on Jim Luther's IterateDirectory() found in MoreFiles +However, it's heavily modified by Dirk Haase +*/ + +/* +** IterateDirectory: File Manager directory iterator routines. +** +** by Jim Luther +** +** File: IterateDirectory.c +** +** Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc. +** All rights reserved. +** +** You may incorporate this sample code into your applications without +** restriction, though the sample code has been provided "AS IS" and the +** responsibility for its operation is 100% yours. +** +** IterateDirectory is designed to drop into the MoreFiles sample code +** library I wrote while in Apple Developer Technical Support +*/ + +/*****************************************************************************/ +/* Includes */ +/*****************************************************************************/ + +#include <Types.h> +#include <Errors.h> +#include <Files.h> +#include <stdio.h> +#include <string.h> + + +#include "zip.h" +#include "macstuff.h" +#include "helpers.h" +#include "recurse.h" +#include "macglob.h" +#include "pathname.h" + + + + +/*****************************************************************************/ +/* Macros, typedefs */ +/*****************************************************************************/ + +/* The RecurseGlobals structure is used to minimize the amount of +** stack space used when recursively calling RecurseDirectoryLevel +** and to hold global information that might be needed at any time. +*/ +struct RecurseGlobals +{ + short vRefNum; + CInfoPBRec cPB; /* the parameter block used for + PBGetCatInfo calls */ + unsigned char *itemName; /* the name of the current item */ + char *FullPath; + short FullPathLen; + OSErr result; /* temporary holder of results - + saves 2 bytes of stack each level */ + Boolean quitFlag; /* set to true if filter wants to + kill interation */ + unsigned short maxLevels; /* Maximum levels to + iterate through */ + unsigned short currentLevel; /* The current level + IterateLevel is on */ +}; + +typedef struct RecurseGlobals RecurseGlobals; +typedef RecurseGlobals *RecurseGlobalsPtr; + + +/*****************************************************************************/ +/* Global Vars */ +/*****************************************************************************/ + +extern MacZipGlobals MacZip; +extern const char ResourceMark[13]; /* "XtraStuf.mac:" var is initialized in file pathname.c */ +extern int extra_fields; /* do not create extra fields if false */ + +static RecurseGlobals theGlobals; + +static unsigned long DirLevels = 0; +static char *buffer; +extern int verbose; /* 1=report oddities in zip file structure */ + +/*****************************************************************************/ +/* Prototypes */ +/*****************************************************************************/ + +int procname(char *filename, int caseflag); +int MatchWild( char *pPat, char *pStr, int case_sens); +Boolean IsZipFile(char *name); + +static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals); +static Boolean isRegularItem( RecurseGlobals *Globals); +static void ProcessFiles(RecurseGlobals *Globals, + Boolean hasDataFork, Boolean hasResourceFork); +static void ProcessDirectory(RecurseGlobals *Globals, + Boolean IncludeItem, long DirID); +static void ProcessItem(RecurseGlobals *Globals, long DirID); + +/*****************************************************************************/ +/* Functions */ +/*****************************************************************************/ + +static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals) +{ +char buffer2[23]; + + /* if maxLevels is zero, we aren't checking levels */ + if ( (Globals->maxLevels == 0) || + /* if currentLevel < maxLevels, look at this level */ + (Globals->currentLevel < Globals->maxLevels) ) + { + short index = 1; + + ++Globals->currentLevel; /* go to next level */ + if (DirLevels < Globals->currentLevel) DirLevels = Globals->currentLevel; + sprintf(buffer2,"Globals->currentLevel: %d",Globals->currentLevel); + + do + { /* Isn't C great... What I'd give for a "WITH + theGlobals DO" about now... */ + + /* Get next source item at the current directory level */ + Globals->cPB.dirInfo.ioFDirIndex = index; + Globals->cPB.dirInfo.ioDrDirID = DirID; + Globals->result = PBGetCatInfoSync((CInfoPBPtr)&Globals->cPB); + + ShowCounter(false); + + if ( Globals->result == noErr ) + { + ProcessItem(Globals, DirID); + } /* if ( Globals->result == noErr ) */ + + ++index; /* prepare to get next item */ + /* time to fall back a level? */ + } while ( (Globals->result == noErr) && (!Globals->quitFlag) ); + + if ( (Globals->result == fnfErr) || /* fnfErr is OK - + it only means we hit + the end of this level */ + (Globals->result == afpAccessDenied) ) /* afpAccessDenied is OK, + too - it only means we cannot see inside a directory */ + { + Globals->result = noErr; + } + + --Globals->currentLevel; /* return to previous level as we leave */ + } +} + + + +/*****************************************************************************/ + +pascal OSErr RecurseDirectory(short vRefNum, + long thedirID, + ConstStr255Param name, + unsigned short maxLevels) +{ + OSErr result; + short theVRefNum; + Boolean isDirectory; + long DirID; + + /* Get the real directory ID and make sure it is a directory */ + result = GetDirectoryID(vRefNum, thedirID, name, &DirID, &isDirectory); + if ( result == noErr ) + { + if ( isDirectory == true ) + { + /* Get the real vRefNum */ + result = DetermineVRefNum(name, vRefNum, &theVRefNum); + if ( result == noErr ) + { + /* Set up the globals we need to access from + the recursive routine. */ + theGlobals.cPB.hFileInfo.ioNamePtr = theGlobals.itemName; + theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum; + theGlobals.itemName[0] = 0; + theGlobals.result = noErr; + theGlobals.quitFlag = false; + theGlobals.maxLevels = maxLevels; + theGlobals.currentLevel = 0; /* start at level 0 */ + + /* Here we go into recursion land... */ + RecurseDirectoryLevel(DirID, &theGlobals); + + result = theGlobals.result; /* set the result */ + } + } + else + { + result = dirNFErr; /* a file was passed instead + of a directory */ + } + } + + return ( result ); +} + + + +/*****************************************************************************/ + +pascal OSErr FSpRecurseDirectory(const FSSpec *spec, + unsigned short maxLevels) +{ + OSErr rc; + + theGlobals.vRefNum = spec->vRefNum; + + /* make room for pathnames */ + theGlobals.itemName = (unsigned char *) StrCalloc(NAME_MAX); + theGlobals.FullPath = StrCalloc(NAME_MAX); + buffer = StrCalloc(NAME_MAX); + + + if ((noisy) && (MacZip.DataForkOnly)) + printf("\n Warning: Datafork only \n"); + + /* reset the count to zero */ + ShowCounter(true); + + if (noisy) leftStatusString("Build File List; Items done:"); + if (noisy) printf("\n Collecting Filenames ..."); + rc = RecurseDirectory(spec->vRefNum, spec->parID, spec->name,maxLevels); + printerr("RecurseDirectory:",rc,rc,__LINE__,__FILE__,""); + + if (noisy) printf("\n... done \n\n %6d matched files found \n", + MacZip.FoundFiles); + if (noisy) printf(" %6d folders found in %d Levels \n", + MacZip.FoundDirectories,DirLevels); + + if (MacZip.BytesOfData > (1024*1024)) + if (noisy) printf(" %4.3f MBytes unzipped size\n\n", + (float) MacZip.BytesOfData/(1024*1024)); + else + if (noisy) printf(" %4.3f KBytes unzipped size\n\n", + (float) MacZip.BytesOfData/1024); + + /* free all memory of pathnames */ + theGlobals.itemName = (unsigned char *) StrFree((char *)theGlobals.itemName); + theGlobals.FullPath = StrFree(theGlobals.FullPath); + buffer = StrFree(buffer); + + return rc; +} + + + + +/* +* Return true if filename == zipfile +* After the first match no further check will be done ! +* +*/ +Boolean IsZipFile(char *filen) +{ +static firstMatch = false; + +if (filen == NULL) + firstMatch = false; + +if (!firstMatch) + { + if (stricmp(filen, MacZip.ZipFullPath) == 0) + { + firstMatch = true; + return true; + } + } + +return false; +} + + + +static Boolean isRegularItem( RecurseGlobals *Globals) +{ +Boolean isInvisible = false, + isAlias = false, + isSystem = false; + +isSystem = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags & + (1 << 12)) == 0 ); +isInvisible = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags & + (1 << 14)) == 0 ); +isAlias = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags & + (1 << 15)) == 0); + +if (isAlias == true) + { + return false; + } + +if (MacZip.IncludeInvisible == true) + { + return true; + } + +if ((isSystem == true) || + (isInvisible == true)) + { + return false; + } + +return true; +} + + + + +static void ProcessFiles(RecurseGlobals *Globals, + Boolean hasDataFork, Boolean hasResourceFork) +{ + /* some file statistics */ +MacZip.FoundFiles++; + +if (hasDataFork == true) + { + MacZip.BytesOfData = + Globals->cPB.hFileInfo.ioFlLgLen + + MacZip.BytesOfData; + MacZip.CurrentFork = DataFork; + MacZip.RawCountOfItems++; + + if (MacZip.DataForkOnly == true) + { + procname(Globals->FullPath, false); + hasResourceFork = false; + } + else + { + procname(Real2RfDfFilen(buffer,Globals->FullPath, + DataFork, MacZip.MacZipMode, + MacZip.DataForkOnly), false); + } + } + +if (hasResourceFork == true) + { + MacZip.BytesOfData = + Globals->cPB.hFileInfo.ioFlRLgLen + + MacZip.BytesOfData; + MacZip.CurrentFork = ResourceFork; + MacZip.RawCountOfItems++; + + procname(Real2RfDfFilen(buffer, Globals->FullPath, + ResourceFork, MacZip.MacZipMode, + MacZip.DataForkOnly), false); + } +} + + + + +static void ProcessDirectory(RecurseGlobals *Globals, + Boolean IncludeItem, long DirID) +{ +OSErr rc; + +MacZip.isDirectory = true; + +GetFullPathFromID(Globals->FullPath,Globals->vRefNum, DirID, + Globals->itemName, &rc); + +MacZip.RawCountOfItems++; +MacZip.FoundDirectories++; + +if (MacZip.StoreFoldersAlso) + { + procname(Globals->FullPath, false); + } + + /* We have a directory */ + if ( !Globals->quitFlag && IncludeItem) + { + /* Dive again if the IterateFilterProc didn't say "quit" and dir is + not an alias */ + RecurseDirectoryLevel(Globals->cPB.dirInfo.ioDrDirID, + Globals); + } +} + + + +static void ProcessItem(RecurseGlobals *Globals, long DirID) +{ +OSErr rc; +Boolean IncludeItem = false, hasDataFork = false; +Boolean hasResourceFork = false; + +IncludeItem = isRegularItem(Globals); + +/* Is it a File? */ +if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) == 0 ) + { + PToCCpy(Globals->itemName,MacZip.FileName); + MacZip.isDirectory = false; + + hasDataFork = (Globals->cPB.hFileInfo.ioFlLgLen != 0); + hasResourceFork = (Globals->cPB.hFileInfo.ioFlRLgLen != 0); + + /* include also files with zero recource- and data-fork */ + if ((hasDataFork == 0) && (hasResourceFork == 0)) + hasDataFork = true; + + if ((hasDataFork == 0) && + (hasResourceFork != 0) && + (extra_fields == false)) + { + IncludeItem = false; + } + + GetFullPathFromID(Globals->FullPath,Globals->vRefNum, + DirID, Globals->itemName, &rc); + printerr("GetFullPathFromID:",rc,rc,__LINE__, + __FILE__,MacZip.FileName); + + if (IncludeItem && /* don't include the zipfile itself */ + (!IsZipFile(Globals->FullPath)) ) + { + if (MATCH(MacZip.Pattern, MacZip.FileName, false) == true) + { + ProcessFiles(Globals, hasDataFork, hasResourceFork); + } /* if (MatchWild( MacZip.FileName,MacZip.Pattern ) == + true) */ + } /* if (!IsZipFile(Globals->FullPath)) */ + } /* Is it a File? */ + +/* Is it a directory? */ +if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 ) + { + ProcessDirectory(Globals,IncludeItem, DirID); + } /* Is it a directory? */ +} |