VirtualBox

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

Last change on this file was 107785, checked in by vboxsync, 4 weeks ago

Runtime/common/vfs/vfsstddir.cpp: Disable unused code, bugref:3409

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