VirtualBox

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

Last change on this file since 84509 was 84509, checked in by vboxsync, 5 years ago

iprt/cdefs.h,*: Introducing RT_FLEXIBLE_ARRAY_EXTENSION as a g++ hack that allows us to use RT_FLEXIBLE_ARRAY without the compiler going all pendantic on us. Only tested with 10.1.0. bugref:9746

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