VirtualBox

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

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

© 2023 Oracle
ContactPrivacy policyTerms of Use