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