VirtualBox

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

Last change on this file since 95307 was 94291, checked in by vboxsync, 3 years ago

IPRT,Storage: Adding RTVfsQueryLabel and internally a generic pfnQueryInfoEx method to the RTVFSOBJOPS function table. Untested implementation of the latter for iso/udf. bugref:9781

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