aboutsummaryrefslogtreecommitdiff
path: root/CPP/7zip/Common/FileStreams.cpp
diff options
context:
space:
mode:
authorIgor Pavlov <87184205+ip7z@users.noreply.github.com>2021-12-27 00:00:00 +0000
committerIgor Pavlov <87184205+ip7z@users.noreply.github.com>2022-03-18 15:35:13 +0500
commitf19f813537c7aea1c20749c914e756b54a9c3cf5 (patch)
tree816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /CPP/7zip/Common/FileStreams.cpp
parent98e06a519b63b81986abe76d28887f6984a7732b (diff)
download7zip-21.07.tar.gz
7zip-21.07.tar.bz2
7zip-21.07.zip
'21.07'21.07
Diffstat (limited to 'CPP/7zip/Common/FileStreams.cpp')
-rw-r--r--CPP/7zip/Common/FileStreams.cpp536
1 files changed, 536 insertions, 0 deletions
diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp
new file mode 100644
index 0000000..9e0e79c
--- /dev/null
+++ b/CPP/7zip/Common/FileStreams.cpp
@@ -0,0 +1,536 @@
1// FileStreams.cpp
2
3#include "StdAfx.h"
4
5#ifndef _WIN32
6#include <fcntl.h>
7#include <unistd.h>
8#include <errno.h>
9#include "../../Windows/FileFind.h"
10#endif
11
12#ifdef SUPPORT_DEVICE_FILE
13#include "../../../C/Alloc.h"
14#include "../../Common/Defs.h"
15#endif
16
17#include "FileStreams.h"
18
19static inline HRESULT GetLastError_HRESULT()
20{
21 DWORD lastError = ::GetLastError();
22 if (lastError == 0)
23 return E_FAIL;
24 return HRESULT_FROM_WIN32(lastError);
25}
26
27static inline HRESULT ConvertBoolToHRESULT(bool result)
28{
29 if (result)
30 return S_OK;
31 return GetLastError_HRESULT();
32}
33
34
35#ifdef SUPPORT_DEVICE_FILE
36static const UInt32 kClusterSize = 1 << 18;
37#endif
38
39CInFileStream::CInFileStream():
40 #ifdef SUPPORT_DEVICE_FILE
41 VirtPos(0),
42 PhyPos(0),
43 Buf(0),
44 BufSize(0),
45 #endif
46 SupportHardLinks(false),
47 Callback(NULL),
48 CallbackRef(0)
49{
50}
51
52CInFileStream::~CInFileStream()
53{
54 #ifdef SUPPORT_DEVICE_FILE
55 MidFree(Buf);
56 #endif
57
58 if (Callback)
59 Callback->InFileStream_On_Destroy(CallbackRef);
60}
61
62STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
63{
64 #ifdef USE_WIN_FILE
65
66 #ifdef SUPPORT_DEVICE_FILE
67 if (processedSize)
68 *processedSize = 0;
69 if (size == 0)
70 return S_OK;
71 if (File.IsDeviceFile)
72 {
73 if (File.SizeDefined)
74 {
75 if (VirtPos >= File.Size)
76 return VirtPos == File.Size ? S_OK : E_FAIL;
77 UInt64 rem = File.Size - VirtPos;
78 if (size > rem)
79 size = (UInt32)rem;
80 }
81 for (;;)
82 {
83 const UInt32 mask = kClusterSize - 1;
84 const UInt64 mask2 = ~(UInt64)mask;
85 UInt64 alignedPos = VirtPos & mask2;
86 if (BufSize > 0 && BufStartPos == alignedPos)
87 {
88 UInt32 pos = (UInt32)VirtPos & mask;
89 if (pos >= BufSize)
90 return S_OK;
91 UInt32 rem = MyMin(BufSize - pos, size);
92 memcpy(data, Buf + pos, rem);
93 VirtPos += rem;
94 if (processedSize)
95 *processedSize += rem;
96 return S_OK;
97 }
98
99 bool useBuf = false;
100 if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 )
101 useBuf = true;
102 else
103 {
104 UInt64 end = VirtPos + size;
105 if ((end & mask) != 0)
106 {
107 end &= mask2;
108 if (end <= VirtPos)
109 useBuf = true;
110 else
111 size = (UInt32)(end - VirtPos);
112 }
113 }
114 if (!useBuf)
115 break;
116 if (alignedPos != PhyPos)
117 {
118 UInt64 realNewPosition;
119 bool result = File.Seek((Int64)alignedPos, FILE_BEGIN, realNewPosition);
120 if (!result)
121 return ConvertBoolToHRESULT(result);
122 PhyPos = realNewPosition;
123 }
124
125 BufStartPos = alignedPos;
126 UInt32 readSize = kClusterSize;
127 if (File.SizeDefined)
128 readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize);
129
130 if (!Buf)
131 {
132 Buf = (Byte *)MidAlloc(kClusterSize);
133 if (!Buf)
134 return E_OUTOFMEMORY;
135 }
136 bool result = File.Read1(Buf, readSize, BufSize);
137 if (!result)
138 return ConvertBoolToHRESULT(result);
139
140 if (BufSize == 0)
141 return S_OK;
142 PhyPos += BufSize;
143 }
144
145 if (VirtPos != PhyPos)
146 {
147 UInt64 realNewPosition;
148 bool result = File.Seek((Int64)VirtPos, FILE_BEGIN, realNewPosition);
149 if (!result)
150 return ConvertBoolToHRESULT(result);
151 PhyPos = VirtPos = realNewPosition;
152 }
153 }
154 #endif
155
156 UInt32 realProcessedSize;
157 const bool result = File.ReadPart(data, size, realProcessedSize);
158 if (processedSize)
159 *processedSize = realProcessedSize;
160
161 #ifdef SUPPORT_DEVICE_FILE
162 VirtPos += realProcessedSize;
163 PhyPos += realProcessedSize;
164 #endif
165
166 if (result)
167 return S_OK;
168
169 #else // USE_WIN_FILE
170
171 if (processedSize)
172 *processedSize = 0;
173 const ssize_t res = File.read_part(data, (size_t)size);
174 if (res != -1)
175 {
176 if (processedSize)
177 *processedSize = (UInt32)res;
178 return S_OK;
179 }
180 #endif // USE_WIN_FILE
181
182 {
183 const DWORD error = ::GetLastError();
184 if (Callback)
185 return Callback->InFileStream_On_Error(CallbackRef, error);
186 if (error == 0)
187 return E_FAIL;
188 return HRESULT_FROM_WIN32(error);
189 }
190}
191
192#ifdef UNDER_CE
193STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
194{
195 size_t s2 = fread(data, 1, size, stdin);
196 int error = ferror(stdin);
197 if (processedSize)
198 *processedSize = s2;
199 if (s2 <= size && error == 0)
200 return S_OK;
201 return E_FAIL;
202}
203#else
204STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
205{
206 #ifdef _WIN32
207
208 DWORD realProcessedSize;
209 UInt32 sizeTemp = (1 << 20);
210 if (sizeTemp > size)
211 sizeTemp = size;
212 BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
213 if (processedSize)
214 *processedSize = realProcessedSize;
215 if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
216 return S_OK;
217 return ConvertBoolToHRESULT(res != FALSE);
218
219 #else
220
221 if (processedSize)
222 *processedSize = 0;
223 ssize_t res;
224 do
225 {
226 res = read(0, data, (size_t)size);
227 }
228 while (res < 0 && (errno == EINTR));
229 if (res == -1)
230 return GetLastError_HRESULT();
231 if (processedSize)
232 *processedSize = (UInt32)res;
233 return S_OK;
234
235 #endif
236}
237
238#endif
239
240STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
241{
242 if (seekOrigin >= 3)
243 return STG_E_INVALIDFUNCTION;
244
245 #ifdef USE_WIN_FILE
246
247 #ifdef SUPPORT_DEVICE_FILE
248 if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END))
249 {
250 switch (seekOrigin)
251 {
252 case STREAM_SEEK_SET: break;
253 case STREAM_SEEK_CUR: offset += VirtPos; break;
254 case STREAM_SEEK_END: offset += File.Size; break;
255 default: return STG_E_INVALIDFUNCTION;
256 }
257 if (offset < 0)
258 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
259 VirtPos = (UInt64)offset;
260 if (newPosition)
261 *newPosition = (UInt64)offset;
262 return S_OK;
263 }
264 #endif
265
266 UInt64 realNewPosition = 0;
267 const bool result = File.Seek(offset, seekOrigin, realNewPosition);
268 const HRESULT hres = ConvertBoolToHRESULT(result);
269
270 /* 21.07: new File.Seek() in 21.07 already returns correct (realNewPosition)
271 in case of error. So we don't need additional code below */
272 // if (!result) { realNewPosition = 0; File.GetPosition(realNewPosition); }
273
274 #ifdef SUPPORT_DEVICE_FILE
275 PhyPos = VirtPos = realNewPosition;
276 #endif
277
278 if (newPosition)
279 *newPosition = realNewPosition;
280
281 return hres;
282
283 #else
284
285 const off_t res = File.seek((off_t)offset, (int)seekOrigin);
286 if (res == -1)
287 {
288 const HRESULT hres = GetLastError_HRESULT();
289 if (newPosition)
290 *newPosition = (UInt64)File.seekToCur();
291 return hres;
292 }
293 if (newPosition)
294 *newPosition = (UInt64)res;
295 return S_OK;
296
297 #endif
298}
299
300STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
301{
302 return ConvertBoolToHRESULT(File.GetLength(*size));
303}
304
305#ifdef USE_WIN_FILE
306
307STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
308{
309 BY_HANDLE_FILE_INFORMATION info;
310 if (File.GetFileInformation(&info))
311 {
312 if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
313 if (cTime) *cTime = info.ftCreationTime;
314 if (aTime) *aTime = info.ftLastAccessTime;
315 if (mTime) *mTime = info.ftLastWriteTime;
316 if (attrib) *attrib = info.dwFileAttributes;
317 return S_OK;
318 }
319 return GetLastError_HRESULT();
320}
321
322STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
323{
324 BY_HANDLE_FILE_INFORMATION info;
325 if (File.GetFileInformation(&info))
326 {
327 props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
328 props->VolID = info.dwVolumeSerialNumber;
329 props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
330 props->FileID_High = 0;
331 props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1;
332 props->Attrib = info.dwFileAttributes;
333 props->CTime = info.ftCreationTime;
334 props->ATime = info.ftLastAccessTime;
335 props->MTime = info.ftLastWriteTime;
336 return S_OK;
337 }
338 return GetLastError_HRESULT();
339}
340
341#elif !defined(_WIN32)
342
343STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
344{
345 struct stat st;
346 if (File.my_fstat(&st) != 0)
347 return GetLastError_HRESULT();
348
349 if (size) *size = (UInt64)st.st_size;
350 #ifdef __APPLE__
351 if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, *cTime);
352 if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, *aTime);
353 if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, *mTime);
354 #else
355 if (cTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, *cTime);
356 if (aTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, *aTime);
357 if (mTime) NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, *mTime);
358 #endif
359 if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
360
361 return S_OK;
362}
363
364// #include <stdio.h>
365
366STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
367{
368 struct stat st;
369 if (File.my_fstat(&st) != 0)
370 return GetLastError_HRESULT();
371
372 props->Size = (UInt64)st.st_size;
373 /*
374 dev_t stat::st_dev:
375 GCC:Linux long unsigned int : __dev_t
376 Mac: int
377 */
378 props->VolID = (UInt64)(Int64)st.st_dev;
379 props->FileID_Low = st.st_ino;
380 props->FileID_High = 0;
381 props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long)
382 props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
383
384 #ifdef __APPLE__
385 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctimespec, props->CTime);
386 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atimespec, props->ATime);
387 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtimespec, props->MTime);
388 #else
389 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_ctim, props->CTime);
390 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_atim, props->ATime);
391 NWindows::NFile::NFind::timespec_To_FILETIME(st.st_mtim, props->MTime);
392 #endif
393
394 /*
395 printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n"
396 , (unsigned)(props->NumLinks)
397 , (unsigned)(st.st_dev)
398 , (unsigned)(st.st_ino)
399 );
400 */
401
402 return S_OK;
403}
404
405#endif
406
407//////////////////////////
408// COutFileStream
409
410HRESULT COutFileStream::Close()
411{
412 return ConvertBoolToHRESULT(File.Close());
413}
414
415STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
416{
417 #ifdef USE_WIN_FILE
418
419 UInt32 realProcessedSize;
420 const bool result = File.Write(data, size, realProcessedSize);
421 ProcessedSize += realProcessedSize;
422 if (processedSize)
423 *processedSize = realProcessedSize;
424 return ConvertBoolToHRESULT(result);
425
426 #else
427
428 if (processedSize)
429 *processedSize = 0;
430 size_t realProcessedSize;
431 const ssize_t res = File.write_full(data, (size_t)size, realProcessedSize);
432 ProcessedSize += realProcessedSize;
433 if (processedSize)
434 *processedSize = (UInt32)realProcessedSize;
435 if (res == -1)
436 return GetLastError_HRESULT();
437 return S_OK;
438
439 #endif
440}
441
442STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
443{
444 if (seekOrigin >= 3)
445 return STG_E_INVALIDFUNCTION;
446
447 #ifdef USE_WIN_FILE
448
449 UInt64 realNewPosition = 0;
450 const bool result = File.Seek(offset, seekOrigin, realNewPosition);
451 if (newPosition)
452 *newPosition = realNewPosition;
453 return ConvertBoolToHRESULT(result);
454
455 #else
456
457 const off_t res = File.seek((off_t)offset, (int)seekOrigin);
458 if (res == -1)
459 return GetLastError_HRESULT();
460 if (newPosition)
461 *newPosition = (UInt64)res;
462 return S_OK;
463
464 #endif
465}
466
467STDMETHODIMP COutFileStream::SetSize(UInt64 newSize)
468{
469 return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize));
470}
471
472HRESULT COutFileStream::GetSize(UInt64 *size)
473{
474 return ConvertBoolToHRESULT(File.GetLength(*size));
475}
476
477#ifdef UNDER_CE
478
479STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
480{
481 size_t s2 = fwrite(data, 1, size, stdout);
482 if (processedSize)
483 *processedSize = s2;
484 return (s2 == size) ? S_OK : E_FAIL;
485}
486
487#else
488
489STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
490{
491 if (processedSize)
492 *processedSize = 0;
493
494 #ifdef _WIN32
495
496 UInt32 realProcessedSize;
497 BOOL res = TRUE;
498 if (size > 0)
499 {
500 // Seems that Windows doesn't like big amounts writing to stdout.
501 // So we limit portions by 32KB.
502 UInt32 sizeTemp = (1 << 15);
503 if (sizeTemp > size)
504 sizeTemp = size;
505 res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
506 data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
507 _size += realProcessedSize;
508 size -= realProcessedSize;
509 data = (const void *)((const Byte *)data + realProcessedSize);
510 if (processedSize)
511 *processedSize += realProcessedSize;
512 }
513 return ConvertBoolToHRESULT(res != FALSE);
514
515 #else
516
517 ssize_t res;
518
519 do
520 {
521 res = write(1, data, (size_t)size);
522 }
523 while (res < 0 && (errno == EINTR));
524
525 if (res == -1)
526 return GetLastError_HRESULT();
527
528 _size += (size_t)res;
529 if (processedSize)
530 *processedSize = (UInt32)res;
531 return S_OK;
532
533 #endif
534}
535
536#endif