xref: /aosp_15_r20/external/lzma/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1 // ArchiveOpenCallback.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/ComTry.h"
6 
7 #include "../../../Windows/FileName.h"
8 #include "../../../Windows/PropVariant.h"
9 #include "../../../Windows/System.h"
10 
11 #include "../../Common/StreamUtils.h"
12 
13 #include "ArchiveOpenCallback.h"
14 
15 // #define DEBUG_VOLUMES
16 
17 #ifdef DEBUG_VOLUMES
18 #include <stdio.h>
19 #endif
20 
21 
22 #ifdef DEBUG_VOLUMES
23   #define PRF(x) x
24 #else
25   #define PRF(x)
26 #endif
27 
28 using namespace NWindows;
29 
Init2(const FString & folderPrefix,const FString & fileName)30 HRESULT COpenCallbackImp::Init2(const FString &folderPrefix, const FString &fileName)
31 {
32   Volumes.Init();
33   FileNames.Clear();
34   FileNames_WasUsed.Clear();
35   FileSizes.Clear();
36   _subArchiveMode = false;
37   // TotalSize = 0;
38   PasswordWasAsked = false;
39   _folderPrefix = folderPrefix;
40   if (!_fileInfo.Find_FollowLink(_folderPrefix + fileName))
41   {
42     // throw 20121118;
43     return GetLastError_noZero_HRESULT();
44   }
45   return S_OK;
46 }
47 
Z7_COM7F_IMF(COpenCallbackImp::SetSubArchiveName (const wchar_t * name))48 Z7_COM7F_IMF(COpenCallbackImp::SetSubArchiveName(const wchar_t *name))
49 {
50   _subArchiveMode = true;
51   _subArchiveName = name;
52   // TotalSize = 0;
53   return S_OK;
54 }
55 
Z7_COM7F_IMF(COpenCallbackImp::SetTotal (const UInt64 * files,const UInt64 * bytes))56 Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes))
57 {
58   COM_TRY_BEGIN
59   if (ReOpenCallback)
60     return ReOpenCallback->SetTotal(files, bytes);
61   if (!Callback)
62     return S_OK;
63   return Callback->Open_SetTotal(files, bytes);
64   COM_TRY_END
65 }
66 
Z7_COM7F_IMF(COpenCallbackImp::SetCompleted (const UInt64 * files,const UInt64 * bytes))67 Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes))
68 {
69   COM_TRY_BEGIN
70   if (ReOpenCallback)
71     return ReOpenCallback->SetCompleted(files, bytes);
72   if (!Callback)
73     return S_OK;
74   return Callback->Open_SetCompleted(files, bytes);
75   COM_TRY_END
76 }
77 
78 
Z7_COM7F_IMF(COpenCallbackImp::GetProperty (PROPID propID,PROPVARIANT * value))79 Z7_COM7F_IMF(COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value))
80 {
81   COM_TRY_BEGIN
82   NCOM::CPropVariant prop;
83   if (_subArchiveMode)
84     switch (propID)
85     {
86       case kpidName: prop = _subArchiveName; break;
87       // case kpidSize:  prop = _subArchiveSize; break; // we don't use it now
88       default: break;
89     }
90   else
91     switch (propID)
92     {
93       case kpidName:  prop = fs2us(_fileInfo.Name); break;
94       case kpidIsDir:  prop = _fileInfo.IsDir(); break;
95       case kpidSize:  prop = _fileInfo.Size; break;
96       case kpidAttrib:  prop = (UInt32)_fileInfo.GetWinAttrib(); break;
97       case kpidPosixAttrib:  prop = (UInt32)_fileInfo.GetPosixAttrib(); break;
98       case kpidCTime:  PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break;
99       case kpidATime:  PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break;
100       case kpidMTime:  PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break;
101       default: break;
102     }
103   prop.Detach(value);
104   return S_OK;
105   COM_TRY_END
106 }
107 
108 
109 // ---------- CInFileStreamVol ----------
110 
111 Z7_class_final(CInFileStreamVol):
112     public IInStream
113   , public IStreamGetSize
114   , public CMyUnknownImp
115 {
116   Z7_IFACES_IMP_UNK_3(
117     IInStream,
118     ISequentialInStream,
119     IStreamGetSize)
120 public:
121   unsigned FileIndex;
122   COpenCallbackImp *OpenCallbackImp;
123   CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
124 
125   HRESULT EnsureOpen()
126   {
127     return OpenCallbackImp->Volumes.EnsureOpen(FileIndex);
128   }
129 
130   ~CInFileStreamVol()
131   {
132     if (OpenCallbackRef)
133       OpenCallbackImp->AtCloseFile(FileIndex);
134   }
135 };
136 
137 
138 void CMultiStreams::InsertToList(unsigned index)
139 {
140   {
141     CSubStream &s = Streams[index];
142     s.Next = Head;
143     s.Prev = -1;
144   }
145   if (Head != -1)
146     Streams[(unsigned)Head].Prev = (int)index;
147   else
148   {
149     // if (Tail != -1) throw 1;
150     Tail = (int)index;
151   }
152   Head = (int)index;
153   NumListItems++;
154 }
155 
156 // s must bee in List
157 void CMultiStreams::RemoveFromList(CSubStream &s)
158 {
159   if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev;
160   if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next;
161   s.Next = -1; // optional
162   s.Prev = -1; // optional
163   NumListItems--;
164 }
165 
166 void CMultiStreams::CloseFile(unsigned index)
167 {
168   CSubStream &s = Streams[index];
169   if (s.Stream)
170   {
171     s.Stream.Release();
172     RemoveFromList(s);
173     // s.InFile->Close();
174     // s.IsOpen = false;
175    #ifdef DEBUG_VOLUMES
176     static int numClosing = 0;
177     numClosing++;
178     printf("\nCloseFile %u, total_closes = %u, num_open_files = %u\n", index, numClosing, NumListItems);
179    #endif
180   }
181 }
182 
183 void CMultiStreams::Init()
184 {
185   Head = -1;
186   Tail = -1;
187   NumListItems = 0;
188   Streams.Clear();
189 }
190 
191 CMultiStreams::CMultiStreams():
192     Head(-1),
193     Tail(-1),
194     NumListItems(0)
195 {
196   NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
197   PRF(printf("\nNumOpenFiles_Limit = %u\n", NumOpenFiles_AllowedMax));
198 }
199 
200 
201 HRESULT CMultiStreams::PrepareToOpenNew()
202 {
203   if (NumListItems < NumOpenFiles_AllowedMax)
204     return S_OK;
205   if (Tail == -1)
206     return E_FAIL;
207   CMultiStreams::CSubStream &tailStream = Streams[(unsigned)Tail];
208   RINOK(InStream_GetPos(tailStream.Stream, tailStream.LocalPos))
209   CloseFile((unsigned)Tail);
210   return S_OK;
211 }
212 
213 
214 HRESULT CMultiStreams::EnsureOpen(unsigned index)
215 {
216   CMultiStreams::CSubStream &s = Streams[index];
217   if (s.Stream)
218   {
219     if ((int)index != Head)
220     {
221       RemoveFromList(s);
222       InsertToList(index);
223     }
224   }
225   else
226   {
227     RINOK(PrepareToOpenNew())
228     {
229       CInFileStream *inFile = new CInFileStream;
230       CMyComPtr<IInStream> inStreamTemp = inFile;
231       if (!inFile->Open(s.Path))
232         return GetLastError_noZero_HRESULT();
233       s.FileSpec = inFile;
234       s.Stream = s.FileSpec;
235       InsertToList(index);
236     }
237     // s.IsOpen = true;
238     if (s.LocalPos != 0)
239     {
240       RINOK(s.Stream->Seek((Int64)s.LocalPos, STREAM_SEEK_SET, &s.LocalPos))
241     }
242    #ifdef DEBUG_VOLUMES
243     static int numOpens = 0;
244     numOpens++;
245     printf("\n-- %u, ReOpen, total_reopens = %u, num_open_files = %u\n", index, numOpens, NumListItems);
246    #endif
247   }
248   return S_OK;
249 }
250 
251 
252 Z7_COM7F_IMF(CInFileStreamVol::Read(void *data, UInt32 size, UInt32 *processedSize))
253 {
254   if (processedSize)
255     *processedSize = 0;
256   if (size == 0)
257     return S_OK;
258   RINOK(EnsureOpen())
259   CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
260   PRF(printf("\n== %u, Read =%u \n", FileIndex, size));
261   return s.Stream->Read(data, size, processedSize);
262 }
263 
264 Z7_COM7F_IMF(CInFileStreamVol::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
265 {
266   // if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION;
267   RINOK(EnsureOpen())
268   CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
269   PRF(printf("\n-- %u, Seek seekOrigin=%u Seek =%u\n", FileIndex, seekOrigin, (unsigned)offset));
270   return s.Stream->Seek(offset, seekOrigin, newPosition);
271 }
272 
273 Z7_COM7F_IMF(CInFileStreamVol::GetSize(UInt64 *size))
274 {
275   RINOK(EnsureOpen())
276   CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
277   return s.FileSpec->GetSize(size);
278 }
279 
280 
281 // from ArchiveExtractCallback.cpp
282 bool IsSafePath(const UString &path);
283 
284 Z7_COM7F_IMF(COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream))
285 {
286   COM_TRY_BEGIN
287   *inStream = NULL;
288 
289   if (_subArchiveMode)
290     return S_FALSE;
291   if (Callback)
292   {
293     RINOK(Callback->Open_CheckBreak())
294   }
295 
296   UString name2 = name;
297 
298 
299   #ifndef Z7_SFX
300 
301   #ifdef _WIN32
302   name2.Replace(L'/', WCHAR_PATH_SEPARATOR);
303   #endif
304 
305   // if (!allowAbsVolPaths)
306   if (!IsSafePath(name2))
307     return S_FALSE;
308 
309   #ifdef _WIN32
310   /* WIN32 allows wildcards in Find() function
311      and doesn't allow wildcard in File.Open()
312      so we can work without the following wildcard check here */
313   if (name2.Find(L'*') >= 0)
314     return S_FALSE;
315   {
316     unsigned startPos = 0;
317     if (name2.IsPrefixedBy_Ascii_NoCase("\\\\?\\"))
318       startPos = 3;
319     if (name2.Find(L'?', startPos) >= 0)
320       return S_FALSE;
321   }
322   #endif
323 
324   #endif
325 
326 
327   FString fullPath;
328   if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath))
329     return S_FALSE;
330   if (!_fileInfo.Find_FollowLink(fullPath))
331     return S_FALSE;
332   if (_fileInfo.IsDir())
333     return S_FALSE;
334 
335   CMultiStreams::CSubStream s;
336 
337   {
338     CInFileStream *inFile = new CInFileStream;
339     CMyComPtr<IInStream> inStreamTemp = inFile;
340     if (!inFile->Open(fullPath))
341       return GetLastError_noZero_HRESULT();
342     RINOK(Volumes.PrepareToOpenNew())
343     s.FileSpec = inFile;
344     s.Stream = s.FileSpec;
345     s.Path = fullPath;
346     // s.Size = _fileInfo.Size;
347     // s.IsOpen = true;
348   }
349 
350   const unsigned fileIndex = Volumes.Streams.Add(s);
351   Volumes.InsertToList(fileIndex);
352 
353   FileSizes.Add(_fileInfo.Size);
354   FileNames.Add(name2);
355   FileNames_WasUsed.Add(true);
356 
357   CInFileStreamVol *inFile = new CInFileStreamVol;
358   CMyComPtr<IInStream> inStreamTemp = inFile;
359   inFile->FileIndex = fileIndex;
360   inFile->OpenCallbackImp = this;
361   inFile->OpenCallbackRef = this;
362   // TotalSize += _fileInfo.Size;
363   *inStream = inStreamTemp.Detach();
364   return S_OK;
365   COM_TRY_END
366 }
367 
368 
369 #ifndef Z7_NO_CRYPTO
370 Z7_COM7F_IMF(COpenCallbackImp::CryptoGetTextPassword(BSTR *password))
371 {
372   COM_TRY_BEGIN
373   if (ReOpenCallback)
374   {
375     Z7_DECL_CMyComPtr_QI_FROM(
376         ICryptoGetTextPassword,
377         getTextPassword, ReOpenCallback)
378     if (getTextPassword)
379       return getTextPassword->CryptoGetTextPassword(password);
380   }
381   if (!Callback)
382     return E_NOTIMPL;
383   PasswordWasAsked = true;
384   return Callback->Open_CryptoGetTextPassword(password);
385   COM_TRY_END
386 }
387 #endif
388 
389 // IProgress
390 Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */))
391 {
392   return S_OK;
393 }
394 
395 Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */))
396 {
397   return S_OK;
398 }
399