VirtualBox

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

Last change on this file since 3672 was 2981, checked in by vboxsync, 17 years ago

InnoTek -> innotek: all the headers and comments.

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