Upload 2.0.2
[physicsfs] / lzma / CPP / 7zip / UI / Common / EnumDirItems.cpp
1 // EnumDirItems.cpp
2
3 #include "StdAfx.h"
4
5 #include "Common/StringConvert.h"
6 #include "Common/Wildcard.h"
7 #include "Common/MyCom.h"
8
9 #include "EnumDirItems.h"
10
11 using namespace NWindows;
12 using namespace NFile;
13 using namespace NName;
14
15 void AddDirFileInfo(
16     const UString &prefix,        // prefix for logical path
17     const UString &fullPathName,  // path on disk: can be relative to some basePrefix
18     const NFind::CFileInfoW &fileInfo, 
19     CObjectVector<CDirItem> &dirItems)
20 {
21   CDirItem item;
22   item.Attributes = fileInfo.Attributes;
23   item.Size = fileInfo.Size;
24   item.CreationTime = fileInfo.CreationTime;
25   item.LastAccessTime = fileInfo.LastAccessTime;
26   item.LastWriteTime = fileInfo.LastWriteTime;
27   item.Name = prefix + fileInfo.Name;
28   item.FullPath = fullPathName;
29   dirItems.Add(item);
30 }
31
32 static void EnumerateDirectory(
33     const UString &baseFolderPrefix,  // base (disk) prefix for scanning  
34     const UString &directory,         // additional disk prefix starting from baseFolderPrefix
35     const UString &prefix,            // logical prefix
36     CObjectVector<CDirItem> &dirItems,
37     UStringVector &errorPaths,
38     CRecordVector<DWORD> &errorCodes)
39 {
40   NFind::CEnumeratorW enumerator(baseFolderPrefix + directory + wchar_t(kAnyStringWildcard));
41   for (;;)
42   { 
43     NFind::CFileInfoW fileInfo;
44     bool found;
45     if (!enumerator.Next(fileInfo, found))
46     {
47       errorCodes.Add(::GetLastError());
48       errorPaths.Add(baseFolderPrefix + directory);
49       return;
50     }
51     if (!found)
52       break;
53     AddDirFileInfo(prefix, directory + fileInfo.Name, fileInfo, dirItems);
54     if (fileInfo.IsDirectory())
55     {
56       EnumerateDirectory(baseFolderPrefix, directory + fileInfo.Name + wchar_t(kDirDelimiter), 
57           prefix + fileInfo.Name + wchar_t(kDirDelimiter), dirItems, errorPaths, errorCodes);
58     }
59   }
60 }
61
62 void EnumerateDirItems(
63     const UString &baseFolderPrefix,   // base (disk) prefix for scanning  
64     const UStringVector &fileNames,    // names relative to baseFolderPrefix
65     const UString &archiveNamePrefix, 
66     CObjectVector<CDirItem> &dirItems,
67     UStringVector &errorPaths,
68     CRecordVector<DWORD> &errorCodes)
69 {
70   for(int i = 0; i < fileNames.Size(); i++)
71   {
72     const UString &fileName = fileNames[i];
73     NFind::CFileInfoW fileInfo;
74     if (!NFind::FindFile(baseFolderPrefix + fileName, fileInfo))
75     {
76       errorCodes.Add(::GetLastError());
77       errorPaths.Add(baseFolderPrefix + fileName);
78       continue;
79     }
80     AddDirFileInfo(archiveNamePrefix, fileName, fileInfo, dirItems);
81     if (fileInfo.IsDirectory())
82     {
83       EnumerateDirectory(baseFolderPrefix, fileName + wchar_t(kDirDelimiter), 
84           archiveNamePrefix + fileInfo.Name +  wchar_t(kDirDelimiter), 
85           dirItems, errorPaths, errorCodes);
86     }
87   }
88 }
89
90 static HRESULT EnumerateDirItems(
91     const NWildcard::CCensorNode &curNode, 
92     const UString &diskPrefix,        // full disk path prefix 
93     const UString &archivePrefix,     // prefix from root
94     const UStringVector &addArchivePrefix,  // prefix from curNode
95     CObjectVector<CDirItem> &dirItems, 
96     bool enterToSubFolders,
97     IEnumDirItemCallback *callback,
98     UStringVector &errorPaths,
99     CRecordVector<DWORD> &errorCodes)
100 {
101   if (!enterToSubFolders)
102     if (curNode.NeedCheckSubDirs())
103       enterToSubFolders = true;
104   if (callback)
105     RINOK(callback->CheckBreak());
106
107   // try direct_names case at first
108   if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
109   {
110     // check that all names are direct
111     int i;
112     for (i = 0; i < curNode.IncludeItems.Size(); i++)
113     {
114       const NWildcard::CItem &item = curNode.IncludeItems[i];
115       if (item.Recursive || item.PathParts.Size() != 1)
116         break;
117       const UString &name = item.PathParts.Front();
118       if (name.IsEmpty() || DoesNameContainWildCard(name))
119         break;
120     }
121     if (i == curNode.IncludeItems.Size())
122     {
123       // all names are direct (no wildcards)
124       // so we don't need file_system's dir enumerator
125       CRecordVector<bool> needEnterVector;
126       for (i = 0; i < curNode.IncludeItems.Size(); i++)
127       {
128         const NWildcard::CItem &item = curNode.IncludeItems[i];
129         const UString &name = item.PathParts.Front();
130         const UString fullPath = diskPrefix + name;
131         NFind::CFileInfoW fileInfo;
132         if (!NFind::FindFile(fullPath, fileInfo))
133         {
134           errorCodes.Add(::GetLastError());
135           errorPaths.Add(fullPath);
136           continue;
137         }
138         bool isDir = fileInfo.IsDirectory();
139         if (isDir && !item.ForDir || !isDir && !item.ForFile)
140         {
141           errorCodes.Add((DWORD)E_FAIL);
142           errorPaths.Add(fullPath);
143           continue;
144         }
145         const UString realName = fileInfo.Name;
146         const UString realDiskPath = diskPrefix + realName;
147         {
148           UStringVector pathParts;
149           pathParts.Add(fileInfo.Name);
150           if (curNode.CheckPathToRoot(false, pathParts, !isDir))
151             continue;
152         }
153         AddDirFileInfo(archivePrefix, realDiskPath, fileInfo, dirItems);
154         if (!isDir)
155           continue;
156         
157         UStringVector addArchivePrefixNew;
158         const NWildcard::CCensorNode *nextNode = 0;
159         int index = curNode.FindSubNode(name);
160         if (index >= 0)
161         {
162           for (int t = needEnterVector.Size(); t <= index; t++)
163             needEnterVector.Add(true);
164           needEnterVector[index] = false;
165           nextNode = &curNode.SubNodes[index];
166         }
167         else
168         {
169           nextNode = &curNode;
170           addArchivePrefixNew.Add(name); // don't change it to realName. It's for shortnames support
171         }
172         RINOK(EnumerateDirItems(*nextNode,   
173             realDiskPath + wchar_t(kDirDelimiter), 
174             archivePrefix + realName + wchar_t(kDirDelimiter), 
175             addArchivePrefixNew, dirItems, true, callback, errorPaths, errorCodes));
176       }
177       for (i = 0; i < curNode.SubNodes.Size(); i++)
178       {
179         if (i < needEnterVector.Size())
180           if (!needEnterVector[i])
181             continue;
182         const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
183         const UString fullPath = diskPrefix + nextNode.Name;
184         NFind::CFileInfoW fileInfo;
185         if (!NFind::FindFile(fullPath, fileInfo))
186         {
187           if (!nextNode.AreThereIncludeItems())
188             continue;
189           errorCodes.Add(::GetLastError());
190           errorPaths.Add(fullPath);
191           continue;
192         }
193         if (!fileInfo.IsDirectory())
194         {
195           errorCodes.Add((DWORD)E_FAIL);
196           errorPaths.Add(fullPath);
197           continue;
198         }
199         RINOK(EnumerateDirItems(nextNode, 
200             diskPrefix + fileInfo.Name + wchar_t(kDirDelimiter), 
201             archivePrefix + fileInfo.Name + wchar_t(kDirDelimiter), 
202             UStringVector(), dirItems, false, callback, errorPaths, errorCodes));
203       }
204       return S_OK;
205     }
206   }
207
208
209   NFind::CEnumeratorW enumerator(diskPrefix + wchar_t(kAnyStringWildcard));
210   for (;;)
211   {
212     NFind::CFileInfoW fileInfo;
213     bool found;
214     if (!enumerator.Next(fileInfo, found))
215     {
216       errorCodes.Add(::GetLastError());
217       errorPaths.Add(diskPrefix);
218       break;
219     }
220     if (!found)
221       break;
222
223     if (callback)
224       RINOK(callback->CheckBreak());
225     const UString &name = fileInfo.Name;
226     bool enterToSubFolders2 = enterToSubFolders;
227     UStringVector addArchivePrefixNew = addArchivePrefix;
228     addArchivePrefixNew.Add(name);
229     {
230       UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
231       if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fileInfo.IsDirectory()))
232         continue;
233     }
234     if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fileInfo.IsDirectory()))
235     {
236       AddDirFileInfo(archivePrefix, diskPrefix + name, fileInfo, dirItems);
237       if (fileInfo.IsDirectory())
238         enterToSubFolders2 = true;
239     }
240     if (!fileInfo.IsDirectory())
241       continue;
242
243     const NWildcard::CCensorNode *nextNode = 0;
244     if (addArchivePrefix.IsEmpty())
245     {
246       int index = curNode.FindSubNode(name);
247       if (index >= 0)
248         nextNode = &curNode.SubNodes[index];
249     }
250     if (!enterToSubFolders2 && nextNode == 0)
251       continue;
252
253     addArchivePrefixNew = addArchivePrefix;
254     if (nextNode == 0)
255     {
256       nextNode = &curNode;
257       addArchivePrefixNew.Add(name);
258     }
259     RINOK(EnumerateDirItems(*nextNode,   
260         diskPrefix + name + wchar_t(kDirDelimiter), 
261         archivePrefix + name + wchar_t(kDirDelimiter), 
262         addArchivePrefixNew, dirItems, enterToSubFolders2, callback, errorPaths, errorCodes));
263   }
264   return S_OK;
265 }
266
267 HRESULT EnumerateItems(
268     const NWildcard::CCensor &censor, 
269     CObjectVector<CDirItem> &dirItems, 
270     IEnumDirItemCallback *callback,
271     UStringVector &errorPaths,
272     CRecordVector<DWORD> &errorCodes)
273 {
274   for (int i = 0; i < censor.Pairs.Size(); i++)
275   {
276     const NWildcard::CPair &pair = censor.Pairs[i];
277     RINOK(EnumerateDirItems(pair.Head, pair.Prefix, L"", UStringVector(), dirItems, false, 
278         callback, errorPaths, errorCodes));
279   }
280   return S_OK;
281 }