VirtualBox

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

Last change on this file since 7300 was 6971, checked in by vboxsync, 17 years ago

Fixed: Newly created files and directories won't be indexed automatically anymore by the Windows Indexing Service.

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