VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win/dir-win.cpp@ 25240

Last change on this file since 25240 was 23298, checked in by vboxsync, 15 years ago

RTDirExists: Added a generic implementation for use on Window because GetFileAttributesEx doesn't do what we like it to do.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.8 KB
Line 
1/* $Id: dir-win.cpp 23298 2009-09-24 16:38:05Z vboxsync $ */
2/** @file
3 * IPRT - Directory, win32.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#define LOG_GROUP RTLOGGROUP_DIR
36#include <Windows.h>
37#include <io.h>
38
39#include <iprt/dir.h>
40#include <iprt/path.h>
41#include <iprt/alloc.h>
42#include <iprt/string.h>
43#include <iprt/assert.h>
44#include <iprt/param.h>
45#include <iprt/err.h>
46#include <iprt/file.h>
47#include <iprt/log.h>
48#include "internal/fs.h"
49#include "internal/path.h"
50#include "internal/dir.h"
51
52
53
54RTDECL(int) RTDirCreate(const char *pszPath, RTFMODE fMode)
55{
56 /*
57 * Validate the file mode.
58 */
59 int rc;
60 fMode = rtFsModeNormalize(fMode, pszPath, 0);
61 if (rtFsModeIsValidPermissions(fMode))
62 {
63 /*
64 * Convert to UTF-16.
65 */
66 PRTUTF16 pwszString;
67 rc = RTStrToUtf16(pszPath, &pwszString);
68 AssertRC(rc);
69 if (RT_SUCCESS(rc))
70 {
71 /*
72 * Create the directory.
73 */
74 if (CreateDirectoryW((LPCWSTR)pwszString, NULL))
75 rc = VINF_SUCCESS;
76 else
77 rc = RTErrConvertFromWin32(GetLastError());
78
79 /*
80 * Turn off indexing of directory through Windows Indexing Service
81 */
82 if (RT_SUCCESS(rc))
83 {
84 if (SetFileAttributesW((LPCWSTR)pwszString, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED))
85 rc = VINF_SUCCESS;
86 else
87 rc = RTErrConvertFromWin32(GetLastError());
88 }
89
90 RTUtf16Free(pwszString);
91 }
92 }
93 else
94 {
95 AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode));
96 rc = VERR_INVALID_FMODE;
97 }
98
99 LogFlow(("RTDirCreate(%p:{%s}, %RTfmode): returns %Rrc\n", pszPath, pszPath, fMode, rc));
100 return rc;
101}
102
103
104RTDECL(int) RTDirRemove(const char *pszPath)
105{
106 /*
107 * Convert to UTF-16.
108 */
109 PRTUTF16 pwszString;
110 int rc = RTStrToUtf16(pszPath, &pwszString);
111 AssertRC(rc);
112 if (RT_SUCCESS(rc))
113 {
114 /*
115 * Remove the directory.
116 */
117 if (RemoveDirectoryW((LPCWSTR)pwszString))
118 rc = VINF_SUCCESS;
119 else
120 rc = RTErrConvertFromWin32(GetLastError());
121
122 RTUtf16Free(pwszString);
123 }
124
125 LogFlow(("RTDirRemove(%p:{%s}): returns %Rrc\n", pszPath, pszPath, rc));
126 return rc;
127}
128
129
130int rtOpenDirNative(PRTDIR pDir, char *pszPathBuf)
131{
132 /*
133 * Setup the search expression.
134 *
135 * pszPathBuf is pointing to the return 4K return buffer for the RTPathReal()
136 * call in rtDirOpenCommon(), so all we gota do is check that we don't overflow
137 * it when adding the wildcard expression.
138 */
139 size_t cchExpr;
140 const char *pszExpr;
141 if (pDir->enmFilter == RTDIRFILTER_WINNT)
142 {
143 pszExpr = pDir->pszFilter;
144 cchExpr = pDir->cchFilter + 1;
145 }
146 else
147 {
148 pszExpr = "*";
149 cchExpr = sizeof("*");
150 }
151 if (pDir->cchPath + cchExpr > RTPATH_MAX)
152 return VERR_FILENAME_TOO_LONG;
153 memcpy(pszPathBuf + pDir->cchPath, pszExpr, cchExpr);
154
155
156 /*
157 * Attempt opening the search.
158 */
159 int rc = VINF_SUCCESS;
160#ifndef RT_DONT_CONVERT_FILENAMES
161 PRTUTF16 pwszName;
162 rc = RTStrToUtf16(pszPathBuf, &pwszName);
163 if (RT_SUCCESS(rc))
164 {
165 pDir->hDir = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data);
166#else
167 pDir->hDir = FindFirstFileA(pszPathBuf, &pDir->Data);
168#endif
169 if (pDir->hDir != INVALID_HANDLE_VALUE)
170 pDir->fDataUnread = true;
171 /* theoretical case of an empty directory. */
172 else if (GetLastError() == ERROR_NO_MORE_FILES)
173 pDir->fDataUnread = false;
174 else
175 rc = RTErrConvertFromWin32(GetLastError());
176#ifndef RT_DONT_CONVERT_FILENAMES
177 RTUtf16Free(pwszName);
178 }
179#endif
180
181 return rc;
182}
183
184
185RTDECL(int) RTDirClose(PRTDIR pDir)
186{
187 /*
188 * Validate input.
189 */
190 if (!pDir)
191 return VERR_INVALID_PARAMETER;
192 if (pDir->u32Magic != RTDIR_MAGIC)
193 {
194 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
195 return VERR_INVALID_PARAMETER;
196 }
197
198 /*
199 * Close the handle.
200 */
201 pDir->u32Magic++;
202 if (pDir->hDir != INVALID_HANDLE_VALUE)
203 {
204 BOOL fRc = FindClose(pDir->hDir);
205 Assert(fRc);
206 pDir->hDir = INVALID_HANDLE_VALUE;
207 }
208 RTStrFree(pDir->pszName);
209 pDir->pszName = NULL;
210 RTMemFree(pDir);
211
212 return VINF_SUCCESS;
213}
214
215
216RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
217{
218 /*
219 * Validate input.
220 */
221 if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
222 {
223 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
224 return VERR_INVALID_PARAMETER;
225 }
226 if (!pDirEntry)
227 {
228 AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
229 return VERR_INVALID_PARAMETER;
230 }
231 size_t cbDirEntry = sizeof(*pDirEntry);
232 if (pcbDirEntry)
233 {
234 cbDirEntry = *pcbDirEntry;
235 if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2]))
236 {
237 AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])));
238 return VERR_INVALID_PARAMETER;
239 }
240 }
241
242 /*
243 * Fetch data?
244 */
245 if (!pDir->fDataUnread)
246 {
247#ifdef RT_DONT_CONVERT_FILENAMES
248 BOOL fRc = FindNextFileA(pDir->hDir, &pDir->Data);
249
250#else
251 RTStrFree(pDir->pszName);
252 pDir->pszName = NULL;
253
254 BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
255#endif
256 if (!fRc)
257 {
258 int iErr = GetLastError();
259 if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
260 return VERR_NO_MORE_FILES;
261 return RTErrConvertFromWin32(iErr);
262 }
263 }
264
265#ifndef RT_DONT_CONVERT_FILENAMES
266 /*
267 * Convert the filename to UTF-8.
268 */
269 if (!pDir->pszName)
270 {
271 int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
272 if (RT_FAILURE(rc))
273 {
274 pDir->pszName = NULL;
275 return rc;
276 }
277 pDir->cchName = strlen(pDir->pszName);
278 }
279#endif
280
281 /*
282 * Check if we've got enough space to return the data.
283 */
284#ifdef RT_DONT_CONVERT_FILENAMES
285 const char *pszName = pDir->Data.cName;
286 const size_t cchName = strlen(pszName);
287#else
288 const char *pszName = pDir->pszName;
289 const size_t cchName = pDir->cchName;
290#endif
291 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName;
292 if (pcbDirEntry)
293 *pcbDirEntry = cbRequired;
294 if (cbRequired > cbDirEntry)
295 return VERR_BUFFER_OVERFLOW;
296
297 /*
298 * Setup the returned data.
299 */
300 pDir->fDataUnread = false;
301 pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */
302 pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
303 ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE;
304 pDirEntry->cbName = (uint16_t)cchName;
305 Assert(pDirEntry->cbName == cchName);
306 memcpy(pDirEntry->szName, pszName, cchName + 1);
307
308 return VINF_SUCCESS;
309}
310
311
312RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs)
313{
314 /*
315 * Validate input.
316 */
317 if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
318 {
319 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
320 return VERR_INVALID_PARAMETER;
321 }
322 if (!pDirEntry)
323 {
324 AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
325 return VERR_INVALID_PARAMETER;
326 }
327 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
328 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
329 {
330 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
331 return VERR_INVALID_PARAMETER;
332 }
333 size_t cbDirEntry = sizeof(*pDirEntry);
334 if (pcbDirEntry)
335 {
336 cbDirEntry = *pcbDirEntry;
337 if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2]))
338 {
339 AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])));
340 return VERR_INVALID_PARAMETER;
341 }
342 }
343
344 /*
345 * Fetch data?
346 */
347 if (!pDir->fDataUnread)
348 {
349#ifdef RT_DONT_CONVERT_FILENAMES
350 BOOL fRc = FindNextFileA(pDir->hDir, &pDir->Data);
351
352#else
353 RTStrFree(pDir->pszName);
354 pDir->pszName = NULL;
355
356 BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
357#endif
358 if (!fRc)
359 {
360 int iErr = GetLastError();
361 if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
362 return VERR_NO_MORE_FILES;
363 return RTErrConvertFromWin32(iErr);
364 }
365 }
366
367#ifndef RT_DONT_CONVERT_FILENAMES
368 /*
369 * Convert the filename to UTF-8.
370 */
371 if (!pDir->pszName)
372 {
373 int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
374 if (RT_FAILURE(rc))
375 {
376 pDir->pszName = NULL;
377 return rc;
378 }
379 pDir->cchName = strlen(pDir->pszName);
380 }
381#endif
382
383 /*
384 * Check if we've got enough space to return the data.
385 */
386#ifdef RT_DONT_CONVERT_FILENAMES
387 const char *pszName = pDir->Data.cName;
388 const size_t cchName = strlen(pszName);
389#else
390 const char *pszName = pDir->pszName;
391 const size_t cchName = pDir->cchName;
392#endif
393 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
394 if (pcbDirEntry)
395 *pcbDirEntry = cbRequired;
396 if (cbRequired > cbDirEntry)
397 return VERR_BUFFER_OVERFLOW;
398
399 /*
400 * Setup the returned data.
401 */
402 pDir->fDataUnread = false;
403 pDirEntry->cbName = (uint16_t)cchName;
404 Assert(pDirEntry->cbName == cchName);
405 memcpy(pDirEntry->szName, pszName, cchName + 1);
406#ifndef RT_DONT_CONVERT_FILENAMES /* this ain't nice since the whole point of this define is not to drag in conversion... */
407 if (pDir->Data.cAlternateFileName[0])
408 {
409 /* copy and calc length */
410 PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName;
411 PRTUTF16 pwszDst = pDirEntry->wszShortName;
412 while (*pwszSrc)
413 *pwszDst++ = *pwszSrc++;
414 pDirEntry->cwcShortName = pwszDst - &pDirEntry->wszShortName[0];
415 /* zero the rest */
416 const PRTUTF16 pwszEnd = &pDirEntry->wszShortName[RT_ELEMENTS(pDirEntry->wszShortName)];
417 while (pwszDst < pwszEnd)
418 *pwszDst++ = '\0';
419 }
420 else
421#endif
422 {
423 memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
424 pDirEntry->cwcShortName = 0;
425 }
426
427 pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32)
428 | (uint64_t)pDir->Data.nFileSizeLow;
429 pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject;
430
431 Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime));
432 RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime);
433 RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime);
434 RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime);
435 pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime;
436
437 pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
438 pszName, cchName);
439
440 /*
441 * Requested attributes (we cannot provide anything actually).
442 */
443 switch (enmAdditionalAttribs)
444 {
445 case RTFSOBJATTRADD_EASIZE:
446 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
447 pDirEntry->Info.Attr.u.EASize.cb = 0;
448 break;
449
450 case RTFSOBJATTRADD_UNIX:
451 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
452 pDirEntry->Info.Attr.u.Unix.uid = ~0U;
453 pDirEntry->Info.Attr.u.Unix.gid = ~0U;
454 pDirEntry->Info.Attr.u.Unix.cHardlinks = 1;
455 pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */
456 pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */
457 pDirEntry->Info.Attr.u.Unix.fFlags = 0;
458 pDirEntry->Info.Attr.u.Unix.GenerationId = 0;
459 pDirEntry->Info.Attr.u.Unix.Device = 0;
460 break;
461
462 case RTFSOBJATTRADD_NOTHING:
463 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
464 break;
465
466 default:
467 AssertMsgFailed(("Impossible!\n"));
468 return VERR_INTERNAL_ERROR;
469 }
470
471 return VINF_SUCCESS;
472}
473
474
475RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename)
476{
477 /*
478 * Validate input.
479 */
480 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
481 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
482 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
483 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
484 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
485
486 /*
487 * Call the worker.
488 */
489 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
490 fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0,
491 RTFS_TYPE_DIRECTORY);
492
493 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
494 return rc;
495}
496
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