Line | Count | Source (jump to first uncovered line) |
1 | | #include "rar.hpp" |
2 | | |
3 | | ScanTree::ScanTree(StringList *FileMasks,RECURSE_MODE Recurse,bool GetLinks,SCAN_DIRS GetDirs) |
4 | 0 | { |
5 | 0 | ScanTree::FileMasks=FileMasks; |
6 | 0 | ScanTree::Recurse=Recurse; |
7 | 0 | ScanTree::GetLinks=GetLinks; |
8 | 0 | ScanTree::GetDirs=GetDirs; |
9 | |
|
10 | 0 | ScanEntireDisk=false; |
11 | 0 | FolderWildcards=false; |
12 | |
|
13 | 0 | FindStack.push_back(NULL); // We need a single NULL pointer for initial Depth==0. |
14 | | |
15 | 0 | SetAllMaskDepth=0; |
16 | 0 | Depth=0; |
17 | 0 | Errors=0; |
18 | 0 | Cmd=NULL; |
19 | 0 | ErrDirList=NULL; |
20 | 0 | ErrDirSpecPathLength=NULL; |
21 | 0 | } |
22 | | |
23 | | |
24 | | ScanTree::~ScanTree() |
25 | 0 | { |
26 | 0 | for (int I=Depth;I>=0;I--) |
27 | 0 | if (FindStack[I]!=NULL) |
28 | 0 | delete FindStack[I]; |
29 | 0 | } |
30 | | |
31 | | |
32 | | SCAN_CODE ScanTree::GetNext(FindData *FD) |
33 | 0 | { |
34 | 0 | if (Depth<0) |
35 | 0 | return SCAN_DONE; |
36 | | |
37 | | #ifndef SILENT |
38 | | uint LoopCount=0; |
39 | | #endif |
40 | | |
41 | 0 | SCAN_CODE FindCode; |
42 | 0 | while (1) |
43 | 0 | { |
44 | 0 | if (CurMask.empty() && !GetNextMask()) |
45 | 0 | return SCAN_DONE; |
46 | | |
47 | | #ifndef SILENT |
48 | | // Let's return some ticks to system or WinRAR can become irresponsible |
49 | | // while scanning files in command like "winrar a -r arc c:\file.ext". |
50 | | // Also we reset system sleep timer here. |
51 | | if ((++LoopCount & 0x3ff)==0) |
52 | | Wait(); |
53 | | #endif |
54 | | |
55 | 0 | FindCode=FindProc(FD); |
56 | 0 | if (FindCode==SCAN_ERROR) |
57 | 0 | { |
58 | 0 | Errors++; |
59 | 0 | continue; |
60 | 0 | } |
61 | 0 | if (FindCode==SCAN_NEXT) |
62 | 0 | continue; |
63 | 0 | if (FindCode==SCAN_SUCCESS && FD->IsDir && GetDirs==SCAN_SKIPDIRS) |
64 | 0 | continue; |
65 | 0 | if (FindCode==SCAN_DONE && GetNextMask()) |
66 | 0 | continue; |
67 | 0 | if (FilterList.ItemsCount()>0 && FindCode==SCAN_SUCCESS) |
68 | 0 | if (!CommandData::CheckArgs(&FilterList,FD->IsDir,FD->Name,false,MATCH_WILDSUBPATH)) |
69 | 0 | continue; |
70 | 0 | break; |
71 | 0 | } |
72 | 0 | return FindCode; |
73 | 0 | } |
74 | | |
75 | | |
76 | | // For masks like dir1\dir2*\*.ext in non-recursive mode. |
77 | | bool ScanTree::ExpandFolderMask() |
78 | 0 | { |
79 | 0 | bool WildcardFound=false; |
80 | 0 | uint SlashPos=0; |
81 | 0 | for (uint I=0;I<CurMask.size();I++) |
82 | 0 | { |
83 | 0 | if (CurMask[I]=='?' || CurMask[I]=='*') |
84 | 0 | WildcardFound=true; |
85 | 0 | if (WildcardFound && IsPathDiv(CurMask[I])) |
86 | 0 | { |
87 | | // First path separator position after folder wildcard mask. |
88 | | // In case of dir1\dir2*\dir3\name.ext mask it may point not to file |
89 | | // name, so we cannot use PointToName() here. |
90 | 0 | SlashPos=I; |
91 | 0 | break; |
92 | 0 | } |
93 | 0 | } |
94 | |
|
95 | 0 | std::wstring Mask=CurMask.substr(0,SlashPos); |
96 | | |
97 | | // Prepare the list of all folders matching the wildcard mask. |
98 | 0 | ExpandedFolderList.Reset(); |
99 | 0 | FindFile Find; |
100 | 0 | Find.SetMask(Mask); |
101 | 0 | FindData FD; |
102 | 0 | while (Find.Next(&FD)) |
103 | 0 | if (FD.IsDir) |
104 | 0 | { |
105 | 0 | FD.Name+=CurMask.substr(SlashPos); |
106 | | |
107 | | // Treat dir*\*, dir*\*.* or dir*\ as dir, so empty 'dir' is also matched |
108 | | // by such mask. Skipping empty dir with dir*\*.* confused some users. |
109 | 0 | std::wstring LastMask=PointToName(FD.Name); |
110 | 0 | if (LastMask==L"*" || LastMask==L"*.*" || LastMask.empty()) |
111 | 0 | RemoveNameFromPath(FD.Name); |
112 | |
|
113 | 0 | ExpandedFolderList.AddString(FD.Name); |
114 | 0 | } |
115 | 0 | if (ExpandedFolderList.ItemsCount()==0) |
116 | 0 | return false; |
117 | | // Return the first matching folder name now. |
118 | 0 | ExpandedFolderList.GetString(CurMask); |
119 | 0 | return true; |
120 | 0 | } |
121 | | |
122 | | |
123 | | // For masks like dir1\dir2*\file.ext this function sets 'dir1' recursive mask |
124 | | // and '*\dir2*\file.ext' filter. Masks without folder wildcards are |
125 | | // returned as is. |
126 | | bool ScanTree::GetFilteredMask() |
127 | 0 | { |
128 | | // If we have some matching folders left for non-recursive folder wildcard |
129 | | // mask, we return it here. |
130 | 0 | if (ExpandedFolderList.ItemsCount()>0 && ExpandedFolderList.GetString(CurMask)) |
131 | 0 | return true; |
132 | | |
133 | 0 | FolderWildcards=false; |
134 | 0 | FilterList.Reset(); |
135 | 0 | if (!FileMasks->GetString(CurMask)) |
136 | 0 | return false; |
137 | | |
138 | | // Check if folder wildcards present. |
139 | 0 | bool WildcardFound=false; |
140 | 0 | uint FolderWildcardCount=0; |
141 | 0 | uint SlashPos=0; |
142 | 0 | uint StartPos=0; |
143 | | #ifdef _WIN_ALL // Not treat the special NTFS \\?\d: path prefix as a wildcard. |
144 | | if (CurMask.rfind(L"\\\\?\\",0)==0) |
145 | | StartPos=4; |
146 | | #endif |
147 | 0 | for (uint I=StartPos;I<CurMask.size();I++) |
148 | 0 | { |
149 | 0 | if (CurMask[I]=='?' || CurMask[I]=='*') |
150 | 0 | WildcardFound=true; |
151 | 0 | if (IsPathDiv(CurMask[I]) || IsDriveDiv(CurMask[I])) |
152 | 0 | { |
153 | 0 | if (WildcardFound) |
154 | 0 | { |
155 | | // Calculate a number of folder wildcards in current mask. |
156 | 0 | FolderWildcardCount++; |
157 | 0 | WildcardFound=false; |
158 | 0 | } |
159 | 0 | if (FolderWildcardCount==0) |
160 | 0 | SlashPos=I; // Slash position before first folder wildcard mask. |
161 | 0 | } |
162 | 0 | } |
163 | 0 | if (FolderWildcardCount==0) |
164 | 0 | return true; |
165 | 0 | FolderWildcards=true; // Global folder wildcards flag. |
166 | | |
167 | | // If we have only one folder wildcard component and -r is missing or -r- |
168 | | // is specified, prepare matching folders in non-recursive mode. |
169 | | // We assume -r for masks like dir1*\dir2*\file*, because it is complicated |
170 | | // to fast find them using OS file find API call. |
171 | 0 | if ((Recurse==RECURSE_NONE || Recurse==RECURSE_DISABLE) && FolderWildcardCount==1) |
172 | 0 | return ExpandFolderMask(); |
173 | | |
174 | | // Convert path\dir*\ to *\dir filter to search for 'dir' in all 'path' subfolders. |
175 | 0 | std::wstring Filter=L"*"; |
176 | 0 | AddEndSlash(Filter); // Path separator is OS dependent, so we set it here instead of variable declaration. |
177 | | |
178 | | // SlashPos might point or not point to path separator for masks like 'dir*', '\dir*' or 'd:dir*' |
179 | 0 | std::wstring WildName=IsPathDiv(CurMask[SlashPos]) || IsDriveDiv(CurMask[SlashPos]) ? CurMask.substr(SlashPos+1) : CurMask.substr(SlashPos); |
180 | 0 | Filter+=WildName; |
181 | | |
182 | | // Treat dir*\* or dir*\*.* as dir\, so empty 'dir' is also matched |
183 | | // by such mask. Skipping empty dir with dir*\*.* confused some users. |
184 | 0 | std::wstring LastMask=PointToName(Filter); |
185 | 0 | if (LastMask==L"*" || LastMask==L"*.*") |
186 | 0 | GetPathWithSep(Filter,Filter); |
187 | |
|
188 | 0 | FilterList.AddString(Filter); |
189 | |
|
190 | 0 | bool RelativeDrive=IsDriveDiv(CurMask[SlashPos]); |
191 | 0 | if (RelativeDrive) |
192 | 0 | SlashPos++; // Use "d:" instead of "d" for d:* mask. |
193 | |
|
194 | 0 | CurMask.erase(SlashPos); |
195 | |
|
196 | 0 | if (!RelativeDrive) // Keep d: mask as is, not convert to d:\* |
197 | 0 | { |
198 | | // We need to append "\*" both for -ep1 to work correctly and to |
199 | | // convert d:\* masks previously truncated to d: back to original form. |
200 | 0 | AddEndSlash(CurMask); |
201 | 0 | CurMask+=MASKALL; |
202 | 0 | } |
203 | 0 | return true; |
204 | 0 | } |
205 | | |
206 | | |
207 | | bool ScanTree::GetNextMask() |
208 | 0 | { |
209 | 0 | if (!GetFilteredMask()) |
210 | 0 | return false; |
211 | | #ifdef _WIN_ALL |
212 | | UnixSlashToDos(CurMask,CurMask); |
213 | | #endif |
214 | | |
215 | | // We shall set it before appending the path separator to \\server\share |
216 | | // UNC mask below, so "rar a -ep1 arc \\server\share" includes paths |
217 | | // starting from "share\". |
218 | 0 | SpecPathLength=GetNamePos(CurMask); |
219 | | |
220 | | // We prefer to scan entire disk if mask like \\server\share\ or c:\ |
221 | | // is specified even without -r, but not with -r-. Use \\server\share\*.*, |
222 | | // c:\*.* mask or -r- to scan only the root directory. Note that UNC names |
223 | | // are possible both in Win32 and Unix, just with proper path separators. |
224 | 0 | if (Recurse!=RECURSE_DISABLE) |
225 | 0 | if (CurMask.size()>2 && CurMask[0]==CPATHDIVIDER && CurMask[1]==CPATHDIVIDER) |
226 | 0 | { |
227 | 0 | auto Slash=CurMask.find(CPATHDIVIDER,2); |
228 | 0 | if (Slash!=std::wstring::npos) |
229 | 0 | { |
230 | 0 | Slash=CurMask.find(CPATHDIVIDER,Slash+1); |
231 | | // If path separator is mssing or it is the last string character. |
232 | 0 | ScanEntireDisk=Slash==std::wstring::npos || |
233 | 0 | Slash!=std::wstring::npos && Slash+1==CurMask.size(); |
234 | | |
235 | | // Win32 FindFirstFile fails for \\server\share names without |
236 | | // the trailing backslash. So we add it here. |
237 | 0 | if (Slash==std::wstring::npos) |
238 | 0 | CurMask+=CPATHDIVIDER; |
239 | 0 | } |
240 | 0 | } |
241 | 0 | else |
242 | 0 | ScanEntireDisk=IsDriveLetter(CurMask) && IsPathDiv(CurMask[2]) && CurMask[3]==0; |
243 | | |
244 | | // Calculate the name position again, because we could modify UNC path above. |
245 | 0 | auto NamePos=GetNamePos(CurMask); |
246 | 0 | std::wstring Name=CurMask.substr(NamePos); |
247 | 0 | if (Name.empty()) |
248 | 0 | CurMask+=MASKALL; |
249 | 0 | if (Name==L"." || Name==L"..") |
250 | 0 | { |
251 | 0 | AddEndSlash(CurMask); |
252 | 0 | CurMask+=MASKALL; |
253 | 0 | } |
254 | 0 | Depth=0; |
255 | |
|
256 | 0 | OrigCurMask=CurMask; |
257 | |
|
258 | 0 | return true; |
259 | 0 | } |
260 | | |
261 | | |
262 | | SCAN_CODE ScanTree::FindProc(FindData *FD) |
263 | 0 | { |
264 | 0 | if (CurMask.empty()) |
265 | 0 | return SCAN_NEXT; |
266 | 0 | bool FastFindFile=false; |
267 | | |
268 | 0 | if (FindStack[Depth]==NULL) // No FindFile object for this depth yet. |
269 | 0 | { |
270 | 0 | bool Wildcards=IsWildcard(CurMask); |
271 | | |
272 | | // If we have a file name without wildcards, we can try to use |
273 | | // FastFind to optimize speed. For example, in Unix it results in |
274 | | // stat call instead of opendir/readdir/closedir. |
275 | 0 | bool FindCode=!Wildcards && FindFile::FastFind(CurMask,FD,GetLinks); |
276 | | |
277 | | // Link check is important for NTFS, where links can have "Directory" |
278 | | // attribute, but we do not want to recurse to them in "get links" mode. |
279 | 0 | bool IsDir=FindCode && FD->IsDir && (!GetLinks || !FD->IsLink); |
280 | | |
281 | | // SearchAll means that we'll use "*" mask for search, so we'll find |
282 | | // subdirectories and will be able to recurse into them. |
283 | | // We do not use "*" for directories at any level or for files |
284 | | // at top level in recursion mode. We always comrpess the entire directory |
285 | | // if folder wildcard is specified. |
286 | 0 | bool SearchAll=!IsDir && (Depth>0 || Recurse==RECURSE_ALWAYS || |
287 | 0 | FolderWildcards && Recurse!=RECURSE_DISABLE || |
288 | 0 | Wildcards && Recurse==RECURSE_WILDCARDS || |
289 | 0 | ScanEntireDisk && Recurse!=RECURSE_DISABLE); |
290 | 0 | if (Depth==0) |
291 | 0 | SearchAllInRoot=SearchAll; |
292 | 0 | if (SearchAll || Wildcards) |
293 | 0 | { |
294 | | // Create the new FindFile object for wildcard based search. |
295 | 0 | FindStack[Depth]=new FindFile; |
296 | |
|
297 | 0 | std::wstring SearchMask=CurMask; |
298 | 0 | if (SearchAll) |
299 | 0 | SetName(SearchMask,MASKALL); |
300 | 0 | FindStack[Depth]->SetMask(SearchMask); |
301 | 0 | } |
302 | 0 | else |
303 | 0 | { |
304 | | // Either we failed to fast find or we found a file or we found |
305 | | // a directory in RECURSE_DISABLE mode, so we do not need to scan it. |
306 | | // We can return here and do not need to process further. |
307 | | // We need to process further only if we fast found a directory. |
308 | 0 | if (!FindCode || !IsDir || Recurse==RECURSE_DISABLE) |
309 | 0 | { |
310 | | // Return SCAN_SUCCESS if we found a file. |
311 | 0 | SCAN_CODE RetCode=SCAN_SUCCESS; |
312 | |
|
313 | 0 | if (!FindCode) |
314 | 0 | { |
315 | | // Return SCAN_ERROR if problem is more serious than just |
316 | | // "file not found". |
317 | 0 | RetCode=FD->Error ? SCAN_ERROR:SCAN_NEXT; |
318 | | |
319 | | // If we failed to find an object, but our current mask is excluded, |
320 | | // we skip this object and avoid indicating an error. |
321 | 0 | if (Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true)) |
322 | 0 | RetCode=SCAN_NEXT; |
323 | 0 | else |
324 | 0 | { |
325 | 0 | ErrHandler.OpenErrorMsg(ErrArcName,CurMask); |
326 | | // User asked to return RARX_NOFILES and not RARX_OPEN here. |
327 | 0 | ErrHandler.SetErrorCode(RARX_NOFILES); |
328 | 0 | } |
329 | 0 | } |
330 | | |
331 | | // If we searched only for one file or directory in "fast find" |
332 | | // (without a wildcard) mode, let's set masks to zero, |
333 | | // so calling function will know that current mask is used |
334 | | // and next one must be read from mask list for next call. |
335 | | // It is not necessary for directories, because even in "fast find" |
336 | | // mode, directory recursing will quit by (Depth < 0) condition, |
337 | | // which returns SCAN_DONE to calling function. |
338 | 0 | CurMask.clear(); |
339 | |
|
340 | 0 | return RetCode; |
341 | 0 | } |
342 | | |
343 | | // We found a directory using only FindFile::FastFind function. |
344 | 0 | FastFindFile=true; |
345 | 0 | } |
346 | 0 | } |
347 | | |
348 | 0 | if (!FastFindFile && !FindStack[Depth]->Next(FD,GetLinks)) |
349 | 0 | { |
350 | | // We cannot find anything more in directory either because of |
351 | | // some error or just as result of all directory entries already read. |
352 | |
|
353 | 0 | bool Error=FD->Error; |
354 | 0 | if (Error) |
355 | 0 | ScanError(Error); |
356 | | |
357 | | // Going to at least one directory level higher. |
358 | 0 | delete FindStack[Depth]; |
359 | 0 | FindStack[Depth--]=NULL; |
360 | 0 | while (Depth>=0 && FindStack[Depth]==NULL) |
361 | 0 | Depth--; |
362 | 0 | if (Depth < 0) |
363 | 0 | { |
364 | | // Directories scanned both in normal and FastFindFile mode, |
365 | | // finally exit from scan here, by (Depth < 0) condition. |
366 | |
|
367 | 0 | if (Error) |
368 | 0 | Errors++; |
369 | 0 | return SCAN_DONE; |
370 | 0 | } |
371 | | |
372 | 0 | auto Slash=CurMask.rfind(CPATHDIVIDER); |
373 | 0 | if (Slash!=std::wstring::npos) |
374 | 0 | { |
375 | 0 | std::wstring Mask; |
376 | 0 | Mask=CurMask.substr(Slash); // Name mask with leading slash like \*.* |
377 | 0 | if (Depth<SetAllMaskDepth) |
378 | 0 | Mask.replace(1, std::wstring::npos, PointToName(OrigCurMask)); |
379 | 0 | CurMask.erase(Slash); |
380 | |
|
381 | 0 | std::wstring DirName=CurMask; |
382 | |
|
383 | 0 | auto PrevSlash=CurMask.rfind(CPATHDIVIDER); |
384 | 0 | if (PrevSlash==std::wstring::npos) |
385 | 0 | CurMask=Mask.substr(1); // Set to name only without leading slash. |
386 | 0 | else |
387 | 0 | { |
388 | 0 | CurMask.erase(PrevSlash); // Remove one of two sequential slashes. |
389 | 0 | CurMask+=Mask; |
390 | 0 | } |
391 | |
|
392 | 0 | if (GetDirs==SCAN_GETDIRSTWICE && |
393 | 0 | FindFile::FastFind(DirName,FD,GetLinks) && FD->IsDir) |
394 | 0 | { |
395 | 0 | FD->Flags|=FDDF_SECONDDIR; |
396 | 0 | return Error ? SCAN_ERROR:SCAN_SUCCESS; |
397 | 0 | } |
398 | 0 | } |
399 | 0 | return Error ? SCAN_ERROR:SCAN_NEXT; |
400 | 0 | } |
401 | | |
402 | | // Link check is required for NTFS links, not for Unix. |
403 | 0 | if (FD->IsDir && (!GetLinks || !FD->IsLink)) |
404 | 0 | { |
405 | | // If we found the directory in top (Depth==0) directory |
406 | | // and if we are not in "fast find" (directory name only as argument) |
407 | | // or in recurse (SearchAll was set when opening the top directory) mode, |
408 | | // we do not recurse into this directory. We either return it by itself |
409 | | // or skip it. |
410 | 0 | if (!FastFindFile && Depth==0 && !SearchAllInRoot) |
411 | 0 | return GetDirs==SCAN_GETCURDIRS ? SCAN_SUCCESS:SCAN_NEXT; |
412 | | |
413 | | // Let's check if directory name is excluded, so we do not waste |
414 | | // time searching in directory, which will be excluded anyway. |
415 | 0 | if (Cmd!=NULL && (Cmd->ExclCheck(FD->Name,true,false,false) || |
416 | 0 | Cmd->ExclDirByAttr(FD->FileAttr))) |
417 | 0 | { |
418 | | // If we are here in "fast find" mode, it means that entire directory |
419 | | // specified in command line is excluded. Then we need to return |
420 | | // SCAN_DONE to go to next mask and avoid the infinite loop |
421 | | // in GetNext() function. Such loop would be possible in case of |
422 | | // SCAN_NEXT code and "rar a arc dir -xdir" command. |
423 | |
|
424 | 0 | return FastFindFile ? SCAN_DONE:SCAN_NEXT; |
425 | 0 | } |
426 | | |
427 | 0 | std::wstring Mask=FastFindFile ? MASKALL:PointToName(CurMask); |
428 | 0 | CurMask=FD->Name; |
429 | |
|
430 | 0 | if (CurMask.size()+Mask.size()+1>=MAXPATHSIZE || Depth>=MAXSCANDEPTH-1) |
431 | 0 | { |
432 | 0 | uiMsg(UIERROR_PATHTOOLONG,CurMask,SPATHDIVIDER,Mask); |
433 | 0 | return SCAN_ERROR; |
434 | 0 | } |
435 | | |
436 | 0 | AddEndSlash(CurMask); |
437 | 0 | CurMask+=Mask; |
438 | |
|
439 | 0 | Depth++; |
440 | |
|
441 | 0 | FindStack.resize(Depth+1); |
442 | | |
443 | | // We need to use OrigCurMask for depths less than SetAllMaskDepth |
444 | | // and "*" for depths equal or larger than SetAllMaskDepth. |
445 | | // It is important when "fast finding" directories at Depth > 0. |
446 | | // For example, if current directory is RootFolder and we compress |
447 | | // the following directories structure: |
448 | | // RootFolder |
449 | | // +--Folder1 |
450 | | // | +--Folder2 |
451 | | // | +--Folder3 |
452 | | // +--Folder4 |
453 | | // with 'rar a -r arcname Folder2' command, rar could add not only |
454 | | // Folder1\Folder2 contents, but also Folder1\Folder3 if we were using |
455 | | // "*" mask at all levels. We need to use "*" mask inside of Folder2, |
456 | | // but return to "Folder2" mask when completing scanning Folder2. |
457 | | // We can rewrite SearchAll expression above to avoid fast finding |
458 | | // directories at Depth > 0, but then 'rar a -r arcname Folder2' |
459 | | // will add the empty Folder2 and do not add its contents. |
460 | |
|
461 | 0 | if (FastFindFile) |
462 | 0 | SetAllMaskDepth=Depth; |
463 | 0 | } |
464 | 0 | if (!FastFindFile && !CmpName(CurMask,FD->Name,MATCH_NAMES)) |
465 | 0 | return SCAN_NEXT; |
466 | | |
467 | 0 | return SCAN_SUCCESS; |
468 | 0 | } |
469 | | |
470 | | |
471 | | void ScanTree::ScanError(bool &Error) |
472 | 0 | { |
473 | | #ifdef _WIN_ALL |
474 | | if (Error) |
475 | | { |
476 | | // Get attributes of parent folder and do not display an error |
477 | | // if it is reparse point. We cannot scan contents of standard |
478 | | // Windows reparse points like "C:\Documents and Settings" |
479 | | // and we do not want to issue numerous useless errors for them. |
480 | | // We cannot just check FD->FileAttr here, it can be undefined |
481 | | // if we process "folder\*" mask or if we process "folder" mask, |
482 | | // but "folder" is inaccessible. |
483 | | auto Slash=GetNamePos(CurMask); |
484 | | if (Slash>1) |
485 | | { |
486 | | std::wstring Parent=CurMask.substr(0,Slash-1); |
487 | | DWORD Attr=GetFileAttr(Parent); |
488 | | if (Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) |
489 | | Error=false; |
490 | | } |
491 | | |
492 | | // Do not display an error if we cannot scan contents of |
493 | | // "System Volume Information" folder. Normally it is not accessible. |
494 | | if (CurMask.find(L"System Volume Information\\")!=std::wstring::npos) |
495 | | Error=false; |
496 | | } |
497 | | #endif |
498 | |
|
499 | 0 | if (Error && Cmd!=NULL && Cmd->ExclCheck(CurMask,false,true,true)) |
500 | 0 | Error=false; |
501 | |
|
502 | 0 | if (Error) |
503 | 0 | { |
504 | 0 | if (ErrDirList!=NULL) |
505 | 0 | ErrDirList->AddString(CurMask); |
506 | 0 | if (ErrDirSpecPathLength!=NULL) |
507 | 0 | ErrDirSpecPathLength->push_back((uint)SpecPathLength); |
508 | 0 | std::wstring FullName; |
509 | | // This conversion works for wildcard masks too. |
510 | 0 | ConvertNameToFull(CurMask,FullName); |
511 | 0 | uiMsg(UIERROR_DIRSCAN,FullName); |
512 | 0 | ErrHandler.SysErrMsg(); |
513 | 0 | } |
514 | 0 | } |