VirtualBox

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

Last change on this file since 69753 was 69753, checked in by vboxsync, 8 years ago

iprt/dir: Morphing PRTDIR into a handle named RTDIR. (Been wanting to correct this for years. Don't know why I makde it a pointer rather than an abstrct handle like everything else.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.0 KB
Line 
1/* $Id: vfsstddir.cpp 69753 2017-11-19 14:27:58Z 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.215389.xyz. 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 RTDIR 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(RTDIR 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 RTDIR 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 RTDIR 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 if (fType == RTFS_TYPE_DIRECTORY)
446 return RTDirRelDirRemove(pThis->hDir, pszEntry);
447
448 RTFSOBJINFO ObjInfo;
449 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
450 if (RT_FAILURE(rc))
451 return rc;
452 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
453 return VERR_WRONG_TYPE;
454 }
455 return RTDirRelPathUnlink(pThis->hDir, pszEntry, 0 /*fUnlink*/);
456}
457
458
459/**
460 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
461 */
462static DECLCALLBACK(int) rtVfsStdDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
463{
464 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
465 if (fType != 0)
466 {
467 RTFSOBJINFO ObjInfo;
468 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
469 if (RT_FAILURE(rc))
470 return rc;
471 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
472 return VERR_WRONG_TYPE;
473 }
474
475 /** @todo RTVFSDIROPS::pfnRenameEntry doesn't really work, this must move to
476 * file system level. */
477 return RTDirRelPathRename(pThis->hDir, pszEntry, pThis->hDir, pszNewName,
478 RTPATHRENAME_FLAGS_NO_SYMLINKS | RTPATHRENAME_FLAGS_NO_REPLACE);
479}
480
481
482/**
483 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
484 */
485static DECLCALLBACK(int) rtVfsStdDir_RewindDir(void *pvThis)
486{
487 NOREF(pvThis);
488 return VERR_NOT_SUPPORTED;
489}
490
491
492/**
493 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
494 */
495static DECLCALLBACK(int) rtVfsStdDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
496{
497 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
498 return RTDirReadEx(pThis->hDir, pDirEntry, pcbDirEntry, enmAddAttr, RTPATH_F_ON_LINK);
499}
500
501
502/**
503 * Standard file operations.
504 */
505DECL_HIDDEN_CONST(const RTVFSDIROPS) g_rtVfsStdDirOps =
506{
507 { /* Obj */
508 RTVFSOBJOPS_VERSION,
509 RTVFSOBJTYPE_DIR,
510 "StdDir",
511 rtVfsStdDir_Close,
512 rtVfsStdDir_QueryInfo,
513 RTVFSOBJOPS_VERSION
514 },
515 RTVFSDIROPS_VERSION,
516 0,
517 { /* ObjSet */
518 RTVFSOBJSETOPS_VERSION,
519 RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
520 rtVfsStdDir_SetMode,
521 rtVfsStdDir_SetTimes,
522 rtVfsStdDir_SetOwner,
523 RTVFSOBJSETOPS_VERSION
524 },
525 rtVfsStdDir_TraversalOpen,
526 rtVfsStdDir_OpenFile,
527 rtVfsStdDir_OpenDir,
528 rtVfsStdDir_CreateDir,
529 rtVfsStdDir_OpenSymlink,
530 rtVfsStdDir_CreateSymlink,
531 rtVfsStdDir_QueryEntryInfo,
532 rtVfsStdDir_UnlinkEntry,
533 rtVfsStdDir_RenameEntry,
534 rtVfsStdDir_RewindDir,
535 rtVfsStdDir_ReadDir,
536 RTVFSDIROPS_VERSION
537};
538
539
540/**
541 * Internal worker for RTVfsDirFromRTDir and RTVfsDirOpenNormal.
542 *
543 * @returns IRPT status code.
544 * @param hDir The IPRT directory handle.
545 * @param fOpen Reserved for future.
546 * @param fLeaveOpen Whether to leave it open or close it.
547 * @param phVfsDir Where to return the handle.
548 */
549static int rtVfsDirFromRTDir(RTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir)
550{
551 PRTVFSSTDDIR pThis;
552 RTVFSDIR hVfsDir;
553 int rc = RTVfsNewDir(&g_rtVfsStdDirOps, sizeof(RTVFSSTDDIR), 0 /*fFlags*/, NIL_RTVFS, NIL_RTVFSLOCK,
554 &hVfsDir, (void **)&pThis);
555 if (RT_SUCCESS(rc))
556 {
557 pThis->hDir = hDir;
558 pThis->fLeaveOpen = fLeaveOpen;
559 pThis->fFlags = fFlags;
560 pThis->hSelf = hVfsDir;
561
562 *phVfsDir = hVfsDir;
563 return VINF_SUCCESS;
564 }
565 return rc;
566}
567
568
569RTDECL(int) RTVfsDirFromRTDir(RTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir)
570{
571 AssertReturn(RTDirIsValid(hDir), VERR_INVALID_HANDLE);
572 return rtVfsDirFromRTDir(hDir, hDir->fFlags, fLeaveOpen, phVfsDir);
573}
574
575
576RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
577{
578 /*
579 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
580 */
581 RTDIR hDir;
582 int rc = RTDirOpenFiltered(&hDir, pszPath, RTDIRFILTER_NONE, fFlags);
583 if (RT_SUCCESS(rc))
584 {
585 /*
586 * Create a VFS file handle.
587 */
588 rc = rtVfsDirFromRTDir(hDir, fFlags, false /*fLeaveOpen*/, phVfsDir);
589 if (RT_SUCCESS(rc))
590 return VINF_SUCCESS;
591
592 RTDirClose(hDir);
593 }
594 return rc;
595}
596
597
598/**
599 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
600 */
601static DECLCALLBACK(int) rtVfsChainStdDir_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
602 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
603{
604 RT_NOREF(pProviderReg, pSpec);
605
606 /*
607 * Basic checks.
608 */
609 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
610 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
611 if (pElement->enmType != RTVFSOBJTYPE_DIR)
612 return VERR_VFS_CHAIN_ONLY_DIR;
613 if (pElement->cArgs < 1)
614 return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
615
616 /*
617 * Parse flag arguments if any, storing them in the element.
618 */
619 uint32_t fFlags = 0;
620 for (uint32_t i = 1; i < pElement->cArgs; i++)
621 if (strcmp(pElement->paArgs[i].psz, "deny-ascent") == 0)
622 fFlags |= RTDIR_F_DENY_ASCENT;
623 else if (strcmp(pElement->paArgs[i].psz, "allow-ascent") == 0)
624 fFlags &= ~RTDIR_F_DENY_ASCENT;
625 else
626 {
627 *poffError = pElement->paArgs[i].offSpec;
628 return RTErrInfoSetF(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Unknown flag argument: %s", pElement->paArgs[i].psz);
629 }
630 pElement->uProvider = fFlags;
631
632 return VINF_SUCCESS;
633}
634
635
636/**
637 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
638 */
639static DECLCALLBACK(int) rtVfsChainStdDir_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
640 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
641 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
642{
643 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
644 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
645
646 RTVFSDIR hVfsDir;
647 int rc = RTVfsDirOpenNormal(pElement->paArgs[0].psz, (uint32_t)pElement->uProvider, &hVfsDir);
648 if (RT_SUCCESS(rc))
649 {
650 *phVfsObj = RTVfsObjFromDir(hVfsDir);
651 RTVfsDirRelease(hVfsDir);
652 if (*phVfsObj != NIL_RTVFSOBJ)
653 return VINF_SUCCESS;
654 rc = VERR_VFS_CHAIN_CAST_FAILED;
655 }
656 return rc;
657}
658
659
660/**
661 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
662 */
663static DECLCALLBACK(bool) rtVfsChainStdDir_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
664 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
665 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
666{
667 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
668 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
669 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
670 return true;
671 return false;
672}
673
674
675/** VFS chain element 'file'. */
676static RTVFSCHAINELEMENTREG g_rtVfsChainStdDirReg =
677{
678 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
679 /* fReserved = */ 0,
680 /* pszName = */ "stddir",
681 /* ListEntry = */ { NULL, NULL },
682 /* pszHelp = */ "Open a real directory. Initial element.\n"
683 "Takes zero or more flag arguments: deny-ascent, allow-ascent",
684 /* pfnValidate = */ rtVfsChainStdDir_Validate,
685 /* pfnInstantiate = */ rtVfsChainStdDir_Instantiate,
686 /* pfnCanReuseElement = */ rtVfsChainStdDir_CanReuseElement,
687 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
688};
689
690RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdDirReg, rtVfsChainStdDirReg);
691
Note: See TracBrowser for help on using the repository browser.

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