recurse.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442
  1. /*
  2. These functions are based on Jim Luther's IterateDirectory() found in MoreFiles
  3. However, it's heavily modified by Dirk Haase
  4. */
  5. /*
  6. ** IterateDirectory: File Manager directory iterator routines.
  7. **
  8. ** by Jim Luther
  9. **
  10. ** File: IterateDirectory.c
  11. **
  12. ** Copyright (c) 1995-1998 Jim Luther and Apple Computer, Inc.
  13. ** All rights reserved.
  14. **
  15. ** You may incorporate this sample code into your applications without
  16. ** restriction, though the sample code has been provided "AS IS" and the
  17. ** responsibility for its operation is 100% yours.
  18. **
  19. ** IterateDirectory is designed to drop into the MoreFiles sample code
  20. ** library I wrote while in Apple Developer Technical Support
  21. */
  22. /*****************************************************************************/
  23. /* Includes */
  24. /*****************************************************************************/
  25. #include <Types.h>
  26. #include <Errors.h>
  27. #include <Files.h>
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include "zip.h"
  31. #include "macstuff.h"
  32. #include "helpers.h"
  33. #include "recurse.h"
  34. #include "macglob.h"
  35. #include "pathname.h"
  36. /*****************************************************************************/
  37. /* Macros, typedefs */
  38. /*****************************************************************************/
  39. /* The RecurseGlobals structure is used to minimize the amount of
  40. ** stack space used when recursively calling RecurseDirectoryLevel
  41. ** and to hold global information that might be needed at any time.
  42. */
  43. struct RecurseGlobals
  44. {
  45. short vRefNum;
  46. CInfoPBRec cPB; /* the parameter block used for
  47. PBGetCatInfo calls */
  48. unsigned char *itemName; /* the name of the current item */
  49. char *FullPath;
  50. short FullPathLen;
  51. OSErr result; /* temporary holder of results -
  52. saves 2 bytes of stack each level */
  53. Boolean quitFlag; /* set to true if filter wants to
  54. kill interation */
  55. unsigned short maxLevels; /* Maximum levels to
  56. iterate through */
  57. unsigned short currentLevel; /* The current level
  58. IterateLevel is on */
  59. };
  60. typedef struct RecurseGlobals RecurseGlobals;
  61. typedef RecurseGlobals *RecurseGlobalsPtr;
  62. /*****************************************************************************/
  63. /* Global Vars */
  64. /*****************************************************************************/
  65. extern MacZipGlobals MacZip;
  66. extern const char ResourceMark[13]; /* "XtraStuf.mac:" var is initialized in file pathname.c */
  67. extern int extra_fields; /* do not create extra fields if false */
  68. static RecurseGlobals theGlobals;
  69. static unsigned long DirLevels = 0;
  70. static char *buffer;
  71. extern int verbose; /* 1=report oddities in zip file structure */
  72. /*****************************************************************************/
  73. /* Prototypes */
  74. /*****************************************************************************/
  75. int procname(char *filename, int caseflag);
  76. int MatchWild( char *pPat, char *pStr, int case_sens);
  77. Boolean IsZipFile(char *name);
  78. static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals);
  79. static Boolean isRegularItem( RecurseGlobals *Globals);
  80. static void ProcessFiles(RecurseGlobals *Globals,
  81. Boolean hasDataFork, Boolean hasResourceFork);
  82. static void ProcessDirectory(RecurseGlobals *Globals,
  83. Boolean IncludeItem, long DirID);
  84. static void ProcessItem(RecurseGlobals *Globals, long DirID);
  85. /*****************************************************************************/
  86. /* Functions */
  87. /*****************************************************************************/
  88. static void RecurseDirectoryLevel(long DirID, RecurseGlobals *Globals)
  89. {
  90. char buffer2[23];
  91. /* if maxLevels is zero, we aren't checking levels */
  92. if ( (Globals->maxLevels == 0) ||
  93. /* if currentLevel < maxLevels, look at this level */
  94. (Globals->currentLevel < Globals->maxLevels) )
  95. {
  96. short index = 1;
  97. ++Globals->currentLevel; /* go to next level */
  98. if (DirLevels < Globals->currentLevel) DirLevels = Globals->currentLevel;
  99. sprintf(buffer2,"Globals->currentLevel: %d",Globals->currentLevel);
  100. do
  101. { /* Isn't C great... What I'd give for a "WITH
  102. theGlobals DO" about now... */
  103. /* Get next source item at the current directory level */
  104. Globals->cPB.dirInfo.ioFDirIndex = index;
  105. Globals->cPB.dirInfo.ioDrDirID = DirID;
  106. Globals->result = PBGetCatInfoSync((CInfoPBPtr)&Globals->cPB);
  107. ShowCounter(false);
  108. if ( Globals->result == noErr )
  109. {
  110. ProcessItem(Globals, DirID);
  111. } /* if ( Globals->result == noErr ) */
  112. ++index; /* prepare to get next item */
  113. /* time to fall back a level? */
  114. } while ( (Globals->result == noErr) && (!Globals->quitFlag) );
  115. if ( (Globals->result == fnfErr) || /* fnfErr is OK -
  116. it only means we hit
  117. the end of this level */
  118. (Globals->result == afpAccessDenied) ) /* afpAccessDenied is OK,
  119. too - it only means we cannot see inside a directory */
  120. {
  121. Globals->result = noErr;
  122. }
  123. --Globals->currentLevel; /* return to previous level as we leave */
  124. }
  125. }
  126. /*****************************************************************************/
  127. pascal OSErr RecurseDirectory(short vRefNum,
  128. long thedirID,
  129. ConstStr255Param name,
  130. unsigned short maxLevels)
  131. {
  132. OSErr result;
  133. short theVRefNum;
  134. Boolean isDirectory;
  135. long DirID;
  136. /* Get the real directory ID and make sure it is a directory */
  137. result = GetDirectoryID(vRefNum, thedirID, name, &DirID, &isDirectory);
  138. if ( result == noErr )
  139. {
  140. if ( isDirectory == true )
  141. {
  142. /* Get the real vRefNum */
  143. result = DetermineVRefNum(name, vRefNum, &theVRefNum);
  144. if ( result == noErr )
  145. {
  146. /* Set up the globals we need to access from
  147. the recursive routine. */
  148. theGlobals.cPB.hFileInfo.ioNamePtr = theGlobals.itemName;
  149. theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
  150. theGlobals.itemName[0] = 0;
  151. theGlobals.result = noErr;
  152. theGlobals.quitFlag = false;
  153. theGlobals.maxLevels = maxLevels;
  154. theGlobals.currentLevel = 0; /* start at level 0 */
  155. /* Here we go into recursion land... */
  156. RecurseDirectoryLevel(DirID, &theGlobals);
  157. result = theGlobals.result; /* set the result */
  158. }
  159. }
  160. else
  161. {
  162. result = dirNFErr; /* a file was passed instead
  163. of a directory */
  164. }
  165. }
  166. return ( result );
  167. }
  168. /*****************************************************************************/
  169. pascal OSErr FSpRecurseDirectory(const FSSpec *spec,
  170. unsigned short maxLevels)
  171. {
  172. OSErr rc;
  173. theGlobals.vRefNum = spec->vRefNum;
  174. /* make room for pathnames */
  175. theGlobals.itemName = (unsigned char *) StrCalloc(NAME_MAX);
  176. theGlobals.FullPath = StrCalloc(NAME_MAX);
  177. buffer = StrCalloc(NAME_MAX);
  178. if ((noisy) && (MacZip.DataForkOnly))
  179. printf("\n Warning: Datafork only \n");
  180. /* reset the count to zero */
  181. ShowCounter(true);
  182. if (noisy) leftStatusString("Build File List; Items done:");
  183. if (noisy) printf("\n Collecting Filenames ...");
  184. rc = RecurseDirectory(spec->vRefNum, spec->parID, spec->name,maxLevels);
  185. printerr("RecurseDirectory:",rc,rc,__LINE__,__FILE__,"");
  186. if (noisy) printf("\n... done \n\n %6d matched files found \n",
  187. MacZip.FoundFiles);
  188. if (noisy) printf(" %6d folders found in %d Levels \n",
  189. MacZip.FoundDirectories,DirLevels);
  190. if (MacZip.BytesOfData > (1024*1024))
  191. if (noisy) printf(" %4.3f MBytes unzipped size\n\n",
  192. (float) MacZip.BytesOfData/(1024*1024));
  193. else
  194. if (noisy) printf(" %4.3f KBytes unzipped size\n\n",
  195. (float) MacZip.BytesOfData/1024);
  196. /* free all memory of pathnames */
  197. theGlobals.itemName = (unsigned char *) StrFree((char *)theGlobals.itemName);
  198. theGlobals.FullPath = StrFree(theGlobals.FullPath);
  199. buffer = StrFree(buffer);
  200. return rc;
  201. }
  202. /*
  203. * Return true if filename == zipfile
  204. * After the first match no further check will be done !
  205. *
  206. */
  207. Boolean IsZipFile(char *filen)
  208. {
  209. static firstMatch = false;
  210. if (filen == NULL)
  211. firstMatch = false;
  212. if (!firstMatch)
  213. {
  214. if (stricmp(filen, MacZip.ZipFullPath) == 0)
  215. {
  216. firstMatch = true;
  217. return true;
  218. }
  219. }
  220. return false;
  221. }
  222. static Boolean isRegularItem( RecurseGlobals *Globals)
  223. {
  224. Boolean isInvisible = false,
  225. isAlias = false,
  226. isSystem = false;
  227. isSystem = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
  228. (1 << 12)) == 0 );
  229. isInvisible = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
  230. (1 << 14)) == 0 );
  231. isAlias = !((Globals->cPB.hFileInfo.ioFlFndrInfo.fdFlags &
  232. (1 << 15)) == 0);
  233. if (isAlias == true)
  234. {
  235. return false;
  236. }
  237. if (MacZip.IncludeInvisible == true)
  238. {
  239. return true;
  240. }
  241. if ((isSystem == true) ||
  242. (isInvisible == true))
  243. {
  244. return false;
  245. }
  246. return true;
  247. }
  248. static void ProcessFiles(RecurseGlobals *Globals,
  249. Boolean hasDataFork, Boolean hasResourceFork)
  250. {
  251. /* some file statistics */
  252. MacZip.FoundFiles++;
  253. if (hasDataFork == true)
  254. {
  255. MacZip.BytesOfData =
  256. Globals->cPB.hFileInfo.ioFlLgLen +
  257. MacZip.BytesOfData;
  258. MacZip.CurrentFork = DataFork;
  259. MacZip.RawCountOfItems++;
  260. if (MacZip.DataForkOnly == true)
  261. {
  262. procname(Globals->FullPath, false);
  263. hasResourceFork = false;
  264. }
  265. else
  266. {
  267. procname(Real2RfDfFilen(buffer,Globals->FullPath,
  268. DataFork, MacZip.MacZipMode,
  269. MacZip.DataForkOnly), false);
  270. }
  271. }
  272. if (hasResourceFork == true)
  273. {
  274. MacZip.BytesOfData =
  275. Globals->cPB.hFileInfo.ioFlRLgLen +
  276. MacZip.BytesOfData;
  277. MacZip.CurrentFork = ResourceFork;
  278. MacZip.RawCountOfItems++;
  279. procname(Real2RfDfFilen(buffer, Globals->FullPath,
  280. ResourceFork, MacZip.MacZipMode,
  281. MacZip.DataForkOnly), false);
  282. }
  283. }
  284. static void ProcessDirectory(RecurseGlobals *Globals,
  285. Boolean IncludeItem, long DirID)
  286. {
  287. OSErr rc;
  288. MacZip.isDirectory = true;
  289. GetFullPathFromID(Globals->FullPath,Globals->vRefNum, DirID,
  290. Globals->itemName, &rc);
  291. MacZip.RawCountOfItems++;
  292. MacZip.FoundDirectories++;
  293. if (MacZip.StoreFoldersAlso)
  294. {
  295. procname(Globals->FullPath, false);
  296. }
  297. /* We have a directory */
  298. if ( !Globals->quitFlag && IncludeItem)
  299. {
  300. /* Dive again if the IterateFilterProc didn't say "quit" and dir is
  301. not an alias */
  302. RecurseDirectoryLevel(Globals->cPB.dirInfo.ioDrDirID,
  303. Globals);
  304. }
  305. }
  306. static void ProcessItem(RecurseGlobals *Globals, long DirID)
  307. {
  308. OSErr rc;
  309. Boolean IncludeItem = false, hasDataFork = false;
  310. Boolean hasResourceFork = false;
  311. IncludeItem = isRegularItem(Globals);
  312. /* Is it a File? */
  313. if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) == 0 )
  314. {
  315. PToCCpy(Globals->itemName,MacZip.FileName);
  316. MacZip.isDirectory = false;
  317. hasDataFork = (Globals->cPB.hFileInfo.ioFlLgLen != 0);
  318. hasResourceFork = (Globals->cPB.hFileInfo.ioFlRLgLen != 0);
  319. /* include also files with zero recource- and data-fork */
  320. if ((hasDataFork == 0) && (hasResourceFork == 0))
  321. hasDataFork = true;
  322. if ((hasDataFork == 0) &&
  323. (hasResourceFork != 0) &&
  324. (extra_fields == false))
  325. {
  326. IncludeItem = false;
  327. }
  328. GetFullPathFromID(Globals->FullPath,Globals->vRefNum,
  329. DirID, Globals->itemName, &rc);
  330. printerr("GetFullPathFromID:",rc,rc,__LINE__,
  331. __FILE__,MacZip.FileName);
  332. if (IncludeItem && /* don't include the zipfile itself */
  333. (!IsZipFile(Globals->FullPath)) )
  334. {
  335. if (MATCH(MacZip.Pattern, MacZip.FileName, false) == true)
  336. {
  337. ProcessFiles(Globals, hasDataFork, hasResourceFork);
  338. } /* if (MatchWild( MacZip.FileName,MacZip.Pattern ) ==
  339. true) */
  340. } /* if (!IsZipFile(Globals->FullPath)) */
  341. } /* Is it a File? */
  342. /* Is it a directory? */
  343. if ( (Globals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
  344. {
  345. ProcessDirectory(Globals,IncludeItem, DirID);
  346. } /* Is it a directory? */
  347. }