VirtualBox

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

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

IPRT: VFS and NT path handling fixes.

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

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