VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/symlink-win.cpp@ 46727

Last change on this file since 46727 was 46593, checked in by vboxsync, 12 years ago

updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.0 KB
Line 
1/* $Id: symlink-win.cpp 46593 2013-06-17 14:32:51Z vboxsync $ */
2/** @file
3 * IPRT - Symbolic Links, Windows.
4 */
5
6/*
7 * Copyright (C) 2010-2011 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP RTLOGGROUP_SYMLINK
32
33#include <iprt/symlink.h>
34
35#include <iprt/assert.h>
36#include <iprt/err.h>
37#include <iprt/log.h>
38#include <iprt/path.h>
39#include <iprt/mem.h>
40#include <iprt/string.h>
41#include "internal/path.h"
42
43#include <Windows.h>
44#include "../init.h"
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50typedef struct MY_REPARSE_DATA_BUFFER
51{
52 ULONG ReparseTag;
53#define MY_IO_REPARSE_TAG_SYMLINK 0xa000000c
54#define MY_IO_REPARSE_TAG_MOUNT_POINT 0xa0000003
55
56 USHORT ReparseDataLength;
57 USHORT Reserved;
58 union
59 {
60 struct
61 {
62 USHORT SubstituteNameOffset;
63 USHORT SubstituteNameLength;
64 USHORT PrintNameOffset;
65 USHORT PrintNameLength;
66 ULONG Flags;
67#define MY_SYMLINK_FLAG_RELATIVE 1
68 WCHAR PathBuffer[1];
69 } SymbolicLinkReparseBuffer;
70 struct
71 {
72 USHORT SubstituteNameOffset;
73 USHORT SubstituteNameLength;
74 USHORT PrintNameOffset;
75 USHORT PrintNameLength;
76 WCHAR PathBuffer[1];
77 } MountPointReparseBuffer;
78 struct
79 {
80 UCHAR DataBuffer[1];
81 } GenericReparseBuffer;
82 };
83} MY_REPARSE_DATA_BUFFER;
84#define MY_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
85
86
87RTDECL(bool) RTSymlinkExists(const char *pszSymlink)
88{
89 bool fRc = false;
90 RTFSOBJINFO ObjInfo;
91 int rc = RTPathQueryInfoEx(pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
92 if (RT_SUCCESS(rc))
93 fRc = RTFS_IS_SYMLINK(ObjInfo.Attr.fMode);
94
95 LogFlow(("RTSymlinkExists(%p={%s}): returns %RTbool\n", pszSymlink, pszSymlink, fRc));
96 return fRc;
97}
98
99
100RTDECL(bool) RTSymlinkIsDangling(const char *pszSymlink)
101{
102 bool fRc = false;
103 RTFSOBJINFO ObjInfo;
104 int rc = RTPathQueryInfoEx(pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
105 if (RT_SUCCESS(rc))
106 {
107 fRc = RTFS_IS_SYMLINK(ObjInfo.Attr.fMode);
108 if (fRc)
109 {
110 rc = RTPathQueryInfoEx(pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
111 fRc = !RT_SUCCESS_NP(rc);
112 }
113 }
114
115 LogFlow(("RTSymlinkIsDangling(%p={%s}): returns %RTbool\n", pszSymlink, pszSymlink, fRc));
116 return fRc;
117}
118
119
120RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, RTSYMLINKTYPE enmType, uint32_t fCreate)
121{
122 /*
123 * Validate the input.
124 */
125 AssertReturn(enmType > RTSYMLINKTYPE_INVALID && enmType < RTSYMLINKTYPE_END, VERR_INVALID_PARAMETER);
126 AssertPtrReturn(pszSymlink, VERR_INVALID_POINTER);
127 AssertPtrReturn(pszTarget, VERR_INVALID_POINTER);
128
129 /*
130 * Resolve the API.
131 */
132 typedef BOOLEAN (WINAPI *PFNCREATESYMBOLICLINKW)(LPCWSTR, LPCWSTR, DWORD);
133 static PFNCREATESYMBOLICLINKW s_pfnCreateSymbolicLinkW = NULL;
134 static bool s_fTried = FALSE;
135 if (!s_fTried)
136 {
137 PFNCREATESYMBOLICLINKW pfn = (PFNCREATESYMBOLICLINKW)GetProcAddress(g_hModKernel32, "CreateSymbolicLinkW");
138 if (pfn)
139 s_pfnCreateSymbolicLinkW = pfn;
140 s_fTried = true;
141 }
142 if (!s_pfnCreateSymbolicLinkW)
143 {
144 LogFlow(("RTSymlinkCreate(%p={%s}, %p={%s}, %d, %#x): returns VERR_NOT_SUPPORTED - Windows API not found\n",
145 pszSymlink, pszSymlink, pszTarget, pszTarget, enmType, fCreate));
146 return VERR_NOT_SUPPORTED;
147 }
148
149 /*
150 * Convert the paths.
151 */
152 PRTUTF16 pwszNativeSymlink;
153 int rc = RTStrToUtf16(pszSymlink, &pwszNativeSymlink);
154 if (RT_SUCCESS(rc))
155 {
156 PRTUTF16 pwszNativeTarget;
157 rc = RTStrToUtf16(pszTarget, &pwszNativeTarget);
158 if (RT_SUCCESS(rc))
159 {
160 /*
161 * Massage the target path, determin the link type.
162 */
163 size_t cchTarget = strlen(pszTarget);
164 size_t cchVolSpecTarget = rtPathVolumeSpecLen(pszTarget);
165#if 0 /* looks like this isn't needed after all. That makes everything much simper :-) */
166 if ( cchTarget > RT_MIN(cchVolSpecTarget, 1)
167 && RTPATH_IS_SLASH(pszTarget[cchTarget - 1]))
168 {
169 size_t cwcNativeTarget = RTUtf16Len(pwszNativeTarget);
170 size_t offFromEnd = 1;
171 while ( offFromEnd < cchTarget
172 && cchTarget - offFromEnd >= cchVolSpecTarget
173 && RTPATH_IS_SLASH(pszTarget[cchTarget - offFromEnd]))
174 {
175 Assert(offFromEnd < cwcNativeTarget);
176 pwszNativeTarget[cwcNativeTarget - offFromEnd] = 0;
177 offFromEnd++;
178 }
179 }
180#endif
181
182 if (enmType == RTSYMLINKTYPE_UNKNOWN)
183 {
184 if ( cchTarget > cchVolSpecTarget
185 && RTPATH_IS_SLASH(pszTarget[cchTarget - 1]))
186 enmType = RTSYMLINKTYPE_DIR;
187 else if (cchVolSpecTarget)
188 {
189 /** @todo this is subject to sharing violations. */
190 DWORD dwAttr = GetFileAttributesW(pwszNativeTarget);
191 if ( dwAttr != INVALID_FILE_ATTRIBUTES
192 && (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
193 enmType = RTSYMLINKTYPE_DIR;
194 }
195 else
196 {
197 /** @todo Join the symlink directory with the target and
198 * look up the attributes on that. -lazy bird. */
199 }
200 }
201
202 /*
203 * Create the link.
204 */
205 if (s_pfnCreateSymbolicLinkW(pwszNativeSymlink, pwszNativeTarget, enmType == RTSYMLINKTYPE_DIR))
206 rc = VINF_SUCCESS;
207 else
208 rc = RTErrConvertFromWin32(GetLastError());
209
210 RTUtf16Free(pwszNativeTarget);
211 }
212 RTUtf16Free(pwszNativeSymlink);
213 }
214
215 LogFlow(("RTSymlinkCreate(%p={%s}, %p={%s}, %d, %#x): returns %Rrc\n", pszSymlink, pszSymlink, pszTarget, pszTarget, enmType, fCreate, rc));
216 return rc;
217}
218
219
220RTDECL(int) RTSymlinkDelete(const char *pszSymlink, uint32_t fDelete)
221{
222 /*
223 * Convert the path.
224 */
225 PRTUTF16 pwszNativeSymlink;
226 int rc = RTStrToUtf16(pszSymlink, &pwszNativeSymlink);
227 if (RT_SUCCESS(rc))
228 {
229 /*
230 * We have to use different APIs depending on whether this is a
231 * directory or file link. This means we're subject to one more race
232 * than on posix at the moment. We could probably avoid this though,
233 * if we wanted to go talk with the native API layer below Win32...
234 */
235 DWORD dwAttr = GetFileAttributesW(pwszNativeSymlink);
236 if (dwAttr != INVALID_FILE_ATTRIBUTES)
237 {
238 if (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT)
239 {
240 BOOL fRc;
241 if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
242 fRc = RemoveDirectoryW(pwszNativeSymlink);
243 else
244 fRc = DeleteFileW(pwszNativeSymlink);
245 if (fRc)
246 rc = VINF_SUCCESS;
247 else
248 rc = RTErrConvertFromWin32(GetLastError());
249 }
250 else
251 rc = VERR_NOT_SYMLINK;
252 }
253 else
254 rc = RTErrConvertFromWin32(GetLastError());
255 RTUtf16Free(pwszNativeSymlink);
256 }
257
258 LogFlow(("RTSymlinkDelete(%p={%s}, %#x): returns %Rrc\n", pszSymlink, pszSymlink, fDelete, rc));
259 return rc;
260}
261
262
263RTDECL(int) RTSymlinkRead(const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead)
264{
265 char *pszMyTarget;
266 int rc = RTSymlinkReadA(pszSymlink, &pszMyTarget);
267 if (RT_SUCCESS(rc))
268 {
269 rc = RTStrCopy(pszTarget, cbTarget, pszMyTarget);
270 RTStrFree(pszMyTarget);
271 }
272 LogFlow(("RTSymlinkRead(%p={%s}): returns %Rrc\n", pszSymlink, pszSymlink, rc));
273 return rc;
274}
275
276
277RTDECL(int) RTSymlinkReadA(const char *pszSymlink, char **ppszTarget)
278{
279 AssertPtr(ppszTarget);
280 PRTUTF16 pwszNativeSymlink;
281 int rc = RTStrToUtf16(pszSymlink, &pwszNativeSymlink);
282 if (RT_SUCCESS(rc))
283 {
284 HANDLE hSymlink = CreateFileW(pwszNativeSymlink,
285 GENERIC_READ,
286 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
287 NULL,
288 OPEN_EXISTING,
289 FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
290 NULL);
291 if (hSymlink != INVALID_HANDLE_VALUE)
292 {
293 DWORD cbReturned = 0;
294 union
295 {
296 MY_REPARSE_DATA_BUFFER Buf;
297 uint8_t abBuf[16*_1K + sizeof(WCHAR)];
298 } u;
299 if (DeviceIoControl(hSymlink,
300 MY_FSCTL_GET_REPARSE_POINT,
301 NULL /*pInBuffer */,
302 0 /*cbInBuffer */,
303 &u.Buf,
304 sizeof(u) - sizeof(WCHAR),
305 &cbReturned,
306 NULL /*pOverlapped*/))
307 {
308 if (u.Buf.ReparseTag == MY_IO_REPARSE_TAG_SYMLINK)
309 {
310 PWCHAR pwszTarget = &u.Buf.SymbolicLinkReparseBuffer.PathBuffer[0];
311 pwszTarget += u.Buf.SymbolicLinkReparseBuffer.SubstituteNameOffset / 2;
312 pwszTarget[u.Buf.SymbolicLinkReparseBuffer.SubstituteNameLength / 2] = 0;
313 if ( !(u.Buf.SymbolicLinkReparseBuffer.Flags & MY_SYMLINK_FLAG_RELATIVE)
314 && pwszTarget[0] == '\\'
315 && pwszTarget[1] == '?'
316 && pwszTarget[2] == '?'
317 && pwszTarget[3] == '\\'
318 && pwszTarget[4] != 0
319 )
320 pwszTarget += 4;
321 rc = RTUtf16ToUtf8(pwszTarget, ppszTarget);
322 }
323 else
324 rc = VERR_NOT_SYMLINK;
325 }
326 else
327 rc = RTErrConvertFromWin32(GetLastError());
328 CloseHandle(hSymlink);
329 }
330 else
331 rc = RTErrConvertFromWin32(GetLastError());
332 RTUtf16Free(pwszNativeSymlink);
333 }
334
335 if (RT_SUCCESS(rc))
336 LogFlow(("RTSymlinkReadA(%p={%s},%p): returns %Rrc *ppszTarget=%p:{%s}\n", pszSymlink, pszSymlink, ppszTarget, rc, *ppszTarget, *ppszTarget));
337 else
338 LogFlow(("RTSymlinkReadA(%p={%s},%p): returns %Rrc\n", pszSymlink, pszSymlink, ppszTarget, rc));
339 return rc;
340}
341
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette