VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/win32/dir-win32.cpp@ 5285

Last change on this file since 5285 was 4071, checked in by vboxsync, 17 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

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