VirtualBox

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

Last change on this file since 54961 was 52953, checked in by vboxsync, 10 years ago

SUP: Use LdrRegisterDllNotification when available to make sure we see all DLLs and get a chance to restore our NtDll hooks.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.3 KB
Line 
1/* $Id: pathint-nt.cpp 52953 2014-10-06 13:30:20Z vboxsync $ */
2/** @file
3 * IPRT - Native NT, Internal Path stuff.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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_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 *
50 * @returns IPRT status code.
51 * @param pNtName Where to return the NT name.
52 * @param phRootDir Where to return the root handle, if applicable.
53 * @param pszPath The UTF-8 path.
54 */
55static int rtNtPathFromWinUtf8PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
56{
57 PRTUTF16 pwszPath = NULL;
58 size_t cwcLen;
59 int rc = RTStrToUtf16Ex(pszPath + 1, RTSTR_MAX, &pwszPath, 0, &cwcLen);
60 if (RT_SUCCESS(rc))
61 {
62 if (cwcLen < _32K - 1)
63 {
64 pwszPath[0] = '\\';
65 pwszPath[1] = '.';
66 pwszPath[2] = '\\';
67
68 pNtName->Buffer = pwszPath;
69 pNtName->Length = (uint16_t)(cwcLen * sizeof(RTUTF16));
70 pNtName->MaximumLength = pNtName->Length + sizeof(RTUTF16);
71 *phRootDir = NULL;
72 return VINF_SUCCESS;
73 }
74
75 RTUtf16Free(pwszPath);
76 rc = VERR_FILENAME_TOO_LONG;
77 }
78 return rc;
79}
80
81
82/**
83 * Handles the pass thru case for UTF-16 input.
84 *
85 * @returns IPRT status code.
86 * @param pNtName Where to return the NT name.
87 * @param phRootDir Stores NULL here, as we don't use it.
88 * @param pwszWinPath The UTF-16 windows-style path.
89 * @param cwcWinPath The length of the windows-style input path.
90 */
91static int rtNtPathFromWinUtf16PassThru(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir,
92 PCRTUTF16 pwszWinPath, size_t cwcWinPath)
93{
94 /* Drop a character because: \\?\ -> \.\ */
95 pwszWinPath++;
96 cwcWinPath--;
97
98 /* Check length and allocate memory for it. */
99 int rc;
100 if (cwcWinPath < _32K - 1)
101 {
102 PRTUTF16 pwszNtPath = (PRTUTF16)RTUtf16Alloc((cwcWinPath + 1) * sizeof(RTUTF16));
103 if (pwszNtPath)
104 {
105 /* Intialize the path. */
106 pwszNtPath[0] = '\\';
107 pwszNtPath[1] = '.';
108 pwszNtPath[2] = '\\';
109 memcpy(pwszNtPath + 3, pwszWinPath + 3, (cwcWinPath - 3) * 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 fFileAttribs See NtCreateFile.
435 * @param fShareAccess See NtCreateFile.
436 * @param fCreateDisposition See NtCreateFile.
437 * @param fCreateOptions See NtCreateFile.
438 * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see
439 * NtCreateFile and InitializeObjectAttributes.
440 * @param phHandle Where to return the handle.
441 * @param pfObjDir If not NULL, the variable pointed to will be set
442 * to @c true if we opened an object directory and
443 * @c false if we opened an directory file (normal
444 * directory).
445 */
446RTDECL(int) RTNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
447 ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
448{
449 *phHandle = RTNT_INVALID_HANDLE_VALUE;
450
451 HANDLE hRootDir;
452 UNICODE_STRING NtName;
453 int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
454 if (RT_SUCCESS(rc))
455 {
456 HANDLE hFile = RTNT_INVALID_HANDLE_VALUE;
457 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
458 OBJECT_ATTRIBUTES ObjAttr;
459 InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
460
461 NTSTATUS rcNt = NtCreateFile(&hFile,
462 fDesiredAccess,
463 &ObjAttr,
464 &Ios,
465 NULL /* AllocationSize*/,
466 FILE_ATTRIBUTE_NORMAL,
467 fShareAccess,
468 FILE_OPEN,
469 fCreateOptions,
470 NULL /*EaBuffer*/,
471 0 /*EaLength*/);
472 if (NT_SUCCESS(rcNt))
473 {
474 if (pfObjDir)
475 *pfObjDir = false;
476 *phHandle = hFile;
477 rc = VINF_SUCCESS;
478 }
479#ifdef IPRT_WITH_NT_PATH_PASSTHRU
480 else if ( pfObjDir
481 && (rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_OBJECT_TYPE_MISMATCH)
482 && RTPATH_IS_SLASH(pszPath[0])
483 && RTPATH_IS_SLASH(pszPath[1])
484 && pszPath[2] == '!'
485 && RTPATH_IS_SLASH(pszPath[3]))
486 {
487 /* Strip trailing slash. */
488 if ( NtName.Length > 2
489 && RTPATH_IS_SLASH(NtName.Buffer[(NtName.Length / 2) - 1]))
490 NtName.Length -= 2;
491
492 /* Rought conversion of the access flags. */
493 ULONG fObjDesiredAccess = 0;
494 if (fDesiredAccess & (GENERIC_ALL | STANDARD_RIGHTS_ALL))
495 fObjDesiredAccess = DIRECTORY_ALL_ACCESS;
496 else
497 {
498 if (fDesiredAccess & (FILE_GENERIC_WRITE | GENERIC_WRITE | STANDARD_RIGHTS_WRITE))
499 fObjDesiredAccess |= DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_OBJECT;
500 if ( (fDesiredAccess & (FILE_LIST_DIRECTORY | FILE_GENERIC_READ | GENERIC_READ | STANDARD_RIGHTS_READ))
501 || !fObjDesiredAccess)
502 fObjDesiredAccess |= DIRECTORY_QUERY | FILE_LIST_DIRECTORY;
503 }
504
505 rcNt = NtOpenDirectoryObject(&hFile, fObjDesiredAccess, &ObjAttr);
506 if (NT_SUCCESS(rcNt))
507 {
508 *pfObjDir = true;
509 *phHandle = hFile;
510 rc = VINF_SUCCESS;
511 }
512 else
513 rc = RTErrConvertFromNtStatus(rcNt);
514 }
515#endif
516 else
517 rc = RTErrConvertFromNtStatus(rcNt);
518 rtNtPathFreeNative(&NtName, &hRootDir);
519 }
520 return rc;
521}
522
523
524/**
525 * Closes an handled open by rtNtPathOpen.
526 *
527 * @returns IPRT status code
528 * @param hHandle The handle value.
529 */
530RTDECL(int) RTNtPathClose(HANDLE hHandle)
531{
532 NTSTATUS rcNt = NtClose(hHandle);
533 if (NT_SUCCESS(rcNt))
534 return VINF_SUCCESS;
535 return RTErrConvertFromNtStatus(rcNt);
536}
537
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