VirtualBox

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

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

r3/win/dir-win.cpp: r=bird: this isn't good enough.

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