1370b324cSopenharmony_ci// Windows/FileLink.cpp
2370b324cSopenharmony_ci
3370b324cSopenharmony_ci#include "StdAfx.h"
4370b324cSopenharmony_ci
5370b324cSopenharmony_ci#include "../../C/CpuArch.h"
6370b324cSopenharmony_ci
7370b324cSopenharmony_ci#ifndef _WIN32
8370b324cSopenharmony_ci#include <unistd.h>
9370b324cSopenharmony_ci#endif
10370b324cSopenharmony_ci
11370b324cSopenharmony_ci#ifdef Z7_DEVICE_FILE
12370b324cSopenharmony_ci#include "../../C/Alloc.h"
13370b324cSopenharmony_ci#endif
14370b324cSopenharmony_ci
15370b324cSopenharmony_ci#include "../Common/UTFConvert.h"
16370b324cSopenharmony_ci#include "../Common/StringConvert.h"
17370b324cSopenharmony_ci
18370b324cSopenharmony_ci#include "FileDir.h"
19370b324cSopenharmony_ci#include "FileFind.h"
20370b324cSopenharmony_ci#include "FileIO.h"
21370b324cSopenharmony_ci#include "FileName.h"
22370b324cSopenharmony_ci
23370b324cSopenharmony_ci#ifdef Z7_OLD_WIN_SDK
24370b324cSopenharmony_ci#ifndef ERROR_INVALID_REPARSE_DATA
25370b324cSopenharmony_ci#define ERROR_INVALID_REPARSE_DATA       4392L
26370b324cSopenharmony_ci#endif
27370b324cSopenharmony_ci#ifndef ERROR_REPARSE_TAG_INVALID
28370b324cSopenharmony_ci#define ERROR_REPARSE_TAG_INVALID        4393L
29370b324cSopenharmony_ci#endif
30370b324cSopenharmony_ci#endif
31370b324cSopenharmony_ci
32370b324cSopenharmony_ci#ifndef _UNICODE
33370b324cSopenharmony_ciextern bool g_IsNT;
34370b324cSopenharmony_ci#endif
35370b324cSopenharmony_ci
36370b324cSopenharmony_cinamespace NWindows {
37370b324cSopenharmony_cinamespace NFile {
38370b324cSopenharmony_ci
39370b324cSopenharmony_ciusing namespace NName;
40370b324cSopenharmony_ci
41370b324cSopenharmony_ci/*
42370b324cSopenharmony_ci  Reparse Points (Junctions and Symbolic Links):
43370b324cSopenharmony_ci  struct
44370b324cSopenharmony_ci  {
45370b324cSopenharmony_ci    UInt32 Tag;
46370b324cSopenharmony_ci    UInt16 Size;     // not including starting 8 bytes
47370b324cSopenharmony_ci    UInt16 Reserved; // = 0
48370b324cSopenharmony_ci
49370b324cSopenharmony_ci    UInt16 SubstituteOffset; // offset in bytes from  start of namesChars
50370b324cSopenharmony_ci    UInt16 SubstituteLen;    // size in bytes, it doesn't include tailed NUL
51370b324cSopenharmony_ci    UInt16 PrintOffset;      // offset in bytes from  start of namesChars
52370b324cSopenharmony_ci    UInt16 PrintLen;         // size in bytes, it doesn't include tailed NUL
53370b324cSopenharmony_ci
54370b324cSopenharmony_ci    [UInt32] Flags;  // for Symbolic Links only.
55370b324cSopenharmony_ci
56370b324cSopenharmony_ci    UInt16 namesChars[]
57370b324cSopenharmony_ci  }
58370b324cSopenharmony_ci
59370b324cSopenharmony_ci  MOUNT_POINT (Junction point):
60370b324cSopenharmony_ci    1) there is NUL wchar after path
61370b324cSopenharmony_ci    2) Default Order in table:
62370b324cSopenharmony_ci         Substitute Path
63370b324cSopenharmony_ci         Print Path
64370b324cSopenharmony_ci    3) pathnames can not contain dot directory names
65370b324cSopenharmony_ci
66370b324cSopenharmony_ci  SYMLINK:
67370b324cSopenharmony_ci    1) there is no NUL wchar after path
68370b324cSopenharmony_ci    2) Default Order in table:
69370b324cSopenharmony_ci         Print Path
70370b324cSopenharmony_ci         Substitute Path
71370b324cSopenharmony_ci*/
72370b324cSopenharmony_ci
73370b324cSopenharmony_ci/*
74370b324cSopenharmony_ciWin10 WSL2:
75370b324cSopenharmony_ciadmin rights + sudo: it creates normal windows symbolic link.
76370b324cSopenharmony_ciin another cases   : it creates IO_REPARSE_TAG_LX_SYMLINK repare point.
77370b324cSopenharmony_ci*/
78370b324cSopenharmony_ci
79370b324cSopenharmony_ci/*
80370b324cSopenharmony_cistatic const UInt32 kReparseFlags_Alias       = (1 << 29);
81370b324cSopenharmony_cistatic const UInt32 kReparseFlags_HighLatency = (1 << 30);
82370b324cSopenharmony_cistatic const UInt32 kReparseFlags_Microsoft   = ((UInt32)1 << 31);
83370b324cSopenharmony_ci
84370b324cSopenharmony_ci#define Z7_WIN_IO_REPARSE_TAG_HSM          (0xC0000004L)
85370b324cSopenharmony_ci#define Z7_WIN_IO_REPARSE_TAG_HSM2         (0x80000006L)
86370b324cSopenharmony_ci#define Z7_WIN_IO_REPARSE_TAG_SIS          (0x80000007L)
87370b324cSopenharmony_ci#define Z7_WIN_IO_REPARSE_TAG_WIM          (0x80000008L)
88370b324cSopenharmony_ci#define Z7_WIN_IO_REPARSE_TAG_CSV          (0x80000009L)
89370b324cSopenharmony_ci#define Z7_WIN_IO_REPARSE_TAG_DFS          (0x8000000AL)
90370b324cSopenharmony_ci#define Z7_WIN_IO_REPARSE_TAG_DFSR         (0x80000012L)
91370b324cSopenharmony_ci*/
92370b324cSopenharmony_ci
93370b324cSopenharmony_ci#define Get16(p) GetUi16(p)
94370b324cSopenharmony_ci#define Get32(p) GetUi32(p)
95370b324cSopenharmony_ci
96370b324cSopenharmony_cistatic const wchar_t * const k_LinkPrefix = L"\\??\\";
97370b324cSopenharmony_cistatic const unsigned k_LinkPrefix_Size = 4;
98370b324cSopenharmony_ci
99370b324cSopenharmony_cistatic bool IsLinkPrefix(const wchar_t *s)
100370b324cSopenharmony_ci{
101370b324cSopenharmony_ci  return IsString1PrefixedByString2(s, k_LinkPrefix);
102370b324cSopenharmony_ci}
103370b324cSopenharmony_ci
104370b324cSopenharmony_ci/*
105370b324cSopenharmony_cistatic const wchar_t * const k_VolumePrefix = L"Volume{";
106370b324cSopenharmony_cistatic const bool IsVolumeName(const wchar_t *s)
107370b324cSopenharmony_ci{
108370b324cSopenharmony_ci  return IsString1PrefixedByString2(s, k_VolumePrefix);
109370b324cSopenharmony_ci}
110370b324cSopenharmony_ci*/
111370b324cSopenharmony_ci
112370b324cSopenharmony_ci#if defined(_WIN32) && !defined(UNDER_CE)
113370b324cSopenharmony_ci
114370b324cSopenharmony_ci#define Set16(p, v) SetUi16(p, v)
115370b324cSopenharmony_ci#define Set32(p, v) SetUi32(p, v)
116370b324cSopenharmony_ci
117370b324cSopenharmony_cistatic void WriteString(Byte *dest, const wchar_t *path)
118370b324cSopenharmony_ci{
119370b324cSopenharmony_ci  for (;;)
120370b324cSopenharmony_ci  {
121370b324cSopenharmony_ci    wchar_t c = *path++;
122370b324cSopenharmony_ci    if (c == 0)
123370b324cSopenharmony_ci      return;
124370b324cSopenharmony_ci    Set16(dest, (UInt16)c)
125370b324cSopenharmony_ci    dest += 2;
126370b324cSopenharmony_ci  }
127370b324cSopenharmony_ci}
128370b324cSopenharmony_ci
129370b324cSopenharmony_cibool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
130370b324cSopenharmony_ci{
131370b324cSopenharmony_ci  bool isAbs = IsAbsolutePath(path);
132370b324cSopenharmony_ci  if (!isAbs && !isSymLink)
133370b324cSopenharmony_ci    return false;
134370b324cSopenharmony_ci
135370b324cSopenharmony_ci  if (isWSL)
136370b324cSopenharmony_ci  {
137370b324cSopenharmony_ci    // unsupported characters probably use Replacement Character UTF-16 0xFFFD
138370b324cSopenharmony_ci    AString utf;
139370b324cSopenharmony_ci    ConvertUnicodeToUTF8(path, utf);
140370b324cSopenharmony_ci    const size_t size = 4 + utf.Len();
141370b324cSopenharmony_ci    if (size != (UInt16)size)
142370b324cSopenharmony_ci      return false;
143370b324cSopenharmony_ci    dest.Alloc(8 + size);
144370b324cSopenharmony_ci    Byte *p = dest;
145370b324cSopenharmony_ci    Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
146370b324cSopenharmony_ci    Set16(p + 4, (UInt16)(size))
147370b324cSopenharmony_ci    Set16(p + 6, 0)
148370b324cSopenharmony_ci    Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG)
149370b324cSopenharmony_ci    memcpy(p + 12, utf.Ptr(), utf.Len());
150370b324cSopenharmony_ci    return true;
151370b324cSopenharmony_ci  }
152370b324cSopenharmony_ci
153370b324cSopenharmony_ci  // usual symbolic LINK (NOT WSL)
154370b324cSopenharmony_ci
155370b324cSopenharmony_ci  bool needPrintName = true;
156370b324cSopenharmony_ci
157370b324cSopenharmony_ci  if (IsSuperPath(path))
158370b324cSopenharmony_ci  {
159370b324cSopenharmony_ci    path += kSuperPathPrefixSize;
160370b324cSopenharmony_ci    if (!IsDrivePath(path))
161370b324cSopenharmony_ci      needPrintName = false;
162370b324cSopenharmony_ci  }
163370b324cSopenharmony_ci
164370b324cSopenharmony_ci  const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0;
165370b324cSopenharmony_ci
166370b324cSopenharmony_ci  size_t len2 = (size_t)MyStringLen(path) * 2;
167370b324cSopenharmony_ci  const size_t len1 = len2 + add_Prefix_Len * 2;
168370b324cSopenharmony_ci  if (!needPrintName)
169370b324cSopenharmony_ci    len2 = 0;
170370b324cSopenharmony_ci
171370b324cSopenharmony_ci  size_t totalNamesSize = (len1 + len2);
172370b324cSopenharmony_ci
173370b324cSopenharmony_ci  /* some WIM imagex software uses old scheme for symbolic links.
174370b324cSopenharmony_ci     so we can old scheme for byte to byte compatibility */
175370b324cSopenharmony_ci
176370b324cSopenharmony_ci  bool newOrderScheme = isSymLink;
177370b324cSopenharmony_ci  // newOrderScheme = false;
178370b324cSopenharmony_ci
179370b324cSopenharmony_ci  if (!newOrderScheme)
180370b324cSopenharmony_ci    totalNamesSize += 2 * 2;
181370b324cSopenharmony_ci
182370b324cSopenharmony_ci  const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
183370b324cSopenharmony_ci  if (size != (UInt16)size)
184370b324cSopenharmony_ci    return false;
185370b324cSopenharmony_ci  dest.Alloc(size);
186370b324cSopenharmony_ci  memset(dest, 0, size);
187370b324cSopenharmony_ci  const UInt32 tag = isSymLink ?
188370b324cSopenharmony_ci      Z7_WIN_IO_REPARSE_TAG_SYMLINK :
189370b324cSopenharmony_ci      Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT;
190370b324cSopenharmony_ci  Byte *p = dest;
191370b324cSopenharmony_ci  Set32(p, tag)
192370b324cSopenharmony_ci  Set16(p + 4, (UInt16)(size - 8))
193370b324cSopenharmony_ci  Set16(p + 6, 0)
194370b324cSopenharmony_ci  p += 8;
195370b324cSopenharmony_ci
196370b324cSopenharmony_ci  unsigned subOffs = 0;
197370b324cSopenharmony_ci  unsigned printOffs = 0;
198370b324cSopenharmony_ci  if (newOrderScheme)
199370b324cSopenharmony_ci    subOffs = (unsigned)len2;
200370b324cSopenharmony_ci  else
201370b324cSopenharmony_ci    printOffs = (unsigned)len1 + 2;
202370b324cSopenharmony_ci
203370b324cSopenharmony_ci  Set16(p + 0, (UInt16)subOffs)
204370b324cSopenharmony_ci  Set16(p + 2, (UInt16)len1)
205370b324cSopenharmony_ci  Set16(p + 4, (UInt16)printOffs)
206370b324cSopenharmony_ci  Set16(p + 6, (UInt16)len2)
207370b324cSopenharmony_ci
208370b324cSopenharmony_ci  p += 8;
209370b324cSopenharmony_ci  if (isSymLink)
210370b324cSopenharmony_ci  {
211370b324cSopenharmony_ci    UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
212370b324cSopenharmony_ci    Set32(p, flags)
213370b324cSopenharmony_ci    p += 4;
214370b324cSopenharmony_ci  }
215370b324cSopenharmony_ci
216370b324cSopenharmony_ci  if (add_Prefix_Len != 0)
217370b324cSopenharmony_ci    WriteString(p + subOffs, k_LinkPrefix);
218370b324cSopenharmony_ci  WriteString(p + subOffs + add_Prefix_Len * 2, path);
219370b324cSopenharmony_ci  if (needPrintName)
220370b324cSopenharmony_ci    WriteString(p + printOffs, path);
221370b324cSopenharmony_ci  return true;
222370b324cSopenharmony_ci}
223370b324cSopenharmony_ci
224370b324cSopenharmony_ci#endif // defined(_WIN32) && !defined(UNDER_CE)
225370b324cSopenharmony_ci
226370b324cSopenharmony_ci
227370b324cSopenharmony_cistatic void GetString(const Byte *p, unsigned len, UString &res)
228370b324cSopenharmony_ci{
229370b324cSopenharmony_ci  wchar_t *s = res.GetBuf(len);
230370b324cSopenharmony_ci  unsigned i;
231370b324cSopenharmony_ci  for (i = 0; i < len; i++)
232370b324cSopenharmony_ci  {
233370b324cSopenharmony_ci    wchar_t c = Get16(p + i * 2);
234370b324cSopenharmony_ci    if (c == 0)
235370b324cSopenharmony_ci      break;
236370b324cSopenharmony_ci    s[i] = c;
237370b324cSopenharmony_ci  }
238370b324cSopenharmony_ci  s[i] = 0;
239370b324cSopenharmony_ci  res.ReleaseBuf_SetLen(i);
240370b324cSopenharmony_ci}
241370b324cSopenharmony_ci
242370b324cSopenharmony_cibool CReparseAttr::Parse(const Byte *p, size_t size)
243370b324cSopenharmony_ci{
244370b324cSopenharmony_ci  ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA;
245370b324cSopenharmony_ci  HeaderError = true;
246370b324cSopenharmony_ci  TagIsUnknown = true;
247370b324cSopenharmony_ci  MinorError = false;
248370b324cSopenharmony_ci
249370b324cSopenharmony_ci  if (size < 8)
250370b324cSopenharmony_ci    return false;
251370b324cSopenharmony_ci  Tag = Get32(p);
252370b324cSopenharmony_ci  UInt32 len = Get16(p + 4);
253370b324cSopenharmony_ci  if (len + 8 != size)
254370b324cSopenharmony_ci  // if (len + 8 > size)
255370b324cSopenharmony_ci    return false;
256370b324cSopenharmony_ci  /*
257370b324cSopenharmony_ci  if ((type & kReparseFlags_Alias) == 0 ||
258370b324cSopenharmony_ci      (type & kReparseFlags_Microsoft) == 0 ||
259370b324cSopenharmony_ci      (type & 0xFFFF) != 3)
260370b324cSopenharmony_ci  */
261370b324cSopenharmony_ci
262370b324cSopenharmony_ci  if (Get16(p + 6) != 0) // padding
263370b324cSopenharmony_ci    return false;
264370b324cSopenharmony_ci
265370b324cSopenharmony_ci  HeaderError = false;
266370b324cSopenharmony_ci
267370b324cSopenharmony_ci  if (   Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT
268370b324cSopenharmony_ci      && Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK
269370b324cSopenharmony_ci      && Tag != Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
270370b324cSopenharmony_ci  {
271370b324cSopenharmony_ci    // for unsupported reparse points
272370b324cSopenharmony_ci    ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH
273370b324cSopenharmony_ci    // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID
274370b324cSopenharmony_ci    return false;
275370b324cSopenharmony_ci  }
276370b324cSopenharmony_ci
277370b324cSopenharmony_ci  TagIsUnknown = false;
278370b324cSopenharmony_ci
279370b324cSopenharmony_ci  p += 8;
280370b324cSopenharmony_ci  size -= 8;
281370b324cSopenharmony_ci
282370b324cSopenharmony_ci  if (Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
283370b324cSopenharmony_ci  {
284370b324cSopenharmony_ci    if (len < 4)
285370b324cSopenharmony_ci      return false;
286370b324cSopenharmony_ci    Flags = Get32(p); // maybe it's not Flags
287370b324cSopenharmony_ci    if (Flags != Z7_WIN_LX_SYMLINK_FLAG)
288370b324cSopenharmony_ci      return false;
289370b324cSopenharmony_ci    len -= 4;
290370b324cSopenharmony_ci    p += 4;
291370b324cSopenharmony_ci    char *s = WslName.GetBuf(len);
292370b324cSopenharmony_ci    unsigned i;
293370b324cSopenharmony_ci    for (i = 0; i < len; i++)
294370b324cSopenharmony_ci    {
295370b324cSopenharmony_ci      char c = (char)p[i];
296370b324cSopenharmony_ci      s[i] = c;
297370b324cSopenharmony_ci      if (c == 0)
298370b324cSopenharmony_ci        break;
299370b324cSopenharmony_ci    }
300370b324cSopenharmony_ci    WslName.ReleaseBuf_SetEnd(i);
301370b324cSopenharmony_ci    MinorError = (i != len);
302370b324cSopenharmony_ci    ErrorCode = 0;
303370b324cSopenharmony_ci    return true;
304370b324cSopenharmony_ci  }
305370b324cSopenharmony_ci
306370b324cSopenharmony_ci  if (len < 8)
307370b324cSopenharmony_ci    return false;
308370b324cSopenharmony_ci  unsigned subOffs = Get16(p);
309370b324cSopenharmony_ci  unsigned subLen = Get16(p + 2);
310370b324cSopenharmony_ci  unsigned printOffs = Get16(p + 4);
311370b324cSopenharmony_ci  unsigned printLen = Get16(p + 6);
312370b324cSopenharmony_ci  len -= 8;
313370b324cSopenharmony_ci  p += 8;
314370b324cSopenharmony_ci
315370b324cSopenharmony_ci  Flags = 0;
316370b324cSopenharmony_ci  if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
317370b324cSopenharmony_ci  {
318370b324cSopenharmony_ci    if (len < 4)
319370b324cSopenharmony_ci      return false;
320370b324cSopenharmony_ci    Flags = Get32(p);
321370b324cSopenharmony_ci    len -= 4;
322370b324cSopenharmony_ci    p += 4;
323370b324cSopenharmony_ci  }
324370b324cSopenharmony_ci
325370b324cSopenharmony_ci  if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
326370b324cSopenharmony_ci    return false;
327370b324cSopenharmony_ci  if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
328370b324cSopenharmony_ci    return false;
329370b324cSopenharmony_ci  GetString(p + subOffs, subLen >> 1, SubsName);
330370b324cSopenharmony_ci  GetString(p + printOffs, printLen >> 1, PrintName);
331370b324cSopenharmony_ci
332370b324cSopenharmony_ci  ErrorCode = 0;
333370b324cSopenharmony_ci  return true;
334370b324cSopenharmony_ci}
335370b324cSopenharmony_ci
336370b324cSopenharmony_ci
337370b324cSopenharmony_cibool CReparseShortInfo::Parse(const Byte *p, size_t size)
338370b324cSopenharmony_ci{
339370b324cSopenharmony_ci  const Byte *start = p;
340370b324cSopenharmony_ci  Offset= 0;
341370b324cSopenharmony_ci  Size = 0;
342370b324cSopenharmony_ci  if (size < 8)
343370b324cSopenharmony_ci    return false;
344370b324cSopenharmony_ci  UInt32 Tag = Get32(p);
345370b324cSopenharmony_ci  UInt32 len = Get16(p + 4);
346370b324cSopenharmony_ci  if (len + 8 > size)
347370b324cSopenharmony_ci    return false;
348370b324cSopenharmony_ci  /*
349370b324cSopenharmony_ci  if ((type & kReparseFlags_Alias) == 0 ||
350370b324cSopenharmony_ci      (type & kReparseFlags_Microsoft) == 0 ||
351370b324cSopenharmony_ci      (type & 0xFFFF) != 3)
352370b324cSopenharmony_ci  */
353370b324cSopenharmony_ci  if (Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT &&
354370b324cSopenharmony_ci      Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK)
355370b324cSopenharmony_ci    // return true;
356370b324cSopenharmony_ci    return false;
357370b324cSopenharmony_ci
358370b324cSopenharmony_ci  if (Get16(p + 6) != 0) // padding
359370b324cSopenharmony_ci    return false;
360370b324cSopenharmony_ci
361370b324cSopenharmony_ci  p += 8;
362370b324cSopenharmony_ci  size -= 8;
363370b324cSopenharmony_ci
364370b324cSopenharmony_ci  if (len != size) // do we need that check?
365370b324cSopenharmony_ci    return false;
366370b324cSopenharmony_ci
367370b324cSopenharmony_ci  if (len < 8)
368370b324cSopenharmony_ci    return false;
369370b324cSopenharmony_ci  unsigned subOffs = Get16(p);
370370b324cSopenharmony_ci  unsigned subLen = Get16(p + 2);
371370b324cSopenharmony_ci  unsigned printOffs = Get16(p + 4);
372370b324cSopenharmony_ci  unsigned printLen = Get16(p + 6);
373370b324cSopenharmony_ci  len -= 8;
374370b324cSopenharmony_ci  p += 8;
375370b324cSopenharmony_ci
376370b324cSopenharmony_ci  // UInt32 Flags = 0;
377370b324cSopenharmony_ci  if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
378370b324cSopenharmony_ci  {
379370b324cSopenharmony_ci    if (len < 4)
380370b324cSopenharmony_ci      return false;
381370b324cSopenharmony_ci    // Flags = Get32(p);
382370b324cSopenharmony_ci    len -= 4;
383370b324cSopenharmony_ci    p += 4;
384370b324cSopenharmony_ci  }
385370b324cSopenharmony_ci
386370b324cSopenharmony_ci  if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
387370b324cSopenharmony_ci    return false;
388370b324cSopenharmony_ci  if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
389370b324cSopenharmony_ci    return false;
390370b324cSopenharmony_ci
391370b324cSopenharmony_ci  Offset = (unsigned)(p - start) + subOffs;
392370b324cSopenharmony_ci  Size = subLen;
393370b324cSopenharmony_ci  return true;
394370b324cSopenharmony_ci}
395370b324cSopenharmony_ci
396370b324cSopenharmony_cibool CReparseAttr::IsOkNamePair() const
397370b324cSopenharmony_ci{
398370b324cSopenharmony_ci  if (IsLinkPrefix(SubsName))
399370b324cSopenharmony_ci  {
400370b324cSopenharmony_ci    if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size)))
401370b324cSopenharmony_ci      return PrintName.IsEmpty();
402370b324cSopenharmony_ci    if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0)
403370b324cSopenharmony_ci      return true;
404370b324cSopenharmony_ci  }
405370b324cSopenharmony_ci  return wcscmp(SubsName, PrintName) == 0;
406370b324cSopenharmony_ci}
407370b324cSopenharmony_ci
408370b324cSopenharmony_ci/*
409370b324cSopenharmony_cibool CReparseAttr::IsVolume() const
410370b324cSopenharmony_ci{
411370b324cSopenharmony_ci  if (!IsLinkPrefix(SubsName))
412370b324cSopenharmony_ci    return false;
413370b324cSopenharmony_ci  return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size));
414370b324cSopenharmony_ci}
415370b324cSopenharmony_ci*/
416370b324cSopenharmony_ci
417370b324cSopenharmony_ciUString CReparseAttr::GetPath() const
418370b324cSopenharmony_ci{
419370b324cSopenharmony_ci  if (IsSymLink_WSL())
420370b324cSopenharmony_ci  {
421370b324cSopenharmony_ci    UString u;
422370b324cSopenharmony_ci    // if (CheckUTF8(attr.WslName)
423370b324cSopenharmony_ci    if (!ConvertUTF8ToUnicode(WslName, u))
424370b324cSopenharmony_ci      MultiByteToUnicodeString2(u, WslName);
425370b324cSopenharmony_ci    return u;
426370b324cSopenharmony_ci  }
427370b324cSopenharmony_ci
428370b324cSopenharmony_ci  UString s (SubsName);
429370b324cSopenharmony_ci  if (IsLinkPrefix(s))
430370b324cSopenharmony_ci  {
431370b324cSopenharmony_ci    s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
432370b324cSopenharmony_ci    if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
433370b324cSopenharmony_ci      s.DeleteFrontal(k_LinkPrefix_Size);
434370b324cSopenharmony_ci  }
435370b324cSopenharmony_ci  return s;
436370b324cSopenharmony_ci}
437370b324cSopenharmony_ci
438370b324cSopenharmony_ci#ifdef Z7_DEVICE_FILE
439370b324cSopenharmony_ci
440370b324cSopenharmony_cinamespace NSystem
441370b324cSopenharmony_ci{
442370b324cSopenharmony_cibool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
443370b324cSopenharmony_ci}
444370b324cSopenharmony_ci#endif // Z7_DEVICE_FILE
445370b324cSopenharmony_ci
446370b324cSopenharmony_ci#if defined(_WIN32) && !defined(UNDER_CE)
447370b324cSopenharmony_ci
448370b324cSopenharmony_cinamespace NIO {
449370b324cSopenharmony_ci
450370b324cSopenharmony_cibool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo)
451370b324cSopenharmony_ci{
452370b324cSopenharmony_ci  reparseData.Free();
453370b324cSopenharmony_ci  CInFile file;
454370b324cSopenharmony_ci  if (!file.OpenReparse(path))
455370b324cSopenharmony_ci    return false;
456370b324cSopenharmony_ci
457370b324cSopenharmony_ci  if (fileInfo)
458370b324cSopenharmony_ci    file.GetFileInformation(fileInfo);
459370b324cSopenharmony_ci
460370b324cSopenharmony_ci  const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
461370b324cSopenharmony_ci  CByteArr buf(kBufSize);
462370b324cSopenharmony_ci  DWORD returnedSize;
463370b324cSopenharmony_ci  if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize))
464370b324cSopenharmony_ci    return false;
465370b324cSopenharmony_ci  reparseData.CopyFrom(buf, returnedSize);
466370b324cSopenharmony_ci  return true;
467370b324cSopenharmony_ci}
468370b324cSopenharmony_ci
469370b324cSopenharmony_cistatic bool CreatePrefixDirOfFile(CFSTR path)
470370b324cSopenharmony_ci{
471370b324cSopenharmony_ci  FString path2 (path);
472370b324cSopenharmony_ci  int pos = path2.ReverseFind_PathSepar();
473370b324cSopenharmony_ci  if (pos < 0)
474370b324cSopenharmony_ci    return true;
475370b324cSopenharmony_ci  #ifdef _WIN32
476370b324cSopenharmony_ci  if (pos == 2 && path2[1] == L':')
477370b324cSopenharmony_ci    return true; // we don't create Disk folder;
478370b324cSopenharmony_ci  #endif
479370b324cSopenharmony_ci  path2.DeleteFrom((unsigned)pos);
480370b324cSopenharmony_ci  return NDir::CreateComplexDir(path2);
481370b324cSopenharmony_ci}
482370b324cSopenharmony_ci
483370b324cSopenharmony_ci
484370b324cSopenharmony_cistatic bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size)
485370b324cSopenharmony_ci{
486370b324cSopenharmony_ci  COutFile file;
487370b324cSopenharmony_ci  if (!file.Open(path,
488370b324cSopenharmony_ci      FILE_SHARE_WRITE,
489370b324cSopenharmony_ci      OPEN_EXISTING,
490370b324cSopenharmony_ci      FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))
491370b324cSopenharmony_ci    return false;
492370b324cSopenharmony_ci
493370b324cSopenharmony_ci  DWORD returnedSize;
494370b324cSopenharmony_ci  return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize);
495370b324cSopenharmony_ci}
496370b324cSopenharmony_ci
497370b324cSopenharmony_ci
498370b324cSopenharmony_ci// If there is Reparse data already, it still writes new Reparse data
499370b324cSopenharmony_cibool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
500370b324cSopenharmony_ci{
501370b324cSopenharmony_ci  NFile::NFind::CFileInfo fi;
502370b324cSopenharmony_ci  if (fi.Find(path))
503370b324cSopenharmony_ci  {
504370b324cSopenharmony_ci    if (fi.IsDir() != isDir)
505370b324cSopenharmony_ci    {
506370b324cSopenharmony_ci      ::SetLastError(ERROR_DIRECTORY);
507370b324cSopenharmony_ci      return false;
508370b324cSopenharmony_ci    }
509370b324cSopenharmony_ci  }
510370b324cSopenharmony_ci  else
511370b324cSopenharmony_ci  {
512370b324cSopenharmony_ci    if (isDir)
513370b324cSopenharmony_ci    {
514370b324cSopenharmony_ci      if (!NDir::CreateComplexDir(path))
515370b324cSopenharmony_ci        return false;
516370b324cSopenharmony_ci    }
517370b324cSopenharmony_ci    else
518370b324cSopenharmony_ci    {
519370b324cSopenharmony_ci      CreatePrefixDirOfFile(path);
520370b324cSopenharmony_ci      COutFile file;
521370b324cSopenharmony_ci      if (!file.Create(path, CREATE_NEW))
522370b324cSopenharmony_ci        return false;
523370b324cSopenharmony_ci    }
524370b324cSopenharmony_ci  }
525370b324cSopenharmony_ci
526370b324cSopenharmony_ci  return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size);
527370b324cSopenharmony_ci}
528370b324cSopenharmony_ci
529370b324cSopenharmony_ci
530370b324cSopenharmony_cibool DeleteReparseData(CFSTR path)
531370b324cSopenharmony_ci{
532370b324cSopenharmony_ci  CByteBuffer reparseData;
533370b324cSopenharmony_ci  if (!GetReparseData(path, reparseData, NULL))
534370b324cSopenharmony_ci    return false;
535370b324cSopenharmony_ci  /* MSDN: The tag specified in the ReparseTag member of this structure
536370b324cSopenharmony_ci     must match the tag of the reparse point to be deleted,
537370b324cSopenharmony_ci     and the ReparseDataLength member must be zero */
538370b324cSopenharmony_ci  #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8
539370b324cSopenharmony_ci  if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE)
540370b324cSopenharmony_ci  {
541370b324cSopenharmony_ci    SetLastError(ERROR_INVALID_REPARSE_DATA);
542370b324cSopenharmony_ci    return false;
543370b324cSopenharmony_ci  }
544370b324cSopenharmony_ci  BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
545370b324cSopenharmony_ci  memset(buf, 0, sizeof(buf));
546370b324cSopenharmony_ci  memcpy(buf, reparseData, 4); // tag
547370b324cSopenharmony_ci  return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf));
548370b324cSopenharmony_ci}
549370b324cSopenharmony_ci
550370b324cSopenharmony_ci}
551370b324cSopenharmony_ci
552370b324cSopenharmony_ci#endif //  defined(_WIN32) && !defined(UNDER_CE)
553370b324cSopenharmony_ci
554370b324cSopenharmony_ci
555370b324cSopenharmony_ci#ifndef _WIN32
556370b324cSopenharmony_ci
557370b324cSopenharmony_cinamespace NIO {
558370b324cSopenharmony_ci
559370b324cSopenharmony_cibool GetReparseData(CFSTR path, CByteBuffer &reparseData)
560370b324cSopenharmony_ci{
561370b324cSopenharmony_ci  reparseData.Free();
562370b324cSopenharmony_ci
563370b324cSopenharmony_ci  #define MAX_PATHNAME_LEN 1024
564370b324cSopenharmony_ci  char buf[MAX_PATHNAME_LEN + 2];
565370b324cSopenharmony_ci  const size_t request = sizeof(buf) - 1;
566370b324cSopenharmony_ci
567370b324cSopenharmony_ci  // printf("\nreadlink() path = %s \n", path);
568370b324cSopenharmony_ci  const ssize_t size = readlink(path, buf, request);
569370b324cSopenharmony_ci  // there is no tail zero
570370b324cSopenharmony_ci
571370b324cSopenharmony_ci  if (size < 0)
572370b324cSopenharmony_ci    return false;
573370b324cSopenharmony_ci  if ((size_t)size >= request)
574370b324cSopenharmony_ci  {
575370b324cSopenharmony_ci    SetLastError(EINVAL); // check it: ENAMETOOLONG
576370b324cSopenharmony_ci    return false;
577370b324cSopenharmony_ci  }
578370b324cSopenharmony_ci
579370b324cSopenharmony_ci  // printf("\nreadlink() res = %s size = %d \n", buf, (int)size);
580370b324cSopenharmony_ci  reparseData.CopyFrom((const Byte *)buf, (size_t)size);
581370b324cSopenharmony_ci  return true;
582370b324cSopenharmony_ci}
583370b324cSopenharmony_ci
584370b324cSopenharmony_ci
585370b324cSopenharmony_ci/*
586370b324cSopenharmony_ci// If there is Reparse data already, it still writes new Reparse data
587370b324cSopenharmony_cibool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
588370b324cSopenharmony_ci{
589370b324cSopenharmony_ci  // AString s;
590370b324cSopenharmony_ci  // s.SetFrom_CalcLen(data, size);
591370b324cSopenharmony_ci  // return (symlink(s, path) == 0);
592370b324cSopenharmony_ci  UNUSED_VAR(path)
593370b324cSopenharmony_ci  UNUSED_VAR(isDir)
594370b324cSopenharmony_ci  UNUSED_VAR(data)
595370b324cSopenharmony_ci  UNUSED_VAR(size)
596370b324cSopenharmony_ci  SetLastError(ENOSYS);
597370b324cSopenharmony_ci  return false;
598370b324cSopenharmony_ci}
599370b324cSopenharmony_ci*/
600370b324cSopenharmony_ci
601370b324cSopenharmony_cibool SetSymLink(CFSTR from, CFSTR to)
602370b324cSopenharmony_ci{
603370b324cSopenharmony_ci  // printf("\nsymlink() %s -> %s\n", from, to);
604370b324cSopenharmony_ci  int ir;
605370b324cSopenharmony_ci  // ir = unlink(path);
606370b324cSopenharmony_ci  // if (ir == 0)
607370b324cSopenharmony_ci  ir = symlink(to, from);
608370b324cSopenharmony_ci  return (ir == 0);
609370b324cSopenharmony_ci}
610370b324cSopenharmony_ci
611370b324cSopenharmony_cibool SetSymLink_UString(CFSTR from, const UString &to)
612370b324cSopenharmony_ci{
613370b324cSopenharmony_ci  AString utf;
614370b324cSopenharmony_ci  ConvertUnicodeToUTF8(to, utf);
615370b324cSopenharmony_ci  return SetSymLink(from, utf);
616370b324cSopenharmony_ci}
617370b324cSopenharmony_ci
618370b324cSopenharmony_ci}
619370b324cSopenharmony_ci
620370b324cSopenharmony_ci#endif // !_WIN32
621370b324cSopenharmony_ci
622370b324cSopenharmony_ci}}
623