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