VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/nt/pathint-nt.cpp@ 58756

最後變更 在這個檔案從58756是 58440,由 vboxsync 提交於 9 年 前

Runtime: pathint-nt.cpp Win32 to NT path prefix conversion fix

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 18.7 KB
 
1/* $Id: pathint-nt.cpp 58440 2015-10-27 17:40:34Z vboxsync $ */
2/** @file
3 * IPRT - Native NT, Internal Path stuff.
4 */
5
6/*
7 * Copyright (C) 2006-2015 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 "internal-r3-nt.h"
33
34#include <iprt/path.h>
35#include <iprt/string.h>
36#include <iprt/err.h>
37#include <iprt/assert.h>
38
39
40/*********************************************************************************************************************************
41* Global Variables *
42*********************************************************************************************************************************/
43static char const g_szPrefixUnc[] = "\\??\\UNC\\";
44static char const g_szPrefix[] = "\\??\\";
45
46
47/**
48 * Handles the pass thru case for UTF-8 input.
49 * Win32 path uses "\\?\" prefix which is converted to "\??\" NT prefix.
50 *
51 * @returns IPRT status code.
52 * @param pNtName Where to return the NT name.
53 * @param phRootDir Where to return the root handle, if applicable.
54 * @param pszPath The UTF-8 path.
55 */
56static int rtNtPathFromWinUtf8PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
57{
58 PRTUTF16 pwszPath = NULL;
59 size_t cwcLen;
60 int rc = RTStrToUtf16Ex(pszPath, RTSTR_MAX, &pwszPath, 0, &cwcLen);
61 if (RT_SUCCESS(rc))
62 {
63 if (cwcLen < _32K - 1)
64 {
65 pwszPath[0] = '\\';
66 pwszPath[1] = '?';
67 pwszPath[2] = '?';
68 pwszPath[3] = '\\';
69
70 pNtName->Buffer = pwszPath;
71 pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
72 pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
73 *phRootDir = NULL;
74 return VINF_SUCCESS;
75 }
76
77 RTUtf16Free(pwszPath);
78 rc = VERR_FILENAME_TOO_LONG;
79 }
80 return rc;
81}
82
83
84/**
85 * Handles the pass thru case for UTF-16 input.
86 * Win32 path uses "\\?\" prefix which is converted to "\??\" NT prefix.
87 *
88 * @returns IPRT status code.
89 * @param pNtName Where to return the NT name.
90 * @param phRootDir Stores NULL here, as we don't use it.
91 * @param pwszWinPath The UTF-16 windows-style path.
92 * @param cwcWinPath The length of the windows-style input path.
93 */
94static int rtNtPathFromWinUtf16PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
95 PCRTUTF16 pwszWinPath, size_t cwcWinPath)
96{
97 /* Check length and allocate memory for it. */
98 int rc;
99 if (cwcWinPath < _32K - 1)
100 {
101 PRTUTF16 pwszNtPath = (PRTUTF16)RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
102 if (pwszNtPath)
103 {
104 /* Intialize the path. */
105 pwszNtPath[0] = '\\';
106 pwszNtPath[1] = '?';
107 pwszNtPath[2] = '?';
108 pwszNtPath[3] = '\\';
109 memcpy(pwszNtPath + 4, pwszWinPath + 4, (cwcWinPath - 4) * sizeof(RTUTF16));
110 pwszNtPath[cwcWinPath] = '\0';
111
112 /* Initialize the return values. */
113 pNtName->Buffer = pwszNtPath;
114 pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
115 pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
116 *phRootDir = NULL;
117
118 rc = VINF_SUCCESS;
119 }
120 else
121 rc = VERR_NO_UTF16_MEMORY;
122 }
123 else
124 rc = VERR_FILENAME_TOO_LONG;
125 return rc;
126}
127
128
129
130
131
132/**
133 * Converts the path to UTF-16 and sets all the return values.
134 *
135 * @returns IPRT status code.
136 * @param pNtName Where to return the NT name.
137 * @param phRootDir Where to return the root handle, if applicable.
138 * @param pszPath The UTF-8 path.
139 */
140static int rtNtPathUtf8ToUniStr(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
141{
142 PRTUTF16 pwszPath = NULL;
143 size_t cwcLen;
144 int rc = RTStrToUtf16Ex(pszPath, RTSTR_MAX, &pwszPath, 0, &cwcLen);
145 if (RT_SUCCESS(rc))
146 {
147 if (cwcLen < _32K - 1)
148 {
149 pNtName->Buffer = pwszPath;
150 pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
151 pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
152 *phRootDir = NULL;
153 return VINF_SUCCESS;
154 }
155
156 RTUtf16Free(pwszPath);
157 rc = VERR_FILENAME_TOO_LONG;
158 }
159 return rc;
160}
161
162
163/**
164 * Converts a path to NT format and encoding.
165 *
166 * @returns IPRT status code.
167 * @param pNtName Where to return the NT name.
168 * @param phRootDir Where to return the root handle, if applicable.
169 * @param pszPath The UTF-8 path.
170 */
171static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
172{
173 /*
174 * Very simple conversion of a win32-like path into an NT path.
175 */
176 const char *pszPrefix = g_szPrefix;
177 size_t cchPrefix = sizeof(g_szPrefix) - 1;
178 size_t cchSkip = 0;
179
180 if ( RTPATH_IS_SLASH(pszPath[0])
181 && RTPATH_IS_SLASH(pszPath[1])
182 && !RTPATH_IS_SLASH(pszPath[2])
183 && pszPath[2])
184 {
185 if ( pszPath[2] == '?'
186 && RTPATH_IS_SLASH(pszPath[3]))
187 return rtNtPathFromWinUtf8PassThru(pNtName, phRootDir, pszPath);
188
189#ifdef IPRT_WITH_NT_PATH_PASSTHRU
190 /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
191 if ( pszPath[2] == '!'
192 && RTPATH_IS_SLASH(pszPath[3]))
193 return rtNtPathUtf8ToUniStr(pNtName, phRootDir, pszPath + 3);
194#endif
195
196 if ( pszPath[2] == '.'
197 && RTPATH_IS_SLASH(pszPath[3]))
198 {
199 /*
200 * Device path.
201 * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
202 */
203 cchSkip = 4;
204 }
205 else
206 {
207 /* UNC */
208 pszPrefix = g_szPrefixUnc;
209 cchPrefix = sizeof(g_szPrefixUnc) - 1;
210 cchSkip = 2;
211 }
212 }
213
214 /*
215 * Straighten out all .. and uncessary . references and convert slashes.
216 */
217 char szPath[RTPATH_MAX];
218 int rc = RTPathAbs(pszPath, &szPath[cchPrefix - cchSkip], sizeof(szPath) - (cchPrefix - cchSkip));
219 if (RT_FAILURE(rc))
220 return rc;
221
222 /*
223 * Add prefix and convert it to UTF16.
224 */
225 memcpy(szPath, pszPrefix, cchPrefix);
226 return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szPath);
227}
228
229
230/**
231 * Converts a UTF-16 windows-style path to NT format.
232 *
233 * @returns IPRT status code.
234 * @param pNtName Where to return the NT name. Free using
235 * RTNtPathFree.
236 * @param phRootDir Where to return the root handle, if applicable.
237 * @param pwszWinPath The UTF-16 windows-style path.
238 * @param cwcWinPath The max length of the windows-style path in
239 * RTUTF16 units. Use RTSTR_MAX if unknown and @a
240 * pwszWinPath is correctly terminated.
241 */
242RTDECL(int) RTNtPathFromWinUtf16Ex(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir, PCRTUTF16 pwszWinPath, size_t cwcWinPath)
243{
244 /*
245 * Validate the input, calculating the correct length.
246 */
247 if (cwcWinPath == 0 || *pwszWinPath == '\0')
248 return VERR_INVALID_NAME;
249
250 RTUtf16NLenEx(pwszWinPath, cwcWinPath, &cwcWinPath);
251 int rc = RTUtf16ValidateEncodingEx(pwszWinPath, cwcWinPath, 0);
252 if (RT_FAILURE(rc))
253 return rc;
254
255 /*
256 * Very simple conversion of a win32-like path into an NT path.
257 */
258 const char *pszPrefix = g_szPrefix;
259 size_t cchPrefix = sizeof(g_szPrefix) - 1;
260 size_t cchSkip = 0;
261
262 if ( RTPATH_IS_SLASH(pwszWinPath[0])
263 && cwcWinPath >= 3
264 && RTPATH_IS_SLASH(pwszWinPath[1])
265 && !RTPATH_IS_SLASH(pwszWinPath[2]) )
266 {
267 if ( pwszWinPath[2] == '?'
268 && cwcWinPath >= 4
269 && RTPATH_IS_SLASH(pwszWinPath[3]))
270 return rtNtPathFromWinUtf16PassThru(pNtName, phRootDir, pwszWinPath, cwcWinPath);
271
272#ifdef IPRT_WITH_NT_PATH_PASSTHRU
273 /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
274 if ( pwszWinPath[2] == '!'
275 && cwcWinPath >= 4
276 && RTPATH_IS_SLASH(pwszWinPath[3]))
277 {
278 pwszWinPath += 3;
279 cwcWinPath -= 3;
280 if (cwcWinPath < _32K - 1)
281 {
282 PRTUTF16 pwszNtPath = RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
283 if (pwszNtPath)
284 {
285 memcpy(pwszNtPath, pwszWinPath, cwcWinPath * sizeof(RTUTF16));
286 pwszNtPath[cwcWinPath] = '\0';
287 pNtName->Buffer = pwszNtPath;
288 pNtName->Length = (uint16_t)(cwcWinPath * sizeof(RTUTF16));
289 pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
290 *phRootDir = NULL;
291 return VINF_SUCCESS;
292 }
293 rc = VERR_NO_UTF16_MEMORY;
294 }
295 else
296 rc = VERR_FILENAME_TOO_LONG;
297 return rc;
298 }
299#endif
300
301 if ( pwszWinPath[2] == '.'
302 && cwcWinPath >= 4
303 && RTPATH_IS_SLASH(pwszWinPath[3]))
304 {
305 /*
306 * Device path.
307 * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
308 */
309 cchSkip = 4;
310 }
311 else
312 {
313 /* UNC */
314 pszPrefix = g_szPrefixUnc;
315 cchPrefix = sizeof(g_szPrefixUnc) - 1;
316 cchSkip = 2;
317 }
318 }
319
320 /*
321 * Straighten out all .. and unnecessary . references and convert slashes.
322 */
323 char szAbsPath[RTPATH_MAX];
324 char szRelPath[RTPATH_MAX];
325 char *pszRelPath = szRelPath;
326 size_t cchRelPath;
327 rc = RTUtf16ToUtf8Ex(pwszWinPath, cwcWinPath, &pszRelPath, sizeof(szRelPath), &cchRelPath);
328 if (RT_SUCCESS(rc))
329 rc = RTPathAbs(szRelPath, &szAbsPath[cchPrefix - cchSkip], sizeof(szAbsPath) - (cchPrefix - cchSkip));
330 if (RT_SUCCESS(rc))
331 {
332 /*
333 * Add prefix and convert it to UTF16.
334 */
335 memcpy(szAbsPath, pszPrefix, cchPrefix);
336 return rtNtPathUtf8ToUniStr(pNtName, phRootDir, szAbsPath);
337 }
338 return rc;
339}
340
341
342/**
343 * Frees the native path and root handle.
344 *
345 * @param pNtName The NT path after a successful rtNtPathToNative
346 * call.
347 * @param phRootDir The root handle variable after a
348 * rtNtPathToNative.
349 */
350static void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
351{
352 RTUtf16Free(pNtName->Buffer);
353 pNtName->Buffer = NULL;
354}
355
356
357/**
358 * Frees the native path and root handle.
359 *
360 * @param pNtName The NT path after a successful
361 * RTNtPathFromWinUtf16Ex call.
362 * @param phRootDir The root handle variable after a successfull
363 * RTNtPathFromWinUtf16Ex call.
364 */
365RTDECL(void) RTNtPathFree(struct _UNICODE_STRING *pNtName, HANDLE *phRootDir)
366{
367 rtNtPathFreeNative(pNtName, phRootDir);
368}
369
370
371/**
372 * Wrapper around NtCreateFile.
373 *
374 * @returns IPRT status code.
375 * @param pszPath The UTF-8 path.
376 * @param fDesiredAccess See NtCreateFile.
377 * @param fFileAttribs See NtCreateFile.
378 * @param fShareAccess See NtCreateFile.
379 * @param fCreateDisposition See NtCreateFile.
380 * @param fCreateOptions See NtCreateFile.
381 * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see
382 * NtCreateFile and InitializeObjectAttributes.
383 * @param phHandle Where to return the handle.
384 * @param puAction Where to return the action taken. Optional.
385 */
386RTDECL(int) RTNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
387 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
388 PHANDLE phHandle, PULONG_PTR puAction)
389{
390 *phHandle = RTNT_INVALID_HANDLE_VALUE;
391
392 HANDLE hRootDir;
393 UNICODE_STRING NtName;
394 int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
395 if (RT_SUCCESS(rc))
396 {
397 HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
398 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
399 OBJECT_ATTRIBUTES ObjAttr;
400 InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
401
402 NTSTATUS rcNt = NtCreateFile(&hFile,
403 fDesiredAccess,
404 &ObjAttr,
405 &Ios,
406 NULL /* AllocationSize*/,
407 fFileAttribs,
408 fShareAccess,
409 fCreateDisposition,
410 fCreateOptions,
411 NULL /*EaBuffer*/,
412 0 /*EaLength*/);
413 if (NT_SUCCESS(rcNt))
414 {
415 if (puAction)
416 *puAction = Ios.Information;
417 *phHandle = hFile;
418 rc = VINF_SUCCESS;
419 }
420 else
421 rc = RTErrConvertFromNtStatus(rcNt);
422 rtNtPathFreeNative(&NtName, &hRootDir);
423 }
424 return rc;
425}
426
427
428/**
429 * Wrapper around NtCreateFile.
430 *
431 * @returns IPRT status code.
432 * @param pszPath The UTF-8 path.
433 * @param fDesiredAccess See NtCreateFile.
434 * @param fShareAccess See NtCreateFile.
435 * @param fCreateOptions See NtCreateFile.
436 * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see
437 * NtCreateFile and InitializeObjectAttributes.
438 * @param phHandle Where to return the handle.
439 * @param pfObjDir If not NULL, the variable pointed to will be set
440 * to @c true if we opened an object directory and
441 * @c false if we opened an directory file (normal
442 * directory).
443 */
444RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
445 ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
446{
447 *phHandle = RTNT_INVALID_HANDLE_VALUE;
448
449 HANDLE hRootDir;
450 UNICODE_STRING NtName;
451 int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
452 if (RT_SUCCESS(rc))
453 {
454 HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
455 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
456 OBJECT_ATTRIBUTES ObjAttr;
457 InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
458
459 NTSTATUS rcNt = NtCreateFile(&hFile,
460 fDesiredAccess,
461 &ObjAttr,
462 &Ios,
463 NULL /* AllocationSize*/,
464 FILE_ATTRIBUTE_NORMAL,
465 fShareAccess,
466 FILE_OPEN,
467 fCreateOptions,
468 NULL /*EaBuffer*/,
469 0 /*EaLength*/);
470 if (NT_SUCCESS(rcNt))
471 {
472 if (pfObjDir)
473 *pfObjDir = false;
474 *phHandle = hFile;
475 rc = VINF_SUCCESS;
476 }
477#ifdef IPRT_WITH_NT_PATH_PASSTHRU
478 else if ( pfObjDir
479 && (rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_OBJECT_TYPE_MISMATCH)
480 && RTPATH_IS_SLASH(pszPath[0])
481 && RTPATH_IS_SLASH(pszPath[1])
482 && pszPath[2] == '!'
483 && RTPATH_IS_SLASH(pszPath[3]))
484 {
485 /* Strip trailing slash. */
486 if ( NtName.Length > 2
487 && RTPATH_IS_SLASH(NtName.Buffer[(NtName.Length / 2) - 1]))
488 NtName.Length -= 2;
489
490 /* Rought conversion of the access flags. */
491 ULONG fObjDesiredAccess = 0;
492 if (fDesiredAccess & (GENERIC_ALL | STANDARD_RIGHTS_ALL))
493 fObjDesiredAccess = DIRECTORY_ALL_ACCESS;
494 else
495 {
496 if (fDesiredAccess & (FILE_GENERIC_WRITE | GENERIC_WRITE | STANDARD_RIGHTS_WRITE))
497 fObjDesiredAccess |= DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_OBJECT;
498 if ( (fDesiredAccess & (FILE_LIST_DIRECTORY | FILE_GENERIC_READ | GENERIC_READ | STANDARD_RIGHTS_READ))
499 || !fObjDesiredAccess)
500 fObjDesiredAccess |= DIRECTORY_QUERY | FILE_LIST_DIRECTORY;
501 }
502
503 rcNt = NtOpenDirectoryObject(&hFile, fObjDesiredAccess, &ObjAttr);
504 if (NT_SUCCESS(rcNt))
505 {
506 *pfObjDir = true;
507 *phHandle = hFile;
508 rc = VINF_SUCCESS;
509 }
510 else
511 rc = RTErrConvertFromNtStatus(rcNt);
512 }
513#endif
514 else
515 rc = RTErrConvertFromNtStatus(rcNt);
516 rtNtPathFreeNative(&NtName, &hRootDir);
517 }
518 return rc;
519}
520
521
522/**
523 * Closes an handled open by rtNtPathOpen.
524 *
525 * @returns IPRT status code
526 * @param hHandle The handle value.
527 */
528RTDECL(int) RTNtPathClose(HANDLE hHandle)
529{
530 NTSTATUS rcNt = NtClose(hHandle);
531 if (NT_SUCCESS(rcNt))
532 return VINF_SUCCESS;
533 return RTErrConvertFromNtStatus(rcNt);
534}
535
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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