VirtualBox

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

Last change on this file since 106580 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.8 KB
Line 
1/* $Id: vfsstddir.cpp 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard Directory Implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_VFS
42#include <iprt/vfs.h>
43#include <iprt/vfslowlevel.h>
44
45#include <iprt/assert.h>
46#include <iprt/dir.h>
47#include <iprt/err.h>
48#include <iprt/file.h>
49#include <iprt/log.h>
50#include <iprt/path.h>
51#include <iprt/string.h>
52
53#define RTDIR_AGNOSTIC
54#include "internal/dir.h"
55
56
57/*********************************************************************************************************************************
58* Structures and Typedefs *
59*********************************************************************************************************************************/
60/**
61 * Private data of a standard directory.
62 */
63typedef struct RTVFSSTDDIR
64{
65 /** The directory handle. */
66 RTDIR hDir;
67 /** Whether to leave the handle open when the VFS handle is closed. */
68 bool fLeaveOpen;
69 /** Open flags, RTDIR_F_XXX. */
70 uint32_t fFlags;
71 /** Handle to the director so we can make sure it sticks around for symbolic
72 * link objects. */
73 RTVFSDIR hSelf;
74} RTVFSSTDDIR;
75/** Pointer to the private data of a standard directory. */
76typedef RTVFSSTDDIR *PRTVFSSTDDIR;
77
78
79/**
80 * Private data of a standard symbolic link.
81 */
82typedef struct RTVFSSTDSYMLINK
83{
84 /** Pointer to the VFS directory where the symbolic link lives . */
85 PRTVFSSTDDIR pDir;
86 /** The symbolic link name. */
87 RT_FLEXIBLE_ARRAY_EXTENSION
88 char szSymlink[RT_FLEXIBLE_ARRAY];
89} RTVFSSTDSYMLINK;
90/** Pointer to the private data of a standard symbolic link. */
91typedef RTVFSSTDSYMLINK *PRTVFSSTDSYMLINK;
92
93
94/*********************************************************************************************************************************
95* Internal Functions *
96*********************************************************************************************************************************/
97static DECLCALLBACK(int) rtVfsStdDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir);
98static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink);
99static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
100 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr);
101static int rtVfsDirFromRTDir(RTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir);
102
103
104
105/**
106 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
107 */
108static DECLCALLBACK(int) rtVfsStdSym_Close(void *pvThis)
109{
110 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
111 RTVfsDirRelease(pThis->pDir->hSelf);
112 pThis->pDir = NULL;
113 return VINF_SUCCESS;
114}
115
116
117/**
118 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
119 */
120static DECLCALLBACK(int) rtVfsStdSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
121{
122 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
123 return rtVfsStdDir_QueryEntryInfo(pThis->pDir, pThis->szSymlink, pObjInfo, enmAddAttr);
124}
125
126/**
127 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
128 */
129static DECLCALLBACK(int) rtVfsStdSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
130{
131 NOREF(pvThis); NOREF(fMode); NOREF(fMask);
132 return VERR_ACCESS_DENIED;
133}
134
135
136/**
137 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
138 */
139static DECLCALLBACK(int) rtVfsStdSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
140 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
141{
142 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
143 return VERR_ACCESS_DENIED;
144}
145
146
147/**
148 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
149 */
150static DECLCALLBACK(int) rtVfsStdSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
151{
152 NOREF(pvThis); NOREF(uid); NOREF(gid);
153 return VERR_ACCESS_DENIED;
154}
155
156
157/**
158 * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
159 */
160static DECLCALLBACK(int) rtVfsStdSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)
161{
162 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
163 return RTDirRelSymlinkRead(pThis->pDir->hDir, pThis->szSymlink, pszTarget, cbTarget, 0 /*fRead*/);
164}
165
166
167/**
168 * Symbolic operations for standard directory.
169 */
170static const RTVFSSYMLINKOPS g_rtVfsStdSymOps =
171{
172 { /* Obj */
173 RTVFSOBJOPS_VERSION,
174 RTVFSOBJTYPE_SYMLINK,
175 "StdSymlink",
176 rtVfsStdSym_Close,
177 rtVfsStdSym_QueryInfo,
178 NULL,
179 RTVFSOBJOPS_VERSION
180 },
181 RTVFSSYMLINKOPS_VERSION,
182 0,
183 { /* ObjSet */
184 RTVFSOBJSETOPS_VERSION,
185 RT_UOFFSETOF(RTVFSSYMLINKOPS, ObjSet) - RT_UOFFSETOF(RTVFSSYMLINKOPS, Obj),
186 rtVfsStdSym_SetMode,
187 rtVfsStdSym_SetTimes,
188 rtVfsStdSym_SetOwner,
189 RTVFSOBJSETOPS_VERSION
190 },
191 rtVfsStdSym_Read,
192 RTVFSSYMLINKOPS_VERSION
193};
194
195
196/**
197 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
198 */
199static DECLCALLBACK(int) rtVfsStdDir_Close(void *pvThis)
200{
201 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
202
203 int rc;
204 if (!pThis->fLeaveOpen)
205 rc = RTDirClose(pThis->hDir);
206 else
207 rc = VINF_SUCCESS;
208 pThis->hDir = NULL;
209
210 return rc;
211}
212
213
214/**
215 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
216 */
217static DECLCALLBACK(int) rtVfsStdDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
218{
219 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
220 return RTDirQueryInfo(pThis->hDir, pObjInfo, enmAddAttr);
221}
222
223
224/**
225 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
226 */
227static DECLCALLBACK(int) rtVfsStdDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
228{
229 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
230 if (fMask != ~RTFS_TYPE_MASK)
231 {
232 RTFSOBJINFO ObjInfo;
233 int rc = RTDirQueryInfo(pThis->hDir, &ObjInfo, RTFSOBJATTRADD_NOTHING);
234 if (RT_FAILURE(rc))
235 return rc;
236 fMode |= ~fMask & ObjInfo.Attr.fMode;
237 }
238#if 0
239 RTPathSetMode
240 return RTFileSetMode(pThis->hDir, fMode);
241#else
242 RT_NOREF(fMode);
243 return VERR_NOT_IMPLEMENTED;
244#endif
245}
246
247
248/**
249 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
250 */
251static DECLCALLBACK(int) rtVfsStdDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
252 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
253{
254 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
255 return RTDirSetTimes(pThis->hDir, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
256}
257
258
259/**
260 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
261 */
262static DECLCALLBACK(int) rtVfsStdDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
263{
264 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
265 return RTDirRelPathSetOwner(pThis->hDir, ".", uid, gid, RTPATH_F_FOLLOW_LINK);
266}
267
268
269/**
270 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
271 */
272static DECLCALLBACK(int) rtVfsStdDir_Open(void *pvThis, const char *pszEntry, uint64_t fFileOpen,
273 uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
274{
275 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
276
277 /*
278 * This is subject to race conditions, but we haven't too much of a choice
279 * without going platform specific here (we'll do that eventually).
280 */
281 RTFSOBJINFO ObjInfo;
282 int rc = RTDirRelPathQueryInfo(pThis->hDir, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
283 if (RT_SUCCESS(rc))
284 {
285 switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
286 {
287 case RTFS_TYPE_DIRECTORY:
288 if (fObjFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
289 {
290 if ( (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
291 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
292 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
293 {
294 RTDIR hSubDir;
295 rc = RTDirRelDirOpenFiltered(pThis->hDir, pszEntry, RTDIRFILTER_NONE, 0 /*fFlags*/, &hSubDir);
296 if (RT_SUCCESS(rc))
297 {
298 RTVFSDIR hVfsDir;
299 rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
300 if (RT_SUCCESS(rc))
301 {
302 *phVfsObj = RTVfsObjFromDir(hVfsDir);
303 RTVfsDirRelease(hVfsDir);
304 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
305 }
306 else
307 RTDirClose(hSubDir);
308 }
309 }
310 else
311 rc = VERR_ALREADY_EXISTS;
312 }
313 else
314 rc = VERR_IS_A_DIRECTORY;
315 break;
316
317 case RTFS_TYPE_FILE:
318 case RTFS_TYPE_DEV_BLOCK:
319 case RTFS_TYPE_DEV_CHAR:
320 case RTFS_TYPE_FIFO:
321 case RTFS_TYPE_SOCKET:
322 switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
323 {
324 case RTFS_TYPE_FILE:
325 rc = fObjFlags & RTVFSOBJ_F_OPEN_FILE ? VINF_SUCCESS : VERR_IS_A_FILE;
326 break;
327 case RTFS_TYPE_DEV_BLOCK:
328 rc = fObjFlags & RTVFSOBJ_F_OPEN_DEV_BLOCK ? VINF_SUCCESS : VERR_IS_A_BLOCK_DEVICE;
329 break;
330 case RTFS_TYPE_DEV_CHAR:
331 rc = fObjFlags & RTVFSOBJ_F_OPEN_DEV_CHAR ? VINF_SUCCESS : VERR_IS_A_CHAR_DEVICE;
332 break;
333 /** @todo These two types should not result in files, but pure I/O streams.
334 * possibly char device too. */
335 case RTFS_TYPE_FIFO:
336 rc = fObjFlags & RTVFSOBJ_F_OPEN_FIFO ? VINF_SUCCESS : VERR_IS_A_FIFO;
337 break;
338 case RTFS_TYPE_SOCKET:
339 rc = fObjFlags & RTVFSOBJ_F_OPEN_SOCKET ? VINF_SUCCESS : VERR_IS_A_SOCKET;
340 break;
341 default:
342 rc = VERR_INVALID_FLAGS;
343 break;
344 }
345 if (RT_SUCCESS(rc))
346 {
347 if ( (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
348 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
349 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
350 {
351 RTFILE hFile;
352 rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fFileOpen, &hFile);
353 if (RT_SUCCESS(rc))
354 {
355 RTVFSFILE hVfsFile;
356 rc = RTVfsFileFromRTFile(hFile, fFileOpen, false /*fLeaveOpen*/, &hVfsFile);
357 if (RT_SUCCESS(rc))
358 {
359 *phVfsObj = RTVfsObjFromFile(hVfsFile);
360 RTVfsFileRelease(hVfsFile);
361 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
362 }
363 else
364 RTFileClose(hFile);
365 }
366 }
367 else
368 rc = VERR_ALREADY_EXISTS;
369 }
370 break;
371
372 case RTFS_TYPE_SYMLINK:
373 if (fObjFlags & RTVFSOBJ_F_OPEN_SYMLINK)
374 {
375 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
376 if (cRefs != UINT32_MAX)
377 {
378 RTVFSSYMLINK hVfsSymlink;
379 PRTVFSSTDSYMLINK pNewSymlink;
380 size_t cchSymlink = strlen(pszEntry);
381 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF_DYN(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
382 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsSymlink, (void **)&pNewSymlink);
383 if (RT_SUCCESS(rc))
384 {
385 memcpy(pNewSymlink->szSymlink, pszEntry, cchSymlink);
386 pNewSymlink->szSymlink[cchSymlink] = '\0';
387 pNewSymlink->pDir = pThis;
388
389 *phVfsObj = RTVfsObjFromSymlink(hVfsSymlink);
390 RTVfsSymlinkRelease(hVfsSymlink);
391 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
392 }
393 else
394 RTVfsDirRelease(pThis->hSelf);
395 }
396 else
397 rc = VERR_INTERNAL_ERROR_2;
398 }
399 else
400 rc = VERR_IS_A_SYMLINK;
401 break;
402
403 default:
404 break;
405 }
406 }
407 else if ( rc == VERR_FILE_NOT_FOUND
408 || rc == VERR_PATH_NOT_FOUND)
409 {
410 /*
411 * Consider file or directory creation.
412 */
413 if ( ( (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
414 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
415 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
416 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_NOTHING)
417 {
418
419 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_FILE)
420 {
421 RTFILE hFile;
422 rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fFileOpen, &hFile);
423 if (RT_SUCCESS(rc))
424 {
425 RTVFSFILE hVfsFile;
426 rc = RTVfsFileFromRTFile(hFile, fFileOpen, false /*fLeaveOpen*/, &hVfsFile);
427 if (RT_SUCCESS(rc))
428 {
429 *phVfsObj = RTVfsObjFromFile(hVfsFile);
430 RTVfsFileRelease(hVfsFile);
431 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
432 }
433 else
434 RTFileClose(hFile);
435 }
436 }
437 else if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_DIRECTORY)
438 {
439 RTDIR hSubDir;
440 rc = RTDirRelDirCreate(pThis->hDir, pszEntry, (fFileOpen & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT,
441 0 /* fFlags */, &hSubDir);
442 if (RT_SUCCESS(rc))
443 {
444 RTVFSDIR hVfsDir;
445 rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
446 if (RT_SUCCESS(rc))
447 {
448 *phVfsObj = RTVfsObjFromDir(hVfsDir);
449 RTVfsDirRelease(hVfsDir);
450 AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
451 }
452 else
453 RTDirClose(hSubDir);
454 }
455 }
456 else
457 rc = VERR_VFS_UNSUPPORTED_CREATE_TYPE;
458 }
459 else
460 rc = VERR_FILE_NOT_FOUND;
461 }
462 return rc;
463}
464
465
466/**
467 * @interface_method_impl{RTVFSDIROPS,pfnFollowAbsoluteSymlink}
468 */
469static DECLCALLBACK(int) rtVfsStdDir_FollowAbsoluteSymlink(void *pvThis, const char *pszRoot, PRTVFSDIR phVfsDir)
470{
471 //PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
472 RT_NOREF(pvThis);
473 /** @todo walking restriction. */
474 return RTVfsDirOpenNormal(pszRoot, 0 /*fFlags*/, phVfsDir);
475}
476
477
478/**
479 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
480 */
481static DECLCALLBACK(int) rtVfsStdDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
482{
483 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
484 RTFILE hFile;
485 int rc = RTDirRelFileOpen(pThis->hDir, pszFilename, fOpen, &hFile);
486 if (RT_SUCCESS(rc))
487 {
488 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
489 if (RT_FAILURE(rc))
490 RTFileClose(hFile);
491 }
492 return rc;
493}
494
495
496/**
497 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}
498 */
499static DECLCALLBACK(int) rtVfsStdDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
500{
501 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
502 /** @todo subdir open flags */
503 RTDIR hSubDir;
504 int rc = RTDirRelDirOpenFiltered(pThis->hDir, pszSubDir, RTDIRFILTER_NONE, fFlags, &hSubDir);
505 if (RT_SUCCESS(rc))
506 {
507 rc = rtVfsDirFromRTDir(hSubDir, fFlags, false, phVfsDir);
508 if (RT_FAILURE(rc))
509 RTDirClose(hSubDir);
510 }
511 return rc;
512}
513
514
515/**
516 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
517 */
518static DECLCALLBACK(int) rtVfsStdDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
519{
520 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
521 int rc;
522 if (!phVfsDir)
523 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, NULL);
524 else
525 {
526 RTDIR hSubDir;
527 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, &hSubDir);
528 if (RT_SUCCESS(rc))
529 {
530 /** @todo subdir open flags... */
531 rc = rtVfsDirFromRTDir(hSubDir, 0, false, phVfsDir);
532 if (RT_FAILURE(rc))
533 RTDirClose(hSubDir);
534 }
535 }
536
537 return rc;
538}
539
540
541/**
542 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
543 */
544static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
545{
546 RTFSOBJINFO ObjInfo;
547 int rc = rtVfsStdDir_QueryEntryInfo(pvThis, pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING);
548 if (RT_SUCCESS(rc))
549 {
550 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
551 {
552 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
553 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
554 if (cRefs != UINT32_MAX)
555 {
556 PRTVFSSTDSYMLINK pNewSymlink;
557 size_t cchSymlink = strlen(pszSymlink);
558 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF_DYN(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
559 NIL_RTVFS, NIL_RTVFSLOCK, phVfsSymlink, (void **)&pNewSymlink);
560 if (RT_SUCCESS(rc))
561 {
562 memcpy(pNewSymlink->szSymlink, pszSymlink, cchSymlink);
563 pNewSymlink->szSymlink[cchSymlink] = '\0';
564 pNewSymlink->pDir = pThis;
565 return VINF_SUCCESS;
566 }
567
568 RTVfsDirRelease(pThis->hSelf);
569 }
570 else
571 rc = VERR_INTERNAL_ERROR_2;
572 }
573 else
574 rc = VERR_NOT_SYMLINK;
575 }
576 return rc;
577}
578
579
580/**
581 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
582 */
583static DECLCALLBACK(int) rtVfsStdDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
584 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
585{
586 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
587 int rc = RTDirRelSymlinkCreate(pThis->hDir, pszSymlink, pszTarget, enmType, 0 /*fCreate*/);
588 if (RT_SUCCESS(rc))
589 {
590 if (!phVfsSymlink)
591 return VINF_SUCCESS;
592 return rtVfsStdDir_OpenSymlink(pThis, pszSymlink, phVfsSymlink);
593 }
594 return rc;
595}
596
597
598/**
599 * @interface_method_impl{RTVFSDIROPS,pfnQueryEntryInfo}
600 */
601static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
602 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
603{
604 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
605 return RTDirRelPathQueryInfo(pThis->hDir, pszEntry, pObjInfo, enmAddAttr, RTPATH_F_ON_LINK);
606}
607
608
609/**
610 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
611 */
612static DECLCALLBACK(int) rtVfsStdDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
613{
614 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
615 if (fType != 0)
616 {
617 if (fType == RTFS_TYPE_DIRECTORY)
618 return RTDirRelDirRemove(pThis->hDir, pszEntry);
619
620 RTFSOBJINFO ObjInfo;
621 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
622 if (RT_FAILURE(rc))
623 return rc;
624 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
625 return VERR_WRONG_TYPE;
626 }
627 return RTDirRelPathUnlink(pThis->hDir, pszEntry, 0 /*fUnlink*/);
628}
629
630
631/**
632 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
633 */
634static DECLCALLBACK(int) rtVfsStdDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
635{
636 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
637 if (fType != 0)
638 {
639 RTFSOBJINFO ObjInfo;
640 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
641 if (RT_FAILURE(rc))
642 return rc;
643 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
644 return VERR_WRONG_TYPE;
645 }
646
647 /** @todo RTVFSDIROPS::pfnRenameEntry doesn't really work, this must move to
648 * file system level. */
649 return RTDirRelPathRename(pThis->hDir, pszEntry, pThis->hDir, pszNewName,
650 RTPATHRENAME_FLAGS_NO_SYMLINKS | RTPATHRENAME_FLAGS_NO_REPLACE);
651}
652
653
654/**
655 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
656 */
657static DECLCALLBACK(int) rtVfsStdDir_RewindDir(void *pvThis)
658{
659 NOREF(pvThis);
660 return VERR_NOT_SUPPORTED;
661}
662
663
664/**
665 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
666 */
667static DECLCALLBACK(int) rtVfsStdDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
668{
669 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
670 return RTDirReadEx(pThis->hDir, pDirEntry, pcbDirEntry, enmAddAttr, RTPATH_F_ON_LINK);
671}
672
673
674/**
675 * Standard file operations.
676 */
677DECL_HIDDEN_CONST(const RTVFSDIROPS) g_rtVfsStdDirOps =
678{
679 { /* Obj */
680 RTVFSOBJOPS_VERSION,
681 RTVFSOBJTYPE_DIR,
682 "StdDir",
683 rtVfsStdDir_Close,
684 rtVfsStdDir_QueryInfo,
685 NULL,
686 RTVFSOBJOPS_VERSION
687 },
688 RTVFSDIROPS_VERSION,
689 0,
690 { /* ObjSet */
691 RTVFSOBJSETOPS_VERSION,
692 RT_UOFFSETOF(RTVFSDIROPS, ObjSet) - RT_UOFFSETOF(RTVFSDIROPS, Obj),
693 rtVfsStdDir_SetMode,
694 rtVfsStdDir_SetTimes,
695 rtVfsStdDir_SetOwner,
696 RTVFSOBJSETOPS_VERSION
697 },
698 rtVfsStdDir_Open,
699 rtVfsStdDir_FollowAbsoluteSymlink,
700 rtVfsStdDir_OpenFile,
701 rtVfsStdDir_OpenDir,
702 rtVfsStdDir_CreateDir,
703 rtVfsStdDir_OpenSymlink,
704 rtVfsStdDir_CreateSymlink,
705 rtVfsStdDir_QueryEntryInfo,
706 rtVfsStdDir_UnlinkEntry,
707 rtVfsStdDir_RenameEntry,
708 rtVfsStdDir_RewindDir,
709 rtVfsStdDir_ReadDir,
710 RTVFSDIROPS_VERSION
711};
712
713
714/**
715 * Internal worker for RTVfsDirFromRTDir and RTVfsDirOpenNormal.
716 *
717 * @returns IRPT status code.
718 * @param hDir The IPRT directory handle.
719 * @param fOpen Reserved for future.
720 * @param fLeaveOpen Whether to leave it open or close it.
721 * @param phVfsDir Where to return the handle.
722 */
723static int rtVfsDirFromRTDir(RTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir)
724{
725 PRTVFSSTDDIR pThis;
726 RTVFSDIR hVfsDir;
727 int rc = RTVfsNewDir(&g_rtVfsStdDirOps, sizeof(RTVFSSTDDIR), 0 /*fFlags*/, NIL_RTVFS, NIL_RTVFSLOCK,
728 &hVfsDir, (void **)&pThis);
729 if (RT_SUCCESS(rc))
730 {
731 pThis->hDir = hDir;
732 pThis->fLeaveOpen = fLeaveOpen;
733 pThis->fFlags = fFlags;
734 pThis->hSelf = hVfsDir;
735
736 *phVfsDir = hVfsDir;
737 return VINF_SUCCESS;
738 }
739 return rc;
740}
741
742
743RTDECL(int) RTVfsDirFromRTDir(RTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir)
744{
745 AssertReturn(RTDirIsValid(hDir), VERR_INVALID_HANDLE);
746 return rtVfsDirFromRTDir(hDir, hDir->fFlags, fLeaveOpen, phVfsDir);
747}
748
749
750RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
751{
752 /*
753 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
754 */
755 RTDIR hDir;
756 int rc = RTDirOpenFiltered(&hDir, pszPath, RTDIRFILTER_NONE, fFlags);
757 if (RT_SUCCESS(rc))
758 {
759 /*
760 * Create a VFS file handle.
761 */
762 rc = rtVfsDirFromRTDir(hDir, fFlags, false /*fLeaveOpen*/, phVfsDir);
763 if (RT_SUCCESS(rc))
764 return VINF_SUCCESS;
765
766 RTDirClose(hDir);
767 }
768 return rc;
769}
770
771
772RTDECL(bool) RTVfsDirIsStdDir(RTVFSDIR hVfsDir)
773{
774 return RTVfsDirToPrivate(hVfsDir, &g_rtVfsStdDirOps) != NULL;
775}
776
777
778/**
779 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
780 */
781static DECLCALLBACK(int) rtVfsChainStdDir_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
782 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
783{
784 RT_NOREF(pProviderReg, pSpec);
785
786 /*
787 * Basic checks.
788 */
789 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
790 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
791 if (pElement->enmType != RTVFSOBJTYPE_DIR)
792 return VERR_VFS_CHAIN_ONLY_DIR;
793 if (pElement->cArgs < 1)
794 return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
795
796 /*
797 * Parse flag arguments if any, storing them in the element.
798 */
799 uint32_t fFlags = 0;
800 for (uint32_t i = 1; i < pElement->cArgs; i++)
801 if (strcmp(pElement->paArgs[i].psz, "deny-ascent") == 0)
802 fFlags |= RTDIR_F_DENY_ASCENT;
803 else if (strcmp(pElement->paArgs[i].psz, "allow-ascent") == 0)
804 fFlags &= ~RTDIR_F_DENY_ASCENT;
805 else
806 {
807 *poffError = pElement->paArgs[i].offSpec;
808 return RTErrInfoSetF(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Unknown flag argument: %s", pElement->paArgs[i].psz);
809 }
810 pElement->uProvider = fFlags;
811
812 return VINF_SUCCESS;
813}
814
815
816/**
817 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
818 */
819static DECLCALLBACK(int) rtVfsChainStdDir_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
820 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
821 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
822{
823 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
824 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
825
826 RTVFSDIR hVfsDir;
827 int rc = RTVfsDirOpenNormal(pElement->paArgs[0].psz, (uint32_t)pElement->uProvider, &hVfsDir);
828 if (RT_SUCCESS(rc))
829 {
830 *phVfsObj = RTVfsObjFromDir(hVfsDir);
831 RTVfsDirRelease(hVfsDir);
832 if (*phVfsObj != NIL_RTVFSOBJ)
833 return VINF_SUCCESS;
834 rc = VERR_VFS_CHAIN_CAST_FAILED;
835 }
836 return rc;
837}
838
839
840/**
841 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
842 */
843static DECLCALLBACK(bool) rtVfsChainStdDir_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
844 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
845 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
846{
847 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
848 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
849 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
850 return true;
851 return false;
852}
853
854
855/** VFS chain element 'file'. */
856static RTVFSCHAINELEMENTREG g_rtVfsChainStdDirReg =
857{
858 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
859 /* fReserved = */ 0,
860 /* pszName = */ "stddir",
861 /* ListEntry = */ { NULL, NULL },
862 /* pszHelp = */ "Open a real directory. Initial element.\n"
863 "Takes zero or more flag arguments: deny-ascent, allow-ascent",
864 /* pfnValidate = */ rtVfsChainStdDir_Validate,
865 /* pfnInstantiate = */ rtVfsChainStdDir_Instantiate,
866 /* pfnCanReuseElement = */ rtVfsChainStdDir_CanReuseElement,
867 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
868};
869
870RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdDirReg, rtVfsChainStdDirReg);
871
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