xref: /aosp_15_r20/external/lzma/CPP/7zip/Common/MultiOutStream.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
1*f6dc9357SAndroid Build Coastguard Worker // MultiOutStream.cpp
2*f6dc9357SAndroid Build Coastguard Worker 
3*f6dc9357SAndroid Build Coastguard Worker #include "StdAfx.h"
4*f6dc9357SAndroid Build Coastguard Worker 
5*f6dc9357SAndroid Build Coastguard Worker // #define DEBUG_VOLUMES
6*f6dc9357SAndroid Build Coastguard Worker 
7*f6dc9357SAndroid Build Coastguard Worker #ifdef DEBUG_VOLUMES
8*f6dc9357SAndroid Build Coastguard Worker #include <stdio.h>
9*f6dc9357SAndroid Build Coastguard Worker   #define PRF(x) x;
10*f6dc9357SAndroid Build Coastguard Worker #else
11*f6dc9357SAndroid Build Coastguard Worker   #define PRF(x)
12*f6dc9357SAndroid Build Coastguard Worker #endif
13*f6dc9357SAndroid Build Coastguard Worker 
14*f6dc9357SAndroid Build Coastguard Worker #include "../../Common/ComTry.h"
15*f6dc9357SAndroid Build Coastguard Worker 
16*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/FileDir.h"
17*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/FileFind.h"
18*f6dc9357SAndroid Build Coastguard Worker #include "../../Windows/System.h"
19*f6dc9357SAndroid Build Coastguard Worker 
20*f6dc9357SAndroid Build Coastguard Worker #include "MultiOutStream.h"
21*f6dc9357SAndroid Build Coastguard Worker 
22*f6dc9357SAndroid Build Coastguard Worker using namespace NWindows;
23*f6dc9357SAndroid Build Coastguard Worker using namespace NFile;
24*f6dc9357SAndroid Build Coastguard Worker using namespace NDir;
25*f6dc9357SAndroid Build Coastguard Worker 
26*f6dc9357SAndroid Build Coastguard Worker static const unsigned k_NumVols_MAX = k_VectorSizeMax - 1;
27*f6dc9357SAndroid Build Coastguard Worker       // 2; // for debug
28*f6dc9357SAndroid Build Coastguard Worker 
29*f6dc9357SAndroid Build Coastguard Worker /*
30*f6dc9357SAndroid Build Coastguard Worker #define UPDATE_HRES(hres, x) \
31*f6dc9357SAndroid Build Coastguard Worker   { const HRESULT res2 = (x); if (hres == SZ_OK) hres = res2; }
32*f6dc9357SAndroid Build Coastguard Worker */
33*f6dc9357SAndroid Build Coastguard Worker 
Destruct()34*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::Destruct()
35*f6dc9357SAndroid Build Coastguard Worker {
36*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
37*f6dc9357SAndroid Build Coastguard Worker   HRESULT hres = S_OK;
38*f6dc9357SAndroid Build Coastguard Worker   HRESULT hres3 = S_OK;
39*f6dc9357SAndroid Build Coastguard Worker 
40*f6dc9357SAndroid Build Coastguard Worker   while (!Streams.IsEmpty())
41*f6dc9357SAndroid Build Coastguard Worker   {
42*f6dc9357SAndroid Build Coastguard Worker     try
43*f6dc9357SAndroid Build Coastguard Worker     {
44*f6dc9357SAndroid Build Coastguard Worker       HRESULT hres2;
45*f6dc9357SAndroid Build Coastguard Worker       if (NeedDelete)
46*f6dc9357SAndroid Build Coastguard Worker       {
47*f6dc9357SAndroid Build Coastguard Worker         /* we could call OptReOpen_and_SetSize() to test that we try to delete correct file,
48*f6dc9357SAndroid Build Coastguard Worker            but we cannot guarantee that (RealSize) will be correct after Write() or another failures.
49*f6dc9357SAndroid Build Coastguard Worker            And we still want to delete files even for such cases.
50*f6dc9357SAndroid Build Coastguard Worker            So we don't check for OptReOpen_and_SetSize() here: */
51*f6dc9357SAndroid Build Coastguard Worker         // if (OptReOpen_and_SetSize(Streams.Size() - 1, 0) == S_OK)
52*f6dc9357SAndroid Build Coastguard Worker         hres2 = CloseStream_and_DeleteFile(Streams.Size() - 1);
53*f6dc9357SAndroid Build Coastguard Worker       }
54*f6dc9357SAndroid Build Coastguard Worker       else
55*f6dc9357SAndroid Build Coastguard Worker       {
56*f6dc9357SAndroid Build Coastguard Worker         hres2 = CloseStream(Streams.Size() - 1);
57*f6dc9357SAndroid Build Coastguard Worker       }
58*f6dc9357SAndroid Build Coastguard Worker       if (hres == S_OK)
59*f6dc9357SAndroid Build Coastguard Worker         hres = hres2;
60*f6dc9357SAndroid Build Coastguard Worker     }
61*f6dc9357SAndroid Build Coastguard Worker     catch(...)
62*f6dc9357SAndroid Build Coastguard Worker     {
63*f6dc9357SAndroid Build Coastguard Worker       hres3 = E_OUTOFMEMORY;
64*f6dc9357SAndroid Build Coastguard Worker     }
65*f6dc9357SAndroid Build Coastguard Worker 
66*f6dc9357SAndroid Build Coastguard Worker     {
67*f6dc9357SAndroid Build Coastguard Worker       /* Stream was released in CloseStream_*() above already, and it was removed from linked list
68*f6dc9357SAndroid Build Coastguard Worker          it's some unexpected case, if Stream is still attached here.
69*f6dc9357SAndroid Build Coastguard Worker          So the following code is optional: */
70*f6dc9357SAndroid Build Coastguard Worker       CVolStream &s = Streams.Back();
71*f6dc9357SAndroid Build Coastguard Worker       if (s.Stream)
72*f6dc9357SAndroid Build Coastguard Worker       {
73*f6dc9357SAndroid Build Coastguard Worker         if (hres3 == S_OK)
74*f6dc9357SAndroid Build Coastguard Worker           hres3 = E_FAIL;
75*f6dc9357SAndroid Build Coastguard Worker         s.Stream.Detach();
76*f6dc9357SAndroid Build Coastguard Worker         /* it will be not failure, even if we call RemoveFromLinkedList()
77*f6dc9357SAndroid Build Coastguard Worker            twice for same CVolStream in this Destruct() function */
78*f6dc9357SAndroid Build Coastguard Worker         RemoveFromLinkedList(Streams.Size() - 1);
79*f6dc9357SAndroid Build Coastguard Worker       }
80*f6dc9357SAndroid Build Coastguard Worker     }
81*f6dc9357SAndroid Build Coastguard Worker     Streams.DeleteBack();
82*f6dc9357SAndroid Build Coastguard Worker     // Delete_LastStream_Records();
83*f6dc9357SAndroid Build Coastguard Worker   }
84*f6dc9357SAndroid Build Coastguard Worker 
85*f6dc9357SAndroid Build Coastguard Worker   if (hres == S_OK)
86*f6dc9357SAndroid Build Coastguard Worker     hres = hres3;
87*f6dc9357SAndroid Build Coastguard Worker   if (hres == S_OK && NumListItems != 0)
88*f6dc9357SAndroid Build Coastguard Worker     hres = E_FAIL;
89*f6dc9357SAndroid Build Coastguard Worker   return hres;
90*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
91*f6dc9357SAndroid Build Coastguard Worker }
92*f6dc9357SAndroid Build Coastguard Worker 
93*f6dc9357SAndroid Build Coastguard Worker 
~CMultiOutStream()94*f6dc9357SAndroid Build Coastguard Worker CMultiOutStream::~CMultiOutStream()
95*f6dc9357SAndroid Build Coastguard Worker {
96*f6dc9357SAndroid Build Coastguard Worker   // we try to avoid exception in destructors
97*f6dc9357SAndroid Build Coastguard Worker   Destruct();
98*f6dc9357SAndroid Build Coastguard Worker }
99*f6dc9357SAndroid Build Coastguard Worker 
100*f6dc9357SAndroid Build Coastguard Worker 
Init(const CRecordVector<UInt64> & sizes)101*f6dc9357SAndroid Build Coastguard Worker void CMultiOutStream::Init(const CRecordVector<UInt64> &sizes)
102*f6dc9357SAndroid Build Coastguard Worker {
103*f6dc9357SAndroid Build Coastguard Worker   Streams.Clear();
104*f6dc9357SAndroid Build Coastguard Worker   InitLinkedList();
105*f6dc9357SAndroid Build Coastguard Worker   Sizes = sizes;
106*f6dc9357SAndroid Build Coastguard Worker   NeedDelete = true;
107*f6dc9357SAndroid Build Coastguard Worker   MTime_Defined = false;
108*f6dc9357SAndroid Build Coastguard Worker   FinalVol_WasReopen = false;
109*f6dc9357SAndroid Build Coastguard Worker   NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
110*f6dc9357SAndroid Build Coastguard Worker 
111*f6dc9357SAndroid Build Coastguard Worker   _streamIndex = 0;
112*f6dc9357SAndroid Build Coastguard Worker   _offsetPos = 0;
113*f6dc9357SAndroid Build Coastguard Worker   _absPos = 0;
114*f6dc9357SAndroid Build Coastguard Worker   _length = 0;
115*f6dc9357SAndroid Build Coastguard Worker   _absLimit = (UInt64)(Int64)-1;
116*f6dc9357SAndroid Build Coastguard Worker 
117*f6dc9357SAndroid Build Coastguard Worker   _restrict_Begin = 0;
118*f6dc9357SAndroid Build Coastguard Worker   _restrict_End = (UInt64)(Int64)-1;
119*f6dc9357SAndroid Build Coastguard Worker   _restrict_Global = 0;
120*f6dc9357SAndroid Build Coastguard Worker 
121*f6dc9357SAndroid Build Coastguard Worker   UInt64 sum = 0;
122*f6dc9357SAndroid Build Coastguard Worker   unsigned i = 0;
123*f6dc9357SAndroid Build Coastguard Worker   for (i = 0; i < Sizes.Size(); i++)
124*f6dc9357SAndroid Build Coastguard Worker   {
125*f6dc9357SAndroid Build Coastguard Worker     if (i >= k_NumVols_MAX)
126*f6dc9357SAndroid Build Coastguard Worker     {
127*f6dc9357SAndroid Build Coastguard Worker       _absLimit = sum;
128*f6dc9357SAndroid Build Coastguard Worker       break;
129*f6dc9357SAndroid Build Coastguard Worker     }
130*f6dc9357SAndroid Build Coastguard Worker     const UInt64 size = Sizes[i];
131*f6dc9357SAndroid Build Coastguard Worker     const UInt64 next = sum + size;
132*f6dc9357SAndroid Build Coastguard Worker     if (next < sum)
133*f6dc9357SAndroid Build Coastguard Worker       break;
134*f6dc9357SAndroid Build Coastguard Worker     sum = next;
135*f6dc9357SAndroid Build Coastguard Worker   }
136*f6dc9357SAndroid Build Coastguard Worker 
137*f6dc9357SAndroid Build Coastguard Worker   // if (Sizes.IsEmpty()) throw "no volume sizes";
138*f6dc9357SAndroid Build Coastguard Worker   const UInt64 size = Sizes.Back();
139*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
140*f6dc9357SAndroid Build Coastguard Worker     throw "zero size last volume";
141*f6dc9357SAndroid Build Coastguard Worker 
142*f6dc9357SAndroid Build Coastguard Worker   if (i == Sizes.Size())
143*f6dc9357SAndroid Build Coastguard Worker     if ((_absLimit - sum) / size >= (k_NumVols_MAX - i))
144*f6dc9357SAndroid Build Coastguard Worker       _absLimit = sum + (k_NumVols_MAX - i) * size;
145*f6dc9357SAndroid Build Coastguard Worker }
146*f6dc9357SAndroid Build Coastguard Worker 
147*f6dc9357SAndroid Build Coastguard Worker 
148*f6dc9357SAndroid Build Coastguard Worker /* IsRestricted():
149*f6dc9357SAndroid Build Coastguard Worker    we must call only if volume is full (s.RealSize==VolSize) or finished.
150*f6dc9357SAndroid Build Coastguard Worker    the function doesn't use VolSize and it uses s.RealSize instead.
151*f6dc9357SAndroid Build Coastguard Worker    it returns true  : if stream is restricted, and we can't close that stream
152*f6dc9357SAndroid Build Coastguard Worker    it returns false : if there is no restriction, and we can close that stream
153*f6dc9357SAndroid Build Coastguard Worker  Note: (RealSize == 0) (empty volume) on restriction bounds are supposed as non-restricted
154*f6dc9357SAndroid Build Coastguard Worker */
IsRestricted(const CVolStream & s) const155*f6dc9357SAndroid Build Coastguard Worker bool CMultiOutStream::IsRestricted(const CVolStream &s) const
156*f6dc9357SAndroid Build Coastguard Worker {
157*f6dc9357SAndroid Build Coastguard Worker   if (s.Start < _restrict_Global)
158*f6dc9357SAndroid Build Coastguard Worker     return true;
159*f6dc9357SAndroid Build Coastguard Worker   if (_restrict_Begin == _restrict_End)
160*f6dc9357SAndroid Build Coastguard Worker     return false;
161*f6dc9357SAndroid Build Coastguard Worker   if (_restrict_Begin <= s.Start)
162*f6dc9357SAndroid Build Coastguard Worker     return _restrict_End > s.Start;
163*f6dc9357SAndroid Build Coastguard Worker   return _restrict_Begin < s.Start + s.RealSize;
164*f6dc9357SAndroid Build Coastguard Worker }
165*f6dc9357SAndroid Build Coastguard Worker 
166*f6dc9357SAndroid Build Coastguard Worker /*
167*f6dc9357SAndroid Build Coastguard Worker // this function check also _length and volSize
168*f6dc9357SAndroid Build Coastguard Worker bool CMultiOutStream::IsRestricted_for_Close(unsigned index) const
169*f6dc9357SAndroid Build Coastguard Worker {
170*f6dc9357SAndroid Build Coastguard Worker   const CVolStream &s = Streams[index];
171*f6dc9357SAndroid Build Coastguard Worker   if (_length <= s.Start) // we don't close streams after the end, because we still can write them later
172*f6dc9357SAndroid Build Coastguard Worker     return true;
173*f6dc9357SAndroid Build Coastguard Worker   // (_length > s.Start)
174*f6dc9357SAndroid Build Coastguard Worker   const UInt64 volSize = GetVolSize_for_Stream(index);
175*f6dc9357SAndroid Build Coastguard Worker   if (volSize == 0)
176*f6dc9357SAndroid Build Coastguard Worker     return IsRestricted_Empty(s);
177*f6dc9357SAndroid Build Coastguard Worker   if (_length - s.Start < volSize)
178*f6dc9357SAndroid Build Coastguard Worker     return true;
179*f6dc9357SAndroid Build Coastguard Worker   return IsRestricted(s);
180*f6dc9357SAndroid Build Coastguard Worker }
181*f6dc9357SAndroid Build Coastguard Worker */
182*f6dc9357SAndroid Build Coastguard Worker 
GetFilePath(unsigned index)183*f6dc9357SAndroid Build Coastguard Worker FString CMultiOutStream::GetFilePath(unsigned index)
184*f6dc9357SAndroid Build Coastguard Worker {
185*f6dc9357SAndroid Build Coastguard Worker   FString name;
186*f6dc9357SAndroid Build Coastguard Worker   name.Add_UInt32((UInt32)(index + 1));
187*f6dc9357SAndroid Build Coastguard Worker   while (name.Len() < 3)
188*f6dc9357SAndroid Build Coastguard Worker     name.InsertAtFront(FTEXT('0'));
189*f6dc9357SAndroid Build Coastguard Worker   name.Insert(0, Prefix);
190*f6dc9357SAndroid Build Coastguard Worker   return name;
191*f6dc9357SAndroid Build Coastguard Worker }
192*f6dc9357SAndroid Build Coastguard Worker 
193*f6dc9357SAndroid Build Coastguard Worker 
194*f6dc9357SAndroid Build Coastguard Worker // we close stream, but we still keep item in Streams[] vector
CloseStream(unsigned index)195*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::CloseStream(unsigned index)
196*f6dc9357SAndroid Build Coastguard Worker {
197*f6dc9357SAndroid Build Coastguard Worker   CVolStream &s = Streams[index];
198*f6dc9357SAndroid Build Coastguard Worker   if (s.Stream)
199*f6dc9357SAndroid Build Coastguard Worker   {
200*f6dc9357SAndroid Build Coastguard Worker     RINOK(s.StreamSpec->Close())
201*f6dc9357SAndroid Build Coastguard Worker     // the following two commands must be called together:
202*f6dc9357SAndroid Build Coastguard Worker     s.Stream.Release();
203*f6dc9357SAndroid Build Coastguard Worker     RemoveFromLinkedList(index);
204*f6dc9357SAndroid Build Coastguard Worker   }
205*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
206*f6dc9357SAndroid Build Coastguard Worker }
207*f6dc9357SAndroid Build Coastguard Worker 
208*f6dc9357SAndroid Build Coastguard Worker 
209*f6dc9357SAndroid Build Coastguard Worker // we close stream and delete file, but we still keep item in Streams[] vector
CloseStream_and_DeleteFile(unsigned index)210*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::CloseStream_and_DeleteFile(unsigned index)
211*f6dc9357SAndroid Build Coastguard Worker {
212*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n====== %u, CloseStream_AndDelete \n", index))
213*f6dc9357SAndroid Build Coastguard Worker   RINOK(CloseStream(index))
214*f6dc9357SAndroid Build Coastguard Worker   FString path = GetFilePath(index);
215*f6dc9357SAndroid Build Coastguard Worker   path += Streams[index].Postfix;
216*f6dc9357SAndroid Build Coastguard Worker   // we can checki that file exist
217*f6dc9357SAndroid Build Coastguard Worker   // if (NFind::DoesFileExist_Raw(path))
218*f6dc9357SAndroid Build Coastguard Worker   if (!DeleteFileAlways(path))
219*f6dc9357SAndroid Build Coastguard Worker     return GetLastError_noZero_HRESULT();
220*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
221*f6dc9357SAndroid Build Coastguard Worker }
222*f6dc9357SAndroid Build Coastguard Worker 
223*f6dc9357SAndroid Build Coastguard Worker 
CloseStream_and_FinalRename(unsigned index)224*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::CloseStream_and_FinalRename(unsigned index)
225*f6dc9357SAndroid Build Coastguard Worker {
226*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n====== %u, CloseStream_and_FinalRename \n", index))
227*f6dc9357SAndroid Build Coastguard Worker   CVolStream &s = Streams[index];
228*f6dc9357SAndroid Build Coastguard Worker   // HRESULT res = S_OK;
229*f6dc9357SAndroid Build Coastguard Worker   bool mtime_WasSet = false;
230*f6dc9357SAndroid Build Coastguard Worker   if (MTime_Defined && s.Stream)
231*f6dc9357SAndroid Build Coastguard Worker   {
232*f6dc9357SAndroid Build Coastguard Worker     if (s.StreamSpec->SetMTime(&MTime))
233*f6dc9357SAndroid Build Coastguard Worker       mtime_WasSet = true;
234*f6dc9357SAndroid Build Coastguard Worker     // else res = GetLastError_noZero_HRESULT();
235*f6dc9357SAndroid Build Coastguard Worker   }
236*f6dc9357SAndroid Build Coastguard Worker 
237*f6dc9357SAndroid Build Coastguard Worker   RINOK(CloseStream(index))
238*f6dc9357SAndroid Build Coastguard Worker   if (s.Postfix.IsEmpty()) // if Postfix is empty, the path is already final
239*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
240*f6dc9357SAndroid Build Coastguard Worker   const FString path = GetFilePath(index);
241*f6dc9357SAndroid Build Coastguard Worker   FString tempPath = path;
242*f6dc9357SAndroid Build Coastguard Worker   tempPath += s.Postfix;
243*f6dc9357SAndroid Build Coastguard Worker 
244*f6dc9357SAndroid Build Coastguard Worker   if (MTime_Defined && !mtime_WasSet)
245*f6dc9357SAndroid Build Coastguard Worker   {
246*f6dc9357SAndroid Build Coastguard Worker     if (!SetDirTime(tempPath, NULL, NULL, &MTime))
247*f6dc9357SAndroid Build Coastguard Worker     {
248*f6dc9357SAndroid Build Coastguard Worker       // res = GetLastError_noZero_HRESULT();
249*f6dc9357SAndroid Build Coastguard Worker     }
250*f6dc9357SAndroid Build Coastguard Worker   }
251*f6dc9357SAndroid Build Coastguard Worker   if (!MyMoveFile(tempPath, path))
252*f6dc9357SAndroid Build Coastguard Worker     return GetLastError_noZero_HRESULT();
253*f6dc9357SAndroid Build Coastguard Worker   /* we clear CVolStream::Postfix. So we will not use Temp path
254*f6dc9357SAndroid Build Coastguard Worker      anymore for this stream, and we will work only with final path */
255*f6dc9357SAndroid Build Coastguard Worker   s.Postfix.Empty();
256*f6dc9357SAndroid Build Coastguard Worker   // we can ignore set_mtime error or we can return it
257*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
258*f6dc9357SAndroid Build Coastguard Worker   // return res;
259*f6dc9357SAndroid Build Coastguard Worker }
260*f6dc9357SAndroid Build Coastguard Worker 
261*f6dc9357SAndroid Build Coastguard Worker 
PrepareToOpenNew()262*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::PrepareToOpenNew()
263*f6dc9357SAndroid Build Coastguard Worker {
264*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("PrepareToOpenNew NumListItems =%u,  NumOpenFiles_AllowedMax = %u \n", NumListItems, NumOpenFiles_AllowedMax))
265*f6dc9357SAndroid Build Coastguard Worker 
266*f6dc9357SAndroid Build Coastguard Worker   if (NumListItems < NumOpenFiles_AllowedMax)
267*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
268*f6dc9357SAndroid Build Coastguard Worker   /* when we create zip archive: in most cases we need only starting
269*f6dc9357SAndroid Build Coastguard Worker      data of restricted region for rewriting zip's local header.
270*f6dc9357SAndroid Build Coastguard Worker      So here we close latest created volume (from Head), and we try to
271*f6dc9357SAndroid Build Coastguard Worker      keep oldest volumes that will be used for header rewriting later. */
272*f6dc9357SAndroid Build Coastguard Worker   const int index = Head;
273*f6dc9357SAndroid Build Coastguard Worker   if (index == -1)
274*f6dc9357SAndroid Build Coastguard Worker     return E_FAIL;
275*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n== %u, PrepareToOpenNew::CloseStream, NumListItems =%u \n", index, NumListItems))
276*f6dc9357SAndroid Build Coastguard Worker   /* we don't expect non-restricted stream here in normal cases (if _restrict_Global was not changed).
277*f6dc9357SAndroid Build Coastguard Worker      if there was non-restricted stream, it should be closed before */
278*f6dc9357SAndroid Build Coastguard Worker   // if (!IsRestricted_for_Close(index)) return CloseStream_and_FinalRename(index);
279*f6dc9357SAndroid Build Coastguard Worker   return CloseStream((unsigned)index);
280*f6dc9357SAndroid Build Coastguard Worker }
281*f6dc9357SAndroid Build Coastguard Worker 
282*f6dc9357SAndroid Build Coastguard Worker 
CreateNewStream(UInt64 newSize)283*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::CreateNewStream(UInt64 newSize)
284*f6dc9357SAndroid Build Coastguard Worker {
285*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n== %u, CreateNewStream, size =%u \n", Streams.Size(), (unsigned)newSize))
286*f6dc9357SAndroid Build Coastguard Worker 
287*f6dc9357SAndroid Build Coastguard Worker   if (Streams.Size() >= k_NumVols_MAX)
288*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG; // E_OUTOFMEMORY
289*f6dc9357SAndroid Build Coastguard Worker 
290*f6dc9357SAndroid Build Coastguard Worker   RINOK(PrepareToOpenNew())
291*f6dc9357SAndroid Build Coastguard Worker   CVolStream s;
292*f6dc9357SAndroid Build Coastguard Worker   s.StreamSpec = new COutFileStream;
293*f6dc9357SAndroid Build Coastguard Worker   s.Stream = s.StreamSpec;
294*f6dc9357SAndroid Build Coastguard Worker   const FString path = GetFilePath(Streams.Size());
295*f6dc9357SAndroid Build Coastguard Worker 
296*f6dc9357SAndroid Build Coastguard Worker   if (NFind::DoesFileExist_Raw(path))
297*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
298*f6dc9357SAndroid Build Coastguard Worker   if (!CreateTempFile2(path, false, s.Postfix, &s.StreamSpec->File))
299*f6dc9357SAndroid Build Coastguard Worker     return GetLastError_noZero_HRESULT();
300*f6dc9357SAndroid Build Coastguard Worker 
301*f6dc9357SAndroid Build Coastguard Worker   s.Start = GetGlobalOffset_for_NewStream();
302*f6dc9357SAndroid Build Coastguard Worker   s.Pos = 0;
303*f6dc9357SAndroid Build Coastguard Worker   s.RealSize = 0;
304*f6dc9357SAndroid Build Coastguard Worker 
305*f6dc9357SAndroid Build Coastguard Worker   const unsigned index = Streams.Add(s);
306*f6dc9357SAndroid Build Coastguard Worker   InsertToLinkedList(index);
307*f6dc9357SAndroid Build Coastguard Worker 
308*f6dc9357SAndroid Build Coastguard Worker   if (newSize != 0)
309*f6dc9357SAndroid Build Coastguard Worker     return s.SetSize2(newSize);
310*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
311*f6dc9357SAndroid Build Coastguard Worker }
312*f6dc9357SAndroid Build Coastguard Worker 
313*f6dc9357SAndroid Build Coastguard Worker 
CreateStreams_If_Required(unsigned streamIndex)314*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::CreateStreams_If_Required(unsigned streamIndex)
315*f6dc9357SAndroid Build Coastguard Worker {
316*f6dc9357SAndroid Build Coastguard Worker   // UInt64 lastStreamSize = 0;
317*f6dc9357SAndroid Build Coastguard Worker   for (;;)
318*f6dc9357SAndroid Build Coastguard Worker   {
319*f6dc9357SAndroid Build Coastguard Worker     const unsigned numStreamsBefore = Streams.Size();
320*f6dc9357SAndroid Build Coastguard Worker     if (streamIndex < numStreamsBefore)
321*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
322*f6dc9357SAndroid Build Coastguard Worker     UInt64 newSize;
323*f6dc9357SAndroid Build Coastguard Worker     if (streamIndex == numStreamsBefore)
324*f6dc9357SAndroid Build Coastguard Worker     {
325*f6dc9357SAndroid Build Coastguard Worker       // it's final volume that will be used for real writing.
326*f6dc9357SAndroid Build Coastguard Worker       /* SetSize(_offsetPos) is not required,
327*f6dc9357SAndroid Build Coastguard Worker       because the file Size will be set later by calling Seek() with Write() */
328*f6dc9357SAndroid Build Coastguard Worker       newSize = 0; // lastStreamSize;
329*f6dc9357SAndroid Build Coastguard Worker     }
330*f6dc9357SAndroid Build Coastguard Worker     else
331*f6dc9357SAndroid Build Coastguard Worker     {
332*f6dc9357SAndroid Build Coastguard Worker       // it's intermediate volume. So we need full volume size
333*f6dc9357SAndroid Build Coastguard Worker       newSize = GetVolSize_for_Stream(numStreamsBefore);
334*f6dc9357SAndroid Build Coastguard Worker     }
335*f6dc9357SAndroid Build Coastguard Worker 
336*f6dc9357SAndroid Build Coastguard Worker     RINOK(CreateNewStream(newSize))
337*f6dc9357SAndroid Build Coastguard Worker 
338*f6dc9357SAndroid Build Coastguard Worker     // optional check
339*f6dc9357SAndroid Build Coastguard Worker     if (numStreamsBefore + 1 != Streams.Size()) return E_FAIL;
340*f6dc9357SAndroid Build Coastguard Worker 
341*f6dc9357SAndroid Build Coastguard Worker     if (streamIndex != numStreamsBefore)
342*f6dc9357SAndroid Build Coastguard Worker     {
343*f6dc9357SAndroid Build Coastguard Worker       // it's intermediate volume. So we can close it, if it's non-restricted
344*f6dc9357SAndroid Build Coastguard Worker       bool isRestricted;
345*f6dc9357SAndroid Build Coastguard Worker       {
346*f6dc9357SAndroid Build Coastguard Worker         const CVolStream &s = Streams[numStreamsBefore];
347*f6dc9357SAndroid Build Coastguard Worker         if (newSize == 0)
348*f6dc9357SAndroid Build Coastguard Worker           isRestricted = IsRestricted_Empty(s);
349*f6dc9357SAndroid Build Coastguard Worker         else
350*f6dc9357SAndroid Build Coastguard Worker           isRestricted = IsRestricted(s);
351*f6dc9357SAndroid Build Coastguard Worker       }
352*f6dc9357SAndroid Build Coastguard Worker       if (!isRestricted)
353*f6dc9357SAndroid Build Coastguard Worker       {
354*f6dc9357SAndroid Build Coastguard Worker         RINOK(CloseStream_and_FinalRename(numStreamsBefore))
355*f6dc9357SAndroid Build Coastguard Worker       }
356*f6dc9357SAndroid Build Coastguard Worker     }
357*f6dc9357SAndroid Build Coastguard Worker   }
358*f6dc9357SAndroid Build Coastguard Worker }
359*f6dc9357SAndroid Build Coastguard Worker 
360*f6dc9357SAndroid Build Coastguard Worker 
ReOpenStream(unsigned streamIndex)361*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::ReOpenStream(unsigned streamIndex)
362*f6dc9357SAndroid Build Coastguard Worker {
363*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n====== %u, ReOpenStream \n", streamIndex))
364*f6dc9357SAndroid Build Coastguard Worker   RINOK(PrepareToOpenNew())
365*f6dc9357SAndroid Build Coastguard Worker   CVolStream &s = Streams[streamIndex];
366*f6dc9357SAndroid Build Coastguard Worker 
367*f6dc9357SAndroid Build Coastguard Worker   FString path = GetFilePath(streamIndex);
368*f6dc9357SAndroid Build Coastguard Worker   path += s.Postfix;
369*f6dc9357SAndroid Build Coastguard Worker 
370*f6dc9357SAndroid Build Coastguard Worker   s.StreamSpec = new COutFileStream;
371*f6dc9357SAndroid Build Coastguard Worker   s.Stream = s.StreamSpec;
372*f6dc9357SAndroid Build Coastguard Worker   s.Pos = 0;
373*f6dc9357SAndroid Build Coastguard Worker 
374*f6dc9357SAndroid Build Coastguard Worker   HRESULT hres;
375*f6dc9357SAndroid Build Coastguard Worker   if (s.StreamSpec->Open_EXISTING(path))
376*f6dc9357SAndroid Build Coastguard Worker   {
377*f6dc9357SAndroid Build Coastguard Worker     if (s.Postfix.IsEmpty())
378*f6dc9357SAndroid Build Coastguard Worker     {
379*f6dc9357SAndroid Build Coastguard Worker       /* it's unexpected case that we open finished volume.
380*f6dc9357SAndroid Build Coastguard Worker          It can mean that the code for restriction is incorrect */
381*f6dc9357SAndroid Build Coastguard Worker       FinalVol_WasReopen = true;
382*f6dc9357SAndroid Build Coastguard Worker     }
383*f6dc9357SAndroid Build Coastguard Worker     UInt64 realSize = 0;
384*f6dc9357SAndroid Build Coastguard Worker     hres = s.StreamSpec->GetSize(&realSize);
385*f6dc9357SAndroid Build Coastguard Worker     if (hres == S_OK)
386*f6dc9357SAndroid Build Coastguard Worker     {
387*f6dc9357SAndroid Build Coastguard Worker       if (realSize == s.RealSize)
388*f6dc9357SAndroid Build Coastguard Worker       {
389*f6dc9357SAndroid Build Coastguard Worker         PRF(printf("\n ReOpenStream OK realSize = %u\n", (unsigned)realSize))
390*f6dc9357SAndroid Build Coastguard Worker         InsertToLinkedList(streamIndex);
391*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
392*f6dc9357SAndroid Build Coastguard Worker       }
393*f6dc9357SAndroid Build Coastguard Worker       // file size was changed between Close() and ReOpen()
394*f6dc9357SAndroid Build Coastguard Worker       // we must release Stream to be consistent with linked list
395*f6dc9357SAndroid Build Coastguard Worker       hres = E_FAIL;
396*f6dc9357SAndroid Build Coastguard Worker     }
397*f6dc9357SAndroid Build Coastguard Worker   }
398*f6dc9357SAndroid Build Coastguard Worker   else
399*f6dc9357SAndroid Build Coastguard Worker     hres = GetLastError_noZero_HRESULT();
400*f6dc9357SAndroid Build Coastguard Worker   s.Stream.Release();
401*f6dc9357SAndroid Build Coastguard Worker   s.StreamSpec = NULL;
402*f6dc9357SAndroid Build Coastguard Worker   return hres;
403*f6dc9357SAndroid Build Coastguard Worker }
404*f6dc9357SAndroid Build Coastguard Worker 
405*f6dc9357SAndroid Build Coastguard Worker 
406*f6dc9357SAndroid Build Coastguard Worker /* Sets size of stream, if new size is not equal to old size (RealSize).
407*f6dc9357SAndroid Build Coastguard Worker    If stream was closed and size change is required, it reopens the stream. */
408*f6dc9357SAndroid Build Coastguard Worker 
OptReOpen_and_SetSize(unsigned index,UInt64 size)409*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::OptReOpen_and_SetSize(unsigned index, UInt64 size)
410*f6dc9357SAndroid Build Coastguard Worker {
411*f6dc9357SAndroid Build Coastguard Worker   CVolStream &s = Streams[index];
412*f6dc9357SAndroid Build Coastguard Worker   if (size == s.RealSize)
413*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
414*f6dc9357SAndroid Build Coastguard Worker   if (!s.Stream)
415*f6dc9357SAndroid Build Coastguard Worker   {
416*f6dc9357SAndroid Build Coastguard Worker     RINOK(ReOpenStream(index))
417*f6dc9357SAndroid Build Coastguard Worker   }
418*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n== %u, OptReOpen_and_SetSize, size =%u RealSize = %u\n", index, (unsigned)size, (unsigned)s.RealSize))
419*f6dc9357SAndroid Build Coastguard Worker   // comment it to debug tail after data
420*f6dc9357SAndroid Build Coastguard Worker   return s.SetSize2(size);
421*f6dc9357SAndroid Build Coastguard Worker }
422*f6dc9357SAndroid Build Coastguard Worker 
423*f6dc9357SAndroid Build Coastguard Worker 
424*f6dc9357SAndroid Build Coastguard Worker /*
425*f6dc9357SAndroid Build Coastguard Worker call Normalize_finalMode(false), if _length was changed.
426*f6dc9357SAndroid Build Coastguard Worker   for all streams starting after _length:
427*f6dc9357SAndroid Build Coastguard Worker     - it sets zero size
428*f6dc9357SAndroid Build Coastguard Worker     - it still keeps file open
429*f6dc9357SAndroid Build Coastguard Worker   Note: after _length reducing with CMultiOutStream::SetSize() we can
430*f6dc9357SAndroid Build Coastguard Worker     have very big number of empty streams at the end of Streams[] list.
431*f6dc9357SAndroid Build Coastguard Worker     And Normalize_finalMode() will runs all these empty streams of Streams[] vector.
432*f6dc9357SAndroid Build Coastguard Worker     So it can be ineffective, if we call Normalize_finalMode() many
433*f6dc9357SAndroid Build Coastguard Worker     times after big reducing of (_length).
434*f6dc9357SAndroid Build Coastguard Worker 
435*f6dc9357SAndroid Build Coastguard Worker call Normalize_finalMode(true) to set final presentations of all streams
436*f6dc9357SAndroid Build Coastguard Worker   for all streams starting after _length:
437*f6dc9357SAndroid Build Coastguard Worker     - it sets zero size
438*f6dc9357SAndroid Build Coastguard Worker     - it removes file
439*f6dc9357SAndroid Build Coastguard Worker     - it removes CVolStream object from Streams[] vector
440*f6dc9357SAndroid Build Coastguard Worker 
441*f6dc9357SAndroid Build Coastguard Worker Note: we don't remove zero sized first volume, if (_length == 0)
442*f6dc9357SAndroid Build Coastguard Worker */
443*f6dc9357SAndroid Build Coastguard Worker 
Normalize_finalMode(bool finalMode)444*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::Normalize_finalMode(bool finalMode)
445*f6dc9357SAndroid Build Coastguard Worker {
446*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n== Normalize_finalMode: _length =%d \n", (unsigned)_length))
447*f6dc9357SAndroid Build Coastguard Worker 
448*f6dc9357SAndroid Build Coastguard Worker   unsigned i = Streams.Size();
449*f6dc9357SAndroid Build Coastguard Worker 
450*f6dc9357SAndroid Build Coastguard Worker   UInt64 offset = 0;
451*f6dc9357SAndroid Build Coastguard Worker 
452*f6dc9357SAndroid Build Coastguard Worker   /* At first we normalize (reduce or increase) the sizes of all existing
453*f6dc9357SAndroid Build Coastguard Worker      streams in Streams[] that can be affected by changed _length.
454*f6dc9357SAndroid Build Coastguard Worker      And we remove tailing zero-size streams, if (finalMode == true) */
455*f6dc9357SAndroid Build Coastguard Worker   while (i != 0)
456*f6dc9357SAndroid Build Coastguard Worker   {
457*f6dc9357SAndroid Build Coastguard Worker     offset = Streams[--i].Start; // it's last item in Streams[]
458*f6dc9357SAndroid Build Coastguard Worker     // we don't want to remove first volume
459*f6dc9357SAndroid Build Coastguard Worker     if (offset < _length || i == 0)
460*f6dc9357SAndroid Build Coastguard Worker     {
461*f6dc9357SAndroid Build Coastguard Worker       const UInt64 volSize = GetVolSize_for_Stream(i);
462*f6dc9357SAndroid Build Coastguard Worker       UInt64 size = _length - offset; // (size != 0) here
463*f6dc9357SAndroid Build Coastguard Worker       if (size > volSize)
464*f6dc9357SAndroid Build Coastguard Worker         size = volSize;
465*f6dc9357SAndroid Build Coastguard Worker       RINOK(OptReOpen_and_SetSize(i, size))
466*f6dc9357SAndroid Build Coastguard Worker       if (_length - offset <= volSize)
467*f6dc9357SAndroid Build Coastguard Worker         return S_OK;
468*f6dc9357SAndroid Build Coastguard Worker       // _length - offset > volSize
469*f6dc9357SAndroid Build Coastguard Worker       offset += volSize;
470*f6dc9357SAndroid Build Coastguard Worker       // _length > offset
471*f6dc9357SAndroid Build Coastguard Worker       break;
472*f6dc9357SAndroid Build Coastguard Worker       // UPDATE_HRES(res, OptReOpen_and_SetSize(i, size));
473*f6dc9357SAndroid Build Coastguard Worker     }
474*f6dc9357SAndroid Build Coastguard Worker 
475*f6dc9357SAndroid Build Coastguard Worker     /* we Set Size of stream to zero even for (finalMode==true), although
476*f6dc9357SAndroid Build Coastguard Worker        that stream will be deleted in next commands */
477*f6dc9357SAndroid Build Coastguard Worker     // UPDATE_HRES(res, OptReOpen_and_SetSize(i, 0));
478*f6dc9357SAndroid Build Coastguard Worker     RINOK(OptReOpen_and_SetSize(i, 0))
479*f6dc9357SAndroid Build Coastguard Worker     if (finalMode)
480*f6dc9357SAndroid Build Coastguard Worker     {
481*f6dc9357SAndroid Build Coastguard Worker       RINOK(CloseStream_and_DeleteFile(i))
482*f6dc9357SAndroid Build Coastguard Worker       /* CVolStream::Stream was released above already, and it was
483*f6dc9357SAndroid Build Coastguard Worker          removed from linked list. So we don't need to update linked list
484*f6dc9357SAndroid Build Coastguard Worker          structure, when we delete last item in Streams[] */
485*f6dc9357SAndroid Build Coastguard Worker       Streams.DeleteBack();
486*f6dc9357SAndroid Build Coastguard Worker       // Delete_LastStream_Records();
487*f6dc9357SAndroid Build Coastguard Worker     }
488*f6dc9357SAndroid Build Coastguard Worker   }
489*f6dc9357SAndroid Build Coastguard Worker 
490*f6dc9357SAndroid Build Coastguard Worker   /* now we create new zero-filled streams to cover all data up to _length */
491*f6dc9357SAndroid Build Coastguard Worker 
492*f6dc9357SAndroid Build Coastguard Worker   if (_length == 0)
493*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
494*f6dc9357SAndroid Build Coastguard Worker 
495*f6dc9357SAndroid Build Coastguard Worker   // (offset) is start offset of next stream after existing Streams[]
496*f6dc9357SAndroid Build Coastguard Worker 
497*f6dc9357SAndroid Build Coastguard Worker   for (;;)
498*f6dc9357SAndroid Build Coastguard Worker   {
499*f6dc9357SAndroid Build Coastguard Worker     // _length > offset
500*f6dc9357SAndroid Build Coastguard Worker     const UInt64 volSize = GetVolSize_for_Stream(Streams.Size());
501*f6dc9357SAndroid Build Coastguard Worker     UInt64 size = _length - offset; // (size != 0) here
502*f6dc9357SAndroid Build Coastguard Worker     if (size > volSize)
503*f6dc9357SAndroid Build Coastguard Worker       size = volSize;
504*f6dc9357SAndroid Build Coastguard Worker     RINOK(CreateNewStream(size))
505*f6dc9357SAndroid Build Coastguard Worker     if (_length - offset <= volSize)
506*f6dc9357SAndroid Build Coastguard Worker       return S_OK;
507*f6dc9357SAndroid Build Coastguard Worker     // _length - offset > volSize)
508*f6dc9357SAndroid Build Coastguard Worker     offset += volSize;
509*f6dc9357SAndroid Build Coastguard Worker     // _length > offset
510*f6dc9357SAndroid Build Coastguard Worker   }
511*f6dc9357SAndroid Build Coastguard Worker }
512*f6dc9357SAndroid Build Coastguard Worker 
513*f6dc9357SAndroid Build Coastguard Worker 
FinalFlush_and_CloseFiles(unsigned & numTotalVolumesRes)514*f6dc9357SAndroid Build Coastguard Worker HRESULT CMultiOutStream::FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes)
515*f6dc9357SAndroid Build Coastguard Worker {
516*f6dc9357SAndroid Build Coastguard Worker   // at first we remove unused zero-sized streams after _length
517*f6dc9357SAndroid Build Coastguard Worker   HRESULT res = Normalize_finalMode(true);
518*f6dc9357SAndroid Build Coastguard Worker   numTotalVolumesRes = Streams.Size();
519*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Streams)
520*f6dc9357SAndroid Build Coastguard Worker   {
521*f6dc9357SAndroid Build Coastguard Worker     const HRESULT res2 = CloseStream_and_FinalRename(i);
522*f6dc9357SAndroid Build Coastguard Worker     if (res == S_OK)
523*f6dc9357SAndroid Build Coastguard Worker       res = res2;
524*f6dc9357SAndroid Build Coastguard Worker   }
525*f6dc9357SAndroid Build Coastguard Worker   if (NumListItems != 0 && res == S_OK)
526*f6dc9357SAndroid Build Coastguard Worker     res = E_FAIL;
527*f6dc9357SAndroid Build Coastguard Worker   return res;
528*f6dc9357SAndroid Build Coastguard Worker }
529*f6dc9357SAndroid Build Coastguard Worker 
530*f6dc9357SAndroid Build Coastguard Worker 
SetMTime_Final(const CFiTime & mTime)531*f6dc9357SAndroid Build Coastguard Worker bool CMultiOutStream::SetMTime_Final(const CFiTime &mTime)
532*f6dc9357SAndroid Build Coastguard Worker {
533*f6dc9357SAndroid Build Coastguard Worker   // we will set mtime only if new value differs from previous
534*f6dc9357SAndroid Build Coastguard Worker   if (!FinalVol_WasReopen && MTime_Defined && Compare_FiTime(&MTime, &mTime) == 0)
535*f6dc9357SAndroid Build Coastguard Worker     return true;
536*f6dc9357SAndroid Build Coastguard Worker   bool res = true;
537*f6dc9357SAndroid Build Coastguard Worker   FOR_VECTOR (i, Streams)
538*f6dc9357SAndroid Build Coastguard Worker   {
539*f6dc9357SAndroid Build Coastguard Worker     CVolStream &s = Streams[i];
540*f6dc9357SAndroid Build Coastguard Worker     if (s.Stream)
541*f6dc9357SAndroid Build Coastguard Worker     {
542*f6dc9357SAndroid Build Coastguard Worker       if (!s.StreamSpec->SetMTime(&mTime))
543*f6dc9357SAndroid Build Coastguard Worker         res = false;
544*f6dc9357SAndroid Build Coastguard Worker     }
545*f6dc9357SAndroid Build Coastguard Worker     else
546*f6dc9357SAndroid Build Coastguard Worker     {
547*f6dc9357SAndroid Build Coastguard Worker       if (!SetDirTime(GetFilePath(i), NULL, NULL, &mTime))
548*f6dc9357SAndroid Build Coastguard Worker         res = false;
549*f6dc9357SAndroid Build Coastguard Worker     }
550*f6dc9357SAndroid Build Coastguard Worker   }
551*f6dc9357SAndroid Build Coastguard Worker   return res;
552*f6dc9357SAndroid Build Coastguard Worker }
553*f6dc9357SAndroid Build Coastguard Worker 
554*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CMultiOutStream::SetSize (UInt64 newSize))555*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CMultiOutStream::SetSize(UInt64 newSize))
556*f6dc9357SAndroid Build Coastguard Worker {
557*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
558*f6dc9357SAndroid Build Coastguard Worker   if ((Int64)newSize < 0)
559*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
560*f6dc9357SAndroid Build Coastguard Worker   if (newSize > _absLimit)
561*f6dc9357SAndroid Build Coastguard Worker   {
562*f6dc9357SAndroid Build Coastguard Worker     /* big seek value was sent to SetSize() or to Seek()+Write().
563*f6dc9357SAndroid Build Coastguard Worker        It can mean one of two situations:
564*f6dc9357SAndroid Build Coastguard Worker          1) some incorrect code called it with big seek value.
565*f6dc9357SAndroid Build Coastguard Worker          2) volume size was small, and we have too big number of volumes
566*f6dc9357SAndroid Build Coastguard Worker     */
567*f6dc9357SAndroid Build Coastguard Worker     /* in Windows SetEndOfFile() can return:
568*f6dc9357SAndroid Build Coastguard Worker        ERROR_NEGATIVE_SEEK:     for >= (1 << 63)
569*f6dc9357SAndroid Build Coastguard Worker        ERROR_INVALID_PARAMETER: for >  (16 TiB - 64 KiB)
570*f6dc9357SAndroid Build Coastguard Worker        ERROR_DISK_FULL:         for <= (16 TiB - 64 KiB)
571*f6dc9357SAndroid Build Coastguard Worker     */
572*f6dc9357SAndroid Build Coastguard Worker     // return E_FAIL;
573*f6dc9357SAndroid Build Coastguard Worker     // return E_OUTOFMEMORY;
574*f6dc9357SAndroid Build Coastguard Worker     return E_INVALIDARG;
575*f6dc9357SAndroid Build Coastguard Worker   }
576*f6dc9357SAndroid Build Coastguard Worker 
577*f6dc9357SAndroid Build Coastguard Worker   if (newSize > _length)
578*f6dc9357SAndroid Build Coastguard Worker   {
579*f6dc9357SAndroid Build Coastguard Worker     // we don't expect such case. So we just define global restriction */
580*f6dc9357SAndroid Build Coastguard Worker     _restrict_Global = newSize;
581*f6dc9357SAndroid Build Coastguard Worker   }
582*f6dc9357SAndroid Build Coastguard Worker   else if (newSize < _restrict_Global)
583*f6dc9357SAndroid Build Coastguard Worker     _restrict_Global = newSize;
584*f6dc9357SAndroid Build Coastguard Worker 
585*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n== CMultiOutStream::SetSize, size =%u \n", (unsigned)newSize))
586*f6dc9357SAndroid Build Coastguard Worker 
587*f6dc9357SAndroid Build Coastguard Worker   _length = newSize;
588*f6dc9357SAndroid Build Coastguard Worker   return Normalize_finalMode(false);
589*f6dc9357SAndroid Build Coastguard Worker 
590*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
591*f6dc9357SAndroid Build Coastguard Worker }
592*f6dc9357SAndroid Build Coastguard Worker 
593*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CMultiOutStream::Write (const void * data,UInt32 size,UInt32 * processedSize))594*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CMultiOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
595*f6dc9357SAndroid Build Coastguard Worker {
596*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
597*f6dc9357SAndroid Build Coastguard Worker   if (processedSize)
598*f6dc9357SAndroid Build Coastguard Worker     *processedSize = 0;
599*f6dc9357SAndroid Build Coastguard Worker   if (size == 0)
600*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
601*f6dc9357SAndroid Build Coastguard Worker 
602*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n -- CMultiOutStream::Write() : _absPos = %6u, size =%6u \n",
603*f6dc9357SAndroid Build Coastguard Worker       (unsigned)_absPos, (unsigned)size))
604*f6dc9357SAndroid Build Coastguard Worker 
605*f6dc9357SAndroid Build Coastguard Worker   if (_absPos > _length)
606*f6dc9357SAndroid Build Coastguard Worker   {
607*f6dc9357SAndroid Build Coastguard Worker     // it create data only up to _absPos.
608*f6dc9357SAndroid Build Coastguard Worker     // but we still can need additional new streams, if _absPos at range of volume
609*f6dc9357SAndroid Build Coastguard Worker     RINOK(SetSize(_absPos))
610*f6dc9357SAndroid Build Coastguard Worker   }
611*f6dc9357SAndroid Build Coastguard Worker 
612*f6dc9357SAndroid Build Coastguard Worker   while (size != 0)
613*f6dc9357SAndroid Build Coastguard Worker   {
614*f6dc9357SAndroid Build Coastguard Worker     UInt64 volSize;
615*f6dc9357SAndroid Build Coastguard Worker     {
616*f6dc9357SAndroid Build Coastguard Worker       if (_streamIndex < Sizes.Size() - 1)
617*f6dc9357SAndroid Build Coastguard Worker       {
618*f6dc9357SAndroid Build Coastguard Worker         volSize = Sizes[_streamIndex];
619*f6dc9357SAndroid Build Coastguard Worker         if (_offsetPos >= volSize)
620*f6dc9357SAndroid Build Coastguard Worker         {
621*f6dc9357SAndroid Build Coastguard Worker           _offsetPos -= volSize;
622*f6dc9357SAndroid Build Coastguard Worker           _streamIndex++;
623*f6dc9357SAndroid Build Coastguard Worker           continue;
624*f6dc9357SAndroid Build Coastguard Worker         }
625*f6dc9357SAndroid Build Coastguard Worker       }
626*f6dc9357SAndroid Build Coastguard Worker       else
627*f6dc9357SAndroid Build Coastguard Worker       {
628*f6dc9357SAndroid Build Coastguard Worker         volSize = Sizes[Sizes.Size() - 1];
629*f6dc9357SAndroid Build Coastguard Worker         if (_offsetPos >= volSize)
630*f6dc9357SAndroid Build Coastguard Worker         {
631*f6dc9357SAndroid Build Coastguard Worker           const UInt64 v = _offsetPos / volSize;
632*f6dc9357SAndroid Build Coastguard Worker           if (v >= ((UInt32)(Int32)-1) - _streamIndex)
633*f6dc9357SAndroid Build Coastguard Worker             return E_INVALIDARG;
634*f6dc9357SAndroid Build Coastguard Worker             // throw 202208;
635*f6dc9357SAndroid Build Coastguard Worker           _streamIndex += (unsigned)v;
636*f6dc9357SAndroid Build Coastguard Worker           _offsetPos -= (unsigned)v * volSize;
637*f6dc9357SAndroid Build Coastguard Worker         }
638*f6dc9357SAndroid Build Coastguard Worker         if (_streamIndex >= k_NumVols_MAX)
639*f6dc9357SAndroid Build Coastguard Worker           return E_INVALIDARG;
640*f6dc9357SAndroid Build Coastguard Worker       }
641*f6dc9357SAndroid Build Coastguard Worker     }
642*f6dc9357SAndroid Build Coastguard Worker 
643*f6dc9357SAndroid Build Coastguard Worker     // (_offsetPos < volSize) here
644*f6dc9357SAndroid Build Coastguard Worker 
645*f6dc9357SAndroid Build Coastguard Worker     /* we can need to create one or more streams here,
646*f6dc9357SAndroid Build Coastguard Worker        vol_size for some streams is allowed to be 0.
647*f6dc9357SAndroid Build Coastguard Worker        Also we close some new created streams, if they are non-restricted */
648*f6dc9357SAndroid Build Coastguard Worker     // file Size will be set later by calling Seek() with Write()
649*f6dc9357SAndroid Build Coastguard Worker 
650*f6dc9357SAndroid Build Coastguard Worker     /* the case (_absPos > _length) was processed above with SetSize(_absPos),
651*f6dc9357SAndroid Build Coastguard Worker        so here it's expected. that we can create optional zero-size streams and then _streamIndex */
652*f6dc9357SAndroid Build Coastguard Worker     RINOK(CreateStreams_If_Required(_streamIndex))
653*f6dc9357SAndroid Build Coastguard Worker 
654*f6dc9357SAndroid Build Coastguard Worker     CVolStream &s = Streams[_streamIndex];
655*f6dc9357SAndroid Build Coastguard Worker 
656*f6dc9357SAndroid Build Coastguard Worker     PRF(printf("\n%d, == Write : Pos = %u, RealSize = %u size =%u \n",
657*f6dc9357SAndroid Build Coastguard Worker         _streamIndex, (unsigned)s.Pos, (unsigned)s.RealSize, size))
658*f6dc9357SAndroid Build Coastguard Worker 
659*f6dc9357SAndroid Build Coastguard Worker     if (!s.Stream)
660*f6dc9357SAndroid Build Coastguard Worker     {
661*f6dc9357SAndroid Build Coastguard Worker       RINOK(ReOpenStream(_streamIndex))
662*f6dc9357SAndroid Build Coastguard Worker     }
663*f6dc9357SAndroid Build Coastguard Worker     if (_offsetPos != s.Pos)
664*f6dc9357SAndroid Build Coastguard Worker     {
665*f6dc9357SAndroid Build Coastguard Worker       RINOK(s.Stream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL))
666*f6dc9357SAndroid Build Coastguard Worker       s.Pos = _offsetPos;
667*f6dc9357SAndroid Build Coastguard Worker     }
668*f6dc9357SAndroid Build Coastguard Worker 
669*f6dc9357SAndroid Build Coastguard Worker     UInt32 curSize = size;
670*f6dc9357SAndroid Build Coastguard Worker     {
671*f6dc9357SAndroid Build Coastguard Worker       const UInt64 rem = volSize - _offsetPos;
672*f6dc9357SAndroid Build Coastguard Worker       if (curSize > rem)
673*f6dc9357SAndroid Build Coastguard Worker         curSize = (UInt32)rem;
674*f6dc9357SAndroid Build Coastguard Worker     }
675*f6dc9357SAndroid Build Coastguard Worker     // curSize != 0
676*f6dc9357SAndroid Build Coastguard Worker     UInt32 realProcessed = 0;
677*f6dc9357SAndroid Build Coastguard Worker 
678*f6dc9357SAndroid Build Coastguard Worker     HRESULT hres = s.Stream->Write(data, curSize, &realProcessed);
679*f6dc9357SAndroid Build Coastguard Worker 
680*f6dc9357SAndroid Build Coastguard Worker     data = (const void *)((const Byte *)data + realProcessed);
681*f6dc9357SAndroid Build Coastguard Worker     size -= realProcessed;
682*f6dc9357SAndroid Build Coastguard Worker     s.Pos += realProcessed;
683*f6dc9357SAndroid Build Coastguard Worker     _offsetPos += realProcessed;
684*f6dc9357SAndroid Build Coastguard Worker     _absPos += realProcessed;
685*f6dc9357SAndroid Build Coastguard Worker     if (_length < _absPos)
686*f6dc9357SAndroid Build Coastguard Worker       _length = _absPos;
687*f6dc9357SAndroid Build Coastguard Worker     if (s.RealSize < _offsetPos)
688*f6dc9357SAndroid Build Coastguard Worker       s.RealSize = _offsetPos;
689*f6dc9357SAndroid Build Coastguard Worker     if (processedSize)
690*f6dc9357SAndroid Build Coastguard Worker       *processedSize += realProcessed;
691*f6dc9357SAndroid Build Coastguard Worker 
692*f6dc9357SAndroid Build Coastguard Worker     if (s.Pos == volSize)
693*f6dc9357SAndroid Build Coastguard Worker     {
694*f6dc9357SAndroid Build Coastguard Worker       bool isRestricted;
695*f6dc9357SAndroid Build Coastguard Worker       if (volSize == 0)
696*f6dc9357SAndroid Build Coastguard Worker         isRestricted = IsRestricted_Empty(s);
697*f6dc9357SAndroid Build Coastguard Worker       else
698*f6dc9357SAndroid Build Coastguard Worker         isRestricted = IsRestricted(s);
699*f6dc9357SAndroid Build Coastguard Worker       if (!isRestricted)
700*f6dc9357SAndroid Build Coastguard Worker       {
701*f6dc9357SAndroid Build Coastguard Worker         const HRESULT res2 = CloseStream_and_FinalRename(_streamIndex);
702*f6dc9357SAndroid Build Coastguard Worker         if (hres == S_OK)
703*f6dc9357SAndroid Build Coastguard Worker           hres = res2;
704*f6dc9357SAndroid Build Coastguard Worker       }
705*f6dc9357SAndroid Build Coastguard Worker       _streamIndex++;
706*f6dc9357SAndroid Build Coastguard Worker       _offsetPos = 0;
707*f6dc9357SAndroid Build Coastguard Worker     }
708*f6dc9357SAndroid Build Coastguard Worker 
709*f6dc9357SAndroid Build Coastguard Worker     RINOK(hres)
710*f6dc9357SAndroid Build Coastguard Worker     if (realProcessed == 0 && curSize != 0)
711*f6dc9357SAndroid Build Coastguard Worker       return E_FAIL;
712*f6dc9357SAndroid Build Coastguard Worker     // break;
713*f6dc9357SAndroid Build Coastguard Worker   }
714*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
715*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
716*f6dc9357SAndroid Build Coastguard Worker }
717*f6dc9357SAndroid Build Coastguard Worker 
718*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CMultiOutStream::Seek (Int64 offset,UInt32 seekOrigin,UInt64 * newPosition))719*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CMultiOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
720*f6dc9357SAndroid Build Coastguard Worker {
721*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n-- CMultiOutStream::Seek seekOrigin=%u Seek =%u\n", seekOrigin, (unsigned)offset))
722*f6dc9357SAndroid Build Coastguard Worker 
723*f6dc9357SAndroid Build Coastguard Worker   switch (seekOrigin)
724*f6dc9357SAndroid Build Coastguard Worker   {
725*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_SET: break;
726*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_CUR: offset += _absPos; break;
727*f6dc9357SAndroid Build Coastguard Worker     case STREAM_SEEK_END: offset += _length; break;
728*f6dc9357SAndroid Build Coastguard Worker     default: return STG_E_INVALIDFUNCTION;
729*f6dc9357SAndroid Build Coastguard Worker   }
730*f6dc9357SAndroid Build Coastguard Worker   if (offset < 0)
731*f6dc9357SAndroid Build Coastguard Worker     return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
732*f6dc9357SAndroid Build Coastguard Worker   if ((UInt64)offset != _absPos)
733*f6dc9357SAndroid Build Coastguard Worker   {
734*f6dc9357SAndroid Build Coastguard Worker     _absPos = (UInt64)offset;
735*f6dc9357SAndroid Build Coastguard Worker     _offsetPos = (UInt64)offset;
736*f6dc9357SAndroid Build Coastguard Worker     _streamIndex = 0;
737*f6dc9357SAndroid Build Coastguard Worker   }
738*f6dc9357SAndroid Build Coastguard Worker   if (newPosition)
739*f6dc9357SAndroid Build Coastguard Worker     *newPosition = (UInt64)offset;
740*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
741*f6dc9357SAndroid Build Coastguard Worker }
742*f6dc9357SAndroid Build Coastguard Worker 
743*f6dc9357SAndroid Build Coastguard Worker 
744*f6dc9357SAndroid Build Coastguard Worker // result value will be saturated to (UInt32)(Int32)-1
745*f6dc9357SAndroid Build Coastguard Worker 
GetStreamIndex_for_Offset(UInt64 offset,UInt64 & relOffset) const746*f6dc9357SAndroid Build Coastguard Worker unsigned CMultiOutStream::GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const
747*f6dc9357SAndroid Build Coastguard Worker {
748*f6dc9357SAndroid Build Coastguard Worker   const unsigned last = Sizes.Size() - 1;
749*f6dc9357SAndroid Build Coastguard Worker   for (unsigned i = 0; i < last; i++)
750*f6dc9357SAndroid Build Coastguard Worker   {
751*f6dc9357SAndroid Build Coastguard Worker     const UInt64 size = Sizes[i];
752*f6dc9357SAndroid Build Coastguard Worker     if (offset < size)
753*f6dc9357SAndroid Build Coastguard Worker     {
754*f6dc9357SAndroid Build Coastguard Worker       relOffset = offset;
755*f6dc9357SAndroid Build Coastguard Worker       return i;
756*f6dc9357SAndroid Build Coastguard Worker     }
757*f6dc9357SAndroid Build Coastguard Worker     offset -= size;
758*f6dc9357SAndroid Build Coastguard Worker   }
759*f6dc9357SAndroid Build Coastguard Worker   const UInt64 size = Sizes[last];
760*f6dc9357SAndroid Build Coastguard Worker   const UInt64 v = offset / size;
761*f6dc9357SAndroid Build Coastguard Worker   if (v >= ((UInt32)(Int32)-1) - last)
762*f6dc9357SAndroid Build Coastguard Worker     return (unsigned)(int)-1; // saturation
763*f6dc9357SAndroid Build Coastguard Worker   relOffset = offset - (unsigned)v * size;
764*f6dc9357SAndroid Build Coastguard Worker   return last + (unsigned)(v);
765*f6dc9357SAndroid Build Coastguard Worker }
766*f6dc9357SAndroid Build Coastguard Worker 
767*f6dc9357SAndroid Build Coastguard Worker 
Z7_COM7F_IMF(CMultiOutStream::SetRestriction (UInt64 begin,UInt64 end))768*f6dc9357SAndroid Build Coastguard Worker Z7_COM7F_IMF(CMultiOutStream::SetRestriction(UInt64 begin, UInt64 end))
769*f6dc9357SAndroid Build Coastguard Worker {
770*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_BEGIN
771*f6dc9357SAndroid Build Coastguard Worker 
772*f6dc9357SAndroid Build Coastguard Worker   // begin = end = 0; // for debug
773*f6dc9357SAndroid Build Coastguard Worker 
774*f6dc9357SAndroid Build Coastguard Worker   PRF(printf("\n==================== CMultiOutStream::SetRestriction %u, %u\n", (unsigned)begin, (unsigned)end))
775*f6dc9357SAndroid Build Coastguard Worker   if (begin > end)
776*f6dc9357SAndroid Build Coastguard Worker   {
777*f6dc9357SAndroid Build Coastguard Worker     // these value are FAILED values.
778*f6dc9357SAndroid Build Coastguard Worker     return E_FAIL;
779*f6dc9357SAndroid Build Coastguard Worker     // return E_INVALIDARG;
780*f6dc9357SAndroid Build Coastguard Worker     /*
781*f6dc9357SAndroid Build Coastguard Worker     // or we can ignore error with 3 ways: no change, non-restricted, saturation:
782*f6dc9357SAndroid Build Coastguard Worker     end = begin;             // non-restricted
783*f6dc9357SAndroid Build Coastguard Worker     end = (UInt64)(Int64)-1; // saturation:
784*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
785*f6dc9357SAndroid Build Coastguard Worker     */
786*f6dc9357SAndroid Build Coastguard Worker   }
787*f6dc9357SAndroid Build Coastguard Worker   UInt64 b = _restrict_Begin;
788*f6dc9357SAndroid Build Coastguard Worker   UInt64 e = _restrict_End;
789*f6dc9357SAndroid Build Coastguard Worker   _restrict_Begin = begin;
790*f6dc9357SAndroid Build Coastguard Worker   _restrict_End = end;
791*f6dc9357SAndroid Build Coastguard Worker 
792*f6dc9357SAndroid Build Coastguard Worker   if (b == e)    // if there were no restriction before
793*f6dc9357SAndroid Build Coastguard Worker     return S_OK; // no work to derestrict now.
794*f6dc9357SAndroid Build Coastguard Worker 
795*f6dc9357SAndroid Build Coastguard Worker   /* [b, e) is previous restricted region. So all volumes that
796*f6dc9357SAndroid Build Coastguard Worker      intersect that [b, e) region are candidats for derestriction */
797*f6dc9357SAndroid Build Coastguard Worker 
798*f6dc9357SAndroid Build Coastguard Worker   if (begin != end) // if there is new non-empty restricted region
799*f6dc9357SAndroid Build Coastguard Worker   {
800*f6dc9357SAndroid Build Coastguard Worker     /* Now we will try to reduce or change (b) and (e) bounds
801*f6dc9357SAndroid Build Coastguard Worker        to reduce main loop that checks volumes for derestriction.
802*f6dc9357SAndroid Build Coastguard Worker        We still use one big derestriction region in main loop, although
803*f6dc9357SAndroid Build Coastguard Worker        in some cases we could have two smaller derestriction regions.
804*f6dc9357SAndroid Build Coastguard Worker        Also usually restriction region cannot move back from previous start position,
805*f6dc9357SAndroid Build Coastguard Worker        so (b <= begin) is expected here for normal cases */
806*f6dc9357SAndroid Build Coastguard Worker     if (b == begin) // if same low bounds
807*f6dc9357SAndroid Build Coastguard Worker       b = end;      // we need to derestrict only after the end of new restricted region
808*f6dc9357SAndroid Build Coastguard Worker     if (e == end)   // if same high bounds
809*f6dc9357SAndroid Build Coastguard Worker       e = begin;    // we need to derestrict only before the begin of new restricted region
810*f6dc9357SAndroid Build Coastguard Worker   }
811*f6dc9357SAndroid Build Coastguard Worker 
812*f6dc9357SAndroid Build Coastguard Worker   if (b > e) //  || b == (UInt64)(Int64)-1
813*f6dc9357SAndroid Build Coastguard Worker     return S_OK;
814*f6dc9357SAndroid Build Coastguard Worker 
815*f6dc9357SAndroid Build Coastguard Worker   /* Here we close finished volumes that are not restricted anymore.
816*f6dc9357SAndroid Build Coastguard Worker      We close (low number) volumes at first. */
817*f6dc9357SAndroid Build Coastguard Worker 
818*f6dc9357SAndroid Build Coastguard Worker   UInt64 offset;
819*f6dc9357SAndroid Build Coastguard Worker   unsigned index = GetStreamIndex_for_Offset(b, offset);
820*f6dc9357SAndroid Build Coastguard Worker 
821*f6dc9357SAndroid Build Coastguard Worker   for (; index < Streams.Size(); index++)
822*f6dc9357SAndroid Build Coastguard Worker   {
823*f6dc9357SAndroid Build Coastguard Worker     {
824*f6dc9357SAndroid Build Coastguard Worker       const CVolStream &s = Streams[index];
825*f6dc9357SAndroid Build Coastguard Worker       if (_length <= s.Start)
826*f6dc9357SAndroid Build Coastguard Worker         break; // we don't close streams after _length
827*f6dc9357SAndroid Build Coastguard Worker       // (_length > s.Start)
828*f6dc9357SAndroid Build Coastguard Worker       const UInt64 volSize = GetVolSize_for_Stream(index);
829*f6dc9357SAndroid Build Coastguard Worker       if (volSize == 0)
830*f6dc9357SAndroid Build Coastguard Worker       {
831*f6dc9357SAndroid Build Coastguard Worker         if (e < s.Start)
832*f6dc9357SAndroid Build Coastguard Worker           break;
833*f6dc9357SAndroid Build Coastguard Worker         // we don't close empty stream, if next byte [s.Start, s.Start] is restricted
834*f6dc9357SAndroid Build Coastguard Worker         if (IsRestricted_Empty(s))
835*f6dc9357SAndroid Build Coastguard Worker           continue;
836*f6dc9357SAndroid Build Coastguard Worker       }
837*f6dc9357SAndroid Build Coastguard Worker       else
838*f6dc9357SAndroid Build Coastguard Worker       {
839*f6dc9357SAndroid Build Coastguard Worker         if (e <= s.Start)
840*f6dc9357SAndroid Build Coastguard Worker           break;
841*f6dc9357SAndroid Build Coastguard Worker         // we don't close non full streams
842*f6dc9357SAndroid Build Coastguard Worker         if (_length - s.Start < volSize)
843*f6dc9357SAndroid Build Coastguard Worker           break;
844*f6dc9357SAndroid Build Coastguard Worker         // (volSize == s.RealSize) is expected here. So no need to check it
845*f6dc9357SAndroid Build Coastguard Worker         // if (volSize != s.RealSize) break;
846*f6dc9357SAndroid Build Coastguard Worker         if (IsRestricted(s))
847*f6dc9357SAndroid Build Coastguard Worker           continue;
848*f6dc9357SAndroid Build Coastguard Worker       }
849*f6dc9357SAndroid Build Coastguard Worker     }
850*f6dc9357SAndroid Build Coastguard Worker     RINOK(CloseStream_and_FinalRename(index))
851*f6dc9357SAndroid Build Coastguard Worker   }
852*f6dc9357SAndroid Build Coastguard Worker 
853*f6dc9357SAndroid Build Coastguard Worker   return S_OK;
854*f6dc9357SAndroid Build Coastguard Worker   COM_TRY_END
855*f6dc9357SAndroid Build Coastguard Worker }
856