1 // Windows/FileIO.cpp
2
3 #include "StdAfx.h"
4
5 #ifdef Z7_DEVICE_FILE
6 #include "../../C/Alloc.h"
7 #endif
8
9 // #include <stdio.h>
10
11 /*
12 #ifndef _WIN32
13 // for ioctl BLKGETSIZE64
14 #include <sys/ioctl.h>
15 #include <linux/fs.h>
16 #endif
17 */
18
19 #include "FileIO.h"
20 #include "FileName.h"
21
GetLastError_noZero_HRESULT()22 HRESULT GetLastError_noZero_HRESULT()
23 {
24 const DWORD res = ::GetLastError();
25 if (res == 0)
26 return E_FAIL;
27 return HRESULT_FROM_WIN32(res);
28 }
29
30 #ifdef _WIN32
31
32 #ifndef _UNICODE
33 extern bool g_IsNT;
34 #endif
35
36 using namespace NWindows;
37 using namespace NFile;
38 using namespace NName;
39
40 namespace NWindows {
41 namespace NFile {
42
43 #ifdef Z7_DEVICE_FILE
44
45 namespace NSystem
46 {
47 bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
48 }
49 #endif
50
51 namespace NIO {
52
53 /*
54 WinXP-64 CreateFile():
55 "" - ERROR_PATH_NOT_FOUND
56 :stream - OK
57 .:stream - ERROR_PATH_NOT_FOUND
58 .\:stream - OK
59
60 folder\:stream - ERROR_INVALID_NAME
61 folder:stream - OK
62
63 c:\:stream - OK
64
65 c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 )
66 c::stream - OK, if current dir is ROOT ( c:\ )
67 */
68
Create(CFSTR path,DWORD desiredAccess,DWORD shareMode,DWORD creationDisposition,DWORD flagsAndAttributes)69 bool CFileBase::Create(CFSTR path, DWORD desiredAccess,
70 DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
71 {
72 if (!Close())
73 return false;
74
75 #ifdef Z7_DEVICE_FILE
76 IsDeviceFile = false;
77 #endif
78
79 #ifndef _UNICODE
80 if (!g_IsNT)
81 {
82 _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode,
83 (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
84 }
85 else
86 #endif
87 {
88 IF_USE_MAIN_PATH
89 _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode,
90 (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
91 #ifdef Z7_LONG_PATH
92 if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
93 {
94 UString superPath;
95 if (GetSuperPath(path, superPath, USE_MAIN_PATH))
96 _handle = ::CreateFileW(superPath, desiredAccess, shareMode,
97 (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
98 }
99 #endif
100 }
101
102 /*
103 #ifndef UNDER_CE
104 #ifndef Z7_SFX
105 if (_handle == INVALID_HANDLE_VALUE)
106 {
107 // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10
108 DWORD lastError = GetLastError();
109 if (lastError == ERROR_CANT_ACCESS_FILE)
110 {
111 CByteBuffer buf;
112 if (NIO::GetReparseData(path, buf, NULL))
113 {
114 CReparseAttr attr;
115 if (attr.Parse(buf, buf.Size()))
116 {
117 FString dirPrefix, fileName;
118 if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName))
119 {
120 FString fullPath;
121 if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath))
122 {
123 // FIX IT: recursion levels must be restricted
124 return Create(fullPath, desiredAccess,
125 shareMode, creationDisposition, flagsAndAttributes);
126 }
127 }
128 }
129 }
130 SetLastError(lastError);
131 }
132 }
133 #endif
134 #endif
135 */
136
137 return (_handle != INVALID_HANDLE_VALUE);
138 }
139
Close()140 bool CFileBase::Close() throw()
141 {
142 if (_handle == INVALID_HANDLE_VALUE)
143 return true;
144 #if 0
145 if (!IsStdStream)
146 #endif
147 {
148 if (!::CloseHandle(_handle))
149 return false;
150 }
151 #if 0
152 IsStdStream = false;
153 IsStdPipeStream = false;
154 #endif
155 _handle = INVALID_HANDLE_VALUE;
156 return true;
157 }
158
GetLength(UInt64 & length) const159 bool CFileBase::GetLength(UInt64 &length) const throw()
160 {
161 #ifdef Z7_DEVICE_FILE
162 if (IsDeviceFile && SizeDefined)
163 {
164 length = Size;
165 return true;
166 }
167 #endif
168
169 DWORD high = 0;
170 const DWORD low = ::GetFileSize(_handle, &high);
171 if (low == INVALID_FILE_SIZE)
172 if (::GetLastError() != NO_ERROR)
173 return false;
174 length = (((UInt64)high) << 32) + low;
175 return true;
176
177 /*
178 LARGE_INTEGER fileSize;
179 // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+
180 if (!GetFileSizeEx(_handle, &fileSize))
181 return false;
182 length = (UInt64)fileSize.QuadPart;
183 return true;
184 */
185 }
186
187
188 /* Specification for SetFilePointer():
189
190 If a new file pointer is a negative value,
191 {
192 the function fails,
193 the file pointer is not moved,
194 the code returned by GetLastError() is ERROR_NEGATIVE_SEEK.
195 }
196
197 If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set
198 {
199 an application can move the file pointer only to sector-aligned positions.
200 A sector-aligned position is a position that is a whole number multiple of
201 the volume sector size.
202 An application can obtain a volume sector size by calling the GetDiskFreeSpace.
203 }
204
205 It is not an error to set a file pointer to a position beyond the end of the file.
206 The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function.
207
208 If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL,
209 an application must call GetLastError to determine whether or not the function has succeeded or failed.
210 */
211
GetPosition(UInt64 & position) const212 bool CFileBase::GetPosition(UInt64 &position) const throw()
213 {
214 LONG high = 0;
215 const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT);
216 if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
217 {
218 // for error case we can set (position) to (-1) or (0) or leave (position) unchanged.
219 // position = (UInt64)(Int64)-1; // for debug
220 position = 0;
221 return false;
222 }
223 position = (((UInt64)(UInt32)high) << 32) + low;
224 return true;
225 // we don't want recursed GetPosition()
226 // return Seek(0, FILE_CURRENT, position);
227 }
228
Seek(Int64 distanceToMove,DWORD moveMethod,UInt64 & newPosition) const229 bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()
230 {
231 #ifdef Z7_DEVICE_FILE
232 if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)
233 {
234 distanceToMove += Size;
235 moveMethod = FILE_BEGIN;
236 }
237 #endif
238
239 LONG high = (LONG)(distanceToMove >> 32);
240 const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
241 if (low == INVALID_SET_FILE_POINTER)
242 {
243 const DWORD lastError = ::GetLastError();
244 if (lastError != NO_ERROR)
245 {
246 // 21.07: we set (newPosition) to real position even after error.
247 GetPosition(newPosition);
248 SetLastError(lastError); // restore LastError
249 return false;
250 }
251 }
252 newPosition = (((UInt64)(UInt32)high) << 32) + low;
253 return true;
254 }
255
Seek(UInt64 position,UInt64 & newPosition) const256 bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()
257 {
258 return Seek((Int64)position, FILE_BEGIN, newPosition);
259 }
260
SeekToBegin() const261 bool CFileBase::SeekToBegin() const throw()
262 {
263 UInt64 newPosition = 0;
264 return Seek(0, newPosition) && (newPosition == 0);
265 }
266
SeekToEnd(UInt64 & newPosition) const267 bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()
268 {
269 return Seek(0, FILE_END, newPosition);
270 }
271
272 // ---------- CInFile ---------
273
274 #ifdef Z7_DEVICE_FILE
275
CorrectDeviceSize()276 void CInFile::CorrectDeviceSize()
277 {
278 // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail
279 const UInt32 kClusterSize = 1 << 14;
280 UInt64 pos = Size & ~(UInt64)(kClusterSize - 1);
281 UInt64 realNewPosition;
282 if (!Seek(pos, realNewPosition))
283 return;
284 Byte *buf = (Byte *)MidAlloc(kClusterSize);
285
286 bool needbackward = true;
287
288 for (;;)
289 {
290 UInt32 processed = 0;
291 // up test is slow for "PhysicalDrive".
292 // processed size for latest block for "PhysicalDrive0" is 0.
293 if (!Read1(buf, kClusterSize, processed))
294 break;
295 if (processed == 0)
296 break;
297 needbackward = false;
298 Size = pos + processed;
299 if (processed != kClusterSize)
300 break;
301 pos += kClusterSize;
302 }
303
304 if (needbackward && pos != 0)
305 {
306 pos -= kClusterSize;
307 for (;;)
308 {
309 // break;
310 if (!Seek(pos, realNewPosition))
311 break;
312 if (!buf)
313 {
314 buf = (Byte *)MidAlloc(kClusterSize);
315 if (!buf)
316 break;
317 }
318 UInt32 processed = 0;
319 // that code doesn't work for "PhysicalDrive0"
320 if (!Read1(buf, kClusterSize, processed))
321 break;
322 if (processed != 0)
323 {
324 Size = pos + processed;
325 break;
326 }
327 if (pos == 0)
328 break;
329 pos -= kClusterSize;
330 }
331 }
332 MidFree(buf);
333 }
334
335
CalcDeviceSize(CFSTR s)336 void CInFile::CalcDeviceSize(CFSTR s)
337 {
338 SizeDefined = false;
339 Size = 0;
340 if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile)
341 return;
342 #ifdef UNDER_CE
343
344 SizeDefined = true;
345 Size = 128 << 20;
346
347 #else
348
349 PARTITION_INFORMATION partInfo;
350 bool needCorrectSize = true;
351
352 /*
353 WinXP 64-bit:
354
355 HDD \\.\PhysicalDrive0 (MBR):
356 GetPartitionInfo == GeometryEx : corrrect size? (includes tail)
357 Geometry : smaller than GeometryEx (no tail, maybe correct too?)
358 MyGetDiskFreeSpace : FAIL
359 Size correction is slow and block size (kClusterSize) must be small?
360
361 HDD partition \\.\N: (NTFS):
362 MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction
363 GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS
364 Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition)
365
366 CD-ROM drive (ISO):
367 MyGetDiskFreeSpace : correct size. Same size can be calculated after correction
368 Geometry == CdRomGeometry : smaller than corrrect size
369 GetPartitionInfo == GeometryEx : larger than corrrect size
370
371 Floppy \\.\a: (FAT):
372 Geometry : correct size.
373 CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL
374 correction works OK for FAT.
375 correction works OK for non-FAT, if kClusterSize = 512.
376 */
377
378 if (GetPartitionInfo(&partInfo))
379 {
380 Size = (UInt64)partInfo.PartitionLength.QuadPart;
381 SizeDefined = true;
382 needCorrectSize = false;
383 if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
384 {
385 FChar path[4] = { s[4], ':', '\\', 0 };
386 UInt64 clusterSize, totalSize, freeSize;
387 if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize))
388 Size = totalSize;
389 else
390 needCorrectSize = true;
391 }
392 }
393
394 if (!SizeDefined)
395 {
396 my_DISK_GEOMETRY_EX geomEx;
397 SizeDefined = GetGeometryEx(&geomEx);
398 if (SizeDefined)
399 Size = (UInt64)geomEx.DiskSize.QuadPart;
400 else
401 {
402 DISK_GEOMETRY geom;
403 SizeDefined = GetGeometry(&geom);
404 if (!SizeDefined)
405 SizeDefined = GetCdRomGeometry(&geom);
406 if (SizeDefined)
407 Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
408 }
409 }
410
411 if (needCorrectSize && SizeDefined && Size != 0)
412 {
413 CorrectDeviceSize();
414 SeekToBegin();
415 }
416
417 // SeekToBegin();
418 #endif
419 }
420
421 // ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
422
423 #define MY_DEVICE_EXTRA_CODE \
424 IsDeviceFile = IsDevicePath(fileName); \
425 CalcDeviceSize(fileName);
426 #else
427 #define MY_DEVICE_EXTRA_CODE
428 #endif
429
Open(CFSTR fileName,DWORD shareMode,DWORD creationDisposition,DWORD flagsAndAttributes)430 bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
431 {
432 DWORD desiredAccess = GENERIC_READ;
433
434 #ifdef _WIN32
435 if (PreserveATime)
436 desiredAccess |= FILE_WRITE_ATTRIBUTES;
437 #endif
438
439 bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
440
441 #ifdef _WIN32
442 if (res && PreserveATime)
443 {
444 FILETIME ft;
445 ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF;
446 ::SetFileTime(_handle, NULL, &ft, NULL);
447 }
448 #endif
449
450 MY_DEVICE_EXTRA_CODE
451 return res;
452 }
453
OpenShared(CFSTR fileName,bool shareForWrite)454 bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite)
455 { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
456
Open(CFSTR fileName)457 bool CInFile::Open(CFSTR fileName)
458 { return OpenShared(fileName, false); }
459
460 // ReadFile and WriteFile functions in Windows have BUG:
461 // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
462 // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
463 // (Insufficient system resources exist to complete the requested service).
464
465 // Probably in some version of Windows there are problems with other sizes:
466 // for 32 MB (maybe also for 16 MB).
467 // And message can be "Network connection was lost"
468
469 static const UInt32 kChunkSizeMax = 1 << 22;
470
Read1(void * data,UInt32 size,UInt32 & processedSize)471 bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()
472 {
473 DWORD processedLoc = 0;
474 const bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
475 processedSize = (UInt32)processedLoc;
476 return res;
477 }
478
ReadPart(void * data,UInt32 size,UInt32 & processedSize)479 bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw()
480 {
481 #if 0
482 const UInt32 chunkSizeMax = (0 || IsStdStream) ? (1 << 20) : kChunkSizeMax;
483 if (size > chunkSizeMax)
484 size = chunkSizeMax;
485 #else
486 if (size > kChunkSizeMax)
487 size = kChunkSizeMax;
488 #endif
489 return Read1(data, size, processedSize);
490 }
491
Read(void * data,UInt32 size,UInt32 & processedSize)492 bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()
493 {
494 processedSize = 0;
495 do
496 {
497 UInt32 processedLoc = 0;
498 const bool res = ReadPart(data, size, processedLoc);
499 processedSize += processedLoc;
500 if (!res)
501 return false;
502 if (processedLoc == 0)
503 return true;
504 data = (void *)((Byte *)data + processedLoc);
505 size -= processedLoc;
506 }
507 while (size);
508 return true;
509 }
510
ReadFull(void * data,size_t size,size_t & processedSize)511 bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw()
512 {
513 processedSize = 0;
514 do
515 {
516 UInt32 processedLoc = 0;
517 const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size);
518 const bool res = Read1(data, sizeLoc, processedLoc);
519 processedSize += processedLoc;
520 if (!res)
521 return false;
522 if (processedLoc == 0)
523 return true;
524 data = (void *)((Byte *)data + processedLoc);
525 size -= processedLoc;
526 }
527 while (size);
528 return true;
529 }
530
531 // ---------- COutFile ---------
532
Open(CFSTR fileName,DWORD shareMode,DWORD creationDisposition,DWORD flagsAndAttributes)533 bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
534 { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
535
Open_Disposition(CFSTR fileName,DWORD creationDisposition)536 bool COutFile::Open_Disposition(CFSTR fileName, DWORD creationDisposition)
537 { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
538
Create_ALWAYS_with_Attribs(CFSTR fileName,DWORD flagsAndAttributes)539 bool COutFile::Create_ALWAYS_with_Attribs(CFSTR fileName, DWORD flagsAndAttributes)
540 { return Open(fileName, FILE_SHARE_READ, CREATE_ALWAYS, flagsAndAttributes); }
541
SetTime(const FILETIME * cTime,const FILETIME * aTime,const FILETIME * mTime)542 bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw()
543 { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
544
SetMTime(const FILETIME * mTime)545 bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); }
546
WritePart(const void * data,UInt32 size,UInt32 & processedSize)547 bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw()
548 {
549 if (size > kChunkSizeMax)
550 size = kChunkSizeMax;
551 DWORD processedLoc = 0;
552 bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
553 processedSize = (UInt32)processedLoc;
554 return res;
555 }
556
Write(const void * data,UInt32 size,UInt32 & processedSize)557 bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
558 {
559 processedSize = 0;
560 do
561 {
562 UInt32 processedLoc = 0;
563 const bool res = WritePart(data, size, processedLoc);
564 processedSize += processedLoc;
565 if (!res)
566 return false;
567 if (processedLoc == 0)
568 return true;
569 data = (const void *)((const Byte *)data + processedLoc);
570 size -= processedLoc;
571 }
572 while (size);
573 return true;
574 }
575
WriteFull(const void * data,size_t size)576 bool COutFile::WriteFull(const void *data, size_t size) throw()
577 {
578 do
579 {
580 UInt32 processedLoc = 0;
581 const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size);
582 if (!WritePart(data, sizeCur, processedLoc))
583 return false;
584 if (processedLoc == 0)
585 return (size == 0);
586 data = (const void *)((const Byte *)data + processedLoc);
587 size -= processedLoc;
588 }
589 while (size);
590 return true;
591 }
592
SetEndOfFile()593 bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); }
594
SetLength(UInt64 length)595 bool COutFile::SetLength(UInt64 length) throw()
596 {
597 UInt64 newPosition;
598 if (!Seek(length, newPosition))
599 return false;
600 if (newPosition != length)
601 return false;
602 return SetEndOfFile();
603 }
604
SetLength_KeepPosition(UInt64 length)605 bool COutFile::SetLength_KeepPosition(UInt64 length) throw()
606 {
607 UInt64 currentPos = 0;
608 if (!GetPosition(currentPos))
609 return false;
610 DWORD lastError = 0;
611 const bool result = SetLength(length);
612 if (!result)
613 lastError = GetLastError();
614 UInt64 currentPos2;
615 const bool result2 = Seek(currentPos, currentPos2);
616 if (lastError != 0)
617 SetLastError(lastError);
618 return (result && result2);
619 }
620
621 }}}
622
623 #else // _WIN32
624
625
626 // POSIX
627
628 #include <fcntl.h>
629 #include <unistd.h>
630
631 namespace NWindows {
632 namespace NFile {
633
634 namespace NDir {
635 bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
636 }
637
638 namespace NIO {
639
OpenBinary(const char * name,int flags,mode_t mode)640 bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode)
641 {
642 #ifdef O_BINARY
643 flags |= O_BINARY;
644 #endif
645
646 Close();
647 _handle = ::open(name, flags, mode);
648 return _handle != -1;
649
650 /*
651 if (_handle == -1)
652 return false;
653 if (IsString1PrefixedByString2(name, "/dev/"))
654 {
655 // /dev/sda
656 // IsDeviceFile = true; // for debug
657 // SizeDefined = false;
658 // SizeDefined = (GetDeviceSize_InBytes(Size) == 0);
659 }
660 return true;
661 */
662 }
663
Close()664 bool CFileBase::Close()
665 {
666 if (_handle == -1)
667 return true;
668 if (close(_handle) != 0)
669 return false;
670 _handle = -1;
671 /*
672 IsDeviceFile = false;
673 SizeDefined = false;
674 */
675 return true;
676 }
677
GetLength(UInt64 & length) const678 bool CFileBase::GetLength(UInt64 &length) const
679 {
680 length = 0;
681 // length = (UInt64)(Int64)-1; // for debug
682 const off_t curPos = seekToCur();
683 if (curPos == -1)
684 return false;
685 const off_t lengthTemp = seek(0, SEEK_END);
686 seek(curPos, SEEK_SET);
687 length = (UInt64)lengthTemp;
688
689 /*
690 // 22.00:
691 if (lengthTemp == 1)
692 if (IsDeviceFile && SizeDefined)
693 {
694 length = Size;
695 return true;
696 }
697 */
698
699 return (lengthTemp != -1);
700 }
701
seek(off_t distanceToMove,int moveMethod) const702 off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const
703 {
704 /*
705 if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END)
706 {
707 printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
708 distanceToMove += Size;
709 moveMethod = SEEK_SET;
710 }
711 */
712
713 // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove);
714 // off_t res = ::lseek(_handle, distanceToMove, moveMethod);
715 // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
716 return ::lseek(_handle, distanceToMove, moveMethod);
717 // return res;
718 }
719
seekToBegin() const720 off_t CFileBase::seekToBegin() const throw()
721 {
722 return seek(0, SEEK_SET);
723 }
724
seekToCur() const725 off_t CFileBase::seekToCur() const throw()
726 {
727 return seek(0, SEEK_CUR);
728 }
729
730 /*
731 bool CFileBase::SeekToBegin() const throw()
732 {
733 return (::seek(0, SEEK_SET) != -1);
734 }
735 */
736
737
738 /////////////////////////
739 // CInFile
740
Open(const char * name)741 bool CInFile::Open(const char *name)
742 {
743 return CFileBase::OpenBinary(name, O_RDONLY);
744 }
745
OpenShared(const char * name,bool)746 bool CInFile::OpenShared(const char *name, bool)
747 {
748 return Open(name);
749 }
750
751
752 /*
753 int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks)
754 {
755 // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition
756 // #include <linux/fs.h>
757 return ioctl(_handle, BLKGETSIZE64, numBlocks);
758 // in block size
759 }
760
761 int CFileBase::GetDeviceSize_InBytes(UInt64 &size)
762 {
763 size = 0;
764 unsigned long long numBlocks;
765 int res = my_ioctl_BLKGETSIZE64(&numBlocks);
766 if (res == 0)
767 size = numBlocks; // another blockSize s possible?
768 printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size);
769 return res;
770 }
771 */
772
773 /*
774 On Linux (32-bit and 64-bit):
775 read(), write() (and similar system calls) will transfer at most
776 0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred.
777 */
778
779 static const size_t kChunkSizeMax = ((size_t)1 << 22);
780
read_part(void * data,size_t size)781 ssize_t CInFile::read_part(void *data, size_t size) throw()
782 {
783 if (size > kChunkSizeMax)
784 size = kChunkSizeMax;
785 return ::read(_handle, data, size);
786 }
787
ReadFull(void * data,size_t size,size_t & processed)788 bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw()
789 {
790 processed = 0;
791 do
792 {
793 const ssize_t res = read_part(data, size);
794 if (res < 0)
795 return false;
796 if (res == 0)
797 break;
798 data = (void *)((Byte *)data + (size_t)res);
799 processed += (size_t)res;
800 size -= (size_t)res;
801 }
802 while (size);
803 return true;
804 }
805
806
807 /////////////////////////
808 // COutFile
809
OpenBinary_forWrite_oflag(const char * name,int oflag)810 bool COutFile::OpenBinary_forWrite_oflag(const char *name, int oflag)
811 {
812 Path = name; // change it : set it only if open is success.
813 return OpenBinary(name, oflag, mode_for_Create);
814 }
815
816
817 /*
818 windows exist non-exist posix
819 CREATE_NEW Fail Create O_CREAT | O_EXCL
820 CREATE_ALWAYS Trunc Create O_CREAT | O_TRUNC
821 OPEN_ALWAYS Open Create O_CREAT
822 OPEN_EXISTING Open Fail 0
823 TRUNCATE_EXISTING Trunc Fail O_TRUNC ???
824
825 // O_CREAT = If the file exists, this flag has no effect except as noted under O_EXCL below.
826 // If O_CREAT and O_EXCL are set, open() shall fail if the file exists.
827 // O_TRUNC : If the file exists and the file is successfully opened, its length shall be truncated to 0.
828 */
Open_EXISTING(const char * name)829 bool COutFile::Open_EXISTING(const char *name)
830 { return OpenBinary_forWrite_oflag(name, O_WRONLY); }
Create_ALWAYS(const char * name)831 bool COutFile::Create_ALWAYS(const char *name)
832 { return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_TRUNC); }
Create_NEW(const char * name)833 bool COutFile::Create_NEW(const char *name)
834 { return OpenBinary_forWrite_oflag(name, O_WRONLY | O_CREAT | O_EXCL); }
Create_ALWAYS_or_Open_ALWAYS(const char * name,bool createAlways)835 bool COutFile::Create_ALWAYS_or_Open_ALWAYS(const char *name, bool createAlways)
836 {
837 return OpenBinary_forWrite_oflag(name,
838 createAlways ?
839 O_WRONLY | O_CREAT | O_TRUNC :
840 O_WRONLY | O_CREAT);
841 }
842 /*
843 bool COutFile::Create_ALWAYS_or_NEW(const char *name, bool createAlways)
844 {
845 return OpenBinary_forWrite_oflag(name,
846 createAlways ?
847 O_WRONLY | O_CREAT | O_TRUNC :
848 O_WRONLY | O_CREAT | O_EXCL);
849 }
850 bool COutFile::Open_Disposition(const char *name, DWORD creationDisposition)
851 {
852 int flag;
853 switch (creationDisposition)
854 {
855 case CREATE_NEW: flag = O_WRONLY | O_CREAT | O_EXCL; break;
856 case CREATE_ALWAYS: flag = O_WRONLY | O_CREAT | O_TRUNC; break;
857 case OPEN_ALWAYS: flag = O_WRONLY | O_CREAT; break;
858 case OPEN_EXISTING: flag = O_WRONLY; break;
859 case TRUNCATE_EXISTING: flag = O_WRONLY | O_TRUNC; break;
860 default:
861 SetLastError(EINVAL);
862 return false;
863 }
864 return OpenBinary_forWrite_oflag(name, flag);
865 }
866 */
867
write_part(const void * data,size_t size)868 ssize_t COutFile::write_part(const void *data, size_t size) throw()
869 {
870 if (size > kChunkSizeMax)
871 size = kChunkSizeMax;
872 return ::write(_handle, data, size);
873 }
874
write_full(const void * data,size_t size,size_t & processed)875 ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw()
876 {
877 processed = 0;
878 do
879 {
880 const ssize_t res = write_part(data, size);
881 if (res < 0)
882 return res;
883 if (res == 0)
884 break;
885 data = (const void *)((const Byte *)data + (size_t)res);
886 processed += (size_t)res;
887 size -= (size_t)res;
888 }
889 while (size);
890 return (ssize_t)processed;
891 }
892
SetLength(UInt64 length)893 bool COutFile::SetLength(UInt64 length) throw()
894 {
895 const off_t len2 = (off_t)length;
896 if ((Int64)length != len2)
897 {
898 SetLastError(EFBIG);
899 return false;
900 }
901 // The value of the seek pointer shall not be modified by a call to ftruncate().
902 const int iret = ftruncate(_handle, len2);
903 return (iret == 0);
904 }
905
Close()906 bool COutFile::Close()
907 {
908 const bool res = CFileBase::Close();
909 if (!res)
910 return res;
911 if (CTime_defined || ATime_defined || MTime_defined)
912 {
913 /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path,
914 CTime_defined ? &CTime : NULL,
915 ATime_defined ? &ATime : NULL,
916 MTime_defined ? &MTime : NULL);
917 }
918 return res;
919 }
920
SetTime(const CFiTime * cTime,const CFiTime * aTime,const CFiTime * mTime)921 bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw()
922 {
923 // On some OS (cygwin, MacOSX ...), you must close the file before updating times
924 // return true;
925
926 if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false;
927 if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false;
928 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
929 return true;
930
931 /*
932 struct timespec times[2];
933 UNUSED_VAR(cTime)
934 if (!aTime && !mTime)
935 return true;
936 bool needChange;
937 needChange = FiTime_To_timespec(aTime, times[0]);
938 needChange |= FiTime_To_timespec(mTime, times[1]);
939 if (!needChange)
940 return true;
941 return futimens(_handle, times) == 0;
942 */
943 }
944
SetMTime(const CFiTime * mTime)945 bool COutFile::SetMTime(const CFiTime *mTime) throw()
946 {
947 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
948 return true;
949 }
950
951 }}}
952
953
954 #endif
955