VirtualBox

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

Last change on this file since 69111 was 69111, checked in by vboxsync, 7 years ago

(C) year

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