mirror of
https://github.com/LisherSong/ps5-web-file-manager.git
synced 2026-10-06 07:00:28 +02:00
New RAR engine for v1.9, replacing dmc_unrar 1.7.0. dmc_unrar only
dispatches RAR5 compression version 5 (switch(file->version) case
0x5000); WinRAR 6.x/7.x writes version 6 -> DMC_UNRAR_FILE_UNSUPPORTED_VERSION
-> user-facing "corrupt archive" on real v6 archives (diagnosed 2026-09-05
from a v6:8M:m0:m3 test file). unrar 7.20.1 natively supports v6,
encrypted and multi-volume RAR.
Vendored into third_party/unrar7/ (new dir) so the tree stays buildable
while src/rar_extract.c still references the dmc facade. Contents are a
verbatim copy of opello/unrar @97e1780 (159 files, v7.20.1) plus two
project files:
- unrar_c_api.h (C facade shim: platform types + dll.hpp re-export)
- VENDORED.md (source pin, build model, license notes)
Build model verified on host (MinGW g++ 16.2, Windows):
- all 49 UnRARDll.vcxproj sources compile with
-std=c++17 -DRARDLL -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
- links + runs: RARGetDllVersion() = 9 (smoke binary in .build/, ignored)
- Windows link additionally needs -lpowrprof
License: UnRAR freeware license (not GPL) - free to use for handling RAR
archives; cannot be used to build a RAR-compatible archiver. THIRD_PARTY_NOTICES
update lands with the engine swap commit.
Next (v1.9 work items): engine swap in rar_extract.c, Makefile .cpp rules,
fixtures + host tests, frontend password/multi-volume, then ELF build.
135 lines
3.7 KiB
C++
135 lines
3.7 KiB
C++
#include "rar.hpp"
|
|
|
|
/* Zone.Identifier stream can include the text like:
|
|
|
|
[ZoneTransfer]
|
|
ZoneId=3
|
|
HostUrl=https://site/path/file.ext
|
|
ReferrerUrl=d:\path\archive.ext
|
|
|
|
Where ZoneId can be:
|
|
|
|
0 = My Computer
|
|
1 = Local intranet
|
|
2 = Trusted sites
|
|
3 = Internet
|
|
4 = Restricted sites
|
|
*/
|
|
|
|
MarkOfTheWeb::MarkOfTheWeb()
|
|
{
|
|
ZoneIdValue=-1; // -1 indicates the missing MOTW.
|
|
AllFields=false;
|
|
}
|
|
|
|
|
|
void MarkOfTheWeb::Clear()
|
|
{
|
|
ZoneIdValue=-1;
|
|
}
|
|
|
|
|
|
void MarkOfTheWeb::ReadZoneIdStream(const std::wstring &FileName,bool AllFields)
|
|
{
|
|
MarkOfTheWeb::AllFields=AllFields;
|
|
ZoneIdValue=-1;
|
|
ZoneIdStream.clear();
|
|
|
|
std::wstring StreamName=FileName+MOTW_STREAM_NAME;
|
|
|
|
File SrcFile;
|
|
if (SrcFile.Open(StreamName))
|
|
{
|
|
ZoneIdStream.resize(MOTW_STREAM_MAX_SIZE);
|
|
int BufSize=SrcFile.Read(&ZoneIdStream[0],ZoneIdStream.size());
|
|
ZoneIdStream.resize(BufSize<0 ? 0:BufSize);
|
|
|
|
if (BufSize<=0)
|
|
return;
|
|
|
|
ZoneIdValue=ParseZoneIdStream(ZoneIdStream);
|
|
}
|
|
}
|
|
|
|
|
|
// 'Stream' contains the raw "Zone.Identifier" NTFS stream data on input
|
|
// and either raw or cleaned stream data on output.
|
|
int MarkOfTheWeb::ParseZoneIdStream(std::string &Stream)
|
|
{
|
|
if (!starts_with(Stream,"[ZoneTransfer]"))
|
|
return -1; // Not a valid Mark of the Web. Prefer the archive MOTW if any.
|
|
|
|
std::string::size_type ZoneId=Stream.find("ZoneId=",0);
|
|
if (ZoneId==std::string::npos || !IsDigit(Stream[ZoneId+7]))
|
|
return -1; // Not a valid Mark of the Web.
|
|
int ZoneIdValue=atoi(&Stream[ZoneId+7]);
|
|
if (ZoneIdValue<0 || ZoneIdValue>4)
|
|
return -1; // Not a valid Mark of the Web.
|
|
|
|
if (!AllFields)
|
|
Stream="[ZoneTransfer]\r\nZoneId=" + std::to_string(ZoneIdValue) + "\r\n";
|
|
|
|
return ZoneIdValue;
|
|
}
|
|
|
|
|
|
void MarkOfTheWeb::CreateZoneIdStream(const std::wstring &Name,StringList &MotwList)
|
|
{
|
|
if (ZoneIdValue==-1)
|
|
return;
|
|
|
|
size_t ExtPos=GetExtPos(Name);
|
|
const wchar *Ext=ExtPos==std::wstring::npos ? L"":&Name[ExtPos+1];
|
|
|
|
bool Matched=false;
|
|
const wchar *CurMask;
|
|
MotwList.Rewind();
|
|
while ((CurMask=MotwList.GetString())!=nullptr)
|
|
{
|
|
// Perform the fast extension comparison for simple *.ext masks.
|
|
// Also we added the fast path to wcsicomp for English only strings.
|
|
// When extracting 100000 files with "Exe and office" masks set
|
|
// this loop spent 85ms with this optimization and wcsicomp optimized
|
|
// for English strings, 415ms with this optimization only, 475ms with
|
|
// wcsicomp optimized only and 795ms without both optimizations.
|
|
bool FastCmp=CurMask[0]=='*' && CurMask[1]=='.' && wcspbrk(CurMask+2,L"*?")==NULL;
|
|
if (FastCmp && wcsicomp(Ext,CurMask+2)==0 || !FastCmp && CmpName(CurMask,Name,MATCH_NAMES))
|
|
{
|
|
Matched=true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!Matched)
|
|
return;
|
|
|
|
std::wstring StreamName=Name+MOTW_STREAM_NAME;
|
|
|
|
File StreamFile;
|
|
if (StreamFile.Create(StreamName)) // Can fail on FAT.
|
|
{
|
|
// We got a report that write to stream failed on Synology 2411+ NAS drive.
|
|
// So we handle it silently instead of aborting.
|
|
StreamFile.SetExceptions(false);
|
|
if (StreamFile.Write(&ZoneIdStream[0],ZoneIdStream.size()))
|
|
StreamFile.Close();
|
|
}
|
|
}
|
|
|
|
|
|
bool MarkOfTheWeb::IsNameConflicting(const std::wstring &StreamName)
|
|
{
|
|
// We must use the case insensitive comparison for L":Zone.Identifier"
|
|
// to catch specially crafted archived streams like L":zone.identifier".
|
|
return wcsicomp(StreamName,MOTW_STREAM_NAME)==0 && ZoneIdValue!=-1;
|
|
}
|
|
|
|
|
|
// Return true and prepare the file stream to write if its ZoneId is stricter
|
|
// than archive ZoneId. If it is missing, less or equally strict, return false.
|
|
bool MarkOfTheWeb::IsFileStreamMoreSecure(std::string &FileStream)
|
|
{
|
|
int StreamZone=ParseZoneIdStream(FileStream);
|
|
return StreamZone>ZoneIdValue;
|
|
}
|