VirtualBox

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

Last change on this file since 48021 was 48021, checked in by vboxsync, 11 years ago

IPRT/vfsbase: RTVfsUtilPumpIoStreams(): properly detect detect EOF

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

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