VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsbase.cpp@ 69826

Last change on this file since 69826 was 69826, checked in by vboxsync, 8 years ago

IPRT/VFS: More path parsing work. Symlinks should work better now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 127.0 KB
Line 
1/* $Id: vfsbase.cpp 69826 2017-11-24 15:50:00Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Base.
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. 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_FS
32#include <iprt/vfs.h>
33#include <iprt/vfslowlevel.h>
34
35#include <iprt/asm.h>
36#include <iprt/err.h>
37#include <iprt/file.h>
38#include <iprt/log.h>
39#include <iprt/mem.h>
40#include <iprt/param.h>
41#include <iprt/path.h>
42#include <iprt/semaphore.h>
43#include <iprt/thread.h>
44#include <iprt/zero.h>
45
46#include "internal/file.h"
47#include "internal/fs.h"
48#include "internal/magics.h"
49#include "internal/path.h"
50//#include "internal/vfs.h"
51
52
53/*********************************************************************************************************************************
54* Defined Constants And Macros *
55*********************************************************************************************************************************/
56/** The instance data alignment. */
57#define RTVFS_INST_ALIGNMENT 16U
58
59/** The max number of symbolic links to resolve in a path. */
60#define RTVFS_MAX_LINKS 20U
61
62
63/** Asserts that the VFS base object vtable is valid. */
64#define RTVFSOBJ_ASSERT_OPS(a_pObjOps, a_enmType) \
65 do \
66 { \
67 Assert((a_pObjOps)->uVersion == RTVFSOBJOPS_VERSION); \
68 Assert((a_pObjOps)->enmType == (a_enmType) || (a_enmType) == RTVFSOBJTYPE_INVALID); \
69 AssertPtr((a_pObjOps)->pszName); \
70 Assert(*(a_pObjOps)->pszName); \
71 AssertPtr((a_pObjOps)->pfnClose); \
72 AssertPtr((a_pObjOps)->pfnQueryInfo); \
73 Assert((a_pObjOps)->uEndMarker == RTVFSOBJOPS_VERSION); \
74 } while (0)
75
76/** Asserts that the VFS set object vtable is valid. */
77#define RTVFSOBJSET_ASSERT_OPS(a_pSetOps, a_offObjOps) \
78 do \
79 { \
80 Assert((a_pSetOps)->uVersion == RTVFSOBJSETOPS_VERSION); \
81 Assert((a_pSetOps)->offObjOps == (a_offObjOps)); \
82 AssertPtr((a_pSetOps)->pfnSetMode); \
83 AssertPtr((a_pSetOps)->pfnSetTimes); \
84 AssertPtr((a_pSetOps)->pfnSetOwner); \
85 Assert((a_pSetOps)->uEndMarker == RTVFSOBJSETOPS_VERSION); \
86 } while (0)
87
88/** Asserts that the VFS directory vtable is valid. */
89#define RTVFSDIR_ASSERT_OPS(pDirOps, a_enmType) \
90 do { \
91 RTVFSOBJ_ASSERT_OPS(&(pDirOps)->Obj, a_enmType); \
92 RTVFSOBJSET_ASSERT_OPS(&(pDirOps)->ObjSet, RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet)); \
93 Assert((pDirOps)->uVersion == RTVFSDIROPS_VERSION); \
94 Assert(!(pDirOps)->fReserved); \
95 AssertPtr((pDirOps)->pfnOpen); \
96 AssertPtrNull((pDirOps)->pfnOpenFile); \
97 AssertPtrNull((pDirOps)->pfnOpenDir); \
98 AssertPtrNull((pDirOps)->pfnCreateDir); \
99 AssertPtrNull((pDirOps)->pfnOpenSymlink); \
100 AssertPtr((pDirOps)->pfnCreateSymlink); \
101 AssertPtr((pDirOps)->pfnUnlinkEntry); \
102 AssertPtr((pDirOps)->pfnRewindDir); \
103 AssertPtr((pDirOps)->pfnReadDir); \
104 Assert((pDirOps)->uEndMarker == RTVFSDIROPS_VERSION); \
105 } while (0)
106
107/** Asserts that the VFS I/O stream vtable is valid. */
108#define RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, a_enmType) \
109 do { \
110 RTVFSOBJ_ASSERT_OPS(&(pIoStreamOps)->Obj, a_enmType); \
111 Assert((pIoStreamOps)->uVersion == RTVFSIOSTREAMOPS_VERSION); \
112 Assert(!((pIoStreamOps)->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); \
113 AssertPtr((pIoStreamOps)->pfnRead); \
114 AssertPtr((pIoStreamOps)->pfnWrite); \
115 AssertPtr((pIoStreamOps)->pfnFlush); \
116 AssertPtr((pIoStreamOps)->pfnPollOne); \
117 AssertPtr((pIoStreamOps)->pfnTell); \
118 AssertPtrNull((pIoStreamOps)->pfnSkip); \
119 AssertPtrNull((pIoStreamOps)->pfnZeroFill); \
120 Assert((pIoStreamOps)->uEndMarker == RTVFSIOSTREAMOPS_VERSION); \
121 } while (0)
122
123/** Asserts that the VFS symlink vtable is valid. */
124#define RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, a_enmType) \
125 do { \
126 RTVFSOBJ_ASSERT_OPS(&(pSymlinkOps)->Obj, a_enmType); \
127 RTVFSOBJSET_ASSERT_OPS(&(pSymlinkOps)->ObjSet, \
128 RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet)); \
129 Assert((pSymlinkOps)->uVersion == RTVFSSYMLINKOPS_VERSION); \
130 Assert(!(pSymlinkOps)->fReserved); \
131 AssertPtr((pSymlinkOps)->pfnRead); \
132 Assert((pSymlinkOps)->uEndMarker == RTVFSSYMLINKOPS_VERSION); \
133 } while (0)
134
135
136/** Validates a VFS handle and returns @a rcRet if it's invalid. */
137#define RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, rcRet) \
138 do { \
139 if ((hVfs) != NIL_RTVFS) \
140 { \
141 AssertPtrReturn((hVfs), (rcRet)); \
142 AssertReturn((hVfs)->uMagic == RTVFS_MAGIC, (rcRet)); \
143 } \
144 } while (0)
145
146
147/*********************************************************************************************************************************
148* Structures and Typedefs *
149*********************************************************************************************************************************/
150/** @todo Move all this stuff to internal/vfs.h */
151
152
153/**
154 * The VFS internal lock data.
155 */
156typedef struct RTVFSLOCKINTERNAL
157{
158 /** The number of references to the this lock. */
159 uint32_t volatile cRefs;
160 /** The lock type. */
161 RTVFSLOCKTYPE enmType;
162 /** Type specific data. */
163 union
164 {
165 /** Read/Write semaphore handle. */
166 RTSEMRW hSemRW;
167 /** Fast mutex semaphore handle. */
168 RTSEMFASTMUTEX hFastMtx;
169 /** Regular mutex semaphore handle. */
170 RTSEMMUTEX hMtx;
171 } u;
172} RTVFSLOCKINTERNAL;
173
174
175/**
176 * The VFS base object handle data.
177 *
178 * All other VFS handles are derived from this one. The final handle type is
179 * indicated by RTVFSOBJOPS::enmType via the RTVFSOBJINTERNAL::pOps member.
180 */
181typedef struct RTVFSOBJINTERNAL
182{
183 /** The VFS magic (RTVFSOBJ_MAGIC). */
184 uint32_t uMagic : 31;
185 /** Set if we've got no VFS reference but still got a valid hVfs.
186 * This is hack for permanent root directory objects. */
187 uint32_t fNoVfsRef : 1;
188 /** The number of references to this VFS object. */
189 uint32_t volatile cRefs;
190 /** Pointer to the instance data. */
191 void *pvThis;
192 /** The vtable. */
193 PCRTVFSOBJOPS pOps;
194 /** The lock protecting all access to the VFS.
195 * Only valid if RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTVFSLOCK. */
196 RTVFSLOCK hLock;
197 /** Reference back to the VFS containing this object. */
198 RTVFS hVfs;
199} RTVFSOBJINTERNAL;
200
201
202/**
203 * The VFS filesystem stream handle data.
204 *
205 * @extends RTVFSOBJINTERNAL
206 */
207typedef struct RTVFSFSSTREAMINTERNAL
208{
209 /** The VFS magic (RTVFSFSTREAM_MAGIC). */
210 uint32_t uMagic;
211 /** File open flags, at a minimum the access mask. */
212 uint32_t fFlags;
213 /** The vtable. */
214 PCRTVFSFSSTREAMOPS pOps;
215 /** The base object handle data. */
216 RTVFSOBJINTERNAL Base;
217} RTVFSFSSTREAMINTERNAL;
218
219
220/**
221 * The VFS handle data.
222 *
223 * @extends RTVFSOBJINTERNAL
224 */
225typedef struct RTVFSINTERNAL
226{
227 /** The VFS magic (RTVFS_MAGIC). */
228 uint32_t uMagic;
229 /** Creation flags (RTVFS_C_XXX). */
230 uint32_t fFlags;
231 /** The vtable. */
232 PCRTVFSOPS pOps;
233 /** The base object handle data. */
234 RTVFSOBJINTERNAL Base;
235} RTVFSINTERNAL;
236
237
238/**
239 * The VFS directory handle data.
240 *
241 * @extends RTVFSOBJINTERNAL
242 */
243typedef struct RTVFSDIRINTERNAL
244{
245 /** The VFS magic (RTVFSDIR_MAGIC). */
246 uint32_t uMagic;
247 /** Reserved for flags or something. */
248 uint32_t fReserved;
249 /** The vtable. */
250 PCRTVFSDIROPS pOps;
251 /** The base object handle data. */
252 RTVFSOBJINTERNAL Base;
253} RTVFSDIRINTERNAL;
254
255
256/**
257 * The VFS symbolic link handle data.
258 *
259 * @extends RTVFSOBJINTERNAL
260 */
261typedef struct RTVFSSYMLINKINTERNAL
262{
263 /** The VFS magic (RTVFSSYMLINK_MAGIC). */
264 uint32_t uMagic;
265 /** Reserved for flags or something. */
266 uint32_t fReserved;
267 /** The vtable. */
268 PCRTVFSSYMLINKOPS pOps;
269 /** The base object handle data. */
270 RTVFSOBJINTERNAL Base;
271} RTVFSSYMLINKINTERNAL;
272
273
274/**
275 * The VFS I/O stream handle data.
276 *
277 * This is often part of a type specific handle, like a file or pipe.
278 *
279 * @extends RTVFSOBJINTERNAL
280 */
281typedef struct RTVFSIOSTREAMINTERNAL
282{
283 /** The VFS magic (RTVFSIOSTREAM_MAGIC). */
284 uint32_t uMagic;
285 /** File open flags, at a minimum the access mask. */
286 uint32_t fFlags;
287 /** The vtable. */
288 PCRTVFSIOSTREAMOPS pOps;
289 /** The base object handle data. */
290 RTVFSOBJINTERNAL Base;
291} RTVFSIOSTREAMINTERNAL;
292
293
294/**
295 * The VFS file handle data.
296 *
297 * @extends RTVFSIOSTREAMINTERNAL
298 */
299typedef struct RTVFSFILEINTERNAL
300{
301 /** The VFS magic (RTVFSFILE_MAGIC). */
302 uint32_t uMagic;
303 /** Reserved for flags or something. */
304 uint32_t fReserved;
305 /** The vtable. */
306 PCRTVFSFILEOPS pOps;
307 /** The stream handle data. */
308 RTVFSIOSTREAMINTERNAL Stream;
309} RTVFSFILEINTERNAL;
310
311#if 0 /* later */
312
313/**
314 * The VFS pipe handle data.
315 *
316 * @extends RTVFSIOSTREAMINTERNAL
317 */
318typedef struct RTVFSPIPEINTERNAL
319{
320 /** The VFS magic (RTVFSPIPE_MAGIC). */
321 uint32_t uMagic;
322 /** Reserved for flags or something. */
323 uint32_t fReserved;
324 /** The vtable. */
325 PCRTVFSPIPEOPS pOps;
326 /** The stream handle data. */
327 RTVFSIOSTREAMINTERNAL Stream;
328} RTVFSPIPEINTERNAL;
329
330
331/**
332 * The VFS socket handle data.
333 *
334 * @extends RTVFSIOSTREAMINTERNAL
335 */
336typedef struct RTVFSSOCKETINTERNAL
337{
338 /** The VFS magic (RTVFSSOCKET_MAGIC). */
339 uint32_t uMagic;
340 /** Reserved for flags or something. */
341 uint32_t fReserved;
342 /** The vtable. */
343 PCRTVFSSOCKETOPS pOps;
344 /** The stream handle data. */
345 RTVFSIOSTREAMINTERNAL Stream;
346} RTVFSSOCKETINTERNAL;
347
348#endif /* later */
349
350
351/*********************************************************************************************************************************
352* Internal Functions *
353*********************************************************************************************************************************/
354DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis);
355static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir);
356static int rtVfsDirFollowSymlinkObjToParent(RTVFSDIRINTERNAL **ppVfsParentDir, RTVFSOBJ hVfsObj,
357 PRTVFSPARSEDPATH pPath, uint32_t fFlags);
358
359
360
361/*
362 *
363 * V F S L o c k A b s t r a c t i o n
364 * V F S L o c k A b s t r a c t i o n
365 * V F S L o c k A b s t r a c t i o n
366 *
367 *
368 */
369
370
371RTDECL(uint32_t) RTVfsLockRetain(RTVFSLOCK hLock)
372{
373 RTVFSLOCKINTERNAL *pThis = hLock;
374 AssertPtrReturn(pThis, UINT32_MAX);
375 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
376
377 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
378 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
379 return cRefs;
380}
381
382
383RTDECL(uint32_t) RTVfsLockRetainDebug(RTVFSLOCK hLock, RT_SRC_POS_DECL)
384{
385 RTVFSLOCKINTERNAL *pThis = hLock;
386 AssertPtrReturn(pThis, UINT32_MAX);
387 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
388
389 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
390 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
391 LogFlow(("RTVfsLockRetainDebug(%p) -> %d; caller: %s %s(%u)\n", hLock, cRefs, pszFunction, pszFile, iLine));
392 RT_SRC_POS_NOREF();
393 return cRefs;
394}
395
396
397/**
398 * Destroys a VFS lock handle.
399 *
400 * @param pThis The lock to destroy.
401 */
402static void rtVfsLockDestroy(RTVFSLOCKINTERNAL *pThis)
403{
404 switch (pThis->enmType)
405 {
406 case RTVFSLOCKTYPE_RW:
407 RTSemRWDestroy(pThis->u.hSemRW);
408 pThis->u.hSemRW = NIL_RTSEMRW;
409 break;
410
411 case RTVFSLOCKTYPE_FASTMUTEX:
412 RTSemFastMutexDestroy(pThis->u.hFastMtx);
413 pThis->u.hFastMtx = NIL_RTSEMFASTMUTEX;
414 break;
415
416 case RTVFSLOCKTYPE_MUTEX:
417 RTSemMutexDestroy(pThis->u.hMtx);
418 pThis->u.hFastMtx = NIL_RTSEMMUTEX;
419 break;
420
421 default:
422 AssertMsgFailedReturnVoid(("%p %d\n", pThis, pThis->enmType));
423 }
424
425 pThis->enmType = RTVFSLOCKTYPE_INVALID;
426 RTMemFree(pThis);
427}
428
429
430RTDECL(uint32_t) RTVfsLockRelease(RTVFSLOCK hLock)
431{
432 RTVFSLOCKINTERNAL *pThis = hLock;
433 if (pThis == NIL_RTVFSLOCK)
434 return 0;
435 AssertPtrReturn(pThis, UINT32_MAX);
436 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
437
438 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
439 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
440 if (cRefs == 0)
441 rtVfsLockDestroy(pThis);
442 return cRefs;
443}
444
445
446/**
447 * Creates a read/write lock.
448 *
449 * @returns IPRT status code
450 * @param phLock Where to return the lock handle.
451 */
452static int rtVfsLockCreateRW(PRTVFSLOCK phLock)
453{
454 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
455 if (!pThis)
456 return VERR_NO_MEMORY;
457
458 pThis->cRefs = 1;
459 pThis->enmType = RTVFSLOCKTYPE_RW;
460
461 int rc = RTSemRWCreate(&pThis->u.hSemRW);
462 if (RT_FAILURE(rc))
463 {
464 RTMemFree(pThis);
465 return rc;
466 }
467
468 *phLock = pThis;
469 return VINF_SUCCESS;
470}
471
472
473/**
474 * Creates a fast mutex lock.
475 *
476 * @returns IPRT status code
477 * @param phLock Where to return the lock handle.
478 */
479static int rtVfsLockCreateFastMutex(PRTVFSLOCK phLock)
480{
481 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
482 if (!pThis)
483 return VERR_NO_MEMORY;
484
485 pThis->cRefs = 1;
486 pThis->enmType = RTVFSLOCKTYPE_FASTMUTEX;
487
488 int rc = RTSemFastMutexCreate(&pThis->u.hFastMtx);
489 if (RT_FAILURE(rc))
490 {
491 RTMemFree(pThis);
492 return rc;
493 }
494
495 *phLock = pThis;
496 return VINF_SUCCESS;
497
498}
499
500
501/**
502 * Creates a mutex lock.
503 *
504 * @returns IPRT status code
505 * @param phLock Where to return the lock handle.
506 */
507static int rtVfsLockCreateMutex(PRTVFSLOCK phLock)
508{
509 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
510 if (!pThis)
511 return VERR_NO_MEMORY;
512
513 pThis->cRefs = 1;
514 pThis->enmType = RTVFSLOCKTYPE_MUTEX;
515
516 int rc = RTSemMutexCreate(&pThis->u.hMtx);
517 if (RT_FAILURE(rc))
518 {
519 RTMemFree(pThis);
520 return rc;
521 }
522
523 *phLock = pThis;
524 return VINF_SUCCESS;
525}
526
527
528/**
529 * Acquires the lock for reading.
530 *
531 * @param hLock Non-nil lock handle.
532 * @internal
533 */
534RTDECL(void) RTVfsLockAcquireReadSlow(RTVFSLOCK hLock)
535{
536 RTVFSLOCKINTERNAL *pThis = hLock;
537 int rc;
538
539 AssertPtr(pThis);
540 switch (pThis->enmType)
541 {
542 case RTVFSLOCKTYPE_RW:
543 rc = RTSemRWRequestRead(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
544 AssertRC(rc);
545 break;
546
547 case RTVFSLOCKTYPE_FASTMUTEX:
548 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
549 AssertRC(rc);
550 break;
551
552 case RTVFSLOCKTYPE_MUTEX:
553 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
554 AssertRC(rc);
555 break;
556 default:
557 AssertFailed();
558 }
559}
560
561
562/**
563 * Release a lock held for reading.
564 *
565 * @param hLock Non-nil lock handle.
566 * @internal
567 */
568RTDECL(void) RTVfsLockReleaseReadSlow(RTVFSLOCK hLock)
569{
570 RTVFSLOCKINTERNAL *pThis = hLock;
571 int rc;
572
573 AssertPtr(pThis);
574 switch (pThis->enmType)
575 {
576 case RTVFSLOCKTYPE_RW:
577 rc = RTSemRWReleaseRead(pThis->u.hSemRW);
578 AssertRC(rc);
579 break;
580
581 case RTVFSLOCKTYPE_FASTMUTEX:
582 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
583 AssertRC(rc);
584 break;
585
586 case RTVFSLOCKTYPE_MUTEX:
587 rc = RTSemMutexRelease(pThis->u.hMtx);
588 AssertRC(rc);
589 break;
590 default:
591 AssertFailed();
592 }
593}
594
595
596/**
597 * Acquires the lock for writing.
598 *
599 * @param hLock Non-nil lock handle.
600 * @internal
601 */
602RTDECL(void) RTVfsLockAcquireWriteSlow(RTVFSLOCK hLock)
603{
604 RTVFSLOCKINTERNAL *pThis = hLock;
605 int rc;
606
607 AssertPtr(pThis);
608 switch (pThis->enmType)
609 {
610 case RTVFSLOCKTYPE_RW:
611 rc = RTSemRWRequestWrite(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
612 AssertRC(rc);
613 break;
614
615 case RTVFSLOCKTYPE_FASTMUTEX:
616 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
617 AssertRC(rc);
618 break;
619
620 case RTVFSLOCKTYPE_MUTEX:
621 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
622 AssertRC(rc);
623 break;
624 default:
625 AssertFailed();
626 }
627}
628
629
630/**
631 * Release a lock held for writing.
632 *
633 * @param hLock Non-nil lock handle.
634 * @internal
635 */
636RTDECL(void) RTVfsLockReleaseWriteSlow(RTVFSLOCK hLock)
637{
638 RTVFSLOCKINTERNAL *pThis = hLock;
639 int rc;
640
641 AssertPtr(pThis);
642 switch (pThis->enmType)
643 {
644 case RTVFSLOCKTYPE_RW:
645 rc = RTSemRWReleaseWrite(pThis->u.hSemRW);
646 AssertRC(rc);
647 break;
648
649 case RTVFSLOCKTYPE_FASTMUTEX:
650 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
651 AssertRC(rc);
652 break;
653
654 case RTVFSLOCKTYPE_MUTEX:
655 rc = RTSemMutexRelease(pThis->u.hMtx);
656 AssertRC(rc);
657 break;
658 default:
659 AssertFailed();
660 }
661}
662
663
664
665/*
666 *
667 * B A S E O B J E C T
668 * B A S E O B J E C T
669 * B A S E O B J E C T
670 *
671 */
672
673/**
674 * Internal object retainer that asserts sanity in strict builds.
675 *
676 * @param pThis The base object handle data.
677 * @param pszCaller Where we're called from.
678 */
679DECLINLINE(void) rtVfsObjRetainVoid(RTVFSOBJINTERNAL *pThis, const char *pszCaller)
680{
681 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
682LogFlow(("rtVfsObjRetainVoid(%p/%p) -> %d; caller=%s\n", pThis, pThis->pvThis, cRefs, pszCaller)); RT_NOREF(pszCaller);
683 AssertMsg(cRefs > 1 && cRefs < _1M,
684 ("%#x %p ops=%p %s (%d); caller=%s\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType, pszCaller));
685 NOREF(cRefs);
686}
687
688
689/**
690 * Initializes the base object part of a new object.
691 *
692 * @returns IPRT status code.
693 * @param pThis Pointer to the base object part.
694 * @param pObjOps The base object vtable.
695 * @param hVfs The VFS handle to associate with.
696 * @param fNoVfsRef If set, do not retain an additional reference to
697 * @a hVfs. Permanent root dir hack.
698 * @param hLock The lock handle, pseudo handle or nil.
699 * @param pvThis Pointer to the private data.
700 */
701static int rtVfsObjInitNewObject(RTVFSOBJINTERNAL *pThis, PCRTVFSOBJOPS pObjOps, RTVFS hVfs, bool fNoVfsRef,
702 RTVFSLOCK hLock, void *pvThis)
703{
704 /*
705 * Deal with the lock first as that's the most complicated matter.
706 */
707 if (hLock != NIL_RTVFSLOCK)
708 {
709 int rc;
710 if (hLock == RTVFSLOCK_CREATE_RW)
711 {
712 rc = rtVfsLockCreateRW(&hLock);
713 AssertRCReturn(rc, rc);
714 }
715 else if (hLock == RTVFSLOCK_CREATE_FASTMUTEX)
716 {
717 rc = rtVfsLockCreateFastMutex(&hLock);
718 AssertRCReturn(rc, rc);
719 }
720 else if (hLock == RTVFSLOCK_CREATE_MUTEX)
721 {
722 rc = rtVfsLockCreateMutex(&hLock);
723 AssertRCReturn(rc, rc);
724 }
725 else
726 {
727 /*
728 * The caller specified a lock, we consume the this reference.
729 */
730 AssertPtrReturn(hLock, VERR_INVALID_HANDLE);
731 AssertReturn(hLock->enmType > RTVFSLOCKTYPE_INVALID && hLock->enmType < RTVFSLOCKTYPE_END, VERR_INVALID_HANDLE);
732 AssertReturn(hLock->cRefs > 0, VERR_INVALID_HANDLE);
733 }
734 }
735 else if (hVfs != NIL_RTVFS)
736 {
737 /*
738 * Retain a reference to the VFS lock, if there is one.
739 */
740 hLock = hVfs->Base.hLock;
741 if (hLock != NIL_RTVFSLOCK)
742 {
743 uint32_t cRefs = RTVfsLockRetain(hLock);
744 if (RT_UNLIKELY(cRefs == UINT32_MAX))
745 return VERR_INVALID_HANDLE;
746 }
747 }
748
749
750 /*
751 * Do the actual initializing.
752 */
753 pThis->uMagic = RTVFSOBJ_MAGIC;
754 pThis->fNoVfsRef = fNoVfsRef;
755 pThis->pvThis = pvThis;
756 pThis->pOps = pObjOps;
757 pThis->cRefs = 1;
758 pThis->hVfs = hVfs;
759 pThis->hLock = hLock;
760 if (hVfs != NIL_RTVFS && !fNoVfsRef)
761 rtVfsObjRetainVoid(&hVfs->Base, "rtVfsObjInitNewObject");
762
763 return VINF_SUCCESS;
764}
765
766
767RTDECL(int) RTVfsNewBaseObj(PCRTVFSOBJOPS pObjOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
768 PRTVFSOBJ phVfsObj, void **ppvInstance)
769{
770 /*
771 * Validate the input, be extra strict in strict builds.
772 */
773 AssertPtr(pObjOps);
774 AssertReturn(pObjOps->uVersion == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
775 AssertReturn(pObjOps->uEndMarker == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
776 RTVFSOBJ_ASSERT_OPS(pObjOps, RTVFSOBJTYPE_BASE);
777 Assert(cbInstance > 0);
778 AssertPtr(ppvInstance);
779 AssertPtr(phVfsObj);
780 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
781
782 /*
783 * Allocate the handle + instance data.
784 */
785 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSOBJINTERNAL), RTVFS_INST_ALIGNMENT)
786 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
787 RTVFSOBJINTERNAL *pThis = (RTVFSOBJINTERNAL *)RTMemAllocZ(cbThis);
788 if (!pThis)
789 return VERR_NO_MEMORY;
790
791 int rc = rtVfsObjInitNewObject(pThis, pObjOps, hVfs, false /*fNoVfsRef*/, hLock,
792 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
793 if (RT_FAILURE(rc))
794 {
795 RTMemFree(pThis);
796 return rc;
797 }
798
799 *phVfsObj = pThis;
800 *ppvInstance = pThis->pvThis;
801 return VINF_SUCCESS;
802}
803
804
805/**
806 * Internal object retainer that asserts sanity in strict builds.
807 *
808 * @returns The new reference count.
809 * @param pThis The base object handle data.
810 */
811DECLINLINE(uint32_t) rtVfsObjRetain(RTVFSOBJINTERNAL *pThis)
812{
813 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
814LogFlow(("rtVfsObjRetain(%p/%p) -> %d\n", pThis, pThis->pvThis, cRefs));
815 AssertMsg(cRefs > 1 && cRefs < _1M,
816 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
817 return cRefs;
818}
819
820/**
821 * Internal object retainer that asserts sanity in strict builds.
822 *
823 * @returns The new reference count.
824 * @param pThis The base object handle data.
825 */
826DECLINLINE(uint32_t) rtVfsObjRetainDebug(RTVFSOBJINTERNAL *pThis, const char *pszApi, RT_SRC_POS_DECL)
827{
828 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
829 AssertMsg(cRefs > 1 && cRefs < _1M,
830 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
831 LogFlow(("%s(%p/%p) -> %2d; caller: %s %s(%d) \n", pszApi, pThis, pThis->pvThis, cRefs, pszFunction, pszFile, iLine));
832 RT_SRC_POS_NOREF(); RT_NOREF(pszApi);
833 return cRefs;
834}
835
836
837#ifdef DEBUG
838# undef RTVfsObjRetain
839#endif
840RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj)
841{
842 RTVFSOBJINTERNAL *pThis = hVfsObj;
843 AssertPtrReturn(pThis, UINT32_MAX);
844 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
845
846 return rtVfsObjRetain(pThis);
847}
848#ifdef DEBUG
849# define RTVfsObjRetain(hVfsObj) RTVfsObjRetainDebug(hVfsObj, RT_SRC_POS)
850#endif
851
852
853RTDECL(uint32_t) RTVfsObjRetainDebug(RTVFSOBJ hVfsObj, RT_SRC_POS_DECL)
854{
855 RTVFSOBJINTERNAL *pThis = hVfsObj;
856 AssertPtrReturn(pThis, UINT32_MAX);
857 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
858
859 return rtVfsObjRetainDebug(pThis, "RTVfsObjRetainDebug", RT_SRC_POS_ARGS);
860}
861
862
863/**
864 * Does the actual object destruction for rtVfsObjRelease().
865 *
866 * @param pThis The object to destroy.
867 */
868static void rtVfsObjDestroy(RTVFSOBJINTERNAL *pThis)
869{
870 RTVFSOBJTYPE const enmType = pThis->pOps->enmType;
871
872 /*
873 * Invalidate the object.
874 */
875 RTVfsLockAcquireWrite(pThis->hLock); /* paranoia */
876 void *pvToFree = NULL;
877 switch (enmType)
878 {
879 case RTVFSOBJTYPE_BASE:
880 pvToFree = pThis;
881 break;
882
883 case RTVFSOBJTYPE_VFS:
884 pvToFree = RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
885 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)->uMagic, RTVFS_MAGIC_DEAD);
886 break;
887
888 case RTVFSOBJTYPE_FS_STREAM:
889 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
890 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base)->uMagic, RTVFSFSSTREAM_MAGIC_DEAD);
891 break;
892
893 case RTVFSOBJTYPE_IO_STREAM:
894 pvToFree = RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
895 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
896 break;
897
898 case RTVFSOBJTYPE_DIR:
899 pvToFree = RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
900 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->uMagic, RTVFSDIR_MAGIC_DEAD);
901 break;
902
903 case RTVFSOBJTYPE_FILE:
904 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
905 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->uMagic, RTVFSFILE_MAGIC_DEAD);
906 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
907 break;
908
909 case RTVFSOBJTYPE_SYMLINK:
910 pvToFree = RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
911 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
912 break;
913
914 case RTVFSOBJTYPE_INVALID:
915 case RTVFSOBJTYPE_END:
916 case RTVFSOBJTYPE_32BIT_HACK:
917 AssertMsgFailed(("enmType=%d ops=%p %s\n", enmType, pThis->pOps, pThis->pOps->pszName));
918 break;
919 /* no default as we want gcc warnings. */
920 }
921 pThis->uMagic = RTVFSOBJ_MAGIC_DEAD;
922 RTVfsLockReleaseWrite(pThis->hLock);
923
924 /*
925 * Close the object and free the handle.
926 */
927 int rc = pThis->pOps->pfnClose(pThis->pvThis);
928 AssertRC(rc);
929 if (pThis->hVfs != NIL_RTVFS)
930 {
931 if (!pThis->fNoVfsRef)
932 rtVfsObjRelease(&pThis->hVfs->Base);
933 pThis->hVfs = NIL_RTVFS;
934 }
935 if (pThis->hLock != NIL_RTVFSLOCK)
936 {
937 RTVfsLockRelease(pThis->hLock);
938 pThis->hLock = NIL_RTVFSLOCK;
939 }
940 RTMemFree(pvToFree);
941}
942
943
944/**
945 * Internal object releaser that asserts sanity in strict builds.
946 *
947 * @returns The new reference count.
948 * @param pcRefs The reference counter.
949 */
950DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis)
951{
952 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
953 AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
954 LogFlow(("rtVfsObjRelease(%p/%p) -> %d\n", pThis, pThis->pvThis, cRefs));
955 if (cRefs == 0)
956 rtVfsObjDestroy(pThis);
957 return cRefs;
958}
959
960
961RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj)
962{
963 RTVFSOBJINTERNAL *pThis = hVfsObj;
964 if (pThis == NIL_RTVFSOBJ)
965 return 0;
966 AssertPtrReturn(pThis, UINT32_MAX);
967 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
968 return rtVfsObjRelease(pThis);
969}
970
971
972RTDECL(RTVFSOBJTYPE) RTVfsObjGetType(RTVFSOBJ hVfsObj)
973{
974 RTVFSOBJINTERNAL *pThis = hVfsObj;
975 if (pThis != NIL_RTVFSOBJ)
976 {
977 AssertPtrReturn(pThis, RTVFSOBJTYPE_INVALID);
978 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, RTVFSOBJTYPE_INVALID);
979 return pThis->pOps->enmType;
980 }
981 return RTVFSOBJTYPE_INVALID;
982}
983
984
985RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj)
986{
987 RTVFSOBJINTERNAL *pThis = hVfsObj;
988 if (pThis != NIL_RTVFSOBJ)
989 {
990 AssertPtrReturn(pThis, NIL_RTVFS);
991 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFS);
992
993 if (pThis->pOps->enmType == RTVFSOBJTYPE_VFS)
994 {
995 rtVfsObjRetainVoid(pThis, "RTVfsObjToVfs");
996 LogFlow(("RTVfsObjToVfs(%p) -> %p\n", pThis, RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)));
997 return RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
998 }
999 }
1000 return NIL_RTVFS;
1001}
1002
1003
1004RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj)
1005{
1006 RTVFSOBJINTERNAL *pThis = hVfsObj;
1007 if (pThis != NIL_RTVFSOBJ)
1008 {
1009 AssertPtrReturn(pThis, NIL_RTVFSFSSTREAM);
1010 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFSSTREAM);
1011
1012 if (pThis->pOps->enmType == RTVFSOBJTYPE_FS_STREAM)
1013 {
1014 rtVfsObjRetainVoid(pThis, "RTVfsObjToFsStream");
1015 return RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
1016 }
1017 }
1018 return NIL_RTVFSFSSTREAM;
1019}
1020
1021
1022RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj)
1023{
1024 RTVFSOBJINTERNAL *pThis = hVfsObj;
1025 if (pThis != NIL_RTVFSOBJ)
1026 {
1027 AssertPtrReturn(pThis, NIL_RTVFSDIR);
1028 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSDIR);
1029
1030 if (pThis->pOps->enmType == RTVFSOBJTYPE_DIR)
1031 {
1032 rtVfsObjRetainVoid(pThis, "RTVfsObjToDir");
1033 return RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
1034 }
1035 }
1036 return NIL_RTVFSDIR;
1037}
1038
1039
1040RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj)
1041{
1042 RTVFSOBJINTERNAL *pThis = hVfsObj;
1043 if (pThis != NIL_RTVFSOBJ)
1044 {
1045 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
1046 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSIOSTREAM);
1047
1048 if ( pThis->pOps->enmType == RTVFSOBJTYPE_IO_STREAM
1049 || pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1050 {
1051 rtVfsObjRetainVoid(pThis, "RTVfsObjToIoStream");
1052 return RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
1053 }
1054 }
1055 return NIL_RTVFSIOSTREAM;
1056}
1057
1058
1059RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj)
1060{
1061 RTVFSOBJINTERNAL *pThis = hVfsObj;
1062 if (pThis != NIL_RTVFSOBJ)
1063 {
1064 AssertPtrReturn(pThis, NIL_RTVFSFILE);
1065 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFILE);
1066
1067 if (pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1068 {
1069 rtVfsObjRetainVoid(pThis, "RTVfsObjToFile");
1070 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
1071 }
1072 }
1073 return NIL_RTVFSFILE;
1074}
1075
1076
1077RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj)
1078{
1079 RTVFSOBJINTERNAL *pThis = hVfsObj;
1080 if (pThis != NIL_RTVFSOBJ)
1081 {
1082 AssertPtrReturn(pThis, NIL_RTVFSSYMLINK);
1083 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSSYMLINK);
1084
1085 if (pThis->pOps->enmType == RTVFSOBJTYPE_SYMLINK)
1086 {
1087 rtVfsObjRetainVoid(pThis, "RTVfsObjToSymlink");
1088 return RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
1089 }
1090 }
1091 return NIL_RTVFSSYMLINK;
1092}
1093
1094
1095RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs)
1096{
1097 if (hVfs != NIL_RTVFS)
1098 {
1099 RTVFSOBJINTERNAL *pThis = &hVfs->Base;
1100 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1101 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1102
1103 rtVfsObjRetainVoid(pThis, "RTVfsObjFromVfs");
1104 LogFlow(("RTVfsObjFromVfs(%p) -> %p\n", hVfs, pThis));
1105 return pThis;
1106 }
1107 return NIL_RTVFSOBJ;
1108}
1109
1110
1111RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss)
1112{
1113 if (hVfsFss != NIL_RTVFSFSSTREAM)
1114 {
1115 RTVFSOBJINTERNAL *pThis = &hVfsFss->Base;
1116 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1117 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1118
1119 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFsStream");
1120 return pThis;
1121 }
1122 return NIL_RTVFSOBJ;
1123}
1124
1125
1126RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir)
1127{
1128 if (hVfsDir != NIL_RTVFSDIR)
1129 {
1130 RTVFSOBJINTERNAL *pThis = &hVfsDir->Base;
1131 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1132 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1133
1134 rtVfsObjRetainVoid(pThis, "RTVfsObjFromDir");
1135 return pThis;
1136 }
1137 return NIL_RTVFSOBJ;
1138}
1139
1140
1141RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos)
1142{
1143 if (hVfsIos != NIL_RTVFSIOSTREAM)
1144 {
1145 RTVFSOBJINTERNAL *pThis = &hVfsIos->Base;
1146 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1147 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1148
1149 rtVfsObjRetainVoid(pThis, "RTVfsObjFromIoStream");
1150 return pThis;
1151 }
1152 return NIL_RTVFSOBJ;
1153}
1154
1155
1156RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile)
1157{
1158 if (hVfsFile != NIL_RTVFSFILE)
1159 {
1160 RTVFSOBJINTERNAL *pThis = &hVfsFile->Stream.Base;
1161 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1162 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1163
1164 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFile");
1165 return pThis;
1166 }
1167 return NIL_RTVFSOBJ;
1168}
1169
1170
1171RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym)
1172{
1173 if (hVfsSym != NIL_RTVFSSYMLINK)
1174 {
1175 RTVFSOBJINTERNAL *pThis = &hVfsSym->Base;
1176 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1177 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1178
1179 rtVfsObjRetainVoid(pThis, "RTVfsObjFromSymlink");
1180 return pThis;
1181 }
1182 return NIL_RTVFSOBJ;
1183}
1184
1185
1186RTDECL(int) RTVfsObjOpen(RTVFS hVfs, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
1187{
1188 /*
1189 * Validate input.
1190 */
1191 RTVFSINTERNAL *pThis = hVfs;
1192 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1193 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1194 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1195 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
1196
1197 int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
1198 if (RT_FAILURE(rc))
1199 return rc;
1200 AssertMsgReturn( RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
1201 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
1202 ("fObjFlags=%#x\n", fObjFlags),
1203 VERR_INVALID_FLAGS);
1204 /*
1205 * Parse the path, assume current directory is root since we've got no
1206 * caller context here.
1207 */
1208 PRTVFSPARSEDPATH pPath;
1209 rc = RTVfsParsePathA(pszPath, "/", &pPath);
1210 if (RT_SUCCESS(rc))
1211 {
1212 /*
1213 * Tranverse the path, resolving the parent node.
1214 * We'll do the symbolic link checking here with help of pfnOpen.
1215 */
1216 RTVFSDIRINTERNAL *pVfsParentDir;
1217 rc = rtVfsTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
1218 if (RT_SUCCESS(rc))
1219 {
1220
1221 /*
1222 * Do the opening. Loop if we need to follow symbolic links.
1223 */
1224 for (uint32_t cLoops = 1; ; cLoops++)
1225 {
1226 /* If we end with a directory slash, adjust open flags. */
1227 if (pPath->fDirSlash)
1228 {
1229 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
1230 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
1231 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
1232 }
1233
1234 /* Open it. */
1235 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
1236 RTVFSOBJ hVfsObj;
1237 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
1238 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
1239 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
1240 if (RT_FAILURE(rc))
1241 break;
1242
1243 /* We're done if we don't follow links or this wasn't a link. */
1244 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
1245 || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
1246 {
1247 *phVfsObj = hVfsObj;
1248 break;
1249 }
1250
1251 /* Follow symbolic link. */
1252 if (cLoops < RTVFS_MAX_LINKS)
1253 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
1254 else
1255 rc = VERR_TOO_MANY_SYMLINKS;
1256 RTVfsObjRelease(hVfsObj);
1257 if (RT_FAILURE(rc))
1258 break;
1259 }
1260 }
1261 RTVfsParsePathFree(pPath);
1262 }
1263 return rc;
1264}
1265
1266
1267RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1268{
1269 RTVFSOBJINTERNAL *pThis = hVfsObj;
1270 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1271 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1272
1273 RTVfsLockAcquireRead(pThis->hLock);
1274 int rc = pThis->pOps->pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
1275 RTVfsLockReleaseRead(pThis->hLock);
1276 return rc;
1277}
1278
1279
1280/**
1281 * Gets the RTVFSOBJSETOPS for the given base object.
1282 *
1283 * @returns Pointer to the vtable if supported by the type, otherwise NULL.
1284 * @param pThis The base object.
1285 */
1286static PCRTVFSOBJSETOPS rtVfsObjGetSetOps(RTVFSOBJINTERNAL *pThis)
1287{
1288 switch (pThis->pOps->enmType)
1289 {
1290 case RTVFSOBJTYPE_DIR:
1291 return &RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->pOps->ObjSet;
1292 case RTVFSOBJTYPE_FILE:
1293 return &RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->pOps->ObjSet;
1294 case RTVFSOBJTYPE_SYMLINK:
1295 return &RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->pOps->ObjSet;
1296 default:
1297 return NULL;
1298 }
1299}
1300
1301
1302RTDECL(int) RTVfsObjSetMode(RTVFSOBJ hVfsObj, RTFMODE fMode, RTFMODE fMask)
1303{
1304 RTVFSOBJINTERNAL *pThis = hVfsObj;
1305 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1306 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1307
1308 fMode = rtFsModeNormalize(fMode, NULL, 0);
1309 if (!rtFsModeIsValid(fMode))
1310 return VERR_INVALID_PARAMETER;
1311
1312 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1313 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1314
1315 RTVfsLockAcquireWrite(pThis->hLock);
1316 int rc = pObjSetOps->pfnSetMode(pThis->pvThis, fMode, fMask);
1317 RTVfsLockReleaseWrite(pThis->hLock);
1318 return rc;
1319}
1320
1321
1322RTDECL(int) RTVfsObjSetTimes(RTVFSOBJ hVfsObj, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1323 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1324{
1325 RTVFSOBJINTERNAL *pThis = hVfsObj;
1326 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1327 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1328
1329 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
1330 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
1331 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
1332 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
1333
1334 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1335 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1336
1337 RTVfsLockAcquireWrite(pThis->hLock);
1338 int rc = pObjSetOps->pfnSetTimes(pThis->pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1339 RTVfsLockReleaseWrite(pThis->hLock);
1340 return rc;
1341}
1342
1343
1344RTDECL(int) RTVfsObjSetOwner(RTVFSOBJ hVfsObj, RTUID uid, RTGID gid)
1345{
1346 RTVFSOBJINTERNAL *pThis = hVfsObj;
1347 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1348 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1349
1350 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1351 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1352
1353 RTVfsLockAcquireWrite(pThis->hLock);
1354 int rc = pObjSetOps->pfnSetOwner(pThis->pvThis, uid, gid);
1355 RTVfsLockReleaseWrite(pThis->hLock);
1356 return rc;
1357}
1358
1359
1360/*
1361 *
1362 * U T I L U T I L U T I L
1363 * U T I L U T I L U T I L
1364 * U T I L U T I L U T I L
1365 *
1366 */
1367
1368
1369RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
1370{
1371 AssertReturn(*pszPath != '/' && *pszPath != '\\', VERR_INTERNAL_ERROR_4);
1372
1373 /* In case *piRestartComp was set higher than the number of components
1374 before making the call to this function. */
1375 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1376 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1377
1378/** @todo The '..' handling doesn't really work wrt to symbolic links in the
1379 * path. */
1380
1381 /*
1382 * Append a slash to the destination path if necessary.
1383 */
1384 char * const pszDst = pPath->szPath;
1385 size_t offDst = pPath->cch;
1386 if (pPath->cComponents > 0)
1387 {
1388 pszDst[offDst++] = '/';
1389 if (offDst >= RTVFSPARSEDPATH_MAX)
1390 return VERR_FILENAME_TOO_LONG;
1391 }
1392 if (pPath->fAbsolute)
1393 Assert(pszDst[offDst - 1] == '/' && pszDst[0] == '/');
1394 else
1395 Assert(offDst == 0 || (pszDst[0] != '/' && pszDst[offDst - 1] == '/'));
1396
1397 /*
1398 * Parse and append the relative path.
1399 */
1400 const char *pszSrc = pszPath;
1401 pPath->fDirSlash = false;
1402 for (;;)
1403 {
1404 /* Copy until we encounter the next slash. */
1405 pPath->aoffComponents[pPath->cComponents++] = (uint16_t)offDst;
1406 for (;;)
1407 {
1408 char ch = *pszSrc++;
1409 if ( ch != '/'
1410 && ch != '\\'
1411 && ch != '\0')
1412 {
1413 pszDst[offDst++] = ch;
1414 if (offDst < RTVFSPARSEDPATH_MAX)
1415 { /* likely */ }
1416 else
1417 return VERR_FILENAME_TOO_LONG;
1418 }
1419 else
1420 {
1421 /* Deal with dot components before we processes the slash/end. */
1422 if (pszDst[offDst - 1] == '.')
1423 {
1424 if ( offDst == 1
1425 || pszDst[offDst - 2] == '/')
1426 {
1427 pPath->cComponents--;
1428 offDst = pPath->aoffComponents[pPath->cComponents];
1429 }
1430 else if ( offDst > 3
1431 && pszDst[offDst - 2] == '.'
1432 && pszDst[offDst - 3] == '/')
1433 {
1434 if ( pPath->fAbsolute
1435 || offDst < 5
1436 || pszDst[offDst - 4] != '.'
1437 || pszDst[offDst - 5] != '.'
1438 || (offDst >= 6 && pszDst[offDst - 6] != '/') )
1439 {
1440 pPath->cComponents -= pPath->cComponents > 1 ? 2 : 1;
1441 offDst = pPath->aoffComponents[pPath->cComponents];
1442 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1443 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1444 }
1445 }
1446 }
1447
1448 if (ch != '\0')
1449 {
1450 /* Skip unnecessary slashes and check for end of path. */
1451 while ((ch = *pszSrc) == '/' || ch == '\\')
1452 pszSrc++;
1453
1454 if (ch == '\0')
1455 pPath->fDirSlash = true;
1456 }
1457
1458 if (ch == '\0')
1459 {
1460 /* Drop trailing slash unless it's the root slash. */
1461 if ( offDst > 0
1462 && pszDst[offDst - 1] == '/'
1463 && ( !pPath->fAbsolute
1464 || offDst > 1))
1465 offDst--;
1466
1467 /* Terminate the string and enter its length. */
1468 pszDst[offDst] = '\0';
1469 pszDst[offDst + 1] = '\0'; /* for aoffComponents[pPath->cComponents] */
1470 pPath->cch = (uint16_t)offDst;
1471 pPath->aoffComponents[pPath->cComponents] = (uint16_t)(offDst + 1);
1472 return VINF_SUCCESS;
1473 }
1474
1475 /* Append component separator before continuing with the next component. */
1476 if (offDst > 0 && pszDst[offDst - 1] != '/')
1477 pszDst[offDst++] = '/';
1478 if (offDst >= RTVFSPARSEDPATH_MAX)
1479 return VERR_FILENAME_TOO_LONG;
1480 break;
1481 }
1482 }
1483 }
1484}
1485
1486
1487/** @todo Replace RTVfsParsePath with RTPathParse and friends? */
1488RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
1489{
1490 if (*pszPath != '/' && *pszPath != '\\')
1491 {
1492 if (pszCwd)
1493 {
1494 /*
1495 * Relative with a CWD.
1496 */
1497 int rc = RTVfsParsePath(pPath, pszCwd, NULL /*crash if pszCwd is not absolute*/);
1498 if (RT_FAILURE(rc))
1499 return rc;
1500 }
1501 else
1502 {
1503 /*
1504 * Relative.
1505 */
1506 pPath->cch = 0;
1507 pPath->cComponents = 0;
1508 pPath->fDirSlash = false;
1509 pPath->fAbsolute = false;
1510 pPath->aoffComponents[0] = 0;
1511 pPath->aoffComponents[1] = 1;
1512 pPath->szPath[0] = '\0';
1513 pPath->szPath[1] = '\0';
1514 }
1515 }
1516 else
1517 {
1518 /*
1519 * Make pszPath relative, i.e. set up pPath for the root and skip
1520 * leading slashes in pszPath before appending it.
1521 */
1522 pPath->cch = 1;
1523 pPath->cComponents = 0;
1524 pPath->fDirSlash = false;
1525 pPath->fAbsolute = true;
1526 pPath->aoffComponents[0] = 1;
1527 pPath->aoffComponents[1] = 2;
1528 pPath->szPath[0] = '/';
1529 pPath->szPath[1] = '\0';
1530 pPath->szPath[2] = '\0';
1531 while (pszPath[0] == '/' || pszPath[0] == '\\')
1532 pszPath++;
1533 if (!pszPath[0])
1534 return VINF_SUCCESS;
1535 }
1536 return RTVfsParsePathAppend(pPath, pszPath, NULL);
1537}
1538
1539
1540
1541RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath)
1542{
1543 /*
1544 * Allocate the output buffer and hand the problem to rtVfsParsePath.
1545 */
1546 int rc;
1547 PRTVFSPARSEDPATH pPath = (PRTVFSPARSEDPATH)RTMemTmpAlloc(sizeof(RTVFSPARSEDPATH));
1548 if (pPath)
1549 {
1550 rc = RTVfsParsePath(pPath, pszPath, pszCwd);
1551 if (RT_FAILURE(rc))
1552 {
1553 RTMemTmpFree(pPath);
1554 pPath = NULL;
1555 }
1556 }
1557 else
1558 rc = VERR_NO_TMP_MEMORY;
1559 *ppPath = pPath; /* always set it */
1560 return rc;
1561}
1562
1563
1564RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath)
1565{
1566 if (pPath)
1567 {
1568 pPath->cch = UINT16_MAX;
1569 pPath->cComponents = UINT16_MAX;
1570 pPath->aoffComponents[0] = UINT16_MAX;
1571 pPath->aoffComponents[1] = UINT16_MAX;
1572 RTMemTmpFree(pPath);
1573 }
1574}
1575
1576
1577/**
1578 * Handles a symbolic link, adding it to
1579 *
1580 * @returns IPRT status code.
1581 * @param ppCurDir The current directory variable. We change it if
1582 * the symbolic links is absolute.
1583 * @param pPath The parsed path to update.
1584 * @param iPathComponent The current path component.
1585 * @param hSymlink The symbolic link to process.
1586 */
1587static int rtVfsTraverseHandleSymlink(RTVFSDIRINTERNAL **ppCurDir, PRTVFSPARSEDPATH pPath,
1588 uint16_t iPathComponent, RTVFSSYMLINK hSymlink)
1589{
1590 /*
1591 * Read the link and append the trailing path to it.
1592 */
1593 char szPath[RTPATH_MAX];
1594 int rc = RTVfsSymlinkRead(hSymlink, szPath, sizeof(szPath) - 1);
1595 if (RT_SUCCESS(rc))
1596 {
1597 szPath[sizeof(szPath) - 1] = '\0';
1598 if (iPathComponent + 1 < pPath->cComponents)
1599 rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iPathComponent + 1]]);
1600 }
1601 if (RT_SUCCESS(rc))
1602 {
1603 /*
1604 * Special hack help vfsstddir.cpp deal with symbolic links.
1605 */
1606 RTVFSDIRINTERNAL *pCurDir = *ppCurDir;
1607 char *pszPath = szPath;
1608 if (pCurDir->pOps->pfnFollowAbsoluteSymlink)
1609 {
1610 size_t cchRoot = rtPathRootSpecLen(szPath);
1611 if (cchRoot > 0)
1612 {
1613 pszPath = &szPath[cchRoot];
1614 char const chSaved = *pszPath;
1615 *pszPath = '\0';
1616 RTVFSDIRINTERNAL *pVfsRootDir;
1617 RTVfsLockAcquireWrite(pCurDir->Base.hLock);
1618 rc = pCurDir->pOps->pfnFollowAbsoluteSymlink(pCurDir, szPath, &pVfsRootDir);
1619 RTVfsLockAcquireWrite(pCurDir->Base.hLock);
1620 *pszPath = chSaved;
1621 if (RT_SUCCESS(rc))
1622 {
1623 RTVfsDirRelease(pCurDir);
1624 *ppCurDir = pCurDir = pVfsRootDir;
1625 }
1626 else if (rc == VERR_PATH_IS_RELATIVE)
1627 pszPath = szPath;
1628 else
1629 return rc;
1630 }
1631 }
1632
1633 rc = RTVfsParsePath(pPath, pszPath, NULL);
1634 if (RT_SUCCESS(rc))
1635 {
1636 /*
1637 * Deal with absolute references in a VFS setup.
1638 * Note! The current approach only correctly handles this on root volumes.
1639 */
1640 if ( pPath->fAbsolute
1641 && pCurDir->Base.hVfs != NIL_RTVFS) /** @todo This needs fixing once we implement mount points. */
1642 {
1643 RTVFSINTERNAL *pVfs = pCurDir->Base.hVfs;
1644 RTVFSDIRINTERNAL *pVfsRootDir;
1645 RTVfsLockAcquireRead(pVfs->Base.hLock);
1646 rc = pVfs->pOps->pfnOpenRoot(pVfs->Base.pvThis, &pVfsRootDir);
1647 RTVfsLockReleaseRead(pVfs->Base.hLock);
1648 if (RT_SUCCESS(rc))
1649 {
1650 RTVfsDirRelease(pCurDir);
1651 *ppCurDir = pCurDir = pVfsRootDir;
1652 }
1653 else
1654 return rc;
1655 }
1656 }
1657 }
1658 else if (rc == VERR_BUFFER_OVERFLOW)
1659 rc = VERR_FILENAME_TOO_LONG;
1660 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
1661}
1662
1663
1664/**
1665 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1666 *
1667 *
1668 * @returns IPRT status code.
1669 * @param pThis The VFS.
1670 * @param pPath The parsed path. This may be changed as symbolic
1671 * links are processed during the path traversal. If
1672 * it contains zero components, a dummy component is
1673 * added to assist the caller.
1674 * @param fFlags RTPATH_F_XXX.
1675 * @param ppVfsParentDir Where to return the parent directory handle
1676 * (referenced).
1677 */
1678static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags,
1679 RTVFSDIRINTERNAL **ppVfsParentDir)
1680{
1681 /*
1682 * Assert sanity.
1683 */
1684 AssertPtr(pThis);
1685 Assert(pThis->uMagic == RTVFSDIR_MAGIC);
1686 Assert(pThis->Base.cRefs > 0);
1687 AssertPtr(pPath);
1688 AssertPtr(ppVfsParentDir);
1689 *ppVfsParentDir = NULL;
1690 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1691
1692 /*
1693 * Start with the pThis directory.
1694 */
1695 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1696 return VERR_INVALID_HANDLE;
1697 RTVFSDIRINTERNAL *pCurDir = pThis;
1698
1699 /*
1700 * Special case for traversing zero components.
1701 * We fake up a "./" in the pPath to help the caller along.
1702 */
1703 if (pPath->cComponents == 0)
1704 {
1705 pPath->fDirSlash = true;
1706 pPath->szPath[0] = '.';
1707 pPath->szPath[1] = '\0';
1708 pPath->szPath[2] = '\0';
1709 pPath->cch = 1;
1710 pPath->cComponents = 1;
1711 pPath->aoffComponents[0] = 0;
1712 pPath->aoffComponents[1] = 1;
1713 pPath->aoffComponents[2] = 1;
1714
1715 *ppVfsParentDir = pCurDir;
1716 return VINF_SUCCESS;
1717 }
1718
1719
1720 /*
1721 * The traversal loop.
1722 */
1723 int rc = VINF_SUCCESS;
1724 unsigned cLinks = 0;
1725 uint16_t iComponent = 0;
1726 for (;;)
1727 {
1728 /*
1729 * Are we done yet?
1730 */
1731 bool fFinal = iComponent + 1 >= pPath->cComponents;
1732 if (fFinal && (fFlags & RTPATH_F_ON_LINK))
1733 {
1734 *ppVfsParentDir = pCurDir;
1735 return VINF_SUCCESS;
1736 }
1737
1738 /*
1739 * Try open the next entry.
1740 */
1741 const char *pszEntry = &pPath->szPath[pPath->aoffComponents[iComponent]];
1742 char *pszEntryEnd = &pPath->szPath[pPath->aoffComponents[iComponent + 1] - 1];
1743 *pszEntryEnd = '\0';
1744 RTVFSDIR hDir = NIL_RTVFSDIR;
1745 RTVFSSYMLINK hSymlink = NIL_RTVFSSYMLINK;
1746 RTVFS hVfsMnt = NIL_RTVFS;
1747 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ;
1748 if (fFinal)
1749 {
1750 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1751 rc = pCurDir->pOps->pfnOpen(pCurDir->Base.pvThis, pszEntry,
1752 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1753 RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING
1754 | RTVFSOBJ_F_TRAVERSAL | RTPATH_F_ON_LINK,
1755 &hVfsObj);
1756 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1757 *pszEntryEnd = '\0';
1758 if (RT_FAILURE(rc))
1759 {
1760 if ( rc == VERR_PATH_NOT_FOUND
1761 || rc == VERR_FILE_NOT_FOUND
1762 || rc == VERR_IS_A_DIRECTORY
1763 || rc == VERR_IS_A_FILE
1764 || rc == VERR_IS_A_FIFO
1765 || rc == VERR_IS_A_SOCKET
1766 || rc == VERR_IS_A_CHAR_DEVICE
1767 || rc == VERR_IS_A_BLOCK_DEVICE
1768 || rc == VERR_NOT_SYMLINK)
1769 {
1770 *ppVfsParentDir = pCurDir;
1771 return VINF_SUCCESS;
1772 }
1773 break;
1774 }
1775 hSymlink = RTVfsObjToSymlink(hVfsObj);
1776 Assert(hSymlink != NIL_RTVFSSYMLINK);
1777 }
1778 else
1779 {
1780 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1781 rc = pCurDir->pOps->pfnOpen(pCurDir->Base.pvThis, pszEntry,
1782 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1783 RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_OPEN_MOUNT
1784 | RTVFSOBJ_F_CREATE_NOTHING | RTVFSOBJ_F_TRAVERSAL | RTPATH_F_ON_LINK,
1785 &hVfsObj);
1786 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1787 *pszEntryEnd = '/';
1788 if (RT_FAILURE(rc))
1789 {
1790 if (rc == VERR_FILE_NOT_FOUND)
1791 rc = VERR_PATH_NOT_FOUND;
1792 break;
1793 }
1794 hDir = RTVfsObjToDir(hVfsObj);
1795 hSymlink = RTVfsObjToSymlink(hVfsObj);
1796 hVfsMnt = RTVfsObjToVfs(hVfsObj);
1797 }
1798 Assert( (hDir != NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1799 || (hDir == NIL_RTVFSDIR && hSymlink != NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1800 || (hDir == NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt != NIL_RTVFS));
1801 RTVfsObjRelease(hVfsObj);
1802
1803 if (hDir != NIL_RTVFSDIR)
1804 {
1805 /*
1806 * Directory - advance down the path.
1807 */
1808 AssertPtr(hDir);
1809 Assert(hDir->uMagic == RTVFSDIR_MAGIC);
1810 RTVfsDirRelease(pCurDir);
1811 pCurDir = hDir;
1812 iComponent++;
1813 }
1814 else if (hSymlink != NIL_RTVFSSYMLINK)
1815 {
1816 /*
1817 * Symbolic link - deal with it and retry the current component.
1818 */
1819 AssertPtr(hSymlink);
1820 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
1821 if (fFlags & RTPATH_F_NO_SYMLINKS)
1822 {
1823 rc = VERR_SYMLINK_NOT_ALLOWED;
1824 break;
1825 }
1826 cLinks++;
1827 if (cLinks >= RTVFS_MAX_LINKS)
1828 {
1829 rc = VERR_TOO_MANY_SYMLINKS;
1830 break;
1831 }
1832 rc = rtVfsTraverseHandleSymlink(&pCurDir, pPath, iComponent, hSymlink);
1833 if (RT_FAILURE(rc))
1834 break;
1835 iComponent = 0;
1836 }
1837 else
1838 {
1839 /*
1840 * Mount point - deal with it and retry the current component.
1841 */
1842 RTVfsDirRelease(pCurDir);
1843 RTVfsLockAcquireRead(hVfsMnt->Base.hLock);
1844 rc = hVfsMnt->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
1845 RTVfsLockReleaseRead(hVfsMnt->Base.hLock);
1846 if (RT_FAILURE(rc))
1847 {
1848 pCurDir = NULL;
1849 break;
1850 }
1851 iComponent = 0;
1852 /** @todo union mounts. */
1853 }
1854 }
1855
1856 if (pCurDir)
1857 RTVfsDirRelease(pCurDir);
1858
1859 return rc;
1860}
1861
1862
1863/**
1864 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1865 *
1866 * @returns IPRT status code.
1867 * @param pThis The VFS.
1868 * @param pPath The parsed path. This may be changed as symbolic
1869 * links are processed during the path traversal.
1870 * @param fFlags RTPATH_F_XXX.
1871 * @param ppVfsParentDir Where to return the parent directory handle
1872 * (referenced).
1873 */
1874static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir)
1875{
1876 /*
1877 * Assert sanity.
1878 */
1879 AssertPtr(pThis);
1880 Assert(pThis->uMagic == RTVFS_MAGIC);
1881 Assert(pThis->Base.cRefs > 0);
1882 AssertPtr(pPath);
1883 AssertPtr(ppVfsParentDir);
1884 *ppVfsParentDir = NULL;
1885 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1886 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1887
1888 /*
1889 * Open the root directory and join paths with the directory traversal.
1890 */
1891 /** @todo Union mounts, traversal optimization methods, races, ++ */
1892 RTVFSDIRINTERNAL *pRootDir;
1893 RTVfsLockAcquireRead(pThis->Base.hLock);
1894 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pRootDir);
1895 RTVfsLockReleaseRead(pThis->Base.hLock);
1896 if (RT_SUCCESS(rc))
1897 {
1898 rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFlags, ppVfsParentDir);
1899 RTVfsDirRelease(pRootDir);
1900 }
1901 return rc;
1902}
1903
1904
1905
1906/**
1907 * Follows a symbolic link object to the next parent directory.
1908 *
1909 * @returns IPRT status code
1910 * @param ppVfsParentDir Pointer to the parent directory of @a hVfsObj on
1911 * input, the parent directory of the link target on
1912 * return.
1913 * @param hVfsObj Symbolic link object handle.
1914 * @param pPath Path buffer to use parse the symbolic link target.
1915 * @param fFlags See rtVfsDirTraverseToParent.
1916 */
1917static int rtVfsDirFollowSymlinkObjToParent(RTVFSDIRINTERNAL **ppVfsParentDir, RTVFSOBJ hVfsObj,
1918 PRTVFSPARSEDPATH pPath, uint32_t fFlags)
1919{
1920 RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
1921 AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, VERR_INTERNAL_ERROR_3);
1922
1923 int rc = rtVfsTraverseHandleSymlink(ppVfsParentDir, pPath, pPath->cComponents, hVfsSymlink);
1924 if (RT_SUCCESS(rc))
1925 {
1926 RTVFSDIRINTERNAL *pVfsStartDir = *ppVfsParentDir;
1927 rc = rtVfsDirTraverseToParent(pVfsStartDir, pPath, fFlags, ppVfsParentDir);
1928 RTVfsDirRelease(pVfsStartDir);
1929 }
1930
1931 RTVfsSymlinkRelease(hVfsSymlink);
1932 return rc;
1933}
1934
1935
1936
1937RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
1938{
1939 NOREF(fEvents);
1940 int rc;
1941 if (fIntr)
1942 rc = RTThreadSleep(cMillies);
1943 else
1944 {
1945 uint64_t uMsStart = RTTimeMilliTS();
1946 do
1947 rc = RTThreadSleep(cMillies);
1948 while ( rc == VERR_INTERRUPTED
1949 && !fIntr
1950 && RTTimeMilliTS() - uMsStart < cMillies);
1951 if (rc == VERR_INTERRUPTED)
1952 rc = VERR_TIMEOUT;
1953 }
1954
1955 *pfRetEvents = 0;
1956 return rc;
1957}
1958
1959
1960RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
1961{
1962 /*
1963 * Allocate a temporary buffer.
1964 */
1965 size_t cbBuf = cbBufHint;
1966 if (!cbBuf)
1967 cbBuf = _64K;
1968 else if (cbBuf < _4K)
1969 cbBuf = _4K;
1970 else if (cbBuf > _1M)
1971 cbBuf = _1M;
1972
1973 void *pvBuf = RTMemTmpAlloc(cbBuf);
1974 if (!pvBuf)
1975 {
1976 cbBuf = _4K;
1977 pvBuf = RTMemTmpAlloc(cbBuf);
1978 if (!pvBuf)
1979 return VERR_NO_TMP_MEMORY;
1980 }
1981
1982 /*
1983 * Pump loop.
1984 */
1985 int rc;
1986 for (;;)
1987 {
1988 size_t cbRead;
1989 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
1990 if (RT_FAILURE(rc))
1991 break;
1992 if (rc == VINF_EOF && cbRead == 0)
1993 break;
1994
1995 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
1996 if (RT_FAILURE(rc))
1997 break;
1998 }
1999
2000 RTMemTmpFree(pvBuf);
2001
2002 /*
2003 * Flush the destination stream on success to make sure we've caught
2004 * errors caused by buffering delays.
2005 */
2006 if (RT_SUCCESS(rc))
2007 rc = RTVfsIoStrmFlush(hVfsIosDst);
2008
2009 return rc;
2010}
2011
2012
2013
2014
2015
2016/*
2017 * F I L E S Y S T E M R O O T
2018 * F I L E S Y S T E M R O O T
2019 * F I L E S Y S T E M R O O T
2020 */
2021
2022
2023RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
2024 PRTVFS phVfs, void **ppvInstance)
2025{
2026 /*
2027 * Validate the input, be extra strict in strict builds.
2028 */
2029 AssertPtr(pVfsOps);
2030 AssertReturn(pVfsOps->uVersion == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
2031 AssertReturn(pVfsOps->uEndMarker == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
2032 RTVFSOBJ_ASSERT_OPS(&pVfsOps->Obj, RTVFSOBJTYPE_VFS);
2033 Assert(cbInstance > 0);
2034 AssertPtr(ppvInstance);
2035 AssertPtr(phVfs);
2036
2037 /*
2038 * Allocate the handle + instance data.
2039 */
2040 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSINTERNAL), RTVFS_INST_ALIGNMENT)
2041 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2042 RTVFSINTERNAL *pThis = (RTVFSINTERNAL *)RTMemAllocZ(cbThis);
2043 if (!pThis)
2044 return VERR_NO_MEMORY;
2045
2046 int rc = rtVfsObjInitNewObject(&pThis->Base, &pVfsOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2047 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2048 if (RT_FAILURE(rc))
2049 {
2050 RTMemFree(pThis);
2051 return rc;
2052 }
2053
2054 pThis->uMagic = RTVFS_MAGIC;
2055 pThis->pOps = pVfsOps;
2056
2057 *phVfs = pThis;
2058 *ppvInstance = pThis->Base.pvThis;
2059
2060 LogFlow(("RTVfsNew -> VINF_SUCCESS; hVfs=%p pvThis=%p\n", pThis, pThis->Base.pvThis));
2061 return VINF_SUCCESS;
2062}
2063
2064#ifdef DEBUG
2065# undef RTVfsRetain
2066#endif
2067RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs)
2068{
2069 RTVFSINTERNAL *pThis = hVfs;
2070 AssertPtrReturn(pThis, UINT32_MAX);
2071 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2072 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2073 LogFlow(("RTVfsRetain(%p/%p) -> %d\n", pThis, pThis->Base.pvThis, cRefs));
2074 return cRefs;
2075}
2076#ifdef DEBUG
2077# define RTVfsRetain(hVfs) RTVfsRetainDebug(hVfs, RT_SRC_POS)
2078#endif
2079
2080
2081RTDECL(uint32_t) RTVfsRetainDebug(RTVFS hVfs, RT_SRC_POS_DECL)
2082{
2083 RTVFSINTERNAL *pThis = hVfs;
2084 AssertPtrReturn(pThis, UINT32_MAX);
2085 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2086 RT_SRC_POS_NOREF();
2087 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsRetainDebug", RT_SRC_POS_ARGS);
2088}
2089
2090
2091RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs)
2092{
2093 RTVFSINTERNAL *pThis = hVfs;
2094 if (pThis == NIL_RTVFS)
2095 return 0;
2096 AssertPtrReturn(pThis, UINT32_MAX);
2097 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2098#ifdef LOG_ENABLED
2099 void *pvThis = pThis->Base.pvThis;
2100#endif
2101 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2102 Log(("RTVfsRelease(%p/%p) -> %d\n", pThis, pvThis, cRefs));
2103 return cRefs;
2104}
2105
2106
2107RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir)
2108{
2109 RTVFSINTERNAL *pThis = hVfs;
2110 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2111 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2112 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
2113 *phDir = NIL_RTVFSDIR;
2114
2115 if (!pThis->pOps->pfnIsRangeInUse)
2116 return VERR_NOT_SUPPORTED;
2117 RTVfsLockAcquireRead(pThis->Base.hLock);
2118 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phDir);
2119 RTVfsLockReleaseRead(pThis->Base.hLock);
2120
2121 return rc;
2122}
2123
2124
2125RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2126{
2127 RTVFSINTERNAL *pThis = hVfs;
2128 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2129 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2130 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2131 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2132 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2133 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2134 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2135
2136 /*
2137 * Parse the path, assume current directory is root since we've got no
2138 * caller context here. Then traverse to the parent directory.
2139 */
2140 PRTVFSPARSEDPATH pPath;
2141 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2142 if (RT_SUCCESS(rc))
2143 {
2144 RTVFSDIRINTERNAL *pVfsParentDir;
2145 if (pPath->cComponents > 0)
2146 {
2147 rc = rtVfsTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
2148 if (RT_SUCCESS(rc))
2149 {
2150 /*
2151 * Call the query method on the parent directory.
2152 */
2153 /** @todo race condition here :/ */
2154 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2155 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2156 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2157 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2158
2159 RTVfsDirRelease(pVfsParentDir);
2160 }
2161 }
2162 /*
2163 * The path boils down to '.', open the root dir and query its info.
2164 */
2165 else
2166 {
2167 RTVfsLockAcquireRead(pThis->Base.hLock);
2168 RTVFSDIR hRootDir = NIL_RTVFSDIR;
2169 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &hRootDir);
2170 RTVfsLockReleaseRead(pThis->Base.hLock);
2171 if (RT_SUCCESS(rc))
2172 {
2173 RTVfsLockAcquireRead(hRootDir->Base.hLock);
2174 rc = hRootDir->Base.pOps->pfnQueryInfo(hRootDir->Base.pvThis, pObjInfo, enmAddAttr);
2175 RTVfsLockReleaseRead(hRootDir->Base.hLock);
2176 RTVfsDirRelease(hRootDir);
2177 }
2178 }
2179
2180 RTVfsParsePathFree(pPath);
2181 }
2182 return rc;
2183}
2184
2185
2186
2187RTDECL(int) RTVfsIsRangeInUse(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed)
2188{
2189 RTVFSINTERNAL *pThis = hVfs;
2190 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2191 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2192
2193 if (!pThis->pOps->pfnIsRangeInUse)
2194 return VERR_NOT_SUPPORTED;
2195 RTVfsLockAcquireRead(pThis->Base.hLock);
2196 int rc = pThis->pOps->pfnIsRangeInUse(pThis->Base.pvThis, off, cb, pfUsed);
2197 RTVfsLockReleaseRead(pThis->Base.hLock);
2198
2199 return rc;
2200}
2201
2202
2203
2204
2205/*
2206 *
2207 * F I L E S Y S T E M S T R E A M
2208 * F I L E S Y S T E M S T R E A M
2209 * F I L E S Y S T E M S T R E A M
2210 *
2211 */
2212
2213
2214RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, bool fReadOnly,
2215 PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
2216{
2217 /*
2218 * Validate the input, be extra strict in strict builds.
2219 */
2220 AssertPtr(pFsStreamOps);
2221 AssertReturn(pFsStreamOps->uVersion == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2222 AssertReturn(pFsStreamOps->uEndMarker == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2223 Assert(!pFsStreamOps->fReserved);
2224 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
2225 if (fReadOnly)
2226 AssertPtr(pFsStreamOps->pfnNext);
2227 else
2228 {
2229 AssertPtr(pFsStreamOps->pfnAdd);
2230 AssertPtr(pFsStreamOps->pfnEnd);
2231 }
2232 Assert(cbInstance > 0);
2233 AssertPtr(ppvInstance);
2234 AssertPtr(phVfsFss);
2235 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2236
2237 /*
2238 * Allocate the handle + instance data.
2239 */
2240 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFSSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
2241 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2242 RTVFSFSSTREAMINTERNAL *pThis = (RTVFSFSSTREAMINTERNAL *)RTMemAllocZ(cbThis);
2243 if (!pThis)
2244 return VERR_NO_MEMORY;
2245
2246 int rc = rtVfsObjInitNewObject(&pThis->Base, &pFsStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2247 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2248
2249 if (RT_FAILURE(rc))
2250 {
2251 RTMemFree(pThis);
2252 return rc;
2253 }
2254
2255 pThis->uMagic = RTVFSFSSTREAM_MAGIC;
2256 pThis->fFlags = fReadOnly
2257 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
2258 : RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL;
2259 pThis->pOps = pFsStreamOps;
2260
2261 *phVfsFss = pThis;
2262 *ppvInstance = pThis->Base.pvThis;
2263 return VINF_SUCCESS;
2264}
2265
2266
2267#ifdef DEBUG
2268# undef RTVfsFsStrmRetain
2269#endif
2270RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss)
2271{
2272 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2273 AssertPtrReturn(pThis, UINT32_MAX);
2274 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2275 return rtVfsObjRetain(&pThis->Base);
2276}
2277#ifdef DEBUG
2278# define RTVfsFsStrmRetain(hVfsFss) RTVfsFsStrmRetainDebug(hVfsFss, RT_SRC_POS)
2279#endif
2280
2281
2282RTDECL(uint32_t) RTVfsFsStrmRetainDebug(RTVFSFSSTREAM hVfsFss, RT_SRC_POS_DECL)
2283{
2284 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2285 AssertPtrReturn(pThis, UINT32_MAX);
2286 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2287 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsFsStrmRetain", RT_SRC_POS_ARGS);
2288}
2289
2290
2291RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss)
2292{
2293 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2294 if (pThis == NIL_RTVFSFSSTREAM)
2295 return 0;
2296 AssertPtrReturn(pThis, UINT32_MAX);
2297 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2298 return rtVfsObjRelease(&pThis->Base);
2299}
2300
2301
2302RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2303{
2304 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2305 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2306 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2307 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2308}
2309
2310
2311RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
2312{
2313 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2314 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2315 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2316 AssertPtrNullReturn(ppszName, VERR_INVALID_POINTER);
2317 if (ppszName)
2318 *ppszName = NULL;
2319 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2320 if (penmType)
2321 *penmType = RTVFSOBJTYPE_INVALID;
2322 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2323 if (phVfsObj)
2324 *phVfsObj = NIL_RTVFSOBJ;
2325
2326 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_INVALID_FUNCTION);
2327
2328 return pThis->pOps->pfnNext(pThis->Base.pvThis, ppszName, penmType, phVfsObj);
2329}
2330
2331
2332RTDECL(int) RTVfsFsStrmAdd(RTVFSFSSTREAM hVfsFss, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)
2333{
2334 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2335 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2336 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2337 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2338 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2339 AssertPtrReturn(hVfsObj, VERR_INVALID_HANDLE);
2340 AssertReturn(hVfsObj->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
2341 AssertReturn(!(fFlags & ~RTVFSFSSTRM_ADD_F_VALID_MASK), VERR_INVALID_FLAGS);
2342 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2343
2344 return pThis->pOps->pfnAdd(pThis->Base.pvThis, pszPath, hVfsObj, fFlags);
2345}
2346
2347
2348RTDECL(int) RTVfsFsStrmPushFile(RTVFSFSSTREAM hVfsFss, const char *pszPath, uint64_t cbFile,
2349 PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
2350{
2351 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2352 AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
2353 *phVfsIos = NIL_RTVFSIOSTREAM;
2354
2355 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2356 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2357
2358 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2359 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2360
2361 AssertReturn(!(fFlags & ~RTVFSFSSTRM_PUSH_F_VALID_MASK), VERR_INVALID_FLAGS);
2362 AssertReturn(RT_BOOL(cbFile == UINT64_MAX) == RT_BOOL(fFlags & RTVFSFSSTRM_PUSH_F_STREAM), VERR_INVALID_FLAGS);
2363
2364 if (cObjInfo)
2365 {
2366 AssertPtrReturn(paObjInfo, VERR_INVALID_POINTER);
2367 AssertReturn(paObjInfo[0].Attr.enmAdditional == RTFSOBJATTRADD_UNIX, VERR_INVALID_PARAMETER);
2368 }
2369
2370 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2371 if (pThis->pOps->pfnPushFile)
2372 return pThis->pOps->pfnPushFile(pThis->Base.pvThis, pszPath, cbFile, paObjInfo, cObjInfo, fFlags, phVfsIos);
2373 return VERR_NOT_SUPPORTED;
2374}
2375
2376
2377RTDECL(int) RTVfsFsStrmEnd(RTVFSFSSTREAM hVfsFss)
2378{
2379 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2380 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2381 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2382
2383 return pThis->pOps->pfnEnd(pThis->Base.pvThis);
2384}
2385
2386
2387RTDECL(void *) RTVfsFsStreamToPrivate(RTVFSFSSTREAM hVfsFss, PCRTVFSFSSTREAMOPS pFsStreamOps)
2388{
2389 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2390 AssertPtrReturn(pThis, NULL);
2391 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, NULL);
2392 if (pThis->pOps != pFsStreamOps)
2393 return NULL;
2394 return pThis->Base.pvThis;
2395}
2396
2397
2398/*
2399 *
2400 * D I R D I R D I R
2401 * D I R D I R D I R
2402 * D I R D I R D I R
2403 *
2404 */
2405
2406
2407RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock,
2408 PRTVFSDIR phVfsDir, void **ppvInstance)
2409{
2410 /*
2411 * Validate the input, be extra strict in strict builds.
2412 */
2413 AssertPtr(pDirOps);
2414 AssertReturn(pDirOps->uVersion == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2415 AssertReturn(pDirOps->uEndMarker == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2416 Assert(!pDirOps->fReserved);
2417 RTVFSDIR_ASSERT_OPS(pDirOps, RTVFSOBJTYPE_DIR);
2418 Assert(cbInstance > 0);
2419 AssertReturn(!(fFlags & ~RTVFSDIR_F_NO_VFS_REF), VERR_INVALID_FLAGS);
2420 AssertPtr(ppvInstance);
2421 AssertPtr(phVfsDir);
2422 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2423
2424 /*
2425 * Allocate the handle + instance data.
2426 */
2427 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSDIRINTERNAL), RTVFS_INST_ALIGNMENT)
2428 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2429 RTVFSDIRINTERNAL *pThis = (RTVFSDIRINTERNAL *)RTMemAllocZ(cbThis);
2430 if (!pThis)
2431 return VERR_NO_MEMORY;
2432
2433 int rc = rtVfsObjInitNewObject(&pThis->Base, &pDirOps->Obj, hVfs, RT_BOOL(fFlags & RTVFSDIR_F_NO_VFS_REF), hLock,
2434 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2435 if (RT_FAILURE(rc))
2436 {
2437 RTMemFree(pThis);
2438 return rc;
2439 }
2440
2441 pThis->uMagic = RTVFSDIR_MAGIC;
2442 pThis->fReserved = 0;
2443 pThis->pOps = pDirOps;
2444
2445 *phVfsDir = pThis;
2446 *ppvInstance = pThis->Base.pvThis;
2447 return VINF_SUCCESS;
2448}
2449
2450
2451#ifdef DEBUG
2452# undef RTVfsDirRetain
2453#endif
2454RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir)
2455{
2456 RTVFSDIRINTERNAL *pThis = hVfsDir;
2457 AssertPtrReturn(pThis, UINT32_MAX);
2458 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2459 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2460 LogFlow(("RTVfsDirRetain(%p/%p) -> %#x\n", pThis, pThis->Base.pvThis, cRefs));
2461 return cRefs;
2462}
2463#ifdef DEBUG
2464# define RTVfsDirRetain(hVfsDir) RTVfsDirRetainDebug(hVfsDir, RT_SRC_POS)
2465#endif
2466
2467
2468RTDECL(uint32_t) RTVfsDirRetainDebug(RTVFSDIR hVfsDir, RT_SRC_POS_DECL)
2469{
2470 RTVFSDIRINTERNAL *pThis = hVfsDir;
2471 AssertPtrReturn(pThis, UINT32_MAX);
2472 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2473 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsDirRetain", RT_SRC_POS_ARGS);
2474}
2475
2476
2477RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir)
2478{
2479 RTVFSDIRINTERNAL *pThis = hVfsDir;
2480 if (pThis == NIL_RTVFSDIR)
2481 return 0;
2482 AssertPtrReturn(pThis, UINT32_MAX);
2483 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2484#ifdef LOG_ENABLED
2485 void *pvThis = pThis->Base.pvThis;
2486#endif
2487 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2488 LogFlow(("RTVfsDirRelease(%p/%p) -> %#x\n", pThis, pvThis, cRefs));
2489 return cRefs;
2490}
2491
2492
2493RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2494{
2495 /*
2496 * Validate input.
2497 */
2498 RTVFSINTERNAL *pThis = hVfs;
2499 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2500 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2501 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2502 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2503 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2504
2505 /*
2506 * Parse the path, assume current directory is root since we've got no
2507 * caller context here.
2508 */
2509 PRTVFSPARSEDPATH pPath;
2510 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2511 if (RT_SUCCESS(rc))
2512 {
2513 if (pPath->cComponents > 0)
2514 {
2515 /*
2516 * Tranverse the path, resolving the parent node and any symlinks
2517 * in the final element, and ask the directory to open the subdir.
2518 */
2519 RTVFSDIRINTERNAL *pVfsParentDir;
2520 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2521 if (RT_SUCCESS(rc))
2522 {
2523 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2524
2525 /** @todo there is a symlink creation race here. */
2526 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2527 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2528 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2529
2530 RTVfsDirRelease(pVfsParentDir);
2531
2532 if (RT_SUCCESS(rc))
2533 {
2534 AssertPtr(*phVfsDir);
2535 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2536 }
2537 }
2538 }
2539 /*
2540 * If the path boils down to '.' return the root directory.
2541 */
2542 else
2543 {
2544 RTVfsLockAcquireRead(pThis->Base.hLock);
2545 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phVfsDir);
2546 RTVfsLockReleaseRead(pThis->Base.hLock);
2547 }
2548 RTVfsParsePathFree(pPath);
2549 }
2550 return rc;
2551}
2552
2553
2554RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2555{
2556 /*
2557 * Validate input.
2558 */
2559 RTVFSDIRINTERNAL *pThis = hVfsDir;
2560 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2561 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2562 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2563 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2564 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2565
2566 /*
2567 * Parse the path, it's always relative to the given directory.
2568 */
2569 PRTVFSPARSEDPATH pPath;
2570 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2571 if (RT_SUCCESS(rc))
2572 {
2573 if (pPath->cComponents > 0)
2574 {
2575 /*
2576 * Tranverse the path, resolving the parent node and any symlinks
2577 * in the final element, and ask the directory to open the subdir.
2578 */
2579 RTVFSDIRINTERNAL *pVfsParentDir;
2580 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2581 if (RT_SUCCESS(rc))
2582 {
2583 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2584
2585 /** @todo there is a symlink creation race here. */
2586 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2587 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2588 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2589
2590 RTVfsDirRelease(pVfsParentDir);
2591
2592 if (RT_SUCCESS(rc))
2593 {
2594 AssertPtr(*phVfsDir);
2595 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2596 }
2597 }
2598 }
2599 /*
2600 * The path boils down to '.', call pfnOpenDir on pThis with '.' as input.
2601 * The caller may wish for a new directory instance to enumerate the entries
2602 * in parallel or some such thing.
2603 */
2604 else
2605 {
2606 RTVfsLockAcquireWrite(pThis->Base.hLock);
2607 rc = pThis->pOps->pfnOpenDir(pThis->Base.pvThis, ".", fFlags, phVfsDir);
2608 RTVfsLockReleaseWrite(pThis->Base.hLock);
2609 }
2610 RTVfsParsePathFree(pPath);
2611 }
2612 return rc;
2613}
2614
2615
2616RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir)
2617{
2618 /*
2619 * Validate input.
2620 */
2621 RTVFSDIRINTERNAL *pThis = hVfsDir;
2622 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2623 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2624 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2625 AssertPtrNullReturn(phVfsDir, VERR_INVALID_POINTER);
2626 AssertReturn(!(fFlags & ~RTDIRCREATE_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
2627 fMode = rtFsModeNormalize(fMode, pszRelPath, 0);
2628 AssertReturn(rtFsModeIsValidPermissions(fMode), VERR_INVALID_FMODE);
2629 if (!(fFlags & RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET))
2630 fMode |= RTFS_DOS_NT_NOT_CONTENT_INDEXED;
2631
2632 /*
2633 * Parse the path, it's always relative to the given directory.
2634 */
2635 PRTVFSPARSEDPATH pPath;
2636 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2637 if (RT_SUCCESS(rc))
2638 {
2639 if (pPath->cComponents > 0)
2640 {
2641 /*
2642 * Tranverse the path, resolving the parent node, not checking for symbolic
2643 * links in the final element, and ask the directory to create the subdir.
2644 */
2645 RTVFSDIRINTERNAL *pVfsParentDir;
2646 rc = rtVfsDirTraverseToParent(pThis, pPath,
2647 fFlags & RTDIRCREATE_FLAGS_NO_SYMLINKS
2648 ? RTPATH_F_NO_SYMLINKS | RTPATH_F_ON_LINK : RTPATH_F_FOLLOW_LINK,
2649 &pVfsParentDir);
2650 if (RT_SUCCESS(rc))
2651 {
2652 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2653
2654 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2655 rc = pVfsParentDir->pOps->pfnCreateDir(pVfsParentDir->Base.pvThis, pszEntryName, fMode, phVfsDir);
2656 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2657
2658 RTVfsDirRelease(pVfsParentDir);
2659
2660 if (RT_SUCCESS(rc) && phVfsDir)
2661 {
2662 AssertPtr(*phVfsDir);
2663 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2664 }
2665 }
2666 }
2667 else
2668 rc = VERR_PATH_ZERO_LENGTH;
2669 RTVfsParsePathFree(pPath);
2670 }
2671 return rc;
2672}
2673
2674
2675RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2676{
2677 /*
2678 * Validate input.
2679 */
2680 RTVFSDIRINTERNAL *pThis = hVfsDir;
2681 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2682 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2683 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2684 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2685
2686 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2687 if (RT_FAILURE(rc))
2688 return rc;
2689
2690 /*
2691 * Parse the relative path.
2692 */
2693 PRTVFSPARSEDPATH pPath;
2694 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2695 if (RT_SUCCESS(rc))
2696 {
2697 if (pPath->cComponents > 0)
2698 {
2699 /*
2700 * Tranverse the path, resolving the parent node and any symlinks
2701 * in the final element, and ask the directory to open the file.
2702 */
2703 RTVFSDIRINTERNAL *pVfsParentDir;
2704 rc = rtVfsDirTraverseToParent(pThis, pPath,
2705 (fOpen & RTFILE_O_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_FOLLOW_LINK,
2706 &pVfsParentDir);
2707 if (RT_SUCCESS(rc))
2708 {
2709 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2710
2711 if ( pVfsParentDir->pOps->pfnOpenFile == NULL
2712 || pPath->fDirSlash)
2713 {
2714 RTVFSOBJ hVfsObj;
2715 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2716 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpen,
2717 RTVFSOBJ_F_OPEN_ANY_FILE | RTVFSOBJ_F_CREATE_FILE
2718 | RTPATH_F_FOLLOW_LINK, &hVfsObj);
2719 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2720 if (RT_SUCCESS(rc))
2721 {
2722 if (RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2723 *phVfsFile = RTVfsObjToFile(hVfsObj);
2724 else
2725 {
2726 /** @todo parse symbolic links. */
2727 AssertFailed();
2728 rc = VERR_NOT_IMPLEMENTED;
2729 }
2730 RTVfsObjRelease(hVfsObj);
2731 }
2732 }
2733 else
2734 {
2735 /** @todo there is a symlink creation race here. */
2736 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2737 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2738 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2739 }
2740
2741 if (RT_SUCCESS(rc))
2742 {
2743 AssertPtr(*phVfsFile);
2744 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2745 }
2746
2747 RTVfsDirRelease(pVfsParentDir);
2748 }
2749 }
2750 else
2751 rc = VERR_NOT_A_FILE;
2752 RTVfsParsePathFree(pPath);
2753 }
2754 return rc;
2755}
2756
2757
2758RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
2759{
2760 RTVFSFILE hVfsFile;
2761 int rc = RTVfsDirOpenFile(hVfsDir, pszPath, fOpen, &hVfsFile);
2762 if (RT_SUCCESS(rc))
2763 {
2764 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
2765 AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
2766 RTVfsFileRelease(hVfsFile);
2767 }
2768 return rc;
2769}
2770
2771
2772RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
2773{
2774 /*
2775 * Validate input.
2776 */
2777 RTVFSDIRINTERNAL *pThis = hVfsDir;
2778 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2779 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2780 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2781 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
2782
2783 int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
2784 if (RT_FAILURE(rc))
2785 return rc;
2786 AssertMsgReturn( RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
2787 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
2788 ("fObjFlags=%#x\n", fObjFlags),
2789 VERR_INVALID_FLAGS);
2790
2791 /*
2792 * Parse the relative path. If it ends with a directory slash or it boils
2793 * down to an empty path (i.e. re-opening hVfsDir), adjust the flags to only
2794 * open/create directories.
2795 */
2796 PRTVFSPARSEDPATH pPath;
2797 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2798 if (RT_SUCCESS(rc))
2799 {
2800 /*
2801 * Tranverse the path, resolving the parent node.
2802 * We'll do the symbolic link checking here with help of pfnOpen.
2803 */
2804 RTVFSDIRINTERNAL *pVfsParentDir;
2805 rc = rtVfsDirTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2806 if (RT_SUCCESS(rc))
2807 {
2808 /*
2809 * Do the opening. Loop if we need to follow symbolic links.
2810 */
2811 for (uint32_t cLoops = 1; ; cLoops++)
2812 {
2813 /* If we end with a directory slash, adjust open flags. */
2814 if (pPath->fDirSlash)
2815 {
2816 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
2817 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
2818 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
2819 }
2820
2821 /* Open it. */
2822 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2823 RTVFSOBJ hVfsObj;
2824 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2825 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
2826 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2827 if (RT_FAILURE(rc))
2828 break;
2829
2830 /* We're done if we don't follow links or this wasn't a link. */
2831 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2832 || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
2833 {
2834 *phVfsObj = hVfsObj;
2835 break;
2836 }
2837
2838 /* Follow symbolic link. */
2839 if (cLoops < RTVFS_MAX_LINKS)
2840 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2841 else
2842 rc = VERR_TOO_MANY_SYMLINKS;
2843 RTVfsObjRelease(hVfsObj);
2844 if (RT_FAILURE(rc))
2845 break;
2846 }
2847
2848 RTVfsDirRelease(pVfsParentDir);
2849 }
2850 RTVfsParsePathFree(pPath);
2851 }
2852 return rc;
2853}
2854
2855
2856RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo,
2857 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2858{
2859 /*
2860 * Validate input.
2861 */
2862 RTVFSDIRINTERNAL *pThis = hVfsDir;
2863 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2864 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2865 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2866 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2867 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2868 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2869 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2870
2871 /*
2872 * Parse the relative path. Then traverse to the parent directory.
2873 */
2874 PRTVFSPARSEDPATH pPath;
2875 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2876 if (RT_SUCCESS(rc))
2877 {
2878 if (pPath->cComponents > 0)
2879 {
2880 RTVFSDIRINTERNAL *pVfsParentDir;
2881 rc = rtVfsDirTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
2882 if (RT_SUCCESS(rc))
2883 {
2884 /*
2885 * Call the query method on the parent directory.
2886 */
2887 /** @todo symlink race condition here :/ */
2888 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2889 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2890 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2891 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2892
2893 RTVfsDirRelease(pVfsParentDir);
2894 }
2895 else
2896 rc = VERR_INVALID_PARAMETER;
2897 }
2898 /*
2899 * The path boils down to '.' so just query the directory.
2900 */
2901 else
2902 {
2903 RTVfsLockAcquireRead(pThis->Base.hLock);
2904 rc = pThis->Base.pOps->pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr);
2905 RTVfsLockReleaseRead(pThis->Base.hLock);
2906 }
2907 RTVfsParsePathFree(pPath);
2908 }
2909 return rc;
2910}
2911
2912
2913RTDECL(int) RTVfsDirRemoveDir(RTVFSDIR hVfsDir, const char *pszRelPath, uint32_t fFlags)
2914{
2915 /*
2916 * Validate input.
2917 */
2918 RTVFSDIRINTERNAL *pThis = hVfsDir;
2919 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2920 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2921 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2922 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2923
2924 /*
2925 * Parse the path, it's always relative to the given directory.
2926 */
2927 PRTVFSPARSEDPATH pPath;
2928 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2929 if (RT_SUCCESS(rc))
2930 {
2931 if (pPath->cComponents > 0)
2932 {
2933 /*
2934 * Tranverse the path, resolving the parent node, not checking for symbolic
2935 * links in the final element, and ask the directory to remove the subdir.
2936 */
2937 RTVFSDIRINTERNAL *pVfsParentDir;
2938 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
2939 if (RT_SUCCESS(rc))
2940 {
2941 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2942
2943 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2944 rc = pVfsParentDir->pOps->pfnUnlinkEntry(pVfsParentDir->Base.pvThis, pszEntryName, RTFS_TYPE_DIRECTORY);
2945 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2946
2947 RTVfsDirRelease(pVfsParentDir);
2948 }
2949 }
2950 else
2951 rc = VERR_PATH_ZERO_LENGTH;
2952 RTVfsParsePathFree(pPath);
2953 }
2954 return rc;
2955}
2956
2957
2958
2959RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
2960{
2961 /*
2962 * Validate input.
2963 */
2964 RTVFSDIRINTERNAL *pThis = hVfsDir;
2965 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2966 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2967 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
2968 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2969
2970 size_t cbDirEntry = sizeof(*pDirEntry);
2971 if (!pcbDirEntry)
2972 pcbDirEntry = &cbDirEntry;
2973 else
2974 {
2975 cbDirEntry = *pcbDirEntry;
2976 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
2977 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
2978 VERR_INVALID_PARAMETER);
2979 }
2980
2981 /*
2982 * Call the directory method.
2983 */
2984 RTVfsLockAcquireRead(pThis->Base.hLock);
2985 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
2986 RTVfsLockReleaseRead(pThis->Base.hLock);
2987 return rc;
2988}
2989
2990
2991/*
2992 *
2993 * S Y M B O L I C L I N K
2994 * S Y M B O L I C L I N K
2995 * S Y M B O L I C L I N K
2996 *
2997 */
2998
2999RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
3000 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
3001{
3002 /*
3003 * Validate the input, be extra strict in strict builds.
3004 */
3005 AssertPtr(pSymlinkOps);
3006 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3007 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3008 Assert(!pSymlinkOps->fReserved);
3009 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
3010 Assert(cbInstance > 0);
3011 AssertPtr(ppvInstance);
3012 AssertPtr(phVfsSym);
3013 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3014
3015 /*
3016 * Allocate the handle + instance data.
3017 */
3018 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
3019 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3020 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
3021 if (!pThis)
3022 return VERR_NO_MEMORY;
3023
3024 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3025 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3026 if (RT_FAILURE(rc))
3027 {
3028 RTMemFree(pThis);
3029 return rc;
3030 }
3031
3032 pThis->uMagic = RTVFSSYMLINK_MAGIC;
3033 pThis->pOps = pSymlinkOps;
3034
3035 *phVfsSym = pThis;
3036 *ppvInstance = pThis->Base.pvThis;
3037 return VINF_SUCCESS;
3038}
3039
3040
3041RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
3042{
3043 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3044 AssertPtrReturn(pThis, UINT32_MAX);
3045 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3046 return rtVfsObjRetain(&pThis->Base);
3047}
3048
3049
3050RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL)
3051{
3052 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3053 AssertPtrReturn(pThis, UINT32_MAX);
3054 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3055 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsSymlinkRetainDebug", RT_SRC_POS_ARGS);
3056}
3057
3058
3059RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
3060{
3061 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3062 if (pThis == NIL_RTVFSSYMLINK)
3063 return 0;
3064 AssertPtrReturn(pThis, UINT32_MAX);
3065 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3066 return rtVfsObjRelease(&pThis->Base);
3067}
3068
3069
3070RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3071{
3072 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3073 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3074 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3075 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3076}
3077
3078
3079RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
3080{
3081 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3082 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3083 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3084
3085 fMode = rtFsModeNormalize(fMode, NULL, 0);
3086 if (!rtFsModeIsValid(fMode))
3087 return VERR_INVALID_PARAMETER;
3088
3089 RTVfsLockAcquireWrite(pThis->Base.hLock);
3090 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
3091 RTVfsLockReleaseWrite(pThis->Base.hLock);
3092 return rc;
3093}
3094
3095
3096RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
3097 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
3098{
3099 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3100 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3101 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3102
3103 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
3104 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
3105 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
3106 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
3107
3108 RTVfsLockAcquireWrite(pThis->Base.hLock);
3109 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
3110 RTVfsLockReleaseWrite(pThis->Base.hLock);
3111 return rc;
3112}
3113
3114
3115RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
3116{
3117 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3118 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3119 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3120
3121 RTVfsLockAcquireWrite(pThis->Base.hLock);
3122 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
3123 RTVfsLockReleaseWrite(pThis->Base.hLock);
3124 return rc;
3125}
3126
3127
3128RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
3129{
3130 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3131 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3132 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3133
3134 RTVfsLockAcquireWrite(pThis->Base.hLock);
3135 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
3136 RTVfsLockReleaseWrite(pThis->Base.hLock);
3137
3138 return rc;
3139}
3140
3141
3142
3143/*
3144 *
3145 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3146 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3147 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3148 *
3149 */
3150
3151RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3152 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
3153{
3154 /*
3155 * Validate the input, be extra strict in strict builds.
3156 */
3157 AssertPtr(pIoStreamOps);
3158 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3159 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3160 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
3161 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
3162 Assert(cbInstance > 0);
3163 Assert(fOpen & RTFILE_O_ACCESS_MASK);
3164 AssertPtr(ppvInstance);
3165 AssertPtr(phVfsIos);
3166 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3167
3168 /*
3169 * Allocate the handle + instance data.
3170 */
3171 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
3172 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3173 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
3174 if (!pThis)
3175 return VERR_NO_MEMORY;
3176
3177 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3178 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3179 if (RT_FAILURE(rc))
3180 {
3181 RTMemFree(pThis);
3182 return rc;
3183 }
3184
3185 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
3186 pThis->fFlags = fOpen;
3187 pThis->pOps = pIoStreamOps;
3188
3189 *phVfsIos = pThis;
3190 *ppvInstance = pThis->Base.pvThis;
3191 return VINF_SUCCESS;
3192}
3193
3194
3195RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
3196{
3197 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3198 AssertPtrReturn(pThis, NULL);
3199 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
3200 if (pThis->pOps != pIoStreamOps)
3201 return NULL;
3202 return pThis->Base.pvThis;
3203}
3204
3205
3206#ifdef DEBUG
3207# undef RTVfsIoStrmRetain
3208#endif
3209RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
3210{
3211 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3212 AssertPtrReturn(pThis, UINT32_MAX);
3213 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3214 return rtVfsObjRetain(&pThis->Base);
3215}
3216#ifdef DEBUG
3217# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS)
3218#endif
3219
3220
3221RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL)
3222{
3223 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3224 AssertPtrReturn(pThis, UINT32_MAX);
3225 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3226 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsIoStrmRetainDebug", RT_SRC_POS_ARGS);
3227}
3228
3229
3230RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
3231{
3232 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3233 if (pThis == NIL_RTVFSIOSTREAM)
3234 return 0;
3235 AssertPtrReturn(pThis, UINT32_MAX);
3236 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3237 return rtVfsObjRelease(&pThis->Base);
3238}
3239
3240
3241RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
3242{
3243 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3244 AssertPtrReturn(pThis, NIL_RTVFSFILE);
3245 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
3246
3247 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3248 {
3249 rtVfsObjRetainVoid(&pThis->Base, "RTVfsIoStrmToFile");
3250 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3251 }
3252
3253 /* this is no crime, so don't assert. */
3254 return NIL_RTVFSFILE;
3255}
3256
3257
3258RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3259{
3260 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3261 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3262 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3263 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3264}
3265
3266
3267RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
3268{
3269 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3270 if (pcbRead)
3271 *pcbRead = 0;
3272 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3273 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3274 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3275 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3276 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3277
3278 RTSGSEG Seg = { pvBuf, cbToRead };
3279 RTSGBUF SgBuf;
3280 RTSgBufInit(&SgBuf, &Seg, 1);
3281
3282 RTVfsLockAcquireWrite(pThis->Base.hLock);
3283 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
3284 RTVfsLockReleaseWrite(pThis->Base.hLock);
3285 return rc;
3286}
3287
3288
3289RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
3290 bool fBlocking, size_t *pcbRead)
3291{
3292 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3293 if (pcbRead)
3294 *pcbRead = 0;
3295 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3296 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3297 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3298 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3299 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3300
3301 RTSGSEG Seg = { pvBuf, cbToRead };
3302 RTSGBUF SgBuf;
3303 RTSgBufInit(&SgBuf, &Seg, 1);
3304
3305 RTVfsLockAcquireWrite(pThis->Base.hLock);
3306 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
3307 RTVfsLockReleaseWrite(pThis->Base.hLock);
3308 return rc;
3309}
3310
3311
3312RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
3313{
3314 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3315 if (pcbWritten)
3316 *pcbWritten = 0;
3317 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3318 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3319 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3320 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3321 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3322
3323 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3324 RTSGBUF SgBuf;
3325 RTSgBufInit(&SgBuf, &Seg, 1);
3326
3327 RTVfsLockAcquireWrite(pThis->Base.hLock);
3328 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
3329 RTVfsLockReleaseWrite(pThis->Base.hLock);
3330 return rc;
3331}
3332
3333
3334RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
3335 bool fBlocking, size_t *pcbWritten)
3336{
3337 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3338 if (pcbWritten)
3339 *pcbWritten = 0;
3340 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3341 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3342 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3343 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3344 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3345
3346 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3347 RTSGBUF SgBuf;
3348 RTSgBufInit(&SgBuf, &Seg, 1);
3349
3350 RTVfsLockAcquireWrite(pThis->Base.hLock);
3351 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
3352 RTVfsLockReleaseWrite(pThis->Base.hLock);
3353 return rc;
3354}
3355
3356
3357RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3358{
3359 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3360 if (pcbRead)
3361 *pcbRead = 0;
3362 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3363 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3364 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3365 AssertPtr(pSgBuf);
3366 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3367 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3368
3369 RTVfsLockAcquireWrite(pThis->Base.hLock);
3370 int rc;
3371 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3372 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
3373 else
3374 {
3375 size_t cbRead = 0;
3376 rc = VINF_SUCCESS;
3377
3378 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3379 {
3380 RTSGBUF SgBuf;
3381 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3382
3383 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
3384 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
3385 if (RT_FAILURE(rc))
3386 break;
3387 cbRead += cbReadSeg;
3388 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
3389 break;
3390 if (off != -1)
3391 off += cbReadSeg;
3392 }
3393
3394 if (pcbRead)
3395 *pcbRead = cbRead;
3396 }
3397 RTVfsLockReleaseWrite(pThis->Base.hLock);
3398 return rc;
3399}
3400
3401
3402RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3403{
3404 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3405 if (pcbWritten)
3406 *pcbWritten = 0;
3407 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3408 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3409 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3410 AssertPtr(pSgBuf);
3411 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3412 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3413
3414 RTVfsLockAcquireWrite(pThis->Base.hLock);
3415 int rc;
3416 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3417 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
3418 else
3419 {
3420 size_t cbWritten = 0;
3421 rc = VINF_SUCCESS;
3422
3423 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3424 {
3425 RTSGBUF SgBuf;
3426 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3427
3428 size_t cbWrittenSeg = 0;
3429 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
3430 if (RT_FAILURE(rc))
3431 break;
3432 if (pcbWritten)
3433 {
3434 cbWritten += cbWrittenSeg;
3435 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
3436 break;
3437 if (off != -1)
3438 off += cbWrittenSeg;
3439 }
3440 else if (off != -1)
3441 off += pSgBuf->paSegs[iSeg].cbSeg;
3442 }
3443
3444 if (pcbWritten)
3445 *pcbWritten = cbWritten;
3446 }
3447 RTVfsLockReleaseWrite(pThis->Base.hLock);
3448 return rc;
3449}
3450
3451
3452RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
3453{
3454 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3455 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3456 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3457
3458 RTVfsLockAcquireWrite(pThis->Base.hLock);
3459 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
3460 RTVfsLockReleaseWrite(pThis->Base.hLock);
3461 return rc;
3462}
3463
3464
3465RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3466 uint32_t *pfRetEvents)
3467{
3468 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3469 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3470 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3471
3472 RTVfsLockAcquireWrite(pThis->Base.hLock);
3473 int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
3474 RTVfsLockReleaseWrite(pThis->Base.hLock);
3475 return rc;
3476}
3477
3478
3479RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
3480{
3481 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3482 AssertPtrReturn(pThis, -1);
3483 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3484
3485 RTFOFF off;
3486 RTVfsLockAcquireRead(pThis->Base.hLock);
3487 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
3488 RTVfsLockReleaseRead(pThis->Base.hLock);
3489 if (RT_FAILURE(rc))
3490 off = rc;
3491 return off;
3492}
3493
3494
3495RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3496{
3497 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3498 AssertPtrReturn(pThis, -1);
3499 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3500 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
3501
3502 int rc;
3503 if (pThis->pOps->pfnSkip)
3504 {
3505 RTVfsLockAcquireWrite(pThis->Base.hLock);
3506 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
3507 RTVfsLockReleaseWrite(pThis->Base.hLock);
3508 }
3509 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3510 {
3511 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3512 RTFOFF offIgnored;
3513
3514 RTVfsLockAcquireWrite(pThis->Base.hLock);
3515 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
3516 RTVfsLockReleaseWrite(pThis->Base.hLock);
3517 }
3518 else
3519 {
3520 void *pvBuf = RTMemTmpAlloc(_64K);
3521 if (pvBuf)
3522 {
3523 rc = VINF_SUCCESS;
3524 while (cb > 0)
3525 {
3526 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
3527 RTVfsLockAcquireWrite(pThis->Base.hLock);
3528 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
3529 RTVfsLockReleaseWrite(pThis->Base.hLock);
3530 if (RT_FAILURE(rc))
3531 break;
3532 cb -= cbToRead;
3533 }
3534
3535 RTMemTmpFree(pvBuf);
3536 }
3537 else
3538 rc = VERR_NO_TMP_MEMORY;
3539 }
3540 return rc;
3541}
3542
3543
3544RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3545{
3546 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3547 AssertPtrReturn(pThis, -1);
3548 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3549
3550 int rc;
3551 if (pThis->pOps->pfnZeroFill)
3552 {
3553 RTVfsLockAcquireWrite(pThis->Base.hLock);
3554 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
3555 RTVfsLockReleaseWrite(pThis->Base.hLock);
3556 }
3557 else
3558 {
3559 rc = VINF_SUCCESS;
3560 while (cb > 0)
3561 {
3562 size_t cbToWrite = (size_t)RT_MIN(cb, (ssize_t)sizeof(g_abRTZero64K));
3563 RTVfsLockAcquireWrite(pThis->Base.hLock);
3564 rc = RTVfsIoStrmWrite(hVfsIos, g_abRTZero64K, cbToWrite, true /*fBlocking*/, NULL);
3565 RTVfsLockReleaseWrite(pThis->Base.hLock);
3566 if (RT_FAILURE(rc))
3567 break;
3568 cb -= cbToWrite;
3569 }
3570 }
3571 return rc;
3572}
3573
3574
3575RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
3576{
3577 /*
3578 * There is where the zero read behavior comes in handy.
3579 */
3580 char bDummy;
3581 size_t cbRead;
3582 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
3583 return rc == VINF_EOF;
3584}
3585
3586
3587
3588RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos)
3589{
3590 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3591 AssertPtrReturn(pThis, 0);
3592 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, 0);
3593 return pThis->fFlags;
3594}
3595
3596
3597
3598/*
3599 *
3600 * F I L E F I L E F I L E
3601 * F I L E F I L E F I L E
3602 * F I L E F I L E F I L E
3603 *
3604 */
3605
3606RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3607 PRTVFSFILE phVfsFile, void **ppvInstance)
3608{
3609 /*
3610 * Validate the input, be extra strict in strict builds.
3611 */
3612 AssertPtr(pFileOps);
3613 AssertReturn(pFileOps->uVersion == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3614 AssertReturn(pFileOps->uEndMarker == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3615 Assert(!pFileOps->fReserved);
3616 RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
3617 Assert(cbInstance > 0);
3618 Assert(fOpen & (RTFILE_O_ACCESS_MASK | RTFILE_O_ACCESS_ATTR_MASK));
3619 AssertPtr(ppvInstance);
3620 AssertPtr(phVfsFile);
3621 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3622
3623 /*
3624 * Allocate the handle + instance data.
3625 */
3626 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
3627 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3628 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
3629 if (!pThis)
3630 return VERR_NO_MEMORY;
3631
3632 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, false /*fNoVfsRef*/, hLock,
3633 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3634 if (RT_FAILURE(rc))
3635 {
3636 RTMemFree(pThis);
3637 return rc;
3638 }
3639
3640 pThis->uMagic = RTVFSFILE_MAGIC;
3641 pThis->fReserved = 0;
3642 pThis->pOps = pFileOps;
3643 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
3644 pThis->Stream.fFlags = fOpen;
3645 pThis->Stream.pOps = &pFileOps->Stream;
3646
3647 *phVfsFile = pThis;
3648 *ppvInstance = pThis->Stream.Base.pvThis;
3649 return VINF_SUCCESS;
3650}
3651
3652
3653RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
3654{
3655 /*
3656 * Validate input.
3657 */
3658 RTVFSINTERNAL *pThis = hVfs;
3659 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3660 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
3661 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
3662 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
3663
3664 int rc = rtFileRecalcAndValidateFlags(&fOpen);
3665 if (RT_FAILURE(rc))
3666 return rc;
3667
3668 /*
3669 * Parse the path, assume current directory is root since we've got no
3670 * caller context here.
3671 */
3672 PRTVFSPARSEDPATH pPath;
3673 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
3674 if (RT_SUCCESS(rc))
3675 {
3676 if ( !pPath->fDirSlash
3677 && pPath->cComponents > 0)
3678 {
3679 /*
3680 * Tranverse the path, resolving the parent node and any symlinks
3681 * in the final element, and ask the directory to open the file.
3682 */
3683 RTVFSDIRINTERNAL *pVfsParentDir;
3684 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
3685 if (RT_SUCCESS(rc))
3686 {
3687 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3688
3689 /** @todo there is a symlink creation race here. */
3690 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3691 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
3692 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3693
3694 RTVfsDirRelease(pVfsParentDir);
3695
3696 if (RT_SUCCESS(rc))
3697 {
3698 AssertPtr(*phVfsFile);
3699 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
3700 }
3701 }
3702 }
3703 else
3704 rc = VERR_NOT_A_FILE;
3705 RTVfsParsePathFree(pPath);
3706 }
3707 return rc;
3708}
3709
3710
3711#ifdef DEBUG
3712# undef RTVfsFileRetain
3713#endif
3714RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
3715{
3716 RTVFSFILEINTERNAL *pThis = hVfsFile;
3717 AssertPtrReturn(pThis, UINT32_MAX);
3718 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3719 return rtVfsObjRetain(&pThis->Stream.Base);
3720}
3721#ifdef DEBUG
3722# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS)
3723#endif
3724
3725
3726RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL)
3727{
3728 RTVFSFILEINTERNAL *pThis = hVfsFile;
3729 AssertPtrReturn(pThis, UINT32_MAX);
3730 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3731 return rtVfsObjRetainDebug(&pThis->Stream.Base, "RTVFsFileRetainDebug", RT_SRC_POS_ARGS);
3732}
3733
3734
3735RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
3736{
3737 RTVFSFILEINTERNAL *pThis = hVfsFile;
3738 if (pThis == NIL_RTVFSFILE)
3739 return 0;
3740 AssertPtrReturn(pThis, UINT32_MAX);
3741 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3742 return rtVfsObjRelease(&pThis->Stream.Base);
3743}
3744
3745
3746RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
3747{
3748 RTVFSFILEINTERNAL *pThis = hVfsFile;
3749 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
3750 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
3751
3752 rtVfsObjRetainVoid(&pThis->Stream.Base, "RTVfsFileToIoStream");
3753 return &pThis->Stream;
3754}
3755
3756
3757RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3758{
3759 RTVFSFILEINTERNAL *pThis = hVfsFile;
3760 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3761 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3762 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
3763}
3764
3765
3766RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3767{
3768 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3769 if (pcbRead)
3770 *pcbRead = 0;
3771 RTVFSFILEINTERNAL *pThis = hVfsFile;
3772 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3773 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3774 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3775}
3776
3777
3778RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3779{
3780 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3781 if (pcbWritten)
3782 *pcbWritten = 0;
3783 RTVFSFILEINTERNAL *pThis = hVfsFile;
3784 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3785 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3786 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3787}
3788
3789
3790RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3791{
3792 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3793 if (pcbWritten)
3794 *pcbWritten = 0;
3795 RTVFSFILEINTERNAL *pThis = hVfsFile;
3796 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3797 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3798
3799 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3800 if (RT_SUCCESS(rc))
3801 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3802
3803 return rc;
3804}
3805
3806
3807RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3808{
3809 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3810 if (pcbRead)
3811 *pcbRead = 0;
3812 RTVFSFILEINTERNAL *pThis = hVfsFile;
3813 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3814 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3815
3816 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3817 if (RT_SUCCESS(rc))
3818 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3819
3820 return rc;
3821}
3822
3823
3824RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3825{
3826 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3827 if (pcbRead)
3828 *pcbRead = 0;
3829 RTVFSFILEINTERNAL *pThis = hVfsFile;
3830 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3831 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3832
3833 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
3834}
3835
3836
3837RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3838{
3839 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3840 if (pcbWritten)
3841 *pcbWritten = 0;
3842 RTVFSFILEINTERNAL *pThis = hVfsFile;
3843 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3844 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3845
3846 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
3847}
3848
3849
3850RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
3851{
3852 RTVFSFILEINTERNAL *pThis = hVfsFile;
3853 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3854 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3855 return RTVfsIoStrmFlush(&pThis->Stream);
3856}
3857
3858
3859RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3860 uint32_t *pfRetEvents)
3861{
3862 RTVFSFILEINTERNAL *pThis = hVfsFile;
3863 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3864 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3865 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
3866}
3867
3868
3869RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
3870{
3871 RTVFSFILEINTERNAL *pThis = hVfsFile;
3872 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3873 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3874 return RTVfsIoStrmTell(&pThis->Stream);
3875}
3876
3877
3878RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
3879{
3880 RTVFSFILEINTERNAL *pThis = hVfsFile;
3881 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3882 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3883
3884 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
3885 || uMethod == RTFILE_SEEK_CURRENT
3886 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
3887 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
3888
3889 RTFOFF offActual = 0;
3890 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3891 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
3892 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3893 if (RT_SUCCESS(rc) && poffActual)
3894 {
3895 Assert(offActual >= 0);
3896 *poffActual = offActual;
3897 }
3898
3899 return rc;
3900}
3901
3902
3903RTDECL(int) RTVfsFileGetSize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
3904{
3905 RTVFSFILEINTERNAL *pThis = hVfsFile;
3906 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3907 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3908 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
3909
3910 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3911 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
3912 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3913
3914 return rc;
3915}
3916
3917
3918RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile)
3919{
3920 RTVFSFILEINTERNAL *pThis = hVfsFile;
3921 AssertPtrReturn(pThis, 0);
3922 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, 0);
3923 return pThis->Stream.fFlags;
3924}
3925
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette