xref: /third_party/lzma/CPP/Windows/FileDir.cpp (revision 370b324c)
1370b324cSopenharmony_ci// Windows/FileDir.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci
6370b324cSopenharmony_ci#ifndef _WIN32
7370b324cSopenharmony_ci#include <stdio.h>
8370b324cSopenharmony_ci#include <stdlib.h>
9370b324cSopenharmony_ci#include <errno.h>
10370b324cSopenharmony_ci#include <limits.h>
11370b324cSopenharmony_ci#include <unistd.h>
12370b324cSopenharmony_ci#include <time.h>
13370b324cSopenharmony_ci#include <utime.h>
14370b324cSopenharmony_ci#include <fcntl.h>
15370b324cSopenharmony_ci#include <sys/stat.h>
16370b324cSopenharmony_ci#include <sys/types.h>
17370b324cSopenharmony_ci
18370b324cSopenharmony_ci#include "../Common/StringConvert.h"
19370b324cSopenharmony_ci#include "../Common/C_FileIO.h"
20370b324cSopenharmony_ci#endif
21370b324cSopenharmony_ci
22370b324cSopenharmony_ci#include "FileDir.h"
23370b324cSopenharmony_ci#include "FileFind.h"
24370b324cSopenharmony_ci#include "FileName.h"
25370b324cSopenharmony_ci
26370b324cSopenharmony_ci#ifndef _UNICODE
27370b324cSopenharmony_ciextern bool g_IsNT;
28370b324cSopenharmony_ci#endif
29370b324cSopenharmony_ci
30370b324cSopenharmony_ciusing namespace NWindows;
31370b324cSopenharmony_ciusing namespace NFile;
32370b324cSopenharmony_ciusing namespace NName;
33370b324cSopenharmony_ci
34370b324cSopenharmony_ci#ifndef _WIN32
35370b324cSopenharmony_ci
36370b324cSopenharmony_cistatic bool FiTime_To_timespec(const CFiTime *ft, timespec &ts)
37370b324cSopenharmony_ci{
38370b324cSopenharmony_ci  if (ft)
39370b324cSopenharmony_ci  {
40370b324cSopenharmony_ci    ts = *ft;
41370b324cSopenharmony_ci    return true;
42370b324cSopenharmony_ci  }
43370b324cSopenharmony_ci  // else
44370b324cSopenharmony_ci  {
45370b324cSopenharmony_ci    ts.tv_sec = 0;
46370b324cSopenharmony_ci    ts.tv_nsec =
47370b324cSopenharmony_ci    #ifdef UTIME_OMIT
48370b324cSopenharmony_ci      UTIME_OMIT; // -2 keep old timesptamp
49370b324cSopenharmony_ci    #else
50370b324cSopenharmony_ci      // UTIME_NOW; -1 // set to the current time
51370b324cSopenharmony_ci      0;
52370b324cSopenharmony_ci    #endif
53370b324cSopenharmony_ci    return false;
54370b324cSopenharmony_ci  }
55370b324cSopenharmony_ci}
56370b324cSopenharmony_ci#endif
57370b324cSopenharmony_ci
58370b324cSopenharmony_cinamespace NWindows {
59370b324cSopenharmony_cinamespace NFile {
60370b324cSopenharmony_cinamespace NDir {
61370b324cSopenharmony_ci
62370b324cSopenharmony_ci#ifdef _WIN32
63370b324cSopenharmony_ci
64370b324cSopenharmony_ci#ifndef UNDER_CE
65370b324cSopenharmony_ci
66370b324cSopenharmony_cibool GetWindowsDir(FString &path)
67370b324cSopenharmony_ci{
68370b324cSopenharmony_ci  const unsigned kBufSize = MAX_PATH + 16;
69370b324cSopenharmony_ci  UINT len;
70370b324cSopenharmony_ci  #ifndef _UNICODE
71370b324cSopenharmony_ci  if (!g_IsNT)
72370b324cSopenharmony_ci  {
73370b324cSopenharmony_ci    TCHAR s[kBufSize + 1];
74370b324cSopenharmony_ci    s[0] = 0;
75370b324cSopenharmony_ci    len = ::GetWindowsDirectory(s, kBufSize);
76370b324cSopenharmony_ci    path = fas2fs(s);
77370b324cSopenharmony_ci  }
78370b324cSopenharmony_ci  else
79370b324cSopenharmony_ci  #endif
80370b324cSopenharmony_ci  {
81370b324cSopenharmony_ci    WCHAR s[kBufSize + 1];
82370b324cSopenharmony_ci    s[0] = 0;
83370b324cSopenharmony_ci    len = ::GetWindowsDirectoryW(s, kBufSize);
84370b324cSopenharmony_ci    path = us2fs(s);
85370b324cSopenharmony_ci  }
86370b324cSopenharmony_ci  return (len != 0 && len < kBufSize);
87370b324cSopenharmony_ci}
88370b324cSopenharmony_ci
89370b324cSopenharmony_ci
90370b324cSopenharmony_ci/*
91370b324cSopenharmony_cinew DOCs for GetSystemDirectory:
92370b324cSopenharmony_ci  returned path does not end with a backslash unless the
93370b324cSopenharmony_ci  system directory is the root directory.
94370b324cSopenharmony_ci*/
95370b324cSopenharmony_ci
96370b324cSopenharmony_cibool GetSystemDir(FString &path)
97370b324cSopenharmony_ci{
98370b324cSopenharmony_ci  const unsigned kBufSize = MAX_PATH + 16;
99370b324cSopenharmony_ci  UINT len;
100370b324cSopenharmony_ci  #ifndef _UNICODE
101370b324cSopenharmony_ci  if (!g_IsNT)
102370b324cSopenharmony_ci  {
103370b324cSopenharmony_ci    TCHAR s[kBufSize + 1];
104370b324cSopenharmony_ci    s[0] = 0;
105370b324cSopenharmony_ci    len = ::GetSystemDirectory(s, kBufSize);
106370b324cSopenharmony_ci    path = fas2fs(s);
107370b324cSopenharmony_ci  }
108370b324cSopenharmony_ci  else
109370b324cSopenharmony_ci  #endif
110370b324cSopenharmony_ci  {
111370b324cSopenharmony_ci    WCHAR s[kBufSize + 1];
112370b324cSopenharmony_ci    s[0] = 0;
113370b324cSopenharmony_ci    len = ::GetSystemDirectoryW(s, kBufSize);
114370b324cSopenharmony_ci    path = us2fs(s);
115370b324cSopenharmony_ci  }
116370b324cSopenharmony_ci  return (len != 0 && len < kBufSize);
117370b324cSopenharmony_ci}
118370b324cSopenharmony_ci#endif // UNDER_CE
119370b324cSopenharmony_ci
120370b324cSopenharmony_ci
121370b324cSopenharmony_cibool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
122370b324cSopenharmony_ci{
123370b324cSopenharmony_ci  #ifndef _UNICODE
124370b324cSopenharmony_ci  if (!g_IsNT)
125370b324cSopenharmony_ci  {
126370b324cSopenharmony_ci    ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
127370b324cSopenharmony_ci    return false;
128370b324cSopenharmony_ci  }
129370b324cSopenharmony_ci  #endif
130370b324cSopenharmony_ci
131370b324cSopenharmony_ci  HANDLE hDir = INVALID_HANDLE_VALUE;
132370b324cSopenharmony_ci  IF_USE_MAIN_PATH
133370b324cSopenharmony_ci    hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
134370b324cSopenharmony_ci        NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
135370b324cSopenharmony_ci  #ifdef Z7_LONG_PATH
136370b324cSopenharmony_ci  if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
137370b324cSopenharmony_ci  {
138370b324cSopenharmony_ci    UString superPath;
139370b324cSopenharmony_ci    if (GetSuperPath(path, superPath, USE_MAIN_PATH))
140370b324cSopenharmony_ci      hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
141370b324cSopenharmony_ci          NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
142370b324cSopenharmony_ci  }
143370b324cSopenharmony_ci  #endif
144370b324cSopenharmony_ci
145370b324cSopenharmony_ci  bool res = false;
146370b324cSopenharmony_ci  if (hDir != INVALID_HANDLE_VALUE)
147370b324cSopenharmony_ci  {
148370b324cSopenharmony_ci    res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime));
149370b324cSopenharmony_ci    ::CloseHandle(hDir);
150370b324cSopenharmony_ci  }
151370b324cSopenharmony_ci  return res;
152370b324cSopenharmony_ci}
153370b324cSopenharmony_ci
154370b324cSopenharmony_ci
155370b324cSopenharmony_ci
156370b324cSopenharmony_cibool SetFileAttrib(CFSTR path, DWORD attrib)
157370b324cSopenharmony_ci{
158370b324cSopenharmony_ci  #ifndef _UNICODE
159370b324cSopenharmony_ci  if (!g_IsNT)
160370b324cSopenharmony_ci  {
161370b324cSopenharmony_ci    if (::SetFileAttributes(fs2fas(path), attrib))
162370b324cSopenharmony_ci      return true;
163370b324cSopenharmony_ci  }
164370b324cSopenharmony_ci  else
165370b324cSopenharmony_ci  #endif
166370b324cSopenharmony_ci  {
167370b324cSopenharmony_ci    IF_USE_MAIN_PATH
168370b324cSopenharmony_ci      if (::SetFileAttributesW(fs2us(path), attrib))
169370b324cSopenharmony_ci        return true;
170370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
171370b324cSopenharmony_ci    if (USE_SUPER_PATH)
172370b324cSopenharmony_ci    {
173370b324cSopenharmony_ci      UString superPath;
174370b324cSopenharmony_ci      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
175370b324cSopenharmony_ci        return BOOLToBool(::SetFileAttributesW(superPath, attrib));
176370b324cSopenharmony_ci    }
177370b324cSopenharmony_ci    #endif
178370b324cSopenharmony_ci  }
179370b324cSopenharmony_ci  return false;
180370b324cSopenharmony_ci}
181370b324cSopenharmony_ci
182370b324cSopenharmony_ci
183370b324cSopenharmony_cibool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
184370b324cSopenharmony_ci{
185370b324cSopenharmony_ci  #ifdef _WIN32
186370b324cSopenharmony_ci  if ((attrib & 0xF0000000) != 0)
187370b324cSopenharmony_ci    attrib &= 0x3FFF;
188370b324cSopenharmony_ci  #endif
189370b324cSopenharmony_ci  return SetFileAttrib(path, attrib);
190370b324cSopenharmony_ci}
191370b324cSopenharmony_ci
192370b324cSopenharmony_ci
193370b324cSopenharmony_cibool RemoveDir(CFSTR path)
194370b324cSopenharmony_ci{
195370b324cSopenharmony_ci  #ifndef _UNICODE
196370b324cSopenharmony_ci  if (!g_IsNT)
197370b324cSopenharmony_ci  {
198370b324cSopenharmony_ci    if (::RemoveDirectory(fs2fas(path)))
199370b324cSopenharmony_ci      return true;
200370b324cSopenharmony_ci  }
201370b324cSopenharmony_ci  else
202370b324cSopenharmony_ci  #endif
203370b324cSopenharmony_ci  {
204370b324cSopenharmony_ci    IF_USE_MAIN_PATH
205370b324cSopenharmony_ci      if (::RemoveDirectoryW(fs2us(path)))
206370b324cSopenharmony_ci        return true;
207370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
208370b324cSopenharmony_ci    if (USE_SUPER_PATH)
209370b324cSopenharmony_ci    {
210370b324cSopenharmony_ci      UString superPath;
211370b324cSopenharmony_ci      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
212370b324cSopenharmony_ci        return BOOLToBool(::RemoveDirectoryW(superPath));
213370b324cSopenharmony_ci    }
214370b324cSopenharmony_ci    #endif
215370b324cSopenharmony_ci  }
216370b324cSopenharmony_ci  return false;
217370b324cSopenharmony_ci}
218370b324cSopenharmony_ci
219370b324cSopenharmony_ci
220370b324cSopenharmony_cibool MyMoveFile(CFSTR oldFile, CFSTR newFile)
221370b324cSopenharmony_ci{
222370b324cSopenharmony_ci  #ifndef _UNICODE
223370b324cSopenharmony_ci  if (!g_IsNT)
224370b324cSopenharmony_ci  {
225370b324cSopenharmony_ci    if (::MoveFile(fs2fas(oldFile), fs2fas(newFile)))
226370b324cSopenharmony_ci      return true;
227370b324cSopenharmony_ci  }
228370b324cSopenharmony_ci  else
229370b324cSopenharmony_ci  #endif
230370b324cSopenharmony_ci  {
231370b324cSopenharmony_ci    IF_USE_MAIN_PATH_2(oldFile, newFile)
232370b324cSopenharmony_ci    {
233370b324cSopenharmony_ci      if (::MoveFileW(fs2us(oldFile), fs2us(newFile)))
234370b324cSopenharmony_ci        return true;
235370b324cSopenharmony_ci    }
236370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
237370b324cSopenharmony_ci    if (USE_SUPER_PATH_2)
238370b324cSopenharmony_ci    {
239370b324cSopenharmony_ci      UString d1, d2;
240370b324cSopenharmony_ci      if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2))
241370b324cSopenharmony_ci        return BOOLToBool(::MoveFileW(d1, d2));
242370b324cSopenharmony_ci    }
243370b324cSopenharmony_ci    #endif
244370b324cSopenharmony_ci  }
245370b324cSopenharmony_ci  return false;
246370b324cSopenharmony_ci}
247370b324cSopenharmony_ci
248370b324cSopenharmony_ci#ifndef UNDER_CE
249370b324cSopenharmony_ciEXTERN_C_BEGIN
250370b324cSopenharmony_citypedef BOOL (WINAPI *Func_CreateHardLinkW)(
251370b324cSopenharmony_ci    LPCWSTR lpFileName,
252370b324cSopenharmony_ci    LPCWSTR lpExistingFileName,
253370b324cSopenharmony_ci    LPSECURITY_ATTRIBUTES lpSecurityAttributes
254370b324cSopenharmony_ci    );
255370b324cSopenharmony_ciEXTERN_C_END
256370b324cSopenharmony_ci#endif // UNDER_CE
257370b324cSopenharmony_ci
258370b324cSopenharmony_cibool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
259370b324cSopenharmony_ci{
260370b324cSopenharmony_ci  #ifndef _UNICODE
261370b324cSopenharmony_ci  if (!g_IsNT)
262370b324cSopenharmony_ci  {
263370b324cSopenharmony_ci    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
264370b324cSopenharmony_ci    return false;
265370b324cSopenharmony_ci    /*
266370b324cSopenharmony_ci    if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL))
267370b324cSopenharmony_ci      return true;
268370b324cSopenharmony_ci    */
269370b324cSopenharmony_ci  }
270370b324cSopenharmony_ci  else
271370b324cSopenharmony_ci  #endif
272370b324cSopenharmony_ci  {
273370b324cSopenharmony_ci    const
274370b324cSopenharmony_ci    Func_CreateHardLinkW
275370b324cSopenharmony_ci      my_CreateHardLinkW = Z7_GET_PROC_ADDRESS(
276370b324cSopenharmony_ci    Func_CreateHardLinkW, ::GetModuleHandleW(L"kernel32.dll"),
277370b324cSopenharmony_ci        "CreateHardLinkW");
278370b324cSopenharmony_ci    if (!my_CreateHardLinkW)
279370b324cSopenharmony_ci      return false;
280370b324cSopenharmony_ci    IF_USE_MAIN_PATH_2(newFileName, existFileName)
281370b324cSopenharmony_ci    {
282370b324cSopenharmony_ci      if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL))
283370b324cSopenharmony_ci        return true;
284370b324cSopenharmony_ci    }
285370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
286370b324cSopenharmony_ci    if (USE_SUPER_PATH_2)
287370b324cSopenharmony_ci    {
288370b324cSopenharmony_ci      UString d1, d2;
289370b324cSopenharmony_ci      if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2))
290370b324cSopenharmony_ci        return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL));
291370b324cSopenharmony_ci    }
292370b324cSopenharmony_ci    #endif
293370b324cSopenharmony_ci  }
294370b324cSopenharmony_ci  return false;
295370b324cSopenharmony_ci}
296370b324cSopenharmony_ci
297370b324cSopenharmony_ci
298370b324cSopenharmony_ci/*
299370b324cSopenharmony_ciWinXP-64 CreateDir():
300370b324cSopenharmony_ci  ""                  - ERROR_PATH_NOT_FOUND
301370b324cSopenharmony_ci  \                   - ERROR_ACCESS_DENIED
302370b324cSopenharmony_ci  C:\                 - ERROR_ACCESS_DENIED, if there is such drive,
303370b324cSopenharmony_ci
304370b324cSopenharmony_ci  D:\folder             - ERROR_PATH_NOT_FOUND, if there is no such drive,
305370b324cSopenharmony_ci  C:\nonExistent\folder - ERROR_PATH_NOT_FOUND
306370b324cSopenharmony_ci
307370b324cSopenharmony_ci  C:\existFolder      - ERROR_ALREADY_EXISTS
308370b324cSopenharmony_ci  C:\existFolder\     - ERROR_ALREADY_EXISTS
309370b324cSopenharmony_ci
310370b324cSopenharmony_ci  C:\folder   - OK
311370b324cSopenharmony_ci  C:\folder\  - OK
312370b324cSopenharmony_ci
313370b324cSopenharmony_ci  \\Server\nonExistent    - ERROR_BAD_NETPATH
314370b324cSopenharmony_ci  \\Server\Share_Readonly - ERROR_ACCESS_DENIED
315370b324cSopenharmony_ci  \\Server\Share          - ERROR_ALREADY_EXISTS
316370b324cSopenharmony_ci
317370b324cSopenharmony_ci  \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED
318370b324cSopenharmony_ci  \\Server\Share_FAT_drive  - ERROR_ALREADY_EXISTS
319370b324cSopenharmony_ci*/
320370b324cSopenharmony_ci
321370b324cSopenharmony_cibool CreateDir(CFSTR path)
322370b324cSopenharmony_ci{
323370b324cSopenharmony_ci  #ifndef _UNICODE
324370b324cSopenharmony_ci  if (!g_IsNT)
325370b324cSopenharmony_ci  {
326370b324cSopenharmony_ci    if (::CreateDirectory(fs2fas(path), NULL))
327370b324cSopenharmony_ci      return true;
328370b324cSopenharmony_ci  }
329370b324cSopenharmony_ci  else
330370b324cSopenharmony_ci  #endif
331370b324cSopenharmony_ci  {
332370b324cSopenharmony_ci    IF_USE_MAIN_PATH
333370b324cSopenharmony_ci      if (::CreateDirectoryW(fs2us(path), NULL))
334370b324cSopenharmony_ci        return true;
335370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
336370b324cSopenharmony_ci    if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
337370b324cSopenharmony_ci    {
338370b324cSopenharmony_ci      UString superPath;
339370b324cSopenharmony_ci      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
340370b324cSopenharmony_ci        return BOOLToBool(::CreateDirectoryW(superPath, NULL));
341370b324cSopenharmony_ci    }
342370b324cSopenharmony_ci    #endif
343370b324cSopenharmony_ci  }
344370b324cSopenharmony_ci  return false;
345370b324cSopenharmony_ci}
346370b324cSopenharmony_ci
347370b324cSopenharmony_ci/*
348370b324cSopenharmony_ci  CreateDir2 returns true, if directory can contain files after the call (two cases):
349370b324cSopenharmony_ci    1) the directory already exists
350370b324cSopenharmony_ci    2) the directory was created
351370b324cSopenharmony_ci  path must be WITHOUT trailing path separator.
352370b324cSopenharmony_ci
353370b324cSopenharmony_ci  We need CreateDir2, since fileInfo.Find() for reserved names like "com8"
354370b324cSopenharmony_ci   returns FILE instead of DIRECTORY. And we need to use SuperPath */
355370b324cSopenharmony_ci
356370b324cSopenharmony_cistatic bool CreateDir2(CFSTR path)
357370b324cSopenharmony_ci{
358370b324cSopenharmony_ci  #ifndef _UNICODE
359370b324cSopenharmony_ci  if (!g_IsNT)
360370b324cSopenharmony_ci  {
361370b324cSopenharmony_ci    if (::CreateDirectory(fs2fas(path), NULL))
362370b324cSopenharmony_ci      return true;
363370b324cSopenharmony_ci  }
364370b324cSopenharmony_ci  else
365370b324cSopenharmony_ci  #endif
366370b324cSopenharmony_ci  {
367370b324cSopenharmony_ci    IF_USE_MAIN_PATH
368370b324cSopenharmony_ci      if (::CreateDirectoryW(fs2us(path), NULL))
369370b324cSopenharmony_ci        return true;
370370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
371370b324cSopenharmony_ci    if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
372370b324cSopenharmony_ci    {
373370b324cSopenharmony_ci      UString superPath;
374370b324cSopenharmony_ci      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
375370b324cSopenharmony_ci      {
376370b324cSopenharmony_ci        if (::CreateDirectoryW(superPath, NULL))
377370b324cSopenharmony_ci          return true;
378370b324cSopenharmony_ci        if (::GetLastError() != ERROR_ALREADY_EXISTS)
379370b324cSopenharmony_ci          return false;
380370b324cSopenharmony_ci        NFind::CFileInfo fi;
381370b324cSopenharmony_ci        if (!fi.Find(us2fs(superPath)))
382370b324cSopenharmony_ci          return false;
383370b324cSopenharmony_ci        return fi.IsDir();
384370b324cSopenharmony_ci      }
385370b324cSopenharmony_ci    }
386370b324cSopenharmony_ci    #endif
387370b324cSopenharmony_ci  }
388370b324cSopenharmony_ci  if (::GetLastError() != ERROR_ALREADY_EXISTS)
389370b324cSopenharmony_ci    return false;
390370b324cSopenharmony_ci  NFind::CFileInfo fi;
391370b324cSopenharmony_ci  if (!fi.Find(path))
392370b324cSopenharmony_ci    return false;
393370b324cSopenharmony_ci  return fi.IsDir();
394370b324cSopenharmony_ci}
395370b324cSopenharmony_ci
396370b324cSopenharmony_ci#endif // _WIN32
397370b324cSopenharmony_ci
398370b324cSopenharmony_cistatic bool CreateDir2(CFSTR path);
399370b324cSopenharmony_ci
400370b324cSopenharmony_cibool CreateComplexDir(CFSTR _path)
401370b324cSopenharmony_ci{
402370b324cSopenharmony_ci  #ifdef _WIN32
403370b324cSopenharmony_ci
404370b324cSopenharmony_ci  {
405370b324cSopenharmony_ci    const DWORD attrib = NFind::GetFileAttrib(_path);
406370b324cSopenharmony_ci    if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
407370b324cSopenharmony_ci      return true;
408370b324cSopenharmony_ci  }
409370b324cSopenharmony_ci
410370b324cSopenharmony_ci  #ifndef UNDER_CE
411370b324cSopenharmony_ci
412370b324cSopenharmony_ci  if (IsDriveRootPath_SuperAllowed(_path))
413370b324cSopenharmony_ci    return false;
414370b324cSopenharmony_ci
415370b324cSopenharmony_ci  const unsigned prefixSize = GetRootPrefixSize(_path);
416370b324cSopenharmony_ci
417370b324cSopenharmony_ci  #endif // UNDER_CE
418370b324cSopenharmony_ci
419370b324cSopenharmony_ci  #else // _WIN32
420370b324cSopenharmony_ci
421370b324cSopenharmony_ci  // Posix
422370b324cSopenharmony_ci  NFind::CFileInfo fi;
423370b324cSopenharmony_ci  if (fi.Find(_path))
424370b324cSopenharmony_ci  {
425370b324cSopenharmony_ci    if (fi.IsDir())
426370b324cSopenharmony_ci      return true;
427370b324cSopenharmony_ci  }
428370b324cSopenharmony_ci
429370b324cSopenharmony_ci  #endif // _WIN32
430370b324cSopenharmony_ci
431370b324cSopenharmony_ci  FString path (_path);
432370b324cSopenharmony_ci
433370b324cSopenharmony_ci  int pos = path.ReverseFind_PathSepar();
434370b324cSopenharmony_ci  if (pos >= 0 && (unsigned)pos == path.Len() - 1)
435370b324cSopenharmony_ci  {
436370b324cSopenharmony_ci    if (path.Len() == 1)
437370b324cSopenharmony_ci      return true;
438370b324cSopenharmony_ci    path.DeleteBack();
439370b324cSopenharmony_ci  }
440370b324cSopenharmony_ci
441370b324cSopenharmony_ci  const FString path2 (path);
442370b324cSopenharmony_ci  pos = (int)path.Len();
443370b324cSopenharmony_ci
444370b324cSopenharmony_ci  for (;;)
445370b324cSopenharmony_ci  {
446370b324cSopenharmony_ci    if (CreateDir2(path))
447370b324cSopenharmony_ci      break;
448370b324cSopenharmony_ci    if (::GetLastError() == ERROR_ALREADY_EXISTS)
449370b324cSopenharmony_ci      return false;
450370b324cSopenharmony_ci    pos = path.ReverseFind_PathSepar();
451370b324cSopenharmony_ci    if (pos < 0 || pos == 0)
452370b324cSopenharmony_ci      return false;
453370b324cSopenharmony_ci
454370b324cSopenharmony_ci    #if defined(_WIN32) && !defined(UNDER_CE)
455370b324cSopenharmony_ci    if (pos == 1 && IS_PATH_SEPAR(path[0]))
456370b324cSopenharmony_ci      return false;
457370b324cSopenharmony_ci    if (prefixSize >= (unsigned)pos + 1)
458370b324cSopenharmony_ci      return false;
459370b324cSopenharmony_ci    #endif
460370b324cSopenharmony_ci
461370b324cSopenharmony_ci    path.DeleteFrom((unsigned)pos);
462370b324cSopenharmony_ci  }
463370b324cSopenharmony_ci
464370b324cSopenharmony_ci  while (pos < (int)path2.Len())
465370b324cSopenharmony_ci  {
466370b324cSopenharmony_ci    int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1));
467370b324cSopenharmony_ci    if (pos2 < 0)
468370b324cSopenharmony_ci      pos = (int)path2.Len();
469370b324cSopenharmony_ci    else
470370b324cSopenharmony_ci      pos += 1 + pos2;
471370b324cSopenharmony_ci    path.SetFrom(path2, (unsigned)pos);
472370b324cSopenharmony_ci    if (!CreateDir(path))
473370b324cSopenharmony_ci      return false;
474370b324cSopenharmony_ci  }
475370b324cSopenharmony_ci
476370b324cSopenharmony_ci  return true;
477370b324cSopenharmony_ci}
478370b324cSopenharmony_ci
479370b324cSopenharmony_ci
480370b324cSopenharmony_ci#ifdef _WIN32
481370b324cSopenharmony_ci
482370b324cSopenharmony_cibool DeleteFileAlways(CFSTR path)
483370b324cSopenharmony_ci{
484370b324cSopenharmony_ci  /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete.
485370b324cSopenharmony_ci     SetFileAttrib("name:stream", ) changes attributes of main file. */
486370b324cSopenharmony_ci  {
487370b324cSopenharmony_ci    DWORD attrib = NFind::GetFileAttrib(path);
488370b324cSopenharmony_ci    if (attrib != INVALID_FILE_ATTRIBUTES
489370b324cSopenharmony_ci        && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0
490370b324cSopenharmony_ci        && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
491370b324cSopenharmony_ci    {
492370b324cSopenharmony_ci      if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY))
493370b324cSopenharmony_ci        return false;
494370b324cSopenharmony_ci    }
495370b324cSopenharmony_ci  }
496370b324cSopenharmony_ci
497370b324cSopenharmony_ci  #ifndef _UNICODE
498370b324cSopenharmony_ci  if (!g_IsNT)
499370b324cSopenharmony_ci  {
500370b324cSopenharmony_ci    if (::DeleteFile(fs2fas(path)))
501370b324cSopenharmony_ci      return true;
502370b324cSopenharmony_ci  }
503370b324cSopenharmony_ci  else
504370b324cSopenharmony_ci  #endif
505370b324cSopenharmony_ci  {
506370b324cSopenharmony_ci    /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")).
507370b324cSopenharmony_ci       Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */
508370b324cSopenharmony_ci    IF_USE_MAIN_PATH
509370b324cSopenharmony_ci      if (::DeleteFileW(fs2us(path)))
510370b324cSopenharmony_ci        return true;
511370b324cSopenharmony_ci    #ifdef Z7_LONG_PATH
512370b324cSopenharmony_ci    if (USE_SUPER_PATH)
513370b324cSopenharmony_ci    {
514370b324cSopenharmony_ci      UString superPath;
515370b324cSopenharmony_ci      if (GetSuperPath(path, superPath, USE_MAIN_PATH))
516370b324cSopenharmony_ci        return BOOLToBool(::DeleteFileW(superPath));
517370b324cSopenharmony_ci    }
518370b324cSopenharmony_ci    #endif
519370b324cSopenharmony_ci  }
520370b324cSopenharmony_ci  return false;
521370b324cSopenharmony_ci}
522370b324cSopenharmony_ci
523370b324cSopenharmony_ci
524370b324cSopenharmony_ci
525370b324cSopenharmony_cibool RemoveDirWithSubItems(const FString &path)
526370b324cSopenharmony_ci{
527370b324cSopenharmony_ci  bool needRemoveSubItems = true;
528370b324cSopenharmony_ci  {
529370b324cSopenharmony_ci    NFind::CFileInfo fi;
530370b324cSopenharmony_ci    if (!fi.Find(path))
531370b324cSopenharmony_ci      return false;
532370b324cSopenharmony_ci    if (!fi.IsDir())
533370b324cSopenharmony_ci    {
534370b324cSopenharmony_ci      ::SetLastError(ERROR_DIRECTORY);
535370b324cSopenharmony_ci      return false;
536370b324cSopenharmony_ci    }
537370b324cSopenharmony_ci    if (fi.HasReparsePoint())
538370b324cSopenharmony_ci      needRemoveSubItems = false;
539370b324cSopenharmony_ci  }
540370b324cSopenharmony_ci
541370b324cSopenharmony_ci  if (needRemoveSubItems)
542370b324cSopenharmony_ci  {
543370b324cSopenharmony_ci    FString s (path);
544370b324cSopenharmony_ci    s.Add_PathSepar();
545370b324cSopenharmony_ci    const unsigned prefixSize = s.Len();
546370b324cSopenharmony_ci    NFind::CEnumerator enumerator;
547370b324cSopenharmony_ci    enumerator.SetDirPrefix(s);
548370b324cSopenharmony_ci    NFind::CDirEntry fi;
549370b324cSopenharmony_ci    bool isError = false;
550370b324cSopenharmony_ci    DWORD lastError = 0;
551370b324cSopenharmony_ci    while (enumerator.Next(fi))
552370b324cSopenharmony_ci    {
553370b324cSopenharmony_ci      s.DeleteFrom(prefixSize);
554370b324cSopenharmony_ci      s += fi.Name;
555370b324cSopenharmony_ci      if (fi.IsDir())
556370b324cSopenharmony_ci      {
557370b324cSopenharmony_ci        if (!RemoveDirWithSubItems(s))
558370b324cSopenharmony_ci        {
559370b324cSopenharmony_ci          lastError = GetLastError();
560370b324cSopenharmony_ci          isError = true;
561370b324cSopenharmony_ci        }
562370b324cSopenharmony_ci      }
563370b324cSopenharmony_ci      else if (!DeleteFileAlways(s))
564370b324cSopenharmony_ci      {
565370b324cSopenharmony_ci        lastError = GetLastError();
566370b324cSopenharmony_ci        isError = false;
567370b324cSopenharmony_ci      }
568370b324cSopenharmony_ci    }
569370b324cSopenharmony_ci    if (isError)
570370b324cSopenharmony_ci    {
571370b324cSopenharmony_ci      SetLastError(lastError);
572370b324cSopenharmony_ci      return false;
573370b324cSopenharmony_ci    }
574370b324cSopenharmony_ci  }
575370b324cSopenharmony_ci
576370b324cSopenharmony_ci  // we clear read-only attrib to remove read-only dir
577370b324cSopenharmony_ci  if (!SetFileAttrib(path, 0))
578370b324cSopenharmony_ci    return false;
579370b324cSopenharmony_ci  return RemoveDir(path);
580370b324cSopenharmony_ci}
581370b324cSopenharmony_ci
582370b324cSopenharmony_ci#endif // _WIN32
583370b324cSopenharmony_ci
584370b324cSopenharmony_ci#ifdef UNDER_CE
585370b324cSopenharmony_ci
586370b324cSopenharmony_cibool MyGetFullPathName(CFSTR path, FString &resFullPath)
587370b324cSopenharmony_ci{
588370b324cSopenharmony_ci  resFullPath = path;
589370b324cSopenharmony_ci  return true;
590370b324cSopenharmony_ci}
591370b324cSopenharmony_ci
592370b324cSopenharmony_ci#else
593370b324cSopenharmony_ci
594370b324cSopenharmony_cibool MyGetFullPathName(CFSTR path, FString &resFullPath)
595370b324cSopenharmony_ci{
596370b324cSopenharmony_ci  return GetFullPath(path, resFullPath);
597370b324cSopenharmony_ci}
598370b324cSopenharmony_ci
599370b324cSopenharmony_ci#ifdef _WIN32
600370b324cSopenharmony_ci
601370b324cSopenharmony_ci/* Win10: SetCurrentDirectory() doesn't support long paths and
602370b324cSopenharmony_ci    doesn't support super prefix "\\?\", if long path behavior is not
603370b324cSopenharmony_ci    enabled in registry (LongPathsEnabled) and in manifest (longPathAware). */
604370b324cSopenharmony_ci
605370b324cSopenharmony_cibool SetCurrentDir(CFSTR path)
606370b324cSopenharmony_ci{
607370b324cSopenharmony_ci  #ifndef _UNICODE
608370b324cSopenharmony_ci  if (!g_IsNT)
609370b324cSopenharmony_ci  {
610370b324cSopenharmony_ci    return BOOLToBool(::SetCurrentDirectory(fs2fas(path)));
611370b324cSopenharmony_ci  }
612370b324cSopenharmony_ci  else
613370b324cSopenharmony_ci  #endif
614370b324cSopenharmony_ci  {
615370b324cSopenharmony_ci    return BOOLToBool(::SetCurrentDirectoryW(fs2us(path)));
616370b324cSopenharmony_ci  }
617370b324cSopenharmony_ci}
618370b324cSopenharmony_ci
619370b324cSopenharmony_ci
620370b324cSopenharmony_ci/*
621370b324cSopenharmony_ciwe use system function GetCurrentDirectory()
622370b324cSopenharmony_cinew GetCurrentDirectory() DOCs:
623370b324cSopenharmony_ci  - If the function fails, the return value is zero.
624370b324cSopenharmony_ci  - If the function succeeds, the return value specifies
625370b324cSopenharmony_ci      the number of characters that are written to the buffer,
626370b324cSopenharmony_ci      not including the terminating null character.
627370b324cSopenharmony_ci  - If the buffer is not large enough, the return value specifies
628370b324cSopenharmony_ci      the required size of the buffer, in characters,
629370b324cSopenharmony_ci      including the null-terminating character.
630370b324cSopenharmony_ci
631370b324cSopenharmony_ciGetCurrentDir() calls GetCurrentDirectory().
632370b324cSopenharmony_ciGetCurrentDirectory() in win10 in tests:
633370b324cSopenharmony_ci  the returned (path) does not end with a backslash, if
634370b324cSopenharmony_ci  current directory is not root directory of drive.
635370b324cSopenharmony_ci  But that behavior is not guarantied in specification docs.
636370b324cSopenharmony_ci*/
637370b324cSopenharmony_ci
638370b324cSopenharmony_cibool GetCurrentDir(FString &path)
639370b324cSopenharmony_ci{
640370b324cSopenharmony_ci  const unsigned kBufSize = MAX_PATH + 16;
641370b324cSopenharmony_ci  path.Empty();
642370b324cSopenharmony_ci
643370b324cSopenharmony_ci  #ifndef _UNICODE
644370b324cSopenharmony_ci  if (!g_IsNT)
645370b324cSopenharmony_ci  {
646370b324cSopenharmony_ci    TCHAR s[kBufSize + 1];
647370b324cSopenharmony_ci    s[0] = 0;
648370b324cSopenharmony_ci    const DWORD len = ::GetCurrentDirectory(kBufSize, s);
649370b324cSopenharmony_ci    if (len == 0 || len >= kBufSize)
650370b324cSopenharmony_ci      return false;
651370b324cSopenharmony_ci    s[kBufSize] = 0;  // optional guard
652370b324cSopenharmony_ci    path = fas2fs(s);
653370b324cSopenharmony_ci    return true;
654370b324cSopenharmony_ci  }
655370b324cSopenharmony_ci  else
656370b324cSopenharmony_ci  #endif
657370b324cSopenharmony_ci  {
658370b324cSopenharmony_ci    DWORD len;
659370b324cSopenharmony_ci    {
660370b324cSopenharmony_ci      WCHAR s[kBufSize + 1];
661370b324cSopenharmony_ci      s[0] = 0;
662370b324cSopenharmony_ci      len = ::GetCurrentDirectoryW(kBufSize, s);
663370b324cSopenharmony_ci      if (len == 0)
664370b324cSopenharmony_ci        return false;
665370b324cSopenharmony_ci      if (len < kBufSize)
666370b324cSopenharmony_ci      {
667370b324cSopenharmony_ci        s[kBufSize] = 0;  // optional guard
668370b324cSopenharmony_ci        path = us2fs(s);
669370b324cSopenharmony_ci        return true;
670370b324cSopenharmony_ci      }
671370b324cSopenharmony_ci    }
672370b324cSopenharmony_ci    UString temp;
673370b324cSopenharmony_ci    const DWORD len2 = ::GetCurrentDirectoryW(len, temp.GetBuf(len));
674370b324cSopenharmony_ci    if (len2 == 0)
675370b324cSopenharmony_ci      return false;
676370b324cSopenharmony_ci    temp.ReleaseBuf_CalcLen(len);
677370b324cSopenharmony_ci    if (temp.Len() != len2 || len - 1 != len2)
678370b324cSopenharmony_ci    {
679370b324cSopenharmony_ci      /* it's unexpected case, if current dir of process
680370b324cSopenharmony_ci         was changed between two function calls,
681370b324cSopenharmony_ci         or some unexpected function implementation */
682370b324cSopenharmony_ci      // SetLastError((DWORD)E_FAIL);  // we can set some error code
683370b324cSopenharmony_ci      return false;
684370b324cSopenharmony_ci    }
685370b324cSopenharmony_ci    path = us2fs(temp);
686370b324cSopenharmony_ci    return true;
687370b324cSopenharmony_ci  }
688370b324cSopenharmony_ci}
689370b324cSopenharmony_ci
690370b324cSopenharmony_ci#endif // _WIN32
691370b324cSopenharmony_ci#endif // UNDER_CE
692370b324cSopenharmony_ci
693370b324cSopenharmony_ci
694370b324cSopenharmony_cibool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName)
695370b324cSopenharmony_ci{
696370b324cSopenharmony_ci  bool res = MyGetFullPathName(path, resDirPrefix);
697370b324cSopenharmony_ci  if (!res)
698370b324cSopenharmony_ci    resDirPrefix = path;
699370b324cSopenharmony_ci  int pos = resDirPrefix.ReverseFind_PathSepar();
700370b324cSopenharmony_ci  pos++;
701370b324cSopenharmony_ci  resFileName = resDirPrefix.Ptr((unsigned)pos);
702370b324cSopenharmony_ci  resDirPrefix.DeleteFrom((unsigned)pos);
703370b324cSopenharmony_ci  return res;
704370b324cSopenharmony_ci}
705370b324cSopenharmony_ci
706370b324cSopenharmony_cibool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix)
707370b324cSopenharmony_ci{
708370b324cSopenharmony_ci  FString resFileName;
709370b324cSopenharmony_ci  return GetFullPathAndSplit(path, resDirPrefix, resFileName);
710370b324cSopenharmony_ci}
711370b324cSopenharmony_ci
712370b324cSopenharmony_ci
713370b324cSopenharmony_ci
714370b324cSopenharmony_cibool MyGetTempPath(FString &path)
715370b324cSopenharmony_ci{
716370b324cSopenharmony_ci  #ifdef _WIN32
717370b324cSopenharmony_ci
718370b324cSopenharmony_ci  /*
719370b324cSopenharmony_ci  new DOCs for GetTempPathW():
720370b324cSopenharmony_ci    - The returned string ends with a backslash.
721370b324cSopenharmony_ci    - The maximum possible return value is MAX_PATH+1 (261).
722370b324cSopenharmony_ci  */
723370b324cSopenharmony_ci
724370b324cSopenharmony_ci  const unsigned kBufSize = MAX_PATH + 16;
725370b324cSopenharmony_ci  DWORD len;
726370b324cSopenharmony_ci  #ifndef _UNICODE
727370b324cSopenharmony_ci  if (!g_IsNT)
728370b324cSopenharmony_ci  {
729370b324cSopenharmony_ci    TCHAR s[kBufSize + 1];
730370b324cSopenharmony_ci    s[0] = 0;
731370b324cSopenharmony_ci    len = ::GetTempPath(kBufSize, s);
732370b324cSopenharmony_ci    path = fas2fs(s);
733370b324cSopenharmony_ci  }
734370b324cSopenharmony_ci  else
735370b324cSopenharmony_ci  #endif
736370b324cSopenharmony_ci  {
737370b324cSopenharmony_ci    WCHAR s[kBufSize + 1];
738370b324cSopenharmony_ci    s[0] = 0;
739370b324cSopenharmony_ci    len = ::GetTempPathW(kBufSize, s);
740370b324cSopenharmony_ci    path = us2fs(s);
741370b324cSopenharmony_ci  }
742370b324cSopenharmony_ci  /* win10: GetTempPathW() doesn't set backslash at the end of path,
743370b324cSopenharmony_ci       if (buffer_size == len_of(path_with_backslash)).
744370b324cSopenharmony_ci     So we normalize path here: */
745370b324cSopenharmony_ci  NormalizeDirPathPrefix(path);
746370b324cSopenharmony_ci  return (len != 0 && len < kBufSize);
747370b324cSopenharmony_ci
748370b324cSopenharmony_ci  #else  // !_WIN32
749370b324cSopenharmony_ci
750370b324cSopenharmony_ci  // FIXME: improve that code
751370b324cSopenharmony_ci  path = STRING_PATH_SEPARATOR "tmp";
752370b324cSopenharmony_ci  const char *s;
753370b324cSopenharmony_ci  if (NFind::DoesDirExist_FollowLink(path))
754370b324cSopenharmony_ci    s = STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR;
755370b324cSopenharmony_ci  else
756370b324cSopenharmony_ci    s = "." STRING_PATH_SEPARATOR;
757370b324cSopenharmony_ci  path = s;
758370b324cSopenharmony_ci  return true;
759370b324cSopenharmony_ci
760370b324cSopenharmony_ci  #endif
761370b324cSopenharmony_ci}
762370b324cSopenharmony_ci
763370b324cSopenharmony_ci
764370b324cSopenharmony_cibool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile)
765370b324cSopenharmony_ci{
766370b324cSopenharmony_ci  UInt32 d =
767370b324cSopenharmony_ci    #ifdef _WIN32
768370b324cSopenharmony_ci      (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
769370b324cSopenharmony_ci    #else
770370b324cSopenharmony_ci      (UInt32)(time(NULL) << 12) ^  ((UInt32)getppid() << 14) ^ (UInt32)(getpid());
771370b324cSopenharmony_ci    #endif
772370b324cSopenharmony_ci
773370b324cSopenharmony_ci  for (unsigned i = 0; i < 100; i++)
774370b324cSopenharmony_ci  {
775370b324cSopenharmony_ci    postfix.Empty();
776370b324cSopenharmony_ci    if (addRandom)
777370b324cSopenharmony_ci    {
778370b324cSopenharmony_ci      char s[16];
779370b324cSopenharmony_ci      UInt32 val = d;
780370b324cSopenharmony_ci      unsigned k;
781370b324cSopenharmony_ci      for (k = 0; k < 8; k++)
782370b324cSopenharmony_ci      {
783370b324cSopenharmony_ci        const unsigned t = val & 0xF;
784370b324cSopenharmony_ci        val >>= 4;
785370b324cSopenharmony_ci        s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
786370b324cSopenharmony_ci      }
787370b324cSopenharmony_ci      s[k] = '\0';
788370b324cSopenharmony_ci      if (outFile)
789370b324cSopenharmony_ci        postfix.Add_Dot();
790370b324cSopenharmony_ci      postfix += s;
791370b324cSopenharmony_ci      UInt32 step = GetTickCount() + 2;
792370b324cSopenharmony_ci      if (step == 0)
793370b324cSopenharmony_ci        step = 1;
794370b324cSopenharmony_ci      d += step;
795370b324cSopenharmony_ci    }
796370b324cSopenharmony_ci    addRandom = true;
797370b324cSopenharmony_ci    if (outFile)
798370b324cSopenharmony_ci      postfix += ".tmp";
799370b324cSopenharmony_ci    FString path (prefix);
800370b324cSopenharmony_ci    path += postfix;
801370b324cSopenharmony_ci    if (NFind::DoesFileOrDirExist(path))
802370b324cSopenharmony_ci    {
803370b324cSopenharmony_ci      SetLastError(ERROR_ALREADY_EXISTS);
804370b324cSopenharmony_ci      continue;
805370b324cSopenharmony_ci    }
806370b324cSopenharmony_ci    if (outFile)
807370b324cSopenharmony_ci    {
808370b324cSopenharmony_ci      if (outFile->Create(path, false))
809370b324cSopenharmony_ci        return true;
810370b324cSopenharmony_ci    }
811370b324cSopenharmony_ci    else
812370b324cSopenharmony_ci    {
813370b324cSopenharmony_ci      if (CreateDir(path))
814370b324cSopenharmony_ci        return true;
815370b324cSopenharmony_ci    }
816370b324cSopenharmony_ci    const DWORD error = GetLastError();
817370b324cSopenharmony_ci    if (error != ERROR_FILE_EXISTS &&
818370b324cSopenharmony_ci        error != ERROR_ALREADY_EXISTS)
819370b324cSopenharmony_ci      break;
820370b324cSopenharmony_ci  }
821370b324cSopenharmony_ci  postfix.Empty();
822370b324cSopenharmony_ci  return false;
823370b324cSopenharmony_ci}
824370b324cSopenharmony_ci
825370b324cSopenharmony_cibool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile)
826370b324cSopenharmony_ci{
827370b324cSopenharmony_ci  if (!Remove())
828370b324cSopenharmony_ci    return false;
829370b324cSopenharmony_ci  _path.Empty();
830370b324cSopenharmony_ci  AString postfix;
831370b324cSopenharmony_ci  if (!CreateTempFile2(prefix, false, postfix, outFile))
832370b324cSopenharmony_ci    return false;
833370b324cSopenharmony_ci  _path = prefix;
834370b324cSopenharmony_ci  _path += postfix;
835370b324cSopenharmony_ci  _mustBeDeleted = true;
836370b324cSopenharmony_ci  return true;
837370b324cSopenharmony_ci}
838370b324cSopenharmony_ci
839370b324cSopenharmony_cibool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile)
840370b324cSopenharmony_ci{
841370b324cSopenharmony_ci  if (!Remove())
842370b324cSopenharmony_ci    return false;
843370b324cSopenharmony_ci  _path.Empty();
844370b324cSopenharmony_ci  FString tempPath;
845370b324cSopenharmony_ci  if (!MyGetTempPath(tempPath))
846370b324cSopenharmony_ci    return false;
847370b324cSopenharmony_ci  AString postfix;
848370b324cSopenharmony_ci  tempPath += namePrefix;
849370b324cSopenharmony_ci  if (!CreateTempFile2(tempPath, true, postfix, outFile))
850370b324cSopenharmony_ci    return false;
851370b324cSopenharmony_ci  _path = tempPath;
852370b324cSopenharmony_ci  _path += postfix;
853370b324cSopenharmony_ci  _mustBeDeleted = true;
854370b324cSopenharmony_ci  return true;
855370b324cSopenharmony_ci}
856370b324cSopenharmony_ci
857370b324cSopenharmony_cibool CTempFile::Remove()
858370b324cSopenharmony_ci{
859370b324cSopenharmony_ci  if (!_mustBeDeleted)
860370b324cSopenharmony_ci    return true;
861370b324cSopenharmony_ci  _mustBeDeleted = !DeleteFileAlways(_path);
862370b324cSopenharmony_ci  return !_mustBeDeleted;
863370b324cSopenharmony_ci}
864370b324cSopenharmony_ci
865370b324cSopenharmony_cibool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore)
866370b324cSopenharmony_ci{
867370b324cSopenharmony_ci  // DWORD attrib = 0;
868370b324cSopenharmony_ci  if (deleteDestBefore)
869370b324cSopenharmony_ci  {
870370b324cSopenharmony_ci    if (NFind::DoesFileExist_Raw(name))
871370b324cSopenharmony_ci    {
872370b324cSopenharmony_ci      // attrib = NFind::GetFileAttrib(name);
873370b324cSopenharmony_ci      if (!DeleteFileAlways(name))
874370b324cSopenharmony_ci        return false;
875370b324cSopenharmony_ci    }
876370b324cSopenharmony_ci  }
877370b324cSopenharmony_ci  DisableDeleting();
878370b324cSopenharmony_ci  return MyMoveFile(_path, name);
879370b324cSopenharmony_ci
880370b324cSopenharmony_ci  /*
881370b324cSopenharmony_ci  if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
882370b324cSopenharmony_ci  {
883370b324cSopenharmony_ci    DWORD attrib2 = NFind::GetFileAttrib(name);
884370b324cSopenharmony_ci    if (attrib2 != INVALID_FILE_ATTRIBUTES)
885370b324cSopenharmony_ci      SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY);
886370b324cSopenharmony_ci  }
887370b324cSopenharmony_ci  */
888370b324cSopenharmony_ci}
889370b324cSopenharmony_ci
890370b324cSopenharmony_ci#ifdef _WIN32
891370b324cSopenharmony_cibool CTempDir::Create(CFSTR prefix)
892370b324cSopenharmony_ci{
893370b324cSopenharmony_ci  if (!Remove())
894370b324cSopenharmony_ci    return false;
895370b324cSopenharmony_ci  _path.Empty();
896370b324cSopenharmony_ci  FString tempPath;
897370b324cSopenharmony_ci  if (!MyGetTempPath(tempPath))
898370b324cSopenharmony_ci    return false;
899370b324cSopenharmony_ci  tempPath += prefix;
900370b324cSopenharmony_ci  AString postfix;
901370b324cSopenharmony_ci  if (!CreateTempFile2(tempPath, true, postfix, NULL))
902370b324cSopenharmony_ci    return false;
903370b324cSopenharmony_ci  _path = tempPath;
904370b324cSopenharmony_ci  _path += postfix;
905370b324cSopenharmony_ci  _mustBeDeleted = true;
906370b324cSopenharmony_ci  return true;
907370b324cSopenharmony_ci}
908370b324cSopenharmony_ci
909370b324cSopenharmony_cibool CTempDir::Remove()
910370b324cSopenharmony_ci{
911370b324cSopenharmony_ci  if (!_mustBeDeleted)
912370b324cSopenharmony_ci    return true;
913370b324cSopenharmony_ci  _mustBeDeleted = !RemoveDirWithSubItems(_path);
914370b324cSopenharmony_ci  return !_mustBeDeleted;
915370b324cSopenharmony_ci}
916370b324cSopenharmony_ci#endif
917370b324cSopenharmony_ci
918370b324cSopenharmony_ci
919370b324cSopenharmony_ci
920370b324cSopenharmony_ci#ifndef _WIN32
921370b324cSopenharmony_ci
922370b324cSopenharmony_cibool RemoveDir(CFSTR path)
923370b324cSopenharmony_ci{
924370b324cSopenharmony_ci  return (rmdir(path) == 0);
925370b324cSopenharmony_ci}
926370b324cSopenharmony_ci
927370b324cSopenharmony_ci
928370b324cSopenharmony_cistatic BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile)
929370b324cSopenharmony_ci{
930370b324cSopenharmony_ci  NWindows::NFile::NIO::COutFile outFile;
931370b324cSopenharmony_ci  if (!outFile.Create(newFile, false))
932370b324cSopenharmony_ci    return FALSE;
933370b324cSopenharmony_ci
934370b324cSopenharmony_ci  NWindows::NFile::NIO::CInFile inFile;
935370b324cSopenharmony_ci  if (!inFile.Open(oldFile))
936370b324cSopenharmony_ci    return FALSE;
937370b324cSopenharmony_ci
938370b324cSopenharmony_ci  char buf[1 << 14];
939370b324cSopenharmony_ci
940370b324cSopenharmony_ci  for (;;)
941370b324cSopenharmony_ci  {
942370b324cSopenharmony_ci    const ssize_t num = inFile.read_part(buf, sizeof(buf));
943370b324cSopenharmony_ci    if (num == 0)
944370b324cSopenharmony_ci      return TRUE;
945370b324cSopenharmony_ci    if (num < 0)
946370b324cSopenharmony_ci      return FALSE;
947370b324cSopenharmony_ci    size_t processed;
948370b324cSopenharmony_ci    const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed);
949370b324cSopenharmony_ci    if (num2 != num || processed != (size_t)num)
950370b324cSopenharmony_ci      return FALSE;
951370b324cSopenharmony_ci  }
952370b324cSopenharmony_ci}
953370b324cSopenharmony_ci
954370b324cSopenharmony_ci
955370b324cSopenharmony_cibool MyMoveFile(CFSTR oldFile, CFSTR newFile)
956370b324cSopenharmony_ci{
957370b324cSopenharmony_ci  int res = rename(oldFile, newFile);
958370b324cSopenharmony_ci  if (res == 0)
959370b324cSopenharmony_ci    return true;
960370b324cSopenharmony_ci  if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem)
961370b324cSopenharmony_ci    return false;
962370b324cSopenharmony_ci
963370b324cSopenharmony_ci  if (My_CopyFile(oldFile, newFile) == FALSE)
964370b324cSopenharmony_ci    return false;
965370b324cSopenharmony_ci
966370b324cSopenharmony_ci  struct stat info_file;
967370b324cSopenharmony_ci  res = stat(oldFile, &info_file);
968370b324cSopenharmony_ci  if (res != 0)
969370b324cSopenharmony_ci    return false;
970370b324cSopenharmony_ci
971370b324cSopenharmony_ci  /*
972370b324cSopenharmony_ci  ret = chmod(dst,info_file.st_mode & g_umask.mask);
973370b324cSopenharmony_ci  */
974370b324cSopenharmony_ci  return (unlink(oldFile) == 0);
975370b324cSopenharmony_ci}
976370b324cSopenharmony_ci
977370b324cSopenharmony_ci
978370b324cSopenharmony_cibool CreateDir(CFSTR path)
979370b324cSopenharmony_ci{
980370b324cSopenharmony_ci  return (mkdir(path, 0777) == 0); // change it
981370b324cSopenharmony_ci}
982370b324cSopenharmony_ci
983370b324cSopenharmony_cistatic bool CreateDir2(CFSTR path)
984370b324cSopenharmony_ci{
985370b324cSopenharmony_ci  return (mkdir(path, 0777) == 0); // change it
986370b324cSopenharmony_ci}
987370b324cSopenharmony_ci
988370b324cSopenharmony_ci
989370b324cSopenharmony_cibool DeleteFileAlways(CFSTR path)
990370b324cSopenharmony_ci{
991370b324cSopenharmony_ci  return (remove(path) == 0);
992370b324cSopenharmony_ci}
993370b324cSopenharmony_ci
994370b324cSopenharmony_cibool SetCurrentDir(CFSTR path)
995370b324cSopenharmony_ci{
996370b324cSopenharmony_ci  return (chdir(path) == 0);
997370b324cSopenharmony_ci}
998370b324cSopenharmony_ci
999370b324cSopenharmony_ci
1000370b324cSopenharmony_cibool GetCurrentDir(FString &path)
1001370b324cSopenharmony_ci{
1002370b324cSopenharmony_ci  path.Empty();
1003370b324cSopenharmony_ci
1004370b324cSopenharmony_ci  #define MY_PATH_MAX  PATH_MAX
1005370b324cSopenharmony_ci  // #define MY_PATH_MAX  1024
1006370b324cSopenharmony_ci
1007370b324cSopenharmony_ci  char s[MY_PATH_MAX + 1];
1008370b324cSopenharmony_ci  char *res = getcwd(s, MY_PATH_MAX);
1009370b324cSopenharmony_ci  if (res)
1010370b324cSopenharmony_ci  {
1011370b324cSopenharmony_ci    path = fas2fs(s);
1012370b324cSopenharmony_ci    return true;
1013370b324cSopenharmony_ci  }
1014370b324cSopenharmony_ci  {
1015370b324cSopenharmony_ci    // if (errno != ERANGE) return false;
1016370b324cSopenharmony_ci    #if defined(__GLIBC__) || defined(__APPLE__)
1017370b324cSopenharmony_ci    /* As an extension to the POSIX.1-2001 standard, glibc's getcwd()
1018370b324cSopenharmony_ci       allocates the buffer dynamically using malloc(3) if buf is NULL. */
1019370b324cSopenharmony_ci    res = getcwd(NULL, 0);
1020370b324cSopenharmony_ci    if (res)
1021370b324cSopenharmony_ci    {
1022370b324cSopenharmony_ci      path = fas2fs(res);
1023370b324cSopenharmony_ci      ::free(res);
1024370b324cSopenharmony_ci      return true;
1025370b324cSopenharmony_ci    }
1026370b324cSopenharmony_ci    #endif
1027370b324cSopenharmony_ci    return false;
1028370b324cSopenharmony_ci  }
1029370b324cSopenharmony_ci}
1030370b324cSopenharmony_ci
1031370b324cSopenharmony_ci
1032370b324cSopenharmony_ci
1033370b324cSopenharmony_ci// #undef UTIME_OMIT // to debug
1034370b324cSopenharmony_ci
1035370b324cSopenharmony_ci#ifndef UTIME_OMIT
1036370b324cSopenharmony_ci  /* we can define UTIME_OMIT for debian and another systems.
1037370b324cSopenharmony_ci     Is it OK to define UTIME_OMIT to -2 here, if UTIME_OMIT is not defined? */
1038370b324cSopenharmony_ci  // #define UTIME_OMIT -2
1039370b324cSopenharmony_ci#endif
1040370b324cSopenharmony_ci
1041370b324cSopenharmony_ci
1042370b324cSopenharmony_ci
1043370b324cSopenharmony_ci
1044370b324cSopenharmony_ci
1045370b324cSopenharmony_cibool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
1046370b324cSopenharmony_ci{
1047370b324cSopenharmony_ci  // need testing
1048370b324cSopenharmony_ci  /*
1049370b324cSopenharmony_ci  struct utimbuf buf;
1050370b324cSopenharmony_ci  struct stat st;
1051370b324cSopenharmony_ci  UNUSED_VAR(cTime)
1052370b324cSopenharmony_ci
1053370b324cSopenharmony_ci  printf("\nstat = %s\n", path);
1054370b324cSopenharmony_ci  int ret = stat(path, &st);
1055370b324cSopenharmony_ci
1056370b324cSopenharmony_ci  if (ret == 0)
1057370b324cSopenharmony_ci  {
1058370b324cSopenharmony_ci    buf.actime  = st.st_atime;
1059370b324cSopenharmony_ci    buf.modtime = st.st_mtime;
1060370b324cSopenharmony_ci  }
1061370b324cSopenharmony_ci  else
1062370b324cSopenharmony_ci  {
1063370b324cSopenharmony_ci    time_t cur_time = time(0);
1064370b324cSopenharmony_ci    buf.actime  = cur_time;
1065370b324cSopenharmony_ci    buf.modtime = cur_time;
1066370b324cSopenharmony_ci  }
1067370b324cSopenharmony_ci
1068370b324cSopenharmony_ci  if (aTime)
1069370b324cSopenharmony_ci  {
1070370b324cSopenharmony_ci    UInt32 ut;
1071370b324cSopenharmony_ci    if (NTime::FileTimeToUnixTime(*aTime, ut))
1072370b324cSopenharmony_ci      buf.actime = ut;
1073370b324cSopenharmony_ci  }
1074370b324cSopenharmony_ci
1075370b324cSopenharmony_ci  if (mTime)
1076370b324cSopenharmony_ci  {
1077370b324cSopenharmony_ci    UInt32 ut;
1078370b324cSopenharmony_ci    if (NTime::FileTimeToUnixTime(*mTime, ut))
1079370b324cSopenharmony_ci      buf.modtime = ut;
1080370b324cSopenharmony_ci  }
1081370b324cSopenharmony_ci
1082370b324cSopenharmony_ci  return utime(path, &buf) == 0;
1083370b324cSopenharmony_ci  */
1084370b324cSopenharmony_ci
1085370b324cSopenharmony_ci  // if (!aTime && !mTime) return true;
1086370b324cSopenharmony_ci
1087370b324cSopenharmony_ci  struct timespec times[2];
1088370b324cSopenharmony_ci  UNUSED_VAR(cTime)
1089370b324cSopenharmony_ci
1090370b324cSopenharmony_ci  bool needChange;
1091370b324cSopenharmony_ci  needChange  = FiTime_To_timespec(aTime, times[0]);
1092370b324cSopenharmony_ci  needChange |= FiTime_To_timespec(mTime, times[1]);
1093370b324cSopenharmony_ci
1094370b324cSopenharmony_ci  /*
1095370b324cSopenharmony_ci  if (mTime)
1096370b324cSopenharmony_ci  {
1097370b324cSopenharmony_ci    printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec);
1098370b324cSopenharmony_ci  }
1099370b324cSopenharmony_ci  */
1100370b324cSopenharmony_ci
1101370b324cSopenharmony_ci  if (!needChange)
1102370b324cSopenharmony_ci    return true;
1103370b324cSopenharmony_ci  const int flags = 0; // follow link
1104370b324cSopenharmony_ci    // = AT_SYMLINK_NOFOLLOW; // don't follow link
1105370b324cSopenharmony_ci  return utimensat(AT_FDCWD, path, times, flags) == 0;
1106370b324cSopenharmony_ci}
1107370b324cSopenharmony_ci
1108370b324cSopenharmony_ci
1109370b324cSopenharmony_ci
1110370b324cSopenharmony_cistruct C_umask
1111370b324cSopenharmony_ci{
1112370b324cSopenharmony_ci  mode_t mask;
1113370b324cSopenharmony_ci
1114370b324cSopenharmony_ci  C_umask()
1115370b324cSopenharmony_ci  {
1116370b324cSopenharmony_ci    /* by security reasons we restrict attributes according
1117370b324cSopenharmony_ci       with process's file mode creation mask (umask) */
1118370b324cSopenharmony_ci    const mode_t um = umask(0); // octal :0022 is expected
1119370b324cSopenharmony_ci    mask = 0777 & (~um);        // octal: 0755 is expected
1120370b324cSopenharmony_ci    umask(um);  // restore the umask
1121370b324cSopenharmony_ci    // printf("\n umask = 0%03o mask = 0%03o\n", um, mask);
1122370b324cSopenharmony_ci
1123370b324cSopenharmony_ci    // mask = 0777; // debug we can disable the restriction:
1124370b324cSopenharmony_ci  }
1125370b324cSopenharmony_ci};
1126370b324cSopenharmony_ci
1127370b324cSopenharmony_cistatic C_umask g_umask;
1128370b324cSopenharmony_ci
1129370b324cSopenharmony_ci// #define PRF(x) x;
1130370b324cSopenharmony_ci#define PRF(x)
1131370b324cSopenharmony_ci
1132370b324cSopenharmony_ci#define TRACE_SetFileAttrib(msg) \
1133370b324cSopenharmony_ci  PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg);)
1134370b324cSopenharmony_ci
1135370b324cSopenharmony_ci#define TRACE_chmod(s, mode) \
1136370b324cSopenharmony_ci  PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode));)
1137370b324cSopenharmony_ci
1138370b324cSopenharmony_ciint my_chown(CFSTR path, uid_t owner, gid_t group)
1139370b324cSopenharmony_ci{
1140370b324cSopenharmony_ci  return chown(path, owner, group);
1141370b324cSopenharmony_ci}
1142370b324cSopenharmony_ci
1143370b324cSopenharmony_cibool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
1144370b324cSopenharmony_ci{
1145370b324cSopenharmony_ci  TRACE_SetFileAttrib("")
1146370b324cSopenharmony_ci
1147370b324cSopenharmony_ci  struct stat st;
1148370b324cSopenharmony_ci
1149370b324cSopenharmony_ci  bool use_lstat = true;
1150370b324cSopenharmony_ci  if (use_lstat)
1151370b324cSopenharmony_ci  {
1152370b324cSopenharmony_ci    if (lstat(path, &st) != 0)
1153370b324cSopenharmony_ci    {
1154370b324cSopenharmony_ci      TRACE_SetFileAttrib("bad lstat()")
1155370b324cSopenharmony_ci      return false;
1156370b324cSopenharmony_ci    }
1157370b324cSopenharmony_ci    // TRACE_chmod("lstat", st.st_mode);
1158370b324cSopenharmony_ci  }
1159370b324cSopenharmony_ci  else
1160370b324cSopenharmony_ci  {
1161370b324cSopenharmony_ci    if (stat(path, &st) != 0)
1162370b324cSopenharmony_ci    {
1163370b324cSopenharmony_ci      TRACE_SetFileAttrib("bad stat()")
1164370b324cSopenharmony_ci      return false;
1165370b324cSopenharmony_ci    }
1166370b324cSopenharmony_ci  }
1167370b324cSopenharmony_ci
1168370b324cSopenharmony_ci  if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION)
1169370b324cSopenharmony_ci  {
1170370b324cSopenharmony_ci    TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION")
1171370b324cSopenharmony_ci    st.st_mode = attrib >> 16;
1172370b324cSopenharmony_ci    if (S_ISDIR(st.st_mode))
1173370b324cSopenharmony_ci    {
1174370b324cSopenharmony_ci      // user/7z must be able to create files in this directory
1175370b324cSopenharmony_ci      st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR);
1176370b324cSopenharmony_ci    }
1177370b324cSopenharmony_ci    else if (!S_ISREG(st.st_mode))
1178370b324cSopenharmony_ci      return true;
1179370b324cSopenharmony_ci  }
1180370b324cSopenharmony_ci  else if (S_ISLNK(st.st_mode))
1181370b324cSopenharmony_ci  {
1182370b324cSopenharmony_ci    /* for most systems: permissions for symlinks are fixed to rwxrwxrwx.
1183370b324cSopenharmony_ci       so we don't need chmod() for symlinks. */
1184370b324cSopenharmony_ci    return true;
1185370b324cSopenharmony_ci    // SetLastError(ENOSYS);
1186370b324cSopenharmony_ci    // return false;
1187370b324cSopenharmony_ci  }
1188370b324cSopenharmony_ci  else
1189370b324cSopenharmony_ci  {
1190370b324cSopenharmony_ci    TRACE_SetFileAttrib("Only Windows Attributes")
1191370b324cSopenharmony_ci    // Only Windows Attributes
1192370b324cSopenharmony_ci    if (S_ISDIR(st.st_mode)
1193370b324cSopenharmony_ci        || (attrib & FILE_ATTRIBUTE_READONLY) == 0)
1194370b324cSopenharmony_ci      return true;
1195370b324cSopenharmony_ci    st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions
1196370b324cSopenharmony_ci  }
1197370b324cSopenharmony_ci
1198370b324cSopenharmony_ci  int res;
1199370b324cSopenharmony_ci  /*
1200370b324cSopenharmony_ci  if (S_ISLNK(st.st_mode))
1201370b324cSopenharmony_ci  {
1202370b324cSopenharmony_ci    printf("\nfchmodat()\n");
1203370b324cSopenharmony_ci    TRACE_chmod(path, (st.st_mode) & g_umask.mask)
1204370b324cSopenharmony_ci    // AT_SYMLINK_NOFOLLOW is not implemted still in Linux.
1205370b324cSopenharmony_ci    res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask,
1206370b324cSopenharmony_ci        S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0);
1207370b324cSopenharmony_ci  }
1208370b324cSopenharmony_ci  else
1209370b324cSopenharmony_ci  */
1210370b324cSopenharmony_ci  {
1211370b324cSopenharmony_ci    TRACE_chmod(path, (st.st_mode) & g_umask.mask)
1212370b324cSopenharmony_ci    res = chmod(path, (st.st_mode) & g_umask.mask);
1213370b324cSopenharmony_ci  }
1214370b324cSopenharmony_ci  // TRACE_SetFileAttrib("End")
1215370b324cSopenharmony_ci  return (res == 0);
1216370b324cSopenharmony_ci}
1217370b324cSopenharmony_ci
1218370b324cSopenharmony_ci
1219370b324cSopenharmony_cibool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
1220370b324cSopenharmony_ci{
1221370b324cSopenharmony_ci  PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName);)
1222370b324cSopenharmony_ci  return (link(existFileName, newFileName) == 0);
1223370b324cSopenharmony_ci}
1224370b324cSopenharmony_ci
1225370b324cSopenharmony_ci#endif // !_WIN32
1226370b324cSopenharmony_ci
1227370b324cSopenharmony_ci// #endif
1228370b324cSopenharmony_ci
1229370b324cSopenharmony_ci}}}
1230