~ubuntu-branches/ubuntu/raring/virtualbox-ose/raring

« back to all changes in this revision

Viewing changes to src/VBox/Runtime/r3/win/symlink-win.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Felix Geyer
  • Date: 2011-01-30 23:27:25 UTC
  • mfrom: (0.3.12 upstream)
  • Revision ID: james.westby@ubuntu.com-20110130232725-2ouajjd2ggdet0zd
Tags: 4.0.2-dfsg-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Add Apport hook.
    - debian/virtualbox-ose.files/source_virtualbox-ose.py
    - debian/virtualbox-ose.install
  - Drop *-source packages.
* Drop ubuntu-01-fix-build-gcc45.patch, fixed upstream.
* Drop ubuntu-02-as-needed.patch, added to the Debian package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: symlink-win.cpp 33437 2010-10-25 16:28:14Z vboxsync $ */
 
2
/** @file
 
3
 * IPRT - Symbolic Links, Windows.
 
4
 */
 
5
 
 
6
/*
 
7
 * Copyright (C) 2010 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
 
 
45
 
 
46
/*******************************************************************************
 
47
*   Structures and Typedefs                                                    *
 
48
*******************************************************************************/
 
49
typedef struct MY_REPARSE_DATA_BUFFER
 
50
{
 
51
    ULONG           ReparseTag;
 
52
#define MY_IO_REPARSE_TAG_SYMLINK       0xa000000c
 
53
#define MY_IO_REPARSE_TAG_MOUNT_POINT   0xa0000003
 
54
 
 
55
    USHORT          ReparseDataLength;
 
56
    USHORT          Reserved;
 
57
    union
 
58
    {
 
59
        struct
 
60
        {
 
61
            USHORT  SubstituteNameOffset;
 
62
            USHORT  SubstituteNameLength;
 
63
            USHORT  PrintNameOffset;
 
64
            USHORT  PrintNameLength;
 
65
            ULONG   Flags;
 
66
#define MY_SYMLINK_FLAG_RELATIVE 1
 
67
            WCHAR   PathBuffer[1];
 
68
        } SymbolicLinkReparseBuffer;
 
69
        struct
 
70
        {
 
71
            USHORT  SubstituteNameOffset;
 
72
            USHORT  SubstituteNameLength;
 
73
            USHORT  PrintNameOffset;
 
74
            USHORT  PrintNameLength;
 
75
            WCHAR   PathBuffer[1];
 
76
        } MountPointReparseBuffer;
 
77
        struct
 
78
        {
 
79
            UCHAR   DataBuffer[1];
 
80
        } GenericReparseBuffer;
 
81
    };
 
82
} MY_REPARSE_DATA_BUFFER;
 
83
#define MY_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS)
 
84
 
 
85
 
 
86
RTDECL(bool) RTSymlinkExists(const char *pszSymlink)
 
