Bug#1109782: unblock: 7zip/25.00+dfsg-1 (10/13)
From
Bastian Germann@21:1/5 to
All on Wed Jul 23 19:40:02 2025
[continued from previous message]
+ REPLACE_SLASHES_from_Linux_to_Sys(u)
+ LinkPath = u;
+ // (LinkPath) uses system path separator.
+ // windows: (LinkPath) doesn't contain linux separator (slash).
+ return true;
}
+
+// in/out: (LinkPath) uses system path separator
+// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
+// out: (LinkPath) is relative path, and LinkPath[0] is not path separator
+// out: isRelative changed to false, if any prefix was removed.
+// note: absolute windows links "c:\" to root will be reduced to empty string: +void CLinkInfo::Remove_AbsPathPrefixes()
+{
+ while (!LinkPath.IsEmpty())
+ {
+ unsigned n = 0;
+ if (!Is_WSL())
+ {
+ n =
+#ifndef _WIN32
+ isWindowsPath ?
+ NName::GetRootPrefixSize_WINDOWS(LinkPath) :
+#endif
+ NName::GetRootPrefixSize(LinkPath);
+/*
+ // "c:path" will be ignored later as "Dangerous absolute path"
+ // so check is not required
+ if (n == 0
+#ifndef _WIN32
+ && isWindowsPath
+#endif
+ && NName::IsDrivePath2(LinkPath))
+ n = 2;
+*/
+ }
+ if (n == 0)
+ {
+ if (!IS_PATH_SEPAR(LinkPath[0]))
+ break;
+ n = 1;
+ }
+ isRelative = false; // (LinkPath) will be treated as relative to root folder of archive
+ LinkPath.DeleteFrontal(n);
+ }
+}
-bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData)
+
+/*
+ it removes redundant separators, if there are double separators,
+ but it keeps double separators at start of string //name/.
+ in/out: system path separator is used
+ windows: slash character (linux separator) is not treated as separator
+ windows: (path) doesn't contain linux separator (slash).
+*/
+static void RemoveRedundantPathSeparators(UString &path)
{
- Clear();
- // this->isLinux = isLinuxData;
-
- if (isLinuxData)
+ wchar_t *dest = path.GetBuf();
+ const wchar_t * const start = dest;
+ const wchar_t *src = dest;
+ for (;;)
{
- isJunction = false;
- isHardLink = false;
- AString utf;
- if (dataSize >= (1 << 12))
- return false;
- utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
- UString u;
- if (!ConvertUTF8ToUnicode(utf, u))
- return false;
- linkPath = u;
-
- // in linux symbolic data: we expect that linux separator '/' is used
- // if windows link was created, then we also must use linux separator
- if (u.IsEmpty())
- return false;
- const wchar_t c = u[0];
- isRelative = !IS_PATH_SEPAR(c);
- return true;
+ wchar_t c = *src++;
+ if (c == 0)
+ break;
+ // if (IS_PATH_SEPAR(c)) // for Windows: we can change (/) to (\).
+ if (c == WCHAR_PATH_SEPARATOR)
+ {
+ if (dest - start >= 2 && dest[-1] == WCHAR_PATH_SEPARATOR)
+ continue;
+ // c = WCHAR_PATH_SEPARATOR; // for Windows: we can change (/) to (\).
+ }
+ *dest++ = c;
}
+ *dest = 0;
+ path.ReleaseBuf_SetLen((unsigned)(dest - path.Ptr()));
+}
- CReparseAttr reparse;
- if (!reparse.Parse(data, dataSize))
- return false;
- isHardLink = false;
- // isCopyLink = false;
- linkPath = reparse.GetPath();
- isJunction = reparse.IsMountPoint();
-
- if (reparse.IsSymLink_WSL())
+
+// in/out: (LinkPath) uses system path separator
+// in/out: windows: (LinkPath) doesn't contain linux separator (slash).
+// out: (LinkPath) is relative path, and LinkPath[0] is not path separator +void CLinkInfo::Normalize_to_RelativeSafe(UStringVector &removePathParts)
+{
+ // We WILL NOT WRITE original absolute link path from archive to filesystem. + // So here we remove all root prefixes from (LinkPath).
+ // If we see any absolute root prefix, then we suppose that this prefix is virtual prefix
+ // that shows that link is relative to root folder of archive
+ RemoveRedundantPathSeparators(LinkPath);
+ // LinkPath = "\\\\?\\r:test\\test2"; // for debug
+ Remove_AbsPathPrefixes();
+ // (LinkPath) now is relative:
+ // if (isRelative == false), then (LinkPath) is relative to root folder of archive
+ // if (isRelative == true ), then (LinkPath) is relative to current item
+ if (LinkPath.IsEmpty() || isRelative || removePathParts.Size() == 0)
+ return;
+
+ // if LinkPath is prefixed by _removePathParts, we remove these paths
+ UStringVector pathParts;
+ SplitPathToParts(LinkPath, pathParts);
+ bool badPrefix = false;
{
- isWSL = true;
- isRelative = reparse.IsRelative_WSL();
+ FOR_VECTOR (i, removePathParts)
+ {
+ if (i >= pathParts.Size()
+ || CompareFileNames(removePathParts[i], pathParts[i]) != 0)
+ {
+ badPrefix = true;
+ break;
+ }
+ }
}
- else
- isRelative = reparse.IsRelative_Win();
-
- // FIXME !!!
- #ifndef _WIN32
- linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
- #endif
-
- return true;
+ if (!badPrefix)
+ pathParts.DeleteFrontal(removePathParts.Size());
+ LinkPath = MakePathFromParts(pathParts);
+ Remove_AbsPathPrefixes();
}
-
+
#endif // SUPPORT_LINKS
@@ -2239,12 +2332,12 @@
{
HRESULT res = S_OK;
- #ifdef SUPPORT_LINKS
+#ifdef SUPPORT_LINKS
size_t reparseSize = 0;
bool repraseMode = false;
bool needSetReparse = false;
- CLinkInfo linkInfo;
+ CLinkInfo link;
if (_bufPtrSeqOutStream)
{
@@ -2258,15 +2351,19 @@
needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode);
if (needSetReparse)
{
- UString linkPath = reparse.GetPath();
+ UString LinkPath = reparse.GetPath();
#ifndef _WIN32
- linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ LinkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
#endif
}
*/
- needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux);
+ needSetReparse = _is_SymLink_in_Data_Linux ?
+ link.Parse_from_LinuxData(_outMemBuf, reparseSize) :
+ link.Parse_from_WindowsReparseData(_outMemBuf, reparseSize);
if (!needSetReparse)
res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path));
+ // (link.LinkPath) uses system path separator.
+ // windows: (link.LinkPath) doesn't contain linux separator (slash).
}
else
{
@@ -2281,23 +2378,18 @@
_bufPtrSeqOutStream.Release();
}
- #endif // SUPPORT_LINKS
-
+#endif // SUPPORT_LINKS
const HRESULT res2 = CloseFile();
-
if (res == S_OK)
res = res2;
-
RINOK(res)
- #ifdef SUPPORT_LINKS
+#ifdef SUPPORT_LINKS
if (repraseMode)
{
_curSize = reparseSize;
_curSize_Defined = true;
-
- #ifdef SUPPORT_LINKS
if (needSetReparse)
{
// in Linux : we must delete empty file before symbolic link creation @@ -2307,31 +2399,19 @@
RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath))
}
{
- /*
- // for DEBUG ONLY: we can extract sym links as WSL links
- // to eliminate (non-admin) errors for sym links.
- #ifdef _WIN32
- if (!linkInfo.isHardLink && !linkInfo.isJunction)
- linkInfo.isWSL = true;
- #endif
- */
bool linkWasSet = false;
- RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet))
+ // link.LinkPath = "r:\\1\\2"; // for debug
+ // link.isJunction = true; // for debug
+ link.Normalize_to_RelativeSafe(_removePathParts);
+ RINOK(SetLink(_diskFilePath, link, linkWasSet))
if (linkWasSet)
- _isSymLinkCreated = linkInfo.IsSymLink();
+ _isSymLinkCreated = true; // link.IsSymLink();
else
_needSetAttrib = false;
}
- /*
- if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, ))
- {
- res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath);
- }
- */
}
- #endif
}
- #endif
+#endif // SUPPORT_LINKS
return res;
}
diff -Nru 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h
--- 7zip-24.09+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 2024-10-11 17:00:00.000000000 +0200
+++ 7zip-25.00+dfsg/CPP/7zip/UI/Common/ArchiveExtractCallback.h 2025-06-16 13:00:00.000000000 +0200
@@ -178,36 +178,50 @@
#ifdef SUPPORT_LINKS
+
+enum ELinkType
+{
+ k_LinkType_HardLink,
+ k_LinkType_PureSymLink,
+ k_LinkType_Junction,
+ k_LinkType_WSL
+ // , k_LinkType_CopyLink;
+};
+
+
struct CLinkInfo
{
- // bool isCopyLink;
- bool isHardLink;
- bool isJunction;
+ ELinkType LinkType;
bool isRelative;
- bool isWSL;
- UString linkPath;
+ // if (isRelative == false), then (LinkPath) is relative to root folder of archive
+ // if (isRelative == true ), then (LinkPath) is relative to current item + bool isWindowsPath;
+ UString LinkPath;
+
+ bool Is_HardLink() const { return LinkType == k_LinkType_HardLink; }
+ bool Is_AnySymLink() const { return LinkType != k_LinkType_HardLink; }
- bool IsSymLink() const { return !isHardLink; }
+ bool Is_WSL() c