"Fossies" - the Fresh Open Source Software Archive 
Member "unrar/win32lnk.cpp" (4 May 2022, 6505 Bytes) of package /linux/misc/unrarsrc-6.1.7.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "win32lnk.cpp" see the
Fossies "Dox" file reference documentation.
1 #define SYMLINK_FLAG_RELATIVE 1
2
3 typedef struct _REPARSE_DATA_BUFFER {
4 ULONG ReparseTag;
5 USHORT ReparseDataLength;
6 USHORT Reserved;
7 union {
8 struct {
9 USHORT SubstituteNameOffset;
10 USHORT SubstituteNameLength;
11 USHORT PrintNameOffset;
12 USHORT PrintNameLength;
13 ULONG Flags;
14 WCHAR PathBuffer[1];
15 } SymbolicLinkReparseBuffer;
16 struct {
17 USHORT SubstituteNameOffset;
18 USHORT SubstituteNameLength;
19 USHORT PrintNameOffset;
20 USHORT PrintNameLength;
21 WCHAR PathBuffer[1];
22 } MountPointReparseBuffer;
23 struct {
24 UCHAR DataBuffer[1];
25 } GenericReparseBuffer;
26 };
27 } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
28
29
30
31
32 bool CreateReparsePoint(CommandData *Cmd,const wchar *Name,FileHeader *hd)
33 {
34 static bool PrivSet=false;
35 if (!PrivSet)
36 {
37 SetPrivilege(SE_RESTORE_NAME);
38 // Not sure if we really need it, but let's request anyway.
39 SetPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME);
40 PrivSet=true;
41 }
42
43 const DWORD BufSize=sizeof(REPARSE_DATA_BUFFER)+2*NM+1024;
44 Array<byte> Buf(BufSize);
45 REPARSE_DATA_BUFFER *rdb=(REPARSE_DATA_BUFFER *)&Buf[0];
46
47 wchar SubstName[NM];
48 wcsncpyz(SubstName,hd->RedirName,ASIZE(SubstName));
49 size_t SubstLength=wcslen(SubstName);
50
51 wchar PrintName[NM],*PrintNameSrc=SubstName,*PrintNameDst=PrintName;
52 bool WinPrefix=wcsncmp(PrintNameSrc,L"\\??\\",4)==0;
53 if (WinPrefix)
54 PrintNameSrc+=4;
55 if (WinPrefix && wcsncmp(PrintNameSrc,L"UNC\\",4)==0)
56 {
57 *(PrintNameDst++)='\\'; // Insert second \ in beginning of share name.
58 PrintNameSrc+=3;
59 }
60 wcscpy(PrintNameDst,PrintNameSrc);
61
62 size_t PrintLength=wcslen(PrintName);
63
64 bool AbsPath=WinPrefix;
65 // IsFullPath is not really needed here, AbsPath check is enough.
66 // We added it just for extra safety, in case some Windows version would
67 // allow to create absolute targets with SYMLINK_FLAG_RELATIVE.
68 // Use hd->FileName instead of Name, since Name can include the destination
69 // path as a prefix, which can confuse IsRelativeSymlinkSafe algorithm.
70 if (!Cmd->AbsoluteLinks && (AbsPath || IsFullPath(hd->RedirName) ||
71 !IsRelativeSymlinkSafe(Cmd,hd->FileName,Name,hd->RedirName)))
72 return false;
73
74 CreatePath(Name,true,Cmd->DisableNames);
75
76 // Overwrite prompt was already issued and confirmed earlier, so we can
77 // remove existing symlink or regular file here. PrepareToDelete was also
78 // called earlier inside of uiAskReplaceEx.
79 if (FileExist(Name))
80 if (IsDir(GetFileAttr(Name)))
81 DelDir(Name);
82 else
83 DelFile(Name);
84
85 // 'DirTarget' check is important for Unix symlinks to directories.
86 // Unix symlinks do not have their own 'directory' attribute.
87 if (hd->Dir || hd->DirTarget)
88 {
89 if (!CreateDirectory(Name,NULL))
90 {
91 uiMsg(UIERROR_DIRCREATE,UINULL,Name);
92 ErrHandler.SetErrorCode(RARX_CREATE);
93 return false;
94 }
95 }
96 else
97 {
98 HANDLE hFile=CreateFile(Name,GENERIC_WRITE,0,NULL,CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
99 if (hFile == INVALID_HANDLE_VALUE)
100 {
101 ErrHandler.CreateErrorMsg(Name);
102 return false;
103 }
104 CloseHandle(hFile);
105 }
106
107
108 if (hd->RedirType==FSREDIR_JUNCTION)
109 {
110 rdb->ReparseTag=IO_REPARSE_TAG_MOUNT_POINT;
111 rdb->ReparseDataLength=USHORT(
112 sizeof(rdb->MountPointReparseBuffer.SubstituteNameOffset)+
113 sizeof(rdb->MountPointReparseBuffer.SubstituteNameLength)+
114 sizeof(rdb->MountPointReparseBuffer.PrintNameOffset)+
115 sizeof(rdb->MountPointReparseBuffer.PrintNameLength)+
116 (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
117 rdb->Reserved=0;
118
119 rdb->MountPointReparseBuffer.SubstituteNameOffset=0;
120 rdb->MountPointReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
121 wcscpy(rdb->MountPointReparseBuffer.PathBuffer,SubstName);
122
123 rdb->MountPointReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
124 rdb->MountPointReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
125 wcscpy(rdb->MountPointReparseBuffer.PathBuffer+SubstLength+1,PrintName);
126 }
127 else
128 if (hd->RedirType==FSREDIR_WINSYMLINK || hd->RedirType==FSREDIR_UNIXSYMLINK)
129 {
130 rdb->ReparseTag=IO_REPARSE_TAG_SYMLINK;
131 rdb->ReparseDataLength=USHORT(
132 sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset)+
133 sizeof(rdb->SymbolicLinkReparseBuffer.SubstituteNameLength)+
134 sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameOffset)+
135 sizeof(rdb->SymbolicLinkReparseBuffer.PrintNameLength)+
136 sizeof(rdb->SymbolicLinkReparseBuffer.Flags)+
137 (SubstLength+1)*sizeof(WCHAR)+(PrintLength+1)*sizeof(WCHAR));
138 rdb->Reserved=0;
139
140 rdb->SymbolicLinkReparseBuffer.SubstituteNameOffset=0;
141 rdb->SymbolicLinkReparseBuffer.SubstituteNameLength=USHORT(SubstLength*sizeof(WCHAR));
142 wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer,SubstName);
143
144 rdb->SymbolicLinkReparseBuffer.PrintNameOffset=USHORT((SubstLength+1)*sizeof(WCHAR));
145 rdb->SymbolicLinkReparseBuffer.PrintNameLength=USHORT(PrintLength*sizeof(WCHAR));
146 wcscpy(rdb->SymbolicLinkReparseBuffer.PathBuffer+SubstLength+1,PrintName);
147
148 rdb->SymbolicLinkReparseBuffer.Flags=AbsPath ? 0:SYMLINK_FLAG_RELATIVE;
149 }
150 else
151 return false;
152
153 HANDLE hFile=CreateFile(Name,GENERIC_READ|GENERIC_WRITE,0,NULL,
154 OPEN_EXISTING,FILE_FLAG_OPEN_REPARSE_POINT|
155 FILE_FLAG_BACKUP_SEMANTICS,NULL);
156 if (hFile==INVALID_HANDLE_VALUE)
157 {
158 ErrHandler.CreateErrorMsg(Name);
159 ErrHandler.SetErrorCode(RARX_CREATE);
160 return false;
161 }
162
163 DWORD Returned;
164 if (!DeviceIoControl(hFile,FSCTL_SET_REPARSE_POINT,rdb,
165 FIELD_OFFSET(REPARSE_DATA_BUFFER,GenericReparseBuffer)+
166 rdb->ReparseDataLength,NULL,0,&Returned,NULL))
167 {
168 CloseHandle(hFile);
169 uiMsg(UIERROR_SLINKCREATE,UINULL,Name);
170
171 DWORD LastError=GetLastError();
172 if ((LastError==ERROR_ACCESS_DENIED || LastError==ERROR_PRIVILEGE_NOT_HELD) &&
173 !IsUserAdmin())
174 uiMsg(UIERROR_NEEDADMIN);
175 ErrHandler.SysErrMsg();
176 ErrHandler.SetErrorCode(RARX_CREATE);
177
178 if (hd->Dir)
179 RemoveDirectory(Name);
180 else
181 DeleteFile(Name);
182 return false;
183 }
184 File LinkFile;
185 LinkFile.SetHandle(hFile);
186 LinkFile.SetOpenFileTime(
187 Cmd->xmtime==EXTTIME_NONE ? NULL:&hd->mtime,
188 Cmd->xctime==EXTTIME_NONE ? NULL:&hd->ctime,
189 Cmd->xatime==EXTTIME_NONE ? NULL:&hd->atime);
190 LinkFile.Close();
191 if (!Cmd->IgnoreGeneralAttr)
192 SetFileAttr(Name,hd->FileAttr);
193 return true;
194 }