-
Notifications
You must be signed in to change notification settings - Fork 45
/
Copy pathmotw.cpp
131 lines (102 loc) · 3.45 KB
/
motw.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#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 (Stream.rfind("[ZoneTransfer]",0)==std::string::npos)
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;
wchar *CurMask;
MotwList.Rewind();
while ((CurMask=MotwList.GetString())!=nullptr)
{
// Perform the fast extension comparison for simple *.ext masks.
// When extracting 100000 files with "Exe and office" masks set,
// this loop spends 1.14s without this optimization and 0.24s with it.
bool FastCmp=CurMask[0]=='*' && CurMask[1]=='.' && !IsWildcard(CurMask+2);
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;
}