VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/dir.cpp@ 108150

最後變更 在這個檔案從108150是 107788,由 vboxsync 提交於 2 月 前

Runtime/r3/dir.cpp: Remove unused variable, bugref:3409

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Id Revision
檔案大小: 28.5 KB
 
1/* $Id: dir.cpp 107788 2025-01-15 15:38:06Z vboxsync $ */
2/** @file
3 * IPRT - Directory Manipulation, Part 1.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
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 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
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
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.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_DIR
42#include <iprt/dir.h>
43#include "internal/iprt.h"
44
45#include <iprt/alloca.h>
46#include <iprt/assert.h>
47#include <iprt/file.h>
48#include <iprt/err.h>
49#include <iprt/log.h>
50#include <iprt/mem.h>
51#include <iprt/param.h>
52#include <iprt/path.h>
53#include <iprt/string.h>
54#include <iprt/uni.h>
55#define RTDIR_AGNOSTIC
56#include "internal/dir.h"
57#include "internal/path.h"
58
59
60static DECLCALLBACK(bool) rtDirFilterWinNtMatch(PRTDIRINTERNAL pDir, const char *pszName);
61static DECLCALLBACK(bool) rtDirFilterWinNtMatchNoWildcards(PRTDIRINTERNAL pDir, const char *pszName);
62DECLINLINE(bool) rtDirFilterWinNtMatchEon(PCRTUNICP puszFilter);
63static bool rtDirFilterWinNtMatchDosStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter);
64static bool rtDirFilterWinNtMatchStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter);
65static bool rtDirFilterWinNtMatchBase(unsigned iDepth, const char *pszName, PCRTUNICP puszFilter);
66
67
68
69RTDECL(int) RTDirCreateFullPath(const char *pszPath, RTFMODE fMode)
70{
71 return RTDirCreateFullPathEx(pszPath, fMode, 0);
72}
73
74
75RTDECL(int) RTDirCreateFullPathEx(const char *pszPath, RTFMODE fMode, uint32_t fFlags)
76{
77 /*
78 * Resolve the path.
79 */
80 char *pszAbsPath = RTPathAbsDup(pszPath);
81 if (!pszAbsPath)
82 return VERR_NO_TMP_MEMORY;
83
84 /*
85 * Iterate the path components making sure each of them exists.
86 */
87 /* skip volume name */
88 char *psz = &pszAbsPath[rtPathVolumeSpecLen(pszAbsPath)];
89
90 /* skip the root slash if any */
91 if (RTPATH_IS_SLASH(*psz))
92 psz++;
93
94 /* iterate over path components. */
95 int rc = VINF_SUCCESS;
96 do
97 {
98 /* the next component is NULL, stop iterating */
99 if (!*psz)
100 break;
101#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
102 char *psz2 = strchr(psz, '/');
103 psz = strchr(psz, RTPATH_SLASH);
104 if (psz2 && (!psz || (uintptr_t)psz2 < (uintptr_t)psz))
105 psz = psz2;
106#else
107 psz = strchr(psz, RTPATH_SLASH);
108#endif
109 if (psz)
110 *psz = '\0';
111
112 /*
113 * ASSUME that RTDirCreate will return VERR_ALREADY_EXISTS and not VERR_ACCESS_DENIED in those cases
114 * where the directory exists but we don't have write access to the parent directory.
115 */
116 rc = RTDirCreate(pszAbsPath, fMode, fFlags);
117 if (rc == VERR_ALREADY_EXISTS)
118 rc = VINF_SUCCESS;
119
120 if (!psz)
121 break;
122 *psz++ = RTPATH_DELIMITER;
123 } while (RT_SUCCESS(rc));
124
125 RTStrFree(pszAbsPath);
126 return rc;
127}
128
129
130/**
131 * Filter a the filename in the against a filter.
132 *
133 * @returns true if the name matches the filter.
134 * @returns false if the name doesn't match filter.
135 * @param pDir The directory handle.
136 * @param pszName The path to match to the filter.
137 */
138static DECLCALLBACK(bool) rtDirFilterWinNtMatchNoWildcards(PRTDIRINTERNAL pDir, const char *pszName)
139{
140 /*
141 * Walk the string and compare.
142 */
143 PCRTUNICP pucFilter = pDir->puszFilter;
144 const char *psz = pszName;
145 RTUNICP uc;
146 do
147 {
148 int rc = RTStrGetCpEx(&psz, &uc);
149 AssertRCReturn(rc, false);
150 RTUNICP ucFilter = *pucFilter++;
151 if ( uc != ucFilter
152 && RTUniCpToUpper(uc) != ucFilter)
153 return false;
154 } while (uc);
155 return true;
156}
157
158
159/**
160 * Matches end of name.
161 */
162DECLINLINE(bool) rtDirFilterWinNtMatchEon(PCRTUNICP puszFilter)
163{
164 RTUNICP ucFilter;
165 while ( (ucFilter = *puszFilter) == '>'
166 || ucFilter == '<'
167 || ucFilter == '*'
168 || ucFilter == '"')
169 puszFilter++;
170 return !ucFilter;
171}
172
173
174/**
175 * Recursive star matching.
176 * Practically the same as normal star, except that the dos star stops
177 * when hitting the last dot.
178 *
179 * @returns true on match.
180 * @returns false on miss.
181 */
182static bool rtDirFilterWinNtMatchDosStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter)
183{
184 AssertReturn(iDepth++ < 256, false);
185
186 /*
187 * If there is no dos star, we should work just like the NT star.
188 * Since that's generally faster algorithms, we jump down to there if we can.
189 */
190 const char *pszDosDot = strrchr(pszNext, '.');
191 if (!pszDosDot && uc == '.')
192 pszDosDot = pszNext - 1;
193 if (!pszDosDot)
194 return rtDirFilterWinNtMatchStar(iDepth, uc, pszNext, puszFilter);
195
196 /*
197 * Inspect the next filter char(s) until we find something to work on.
198 */
199 RTUNICP ucFilter = *puszFilter++;
200 switch (ucFilter)
201 {
202 /*
203 * The star expression is the last in the pattern.
204 * We're fine if the name ends with a dot.
205 */
206 case '\0':
207 return !pszDosDot[1];
208
209 /*
210 * Simplified by brute force.
211 */
212 case '>': /* dos question mark */
213 case '?':
214 case '*':
215 case '<': /* dos star */
216 case '"': /* dos dot */
217 {
218 puszFilter--;
219 const char *pszStart = pszNext;
220 do
221 {
222 if (rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
223 return true;
224 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
225 } while ((intptr_t)pszDosDot - (intptr_t)pszNext >= -1);
226
227 /* backtrack and do the current char. */
228 pszNext = RTStrPrevCp(NULL, pszStart); AssertReturn(pszNext, false);
229 return rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter);
230 }
231
232 /*
233 * Ok, we've got zero or more characters.
234 * We'll try match starting at each occurrence of this character.
235 */
236 default:
237 {
238 if ( RTUniCpToUpper(uc) == ucFilter
239 && rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
240 return true;
241 do
242 {
243 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
244 if ( RTUniCpToUpper(uc) == ucFilter
245 && rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
246 return true;
247 } while ((intptr_t)pszDosDot - (intptr_t)pszNext >= -1);
248 return false;
249 }
250 }
251 /* won't ever get here! */
252}
253
254
255/**
256 * Recursive star matching.
257 *
258 * @returns true on match.
259 * @returns false on miss.
260 */
261static bool rtDirFilterWinNtMatchStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter)
262{
263 AssertReturn(iDepth++ < 256, false);
264
265 /*
266 * Inspect the next filter char(s) until we find something to work on.
267 */
268 for (;;)
269 {
270 RTUNICP ucFilter = *puszFilter++;
271 switch (ucFilter)
272 {
273 /*
274 * The star expression is the last in the pattern.
275 * Cool, that means we're done!
276 */
277 case '\0':
278 return true;
279
280 /*
281 * Just in case (doubt we ever get here), just merge it with the current one.
282 */
283 case '*':
284 break;
285
286 /*
287 * Skip a fixed number of chars.
288 * Figure out how many by walking the filter ignoring '*'s.
289 */
290 case '?':
291 {
292 unsigned cQms = 1;
293 while ((ucFilter = *puszFilter) == '*' || ucFilter == '?')
294 {
295 cQms += ucFilter == '?';
296 puszFilter++;
297 }
298 do
299 {
300 if (!uc)
301 return false;
302 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
303 } while (--cQms > 0);
304 /* done? */
305 if (!ucFilter)
306 return true;
307 break;
308 }
309
310 /*
311 * The simple way is to try char by char and match the remaining
312 * expression. If it's trailing we're done.
313 */
314 case '>': /* dos question mark */
315 {
316 if (rtDirFilterWinNtMatchEon(puszFilter))
317 return true;
318 const char *pszStart = pszNext;
319 do
320 {
321 if (rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
322 return true;
323 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
324 } while (uc);
325
326 /* backtrack and do the current char. */
327 pszNext = RTStrPrevCp(NULL, pszStart); AssertReturn(pszNext, false);
328 return rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter);
329 }
330
331 /*
332 * This bugger is interesting.
333 * Time for brute force. Iterate the name char by char.
334 */
335 case '<':
336 {
337 do
338 {
339 if (rtDirFilterWinNtMatchDosStar(iDepth, uc, pszNext, puszFilter))
340 return true;
341 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
342 } while (uc);
343 return false;
344 }
345
346 /*
347 * This guy matches a '.' or the end of the name.
348 * It's very simple if the rest of the filter expression also matches eon.
349 */
350 case '"':
351 if (rtDirFilterWinNtMatchEon(puszFilter))
352 return true;
353 ucFilter = '.';
354 RT_FALL_THRU();
355
356 /*
357 * Ok, we've got zero or more characters.
358 * We'll try match starting at each occurrence of this character.
359 */
360 default:
361 {
362 do
363 {
364 if ( RTUniCpToUpper(uc) == ucFilter
365 && rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
366 return true;
367 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
368 } while (uc);
369 return false;
370 }
371 }
372 } /* for (;;) */
373
374 /* won't ever get here! */
375}
376
377
378/**
379 * Filter a the filename in the against a filter.
380 *
381 * The rules are as follows:
382 * '?' Matches exactly one char.
383 * '*' Matches zero or more chars.
384 * '<' The dos star, matches zero or more chars except the DOS dot.
385 * '>' The dos question mark, matches one char, but dots and end-of-name eats them.
386 * '"' The dos dot, matches a dot or end-of-name.
387 *
388 * @returns true if the name matches the filter.
389 * @returns false if the name doesn't match filter.
390 * @param iDepth The recursion depth.
391 * @param pszName The path to match to the filter.
392 * @param puszFilter The filter string.
393 */
394static bool rtDirFilterWinNtMatchBase(unsigned iDepth, const char *pszName, PCRTUNICP puszFilter)
395{
396 AssertReturn(iDepth++ < 256, false);
397
398 /*
399 * Walk the string and match it up char by char.
400 */
401 RTUNICP uc;
402 do
403 {
404 RTUNICP ucFilter = *puszFilter++;
405 int rc = RTStrGetCpEx(&pszName, &uc); AssertRCReturn(rc, false);
406 switch (ucFilter)
407 {
408 /* Exactly one char. */
409 case '?':
410 if (!uc)
411 return false;
412 break;
413
414 /* One char, but the dos dot and end-of-name eats '>' and '<'. */
415 case '>': /* dos ? */
416 if (!uc)
417 return rtDirFilterWinNtMatchEon(puszFilter);
418 if (uc == '.')
419 {
420 while ((ucFilter = *puszFilter) == '>' || ucFilter == '<')
421 puszFilter++;
422 if (ucFilter == '"' || ucFilter == '.') /* not 100% sure about the last dot */
423 ++puszFilter;
424 else /* the does question mark doesn't match '.'s, so backtrack. */
425 pszName = RTStrPrevCp(NULL, pszName);
426 }
427 break;
428
429 /* Match a dot or the end-of-name. */
430 case '"': /* dos '.' */
431 if (uc != '.')
432 {
433 if (uc)
434 return false;
435 return rtDirFilterWinNtMatchEon(puszFilter);
436 }
437 break;
438
439 /* zero or more */
440 case '*':
441 return rtDirFilterWinNtMatchStar(iDepth, uc, pszName, puszFilter);
442 case '<': /* dos '*' */
443 return rtDirFilterWinNtMatchDosStar(iDepth, uc, pszName, puszFilter);
444
445
446 /* uppercased match */
447 default:
448 {
449 if (RTUniCpToUpper(uc) != ucFilter)
450 return false;
451 break;
452 }
453 }
454 } while (uc);
455
456 return true;
457}
458
459
460/**
461 * Filter a the filename in the against a filter.
462 *
463 * @returns true if the name matches the filter.
464 * @returns false if the name doesn't match filter.
465 * @param pDir The directory handle.
466 * @param pszName The path to match to the filter.
467 */
468static DECLCALLBACK(bool) rtDirFilterWinNtMatch(PRTDIRINTERNAL pDir, const char *pszName)
469{
470 return rtDirFilterWinNtMatchBase(0, pszName, pDir->puszFilter);
471}
472
473
474/**
475 * Initializes a WinNt like wildcard filter.
476 *
477 * @returns Pointer to the filter function.
478 * @returns NULL if the filter doesn't filter out anything.
479 * @param pDir The directory handle (not yet opened).
480 */
481static PFNRTDIRFILTER rtDirFilterWinNtInit(PRTDIRINTERNAL pDir)
482{
483 /*
484 * Check for the usual * and <"< (*.* in DOS language) patterns.
485 */
486 if ( (pDir->cchFilter == 1 && pDir->pszFilter[0] == '*')
487 || (pDir->cchFilter == 3 && !memcmp(pDir->pszFilter, "<\".>", 3))
488 )
489 return NULL;
490
491 /*
492 * Uppercase the expression, also do a little optimizations when possible.
493 */
494 bool fHaveWildcards = false;
495 unsigned iRead = 0;
496 unsigned iWrite = 0;
497 while (iRead < pDir->cucFilter)
498 {
499 RTUNICP uc = pDir->puszFilter[iRead++];
500 if (uc == '*')
501 {
502 fHaveWildcards = true;
503 /* remove extra stars. */
504 while (pDir->puszFilter[iRead + 1] == '*')
505 iRead++;
506 }
507 else if (uc == '?' || uc == '>' || uc == '<' || uc == '"')
508 fHaveWildcards = true;
509 else
510 uc = RTUniCpToUpper(uc);
511 pDir->puszFilter[iWrite++] = uc;
512 }
513 pDir->puszFilter[iWrite] = 0;
514 pDir->cucFilter = iWrite;
515
516 return fHaveWildcards
517 ? rtDirFilterWinNtMatch
518 : rtDirFilterWinNtMatchNoWildcards;
519}
520
521
522/**
523 * Common worker for opening a directory.
524 *
525 * @returns IPRT status code.
526 * @param phDir Where to store the directory handle.
527 * @param pszPath The specified path.
528 * @param pszFilter Pointer to where the filter start in the path.
529 * NULL if no filter.
530 * @param enmFilter The type of filter to apply.
531 * @param fFlags RTDIR_F_XXX.
532 * @param hRelativeDir The directory @a pvNativeRelative is relative
533 * to, ~(uintptr_t)0 if absolute.
534 * @param pvNativeRelative The native relative path. NULL if absolute or
535 * we're to use (consume) hRelativeDir.
536 */
537static int rtDirOpenCommon(RTDIR *phDir, const char *pszPath, const char *pszFilter, RTDIRFILTER enmFilter,
538 uint32_t fFlags, uintptr_t hRelativeDir, void *pvNativeRelative)
539{
540 /*
541 * Expand the path.
542 *
543 * The purpose of this exercise to have the abs path around
544 * for querying extra information about the objects we list.
545 * As a sideeffect we also validate the path here.
546 *
547 * Note! The RTDIR_F_NO_ABS_PATH mess is there purely for allowing us to
548 * work around PATH_MAX using CWD on linux and other unixy systems.
549 */
550 char *pszAbsPath;
551 size_t cbFilter; /* includes '\0' (thus cb and not cch). */
552 size_t cucFilter0; /* includes U+0. */
553 bool fDirSlash = false;
554 if (!pszFilter)
555 {
556 if (*pszPath != '\0')
557 {
558 const char *pszLast = strchr(pszPath, '\0') - 1;
559 if (RTPATH_IS_SLASH(*pszLast))
560 fDirSlash = true;
561 }
562
563 cbFilter = cucFilter0 = 0;
564 if (!(fFlags & RTDIR_F_NO_ABS_PATH))
565 pszAbsPath = RTPathAbsExDup(NULL, pszPath, RTPATHABS_F_ENSURE_TRAILING_SLASH);
566 else
567 {
568 size_t cchTmp = strlen(pszPath);
569 pszAbsPath = RTStrAlloc(cchTmp + 2);
570 if (pszAbsPath)
571 {
572 memcpy(pszAbsPath, pszPath, cchTmp);
573 pszAbsPath[cchTmp] = RTPATH_SLASH;
574 pszAbsPath[cchTmp + 1 - fDirSlash] = '\0';
575 }
576 }
577 }
578 else
579 {
580 cbFilter = strlen(pszFilter) + 1;
581 cucFilter0 = RTStrUniLen(pszFilter) + 1;
582
583 if (pszFilter != pszPath)
584 {
585 /* yea, I'm lazy. sue me. */
586 char *pszTmp = RTStrDup(pszPath);
587 if (!pszTmp)
588 return VERR_NO_MEMORY;
589 pszTmp[pszFilter - pszPath] = '\0';
590 if (!(fFlags & RTDIR_F_NO_ABS_PATH))
591 {
592 pszAbsPath = RTPathAbsExDup(NULL, pszTmp, RTPATHABS_F_ENSURE_TRAILING_SLASH);
593 RTStrFree(pszTmp);
594 }
595 else
596 {
597 pszAbsPath = pszTmp;
598 RTPathEnsureTrailingSeparator(pszAbsPath, strlen(pszPath) + 1);
599 }
600 }
601 else if (!(fFlags & RTDIR_F_NO_ABS_PATH))
602 pszAbsPath = RTPathAbsExDup(NULL, ".", RTPATHABS_F_ENSURE_TRAILING_SLASH);
603 else
604 pszAbsPath = RTStrDup("." RTPATH_SLASH_STR);
605 fDirSlash = true;
606 }
607 if (!pszAbsPath)
608 return VERR_NO_MEMORY;
609 Assert(strchr(pszAbsPath, '\0')[-1] == RTPATH_SLASH);
610
611 /*
612 * Allocate and initialize the directory handle.
613 *
614 * The posix definition of Data.d_name allows it to be < NAME_MAX + 1,
615 * thus the horrible ugliness here. Solaris uses d_name[1] for instance.
616 */
617 size_t const cchAbsPath = strlen(pszAbsPath);
618 size_t const cbDir = rtDirNativeGetStructSize(pszAbsPath);
619 size_t const cbAllocated = cbDir
620 + cucFilter0 * sizeof(RTUNICP)
621 + cbFilter
622 + cchAbsPath + 1 + 4;
623 PRTDIRINTERNAL pDir = (PRTDIRINTERNAL)RTMemAllocZ(cbAllocated);
624 if (!pDir)
625 {
626 RTStrFree(pszAbsPath);
627 return VERR_NO_MEMORY;
628 }
629 uint8_t *pb = (uint8_t *)pDir + cbDir;
630
631 /* initialize it */
632 pDir->u32Magic = RTDIR_MAGIC;
633 pDir->cbSelf = cbDir;
634 if (cbFilter)
635 {
636 pDir->puszFilter = (PRTUNICP)pb;
637 int rc2 = RTStrToUniEx(pszFilter, RTSTR_MAX, &pDir->puszFilter, cucFilter0, &pDir->cucFilter);
638 AssertRC(rc2);
639 pb += cucFilter0 * sizeof(RTUNICP);
640 pDir->pszFilter = (char *)memcpy(pb, pszFilter, cbFilter);
641 pDir->cchFilter = cbFilter - 1;
642 pb += cbFilter;
643 }
644 else
645 {
646 pDir->puszFilter = NULL;
647 pDir->cucFilter = 0;
648 pDir->pszFilter = NULL;
649 pDir->cchFilter = 0;
650 }
651 pDir->enmFilter = enmFilter;
652 switch (enmFilter)
653 {
654 default:
655 case RTDIRFILTER_NONE:
656 pDir->pfnFilter = NULL;
657 break;
658 case RTDIRFILTER_WINNT:
659 pDir->pfnFilter = rtDirFilterWinNtInit(pDir);
660 break;
661 case RTDIRFILTER_UNIX:
662 pDir->pfnFilter = NULL;
663 break;
664 case RTDIRFILTER_UNIX_UPCASED:
665 pDir->pfnFilter = NULL;
666 break;
667 }
668 pDir->cchPath = cchAbsPath;
669 pDir->pszPath = (char *)memcpy(pb, pszAbsPath, cchAbsPath);
670 pb[cchAbsPath] = '\0';
671 Assert(pb - (uint8_t *)pDir + cchAbsPath + 1 <= cbAllocated);
672 pDir->pszName = NULL;
673 pDir->cchName = 0;
674 pDir->fFlags = fFlags;
675 pDir->fDirSlash = fDirSlash;
676 pDir->fDataUnread = false;
677
678 /*
679 * Hand it over to the native part.
680 */
681 int rc = rtDirNativeOpen(pDir, hRelativeDir, pvNativeRelative);
682 if (RT_SUCCESS(rc))
683 *phDir = pDir;
684 else
685 RTMemFree(pDir);
686 RTStrFree(pszAbsPath);
687 return rc;
688}
689
690
691RTDECL(int) RTDirOpen(RTDIR *phDir, const char *pszPath)
692{
693 /*
694 * Validate input.
695 */
696 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
697 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
698
699 /*
700 * Take common cause with RTDirOpenFiltered().
701 */
702 int rc = rtDirOpenCommon(phDir, pszPath, NULL, RTDIRFILTER_NONE, 0 /*fFlags*/, ~(uintptr_t)0, NULL);
703 LogFlow(("RTDirOpen(%p:{%p}, %p:{%s}): return %Rrc\n", phDir, *phDir, pszPath, pszPath, rc));
704 return rc;
705}
706
707
708DECLHIDDEN(int) rtDirOpenRelativeOrHandle(RTDIR *phDir, const char *pszPath, RTDIRFILTER enmFilter, uint32_t fFlags,
709 uintptr_t hRelativeDir, void *pvNativeRelative)
710{
711 /*
712 * Validate input.
713 */
714 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
715 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
716 AssertReturn(!(fFlags & ~RTDIR_F_VALID_MASK), VERR_INVALID_FLAGS);
717 switch (enmFilter)
718 {
719 case RTDIRFILTER_UNIX:
720 case RTDIRFILTER_UNIX_UPCASED:
721 AssertMsgFailed(("%d is not implemented!\n", enmFilter));
722 return VERR_NOT_IMPLEMENTED;
723 case RTDIRFILTER_NONE:
724 case RTDIRFILTER_WINNT:
725 break;
726 default:
727 AssertMsgFailedReturn(("%d\n", enmFilter), VERR_INVALID_PARAMETER);
728 }
729
730 /*
731 * Find the last component, i.e. where the filter criteria starts and the dir name ends.
732 */
733 const char *pszFilter;
734 if (enmFilter == RTDIRFILTER_NONE)
735 pszFilter = NULL;
736 else
737 {
738 pszFilter = RTPathFilename(pszPath);
739 if (!pszFilter) /* trailing slash => directory to read => no filter. */
740 enmFilter = RTDIRFILTER_NONE;
741 }
742
743 /*
744 * Call worker common with RTDirOpen which will verify the path, allocate
745 * and initialize the handle, and finally call the backend.
746 */
747 int rc = rtDirOpenCommon(phDir, pszPath, pszFilter, enmFilter, fFlags, hRelativeDir, pvNativeRelative);
748
749 LogFlow(("RTDirOpenFiltered(%p:{%p}, %p:{%s}, %d, %#x, %p, %p): return %Rrc\n",
750 phDir,*phDir, pszPath, pszPath, enmFilter, fFlags, hRelativeDir, pvNativeRelative, rc));
751 return rc;
752}
753
754
755RTDECL(int) RTDirOpenFiltered(RTDIR *phDir, const char *pszPath, RTDIRFILTER enmFilter, uint32_t fFlags)
756{
757 return rtDirOpenRelativeOrHandle(phDir, pszPath, enmFilter, fFlags, ~(uintptr_t)0, NULL);
758}
759
760
761RTDECL(bool) RTDirIsValid(RTDIR hDir)
762{
763 return RT_VALID_PTR(hDir)
764 && hDir->u32Magic == RTDIR_MAGIC;
765}
766
767
768RTDECL(int) RTDirFlushParent(const char *pszChild)
769{
770 char *pszPath;
771 char *pszPathFree = NULL;
772 size_t const cchChild = strlen(pszChild);
773 if (cchChild < RTPATH_MAX)
774 pszPath = (char *)alloca(cchChild + 1);
775 else
776 {
777 pszPathFree = pszPath = (char *)RTMemTmpAlloc(cchChild + 1);
778 if (!pszPath)
779 return VERR_NO_TMP_MEMORY;
780 }
781 memcpy(pszPath, pszChild, cchChild);
782 pszPath[cchChild] = '\0';
783 RTPathStripFilename(pszPath);
784
785 int rc = RTDirFlush(pszPath);
786
787 if (pszPathFree)
788 RTMemTmpFree(pszPathFree);
789 return rc;
790}
791
792
793RTDECL(int) RTDirQueryUnknownTypeEx(const char *pszComposedName, bool fFollowSymlinks,
794 RTDIRENTRYTYPE *penmType, PRTFSOBJINFO pObjInfo)
795{
796 int rc = RTPathQueryInfoEx(pszComposedName, pObjInfo, RTFSOBJATTRADD_NOTHING,
797 fFollowSymlinks ? RTPATH_F_FOLLOW_LINK : RTPATH_F_ON_LINK);
798 if (RT_FAILURE(rc))
799 return rc;
800
801 if (RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
802 *penmType = RTDIRENTRYTYPE_DIRECTORY;
803 else if (RTFS_IS_FILE(pObjInfo->Attr.fMode))
804 *penmType = RTDIRENTRYTYPE_FILE;
805 else if (RTFS_IS_SYMLINK(pObjInfo->Attr.fMode))
806 *penmType = RTDIRENTRYTYPE_SYMLINK;
807 else if (RTFS_IS_FIFO(pObjInfo->Attr.fMode))
808 *penmType = RTDIRENTRYTYPE_FIFO;
809 else if (RTFS_IS_DEV_CHAR(pObjInfo->Attr.fMode))
810 *penmType = RTDIRENTRYTYPE_DEV_CHAR;
811 else if (RTFS_IS_DEV_BLOCK(pObjInfo->Attr.fMode))
812 *penmType = RTDIRENTRYTYPE_DEV_BLOCK;
813 else if (RTFS_IS_SOCKET(pObjInfo->Attr.fMode))
814 *penmType = RTDIRENTRYTYPE_SOCKET;
815 else if (RTFS_IS_WHITEOUT(pObjInfo->Attr.fMode))
816 *penmType = RTDIRENTRYTYPE_WHITEOUT;
817 else
818 *penmType = RTDIRENTRYTYPE_UNKNOWN;
819
820 return VINF_SUCCESS;
821}
822
823
824RTDECL(int) RTDirQueryUnknownType(const char *pszComposedName, bool fFollowSymlinks, RTDIRENTRYTYPE *penmType)
825{
826 if ( *penmType != RTDIRENTRYTYPE_UNKNOWN
827 && ( !fFollowSymlinks
828 || *penmType != RTDIRENTRYTYPE_SYMLINK))
829 return VINF_SUCCESS;
830
831 RTFSOBJINFO ObjInfo;
832 return RTDirQueryUnknownTypeEx(pszComposedName, fFollowSymlinks, penmType, &ObjInfo);
833}
834
835
836RTDECL(bool) RTDirEntryIsStdDotLink(PRTDIRENTRY pDirEntry)
837{
838 if (pDirEntry->szName[0] != '.')
839 return false;
840 if (pDirEntry->cbName == 1)
841 return true;
842 if (pDirEntry->cbName != 2)
843 return false;
844 return pDirEntry->szName[1] == '.';
845}
846
847
848RTDECL(bool) RTDirEntryExIsStdDotLink(PCRTDIRENTRYEX pDirEntryEx)
849{
850 if (pDirEntryEx->szName[0] != '.')
851 return false;
852 if (pDirEntryEx->cbName == 1)
853 return true;
854 if (pDirEntryEx->cbName != 2)
855 return false;
856 return pDirEntryEx->szName[1] == '.';
857}
858
859
860RTDECL(int) RTDirReadExA(RTDIR hDir, PRTDIRENTRYEX *ppDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
861{
862 PRTDIRENTRYEX pDirEntry = *ppDirEntry;
863 size_t cbDirEntry = *pcbDirEntry;
864 if (pDirEntry != NULL && cbDirEntry >= sizeof(RTDIRENTRYEX))
865 { /* likely */ }
866 else
867 {
868 Assert(pDirEntry == NULL);
869 Assert(cbDirEntry == 0);
870
871 cbDirEntry = RT_ALIGN_Z(sizeof(RTDIRENTRYEX), 16);
872 *ppDirEntry = pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntry);
873 if (pDirEntry)
874 *pcbDirEntry = cbDirEntry;
875 else
876 {
877 *pcbDirEntry = 0;
878 return VERR_NO_TMP_MEMORY;
879 }
880 }
881
882 for (;;)
883 {
884 int rc = RTDirReadEx(hDir, pDirEntry, &cbDirEntry, enmAddAttr, fFlags);
885 if (rc != VERR_BUFFER_OVERFLOW)
886 return rc;
887
888 /* Grow the buffer. */
889 RTMemTmpFree(pDirEntry);
890 cbDirEntry = RT_MAX(RT_ALIGN_Z(cbDirEntry, 64), *pcbDirEntry + 64);
891 *ppDirEntry = pDirEntry = (PRTDIRENTRYEX)RTMemTmpAlloc(cbDirEntry);
892 if (pDirEntry)
893 *pcbDirEntry = cbDirEntry;
894 else
895 {
896 *pcbDirEntry = 0;
897 return VERR_NO_TMP_MEMORY;
898 }
899 }
900}
901
902
903RTDECL(void) RTDirReadExAFree(PRTDIRENTRYEX *ppDirEntry, size_t *pcbDirEntry)
904{
905 PRTDIRENTRYEX pDirEntry = *ppDirEntry;
906 if (pDirEntry != NULL && *pcbDirEntry >= sizeof(*pcbDirEntry))
907 RTMemTmpFree(pDirEntry);
908 else
909 {
910 Assert(pDirEntry == NULL);
911 Assert(*pcbDirEntry == 0);
912 }
913 *ppDirEntry = NULL;
914 *pcbDirEntry = 0;
915}
916
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette