VirtualBox

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

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

*: Made RT_UOFFSETOF, RT_OFFSETOF, RT_UOFFSETOF_ADD and RT_OFFSETOF_ADD work like builtin_offsetof() and require compile time resolvable requests, adding RT_UOFFSETOF_DYN for the dynamic questions that can only be answered at runtime.

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