1 // FileStreams.cpp
2
3 #include "StdAfx.h"
4
5 // #include <stdio.h>
6
7 #ifndef _WIN32
8 #include <fcntl.h>
9 #include <unistd.h>
10 #include <errno.h>
11 #include <grp.h>
12 #include <pwd.h>
13
14 // for major()/minor():
15 #include <sys/types.h>
16 #if defined(__FreeBSD__) || defined(BSD) || defined(__APPLE__)
17 #else
18 #ifndef major
19 #include <sys/sysmacros.h>
20 #endif
21 #endif
22
23 #endif // _WIN32
24
25 #include "../../Windows/FileFind.h"
26
27 #ifdef Z7_DEVICE_FILE
28 #include "../../../C/Alloc.h"
29 #include "../../Common/Defs.h"
30 #endif
31
32 #include "../PropID.h"
33
34 #include "FileStreams.h"
35
GetLastError_HRESULT()36 static inline HRESULT GetLastError_HRESULT()
37 {
38 DWORD lastError = ::GetLastError();
39 if (lastError == 0)
40 return E_FAIL;
41 return HRESULT_FROM_WIN32(lastError);
42 }
43
ConvertBoolToHRESULT(bool result)44 static inline HRESULT ConvertBoolToHRESULT(bool result)
45 {
46 if (result)
47 return S_OK;
48 return GetLastError_HRESULT();
49 }
50
51
52 #ifdef Z7_DEVICE_FILE
53 static const UInt32 kClusterSize = 1 << 18;
54 #endif
55
CInFileStream()56 CInFileStream::CInFileStream():
57 #ifdef Z7_DEVICE_FILE
58 VirtPos(0),
59 PhyPos(0),
60 Buf(NULL),
61 BufSize(0),
62 #endif
63 #ifndef _WIN32
64 _uid(0),
65 _gid(0),
66 StoreOwnerId(false),
67 StoreOwnerName(false),
68 #endif
69 _info_WasLoaded(false),
70 SupportHardLinks(false),
71 Callback(NULL),
72 CallbackRef(0)
73 {
74 }
75
~CInFileStream()76 CInFileStream::~CInFileStream()
77 {
78 #ifdef Z7_DEVICE_FILE
79 MidFree(Buf);
80 #endif
81
82 if (Callback)
83 Callback->InFileStream_On_Destroy(this, CallbackRef);
84 }
85
Read(void *data, UInt32 size, UInt32 *processedSize)86 Z7_COM7F_IMF(CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
87 {
88 #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
89
90 #ifdef Z7_DEVICE_FILE
91 if (processedSize)
92 *processedSize = 0;
93 if (size == 0)
94 return S_OK;
95 if (File.IsDeviceFile)
96 {
97 if (File.SizeDefined)
98 {
99 if (VirtPos >= File.Size)
100 return VirtPos == File.Size ? S_OK : E_FAIL;
101 const UInt64 rem = File.Size - VirtPos;
102 if (size > rem)
103 size = (UInt32)rem;
104 }
105 for (;;)
106 {
107 const UInt32 mask = kClusterSize - 1;
108 const UInt64 mask2 = ~(UInt64)mask;
109 const UInt64 alignedPos = VirtPos & mask2;
110 if (BufSize > 0 && BufStartPos == alignedPos)
111 {
112 const UInt32 pos = (UInt32)VirtPos & mask;
113 if (pos >= BufSize)
114 return S_OK;
115 const UInt32 rem = MyMin(BufSize - pos, size);
116 memcpy(data, Buf + pos, rem);
117 VirtPos += rem;
118 if (processedSize)
119 *processedSize += rem;
120 return S_OK;
121 }
122
123 bool useBuf = false;
124 if ((VirtPos & mask) != 0 || ((size_t)(ptrdiff_t)data & mask) != 0 )
125 useBuf = true;
126 else
127 {
128 UInt64 end = VirtPos + size;
129 if ((end & mask) != 0)
130 {
131 end &= mask2;
132 if (end <= VirtPos)
133 useBuf = true;
134 else
135 size = (UInt32)(end - VirtPos);
136 }
137 }
138 if (!useBuf)
139 break;
140 if (alignedPos != PhyPos)
141 {
142 UInt64 realNewPosition;
143 const bool result = File.Seek((Int64)alignedPos, FILE_BEGIN, realNewPosition);
144 if (!result)
145 return ConvertBoolToHRESULT(result);
146 PhyPos = realNewPosition;
147 }
148
149 BufStartPos = alignedPos;
150 UInt32 readSize = kClusterSize;
151 if (File.SizeDefined)
152 readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize);
153
154 if (!Buf)
155 {
156 Buf = (Byte *)MidAlloc(kClusterSize);
157 if (!Buf)
158 return E_OUTOFMEMORY;
159 }
160 const bool result = File.Read1(Buf, readSize, BufSize);
161 if (!result)
162 return ConvertBoolToHRESULT(result);
163
164 if (BufSize == 0)
165 return S_OK;
166 PhyPos += BufSize;
167 }
168
169 if (VirtPos != PhyPos)
170 {
171 UInt64 realNewPosition;
172 bool result = File.Seek((Int64)VirtPos, FILE_BEGIN, realNewPosition);
173 if (!result)
174 return ConvertBoolToHRESULT(result);
175 PhyPos = VirtPos = realNewPosition;
176 }
177 }
178 #endif
179
180 UInt32 realProcessedSize;
181 const bool result = File.ReadPart(data, size, realProcessedSize);
182 if (processedSize)
183 *processedSize = realProcessedSize;
184
185 #ifdef Z7_DEVICE_FILE
186 VirtPos += realProcessedSize;
187 PhyPos += realProcessedSize;
188 #endif
189
190 if (result)
191 return S_OK;
192
193 #else // Z7_FILE_STREAMS_USE_WIN_FILE
194
195 if (processedSize)
196 *processedSize = 0;
197 const ssize_t res = File.read_part(data, (size_t)size);
198 if (res != -1)
199 {
200 if (processedSize)
201 *processedSize = (UInt32)res;
202 return S_OK;
203 }
204 #endif // Z7_FILE_STREAMS_USE_WIN_FILE
205
206 {
207 const DWORD error = ::GetLastError();
208 if (Callback)
209 return Callback->InFileStream_On_Error(CallbackRef, error);
210 if (error == 0)
211 return E_FAIL;
212 return HRESULT_FROM_WIN32(error);
213 }
214 }
215
216 #ifdef UNDER_CE
Read(void *data, UInt32 size, UInt32 *processedSize)217 Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
218 {
219 size_t s2 = fread(data, 1, size, stdin);
220 int error = ferror(stdin);
221 if (processedSize)
222 *processedSize = s2;
223 if (s2 <= size && error == 0)
224 return S_OK;
225 return E_FAIL;
226 }
227 #else
Read(void *data, UInt32 size, UInt32 *processedSize)228 Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
229 {
230 #ifdef _WIN32
231
232 DWORD realProcessedSize;
233 UInt32 sizeTemp = (1 << 20);
234 if (sizeTemp > size)
235 sizeTemp = size;
236 BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
237 if (processedSize)
238 *processedSize = realProcessedSize;
239 if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
240 return S_OK;
241 return ConvertBoolToHRESULT(res != FALSE);
242
243 #else
244
245 if (processedSize)
246 *processedSize = 0;
247 ssize_t res;
248 do
249 {
250 res = read(0, data, (size_t)size);
251 }
252 while (res < 0 && (errno == EINTR));
253 if (res == -1)
254 return GetLastError_HRESULT();
255 if (processedSize)
256 *processedSize = (UInt32)res;
257 return S_OK;
258
259 #endif
260 }
261
262 #endif
263
Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)264 Z7_COM7F_IMF(CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
265 {
266 if (seekOrigin >= 3)
267 return STG_E_INVALIDFUNCTION;
268
269 #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
270
271 #ifdef Z7_DEVICE_FILE
272 if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END))
273 {
274 switch (seekOrigin)
275 {
276 case STREAM_SEEK_SET: break;
277 case STREAM_SEEK_CUR: offset += VirtPos; break;
278 case STREAM_SEEK_END: offset += File.Size; break;
279 default: return STG_E_INVALIDFUNCTION;
280 }
281 if (offset < 0)
282 return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
283 VirtPos = (UInt64)offset;
284 if (newPosition)
285 *newPosition = (UInt64)offset;
286 return S_OK;
287 }
288 #endif
289
290 UInt64 realNewPosition = 0;
291 const bool result = File.Seek(offset, seekOrigin, realNewPosition);
292 const HRESULT hres = ConvertBoolToHRESULT(result);
293
294 /* 21.07: new File.Seek() in 21.07 already returns correct (realNewPosition)
295 in case of error. So we don't need additional code below */
296 // if (!result) { realNewPosition = 0; File.GetPosition(realNewPosition); }
297
298 #ifdef Z7_DEVICE_FILE
299 PhyPos = VirtPos = realNewPosition;
300 #endif
301
302 if (newPosition)
303 *newPosition = realNewPosition;
304
305 return hres;
306
307 #else
308
309 const off_t res = File.seek((off_t)offset, (int)seekOrigin);
310 if (res == -1)
311 {
312 const HRESULT hres = GetLastError_HRESULT();
313 if (newPosition)
314 *newPosition = (UInt64)File.seekToCur();
315 return hres;
316 }
317 if (newPosition)
318 *newPosition = (UInt64)res;
319 return S_OK;
320
321 #endif
322 }
323
GetSize(UInt64 *size)324 Z7_COM7F_IMF(CInFileStream::GetSize(UInt64 *size))
325 {
326 return ConvertBoolToHRESULT(File.GetLength(*size));
327 }
328
329 #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
330
GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)331 Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
332 {
333 if (!_info_WasLoaded)
334 {
335 RINOK(ReloadProps())
336 }
337 const BY_HANDLE_FILE_INFORMATION &info = _info;
338 /*
339 BY_HANDLE_FILE_INFORMATION info;
340 if (!File.GetFileInformation(&info))
341 return GetLastError_HRESULT();
342 */
343 {
344 if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
345 if (cTime) *cTime = info.ftCreationTime;
346 if (aTime) *aTime = info.ftLastAccessTime;
347 if (mTime) *mTime = info.ftLastWriteTime;
348 if (attrib) *attrib = info.dwFileAttributes;
349 return S_OK;
350 }
351 }
352
GetProps2(CStreamFileProps *props)353 Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props))
354 {
355 if (!_info_WasLoaded)
356 {
357 RINOK(ReloadProps())
358 }
359 const BY_HANDLE_FILE_INFORMATION &info = _info;
360 /*
361 BY_HANDLE_FILE_INFORMATION info;
362 if (!File.GetFileInformation(&info))
363 return GetLastError_HRESULT();
364 */
365 {
366 props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
367 props->VolID = info.dwVolumeSerialNumber;
368 props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
369 props->FileID_High = 0;
370 props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1;
371 props->Attrib = info.dwFileAttributes;
372 props->CTime = info.ftCreationTime;
373 props->ATime = info.ftLastAccessTime;
374 props->MTime = info.ftLastWriteTime;
375 return S_OK;
376 }
377 }
378
GetProperty(PROPID propID, PROPVARIANT *value)379 Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value))
380 {
381 if (!_info_WasLoaded)
382 {
383 RINOK(ReloadProps())
384 }
385
386 if (!_info_WasLoaded)
387 return S_OK;
388
389 NWindows::NCOM::CPropVariant prop;
390
391 #ifdef Z7_DEVICE_FILE
392 if (File.IsDeviceFile)
393 {
394 switch (propID)
395 {
396 case kpidSize:
397 if (File.SizeDefined)
398 prop = File.Size;
399 break;
400 // case kpidAttrib: prop = (UInt32)0; break;
401 case kpidPosixAttrib:
402 {
403 prop = (UInt32)NWindows::NFile::NFind::NAttributes::
404 Get_PosixMode_From_WinAttrib(0);
405 /* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute
406 so we don't use MY_LIN_S_IFBLK here */
407 // prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug
408 break;
409 }
410 /*
411 case kpidDeviceMajor:
412 prop = (UInt32)8; // id for SCSI type device (sda)
413 break;
414 case kpidDeviceMinor:
415 prop = (UInt32)0;
416 break;
417 */
418 }
419 }
420 else
421 #endif
422 {
423 switch (propID)
424 {
425 case kpidSize:
426 {
427 const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow;
428 prop = size;
429 break;
430 }
431 case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break;
432 case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break;
433 case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break;
434 case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break;
435 case kpidPosixAttrib:
436 prop = (UInt32)NWindows::NFile::NFind::NAttributes::
437 Get_PosixMode_From_WinAttrib(_info.dwFileAttributes);
438 // | (UInt32)(1 << 21); // for debug
439 break;
440 }
441 }
442 prop.Detach(value);
443 return S_OK;
444 }
445
446
ReloadProps()447 Z7_COM7F_IMF(CInFileStream::ReloadProps())
448 {
449 #ifdef Z7_DEVICE_FILE
450 if (File.IsDeviceFile)
451 {
452 memset(&_info, 0, sizeof(_info));
453 if (File.SizeDefined)
454 {
455 _info.nFileSizeHigh = (DWORD)(File.Size >> 32);
456 _info.nFileSizeLow = (DWORD)(File.Size);
457 }
458 _info.nNumberOfLinks = 1;
459 _info_WasLoaded = true;
460 return S_OK;
461 }
462 #endif
463 _info_WasLoaded = File.GetFileInformation(&_info);
464 if (!_info_WasLoaded)
465 return GetLastError_HRESULT();
466 return S_OK;
467 }
468
469
470 #elif !defined(_WIN32)
471
GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)472 Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
473 {
474 if (!_info_WasLoaded)
475 {
476 RINOK(ReloadProps())
477 }
478 const struct stat &st = _info;
479 /*
480 struct stat st;
481 if (File.my_fstat(&st) != 0)
482 return GetLastError_HRESULT();
483 */
484
485 if (size) *size = (UInt64)st.st_size;
486 if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime);
487 if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime);
488 if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime);
489 if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
490
491 return S_OK;
492 }
493
494 // #include <stdio.h>
495
GetProps2(CStreamFileProps *props)496 Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props))
497 {
498 if (!_info_WasLoaded)
499 {
500 RINOK(ReloadProps())
501 }
502 const struct stat &st = _info;
503 /*
504 struct stat st;
505 if (File.my_fstat(&st) != 0)
506 return GetLastError_HRESULT();
507 */
508
509 props->Size = (UInt64)st.st_size;
510 /*
511 dev_t stat::st_dev:
512 GCC:Linux long unsigned int : __dev_t
513 Mac: int
514 */
515 props->VolID = (UInt64)(Int64)st.st_dev;
516 props->FileID_Low = st.st_ino;
517 props->FileID_High = 0;
518 props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long)
519 props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
520
521 FiTime_To_FILETIME (ST_CTIME(st), props->CTime);
522 FiTime_To_FILETIME (ST_ATIME(st), props->ATime);
523 FiTime_To_FILETIME (ST_MTIME(st), props->MTime);
524
525 /*
526 printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n"
527 , (unsigned)(props->NumLinks)
528 , (unsigned)(st.st_dev)
529 , (unsigned)(st.st_ino)
530 );
531 */
532
533 return S_OK;
534 }
535
GetProperty(PROPID propID, PROPVARIANT *value)536 Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value))
537 {
538 if (!_info_WasLoaded)
539 {
540 RINOK(ReloadProps())
541 }
542
543 if (!_info_WasLoaded)
544 return S_OK;
545
546 const struct stat &st = _info;
547
548 NWindows::NCOM::CPropVariant prop;
549 {
550 switch (propID)
551 {
552 case kpidSize: prop = (UInt64)st.st_size; break;
553 case kpidAttrib:
554 prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
555 break;
556 case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break;
557 case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break;
558 case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break;
559 case kpidPosixAttrib: prop = (UInt32)st.st_mode; break;
560
561 #if defined(__APPLE__)
562 #pragma GCC diagnostic push
563 #pragma GCC diagnostic ignored "-Wsign-conversion"
564 #endif
565
566 case kpidDeviceMajor:
567 {
568 // printf("\nst.st_rdev = %d\n", st.st_rdev);
569 if (S_ISCHR(st.st_mode) ||
570 S_ISBLK(st.st_mode))
571 prop = (UInt32)(major(st.st_rdev)); // + 1000);
572 // prop = (UInt32)12345678; // for debug
573 break;
574 }
575
576 case kpidDeviceMinor:
577 if (S_ISCHR(st.st_mode) ||
578 S_ISBLK(st.st_mode))
579 prop = (UInt32)(minor(st.st_rdev)); // + 100);
580 // prop = (UInt32)(st.st_rdev); // for debug
581 // printf("\nst.st_rdev = %d\n", st.st_rdev);
582 // prop = (UInt32)123456789; // for debug
583 break;
584
585 #if defined(__APPLE__)
586 #pragma GCC diagnostic pop
587 #endif
588
589 /*
590 case kpidDevice:
591 if (S_ISCHR(st.st_mode) ||
592 S_ISBLK(st.st_mode))
593 prop = (UInt64)(st.st_rdev);
594 break;
595 */
596
597 case kpidUserId:
598 {
599 if (StoreOwnerId)
600 prop = (UInt32)st.st_uid;
601 break;
602 }
603 case kpidGroupId:
604 {
605 if (StoreOwnerId)
606 prop = (UInt32)st.st_gid;
607 break;
608 }
609 case kpidUser:
610 {
611 if (StoreOwnerName)
612 {
613 const uid_t uid = st.st_uid;
614 {
615 if (!OwnerName.IsEmpty() && _uid == uid)
616 prop = OwnerName;
617 else
618 {
619 const passwd *pw = getpwuid(uid);
620 if (pw)
621 {
622 // we can use utf-8 here.
623 // prop = pw->pw_name;
624 }
625 }
626 }
627 }
628 break;
629 }
630 case kpidGroup:
631 {
632 if (StoreOwnerName)
633 {
634 const uid_t gid = st.st_gid;
635 {
636 if (!OwnerGroup.IsEmpty() && _gid == gid)
637 prop = OwnerGroup;
638 else
639 {
640 const group *gr = getgrgid(gid);
641 if (gr)
642 {
643 // we can use utf-8 here.
644 // prop = gr->gr_name;
645 }
646 }
647 }
648 }
649 break;
650 }
651 }
652 }
653 prop.Detach(value);
654 return S_OK;
655 }
656
657
ReloadProps()658 Z7_COM7F_IMF(CInFileStream::ReloadProps())
659 {
660 _info_WasLoaded = (File.my_fstat(&_info) == 0);
661 if (!_info_WasLoaded)
662 return GetLastError_HRESULT();
663 return S_OK;
664 }
665
666 #endif
667
668
669
670
671 //////////////////////////
672 // COutFileStream
673
Close()674 HRESULT COutFileStream::Close()
675 {
676 return ConvertBoolToHRESULT(File.Close());
677 }
678
Write(const void *data, UInt32 size, UInt32 *processedSize)679 Z7_COM7F_IMF(COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
680 {
681 #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
682
683 UInt32 realProcessedSize;
684 const bool result = File.Write(data, size, realProcessedSize);
685 ProcessedSize += realProcessedSize;
686 if (processedSize)
687 *processedSize = realProcessedSize;
688 return ConvertBoolToHRESULT(result);
689
690 #else
691
692 if (processedSize)
693 *processedSize = 0;
694 size_t realProcessedSize;
695 const ssize_t res = File.write_full(data, (size_t)size, realProcessedSize);
696 ProcessedSize += realProcessedSize;
697 if (processedSize)
698 *processedSize = (UInt32)realProcessedSize;
699 if (res == -1)
700 return GetLastError_HRESULT();
701 return S_OK;
702
703 #endif
704 }
705
Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)706 Z7_COM7F_IMF(COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
707 {
708 if (seekOrigin >= 3)
709 return STG_E_INVALIDFUNCTION;
710
711 #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
712
713 UInt64 realNewPosition = 0;
714 const bool result = File.Seek(offset, seekOrigin, realNewPosition);
715 if (newPosition)
716 *newPosition = realNewPosition;
717 return ConvertBoolToHRESULT(result);
718
719 #else
720
721 const off_t res = File.seek((off_t)offset, (int)seekOrigin);
722 if (res == -1)
723 return GetLastError_HRESULT();
724 if (newPosition)
725 *newPosition = (UInt64)res;
726 return S_OK;
727
728 #endif
729 }
730
SetSize(UInt64 newSize)731 Z7_COM7F_IMF(COutFileStream::SetSize(UInt64 newSize))
732 {
733 return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize));
734 }
735
GetSize(UInt64 *size)736 HRESULT COutFileStream::GetSize(UInt64 *size)
737 {
738 return ConvertBoolToHRESULT(File.GetLength(*size));
739 }
740
741 #ifdef UNDER_CE
742
Write(const void *data, UInt32 size, UInt32 *processedSize)743 Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
744 {
745 size_t s2 = fwrite(data, 1, size, stdout);
746 if (processedSize)
747 *processedSize = s2;
748 return (s2 == size) ? S_OK : E_FAIL;
749 }
750
751 #else
752
Write(const void *data, UInt32 size, UInt32 *processedSize)753 Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
754 {
755 if (processedSize)
756 *processedSize = 0;
757
758 #ifdef _WIN32
759
760 UInt32 realProcessedSize;
761 BOOL res = TRUE;
762 if (size > 0)
763 {
764 // Seems that Windows doesn't like big amounts writing to stdout.
765 // So we limit portions by 32KB.
766 UInt32 sizeTemp = (1 << 15);
767 if (sizeTemp > size)
768 sizeTemp = size;
769 res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
770 data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
771 _size += realProcessedSize;
772 size -= realProcessedSize;
773 data = (const void *)((const Byte *)data + realProcessedSize);
774 if (processedSize)
775 *processedSize += realProcessedSize;
776 }
777 return ConvertBoolToHRESULT(res != FALSE);
778
779 #else
780
781 ssize_t res;
782
783 do
784 {
785 res = write(1, data, (size_t)size);
786 }
787 while (res < 0 && (errno == EINTR));
788
789 if (res == -1)
790 return GetLastError_HRESULT();
791
792 _size += (size_t)res;
793 if (processedSize)
794 *processedSize = (UInt32)res;
795 return S_OK;
796
797 #endif
798 }
799
800 #endif
801