VirtualBox

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

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

IPRT: Added RTPATHABS_F_ENSURE_TRAILING_SLASH to RTPathAbsEx and fixed a couple of issues related to VERR_BUFFER_OVERFLOW code paths. bugref:9172

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