VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/pathint-win.cpp@ 74461

最後變更 在這個檔案從74461是 74461,由 vboxsync 提交於 7 年 前

IPRT: Implemented long filename support for windows (except for LoadLibrary). bugref:9248 [build fix]

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 7.3 KB
 
1/* $Id: pathint-win.cpp 74461 2018-09-25 15:55:40Z vboxsync $ */
2/** @file
3 * IPRT - Windows, Internal Path stuff.
4 */
5
6/*
7 * Copyright (C) 2006-2018 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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_FS
32#include <iprt/path.h>
33
34#include <iprt/assert.h>
35#include <iprt/ctype.h>
36#include <iprt/err.h>
37#include <iprt/string.h>
38
39#include <iprt/nt/nt-and-windows.h>
40
41/*********************************************************************************************************************************
42* Defined Constants And Macros *
43*********************************************************************************************************************************/
44/** The max number of non-null characters we pass to an Win32 API.
45 * You would think that MAX_PATH gives this length, however CreateDirectoryW was
46 * found to fail on Windows 10 (1803++) if given a perfectly formed path argument
47 * of 248 or more characters. Same when going thru UNC.
48 *
49 * So, to be conservative, we put the max number of characters in a non-\\?\
50 * path to 243, not counting the terminator.
51 */
52#define ACTUAL_MAX_PATH 243
53
54
55DECL_NO_INLINE(static, bool) rtPathWinTryConvertToAbs(PRTUTF16 *ppwszPath)
56{
57 RTUTF16 wszFullPath[MAX_PATH + 1];
58 DWORD cwcFull = GetFullPathNameW(*ppwszPath, MAX_PATH + 1, wszFullPath, NULL);
59 if (cwcFull <= ACTUAL_MAX_PATH)
60 {
61 RTUtf16Free(*ppwszPath);
62 PRTUTF16 const pwszCopy = RTUtf16Dup(wszFullPath);
63 *ppwszPath = pwszCopy;
64 if (pwszCopy)
65 return true;
66 }
67 return false;
68}
69
70
71RTDECL(int) RTPathWinFromUtf8(PRTUTF16 *ppwszPath, const char *pszPath, uint32_t fFlags)
72{
73 Assert(fFlags == 0);
74 RT_NOREF(fFlags);
75
76 /*
77 * Do a straight conversion first.
78 */
79 *ppwszPath = NULL;
80 size_t cwcResult = 0;
81 int rc = RTStrToUtf16Ex(pszPath, RTSTR_MAX, ppwszPath, 0, &cwcResult);
82 if (RT_SUCCESS(rc))
83 {
84 /*
85 * Check the resulting length. This is straight forward for absolute
86 * paths, but gets complicated for relative ones.
87 */
88 if (cwcResult <= ACTUAL_MAX_PATH)
89 {
90 if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
91 {
92 if (RTPATH_IS_SLASH(pszPath[2]))
93 return VINF_SUCCESS;
94
95 /* Drive relative path. Found no simple way of getting the current
96 path of a drive, so we try convert it to an absolute path and see
97 how that works out. It is what the API we're calling will have to
98 do anyway, so this should perform just as well. */
99 if (rtPathWinTryConvertToAbs(ppwszPath))
100 return VINF_SUCCESS;
101 }
102 else if (RTPATH_IS_SLASH(pszPath[0]))
103 {
104 if ( RTPATH_IS_SLASH(pszPath[1])
105 && !RTPATH_IS_SLASH(pszPath[2])
106 && pszPath[2] != '\0')
107 {
108 /* Passthru prefix '\\?\' is fine. */
109 if ( pszPath[2] == '?'
110 && !RTPATH_IS_SLASH(pszPath[3]))
111 return VINF_SUCCESS;
112
113 /* UNC requires a longer prefix ('\??\UNC\' instead of '\??\'), so
114 subtract 3 chars from the max limit to be on the safe side. */
115 if (cwcResult <= ACTUAL_MAX_PATH - 3)
116 return VINF_SUCCESS;
117 }
118 else
119 {
120 /* Drive relative. Win32 will prepend a two letter drive specification. */
121 if (cwcResult <= ACTUAL_MAX_PATH - 2)
122 return VINF_SUCCESS;
123 }
124 }
125 else
126 {
127 /* Relative to CWD. We can use the API to get it's current length.
128 Any race conditions here is entirely the caller's problem. */
129 size_t cwcCwd = GetCurrentDirectoryW(0, NULL);
130 if (cwcCwd + cwcResult <= ACTUAL_MAX_PATH - 1)
131 return VINF_SUCCESS;
132 }
133 }
134 /*
135 * We're good if the caller already supplied the passthru/length prefix: '\\?\'
136 */
137 else if ( pszPath[1] == '?'
138 && RTPATH_IS_SLASH(pszPath[3])
139 && RTPATH_IS_SLASH(pszPath[1])
140 && RTPATH_IS_SLASH(pszPath[0]))
141 return VINF_SUCCESS;
142
143 /*
144 * Long path requiring \\?\ prefixing.
145 *
146 * We piggy back on the NT conversion here and ASSUME RTUtf16Free is the right
147 * way to free the result.
148 */
149 RTUtf16Free(*ppwszPath);
150 *ppwszPath = NULL;
151
152 struct _UNICODE_STRING NtName = { 0, 0, NULL };
153 HANDLE hRootDir = NULL;
154 rc = RTNtPathFromWinUtf8(&NtName, &hRootDir, pszPath);
155 if (RT_SUCCESS(rc))
156 {
157 /* No root dir handle. */
158 if (hRootDir == NULL)
159 {
160 /* Convert the NT '\??\' prefix to a win32 passthru prefix '\\?\' */
161 if ( NtName.Buffer[0] == '\\'
162 && NtName.Buffer[1] == '?'
163 && NtName.Buffer[2] == '?'
164 && NtName.Buffer[3] == '\\')
165 {
166 NtName.Buffer[1] = '\\';
167
168 /* Zero termination paranoia. */
169 if (NtName.Buffer[NtName.Length / sizeof(RTUTF16)] == '\0')
170 {
171 *ppwszPath = NtName.Buffer;
172 return VINF_SUCCESS;
173 }
174 AssertMsgFailed(("Length=%u %.*ls\n", NtName.Length, NtName.Length / sizeof(RTUTF16), NtName.Buffer));
175 }
176 else
177 AssertMsgFailed(("%ls\n", NtName.Buffer));
178 }
179 else
180 AssertMsgFailed(("%s\n", pszPath));
181 RTNtPathFree(&NtName, &hRootDir);
182 }
183 }
184 return rc;
185}
186
187
188RTDECL(void) RTPathWinFree(PRTUTF16 pwszPath)
189{
190 RTUtf16Free(pwszPath);
191}
192
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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