VirtualBox

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

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

IPRT: Some more fat bits.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 89.3 KB
Line 
1/* $Id: vfsbase.cpp 66652 2017-04-24 09:48:49Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Base.
4 */
5
6/*
7 * Copyright (C) 2010-2016 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#include <iprt/vfs.h>
32#include <iprt/vfslowlevel.h>
33
34#include <iprt/asm.h>
35#include <iprt/err.h>
36#include <iprt/file.h>
37#include <iprt/mem.h>
38#include <iprt/param.h>
39#include <iprt/path.h>
40#include <iprt/semaphore.h>
41#include <iprt/thread.h>
42
43#include "internal/file.h"
44#include "internal/fs.h"
45#include "internal/magics.h"
46//#include "internal/vfs.h"
47
48
49/*********************************************************************************************************************************
50* Defined Constants And Macros *
51*********************************************************************************************************************************/
52/** The instance data alignment. */
53#define RTVFS_INST_ALIGNMENT 16U
54
55/** The max number of symbolic links to resolve in a path. */
56#define RTVFS_MAX_LINKS 20U
57
58
59/** Asserts that the VFS base object vtable is valid. */
60#define RTVFSOBJ_ASSERT_OPS(a_pObjOps, a_enmType) \
61 do \
62 { \
63 Assert((a_pObjOps)->uVersion == RTVFSOBJOPS_VERSION); \
64 Assert((a_pObjOps)->enmType == (a_enmType) || (a_enmType) == RTVFSOBJTYPE_INVALID); \
65 AssertPtr((a_pObjOps)->pszName); \
66 Assert(*(a_pObjOps)->pszName); \
67 AssertPtr((a_pObjOps)->pfnClose); \
68 AssertPtr((a_pObjOps)->pfnQueryInfo); \
69 Assert((a_pObjOps)->uEndMarker == RTVFSOBJOPS_VERSION); \
70 } while (0)
71
72/** Asserts that the VFS set object vtable is valid. */
73#define RTVFSOBJSET_ASSERT_OPS(a_pSetOps, a_offObjOps) \
74 do \
75 { \
76 Assert((a_pSetOps)->uVersion == RTVFSOBJSETOPS_VERSION); \
77 Assert((a_pSetOps)->offObjOps == (a_offObjOps)); \
78 AssertPtr((a_pSetOps)->pfnSetMode); \
79 AssertPtr((a_pSetOps)->pfnSetTimes); \
80 AssertPtr((a_pSetOps)->pfnSetOwner); \
81 Assert((a_pSetOps)->uEndMarker == RTVFSOBJSETOPS_VERSION); \
82 } while (0)
83
84/** Asserts that the VFS directory vtable is valid. */
85#define RTVFSDIR_ASSERT_OPS(pDirOps, a_enmType) \
86 do { \
87 RTVFSOBJ_ASSERT_OPS(&(pDirOps)->Obj, a_enmType); \
88 RTVFSOBJSET_ASSERT_OPS(&(pDirOps)->ObjSet, RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet)); \
89 Assert((pDirOps)->uVersion == RTVFSDIROPS_VERSION); \
90 Assert(!(pDirOps)->fReserved); \
91 AssertPtr((pDirOps)->pfnTraversalOpen); \
92 AssertPtr((pDirOps)->pfnOpenFile); \
93 AssertPtr((pDirOps)->pfnOpenDir); \
94 AssertPtr((pDirOps)->pfnCreateDir); \
95 AssertPtr((pDirOps)->pfnOpenSymlink); \
96 AssertPtr((pDirOps)->pfnCreateSymlink); \
97 AssertPtr((pDirOps)->pfnUnlinkEntry); \
98 AssertPtr((pDirOps)->pfnRewindDir); \
99 AssertPtr((pDirOps)->pfnReadDir); \
100 Assert((pDirOps)->uEndMarker == RTVFSDIROPS_VERSION); \
101 } while (0)
102
103/** Asserts that the VFS I/O stream vtable is valid. */
104#define RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, a_enmType) \
105 do { \
106 RTVFSOBJ_ASSERT_OPS(&(pIoStreamOps)->Obj, a_enmType); \
107 Assert((pIoStreamOps)->uVersion == RTVFSIOSTREAMOPS_VERSION); \
108 Assert(!((pIoStreamOps)->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); \
109 AssertPtr((pIoStreamOps)->pfnRead); \
110 AssertPtr((pIoStreamOps)->pfnWrite); \
111 AssertPtr((pIoStreamOps)->pfnFlush); \
112 AssertPtr((pIoStreamOps)->pfnPollOne); \
113 AssertPtr((pIoStreamOps)->pfnTell); \
114 AssertPtrNull((pIoStreamOps)->pfnSkip); \
115 AssertPtrNull((pIoStreamOps)->pfnZeroFill); \
116 Assert((pIoStreamOps)->uEndMarker == RTVFSIOSTREAMOPS_VERSION); \
117 } while (0)
118
119/** Asserts that the VFS symlink vtable is valid. */
120#define RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, a_enmType) \
121 do { \
122 RTVFSOBJ_ASSERT_OPS(&(pSymlinkOps)->Obj, a_enmType); \
123 RTVFSOBJSET_ASSERT_OPS(&(pSymlinkOps)->ObjSet, \
124 RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet)); \
125 Assert((pSymlinkOps)->uVersion == RTVFSSYMLINKOPS_VERSION); \
126 Assert(!(pSymlinkOps)->fReserved); \
127 AssertPtr((pSymlinkOps)->pfnRead); \
128 Assert((pSymlinkOps)->uEndMarker == RTVFSSYMLINKOPS_VERSION); \
129 } while (0)
130
131
132/** Validates a VFS handle and returns @a rcRet if it's invalid. */
133#define RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, rcRet) \
134 do { \
135 if ((hVfs) != NIL_RTVFS) \
136 { \
137 AssertPtrReturn((hVfs), (rcRet)); \
138 AssertReturn((hVfs)->uMagic == RTVFS_MAGIC, (rcRet)); \
139 } \
140 } while (0)
141
142
143/*********************************************************************************************************************************
144* Structures and Typedefs *
145*********************************************************************************************************************************/
146/** @todo Move all this stuff to internal/vfs.h */
147
148
149/**
150 * The VFS internal lock data.
151 */
152typedef struct RTVFSLOCKINTERNAL
153{
154 /** The number of references to the this lock. */
155 uint32_t volatile cRefs;
156 /** The lock type. */
157 RTVFSLOCKTYPE enmType;
158 /** Type specific data. */
159 union
160 {
161 /** Read/Write semaphore handle. */
162 RTSEMRW hSemRW;
163 /** Fast mutex semaphore handle. */
164 RTSEMFASTMUTEX hFastMtx;
165 /** Regular mutex semaphore handle. */
166 RTSEMMUTEX hMtx;
167 } u;
168} RTVFSLOCKINTERNAL;
169
170
171/**
172 * The VFS base object handle data.
173 *
174 * All other VFS handles are derived from this one. The final handle type is
175 * indicated by RTVFSOBJOPS::enmType via the RTVFSOBJINTERNAL::pOps member.
176 */
177typedef struct RTVFSOBJINTERNAL
178{
179 /** The VFS magic (RTVFSOBJ_MAGIC). */
180 uint32_t uMagic;
181 /** The number of references to this VFS object. */
182 uint32_t volatile cRefs;
183 /** Pointer to the instance data. */
184 void *pvThis;
185 /** The vtable. */
186 PCRTVFSOBJOPS pOps;
187 /** The lock protecting all access to the VFS.
188 * Only valid RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTVFSLOCK. */
189 RTVFSLOCK hLock;
190 /** Reference back to the VFS containing this object. */
191 RTVFS hVfs;
192} RTVFSOBJINTERNAL;
193
194
195/**
196 * The VFS filesystem stream handle data.
197 *
198 * @extends RTVFSOBJINTERNAL
199 */
200typedef struct RTVFSFSSTREAMINTERNAL
201{
202 /** The VFS magic (RTVFSFSTREAM_MAGIC). */
203 uint32_t uMagic;
204 /** File open flags, at a minimum the access mask. */
205 uint32_t fFlags;
206 /** The vtable. */
207 PCRTVFSFSSTREAMOPS pOps;
208 /** The base object handle data. */
209 RTVFSOBJINTERNAL Base;
210} RTVFSFSSTREAMINTERNAL;
211
212
213/**
214 * The VFS handle data.
215 *
216 * @extends RTVFSOBJINTERNAL
217 */
218typedef struct RTVFSINTERNAL
219{
220 /** The VFS magic (RTVFS_MAGIC). */
221 uint32_t uMagic;
222 /** Creation flags (RTVFS_C_XXX). */
223 uint32_t fFlags;
224 /** The vtable. */
225 PCRTVFSOPS pOps;
226 /** The base object handle data. */
227 RTVFSOBJINTERNAL Base;
228} RTVFSINTERNAL;
229
230
231/**
232 * The VFS directory handle data.
233 *
234 * @extends RTVFSOBJINTERNAL
235 */
236typedef struct RTVFSDIRINTERNAL
237{
238 /** The VFS magic (RTVFSDIR_MAGIC). */
239 uint32_t uMagic;
240 /** Reserved for flags or something. */
241 uint32_t fReserved;
242 /** The vtable. */
243 PCRTVFSDIROPS pOps;
244 /** The base object handle data. */
245 RTVFSOBJINTERNAL Base;
246} RTVFSDIRINTERNAL;
247
248
249/**
250 * The VFS symbolic link handle data.
251 *
252 * @extends RTVFSOBJINTERNAL
253 */
254typedef struct RTVFSSYMLINKINTERNAL
255{
256 /** The VFS magic (RTVFSSYMLINK_MAGIC). */
257 uint32_t uMagic;
258 /** Reserved for flags or something. */
259 uint32_t fReserved;
260 /** The vtable. */
261 PCRTVFSSYMLINKOPS pOps;
262 /** The base object handle data. */
263 RTVFSOBJINTERNAL Base;
264} RTVFSSYMLINKINTERNAL;
265
266
267/**
268 * The VFS I/O stream handle data.
269 *
270 * This is often part of a type specific handle, like a file or pipe.
271 *
272 * @extends RTVFSOBJINTERNAL
273 */
274typedef struct RTVFSIOSTREAMINTERNAL
275{
276 /** The VFS magic (RTVFSIOSTREAM_MAGIC). */
277 uint32_t uMagic;
278 /** File open flags, at a minimum the access mask. */
279 uint32_t fFlags;
280 /** The vtable. */
281 PCRTVFSIOSTREAMOPS pOps;
282 /** The base object handle data. */
283 RTVFSOBJINTERNAL Base;
284} RTVFSIOSTREAMINTERNAL;
285
286
287/**
288 * The VFS file handle data.
289 *
290 * @extends RTVFSIOSTREAMINTERNAL
291 */
292typedef struct RTVFSFILEINTERNAL
293{
294 /** The VFS magic (RTVFSFILE_MAGIC). */
295 uint32_t uMagic;
296 /** Reserved for flags or something. */
297 uint32_t fReserved;
298 /** The vtable. */
299 PCRTVFSFILEOPS pOps;
300 /** The stream handle data. */
301 RTVFSIOSTREAMINTERNAL Stream;
302} RTVFSFILEINTERNAL;
303
304#if 0 /* later */
305
306/**
307 * The VFS pipe handle data.
308 *
309 * @extends RTVFSIOSTREAMINTERNAL
310 */
311typedef struct RTVFSPIPEINTERNAL
312{
313 /** The VFS magic (RTVFSPIPE_MAGIC). */
314 uint32_t uMagic;
315 /** Reserved for flags or something. */
316 uint32_t fReserved;
317 /** The vtable. */
318 PCRTVFSPIPEOPS pOps;
319 /** The stream handle data. */
320 RTVFSIOSTREAMINTERNAL Stream;
321} RTVFSPIPEINTERNAL;
322
323
324/**
325 * The VFS socket handle data.
326 *
327 * @extends RTVFSIOSTREAMINTERNAL
328 */
329typedef struct RTVFSSOCKETINTERNAL
330{
331 /** The VFS magic (RTVFSSOCKET_MAGIC). */
332 uint32_t uMagic;
333 /** Reserved for flags or something. */
334 uint32_t fReserved;
335 /** The vtable. */
336 PCRTVFSSOCKETOPS pOps;
337 /** The stream handle data. */
338 RTVFSIOSTREAMINTERNAL Stream;
339} RTVFSSOCKETINTERNAL;
340
341#endif /* later */
342
343
344
345/*
346 *
347 * V F S L o c k A b s t r a c t i o n
348 * V F S L o c k A b s t r a c t i o n
349 * V F S L o c k A b s t r a c t i o n
350 *
351 *
352 */
353
354
355RTDECL(uint32_t) RTVfsLockRetain(RTVFSLOCK hLock)
356{
357 RTVFSLOCKINTERNAL *pThis = hLock;
358 AssertPtrReturn(pThis, UINT32_MAX);
359 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
360
361 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
362 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
363 return cRefs;
364}
365
366
367/**
368 * Destroys a VFS lock handle.
369 *
370 * @param pThis The lock to destroy.
371 */
372static void rtVfsLockDestroy(RTVFSLOCKINTERNAL *pThis)
373{
374 switch (pThis->enmType)
375 {
376 case RTVFSLOCKTYPE_RW:
377 RTSemRWDestroy(pThis->u.hSemRW);
378 pThis->u.hSemRW = NIL_RTSEMRW;
379 break;
380
381 case RTVFSLOCKTYPE_FASTMUTEX:
382 RTSemFastMutexDestroy(pThis->u.hFastMtx);
383 pThis->u.hFastMtx = NIL_RTSEMFASTMUTEX;
384 break;
385
386 case RTVFSLOCKTYPE_MUTEX:
387 RTSemMutexDestroy(pThis->u.hMtx);
388 pThis->u.hFastMtx = NIL_RTSEMMUTEX;
389 break;
390
391 default:
392 AssertMsgFailedReturnVoid(("%p %d\n", pThis, pThis->enmType));
393 }
394
395 pThis->enmType = RTVFSLOCKTYPE_INVALID;
396 RTMemFree(pThis);
397}
398
399
400RTDECL(uint32_t) RTVfsLockRelease(RTVFSLOCK hLock)
401{
402 RTVFSLOCKINTERNAL *pThis = hLock;
403 if (pThis == NIL_RTVFSLOCK)
404 return 0;
405 AssertPtrReturn(pThis, UINT32_MAX);
406 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
407
408 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
409 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
410 if (cRefs == 0)
411 rtVfsLockDestroy(pThis);
412 return cRefs;
413}
414
415
416/**
417 * Creates a read/write lock.
418 *
419 * @returns IPRT status code
420 * @param phLock Where to return the lock handle.
421 */
422static int rtVfsLockCreateRW(PRTVFSLOCK phLock)
423{
424 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
425 if (!pThis)
426 return VERR_NO_MEMORY;
427
428 pThis->cRefs = 1;
429 pThis->enmType = RTVFSLOCKTYPE_RW;
430
431 int rc = RTSemRWCreate(&pThis->u.hSemRW);
432 if (RT_FAILURE(rc))
433 {
434 RTMemFree(pThis);
435 return rc;
436 }
437
438 *phLock = pThis;
439 return VINF_SUCCESS;
440}
441
442
443/**
444 * Creates a fast mutex lock.
445 *
446 * @returns IPRT status code
447 * @param phLock Where to return the lock handle.
448 */
449static int rtVfsLockCreateFastMutex(PRTVFSLOCK phLock)
450{
451 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
452 if (!pThis)
453 return VERR_NO_MEMORY;
454
455 pThis->cRefs = 1;
456 pThis->enmType = RTVFSLOCKTYPE_FASTMUTEX;
457
458 int rc = RTSemFastMutexCreate(&pThis->u.hFastMtx);
459 if (RT_FAILURE(rc))
460 {
461 RTMemFree(pThis);
462 return rc;
463 }
464
465 *phLock = pThis;
466 return VINF_SUCCESS;
467
468}
469
470
471/**
472 * Creates a mutex lock.
473 *
474 * @returns IPRT status code
475 * @param phLock Where to return the lock handle.
476 */
477static int rtVfsLockCreateMutex(PRTVFSLOCK phLock)
478{
479 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
480 if (!pThis)
481 return VERR_NO_MEMORY;
482
483 pThis->cRefs = 1;
484 pThis->enmType = RTVFSLOCKTYPE_MUTEX;
485
486 int rc = RTSemMutexCreate(&pThis->u.hMtx);
487 if (RT_FAILURE(rc))
488 {
489 RTMemFree(pThis);
490 return rc;
491 }
492
493 *phLock = pThis;
494 return VINF_SUCCESS;
495}
496
497
498/**
499 * Acquires the lock for reading.
500 *
501 * @param hLock Non-nil lock handle.
502 * @internal
503 */
504RTDECL(void) RTVfsLockAcquireReadSlow(RTVFSLOCK hLock)
505{
506 RTVFSLOCKINTERNAL *pThis = hLock;
507 int rc;
508
509 AssertPtr(pThis);
510 switch (pThis->enmType)
511 {
512 case RTVFSLOCKTYPE_RW:
513 rc = RTSemRWRequestRead(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
514 AssertRC(rc);
515 break;
516
517 case RTVFSLOCKTYPE_FASTMUTEX:
518 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
519 AssertRC(rc);
520 break;
521
522 case RTVFSLOCKTYPE_MUTEX:
523 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
524 AssertRC(rc);
525 break;
526 default:
527 AssertFailed();
528 }
529}
530
531
532/**
533 * Release a lock held for reading.
534 *
535 * @param hLock Non-nil lock handle.
536 * @internal
537 */
538RTDECL(void) RTVfsLockReleaseReadSlow(RTVFSLOCK hLock)
539{
540 RTVFSLOCKINTERNAL *pThis = hLock;
541 int rc;
542
543 AssertPtr(pThis);
544 switch (pThis->enmType)
545 {
546 case RTVFSLOCKTYPE_RW:
547 rc = RTSemRWReleaseRead(pThis->u.hSemRW);
548 AssertRC(rc);
549 break;
550
551 case RTVFSLOCKTYPE_FASTMUTEX:
552 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
553 AssertRC(rc);
554 break;
555
556 case RTVFSLOCKTYPE_MUTEX:
557 rc = RTSemMutexRelease(pThis->u.hMtx);
558 AssertRC(rc);
559 break;
560 default:
561 AssertFailed();
562 }
563}
564
565
566/**
567 * Acquires the lock for writing.
568 *
569 * @param hLock Non-nil lock handle.
570 * @internal
571 */
572RTDECL(void) RTVfsLockAcquireWriteSlow(RTVFSLOCK hLock)
573{
574 RTVFSLOCKINTERNAL *pThis = hLock;
575 int rc;
576
577 AssertPtr(pThis);
578 switch (pThis->enmType)
579 {
580 case RTVFSLOCKTYPE_RW:
581 rc = RTSemRWRequestWrite(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
582 AssertRC(rc);
583 break;
584
585 case RTVFSLOCKTYPE_FASTMUTEX:
586 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
587 AssertRC(rc);
588 break;
589
590 case RTVFSLOCKTYPE_MUTEX:
591 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
592 AssertRC(rc);
593 break;
594 default:
595 AssertFailed();
596 }
597}
598
599
600/**
601 * Release a lock held for writing.
602 *
603 * @param hLock Non-nil lock handle.
604 * @internal
605 */
606RTDECL(void) RTVfsLockReleaseWriteSlow(RTVFSLOCK hLock)
607{
608 RTVFSLOCKINTERNAL *pThis = hLock;
609 int rc;
610
611 AssertPtr(pThis);
612 switch (pThis->enmType)
613 {
614 case RTVFSLOCKTYPE_RW:
615 rc = RTSemRWReleaseWrite(pThis->u.hSemRW);
616 AssertRC(rc);
617 break;
618
619 case RTVFSLOCKTYPE_FASTMUTEX:
620 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
621 AssertRC(rc);
622 break;
623
624 case RTVFSLOCKTYPE_MUTEX:
625 rc = RTSemMutexRelease(pThis->u.hMtx);
626 AssertRC(rc);
627 break;
628 default:
629 AssertFailed();
630 }
631}
632
633
634
635/*
636 *
637 * B A S E O B J E C T
638 * B A S E O B J E C T
639 * B A S E O B J E C T
640 *
641 */
642
643/**
644 * Internal object retainer that asserts sanity in strict builds.
645 *
646 * @param pThis The base object handle data.
647 */
648DECLINLINE(void) rtVfsObjRetainVoid(RTVFSOBJINTERNAL *pThis)
649{
650 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
651 AssertMsg(cRefs > 1 && cRefs < _1M,
652 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
653 NOREF(cRefs);
654}
655
656
657/**
658 * Initializes the base object part of a new object.
659 *
660 * @returns IPRT status code.
661 * @param pThis Pointer to the base object part.
662 * @param pObjOps The base object vtable.
663 * @param hVfs The VFS handle to associate with.
664 * @param hLock The lock handle, pseudo handle or nil.
665 * @param pvThis Pointer to the private data.
666 */
667static int rtVfsObjInitNewObject(RTVFSOBJINTERNAL *pThis, PCRTVFSOBJOPS pObjOps, RTVFS hVfs, RTVFSLOCK hLock, void *pvThis)
668{
669 /*
670 * Deal with the lock first as that's the most complicated matter.
671 */
672 if (hLock != NIL_RTVFSLOCK)
673 {
674 int rc;
675 if (hLock == RTVFSLOCK_CREATE_RW)
676 {
677 rc = rtVfsLockCreateRW(&hLock);
678 AssertRCReturn(rc, rc);
679 }
680 else if (hLock == RTVFSLOCK_CREATE_FASTMUTEX)
681 {
682 rc = rtVfsLockCreateFastMutex(&hLock);
683 AssertRCReturn(rc, rc);
684 }
685 else if (hLock == RTVFSLOCK_CREATE_MUTEX)
686 {
687 rc = rtVfsLockCreateMutex(&hLock);
688 AssertRCReturn(rc, rc);
689 }
690 else
691 {
692 /*
693 * The caller specified a lock, we consume the this reference.
694 */
695 AssertPtrReturn(hLock, VERR_INVALID_HANDLE);
696 AssertReturn(hLock->enmType > RTVFSLOCKTYPE_INVALID && hLock->enmType < RTVFSLOCKTYPE_END, VERR_INVALID_HANDLE);
697 AssertReturn(hLock->cRefs > 0, VERR_INVALID_HANDLE);
698 }
699 }
700 else if (hVfs != NIL_RTVFS)
701 {
702 /*
703 * Retain a reference to the VFS lock, if there is one.
704 */
705 hLock = hVfs->Base.hLock;
706 if (hLock != NIL_RTVFSLOCK)
707 {
708 uint32_t cRefs = RTVfsLockRetain(hLock);
709 if (RT_UNLIKELY(cRefs == UINT32_MAX))
710 return VERR_INVALID_HANDLE;
711 }
712 }
713
714
715 /*
716 * Do the actual initializing.
717 */
718 pThis->uMagic = RTVFSOBJ_MAGIC;
719 pThis->pvThis = pvThis;
720 pThis->pOps = pObjOps;
721 pThis->cRefs = 1;
722 pThis->hVfs = hVfs;
723 pThis->hLock = hLock;
724 if (hVfs != NIL_RTVFS)
725 rtVfsObjRetainVoid(&hVfs->Base);
726
727 return VINF_SUCCESS;
728}
729
730
731RTDECL(int) RTVfsNewBaseObj(PCRTVFSOBJOPS pObjOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
732 PRTVFSOBJ phVfsObj, void **ppvInstance)
733{
734 /*
735 * Validate the input, be extra strict in strict builds.
736 */
737 AssertPtr(pObjOps);
738 AssertReturn(pObjOps->uVersion == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
739 AssertReturn(pObjOps->uEndMarker == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
740 RTVFSOBJ_ASSERT_OPS(pObjOps, RTVFSOBJTYPE_BASE);
741 Assert(cbInstance > 0);
742 AssertPtr(ppvInstance);
743 AssertPtr(phVfsObj);
744 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
745
746 /*
747 * Allocate the handle + instance data.
748 */
749 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSOBJINTERNAL), RTVFS_INST_ALIGNMENT)
750 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
751 RTVFSOBJINTERNAL *pThis = (RTVFSOBJINTERNAL *)RTMemAllocZ(cbThis);
752 if (!pThis)
753 return VERR_NO_MEMORY;
754
755 int rc = rtVfsObjInitNewObject(pThis, pObjOps, hVfs, hLock,
756 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
757 if (RT_FAILURE(rc))
758 {
759 RTMemFree(pThis);
760 return rc;
761 }
762
763 *phVfsObj = pThis;
764 *ppvInstance = pThis->pvThis;
765 return VINF_SUCCESS;
766}
767
768
769/**
770 * Internal object retainer that asserts sanity in strict builds.
771 *
772 * @returns The new reference count.
773 * @param pThis The base object handle data.
774 */
775DECLINLINE(uint32_t) rtVfsObjRetain(RTVFSOBJINTERNAL *pThis)
776{
777 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
778 AssertMsg(cRefs > 1 && cRefs < _1M,
779 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
780 return cRefs;
781}
782
783
784RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj)
785{
786 RTVFSOBJINTERNAL *pThis = hVfsObj;
787 AssertPtrReturn(pThis, UINT32_MAX);
788 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
789
790 return rtVfsObjRetain(pThis);
791}
792
793
794/**
795 * Does the actual object destruction for rtVfsObjRelease().
796 *
797 * @param pThis The object to destroy.
798 */
799static void rtVfsObjDestroy(RTVFSOBJINTERNAL *pThis)
800{
801 RTVFSOBJTYPE const enmType = pThis->pOps->enmType;
802
803 /*
804 * Invalidate the object.
805 */
806 RTVfsLockAcquireWrite(pThis->hLock); /* paranoia */
807 void *pvToFree = NULL;
808 switch (enmType)
809 {
810 case RTVFSOBJTYPE_BASE:
811 pvToFree = pThis;
812 break;
813
814 case RTVFSOBJTYPE_VFS:
815 pvToFree = RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
816 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)->uMagic, RTVFS_MAGIC_DEAD);
817 break;
818
819 case RTVFSOBJTYPE_FS_STREAM:
820 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
821 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base)->uMagic, RTVFSFSSTREAM_MAGIC_DEAD);
822 break;
823
824 case RTVFSOBJTYPE_IO_STREAM:
825 pvToFree = RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
826 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
827 break;
828
829 case RTVFSOBJTYPE_DIR:
830 pvToFree = RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
831 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->uMagic, RTVFSDIR_MAGIC_DEAD);
832 break;
833
834 case RTVFSOBJTYPE_FILE:
835 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
836 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->uMagic, RTVFSFILE_MAGIC_DEAD);
837 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
838 break;
839
840 case RTVFSOBJTYPE_SYMLINK:
841 pvToFree = RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
842 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
843 break;
844
845 case RTVFSOBJTYPE_INVALID:
846 case RTVFSOBJTYPE_END:
847 case RTVFSOBJTYPE_32BIT_HACK:
848 AssertMsgFailed(("enmType=%d ops=%p %s\n", enmType, pThis->pOps, pThis->pOps->pszName));
849 break;
850 /* no default as we want gcc warnings. */
851 }
852 ASMAtomicWriteU32(&pThis->uMagic, RTVFSOBJ_MAGIC_DEAD);
853 RTVfsLockReleaseWrite(pThis->hLock);
854
855 /*
856 * Close the object and free the handle.
857 */
858 int rc = pThis->pOps->pfnClose(pThis->pvThis);
859 AssertRC(rc);
860 RTMemFree(pvToFree);
861}
862
863
864/**
865 * Internal object releaser that asserts sanity in strict builds.
866 *
867 * @returns The new reference count.
868 * @param pcRefs The reference counter.
869 */
870DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis)
871{
872 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
873 AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
874 if (cRefs == 0)
875 rtVfsObjDestroy(pThis);
876 return cRefs;
877}
878
879
880RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj)
881{
882 RTVFSOBJINTERNAL *pThis = hVfsObj;
883 if (pThis == NIL_RTVFSOBJ)
884 return 0;
885 AssertPtrReturn(pThis, UINT32_MAX);
886 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
887 return rtVfsObjRelease(pThis);
888}
889
890
891RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj)
892{
893 RTVFSOBJINTERNAL *pThis = hVfsObj;
894 if (pThis != NIL_RTVFSOBJ)
895 {
896 AssertPtrReturn(pThis, NIL_RTVFS);
897 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFS);
898
899 if (pThis->pOps->enmType == RTVFSOBJTYPE_VFS)
900 {
901 rtVfsObjRetainVoid(pThis);
902 return RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
903 }
904 }
905 return NIL_RTVFS;
906}
907
908
909RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj)
910{
911 RTVFSOBJINTERNAL *pThis = hVfsObj;
912 if (pThis != NIL_RTVFSOBJ)
913 {
914 AssertPtrReturn(pThis, NIL_RTVFSFSSTREAM);
915 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFSSTREAM);
916
917 if (pThis->pOps->enmType == RTVFSOBJTYPE_FS_STREAM)
918 {
919 rtVfsObjRetainVoid(pThis);
920 return RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
921 }
922 }
923 return NIL_RTVFSFSSTREAM;
924}
925
926
927RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj)
928{
929 RTVFSOBJINTERNAL *pThis = hVfsObj;
930 if (pThis != NIL_RTVFSOBJ)
931 {
932 AssertPtrReturn(pThis, NIL_RTVFSDIR);
933 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSDIR);
934
935 if (pThis->pOps->enmType == RTVFSOBJTYPE_DIR)
936 {
937 rtVfsObjRetainVoid(pThis);
938 return RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
939 }
940 }
941 return NIL_RTVFSDIR;
942}
943
944
945RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj)
946{
947 RTVFSOBJINTERNAL *pThis = hVfsObj;
948 if (pThis != NIL_RTVFSOBJ)
949 {
950 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
951 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSIOSTREAM);
952
953 if ( pThis->pOps->enmType == RTVFSOBJTYPE_IO_STREAM
954 || pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
955 {
956 rtVfsObjRetainVoid(pThis);
957 return RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
958 }
959 }
960 return NIL_RTVFSIOSTREAM;
961}
962
963
964RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj)
965{
966 RTVFSOBJINTERNAL *pThis = hVfsObj;
967 if (pThis != NIL_RTVFSOBJ)
968 {
969 AssertPtrReturn(pThis, NIL_RTVFSFILE);
970 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFILE);
971
972 if (pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
973 {
974 rtVfsObjRetainVoid(pThis);
975 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
976 }
977 }
978 return NIL_RTVFSFILE;
979}
980
981
982RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj)
983{
984 RTVFSOBJINTERNAL *pThis = hVfsObj;
985 if (pThis != NIL_RTVFSOBJ)
986 {
987 AssertPtrReturn(pThis, NIL_RTVFSSYMLINK);
988 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSSYMLINK);
989
990 if (pThis->pOps->enmType == RTVFSOBJTYPE_SYMLINK)
991 {
992 rtVfsObjRetainVoid(pThis);
993 return RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
994 }
995 }
996 return NIL_RTVFSSYMLINK;
997}
998
999
1000RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs)
1001{
1002 if (hVfs != NIL_RTVFS)
1003 {
1004 RTVFSOBJINTERNAL *pThis = &hVfs->Base;
1005 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1006 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1007
1008 rtVfsObjRetainVoid(pThis);
1009 return pThis;
1010 }
1011 return NIL_RTVFSOBJ;
1012}
1013
1014
1015RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss)
1016{
1017 if (hVfsFss != NIL_RTVFSFSSTREAM)
1018 {
1019 RTVFSOBJINTERNAL *pThis = &hVfsFss->Base;
1020 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1021 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1022
1023 rtVfsObjRetainVoid(pThis);
1024 return pThis;
1025 }
1026 return NIL_RTVFSOBJ;
1027}
1028
1029
1030RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir)
1031{
1032 if (hVfsDir != NIL_RTVFSDIR)
1033 {
1034 RTVFSOBJINTERNAL *pThis = &hVfsDir->Base;
1035 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1036 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1037
1038 rtVfsObjRetainVoid(pThis);
1039 return pThis;
1040 }
1041 return NIL_RTVFSOBJ;
1042}
1043
1044
1045RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos)
1046{
1047 if (hVfsIos != NIL_RTVFSIOSTREAM)
1048 {
1049 RTVFSOBJINTERNAL *pThis = &hVfsIos->Base;
1050 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1051 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1052
1053 rtVfsObjRetainVoid(pThis);
1054 return pThis;
1055 }
1056 return NIL_RTVFSOBJ;
1057}
1058
1059
1060RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile)
1061{
1062 if (hVfsFile != NIL_RTVFSFILE)
1063 {
1064 RTVFSOBJINTERNAL *pThis = &hVfsFile->Stream.Base;
1065 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1066 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1067
1068 rtVfsObjRetainVoid(pThis);
1069 return pThis;
1070 }
1071 return NIL_RTVFSOBJ;
1072}
1073
1074
1075RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym)
1076{
1077 if (hVfsSym != NIL_RTVFSSYMLINK)
1078 {
1079 RTVFSOBJINTERNAL *pThis = &hVfsSym->Base;
1080 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1081 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1082
1083 rtVfsObjRetainVoid(pThis);
1084 return pThis;
1085 }
1086 return NIL_RTVFSOBJ;
1087}
1088
1089
1090
1091RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1092{
1093 RTVFSOBJINTERNAL *pThis = hVfsObj;
1094 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1095 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1096
1097 RTVfsLockAcquireRead(pThis->hLock);
1098 int rc = pThis->pOps->pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
1099 RTVfsLockReleaseRead(pThis->hLock);
1100 return rc;
1101}
1102
1103
1104
1105/*
1106 *
1107 * U T I L U T I L U T I L
1108 * U T I L U T I L U T I L
1109 * U T I L U T I L U T I L
1110 *
1111 */
1112
1113
1114
1115/**
1116 * Removes dots from the path.
1117 *
1118 * @returns The new @a pszDst value.
1119 * @param pPath The path parsing buffer.
1120 * @param pszDst The current szPath position. This will be
1121 * updated and returned.
1122 * @param fTheEnd Indicates whether we're at the end of the path
1123 * or not.
1124 * @param piRestartComp The component to restart parsing at.
1125 */
1126static char *rtVfsParsePathHandleDots(PRTVFSPARSEDPATH pPath, char *pszDst, bool fTheEnd, uint16_t *piRestartComp)
1127{
1128 if (pszDst[-1] != '.')
1129 return pszDst;
1130
1131 if (pszDst[-2] == '/')
1132 {
1133 pPath->cComponents--;
1134 pszDst = &pPath->szPath[pPath->aoffComponents[pPath->cComponents]];
1135 }
1136 else if (pszDst[-2] == '.' && pszDst[-3] == '/')
1137 {
1138 pPath->cComponents -= pPath->cComponents > 1 ? 2 : 1;
1139 pszDst = &pPath->szPath[pPath->aoffComponents[pPath->cComponents]];
1140 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1141 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1142 }
1143 else
1144 return pszDst;
1145
1146 /*
1147 * Drop the trailing slash if we're at the end of the source path.
1148 */
1149 if (fTheEnd && pPath->cComponents == 0)
1150 pszDst--;
1151 return pszDst;
1152}
1153
1154
1155RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
1156{
1157 AssertReturn(*pszPath != '/', VERR_INTERNAL_ERROR_4);
1158
1159 /* In case *piRestartComp was set higher than the number of components
1160 before making the call to this function. */
1161 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1162 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1163
1164 /*
1165 * Append a slash to the destination path if necessary.
1166 */
1167 char *pszDst = &pPath->szPath[pPath->cch];
1168 if (pPath->cComponents > 0)
1169 {
1170 *pszDst++ = '/';
1171 if (pszDst - &pPath->szPath[0] >= RTVFSPARSEDPATH_MAX)
1172 return VERR_FILENAME_TOO_LONG;
1173 }
1174 Assert(pszDst[-1] == '/');
1175
1176 /*
1177 * Parse and append the relative path.
1178 */
1179 const char *pszSrc = pszPath;
1180 pPath->fDirSlash = false;
1181 while (pszSrc[0])
1182 {
1183 /* Skip unncessary slashes. */
1184 while (pszSrc[0] == '/')
1185 pszSrc++;
1186
1187 /* Copy until we encounter the next slash. */
1188 pPath->aoffComponents[pPath->cComponents++] = pszDst - &pPath->szPath[0];
1189 while (pszSrc[0])
1190 {
1191 if (pszSrc[0] == '/')
1192 {
1193 pszSrc++;
1194 if (pszSrc[0])
1195 *pszDst++ = '/';
1196 else
1197 pPath->fDirSlash = true;
1198 pszDst = rtVfsParsePathHandleDots(pPath, pszDst, pszSrc[0] == '\0', piRestartComp);
1199 break;
1200 }
1201
1202 *pszDst++ = *pszSrc++;
1203 if (pszDst - &pPath->szPath[0] >= RTVFSPARSEDPATH_MAX)
1204 return VERR_FILENAME_TOO_LONG;
1205 }
1206 }
1207 pszDst = rtVfsParsePathHandleDots(pPath, pszDst, true /*fTheEnd*/, piRestartComp);
1208
1209 /* Terminate the string and enter its length. */
1210 pszDst[0] = '\0';
1211 pszDst[1] = '\0'; /* for aoffComponents */
1212 pPath->cch = (uint16_t)(pszDst - &pPath->szPath[0]);
1213 pPath->aoffComponents[pPath->cComponents] = pPath->cch + 1;
1214
1215 return VINF_SUCCESS;
1216}
1217
1218
1219/** @todo Replace RTVfsParsePath with RTPathParse and friends? */
1220RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
1221{
1222 if (*pszPath != '/')
1223 {
1224 /*
1225 * Relative, recurse and parse pszCwd first.
1226 */
1227 int rc = RTVfsParsePath(pPath, pszCwd, NULL /*crash if pszCwd is not absolute*/);
1228 if (RT_FAILURE(rc))
1229 return rc;
1230 }
1231 else
1232 {
1233 /*
1234 * Make pszPath relative, i.e. set up pPath for the root and skip
1235 * leading slashes in pszPath before appending it.
1236 */
1237 pPath->cch = 1;
1238 pPath->cComponents = 0;
1239 pPath->fDirSlash = false;
1240 pPath->aoffComponents[0] = 1;
1241 pPath->aoffComponents[1] = 2;
1242 pPath->szPath[0] = '/';
1243 pPath->szPath[1] = '\0';
1244 pPath->szPath[2] = '\0';
1245 while (pszPath[0] == '/')
1246 pszPath++;
1247 if (!pszPath[0])
1248 return VINF_SUCCESS;
1249 }
1250 return RTVfsParsePathAppend(pPath, pszPath, NULL);
1251}
1252
1253
1254
1255RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath)
1256{
1257 /*
1258 * Allocate the output buffer and hand the problem to rtVfsParsePath.
1259 */
1260 int rc;
1261 PRTVFSPARSEDPATH pPath = (PRTVFSPARSEDPATH)RTMemTmpAlloc(sizeof(RTVFSPARSEDPATH));
1262 if (pPath)
1263 {
1264 rc = RTVfsParsePath(pPath, pszPath, pszCwd);
1265 if (RT_FAILURE(rc))
1266 {
1267 RTMemTmpFree(pPath);
1268 pPath = NULL;
1269 }
1270 }
1271 else
1272 rc = VERR_NO_TMP_MEMORY;
1273 *ppPath = pPath; /* always set it */
1274 return rc;
1275}
1276
1277
1278RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath)
1279{
1280 if (pPath)
1281 {
1282 pPath->cch = UINT16_MAX;
1283 pPath->cComponents = UINT16_MAX;
1284 pPath->aoffComponents[0] = UINT16_MAX;
1285 pPath->aoffComponents[1] = UINT16_MAX;
1286 RTMemTmpFree(pPath);
1287 }
1288}
1289
1290
1291/**
1292 * Handles a symbolic link, adding it to
1293 *
1294 * @returns IPRT status code.
1295 * @param pPath The parsed path to update.
1296 * @param piComponent The component iterator to update.
1297 * @param hSymlink The symbolic link to process.
1298 */
1299static int rtVfsTraverseHandleSymlink(PRTVFSPARSEDPATH pPath, uint16_t *piComponent, RTVFSSYMLINK hSymlink)
1300{
1301 /*
1302 * Read the link.
1303 */
1304 char szPath[RTPATH_MAX];
1305 int rc = RTVfsSymlinkRead(hSymlink, szPath, sizeof(szPath) - 1);
1306 if (RT_SUCCESS(rc))
1307 {
1308 szPath[sizeof(szPath) - 1] = '\0';
1309 if (szPath[0] == '/')
1310 {
1311 /*
1312 * Absolute symlink.
1313 */
1314 rc = RTVfsParsePath(pPath, szPath, NULL);
1315 if (RT_SUCCESS(rc))
1316 {
1317 *piComponent = 0;
1318 return VINF_SUCCESS;
1319 }
1320 }
1321 else
1322 {
1323 /*
1324 * Relative symlink, must replace the current component with the
1325 * link value. We do that by using the remainder of the symlink
1326 * buffer as temporary storage.
1327 */
1328 uint16_t iComponent = *piComponent;
1329 if (iComponent + 1 < pPath->cComponents)
1330 rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iComponent + 1]]);
1331 if (RT_SUCCESS(rc))
1332 {
1333 pPath->cch = pPath->aoffComponents[iComponent] - (iComponent > 0);
1334 pPath->aoffComponents[iComponent + 1] = pPath->cch + 1;
1335 pPath->szPath[pPath->cch] = '\0';
1336 pPath->szPath[pPath->cch + 1] = '\0';
1337
1338 rc = RTVfsParsePathAppend(pPath, szPath, &iComponent);
1339 if (RT_SUCCESS(rc))
1340 {
1341 *piComponent = iComponent;
1342 return VINF_SUCCESS;
1343 }
1344 }
1345 }
1346 }
1347 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
1348}
1349
1350
1351/**
1352 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1353 *
1354 * @returns IPRT status code.
1355 * @param pThis The VFS.
1356 * @param pPath The parsed path. This may be changed as symbolic
1357 * links are processed during the path traversal.
1358 * @param fFollowSymlink Whether to follow the final component if it is a
1359 * symbolic link.
1360 * @param ppVfsParentDir Where to return the parent directory handle
1361 * (referenced).
1362 */
1363static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, bool fFollowSymlink,
1364 RTVFSDIRINTERNAL **ppVfsParentDir)
1365{
1366 /*
1367 * Assert sanity.
1368 */
1369 AssertPtr(pThis);
1370 Assert(pThis->uMagic == RTVFSDIR_MAGIC);
1371 Assert(pThis->Base.cRefs > 0);
1372 AssertPtr(pPath);
1373 AssertPtr(ppVfsParentDir);
1374 *ppVfsParentDir = NULL;
1375 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1376
1377 /*
1378 * Start with the pThis directory.
1379 */
1380 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1381 return VERR_INVALID_HANDLE;
1382 RTVFSDIRINTERNAL *pCurDir = pThis;
1383
1384 /*
1385 * The traversal loop.
1386 */
1387 int rc = VINF_SUCCESS;
1388 unsigned cLinks = 0;
1389 uint16_t iComponent = 0;
1390 for (;;)
1391 {
1392 /*
1393 * Are we done yet?
1394 */
1395 bool fFinal = iComponent + 1 >= pPath->cComponents;
1396 if (fFinal && !fFollowSymlink)
1397 {
1398 *ppVfsParentDir = pCurDir;
1399 return VINF_SUCCESS;
1400 }
1401
1402 /*
1403 * Try open the next entry.
1404 */
1405 const char *pszEntry = &pPath->szPath[pPath->aoffComponents[iComponent]];
1406 char *pszEntryEnd = &pPath->szPath[pPath->aoffComponents[iComponent + 1] - 1];
1407 *pszEntryEnd = '\0';
1408 RTVFSDIR hDir = NIL_RTVFSDIR;
1409 RTVFSSYMLINK hSymlink = NIL_RTVFSSYMLINK;
1410 RTVFS hVfsMnt = NIL_RTVFS;
1411 if (fFinal)
1412 {
1413 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1414 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, NULL, &hSymlink, NULL);
1415 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1416 *pszEntryEnd = '\0';
1417 if ( rc == VERR_PATH_NOT_FOUND
1418 || rc == VERR_NOT_A_DIRECTORY)
1419 rc = VINF_SUCCESS;
1420 if (RT_FAILURE(rc))
1421 break;
1422
1423 if (hSymlink == NIL_RTVFSSYMLINK)
1424 {
1425 *ppVfsParentDir = pCurDir;
1426 return VINF_SUCCESS;
1427 }
1428 }
1429 else
1430 {
1431 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1432 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, &hDir, &hSymlink, &hVfsMnt);
1433 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1434 *pszEntryEnd = '/';
1435 if (RT_FAILURE(rc))
1436 break;
1437
1438 if ( hDir == NIL_RTVFSDIR
1439 && hSymlink == NIL_RTVFSSYMLINK
1440 && hVfsMnt == NIL_RTVFS)
1441 {
1442 rc = VERR_NOT_A_DIRECTORY;
1443 break;
1444 }
1445 }
1446 Assert( (hDir != NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1447 || (hDir == NIL_RTVFSDIR && hSymlink != NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1448 || (hDir == NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt != NIL_RTVFS));
1449
1450 if (hDir != NIL_RTVFSDIR)
1451 {
1452 /*
1453 * Directory - advance down the path.
1454 */
1455 AssertPtr(hDir);
1456 Assert(hDir->uMagic == RTVFSDIR_MAGIC);
1457 RTVfsDirRelease(pCurDir);
1458 pCurDir = hDir;
1459 iComponent++;
1460 }
1461 else if (hSymlink != NIL_RTVFSSYMLINK)
1462 {
1463 /*
1464 * Symbolic link - deal with it and retry the current component.
1465 */
1466 AssertPtr(hSymlink);
1467 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
1468 cLinks++;
1469 if (cLinks >= RTVFS_MAX_LINKS)
1470 {
1471 rc = VERR_TOO_MANY_SYMLINKS;
1472 break;
1473 }
1474 uint16_t iRestartComp = iComponent;
1475 rc = rtVfsTraverseHandleSymlink(pPath, &iRestartComp, hSymlink);
1476 if (RT_FAILURE(rc))
1477 break;
1478 if (iRestartComp != iComponent)
1479 {
1480 /* Must restart from the root. */
1481 RTVfsDirRelease(pCurDir);
1482 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1483 {
1484 rc = VERR_INVALID_HANDLE;
1485 pCurDir = NULL;
1486 break;
1487 }
1488 pCurDir = pThis;
1489 iComponent = 0;
1490 }
1491 }
1492 else
1493 {
1494 /*
1495 * Mount point - deal with it and retry the current component.
1496 */
1497 RTVfsDirRelease(pCurDir);
1498 RTVfsLockAcquireRead(hVfsMnt->Base.hLock);
1499 rc = hVfsMnt->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
1500 RTVfsLockReleaseRead(hVfsMnt->Base.hLock);
1501 if (RT_FAILURE(rc))
1502 {
1503 pCurDir = NULL;
1504 break;
1505 }
1506 iComponent = 0;
1507 /** @todo union mounts. */
1508 }
1509 }
1510
1511 if (pCurDir)
1512 RTVfsDirRelease(pCurDir);
1513
1514 return rc;
1515}
1516
1517
1518/**
1519 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1520 *
1521 * @returns IPRT status code.
1522 * @param pThis The VFS.
1523 * @param pPath The parsed path. This may be changed as symbolic
1524 * links are processed during the path traversal.
1525 * @param fFollowSymlink Whether to follow the final component if it is a
1526 * symbolic link.
1527 * @param ppVfsParentDir Where to return the parent directory handle
1528 * (referenced).
1529 */
1530static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, bool fFollowSymlink,
1531 RTVFSDIRINTERNAL **ppVfsParentDir)
1532{
1533 /*
1534 * Assert sanity.
1535 */
1536 AssertPtr(pThis);
1537 Assert(pThis->uMagic == RTVFS_MAGIC);
1538 Assert(pThis->Base.cRefs > 0);
1539 AssertPtr(pPath);
1540 AssertPtr(ppVfsParentDir);
1541 *ppVfsParentDir = NULL;
1542 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1543
1544 /*
1545 * Open the root directory and join paths with the directory traversal.
1546 */
1547 /** @todo Union mounts, traversal optimization methods, races, ++ */
1548 RTVFSDIRINTERNAL *pRootDir;
1549 RTVfsLockAcquireRead(pThis->Base.hLock);
1550 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pRootDir);
1551 RTVfsLockReleaseRead(pThis->Base.hLock);
1552 if (RT_SUCCESS(rc))
1553 {
1554 rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFollowSymlink, ppVfsParentDir);
1555 RTVfsDirRelease(pRootDir);
1556 }
1557 return rc;
1558}
1559
1560
1561RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
1562{
1563 NOREF(fEvents);
1564 int rc;
1565 if (fIntr)
1566 rc = RTThreadSleep(cMillies);
1567 else
1568 {
1569 uint64_t uMsStart = RTTimeMilliTS();
1570 do
1571 rc = RTThreadSleep(cMillies);
1572 while ( rc == VERR_INTERRUPTED
1573 && !fIntr
1574 && RTTimeMilliTS() - uMsStart < cMillies);
1575 if (rc == VERR_INTERRUPTED)
1576 rc = VERR_TIMEOUT;
1577 }
1578
1579 *pfRetEvents = 0;
1580 return rc;
1581}
1582
1583
1584RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
1585{
1586 /*
1587 * Allocate a temporary buffer.
1588 */
1589 size_t cbBuf = cbBufHint;
1590 if (!cbBuf)
1591 cbBuf = _64K;
1592 else if (cbBuf < _4K)
1593 cbBuf = _4K;
1594 else if (cbBuf > _1M)
1595 cbBuf = _1M;
1596
1597 void *pvBuf = RTMemTmpAlloc(cbBuf);
1598 if (!pvBuf)
1599 {
1600 cbBuf = _4K;
1601 pvBuf = RTMemTmpAlloc(cbBuf);
1602 if (!pvBuf)
1603 return VERR_NO_TMP_MEMORY;
1604 }
1605
1606 /*
1607 * Pump loop.
1608 */
1609 int rc;
1610 for (;;)
1611 {
1612 size_t cbRead;
1613 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
1614 if (RT_FAILURE(rc))
1615 break;
1616 if (rc == VINF_EOF && cbRead == 0)
1617 break;
1618
1619 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
1620 if (RT_FAILURE(rc))
1621 break;
1622 }
1623
1624 RTMemTmpFree(pvBuf);
1625
1626 /*
1627 * Flush the destination stream on success to make sure we've caught
1628 * errors caused by buffering delays.
1629 */
1630 if (RT_SUCCESS(rc))
1631 rc = RTVfsIoStrmFlush(hVfsIosDst);
1632
1633 return rc;
1634}
1635
1636
1637
1638
1639
1640/*
1641 * F I L E S Y S T E M R O O T
1642 * F I L E S Y S T E M R O O T
1643 * F I L E S Y S T E M R O O T
1644 */
1645
1646
1647RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
1648 PRTVFS phVfs, void **ppvInstance)
1649{
1650 /*
1651 * Validate the input, be extra strict in strict builds.
1652 */
1653 AssertPtr(pVfsOps);
1654 AssertReturn(pVfsOps->uVersion == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
1655 AssertReturn(pVfsOps->uEndMarker == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
1656 RTVFSOBJ_ASSERT_OPS(&pVfsOps->Obj, RTVFSOBJTYPE_VFS);
1657 Assert(cbInstance > 0);
1658 AssertPtr(ppvInstance);
1659 AssertPtr(phVfs);
1660
1661 /*
1662 * Allocate the handle + instance data.
1663 */
1664 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSINTERNAL), RTVFS_INST_ALIGNMENT)
1665 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1666 RTVFSINTERNAL *pThis = (RTVFSINTERNAL *)RTMemAllocZ(cbThis);
1667 if (!pThis)
1668 return VERR_NO_MEMORY;
1669
1670 int rc = rtVfsObjInitNewObject(&pThis->Base, &pVfsOps->Obj, hVfs, hLock,
1671 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1672 if (RT_FAILURE(rc))
1673 {
1674 RTMemFree(pThis);
1675 return rc;
1676 }
1677
1678 pThis->uMagic = RTVFS_MAGIC;
1679 pThis->pOps = pVfsOps;
1680
1681 *phVfs = pThis;
1682 *ppvInstance = pThis->Base.pvThis;
1683
1684 return VINF_SUCCESS;
1685}
1686
1687
1688RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs)
1689{
1690 RTVFSINTERNAL *pThis = hVfs;
1691 AssertPtrReturn(pThis, UINT32_MAX);
1692 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1693 return rtVfsObjRetain(&pThis->Base);
1694}
1695
1696
1697RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs)
1698{
1699 RTVFSINTERNAL *pThis = hVfs;
1700 if (pThis == NIL_RTVFS)
1701 return 0;
1702 AssertPtrReturn(pThis, UINT32_MAX);
1703 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1704 return rtVfsObjRelease(&pThis->Base);
1705}
1706
1707
1708RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir)
1709{
1710 RTVFSINTERNAL *pThis = hVfs;
1711 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1712 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1713 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
1714 *phDir = NIL_RTVFSDIR;
1715
1716 if (!pThis->pOps->pfnIsRangeInUse)
1717 return VERR_NOT_SUPPORTED;
1718 RTVfsLockAcquireRead(pThis->Base.hLock);
1719 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phDir);
1720 RTVfsLockReleaseRead(pThis->Base.hLock);
1721
1722 return rc;
1723}
1724
1725
1726
1727RTDECL(int) RTVfsIsRangeInUse(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed)
1728{
1729 RTVFSINTERNAL *pThis = hVfs;
1730 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1731 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1732
1733 if (!pThis->pOps->pfnIsRangeInUse)
1734 return VERR_NOT_SUPPORTED;
1735 RTVfsLockAcquireRead(pThis->Base.hLock);
1736 int rc = pThis->pOps->pfnIsRangeInUse(pThis->Base.pvThis, off, cb, pfUsed);
1737 RTVfsLockReleaseRead(pThis->Base.hLock);
1738
1739 return rc;
1740}
1741
1742
1743
1744
1745/*
1746 *
1747 * F I L E S Y S T E M S T R E A M
1748 * F I L E S Y S T E M S T R E A M
1749 * F I L E S Y S T E M S T R E A M
1750 *
1751 */
1752
1753
1754RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
1755 PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
1756{
1757 /*
1758 * Validate the input, be extra strict in strict builds.
1759 */
1760 AssertPtr(pFsStreamOps);
1761 AssertReturn(pFsStreamOps->uVersion == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1762 AssertReturn(pFsStreamOps->uEndMarker == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1763 Assert(!pFsStreamOps->fReserved);
1764 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
1765 AssertPtr(pFsStreamOps->pfnNext);
1766 Assert(cbInstance > 0);
1767 AssertPtr(ppvInstance);
1768 AssertPtr(phVfsFss);
1769 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
1770
1771 /*
1772 * Allocate the handle + instance data.
1773 */
1774 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFSSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
1775 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1776 RTVFSFSSTREAMINTERNAL *pThis = (RTVFSFSSTREAMINTERNAL *)RTMemAllocZ(cbThis);
1777 if (!pThis)
1778 return VERR_NO_MEMORY;
1779
1780 int rc = rtVfsObjInitNewObject(&pThis->Base, &pFsStreamOps->Obj, hVfs, hLock,
1781 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1782
1783 if (RT_FAILURE(rc))
1784 {
1785 RTMemFree(pThis);
1786 return rc;
1787 }
1788
1789 pThis->uMagic = RTVFSFSSTREAM_MAGIC;
1790 pThis->fFlags = RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
1791 pThis->pOps = pFsStreamOps;
1792
1793 *phVfsFss = pThis;
1794 *ppvInstance = pThis->Base.pvThis;
1795 return VINF_SUCCESS;
1796}
1797
1798
1799RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss)
1800{
1801 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1802 AssertPtrReturn(pThis, UINT32_MAX);
1803 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
1804 return rtVfsObjRetain(&pThis->Base);
1805}
1806
1807
1808RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss)
1809{
1810 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1811 if (pThis == NIL_RTVFSFSSTREAM)
1812 return 0;
1813 AssertPtrReturn(pThis, UINT32_MAX);
1814 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
1815 return rtVfsObjRelease(&pThis->Base);
1816}
1817
1818
1819RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1820{
1821 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1822 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1823 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
1824 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
1825}
1826
1827
1828RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
1829{
1830 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1831 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1832 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
1833 AssertPtrNullReturn(ppszName, VERR_INVALID_POINTER);
1834 if (ppszName)
1835 *ppszName = NULL;
1836 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
1837 if (penmType)
1838 *penmType = RTVFSOBJTYPE_INVALID;
1839 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
1840 if (phVfsObj)
1841 *phVfsObj = NIL_RTVFSOBJ;
1842
1843 return pThis->pOps->pfnNext(pThis->Base.pvThis, ppszName, penmType, phVfsObj);
1844}
1845
1846
1847
1848
1849/*
1850 *
1851 * D I R D I R D I R
1852 * D I R D I R D I R
1853 * D I R D I R D I R
1854 *
1855 */
1856
1857
1858RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock,
1859 PRTVFSDIR phVfsDir, void **ppvInstance)
1860{
1861 /*
1862 * Validate the input, be extra strict in strict builds.
1863 */
1864 AssertPtr(pDirOps);
1865 AssertReturn(pDirOps->uVersion == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
1866 AssertReturn(pDirOps->uEndMarker == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
1867 Assert(!pDirOps->fReserved);
1868 RTVFSDIR_ASSERT_OPS(pDirOps, RTVFSOBJTYPE_DIR);
1869 Assert(cbInstance > 0);
1870 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
1871 AssertPtr(ppvInstance);
1872 AssertPtr(phVfsDir);
1873 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
1874
1875 /*
1876 * Allocate the handle + instance data.
1877 */
1878 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSDIRINTERNAL), RTVFS_INST_ALIGNMENT)
1879 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1880 RTVFSDIRINTERNAL *pThis = (RTVFSDIRINTERNAL *)RTMemAllocZ(cbThis);
1881 if (!pThis)
1882 return VERR_NO_MEMORY;
1883
1884 int rc = rtVfsObjInitNewObject(&pThis->Base, &pDirOps->Obj, hVfs, hLock,
1885 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1886 if (RT_FAILURE(rc))
1887 {
1888 RTMemFree(pThis);
1889 return rc;
1890 }
1891
1892 pThis->uMagic = RTVFSDIR_MAGIC;
1893 pThis->fReserved = 0;
1894 pThis->pOps = pDirOps;
1895
1896 *phVfsDir = pThis;
1897 *ppvInstance = pThis->Base.pvThis;
1898 return VINF_SUCCESS;
1899}
1900
1901
1902RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir)
1903{
1904 RTVFSDIRINTERNAL *pThis = hVfsDir;
1905 AssertPtrReturn(pThis, UINT32_MAX);
1906 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
1907 return rtVfsObjRetain(&pThis->Base);
1908}
1909
1910
1911RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir)
1912{
1913 RTVFSDIRINTERNAL *pThis = hVfsDir;
1914 if (pThis == NIL_RTVFSDIR)
1915 return 0;
1916 AssertPtrReturn(pThis, UINT32_MAX);
1917 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
1918 return rtVfsObjRelease(&pThis->Base);
1919}
1920
1921
1922RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
1923{
1924 /*
1925 * Validate input.
1926 */
1927 RTVFSINTERNAL *pThis = hVfs;
1928 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1929 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1930 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1931 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
1932 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
1933
1934 /*
1935 * Parse the path, assume current directory is root since we've got no
1936 * caller context here.
1937 */
1938 PRTVFSPARSEDPATH pPath;
1939 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
1940 if (RT_SUCCESS(rc))
1941 {
1942 /*
1943 * Tranverse the path, resolving the parent node and any symlinks
1944 * in the final element, and ask the directory to open the subdir.
1945 */
1946 RTVFSDIRINTERNAL *pVfsParentDir;
1947 rc = rtVfsTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);
1948 if (RT_SUCCESS(rc))
1949 {
1950 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
1951
1952 /** @todo there is a symlink creation race here. */
1953 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
1954 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
1955 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
1956
1957 RTVfsDirRelease(pVfsParentDir);
1958
1959 if (RT_SUCCESS(rc))
1960 {
1961 AssertPtr(*phVfsDir);
1962 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
1963 }
1964 }
1965 RTVfsParsePathFree(pPath);
1966 }
1967 return rc;
1968}
1969
1970
1971RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
1972{
1973 /*
1974 * Validate input.
1975 */
1976 RTVFSDIRINTERNAL *pThis = hVfsDir;
1977 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1978 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
1979 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1980 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
1981 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
1982
1983 /*
1984 * Parse the path, it's always relative to the given directory.
1985 */
1986 PRTVFSPARSEDPATH pPath;
1987 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
1988 if (RT_SUCCESS(rc))
1989 {
1990 /*
1991 * Tranverse the path, resolving the parent node and any symlinks
1992 * in the final element, and ask the directory to open the subdir.
1993 */
1994 RTVFSDIRINTERNAL *pVfsParentDir;
1995 rc = rtVfsDirTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);
1996 if (RT_SUCCESS(rc))
1997 {
1998 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
1999
2000 /** @todo there is a symlink creation race here. */
2001 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2002 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2003 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2004
2005 RTVfsDirRelease(pVfsParentDir);
2006
2007 if (RT_SUCCESS(rc))
2008 {
2009 AssertPtr(*phVfsDir);
2010 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2011 }
2012 }
2013 RTVfsParsePathFree(pPath);
2014 }
2015 return rc;
2016}
2017
2018
2019RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2020{
2021 /*
2022 * Validate input.
2023 */
2024 RTVFSDIRINTERNAL *pThis = hVfsDir;
2025 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2026 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2027 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2028 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2029
2030 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2031 if (RT_FAILURE(rc))
2032 return rc;
2033
2034 /*
2035 * Parse the path, assume current directory is root since we've got no
2036 * caller context here.
2037 */
2038 PRTVFSPARSEDPATH pPath;
2039 rc = RTVfsParsePathA(pszPath, "/", &pPath);
2040 if (RT_SUCCESS(rc))
2041 {
2042 if (!pPath->fDirSlash)
2043 {
2044 /*
2045 * Tranverse the path, resolving the parent node and any symlinks
2046 * in the final element, and ask the directory to open the file.
2047 */
2048 RTVFSDIRINTERNAL *pVfsParentDir;
2049 rc = rtVfsDirTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);
2050 if (RT_SUCCESS(rc))
2051 {
2052 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2053
2054 /** @todo there is a symlink creation race here. */
2055 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2056 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2057 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2058
2059 RTVfsDirRelease(pVfsParentDir);
2060
2061 if (RT_SUCCESS(rc))
2062 {
2063 AssertPtr(*phVfsFile);
2064 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2065 }
2066 }
2067 }
2068 else
2069 rc = VERR_INVALID_PARAMETER;
2070 RTVfsParsePathFree(pPath);
2071 }
2072 return rc;
2073}
2074
2075
2076/*
2077 *
2078 * S Y M B O L I C L I N K
2079 * S Y M B O L I C L I N K
2080 * S Y M B O L I C L I N K
2081 *
2082 */
2083
2084RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
2085 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
2086{
2087 /*
2088 * Validate the input, be extra strict in strict builds.
2089 */
2090 AssertPtr(pSymlinkOps);
2091 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
2092 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
2093 Assert(!pSymlinkOps->fReserved);
2094 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
2095 Assert(cbInstance > 0);
2096 AssertPtr(ppvInstance);
2097 AssertPtr(phVfsSym);
2098 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2099
2100 /*
2101 * Allocate the handle + instance data.
2102 */
2103 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
2104 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2105 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
2106 if (!pThis)
2107 return VERR_NO_MEMORY;
2108
2109 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, hLock,
2110 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2111 if (RT_FAILURE(rc))
2112 {
2113 RTMemFree(pThis);
2114 return rc;
2115 }
2116
2117 pThis->uMagic = RTVFSSYMLINK_MAGIC;
2118 pThis->pOps = pSymlinkOps;
2119
2120 *phVfsSym = pThis;
2121 *ppvInstance = pThis->Base.pvThis;
2122 return VINF_SUCCESS;
2123}
2124
2125
2126RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
2127{
2128 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2129 AssertPtrReturn(pThis, UINT32_MAX);
2130 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2131 return rtVfsObjRetain(&pThis->Base);
2132}
2133
2134
2135RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
2136{
2137 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2138 if (pThis == NIL_RTVFSSYMLINK)
2139 return 0;
2140 AssertPtrReturn(pThis, UINT32_MAX);
2141 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2142 return rtVfsObjRelease(&pThis->Base);
2143}
2144
2145
2146RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2147{
2148 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2149 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2150 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2151 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2152}
2153
2154
2155RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
2156{
2157 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2158 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2159 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2160
2161 fMode = rtFsModeNormalize(fMode, NULL, 0);
2162 if (!rtFsModeIsValid(fMode))
2163 return VERR_INVALID_PARAMETER;
2164
2165 RTVfsLockAcquireWrite(pThis->Base.hLock);
2166 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
2167 RTVfsLockReleaseWrite(pThis->Base.hLock);
2168 return rc;
2169}
2170
2171
2172RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
2173 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
2174{
2175 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2176 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2177 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2178
2179 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
2180 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
2181 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
2182 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
2183
2184 RTVfsLockAcquireWrite(pThis->Base.hLock);
2185 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
2186 RTVfsLockReleaseWrite(pThis->Base.hLock);
2187 return rc;
2188}
2189
2190
2191RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
2192{
2193 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2194 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2195 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2196
2197 RTVfsLockAcquireWrite(pThis->Base.hLock);
2198 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
2199 RTVfsLockReleaseWrite(pThis->Base.hLock);
2200 return rc;
2201}
2202
2203
2204RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
2205{
2206 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2207 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2208 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2209
2210 RTVfsLockAcquireWrite(pThis->Base.hLock);
2211 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
2212 RTVfsLockReleaseWrite(pThis->Base.hLock);
2213
2214 return rc;
2215}
2216
2217
2218
2219/*
2220 *
2221 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2222 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2223 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2224 *
2225 */
2226
2227RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
2228 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
2229{
2230 /*
2231 * Validate the input, be extra strict in strict builds.
2232 */
2233 AssertPtr(pIoStreamOps);
2234 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2235 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2236 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
2237 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
2238 Assert(cbInstance > 0);
2239 Assert(fOpen & RTFILE_O_ACCESS_MASK);
2240 AssertPtr(ppvInstance);
2241 AssertPtr(phVfsIos);
2242 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2243
2244 /*
2245 * Allocate the handle + instance data.
2246 */
2247 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
2248 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2249 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
2250 if (!pThis)
2251 return VERR_NO_MEMORY;
2252
2253 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, hLock,
2254 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2255 if (RT_FAILURE(rc))
2256 {
2257 RTMemFree(pThis);
2258 return rc;
2259 }
2260
2261 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
2262 pThis->fFlags = fOpen;
2263 pThis->pOps = pIoStreamOps;
2264
2265 *phVfsIos = pThis;
2266 *ppvInstance = pThis->Base.pvThis;
2267 return VINF_SUCCESS;
2268}
2269
2270
2271RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
2272{
2273 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2274 AssertPtrReturn(pThis, NULL);
2275 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
2276 if (pThis->pOps != pIoStreamOps)
2277 return NULL;
2278 return pThis->Base.pvThis;
2279}
2280
2281
2282RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
2283{
2284 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2285 AssertPtrReturn(pThis, UINT32_MAX);
2286 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2287 return rtVfsObjRetain(&pThis->Base);
2288}
2289
2290
2291RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
2292{
2293 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2294 if (pThis == NIL_RTVFSIOSTREAM)
2295 return 0;
2296 AssertPtrReturn(pThis, UINT32_MAX);
2297 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2298 return rtVfsObjRelease(&pThis->Base);
2299}
2300
2301
2302RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
2303{
2304 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2305 AssertPtrReturn(pThis, NIL_RTVFSFILE);
2306 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
2307
2308 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
2309 {
2310 rtVfsObjRetainVoid(&pThis->Base);
2311 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
2312 }
2313
2314 /* this is no crime, so don't assert. */
2315 return NIL_RTVFSFILE;
2316}
2317
2318
2319RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2320{
2321 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2322 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2323 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2324 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2325}
2326
2327
2328RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
2329{
2330 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2331 if (pcbRead)
2332 *pcbRead = 0;
2333 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2334 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2335 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2336 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2337 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2338
2339 RTSGSEG Seg = { pvBuf, cbToRead };
2340 RTSGBUF SgBuf;
2341 RTSgBufInit(&SgBuf, &Seg, 1);
2342
2343 RTVfsLockAcquireWrite(pThis->Base.hLock);
2344 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
2345 RTVfsLockReleaseWrite(pThis->Base.hLock);
2346 return rc;
2347}
2348
2349
2350RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
2351 bool fBlocking, size_t *pcbRead)
2352{
2353 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2354 if (pcbRead)
2355 *pcbRead = 0;
2356 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2357 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2358 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2359 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2360 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2361
2362 RTSGSEG Seg = { pvBuf, cbToRead };
2363 RTSGBUF SgBuf;
2364 RTSgBufInit(&SgBuf, &Seg, 1);
2365
2366 RTVfsLockAcquireWrite(pThis->Base.hLock);
2367 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
2368 RTVfsLockReleaseWrite(pThis->Base.hLock);
2369 return rc;
2370}
2371
2372
2373RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
2374{
2375 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2376 if (pcbWritten)
2377 *pcbWritten = 0;
2378 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2379 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2380 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2381 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2382 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2383
2384 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
2385 RTSGBUF SgBuf;
2386 RTSgBufInit(&SgBuf, &Seg, 1);
2387
2388 RTVfsLockAcquireWrite(pThis->Base.hLock);
2389 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
2390 RTVfsLockReleaseWrite(pThis->Base.hLock);
2391 return rc;
2392}
2393
2394
2395RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
2396 bool fBlocking, size_t *pcbWritten)
2397{
2398 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2399 if (pcbWritten)
2400 *pcbWritten = 0;
2401 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2402 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2403 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2404 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2405 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2406
2407 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
2408 RTSGBUF SgBuf;
2409 RTSgBufInit(&SgBuf, &Seg, 1);
2410
2411 RTVfsLockAcquireWrite(pThis->Base.hLock);
2412 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
2413 RTVfsLockReleaseWrite(pThis->Base.hLock);
2414 return rc;
2415}
2416
2417
2418RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
2419{
2420 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2421 if (pcbRead)
2422 *pcbRead = 0;
2423 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2424 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2425 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2426 AssertPtr(pSgBuf);
2427 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2428 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2429
2430 RTVfsLockAcquireWrite(pThis->Base.hLock);
2431 int rc;
2432 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
2433 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
2434 else
2435 {
2436 size_t cbRead = 0;
2437 rc = VINF_SUCCESS;
2438
2439 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
2440 {
2441 RTSGBUF SgBuf;
2442 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
2443
2444 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
2445 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
2446 if (RT_FAILURE(rc))
2447 break;
2448 cbRead += cbReadSeg;
2449 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
2450 break;
2451 if (off != -1)
2452 off += cbReadSeg;
2453 }
2454
2455 if (pcbRead)
2456 *pcbRead = cbRead;
2457 }
2458 RTVfsLockReleaseWrite(pThis->Base.hLock);
2459 return rc;
2460}
2461
2462
2463RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
2464{
2465 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2466 if (pcbWritten)
2467 *pcbWritten = 0;
2468 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2469 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2470 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2471 AssertPtr(pSgBuf);
2472 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2473 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2474
2475 RTVfsLockAcquireWrite(pThis->Base.hLock);
2476 int rc;
2477 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
2478 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
2479 else
2480 {
2481 size_t cbWritten = 0;
2482 rc = VINF_SUCCESS;
2483
2484 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
2485 {
2486 RTSGBUF SgBuf;
2487 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
2488
2489 size_t cbWrittenSeg = 0;
2490 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
2491 if (RT_FAILURE(rc))
2492 break;
2493 if (pcbWritten)
2494 {
2495 cbWritten += cbWrittenSeg;
2496 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
2497 break;
2498 if (off != -1)
2499 off += cbWrittenSeg;
2500 }
2501 else if (off != -1)
2502 off += pSgBuf->paSegs[iSeg].cbSeg;
2503 }
2504
2505 if (pcbWritten)
2506 *pcbWritten = cbWritten;
2507 }
2508 RTVfsLockReleaseWrite(pThis->Base.hLock);
2509 return rc;
2510}
2511
2512
2513RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
2514{
2515 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2516 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2517 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2518
2519 RTVfsLockAcquireWrite(pThis->Base.hLock);
2520 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
2521 RTVfsLockReleaseWrite(pThis->Base.hLock);
2522 return rc;
2523}
2524
2525
2526RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
2527 uint32_t *pfRetEvents)
2528{
2529 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2530 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2531 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2532
2533 RTVfsLockAcquireWrite(pThis->Base.hLock);
2534 int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
2535 RTVfsLockReleaseWrite(pThis->Base.hLock);
2536 return rc;
2537}
2538
2539
2540RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
2541{
2542 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2543 AssertPtrReturn(pThis, -1);
2544 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2545
2546 RTFOFF off;
2547 RTVfsLockAcquireRead(pThis->Base.hLock);
2548 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
2549 RTVfsLockReleaseRead(pThis->Base.hLock);
2550 if (RT_FAILURE(rc))
2551 off = rc;
2552 return off;
2553}
2554
2555
2556RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
2557{
2558 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2559 AssertPtrReturn(pThis, -1);
2560 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2561 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
2562
2563 int rc;
2564 if (pThis->pOps->pfnSkip)
2565 {
2566 RTVfsLockAcquireWrite(pThis->Base.hLock);
2567 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
2568 RTVfsLockReleaseWrite(pThis->Base.hLock);
2569 }
2570 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
2571 {
2572 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
2573 RTFOFF offIgnored;
2574
2575 RTVfsLockAcquireWrite(pThis->Base.hLock);
2576 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
2577 RTVfsLockReleaseWrite(pThis->Base.hLock);
2578 }
2579 else
2580 {
2581 void *pvBuf = RTMemTmpAlloc(_64K);
2582 if (pvBuf)
2583 {
2584 rc = VINF_SUCCESS;
2585 while (cb > 0)
2586 {
2587 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
2588 RTVfsLockAcquireWrite(pThis->Base.hLock);
2589 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
2590 RTVfsLockReleaseWrite(pThis->Base.hLock);
2591 if (RT_FAILURE(rc))
2592 break;
2593 cb -= cbToRead;
2594 }
2595
2596 RTMemTmpFree(pvBuf);
2597 }
2598 else
2599 rc = VERR_NO_TMP_MEMORY;
2600 }
2601 return rc;
2602}
2603
2604
2605RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
2606{
2607 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2608 AssertPtrReturn(pThis, -1);
2609 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2610
2611 int rc;
2612 if (pThis->pOps->pfnSkip)
2613 {
2614 RTVfsLockAcquireWrite(pThis->Base.hLock);
2615 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
2616 RTVfsLockReleaseWrite(pThis->Base.hLock);
2617 }
2618 else
2619 {
2620 void *pvBuf = RTMemTmpAllocZ(_64K);
2621 if (pvBuf)
2622 {
2623 rc = VINF_SUCCESS;
2624 while (cb > 0)
2625 {
2626 size_t cbToWrite = (size_t)RT_MIN(cb, _64K);
2627 RTVfsLockAcquireWrite(pThis->Base.hLock);
2628 rc = RTVfsIoStrmWrite(hVfsIos, pvBuf, cbToWrite, true /*fBlocking*/, NULL);
2629 RTVfsLockReleaseWrite(pThis->Base.hLock);
2630 if (RT_FAILURE(rc))
2631 break;
2632 cb -= cbToWrite;
2633 }
2634
2635 RTMemTmpFree(pvBuf);
2636 }
2637 else
2638 rc = VERR_NO_TMP_MEMORY;
2639 }
2640 return rc;
2641}
2642
2643
2644RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
2645{
2646 /*
2647 * There is where the zero read behavior comes in handy.
2648 */
2649 char bDummy;
2650 size_t cbRead;
2651 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
2652 return rc == VINF_EOF;
2653}
2654
2655
2656
2657
2658
2659
2660/*
2661 *
2662 * F I L E F I L E F I L E
2663 * F I L E F I L E F I L E
2664 * F I L E F I L E F I L E
2665 *
2666 */
2667
2668RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
2669 PRTVFSFILE phVfsFile, void **ppvInstance)
2670{
2671 /*
2672 * Validate the input, be extra strict in strict builds.
2673 */
2674 AssertPtr(pFileOps);
2675 AssertReturn(pFileOps->uVersion == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
2676 AssertReturn(pFileOps->uEndMarker == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
2677 Assert(!pFileOps->fReserved);
2678 RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
2679 Assert(cbInstance > 0);
2680 Assert(fOpen & RTFILE_O_ACCESS_MASK);
2681 AssertPtr(ppvInstance);
2682 AssertPtr(phVfsFile);
2683 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2684
2685 /*
2686 * Allocate the handle + instance data.
2687 */
2688 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
2689 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2690 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
2691 if (!pThis)
2692 return VERR_NO_MEMORY;
2693
2694 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, hLock,
2695 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2696 if (RT_FAILURE(rc))
2697 {
2698 RTMemFree(pThis);
2699 return rc;
2700 }
2701
2702 pThis->uMagic = RTVFSFILE_MAGIC;
2703 pThis->fReserved = 0;
2704 pThis->pOps = pFileOps;
2705 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
2706 pThis->Stream.fFlags = fOpen;
2707 pThis->Stream.pOps = &pFileOps->Stream;
2708
2709 *phVfsFile = pThis;
2710 *ppvInstance = pThis->Stream.Base.pvThis;
2711 return VINF_SUCCESS;
2712}
2713
2714
2715RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
2716{
2717 /*
2718 * Validate input.
2719 */
2720 RTVFSINTERNAL *pThis = hVfs;
2721 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2722 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2723 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
2724 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2725
2726 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2727 if (RT_FAILURE(rc))
2728 return rc;
2729
2730 /*
2731 * Parse the path, assume current directory is root since we've got no
2732 * caller context here.
2733 */
2734 PRTVFSPARSEDPATH pPath;
2735 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
2736 if (RT_SUCCESS(rc))
2737 {
2738 if (!pPath->fDirSlash)
2739 {
2740 /*
2741 * Tranverse the path, resolving the parent node and any symlinks
2742 * in the final element, and ask the directory to open the file.
2743 */
2744 RTVFSDIRINTERNAL *pVfsParentDir;
2745 rc = rtVfsTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);
2746 if (RT_SUCCESS(rc))
2747 {
2748 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2749
2750 /** @todo there is a symlink creation race here. */
2751 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2752 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2753 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2754
2755 RTVfsDirRelease(pVfsParentDir);
2756
2757 if (RT_SUCCESS(rc))
2758 {
2759 AssertPtr(*phVfsFile);
2760 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2761 }
2762 }
2763 }
2764 else
2765 rc = VERR_INVALID_PARAMETER;
2766 RTVfsParsePathFree(pPath);
2767 }
2768 return rc;
2769}
2770
2771
2772RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
2773{
2774 RTVFSFILEINTERNAL *pThis = hVfsFile;
2775 AssertPtrReturn(pThis, UINT32_MAX);
2776 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
2777 return rtVfsObjRetain(&pThis->Stream.Base);
2778}
2779
2780
2781RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
2782{
2783 RTVFSFILEINTERNAL *pThis = hVfsFile;
2784 if (pThis == NIL_RTVFSFILE)
2785 return 0;
2786 AssertPtrReturn(pThis, UINT32_MAX);
2787 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
2788 return rtVfsObjRelease(&pThis->Stream.Base);
2789}
2790
2791
2792RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
2793{
2794 RTVFSFILEINTERNAL *pThis = hVfsFile;
2795 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
2796 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
2797
2798 rtVfsObjRetainVoid(&pThis->Stream.Base);
2799 return &pThis->Stream;
2800}
2801
2802
2803RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2804{
2805 RTVFSFILEINTERNAL *pThis = hVfsFile;
2806 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2807 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2808 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
2809}
2810
2811
2812RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
2813{
2814 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2815 if (pcbRead)
2816 *pcbRead = 0;
2817 RTVFSFILEINTERNAL *pThis = hVfsFile;
2818 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2819 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2820 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
2821}
2822
2823
2824RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
2825{
2826 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2827 if (pcbWritten)
2828 *pcbWritten = 0;
2829 RTVFSFILEINTERNAL *pThis = hVfsFile;
2830 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2831 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2832 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
2833}
2834
2835
2836RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
2837{
2838 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2839 if (pcbWritten)
2840 *pcbWritten = 0;
2841 RTVFSFILEINTERNAL *pThis = hVfsFile;
2842 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2843 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2844
2845 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
2846 if (RT_SUCCESS(rc))
2847 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
2848
2849 return rc;
2850}
2851
2852
2853RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
2854{
2855 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2856 if (pcbRead)
2857 *pcbRead = 0;
2858 RTVFSFILEINTERNAL *pThis = hVfsFile;
2859 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2860 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2861
2862 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
2863 if (RT_SUCCESS(rc))
2864 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
2865
2866 return rc;
2867}
2868
2869
2870RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
2871{
2872 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2873 if (pcbRead)
2874 *pcbRead = 0;
2875 RTVFSFILEINTERNAL *pThis = hVfsFile;
2876 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2877 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2878
2879 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
2880}
2881
2882
2883RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
2884{
2885 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2886 if (pcbWritten)
2887 *pcbWritten = 0;
2888 RTVFSFILEINTERNAL *pThis = hVfsFile;
2889 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2890 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2891
2892 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
2893}
2894
2895
2896RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
2897{
2898 RTVFSFILEINTERNAL *pThis = hVfsFile;
2899 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2900 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2901 return RTVfsIoStrmFlush(&pThis->Stream);
2902}
2903
2904
2905RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
2906 uint32_t *pfRetEvents)
2907{
2908 RTVFSFILEINTERNAL *pThis = hVfsFile;
2909 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2910 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2911 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
2912}
2913
2914
2915RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
2916{
2917 RTVFSFILEINTERNAL *pThis = hVfsFile;
2918 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2919 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2920 return RTVfsIoStrmTell(&pThis->Stream);
2921}
2922
2923
2924RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
2925{
2926 RTVFSFILEINTERNAL *pThis = hVfsFile;
2927 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2928 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2929
2930 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
2931 || uMethod == RTFILE_SEEK_CURRENT
2932 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
2933 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
2934
2935 RTFOFF offActual = 0;
2936 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
2937 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
2938 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
2939 if (RT_SUCCESS(rc) && poffActual)
2940 {
2941 Assert(offActual >= 0);
2942 *poffActual = offActual;
2943 }
2944
2945 return rc;
2946}
2947
2948
2949RTDECL(int) RTVfsFileGetSize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
2950{
2951 RTVFSFILEINTERNAL *pThis = hVfsFile;
2952 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2953 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
2954 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
2955
2956 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
2957 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
2958 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
2959
2960 return rc;
2961}
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