VirtualBox

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

最後變更 在這個檔案從69434是 69111,由 vboxsync 提交於 7 年 前

(C) year

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 106.8 KB
 
1/* $Id: vfsbase.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Base.
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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 if (pThis->hLock != NIL_RTVFSLOCK)
932 {
933 RTVfsLockRelease(pThis->hLock);
934 pThis->hLock = NIL_RTVFSLOCK;
935 }
936 RTMemFree(pvToFree);
937}
938
939
940/**
941 * Internal object releaser that asserts sanity in strict builds.
942 *
943 * @returns The new reference count.
944 * @param pcRefs The reference counter.
945 */
946DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis)
947{
948 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
949 AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
950 LogFlow(("rtVfsObjRelease(%p/%p) -> %d\n", pThis, pThis->pvThis, cRefs));
951 if (cRefs == 0)
952 rtVfsObjDestroy(pThis);
953 return cRefs;
954}
955
956
957RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj)
958{
959 RTVFSOBJINTERNAL *pThis = hVfsObj;
960 if (pThis == NIL_RTVFSOBJ)
961 return 0;
962 AssertPtrReturn(pThis, UINT32_MAX);
963 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
964 return rtVfsObjRelease(pThis);
965}
966
967
968RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj)
969{
970 RTVFSOBJINTERNAL *pThis = hVfsObj;
971 if (pThis != NIL_RTVFSOBJ)
972 {
973 AssertPtrReturn(pThis, NIL_RTVFS);
974 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFS);
975
976 if (pThis->pOps->enmType == RTVFSOBJTYPE_VFS)
977 {
978 rtVfsObjRetainVoid(pThis, "RTVfsObjToVfs");
979 LogFlow(("RTVfsObjToVfs(%p) -> %p\n", pThis, RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)));
980 return RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
981 }
982 }
983 return NIL_RTVFS;
984}
985
986
987RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj)
988{
989 RTVFSOBJINTERNAL *pThis = hVfsObj;
990 if (pThis != NIL_RTVFSOBJ)
991 {
992 AssertPtrReturn(pThis, NIL_RTVFSFSSTREAM);
993 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFSSTREAM);
994
995 if (pThis->pOps->enmType == RTVFSOBJTYPE_FS_STREAM)
996 {
997 rtVfsObjRetainVoid(pThis, "RTVfsObjToFsStream");
998 return RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
999 }
1000 }
1001 return NIL_RTVFSFSSTREAM;
1002}
1003
1004
1005RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj)
1006{
1007 RTVFSOBJINTERNAL *pThis = hVfsObj;
1008 if (pThis != NIL_RTVFSOBJ)
1009 {
1010 AssertPtrReturn(pThis, NIL_RTVFSDIR);
1011 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSDIR);
1012
1013 if (pThis->pOps->enmType == RTVFSOBJTYPE_DIR)
1014 {
1015 rtVfsObjRetainVoid(pThis, "RTVfsObjToDir");
1016 return RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
1017 }
1018 }
1019 return NIL_RTVFSDIR;
1020}
1021
1022
1023RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj)
1024{
1025 RTVFSOBJINTERNAL *pThis = hVfsObj;
1026 if (pThis != NIL_RTVFSOBJ)
1027 {
1028 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
1029 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSIOSTREAM);
1030
1031 if ( pThis->pOps->enmType == RTVFSOBJTYPE_IO_STREAM
1032 || pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1033 {
1034 rtVfsObjRetainVoid(pThis, "RTVfsObjToIoStream");
1035 return RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
1036 }
1037 }
1038 return NIL_RTVFSIOSTREAM;
1039}
1040
1041
1042RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj)
1043{
1044 RTVFSOBJINTERNAL *pThis = hVfsObj;
1045 if (pThis != NIL_RTVFSOBJ)
1046 {
1047 AssertPtrReturn(pThis, NIL_RTVFSFILE);
1048 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFILE);
1049
1050 if (pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1051 {
1052 rtVfsObjRetainVoid(pThis, "RTVfsObjToFile");
1053 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
1054 }
1055 }
1056 return NIL_RTVFSFILE;
1057}
1058
1059
1060RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj)
1061{
1062 RTVFSOBJINTERNAL *pThis = hVfsObj;
1063 if (pThis != NIL_RTVFSOBJ)
1064 {
1065 AssertPtrReturn(pThis, NIL_RTVFSSYMLINK);
1066 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSSYMLINK);
1067
1068 if (pThis->pOps->enmType == RTVFSOBJTYPE_SYMLINK)
1069 {
1070 rtVfsObjRetainVoid(pThis, "RTVfsObjToSymlink");
1071 return RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
1072 }
1073 }
1074 return NIL_RTVFSSYMLINK;
1075}
1076
1077
1078RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs)
1079{
1080 if (hVfs != NIL_RTVFS)
1081 {
1082 RTVFSOBJINTERNAL *pThis = &hVfs->Base;
1083 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1084 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1085
1086 rtVfsObjRetainVoid(pThis, "RTVfsObjFromVfs");
1087 LogFlow(("RTVfsObjFromVfs(%p) -> %p\n", hVfs, pThis));
1088 return pThis;
1089 }
1090 return NIL_RTVFSOBJ;
1091}
1092
1093
1094RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss)
1095{
1096 if (hVfsFss != NIL_RTVFSFSSTREAM)
1097 {
1098 RTVFSOBJINTERNAL *pThis = &hVfsFss->Base;
1099 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1100 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1101
1102 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFsStream");
1103 return pThis;
1104 }
1105 return NIL_RTVFSOBJ;
1106}
1107
1108
1109RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir)
1110{
1111 if (hVfsDir != NIL_RTVFSDIR)
1112 {
1113 RTVFSOBJINTERNAL *pThis = &hVfsDir->Base;
1114 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1115 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1116
1117 rtVfsObjRetainVoid(pThis, "RTVfsObjFromDir");
1118 return pThis;
1119 }
1120 return NIL_RTVFSOBJ;
1121}
1122
1123
1124RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos)
1125{
1126 if (hVfsIos != NIL_RTVFSIOSTREAM)
1127 {
1128 RTVFSOBJINTERNAL *pThis = &hVfsIos->Base;
1129 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1130 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1131
1132 rtVfsObjRetainVoid(pThis, "RTVfsObjFromIoStream");
1133 return pThis;
1134 }
1135 return NIL_RTVFSOBJ;
1136}
1137
1138
1139RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile)
1140{
1141 if (hVfsFile != NIL_RTVFSFILE)
1142 {
1143 RTVFSOBJINTERNAL *pThis = &hVfsFile->Stream.Base;
1144 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1145 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1146
1147 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFile");
1148 return pThis;
1149 }
1150 return NIL_RTVFSOBJ;
1151}
1152
1153
1154RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym)
1155{
1156 if (hVfsSym != NIL_RTVFSSYMLINK)
1157 {
1158 RTVFSOBJINTERNAL *pThis = &hVfsSym->Base;
1159 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1160 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1161
1162 rtVfsObjRetainVoid(pThis, "RTVfsObjFromSymlink");
1163 return pThis;
1164 }
1165 return NIL_RTVFSOBJ;
1166}
1167
1168
1169
1170RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1171{
1172 RTVFSOBJINTERNAL *pThis = hVfsObj;
1173 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1174 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1175
1176 RTVfsLockAcquireRead(pThis->hLock);
1177 int rc = pThis->pOps->pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
1178 RTVfsLockReleaseRead(pThis->hLock);
1179 return rc;
1180}
1181
1182
1183
1184/*
1185 *
1186 * U T I L U T I L U T I L
1187 * U T I L U T I L U T I L
1188 * U T I L U T I L U T I L
1189 *
1190 */
1191
1192
1193
1194/**
1195 * Removes dots from the path.
1196 *
1197 * @returns The new @a pszDst value.
1198 * @param pPath The path parsing buffer.
1199 * @param pszDst The current szPath position. This will be
1200 * updated and returned.
1201 * @param fTheEnd Indicates whether we're at the end of the path
1202 * or not.
1203 * @param piRestartComp The component to restart parsing at.
1204 */
1205static char *rtVfsParsePathHandleDots(PRTVFSPARSEDPATH pPath, char *pszDst, bool fTheEnd, uint16_t *piRestartComp)
1206{
1207 if (pszDst[-1] != '.')
1208 return pszDst;
1209
1210 if (pszDst[-2] == '/')
1211 {
1212 pPath->cComponents--;
1213 pszDst = &pPath->szPath[pPath->aoffComponents[pPath->cComponents]];
1214 }
1215 else if (pszDst[-2] == '.' && pszDst[-3] == '/')
1216 {
1217 pPath->cComponents -= pPath->cComponents > 1 ? 2 : 1;
1218 pszDst = &pPath->szPath[pPath->aoffComponents[pPath->cComponents]];
1219 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1220 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1221 }
1222 else
1223 return pszDst;
1224
1225 /*
1226 * Drop the trailing slash if we're at the end of the source path.
1227 */
1228 if (fTheEnd && pPath->cComponents == 0)
1229 pszDst--;
1230 return pszDst;
1231}
1232
1233
1234RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
1235{
1236 AssertReturn(*pszPath != '/', VERR_INTERNAL_ERROR_4);
1237
1238 /* In case *piRestartComp was set higher than the number of components
1239 before making the call to this function. */
1240 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1241 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1242
1243 /*
1244 * Append a slash to the destination path if necessary.
1245 */
1246 char *pszDst = &pPath->szPath[pPath->cch];
1247 if (pPath->cComponents > 0)
1248 {
1249 *pszDst++ = '/';
1250 if (pszDst - &pPath->szPath[0] >= RTVFSPARSEDPATH_MAX)
1251 return VERR_FILENAME_TOO_LONG;
1252 }
1253 Assert(pszDst[-1] == '/');
1254
1255 /*
1256 * Parse and append the relative path.
1257 */
1258 const char *pszSrc = pszPath;
1259 pPath->fDirSlash = false;
1260 while (pszSrc[0])
1261 {
1262 /* Skip unncessary slashes. */
1263 while (pszSrc[0] == '/')
1264 pszSrc++;
1265
1266 /* Copy until we encounter the next slash. */
1267 pPath->aoffComponents[pPath->cComponents++] = pszDst - &pPath->szPath[0];
1268 while (pszSrc[0])
1269 {
1270 if (pszSrc[0] == '/')
1271 {
1272 pszSrc++;
1273 if (pszSrc[0])
1274 *pszDst++ = '/';
1275 else
1276 pPath->fDirSlash = true;
1277 pszDst = rtVfsParsePathHandleDots(pPath, pszDst, pszSrc[0] == '\0', piRestartComp);
1278 break;
1279 }
1280
1281 *pszDst++ = *pszSrc++;
1282 if (pszDst - &pPath->szPath[0] >= RTVFSPARSEDPATH_MAX)
1283 return VERR_FILENAME_TOO_LONG;
1284 }
1285 }
1286 pszDst = rtVfsParsePathHandleDots(pPath, pszDst, true /*fTheEnd*/, piRestartComp);
1287
1288 /* Terminate the string and enter its length. */
1289 pszDst[0] = '\0';
1290 pszDst[1] = '\0'; /* for aoffComponents */
1291 pPath->cch = (uint16_t)(pszDst - &pPath->szPath[0]);
1292 pPath->aoffComponents[pPath->cComponents] = pPath->cch + 1;
1293
1294 return VINF_SUCCESS;
1295}
1296
1297
1298/** @todo Replace RTVfsParsePath with RTPathParse and friends? */
1299RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
1300{
1301 if (*pszPath != '/')
1302 {
1303 /*
1304 * Relative, recurse and parse pszCwd first.
1305 */
1306 int rc = RTVfsParsePath(pPath, pszCwd, NULL /*crash if pszCwd is not absolute*/);
1307 if (RT_FAILURE(rc))
1308 return rc;
1309 }
1310 else
1311 {
1312 /*
1313 * Make pszPath relative, i.e. set up pPath for the root and skip
1314 * leading slashes in pszPath before appending it.
1315 */
1316 pPath->cch = 1;
1317 pPath->cComponents = 0;
1318 pPath->fDirSlash = false;
1319 pPath->aoffComponents[0] = 1;
1320 pPath->aoffComponents[1] = 2;
1321 pPath->szPath[0] = '/';
1322 pPath->szPath[1] = '\0';
1323 pPath->szPath[2] = '\0';
1324 while (pszPath[0] == '/')
1325 pszPath++;
1326 if (!pszPath[0])
1327 return VINF_SUCCESS;
1328 }
1329 return RTVfsParsePathAppend(pPath, pszPath, NULL);
1330}
1331
1332
1333
1334RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath)
1335{
1336 /*
1337 * Allocate the output buffer and hand the problem to rtVfsParsePath.
1338 */
1339 int rc;
1340 PRTVFSPARSEDPATH pPath = (PRTVFSPARSEDPATH)RTMemTmpAlloc(sizeof(RTVFSPARSEDPATH));
1341 if (pPath)
1342 {
1343 rc = RTVfsParsePath(pPath, pszPath, pszCwd);
1344 if (RT_FAILURE(rc))
1345 {
1346 RTMemTmpFree(pPath);
1347 pPath = NULL;
1348 }
1349 }
1350 else
1351 rc = VERR_NO_TMP_MEMORY;
1352 *ppPath = pPath; /* always set it */
1353 return rc;
1354}
1355
1356
1357RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath)
1358{
1359 if (pPath)
1360 {
1361 pPath->cch = UINT16_MAX;
1362 pPath->cComponents = UINT16_MAX;
1363 pPath->aoffComponents[0] = UINT16_MAX;
1364 pPath->aoffComponents[1] = UINT16_MAX;
1365 RTMemTmpFree(pPath);
1366 }
1367}
1368
1369
1370/**
1371 * Handles a symbolic link, adding it to
1372 *
1373 * @returns IPRT status code.
1374 * @param pPath The parsed path to update.
1375 * @param piComponent The component iterator to update.
1376 * @param hSymlink The symbolic link to process.
1377 */
1378static int rtVfsTraverseHandleSymlink(PRTVFSPARSEDPATH pPath, uint16_t *piComponent, RTVFSSYMLINK hSymlink)
1379{
1380 /*
1381 * Read the link.
1382 */
1383 char szPath[RTPATH_MAX];
1384 int rc = RTVfsSymlinkRead(hSymlink, szPath, sizeof(szPath) - 1);
1385 if (RT_SUCCESS(rc))
1386 {
1387 szPath[sizeof(szPath) - 1] = '\0';
1388 if (szPath[0] == '/')
1389 {
1390 /*
1391 * Absolute symlink.
1392 */
1393 rc = RTVfsParsePath(pPath, szPath, NULL);
1394 if (RT_SUCCESS(rc))
1395 {
1396 *piComponent = 0;
1397 return VINF_SUCCESS;
1398 }
1399 }
1400 else
1401 {
1402 /*
1403 * Relative symlink, must replace the current component with the
1404 * link value. We do that by using the remainder of the symlink
1405 * buffer as temporary storage.
1406 */
1407 uint16_t iComponent = *piComponent;
1408 if (iComponent + 1 < pPath->cComponents)
1409 rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iComponent + 1]]);
1410 if (RT_SUCCESS(rc))
1411 {
1412 pPath->cch = pPath->aoffComponents[iComponent] - (iComponent > 0);
1413 pPath->aoffComponents[iComponent + 1] = pPath->cch + 1;
1414 pPath->szPath[pPath->cch] = '\0';
1415 pPath->szPath[pPath->cch + 1] = '\0';
1416
1417 rc = RTVfsParsePathAppend(pPath, szPath, &iComponent);
1418 if (RT_SUCCESS(rc))
1419 {
1420 *piComponent = iComponent;
1421 return VINF_SUCCESS;
1422 }
1423 }
1424 }
1425 }
1426 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
1427}
1428
1429
1430/**
1431 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1432 *
1433 * @returns IPRT status code.
1434 * @param pThis The VFS.
1435 * @param pPath The parsed path. This may be changed as symbolic
1436 * links are processed during the path traversal.
1437 * @param fFlags RTPATH_F_XXX.
1438 * @param ppVfsParentDir Where to return the parent directory handle
1439 * (referenced).
1440 */
1441static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags,
1442 RTVFSDIRINTERNAL **ppVfsParentDir)
1443{
1444 /*
1445 * Assert sanity.
1446 */
1447 AssertPtr(pThis);
1448 Assert(pThis->uMagic == RTVFSDIR_MAGIC);
1449 Assert(pThis->Base.cRefs > 0);
1450 AssertPtr(pPath);
1451 AssertPtr(ppVfsParentDir);
1452 *ppVfsParentDir = NULL;
1453 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1454 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1455
1456 /*
1457 * Start with the pThis directory.
1458 */
1459 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1460 return VERR_INVALID_HANDLE;
1461 RTVFSDIRINTERNAL *pCurDir = pThis;
1462
1463 /*
1464 * The traversal loop.
1465 */
1466 int rc = VINF_SUCCESS;
1467 unsigned cLinks = 0;
1468 uint16_t iComponent = 0;
1469 for (;;)
1470 {
1471 /*
1472 * Are we done yet?
1473 */
1474 bool fFinal = iComponent + 1 >= pPath->cComponents;
1475 if (fFinal && (fFlags & RTPATH_F_ON_LINK))
1476 {
1477 *ppVfsParentDir = pCurDir;
1478 return VINF_SUCCESS;
1479 }
1480
1481 /*
1482 * Try open the next entry.
1483 */
1484 const char *pszEntry = &pPath->szPath[pPath->aoffComponents[iComponent]];
1485 char *pszEntryEnd = &pPath->szPath[pPath->aoffComponents[iComponent + 1] - 1];
1486 *pszEntryEnd = '\0';
1487 RTVFSDIR hDir = NIL_RTVFSDIR;
1488 RTVFSSYMLINK hSymlink = NIL_RTVFSSYMLINK;
1489 RTVFS hVfsMnt = NIL_RTVFS;
1490 if (fFinal)
1491 {
1492 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1493 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, NULL, &hSymlink, NULL);
1494 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1495 *pszEntryEnd = '\0';
1496 if ( rc == VERR_PATH_NOT_FOUND
1497 || rc == VERR_NOT_A_DIRECTORY
1498 || rc == VERR_NOT_SYMLINK)
1499 rc = VINF_SUCCESS;
1500 if (RT_FAILURE(rc))
1501 break;
1502
1503 if (hSymlink == NIL_RTVFSSYMLINK)
1504 {
1505 *ppVfsParentDir = pCurDir;
1506 return VINF_SUCCESS;
1507 }
1508 }
1509 else
1510 {
1511 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1512 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, &hDir, &hSymlink, &hVfsMnt);
1513 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1514 *pszEntryEnd = '/';
1515 if (RT_FAILURE(rc))
1516 break;
1517
1518 if ( hDir == NIL_RTVFSDIR
1519 && hSymlink == NIL_RTVFSSYMLINK
1520 && hVfsMnt == NIL_RTVFS)
1521 {
1522 rc = VERR_NOT_A_DIRECTORY;
1523 break;
1524 }
1525 }
1526 Assert( (hDir != NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1527 || (hDir == NIL_RTVFSDIR && hSymlink != NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1528 || (hDir == NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt != NIL_RTVFS));
1529
1530 if (hDir != NIL_RTVFSDIR)
1531 {
1532 /*
1533 * Directory - advance down the path.
1534 */
1535 AssertPtr(hDir);
1536 Assert(hDir->uMagic == RTVFSDIR_MAGIC);
1537 RTVfsDirRelease(pCurDir);
1538 pCurDir = hDir;
1539 iComponent++;
1540 }
1541 else if (hSymlink != NIL_RTVFSSYMLINK)
1542 {
1543 /*
1544 * Symbolic link - deal with it and retry the current component.
1545 */
1546 AssertPtr(hSymlink);
1547 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
1548 if (fFlags & RTPATH_F_NO_SYMLINKS)
1549 {
1550 rc = VERR_SYMLINK_NOT_ALLOWED;
1551 break;
1552 }
1553 cLinks++;
1554 if (cLinks >= RTVFS_MAX_LINKS)
1555 {
1556 rc = VERR_TOO_MANY_SYMLINKS;
1557 break;
1558 }
1559 uint16_t iRestartComp = iComponent;
1560 rc = rtVfsTraverseHandleSymlink(pPath, &iRestartComp, hSymlink);
1561 if (RT_FAILURE(rc))
1562 break;
1563 if (iRestartComp != iComponent)
1564 {
1565 /* Must restart from the root. */
1566 RTVfsDirRelease(pCurDir);
1567 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1568 {
1569 rc = VERR_INVALID_HANDLE;
1570 pCurDir = NULL;
1571 break;
1572 }
1573 pCurDir = pThis;
1574 iComponent = 0;
1575 }
1576 }
1577 else
1578 {
1579 /*
1580 * Mount point - deal with it and retry the current component.
1581 */
1582 RTVfsDirRelease(pCurDir);
1583 RTVfsLockAcquireRead(hVfsMnt->Base.hLock);
1584 rc = hVfsMnt->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
1585 RTVfsLockReleaseRead(hVfsMnt->Base.hLock);
1586 if (RT_FAILURE(rc))
1587 {
1588 pCurDir = NULL;
1589 break;
1590 }
1591 iComponent = 0;
1592 /** @todo union mounts. */
1593 }
1594 }
1595
1596 if (pCurDir)
1597 RTVfsDirRelease(pCurDir);
1598
1599 return rc;
1600}
1601
1602
1603/**
1604 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1605 *
1606 * @returns IPRT status code.
1607 * @param pThis The VFS.
1608 * @param pPath The parsed path. This may be changed as symbolic
1609 * links are processed during the path traversal.
1610 * @param fFlags RTPATH_F_XXX.
1611 * @param ppVfsParentDir Where to return the parent directory handle
1612 * (referenced).
1613 */
1614static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir)
1615{
1616 /*
1617 * Assert sanity.
1618 */
1619 AssertPtr(pThis);
1620 Assert(pThis->uMagic == RTVFS_MAGIC);
1621 Assert(pThis->Base.cRefs > 0);
1622 AssertPtr(pPath);
1623 AssertPtr(ppVfsParentDir);
1624 *ppVfsParentDir = NULL;
1625 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1626 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1627
1628 /*
1629 * Open the root directory and join paths with the directory traversal.
1630 */
1631 /** @todo Union mounts, traversal optimization methods, races, ++ */
1632 RTVFSDIRINTERNAL *pRootDir;
1633 RTVfsLockAcquireRead(pThis->Base.hLock);
1634 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pRootDir);
1635 RTVfsLockReleaseRead(pThis->Base.hLock);
1636 if (RT_SUCCESS(rc))
1637 {
1638 rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFlags, ppVfsParentDir);
1639 RTVfsDirRelease(pRootDir);
1640 }
1641 return rc;
1642}
1643
1644
1645RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
1646{
1647 NOREF(fEvents);
1648 int rc;
1649 if (fIntr)
1650 rc = RTThreadSleep(cMillies);
1651 else
1652 {
1653 uint64_t uMsStart = RTTimeMilliTS();
1654 do
1655 rc = RTThreadSleep(cMillies);
1656 while ( rc == VERR_INTERRUPTED
1657 && !fIntr
1658 && RTTimeMilliTS() - uMsStart < cMillies);
1659 if (rc == VERR_INTERRUPTED)
1660 rc = VERR_TIMEOUT;
1661 }
1662
1663 *pfRetEvents = 0;
1664 return rc;
1665}
1666
1667
1668RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
1669{
1670 /*
1671 * Allocate a temporary buffer.
1672 */
1673 size_t cbBuf = cbBufHint;
1674 if (!cbBuf)
1675 cbBuf = _64K;
1676 else if (cbBuf < _4K)
1677 cbBuf = _4K;
1678 else if (cbBuf > _1M)
1679 cbBuf = _1M;
1680
1681 void *pvBuf = RTMemTmpAlloc(cbBuf);
1682 if (!pvBuf)
1683 {
1684 cbBuf = _4K;
1685 pvBuf = RTMemTmpAlloc(cbBuf);
1686 if (!pvBuf)
1687 return VERR_NO_TMP_MEMORY;
1688 }
1689
1690 /*
1691 * Pump loop.
1692 */
1693 int rc;
1694 for (;;)
1695 {
1696 size_t cbRead;
1697 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
1698 if (RT_FAILURE(rc))
1699 break;
1700 if (rc == VINF_EOF && cbRead == 0)
1701 break;
1702
1703 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
1704 if (RT_FAILURE(rc))
1705 break;
1706 }
1707
1708 RTMemTmpFree(pvBuf);
1709
1710 /*
1711 * Flush the destination stream on success to make sure we've caught
1712 * errors caused by buffering delays.
1713 */
1714 if (RT_SUCCESS(rc))
1715 rc = RTVfsIoStrmFlush(hVfsIosDst);
1716
1717 return rc;
1718}
1719
1720
1721
1722
1723
1724/*
1725 * F I L E S Y S T E M R O O T
1726 * F I L E S Y S T E M R O O T
1727 * F I L E S Y S T E M R O O T
1728 */
1729
1730
1731RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
1732 PRTVFS phVfs, void **ppvInstance)
1733{
1734 /*
1735 * Validate the input, be extra strict in strict builds.
1736 */
1737 AssertPtr(pVfsOps);
1738 AssertReturn(pVfsOps->uVersion == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
1739 AssertReturn(pVfsOps->uEndMarker == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
1740 RTVFSOBJ_ASSERT_OPS(&pVfsOps->Obj, RTVFSOBJTYPE_VFS);
1741 Assert(cbInstance > 0);
1742 AssertPtr(ppvInstance);
1743 AssertPtr(phVfs);
1744
1745 /*
1746 * Allocate the handle + instance data.
1747 */
1748 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSINTERNAL), RTVFS_INST_ALIGNMENT)
1749 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1750 RTVFSINTERNAL *pThis = (RTVFSINTERNAL *)RTMemAllocZ(cbThis);
1751 if (!pThis)
1752 return VERR_NO_MEMORY;
1753
1754 int rc = rtVfsObjInitNewObject(&pThis->Base, &pVfsOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
1755 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1756 if (RT_FAILURE(rc))
1757 {
1758 RTMemFree(pThis);
1759 return rc;
1760 }
1761
1762 pThis->uMagic = RTVFS_MAGIC;
1763 pThis->pOps = pVfsOps;
1764
1765 *phVfs = pThis;
1766 *ppvInstance = pThis->Base.pvThis;
1767
1768 LogFlow(("RTVfsNew -> VINF_SUCCESS; hVfs=%p pvThis=%p\n", pThis, pThis->Base.pvThis));
1769 return VINF_SUCCESS;
1770}
1771
1772#ifdef DEBUG
1773# undef RTVfsRetain
1774#endif
1775RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs)
1776{
1777 RTVFSINTERNAL *pThis = hVfs;
1778 AssertPtrReturn(pThis, UINT32_MAX);
1779 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1780 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
1781 LogFlow(("RTVfsRetain(%p/%p) -> %d\n", pThis, pThis->Base.pvThis, cRefs));
1782 return cRefs;
1783}
1784#ifdef DEBUG
1785# define RTVfsRetain(hVfs) RTVfsRetainDebug(hVfs, RT_SRC_POS)
1786#endif
1787
1788
1789RTDECL(uint32_t) RTVfsRetainDebug(RTVFS hVfs, RT_SRC_POS_DECL)
1790{
1791 RTVFSINTERNAL *pThis = hVfs;
1792 AssertPtrReturn(pThis, UINT32_MAX);
1793 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1794 RT_SRC_POS_NOREF();
1795 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsRetainDebug", RT_SRC_POS_ARGS);
1796}
1797
1798
1799RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs)
1800{
1801 RTVFSINTERNAL *pThis = hVfs;
1802 if (pThis == NIL_RTVFS)
1803 return 0;
1804 AssertPtrReturn(pThis, UINT32_MAX);
1805 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1806#ifdef LOG_ENABLED
1807 void *pvThis = pThis->Base.pvThis;
1808#endif
1809 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
1810 Log(("RTVfsRelease(%p/%p) -> %d\n", pThis, pvThis, cRefs));
1811 return cRefs;
1812}
1813
1814
1815RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir)
1816{
1817 RTVFSINTERNAL *pThis = hVfs;
1818 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1819 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1820 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
1821 *phDir = NIL_RTVFSDIR;
1822
1823 if (!pThis->pOps->pfnIsRangeInUse)
1824 return VERR_NOT_SUPPORTED;
1825 RTVfsLockAcquireRead(pThis->Base.hLock);
1826 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phDir);
1827 RTVfsLockReleaseRead(pThis->Base.hLock);
1828
1829 return rc;
1830}
1831
1832
1833RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
1834{
1835 RTVFSINTERNAL *pThis = hVfs;
1836 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1837 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1838 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1839 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
1840 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
1841 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
1842 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
1843
1844 /*
1845 * Parse the path, assume current directory is root since we've got no
1846 * caller context here. Then traverse to the parent directory.
1847 */
1848 PRTVFSPARSEDPATH pPath;
1849 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
1850 if (RT_SUCCESS(rc))
1851 {
1852 RTVFSDIRINTERNAL *pVfsParentDir;
1853 if (pPath->cComponents > 0)
1854 {
1855 rc = rtVfsTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
1856 if (RT_SUCCESS(rc))
1857 {
1858 /*
1859 * Call the query method on the parent directory.
1860 */
1861 /** @todo race condition here :/ */
1862 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
1863 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
1864 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
1865 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
1866
1867 RTVfsDirRelease(pVfsParentDir);
1868 }
1869 }
1870 /*
1871 * The path boils down to '.', open the root dir and query its info.
1872 */
1873 else
1874 {
1875 RTVfsLockAcquireRead(pThis->Base.hLock);
1876 RTVFSDIR hRootDir = NIL_RTVFSDIR;
1877 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &hRootDir);
1878 RTVfsLockReleaseRead(pThis->Base.hLock);
1879 if (RT_SUCCESS(rc))
1880 {
1881 RTVfsLockAcquireRead(hRootDir->Base.hLock);
1882 rc = hRootDir->Base.pOps->pfnQueryInfo(hRootDir->Base.pvThis, pObjInfo, enmAddAttr);
1883 RTVfsLockReleaseRead(hRootDir->Base.hLock);
1884 RTVfsDirRelease(hRootDir);
1885 }
1886 }
1887
1888 RTVfsParsePathFree(pPath);
1889 }
1890 return rc;
1891}
1892
1893
1894
1895RTDECL(int) RTVfsIsRangeInUse(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed)
1896{
1897 RTVFSINTERNAL *pThis = hVfs;
1898 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1899 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1900
1901 if (!pThis->pOps->pfnIsRangeInUse)
1902 return VERR_NOT_SUPPORTED;
1903 RTVfsLockAcquireRead(pThis->Base.hLock);
1904 int rc = pThis->pOps->pfnIsRangeInUse(pThis->Base.pvThis, off, cb, pfUsed);
1905 RTVfsLockReleaseRead(pThis->Base.hLock);
1906
1907 return rc;
1908}
1909
1910
1911
1912
1913/*
1914 *
1915 * F I L E S Y S T E M S T R E A M
1916 * F I L E S Y S T E M S T R E A M
1917 * F I L E S Y S T E M S T R E A M
1918 *
1919 */
1920
1921
1922RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, bool fReadOnly,
1923 PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
1924{
1925 /*
1926 * Validate the input, be extra strict in strict builds.
1927 */
1928 AssertPtr(pFsStreamOps);
1929 AssertReturn(pFsStreamOps->uVersion == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1930 AssertReturn(pFsStreamOps->uEndMarker == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1931 Assert(!pFsStreamOps->fReserved);
1932 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
1933 if (fReadOnly)
1934 AssertPtr(pFsStreamOps->pfnNext);
1935 else
1936 {
1937 AssertPtr(pFsStreamOps->pfnAdd);
1938 AssertPtr(pFsStreamOps->pfnEnd);
1939 }
1940 Assert(cbInstance > 0);
1941 AssertPtr(ppvInstance);
1942 AssertPtr(phVfsFss);
1943 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
1944
1945 /*
1946 * Allocate the handle + instance data.
1947 */
1948 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFSSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
1949 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1950 RTVFSFSSTREAMINTERNAL *pThis = (RTVFSFSSTREAMINTERNAL *)RTMemAllocZ(cbThis);
1951 if (!pThis)
1952 return VERR_NO_MEMORY;
1953
1954 int rc = rtVfsObjInitNewObject(&pThis->Base, &pFsStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
1955 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1956
1957 if (RT_FAILURE(rc))
1958 {
1959 RTMemFree(pThis);
1960 return rc;
1961 }
1962
1963 pThis->uMagic = RTVFSFSSTREAM_MAGIC;
1964 pThis->fFlags = fReadOnly
1965 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
1966 : RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL;
1967 pThis->pOps = pFsStreamOps;
1968
1969 *phVfsFss = pThis;
1970 *ppvInstance = pThis->Base.pvThis;
1971 return VINF_SUCCESS;
1972}
1973
1974
1975#ifdef DEBUG
1976# undef RTVfsFsStrmRetain
1977#endif
1978RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss)
1979{
1980 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1981 AssertPtrReturn(pThis, UINT32_MAX);
1982 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
1983 return rtVfsObjRetain(&pThis->Base);
1984}
1985#ifdef DEBUG
1986# define RTVfsFsStrmRetain(hVfsFss) RTVfsFsStrmRetainDebug(hVfsFss, RT_SRC_POS)
1987#endif
1988
1989
1990RTDECL(uint32_t) RTVfsFsStrmRetainDebug(RTVFSFSSTREAM hVfsFss, RT_SRC_POS_DECL)
1991{
1992 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1993 AssertPtrReturn(pThis, UINT32_MAX);
1994 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
1995 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsFsStrmRetain", RT_SRC_POS_ARGS);
1996}
1997
1998
1999RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss)
2000{
2001 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2002 if (pThis == NIL_RTVFSFSSTREAM)
2003 return 0;
2004 AssertPtrReturn(pThis, UINT32_MAX);
2005 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2006 return rtVfsObjRelease(&pThis->Base);
2007}
2008
2009
2010RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2011{
2012 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2013 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2014 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2015 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2016}
2017
2018
2019RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
2020{
2021 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2022 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2023 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2024 AssertPtrNullReturn(ppszName, VERR_INVALID_POINTER);
2025 if (ppszName)
2026 *ppszName = NULL;
2027 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2028 if (penmType)
2029 *penmType = RTVFSOBJTYPE_INVALID;
2030 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2031 if (phVfsObj)
2032 *phVfsObj = NIL_RTVFSOBJ;
2033
2034 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_INVALID_FUNCTION);
2035
2036 return pThis->pOps->pfnNext(pThis->Base.pvThis, ppszName, penmType, phVfsObj);
2037}
2038
2039
2040RTDECL(int) RTVfsFsStrmAdd(RTVFSFSSTREAM hVfsFss, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)
2041{
2042 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2043 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2044 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2045 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2046 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2047 AssertPtrReturn(hVfsObj, VERR_INVALID_HANDLE);
2048 AssertReturn(hVfsObj->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
2049 AssertReturn(!(fFlags & ~RTVFSFSSTRM_ADD_F_VALID_MASK), VERR_INVALID_FLAGS);
2050 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2051
2052 return pThis->pOps->pfnAdd(pThis->Base.pvThis, pszPath, hVfsObj, fFlags);
2053}
2054
2055
2056RTDECL(int) RTVfsFsStrmPushFile(RTVFSFSSTREAM hVfsFss, const char *pszPath, uint64_t cbFile,
2057 PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
2058{
2059 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2060 AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
2061 *phVfsIos = NIL_RTVFSIOSTREAM;
2062
2063 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2064 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2065
2066 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2067 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2068
2069 AssertReturn(!(fFlags & ~RTVFSFSSTRM_PUSH_F_VALID_MASK), VERR_INVALID_FLAGS);
2070 AssertReturn(RT_BOOL(cbFile == UINT64_MAX) == RT_BOOL(fFlags & RTVFSFSSTRM_PUSH_F_STREAM), VERR_INVALID_FLAGS);
2071
2072 if (cObjInfo)
2073 {
2074 AssertPtrReturn(paObjInfo, VERR_INVALID_POINTER);
2075 AssertReturn(paObjInfo[0].Attr.enmAdditional == RTFSOBJATTRADD_UNIX, VERR_INVALID_PARAMETER);
2076 }
2077
2078 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2079 if (pThis->pOps->pfnPushFile)
2080 return pThis->pOps->pfnPushFile(pThis->Base.pvThis, pszPath, cbFile, paObjInfo, cObjInfo, fFlags, phVfsIos);
2081 return VERR_NOT_SUPPORTED;
2082}
2083
2084
2085RTDECL(int) RTVfsFsStrmEnd(RTVFSFSSTREAM hVfsFss)
2086{
2087 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2088 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2089 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2090
2091 return pThis->pOps->pfnEnd(pThis->Base.pvThis);
2092}
2093
2094
2095RTDECL(void *) RTVfsFsStreamToPrivate(RTVFSFSSTREAM hVfsFss, PCRTVFSFSSTREAMOPS pFsStreamOps)
2096{
2097 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2098 AssertPtrReturn(pThis, NULL);
2099 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, NULL);
2100 if (pThis->pOps != pFsStreamOps)
2101 return NULL;
2102 return pThis->Base.pvThis;
2103}
2104
2105
2106/*
2107 *
2108 * D I R D I R D I R
2109 * D I R D I R D I R
2110 * D I R D I R D I R
2111 *
2112 */
2113
2114
2115RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock,
2116 PRTVFSDIR phVfsDir, void **ppvInstance)
2117{
2118 /*
2119 * Validate the input, be extra strict in strict builds.
2120 */
2121 AssertPtr(pDirOps);
2122 AssertReturn(pDirOps->uVersion == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2123 AssertReturn(pDirOps->uEndMarker == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2124 Assert(!pDirOps->fReserved);
2125 RTVFSDIR_ASSERT_OPS(pDirOps, RTVFSOBJTYPE_DIR);
2126 Assert(cbInstance > 0);
2127 AssertReturn(!(fFlags & ~RTVFSDIR_F_NO_VFS_REF), VERR_INVALID_FLAGS);
2128 AssertPtr(ppvInstance);
2129 AssertPtr(phVfsDir);
2130 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2131
2132 /*
2133 * Allocate the handle + instance data.
2134 */
2135 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSDIRINTERNAL), RTVFS_INST_ALIGNMENT)
2136 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2137 RTVFSDIRINTERNAL *pThis = (RTVFSDIRINTERNAL *)RTMemAllocZ(cbThis);
2138 if (!pThis)
2139 return VERR_NO_MEMORY;
2140
2141 int rc = rtVfsObjInitNewObject(&pThis->Base, &pDirOps->Obj, hVfs, RT_BOOL(fFlags & RTVFSDIR_F_NO_VFS_REF), hLock,
2142 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2143 if (RT_FAILURE(rc))
2144 {
2145 RTMemFree(pThis);
2146 return rc;
2147 }
2148
2149 pThis->uMagic = RTVFSDIR_MAGIC;
2150 pThis->fReserved = 0;
2151 pThis->pOps = pDirOps;
2152
2153 *phVfsDir = pThis;
2154 *ppvInstance = pThis->Base.pvThis;
2155 return VINF_SUCCESS;
2156}
2157
2158
2159#ifdef DEBUG
2160# undef RTVfsDirRetain
2161#endif
2162RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir)
2163{
2164 RTVFSDIRINTERNAL *pThis = hVfsDir;
2165 AssertPtrReturn(pThis, UINT32_MAX);
2166 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2167 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2168 LogFlow(("RTVfsDirRetain(%p/%p) -> %#x\n", pThis, pThis->Base.pvThis, cRefs));
2169 return cRefs;
2170}
2171#ifdef DEBUG
2172# define RTVfsDirRetain(hVfsDir) RTVfsDirRetainDebug(hVfsDir, RT_SRC_POS)
2173#endif
2174
2175
2176RTDECL(uint32_t) RTVfsDirRetainDebug(RTVFSDIR hVfsDir, RT_SRC_POS_DECL)
2177{
2178 RTVFSDIRINTERNAL *pThis = hVfsDir;
2179 AssertPtrReturn(pThis, UINT32_MAX);
2180 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2181 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsDirRetain", RT_SRC_POS_ARGS);
2182}
2183
2184
2185RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir)
2186{
2187 RTVFSDIRINTERNAL *pThis = hVfsDir;
2188 if (pThis == NIL_RTVFSDIR)
2189 return 0;
2190 AssertPtrReturn(pThis, UINT32_MAX);
2191 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2192#ifdef LOG_ENABLED
2193 void *pvThis = pThis->Base.pvThis;
2194#endif
2195 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2196 LogFlow(("RTVfsDirRelease(%p/%p) -> %#x\n", pThis, pvThis, cRefs));
2197 return cRefs;
2198}
2199
2200
2201RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2202{
2203 /*
2204 * Validate input.
2205 */
2206 RTVFSINTERNAL *pThis = hVfs;
2207 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2208 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2209 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2210 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2211 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2212
2213 /*
2214 * Parse the path, assume current directory is root since we've got no
2215 * caller context here.
2216 */
2217 PRTVFSPARSEDPATH pPath;
2218 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2219 if (RT_SUCCESS(rc))
2220 {
2221 if (pPath->cComponents > 0)
2222 {
2223 /*
2224 * Tranverse the path, resolving the parent node and any symlinks
2225 * in the final element, and ask the directory to open the subdir.
2226 */
2227 RTVFSDIRINTERNAL *pVfsParentDir;
2228 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2229 if (RT_SUCCESS(rc))
2230 {
2231 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2232
2233 /** @todo there is a symlink creation race here. */
2234 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2235 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2236 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2237
2238 RTVfsDirRelease(pVfsParentDir);
2239
2240 if (RT_SUCCESS(rc))
2241 {
2242 AssertPtr(*phVfsDir);
2243 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2244 }
2245 }
2246 }
2247 /*
2248 * If the path boils down to '.' return the root directory.
2249 */
2250 else
2251 {
2252 RTVfsLockAcquireRead(pThis->Base.hLock);
2253 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phVfsDir);
2254 RTVfsLockReleaseRead(pThis->Base.hLock);
2255 }
2256 RTVfsParsePathFree(pPath);
2257 }
2258 return rc;
2259}
2260
2261
2262RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2263{
2264 /*
2265 * Validate input.
2266 */
2267 RTVFSDIRINTERNAL *pThis = hVfsDir;
2268 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2269 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2270 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2271 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2272 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2273
2274 /*
2275 * Parse the path, it's always relative to the given directory.
2276 */
2277 PRTVFSPARSEDPATH pPath;
2278 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2279 if (RT_SUCCESS(rc))
2280 {
2281 if (pPath->cComponents > 0)
2282 {
2283 /*
2284 * Tranverse the path, resolving the parent node and any symlinks
2285 * in the final element, and ask the directory to open the subdir.
2286 */
2287 RTVFSDIRINTERNAL *pVfsParentDir;
2288 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2289 if (RT_SUCCESS(rc))
2290 {
2291 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2292
2293 /** @todo there is a symlink creation race here. */
2294 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2295 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2296 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2297
2298 RTVfsDirRelease(pVfsParentDir);
2299
2300 if (RT_SUCCESS(rc))
2301 {
2302 AssertPtr(*phVfsDir);
2303 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2304 }
2305 }
2306 }
2307 /*
2308 * The path boils down to '.', call pfnOpenDir on pThis with '.' as input.
2309 * The caller may wish for a new directory instance to enumerate the entries
2310 * in parallel or some such thing.
2311 */
2312 else
2313 {
2314 RTVfsLockAcquireWrite(pThis->Base.hLock);
2315 rc = pThis->pOps->pfnOpenDir(pThis->Base.pvThis, ".", fFlags, phVfsDir);
2316 RTVfsLockReleaseWrite(pThis->Base.hLock);
2317 }
2318 RTVfsParsePathFree(pPath);
2319 }
2320 return rc;
2321}
2322
2323
2324RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2325{
2326 /*
2327 * Validate input.
2328 */
2329 RTVFSDIRINTERNAL *pThis = hVfsDir;
2330 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2331 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2332 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2333 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2334
2335 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2336 if (RT_FAILURE(rc))
2337 return rc;
2338
2339 /*
2340 * Parse the path, assume current directory is root since we've got no
2341 * caller context here.
2342 */
2343 PRTVFSPARSEDPATH pPath;
2344 rc = RTVfsParsePathA(pszPath, "/", &pPath);
2345 if (RT_SUCCESS(rc))
2346 {
2347 if ( !pPath->fDirSlash
2348 && pPath->cComponents > 0)
2349 {
2350 /*
2351 * Tranverse the path, resolving the parent node and any symlinks
2352 * in the final element, and ask the directory to open the file.
2353 */
2354 RTVFSDIRINTERNAL *pVfsParentDir;
2355 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2356 if (RT_SUCCESS(rc))
2357 {
2358 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2359
2360 /** @todo there is a symlink creation race here. */
2361 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2362 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2363 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2364
2365 RTVfsDirRelease(pVfsParentDir);
2366
2367 if (RT_SUCCESS(rc))
2368 {
2369 AssertPtr(*phVfsFile);
2370 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2371 }
2372 }
2373 }
2374 else
2375 rc = VERR_NOT_A_FILE;
2376 RTVfsParsePathFree(pPath);
2377 }
2378 return rc;
2379}
2380
2381
2382RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
2383{
2384 RTVFSFILE hVfsFile;
2385 int rc = RTVfsDirOpenFile(hVfsDir, pszPath, fOpen, &hVfsFile);
2386 if (RT_SUCCESS(rc))
2387 {
2388 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
2389 AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
2390 RTVfsFileRelease(hVfsFile);
2391 }
2392 return rc;
2393}
2394
2395
2396
2397RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo,
2398 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2399{
2400 /*
2401 * Validate input.
2402 */
2403 RTVFSDIRINTERNAL *pThis = hVfsDir;
2404 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2405 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2406 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2407 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2408 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2409 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2410 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2411
2412 /*
2413 * Parse the path, assume current directory is root since we've got no
2414 * caller context here. Then traverse to the parent directory.
2415 */
2416 PRTVFSPARSEDPATH pPath;
2417 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2418 if (RT_SUCCESS(rc))
2419 {
2420 if (pPath->cComponents > 0)
2421 {
2422 RTVFSDIRINTERNAL *pVfsParentDir;
2423 rc = rtVfsDirTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
2424 if (RT_SUCCESS(rc))
2425 {
2426 /*
2427 * Call the query method on the parent directory.
2428 */
2429 /** @todo symlink race condition here :/ */
2430 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2431 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2432 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2433 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2434
2435 RTVfsDirRelease(pVfsParentDir);
2436 }
2437 else
2438 rc = VERR_INVALID_PARAMETER;
2439 }
2440 /*
2441 * The path boils down to '.' so just query the directory.
2442 */
2443 else
2444 {
2445 RTVfsLockAcquireRead(pThis->Base.hLock);
2446 rc = pThis->Base.pOps->pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr);
2447 RTVfsLockReleaseRead(pThis->Base.hLock);
2448 }
2449 RTVfsParsePathFree(pPath);
2450 }
2451 return rc;
2452}
2453
2454
2455RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
2456{
2457 /*
2458 * Validate input.
2459 */
2460 RTVFSDIRINTERNAL *pThis = hVfsDir;
2461 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2462 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2463 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
2464 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2465
2466 size_t cbDirEntry = sizeof(*pDirEntry);
2467 if (!pcbDirEntry)
2468 pcbDirEntry = &cbDirEntry;
2469 else
2470 {
2471 cbDirEntry = *pcbDirEntry;
2472 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
2473 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
2474 VERR_INVALID_PARAMETER);
2475 }
2476
2477 /*
2478 * Call the directory method.
2479 */
2480 RTVfsLockAcquireRead(pThis->Base.hLock);
2481 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
2482 RTVfsLockReleaseRead(pThis->Base.hLock);
2483 return rc;
2484}
2485
2486
2487/*
2488 *
2489 * S Y M B O L I C L I N K
2490 * S Y M B O L I C L I N K
2491 * S Y M B O L I C L I N K
2492 *
2493 */
2494
2495RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
2496 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
2497{
2498 /*
2499 * Validate the input, be extra strict in strict builds.
2500 */
2501 AssertPtr(pSymlinkOps);
2502 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
2503 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
2504 Assert(!pSymlinkOps->fReserved);
2505 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
2506 Assert(cbInstance > 0);
2507 AssertPtr(ppvInstance);
2508 AssertPtr(phVfsSym);
2509 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2510
2511 /*
2512 * Allocate the handle + instance data.
2513 */
2514 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
2515 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2516 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
2517 if (!pThis)
2518 return VERR_NO_MEMORY;
2519
2520 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2521 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2522 if (RT_FAILURE(rc))
2523 {
2524 RTMemFree(pThis);
2525 return rc;
2526 }
2527
2528 pThis->uMagic = RTVFSSYMLINK_MAGIC;
2529 pThis->pOps = pSymlinkOps;
2530
2531 *phVfsSym = pThis;
2532 *ppvInstance = pThis->Base.pvThis;
2533 return VINF_SUCCESS;
2534}
2535
2536
2537RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
2538{
2539 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2540 AssertPtrReturn(pThis, UINT32_MAX);
2541 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2542 return rtVfsObjRetain(&pThis->Base);
2543}
2544
2545
2546RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL)
2547{
2548 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2549 AssertPtrReturn(pThis, UINT32_MAX);
2550 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2551 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsSymlinkRetainDebug", RT_SRC_POS_ARGS);
2552}
2553
2554
2555RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
2556{
2557 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2558 if (pThis == NIL_RTVFSSYMLINK)
2559 return 0;
2560 AssertPtrReturn(pThis, UINT32_MAX);
2561 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2562 return rtVfsObjRelease(&pThis->Base);
2563}
2564
2565
2566RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2567{
2568 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2569 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2570 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2571 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2572}
2573
2574
2575RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
2576{
2577 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2578 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2579 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2580
2581 fMode = rtFsModeNormalize(fMode, NULL, 0);
2582 if (!rtFsModeIsValid(fMode))
2583 return VERR_INVALID_PARAMETER;
2584
2585 RTVfsLockAcquireWrite(pThis->Base.hLock);
2586 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
2587 RTVfsLockReleaseWrite(pThis->Base.hLock);
2588 return rc;
2589}
2590
2591
2592RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
2593 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
2594{
2595 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2596 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2597 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2598
2599 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
2600 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
2601 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
2602 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
2603
2604 RTVfsLockAcquireWrite(pThis->Base.hLock);
2605 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
2606 RTVfsLockReleaseWrite(pThis->Base.hLock);
2607 return rc;
2608}
2609
2610
2611RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
2612{
2613 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2614 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2615 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2616
2617 RTVfsLockAcquireWrite(pThis->Base.hLock);
2618 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
2619 RTVfsLockReleaseWrite(pThis->Base.hLock);
2620 return rc;
2621}
2622
2623
2624RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
2625{
2626 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2627 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2628 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2629
2630 RTVfsLockAcquireWrite(pThis->Base.hLock);
2631 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
2632 RTVfsLockReleaseWrite(pThis->Base.hLock);
2633
2634 return rc;
2635}
2636
2637
2638
2639/*
2640 *
2641 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2642 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2643 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2644 *
2645 */
2646
2647RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
2648 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
2649{
2650 /*
2651 * Validate the input, be extra strict in strict builds.
2652 */
2653 AssertPtr(pIoStreamOps);
2654 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2655 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2656 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
2657 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
2658 Assert(cbInstance > 0);
2659 Assert(fOpen & RTFILE_O_ACCESS_MASK);
2660 AssertPtr(ppvInstance);
2661 AssertPtr(phVfsIos);
2662 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2663
2664 /*
2665 * Allocate the handle + instance data.
2666 */
2667 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
2668 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2669 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
2670 if (!pThis)
2671 return VERR_NO_MEMORY;
2672
2673 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2674 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2675 if (RT_FAILURE(rc))
2676 {
2677 RTMemFree(pThis);
2678 return rc;
2679 }
2680
2681 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
2682 pThis->fFlags = fOpen;
2683 pThis->pOps = pIoStreamOps;
2684
2685 *phVfsIos = pThis;
2686 *ppvInstance = pThis->Base.pvThis;
2687 return VINF_SUCCESS;
2688}
2689
2690
2691RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
2692{
2693 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2694 AssertPtrReturn(pThis, NULL);
2695 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
2696 if (pThis->pOps != pIoStreamOps)
2697 return NULL;
2698 return pThis->Base.pvThis;
2699}
2700
2701
2702#ifdef DEBUG
2703# undef RTVfsIoStrmRetain
2704#endif
2705RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
2706{
2707 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2708 AssertPtrReturn(pThis, UINT32_MAX);
2709 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2710 return rtVfsObjRetain(&pThis->Base);
2711}
2712#ifdef DEBUG
2713# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS)
2714#endif
2715
2716
2717RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL)
2718{
2719 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2720 AssertPtrReturn(pThis, UINT32_MAX);
2721 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2722 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsIoStrmRetainDebug", RT_SRC_POS_ARGS);
2723}
2724
2725
2726RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
2727{
2728 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2729 if (pThis == NIL_RTVFSIOSTREAM)
2730 return 0;
2731 AssertPtrReturn(pThis, UINT32_MAX);
2732 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2733 return rtVfsObjRelease(&pThis->Base);
2734}
2735
2736
2737RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
2738{
2739 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2740 AssertPtrReturn(pThis, NIL_RTVFSFILE);
2741 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
2742
2743 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
2744 {
2745 rtVfsObjRetainVoid(&pThis->Base, "RTVfsIoStrmToFile");
2746 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
2747 }
2748
2749 /* this is no crime, so don't assert. */
2750 return NIL_RTVFSFILE;
2751}
2752
2753
2754RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2755{
2756 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2757 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2758 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2759 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2760}
2761
2762
2763RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
2764{
2765 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2766 if (pcbRead)
2767 *pcbRead = 0;
2768 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2769 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2770 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2771 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2772 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2773
2774 RTSGSEG Seg = { pvBuf, cbToRead };
2775 RTSGBUF SgBuf;
2776 RTSgBufInit(&SgBuf, &Seg, 1);
2777
2778 RTVfsLockAcquireWrite(pThis->Base.hLock);
2779 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
2780 RTVfsLockReleaseWrite(pThis->Base.hLock);
2781 return rc;
2782}
2783
2784
2785RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
2786 bool fBlocking, size_t *pcbRead)
2787{
2788 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2789 if (pcbRead)
2790 *pcbRead = 0;
2791 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2792 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2793 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2794 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2795 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2796
2797 RTSGSEG Seg = { pvBuf, cbToRead };
2798 RTSGBUF SgBuf;
2799 RTSgBufInit(&SgBuf, &Seg, 1);
2800
2801 RTVfsLockAcquireWrite(pThis->Base.hLock);
2802 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
2803 RTVfsLockReleaseWrite(pThis->Base.hLock);
2804 return rc;
2805}
2806
2807
2808RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
2809{
2810 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2811 if (pcbWritten)
2812 *pcbWritten = 0;
2813 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2814 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2815 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2816 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2817 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2818
2819 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
2820 RTSGBUF SgBuf;
2821 RTSgBufInit(&SgBuf, &Seg, 1);
2822
2823 RTVfsLockAcquireWrite(pThis->Base.hLock);
2824 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
2825 RTVfsLockReleaseWrite(pThis->Base.hLock);
2826 return rc;
2827}
2828
2829
2830RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
2831 bool fBlocking, size_t *pcbWritten)
2832{
2833 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2834 if (pcbWritten)
2835 *pcbWritten = 0;
2836 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2837 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2838 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2839 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2840 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2841
2842 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
2843 RTSGBUF SgBuf;
2844 RTSgBufInit(&SgBuf, &Seg, 1);
2845
2846 RTVfsLockAcquireWrite(pThis->Base.hLock);
2847 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
2848 RTVfsLockReleaseWrite(pThis->Base.hLock);
2849 return rc;
2850}
2851
2852
2853RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
2854{
2855 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2856 if (pcbRead)
2857 *pcbRead = 0;
2858 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2859 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2860 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2861 AssertPtr(pSgBuf);
2862 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2863 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2864
2865 RTVfsLockAcquireWrite(pThis->Base.hLock);
2866 int rc;
2867 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
2868 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
2869 else
2870 {
2871 size_t cbRead = 0;
2872 rc = VINF_SUCCESS;
2873
2874 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
2875 {
2876 RTSGBUF SgBuf;
2877 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
2878
2879 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
2880 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
2881 if (RT_FAILURE(rc))
2882 break;
2883 cbRead += cbReadSeg;
2884 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
2885 break;
2886 if (off != -1)
2887 off += cbReadSeg;
2888 }
2889
2890 if (pcbRead)
2891 *pcbRead = cbRead;
2892 }
2893 RTVfsLockReleaseWrite(pThis->Base.hLock);
2894 return rc;
2895}
2896
2897
2898RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
2899{
2900 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2901 if (pcbWritten)
2902 *pcbWritten = 0;
2903 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2904 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2905 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2906 AssertPtr(pSgBuf);
2907 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2908 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2909
2910 RTVfsLockAcquireWrite(pThis->Base.hLock);
2911 int rc;
2912 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
2913 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
2914 else
2915 {
2916 size_t cbWritten = 0;
2917 rc = VINF_SUCCESS;
2918
2919 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
2920 {
2921 RTSGBUF SgBuf;
2922 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
2923
2924 size_t cbWrittenSeg = 0;
2925 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
2926 if (RT_FAILURE(rc))
2927 break;
2928 if (pcbWritten)
2929 {
2930 cbWritten += cbWrittenSeg;
2931 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
2932 break;
2933 if (off != -1)
2934 off += cbWrittenSeg;
2935 }
2936 else if (off != -1)
2937 off += pSgBuf->paSegs[iSeg].cbSeg;
2938 }
2939
2940 if (pcbWritten)
2941 *pcbWritten = cbWritten;
2942 }
2943 RTVfsLockReleaseWrite(pThis->Base.hLock);
2944 return rc;
2945}
2946
2947
2948RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
2949{
2950 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2951 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2952 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2953
2954 RTVfsLockAcquireWrite(pThis->Base.hLock);
2955 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
2956 RTVfsLockReleaseWrite(pThis->Base.hLock);
2957 return rc;
2958}
2959
2960
2961RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
2962 uint32_t *pfRetEvents)
2963{
2964 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2965 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2966 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2967
2968 RTVfsLockAcquireWrite(pThis->Base.hLock);
2969 int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
2970 RTVfsLockReleaseWrite(pThis->Base.hLock);
2971 return rc;
2972}
2973
2974
2975RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
2976{
2977 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2978 AssertPtrReturn(pThis, -1);
2979 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2980
2981 RTFOFF off;
2982 RTVfsLockAcquireRead(pThis->Base.hLock);
2983 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
2984 RTVfsLockReleaseRead(pThis->Base.hLock);
2985 if (RT_FAILURE(rc))
2986 off = rc;
2987 return off;
2988}
2989
2990
2991RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
2992{
2993 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2994 AssertPtrReturn(pThis, -1);
2995 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2996 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
2997
2998 int rc;
2999 if (pThis->pOps->pfnSkip)
3000 {
3001 RTVfsLockAcquireWrite(pThis->Base.hLock);
3002 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
3003 RTVfsLockReleaseWrite(pThis->Base.hLock);
3004 }
3005 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3006 {
3007 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3008 RTFOFF offIgnored;
3009
3010 RTVfsLockAcquireWrite(pThis->Base.hLock);
3011 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
3012 RTVfsLockReleaseWrite(pThis->Base.hLock);
3013 }
3014 else
3015 {
3016 void *pvBuf = RTMemTmpAlloc(_64K);
3017 if (pvBuf)
3018 {
3019 rc = VINF_SUCCESS;
3020 while (cb > 0)
3021 {
3022 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
3023 RTVfsLockAcquireWrite(pThis->Base.hLock);
3024 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
3025 RTVfsLockReleaseWrite(pThis->Base.hLock);
3026 if (RT_FAILURE(rc))
3027 break;
3028 cb -= cbToRead;
3029 }
3030
3031 RTMemTmpFree(pvBuf);
3032 }
3033 else
3034 rc = VERR_NO_TMP_MEMORY;
3035 }
3036 return rc;
3037}
3038
3039
3040RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3041{
3042 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3043 AssertPtrReturn(pThis, -1);
3044 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3045
3046 int rc;
3047 if (pThis->pOps->pfnZeroFill)
3048 {
3049 RTVfsLockAcquireWrite(pThis->Base.hLock);
3050 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
3051 RTVfsLockReleaseWrite(pThis->Base.hLock);
3052 }
3053 else
3054 {
3055 rc = VINF_SUCCESS;
3056 while (cb > 0)
3057 {
3058 size_t cbToWrite = (size_t)RT_MIN(cb, (ssize_t)sizeof(g_abRTZero64K));
3059 RTVfsLockAcquireWrite(pThis->Base.hLock);
3060 rc = RTVfsIoStrmWrite(hVfsIos, g_abRTZero64K, cbToWrite, true /*fBlocking*/, NULL);
3061 RTVfsLockReleaseWrite(pThis->Base.hLock);
3062 if (RT_FAILURE(rc))
3063 break;
3064 cb -= cbToWrite;
3065 }
3066 }
3067 return rc;
3068}
3069
3070
3071RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
3072{
3073 /*
3074 * There is where the zero read behavior comes in handy.
3075 */
3076 char bDummy;
3077 size_t cbRead;
3078 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
3079 return rc == VINF_EOF;
3080}
3081
3082
3083
3084RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos)
3085{
3086 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3087 AssertPtrReturn(pThis, 0);
3088 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, 0);
3089 return pThis->fFlags;
3090}
3091
3092
3093
3094/*
3095 *
3096 * F I L E F I L E F I L E
3097 * F I L E F I L E F I L E
3098 * F I L E F I L E F I L E
3099 *
3100 */
3101
3102RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3103 PRTVFSFILE phVfsFile, void **ppvInstance)
3104{
3105 /*
3106 * Validate the input, be extra strict in strict builds.
3107 */
3108 AssertPtr(pFileOps);
3109 AssertReturn(pFileOps->uVersion == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3110 AssertReturn(pFileOps->uEndMarker == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3111 Assert(!pFileOps->fReserved);
3112 RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
3113 Assert(cbInstance > 0);
3114 Assert(fOpen & RTFILE_O_ACCESS_MASK);
3115 AssertPtr(ppvInstance);
3116 AssertPtr(phVfsFile);
3117 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3118
3119 /*
3120 * Allocate the handle + instance data.
3121 */
3122 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
3123 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3124 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
3125 if (!pThis)
3126 return VERR_NO_MEMORY;
3127
3128 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, false /*fNoVfsRef*/, hLock,
3129 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3130 if (RT_FAILURE(rc))
3131 {
3132 RTMemFree(pThis);
3133 return rc;
3134 }
3135
3136 pThis->uMagic = RTVFSFILE_MAGIC;
3137 pThis->fReserved = 0;
3138 pThis->pOps = pFileOps;
3139 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
3140 pThis->Stream.fFlags = fOpen;
3141 pThis->Stream.pOps = &pFileOps->Stream;
3142
3143 *phVfsFile = pThis;
3144 *ppvInstance = pThis->Stream.Base.pvThis;
3145 return VINF_SUCCESS;
3146}
3147
3148
3149RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
3150{
3151 /*
3152 * Validate input.
3153 */
3154 RTVFSINTERNAL *pThis = hVfs;
3155 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3156 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
3157 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
3158 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
3159
3160 int rc = rtFileRecalcAndValidateFlags(&fOpen);
3161 if (RT_FAILURE(rc))
3162 return rc;
3163
3164 /*
3165 * Parse the path, assume current directory is root since we've got no
3166 * caller context here.
3167 */
3168 PRTVFSPARSEDPATH pPath;
3169 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
3170 if (RT_SUCCESS(rc))
3171 {
3172 if ( !pPath->fDirSlash
3173 && pPath->cComponents > 0)
3174 {
3175 /*
3176 * Tranverse the path, resolving the parent node and any symlinks
3177 * in the final element, and ask the directory to open the file.
3178 */
3179 RTVFSDIRINTERNAL *pVfsParentDir;
3180 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
3181 if (RT_SUCCESS(rc))
3182 {
3183 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3184
3185 /** @todo there is a symlink creation race here. */
3186 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3187 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
3188 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3189
3190 RTVfsDirRelease(pVfsParentDir);
3191
3192 if (RT_SUCCESS(rc))
3193 {
3194 AssertPtr(*phVfsFile);
3195 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
3196 }
3197 }
3198 }
3199 else
3200 rc = VERR_NOT_A_FILE;
3201 RTVfsParsePathFree(pPath);
3202 }
3203 return rc;
3204}
3205
3206
3207#ifdef DEBUG
3208# undef RTVfsFileRetain
3209#endif
3210RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
3211{
3212 RTVFSFILEINTERNAL *pThis = hVfsFile;
3213 AssertPtrReturn(pThis, UINT32_MAX);
3214 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3215 return rtVfsObjRetain(&pThis->Stream.Base);
3216}
3217#ifdef DEBUG
3218# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS)
3219#endif
3220
3221
3222RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL)
3223{
3224 RTVFSFILEINTERNAL *pThis = hVfsFile;
3225 AssertPtrReturn(pThis, UINT32_MAX);
3226 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3227 return rtVfsObjRetainDebug(&pThis->Stream.Base, "RTVFsFileRetainDebug", RT_SRC_POS_ARGS);
3228}
3229
3230
3231RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
3232{
3233 RTVFSFILEINTERNAL *pThis = hVfsFile;
3234 if (pThis == NIL_RTVFSFILE)
3235 return 0;
3236 AssertPtrReturn(pThis, UINT32_MAX);
3237 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3238 return rtVfsObjRelease(&pThis->Stream.Base);
3239}
3240
3241
3242RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
3243{
3244 RTVFSFILEINTERNAL *pThis = hVfsFile;
3245 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
3246 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
3247
3248 rtVfsObjRetainVoid(&pThis->Stream.Base, "RTVfsFileToIoStream");
3249 return &pThis->Stream;
3250}
3251
3252
3253RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3254{
3255 RTVFSFILEINTERNAL *pThis = hVfsFile;
3256 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3257 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3258 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
3259}
3260
3261
3262RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3263{
3264 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3265 if (pcbRead)
3266 *pcbRead = 0;
3267 RTVFSFILEINTERNAL *pThis = hVfsFile;
3268 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3269 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3270 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3271}
3272
3273
3274RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3275{
3276 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3277 if (pcbWritten)
3278 *pcbWritten = 0;
3279 RTVFSFILEINTERNAL *pThis = hVfsFile;
3280 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3281 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3282 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3283}
3284
3285
3286RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3287{
3288 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3289 if (pcbWritten)
3290 *pcbWritten = 0;
3291 RTVFSFILEINTERNAL *pThis = hVfsFile;
3292 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3293 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3294
3295 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3296 if (RT_SUCCESS(rc))
3297 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3298
3299 return rc;
3300}
3301
3302
3303RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3304{
3305 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3306 if (pcbRead)
3307 *pcbRead = 0;
3308 RTVFSFILEINTERNAL *pThis = hVfsFile;
3309 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3310 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3311
3312 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3313 if (RT_SUCCESS(rc))
3314 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3315
3316 return rc;
3317}
3318
3319
3320RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3321{
3322 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3323 if (pcbRead)
3324 *pcbRead = 0;
3325 RTVFSFILEINTERNAL *pThis = hVfsFile;
3326 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3327 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3328
3329 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
3330}
3331
3332
3333RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3334{
3335 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3336 if (pcbWritten)
3337 *pcbWritten = 0;
3338 RTVFSFILEINTERNAL *pThis = hVfsFile;
3339 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3340 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3341
3342 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
3343}
3344
3345
3346RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
3347{
3348 RTVFSFILEINTERNAL *pThis = hVfsFile;
3349 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3350 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3351 return RTVfsIoStrmFlush(&pThis->Stream);
3352}
3353
3354
3355RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3356 uint32_t *pfRetEvents)
3357{
3358 RTVFSFILEINTERNAL *pThis = hVfsFile;
3359 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3360 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3361 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
3362}
3363
3364
3365RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
3366{
3367 RTVFSFILEINTERNAL *pThis = hVfsFile;
3368 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3369 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3370 return RTVfsIoStrmTell(&pThis->Stream);
3371}
3372
3373
3374RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
3375{
3376 RTVFSFILEINTERNAL *pThis = hVfsFile;
3377 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3378 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3379
3380 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
3381 || uMethod == RTFILE_SEEK_CURRENT
3382 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
3383 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
3384
3385 RTFOFF offActual = 0;
3386 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3387 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
3388 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3389 if (RT_SUCCESS(rc) && poffActual)
3390 {
3391 Assert(offActual >= 0);
3392 *poffActual = offActual;
3393 }
3394
3395 return rc;
3396}
3397
3398
3399RTDECL(int) RTVfsFileGetSize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
3400{
3401 RTVFSFILEINTERNAL *pThis = hVfsFile;
3402 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3403 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3404 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
3405
3406 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3407 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
3408 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3409
3410 return rc;
3411}
3412
3413
3414RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile)
3415{
3416 RTVFSFILEINTERNAL *pThis = hVfsFile;
3417 AssertPtrReturn(pThis, 0);
3418 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, 0);
3419 return pThis->Stream.fFlags;
3420}
3421
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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