VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/dir-posix.cpp@ 76878

Last change on this file since 76878 was 76878, checked in by vboxsync, 6 years ago

IPRT/dir-poix.cpp,FsPerf.cpp: Darwin adjustments, realizing that the posix mkdir/rmdir code in IPRT does unnecessary work compared to windows wrt return codes in the already-exists-by-is-not-a-directory cases. Better have the functions return same statuses on all platforms where possibble. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 22.9 KB
Line 
1/* $Id: dir-posix.cpp 76878 2019-01-18 10:15:56Z vboxsync $ */
2/** @file
3 * IPRT - Directory manipulation, POSIX.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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 <errno.h>
33#include <unistd.h>
34#include <sys/types.h>
35#include <sys/stat.h>
36#include <fcntl.h>
37#include <dirent.h>
38#include <dlfcn.h>
39#include <stdio.h>
40
41#include <iprt/dir.h>
42#include "internal/iprt.h"
43
44#include <iprt/alloca.h>
45#include <iprt/asm.h>
46#include <iprt/assert.h>
47#include <iprt/err.h>
48#include <iprt/log.h>
49#include <iprt/mem.h>
50#include <iprt/param.h>
51#include <iprt/path.h>
52#include <iprt/string.h>
53#include "internal/dir.h"
54#include "internal/fs.h"
55#include "internal/path.h"
56
57#if !defined(RT_OS_SOLARIS) && !defined(RT_OS_HAIKU)
58# define HAVE_DIRENT_D_TYPE 1
59#endif
60
61
62RTDECL(bool) RTDirExists(const char *pszPath)
63{
64 bool fRc = false;
65 char const *pszNativePath;
66 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);
67 if (RT_SUCCESS(rc))
68 {
69 struct stat s;
70 fRc = !stat(pszNativePath, &s)
71 && S_ISDIR(s.st_mode);
72
73 rtPathFreeNative(pszNativePath, pszPath);
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, uint32_t fCreate)
82{
83 RT_NOREF_PV(fCreate);
84
85 int rc;
86 fMode = rtFsModeNormalize(fMode, pszPath, 0);
87 if (rtFsModeIsValidPermissions(fMode))
88 {
89 char const *pszNativePath;
90 rc = rtPathToNative(&pszNativePath, pszPath, NULL);
91 if (RT_SUCCESS(rc))
92 {
93 if (mkdir(pszNativePath, fMode & RTFS_UNIX_MASK) == 0)
94 rc = VINF_SUCCESS;
95 else
96 {
97 rc = errno;
98 /*bool fVerifyIsDir = true; - Windows returns VERR_ALREADY_EXISTS, so why bother with this. */
99#ifdef RT_OS_SOLARIS
100 /*
101 * mkdir on nfs mount points has been/is busted in various
102 * during the Nevada development cycle. We've observed:
103 * - Build 111b (2009.06) returns EACCES.
104 * - Build ca. 70-80 returns ENOSYS.
105 */
106 if ( rc == ENOSYS
107 || rc == EACCES)
108 {
109 rc = RTErrConvertFromErrno(rc);
110 fVerifyIsDir = false; /* We'll check if it's a dir ourselves since we're going to stat() anyway. */
111 struct stat st;
112 if (!stat(pszNativePath, &st))
113 {
114 rc = VERR_ALREADY_EXISTS;
115 /* Windows returns VERR_ALREADY_EXISTS, so why bother with this:
116 if (!S_ISDIR(st.st_mode))
117 rc = VERR_IS_A_FILE; */
118 }
119 }
120 else
121 rc = RTErrConvertFromErrno(rc);
122#else
123 rc = RTErrConvertFromErrno(rc);
124#endif
125#if 0 /* Windows returns VERR_ALREADY_EXISTS, so why bother with this. */
126 if ( rc == VERR_ALREADY_EXISTS
127 && fVerifyIsDir == true)
128 {
129 /*
130 * Verify that it really exists as a directory.
131 */
132 struct stat st;
133 if (!stat(pszNativePath, &st) && !S_ISDIR(st.st_mode))
134 rc = VERR_IS_A_FILE;
135 }
136#endif
137 }
138 }
139
140 rtPathFreeNative(pszNativePath, pszPath);
141 }
142 else
143 {
144 AssertMsgFailed(("Invalid file mode! %RTfmode\n", fMode));
145 rc = VERR_INVALID_FMODE;
146 }
147 LogFlow(("RTDirCreate(%p={%s}, %RTfmode): returns %Rrc\n", pszPath, pszPath, fMode, rc));
148 return rc;
149}
150
151
152RTDECL(int) RTDirRemove(const char *pszPath)
153{
154 char const *pszNativePath;
155 int rc = rtPathToNative(&pszNativePath, pszPath, NULL);
156 if (RT_SUCCESS(rc))
157 {
158 if (rmdir(pszNativePath))
159 {
160 rc = errno;
161 if (rc != ENOTDIR)
162 rc = RTErrConvertFromErrno(rc);
163 else
164 {
165 rc = RTErrConvertFromErrno(rc);
166 struct stat st;
167 if (!stat(pszNativePath, &st) && !S_ISDIR(st.st_mode))
168 rc = VERR_NOT_A_DIRECTORY;
169 }
170 }
171
172 rtPathFreeNative(pszNativePath, pszPath);
173 }
174
175 LogFlow(("RTDirRemove(%p={%s}): returns %Rrc\n", pszPath, pszPath, rc));
176 return rc;
177}
178
179
180RTDECL(int) RTDirFlush(const char *pszPath)
181{
182 /*
183 * Linux: The fsync() man page hints at this being required for ensuring
184 * consistency between directory and file in case of a crash.
185 *
186 * Solaris: No mentioned is made of directories on the fsync man page.
187 * While rename+fsync will do what we want on ZFS, the code needs more
188 * careful studying wrt whether the directory entry of a new file is
189 * implicitly synced when the file is synced (it's very likely for ZFS).
190 *
191 * FreeBSD: The FFS fsync code seems to flush the directory entry as well
192 * in some cases. Don't know exactly what's up with rename, but from the
193 * look of things fsync(dir) should work.
194 */
195 int rc;
196#ifdef O_DIRECTORY
197 int fd = open(pszPath, O_RDONLY | O_DIRECTORY, 0);
198#else
199 int fd = open(pszPath, O_RDONLY, 0);
200#endif
201 if (fd >= 0)
202 {
203 if (fsync(fd) == 0)
204 rc = VINF_SUCCESS;
205 else
206 {
207 /* Linux fsync(2) man page documents both errors as an indication
208 * that the file descriptor can't be flushed (seen EINVAL for usual
209 * directories on CIFS). BSD (OS X) fsync(2) documents only the
210 * latter, and Solaris fsync(3C) pretends there is no problem. */
211 if (errno == EROFS || errno == EINVAL)
212 rc = VERR_NOT_SUPPORTED;
213 else
214 rc = RTErrConvertFromErrno(errno);
215 }
216 close(fd);
217 }
218 else
219 rc = RTErrConvertFromErrno(errno);
220 return rc;
221}
222
223
224size_t rtDirNativeGetStructSize(const char *pszPath)
225{
226 long cbNameMax = pathconf(pszPath, _PC_NAME_MAX);
227# ifdef NAME_MAX
228 if (cbNameMax < NAME_MAX) /* This is plain paranoia, but it doesn't hurt. */
229 cbNameMax = NAME_MAX;
230# endif
231# ifdef _XOPEN_NAME_MAX
232 if (cbNameMax < _XOPEN_NAME_MAX) /* Ditto. */
233 cbNameMax = _XOPEN_NAME_MAX;
234# endif
235 size_t cbDir = RT_UOFFSETOF_DYN(RTDIRINTERNAL, Data.d_name[cbNameMax + 1]);
236 if (cbDir < sizeof(RTDIRINTERNAL)) /* Ditto. */
237 cbDir = sizeof(RTDIRINTERNAL);
238 cbDir = RT_ALIGN_Z(cbDir, 8);
239
240 return cbDir;
241}
242
243
244int rtDirNativeOpen(PRTDIRINTERNAL pDir, char *pszPathBuf, uintptr_t hRelativeDir, void *pvNativeRelative)
245{
246 NOREF(pszPathBuf); /* only used on windows */
247 NOREF(hRelativeDir);
248 NOREF(pvNativeRelative);
249
250 /*
251 * Convert to a native path and try opendir.
252 */
253 char *pszSlash = NULL;
254 char const *pszNativePath;
255 int rc;
256 if ( !(pDir->fFlags & RTDIR_F_NO_FOLLOW)
257 || pDir->fDirSlash
258 || pDir->cchPath <= 1)
259 rc = rtPathToNative(&pszNativePath, pDir->pszPath, NULL);
260 else
261 {
262 pszSlash = (char *)&pDir->pszPath[pDir->cchPath - 1];
263 *pszSlash = '\0';
264 rc = rtPathToNative(&pszNativePath, pDir->pszPath, NULL);
265 }
266 if (RT_SUCCESS(rc))
267 {
268 if ( !(pDir->fFlags & RTDIR_F_NO_FOLLOW)
269 || pDir->fDirSlash)
270 pDir->pDir = opendir(pszNativePath);
271 else
272 {
273 /*
274 * If we can get fdopendir() and have both O_NOFOLLOW and O_DIRECTORY,
275 * we will use open() to safely open the directory without following
276 * symlinks in the final component, and then use fdopendir to get a DIR
277 * from the file descriptor.
278 *
279 * If we cannot get that, we will use lstat() + opendir() as a fallback.
280 *
281 * We ASSUME that support for the O_NOFOLLOW and O_DIRECTORY flags is
282 * older than fdopendir().
283 */
284#if defined(O_NOFOLLOW) && defined(O_DIRECTORY)
285 /* Need to resolve fdopendir dynamically. */
286 typedef DIR * (*PFNFDOPENDIR)(int);
287 static PFNFDOPENDIR s_pfnFdOpenDir = NULL;
288 static bool volatile s_fInitalized = false;
289
290 PFNFDOPENDIR pfnFdOpenDir = s_pfnFdOpenDir;
291 ASMCompilerBarrier();
292 if (s_fInitalized)
293 { /* likely */ }
294 else
295 {
296 pfnFdOpenDir = (PFNFDOPENDIR)(uintptr_t)dlsym(RTLD_DEFAULT, "fdopendir");
297 s_pfnFdOpenDir = pfnFdOpenDir;
298 ASMAtomicWriteBool(&s_fInitalized, true);
299 }
300
301 if (pfnFdOpenDir)
302 {
303 int fd = open(pszNativePath, O_RDONLY | O_DIRECTORY | O_NOFOLLOW, 0);
304 if (fd >= 0)
305 {
306 pDir->pDir = pfnFdOpenDir(fd);
307 if (RT_UNLIKELY(!pDir->pDir))
308 {
309 rc = RTErrConvertFromErrno(errno);
310 close(fd);
311 }
312 }
313 else
314 {
315 /* WSL returns ELOOP here, but we take no chances that O_NOFOLLOW
316 takes precedence over O_DIRECTORY everywhere. */
317 int iErr = errno;
318 if (iErr == ELOOP || iErr == ENOTDIR)
319 {
320 struct stat St;
321 if ( lstat(pszNativePath, &St) == 0
322 && S_ISLNK(St.st_mode))
323 rc = VERR_IS_A_SYMLINK;
324 else
325 rc = RTErrConvertFromErrno(iErr);
326 }
327 }
328 }
329 else
330#endif
331 {
332 /* Fallback. This contains a race condition. */
333 struct stat St;
334 if ( lstat(pszNativePath, &St) != 0
335 || !S_ISLNK(St.st_mode))
336 pDir->pDir = opendir(pszNativePath);
337 else
338 rc = VERR_IS_A_SYMLINK;
339 }
340 }
341 if (pDir->pDir)
342 {
343 /*
344 * Init data (allocated as all zeros).
345 */
346 pDir->fDataUnread = false; /* spelling it out */
347 }
348 else if (RT_SUCCESS_NP(rc))
349 rc = RTErrConvertFromErrno(errno);
350
351 rtPathFreeNative(pszNativePath, pDir->pszPath);
352 }
353 if (pszSlash)
354 *pszSlash = RTPATH_SLASH;
355 return rc;
356}
357
358
359RTDECL(int) RTDirClose(RTDIR hDir)
360{
361 PRTDIRINTERNAL pDir = hDir;
362
363 /*
364 * Validate input.
365 */
366 if (!pDir)
367 return VERR_INVALID_PARAMETER;
368 if (pDir->u32Magic != RTDIR_MAGIC)
369 {
370 AssertMsgFailed(("Invalid pDir=%p\n", pDir));
371 return VERR_INVALID_PARAMETER;
372 }
373
374 /*
375 * Close the handle.
376 */
377 int rc = VINF_SUCCESS;
378 pDir->u32Magic = RTDIR_MAGIC_DEAD;
379 if (closedir(pDir->pDir))
380 {
381 rc = RTErrConvertFromErrno(errno);
382 AssertMsgFailed(("closedir(%p) -> errno=%d (%Rrc)\n", pDir->pDir, errno, rc));
383 }
384
385 RTMemFree(pDir);
386 return rc;
387}
388
389
390/**
391 * Ensure that there is unread data in the buffer
392 * and that there is a converted filename hanging around.
393 *
394 * @returns IPRT status code.
395 * @param pDir the open directory. Fully validated.
396 */
397static int rtDirReadMore(PRTDIRINTERNAL pDir)
398{
399 /** @todo try avoid the rematching on buffer overflow errors. */
400 for (;;)
401 {
402 /*
403 * Fetch data?
404 */
405 if (!pDir->fDataUnread)
406 {
407 struct dirent *pResult = NULL;
408#if RT_GNUC_PREREQ(4, 6)
409# pragma GCC diagnostic push
410# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
411#endif
412 int rc = readdir_r(pDir->pDir, &pDir->Data, &pResult);
413#if RT_GNUC_PREREQ(4, 6)
414# pragma GCC diagnostic pop
415#endif
416 if (rc)
417 {
418 rc = RTErrConvertFromErrno(rc);
419 /** @todo Consider translating ENOENT (The current
420 * position of the directory stream is invalid)
421 * differently. */
422 AssertMsg(rc == VERR_FILE_NOT_FOUND, ("%Rrc\n", rc));
423 return rc;
424 }
425 if (!pResult)
426 return VERR_NO_MORE_FILES;
427 }
428
429 /*
430 * Convert the filename to UTF-8.
431 */
432 if (!pDir->pszName)
433 {
434 int rc = rtPathFromNative(&pDir->pszName, pDir->Data.d_name, pDir->pszPath);
435 if (RT_FAILURE(rc))
436 {
437 pDir->pszName = NULL;
438 return rc;
439 }
440 pDir->cchName = strlen(pDir->pszName);
441 }
442 if ( !pDir->pfnFilter
443 || pDir->pfnFilter(pDir, pDir->pszName))
444 break;
445 rtPathFreeIprt(pDir->pszName, pDir->Data.d_name);
446 pDir->pszName = NULL;
447 pDir->fDataUnread = false;
448 }
449
450 pDir->fDataUnread = true;
451 return VINF_SUCCESS;
452}
453
454
455#ifdef HAVE_DIRENT_D_TYPE
456/**
457 * Converts the d_type field to IPRT directory entry type.
458 *
459 * @returns IPRT directory entry type.
460 * @param Unix
461 */
462static RTDIRENTRYTYPE rtDirType(int iType)
463{
464 switch (iType)
465 {
466 case DT_UNKNOWN: return RTDIRENTRYTYPE_UNKNOWN;
467 case DT_FIFO: return RTDIRENTRYTYPE_FIFO;
468 case DT_CHR: return RTDIRENTRYTYPE_DEV_CHAR;
469 case DT_DIR: return RTDIRENTRYTYPE_DIRECTORY;
470 case DT_BLK: return RTDIRENTRYTYPE_DEV_BLOCK;
471 case DT_REG: return RTDIRENTRYTYPE_FILE;
472 case DT_LNK: return RTDIRENTRYTYPE_SYMLINK;
473 case DT_SOCK: return RTDIRENTRYTYPE_SOCKET;
474 case DT_WHT: return RTDIRENTRYTYPE_WHITEOUT;
475 default:
476 AssertMsgFailed(("iType=%d\n", iType));
477 return RTDIRENTRYTYPE_UNKNOWN;
478 }
479}
480#endif /*HAVE_DIRENT_D_TYPE */
481
482
483RTDECL(int) RTDirRead(RTDIR hDir, PRTDIRENTRY pDirEntry, size_t *pcbDirEntry)
484{
485 PRTDIRINTERNAL pDir = hDir;
486
487 /*
488 * Validate and digest input.
489 */
490 if (!rtDirValidHandle(pDir))
491 return VERR_INVALID_PARAMETER;
492 AssertMsgReturn(VALID_PTR(pDirEntry), ("%p\n", pDirEntry), VERR_INVALID_POINTER);
493
494 size_t cbDirEntry = sizeof(*pDirEntry);
495 if (pcbDirEntry)
496 {
497 AssertMsgReturn(VALID_PTR(pcbDirEntry), ("%p\n", pcbDirEntry), VERR_INVALID_POINTER);
498 cbDirEntry = *pcbDirEntry;
499 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRY, szName[2]),
500 ("Invalid *pcbDirEntry=%d (min %zu)\n", *pcbDirEntry, RT_UOFFSETOF(RTDIRENTRYEX, szName[2])),
501 VERR_INVALID_PARAMETER);
502 }
503
504 /*
505 * Fetch more data if necessary and/or convert the name.
506 */
507 int rc = rtDirReadMore(pDir);
508 if (RT_SUCCESS(rc))
509 {
510 /*
511 * Check if we've got enough space to return the data.
512 */
513 const char *pszName = pDir->pszName;
514 const size_t cchName = pDir->cchName;
515 const size_t cbRequired = RT_UOFFSETOF(RTDIRENTRY, szName[1]) + cchName;
516 if (pcbDirEntry)
517 *pcbDirEntry = cbRequired;
518 if (cbRequired <= cbDirEntry)
519 {
520 /*
521 * Setup the returned data.
522 */
523 pDirEntry->INodeId = pDir->Data.d_ino; /* may need #ifdefing later */
524#ifdef HAVE_DIRENT_D_TYPE
525 pDirEntry->enmType = rtDirType(pDir->Data.d_type);
526#else
527 pDirEntry->enmType = RTDIRENTRYTYPE_UNKNOWN;
528#endif
529 pDirEntry->cbName = (uint16_t)cchName;
530 Assert(pDirEntry->cbName == cchName);
531 memcpy(pDirEntry->szName, pszName, cchName + 1);
532
533 /* free cached data */
534 pDir->fDataUnread = false;
535 rtPathFreeIprt(pDir->pszName, pDir->Data.d_name);
536 pDir->pszName = NULL;
537 }
538 else
539 rc = VERR_BUFFER_OVERFLOW;
540 }
541
542 LogFlow(("RTDirRead(%p:{%s}, %p:{%s}, %p:{%u}): returns %Rrc\n",
543 pDir, pDir->pszPath, pDirEntry, RT_SUCCESS(rc) ? pDirEntry->szName : "<failed>",
544 pcbDirEntry, pcbDirEntry ? *pcbDirEntry : 0, rc));
545 return rc;
546}
547
548
549/**
550 * Fills dummy info into the info structure.
551 * This function is called if we cannot stat the file.
552 *
553 * @param pInfo The struct in question.
554 * @param
555 */
556static void rtDirSetDummyInfo(PRTFSOBJINFO pInfo, RTDIRENTRYTYPE enmType)
557{
558 pInfo->cbObject = 0;
559 pInfo->cbAllocated = 0;
560 RTTimeSpecSetNano(&pInfo->AccessTime, 0);
561 RTTimeSpecSetNano(&pInfo->ModificationTime, 0);
562 RTTimeSpecSetNano(&pInfo->ChangeTime, 0);
563 RTTimeSpecSetNano(&pInfo->BirthTime, 0);
564 memset(&pInfo->Attr, 0, sizeof(pInfo->Attr));
565 pInfo->Attr.enmAdditional = RTFSOBJATTRADD_NOTHING;
566 switch (enmType)
567 {
568 default:
569 case RTDIRENTRYTYPE_UNKNOWN: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL; break;
570 case RTDIRENTRYTYPE_FIFO: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FIFO; break;
571 case RTDIRENTRYTYPE_DEV_CHAR: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_DEV_CHAR; break;
572 case RTDIRENTRYTYPE_DIRECTORY: pInfo->Attr.fMode = RTFS_DOS_DIRECTORY | RTFS_TYPE_DIRECTORY; break;
573 case RTDIRENTRYTYPE_DEV_BLOCK: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_DEV_BLOCK; break;
574 case RTDIRENTRYTYPE_FILE: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_FILE; break;
575 case RTDIRENTRYTYPE_SYMLINK: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_SYMLINK; break;
576 case RTDIRENTRYTYPE_SOCKET: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_SOCKET; break;
577 case RTDIRENTRYTYPE_WHITEOUT: pInfo->Attr.fMode = RTFS_DOS_NT_NORMAL | RTFS_TYPE_WHITEOUT; break;
578 }
579}
580
581
582RTDECL(int) RTDirReadEx(RTDIR hDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry,
583 RTFSOBJATTRADD enmAdditionalAttribs, uint32_t fFlags)
584{
585 PRTDIRINTERNAL pDir = hDir;
586
587 /*
588 * Validate and digest input.
589 */
590 if (!rtDirValidHandle(pDir))
591 return VERR_INVALID_PARAMETER;
592 AssertMsgReturn(VALID_PTR(pDirEntry), ("%p\n", pDirEntry), VERR_INVALID_POINTER);
593 AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
594 && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
595 ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
596 VERR_INVALID_PARAMETER);
597 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
598 size_t cbDirEntry = sizeof(*pDirEntry);
599 if (pcbDirEntry)
600 {
601 AssertMsgReturn(VALID_PTR(pcbDirEntry), ("%p\n", pcbDirEntry), VERR_INVALID_POINTER);
602 cbDirEntry = *pcbDirEntry;
603 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
604 ("Invalid *pcbDirEntry=%zu (min %zu)\n", *pcbDirEntry, RT_UOFFSETOF(RTDIRENTRYEX, szName[2])),
605 VERR_INVALID_PARAMETER);
606 }
607
608 /*
609 * Fetch more data if necessary and/or convert the name.
610 */
611 int rc = rtDirReadMore(pDir);
612 if (RT_SUCCESS(rc))
613 {
614 /*
615 * Check if we've got enough space to return the data.
616 */
617 const char *pszName = pDir->pszName;
618 const size_t cchName = pDir->cchName;
619 const size_t cbRequired = RT_UOFFSETOF(RTDIRENTRYEX, szName[1]) + cchName;
620 if (pcbDirEntry)
621 *pcbDirEntry = cbRequired;
622 if (cbRequired <= cbDirEntry)
623 {
624 /*
625 * Setup the returned data.
626 */
627 pDirEntry->cwcShortName = 0;
628 pDirEntry->wszShortName[0] = 0;
629 pDirEntry->cbName = (uint16_t)cchName;
630 Assert(pDirEntry->cbName == cchName);
631 memcpy(pDirEntry->szName, pszName, cchName + 1);
632
633 /* get the info data */
634 size_t cch = cchName + pDir->cchPath + 1;
635 char *pszNamePath = (char *)alloca(cch);
636 if (pszNamePath)
637 {
638 memcpy(pszNamePath, pDir->pszPath, pDir->cchPath);
639 memcpy(pszNamePath + pDir->cchPath, pszName, cchName + 1);
640 rc = RTPathQueryInfoEx(pszNamePath, &pDirEntry->Info, enmAdditionalAttribs, fFlags);
641 }
642 else
643 rc = VERR_NO_MEMORY;
644 if (RT_FAILURE(rc))
645 {
646#ifdef HAVE_DIRENT_D_TYPE
647 rtDirSetDummyInfo(&pDirEntry->Info, rtDirType(pDir->Data.d_type));
648#else
649 rtDirSetDummyInfo(&pDirEntry->Info, RTDIRENTRYTYPE_UNKNOWN);
650#endif
651 rc = VWRN_NO_DIRENT_INFO;
652 }
653
654 /* free cached data */
655 pDir->fDataUnread = false;
656 rtPathFreeIprt(pDir->pszName, pDir->Data.d_name);
657 pDir->pszName = NULL;
658 }
659 else
660 rc = VERR_BUFFER_OVERFLOW;
661 }
662
663 return rc;
664}
665
666
667RTDECL(int) RTDirRewind(RTDIR hDir)
668{
669 PRTDIRINTERNAL pDir = hDir;
670
671 /*
672 * Validate and digest input.
673 */
674 if (!rtDirValidHandle(pDir))
675 return VERR_INVALID_PARAMETER;
676
677 /*
678 * Do the rewinding.
679 */
680 /** @todo OS/2 does not rescan the directory as it should. */
681 rewinddir(pDir->pDir);
682 pDir->fDataUnread = false;
683
684 return VINF_SUCCESS;
685}
686
687
688RTDECL(int) RTDirRename(const char *pszSrc, const char *pszDst, unsigned fRename)
689{
690 /*
691 * Validate input.
692 */
693 AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
694 AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
695 AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
696 AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
697 AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
698
699 /*
700 * Take common cause with RTPathRename.
701 */
702 int rc = rtPathPosixRename(pszSrc, pszDst, fRename, RTFS_TYPE_DIRECTORY);
703
704 LogFlow(("RTDirRename(%p:{%s}, %p:{%s}): returns %Rrc\n",
705 pszSrc, pszSrc, pszDst, pszDst, rc));
706 return rc;
707}
708
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