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