VirtualBox

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

Last change on this file since 34079 was 34002, checked in by vboxsync, 14 years ago

iprt: Working on tar vfs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.7 KB
Line 
1/* $Id: dir-win.cpp 34002 2010-11-11 17:16:37Z vboxsync $ */
2/** @file
3 * IPRT - Directory, win32.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Oracle Corporation
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#include <io.h>
34
35#include <iprt/dir.h>
36#include <iprt/path.h>
37#include <iprt/alloc.h>
38#include <iprt/string.h>
39#include <iprt/assert.h>
40#include <iprt/param.h>
41#include <iprt/err.h>
42#include <iprt/file.h>
43#include <iprt/log.h>
44#include "internal/fs.h"
45#include "internal/path.h"
46#include "internal/dir.h"
47
48
49
50RTDECL(int) RTDirCreate(const char *pszPath, RTFMODE fMode)
51{
52 /*
53 * Validate the file mode.
54 */
55 int rc;
56 fMode = rtFsModeNormalize(fMode, pszPath, 0);
57 if (rtFsModeIsValidPermissions(fMode))
58 {
59 /*
60 * Convert to UTF-16.
61 */
62 PRTUTF16 pwszString;
63 rc = RTStrToUtf16(pszPath, &pwszString);
64 AssertRC(rc);
65 if (RT_SUCCESS(rc))
66 {
67 /*
68 * Create the directory.
69 */
70 if (CreateDirectoryW((LPCWSTR)pwszString, NULL))
71 rc = VINF_SUCCESS;
72 else
73 rc = RTErrConvertFromWin32(GetLastError());
74
75 /*
76 * Turn off indexing of directory through Windows Indexing Service
77 */
78 if (RT_SUCCESS(rc))
79 {
80 if (SetFileAttributesW((LPCWSTR)pwszString, FILE_ATTRIBUTE_NOT_CONTENT_INDEXED))
81 rc = VINF_SUCCESS;
82 else
83 rc = RTErrConvertFromWin32(GetLastError());
84 }
85
86 RTUtf16Free(pwszString);
87 }
88 }
89 else
90 {
91 AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode));
92 rc = VERR_INVALID_FMODE;
93 }
94
95 LogFlow(("RTDirCreate(%p:{%s}, %RTfmode): returns %Rrc\n", pszPath, pszPath, fMode, rc));
96 return rc;
97}
98
99
100RTDECL(int) RTDirRemove(const char *pszPath)
101{
102 /*
103 * Convert to UTF-16.
104 */
105 PRTUTF16 pwszString;
106 int rc = RTStrToUtf16(pszPath, &pwszString);
107 AssertRC(rc);
108 if (RT_SUCCESS(rc))
109 {
110 /*
111 * Remove the directory.
112 */
113 if (RemoveDirectoryW((LPCWSTR)pwszString))
114 rc = VINF_SUCCESS;
115 else
116 rc = RTErrConvertFromWin32(GetLastError());
117
118 RTUtf16Free(pwszString);
119 }
120
121 LogFlow(("RTDirRemove(%p:{%s}): returns %Rrc\n", pszPath, pszPath, rc));
122 return rc;
123}
124
125
126RTDECL(int) RTDirFlush(const char *pszPath)
127{
128 return VERR_NOT_SUPPORTED;
129}
130
131
132int rtDirNativeOpen(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 PRTUTF16 pwszName;
163 rc = RTStrToUtf16(pszPathBuf, &pwszName);
164 if (RT_SUCCESS(rc))
165 {
166 pDir->hDir = FindFirstFileW((LPCWSTR)pwszName, &pDir->Data);
167 if (pDir->hDir != INVALID_HANDLE_VALUE)
168 pDir->fDataUnread = true;
169 /* theoretical case of an empty directory. */
170 else if (GetLastError() == ERROR_NO_MORE_FILES)
171 pDir->fDataUnread = false;
172 else
173 rc = RTErrConvertFromWin32(GetLastError());
174 RTUtf16Free(pwszName);
175 }
176
177 return rc;
178}
179
180
181RTDECL(int) RTDirClose(PRTDIR pDir)
182{
183 /*
184 * Validate input.
185 */
186 if (!pDir)
187 return VERR_INVALID_PARAMETER;
188 if (pDir->u32Magic != RTDIR_MAGIC)
189 {
190 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
191 return VERR_INVALID_PARAMETER;
192 }
193
194 /*
195 * Close the handle.
196 */
197 pDir->u32Magic++;
198 if (pDir->hDir != INVALID_HANDLE_VALUE)
199 {
200 BOOL fRc = FindClose(pDir->hDir);
201 Assert(fRc);
202 pDir->hDir = INVALID_HANDLE_VALUE;
203 }
204 RTStrFree(pDir->pszName);
205 pDir->pszName = NULL;
206 RTMemFree(pDir);
207
208 return VINF_SUCCESS;
209}
210
211
212RTDECL(int) RTDirRead(PRTDIR pDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
213{
214 /*
215 * Validate input.
216 */
217 if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
218 {
219 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
220 return VERR_INVALID_PARAMETER;
221 }
222 if (!pDirEntry)
223 {
224 AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
225 return VERR_INVALID_PARAMETER;
226 }
227 size_t cbDirEntry = sizeof(*pDirEntry);
228 if (pcbDirEntry)
229 {
230 cbDirEntry = *pcbDirEntry;
231 if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRY, szName[2]))
232 {
233 AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRY, szName[2])));
234 return VERR_INVALID_PARAMETER;
235 }
236 }
237
238 /*
239 * Fetch data?
240 */
241 if (!pDir->fDataUnread)
242 {
243 RTStrFree(pDir->pszName);
244 pDir->pszName = NULL;
245
246 BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
247 if (!fRc)
248 {
249 int iErr = GetLastError();
250 if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
251 return VERR_NO_MORE_FILES;
252 return RTErrConvertFromWin32(iErr);
253 }
254 }
255
256 /*
257 * Convert the filename to UTF-8.
258 */
259 if (!pDir->pszName)
260 {
261 int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
262 if (RT_FAILURE(rc))
263 {
264 pDir->pszName = NULL;
265 return rc;
266 }
267 pDir->cchName = strlen(pDir->pszName);
268 }
269
270 /*
271 * Check if we've got enough space to return the data.
272 */
273 const char *pszName = pDir->pszName;
274 const size_t cchName = pDir->cchName;
275 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRY, szName[1]) + cchName;
276 if (pcbDirEntry)
277 *pcbDirEntry = cbRequired;
278 if (cbRequired > cbDirEntry)
279 return VERR_BUFFER_OVERFLOW;
280
281 /*
282 * Setup the returned data.
283 */
284 pDir->fDataUnread = false;
285 pDirEntry->INodeId = 0; /** @todo we can use the fileid here if we must (see GetFileInformationByHandle). */
286 pDirEntry->enmType = pDir->Data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY
287 ? RTDIRENTRYTYPE_DIRECTORY : RTDIRENTRYTYPE_FILE;
288 pDirEntry->cbName = (uint16_t)cchName;
289 Assert(pDirEntry->cbName == cchName);
290 memcpy(pDirEntry->szName, pszName, cchName + 1);
291
292 return VINF_SUCCESS;
293}
294
295
296RTDECL(int) RTDirReadEx(PRTDIR pDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
297{
298 /** @todo Symlinks: Find[First|Next]FileW will return info about
299 the link, so RTPATH_F_FOLLOW_LINK is not handled correctly. */
300 /*
301 * Validate input.
302 */
303 if (!pDir || pDir->u32Magic != RTDIR_MAGIC)
304 {
305 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
306 return VERR_INVALID_PARAMETER;
307 }
308 if (!pDirEntry)
309 {
310 AssertMsgFailed(("Invalid pDirEntry=%p\n", pDirEntry));
311 return VERR_INVALID_PARAMETER;
312 }
313 if ( enmAdditionalAttribs < RTFSOBJATTRADD_NOTHING
314 || enmAdditionalAttribs > RTFSOBJATTRADD_LAST)
315 {
316 AssertMsgFailed(("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs));
317 return VERR_INVALID_PARAMETER;
318 }
319 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
320 size_t cbDirEntry = sizeof(*pDirEntry);
321 if (pcbDirEntry)
322 {
323 cbDirEntry = *pcbDirEntry;
324 if (cbDirEntry < RT_UOFFSETOF(RTDIRENTRYEX, szName[2]))
325 {
326 AssertMsgFailed(("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])));
327 return VERR_INVALID_PARAMETER;
328 }
329 }
330
331 /*
332 * Fetch data?
333 */
334 if (!pDir->fDataUnread)
335 {
336 RTStrFree(pDir->pszName);
337 pDir->pszName = NULL;
338
339 BOOL fRc = FindNextFileW(pDir->hDir, &pDir->Data);
340 if (!fRc)
341 {
342 int iErr = GetLastError();
343 if (pDir->hDir == INVALID_HANDLE_VALUE || iErr == ERROR_NO_MORE_FILES)
344 return VERR_NO_MORE_FILES;
345 return RTErrConvertFromWin32(iErr);
346 }
347 }
348
349 /*
350 * Convert the filename to UTF-8.
351 */
352 if (!pDir->pszName)
353 {
354 int rc = RTUtf16ToUtf8((PCRTUTF16)pDir->Data.cFileName, &pDir->pszName);
355 if (RT_FAILURE(rc))
356 {
357 pDir->pszName = NULL;
358 return rc;
359 }
360 pDir->cchName = strlen(pDir->pszName);
361 }
362
363 /*
364 * Check if we've got enough space to return the data.
365 */
366 const char *pszName = pDir->pszName;
367 const size_t cchName = pDir->cchName;
368 const size_t cbRequired = RT_OFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
369 if (pcbDirEntry)
370 *pcbDirEntry = cbRequired;
371 if (cbRequired > cbDirEntry)
372 return VERR_BUFFER_OVERFLOW;
373
374 /*
375 * Setup the returned data.
376 */
377 pDir->fDataUnread = false;
378 pDirEntry->cbName = (uint16_t)cchName;
379 Assert(pDirEntry->cbName == cchName);
380 memcpy(pDirEntry->szName, pszName, cchName + 1);
381 if (pDir->Data.cAlternateFileName[0])
382 {
383 /* copy and calc length */
384 PCRTUTF16 pwszSrc = (PCRTUTF16)pDir->Data.cAlternateFileName;
385 PRTUTF16 pwszDst = pDirEntry->wszShortName;
386 while (*pwszSrc)
387 *pwszDst++ = *pwszSrc++;
388 pDirEntry->cwcShortName = pwszDst - &pDirEntry->wszShortName[0];
389 /* zero the rest */
390 const PRTUTF16 pwszEnd = &pDirEntry->wszShortName[RT_ELEMENTS(pDirEntry->wszShortName)];
391 while (pwszDst < pwszEnd)
392 *pwszDst++ = '\0';
393 }
394 else
395 {
396 memset(pDirEntry->wszShortName, 0, sizeof(pDirEntry->wszShortName));
397 pDirEntry->cwcShortName = 0;
398 }
399
400 pDirEntry->Info.cbObject = ((uint64_t)pDir->Data.nFileSizeHigh << 32)
401 | (uint64_t)pDir->Data.nFileSizeLow;
402 pDirEntry->Info.cbAllocated = pDirEntry->Info.cbObject;
403
404 Assert(sizeof(uint64_t) == sizeof(pDir->Data.ftCreationTime));
405 RTTimeSpecSetNtTime(&pDirEntry->Info.BirthTime, *(uint64_t *)&pDir->Data.ftCreationTime);
406 RTTimeSpecSetNtTime(&pDirEntry->Info.AccessTime, *(uint64_t *)&pDir->Data.ftLastAccessTime);
407 RTTimeSpecSetNtTime(&pDirEntry->Info.ModificationTime, *(uint64_t *)&pDir->Data.ftLastWriteTime);
408 pDirEntry->Info.ChangeTime = pDirEntry->Info.ModificationTime;
409
410 pDirEntry->Info.Attr.fMode = rtFsModeFromDos((pDir->Data.dwFileAttributes << RTFS_DOS_SHIFT) & RTFS_DOS_MASK_NT,
411 pszName, cchName);
412
413 /*
414 * Requested attributes (we cannot provide anything actually).
415 */
416 switch (enmAdditionalAttribs)
417 {
418 case RTFSOBJATTRADD_EASIZE:
419 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
420 pDirEntry->Info.Attr.u.EASize.cb = 0;
421 break;
422
423 case RTFSOBJATTRADD_UNIX:
424 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX;
425 pDirEntry->Info.Attr.u.Unix.uid = ~0U;
426 pDirEntry->Info.Attr.u.Unix.gid = ~0U;
427 pDirEntry->Info.Attr.u.Unix.cHardlinks = 1;
428 pDirEntry->Info.Attr.u.Unix.INodeIdDevice = 0; /** @todo Use the volume serial number (see GetFileInformationByHandle). */
429 pDirEntry->Info.Attr.u.Unix.INodeId = 0; /** @todo Use the fileid (see GetFileInformationByHandle). */
430 pDirEntry->Info.Attr.u.Unix.fFlags = 0;
431 pDirEntry->Info.Attr.u.Unix.GenerationId = 0;
432 pDirEntry->Info.Attr.u.Unix.Device = 0;
433 break;
434
435 case RTFSOBJATTRADD_NOTHING:
436 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
437 break;
438
439 case RTFSOBJATTRADD_UNIX_OWNER:
440 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_OWNER;
441 pDirEntry->Info.Attr.u.UnixOwner.uid = ~0U;
442 pDirEntry->Info.Attr.u.UnixOwner.szName[0] = '\0'; /** @todo return something sensible here. */
443 break;
444
445 case RTFSOBJATTRADD_UNIX_GROUP:
446 pDirEntry->Info.Attr.enmAdditional = RTFSOBJATTRADD_UNIX_GROUP;
447 pDirEntry->Info.Attr.u.UnixGroup.gid = ~0U;
448 pDirEntry->Info.Attr.u.UnixGroup.szName[0] = '\0';
449 break;
450
451 default:
452 AssertMsgFailed(("Impossible!\n"));
453 return VERR_INTERNAL_ERROR;
454 }
455
456 return VINF_SUCCESS;
457}
458
459
460RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename)
461{
462 /*
463 * Validate input.
464 */
465 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
466 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
467 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
468 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
469 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
470
471 /*
472 * Call the worker.
473 */
474 int rc = rtPathWin32MoveRename(pszSrc, pszDst,
475 fRename & RTPATHRENAME_FLAGS_REPLACE ? MOVEFILE_REPLACE_EXISTING : 0,
476 RTFS_TYPE_DIRECTORY);
477
478 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
479 return rc;
480}
481
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