VirtualBox

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

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

IPRT: VFS opening reworking in progress.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.4 KB
Line 
1/* $Id: vfsstddir.cpp 69813 2017-11-23 18:33:30Z 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 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,pfnOpenObj}
308 */
309static DECLCALLBACK(int) rtVfsStdDir_OpenObj(void *pvThis, const char *pszEntry, uint64_t fOpen,
310 uint32_t fFlags, PRTVFSOBJ phVfsObj)
311{
312 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
313
314 /*
315 * This is subject to race conditions, but we haven't too much of a choice
316 * without going platform specific here (we'll do that eventually).
317 */
318 RTFSOBJINFO ObjInfo;
319 int rc = RTDirRelPathQueryInfo(pThis->hDir, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
320 if (RT_SUCCESS(rc))
321 {
322 switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
323 {
324 case RTFS_TYPE_DIRECTORY:
325 if (!(fFlags & RTVFSOBJ_F_OPEN_DIRECTORY))
326 {
327 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
328 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
329 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
330 {
331 RTDIR hSubDir;
332 rc = RTDirRelDirOpenFiltered(pThis->hDir, pszEntry, RTDIRFILTER_NONE, fFlags, &hSubDir);
333 if (RT_SUCCESS(rc))
334 {
335 RTVFSDIR hVfsDir;
336 rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
337 if (RT_SUCCESS(rc))
338 {
339 *phVfsObj = RTVfsObjFromDir(hVfsDir);
340 RTVfsDirRelease(hVfsDir);
341 AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
342 }
343 else
344 RTDirClose(hSubDir);
345 }
346 }
347 else
348 rc = VERR_ALREADY_EXISTS;
349 }
350 else
351 rc = VERR_IS_A_DIRECTORY;
352 break;
353
354 case RTFS_TYPE_FILE:
355 case RTFS_TYPE_DEV_BLOCK:
356 case RTFS_TYPE_DEV_CHAR:
357 case RTFS_TYPE_FIFO:
358 case RTFS_TYPE_SOCKET:
359 switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
360 {
361 case RTFS_TYPE_FILE:
362 rc = fFlags & RTVFSOBJ_F_OPEN_FILE ? VINF_SUCCESS : VERR_IS_A_FILE;
363 break;
364 case RTFS_TYPE_DEV_BLOCK:
365 rc = fFlags & RTVFSOBJ_F_OPEN_DEV_BLOCK ? VINF_SUCCESS : VERR_IS_A_BLOCK_DEVICE;
366 break;
367 case RTFS_TYPE_DEV_CHAR:
368 rc = fFlags & RTVFSOBJ_F_OPEN_DEV_CHAR ? VINF_SUCCESS : VERR_IS_A_CHAR_DEVICE;
369 break;
370 /** @todo These two types should not result in files, but pure I/O streams.
371 * possibly char device too. */
372 case RTFS_TYPE_FIFO:
373 rc = fFlags & RTVFSOBJ_F_OPEN_FIFO ? VINF_SUCCESS : VERR_IS_A_FIFO;
374 break;
375 case RTFS_TYPE_SOCKET:
376 rc = fFlags & RTVFSOBJ_F_OPEN_SOCKET ? VINF_SUCCESS : VERR_IS_A_SOCKET;
377 break;
378 default:
379 rc = VERR_INVALID_FLAGS;
380 break;
381 }
382 if (RT_SUCCESS(rc))
383 {
384 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
385 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
386 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
387 {
388 RTFILE hFile;
389 rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fOpen, &hFile);
390 if (RT_SUCCESS(rc))
391 {
392 RTVFSFILE hVfsFile;
393 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile);
394 if (RT_SUCCESS(rc))
395 {
396 *phVfsObj = RTVfsObjFromFile(hVfsFile);
397 RTVfsFileRelease(hVfsFile);
398 AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
399 }
400 else
401 RTFileClose(hFile);
402 }
403 }
404 else
405 rc = VERR_ALREADY_EXISTS;
406 }
407 break;
408
409 case RTFS_TYPE_SYMLINK:
410 if (fFlags & RTVFSOBJ_F_OPEN_SYMLINK)
411 {
412 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
413 if (cRefs != UINT32_MAX)
414 {
415 RTVFSSYMLINK hVfsSymlink;
416 PRTVFSSTDSYMLINK pNewSymlink;
417 size_t cchSymlink = strlen(pszEntry);
418 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
419 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsSymlink, (void **)&pNewSymlink);
420 if (RT_SUCCESS(rc))
421 {
422 memcpy(pNewSymlink->szSymlink, pszEntry, cchSymlink);
423 pNewSymlink->szSymlink[cchSymlink] = '\0';
424 pNewSymlink->pDir = pThis;
425
426 *phVfsObj = RTVfsObjFromSymlink(hVfsSymlink);
427 RTVfsSymlinkRelease(hVfsSymlink);
428 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
429 }
430 else
431 RTVfsDirRelease(pThis->hSelf);
432 }
433 else
434 rc = VERR_INTERNAL_ERROR_2;
435 }
436 else
437 rc = VERR_IS_A_SYMLINK;
438 break;
439
440 default:
441 break;
442 }
443 }
444 else if ( rc == VERR_FILE_NOT_FOUND
445 || rc == VERR_PATH_NOT_FOUND)
446 {
447 /*
448 * Consider file or directory creation.
449 */
450 if ( ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
451 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
452 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
453 && (fFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_NOTHING)
454 {
455
456 if ((fFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_FILE)
457 {
458 RTFILE hFile;
459 rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fOpen, &hFile);
460 if (RT_SUCCESS(rc))
461 {
462 RTVFSFILE hVfsFile;
463 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, &hVfsFile);
464 if (RT_SUCCESS(rc))
465 {
466 *phVfsObj = RTVfsObjFromFile(hVfsFile);
467 RTVfsFileRelease(hVfsFile);
468 AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
469 }
470 else
471 RTFileClose(hFile);
472 }
473 }
474 else if ((fFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_DIRECTORY)
475 {
476 RTDIR hSubDir;
477 rc = RTDirRelDirCreate(pThis->hDir, pszEntry, (fOpen & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT,
478 0 /* fFlags */, &hSubDir);
479 if (RT_SUCCESS(rc))
480 {
481 RTVFSDIR hVfsDir;
482 rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
483 if (RT_SUCCESS(rc))
484 {
485 *phVfsObj = RTVfsObjFromDir(hVfsDir);
486 RTVfsDirRelease(hVfsDir);
487 AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
488 }
489 else
490 RTDirClose(hSubDir);
491 }
492 }
493 else
494 rc = VERR_VFS_UNSUPPORTED_CREATE_TYPE;
495 }
496 else
497 rc = VERR_FILE_NOT_FOUND;
498 }
499 return rc;
500}
501
502
503/**
504 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
505 */
506static DECLCALLBACK(int) rtVfsStdDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
507{
508 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
509 RTFILE hFile;
510 int rc = RTDirRelFileOpen(pThis->hDir, pszFilename, fOpen, &hFile);
511 if (RT_SUCCESS(rc))
512 {
513 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
514 if (RT_FAILURE(rc))
515 RTFileClose(hFile);
516 }
517 return rc;
518}
519
520
521/**
522 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}
523 */
524static DECLCALLBACK(int) rtVfsStdDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
525{
526 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
527 /** @todo subdir open flags */
528 RTDIR hSubDir;
529 int rc = RTDirRelDirOpenFiltered(pThis->hDir, pszSubDir, RTDIRFILTER_NONE, fFlags, &hSubDir);
530 if (RT_SUCCESS(rc))
531 {
532 rc = rtVfsDirFromRTDir(hSubDir, fFlags, false, phVfsDir);
533 if (RT_FAILURE(rc))
534 RTDirClose(hSubDir);
535 }
536 return rc;
537}
538
539
540/**
541 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
542 */
543static DECLCALLBACK(int) rtVfsStdDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
544{
545 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
546 int rc;
547 if (!phVfsDir)
548 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, NULL);
549 else
550 {
551 RTDIR hSubDir;
552 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, &hSubDir);
553 if (RT_SUCCESS(rc))
554 {
555 /** @todo subdir open flags... */
556 rc = rtVfsDirFromRTDir(hSubDir, 0, false, phVfsDir);
557 if (RT_FAILURE(rc))
558 RTDirClose(hSubDir);
559 }
560 }
561
562 return rc;
563}
564
565
566/**
567 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
568 */
569static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
570{
571 RTFSOBJINFO ObjInfo;
572 int rc = rtVfsStdDir_QueryEntryInfo(pvThis, pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING);
573 if (RT_SUCCESS(rc))
574 {
575 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
576 {
577 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
578 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
579 if (cRefs != UINT32_MAX)
580 {
581 PRTVFSSTDSYMLINK pNewSymlink;
582 size_t cchSymlink = strlen(pszSymlink);
583 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
584 NIL_RTVFS, NIL_RTVFSLOCK, phVfsSymlink, (void **)&pNewSymlink);
585 if (RT_SUCCESS(rc))
586 {
587 memcpy(pNewSymlink->szSymlink, pszSymlink, cchSymlink);
588 pNewSymlink->szSymlink[cchSymlink] = '\0';
589 pNewSymlink->pDir = pThis;
590 return VINF_SUCCESS;
591 }
592
593 RTVfsDirRelease(pThis->hSelf);
594 }
595 else
596 rc = VERR_INTERNAL_ERROR_2;
597 }
598 else
599 rc = VERR_NOT_SYMLINK;
600 }
601 return rc;
602}
603
604
605/**
606 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
607 */
608static DECLCALLBACK(int) rtVfsStdDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
609 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
610{
611 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
612 int rc = RTDirRelSymlinkCreate(pThis->hDir, pszSymlink, pszTarget, enmType, 0 /*fCreate*/);
613 if (RT_SUCCESS(rc))
614 {
615 if (!phVfsSymlink)
616 return VINF_SUCCESS;
617 return rtVfsStdDir_OpenSymlink(pThis, pszSymlink, phVfsSymlink);
618 }
619 return rc;
620}
621
622
623/**
624 * @interface_method_impl{RTVFSDIROPS,pfnQueryEntryInfo}
625 */
626static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
627 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
628{
629 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
630 return RTDirRelPathQueryInfo(pThis->hDir, pszEntry, pObjInfo, enmAddAttr, RTPATH_F_ON_LINK);
631}
632
633
634/**
635 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
636 */
637static DECLCALLBACK(int) rtVfsStdDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
638{
639 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
640 if (fType != 0)
641 {
642 if (fType == RTFS_TYPE_DIRECTORY)
643 return RTDirRelDirRemove(pThis->hDir, pszEntry);
644
645 RTFSOBJINFO ObjInfo;
646 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
647 if (RT_FAILURE(rc))
648 return rc;
649 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
650 return VERR_WRONG_TYPE;
651 }
652 return RTDirRelPathUnlink(pThis->hDir, pszEntry, 0 /*fUnlink*/);
653}
654
655
656/**
657 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
658 */
659static DECLCALLBACK(int) rtVfsStdDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
660{
661 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
662 if (fType != 0)
663 {
664 RTFSOBJINFO ObjInfo;
665 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
666 if (RT_FAILURE(rc))
667 return rc;
668 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
669 return VERR_WRONG_TYPE;
670 }
671
672 /** @todo RTVFSDIROPS::pfnRenameEntry doesn't really work, this must move to
673 * file system level. */
674 return RTDirRelPathRename(pThis->hDir, pszEntry, pThis->hDir, pszNewName,
675 RTPATHRENAME_FLAGS_NO_SYMLINKS | RTPATHRENAME_FLAGS_NO_REPLACE);
676}
677
678
679/**
680 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
681 */
682static DECLCALLBACK(int) rtVfsStdDir_RewindDir(void *pvThis)
683{
684 NOREF(pvThis);
685 return VERR_NOT_SUPPORTED;
686}
687
688
689/**
690 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
691 */
692static DECLCALLBACK(int) rtVfsStdDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
693{
694 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
695 return RTDirReadEx(pThis->hDir, pDirEntry, pcbDirEntry, enmAddAttr, RTPATH_F_ON_LINK);
696}
697
698
699/**
700 * Standard file operations.
701 */
702DECL_HIDDEN_CONST(const RTVFSDIROPS) g_rtVfsStdDirOps =
703{
704 { /* Obj */
705 RTVFSOBJOPS_VERSION,
706 RTVFSOBJTYPE_DIR,
707 "StdDir",
708 rtVfsStdDir_Close,
709 rtVfsStdDir_QueryInfo,
710 RTVFSOBJOPS_VERSION
711 },
712 RTVFSDIROPS_VERSION,
713 0,
714 { /* ObjSet */
715 RTVFSOBJSETOPS_VERSION,
716 RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet),
717 rtVfsStdDir_SetMode,
718 rtVfsStdDir_SetTimes,
719 rtVfsStdDir_SetOwner,
720 RTVFSOBJSETOPS_VERSION
721 },
722 rtVfsStdDir_OpenObj,
723 rtVfsStdDir_TraversalOpen,
724 rtVfsStdDir_OpenFile,
725 rtVfsStdDir_OpenDir,
726 rtVfsStdDir_CreateDir,
727 rtVfsStdDir_OpenSymlink,
728 rtVfsStdDir_CreateSymlink,
729 rtVfsStdDir_QueryEntryInfo,
730 rtVfsStdDir_UnlinkEntry,
731 rtVfsStdDir_RenameEntry,
732 rtVfsStdDir_RewindDir,
733 rtVfsStdDir_ReadDir,
734 RTVFSDIROPS_VERSION
735};
736
737
738/**
739 * Internal worker for RTVfsDirFromRTDir and RTVfsDirOpenNormal.
740 *
741 * @returns IRPT status code.
742 * @param hDir The IPRT directory handle.
743 * @param fOpen Reserved for future.
744 * @param fLeaveOpen Whether to leave it open or close it.
745 * @param phVfsDir Where to return the handle.
746 */
747static int rtVfsDirFromRTDir(RTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir)
748{
749 PRTVFSSTDDIR pThis;
750 RTVFSDIR hVfsDir;
751 int rc = RTVfsNewDir(&g_rtVfsStdDirOps, sizeof(RTVFSSTDDIR), 0 /*fFlags*/, NIL_RTVFS, NIL_RTVFSLOCK,
752 &hVfsDir, (void **)&pThis);
753 if (RT_SUCCESS(rc))
754 {
755 pThis->hDir = hDir;
756 pThis->fLeaveOpen = fLeaveOpen;
757 pThis->fFlags = fFlags;
758 pThis->hSelf = hVfsDir;
759
760 *phVfsDir = hVfsDir;
761 return VINF_SUCCESS;
762 }
763 return rc;
764}
765
766
767RTDECL(int) RTVfsDirFromRTDir(RTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir)
768{
769 AssertReturn(RTDirIsValid(hDir), VERR_INVALID_HANDLE);
770 return rtVfsDirFromRTDir(hDir, hDir->fFlags, fLeaveOpen, phVfsDir);
771}
772
773
774RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
775{
776 /*
777 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
778 */
779 RTDIR hDir;
780 int rc = RTDirOpenFiltered(&hDir, pszPath, RTDIRFILTER_NONE, fFlags);
781 if (RT_SUCCESS(rc))
782 {
783 /*
784 * Create a VFS file handle.
785 */
786 rc = rtVfsDirFromRTDir(hDir, fFlags, false /*fLeaveOpen*/, phVfsDir);
787 if (RT_SUCCESS(rc))
788 return VINF_SUCCESS;
789
790 RTDirClose(hDir);
791 }
792 return rc;
793}
794
795
796/**
797 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
798 */
799static DECLCALLBACK(int) rtVfsChainStdDir_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
800 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
801{
802 RT_NOREF(pProviderReg, pSpec);
803
804 /*
805 * Basic checks.
806 */
807 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
808 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
809 if (pElement->enmType != RTVFSOBJTYPE_DIR)
810 return VERR_VFS_CHAIN_ONLY_DIR;
811 if (pElement->cArgs < 1)
812 return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
813
814 /*
815 * Parse flag arguments if any, storing them in the element.
816 */
817 uint32_t fFlags = 0;
818 for (uint32_t i = 1; i < pElement->cArgs; i++)
819 if (strcmp(pElement->paArgs[i].psz, "deny-ascent") == 0)
820 fFlags |= RTDIR_F_DENY_ASCENT;
821 else if (strcmp(pElement->paArgs[i].psz, "allow-ascent") == 0)
822 fFlags &= ~RTDIR_F_DENY_ASCENT;
823 else
824 {
825 *poffError = pElement->paArgs[i].offSpec;
826 return RTErrInfoSetF(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Unknown flag argument: %s", pElement->paArgs[i].psz);
827 }
828 pElement->uProvider = fFlags;
829
830 return VINF_SUCCESS;
831}
832
833
834/**
835 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
836 */
837static DECLCALLBACK(int) rtVfsChainStdDir_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
838 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
839 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
840{
841 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
842 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
843
844 RTVFSDIR hVfsDir;
845 int rc = RTVfsDirOpenNormal(pElement->paArgs[0].psz, (uint32_t)pElement->uProvider, &hVfsDir);
846 if (RT_SUCCESS(rc))
847 {
848 *phVfsObj = RTVfsObjFromDir(hVfsDir);
849 RTVfsDirRelease(hVfsDir);
850 if (*phVfsObj != NIL_RTVFSOBJ)
851 return VINF_SUCCESS;
852 rc = VERR_VFS_CHAIN_CAST_FAILED;
853 }
854 return rc;
855}
856
857
858/**
859 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
860 */
861static DECLCALLBACK(bool) rtVfsChainStdDir_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
862 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
863 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
864{
865 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
866 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
867 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
868 return true;
869 return false;
870}
871
872
873/** VFS chain element 'file'. */
874static RTVFSCHAINELEMENTREG g_rtVfsChainStdDirReg =
875{
876 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
877 /* fReserved = */ 0,
878 /* pszName = */ "stddir",
879 /* ListEntry = */ { NULL, NULL },
880 /* pszHelp = */ "Open a real directory. Initial element.\n"
881 "Takes zero or more flag arguments: deny-ascent, allow-ascent",
882 /* pfnValidate = */ rtVfsChainStdDir_Validate,
883 /* pfnInstantiate = */ rtVfsChainStdDir_Instantiate,
884 /* pfnCanReuseElement = */ rtVfsChainStdDir_CanReuseElement,
885 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
886};
887
888RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdDirReg, rtVfsChainStdDirReg);
889
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