VirtualBox

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

Last change on this file since 22509 was 20111, checked in by vboxsync, 16 years ago

IPRT: Use the generic RTDirCreateTemp implementation - made it a bit more flexible and added a testcase for it.

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