VirtualBox

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

最後變更 在這個檔案從75881是 74462,由 vboxsync 提交於 6 年 前

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

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