VirtualBox

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

Last change on this file since 6749 was 5999, checked in by vboxsync, 17 years ago

The Giant CDDL Dual-License Header Change.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette