1 // Windows/FileIO.cpp
2
3 #include "StdAfx.h"
4
5 #ifdef SUPPORT_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 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 SUPPORT_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 SUPPORT_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 WIN_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 _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 (!::CloseHandle(_handle))
145 return false;
146 _handle = INVALID_HANDLE_VALUE;
147 return true;
148 }
149
GetLength(UInt64 & length) const150 bool CFileBase::GetLength(UInt64 &length) const throw()
151 {
152 #ifdef SUPPORT_DEVICE_FILE
153 if (IsDeviceFile && SizeDefined)
154 {
155 length = Size;
156 return true;
157 }
158 #endif
159
160 DWORD high = 0;
161 const DWORD low = ::GetFileSize(_handle, &high);
162 if (low == INVALID_FILE_SIZE)
163 if (::GetLastError() != NO_ERROR)
164 return false;
165 length = (((UInt64)high) << 32) + low;
166 return true;
167
168 /*
169 LARGE_INTEGER fileSize;
170 // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+
171 if (!GetFileSizeEx(_handle, &fileSize))
172 return false;
173 length = (UInt64)fileSize.QuadPart;
174 return true;
175 */
176 }
177
178
179 /* Specification for SetFilePointer():
180
181 If a new file pointer is a negative value,
182 {
183 the function fails,
184 the file pointer is not moved,
185 the code returned by GetLastError() is ERROR_NEGATIVE_SEEK.
186 }
187
188 If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set
189 {
190 an application can move the file pointer only to sector-aligned positions.
191 A sector-aligned position is a position that is a whole number multiple of
192 the volume sector size.
193 An application can obtain a volume sector size by calling the GetDiskFreeSpace.
194 }
195
196 It is not an error to set a file pointer to a position beyond the end of the file.
197 The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function.
198
199 If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL,
200 an application must call GetLastError to determine whether or not the function has succeeded or failed.
201 */
202
GetPosition(UInt64 & position) const203 bool CFileBase::GetPosition(UInt64 &position) const throw()
204 {
205 LONG high = 0;
206 const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT);
207 if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
208 {
209 // for error case we can set (position) to (-1) or (0) or leave (position) unchanged.
210 // position = (UInt64)(Int64)-1; // for debug
211 position = 0;
212 return false;
213 }
214 position = (((UInt64)(UInt32)high) << 32) + low;
215 return true;
216 // we don't want recursed GetPosition()
217 // return Seek(0, FILE_CURRENT, position);
218 }
219
Seek(Int64 distanceToMove,DWORD moveMethod,UInt64 & newPosition) const220 bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()
221 {
222 #ifdef SUPPORT_DEVICE_FILE
223 if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)
224 {
225 distanceToMove += Size;
226 moveMethod = FILE_BEGIN;
227 }
228 #endif
229
230 LONG high = (LONG)(distanceToMove >> 32);
231 const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
232 if (low == INVALID_SET_FILE_POINTER)
233 {
234 const DWORD lastError = ::GetLastError();
235 if (lastError != NO_ERROR)
236 {
237 // 21.07: we set (newPosition) to real position even after error.
238 GetPosition(newPosition);
239 SetLastError(lastError); // restore LastError
240 return false;
241 }
242 }
243 newPosition = (((UInt64)(UInt32)high) << 32) + low;
244 return true;
245 }
246
Seek(UInt64 position,UInt64 & newPosition) const247 bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()
248 {
249 return Seek((Int64)position, FILE_BEGIN, newPosition);
250 }
251
SeekToBegin() const252 bool CFileBase::SeekToBegin() const throw()
253 {
254 UInt64 newPosition = 0;
255 return Seek(0, newPosition) && (newPosition == 0);
256 }
257
SeekToEnd(UInt64 & newPosition) const258 bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()
259 {
260 return Seek(0, FILE_END, newPosition);
261 }
262
263 // ---------- CInFile ---------
264
265 #ifdef SUPPORT_DEVICE_FILE
266
CorrectDeviceSize()267 void CInFile::CorrectDeviceSize()
268 {
269 // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail
270 static const UInt32 kClusterSize = 1 << 14;
271 UInt64 pos = Size & ~(UInt64)(kClusterSize - 1);
272 UInt64 realNewPosition;
273 if (!Seek(pos, realNewPosition))
274 return;
275 Byte *buf = (Byte *)MidAlloc(kClusterSize);
276
277 bool needbackward = true;
278
279 for (;;)
280 {
281 UInt32 processed = 0;
282 // up test is slow for "PhysicalDrive".
283 // processed size for latest block for "PhysicalDrive0" is 0.
284 if (!Read1(buf, kClusterSize, processed))
285 break;
286 if (processed == 0)
287 break;
288 needbackward = false;
289 Size = pos + processed;
290 if (processed != kClusterSize)
291 break;
292 pos += kClusterSize;
293 }
294
295 if (needbackward && pos != 0)
296 {
297 pos -= kClusterSize;
298 for (;;)
299 {
300 // break;
301 if (!Seek(pos, realNewPosition))
302 break;
303 if (!buf)
304 {
305 buf = (Byte *)MidAlloc(kClusterSize);
306 if (!buf)
307 break;
308 }
309 UInt32 processed = 0;
310 // that code doesn't work for "PhysicalDrive0"
311 if (!Read1(buf, kClusterSize, processed))
312 break;
313 if (processed != 0)
314 {
315 Size = pos + processed;
316 break;
317 }
318 if (pos == 0)
319 break;
320 pos -= kClusterSize;
321 }
322 }
323 MidFree(buf);
324 }
325
326
CalcDeviceSize(CFSTR s)327 void CInFile::CalcDeviceSize(CFSTR s)
328 {
329 SizeDefined = false;
330 Size = 0;
331 if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile)
332 return;
333 #ifdef UNDER_CE
334
335 SizeDefined = true;
336 Size = 128 << 20;
337
338 #else
339
340 PARTITION_INFORMATION partInfo;
341 bool needCorrectSize = true;
342
343 /*
344 WinXP 64-bit:
345
346 HDD \\.\PhysicalDrive0 (MBR):
347 GetPartitionInfo == GeometryEx : corrrect size? (includes tail)
348 Geometry : smaller than GeometryEx (no tail, maybe correct too?)
349 MyGetDiskFreeSpace : FAIL
350 Size correction is slow and block size (kClusterSize) must be small?
351
352 HDD partition \\.\N: (NTFS):
353 MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction
354 GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS
355 Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition)
356
357 CD-ROM drive (ISO):
358 MyGetDiskFreeSpace : correct size. Same size can be calculated after correction
359 Geometry == CdRomGeometry : smaller than corrrect size
360 GetPartitionInfo == GeometryEx : larger than corrrect size
361
362 Floppy \\.\a: (FAT):
363 Geometry : correct size.
364 CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL
365 correction works OK for FAT.
366 correction works OK for non-FAT, if kClusterSize = 512.
367 */
368
369 if (GetPartitionInfo(&partInfo))
370 {
371 Size = (UInt64)partInfo.PartitionLength.QuadPart;
372 SizeDefined = true;
373 needCorrectSize = false;
374 if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
375 {
376 FChar path[4] = { s[4], ':', '\\', 0 };
377 UInt64 clusterSize, totalSize, freeSize;
378 if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize))
379 Size = totalSize;
380 else
381 needCorrectSize = true;
382 }
383 }
384
385 if (!SizeDefined)
386 {
387 my_DISK_GEOMETRY_EX geomEx;
388 SizeDefined = GetGeometryEx(&geomEx);
389 if (SizeDefined)
390 Size = (UInt64)geomEx.DiskSize.QuadPart;
391 else
392 {
393 DISK_GEOMETRY geom;
394 SizeDefined = GetGeometry(&geom);
395 if (!SizeDefined)
396 SizeDefined = GetCdRomGeometry(&geom);
397 if (SizeDefined)
398 Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
399 }
400 }
401
402 if (needCorrectSize && SizeDefined && Size != 0)
403 {
404 CorrectDeviceSize();
405 SeekToBegin();
406 }
407
408 // SeekToBegin();
409 #endif
410 }
411
412 // ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
413
414 #define MY_DEVICE_EXTRA_CODE \
415 IsDeviceFile = IsDevicePath(fileName); \
416 CalcDeviceSize(fileName);
417 #else
418 #define MY_DEVICE_EXTRA_CODE
419 #endif
420
Open(CFSTR fileName,DWORD shareMode,DWORD creationDisposition,DWORD flagsAndAttributes)421 bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
422 {
423 DWORD desiredAccess = GENERIC_READ;
424
425 #ifdef _WIN32
426 if (PreserveATime)
427 desiredAccess |= FILE_WRITE_ATTRIBUTES;
428 #endif
429
430 bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
431
432 #ifdef _WIN32
433 if (res && PreserveATime)
434 {
435 FILETIME ft;
436 ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF;
437 ::SetFileTime(_handle, NULL, &ft, NULL);
438 }
439 #endif
440
441 MY_DEVICE_EXTRA_CODE
442 return res;
443 }
444
OpenShared(CFSTR fileName,bool shareForWrite)445 bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite)
446 { return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
447
Open(CFSTR fileName)448 bool CInFile::Open(CFSTR fileName)
449 { return OpenShared(fileName, false); }
450
451 // ReadFile and WriteFile functions in Windows have BUG:
452 // If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
453 // from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
454 // (Insufficient system resources exist to complete the requested service).
455
456 // Probably in some version of Windows there are problems with other sizes:
457 // for 32 MB (maybe also for 16 MB).
458 // And message can be "Network connection was lost"
459
460 static const UInt32 kChunkSizeMax = (1 << 22);
461
Read1(void * data,UInt32 size,UInt32 & processedSize)462 bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()
463 {
464 DWORD processedLoc = 0;
465 bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
466 processedSize = (UInt32)processedLoc;
467 return res;
468 }
469
ReadPart(void * data,UInt32 size,UInt32 & processedSize)470 bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw()
471 {
472 if (size > kChunkSizeMax)
473 size = kChunkSizeMax;
474 return Read1(data, size, processedSize);
475 }
476
Read(void * data,UInt32 size,UInt32 & processedSize)477 bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()
478 {
479 processedSize = 0;
480 do
481 {
482 UInt32 processedLoc = 0;
483 bool res = ReadPart(data, size, processedLoc);
484 processedSize += processedLoc;
485 if (!res)
486 return false;
487 if (processedLoc == 0)
488 return true;
489 data = (void *)((unsigned char *)data + processedLoc);
490 size -= processedLoc;
491 }
492 while (size > 0);
493 return true;
494 }
495
ReadFull(void * data,size_t size,size_t & processedSize)496 bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw()
497 {
498 processedSize = 0;
499 do
500 {
501 UInt32 processedLoc = 0;
502 const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size);
503 const bool res = Read1(data, sizeLoc, processedLoc);
504 processedSize += processedLoc;
505 if (!res)
506 return false;
507 if (processedLoc == 0)
508 return true;
509 data = (void *)((unsigned char *)data + processedLoc);
510 size -= processedLoc;
511 }
512 while (size > 0);
513 return true;
514 }
515
516 // ---------- COutFile ---------
517
GetCreationDisposition(bool createAlways)518 static inline DWORD GetCreationDisposition(bool createAlways)
519 { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
520
Open(CFSTR fileName,DWORD shareMode,DWORD creationDisposition,DWORD flagsAndAttributes)521 bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
522 { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
523
Open(CFSTR fileName,DWORD creationDisposition)524 bool COutFile::Open(CFSTR fileName, DWORD creationDisposition)
525 { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
526
Create(CFSTR fileName,bool createAlways)527 bool COutFile::Create(CFSTR fileName, bool createAlways)
528 { return Open(fileName, GetCreationDisposition(createAlways)); }
529
CreateAlways(CFSTR fileName,DWORD flagsAndAttributes)530 bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes)
531 { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), flagsAndAttributes); }
532
SetTime(const FILETIME * cTime,const FILETIME * aTime,const FILETIME * mTime)533 bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw()
534 { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
535
SetMTime(const FILETIME * mTime)536 bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); }
537
WritePart(const void * data,UInt32 size,UInt32 & processedSize)538 bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw()
539 {
540 if (size > kChunkSizeMax)
541 size = kChunkSizeMax;
542 DWORD processedLoc = 0;
543 bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
544 processedSize = (UInt32)processedLoc;
545 return res;
546 }
547
Write(const void * data,UInt32 size,UInt32 & processedSize)548 bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
549 {
550 processedSize = 0;
551 do
552 {
553 UInt32 processedLoc = 0;
554 bool res = WritePart(data, size, processedLoc);
555 processedSize += processedLoc;
556 if (!res)
557 return false;
558 if (processedLoc == 0)
559 return true;
560 data = (const void *)((const unsigned char *)data + processedLoc);
561 size -= processedLoc;
562 }
563 while (size != 0);
564 return true;
565 }
566
WriteFull(const void * data,size_t size)567 bool COutFile::WriteFull(const void *data, size_t size) throw()
568 {
569 do
570 {
571 UInt32 processedLoc = 0;
572 const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size);
573 if (!WritePart(data, sizeCur, processedLoc))
574 return false;
575 if (processedLoc == 0)
576 return (size == 0);
577 data = (const void *)((const unsigned char *)data + processedLoc);
578 size -= processedLoc;
579 }
580 while (size != 0);
581 return true;
582 }
583
SetEndOfFile()584 bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); }
585
SetLength(UInt64 length)586 bool COutFile::SetLength(UInt64 length) throw()
587 {
588 UInt64 newPosition;
589 if (!Seek(length, newPosition))
590 return false;
591 if (newPosition != length)
592 return false;
593 return SetEndOfFile();
594 }
595
SetLength_KeepPosition(UInt64 length)596 bool COutFile::SetLength_KeepPosition(UInt64 length) throw()
597 {
598 UInt64 currentPos = 0;
599 if (!GetPosition(currentPos))
600 return false;
601 DWORD lastError = 0;
602 const bool result = SetLength(length);
603 if (!result)
604 lastError = GetLastError();
605 UInt64 currentPos2;
606 const bool result2 = Seek(currentPos, currentPos2);
607 if (lastError != 0)
608 SetLastError(lastError);
609 return (result && result2);
610 }
611
612 }}}
613
614 #else // _WIN32
615
616
617 // POSIX
618
619 #include <fcntl.h>
620 #include <unistd.h>
621
622 namespace NWindows {
623 namespace NFile {
624
625 namespace NDir {
626 bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
627 }
628
629 namespace NIO {
630
OpenBinary(const char * name,int flags)631 bool CFileBase::OpenBinary(const char *name, int flags)
632 {
633 #ifdef O_BINARY
634 flags |= O_BINARY;
635 #endif
636
637 Close();
638 _handle = ::open(name, flags, 0666);
639 return _handle != -1;
640
641 /*
642 if (_handle == -1)
643 return false;
644 if (IsString1PrefixedByString2(name, "/dev/"))
645 {
646 // /dev/sda
647 // IsDeviceFile = true; // for debug
648 // SizeDefined = false;
649 // SizeDefined = (GetDeviceSize_InBytes(Size) == 0);
650 }
651 return true;
652 */
653 }
654
Close()655 bool CFileBase::Close()
656 {
657 if (_handle == -1)
658 return true;
659 if (close(_handle) != 0)
660 return false;
661 _handle = -1;
662 /*
663 IsDeviceFile = false;
664 SizeDefined = false;
665 */
666 return true;
667 }
668
GetLength(UInt64 & length) const669 bool CFileBase::GetLength(UInt64 &length) const
670 {
671 length = 0;
672 // length = (UInt64)(Int64)-1; // for debug
673 const off_t curPos = seekToCur();
674 if (curPos == -1)
675 return false;
676 const off_t lengthTemp = seek(0, SEEK_END);
677 seek(curPos, SEEK_SET);
678 length = (UInt64)lengthTemp;
679
680 /*
681 // 22.00:
682 if (lengthTemp == 1)
683 if (IsDeviceFile && SizeDefined)
684 {
685 length = Size;
686 return true;
687 }
688 */
689
690 return (lengthTemp != -1);
691 }
692
seek(off_t distanceToMove,int moveMethod) const693 off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const
694 {
695 /*
696 if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END)
697 {
698 printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
699 distanceToMove += Size;
700 moveMethod = SEEK_SET;
701 }
702 */
703
704 // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove);
705 // off_t res = ::lseek(_handle, distanceToMove, moveMethod);
706 // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
707 return ::lseek(_handle, distanceToMove, moveMethod);
708 // return res;
709 }
710
seekToBegin() const711 off_t CFileBase::seekToBegin() const throw()
712 {
713 return seek(0, SEEK_SET);
714 }
715
seekToCur() const716 off_t CFileBase::seekToCur() const throw()
717 {
718 return seek(0, SEEK_CUR);
719 }
720
721 /*
722 bool CFileBase::SeekToBegin() const throw()
723 {
724 return (::seek(0, SEEK_SET) != -1);
725 }
726 */
727
728
729 /////////////////////////
730 // CInFile
731
Open(const char * name)732 bool CInFile::Open(const char *name)
733 {
734 return CFileBase::OpenBinary(name, O_RDONLY);
735 }
736
OpenShared(const char * name,bool)737 bool CInFile::OpenShared(const char *name, bool)
738 {
739 return Open(name);
740 }
741
742
743 /*
744 int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks)
745 {
746 // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition
747 // #include <linux/fs.h>
748 return ioctl(_handle, BLKGETSIZE64, numBlocks);
749 // in block size
750 }
751
752 int CFileBase::GetDeviceSize_InBytes(UInt64 &size)
753 {
754 size = 0;
755 unsigned long long numBlocks;
756 int res = my_ioctl_BLKGETSIZE64(&numBlocks);
757 if (res == 0)
758 size = numBlocks; // another blockSize s possible?
759 printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size);
760 return res;
761 }
762 */
763
764 /*
765 On Linux (32-bit and 64-bit):
766 read(), write() (and similar system calls) will transfer at most
767 0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred.
768 */
769
770 static const size_t kChunkSizeMax = ((size_t)1 << 22);
771
read_part(void * data,size_t size)772 ssize_t CInFile::read_part(void *data, size_t size) throw()
773 {
774 if (size > kChunkSizeMax)
775 size = kChunkSizeMax;
776 return ::read(_handle, data, size);
777 }
778
ReadFull(void * data,size_t size,size_t & processed)779 bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw()
780 {
781 processed = 0;
782 do
783 {
784 const ssize_t res = read_part(data, size);
785 if (res < 0)
786 return false;
787 if (res == 0)
788 break;
789 data = (void *)((unsigned char *)data + (size_t)res);
790 size -= (size_t)res;
791 processed += (size_t)res;
792 }
793 while (size > 0);
794 return true;
795 }
796
797
798 /////////////////////////
799 // COutFile
800
Create(const char * name,bool createAlways)801 bool COutFile::Create(const char *name, bool createAlways)
802 {
803 Path = name; // change it : set it only if open is success.
804 if (createAlways)
805 {
806 Close();
807 _handle = ::creat(name, 0666);
808 return _handle != -1;
809 }
810 return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);
811 }
812
Open(const char * name,DWORD creationDisposition)813 bool COutFile::Open(const char *name, DWORD creationDisposition)
814 {
815 UNUSED_VAR(creationDisposition) // FIXME
816 return Create(name, false);
817 }
818
write_part(const void * data,size_t size)819 ssize_t COutFile::write_part(const void *data, size_t size) throw()
820 {
821 if (size > kChunkSizeMax)
822 size = kChunkSizeMax;
823 return ::write(_handle, data, size);
824 }
825
write_full(const void * data,size_t size,size_t & processed)826 ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw()
827 {
828 processed = 0;
829 do
830 {
831 const ssize_t res = write_part(data, size);
832 if (res < 0)
833 return res;
834 if (res == 0)
835 break;
836 data = (const void *)((const unsigned char *)data + (size_t)res);
837 size -= (size_t)res;
838 processed += (size_t)res;
839 }
840 while (size > 0);
841 return (ssize_t)processed;
842 }
843
SetLength(UInt64 length)844 bool COutFile::SetLength(UInt64 length) throw()
845 {
846 const off_t len2 = (off_t)length;
847 if ((Int64)length != len2)
848 {
849 SetLastError(EFBIG);
850 return false;
851 }
852 // The value of the seek pointer shall not be modified by a call to ftruncate().
853 int iret = ftruncate(_handle, len2);
854 return (iret == 0);
855 }
856
Close()857 bool COutFile::Close()
858 {
859 bool res = CFileBase::Close();
860 if (!res)
861 return res;
862 if (CTime_defined || ATime_defined || MTime_defined)
863 {
864 /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path,
865 CTime_defined ? &CTime : NULL,
866 ATime_defined ? &ATime : NULL,
867 MTime_defined ? &MTime : NULL);
868 }
869 return res;
870 }
871
SetTime(const CFiTime * cTime,const CFiTime * aTime,const CFiTime * mTime)872 bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw()
873 {
874 // On some OS (cygwin, MacOSX ...), you must close the file before updating times
875 // return true;
876
877 if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false;
878 if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false;
879 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
880 return true;
881
882 /*
883 struct timespec times[2];
884 UNUSED_VAR(cTime)
885 if (!aTime && !mTime)
886 return true;
887 bool needChange;
888 needChange = FiTime_To_timespec(aTime, times[0]);
889 needChange |= FiTime_To_timespec(mTime, times[1]);
890 if (!needChange)
891 return true;
892 return futimens(_handle, times) == 0;
893 */
894 }
895
SetMTime(const CFiTime * mTime)896 bool COutFile::SetMTime(const CFiTime *mTime) throw()
897 {
898 if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
899 return true;
900 }
901
902 }}}
903
904
905 #endif
906