1370b324cSopenharmony_ci// Windows/FileIO.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#ifdef Z7_DEVICE_FILE
6370b324cSopenharmony_ci#include "../../C/Alloc.h"
7370b324cSopenharmony_ci#endif
8370b324cSopenharmony_ci
9370b324cSopenharmony_ci// #include <stdio.h>
10370b324cSopenharmony_ci
11370b324cSopenharmony_ci/*
12370b324cSopenharmony_ci#ifndef _WIN32
13370b324cSopenharmony_ci// for ioctl BLKGETSIZE64
14370b324cSopenharmony_ci#include <sys/ioctl.h>
15370b324cSopenharmony_ci#include <linux/fs.h>
16370b324cSopenharmony_ci#endif
17370b324cSopenharmony_ci*/
18370b324cSopenharmony_ci
19370b324cSopenharmony_ci#include "FileIO.h"
20370b324cSopenharmony_ci#include "FileName.h"
21370b324cSopenharmony_ci
22370b324cSopenharmony_ciHRESULT GetLastError_noZero_HRESULT()
23370b324cSopenharmony_ci{
24370b324cSopenharmony_ci  const DWORD res = ::GetLastError();
25370b324cSopenharmony_ci  if (res == 0)
26370b324cSopenharmony_ci    return E_FAIL;
27370b324cSopenharmony_ci  return HRESULT_FROM_WIN32(res);
28370b324cSopenharmony_ci}
29370b324cSopenharmony_ci
30370b324cSopenharmony_ci#ifdef _WIN32
31370b324cSopenharmony_ci
32370b324cSopenharmony_ci#ifndef _UNICODE
33370b324cSopenharmony_ciextern bool g_IsNT;
34370b324cSopenharmony_ci#endif
35370b324cSopenharmony_ci
36370b324cSopenharmony_ciusing namespace NWindows;
37370b324cSopenharmony_ciusing namespace NFile;
38370b324cSopenharmony_ciusing namespace NName;
39370b324cSopenharmony_ci
40370b324cSopenharmony_cinamespace NWindows {
41370b324cSopenharmony_cinamespace NFile {
42370b324cSopenharmony_ci
43370b324cSopenharmony_ci#ifdef Z7_DEVICE_FILE
44370b324cSopenharmony_ci
45370b324cSopenharmony_cinamespace NSystem
46370b324cSopenharmony_ci{
47370b324cSopenharmony_cibool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
48370b324cSopenharmony_ci}
49370b324cSopenharmony_ci#endif
50370b324cSopenharmony_ci
51370b324cSopenharmony_cinamespace NIO {
52370b324cSopenharmony_ci
53370b324cSopenharmony_ci/*
54370b324cSopenharmony_ciWinXP-64 CreateFile():
55370b324cSopenharmony_ci  ""             -  ERROR_PATH_NOT_FOUND
56370b324cSopenharmony_ci  :stream        -  OK
57370b324cSopenharmony_ci  .:stream       -  ERROR_PATH_NOT_FOUND
58370b324cSopenharmony_ci  .\:stream      -  OK
59370b324cSopenharmony_ci
60370b324cSopenharmony_ci  folder\:stream -  ERROR_INVALID_NAME
61370b324cSopenharmony_ci  folder:stream  -  OK
62370b324cSopenharmony_ci
63370b324cSopenharmony_ci  c:\:stream     -  OK
64370b324cSopenharmony_ci
65370b324cSopenharmony_ci  c::stream      -  ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 )
66370b324cSopenharmony_ci  c::stream      -  OK,                 if current dir is ROOT     ( c:\ )
67370b324cSopenharmony_ci*/
68370b324cSopenharmony_ci
69370b324cSopenharmony_cibool CFileBase::Create(CFSTR path, DWORD desiredAccess,
70370b324cSopenharmony_ci    DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
71370b324cSopenharmony_ci{
72370b324cSopenharmony_ci  if (!Close())
73370b324cSopenharmony_ci    return false;
74370b324cSopenharmony_ci
75370b324cSopenharmony_ci  #ifdef Z7_DEVICE_FILE
76370b324cSopenharmony_ci  IsDeviceFile = false;
77370b324cSopenharmony_ci  #endif
78370b324cSopenharmony_ci
79370b324cSopenharmony_ci  #ifndef _UNICODE
80370b324cSopenharmony_ci  if (!g_IsNT)
81370b324cSopenharmony_ci  {
82370b324cSopenharmony_ci    _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode,
83370b324cSopenharmony_ci        (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
84370b324cSopenharmony_ci  }
85370b324cSopenharmony_ci  else
86370b324cSopenharmony_ci  #endif
87370b324cSopenharmony_ci  {
88370b324cSopenharmony_ci    IF_USE_MAIN_PATH
89370b324cSopenharmony_ci      _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode,
90370b324cSopenharmony_ci        (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
91370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
92370b324cSopenharmony_ci    if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
93370b324cSopenharmony_ci    {
94370b324cSopenharmony_ci      UString superPath;
95370b324cSopenharmony_ci      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
96370b324cSopenharmony_ci        _handle = ::CreateFileW(superPath, desiredAccess, shareMode,
97370b324cSopenharmony_ci            (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
98370b324cSopenharmony_ci    }
99370b324cSopenharmony_ci    #endif
100370b324cSopenharmony_ci  }
101370b324cSopenharmony_ci
102370b324cSopenharmony_ci  /*
103370b324cSopenharmony_ci  #ifndef UNDER_CE
104370b324cSopenharmony_ci  #ifndef Z7_SFX
105370b324cSopenharmony_ci  if (_handle == INVALID_HANDLE_VALUE)
106370b324cSopenharmony_ci  {
107370b324cSopenharmony_ci    // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10
108370b324cSopenharmony_ci    DWORD lastError = GetLastError();
109370b324cSopenharmony_ci    if (lastError == ERROR_CANT_ACCESS_FILE)
110370b324cSopenharmony_ci    {
111370b324cSopenharmony_ci      CByteBuffer buf;
112370b324cSopenharmony_ci      if (NIO::GetReparseData(path, buf, NULL))
113370b324cSopenharmony_ci      {
114370b324cSopenharmony_ci        CReparseAttr attr;
115370b324cSopenharmony_ci        if (attr.Parse(buf, buf.Size()))
116370b324cSopenharmony_ci        {
117370b324cSopenharmony_ci          FString dirPrefix, fileName;
118370b324cSopenharmony_ci          if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName))
119370b324cSopenharmony_ci          {
120370b324cSopenharmony_ci            FString fullPath;
121370b324cSopenharmony_ci            if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath))
122370b324cSopenharmony_ci            {
123370b324cSopenharmony_ci              // FIX IT: recursion levels must be restricted
124370b324cSopenharmony_ci              return Create(fullPath, desiredAccess,
125370b324cSopenharmony_ci                shareMode, creationDisposition, flagsAndAttributes);
126370b324cSopenharmony_ci            }
127370b324cSopenharmony_ci          }
128370b324cSopenharmony_ci        }
129370b324cSopenharmony_ci      }
130370b324cSopenharmony_ci      SetLastError(lastError);
131370b324cSopenharmony_ci    }
132370b324cSopenharmony_ci  }
133370b324cSopenharmony_ci  #endif
134370b324cSopenharmony_ci  #endif
135370b324cSopenharmony_ci  */
136370b324cSopenharmony_ci
137370b324cSopenharmony_ci  return (_handle != INVALID_HANDLE_VALUE);
138370b324cSopenharmony_ci}
139370b324cSopenharmony_ci
140370b324cSopenharmony_cibool CFileBase::Close() throw()
141370b324cSopenharmony_ci{
142370b324cSopenharmony_ci  if (_handle == INVALID_HANDLE_VALUE)
143370b324cSopenharmony_ci    return true;
144370b324cSopenharmony_ci  if (!::CloseHandle(_handle))
145370b324cSopenharmony_ci    return false;
146370b324cSopenharmony_ci  _handle = INVALID_HANDLE_VALUE;
147370b324cSopenharmony_ci  return true;
148370b324cSopenharmony_ci}
149370b324cSopenharmony_ci
150370b324cSopenharmony_cibool CFileBase::GetLength(UInt64 &length) const throw()
151370b324cSopenharmony_ci{
152370b324cSopenharmony_ci  #ifdef Z7_DEVICE_FILE
153370b324cSopenharmony_ci  if (IsDeviceFile && SizeDefined)
154370b324cSopenharmony_ci  {
155370b324cSopenharmony_ci    length = Size;
156370b324cSopenharmony_ci    return true;
157370b324cSopenharmony_ci  }
158370b324cSopenharmony_ci  #endif
159370b324cSopenharmony_ci
160370b324cSopenharmony_ci  DWORD high = 0;
161370b324cSopenharmony_ci  const DWORD low = ::GetFileSize(_handle, &high);
162370b324cSopenharmony_ci  if (low == INVALID_FILE_SIZE)
163370b324cSopenharmony_ci    if (::GetLastError() != NO_ERROR)
164370b324cSopenharmony_ci      return false;
165370b324cSopenharmony_ci  length = (((UInt64)high) << 32) + low;
166370b324cSopenharmony_ci  return true;
167370b324cSopenharmony_ci
168370b324cSopenharmony_ci  /*
169370b324cSopenharmony_ci  LARGE_INTEGER fileSize;
170370b324cSopenharmony_ci  // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+
171370b324cSopenharmony_ci  if (!GetFileSizeEx(_handle, &fileSize))
172370b324cSopenharmony_ci    return false;
173370b324cSopenharmony_ci  length = (UInt64)fileSize.QuadPart;
174370b324cSopenharmony_ci  return true;
175370b324cSopenharmony_ci  */
176370b324cSopenharmony_ci}
177370b324cSopenharmony_ci
178370b324cSopenharmony_ci
179370b324cSopenharmony_ci/* Specification for SetFilePointer():
180370b324cSopenharmony_ci
181370b324cSopenharmony_ci   If a new file pointer is a negative value,
182370b324cSopenharmony_ci   {
183370b324cSopenharmony_ci     the function fails,
184370b324cSopenharmony_ci     the file pointer is not moved,
185370b324cSopenharmony_ci     the code returned by GetLastError() is ERROR_NEGATIVE_SEEK.
186370b324cSopenharmony_ci   }
187370b324cSopenharmony_ci
188370b324cSopenharmony_ci   If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set
189370b324cSopenharmony_ci   {
190370b324cSopenharmony_ci     an application can move the file pointer only to sector-aligned positions.
191370b324cSopenharmony_ci     A sector-aligned position is a position that is a whole number multiple of
192370b324cSopenharmony_ci     the volume sector size.
193370b324cSopenharmony_ci     An application can obtain a volume sector size by calling the GetDiskFreeSpace.
194370b324cSopenharmony_ci   }
195370b324cSopenharmony_ci
196370b324cSopenharmony_ci   It is not an error to set a file pointer to a position beyond the end of the file.
197370b324cSopenharmony_ci   The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function.
198370b324cSopenharmony_ci
199370b324cSopenharmony_ci   If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL,
200370b324cSopenharmony_ci   an application must call GetLastError to determine whether or not the function has succeeded or failed.
201370b324cSopenharmony_ci*/
202370b324cSopenharmony_ci
203370b324cSopenharmony_cibool CFileBase::GetPosition(UInt64 &position) const throw()
204370b324cSopenharmony_ci{
205370b324cSopenharmony_ci  LONG high = 0;
206370b324cSopenharmony_ci  const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT);
207370b324cSopenharmony_ci  if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
208370b324cSopenharmony_ci  {
209370b324cSopenharmony_ci    // for error case we can set (position)  to (-1) or (0) or leave (position) unchanged.
210370b324cSopenharmony_ci    // position = (UInt64)(Int64)-1; // for debug
211370b324cSopenharmony_ci    position = 0;
212370b324cSopenharmony_ci    return false;
213370b324cSopenharmony_ci  }
214370b324cSopenharmony_ci  position = (((UInt64)(UInt32)high) << 32) + low;
215370b324cSopenharmony_ci  return true;
216370b324cSopenharmony_ci  // we don't want recursed GetPosition()
217370b324cSopenharmony_ci  // return Seek(0, FILE_CURRENT, position);
218370b324cSopenharmony_ci}
219370b324cSopenharmony_ci
220370b324cSopenharmony_cibool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()
221370b324cSopenharmony_ci{
222370b324cSopenharmony_ci  #ifdef Z7_DEVICE_FILE
223370b324cSopenharmony_ci  if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)
224370b324cSopenharmony_ci  {
225370b324cSopenharmony_ci    distanceToMove += Size;
226370b324cSopenharmony_ci    moveMethod = FILE_BEGIN;
227370b324cSopenharmony_ci  }
228370b324cSopenharmony_ci  #endif
229370b324cSopenharmony_ci
230370b324cSopenharmony_ci  LONG high = (LONG)(distanceToMove >> 32);
231370b324cSopenharmony_ci  const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
232370b324cSopenharmony_ci  if (low == INVALID_SET_FILE_POINTER)
233370b324cSopenharmony_ci  {
234370b324cSopenharmony_ci    const DWORD lastError = ::GetLastError();
235370b324cSopenharmony_ci    if (lastError != NO_ERROR)
236370b324cSopenharmony_ci    {
237370b324cSopenharmony_ci      // 21.07: we set (newPosition) to real position even after error.
238370b324cSopenharmony_ci      GetPosition(newPosition);
239370b324cSopenharmony_ci      SetLastError(lastError); // restore LastError
240370b324cSopenharmony_ci      return false;
241370b324cSopenharmony_ci    }
242370b324cSopenharmony_ci  }
243370b324cSopenharmony_ci  newPosition = (((UInt64)(UInt32)high) << 32) + low;
244370b324cSopenharmony_ci  return true;
245370b324cSopenharmony_ci}
246370b324cSopenharmony_ci
247370b324cSopenharmony_cibool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()
248370b324cSopenharmony_ci{
249370b324cSopenharmony_ci  return Seek((Int64)position, FILE_BEGIN, newPosition);
250370b324cSopenharmony_ci}
251370b324cSopenharmony_ci
252370b324cSopenharmony_cibool CFileBase::SeekToBegin() const throw()
253370b324cSopenharmony_ci{
254370b324cSopenharmony_ci  UInt64 newPosition = 0;
255370b324cSopenharmony_ci  return Seek(0, newPosition) && (newPosition == 0);
256370b324cSopenharmony_ci}
257370b324cSopenharmony_ci
258370b324cSopenharmony_cibool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()
259370b324cSopenharmony_ci{
260370b324cSopenharmony_ci  return Seek(0, FILE_END, newPosition);
261370b324cSopenharmony_ci}
262370b324cSopenharmony_ci
263370b324cSopenharmony_ci// ---------- CInFile ---------
264370b324cSopenharmony_ci
265370b324cSopenharmony_ci#ifdef Z7_DEVICE_FILE
266370b324cSopenharmony_ci
267370b324cSopenharmony_civoid CInFile::CorrectDeviceSize()
268370b324cSopenharmony_ci{
269370b324cSopenharmony_ci  // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail
270370b324cSopenharmony_ci  const UInt32 kClusterSize = 1 << 14;
271370b324cSopenharmony_ci  UInt64 pos = Size & ~(UInt64)(kClusterSize - 1);
272370b324cSopenharmony_ci  UInt64 realNewPosition;
273370b324cSopenharmony_ci  if (!Seek(pos, realNewPosition))
274370b324cSopenharmony_ci    return;
275370b324cSopenharmony_ci  Byte *buf = (Byte *)MidAlloc(kClusterSize);
276370b324cSopenharmony_ci
277370b324cSopenharmony_ci  bool needbackward = true;
278370b324cSopenharmony_ci
279370b324cSopenharmony_ci  for (;;)
280370b324cSopenharmony_ci  {
281370b324cSopenharmony_ci    UInt32 processed = 0;
282370b324cSopenharmony_ci    // up test is slow for "PhysicalDrive".
283370b324cSopenharmony_ci    // processed size for latest block for "PhysicalDrive0" is 0.
284370b324cSopenharmony_ci    if (!Read1(buf, kClusterSize, processed))
285370b324cSopenharmony_ci      break;
286370b324cSopenharmony_ci    if (processed == 0)
287370b324cSopenharmony_ci      break;
288370b324cSopenharmony_ci    needbackward = false;
289370b324cSopenharmony_ci    Size = pos + processed;
290370b324cSopenharmony_ci    if (processed != kClusterSize)
291370b324cSopenharmony_ci      break;
292370b324cSopenharmony_ci    pos += kClusterSize;
293370b324cSopenharmony_ci  }
294370b324cSopenharmony_ci
295370b324cSopenharmony_ci  if (needbackward && pos != 0)
296370b324cSopenharmony_ci  {
297370b324cSopenharmony_ci    pos -= kClusterSize;
298370b324cSopenharmony_ci    for (;;)
299370b324cSopenharmony_ci    {
300370b324cSopenharmony_ci      // break;
301370b324cSopenharmony_ci      if (!Seek(pos, realNewPosition))
302370b324cSopenharmony_ci        break;
303370b324cSopenharmony_ci      if (!buf)
304370b324cSopenharmony_ci      {
305370b324cSopenharmony_ci        buf = (Byte *)MidAlloc(kClusterSize);
306370b324cSopenharmony_ci        if (!buf)
307370b324cSopenharmony_ci          break;
308370b324cSopenharmony_ci      }
309370b324cSopenharmony_ci      UInt32 processed = 0;
310370b324cSopenharmony_ci      // that code doesn't work for "PhysicalDrive0"
311370b324cSopenharmony_ci      if (!Read1(buf, kClusterSize, processed))
312370b324cSopenharmony_ci        break;
313370b324cSopenharmony_ci      if (processed != 0)
314370b324cSopenharmony_ci      {
315370b324cSopenharmony_ci        Size = pos + processed;
316370b324cSopenharmony_ci        break;
317370b324cSopenharmony_ci      }
318370b324cSopenharmony_ci      if (pos == 0)
319370b324cSopenharmony_ci        break;
320370b324cSopenharmony_ci      pos -= kClusterSize;
321370b324cSopenharmony_ci    }
322370b324cSopenharmony_ci  }
323370b324cSopenharmony_ci  MidFree(buf);
324370b324cSopenharmony_ci}
325370b324cSopenharmony_ci
326370b324cSopenharmony_ci
327370b324cSopenharmony_civoid CInFile::CalcDeviceSize(CFSTR s)
328370b324cSopenharmony_ci{
329370b324cSopenharmony_ci  SizeDefined = false;
330370b324cSopenharmony_ci  Size = 0;
331370b324cSopenharmony_ci  if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile)
332370b324cSopenharmony_ci    return;
333370b324cSopenharmony_ci  #ifdef UNDER_CE
334370b324cSopenharmony_ci
335370b324cSopenharmony_ci  SizeDefined = true;
336370b324cSopenharmony_ci  Size = 128 << 20;
337370b324cSopenharmony_ci
338370b324cSopenharmony_ci  #else
339370b324cSopenharmony_ci
340370b324cSopenharmony_ci  PARTITION_INFORMATION partInfo;
341370b324cSopenharmony_ci  bool needCorrectSize = true;
342370b324cSopenharmony_ci
343370b324cSopenharmony_ci  /*
344370b324cSopenharmony_ci    WinXP 64-bit:
345370b324cSopenharmony_ci
346370b324cSopenharmony_ci    HDD \\.\PhysicalDrive0 (MBR):
347370b324cSopenharmony_ci      GetPartitionInfo == GeometryEx :  corrrect size? (includes tail)
348370b324cSopenharmony_ci      Geometry   :  smaller than GeometryEx (no tail, maybe correct too?)
349370b324cSopenharmony_ci      MyGetDiskFreeSpace : FAIL
350370b324cSopenharmony_ci      Size correction is slow and block size (kClusterSize) must be small?
351370b324cSopenharmony_ci
352370b324cSopenharmony_ci    HDD partition \\.\N: (NTFS):
353370b324cSopenharmony_ci      MyGetDiskFreeSpace   :  Size of NTFS clusters. Same size can be calculated after correction
354370b324cSopenharmony_ci      GetPartitionInfo     :  size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS
355370b324cSopenharmony_ci      Geometry / CdRomGeometry / GeometryEx :  size of HDD (not that partition)
356370b324cSopenharmony_ci
357370b324cSopenharmony_ci    CD-ROM drive (ISO):
358370b324cSopenharmony_ci      MyGetDiskFreeSpace   :  correct size. Same size can be calculated after correction
359370b324cSopenharmony_ci      Geometry == CdRomGeometry  :  smaller than corrrect size
360370b324cSopenharmony_ci      GetPartitionInfo == GeometryEx :  larger than corrrect size
361370b324cSopenharmony_ci
362370b324cSopenharmony_ci    Floppy \\.\a: (FAT):
363370b324cSopenharmony_ci      Geometry :  correct size.
364370b324cSopenharmony_ci      CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL
365370b324cSopenharmony_ci      correction works OK for FAT.
366370b324cSopenharmony_ci      correction works OK for non-FAT, if kClusterSize = 512.
367370b324cSopenharmony_ci  */
368370b324cSopenharmony_ci
369370b324cSopenharmony_ci  if (GetPartitionInfo(&partInfo))
370370b324cSopenharmony_ci  {
371370b324cSopenharmony_ci    Size = (UInt64)partInfo.PartitionLength.QuadPart;
372370b324cSopenharmony_ci    SizeDefined = true;
373370b324cSopenharmony_ci    needCorrectSize = false;
374370b324cSopenharmony_ci    if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
375370b324cSopenharmony_ci    {
376370b324cSopenharmony_ci      FChar path[4] = { s[4], ':', '\\', 0 };
377370b324cSopenharmony_ci      UInt64 clusterSize, totalSize, freeSize;
378370b324cSopenharmony_ci      if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize))
379370b324cSopenharmony_ci        Size = totalSize;
380370b324cSopenharmony_ci      else
381370b324cSopenharmony_ci        needCorrectSize = true;
382370b324cSopenharmony_ci    }
383370b324cSopenharmony_ci  }
384370b324cSopenharmony_ci
385370b324cSopenharmony_ci  if (!SizeDefined)
386370b324cSopenharmony_ci  {
387370b324cSopenharmony_ci    my_DISK_GEOMETRY_EX geomEx;
388370b324cSopenharmony_ci    SizeDefined = GetGeometryEx(&geomEx);
389370b324cSopenharmony_ci    if (SizeDefined)
390370b324cSopenharmony_ci      Size = (UInt64)geomEx.DiskSize.QuadPart;
391370b324cSopenharmony_ci    else
392370b324cSopenharmony_ci    {
393370b324cSopenharmony_ci      DISK_GEOMETRY geom;
394370b324cSopenharmony_ci      SizeDefined = GetGeometry(&geom);
395370b324cSopenharmony_ci      if (!SizeDefined)
396370b324cSopenharmony_ci        SizeDefined = GetCdRomGeometry(&geom);
397370b324cSopenharmony_ci      if (SizeDefined)
398370b324cSopenharmony_ci        Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
399370b324cSopenharmony_ci    }
400370b324cSopenharmony_ci  }
401370b324cSopenharmony_ci
402370b324cSopenharmony_ci  if (needCorrectSize && SizeDefined && Size != 0)
403370b324cSopenharmony_ci  {
404370b324cSopenharmony_ci    CorrectDeviceSize();
405370b324cSopenharmony_ci    SeekToBegin();
406370b324cSopenharmony_ci  }
407370b324cSopenharmony_ci
408370b324cSopenharmony_ci  // SeekToBegin();
409370b324cSopenharmony_ci  #endif
410370b324cSopenharmony_ci}
411370b324cSopenharmony_ci
412370b324cSopenharmony_ci// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
413370b324cSopenharmony_ci
414370b324cSopenharmony_ci#define MY_DEVICE_EXTRA_CODE \
415370b324cSopenharmony_ci  IsDeviceFile = IsDevicePath(fileName); \
416370b324cSopenharmony_ci  CalcDeviceSize(fileName);
417370b324cSopenharmony_ci#else
418370b324cSopenharmony_ci#define MY_DEVICE_EXTRA_CODE
419370b324cSopenharmony_ci#endif
420370b324cSopenharmony_ci
421370b324cSopenharmony_cibool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
422370b324cSopenharmony_ci{
423370b324cSopenharmony_ci  DWORD desiredAccess = GENERIC_READ;
424370b324cSopenharmony_ci
425370b324cSopenharmony_ci  #ifdef _WIN32
426370b324cSopenharmony_ci  if (PreserveATime)
427370b324cSopenharmony_ci    desiredAccess |= FILE_WRITE_ATTRIBUTES;
428370b324cSopenharmony_ci  #endif
429370b324cSopenharmony_ci
430370b324cSopenharmony_ci  bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
431370b324cSopenharmony_ci
432370b324cSopenharmony_ci  #ifdef _WIN32
433370b324cSopenharmony_ci  if (res && PreserveATime)
434370b324cSopenharmony_ci  {
435370b324cSopenharmony_ci    FILETIME ft;
436370b324cSopenharmony_ci    ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF;
437370b324cSopenharmony_ci    ::SetFileTime(_handle, NULL, &ft, NULL);
438370b324cSopenharmony_ci  }
439370b324cSopenharmony_ci  #endif
440370b324cSopenharmony_ci
441370b324cSopenharmony_ci  MY_DEVICE_EXTRA_CODE
442370b324cSopenharmony_ci  return res;
443370b324cSopenharmony_ci}
444370b324cSopenharmony_ci
445370b324cSopenharmony_cibool CInFile::OpenShared(CFSTR fileName, bool shareForWrite)
446370b324cSopenharmony_ci{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
447370b324cSopenharmony_ci
448370b324cSopenharmony_cibool CInFile::Open(CFSTR fileName)
449370b324cSopenharmony_ci  { return OpenShared(fileName, false); }
450370b324cSopenharmony_ci
451370b324cSopenharmony_ci// ReadFile and WriteFile functions in Windows have BUG:
452370b324cSopenharmony_ci// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
453370b324cSopenharmony_ci// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
454370b324cSopenharmony_ci// (Insufficient system resources exist to complete the requested service).
455370b324cSopenharmony_ci
456370b324cSopenharmony_ci// Probably in some version of Windows there are problems with other sizes:
457370b324cSopenharmony_ci// for 32 MB (maybe also for 16 MB).
458370b324cSopenharmony_ci// And message can be "Network connection was lost"
459370b324cSopenharmony_ci
460370b324cSopenharmony_cistatic const UInt32 kChunkSizeMax = (1 << 22);
461370b324cSopenharmony_ci
462370b324cSopenharmony_cibool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()
463370b324cSopenharmony_ci{
464370b324cSopenharmony_ci  DWORD processedLoc = 0;
465370b324cSopenharmony_ci  const bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
466370b324cSopenharmony_ci  processedSize = (UInt32)processedLoc;
467370b324cSopenharmony_ci  return res;
468370b324cSopenharmony_ci}
469370b324cSopenharmony_ci
470370b324cSopenharmony_cibool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw()
471370b324cSopenharmony_ci{
472370b324cSopenharmony_ci  if (size > kChunkSizeMax)
473370b324cSopenharmony_ci    size = kChunkSizeMax;
474370b324cSopenharmony_ci  return Read1(data, size, processedSize);
475370b324cSopenharmony_ci}
476370b324cSopenharmony_ci
477370b324cSopenharmony_cibool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()
478370b324cSopenharmony_ci{
479370b324cSopenharmony_ci  processedSize = 0;
480370b324cSopenharmony_ci  do
481370b324cSopenharmony_ci  {
482370b324cSopenharmony_ci    UInt32 processedLoc = 0;
483370b324cSopenharmony_ci    const bool res = ReadPart(data, size, processedLoc);
484370b324cSopenharmony_ci    processedSize += processedLoc;
485370b324cSopenharmony_ci    if (!res)
486370b324cSopenharmony_ci      return false;
487370b324cSopenharmony_ci    if (processedLoc == 0)
488370b324cSopenharmony_ci      return true;
489370b324cSopenharmony_ci    data = (void *)((unsigned char *)data + processedLoc);
490370b324cSopenharmony_ci    size -= processedLoc;
491370b324cSopenharmony_ci  }
492370b324cSopenharmony_ci  while (size > 0);
493370b324cSopenharmony_ci  return true;
494370b324cSopenharmony_ci}
495370b324cSopenharmony_ci
496370b324cSopenharmony_cibool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw()
497370b324cSopenharmony_ci{
498370b324cSopenharmony_ci  processedSize = 0;
499370b324cSopenharmony_ci  do
500370b324cSopenharmony_ci  {
501370b324cSopenharmony_ci    UInt32 processedLoc = 0;
502370b324cSopenharmony_ci    const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size);
503370b324cSopenharmony_ci    const bool res = Read1(data, sizeLoc, processedLoc);
504370b324cSopenharmony_ci    processedSize += processedLoc;
505370b324cSopenharmony_ci    if (!res)
506370b324cSopenharmony_ci      return false;
507370b324cSopenharmony_ci    if (processedLoc == 0)
508370b324cSopenharmony_ci      return true;
509370b324cSopenharmony_ci    data = (void *)((unsigned char *)data + processedLoc);
510370b324cSopenharmony_ci    size -= processedLoc;
511370b324cSopenharmony_ci  }
512370b324cSopenharmony_ci  while (size > 0);
513370b324cSopenharmony_ci  return true;
514370b324cSopenharmony_ci}
515370b324cSopenharmony_ci
516370b324cSopenharmony_ci// ---------- COutFile ---------
517370b324cSopenharmony_ci
518370b324cSopenharmony_cistatic inline DWORD GetCreationDisposition(bool createAlways)
519370b324cSopenharmony_ci  { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
520370b324cSopenharmony_ci
521370b324cSopenharmony_cibool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
522370b324cSopenharmony_ci  { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
523370b324cSopenharmony_ci
524370b324cSopenharmony_cibool COutFile::Open(CFSTR fileName, DWORD creationDisposition)
525370b324cSopenharmony_ci  { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
526370b324cSopenharmony_ci
527370b324cSopenharmony_cibool COutFile::Create(CFSTR fileName, bool createAlways)
528370b324cSopenharmony_ci  { return Open(fileName, GetCreationDisposition(createAlways)); }
529370b324cSopenharmony_ci
530370b324cSopenharmony_cibool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes)
531370b324cSopenharmony_ci  { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), flagsAndAttributes); }
532370b324cSopenharmony_ci
533370b324cSopenharmony_cibool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw()
534370b324cSopenharmony_ci  { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
535370b324cSopenharmony_ci
536370b324cSopenharmony_cibool COutFile::SetMTime(const FILETIME *mTime) throw() {  return SetTime(NULL, NULL, mTime); }
537370b324cSopenharmony_ci
538370b324cSopenharmony_cibool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw()
539370b324cSopenharmony_ci{
540370b324cSopenharmony_ci  if (size > kChunkSizeMax)
541370b324cSopenharmony_ci    size = kChunkSizeMax;
542370b324cSopenharmony_ci  DWORD processedLoc = 0;
543370b324cSopenharmony_ci  bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
544370b324cSopenharmony_ci  processedSize = (UInt32)processedLoc;
545370b324cSopenharmony_ci  return res;
546370b324cSopenharmony_ci}
547370b324cSopenharmony_ci
548370b324cSopenharmony_cibool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
549370b324cSopenharmony_ci{
550370b324cSopenharmony_ci  processedSize = 0;
551370b324cSopenharmony_ci  do
552370b324cSopenharmony_ci  {
553370b324cSopenharmony_ci    UInt32 processedLoc = 0;
554370b324cSopenharmony_ci    const bool res = WritePart(data, size, processedLoc);
555370b324cSopenharmony_ci    processedSize += processedLoc;
556370b324cSopenharmony_ci    if (!res)
557370b324cSopenharmony_ci      return false;
558370b324cSopenharmony_ci    if (processedLoc == 0)
559370b324cSopenharmony_ci      return true;
560370b324cSopenharmony_ci    data = (const void *)((const unsigned char *)data + processedLoc);
561370b324cSopenharmony_ci    size -= processedLoc;
562370b324cSopenharmony_ci  }
563370b324cSopenharmony_ci  while (size != 0);
564370b324cSopenharmony_ci  return true;
565370b324cSopenharmony_ci}
566370b324cSopenharmony_ci
567370b324cSopenharmony_cibool COutFile::WriteFull(const void *data, size_t size) throw()
568370b324cSopenharmony_ci{
569370b324cSopenharmony_ci  do
570370b324cSopenharmony_ci  {
571370b324cSopenharmony_ci    UInt32 processedLoc = 0;
572370b324cSopenharmony_ci    const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size);
573370b324cSopenharmony_ci    if (!WritePart(data, sizeCur, processedLoc))
574370b324cSopenharmony_ci      return false;
575370b324cSopenharmony_ci    if (processedLoc == 0)
576370b324cSopenharmony_ci      return (size == 0);
577370b324cSopenharmony_ci    data = (const void *)((const unsigned char *)data + processedLoc);
578370b324cSopenharmony_ci    size -= processedLoc;
579370b324cSopenharmony_ci  }
580370b324cSopenharmony_ci  while (size != 0);
581370b324cSopenharmony_ci  return true;
582370b324cSopenharmony_ci}
583370b324cSopenharmony_ci
584370b324cSopenharmony_cibool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); }
585370b324cSopenharmony_ci
586370b324cSopenharmony_cibool COutFile::SetLength(UInt64 length) throw()
587370b324cSopenharmony_ci{
588370b324cSopenharmony_ci  UInt64 newPosition;
589370b324cSopenharmony_ci  if (!Seek(length, newPosition))
590370b324cSopenharmony_ci    return false;
591370b324cSopenharmony_ci  if (newPosition != length)
592370b324cSopenharmony_ci    return false;
593370b324cSopenharmony_ci  return SetEndOfFile();
594370b324cSopenharmony_ci}
595370b324cSopenharmony_ci
596370b324cSopenharmony_cibool COutFile::SetLength_KeepPosition(UInt64 length) throw()
597370b324cSopenharmony_ci{
598370b324cSopenharmony_ci  UInt64 currentPos = 0;
599370b324cSopenharmony_ci  if (!GetPosition(currentPos))
600370b324cSopenharmony_ci    return false;
601370b324cSopenharmony_ci  DWORD lastError = 0;
602370b324cSopenharmony_ci  const bool result = SetLength(length);
603370b324cSopenharmony_ci  if (!result)
604370b324cSopenharmony_ci    lastError = GetLastError();
605370b324cSopenharmony_ci  UInt64 currentPos2;
606370b324cSopenharmony_ci  const bool result2 = Seek(currentPos, currentPos2);
607370b324cSopenharmony_ci  if (lastError != 0)
608370b324cSopenharmony_ci    SetLastError(lastError);
609370b324cSopenharmony_ci  return (result && result2);
610370b324cSopenharmony_ci}
611370b324cSopenharmony_ci
612370b324cSopenharmony_ci}}}
613370b324cSopenharmony_ci
614370b324cSopenharmony_ci#else // _WIN32
615370b324cSopenharmony_ci
616370b324cSopenharmony_ci
617370b324cSopenharmony_ci// POSIX
618370b324cSopenharmony_ci
619370b324cSopenharmony_ci#include <fcntl.h>
620370b324cSopenharmony_ci#include <unistd.h>
621370b324cSopenharmony_ci
622370b324cSopenharmony_cinamespace NWindows {
623370b324cSopenharmony_cinamespace NFile {
624370b324cSopenharmony_ci
625370b324cSopenharmony_cinamespace NDir {
626370b324cSopenharmony_cibool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
627370b324cSopenharmony_ci}
628370b324cSopenharmony_ci
629370b324cSopenharmony_cinamespace NIO {
630370b324cSopenharmony_ci
631370b324cSopenharmony_cibool CFileBase::OpenBinary(const char *name, int flags, mode_t mode)
632370b324cSopenharmony_ci{
633370b324cSopenharmony_ci  #ifdef O_BINARY
634370b324cSopenharmony_ci  flags |= O_BINARY;
635370b324cSopenharmony_ci  #endif
636370b324cSopenharmony_ci
637370b324cSopenharmony_ci  Close();
638370b324cSopenharmony_ci  _handle = ::open(name, flags, mode);
639370b324cSopenharmony_ci  return _handle != -1;
640370b324cSopenharmony_ci
641370b324cSopenharmony_ci  /*
642370b324cSopenharmony_ci  if (_handle == -1)
643370b324cSopenharmony_ci    return false;
644370b324cSopenharmony_ci  if (IsString1PrefixedByString2(name, "/dev/"))
645370b324cSopenharmony_ci  {
646370b324cSopenharmony_ci    // /dev/sda
647370b324cSopenharmony_ci    // IsDeviceFile = true; // for debug
648370b324cSopenharmony_ci    // SizeDefined = false;
649370b324cSopenharmony_ci    // SizeDefined = (GetDeviceSize_InBytes(Size) == 0);
650370b324cSopenharmony_ci  }
651370b324cSopenharmony_ci  return true;
652370b324cSopenharmony_ci  */
653370b324cSopenharmony_ci}
654370b324cSopenharmony_ci
655370b324cSopenharmony_cibool CFileBase::Close()
656370b324cSopenharmony_ci{
657370b324cSopenharmony_ci  if (_handle == -1)
658370b324cSopenharmony_ci    return true;
659370b324cSopenharmony_ci  if (close(_handle) != 0)
660370b324cSopenharmony_ci    return false;
661370b324cSopenharmony_ci  _handle = -1;
662370b324cSopenharmony_ci  /*
663370b324cSopenharmony_ci  IsDeviceFile = false;
664370b324cSopenharmony_ci  SizeDefined = false;
665370b324cSopenharmony_ci  */
666370b324cSopenharmony_ci  return true;
667370b324cSopenharmony_ci}
668370b324cSopenharmony_ci
669370b324cSopenharmony_cibool CFileBase::GetLength(UInt64 &length) const
670370b324cSopenharmony_ci{
671370b324cSopenharmony_ci  length = 0;
672370b324cSopenharmony_ci  // length = (UInt64)(Int64)-1; // for debug
673370b324cSopenharmony_ci  const off_t curPos = seekToCur();
674370b324cSopenharmony_ci  if (curPos == -1)
675370b324cSopenharmony_ci    return false;
676370b324cSopenharmony_ci  const off_t lengthTemp = seek(0, SEEK_END);
677370b324cSopenharmony_ci  seek(curPos, SEEK_SET);
678370b324cSopenharmony_ci  length = (UInt64)lengthTemp;
679370b324cSopenharmony_ci
680370b324cSopenharmony_ci  /*
681370b324cSopenharmony_ci  // 22.00:
682370b324cSopenharmony_ci  if (lengthTemp == 1)
683370b324cSopenharmony_ci  if (IsDeviceFile && SizeDefined)
684370b324cSopenharmony_ci  {
685370b324cSopenharmony_ci    length = Size;
686370b324cSopenharmony_ci    return true;
687370b324cSopenharmony_ci  }
688370b324cSopenharmony_ci  */
689370b324cSopenharmony_ci
690370b324cSopenharmony_ci  return (lengthTemp != -1);
691370b324cSopenharmony_ci}
692370b324cSopenharmony_ci
693370b324cSopenharmony_cioff_t CFileBase::seek(off_t distanceToMove, int moveMethod) const
694370b324cSopenharmony_ci{
695370b324cSopenharmony_ci  /*
696370b324cSopenharmony_ci  if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END)
697370b324cSopenharmony_ci  {
698370b324cSopenharmony_ci    printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
699370b324cSopenharmony_ci    distanceToMove += Size;
700370b324cSopenharmony_ci    moveMethod = SEEK_SET;
701370b324cSopenharmony_ci  }
702370b324cSopenharmony_ci  */
703370b324cSopenharmony_ci
704370b324cSopenharmony_ci  // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove);
705370b324cSopenharmony_ci  // off_t res = ::lseek(_handle, distanceToMove, moveMethod);
706370b324cSopenharmony_ci  // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
707370b324cSopenharmony_ci  return ::lseek(_handle, distanceToMove, moveMethod);
708370b324cSopenharmony_ci  // return res;
709370b324cSopenharmony_ci}
710370b324cSopenharmony_ci
711370b324cSopenharmony_cioff_t CFileBase::seekToBegin() const throw()
712370b324cSopenharmony_ci{
713370b324cSopenharmony_ci  return seek(0, SEEK_SET);
714370b324cSopenharmony_ci}
715370b324cSopenharmony_ci
716370b324cSopenharmony_cioff_t CFileBase::seekToCur() const throw()
717370b324cSopenharmony_ci{
718370b324cSopenharmony_ci  return seek(0, SEEK_CUR);
719370b324cSopenharmony_ci}
720370b324cSopenharmony_ci
721370b324cSopenharmony_ci/*
722370b324cSopenharmony_cibool CFileBase::SeekToBegin() const throw()
723370b324cSopenharmony_ci{
724370b324cSopenharmony_ci  return (::seek(0, SEEK_SET) != -1);
725370b324cSopenharmony_ci}
726370b324cSopenharmony_ci*/
727370b324cSopenharmony_ci
728370b324cSopenharmony_ci
729370b324cSopenharmony_ci/////////////////////////
730370b324cSopenharmony_ci// CInFile
731370b324cSopenharmony_ci
732370b324cSopenharmony_cibool CInFile::Open(const char *name)
733370b324cSopenharmony_ci{
734370b324cSopenharmony_ci  return CFileBase::OpenBinary(name, O_RDONLY);
735370b324cSopenharmony_ci}
736370b324cSopenharmony_ci
737370b324cSopenharmony_cibool CInFile::OpenShared(const char *name, bool)
738370b324cSopenharmony_ci{
739370b324cSopenharmony_ci  return Open(name);
740370b324cSopenharmony_ci}
741370b324cSopenharmony_ci
742370b324cSopenharmony_ci
743370b324cSopenharmony_ci/*
744370b324cSopenharmony_ciint CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks)
745370b324cSopenharmony_ci{
746370b324cSopenharmony_ci  // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition
747370b324cSopenharmony_ci  // #include <linux/fs.h>
748370b324cSopenharmony_ci  return ioctl(_handle, BLKGETSIZE64, numBlocks);
749370b324cSopenharmony_ci  // in block size
750370b324cSopenharmony_ci}
751370b324cSopenharmony_ci
752370b324cSopenharmony_ciint CFileBase::GetDeviceSize_InBytes(UInt64 &size)
753370b324cSopenharmony_ci{
754370b324cSopenharmony_ci  size = 0;
755370b324cSopenharmony_ci  unsigned long long numBlocks;
756370b324cSopenharmony_ci  int res = my_ioctl_BLKGETSIZE64(&numBlocks);
757370b324cSopenharmony_ci  if (res == 0)
758370b324cSopenharmony_ci    size = numBlocks; // another blockSize s possible?
759370b324cSopenharmony_ci  printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size);
760370b324cSopenharmony_ci  return res;
761370b324cSopenharmony_ci}
762370b324cSopenharmony_ci*/
763370b324cSopenharmony_ci
764370b324cSopenharmony_ci/*
765370b324cSopenharmony_ciOn Linux (32-bit and 64-bit):
766370b324cSopenharmony_ciread(), write() (and similar system calls) will transfer at most
767370b324cSopenharmony_ci0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred.
768370b324cSopenharmony_ci*/
769370b324cSopenharmony_ci
770370b324cSopenharmony_cistatic const size_t kChunkSizeMax = ((size_t)1 << 22);
771370b324cSopenharmony_ci
772370b324cSopenharmony_cissize_t CInFile::read_part(void *data, size_t size) throw()
773370b324cSopenharmony_ci{
774370b324cSopenharmony_ci  if (size > kChunkSizeMax)
775370b324cSopenharmony_ci    size = kChunkSizeMax;
776370b324cSopenharmony_ci  return ::read(_handle, data, size);
777370b324cSopenharmony_ci}
778370b324cSopenharmony_ci
779370b324cSopenharmony_cibool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw()
780370b324cSopenharmony_ci{
781370b324cSopenharmony_ci  processed = 0;
782370b324cSopenharmony_ci  do
783370b324cSopenharmony_ci  {
784370b324cSopenharmony_ci    const ssize_t res = read_part(data, size);
785370b324cSopenharmony_ci    if (res < 0)
786370b324cSopenharmony_ci      return false;
787370b324cSopenharmony_ci    if (res == 0)
788370b324cSopenharmony_ci      break;
789370b324cSopenharmony_ci    data = (void *)((unsigned char *)data + (size_t)res);
790370b324cSopenharmony_ci    size -= (size_t)res;
791370b324cSopenharmony_ci    processed += (size_t)res;
792370b324cSopenharmony_ci  }
793370b324cSopenharmony_ci  while (size > 0);
794370b324cSopenharmony_ci  return true;
795370b324cSopenharmony_ci}
796370b324cSopenharmony_ci
797370b324cSopenharmony_ci
798370b324cSopenharmony_ci/////////////////////////
799370b324cSopenharmony_ci// COutFile
800370b324cSopenharmony_ci
801370b324cSopenharmony_cibool COutFile::Create(const char *name, bool createAlways)
802370b324cSopenharmony_ci{
803370b324cSopenharmony_ci  Path = name; // change it : set it only if open is success.
804370b324cSopenharmony_ci  if (createAlways)
805370b324cSopenharmony_ci  {
806370b324cSopenharmony_ci    Close();
807370b324cSopenharmony_ci    _handle = ::creat(name, mode_for_Create);
808370b324cSopenharmony_ci    return _handle != -1;
809370b324cSopenharmony_ci  }
810370b324cSopenharmony_ci  return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY, mode_for_Create);
811370b324cSopenharmony_ci}
812370b324cSopenharmony_ci
813370b324cSopenharmony_cibool COutFile::Open(const char *name, DWORD creationDisposition)
814370b324cSopenharmony_ci{
815370b324cSopenharmony_ci  UNUSED_VAR(creationDisposition) // FIXME
816370b324cSopenharmony_ci  return Create(name, false);
817370b324cSopenharmony_ci}
818370b324cSopenharmony_ci
819370b324cSopenharmony_cissize_t COutFile::write_part(const void *data, size_t size) throw()
820370b324cSopenharmony_ci{
821370b324cSopenharmony_ci  if (size > kChunkSizeMax)
822370b324cSopenharmony_ci    size = kChunkSizeMax;
823370b324cSopenharmony_ci  return ::write(_handle, data, size);
824370b324cSopenharmony_ci}
825370b324cSopenharmony_ci
826370b324cSopenharmony_cissize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw()
827370b324cSopenharmony_ci{
828370b324cSopenharmony_ci  processed = 0;
829370b324cSopenharmony_ci  do
830370b324cSopenharmony_ci  {
831370b324cSopenharmony_ci    const ssize_t res = write_part(data, size);
832370b324cSopenharmony_ci    if (res < 0)
833370b324cSopenharmony_ci      return res;
834370b324cSopenharmony_ci    if (res == 0)
835370b324cSopenharmony_ci      break;
836370b324cSopenharmony_ci    data = (const void *)((const unsigned char *)data + (size_t)res);
837370b324cSopenharmony_ci    size -= (size_t)res;
838370b324cSopenharmony_ci    processed += (size_t)res;
839370b324cSopenharmony_ci  }
840370b324cSopenharmony_ci  while (size > 0);
841370b324cSopenharmony_ci  return (ssize_t)processed;
842370b324cSopenharmony_ci}
843370b324cSopenharmony_ci
844370b324cSopenharmony_cibool COutFile::SetLength(UInt64 length) throw()
845370b324cSopenharmony_ci{
846370b324cSopenharmony_ci  const off_t len2 = (off_t)length;
847370b324cSopenharmony_ci  if ((Int64)length != len2)
848370b324cSopenharmony_ci  {
849370b324cSopenharmony_ci    SetLastError(EFBIG);
850370b324cSopenharmony_ci    return false;
851370b324cSopenharmony_ci  }
852370b324cSopenharmony_ci  // The value of the seek pointer shall not be modified by a call to ftruncate().
853370b324cSopenharmony_ci  const int iret = ftruncate(_handle, len2);
854370b324cSopenharmony_ci  return (iret == 0);
855370b324cSopenharmony_ci}
856370b324cSopenharmony_ci
857370b324cSopenharmony_cibool COutFile::Close()
858370b324cSopenharmony_ci{
859370b324cSopenharmony_ci  const bool res = CFileBase::Close();
860370b324cSopenharmony_ci  if (!res)
861370b324cSopenharmony_ci    return res;
862370b324cSopenharmony_ci  if (CTime_defined || ATime_defined || MTime_defined)
863370b324cSopenharmony_ci  {
864370b324cSopenharmony_ci    /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path,
865370b324cSopenharmony_ci        CTime_defined ? &CTime : NULL,
866370b324cSopenharmony_ci        ATime_defined ? &ATime : NULL,
867370b324cSopenharmony_ci        MTime_defined ? &MTime : NULL);
868370b324cSopenharmony_ci  }
869370b324cSopenharmony_ci  return res;
870370b324cSopenharmony_ci}
871370b324cSopenharmony_ci
872370b324cSopenharmony_cibool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw()
873370b324cSopenharmony_ci{
874370b324cSopenharmony_ci  // On some OS (cygwin, MacOSX ...), you must close the file before updating times
875370b324cSopenharmony_ci  // return true;
876370b324cSopenharmony_ci
877370b324cSopenharmony_ci  if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false;
878370b324cSopenharmony_ci  if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false;
879370b324cSopenharmony_ci  if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
880370b324cSopenharmony_ci  return true;
881370b324cSopenharmony_ci
882370b324cSopenharmony_ci  /*
883370b324cSopenharmony_ci  struct timespec times[2];
884370b324cSopenharmony_ci  UNUSED_VAR(cTime)
885370b324cSopenharmony_ci  if (!aTime && !mTime)
886370b324cSopenharmony_ci    return true;
887370b324cSopenharmony_ci  bool needChange;
888370b324cSopenharmony_ci  needChange  = FiTime_To_timespec(aTime, times[0]);
889370b324cSopenharmony_ci  needChange |= FiTime_To_timespec(mTime, times[1]);
890370b324cSopenharmony_ci  if (!needChange)
891370b324cSopenharmony_ci    return true;
892370b324cSopenharmony_ci  return futimens(_handle, times) == 0;
893370b324cSopenharmony_ci  */
894370b324cSopenharmony_ci}
895370b324cSopenharmony_ci
896370b324cSopenharmony_cibool COutFile::SetMTime(const CFiTime *mTime) throw()
897370b324cSopenharmony_ci{
898370b324cSopenharmony_ci  if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
899370b324cSopenharmony_ci  return true;
900370b324cSopenharmony_ci}
901370b324cSopenharmony_ci
902370b324cSopenharmony_ci}}}
903370b324cSopenharmony_ci
904370b324cSopenharmony_ci
905370b324cSopenharmony_ci#endif
906