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