summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/lzma/CPP/Windows/FileLink.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/lzma/CPP/Windows/FileLink.cpp')
-rw-r--r--3rdparty/lzma/CPP/Windows/FileLink.cpp316
1 files changed, 251 insertions, 65 deletions
diff --git a/3rdparty/lzma/CPP/Windows/FileLink.cpp b/3rdparty/lzma/CPP/Windows/FileLink.cpp
index 25d49ac3ed6..2b9fa1a0930 100644
--- a/3rdparty/lzma/CPP/Windows/FileLink.cpp
+++ b/3rdparty/lzma/CPP/Windows/FileLink.cpp
@@ -4,15 +4,31 @@
#include "../../C/CpuArch.h"
-#ifdef SUPPORT_DEVICE_FILE
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#ifdef Z7_DEVICE_FILE
#include "../../C/Alloc.h"
#endif
+#include "../Common/UTFConvert.h"
+#include "../Common/StringConvert.h"
+
#include "FileDir.h"
#include "FileFind.h"
#include "FileIO.h"
#include "FileName.h"
+#ifdef Z7_OLD_WIN_SDK
+#ifndef ERROR_INVALID_REPARSE_DATA
+#define ERROR_INVALID_REPARSE_DATA 4392L
+#endif
+#ifndef ERROR_REPARSE_TAG_INVALID
+#define ERROR_REPARSE_TAG_INVALID 4393L
+#endif
+#endif
+
#ifndef _UNICODE
extern bool g_IsNT;
#endif
@@ -55,61 +71,87 @@ using namespace NName;
*/
/*
+Win10 WSL2:
+admin rights + sudo: it creates normal windows symbolic link.
+in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point.
+*/
+
+/*
static const UInt32 kReparseFlags_Alias = (1 << 29);
static const UInt32 kReparseFlags_HighLatency = (1 << 30);
static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31);
-#define _my_IO_REPARSE_TAG_HSM (0xC0000004L)
-#define _my_IO_REPARSE_TAG_HSM2 (0x80000006L)
-#define _my_IO_REPARSE_TAG_SIS (0x80000007L)
-#define _my_IO_REPARSE_TAG_WIM (0x80000008L)
-#define _my_IO_REPARSE_TAG_CSV (0x80000009L)
-#define _my_IO_REPARSE_TAG_DFS (0x8000000AL)
-#define _my_IO_REPARSE_TAG_DFSR (0x80000012L)
+#define Z7_WIN_IO_REPARSE_TAG_HSM (0xC0000004L)
+#define Z7_WIN_IO_REPARSE_TAG_HSM2 (0x80000006L)
+#define Z7_WIN_IO_REPARSE_TAG_SIS (0x80000007L)
+#define Z7_WIN_IO_REPARSE_TAG_WIM (0x80000008L)
+#define Z7_WIN_IO_REPARSE_TAG_CSV (0x80000009L)
+#define Z7_WIN_IO_REPARSE_TAG_DFS (0x8000000AL)
+#define Z7_WIN_IO_REPARSE_TAG_DFSR (0x80000012L)
*/
#define Get16(p) GetUi16(p)
#define Get32(p) GetUi32(p)
-#define Set16(p, v) SetUi16(p, v)
-#define Set32(p, v) SetUi32(p, v)
-
-static const wchar_t *k_LinkPrefix = L"\\??\\";
+static const wchar_t * const k_LinkPrefix = L"\\??\\";
static const unsigned k_LinkPrefix_Size = 4;
-static const bool IsLinkPrefix(const wchar_t *s)
+static bool IsLinkPrefix(const wchar_t *s)
{
return IsString1PrefixedByString2(s, k_LinkPrefix);
}
/*
-static const wchar_t *k_VolumePrefix = L"Volume{";
+static const wchar_t * const k_VolumePrefix = L"Volume{";
static const bool IsVolumeName(const wchar_t *s)
{
return IsString1PrefixedByString2(s, k_VolumePrefix);
}
*/
-void WriteString(Byte *dest, const wchar_t *path)
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+#define Set16(p, v) SetUi16(p, v)
+#define Set32(p, v) SetUi32(p, v)
+
+static void WriteString(Byte *dest, const wchar_t *path)
{
for (;;)
{
wchar_t c = *path++;
if (c == 0)
return;
- Set16(dest, (UInt16)c);
+ Set16(dest, (UInt16)c)
dest += 2;
}
}
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
+bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
{
bool isAbs = IsAbsolutePath(path);
if (!isAbs && !isSymLink)
return false;
+ if (isWSL)
+ {
+ // unsupported characters probably use Replacement Character UTF-16 0xFFFD
+ AString utf;
+ ConvertUnicodeToUTF8(path, utf);
+ const size_t size = 4 + utf.Len();
+ if (size != (UInt16)size)
+ return false;
+ dest.Alloc(8 + size);
+ Byte *p = dest;
+ Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
+ Set16(p + 4, (UInt16)(size))
+ Set16(p + 6, 0)
+ Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG)
+ memcpy(p + 12, utf.Ptr(), utf.Len());
+ return true;
+ }
+
+ // usual symbolic LINK (NOT WSL)
+
bool needPrintName = true;
if (IsSuperPath(path))
@@ -121,12 +163,12 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0;
- unsigned len2 = MyStringLen(path) * 2;
- const unsigned len1 = len2 + add_Prefix_Len * 2;
+ size_t len2 = (size_t)MyStringLen(path) * 2;
+ const size_t len1 = len2 + add_Prefix_Len * 2;
if (!needPrintName)
len2 = 0;
- unsigned totalNamesSize = (len1 + len2);
+ size_t totalNamesSize = (len1 + len2);
/* some WIM imagex software uses old scheme for symbolic links.
so we can old scheme for byte to byte compatibility */
@@ -138,34 +180,36 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
totalNamesSize += 2 * 2;
const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
+ if (size != (UInt16)size)
+ return false;
dest.Alloc(size);
memset(dest, 0, size);
const UInt32 tag = isSymLink ?
- _my_IO_REPARSE_TAG_SYMLINK :
- _my_IO_REPARSE_TAG_MOUNT_POINT;
+ Z7_WIN_IO_REPARSE_TAG_SYMLINK :
+ Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT;
Byte *p = dest;
- Set32(p, tag);
- Set16(p + 4, (UInt16)(size - 8));
- Set16(p + 6, 0);
+ Set32(p, tag)
+ Set16(p + 4, (UInt16)(size - 8))
+ Set16(p + 6, 0)
p += 8;
unsigned subOffs = 0;
unsigned printOffs = 0;
if (newOrderScheme)
- subOffs = len2;
+ subOffs = (unsigned)len2;
else
- printOffs = len1 + 2;
+ printOffs = (unsigned)len1 + 2;
- Set16(p + 0, (UInt16)subOffs);
- Set16(p + 2, (UInt16)len1);
- Set16(p + 4, (UInt16)printOffs);
- Set16(p + 6, (UInt16)len2);
+ Set16(p + 0, (UInt16)subOffs)
+ Set16(p + 2, (UInt16)len1)
+ Set16(p + 4, (UInt16)printOffs)
+ Set16(p + 6, (UInt16)len2)
p += 8;
if (isSymLink)
{
- UInt32 flags = isAbs ? 0 : _my_SYMLINK_FLAG_RELATIVE;
- Set32(p, flags);
+ UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
+ Set32(p, flags)
p += 4;
}
@@ -177,7 +221,8 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
return true;
}
-#endif
+#endif // defined(_WIN32) && !defined(UNDER_CE)
+
static void GetString(const Byte *p, unsigned len, UString &res)
{
@@ -196,30 +241,67 @@ static void GetString(const Byte *p, unsigned len, UString &res)
bool CReparseAttr::Parse(const Byte *p, size_t size)
{
+ ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA;
+ HeaderError = true;
+ TagIsUnknown = true;
+ MinorError = false;
+
if (size < 8)
return false;
Tag = Get32(p);
UInt32 len = Get16(p + 4);
- if (len + 8 > size)
+ if (len + 8 != size)
+ // if (len + 8 > size)
return false;
/*
if ((type & kReparseFlags_Alias) == 0 ||
(type & kReparseFlags_Microsoft) == 0 ||
(type & 0xFFFF) != 3)
*/
- if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT &&
- Tag != _my_IO_REPARSE_TAG_SYMLINK)
- // return true;
- return false;
if (Get16(p + 6) != 0) // padding
return false;
-
+
+ HeaderError = false;
+
+ if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT
+ && Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK
+ && Tag != Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
+ {
+ // for unsupported reparse points
+ ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH
+ // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID
+ return false;
+ }
+
+ TagIsUnknown = false;
+
p += 8;
size -= 8;
- if (len != size) // do we need that check?
- return false;
+ if (Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
+ {
+ if (len < 4)
+ return false;
+ Flags = Get32(p); // maybe it's not Flags
+ if (Flags != Z7_WIN_LX_SYMLINK_FLAG)
+ return false;
+ len -= 4;
+ p += 4;
+ char *s = WslName.GetBuf(len);
+ unsigned i;
+ for (i = 0; i < len; i++)
+ {
+ char c = (char)p[i];
+ s[i] = c;
+ if (c == 0)
+ break;
+ }
+ WslName.ReleaseBuf_SetEnd(i);
+ MinorError = (i != len);
+ ErrorCode = 0;
+ return true;
+ }
if (len < 8)
return false;
@@ -231,7 +313,7 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
p += 8;
Flags = 0;
- if (Tag == _my_IO_REPARSE_TAG_SYMLINK)
+ if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
{
if (len < 4)
return false;
@@ -247,9 +329,11 @@ bool CReparseAttr::Parse(const Byte *p, size_t size)
GetString(p + subOffs, subLen >> 1, SubsName);
GetString(p + printOffs, printLen >> 1, PrintName);
+ ErrorCode = 0;
return true;
}
+
bool CReparseShortInfo::Parse(const Byte *p, size_t size)
{
const Byte *start = p;
@@ -266,8 +350,8 @@ bool CReparseShortInfo::Parse(const Byte *p, size_t size)
(type & kReparseFlags_Microsoft) == 0 ||
(type & 0xFFFF) != 3)
*/
- if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT &&
- Tag != _my_IO_REPARSE_TAG_SYMLINK)
+ if (Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT &&
+ Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK)
// return true;
return false;
@@ -290,7 +374,7 @@ bool CReparseShortInfo::Parse(const Byte *p, size_t size)
p += 8;
// UInt32 Flags = 0;
- if (Tag == _my_IO_REPARSE_TAG_SYMLINK)
+ if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
{
if (len < 4)
return false;
@@ -332,26 +416,34 @@ bool CReparseAttr::IsVolume() const
UString CReparseAttr::GetPath() const
{
- UString s = SubsName;
+ if (IsSymLink_WSL())
+ {
+ UString u;
+ // if (CheckUTF8(attr.WslName)
+ if (!ConvertUTF8ToUnicode(WslName, u))
+ MultiByteToUnicodeString2(u, WslName);
+ return u;
+ }
+
+ UString s (SubsName);
if (IsLinkPrefix(s))
{
- s.ReplaceOneCharAtPos(1, '\\');
+ s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
s.DeleteFrontal(k_LinkPrefix_Size);
}
return s;
}
-
-#ifdef SUPPORT_DEVICE_FILE
+#ifdef Z7_DEVICE_FILE
namespace NSystem
{
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
}
-#endif
+#endif // Z7_DEVICE_FILE
-#ifndef UNDER_CE
+#if defined(_WIN32) && !defined(UNDER_CE)
namespace NIO {
@@ -376,7 +468,7 @@ bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMA
static bool CreatePrefixDirOfFile(CFSTR path)
{
- FString path2 = path;
+ FString path2 (path);
int pos = path2.ReverseFind_PathSepar();
if (pos < 0)
return true;
@@ -384,11 +476,26 @@ static bool CreatePrefixDirOfFile(CFSTR path)
if (pos == 2 && path2[1] == L':')
return true; // we don't create Disk folder;
#endif
- path2.DeleteFrom(pos);
+ path2.DeleteFrom((unsigned)pos);
return NDir::CreateComplexDir(path2);
}
-// If there is Reprase data already, it still writes new Reparse data
+
+static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size)
+{
+ COutFile file;
+ if (!file.Open(path,
+ FILE_SHARE_WRITE,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))
+ return false;
+
+ DWORD returnedSize;
+ return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize);
+}
+
+
+// If there is Reparse data already, it still writes new Reparse data
bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
{
NFile::NFind::CFileInfo fi;
@@ -416,21 +523,100 @@ bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
}
}
- COutFile file;
- if (!file.Open(path,
- FILE_SHARE_WRITE,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))
+ return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size);
+}
+
+
+bool DeleteReparseData(CFSTR path)
+{
+ CByteBuffer reparseData;
+ if (!GetReparseData(path, reparseData, NULL))
+ return false;
+ /* MSDN: The tag specified in the ReparseTag member of this structure
+ must match the tag of the reparse point to be deleted,
+ and the ReparseDataLength member must be zero */
+ #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8
+ if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE)
+ {
+ SetLastError(ERROR_INVALID_REPARSE_DATA);
return false;
+ }
+ BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, reparseData, 4); // tag
+ return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf));
+}
- DWORD returnedSize;
- if (!file.DeviceIoControl(my_FSCTL_SET_REPARSE_POINT, (void *)data, size, NULL, 0, &returnedSize))
+}
+
+#endif // defined(_WIN32) && !defined(UNDER_CE)
+
+
+#ifndef _WIN32
+
+namespace NIO {
+
+bool GetReparseData(CFSTR path, CByteBuffer &reparseData)
+{
+ reparseData.Free();
+
+ #define MAX_PATHNAME_LEN 1024
+ char buf[MAX_PATHNAME_LEN + 2];
+ const size_t request = sizeof(buf) - 1;
+
+ // printf("\nreadlink() path = %s \n", path);
+ const ssize_t size = readlink(path, buf, request);
+ // there is no tail zero
+
+ if (size < 0)
return false;
+ if ((size_t)size >= request)
+ {
+ SetLastError(EINVAL); // check it: ENAMETOOLONG
+ return false;
+ }
+
+ // printf("\nreadlink() res = %s size = %d \n", buf, (int)size);
+ reparseData.CopyFrom((const Byte *)buf, (size_t)size);
return true;
}
+
+/*
+// If there is Reparse data already, it still writes new Reparse data
+bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
+{
+ // AString s;
+ // s.SetFrom_CalcLen(data, size);
+ // return (symlink(s, path) == 0);
+ UNUSED_VAR(path)
+ UNUSED_VAR(isDir)
+ UNUSED_VAR(data)
+ UNUSED_VAR(size)
+ SetLastError(ENOSYS);
+ return false;
}
+*/
-#endif
+bool SetSymLink(CFSTR from, CFSTR to)
+{
+ // printf("\nsymlink() %s -> %s\n", from, to);
+ int ir;
+ // ir = unlink(path);
+ // if (ir == 0)
+ ir = symlink(to, from);
+ return (ir == 0);
+}
+
+bool SetSymLink_UString(CFSTR from, const UString &to)
+{
+ AString utf;
+ ConvertUnicodeToUTF8(to, utf);
+ return SetSymLink(from, utf);
+}
+
+}
+
+#endif // !_WIN32
}}