1370b324cSopenharmony_ci// MultiOutStream.cpp 2370b324cSopenharmony_ci 3370b324cSopenharmony_ci#include "StdAfx.h" 4370b324cSopenharmony_ci 5370b324cSopenharmony_ci// #define DEBUG_VOLUMES 6370b324cSopenharmony_ci 7370b324cSopenharmony_ci#ifdef DEBUG_VOLUMES 8370b324cSopenharmony_ci#include <stdio.h> 9370b324cSopenharmony_ci #define PRF(x) x; 10370b324cSopenharmony_ci#else 11370b324cSopenharmony_ci #define PRF(x) 12370b324cSopenharmony_ci#endif 13370b324cSopenharmony_ci 14370b324cSopenharmony_ci#include "../../Common/ComTry.h" 15370b324cSopenharmony_ci 16370b324cSopenharmony_ci#include "../../Windows/FileDir.h" 17370b324cSopenharmony_ci#include "../../Windows/FileFind.h" 18370b324cSopenharmony_ci#include "../../Windows/System.h" 19370b324cSopenharmony_ci 20370b324cSopenharmony_ci#include "MultiOutStream.h" 21370b324cSopenharmony_ci 22370b324cSopenharmony_ciusing namespace NWindows; 23370b324cSopenharmony_ciusing namespace NFile; 24370b324cSopenharmony_ciusing namespace NDir; 25370b324cSopenharmony_ci 26370b324cSopenharmony_cistatic const unsigned k_NumVols_MAX = k_VectorSizeMax - 1; 27370b324cSopenharmony_ci // 2; // for debug 28370b324cSopenharmony_ci 29370b324cSopenharmony_ci/* 30370b324cSopenharmony_ci#define UPDATE_HRES(hres, x) \ 31370b324cSopenharmony_ci { const HRESULT res2 = (x); if (hres == SZ_OK) hres = res2; } 32370b324cSopenharmony_ci*/ 33370b324cSopenharmony_ci 34370b324cSopenharmony_ciHRESULT CMultiOutStream::Destruct() 35370b324cSopenharmony_ci{ 36370b324cSopenharmony_ci COM_TRY_BEGIN 37370b324cSopenharmony_ci HRESULT hres = S_OK; 38370b324cSopenharmony_ci HRESULT hres3 = S_OK; 39370b324cSopenharmony_ci 40370b324cSopenharmony_ci while (!Streams.IsEmpty()) 41370b324cSopenharmony_ci { 42370b324cSopenharmony_ci try 43370b324cSopenharmony_ci { 44370b324cSopenharmony_ci HRESULT hres2; 45370b324cSopenharmony_ci if (NeedDelete) 46370b324cSopenharmony_ci { 47370b324cSopenharmony_ci /* we could call OptReOpen_and_SetSize() to test that we try to delete correct file, 48370b324cSopenharmony_ci but we cannot guarantee that (RealSize) will be correct after Write() or another failures. 49370b324cSopenharmony_ci And we still want to delete files even for such cases. 50370b324cSopenharmony_ci So we don't check for OptReOpen_and_SetSize() here: */ 51370b324cSopenharmony_ci // if (OptReOpen_and_SetSize(Streams.Size() - 1, 0) == S_OK) 52370b324cSopenharmony_ci hres2 = CloseStream_and_DeleteFile(Streams.Size() - 1); 53370b324cSopenharmony_ci } 54370b324cSopenharmony_ci else 55370b324cSopenharmony_ci { 56370b324cSopenharmony_ci hres2 = CloseStream(Streams.Size() - 1); 57370b324cSopenharmony_ci } 58370b324cSopenharmony_ci if (hres == S_OK) 59370b324cSopenharmony_ci hres = hres2; 60370b324cSopenharmony_ci } 61370b324cSopenharmony_ci catch(...) 62370b324cSopenharmony_ci { 63370b324cSopenharmony_ci hres3 = E_OUTOFMEMORY; 64370b324cSopenharmony_ci } 65370b324cSopenharmony_ci 66370b324cSopenharmony_ci { 67370b324cSopenharmony_ci /* Stream was released in CloseStream_*() above already, and it was removed from linked list 68370b324cSopenharmony_ci it's some unexpected case, if Stream is still attached here. 69370b324cSopenharmony_ci So the following code is optional: */ 70370b324cSopenharmony_ci CVolStream &s = Streams.Back(); 71370b324cSopenharmony_ci if (s.Stream) 72370b324cSopenharmony_ci { 73370b324cSopenharmony_ci if (hres3 == S_OK) 74370b324cSopenharmony_ci hres3 = E_FAIL; 75370b324cSopenharmony_ci s.Stream.Detach(); 76370b324cSopenharmony_ci /* it will be not failure, even if we call RemoveFromLinkedList() 77370b324cSopenharmony_ci twice for same CVolStream in this Destruct() function */ 78370b324cSopenharmony_ci RemoveFromLinkedList(Streams.Size() - 1); 79370b324cSopenharmony_ci } 80370b324cSopenharmony_ci } 81370b324cSopenharmony_ci Streams.DeleteBack(); 82370b324cSopenharmony_ci // Delete_LastStream_Records(); 83370b324cSopenharmony_ci } 84370b324cSopenharmony_ci 85370b324cSopenharmony_ci if (hres == S_OK) 86370b324cSopenharmony_ci hres = hres3; 87370b324cSopenharmony_ci if (hres == S_OK && NumListItems != 0) 88370b324cSopenharmony_ci hres = E_FAIL; 89370b324cSopenharmony_ci return hres; 90370b324cSopenharmony_ci COM_TRY_END 91370b324cSopenharmony_ci} 92370b324cSopenharmony_ci 93370b324cSopenharmony_ci 94370b324cSopenharmony_ciCMultiOutStream::~CMultiOutStream() 95370b324cSopenharmony_ci{ 96370b324cSopenharmony_ci // we try to avoid exception in destructors 97370b324cSopenharmony_ci Destruct(); 98370b324cSopenharmony_ci} 99370b324cSopenharmony_ci 100370b324cSopenharmony_ci 101370b324cSopenharmony_civoid CMultiOutStream::Init(const CRecordVector<UInt64> &sizes) 102370b324cSopenharmony_ci{ 103370b324cSopenharmony_ci Streams.Clear(); 104370b324cSopenharmony_ci InitLinkedList(); 105370b324cSopenharmony_ci Sizes = sizes; 106370b324cSopenharmony_ci NeedDelete = true; 107370b324cSopenharmony_ci MTime_Defined = false; 108370b324cSopenharmony_ci FinalVol_WasReopen = false; 109370b324cSopenharmony_ci NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks(); 110370b324cSopenharmony_ci 111370b324cSopenharmony_ci _streamIndex = 0; 112370b324cSopenharmony_ci _offsetPos = 0; 113370b324cSopenharmony_ci _absPos = 0; 114370b324cSopenharmony_ci _length = 0; 115370b324cSopenharmony_ci _absLimit = (UInt64)(Int64)-1; 116370b324cSopenharmony_ci 117370b324cSopenharmony_ci _restrict_Begin = 0; 118370b324cSopenharmony_ci _restrict_End = (UInt64)(Int64)-1; 119370b324cSopenharmony_ci _restrict_Global = 0; 120370b324cSopenharmony_ci 121370b324cSopenharmony_ci UInt64 sum = 0; 122370b324cSopenharmony_ci unsigned i = 0; 123370b324cSopenharmony_ci for (i = 0; i < Sizes.Size(); i++) 124370b324cSopenharmony_ci { 125370b324cSopenharmony_ci if (i >= k_NumVols_MAX) 126370b324cSopenharmony_ci { 127370b324cSopenharmony_ci _absLimit = sum; 128370b324cSopenharmony_ci break; 129370b324cSopenharmony_ci } 130370b324cSopenharmony_ci const UInt64 size = Sizes[i]; 131370b324cSopenharmony_ci const UInt64 next = sum + size; 132370b324cSopenharmony_ci if (next < sum) 133370b324cSopenharmony_ci break; 134370b324cSopenharmony_ci sum = next; 135370b324cSopenharmony_ci } 136370b324cSopenharmony_ci 137370b324cSopenharmony_ci // if (Sizes.IsEmpty()) throw "no volume sizes"; 138370b324cSopenharmony_ci const UInt64 size = Sizes.Back(); 139370b324cSopenharmony_ci if (size == 0) 140370b324cSopenharmony_ci throw "zero size last volume"; 141370b324cSopenharmony_ci 142370b324cSopenharmony_ci if (i == Sizes.Size()) 143370b324cSopenharmony_ci if ((_absLimit - sum) / size >= (k_NumVols_MAX - i)) 144370b324cSopenharmony_ci _absLimit = sum + (k_NumVols_MAX - i) * size; 145370b324cSopenharmony_ci} 146370b324cSopenharmony_ci 147370b324cSopenharmony_ci 148370b324cSopenharmony_ci/* IsRestricted(): 149370b324cSopenharmony_ci we must call only if volume is full (s.RealSize==VolSize) or finished. 150370b324cSopenharmony_ci the function doesn't use VolSize and it uses s.RealSize instead. 151370b324cSopenharmony_ci it returns true : if stream is restricted, and we can't close that stream 152370b324cSopenharmony_ci it returns false : if there is no restriction, and we can close that stream 153370b324cSopenharmony_ci Note: (RealSize == 0) (empty volume) on restriction bounds are supposed as non-restricted 154370b324cSopenharmony_ci*/ 155370b324cSopenharmony_cibool CMultiOutStream::IsRestricted(const CVolStream &s) const 156370b324cSopenharmony_ci{ 157370b324cSopenharmony_ci if (s.Start < _restrict_Global) 158370b324cSopenharmony_ci return true; 159370b324cSopenharmony_ci if (_restrict_Begin == _restrict_End) 160370b324cSopenharmony_ci return false; 161370b324cSopenharmony_ci if (_restrict_Begin <= s.Start) 162370b324cSopenharmony_ci return _restrict_End > s.Start; 163370b324cSopenharmony_ci return _restrict_Begin < s.Start + s.RealSize; 164370b324cSopenharmony_ci} 165370b324cSopenharmony_ci 166370b324cSopenharmony_ci/* 167370b324cSopenharmony_ci// this function check also _length and volSize 168370b324cSopenharmony_cibool CMultiOutStream::IsRestricted_for_Close(unsigned index) const 169370b324cSopenharmony_ci{ 170370b324cSopenharmony_ci const CVolStream &s = Streams[index]; 171370b324cSopenharmony_ci if (_length <= s.Start) // we don't close streams after the end, because we still can write them later 172370b324cSopenharmony_ci return true; 173370b324cSopenharmony_ci // (_length > s.Start) 174370b324cSopenharmony_ci const UInt64 volSize = GetVolSize_for_Stream(index); 175370b324cSopenharmony_ci if (volSize == 0) 176370b324cSopenharmony_ci return IsRestricted_Empty(s); 177370b324cSopenharmony_ci if (_length - s.Start < volSize) 178370b324cSopenharmony_ci return true; 179370b324cSopenharmony_ci return IsRestricted(s); 180370b324cSopenharmony_ci} 181370b324cSopenharmony_ci*/ 182370b324cSopenharmony_ci 183370b324cSopenharmony_ciFString CMultiOutStream::GetFilePath(unsigned index) 184370b324cSopenharmony_ci{ 185370b324cSopenharmony_ci FString name; 186370b324cSopenharmony_ci name.Add_UInt32(index + 1); 187370b324cSopenharmony_ci while (name.Len() < 3) 188370b324cSopenharmony_ci name.InsertAtFront(FTEXT('0')); 189370b324cSopenharmony_ci name.Insert(0, Prefix); 190370b324cSopenharmony_ci return name; 191370b324cSopenharmony_ci} 192370b324cSopenharmony_ci 193370b324cSopenharmony_ci 194370b324cSopenharmony_ci// we close stream, but we still keep item in Streams[] vector 195370b324cSopenharmony_ciHRESULT CMultiOutStream::CloseStream(unsigned index) 196370b324cSopenharmony_ci{ 197370b324cSopenharmony_ci CVolStream &s = Streams[index]; 198370b324cSopenharmony_ci if (s.Stream) 199370b324cSopenharmony_ci { 200370b324cSopenharmony_ci RINOK(s.StreamSpec->Close()) 201370b324cSopenharmony_ci // the following two commands must be called together: 202370b324cSopenharmony_ci s.Stream.Release(); 203370b324cSopenharmony_ci RemoveFromLinkedList(index); 204370b324cSopenharmony_ci } 205370b324cSopenharmony_ci return S_OK; 206370b324cSopenharmony_ci} 207370b324cSopenharmony_ci 208370b324cSopenharmony_ci 209370b324cSopenharmony_ci// we close stream and delete file, but we still keep item in Streams[] vector 210370b324cSopenharmony_ciHRESULT CMultiOutStream::CloseStream_and_DeleteFile(unsigned index) 211370b324cSopenharmony_ci{ 212370b324cSopenharmony_ci PRF(printf("\n====== %u, CloseStream_AndDelete \n", index)); 213370b324cSopenharmony_ci RINOK(CloseStream(index)) 214370b324cSopenharmony_ci FString path = GetFilePath(index); 215370b324cSopenharmony_ci path += Streams[index].Postfix; 216370b324cSopenharmony_ci // we can checki that file exist 217370b324cSopenharmony_ci // if (NFind::DoesFileExist_Raw(path)) 218370b324cSopenharmony_ci if (!DeleteFileAlways(path)) 219370b324cSopenharmony_ci return GetLastError_noZero_HRESULT(); 220370b324cSopenharmony_ci return S_OK; 221370b324cSopenharmony_ci} 222370b324cSopenharmony_ci 223370b324cSopenharmony_ci 224370b324cSopenharmony_ciHRESULT CMultiOutStream::CloseStream_and_FinalRename(unsigned index) 225370b324cSopenharmony_ci{ 226370b324cSopenharmony_ci PRF(printf("\n====== %u, CloseStream_and_FinalRename \n", index)); 227370b324cSopenharmony_ci CVolStream &s = Streams[index]; 228370b324cSopenharmony_ci // HRESULT res = S_OK; 229370b324cSopenharmony_ci bool mtime_WasSet = false; 230370b324cSopenharmony_ci if (MTime_Defined && s.Stream) 231370b324cSopenharmony_ci { 232370b324cSopenharmony_ci if (s.StreamSpec->SetMTime(&MTime)) 233370b324cSopenharmony_ci mtime_WasSet = true; 234370b324cSopenharmony_ci // else res = GetLastError_noZero_HRESULT(); 235370b324cSopenharmony_ci } 236370b324cSopenharmony_ci 237370b324cSopenharmony_ci RINOK(CloseStream(index)) 238370b324cSopenharmony_ci if (s.Postfix.IsEmpty()) // if Postfix is empty, the path is already final 239370b324cSopenharmony_ci return S_OK; 240370b324cSopenharmony_ci const FString path = GetFilePath(index); 241370b324cSopenharmony_ci FString tempPath = path; 242370b324cSopenharmony_ci tempPath += s.Postfix; 243370b324cSopenharmony_ci 244370b324cSopenharmony_ci if (MTime_Defined && !mtime_WasSet) 245370b324cSopenharmony_ci { 246370b324cSopenharmony_ci if (!SetDirTime(tempPath, NULL, NULL, &MTime)) 247370b324cSopenharmony_ci { 248370b324cSopenharmony_ci // res = GetLastError_noZero_HRESULT(); 249370b324cSopenharmony_ci } 250370b324cSopenharmony_ci } 251370b324cSopenharmony_ci if (!MyMoveFile(tempPath, path)) 252370b324cSopenharmony_ci return GetLastError_noZero_HRESULT(); 253370b324cSopenharmony_ci /* we clear CVolStream::Postfix. So we will not use Temp path 254370b324cSopenharmony_ci anymore for this stream, and we will work only with final path */ 255370b324cSopenharmony_ci s.Postfix.Empty(); 256370b324cSopenharmony_ci // we can ignore set_mtime error or we can return it 257370b324cSopenharmony_ci return S_OK; 258370b324cSopenharmony_ci // return res; 259370b324cSopenharmony_ci} 260370b324cSopenharmony_ci 261370b324cSopenharmony_ci 262370b324cSopenharmony_ciHRESULT CMultiOutStream::PrepareToOpenNew() 263370b324cSopenharmony_ci{ 264370b324cSopenharmony_ci if (NumListItems < NumOpenFiles_AllowedMax) 265370b324cSopenharmony_ci return S_OK; 266370b324cSopenharmony_ci /* when we create zip archive: in most cases we need only starting 267370b324cSopenharmony_ci data of restricted region for rewriting zip's local header. 268370b324cSopenharmony_ci So here we close latest created volume (from Head), and we try to 269370b324cSopenharmony_ci keep oldest volumes that will be used for header rewriting later. */ 270370b324cSopenharmony_ci const int index = Head; 271370b324cSopenharmony_ci if (index == -1) 272370b324cSopenharmony_ci return E_FAIL; 273370b324cSopenharmony_ci PRF(printf("\n== %u, PrepareToOpenNew::CloseStream, NumListItems =%u \n", index, NumListItems)); 274370b324cSopenharmony_ci /* we don't expect non-restricted stream here in normal cases (if _restrict_Global was not changed). 275370b324cSopenharmony_ci if there was non-restricted stream, it should be closed before */ 276370b324cSopenharmony_ci // if (!IsRestricted_for_Close(index)) return CloseStream_and_FinalRename(index); 277370b324cSopenharmony_ci return CloseStream((unsigned)index); 278370b324cSopenharmony_ci} 279370b324cSopenharmony_ci 280370b324cSopenharmony_ci 281370b324cSopenharmony_ciHRESULT CMultiOutStream::CreateNewStream(UInt64 newSize) 282370b324cSopenharmony_ci{ 283370b324cSopenharmony_ci PRF(printf("\n== %u, CreateNewStream, size =%u \n", Streams.Size(), (unsigned)newSize)); 284370b324cSopenharmony_ci 285370b324cSopenharmony_ci if (Streams.Size() >= k_NumVols_MAX) 286370b324cSopenharmony_ci return E_INVALIDARG; // E_OUTOFMEMORY 287370b324cSopenharmony_ci 288370b324cSopenharmony_ci RINOK(PrepareToOpenNew()) 289370b324cSopenharmony_ci CVolStream s; 290370b324cSopenharmony_ci s.StreamSpec = new COutFileStream; 291370b324cSopenharmony_ci s.Stream = s.StreamSpec; 292370b324cSopenharmony_ci const FString path = GetFilePath(Streams.Size()); 293370b324cSopenharmony_ci 294370b324cSopenharmony_ci if (NFind::DoesFileExist_Raw(path)) 295370b324cSopenharmony_ci return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS); 296370b324cSopenharmony_ci if (!CreateTempFile2(path, false, s.Postfix, &s.StreamSpec->File)) 297370b324cSopenharmony_ci return GetLastError_noZero_HRESULT(); 298370b324cSopenharmony_ci 299370b324cSopenharmony_ci s.Start = GetGlobalOffset_for_NewStream(); 300370b324cSopenharmony_ci s.Pos = 0; 301370b324cSopenharmony_ci s.RealSize = 0; 302370b324cSopenharmony_ci 303370b324cSopenharmony_ci const unsigned index = Streams.Add(s); 304370b324cSopenharmony_ci InsertToLinkedList(index); 305370b324cSopenharmony_ci 306370b324cSopenharmony_ci if (newSize != 0) 307370b324cSopenharmony_ci return s.SetSize2(newSize); 308370b324cSopenharmony_ci return S_OK; 309370b324cSopenharmony_ci} 310370b324cSopenharmony_ci 311370b324cSopenharmony_ci 312370b324cSopenharmony_ciHRESULT CMultiOutStream::CreateStreams_If_Required(unsigned streamIndex) 313370b324cSopenharmony_ci{ 314370b324cSopenharmony_ci // UInt64 lastStreamSize = 0; 315370b324cSopenharmony_ci for (;;) 316370b324cSopenharmony_ci { 317370b324cSopenharmony_ci const unsigned numStreamsBefore = Streams.Size(); 318370b324cSopenharmony_ci if (streamIndex < numStreamsBefore) 319370b324cSopenharmony_ci return S_OK; 320370b324cSopenharmony_ci UInt64 newSize; 321370b324cSopenharmony_ci if (streamIndex == numStreamsBefore) 322370b324cSopenharmony_ci { 323370b324cSopenharmony_ci // it's final volume that will be used for real writing. 324370b324cSopenharmony_ci /* SetSize(_offsetPos) is not required, 325370b324cSopenharmony_ci because the file Size will be set later by calling Seek() with Write() */ 326370b324cSopenharmony_ci newSize = 0; // lastStreamSize; 327370b324cSopenharmony_ci } 328370b324cSopenharmony_ci else 329370b324cSopenharmony_ci { 330370b324cSopenharmony_ci // it's intermediate volume. So we need full volume size 331370b324cSopenharmony_ci newSize = GetVolSize_for_Stream(numStreamsBefore); 332370b324cSopenharmony_ci } 333370b324cSopenharmony_ci 334370b324cSopenharmony_ci RINOK(CreateNewStream(newSize)) 335370b324cSopenharmony_ci 336370b324cSopenharmony_ci // optional check 337370b324cSopenharmony_ci if (numStreamsBefore + 1 != Streams.Size()) return E_FAIL; 338370b324cSopenharmony_ci 339370b324cSopenharmony_ci if (streamIndex != numStreamsBefore) 340370b324cSopenharmony_ci { 341370b324cSopenharmony_ci // it's intermediate volume. So we can close it, if it's non-restricted 342370b324cSopenharmony_ci bool isRestricted; 343370b324cSopenharmony_ci { 344370b324cSopenharmony_ci const CVolStream &s = Streams[numStreamsBefore]; 345370b324cSopenharmony_ci if (newSize == 0) 346370b324cSopenharmony_ci isRestricted = IsRestricted_Empty(s); 347370b324cSopenharmony_ci else 348370b324cSopenharmony_ci isRestricted = IsRestricted(s); 349370b324cSopenharmony_ci } 350370b324cSopenharmony_ci if (!isRestricted) 351370b324cSopenharmony_ci { 352370b324cSopenharmony_ci RINOK(CloseStream_and_FinalRename(numStreamsBefore)) 353370b324cSopenharmony_ci } 354370b324cSopenharmony_ci } 355370b324cSopenharmony_ci } 356370b324cSopenharmony_ci} 357370b324cSopenharmony_ci 358370b324cSopenharmony_ci 359370b324cSopenharmony_ciHRESULT CMultiOutStream::ReOpenStream(unsigned streamIndex) 360370b324cSopenharmony_ci{ 361370b324cSopenharmony_ci PRF(printf("\n====== %u, ReOpenStream \n", streamIndex)); 362370b324cSopenharmony_ci RINOK(PrepareToOpenNew()) 363370b324cSopenharmony_ci CVolStream &s = Streams[streamIndex]; 364370b324cSopenharmony_ci 365370b324cSopenharmony_ci FString path = GetFilePath(streamIndex); 366370b324cSopenharmony_ci path += s.Postfix; 367370b324cSopenharmony_ci 368370b324cSopenharmony_ci s.StreamSpec = new COutFileStream; 369370b324cSopenharmony_ci s.Stream = s.StreamSpec; 370370b324cSopenharmony_ci s.Pos = 0; 371370b324cSopenharmony_ci 372370b324cSopenharmony_ci HRESULT hres; 373370b324cSopenharmony_ci if (s.StreamSpec->Open(path, OPEN_EXISTING)) 374370b324cSopenharmony_ci { 375370b324cSopenharmony_ci if (s.Postfix.IsEmpty()) 376370b324cSopenharmony_ci { 377370b324cSopenharmony_ci /* it's unexpected case that we open finished volume. 378370b324cSopenharmony_ci It can mean that the code for restriction is incorrect */ 379370b324cSopenharmony_ci FinalVol_WasReopen = true; 380370b324cSopenharmony_ci } 381370b324cSopenharmony_ci UInt64 realSize = 0; 382370b324cSopenharmony_ci hres = s.StreamSpec->GetSize(&realSize); 383370b324cSopenharmony_ci if (hres == S_OK) 384370b324cSopenharmony_ci { 385370b324cSopenharmony_ci if (realSize == s.RealSize) 386370b324cSopenharmony_ci { 387370b324cSopenharmony_ci InsertToLinkedList(streamIndex); 388370b324cSopenharmony_ci return S_OK; 389370b324cSopenharmony_ci } 390370b324cSopenharmony_ci // file size was changed between Close() and ReOpen() 391370b324cSopenharmony_ci // we must release Stream to be consistent with linked list 392370b324cSopenharmony_ci hres = E_FAIL; 393370b324cSopenharmony_ci } 394370b324cSopenharmony_ci } 395370b324cSopenharmony_ci else 396370b324cSopenharmony_ci hres = GetLastError_noZero_HRESULT(); 397370b324cSopenharmony_ci s.Stream.Release(); 398370b324cSopenharmony_ci s.StreamSpec = NULL; 399370b324cSopenharmony_ci return hres; 400370b324cSopenharmony_ci} 401370b324cSopenharmony_ci 402370b324cSopenharmony_ci 403370b324cSopenharmony_ci/* Sets size of stream, if new size is not equal to old size (RealSize). 404370b324cSopenharmony_ci If stream was closed and size change is required, it reopens the stream. */ 405370b324cSopenharmony_ci 406370b324cSopenharmony_ciHRESULT CMultiOutStream::OptReOpen_and_SetSize(unsigned index, UInt64 size) 407370b324cSopenharmony_ci{ 408370b324cSopenharmony_ci CVolStream &s = Streams[index]; 409370b324cSopenharmony_ci if (size == s.RealSize) 410370b324cSopenharmony_ci return S_OK; 411370b324cSopenharmony_ci if (!s.Stream) 412370b324cSopenharmony_ci { 413370b324cSopenharmony_ci RINOK(ReOpenStream(index)) 414370b324cSopenharmony_ci } 415370b324cSopenharmony_ci PRF(printf("\n== %u, OptReOpen_and_SetSize, size =%u RealSize = %u\n", index, (unsigned)size, (unsigned)s.RealSize)); 416370b324cSopenharmony_ci // comment it to debug tail after data 417370b324cSopenharmony_ci return s.SetSize2(size); 418370b324cSopenharmony_ci} 419370b324cSopenharmony_ci 420370b324cSopenharmony_ci 421370b324cSopenharmony_ci/* 422370b324cSopenharmony_cicall Normalize_finalMode(false), if _length was changed. 423370b324cSopenharmony_ci for all streams starting after _length: 424370b324cSopenharmony_ci - it sets zero size 425370b324cSopenharmony_ci - it still keeps file open 426370b324cSopenharmony_ci Note: after _length reducing with CMultiOutStream::SetSize() we can 427370b324cSopenharmony_ci have very big number of empty streams at the end of Streams[] list. 428370b324cSopenharmony_ci And Normalize_finalMode() will runs all these empty streams of Streams[] vector. 429370b324cSopenharmony_ci So it can be ineffective, if we call Normalize_finalMode() many 430370b324cSopenharmony_ci times after big reducing of (_length). 431370b324cSopenharmony_ci 432370b324cSopenharmony_cicall Normalize_finalMode(true) to set final presentations of all streams 433370b324cSopenharmony_ci for all streams starting after _length: 434370b324cSopenharmony_ci - it sets zero size 435370b324cSopenharmony_ci - it removes file 436370b324cSopenharmony_ci - it removes CVolStream object from Streams[] vector 437370b324cSopenharmony_ci 438370b324cSopenharmony_ciNote: we don't remove zero sized first volume, if (_length == 0) 439370b324cSopenharmony_ci*/ 440370b324cSopenharmony_ci 441370b324cSopenharmony_ciHRESULT CMultiOutStream::Normalize_finalMode(bool finalMode) 442370b324cSopenharmony_ci{ 443370b324cSopenharmony_ci PRF(printf("\n== Normalize_finalMode: _length =%d \n", (unsigned)_length)); 444370b324cSopenharmony_ci 445370b324cSopenharmony_ci unsigned i = Streams.Size(); 446370b324cSopenharmony_ci 447370b324cSopenharmony_ci UInt64 offset = 0; 448370b324cSopenharmony_ci 449370b324cSopenharmony_ci /* At first we normalize (reduce or increase) the sizes of all existing 450370b324cSopenharmony_ci streams in Streams[] that can be affected by changed _length. 451370b324cSopenharmony_ci And we remove tailing zero-size streams, if (finalMode == true) */ 452370b324cSopenharmony_ci while (i != 0) 453370b324cSopenharmony_ci { 454370b324cSopenharmony_ci offset = Streams[--i].Start; // it's last item in Streams[] 455370b324cSopenharmony_ci // we don't want to remove first volume 456370b324cSopenharmony_ci if (offset < _length || i == 0) 457370b324cSopenharmony_ci { 458370b324cSopenharmony_ci const UInt64 volSize = GetVolSize_for_Stream(i); 459370b324cSopenharmony_ci UInt64 size = _length - offset; // (size != 0) here 460370b324cSopenharmony_ci if (size > volSize) 461370b324cSopenharmony_ci size = volSize; 462370b324cSopenharmony_ci RINOK(OptReOpen_and_SetSize(i, size)) 463370b324cSopenharmony_ci if (_length - offset <= volSize) 464370b324cSopenharmony_ci return S_OK; 465370b324cSopenharmony_ci // _length - offset > volSize 466370b324cSopenharmony_ci offset += volSize; 467370b324cSopenharmony_ci // _length > offset 468370b324cSopenharmony_ci break; 469370b324cSopenharmony_ci // UPDATE_HRES(res, OptReOpen_and_SetSize(i, size)); 470370b324cSopenharmony_ci } 471370b324cSopenharmony_ci 472370b324cSopenharmony_ci /* we Set Size of stream to zero even for (finalMode==true), although 473370b324cSopenharmony_ci that stream will be deleted in next commands */ 474370b324cSopenharmony_ci // UPDATE_HRES(res, OptReOpen_and_SetSize(i, 0)); 475370b324cSopenharmony_ci RINOK(OptReOpen_and_SetSize(i, 0)) 476370b324cSopenharmony_ci if (finalMode) 477370b324cSopenharmony_ci { 478370b324cSopenharmony_ci RINOK(CloseStream_and_DeleteFile(i)) 479370b324cSopenharmony_ci /* CVolStream::Stream was released above already, and it was 480370b324cSopenharmony_ci removed from linked list. So we don't need to update linked list 481370b324cSopenharmony_ci structure, when we delete last item in Streams[] */ 482370b324cSopenharmony_ci Streams.DeleteBack(); 483370b324cSopenharmony_ci // Delete_LastStream_Records(); 484370b324cSopenharmony_ci } 485370b324cSopenharmony_ci } 486370b324cSopenharmony_ci 487370b324cSopenharmony_ci /* now we create new zero-filled streams to cover all data up to _length */ 488370b324cSopenharmony_ci 489370b324cSopenharmony_ci if (_length == 0) 490370b324cSopenharmony_ci return S_OK; 491370b324cSopenharmony_ci 492370b324cSopenharmony_ci // (offset) is start offset of next stream after existing Streams[] 493370b324cSopenharmony_ci 494370b324cSopenharmony_ci for (;;) 495370b324cSopenharmony_ci { 496370b324cSopenharmony_ci // _length > offset 497370b324cSopenharmony_ci const UInt64 volSize = GetVolSize_for_Stream(Streams.Size()); 498370b324cSopenharmony_ci UInt64 size = _length - offset; // (size != 0) here 499370b324cSopenharmony_ci if (size > volSize) 500370b324cSopenharmony_ci size = volSize; 501370b324cSopenharmony_ci RINOK(CreateNewStream(size)) 502370b324cSopenharmony_ci if (_length - offset <= volSize) 503370b324cSopenharmony_ci return S_OK; 504370b324cSopenharmony_ci // _length - offset > volSize) 505370b324cSopenharmony_ci offset += volSize; 506370b324cSopenharmony_ci // _length > offset 507370b324cSopenharmony_ci } 508370b324cSopenharmony_ci} 509370b324cSopenharmony_ci 510370b324cSopenharmony_ci 511370b324cSopenharmony_ciHRESULT CMultiOutStream::FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes) 512370b324cSopenharmony_ci{ 513370b324cSopenharmony_ci // at first we remove unused zero-sized streams after _length 514370b324cSopenharmony_ci HRESULT res = Normalize_finalMode(true); 515370b324cSopenharmony_ci numTotalVolumesRes = Streams.Size(); 516370b324cSopenharmony_ci FOR_VECTOR (i, Streams) 517370b324cSopenharmony_ci { 518370b324cSopenharmony_ci const HRESULT res2 = CloseStream_and_FinalRename(i); 519370b324cSopenharmony_ci if (res == S_OK) 520370b324cSopenharmony_ci res = res2; 521370b324cSopenharmony_ci } 522370b324cSopenharmony_ci if (NumListItems != 0 && res == S_OK) 523370b324cSopenharmony_ci res = E_FAIL; 524370b324cSopenharmony_ci return res; 525370b324cSopenharmony_ci} 526370b324cSopenharmony_ci 527370b324cSopenharmony_ci 528370b324cSopenharmony_cibool CMultiOutStream::SetMTime_Final(const CFiTime &mTime) 529370b324cSopenharmony_ci{ 530370b324cSopenharmony_ci // we will set mtime only if new value differs from previous 531370b324cSopenharmony_ci if (!FinalVol_WasReopen && MTime_Defined && Compare_FiTime(&MTime, &mTime) == 0) 532370b324cSopenharmony_ci return true; 533370b324cSopenharmony_ci bool res = true; 534370b324cSopenharmony_ci FOR_VECTOR (i, Streams) 535370b324cSopenharmony_ci { 536370b324cSopenharmony_ci CVolStream &s = Streams[i]; 537370b324cSopenharmony_ci if (s.Stream) 538370b324cSopenharmony_ci { 539370b324cSopenharmony_ci if (!s.StreamSpec->SetMTime(&mTime)) 540370b324cSopenharmony_ci res = false; 541370b324cSopenharmony_ci } 542370b324cSopenharmony_ci else 543370b324cSopenharmony_ci { 544370b324cSopenharmony_ci if (!SetDirTime(GetFilePath(i), NULL, NULL, &mTime)) 545370b324cSopenharmony_ci res = false; 546370b324cSopenharmony_ci } 547370b324cSopenharmony_ci } 548370b324cSopenharmony_ci return res; 549370b324cSopenharmony_ci} 550370b324cSopenharmony_ci 551370b324cSopenharmony_ci 552370b324cSopenharmony_ciZ7_COM7F_IMF(CMultiOutStream::SetSize(UInt64 newSize)) 553370b324cSopenharmony_ci{ 554370b324cSopenharmony_ci COM_TRY_BEGIN 555370b324cSopenharmony_ci if ((Int64)newSize < 0) 556370b324cSopenharmony_ci return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 557370b324cSopenharmony_ci if (newSize > _absLimit) 558370b324cSopenharmony_ci { 559370b324cSopenharmony_ci /* big seek value was sent to SetSize() or to Seek()+Write(). 560370b324cSopenharmony_ci It can mean one of two situations: 561370b324cSopenharmony_ci 1) some incorrect code called it with big seek value. 562370b324cSopenharmony_ci 2) volume size was small, and we have too big number of volumes 563370b324cSopenharmony_ci */ 564370b324cSopenharmony_ci /* in Windows SetEndOfFile() can return: 565370b324cSopenharmony_ci ERROR_NEGATIVE_SEEK: for >= (1 << 63) 566370b324cSopenharmony_ci ERROR_INVALID_PARAMETER: for > (16 TiB - 64 KiB) 567370b324cSopenharmony_ci ERROR_DISK_FULL: for <= (16 TiB - 64 KiB) 568370b324cSopenharmony_ci */ 569370b324cSopenharmony_ci // return E_FAIL; 570370b324cSopenharmony_ci // return E_OUTOFMEMORY; 571370b324cSopenharmony_ci return E_INVALIDARG; 572370b324cSopenharmony_ci } 573370b324cSopenharmony_ci 574370b324cSopenharmony_ci if (newSize > _length) 575370b324cSopenharmony_ci { 576370b324cSopenharmony_ci // we don't expect such case. So we just define global restriction */ 577370b324cSopenharmony_ci _restrict_Global = newSize; 578370b324cSopenharmony_ci } 579370b324cSopenharmony_ci else if (newSize < _restrict_Global) 580370b324cSopenharmony_ci _restrict_Global = newSize; 581370b324cSopenharmony_ci 582370b324cSopenharmony_ci PRF(printf("\n== SetSize, size =%u \n", (unsigned)newSize)); 583370b324cSopenharmony_ci 584370b324cSopenharmony_ci _length = newSize; 585370b324cSopenharmony_ci return Normalize_finalMode(false); 586370b324cSopenharmony_ci 587370b324cSopenharmony_ci COM_TRY_END 588370b324cSopenharmony_ci} 589370b324cSopenharmony_ci 590370b324cSopenharmony_ci 591370b324cSopenharmony_ciZ7_COM7F_IMF(CMultiOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)) 592370b324cSopenharmony_ci{ 593370b324cSopenharmony_ci COM_TRY_BEGIN 594370b324cSopenharmony_ci if (processedSize) 595370b324cSopenharmony_ci *processedSize = 0; 596370b324cSopenharmony_ci if (size == 0) 597370b324cSopenharmony_ci return S_OK; 598370b324cSopenharmony_ci 599370b324cSopenharmony_ci if (_absPos > _length) 600370b324cSopenharmony_ci { 601370b324cSopenharmony_ci // it create data only up to _absPos. 602370b324cSopenharmony_ci // but we still can need additional new streams, if _absPos at range of volume 603370b324cSopenharmony_ci RINOK(SetSize(_absPos)) 604370b324cSopenharmony_ci } 605370b324cSopenharmony_ci 606370b324cSopenharmony_ci while (size != 0) 607370b324cSopenharmony_ci { 608370b324cSopenharmony_ci UInt64 volSize; 609370b324cSopenharmony_ci { 610370b324cSopenharmony_ci if (_streamIndex < Sizes.Size() - 1) 611370b324cSopenharmony_ci { 612370b324cSopenharmony_ci volSize = Sizes[_streamIndex]; 613370b324cSopenharmony_ci if (_offsetPos >= volSize) 614370b324cSopenharmony_ci { 615370b324cSopenharmony_ci _offsetPos -= volSize; 616370b324cSopenharmony_ci _streamIndex++; 617370b324cSopenharmony_ci continue; 618370b324cSopenharmony_ci } 619370b324cSopenharmony_ci } 620370b324cSopenharmony_ci else 621370b324cSopenharmony_ci { 622370b324cSopenharmony_ci volSize = Sizes[Sizes.Size() - 1]; 623370b324cSopenharmony_ci if (_offsetPos >= volSize) 624370b324cSopenharmony_ci { 625370b324cSopenharmony_ci const UInt64 v = _offsetPos / volSize; 626370b324cSopenharmony_ci if (v >= ((UInt32)(Int32)-1) - _streamIndex) 627370b324cSopenharmony_ci return E_INVALIDARG; 628370b324cSopenharmony_ci // throw 202208; 629370b324cSopenharmony_ci _streamIndex += (unsigned)v; 630370b324cSopenharmony_ci _offsetPos -= (unsigned)v * volSize; 631370b324cSopenharmony_ci } 632370b324cSopenharmony_ci if (_streamIndex >= k_NumVols_MAX) 633370b324cSopenharmony_ci return E_INVALIDARG; 634370b324cSopenharmony_ci } 635370b324cSopenharmony_ci } 636370b324cSopenharmony_ci 637370b324cSopenharmony_ci // (_offsetPos < volSize) here 638370b324cSopenharmony_ci 639370b324cSopenharmony_ci /* we can need to create one or more streams here, 640370b324cSopenharmony_ci vol_size for some streams is allowed to be 0. 641370b324cSopenharmony_ci Also we close some new created streams, if they are non-restricted */ 642370b324cSopenharmony_ci // file Size will be set later by calling Seek() with Write() 643370b324cSopenharmony_ci 644370b324cSopenharmony_ci /* the case (_absPos > _length) was processed above with SetSize(_absPos), 645370b324cSopenharmony_ci so here it's expected. that we can create optional zero-size streams and then _streamIndex */ 646370b324cSopenharmony_ci RINOK(CreateStreams_If_Required(_streamIndex)) 647370b324cSopenharmony_ci 648370b324cSopenharmony_ci CVolStream &s = Streams[_streamIndex]; 649370b324cSopenharmony_ci 650370b324cSopenharmony_ci PRF(printf("\n%d, == Write : Pos = %u, RealSize = %u size =%u \n", 651370b324cSopenharmony_ci _streamIndex, (unsigned)s.Pos, (unsigned)s.RealSize, size)); 652370b324cSopenharmony_ci 653370b324cSopenharmony_ci if (!s.Stream) 654370b324cSopenharmony_ci { 655370b324cSopenharmony_ci RINOK(ReOpenStream(_streamIndex)) 656370b324cSopenharmony_ci } 657370b324cSopenharmony_ci if (_offsetPos != s.Pos) 658370b324cSopenharmony_ci { 659370b324cSopenharmony_ci RINOK(s.Stream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL)) 660370b324cSopenharmony_ci s.Pos = _offsetPos; 661370b324cSopenharmony_ci } 662370b324cSopenharmony_ci 663370b324cSopenharmony_ci UInt32 curSize = size; 664370b324cSopenharmony_ci { 665370b324cSopenharmony_ci const UInt64 rem = volSize - _offsetPos; 666370b324cSopenharmony_ci if (curSize > rem) 667370b324cSopenharmony_ci curSize = (UInt32)rem; 668370b324cSopenharmony_ci } 669370b324cSopenharmony_ci // curSize != 0 670370b324cSopenharmony_ci UInt32 realProcessed = 0; 671370b324cSopenharmony_ci 672370b324cSopenharmony_ci HRESULT hres = s.Stream->Write(data, curSize, &realProcessed); 673370b324cSopenharmony_ci 674370b324cSopenharmony_ci data = (const void *)((const Byte *)data + realProcessed); 675370b324cSopenharmony_ci size -= realProcessed; 676370b324cSopenharmony_ci s.Pos += realProcessed; 677370b324cSopenharmony_ci _offsetPos += realProcessed; 678370b324cSopenharmony_ci _absPos += realProcessed; 679370b324cSopenharmony_ci if (_length < _absPos) 680370b324cSopenharmony_ci _length = _absPos; 681370b324cSopenharmony_ci if (s.RealSize < _offsetPos) 682370b324cSopenharmony_ci s.RealSize = _offsetPos; 683370b324cSopenharmony_ci if (processedSize) 684370b324cSopenharmony_ci *processedSize += realProcessed; 685370b324cSopenharmony_ci 686370b324cSopenharmony_ci if (s.Pos == volSize) 687370b324cSopenharmony_ci { 688370b324cSopenharmony_ci bool isRestricted; 689370b324cSopenharmony_ci if (volSize == 0) 690370b324cSopenharmony_ci isRestricted = IsRestricted_Empty(s); 691370b324cSopenharmony_ci else 692370b324cSopenharmony_ci isRestricted = IsRestricted(s); 693370b324cSopenharmony_ci if (!isRestricted) 694370b324cSopenharmony_ci { 695370b324cSopenharmony_ci const HRESULT res2 = CloseStream_and_FinalRename(_streamIndex); 696370b324cSopenharmony_ci if (hres == S_OK) 697370b324cSopenharmony_ci hres = res2; 698370b324cSopenharmony_ci } 699370b324cSopenharmony_ci _streamIndex++; 700370b324cSopenharmony_ci _offsetPos = 0; 701370b324cSopenharmony_ci } 702370b324cSopenharmony_ci 703370b324cSopenharmony_ci RINOK(hres) 704370b324cSopenharmony_ci if (realProcessed == 0 && curSize != 0) 705370b324cSopenharmony_ci return E_FAIL; 706370b324cSopenharmony_ci // break; 707370b324cSopenharmony_ci } 708370b324cSopenharmony_ci return S_OK; 709370b324cSopenharmony_ci COM_TRY_END 710370b324cSopenharmony_ci} 711370b324cSopenharmony_ci 712370b324cSopenharmony_ci 713370b324cSopenharmony_ciZ7_COM7F_IMF(CMultiOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) 714370b324cSopenharmony_ci{ 715370b324cSopenharmony_ci PRF(printf("\n-- Seek seekOrigin=%u Seek =%u\n", seekOrigin, (unsigned)offset)); 716370b324cSopenharmony_ci 717370b324cSopenharmony_ci switch (seekOrigin) 718370b324cSopenharmony_ci { 719370b324cSopenharmony_ci case STREAM_SEEK_SET: break; 720370b324cSopenharmony_ci case STREAM_SEEK_CUR: offset += _absPos; break; 721370b324cSopenharmony_ci case STREAM_SEEK_END: offset += _length; break; 722370b324cSopenharmony_ci default: return STG_E_INVALIDFUNCTION; 723370b324cSopenharmony_ci } 724370b324cSopenharmony_ci if (offset < 0) 725370b324cSopenharmony_ci return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; 726370b324cSopenharmony_ci if ((UInt64)offset != _absPos) 727370b324cSopenharmony_ci { 728370b324cSopenharmony_ci _absPos = (UInt64)offset; 729370b324cSopenharmony_ci _offsetPos = (UInt64)offset; 730370b324cSopenharmony_ci _streamIndex = 0; 731370b324cSopenharmony_ci } 732370b324cSopenharmony_ci if (newPosition) 733370b324cSopenharmony_ci *newPosition = (UInt64)offset; 734370b324cSopenharmony_ci return S_OK; 735370b324cSopenharmony_ci} 736370b324cSopenharmony_ci 737370b324cSopenharmony_ci 738370b324cSopenharmony_ci// result value will be saturated to (UInt32)(Int32)-1 739370b324cSopenharmony_ci 740370b324cSopenharmony_ciunsigned CMultiOutStream::GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const 741370b324cSopenharmony_ci{ 742370b324cSopenharmony_ci const unsigned last = Sizes.Size() - 1; 743370b324cSopenharmony_ci for (unsigned i = 0; i < last; i++) 744370b324cSopenharmony_ci { 745370b324cSopenharmony_ci const UInt64 size = Sizes[i]; 746370b324cSopenharmony_ci if (offset < size) 747370b324cSopenharmony_ci { 748370b324cSopenharmony_ci relOffset = offset; 749370b324cSopenharmony_ci return i; 750370b324cSopenharmony_ci } 751370b324cSopenharmony_ci offset -= size; 752370b324cSopenharmony_ci } 753370b324cSopenharmony_ci const UInt64 size = Sizes[last]; 754370b324cSopenharmony_ci const UInt64 v = offset / size; 755370b324cSopenharmony_ci if (v >= ((UInt32)(Int32)-1) - last) 756370b324cSopenharmony_ci return (UInt32)(Int32)-1; // saturation 757370b324cSopenharmony_ci relOffset = offset - (unsigned)v * size; 758370b324cSopenharmony_ci return last + (unsigned)(v); 759370b324cSopenharmony_ci} 760370b324cSopenharmony_ci 761370b324cSopenharmony_ci 762370b324cSopenharmony_ciZ7_COM7F_IMF(CMultiOutStream::SetRestriction(UInt64 begin, UInt64 end)) 763370b324cSopenharmony_ci{ 764370b324cSopenharmony_ci COM_TRY_BEGIN 765370b324cSopenharmony_ci 766370b324cSopenharmony_ci // begin = end = 0; // for debug 767370b324cSopenharmony_ci 768370b324cSopenharmony_ci PRF(printf("\n==================== CMultiOutStream::SetRestriction %u, %u\n", (unsigned)begin, (unsigned)end)); 769370b324cSopenharmony_ci if (begin > end) 770370b324cSopenharmony_ci { 771370b324cSopenharmony_ci // these value are FAILED values. 772370b324cSopenharmony_ci return E_FAIL; 773370b324cSopenharmony_ci // return E_INVALIDARG; 774370b324cSopenharmony_ci /* 775370b324cSopenharmony_ci // or we can ignore error with 3 ways: no change, non-restricted, saturation: 776370b324cSopenharmony_ci end = begin; // non-restricted 777370b324cSopenharmony_ci end = (UInt64)(Int64)-1; // saturation: 778370b324cSopenharmony_ci return S_OK; 779370b324cSopenharmony_ci */ 780370b324cSopenharmony_ci } 781370b324cSopenharmony_ci UInt64 b = _restrict_Begin; 782370b324cSopenharmony_ci UInt64 e = _restrict_End; 783370b324cSopenharmony_ci _restrict_Begin = begin; 784370b324cSopenharmony_ci _restrict_End = end; 785370b324cSopenharmony_ci 786370b324cSopenharmony_ci if (b == e) // if there were no restriction before 787370b324cSopenharmony_ci return S_OK; // no work to derestrict now. 788370b324cSopenharmony_ci 789370b324cSopenharmony_ci /* [b, e) is previous restricted region. So all volumes that 790370b324cSopenharmony_ci intersect that [b, e) region are candidats for derestriction */ 791370b324cSopenharmony_ci 792370b324cSopenharmony_ci if (begin != end) // if there is new non-empty restricted region 793370b324cSopenharmony_ci { 794370b324cSopenharmony_ci /* Now we will try to reduce or change (b) and (e) bounds 795370b324cSopenharmony_ci to reduce main loop that checks volumes for derestriction. 796370b324cSopenharmony_ci We still use one big derestriction region in main loop, although 797370b324cSopenharmony_ci in some cases we could have two smaller derestriction regions. 798370b324cSopenharmony_ci Also usually restriction region cannot move back from previous start position, 799370b324cSopenharmony_ci so (b <= begin) is expected here for normal cases */ 800370b324cSopenharmony_ci if (b == begin) // if same low bounds 801370b324cSopenharmony_ci b = end; // we need to derestrict only after the end of new restricted region 802370b324cSopenharmony_ci if (e == end) // if same high bounds 803370b324cSopenharmony_ci e = begin; // we need to derestrict only before the begin of new restricted region 804370b324cSopenharmony_ci } 805370b324cSopenharmony_ci 806370b324cSopenharmony_ci if (b > e) // || b == (UInt64)(Int64)-1 807370b324cSopenharmony_ci return S_OK; 808370b324cSopenharmony_ci 809370b324cSopenharmony_ci /* Here we close finished volumes that are not restricted anymore. 810370b324cSopenharmony_ci We close (low number) volumes at first. */ 811370b324cSopenharmony_ci 812370b324cSopenharmony_ci UInt64 offset; 813370b324cSopenharmony_ci unsigned index = GetStreamIndex_for_Offset(b, offset); 814370b324cSopenharmony_ci 815370b324cSopenharmony_ci for (; index < Streams.Size(); index++) 816370b324cSopenharmony_ci { 817370b324cSopenharmony_ci { 818370b324cSopenharmony_ci const CVolStream &s = Streams[index]; 819370b324cSopenharmony_ci if (_length <= s.Start) 820370b324cSopenharmony_ci break; // we don't close streams after _length 821370b324cSopenharmony_ci // (_length > s.Start) 822370b324cSopenharmony_ci const UInt64 volSize = GetVolSize_for_Stream(index); 823370b324cSopenharmony_ci if (volSize == 0) 824370b324cSopenharmony_ci { 825370b324cSopenharmony_ci if (e < s.Start) 826370b324cSopenharmony_ci break; 827370b324cSopenharmony_ci // we don't close empty stream, if next byte [s.Start, s.Start] is restricted 828370b324cSopenharmony_ci if (IsRestricted_Empty(s)) 829370b324cSopenharmony_ci continue; 830370b324cSopenharmony_ci } 831370b324cSopenharmony_ci else 832370b324cSopenharmony_ci { 833370b324cSopenharmony_ci if (e <= s.Start) 834370b324cSopenharmony_ci break; 835370b324cSopenharmony_ci // we don't close non full streams 836370b324cSopenharmony_ci if (_length - s.Start < volSize) 837370b324cSopenharmony_ci break; 838370b324cSopenharmony_ci // (volSize == s.RealSize) is expected here. So no need to check it 839370b324cSopenharmony_ci // if (volSize != s.RealSize) break; 840370b324cSopenharmony_ci if (IsRestricted(s)) 841370b324cSopenharmony_ci continue; 842370b324cSopenharmony_ci } 843370b324cSopenharmony_ci } 844370b324cSopenharmony_ci RINOK(CloseStream_and_FinalRename(index)) 845370b324cSopenharmony_ci } 846370b324cSopenharmony_ci 847370b324cSopenharmony_ci return S_OK; 848370b324cSopenharmony_ci COM_TRY_END 849370b324cSopenharmony_ci} 850