VirtualBox

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

Last change on this file since 9566 was 9358, checked in by vboxsync, 16 years ago

More fun.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 21.9 KB
Line 
1/* $Id: dir.cpp 9358 2008-06-03 15:59:24Z vboxsync $ */
2/** @file
3 * IPRT - Directory Manipulation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#define LOG_GROUP RTLOGGROUP_DIR
36#ifdef RT_OS_WINDOWS /* PORTME: Assumes everyone else is using dir-posix.cpp */
37# include <Windows.h>
38#else
39# include <dirent.h>
40# include <unistd.h>
41# include <limits.h>
42#endif
43
44#include <iprt/dir.h>
45#include <iprt/path.h>
46#include <iprt/alloc.h>
47#include <iprt/log.h>
48#include <iprt/param.h>
49#include <iprt/string.h>
50#include <iprt/err.h>
51#include <iprt/assert.h>
52#include <iprt/uni.h>
53#include "internal/fs.h"
54#include "internal/dir.h"
55
56
57static DECLCALLBACK(bool) rtDirFilterWinNtMatch(PRTDIR pDir, const char *pszName);
58static DECLCALLBACK(bool) rtDirFilterWinNtMatchNoWildcards(PRTDIR pDir, const char *pszName);
59DECLINLINE(bool) rtDirFilterWinNtMatchEon(PCRTUNICP puszFilter);
60static bool rtDirFilterWinNtMatchDosStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter);
61static bool rtDirFilterWinNtMatchStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter);
62static bool rtDirFilterWinNtMatchBase(unsigned iDepth, const char *pszName, PCRTUNICP puszFilter);
63
64
65
66RTDECL(int) RTDirCreateFullPath(const char *pszPath, RTFMODE fMode)
67{
68 /*
69 * Resolve the path.
70 */
71 char szAbsPath[RTPATH_MAX];
72 int rc = RTPathAbs(pszPath, szAbsPath, sizeof(szAbsPath));
73 if (RT_FAILURE(rc))
74 return rc;
75
76 /*
77 * Iterate the path components making sure each of them exists.
78 */
79 /* skip volume name */
80 char *psz = &szAbsPath[rtPathVolumeSpecLen(szAbsPath)];
81
82 /* skip the root slash if any */
83 if ( psz[0] == '/'
84#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
85 || psz[0] == '\\'
86#endif
87 )
88 psz++;
89
90 /* iterate over path components. */
91 do
92 {
93 /* the next component is NULL, stop iterating */
94 if (!*psz)
95 break;
96#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
97 psz = strpbrk(psz, "\\/");
98#else
99 psz = strchr(psz, '/');
100#endif
101 if (psz)
102 *psz = '\0';
103 /*
104 * ASSUME that RTDirCreate will return VERR_ALREADY_EXISTS and not VERR_ACCESS_DENIED in those cases
105 * where the directory exists but we don't have write access to the parent directory.
106 */
107 rc = RTDirCreate(szAbsPath, fMode);
108 if (rc == VERR_ALREADY_EXISTS)
109 rc = VINF_SUCCESS;
110 if (!psz)
111 break;
112 *psz++ = RTPATH_DELIMITER;
113 } while (RT_SUCCESS(rc));
114
115 return rc;
116}
117
118
119/**
120 * Filter a the filename in the against a filter.
121 *
122 * @returns true if the name matches the filter.
123 * @returns false if the name doesn't match filter.
124 * @param pDir The directory handle.
125 * @param pszName The path to match to the filter.
126 */
127static DECLCALLBACK(bool) rtDirFilterWinNtMatchNoWildcards(PRTDIR pDir, const char *pszName)
128{
129 /*
130 * Walk the string and compare.
131 */
132 PCRTUNICP pucFilter = pDir->puszFilter;
133 const char *psz = pszName;
134 RTUNICP uc;
135 do
136 {
137 int rc = RTStrGetCpEx(&psz, &uc);
138 AssertRCReturn(rc, false);
139 RTUNICP ucFilter = *pucFilter++;
140 if ( uc != ucFilter
141 && RTUniCpToUpper(uc) != ucFilter)
142 return false;
143 } while (uc);
144 return true;
145}
146
147
148/**
149 * Matches end of name.
150 */
151DECLINLINE(bool) rtDirFilterWinNtMatchEon(PCRTUNICP puszFilter)
152{
153 RTUNICP ucFilter;
154 while ( (ucFilter = *puszFilter) == '>'
155 || ucFilter == '<'
156 || ucFilter == '*'
157 || ucFilter == '"')
158 puszFilter++;
159 return !ucFilter;
160}
161
162
163/**
164 * Recursive star matching.
165 * Practically the same as normal star, except that the dos star stops
166 * when hitting the last dot.
167 *
168 * @returns true on match.
169 * @returns false on miss.
170 */
171static bool rtDirFilterWinNtMatchDosStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter)
172{
173 AssertReturn(iDepth++ < 256, false);
174
175 /*
176 * If there is no dos star, we should work just like the NT star.
177 * Since that's generally faster algorithms, we jump down to there if we can.
178 */
179 const char *pszDosDot = strrchr(pszNext, '.');
180 if (!pszDosDot && uc == '.')
181 pszDosDot = pszNext - 1;
182 if (!pszDosDot)
183 return rtDirFilterWinNtMatchStar(iDepth, uc, pszNext, puszFilter);
184
185 /*
186 * Inspect the next filter char(s) until we find something to work on.
187 */
188 RTUNICP ucFilter = *puszFilter++;
189 switch (ucFilter)
190 {
191 /*
192 * The star expression is the last in the pattern.
193 * We're fine if the name ends with a dot.
194 */
195 case '\0':
196 return !pszDosDot[1];
197
198 /*
199 * Simplified by brute force.
200 */
201 case '>': /* dos question mark */
202 case '?':
203 case '*':
204 case '<': /* dos star */
205 case '"': /* dos dot */
206 {
207 puszFilter--;
208 const char *pszStart = pszNext;
209 do
210 {
211 if (rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
212 return true;
213 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
214 } while ((intptr_t)pszDosDot - (intptr_t)pszNext >= -1);
215
216 /* backtrack and do the current char. */
217 pszNext = RTStrPrevCp(NULL, pszStart); AssertReturn(pszNext, false);
218 return rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter);
219 }
220
221 /*
222 * Ok, we've got zero or more characters.
223 * We'll try match starting at each occurence of this character.
224 */
225 default:
226 {
227 if ( RTUniCpToUpper(uc) == ucFilter
228 && rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
229 return true;
230 do
231 {
232 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
233 if ( RTUniCpToUpper(uc) == ucFilter
234 && rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
235 return true;
236 } while ((intptr_t)pszDosDot - (intptr_t)pszNext >= -1);
237 return false;
238 }
239 }
240 /* won't ever get here! */
241}
242
243
244/**
245 * Recursive star matching.
246 *
247 * @returns true on match.
248 * @returns false on miss.
249 */
250static bool rtDirFilterWinNtMatchStar(unsigned iDepth, RTUNICP uc, const char *pszNext, PCRTUNICP puszFilter)
251{
252 AssertReturn(iDepth++ < 256, false);
253
254 /*
255 * Inspect the next filter char(s) until we find something to work on.
256 */
257 for (;;)
258 {
259 RTUNICP ucFilter = *puszFilter++;
260 switch (ucFilter)
261 {
262 /*
263 * The star expression is the last in the pattern.
264 * Cool, that means we're done!
265 */
266 case '\0':
267 return true;
268
269 /*
270 * Just in case (doubt we ever get here), just merge it with the current one.
271 */
272 case '*':
273 break;
274
275 /*
276 * Skip a fixed number of chars.
277 * Figure out how many by walking the filter ignoring '*'s.
278 */
279 case '?':
280 {
281 unsigned cQms = 1;
282 while ((ucFilter = *puszFilter) == '*' || ucFilter == '?')
283 {
284 cQms += ucFilter == '?';
285 puszFilter++;
286 }
287 do
288 {
289 if (!uc)
290 return false;
291 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
292 } while (--cQms > 0);
293 /* done? */
294 if (!ucFilter)
295 return true;
296 break;
297 }
298
299 /*
300 * The simple way is to try char by char and match the remaining
301 * expression. If it's trailing we're done.
302 */
303 case '>': /* dos question mark */
304 {
305 if (rtDirFilterWinNtMatchEon(puszFilter))
306 return true;
307 const char *pszStart = pszNext;
308 do
309 {
310 if (rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
311 return true;
312 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
313 } while (uc);
314
315 /* backtrack and do the current char. */
316 pszNext = RTStrPrevCp(NULL, pszStart); AssertReturn(pszNext, false);
317 return rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter);
318 }
319
320 /*
321 * This bugger is interesting.
322 * Time for brute force. Iterate the name char by char.
323 */
324 case '<':
325 {
326 do
327 {
328 if (rtDirFilterWinNtMatchDosStar(iDepth, uc, pszNext, puszFilter))
329 return true;
330 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
331 } while (uc);
332 return false;
333 }
334
335 /*
336 * This guy matches a '.' or the end of the name.
337 * It's very simple if the rest of the filter expression also matches eon.
338 */
339 case '"':
340 if (rtDirFilterWinNtMatchEon(puszFilter))
341 return true;
342 ucFilter = '.';
343 /* fall thru */
344
345 /*
346 * Ok, we've got zero or more characters.
347 * We'll try match starting at each occurence of this character.
348 */
349 default:
350 {
351 do
352 {
353 if ( RTUniCpToUpper(uc) == ucFilter
354 && rtDirFilterWinNtMatchBase(iDepth, pszNext, puszFilter))
355 return true;
356 int rc = RTStrGetCpEx(&pszNext, &uc); AssertRCReturn(rc, false);
357 } while (uc);
358 return false;
359 }
360 }
361 } /* for (;;) */
362
363 /* won't ever get here! */
364}
365
366
367/**
368 * Filter a the filename in the against a filter.
369 *
370 * The rules are as follows:
371 * '?' Matches exactly one char.
372 * '*' Matches zero or more chars.
373 * '<' The dos star, matches zero or more chars except the DOS dot.
374 * '>' The dos question mark, matches one char, but dots and end-of-name eats them.
375 * '"' The dos dot, matches a dot or end-of-name.
376 *
377 * @returns true if the name matches the filter.
378 * @returns false if the name doesn't match filter.
379 * @param iDepth The recursion depth.
380 * @param pszName The path to match to the filter.
381 * @param puszFilter The filter string.
382 */
383static bool rtDirFilterWinNtMatchBase(unsigned iDepth, const char *pszName, PCRTUNICP puszFilter)
384{
385 AssertReturn(iDepth++ < 256, false);
386
387 /*
388 * Walk the string and match it up char by char.
389 */
390 RTUNICP uc;
391 do
392 {
393 RTUNICP ucFilter = *puszFilter++;
394 int rc = RTStrGetCpEx(&pszName, &uc); AssertRCReturn(rc, false);
395 switch (ucFilter)
396 {
397 /* Exactly one char. */
398 case '?':
399 if (!uc)
400 return false;
401 break;
402
403 /* One char, but the dos dot and end-of-name eats '>' and '<'. */
404 case '>': /* dos ? */
405 if (!uc)
406 return rtDirFilterWinNtMatchEon(puszFilter);
407 if (uc == '.')
408 {
409 while ((ucFilter = *puszFilter) == '>' || ucFilter == '<')
410 puszFilter++;
411 if (ucFilter == '"' || ucFilter == '.') /* not 100% sure about the last dot */
412 ++puszFilter;
413 else /* the does question mark doesn't match '.'s, so backtrack. */
414 pszName = RTStrPrevCp(NULL, pszName);
415 }
416 break;
417
418 /* Match a dot or the end-of-name. */
419 case '"': /* dos '.' */
420 if (uc != '.')
421 {
422 if (uc)
423 return false;
424 return rtDirFilterWinNtMatchEon(puszFilter);
425 }
426 break;
427
428 /* zero or more */
429 case '*':
430 return rtDirFilterWinNtMatchStar(iDepth, uc, pszName, puszFilter);
431 case '<': /* dos '*' */
432 return rtDirFilterWinNtMatchDosStar(iDepth, uc, pszName, puszFilter);
433
434
435 /* uppercased match */
436 default:
437 {
438 if (RTUniCpToUpper(uc) != ucFilter)
439 return false;
440 break;
441 }
442 }
443 } while (uc);
444
445 return true;
446}
447
448
449/**
450 * Filter a the filename in the against a filter.
451 *
452 * @returns true if the name matches the filter.
453 * @returns false if the name doesn't match filter.
454 * @param pDir The directory handle.
455 * @param pszName The path to match to the filter.
456 */
457static DECLCALLBACK(bool) rtDirFilterWinNtMatch(PRTDIR pDir, const char *pszName)
458{
459 return rtDirFilterWinNtMatchBase(0, pszName, pDir->puszFilter);
460}
461
462
463/**
464 * Initializes a WinNt like wildcard filter.
465 *
466 * @returns Pointer to the filter function.
467 * @returns NULL if the filter doesn't filter out anything.
468 * @param pDir The directory handle (not yet opened).
469 */
470static PFNRTDIRFILTER rtDirFilterWinNtInit(PRTDIR pDir)
471{
472 /*
473 * Check for the usual * and <"< (*.* in DOS language) patterns.
474 */
475 if ( (pDir->cchFilter == 1 && pDir->pszFilter[0] == '*')
476 || (pDir->cchFilter == 3 && !memcmp(pDir->pszFilter, "<\".>", 3))
477 )
478 return NULL;
479
480 /*
481 * Uppercase the expression, also do a little optimizations when possible.
482 */
483 bool fHaveWildcards = false;
484 unsigned iRead = 0;
485 unsigned iWrite = 0;
486 while (iRead < pDir->cucFilter)
487 {
488 RTUNICP uc = pDir->puszFilter[iRead++];
489 if (uc == '*')
490 {
491 fHaveWildcards = true;
492 /* remove extra stars. */
493 RTUNICP uc2;
494 while ((uc2 = pDir->puszFilter[iRead + 1]) == '*')
495 iRead++;
496 }
497 else if (uc == '?' || uc == '>' || uc == '<' || uc == '"')
498 fHaveWildcards = true;
499 else
500 uc = RTUniCpToUpper(uc);
501 pDir->puszFilter[iWrite++] = uc;
502 }
503 pDir->puszFilter[iWrite] = 0;
504 pDir->cucFilter = iWrite;
505
506 return fHaveWildcards
507 ? rtDirFilterWinNtMatch
508 : rtDirFilterWinNtMatchNoWildcards;
509}
510
511
512/**
513 * Common worker for opening a directory.
514 *
515 * @returns IPRT status code.
516 * @param ppDir Where to store the directory handle.
517 * @param pszPath The specified path.
518 * @param pszFilter Pointer to where the filter start in the path. NULL if no filter.
519 * @param enmFilter The type of filter to apply.
520 */
521static int rtDirOpenCommon(PRTDIR *ppDir, const char *pszPath, const char *pszFilter, RTDIRFILTER enmFilter)
522{
523 /*
524 * Expand the path.
525 *
526 * The purpose of this exercise to have the abs path around
527 * for querying extra information about the objects we list.
528 * As a sideeffect we also validate the path here.
529 */
530 char szRealPath[RTPATH_MAX + 1];
531 int rc;
532 size_t cbFilter; /* includes '\0' (thus cb and not cch). */
533 size_t cucFilter0; /* includes U+0. */
534 if (!pszFilter)
535 {
536 cbFilter = cucFilter0 = 0;
537 rc = RTPathReal(pszPath, szRealPath, sizeof(szRealPath) - 1);
538 }
539 else
540 {
541 cbFilter = strlen(pszFilter) + 1;
542 cucFilter0 = RTStrUniLen(pszFilter) + 1;
543
544 if (pszFilter != pszPath)
545 {
546 /* yea, I'm lazy. sue me. */
547 char *pszTmp = RTStrDup(pszPath);
548 if (!pszTmp)
549 return VERR_NO_MEMORY;
550 pszTmp[pszFilter - pszPath] = '\0';
551 rc = RTPathReal(pszTmp, szRealPath, sizeof(szRealPath) - 1);
552 RTStrFree(pszTmp);
553 }
554 else
555 rc = RTPathReal(".", szRealPath, sizeof(szRealPath) - 1);
556 }
557 if (RT_FAILURE(rc))
558 return rc;
559
560 /* add trailing '/' if missing. */
561 size_t cchRealPath = strlen(szRealPath);
562 if (!RTPATH_IS_SEP(szRealPath[cchRealPath - 1]))
563 {
564 szRealPath[cchRealPath++] = RTPATH_SLASH;
565 szRealPath[cchRealPath] = '\0';
566 }
567
568 /*
569 * Allocate and initialize the directory handle.
570 *
571 * The posix definition of Data.d_name allows it to be < NAME_MAX + 1,
572 * thus the horrible uglyness here. Solaris uses d_name[1] for instance.
573 */
574#ifndef RT_OS_WINDOWS
575 long cbNameMax = pathconf(szRealPath, _PC_NAME_MAX);
576# ifdef NAME_MAX
577 if (cbNameMax < NAME_MAX) /* This is plain paranoia, but it doesn't hurt. */
578 cbNameMax = NAME_MAX;
579# endif
580# ifdef _XOPEN_NAME_MAX
581 if (cbNameMax < _XOPEN_NAME_MAX) /* Ditto. */
582 cbNameMax = _XOPEN_NAME_MAX;
583# endif
584 size_t cbDir = RT_OFFSETOF(RTDIR, Data.d_name[cbNameMax + 1]);
585 if (cbDir < sizeof(RTDIR)) /* Ditto. */
586 cbDir = sizeof(RTDIR);
587 cbDir = RT_ALIGN_Z(cbDir, 8);
588#else
589 size_t cbDir = sizeof(RTDIR);
590#endif
591 size_t const cbAllocated = cbDir
592 + cucFilter0 * sizeof(RTUNICP)
593 + cbFilter
594 + cchRealPath + 1 + 4;
595 PRTDIR pDir = (PRTDIR)RTMemAlloc(cbAllocated);
596 if (!pDir)
597 return VERR_NO_MEMORY;
598 uint8_t *pb = (uint8_t *)pDir + cbDir;
599
600 /* initialize it */
601 pDir->u32Magic = RTDIR_MAGIC;
602 if (cbFilter)
603 {
604 pDir->puszFilter = (PRTUNICP)pb;
605 rc = RTStrToUniEx(pszFilter, RTSTR_MAX, &pDir->puszFilter, cucFilter0, &pDir->cucFilter);
606 AssertRC(rc);
607 pb += cucFilter0 * sizeof(RTUNICP);
608 pDir->pszFilter = (char *)memcpy(pb, pszFilter, cbFilter);
609 pDir->cchFilter = cbFilter - 1;
610 pb += cbFilter;
611 }
612 else
613 {
614 pDir->puszFilter = NULL;
615 pDir->cucFilter = 0;
616 pDir->pszFilter = NULL;
617 pDir->cchFilter = 0;
618 }
619 pDir->enmFilter = enmFilter;
620 switch (enmFilter)
621 {
622 default:
623 case RTDIRFILTER_NONE:
624 pDir->pfnFilter = NULL;
625 break;
626 case RTDIRFILTER_WINNT:
627 pDir->pfnFilter = rtDirFilterWinNtInit(pDir);
628 break;
629 case RTDIRFILTER_UNIX:
630 pDir->pfnFilter = NULL;
631 break;
632 case RTDIRFILTER_UNIX_UPCASED:
633 pDir->pfnFilter = NULL;
634 break;
635 }
636 pDir->cchPath = cchRealPath;
637 pDir->pszPath = (char *)memcpy(pb, szRealPath, cchRealPath + 1);
638 Assert(pb - (uint8_t *)pDir + cchRealPath + 1 <= cbAllocated);
639 pDir->fDataUnread = false;
640#ifndef RT_DONT_CONVERT_FILENAMES
641 pDir->pszName = NULL;
642 pDir->cchName = 0;
643#endif
644#ifndef RT_OS_WINDOWS
645 pDir->cbMaxName = cbDir - RT_OFFSETOF(RTDIR, Data.d_name);
646#endif
647
648 /*
649 * Hand it over to the native part.
650 */
651 rc = rtOpenDirNative(pDir, szRealPath);
652 if (RT_SUCCESS(rc))
653 *ppDir = pDir;
654 else
655 RTMemFree(pDir);
656
657 return rc;
658}
659
660
661
662RTDECL(int) RTDirOpen(PRTDIR *ppDir, const char *pszPath)
663{
664 /*
665 * Validate input.
666 */
667 AssertMsgReturn(VALID_PTR(ppDir), ("%p\n", ppDir), VERR_INVALID_POINTER);
668 AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
669
670 /*
671 * Take common cause with RTDirOpenFiltered().
672 */
673 int rc = rtDirOpenCommon(ppDir, pszPath, NULL, RTDIRFILTER_NONE);
674 LogFlow(("RTDirOpen(%p:{%p}, %p:{%s}): return %Rrc\n", ppDir, *ppDir, pszPath, pszPath, rc));
675 return rc;
676}
677
678
679RTDECL(int) RTDirOpenFiltered(PRTDIR *ppDir, const char *pszPath, RTDIRFILTER enmFilter)
680{
681 /*
682 * Validate input.
683 */
684 AssertMsgReturn(VALID_PTR(ppDir), ("%p\n", ppDir), VERR_INVALID_POINTER);
685 AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
686 switch (enmFilter)
687 {
688 case RTDIRFILTER_UNIX:
689 case RTDIRFILTER_UNIX_UPCASED:
690 AssertMsgFailed(("%d is not implemented!\n", enmFilter));
691 return VERR_NOT_IMPLEMENTED;
692 case RTDIRFILTER_NONE:
693 case RTDIRFILTER_WINNT:
694 break;
695 default:
696 AssertMsgFailedReturn(("%d\n", enmFilter), VERR_INVALID_PARAMETER);
697 }
698
699 /*
700 * Find the last component, i.e. where the filter criteria starts and the dir name ends.
701 */
702 const char *pszFilter = enmFilter != RTDIRFILTER_NONE
703 ? RTPathFilename(pszPath)
704 : NULL;
705
706 /*
707 * Call worker common with RTDirOpen which will verify the path, allocate
708 * and initialize the handle, and finally call the backend.
709 */
710 int rc = rtDirOpenCommon(ppDir, pszPath, pszFilter, enmFilter);
711
712 LogFlow(("RTDirOpenFiltered(%p:{%p}, %p:{%s}, %d): return %Rrc\n",
713 ppDir, *ppDir, pszPath, pszPath, enmFilter, rc));
714 return rc;
715}
716
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