Update to 7-Zip Version 21.02

This commit is contained in:
Tino Reichardt
2021-05-13 16:39:14 +02:00
parent 3724ecfedc
commit 48fa49f76c
620 changed files with 35032 additions and 10925 deletions

View File

@@ -4,10 +4,17 @@
#include "../../C/CpuArch.h"
#ifndef _WIN32
#include <unistd.h>
#endif
#ifdef SUPPORT_DEVICE_FILE
#include "../../C/Alloc.h"
#endif
#include "../Common/UTFConvert.h"
#include "../Common/StringConvert.h"
#include "FileDir.h"
#include "FileFind.h"
#include "FileIO.h"
@@ -54,6 +61,12 @@ using namespace NName;
Substitute Path
*/
/*
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);
@@ -71,13 +84,10 @@ static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31);
#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 * 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);
}
@@ -90,7 +100,12 @@ static const bool IsVolumeName(const wchar_t *s)
}
*/
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 (;;)
{
@@ -102,14 +117,32 @@ void WriteString(Byte *dest, const wchar_t *path)
}
}
#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, _my_IO_REPARSE_TAG_LX_SYMLINK);
Set16(p + 4, (UInt16)(size));
Set16(p + 6, 0);
Set32(p + 8, _my_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 +154,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,6 +171,8 @@ 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 ?
@@ -152,9 +187,9 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
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);
@@ -177,7 +212,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)
{
@@ -194,35 +230,69 @@ static void GetString(const Byte *p, unsigned len, UString &res)
res.ReleaseBuf_SetLen(i);
}
bool CReparseAttr::Parse(const Byte *p, size_t size, DWORD &errorCode)
bool CReparseAttr::Parse(const Byte *p, size_t size)
{
errorCode = ERROR_INVALID_REPARSE_DATA;
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)
{
errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID
return false;
}
if (Get16(p + 6) != 0) // padding
return false;
HeaderError = false;
if ( Tag != _my_IO_REPARSE_TAG_MOUNT_POINT
&& Tag != _my_IO_REPARSE_TAG_SYMLINK
&& Tag != _my_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 == _my_IO_REPARSE_TAG_LX_SYMLINK)
{
if (len < 4)
return false;
Flags = Get32(p); // maybe it's not Flags
if (Flags != _my_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;
@@ -250,10 +320,11 @@ bool CReparseAttr::Parse(const Byte *p, size_t size, DWORD &errorCode)
GetString(p + subOffs, subLen >> 1, SubsName);
GetString(p + printOffs, printLen >> 1, PrintName);
errorCode = 0;
ErrorCode = 0;
return true;
}
bool CReparseShortInfo::Parse(const Byte *p, size_t size)
{
const Byte *start = p;
@@ -336,26 +407,34 @@ bool CReparseAttr::IsVolume() const
UString CReparseAttr::GetPath() const
{
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
namespace NSystem
{
bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
}
#endif
#endif // SUPPORT_DEVICE_FILE
#ifndef UNDER_CE
#if defined(_WIN32) && !defined(UNDER_CE)
namespace NIO {
@@ -388,11 +467,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;
@@ -420,21 +514,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 false;
return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size);
}
DWORD returnedSize;
if (!file.DeviceIoControl(my_FSCTL_SET_REPARSE_POINT, (void *)data, size, NULL, 0, &returnedSize))
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));
}
}
#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;
}
*/
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);
}
#endif
bool SetSymLink_UString(CFSTR from, const UString &to)
{
AString utf;
ConvertUnicodeToUTF8(to, utf);
return SetSymLink(from, utf);
}
}
#endif // !_WIN32
}}