3
ScanTree::ScanTree(StringList *FileMasks,int Recurse,bool GetLinks,int GetDirs)
3
ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs)
5
5
ScanTree::FileMasks=FileMasks;
6
6
ScanTree::Recurse=Recurse;
32
int ScanTree::GetNext(FindData *FindData)
31
SCAN_CODE ScanTree::GetNext(FindData *FindData)
40
if ((*CurMask==0 || FastFindFile && Depth==0) && !PrepareMasks())
39
if (*CurMask==0 && !GetNextMask())
42
42
FindCode=FindProc(FindData);
43
43
if (FindCode==SCAN_ERROR)
60
bool ScanTree::PrepareMasks()
60
bool ScanTree::GetNextMask()
63
62
if (!FileMasks->GetString(CurMask,CurMaskW,sizeof(CurMask)))
65
64
CurMask[ASIZE(CurMask)-1]=0;
117
int ScanTree::FindProc(FindData *FindData)
114
SCAN_CODE ScanTree::FindProc(FindData *FindData)
120
117
return(SCAN_NEXT);
122
if (FindStack[Depth]==NULL)
118
bool FastFindFile=false;
120
if (FindStack[Depth]==NULL) // No FindFile object for this depth yet.
124
122
bool Wildcards=IsWildcard(CurMask,CurMaskW);
124
// If we have a file name without wildcards, we can try to use
125
// FastFind to optimize speed. For example, in Unix it results in
126
// stat call instead of opendir/readdir/closedir.
125
127
bool FindCode=!Wildcards && FindFile::FastFind(CurMask,CurMaskW,FindData,GetLinks);
126
129
bool IsDir=FindCode && FindData->IsDir;
131
// SearchAll means that we'll use "*" mask for search, so we'll find
132
// subdirectories and will be able to recurse into them.
133
// We do not use "*" for directories at any level or for files
134
// at top level in recursion mode.
127
135
bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS ||
128
Wildcards && Recurse==RECURSE_WILDCARDS || ScanEntireDisk);
136
Wildcards && Recurse==RECURSE_WILDCARDS ||
137
ScanEntireDisk && Recurse!=RECURSE_DISABLE);
130
139
SearchAllInRoot=SearchAll;
131
140
if (SearchAll || Wildcards)
142
// Create the new FindFile object for wildcard based search.
133
143
FindStack[Depth]=new FindFile;
134
144
char SearchMask[NM];
135
145
strcpy(SearchMask,CurMask);
160
// Either we failed to fast find or we found a file or we found
161
// a directory in RECURSE_DISABLE mode, so we do not need to scan it.
162
// We can return here and do not need to process further.
163
// We need to process further only if we fast found a directory.
164
if (!FindCode || !FindData->IsDir || Recurse==RECURSE_DISABLE)
166
// Return SCAN_SUCCESS if we found a file.
167
SCAN_CODE RetCode=SCAN_SUCCESS;
171
// Return SCAN_ERROR if problem is more serious than just
173
RetCode=FindData->Error ? SCAN_ERROR:SCAN_NEXT;
175
// If we failed to find an object, but our current mask is excluded,
176
// we skip this object and avoid indicating an error.
177
if (Cmd!=NULL && Cmd->ExclCheck(CurMask,true))
180
ErrHandler.OpenErrorMsg(ErrArcName,CurMask);
183
// If we searched only for one file or directory in "fast find"
184
// (without a wildcard) mode, let's set masks to zero,
185
// so calling function will know that current mask is used
186
// and next one must be read from mask list for next call.
187
// It is not necessary for directories, because even in "fast find"
188
// mode, directory recursing will quit by (Depth < 0) condition,
189
// which returns SCAN_DONE to calling function.
196
// We found a directory using only FindFile::FastFind function.
150
197
FastFindFile=true;
153
if (Cmd!=NULL && Cmd->ExclCheck(CurMask,true))
155
ErrHandler.OpenErrorMsg(ErrArcName,CurMask);
156
return(FindData->Error ? SCAN_ERROR:SCAN_NEXT);
161
201
if (!FastFindFile && !FindStack[Depth]->Next(FindData,GetLinks))
203
// We cannot find anything more in directory either because of
204
// some error or just as result of all directory entries already read.
163
206
bool Error=FindData->Error;
239
// Going to at least one directory level higher.
196
240
delete FindStack[Depth];
197
241
FindStack[Depth--]=NULL;
198
242
while (Depth>=0 && FindStack[Depth]==NULL)
246
// Directories scanned both in normal and FastFindFile mode,
247
// finally exit from scan here, by (Depth < 0) condition.
204
251
return(SCAN_DONE);
253
300
if (FindData->IsDir)
302
// If we found the directory in top (Depth==0) directory
303
// and if we are not in "fast find" (directory name only as argument)
304
// or in recurse (SearchAll was set when opening the top directory) mode,
305
// we do not recurse into this directory. We either return it by itself
255
307
if (!FastFindFile && Depth==0 && !SearchAllInRoot)
256
308
return(GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT);
258
// if (GetDirs==SCAN_GETCURDIRS && Depth==0 && !SearchAllInRoot)
259
// return(SCAN_SUCCESS);
310
// Let's check if directory name is excluded, so we do not waste
311
// time searching in directory, which will be excluded anyway.
312
if (Cmd!=NULL && Cmd->ExclCheck(FindData->Name,false))
314
// If we are here in "fast find" mode, it means that entire directory
315
// specified in command line is excluded. Then we need to return
316
// SCAN_DONE to go to next mask and avoid the infinite loop
317
// in GetNext() function. Such loop would be possible in case of
318
// SCAN_NEXT code and "rar a arc dir -xdir" command.
320
return(FastFindFile ? SCAN_DONE:SCAN_NEXT);
262
bool MaskAll=FastFindFile;
264
// bool MaskAll=CmpName(CurMask,FindData->Name,MATCH_NAMES);
266
strcpy(Mask,MaskAll ? MASKALL:PointToName(CurMask));
325
strcpy(Mask,FastFindFile ? MASKALL:PointToName(CurMask));
267
326
strcpy(CurMask,FindData->Name);
269
328
if (strlen(CurMask)+strlen(Mask)+1>=NM || Depth>=MAXSCANDEPTH-1)
295
354
strcatw(CurMaskW,Mask);
358
// We need to use OrigCurMask for depths less than SetAllMaskDepth
359
// and "*" for depths equal or larger than SetAllMaskDepth.
360
// It is important when "fast finding" directories at Depth > 0.
361
// For example, if current directory is RootFolder and we compress
362
// the following directories structure:
368
// with 'rar a -r arcname Folder2' command, rar could add not only
369
// Folder1\Folder2 contents, but also Folder1\Folder3 if we were using
370
// "*" mask at all levels. We need to use "*" mask inside of Folder2,
371
// but return to "Folder2" mask when completing scanning Folder2.
372
// We can rewrite SearchAll expression above to avoid fast finding
373
// directories at Depth > 0, but then 'rar a -r arcname Folder2'
374
// will add the empty Folder2 and do not add its contents.
299
377
SetAllMaskDepth=Depth;
301
379
if (!FastFindFile && !CmpName(CurMask,FindData->Name,MATCH_NAMES))
302
380
return(SCAN_NEXT);
303
382
return(SCAN_SUCCESS);