VirtualBox

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

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

RTVfsIoStrmZeroFill: Fixed wrong method test (pfnSkip instead of pfnZeroFill); use g_abRTZero64K instead of the heap.

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