VirtualBox

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

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

iso9660vfs,fatvfs: reference count fix

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