VirtualBox

source: vbox/trunk/src/VBox/Runtime/nt/RTNtPathExpand8dot3Path.cpp

Last change on this file was 106061, checked in by vboxsync, 3 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.0 KB
Line 
1/* $Id: RTNtPathExpand8dot3Path.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Native NT, RTNtPathExpand8dot3Path.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_FS
42#if !defined(IPRT_NT_MAP_TO_ZW) && defined(IN_RING0)
43# define IPRT_NT_MAP_TO_ZW
44#endif
45#ifdef IN_SUP_HARDENED_R3
46# include <iprt/nt/nt-and-windows.h>
47#else
48# include <iprt/nt/nt.h>
49#endif
50
51#include <iprt/mem.h>
52#include <iprt/errcore.h>
53#include <iprt/string.h>
54
55
56
57/**
58 * Fixes up a path possibly containing one or more alternative 8-dot-3 style
59 * components.
60 *
61 * The path is fixed up in place. Errors are ignored.
62 *
63 * @returns VINF_SUCCESS if it all went smoothly, informational status codes
64 * indicating the nature of last problem we ran into.
65 *
66 * @param pUniStr The path to fix up. MaximumLength is the max buffer
67 * length.
68 * @param fPathOnly Whether to only process the path and leave the filename
69 * as passed in.
70 */
71RTDECL(int) RTNtPathExpand8dot3Path(PUNICODE_STRING pUniStr, bool fPathOnly)
72{
73 int rc = VINF_SUCCESS;
74
75 /*
76 * We could use FileNormalizedNameInformation here and slap the volume device
77 * path in front of the result, but it's only supported since windows 8.0
78 * according to some docs... So we expand all supicious names.
79 */
80 union fix8dot3tmp
81 {
82 FILE_BOTH_DIR_INFORMATION Info;
83 uint8_t abBuffer[sizeof(FILE_BOTH_DIR_INFORMATION) + 2048 * sizeof(WCHAR)];
84 } *puBuf = NULL;
85
86
87 PRTUTF16 pwszFix = pUniStr->Buffer;
88 while (*pwszFix)
89 {
90 pwszFix = RTNtPathFindPossible8dot3Name(pwszFix);
91 if (pwszFix == NULL)
92 break;
93
94 RTUTF16 wc;
95 PRTUTF16 pwszFixEnd = pwszFix;
96 while ((wc = *pwszFixEnd) != '\0' && wc != '\\' && wc != '/')
97 pwszFixEnd++;
98 if (wc == '\0' && fPathOnly)
99 break;
100
101 if (!puBuf)
102 {
103 puBuf = (union fix8dot3tmp *)RTMemAlloc(sizeof(*puBuf));
104 if (!puBuf)
105 {
106 rc = -VERR_NO_MEMORY;
107 break;
108 }
109 }
110
111 RTUTF16 const wcSaved = *pwszFix;
112 *pwszFix = '\0'; /* paranoia. */
113
114 UNICODE_STRING NtDir;
115 NtDir.Buffer = pUniStr->Buffer;
116 NtDir.Length = NtDir.MaximumLength = (USHORT)((pwszFix - pUniStr->Buffer) * sizeof(WCHAR));
117
118 HANDLE hDir = RTNT_INVALID_HANDLE_VALUE;
119 IO_STATUS_BLOCK Ios = RTNT_IO_STATUS_BLOCK_INITIALIZER;
120
121 OBJECT_ATTRIBUTES ObjAttr;
122 InitializeObjectAttributes(&ObjAttr, &NtDir, OBJ_CASE_INSENSITIVE, NULL /*hRootDir*/, NULL /*pSecDesc*/);
123#ifdef IN_RING0
124 ObjAttr.Attributes |= OBJ_KERNEL_HANDLE;
125#endif
126
127 NTSTATUS rcNt = NtCreateFile(&hDir,
128 FILE_LIST_DIRECTORY | SYNCHRONIZE,
129 &ObjAttr,
130 &Ios,
131 NULL /* Allocation Size*/,
132 FILE_ATTRIBUTE_NORMAL,
133 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
134 FILE_OPEN,
135 FILE_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT | FILE_SYNCHRONOUS_IO_NONALERT,
136 NULL /*EaBuffer*/,
137 0 /*EaLength*/);
138 *pwszFix = wcSaved;
139 if (NT_SUCCESS(rcNt))
140 {
141 RT_ZERO(*puBuf);
142
143 RTNT_IO_STATUS_BLOCK_REINIT(&Ios);
144 UNICODE_STRING NtFilterStr;
145 NtFilterStr.Buffer = pwszFix;
146 NtFilterStr.Length = (USHORT)((uintptr_t)pwszFixEnd - (uintptr_t)pwszFix);
147 NtFilterStr.MaximumLength = NtFilterStr.Length;
148 rcNt = NtQueryDirectoryFile(hDir,
149 NULL /* Event */,
150 NULL /* ApcRoutine */,
151 NULL /* ApcContext */,
152 &Ios,
153 puBuf,
154 sizeof(*puBuf) - sizeof(WCHAR),
155 FileBothDirectoryInformation,
156 FALSE /*ReturnSingleEntry*/,
157 &NtFilterStr,
158 FALSE /*RestartScan */);
159 if (NT_SUCCESS(rcNt) && puBuf->Info.NextEntryOffset == 0) /* There shall only be one entry matching... */
160 {
161 uint32_t offName = puBuf->Info.FileNameLength / sizeof(WCHAR);
162 while (offName > 0 && puBuf->Info.FileName[offName - 1] != '\\' && puBuf->Info.FileName[offName - 1] != '/')
163 offName--;
164 uint32_t cwcNameNew = (puBuf->Info.FileNameLength / sizeof(WCHAR)) - offName;
165 uint32_t cwcNameOld = (uint32_t)(pwszFixEnd - pwszFix);
166
167 if (cwcNameOld == cwcNameNew)
168 memcpy(pwszFix, &puBuf->Info.FileName[offName], cwcNameNew * sizeof(WCHAR));
169 else if ( pUniStr->Length + cwcNameNew * sizeof(WCHAR) - cwcNameOld * sizeof(WCHAR) + sizeof(WCHAR)
170 <= pUniStr->MaximumLength)
171 {
172 size_t cwcLeft = pUniStr->Length - (pwszFixEnd - pUniStr->Buffer) * sizeof(WCHAR) + sizeof(WCHAR);
173 memmove(&pwszFix[cwcNameNew], pwszFixEnd, cwcLeft * sizeof(WCHAR));
174 pUniStr->Length -= (USHORT)(cwcNameOld * sizeof(WCHAR));
175 pUniStr->Length += (USHORT)(cwcNameNew * sizeof(WCHAR));
176 pwszFixEnd -= cwcNameOld;
177 pwszFixEnd += cwcNameNew;
178 memcpy(pwszFix, &puBuf->Info.FileName[offName], cwcNameNew * sizeof(WCHAR));
179 }
180 else
181 rc = VINF_BUFFER_OVERFLOW;
182 }
183 else if (NT_SUCCESS(rcNt))
184 rc = -VERR_DUPLICATE;
185 else
186 {
187 rc = -RTErrConvertFromNtStatus(rcNt);
188 if (rc < 0)
189 rc = -rc;
190 }
191
192 NtClose(hDir);
193 }
194 else
195 rc = -RTErrConvertFromNtStatus(rcNt);
196
197 /* Advance */
198 pwszFix = pwszFixEnd;
199 }
200
201 if (puBuf)
202 RTMemFree(puBuf);
203
204 if (pUniStr->Length < pUniStr->MaximumLength)
205 pUniStr->Buffer[pUniStr->Length / sizeof(WCHAR)] = '\0';
206
207 return rc;
208}
209
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