VirtualBox

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

Last change on this file since 75879 was 74460, checked in by vboxsync, 6 years ago

IPRT: Implemented long filename support for windows (except for LoadLibrary). bugref:9248

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