VirtualBox

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

Last change on this file since 69679 was 69679, checked in by vboxsync, 7 years ago

iprt: A bunch of basic function for working the file system relative to an open directory. There is only a default implementation currently, the path race conditions will first be eliminated/reduced with platform specific implementations (POSIX, NT). Also added a VFS wrapper around RTDIR handles, completing RTVfsChainOpenDir and making RTLs work on normal directories too (instead of only isofs and fat). [build fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 KB
Line 
1/* $Id: vfsstddir.cpp 69679 2017-11-13 15:53:01Z 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.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_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 = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */);
350 if ( RT_SUCCESS(rc)
351 && phVfsDir)
352 {
353 /** @todo subdir open flags */
354 PRTDIR hSubDir;
355 rc = RTDirRelDirOpen(pThis->hDir, pszSubDir, &hSubDir);
356 if (RT_SUCCESS(rc))
357 {
358 rc = rtVfsDirFromRTDir(hSubDir, 0, false, phVfsDir);
359 if (RT_FAILURE(rc))
360 RTDirClose(hSubDir);
361 }
362 }
363 return rc;
364}
365
366
367/**
368 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
369 */
370static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
371{
372 RTFSOBJINFO ObjInfo;
373 int rc = rtVfsStdDir_QueryEntryInfo(pvThis, pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING);
374 if (RT_SUCCESS(rc))
375 {
376 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
377 {
378 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
379 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
380 if (cRefs != UINT32_MAX)
381 {
382 PRTVFSSTDSYMLINK pNewSymlink;
383 size_t cchSymlink = strlen(pszSymlink);
384 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
385 NIL_RTVFS, NIL_RTVFSLOCK, phVfsSymlink, (void **)&pNewSymlink);
386 if (RT_SUCCESS(rc))
387 {
388 memcpy(pNewSymlink->szSymlink, pszSymlink, cchSymlink);
389 pNewSymlink->szSymlink[cchSymlink] = '\0';
390 pNewSymlink->pDir = pThis;
391 return VINF_SUCCESS;
392 }
393
394 RTVfsDirRelease(pThis->hSelf);
395 }
396 else
397 rc = VERR_INTERNAL_ERROR_2;
398 }
399 else
400 rc = VERR_NOT_SYMLINK;
401 }
402 return rc;
403}
404
405
406/**
407 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
408 */
409static DECLCALLBACK(int) rtVfsStdDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
410 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
411{
412 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
413 int rc = RTDirRelSymlinkCreate(pThis->hDir, pszSymlink, pszTarget, enmType, 0 /*fCreate*/);
414 if (RT_SUCCESS(rc))
415 {
416 if (!phVfsSymlink)
417 return VINF_SUCCESS;
418 return rtVfsStdDir_OpenSymlink(pThis, pszSymlink, phVfsSymlink);
419 }
420 return rc;
421}
422
423
424/**
425 * @interface_method_impl{RTVFSDIROPS,pfnQueryEntryInfo}
426 */
427static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
428 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
429{
430 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
431 return RTDirRelPathQueryInfo(pThis->hDir, pszEntry, pObjInfo, enmAddAttr, RTPATH_F_ON_LINK);
432}
433
434
435/**
436 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
437 */
438static DECLCALLBACK(int) rtVfsStdDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
439{
440 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
441 if (fType != 0)
442 {
443 RTFSOBJINFO ObjInfo;
444 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
445 if (RT_FAILURE(rc))
446 return rc;
447 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
448 return VERR_WRONG_TYPE;
449 }
450 return RTDirRelPathUnlink(pThis->hDir, pszEntry, 0 /*fUnlink*/);
451}
452
453
454/**
455 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
456 */
457static DECLCALLBACK(int) rtVfsStdDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
458{
459 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
460 if (fType != 0)
461 {
462 RTFSOBJINFO ObjInfo;
463 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
464 if (RT_FAILURE(rc))
465 return rc;
466 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
467 return VERR_WRONG_TYPE;
468 }
469
470 /** @todo RTVFSDIROPS::pfnRenameEntry doesn't really work, this must move to
471 * file system level. */
472 return RTDirRelPathRename(pThis->hDir, pszEntry, pThis->hDir, pszNewName,
473 RTPATHRENAME_FLAGS_NO_SYMLINKS | RTPATHRENAME_FLAGS_NO_REPLACE);
474}
475
476
477/**
478 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
479 */
480static DECLCALLBACK(int) rtVfsStdDir_RewindDir(void *pvThis)
481{
482 NOREF(pvThis);
483 return VERR_NOT_SUPPORTED;
484}
485
486
487/**
488 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
489 */
490static DECLCALLBACK(int) rtVfsStdDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
491{
492 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
493 return RTDirReadEx(pThis->hDir, pDirEntry, pcbDirEntry, enmAddAttr, RTPATH_F_ON_LINK);
494}
495
496
497/**
498 * Standard file operations.
499 */
500DECL_HIDDEN_CONST(const RTVFSDIROPS) g_rtVfsStdDirOps =
501{
502 { /* Obj */
503 RTVFSOBJOPS_VERSION,
504 RTVFSOBJTYPE_DIR,
505 "StdDir",
506 rtVfsStdDir_Close,
507 rtVfsStdDir_QueryInfo,
508 RTVFSOBJOPS_VERSION
509 },
510 RTVFSDIROPS_VERSION,
511 0,
512 { /* ObjSet */
513 RTVFSOBJSETOPS_VERSION,
514 RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
515 rtVfsStdDir_SetMode,
516 rtVfsStdDir_SetTimes,
517 rtVfsStdDir_SetOwner,
518 RTVFSOBJSETOPS_VERSION
519 },
520 rtVfsStdDir_TraversalOpen,
521 rtVfsStdDir_OpenFile,
522 rtVfsStdDir_OpenDir,
523 rtVfsStdDir_CreateDir,
524 rtVfsStdDir_OpenSymlink,
525 rtVfsStdDir_CreateSymlink,
526 rtVfsStdDir_QueryEntryInfo,
527 rtVfsStdDir_UnlinkEntry,
528 rtVfsStdDir_RenameEntry,
529 rtVfsStdDir_RewindDir,
530 rtVfsStdDir_ReadDir,
531 RTVFSDIROPS_VERSION
532};
533
534
535/**
536 * Internal worker for RTVfsDirFromRTDir and RTVfsDirOpenNormal.
537 *
538 * @returns IRPT status code.
539 * @param hDir The IPRT directory handle.
540 * @param fOpen Reserved for future.
541 * @param fLeaveOpen Whether to leave it open or close it.
542 * @param phVfsDir Where to return the handle.
543 */
544static int rtVfsDirFromRTDir(PRTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir)
545{
546 PRTVFSSTDDIR pThis;
547 RTVFSDIR hVfsDir;
548 int rc = RTVfsNewDir(&g_rtVfsStdDirOps, sizeof(RTVFSSTDDIR), 0 /*fFlags*/, NIL_RTVFS, NIL_RTVFSLOCK,
549 &hVfsDir, (void **)&pThis);
550 if (RT_SUCCESS(rc))
551 {
552 pThis->hDir = hDir;
553 pThis->fLeaveOpen = fLeaveOpen;
554 pThis->fFlags = fFlags;
555 pThis->hSelf = hVfsDir;
556
557 *phVfsDir = hVfsDir;
558 return VINF_SUCCESS;
559 }
560 return rc;
561}
562
563
564RTDECL(int) RTVfsDirFromRTDir(PRTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir)
565{
566 AssertReturn(RTDirIsValid(hDir), VERR_INVALID_HANDLE);
567 return rtVfsDirFromRTDir(hDir, hDir->fFlags, fLeaveOpen, phVfsDir);
568}
569
570
571RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
572{
573 /*
574 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
575 */
576 PRTDIR hDir;
577 int rc = RTDirOpenFiltered(&hDir, pszPath, RTDIRFILTER_NONE, fFlags);
578 if (RT_SUCCESS(rc))
579 {
580 /*
581 * Create a VFS file handle.
582 */
583 rc = rtVfsDirFromRTDir(hDir, fFlags, false /*fLeaveOpen*/, phVfsDir);
584 if (RT_SUCCESS(rc))
585 return VINF_SUCCESS;
586
587 RTDirClose(hDir);
588 }
589 return rc;
590}
591
592
593/**
594 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
595 */
596static DECLCALLBACK(int) rtVfsChainStdDir_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
597 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
598{
599 RT_NOREF(pProviderReg, pSpec);
600
601 /*
602 * Basic checks.
603 */
604 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
605 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
606 if (pElement->enmType != RTVFSOBJTYPE_DIR)
607 return VERR_VFS_CHAIN_ONLY_DIR;
608 if (pElement->cArgs < 1)
609 return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
610
611 /*
612 * Parse flag arguments if any, storing them in the element.
613 */
614 uint32_t fFlags = 0;
615 for (uint32_t i = 1; i < pElement->cArgs; i++)
616 if (strcmp(pElement->paArgs[i].psz, "deny-ascent") == 0)
617 fFlags |= RTDIR_F_DENY_ASCENT;
618 else if (strcmp(pElement->paArgs[i].psz, "allow-ascent") == 0)
619 fFlags &= ~RTDIR_F_DENY_ASCENT;
620 else
621 {
622 *poffError = pElement->paArgs[i].offSpec;
623 return RTErrInfoSetF(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Unknown flag argument: %s", pElement->paArgs[i].psz);
624 }
625 pElement->uProvider = fFlags;
626
627 return VINF_SUCCESS;
628}
629
630
631/**
632 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
633 */
634static DECLCALLBACK(int) rtVfsChainStdDir_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
635 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
636 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
637{
638 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
639 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
640
641 RTVFSDIR hVfsDir;
642 int rc = RTVfsDirOpenNormal(pElement->paArgs[0].psz, (uint32_t)pElement->uProvider, &hVfsDir);
643 if (RT_SUCCESS(rc))
644 {
645 *phVfsObj = RTVfsObjFromDir(hVfsDir);
646 RTVfsDirRelease(hVfsDir);
647 if (*phVfsObj != NIL_RTVFSOBJ)
648 return VINF_SUCCESS;
649 rc = VERR_VFS_CHAIN_CAST_FAILED;
650 }
651 return rc;
652}
653
654
655/**
656 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
657 */
658static DECLCALLBACK(bool) rtVfsChainStdDir_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
659 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
660 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
661{
662 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
663 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
664 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
665 return true;
666 return false;
667}
668
669
670/** VFS chain element 'file'. */
671static RTVFSCHAINELEMENTREG g_rtVfsChainStdDirReg =
672{
673 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
674 /* fReserved = */ 0,
675 /* pszName = */ "stddir",
676 /* ListEntry = */ { NULL, NULL },
677 /* pszHelp = */ "Open a real directory. Initial element.\n"
678 "Takes zero or more flag arguments: deny-ascent, allow-ascent",
679 /* pfnValidate = */ rtVfsChainStdDir_Validate,
680 /* pfnInstantiate = */ rtVfsChainStdDir_Instantiate,
681 /* pfnCanReuseElement = */ rtVfsChainStdDir_CanReuseElement,
682 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
683};
684
685RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdDirReg, rtVfsChainStdDirReg);
686
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