VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/direnum-win.cpp@ 95084

Last change on this file since 95084 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 12.6 KB
Line 
1/* $Id: direnum-win.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * IPRT - Directory Enumeration, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2022 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_DIR
32#include <iprt/win/windows.h>
33
34#include <iprt/dir.h>
35#include <iprt/path.h>
36#include <iprt/mem.h>
37#include <iprt/string.h>
38#include <iprt/assert.h>
39#include <iprt/err.h>
40#include <iprt/file.h>
41#include <iprt/log.h>
42#include "internal/fs.h"
43#include "internal/dir.h"
44
45
46size_t rtDirNativeGetStructSize(const char *pszPath)
47{
48 NOREF(pszPath);
49 return sizeof(RTDIRINTERNAL);
50}
51
52
53int rtDirNativeOpen(PRTDIRINTERNAL pDir, uintptr_t hRelativeDir, void *pvNativeRelative))
54{
55 RT_NOREF(hRelativeDir, pvNativeRelative);
56
57 /*
58 * Setup the search expression.
59 *
60 * pszPathBuf is pointing to the return 4K return buffer for the RTPathReal()
61 * call in rtDirOpenCommon(), so all we gota do is check that we don't overflow
62 * it when adding the wildcard expression.
63 */
64/** @todo the pszPathBuf argument was removed in order to support paths longer than RTPATH_MAX. Rewrite this code. */
65 size_t cbExpr;
66 const char *pszExpr;
67 if (pDir->enmFilter == RTDIRFILTER_WINNT)
68 {
69 pszExpr = pDir->pszFilter;
70 cbExpr = pDir->cchFilter + 1;
71 }
72 else
73 {
74 pszExpr = "*";
75 cbExpr = sizeof("*");
76 }
77 if (pDir->cchPath + cbExpr > RTPATH_MAX)
78 return VERR_FILENAME_TOO_LONG;
79 memcpy(pszPathBuf + pDir->cchPath, pszExpr, cbExpr);
80
81
82 /*
83 * Attempt opening the search.
84 */
85 PRTUTF16 pwszName;
86 int rc = RTPathWinFromUtf8(pwszPathBuf, &pwszName, 0 /*fFlags*/);
87 if (RT_SUCCESS(rc))
88 {
89 pDir->hDir = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data);
90 if (pDir->hDir != INVALID_HANDLE_VALUE)
91 pDir->fDataUnread = true;
92 else
93 {
94 DWORD dwErr = GetLastError();
95 /* Theoretical case of an empty directory or more normal case of no matches. */
96 if ( dwErr == ERROR_FILE_NOT_FOUND
97 || dwErr == ERROR_NO_MORE_FILES /* ???*/)
98 pDir->fDataUnread = false;
99 else
100 rc = RTErrConvertFromWin32(GetLastError());
101 }
102 RTPathWinFree(pwszName);
103 }
104
105 return rc;
106}
107
108
109RTDECL(int) RTDirClose(PRTDIRINTERNAL pDir)
110{
111 /*
112 * Validate input.
113 */
114 if (!pDir)
115 return VERR_INVALID_PARAMETER;
116 if (pDir->u32Magic != RTDIR_MAGIC)
117 {
118 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
119 return VERR_INVALID_PARAMETER;
120 }
121
122 /*
123 * Close the handle.
124 */
125 pDir->u32Magic++;
126 if (pDir->hDir != INVALID_HANDLE_VALUE)
127 {
128 BOOL fRc = FindClose(pDir->hDir);
129 Assert(fRc);
130 pDir->hDir = INVALID_HANDLE_VALUE;
131 }
132 RTStrFree(pDir->pszName);
133 pDir->pszName = NULL;
134 RTMemFree(pDir);
135
136 return VINF_SUCCESS;
137}
138
139
140RTDECL(int) RTDirRead(RTDIR hDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
141{
142 PPRTDIRINTERNAL pDir = hDir;
143
144 /*
145 * Validate input.
146 */
147 if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
148 {
149 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
150 return VERR_INVALID_PARAMETER;
151 }
152 if (!pDirEntry)
153 {
154 AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
155 return VERR_INVALID_PARAMETER;
156 }
157 size_t cbDirEntry = sizeof(*pDirEntry);
158 if (pcbDirEntry)
159 {
160 cbDirEntry = *pcbDirEntry;
161 if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2]))
162 {
163 AssertMsgFailed(("Invalid *pcbDirEntry=%zu (min %zu)\n", *pcbDirEntry, RT_UOFFSETOF(RTDIRENTRY, szName[2])));
164 return VERR_INVALID_PARAMETER;
165 }
166 }
167
168 /*
169 * Fetch data?
170 */
171 if (!pDir->fDataUnread)
172 {
173 RTStrFree(pDir->pszName);
174 pDir->pszName = NULL;
175
176 BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
177 if (!fRc)
178 {
179 int iErr = GetLastError();
180 if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
181 return VERR_NO_MORE_FILES;
182 return RTErrConvertFromWin32(iErr);
183 }
184 }
185
186 /*
187 * Convert the filename to UTF-8.
188 */
189 if (!pDir->pszName)
190 {
191 int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
192 if (RT_FAILURE(rc))
193 {
194 pDir->pszName = NULL;
195 return rc;
196 }
197 pDir->cchName = strlen(pDir->pszName);
198 }
199
200 /*
201 * Check if we've got enough space to return the data.
202 */
203 const char *pszName = pDir->pszName;
204 const size_t cchName = pDir->cchName;
205 const size_t cbRequired = RT_UOFFSETOF(RTDIRENTRY, szName[1]) + cchName;
206 if (pcbDirEntry)
207 *pcbDirEntry = cbRequired;
208 if (cbRequired > cbDirEntry)
209 return VERR_BUFFER_OVERFLOW;
210
211 /*
212 * Setup the returned data.
213 */
214 pDir->fDataUnread = false;
215 pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */
216 pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
217 ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE;
218 pDirEntry->cbName = (uint16_t)cchName;
219 Assert(pDirEntry->cbName == cchName);
220 memcpy(pDirEntry->szName, pszName, cchName + 1);
221
222 return VINF_SUCCESS;
223}
224
225
226RTDECL(int) RTDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
227{
228 PPRTDIRINTERNAL pDir = hDir;
229 /** @todo Symlinks: Find[First|Next]FileW will return info about
230 the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
231 /*
232 * Validate input.
233 */
234 if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
235 {
236 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
237 return VERR_INVALID_PARAMETER;
238 }
239 if (!pDirEntry)
240 {
241 AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
242 return VERR_INVALID_PARAMETER;
243 }
244 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
245 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
246 {
247 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
248 return VERR_INVALID_PARAMETER;
249 }
250 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
251 size_t cbDirEntry = sizeof(*pDirEntry);
252 if (pcbDirEntry)
253 {
254 cbDirEntry = *pcbDirEntry;
255 if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2]))
256 {
257 AssertMsgFailed(("Invalid *pcbDirEntry=%zu (min %zu)\n", *pcbDirEntry, RT_UOFFSETOF(RTDIRENTRYEX, szName[2])));
258 return VERR_INVALID_PARAMETER;
259 }
260 }
261
262 /*
263 * Fetch data?
264 */
265 if (!pDir->fDataUnread)
266 {
267 RTStrFree(pDir->pszName);
268 pDir->pszName = NULL;
269
270 BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
271 if (!fRc)
272 {
273 int iErr = GetLastError();
274 if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
275 return VERR_NO_MORE_FILES;
276 return RTErrConvertFromWin32(iErr);
277 }
278 }
279
280 /*
281 * Convert the filename to UTF-8.
282 */
283 if (!pDir->pszName)
284 {
285 int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
286 if (RT_FAILURE(rc))
287 {
288 pDir->pszName = NULL;
289 return rc;
290 }
291 pDir->cchName = strlen(pDir->pszName);
292 }
293
294 /*
295 * Check if we've got enough space to return the data.
296 */
297 const char *pszName = pDir->pszName;
298 const size_t cchName = pDir->cchName;
299 const size_t cbRequired = RT_UOFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
300 if (pcbDirEntry)
301 *pcbDirEntry = cbRequired;
302 if (cbRequired > cbDirEntry)
303 return VERR_BUFFER_OVERFLOW;
304
305 /*
306 * Setup the returned data.
307 */
308 pDir->fDataUnread = false;
309 pDirEntry->cbName = (uint16_t)cchName;
310 Assert(pDirEntry->cbName == cchName);
311 memcpy(pDirEntry->szName, pszName, cchName + 1);
312 if (pDir->Data.cAlternateFileName[0])
313 {
314 /* copy and calc length */
315 PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName;
316 PRTUTF16 pwszDst = pDirEntry->wszShortName;
317 uint32_t off = 0;
318 while (off < RT_ELEMENTS(pDirEntry->wszShortName) - 1U && pwszSrc[off])
319 {
320 pwszDst[off] = pwszSrc[off];
321 off++;
322 }
323 pDirEntry->cwcShortName = (uint16_t)off;
324
325 /* zero the rest */
326 do
327 pwszDst[off++] = '\0';
328 while (off < RT_ELEMENTS(pDirEntry->wszShortName));
329 }
330 else
331 {
332 memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
333 pDirEntry->cwcShortName = 0;
334 }
335
336 pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32)
337 | (uint64_t)pDir->Data.nFileSizeLow;
338 pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject;
339
340 Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime));
341 RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime);
342 RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime);
343 RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime);
344 pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime;
345
346 pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
347 pszName, cchName, pDir->Data.dwReserved0, 0);
348
349 /*
350 * Requested attributes (we cannot provide anything actually).
351 */
352 switch (enmAdditionalAttribs)
353 {
354 case RTFSOBJATTRADD_EASIZE:
355 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
356 pDirEntry->Info.Attr.u.EASize.cb = 0;
357 break;
358
359 case RTFSOBJATTRADD_UNIX:
360 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
361 pDirEntry->Info.Attr.u.Unix.uid = ~0U;
362 pDirEntry->Info.Attr.u.Unix.gid = ~0U;
363 pDirEntry->Info.Attr.u.Unix.cHardlinks = 1;
364 pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */
365 pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */
366 pDirEntry->Info.Attr.u.Unix.fFlags = 0;
367 pDirEntry->Info.Attr.u.Unix.GenerationId = 0;
368 pDirEntry->Info.Attr.u.Unix.Device = 0;
369 break;
370
371 case RTFSOBJATTRADD_NOTHING:
372 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
373 break;
374
375 case RTFSOBJATTRADD_UNIX_OWNER:
376 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
377 pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U;
378 pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
379 break;
380
381 case RTFSOBJATTRADD_UNIX_GROUP:
382 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
383 pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U;
384 pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0';
385 break;
386
387 default:
388 AssertMsgFailed(("Impossible!\n"));
389 return VERR_INTERNAL_ERROR;
390 }
391
392 return VINF_SUCCESS;
393}
394
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