VirtualBox

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

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

IPRT/RTDirRemove/posix: Translate EEXIST to VERR_DIR_NOT_EMTPY as solaris returns it for non-empty directories and opengroup documents EEXIST and ENOTEMPTY as equivalent. bugref:9172

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