VirtualBox

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

Last change on this file since 69861 was 69861, checked in by vboxsync, 7 years ago

iprt/formats/ntfs: updates

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

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