VirtualBox

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

Last change on this file was 101160, checked in by vboxsync, 9 months ago

trying to fix additions warning for r3/posix/dir-posix.cpp(111), comparison between signed and unsigned integer expressions

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

© 2023 Oracle
ContactPrivacy policyTerms of Use