87
{
 
88
    bool        fRc = false;
 
89
    RTFSOBJINFO ObjInfo;
 
90
    int rc = RTPathQueryInfoEx(pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
 
91
    if (RT_SUCCESS(rc))
 
92
        fRc = RTFS_IS_SYMLINK(ObjInfo.Attr.fMode);
 
93
 
 
94
    LogFlow(("RTSymlinkExists(%p={%s}): returns %RTbool\n", pszSymlink, pszSymlink, fRc));
 
95
    return fRc;
 
96
}
 
97
 
 
98
 
 
99
RTDECL(bool) RTSymlinkIsDangling(const char *pszSymlink)
 
100
{
 
101
    bool        fRc = false;
 
102
    RTFSOBJINFO ObjInfo;
 
103
    int rc = RTPathQueryInfoEx(pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
 
104
    if (RT_SUCCESS(rc))
 
105
    {
 
106
        fRc = RTFS_IS_SYMLINK(ObjInfo.Attr.fMode);
 
107
        if (fRc)
 
108
        {
 
109
            rc = RTPathQueryInfoEx(pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
 
110
            fRc = !RT_SUCCESS_NP(rc);
 
111
        }
 
112
    }
 
113
 
 
114
    LogFlow(("RTSymlinkIsDangling(%p={%s}): returns %RTbool\n", pszSymlink, pszSymlink, fRc));
 
115
    return fRc;
 
116
}
 
117
 
 
118
 
 
119
RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, RTSYMLINKTYPE enmType)
 
120
{
 
121
    /*
 
122
     * Validate the input.
 
123
     */
 
124
    AssertReturn(enmType > RTSYMLINKTYPE_INVALID && enmType < RTSYMLINKTYPE_END, VERR_INVALID_PARAMETER);
 
125
    AssertPtrReturn(pszSymlink, VERR_INVALID_POINTER);
 
126
    AssertPtrReturn(pszTarget, VERR_INVALID_POINTER);
 
127
 
 
128
    /*
 
129
     * Resolve the API.
 
130
     */
 
131
    typedef BOOLEAN (WINAPI *PFNCREATESYMBOLICLINKW)(LPCWSTR, LPCWSTR, DWORD);
 
132
    static PFNCREATESYMBOLICLINKW   s_pfnCreateSymbolicLinkW = NULL;
 
133
    static bool                     s_fTried = FALSE;
 
134
    if (!s_fTried)
 
135
    {
 
136
        HMODULE hmod = LoadLibrary("KERNEL32.DLL");
 
137
        if (hmod)
 
138
        {
 
139
            PFNCREATESYMBOLICLINKW pfn = (PFNCREATESYMBOLICLINKW)GetProcAddress(hmod, "CreateSymbolicLinkW");
 
140
            if (pfn)
 
141
                s_pfnCreateSymbolicLinkW = pfn;
 
142
        }
 
143
        s_fTried = true;
 
144
    }
 
145
    if (!s_pfnCreateSymbolicLinkW)
 
146
    {
 
147
        LogFlow(("RTSymlinkCreate(%p={%s}, %p={%s}, %d): returns VERR_NOT_SUPPORTED - Windows API not found\n",
 
148
                 pszSymlink, pszSymlink, pszTarget, pszTarget, enmType));
 
149
        return VERR_NOT_SUPPORTED;
 
150
    }
 
151
 
 
152
    /*
 
153
     * Convert the paths.
 
154
     */
 
155
    PRTUTF16 pwszNativeSymlink;
 
156
    int rc = RTStrToUtf16(pszSymlink, &pwszNativeSymlink);
 
157
    if (RT_SUCCESS(rc))
 
158
    {
 
159
        PRTUTF16 pwszNativeTarget;
 
160
        rc = RTStrToUtf16(pszTarget, &pwszNativeTarget);
 
161
        if (RT_SUCCESS(rc))
 
162
        {
 
163
            /*
 
164
             * Massage the target path, determin the link type.
 
165
             */
 
166
            size_t cchTarget        = strlen(pszTarget);
 
167
            size_t cchVolSpecTarget = rtPathVolumeSpecLen(pszTarget);
 
168
#if 0 /* looks like this isn't needed after all. That makes everything much simper :-) */
 
169
            if (   cchTarget > RT_MIN(cchVolSpecTarget, 1)
 
170
                && RTPATH_IS_SLASH(pszTarget[cchTarget - 1]))
 
171
            {
 
172
                size_t cwcNativeTarget = RTUtf16Len(pwszNativeTarget);
 
173
                size_t offFromEnd = 1;
 
174
                while (   offFromEnd < cchTarget
 
175
                       && cchTarget - offFromEnd >= cchVolSpecTarget
 
176
                       && RTPATH_IS_SLASH(pszTarget[cchTarget - offFromEnd]))
 
177
                {
 
178
                    Assert(offFromEnd < cwcNativeTarget);
 
179
                    pwszNativeTarget[cwcNativeTarget - offFromEnd] = 0;
 
180
                    offFromEnd++;
 
181
                }
 
182
            }
 
183
#endif
 
184
 
 
185
            if (enmType == RTSYMLINKTYPE_UNKNOWN)
 
186
            {
 
187
                if (   cchTarget > cchVolSpecTarget
 
188
                    && RTPATH_IS_SLASH(pszTarget[cchTarget - 1]))
 
189
                    enmType = RTSYMLINKTYPE_DIR;
 
190
                else if (cchVolSpecTarget)
 
191
                {
 
192
                    /** @todo this is subject to sharing violations. */
 
193
                    DWORD dwAttr = GetFileAttributesW(pwszNativeTarget);
 
194
                    if (   dwAttr != INVALID_FILE_ATTRIBUTES
 
195
                        && (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
 
196
                        enmType = RTSYMLINKTYPE_DIR;
 
197
                }
 
198
                else
 
199
                {
 
200
                    /** @todo Join the symlink directory with the target and
 
201
                     *        look up the attributes on that. -lazy bird. */
 
202
                }
 
203
            }
 
204
 
 
205
            /*
 
206
             * Create the link.
 
207
             */
 
208
            if (s_pfnCreateSymbolicLinkW(pwszNativeSymlink, pwszNativeTarget, enmType == RTSYMLINKTYPE_DIR))
 
209
                rc = VINF_SUCCESS;
 
210
            else
 
211
                rc = RTErrConvertFromWin32(GetLastError());
 
212
 
 
213
            RTUtf16Free(pwszNativeTarget);
 
214
        }
 
215
        RTUtf16Free(pwszNativeSymlink);
 
216
    }
 
217
 
 
218
    LogFlow(("RTSymlinkCreate(%p={%s}, %p={%s}, %d): returns %Rrc\n", pszSymlink, pszSymlink, pszTarget, pszTarget, enmType, rc));
 
219
    return rc;
 
220
}
 
221
 
 
222
 
 
223
RTDECL(int) RTSymlinkDelete(const char *pszSymlink)
 
224
{
 
225
    /*
 
226
     * Convert the path.
 
227
     */
 
228
    PRTUTF16 pwszNativeSymlink;
 
229
    int rc = RTStrToUtf16(pszSymlink, &pwszNativeSymlink);
 
230
    if (RT_SUCCESS(rc))
 
231
    {
 
232
        /*
 
233
         * We have to use different APIs depending on whether this is a
 
234
         * directory or file link.  This means we're subject to one more race
 
235
         * than on posix at the moment.  We could probably avoid this though,
 
236
         * if we wanted to go talk with the native API layer below Win32...
 
237
         */
 
238
        DWORD dwAttr = GetFileAttributesW(pwszNativeSymlink);
 
239
        if (dwAttr != INVALID_FILE_ATTRIBUTES)
 
240
        {
 
241
            if (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT)
 
242
            {
 
243
                BOOL fRc;
 
244
                if (dwAttr & FILE_ATTRIBUTE_DIRECTORY)
 
245
                    fRc = RemoveDirectoryW(pwszNativeSymlink);
 
246
                else
 
247
                    fRc = DeleteFileW(pwszNativeSymlink);
 
248
                if (fRc)
 
249
                    rc = VINF_SUCCESS;
 
250
                else
 
251
                    rc = RTErrConvertFromWin32(GetLastError());
 
252
            }
 
253
            else
 
254
                rc = VERR_NOT_SYMLINK;
 
255
        }
 
256
        else
 
257
            rc = RTErrConvertFromWin32(GetLastError());
 
258
        RTUtf16Free(pwszNativeSymlink);
 
259
    }
 
260
 
 
261
    LogFlow(("RTSymlinkDelete(%p={%s}): returns %Rrc\n", pszSymlink, pszSymlink, rc));
 
262
    return rc;
 
263
}
 
264
 
 
265
 
 
266
RTDECL(int) RTSymlinkRead(const char *pszSymlink, char *pszTarget, size_t cbTarget)
 
267
{
 
268
    char *pszMyTarget;
 
269
    int rc = RTSymlinkReadA(pszSymlink, &pszMyTarget);
 
270
    if (RT_SUCCESS(rc))
 
271
    {
 
272
        rc = RTStrCopy(pszTarget, cbTarget, pszMyTarget);
 
273
        RTStrFree(pszMyTarget);
 
274
    }
 
275
    LogFlow(("RTSymlinkRead(%p={%s}): returns %Rrc\n", pszSymlink, pszSymlink, rc));
 
276
    return rc;
 
277
}
 
278
 
 
279
 
 
280
RTDECL(int) RTSymlinkReadA(const char *pszSymlink, char **ppszTarget)
 
281
{
 
282
    AssertPtr(ppszTarget);
 
283
    PRTUTF16 pwszNativeSymlink;
 
284
    int rc = RTStrToUtf16(pszSymlink, &pwszNativeSymlink);
 
285
    if (RT_SUCCESS(rc))
 
286
    {
 
287
        HANDLE hSymlink = CreateFileW(pwszNativeSymlink,
 
288
                                      GENERIC_READ,
 
289
                                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
 
290
                                      NULL,
 
291
                                      OPEN_EXISTING,
 
292
                                      FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
 
293
                                      NULL);
 
294
        if (hSymlink != INVALID_HANDLE_VALUE)
 
295
        {
 
296
            DWORD cbReturned = 0;
 
297
            union
 
298
            {
 
299
                MY_REPARSE_DATA_BUFFER  Buf;
 
300
                uint8_t                 abBuf[16*_1K + sizeof(WCHAR)];
 
301
            } u;
 
302
            if (DeviceIoControl(hSymlink,
 
303
                                MY_FSCTL_GET_REPARSE_POINT,
 
304
                                NULL /*pInBuffer */,
 
305
                                0 /*cbInBuffer */,
 
306
                                &u.Buf,
 
307
                                sizeof(u) - sizeof(WCHAR),
 
308
                                &cbReturned,
 
309
                                NULL /*pOverlapped*/))
 
310
            {
 
311
                if (u.Buf.ReparseTag == MY_IO_REPARSE_TAG_SYMLINK)
 
312
                {
 
313
                    PWCHAR pwszTarget = &u.Buf.SymbolicLinkReparseBuffer.PathBuffer[0];
 
314
                    pwszTarget += u.Buf.SymbolicLinkReparseBuffer.SubstituteNameOffset / 2;
 
315
                    pwszTarget[u.Buf.SymbolicLinkReparseBuffer.SubstituteNameLength / 2] = 0;
 
316
                    if (   !(u.Buf.SymbolicLinkReparseBuffer.Flags & MY_SYMLINK_FLAG_RELATIVE)
 
317
                        && pwszTarget[0] == '\\'
 
318
                        && pwszTarget[1] == '?'
 
319
                        && pwszTarget[2] == '?'
 
320
                        && pwszTarget[3] == '\\'
 
321
                        && pwszTarget[4] != 0
 
322
                       )
 
323
                        pwszTarget += 4;
 
324
                    rc = RTUtf16ToUtf8(pwszTarget, ppszTarget);
 
325
                }
 
326
                else
 
327
                    rc = VERR_NOT_SYMLINK;
 
328
            }
 
329
            else
 
330
                rc = RTErrConvertFromWin32(GetLastError());
 
331
            CloseHandle(hSymlink);
 
332
        }
 
333
        else
 
334
            rc = RTErrConvertFromWin32(GetLastError());
 
335
        RTUtf16Free(pwszNativeSymlink);
 
336
    }
 
337
 
 
338
    if (RT_SUCCESS(rc))
 
339
        LogFlow(("RTSymlinkReadA(%p={%s},%p): returns %Rrc *ppszTarget=%p:{%s}\n", pszSymlink, pszSymlink, ppszTarget, rc, *ppszTarget, *ppszTarget));
 
340
    else
 
341
        LogFlow(("RTSymlinkReadA(%p={%s},%p): returns %Rrc\n", pszSymlink, pszSymlink, ppszTarget, rc));
 
342
    return rc;
 
343
}
 
344