VirtualBox

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

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

IPRT/VFS: Got rid of the pfnTraversalOpen method.

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