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