VirtualBox

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

Last change on this file since 48789 was 47535, checked in by vboxsync, 12 years ago

IPRT: Wrote native NT directory enumeration - not enabled by default. Provides ChangeTime and later file ID (inode no). Can also enumerate object directories, just for the fun of it.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.1 KB
Line 
1/* $Id: pathint-nt.cpp 47535 2013-08-05 01:54:25Z 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/**
42 * Handles the pass thru case.
43 *
44 * @returns IPRT status code.
45 * @param pNtName Where to return the NT name.
46 * @param phRootDir Where to return the root handle, if applicable.
47 * @param pszPath The UTF-8 path.
48 */
49static int rtNtPathToNativePassThruWin(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
50{
51 PRTUTF16 pwszPath = NULL;
52 size_t cwcLen;
53 int rc = RTStrToUtf16Ex(pszPath + 1, RTSTR_MAX, &pwszPath, 0, &cwcLen);
54 if (RT_SUCCESS(rc))
55 {
56 if (cwcLen < _32K - 1)
57 {
58 pwszPath[0] = '\\';
59 pwszPath[1] = '.';
60 pwszPath[2] = '\\';
61
62 pNtName->Buffer = pwszPath;
63 pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
64 *phRootDir = NULL;
65 return VINF_SUCCESS;
66 }
67
68 RTUtf16Free(pwszPath);
69 rc = VERR_FILENAME_TOO_LONG;
70 }
71 return rc;
72}
73
74
75/**
76 * Converts the path to UTF-16 and sets all the return values.
77 *
78 * @returns IPRT status code.
79 * @param pNtName Where to return the NT name.
80 * @param phRootDir Where to return the root handle, if applicable.
81 * @param pszPath The UTF-8 path.
82 */
83static int rtNtPathToNativeToUtf16(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
84{
85 PRTUTF16 pwszPath = NULL;
86 size_t cwcLen;
87 int rc = RTStrToUtf16Ex(pszPath, RTSTR_MAX, &pwszPath, 0, &cwcLen);
88 if (RT_SUCCESS(rc))
89 {
90 if (cwcLen < _32K - 1)
91 {
92 pNtName->Buffer = pwszPath;
93 pNtName->MaximumLength = pNtName->Length = (uint16_t)(cwcLen * 2);
94 *phRootDir = NULL;
95 return VINF_SUCCESS;
96 }
97
98 RTUtf16Free(pwszPath);
99 rc = VERR_FILENAME_TOO_LONG;
100 }
101 return rc;
102}
103
104
105/**
106 * Converts a path to NT format and encoding.
107 *
108 * @returns IPRT status code.
109 * @param pNtName Where to return the NT name.
110 * @param phRootDir Where to return the root handle, if applicable.
111 * @param pszPath The UTF-8 path.
112 */
113static int rtNtPathToNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir, const char *pszPath)
114{
115 static char const s_szPrefixUnc[] = "\\??\\UNC\\";
116 static char const s_szPrefix[] = "\\??\\";
117
118 /*
119 * Very simple conversion of a win32-like path into an NT path.
120 */
121 const char *pszPrefix = s_szPrefix;
122 size_t cchPrefix = sizeof(s_szPrefix) - 1;
123 size_t cchSkip = 0;
124
125 if ( RTPATH_IS_SLASH(pszPath[0])
126 && RTPATH_IS_SLASH(pszPath[1])
127 && !RTPATH_IS_SLASH(pszPath[2])
128 && pszPath[2])
129 {
130 if ( pszPath[2] == '?'
131 && RTPATH_IS_SLASH(pszPath[3]))
132 return rtNtPathToNativePassThruWin(pNtName, phRootDir, pszPath);
133
134#ifdef IPRT_WITH_NT_PATH_PASSTHRU
135 /* Special hack: The path starts with "\\\\!\\", we will skip past the bang and pass it thru. */
136 if ( pszPath[2] == '!'
137 && RTPATH_IS_SLASH(pszPath[3]))
138 return rtNtPathToNativeToUtf16(pNtName, phRootDir, pszPath + 3);
139#endif
140
141 if ( pszPath[2] == '.'
142 && RTPATH_IS_SLASH(pszPath[3]))
143 {
144 /*
145 * Device path.
146 * Note! I suspect \\.\stuff\..\otherstuff may be handled differently by windows.
147 */
148 cchSkip = 4;
149 }
150 else
151 {
152 /* UNC */
153 pszPrefix = s_szPrefixUnc;
154 cchPrefix = sizeof(s_szPrefixUnc) - 1;
155 cchSkip = 2;
156 }
157 }
158
159 /*
160 * Straighten out all .. and uncessary . references and convert slashes.
161 */
162 char szPath[RTPATH_MAX];
163 int rc = RTPathAbs(pszPath, &szPath[cchPrefix - cchSkip], sizeof(szPath) - (cchPrefix - cchSkip));
164 if (RT_FAILURE(rc))
165 return rc;
166
167 /*
168 * Add prefix and convert it to UTF16.
169 */
170 memcpy(szPath, pszPrefix, cchPrefix);
171 return rtNtPathToNativeToUtf16(pNtName, phRootDir, szPath);
172}
173
174
175/**
176 * Frees the native path and root handle.
177 *
178 * @param pNtName The NT path after a successful rtNtPathToNative
179 * call.
180 * @param phRootDir The root handle variable after a
181 * rtNtPathToNative.
182 */
183void rtNtPathFreeNative(struct _UNICODE_STRING *pNtName, PHANDLE phRootDir)
184{
185 RTUtf16Free(pNtName->Buffer);
186 pNtName->Buffer = NULL;
187}
188
189
190/**
191 * Wrapper around NtCreateFile.
192 *
193 * @returns IPRT status code.
194 * @param pszPath The UTF-8 path.
195 * @param fDesiredAccess See NtCreateFile.
196 * @param fFileAttribs See NtCreateFile.
197 * @param fShareAccess See NtCreateFile.
198 * @param fCreateDisposition See NtCreateFile.
199 * @param fCreateOptions See NtCreateFile.
200 * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see
201 * NtCreateFile and InitializeObjectAttributes.
202 * @param phHandle Where to return the handle.
203 * @param puAction Where to return the action taken. Optional.
204 */
205int rtNtPathOpen(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fFileAttribs, ULONG fShareAccess,
206 ULONG fCreateDisposition, ULONG fCreateOptions, ULONG fObjAttribs,
207 PHANDLE phHandle, PULONG_PTR puAction)
208{
209 *phHandle = MY_INVALID_HANDLE_VALUE;
210
211 HANDLE hRootDir;
212 UNICODE_STRING NtName;
213 int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
214 if (RT_SUCCESS(rc))
215 {
216 HANDLE hFile = MY_INVALID_HANDLE_VALUE;
217 IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
218 OBJECT_ATTRIBUTES ObjAttr;
219 InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
220
221 NTSTATUS rcNt = NtCreateFile(&hFile,
222 fDesiredAccess,
223 &ObjAttr,
224 &Ios,
225 NULL /* AllocationSize*/,
226 fFileAttribs,
227 fShareAccess,
228 fCreateDisposition,
229 fCreateOptions,
230 NULL /*EaBuffer*/,
231 0 /*EaLength*/);
232 if (NT_SUCCESS(rcNt))
233 {
234 if (puAction)
235 *puAction = Ios.Information;
236 *phHandle = hFile;
237 rc = VINF_SUCCESS;
238 }
239 else
240 rc = RTErrConvertFromNtStatus(rcNt);
241 rtNtPathFreeNative(&NtName, &hRootDir);
242 }
243 return rc;
244}
245
246
247/**
248 * Wrapper around NtCreateFile.
249 *
250 * @returns IPRT status code.
251 * @param pszPath The UTF-8 path.
252 * @param fDesiredAccess See NtCreateFile.
253 * @param fFileAttribs See NtCreateFile.
254 * @param fShareAccess See NtCreateFile.
255 * @param fCreateDisposition See NtCreateFile.
256 * @param fCreateOptions See NtCreateFile.
257 * @param fObjAttribs The OBJECT_ATTRIBUTES::Attributes value, see
258 * NtCreateFile and InitializeObjectAttributes.
259 * @param phHandle Where to return the handle.
260 * @param pfObjDir If not NULL, the variable pointed to will be set
261 * to @c true if we opened an object directory and
262 * @c false if we opened an directory file (normal
263 * directory).
264 */
265int rtNtPathOpenDir(const char *pszPath, ACCESS_MASK fDesiredAccess, ULONG fShareAccess, ULONG fCreateOptions,
266 ULONG fObjAttribs, PHANDLE phHandle, bool *pfObjDir)
267{
268 *phHandle = MY_INVALID_HANDLE_VALUE;
269
270 HANDLE hRootDir;
271 UNICODE_STRING NtName;
272 int rc = rtNtPathToNative(&NtName, &hRootDir, pszPath);
273 if (RT_SUCCESS(rc))
274 {
275 HANDLE hFile = MY_INVALID_HANDLE_VALUE;
276 IO_STATUS_BLOCK Ios = MY_IO_STATUS_BLOCK_INITIALIZER;
277 OBJECT_ATTRIBUTES ObjAttr;
278 InitializeObjectAttributes(&ObjAttr, &NtName, fObjAttribs, hRootDir, NULL);
279
280 NTSTATUS rcNt = NtCreateFile(&hFile,
281 fDesiredAccess,
282 &ObjAttr,
283 &Ios,
284 NULL /* AllocationSize*/,
285 FILE_ATTRIBUTE_NORMAL,
286 fShareAccess,
287 FILE_OPEN,
288 fCreateOptions,
289 NULL /*EaBuffer*/,
290 0 /*EaLength*/);
291 if (NT_SUCCESS(rcNt))
292 {
293 if (pfObjDir)
294 *pfObjDir = false;
295 *phHandle = hFile;
296 rc = VINF_SUCCESS;
297 }
298#ifdef IPRT_WITH_NT_PATH_PASSTHRU
299 else if ( pfObjDir
300 && (rcNt == STATUS_OBJECT_NAME_INVALID || rcNt == STATUS_OBJECT_TYPE_MISMATCH)
301 && RTPATH_IS_SLASH(pszPath[0])
302 && RTPATH_IS_SLASH(pszPath[1])
303 && pszPath[2] == '!'
304 && RTPATH_IS_SLASH(pszPath[3]))
305 {
306 /* Strip trailing slash. */
307 if ( NtName.Length > 2
308 && RTPATH_IS_SLASH(NtName.Buffer[(NtName.Length / 2) - 1]))
309 NtName.Length -= 2;
310
311 /* Rought conversion of the access flags. */
312 ULONG fObjDesiredAccess = 0;
313 if (fDesiredAccess & (GENERIC_ALL | STANDARD_RIGHTS_ALL))
314 fObjDesiredAccess = DIRECTORY_ALL_ACCESS;
315 else
316 {
317 if (fDesiredAccess & (FILE_GENERIC_WRITE | GENERIC_WRITE | STANDARD_RIGHTS_WRITE))
318 fObjDesiredAccess |= DIRECTORY_CREATE_OBJECT | DIRECTORY_CREATE_OBJECT;
319 if ( (fDesiredAccess & (FILE_LIST_DIRECTORY | FILE_GENERIC_READ | GENERIC_READ | STANDARD_RIGHTS_READ))
320 || !fObjDesiredAccess)
321 fObjDesiredAccess |= DIRECTORY_QUERY | FILE_LIST_DIRECTORY;
322 }
323
324 rcNt = NtOpenDirectoryObject(&hFile, fObjDesiredAccess, &ObjAttr);
325 if (NT_SUCCESS(rcNt))
326 {
327 *pfObjDir = true;
328 *phHandle = hFile;
329 rc = VINF_SUCCESS;
330 }
331 else
332 rc = RTErrConvertFromNtStatus(rcNt);
333 }
334#endif
335 else
336 rc = RTErrConvertFromNtStatus(rcNt);
337 rtNtPathFreeNative(&NtName, &hRootDir);
338 }
339 return rc;
340}
341
342
343/**
344 * Closes an handled open by rtNtPathOpen.
345 *
346 * @returns IPRT status code
347 * @param hHandle The handle value.
348 */
349int rtNtPathClose(HANDLE hHandle)
350{
351 NTSTATUS rcNt = NtClose(hHandle);
352 if (NT_SUCCESS(rcNt))
353 return VINF_SUCCESS;
354 return RTErrConvertFromNtStatus(rcNt);
355}
356
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