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
36static 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
44static 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
53static const UInt32 kClusterSize = 1 << 18;
54#endif
55
56CInFileStream::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
76CInFileStream::~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
86Z7_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
217Z7_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
228Z7_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
264Z7_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
324Z7_COM7F_IMF(CInFileStream::GetSize(UInt64 *size))
325{
326  return ConvertBoolToHRESULT(File.GetLength(*size));
327}
328
329#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
330
331Z7_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
353Z7_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
379Z7_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
447Z7_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
472Z7_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
496Z7_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
536Z7_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
658Z7_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
674HRESULT COutFileStream::Close()
675{
676  return ConvertBoolToHRESULT(File.Close());
677}
678
679Z7_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
706Z7_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
731Z7_COM7F_IMF(COutFileStream::SetSize(UInt64 newSize))
732{
733  return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize));
734}
735
736HRESULT COutFileStream::GetSize(UInt64 *size)
737{
738  return ConvertBoolToHRESULT(File.GetLength(*size));
739}
740
741#ifdef UNDER_CE
742
743Z7_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
753Z7_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