Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | |
3 | | static bool UnixSymlink(CommandData *Cmd,const char *Target,const wchar *LinkName,RarTime *ftm,RarTime *fta) |
4 | 0 | { |
5 | 0 | CreatePath(LinkName,true,Cmd->DisableNames); |
6 | | |
7 | | // Overwrite prompt was already issued and confirmed earlier, so we can |
8 | | // remove existing symlink or regular file here. PrepareToDelete was also |
9 | | // called earlier inside of uiAskReplaceEx. |
10 | 0 | DelFile(LinkName); |
11 | |
|
12 | 0 | char LinkNameA[NM]; |
13 | 0 | WideToChar(LinkName,LinkNameA,ASIZE(LinkNameA)); |
14 | 0 | if (symlink(Target,LinkNameA)==-1) // Error. |
15 | 0 | { |
16 | 0 | if (errno==EEXIST) |
17 | 0 | uiMsg(UIERROR_ULINKEXIST,LinkName); |
18 | 0 | else |
19 | 0 | { |
20 | 0 | uiMsg(UIERROR_SLINKCREATE,UINULL,LinkName); |
21 | 0 | ErrHandler.SetErrorCode(RARX_WARNING); |
22 | 0 | } |
23 | 0 | return false; |
24 | 0 | } |
25 | 0 | #ifdef USE_LUTIMES |
26 | 0 | #ifdef UNIX_TIME_NS |
27 | 0 | timespec times[2]; |
28 | 0 | times[0].tv_sec=fta->GetUnix(); |
29 | 0 | times[0].tv_nsec=fta->IsSet() ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW; |
30 | 0 | times[1].tv_sec=ftm->GetUnix(); |
31 | 0 | times[1].tv_nsec=ftm->IsSet() ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW; |
32 | 0 | utimensat(AT_FDCWD,LinkNameA,times,AT_SYMLINK_NOFOLLOW); |
33 | | #else |
34 | | struct timeval tv[2]; |
35 | | tv[0].tv_sec=fta->GetUnix(); |
36 | | tv[0].tv_usec=long(fta->GetUnixNS()%1000000000/1000); |
37 | | tv[1].tv_sec=ftm->GetUnix(); |
38 | | tv[1].tv_usec=long(ftm->GetUnixNS()%1000000000/1000); |
39 | | lutimes(LinkNameA,tv); |
40 | | #endif |
41 | 0 | #endif |
42 | |
|
43 | 0 | return true; |
44 | 0 | } |
45 | | |
46 | | |
47 | | static bool IsFullPath(const char *PathA) // Unix ASCII version. |
48 | 0 | { |
49 | 0 | return *PathA==CPATHDIVIDER; |
50 | 0 | } |
51 | | |
52 | | |
53 | | // For security purpose we prefer to be sure that CharToWide completed |
54 | | // successfully and even if it truncated a string for some reason, |
55 | | // it didn't affect the number of path related characters we analyze |
56 | | // in IsRelativeSymlinkSafe later. |
57 | | // This check is likely to be excessive, but let's keep it anyway. |
58 | | static bool SafeCharToWide(const char *Src,wchar *Dest,size_t DestSize) |
59 | 0 | { |
60 | 0 | if (!CharToWide(Src,Dest,DestSize) || *Dest==0) |
61 | 0 | return false; |
62 | 0 | uint SrcChars=0,DestChars=0; |
63 | 0 | for (uint I=0;Src[I]!=0;I++) |
64 | 0 | if (Src[I]=='/' || Src[I]=='.') |
65 | 0 | SrcChars++; |
66 | 0 | for (uint I=0;Dest[I]!=0;I++) |
67 | 0 | if (Dest[I]=='/' || Dest[I]=='.') |
68 | 0 | DestChars++; |
69 | 0 | return SrcChars==DestChars; |
70 | 0 | } |
71 | | |
72 | | |
73 | | bool ExtractUnixLink30(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) |
74 | 0 | { |
75 | 0 | char Target[NM]; |
76 | 0 | if (IsLink(Arc.FileHead.FileAttr)) |
77 | 0 | { |
78 | 0 | size_t DataSize=(size_t)Arc.FileHead.PackSize; |
79 | 0 | if (DataSize>ASIZE(Target)-1) |
80 | 0 | return false; |
81 | 0 | if ((size_t)DataIO.UnpRead((byte *)Target,DataSize)!=DataSize) |
82 | 0 | return false; |
83 | 0 | Target[DataSize]=0; |
84 | |
|
85 | 0 | DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,1); |
86 | 0 | DataIO.UnpHash.Update(Target,strlen(Target)); |
87 | 0 | DataIO.UnpHash.Result(&Arc.FileHead.FileHash); |
88 | | |
89 | | // Return true in case of bad checksum, so link will be processed further |
90 | | // and extraction routine will report the checksum error. |
91 | 0 | if (!DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL)) |
92 | 0 | return true; |
93 | | |
94 | 0 | wchar TargetW[NM]; |
95 | 0 | if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW))) |
96 | 0 | return false; |
97 | | // Use Arc.FileHead.FileName instead of LinkName, since LinkName |
98 | | // can include the destination path as a prefix, which can |
99 | | // confuse IsRelativeSymlinkSafe algorithm. |
100 | 0 | if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) || |
101 | 0 | !IsRelativeSymlinkSafe(Cmd,Arc.FileHead.FileName,LinkName,TargetW))) |
102 | 0 | return false; |
103 | 0 | return UnixSymlink(Cmd,Target,LinkName,&Arc.FileHead.mtime,&Arc.FileHead.atime); |
104 | 0 | } |
105 | 0 | return false; |
106 | 0 | } |
107 | | |
108 | | |
109 | | bool ExtractUnixLink50(CommandData *Cmd,const wchar *Name,FileHeader *hd) |
110 | 0 | { |
111 | 0 | char Target[NM]; |
112 | 0 | WideToChar(hd->RedirName,Target,ASIZE(Target)); |
113 | 0 | if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_JUNCTION) |
114 | 0 | { |
115 | | // Cannot create Windows absolute path symlinks in Unix. Only relative path |
116 | | // Windows symlinks can be created here. RAR 5.0 used \??\ prefix |
117 | | // for Windows absolute symlinks, since RAR 5.1 /??/ is used. |
118 | | // We escape ? as \? to avoid "trigraph" warning |
119 | 0 | if (strncmp(Target,"\\??\\",4)==0 || strncmp(Target,"/\?\?/",4)==0) |
120 | 0 | return false; |
121 | 0 | DosSlashToUnix(Target,Target,ASIZE(Target)); |
122 | 0 | } |
123 | | |
124 | 0 | wchar TargetW[NM]; |
125 | 0 | if (!SafeCharToWide(Target,TargetW,ASIZE(TargetW))) |
126 | 0 | return false; |
127 | | // Use hd->FileName instead of LinkName, since LinkName can include |
128 | | // the destination path as a prefix, which can confuse |
129 | | // IsRelativeSymlinkSafe algorithm. |
130 | | // 2022.05.04: Use TargetW instead of previously used hd->RedirName |
131 | | // for security reason. |
132 | 0 | if (!Cmd->AbsoluteLinks && (IsFullPath(TargetW) || |
133 | 0 | !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,TargetW))) |
134 | 0 | return false; |
135 | 0 | return UnixSymlink(Cmd,Target,Name,&hd->mtime,&hd->atime); |
136 | 0 | } |