VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp@ 69716

最後變更 在這個檔案從69716是 69716,由 vboxsync 提交於 7 年 前

IPRT: More work on directory relative APIs (NT mainly) and VFS; introducing RTMkDir (test) tool.

  • Added RTVfsDirCreateDir
  • Added RTVfsChainOpenParentDir and RTVfsChainSplitOffFinalPath.
  • Added new tool for testing this called RTMkDir.
  • Fixed directory traversal problem with stddir by making it okay to return VERR_FILE_NOT_FOUND as well.
  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 21.9 KB
 
1/* $Id: vfsstddir.cpp 69716 2017-11-16 14:31:25Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard Directory Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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_VFS
32#include <iprt/vfs.h>
33#include <iprt/vfslowlevel.h>
34
35#include <iprt/assert.h>
36#include <iprt/dir.h>
37#include <iprt/err.h>
38#include <iprt/file.h>
39#include <iprt/log.h>
40#include <iprt/path.h>
41#include <iprt/string.h>
42
43#define RTDIR_AGNOSTIC
44#include "internal/dir.h"
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50/**
51 * Private data of a standard directory.
52 */
53typedef struct RTVFSSTDDIR
54{
55 /** The directory handle. */
56 PRTDIR hDir;
57 /** Whether to leave the handle open when the VFS handle is closed. */
58 bool fLeaveOpen;
59 /** Open flags, RTDIR_F_XXX. */
60 uint32_t fFlags;
61 /** Handle to the director so we can make sure it sticks around for symbolic
62 * link objects. */
63 RTVFSDIR hSelf;
64} RTVFSSTDDIR;
65/** Pointer to the private data of a standard directory. */
66typedef RTVFSSTDDIR *PRTVFSSTDDIR;
67
68
69/**
70 * Private data of a standard symbolic link.
71 */
72typedef struct RTVFSSTDSYMLINK
73{
74 /** Pointer to the VFS directory where the symbolic link lives . */
75 PRTVFSSTDDIR pDir;
76 /** The symbolic link name. */
77 char szSymlink[RT_FLEXIBLE_ARRAY];
78} RTVFSSTDSYMLINK;
79/** Pointer to the private data of a standard symbolic link. */
80typedef RTVFSSTDSYMLINK *PRTVFSSTDSYMLINK;
81
82
83/*********************************************************************************************************************************
84* Internal Functions *
85*********************************************************************************************************************************/
86static DECLCALLBACK(int) rtVfsStdDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir);
87static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink);
88static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
89 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr);
90static int rtVfsDirFromRTDir(PRTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir);
91
92
93
94/**
95 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
96 */
97static DECLCALLBACK(int) rtVfsStdSym_Close(void *pvThis)
98{
99 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
100 RTVfsDirRelease(pThis->pDir->hSelf);
101 pThis->pDir = NULL;
102 return VINF_SUCCESS;
103}
104
105
106/**
107 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
108 */
109static DECLCALLBACK(int) rtVfsStdSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
110{
111 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
112 return rtVfsStdDir_QueryEntryInfo(pThis->pDir, pThis->szSymlink, pObjInfo, enmAddAttr);
113}
114
115/**
116 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
117 */
118static DECLCALLBACK(int) rtVfsStdSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
119{
120 NOREF(pvThis); NOREF(fMode); NOREF(fMask);
121 return VERR_ACCESS_DENIED;
122}
123
124
125/**
126 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
127 */
128static DECLCALLBACK(int) rtVfsStdSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
129 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
130{
131 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
132 return VERR_ACCESS_DENIED;
133}
134
135
136/**
137 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
138 */
139static DECLCALLBACK(int) rtVfsStdSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
140{
141 NOREF(pvThis); NOREF(uid); NOREF(gid);
142 return VERR_ACCESS_DENIED;
143}
144
145
146/**
147 * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
148 */
149static DECLCALLBACK(int) rtVfsStdSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)
150{
151 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
152 return RTDirRelSymlinkRead(pThis->pDir->hDir, pThis->szSymlink, pszTarget, cbTarget, 0 /*fRead*/);
153}
154
155
156/**
157 * Symbolic operations for standard directory.
158 */
159static const RTVFSSYMLINKOPS g_rtVfsStdSymOps =
160{
161 { /* Obj */
162 RTVFSOBJOPS_VERSION,
163 RTVFSOBJTYPE_SYMLINK,
164 "StdSymlink",
165 rtVfsStdSym_Close,
166 rtVfsStdSym_QueryInfo,
167 RTVFSOBJOPS_VERSION
168 },
169 RTVFSSYMLINKOPS_VERSION,
170 0,
171 { /* ObjSet */
172 RTVFSOBJSETOPS_VERSION,
173 RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet),
174 rtVfsStdSym_SetMode,
175 rtVfsStdSym_SetTimes,
176 rtVfsStdSym_SetOwner,
177 RTVFSOBJSETOPS_VERSION
178 },
179 rtVfsStdSym_Read,
180 RTVFSSYMLINKOPS_VERSION
181};
182
183
184/**
185 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
186 */
187static DECLCALLBACK(int) rtVfsStdDir_Close(void *pvThis)
188{
189 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
190
191 int rc;
192 if (!pThis->fLeaveOpen)
193 rc = RTDirClose(pThis->hDir);
194 else
195 rc = VINF_SUCCESS;
196 pThis->hDir = NULL;
197
198 return rc;
199}
200
201
202/**
203 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
204 */
205static DECLCALLBACK(int) rtVfsStdDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
206{
207 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
208 return RTDirQueryInfo(pThis->hDir, pObjInfo, enmAddAttr);
209}
210
211
212/**
213 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
214 */
215static DECLCALLBACK(int) rtVfsStdDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
216{
217 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
218 if (fMask != ~RTFS_TYPE_MASK)
219 {
220 RTFSOBJINFO ObjInfo;
221 int rc = RTDirQueryInfo(pThis->hDir, &ObjInfo, RTFSOBJATTRADD_NOTHING);
222 if (RT_FAILURE(rc))
223 return rc;
224 fMode |= ~fMask & ObjInfo.Attr.fMode;
225 }
226 //RTPathSetMode
227 //return RTFileSetMode(pThis->hDir, fMode);
228 return VERR_NOT_IMPLEMENTED;
229}
230
231
232/**
233 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
234 */
235static DECLCALLBACK(int) rtVfsStdDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
236 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
237{
238 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
239 return RTDirSetTimes(pThis->hDir, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
240}
241
242
243/**
244 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
245 */
246static DECLCALLBACK(int) rtVfsStdDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
247{
248 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
249 return RTDirRelPathSetOwner(pThis->hDir, ".", uid, gid, RTPATH_F_FOLLOW_LINK);
250}
251
252
253
254/**
255 * @interface_method_impl{RTVFSDIROPS,pfnTraversalOpen}
256 */
257static DECLCALLBACK(int) rtVfsStdDir_TraversalOpen(void *pvThis, const char *pszEntry, PRTVFSDIR phVfsDir,
258 PRTVFSSYMLINK phVfsSymlink, PRTVFS phVfsMounted)
259{
260 /* No union mounting or mount points here (yet). */
261 if (phVfsMounted)
262 *phVfsMounted = NIL_RTVFS;
263
264 int rc;
265 if (phVfsDir || phVfsSymlink)
266 {
267 if (phVfsDir)
268 *phVfsDir = NIL_RTVFSDIR;
269 if (phVfsSymlink)
270 *phVfsSymlink = NIL_RTVFSSYMLINK;
271
272 RTFSOBJINFO ObjInfo;
273 rc = rtVfsStdDir_QueryEntryInfo(pvThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
274 if (RT_SUCCESS(rc))
275 {
276 switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
277 {
278 case RTFS_TYPE_DIRECTORY:
279 if (phVfsDir)
280 rc = rtVfsStdDir_OpenDir(pvThis, pszEntry, 0, phVfsDir);
281 else
282 rc = VERR_NOT_SYMLINK;
283 break;
284
285 case RTFS_TYPE_SYMLINK:
286 if (phVfsSymlink)
287 rc = rtVfsStdDir_OpenSymlink(pvThis, pszEntry, phVfsSymlink);
288 else
289 rc = VERR_NOT_A_DIRECTORY;
290 break;
291
292 default:
293 rc = phVfsDir ? VERR_NOT_A_DIRECTORY : VERR_NOT_SYMLINK;
294 break;
295 }
296 }
297 }
298 else
299 rc = VERR_PATH_NOT_FOUND;
300
301 LogFlow(("rtVfsStdDir_TraversalOpen: %s -> %Rrc\n", pszEntry, rc));
302 return rc;
303}
304
305
306/**
307 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
308 */
309static DECLCALLBACK(int) rtVfsStdDir_OpenFile(void *pvThis, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
310{
311 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
312 RTFILE hFile;
313 int rc = RTDirRelFileOpen(pThis->hDir, pszFilename, fOpen, &hFile);
314 if (RT_SUCCESS(rc))
315 {
316 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
317 if (RT_FAILURE(rc))
318 RTFileClose(hFile);
319 }
320 return rc;
321}
322
323
324/**
325 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}
326 */
327static DECLCALLBACK(int) rtVfsStdDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
328{
329 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
330 /** @todo subdir open flags */
331 PRTDIR hSubDir;
332 int rc = RTDirRelDirOpenFiltered(pThis->hDir, pszSubDir, RTDIRFILTER_NONE, fFlags, &hSubDir);
333 if (RT_SUCCESS(rc))
334 {
335 rc = rtVfsDirFromRTDir(hSubDir, fFlags, false, phVfsDir);
336 if (RT_FAILURE(rc))
337 RTDirClose(hSubDir);
338 }
339 return rc;
340}
341
342
343/**
344 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
345 */
346static DECLCALLBACK(int) rtVfsStdDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
347{
348 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
349 int rc;
350 if (!phVfsDir)
351 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, NULL);
352 else
353 {
354 PRTDIR hSubDir;
355 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, &hSubDir);
356 if (RT_SUCCESS(rc))
357 {
358 /** @todo subdir open flags... */
359 rc = rtVfsDirFromRTDir(hSubDir, 0, false, phVfsDir);
360 if (RT_FAILURE(rc))
361 RTDirClose(hSubDir);
362 }
363 }
364
365 return rc;
366}
367
368
369/**
370 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
371 */
372static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
373{
374 RTFSOBJINFO ObjInfo;
375 int rc = rtVfsStdDir_QueryEntryInfo(pvThis, pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING);
376 if (RT_SUCCESS(rc))
377 {
378 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
379 {
380 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
381 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
382 if (cRefs != UINT32_MAX)
383 {
384 PRTVFSSTDSYMLINK pNewSymlink;
385 size_t cchSymlink = strlen(pszSymlink);
386 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
387 NIL_RTVFS, NIL_RTVFSLOCK, phVfsSymlink, (void **)&pNewSymlink);
388 if (RT_SUCCESS(rc))
389 {
390 memcpy(pNewSymlink->szSymlink, pszSymlink, cchSymlink);
391 pNewSymlink->szSymlink[cchSymlink] = '\0';
392 pNewSymlink->pDir = pThis;
393 return VINF_SUCCESS;
394 }
395
396 RTVfsDirRelease(pThis->hSelf);
397 }
398 else
399 rc = VERR_INTERNAL_ERROR_2;
400 }
401 else
402 rc = VERR_NOT_SYMLINK;
403 }
404 return rc;
405}
406
407
408/**
409 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
410 */
411static DECLCALLBACK(int) rtVfsStdDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
412 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
413{
414 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
415 int rc = RTDirRelSymlinkCreate(pThis->hDir, pszSymlink, pszTarget, enmType, 0 /*fCreate*/);
416 if (RT_SUCCESS(rc))
417 {
418 if (!phVfsSymlink)
419 return VINF_SUCCESS;
420 return rtVfsStdDir_OpenSymlink(pThis, pszSymlink, phVfsSymlink);
421 }
422 return rc;
423}
424
425
426/**
427 * @interface_method_impl{RTVFSDIROPS,pfnQueryEntryInfo}
428 */
429static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
430 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
431{
432 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
433 return RTDirRelPathQueryInfo(pThis->hDir, pszEntry, pObjInfo, enmAddAttr, RTPATH_F_ON_LINK);
434}
435
436
437/**
438 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
439 */
440static DECLCALLBACK(int) rtVfsStdDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
441{
442 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
443 if (fType != 0)
444 {
445 RTFSOBJINFO ObjInfo;
446 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
447 if (RT_FAILURE(rc))
448 return rc;
449 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
450 return VERR_WRONG_TYPE;
451 }
452 return RTDirRelPathUnlink(pThis->hDir, pszEntry, 0 /*fUnlink*/);
453}
454
455
456/**
457 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
458 */
459static DECLCALLBACK(int) rtVfsStdDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
460{
461 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
462 if (fType != 0)
463 {
464 RTFSOBJINFO ObjInfo;
465 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
466 if (RT_FAILURE(rc))
467 return rc;
468 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
469 return VERR_WRONG_TYPE;
470 }
471
472 /** @todo RTVFSDIROPS::pfnRenameEntry doesn't really work, this must move to
473 * file system level. */
474 return RTDirRelPathRename(pThis->hDir, pszEntry, pThis->hDir, pszNewName,
475 RTPATHRENAME_FLAGS_NO_SYMLINKS | RTPATHRENAME_FLAGS_NO_REPLACE);
476}
477
478
479/**
480 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
481 */
482static DECLCALLBACK(int) rtVfsStdDir_RewindDir(void *pvThis)
483{
484 NOREF(pvThis);
485 return VERR_NOT_SUPPORTED;
486}
487
488
489/**
490 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
491 */
492static DECLCALLBACK(int) rtVfsStdDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
493{
494 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
495 return RTDirReadEx(pThis->hDir, pDirEntry, pcbDirEntry, enmAddAttr, RTPATH_F_ON_LINK);
496}
497
498
499/**
500 * Standard file operations.
501 */
502DECL_HIDDEN_CONST(const RTVFSDIROPS) g_rtVfsStdDirOps =
503{
504 { /* Obj */
505 RTVFSOBJOPS_VERSION,
506 RTVFSOBJTYPE_DIR,
507 "StdDir",
508 rtVfsStdDir_Close,
509 rtVfsStdDir_QueryInfo,
510 RTVFSOBJOPS_VERSION
511 },
512 RTVFSDIROPS_VERSION,
513 0,
514 { /* ObjSet */
515 RTVFSOBJSETOPS_VERSION,
516 RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
517 rtVfsStdDir_SetMode,
518 rtVfsStdDir_SetTimes,
519 rtVfsStdDir_SetOwner,
520 RTVFSOBJSETOPS_VERSION
521 },
522 rtVfsStdDir_TraversalOpen,
523 rtVfsStdDir_OpenFile,
524 rtVfsStdDir_OpenDir,
525 rtVfsStdDir_CreateDir,
526 rtVfsStdDir_OpenSymlink,
527 rtVfsStdDir_CreateSymlink,
528 rtVfsStdDir_QueryEntryInfo,
529 rtVfsStdDir_UnlinkEntry,
530 rtVfsStdDir_RenameEntry,
531 rtVfsStdDir_RewindDir,
532 rtVfsStdDir_ReadDir,
533 RTVFSDIROPS_VERSION
534};
535
536
537/**
538 * Internal worker for RTVfsDirFromRTDir and RTVfsDirOpenNormal.
539 *
540 * @returns IRPT status code.
541 * @param hDir The IPRT directory handle.
542 * @param fOpen Reserved for future.
543 * @param fLeaveOpen Whether to leave it open or close it.
544 * @param phVfsDir Where to return the handle.
545 */
546static int rtVfsDirFromRTDir(PRTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir)
547{
548 PRTVFSSTDDIR pThis;
549 RTVFSDIR hVfsDir;
550 int rc = RTVfsNewDir(&g_rtVfsStdDirOps, sizeof(RTVFSSTDDIR), 0 /*fFlags*/, NIL_RTVFS, NIL_RTVFSLOCK,
551 &hVfsDir, (void **)&pThis);
552 if (RT_SUCCESS(rc))
553 {
554 pThis->hDir = hDir;
555 pThis->fLeaveOpen = fLeaveOpen;
556 pThis->fFlags = fFlags;
557 pThis->hSelf = hVfsDir;
558
559 *phVfsDir = hVfsDir;
560 return VINF_SUCCESS;
561 }
562 return rc;
563}
564
565
566RTDECL(int) RTVfsDirFromRTDir(PRTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir)
567{
568 AssertReturn(RTDirIsValid(hDir), VERR_INVALID_HANDLE);
569 return rtVfsDirFromRTDir(hDir, hDir->fFlags, fLeaveOpen, phVfsDir);
570}
571
572
573RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
574{
575 /*
576 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
577 */
578 PRTDIR hDir;
579 int rc = RTDirOpenFiltered(&hDir, pszPath, RTDIRFILTER_NONE, fFlags);
580 if (RT_SUCCESS(rc))
581 {
582 /*
583 * Create a VFS file handle.
584 */
585 rc = rtVfsDirFromRTDir(hDir, fFlags, false /*fLeaveOpen*/, phVfsDir);
586 if (RT_SUCCESS(rc))
587 return VINF_SUCCESS;
588
589 RTDirClose(hDir);
590 }
591 return rc;
592}
593
594
595/**
596 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
597 */
598static DECLCALLBACK(int) rtVfsChainStdDir_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
599 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
600{
601 RT_NOREF(pProviderReg, pSpec);
602
603 /*
604 * Basic checks.
605 */
606 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
607 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
608 if (pElement->enmType != RTVFSOBJTYPE_DIR)
609 return VERR_VFS_CHAIN_ONLY_DIR;
610 if (pElement->cArgs < 1)
611 return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
612
613 /*
614 * Parse flag arguments if any, storing them in the element.
615 */
616 uint32_t fFlags = 0;
617 for (uint32_t i = 1; i < pElement->cArgs; i++)
618 if (strcmp(pElement->paArgs[i].psz, "deny-ascent") == 0)
619 fFlags |= RTDIR_F_DENY_ASCENT;
620 else if (strcmp(pElement->paArgs[i].psz, "allow-ascent") == 0)
621 fFlags &= ~RTDIR_F_DENY_ASCENT;
622 else
623 {
624 *poffError = pElement->paArgs[i].offSpec;
625 return RTErrInfoSetF(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Unknown flag argument: %s", pElement->paArgs[i].psz);
626 }
627 pElement->uProvider = fFlags;
628
629 return VINF_SUCCESS;
630}
631
632
633/**
634 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
635 */
636static DECLCALLBACK(int) rtVfsChainStdDir_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
637 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
638 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
639{
640 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
641 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
642
643 RTVFSDIR hVfsDir;
644 int rc = RTVfsDirOpenNormal(pElement->paArgs[0].psz, (uint32_t)pElement->uProvider, &hVfsDir);
645 if (RT_SUCCESS(rc))
646 {
647 *phVfsObj = RTVfsObjFromDir(hVfsDir);
648 RTVfsDirRelease(hVfsDir);
649 if (*phVfsObj != NIL_RTVFSOBJ)
650 return VINF_SUCCESS;
651 rc = VERR_VFS_CHAIN_CAST_FAILED;
652 }
653 return rc;
654}
655
656
657/**
658 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
659 */
660static DECLCALLBACK(bool) rtVfsChainStdDir_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
661 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
662 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
663{
664 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
665 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
666 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
667 return true;
668 return false;
669}
670
671
672/** VFS chain element 'file'. */
673static RTVFSCHAINELEMENTREG g_rtVfsChainStdDirReg =
674{
675 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
676 /* fReserved = */ 0,
677 /* pszName = */ "stddir",
678 /* ListEntry = */ { NULL, NULL },
679 /* pszHelp = */ "Open a real directory. Initial element.\n"
680 "Takes zero or more flag arguments: deny-ascent, allow-ascent",
681 /* pfnValidate = */ rtVfsChainStdDir_Validate,
682 /* pfnInstantiate = */ rtVfsChainStdDir_Instantiate,
683 /* pfnCanReuseElement = */ rtVfsChainStdDir_CanReuseElement,
684 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
685};
686
687RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdDirReg, rtVfsChainStdDirReg);
688
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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