VirtualBox

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

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

IPRT/VFS: Reimplemented RTVfsDirOpen and RTVfsDirOpenDir to use pfnOpen, making pfnOpenDir optional. Fixed a couple of problems related to '.' and '..' handling in pfnQueryEntryInfo and pfnOpen implementations.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 132.1 KB
Line 
1/* $Id: vfsbase.cpp 69828 2017-11-24 17:32:23Z 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.215389.xyz. 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->pfnIsRangeInUse)
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) RTVfsIsRangeInUse(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->pfnIsRangeInUse)
2233 return VERR_NOT_SUPPORTED;
2234 RTVfsLockAcquireRead(pThis->Base.hLock);
2235 int rc = pThis->pOps->pfnIsRangeInUse(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->pfnQueryEntryInfo)
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 rc = rtVfsDirTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2640 if (RT_SUCCESS(rc))
2641 {
2642 /*
2643 * Do the opening. Loop if we need to follow symbolic links.
2644 */
2645 uint64_t fOpenFlags = RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN;
2646 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING;
2647 for (uint32_t cLoops = 1; ; cLoops++)
2648 {
2649 /* Do the querying. If pfnOpenDir is available, we use it first, falling
2650 back on pfnOpen in case of symbolic links that needs following. */
2651 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2652 if (pVfsParentDir->pOps->pfnQueryEntryInfo)
2653 {
2654 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2655 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2656 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2657 if (RT_SUCCESS(rc)
2658 || ( rc != VERR_NOT_A_DIRECTORY
2659 && rc != VERR_IS_A_SYMLINK))
2660 break;
2661 }
2662
2663 RTVFSOBJ hVfsObj;
2664 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2665 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpenFlags, fObjFlags, &hVfsObj);
2666 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2667 if (RT_FAILURE(rc))
2668 break;
2669
2670 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2671 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2672 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2673 {
2674 *phVfsDir = RTVfsObjToDir(hVfsObj);
2675 AssertStmt(*phVfsDir != NIL_RTVFSDIR, rc = VERR_INTERNAL_ERROR_3);
2676 RTVfsObjRelease(hVfsObj);
2677 break;
2678 }
2679
2680 /* Follow symbolic link. */
2681 if (cLoops < RTVFS_MAX_LINKS)
2682 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2683 else
2684 rc = VERR_TOO_MANY_SYMLINKS;
2685 RTVfsObjRelease(hVfsObj);
2686 if (RT_FAILURE(rc))
2687 break;
2688 }
2689 RTVfsDirRelease(pVfsParentDir);
2690 }
2691 RTVfsParsePathFree(pPath);
2692 }
2693 return rc;
2694}
2695
2696
2697RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir)
2698{
2699 /*
2700 * Validate input.
2701 */
2702 RTVFSDIRINTERNAL *pThis = hVfsDir;
2703 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2704 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2705 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2706 AssertPtrNullReturn(phVfsDir, VERR_INVALID_POINTER);
2707 AssertReturn(!(fFlags & ~RTDIRCREATE_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
2708 fMode = rtFsModeNormalize(fMode, pszRelPath, 0);
2709 AssertReturn(rtFsModeIsValidPermissions(fMode), VERR_INVALID_FMODE);
2710 if (!(fFlags & RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET))
2711 fMode |= RTFS_DOS_NT_NOT_CONTENT_INDEXED;
2712
2713 /*
2714 * Parse the path, it's always relative to the given directory.
2715 */
2716 PRTVFSPARSEDPATH pPath;
2717 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2718 if (RT_SUCCESS(rc))
2719 {
2720 if (pPath->cComponents > 0)
2721 {
2722 /*
2723 * Tranverse the path, resolving the parent node, not checking for symbolic
2724 * links in the final element, and ask the directory to create the subdir.
2725 */
2726 RTVFSDIRINTERNAL *pVfsParentDir;
2727 rc = rtVfsDirTraverseToParent(pThis, pPath,
2728 fFlags & RTDIRCREATE_FLAGS_NO_SYMLINKS
2729 ? RTPATH_F_NO_SYMLINKS | RTPATH_F_ON_LINK : RTPATH_F_FOLLOW_LINK,
2730 &pVfsParentDir);
2731 if (RT_SUCCESS(rc))
2732 {
2733 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2734
2735 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2736 rc = pVfsParentDir->pOps->pfnCreateDir(pVfsParentDir->Base.pvThis, pszEntryName, fMode, phVfsDir);
2737 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2738
2739 RTVfsDirRelease(pVfsParentDir);
2740
2741 if (RT_SUCCESS(rc) && phVfsDir)
2742 {
2743 AssertPtr(*phVfsDir);
2744 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2745 }
2746 }
2747 }
2748 else
2749 rc = VERR_PATH_ZERO_LENGTH;
2750 RTVfsParsePathFree(pPath);
2751 }
2752 return rc;
2753}
2754
2755
2756RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2757{
2758 /*
2759 * Validate input.
2760 */
2761 RTVFSDIRINTERNAL *pThis = hVfsDir;
2762 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2763 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2764 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2765 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2766
2767 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2768 if (RT_FAILURE(rc))
2769 return rc;
2770
2771 /*
2772 * Parse the relative path.
2773 */
2774 PRTVFSPARSEDPATH pPath;
2775 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2776 if (RT_SUCCESS(rc))
2777 {
2778 if (pPath->cComponents > 0)
2779 {
2780 /*
2781 * Tranverse the path, resolving the parent node and any symlinks
2782 * in the final element, and ask the directory to open the file.
2783 */
2784 RTVFSDIRINTERNAL *pVfsParentDir;
2785 rc = rtVfsDirTraverseToParent(pThis, pPath,
2786 (fOpen & RTFILE_O_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_FOLLOW_LINK,
2787 &pVfsParentDir);
2788 if (RT_SUCCESS(rc))
2789 {
2790 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2791
2792 if ( pVfsParentDir->pOps->pfnOpenFile == NULL
2793 || pPath->fDirSlash)
2794 {
2795 RTVFSOBJ hVfsObj;
2796 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2797 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpen,
2798 RTVFSOBJ_F_OPEN_ANY_FILE | RTVFSOBJ_F_CREATE_FILE
2799 | RTPATH_F_FOLLOW_LINK, &hVfsObj);
2800 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2801 if (RT_SUCCESS(rc))
2802 {
2803 if (RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2804 *phVfsFile = RTVfsObjToFile(hVfsObj);
2805 else
2806 {
2807 /** @todo parse symbolic links. */
2808 AssertFailed();
2809 rc = VERR_NOT_IMPLEMENTED;
2810 }
2811 RTVfsObjRelease(hVfsObj);
2812 }
2813 }
2814 else
2815 {
2816 /** @todo there is a symlink creation race here. */
2817 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2818 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2819 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2820 }
2821
2822 if (RT_SUCCESS(rc))
2823 {
2824 AssertPtr(*phVfsFile);
2825 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2826 }
2827
2828 RTVfsDirRelease(pVfsParentDir);
2829 }
2830 }
2831 else
2832 rc = VERR_NOT_A_FILE;
2833 RTVfsParsePathFree(pPath);
2834 }
2835 return rc;
2836}
2837
2838
2839RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
2840{
2841 RTVFSFILE hVfsFile;
2842 int rc = RTVfsDirOpenFile(hVfsDir, pszPath, fOpen, &hVfsFile);
2843 if (RT_SUCCESS(rc))
2844 {
2845 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
2846 AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
2847 RTVfsFileRelease(hVfsFile);
2848 }
2849 return rc;
2850}
2851
2852
2853RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
2854{
2855 /*
2856 * Validate input.
2857 */
2858 RTVFSDIRINTERNAL *pThis = hVfsDir;
2859 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2860 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2861 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2862 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
2863
2864 int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
2865 if (RT_FAILURE(rc))
2866 return rc;
2867 AssertMsgReturn( RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
2868 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
2869 ("fObjFlags=%#x\n", fObjFlags),
2870 VERR_INVALID_FLAGS);
2871
2872 /*
2873 * Parse the relative path. If it ends with a directory slash or it boils
2874 * down to an empty path (i.e. re-opening hVfsDir), adjust the flags to only
2875 * open/create directories.
2876 */
2877 PRTVFSPARSEDPATH pPath;
2878 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2879 if (RT_SUCCESS(rc))
2880 {
2881 /*
2882 * Tranverse the path, resolving the parent node.
2883 * We'll do the symbolic link checking here with help of pfnOpen.
2884 */
2885 RTVFSDIRINTERNAL *pVfsParentDir;
2886 rc = rtVfsDirTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2887 if (RT_SUCCESS(rc))
2888 {
2889 /*
2890 * Do the opening. Loop if we need to follow symbolic links.
2891 */
2892 for (uint32_t cLoops = 1;; cLoops++)
2893 {
2894 /* If we end with a directory slash, adjust open flags. */
2895 if (pPath->fDirSlash)
2896 {
2897 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
2898 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
2899 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
2900 }
2901 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
2902 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
2903
2904 /* Open it. */
2905 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2906 RTVFSOBJ hVfsObj;
2907 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2908 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
2909 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2910 if (RT_FAILURE(rc))
2911 break;
2912
2913 /* We're done if we don't follow links or this wasn't a link. */
2914 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2915 || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
2916 {
2917 *phVfsObj = hVfsObj;
2918 break;
2919 }
2920
2921 /* Follow symbolic link. */
2922 if (cLoops < RTVFS_MAX_LINKS)
2923 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2924 else
2925 rc = VERR_TOO_MANY_SYMLINKS;
2926 RTVfsObjRelease(hVfsObj);
2927 if (RT_FAILURE(rc))
2928 break;
2929 }
2930
2931 RTVfsDirRelease(pVfsParentDir);
2932 }
2933 RTVfsParsePathFree(pPath);
2934 }
2935 return rc;
2936}
2937
2938
2939RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo,
2940 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2941{
2942 /*
2943 * Validate input.
2944 */
2945 RTVFSDIRINTERNAL *pThis = hVfsDir;
2946 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2947 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2948 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2949 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2950 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2951 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2952 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2953
2954 /*
2955 * Parse the relative path. Then traverse to the parent directory.
2956 */
2957 PRTVFSPARSEDPATH pPath;
2958 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2959 if (RT_SUCCESS(rc))
2960 {
2961 if (pPath->cComponents > 0)
2962 {
2963 RTVFSDIRINTERNAL *pVfsParentDir;
2964 rc = rtVfsDirTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
2965 if (RT_SUCCESS(rc))
2966 {
2967 /*
2968 * Call the query method on the parent directory.
2969 */
2970 /** @todo symlink race condition here :/ */
2971 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2972 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2973 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2974 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2975
2976 RTVfsDirRelease(pVfsParentDir);
2977 }
2978 else
2979 rc = VERR_INVALID_PARAMETER;
2980 }
2981 /*
2982 * The path boils down to '.' so just query the directory.
2983 */
2984 else
2985 {
2986 RTVfsLockAcquireRead(pThis->Base.hLock);
2987 rc = pThis->Base.pOps->pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr);
2988 RTVfsLockReleaseRead(pThis->Base.hLock);
2989 }
2990 RTVfsParsePathFree(pPath);
2991 }
2992 return rc;
2993}
2994
2995
2996RTDECL(int) RTVfsDirRemoveDir(RTVFSDIR hVfsDir, const char *pszRelPath, uint32_t fFlags)
2997{
2998 /*
2999 * Validate input.
3000 */
3001 RTVFSDIRINTERNAL *pThis = hVfsDir;
3002 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3003 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3004 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
3005 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
3006
3007 /*
3008 * Parse the path, it's always relative to the given directory.
3009 */
3010 PRTVFSPARSEDPATH pPath;
3011 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
3012 if (RT_SUCCESS(rc))
3013 {
3014 if (pPath->cComponents > 0)
3015 {
3016 /*
3017 * Tranverse the path, resolving the parent node, not checking for symbolic
3018 * links in the final element, and ask the directory to remove the subdir.
3019 */
3020 RTVFSDIRINTERNAL *pVfsParentDir;
3021 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
3022 if (RT_SUCCESS(rc))
3023 {
3024 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3025
3026 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3027 rc = pVfsParentDir->pOps->pfnUnlinkEntry(pVfsParentDir->Base.pvThis, pszEntryName, RTFS_TYPE_DIRECTORY);
3028 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3029
3030 RTVfsDirRelease(pVfsParentDir);
3031 }
3032 }
3033 else
3034 rc = VERR_PATH_ZERO_LENGTH;
3035 RTVfsParsePathFree(pPath);
3036 }
3037 return rc;
3038}
3039
3040
3041
3042RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
3043{
3044 /*
3045 * Validate input.
3046 */
3047 RTVFSDIRINTERNAL *pThis = hVfsDir;
3048 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3049 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3050 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
3051 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
3052
3053 size_t cbDirEntry = sizeof(*pDirEntry);
3054 if (!pcbDirEntry)
3055 pcbDirEntry = &cbDirEntry;
3056 else
3057 {
3058 cbDirEntry = *pcbDirEntry;
3059 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
3060 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
3061 VERR_INVALID_PARAMETER);
3062 }
3063
3064 /*
3065 * Call the directory method.
3066 */
3067 RTVfsLockAcquireRead(pThis->Base.hLock);
3068 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
3069 RTVfsLockReleaseRead(pThis->Base.hLock);
3070 return rc;
3071}
3072
3073
3074/*
3075 *
3076 * S Y M B O L I C L I N K
3077 * S Y M B O L I C L I N K
3078 * S Y M B O L I C L I N K
3079 *
3080 */
3081
3082RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
3083 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
3084{
3085 /*
3086 * Validate the input, be extra strict in strict builds.
3087 */
3088 AssertPtr(pSymlinkOps);
3089 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3090 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3091 Assert(!pSymlinkOps->fReserved);
3092 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
3093 Assert(cbInstance > 0);
3094 AssertPtr(ppvInstance);
3095 AssertPtr(phVfsSym);
3096 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3097
3098 /*
3099 * Allocate the handle + instance data.
3100 */
3101 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
3102 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3103 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
3104 if (!pThis)
3105 return VERR_NO_MEMORY;
3106
3107 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3108 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3109 if (RT_FAILURE(rc))
3110 {
3111 RTMemFree(pThis);
3112 return rc;
3113 }
3114
3115 pThis->uMagic = RTVFSSYMLINK_MAGIC;
3116 pThis->pOps = pSymlinkOps;
3117
3118 *phVfsSym = pThis;
3119 *ppvInstance = pThis->Base.pvThis;
3120 return VINF_SUCCESS;
3121}
3122
3123
3124RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
3125{
3126 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3127 AssertPtrReturn(pThis, UINT32_MAX);
3128 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3129 return rtVfsObjRetain(&pThis->Base);
3130}
3131
3132
3133RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL)
3134{
3135 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3136 AssertPtrReturn(pThis, UINT32_MAX);
3137 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3138 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsSymlinkRetainDebug", RT_SRC_POS_ARGS);
3139}
3140
3141
3142RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
3143{
3144 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3145 if (pThis == NIL_RTVFSSYMLINK)
3146 return 0;
3147 AssertPtrReturn(pThis, UINT32_MAX);
3148 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3149 return rtVfsObjRelease(&pThis->Base);
3150}
3151
3152
3153RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3154{
3155 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3156 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3157 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3158 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3159}
3160
3161
3162RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
3163{
3164 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3165 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3166 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3167
3168 fMode = rtFsModeNormalize(fMode, NULL, 0);
3169 if (!rtFsModeIsValid(fMode))
3170 return VERR_INVALID_PARAMETER;
3171
3172 RTVfsLockAcquireWrite(pThis->Base.hLock);
3173 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
3174 RTVfsLockReleaseWrite(pThis->Base.hLock);
3175 return rc;
3176}
3177
3178
3179RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
3180 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
3181{
3182 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3183 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3184 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3185
3186 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
3187 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
3188 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
3189 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
3190
3191 RTVfsLockAcquireWrite(pThis->Base.hLock);
3192 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
3193 RTVfsLockReleaseWrite(pThis->Base.hLock);
3194 return rc;
3195}
3196
3197
3198RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
3199{
3200 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3201 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3202 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3203
3204 RTVfsLockAcquireWrite(pThis->Base.hLock);
3205 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
3206 RTVfsLockReleaseWrite(pThis->Base.hLock);
3207 return rc;
3208}
3209
3210
3211RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
3212{
3213 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3214 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3215 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3216
3217 RTVfsLockAcquireWrite(pThis->Base.hLock);
3218 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
3219 RTVfsLockReleaseWrite(pThis->Base.hLock);
3220
3221 return rc;
3222}
3223
3224
3225
3226/*
3227 *
3228 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3229 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3230 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3231 *
3232 */
3233
3234RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3235 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
3236{
3237 /*
3238 * Validate the input, be extra strict in strict builds.
3239 */
3240 AssertPtr(pIoStreamOps);
3241 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3242 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3243 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
3244 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
3245 Assert(cbInstance > 0);
3246 Assert(fOpen & RTFILE_O_ACCESS_MASK);
3247 AssertPtr(ppvInstance);
3248 AssertPtr(phVfsIos);
3249 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3250
3251 /*
3252 * Allocate the handle + instance data.
3253 */
3254 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
3255 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3256 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
3257 if (!pThis)
3258 return VERR_NO_MEMORY;
3259
3260 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3261 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3262 if (RT_FAILURE(rc))
3263 {
3264 RTMemFree(pThis);
3265 return rc;
3266 }
3267
3268 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
3269 pThis->fFlags = fOpen;
3270 pThis->pOps = pIoStreamOps;
3271
3272 *phVfsIos = pThis;
3273 *ppvInstance = pThis->Base.pvThis;
3274 return VINF_SUCCESS;
3275}
3276
3277
3278RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
3279{
3280 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3281 AssertPtrReturn(pThis, NULL);
3282 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
3283 if (pThis->pOps != pIoStreamOps)
3284 return NULL;
3285 return pThis->Base.pvThis;
3286}
3287
3288
3289#ifdef DEBUG
3290# undef RTVfsIoStrmRetain
3291#endif
3292RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
3293{
3294 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3295 AssertPtrReturn(pThis, UINT32_MAX);
3296 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3297 return rtVfsObjRetain(&pThis->Base);
3298}
3299#ifdef DEBUG
3300# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS)
3301#endif
3302
3303
3304RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL)
3305{
3306 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3307 AssertPtrReturn(pThis, UINT32_MAX);
3308 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3309 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsIoStrmRetainDebug", RT_SRC_POS_ARGS);
3310}
3311
3312
3313RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
3314{
3315 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3316 if (pThis == NIL_RTVFSIOSTREAM)
3317 return 0;
3318 AssertPtrReturn(pThis, UINT32_MAX);
3319 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3320 return rtVfsObjRelease(&pThis->Base);
3321}
3322
3323
3324RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
3325{
3326 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3327 AssertPtrReturn(pThis, NIL_RTVFSFILE);
3328 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
3329
3330 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3331 {
3332 rtVfsObjRetainVoid(&pThis->Base, "RTVfsIoStrmToFile");
3333 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3334 }
3335
3336 /* this is no crime, so don't assert. */
3337 return NIL_RTVFSFILE;
3338}
3339
3340
3341RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3342{
3343 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3344 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3345 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3346 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3347}
3348
3349
3350RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
3351{
3352 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3353 if (pcbRead)
3354 *pcbRead = 0;
3355 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3356 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3357 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3358 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3359 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3360
3361 RTSGSEG Seg = { pvBuf, cbToRead };
3362 RTSGBUF SgBuf;
3363 RTSgBufInit(&SgBuf, &Seg, 1);
3364
3365 RTVfsLockAcquireWrite(pThis->Base.hLock);
3366 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
3367 RTVfsLockReleaseWrite(pThis->Base.hLock);
3368 return rc;
3369}
3370
3371
3372RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
3373 bool fBlocking, size_t *pcbRead)
3374{
3375 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3376 if (pcbRead)
3377 *pcbRead = 0;
3378 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3379 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3380 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3381 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3382 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3383
3384 RTSGSEG Seg = { pvBuf, cbToRead };
3385 RTSGBUF SgBuf;
3386 RTSgBufInit(&SgBuf, &Seg, 1);
3387
3388 RTVfsLockAcquireWrite(pThis->Base.hLock);
3389 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
3390 RTVfsLockReleaseWrite(pThis->Base.hLock);
3391 return rc;
3392}
3393
3394
3395RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
3396{
3397 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3398 if (pcbWritten)
3399 *pcbWritten = 0;
3400 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3401 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3402 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3403 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3404 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3405
3406 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3407 RTSGBUF SgBuf;
3408 RTSgBufInit(&SgBuf, &Seg, 1);
3409
3410 RTVfsLockAcquireWrite(pThis->Base.hLock);
3411 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
3412 RTVfsLockReleaseWrite(pThis->Base.hLock);
3413 return rc;
3414}
3415
3416
3417RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
3418 bool fBlocking, size_t *pcbWritten)
3419{
3420 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3421 if (pcbWritten)
3422 *pcbWritten = 0;
3423 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3424 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3425 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3426 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3427 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3428
3429 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3430 RTSGBUF SgBuf;
3431 RTSgBufInit(&SgBuf, &Seg, 1);
3432
3433 RTVfsLockAcquireWrite(pThis->Base.hLock);
3434 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
3435 RTVfsLockReleaseWrite(pThis->Base.hLock);
3436 return rc;
3437}
3438
3439
3440RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3441{
3442 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3443 if (pcbRead)
3444 *pcbRead = 0;
3445 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3446 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3447 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3448 AssertPtr(pSgBuf);
3449 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3450 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3451
3452 RTVfsLockAcquireWrite(pThis->Base.hLock);
3453 int rc;
3454 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3455 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
3456 else
3457 {
3458 size_t cbRead = 0;
3459 rc = VINF_SUCCESS;
3460
3461 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3462 {
3463 RTSGBUF SgBuf;
3464 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3465
3466 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
3467 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
3468 if (RT_FAILURE(rc))
3469 break;
3470 cbRead += cbReadSeg;
3471 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
3472 break;
3473 if (off != -1)
3474 off += cbReadSeg;
3475 }
3476
3477 if (pcbRead)
3478 *pcbRead = cbRead;
3479 }
3480 RTVfsLockReleaseWrite(pThis->Base.hLock);
3481 return rc;
3482}
3483
3484
3485RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3486{
3487 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3488 if (pcbWritten)
3489 *pcbWritten = 0;
3490 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3491 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3492 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3493 AssertPtr(pSgBuf);
3494 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3495 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3496
3497 RTVfsLockAcquireWrite(pThis->Base.hLock);
3498 int rc;
3499 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3500 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
3501 else
3502 {
3503 size_t cbWritten = 0;
3504 rc = VINF_SUCCESS;
3505
3506 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3507 {
3508 RTSGBUF SgBuf;
3509 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3510
3511 size_t cbWrittenSeg = 0;
3512 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
3513 if (RT_FAILURE(rc))
3514 break;
3515 if (pcbWritten)
3516 {
3517 cbWritten += cbWrittenSeg;
3518 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
3519 break;
3520 if (off != -1)
3521 off += cbWrittenSeg;
3522 }
3523 else if (off != -1)
3524 off += pSgBuf->paSegs[iSeg].cbSeg;
3525 }
3526
3527 if (pcbWritten)
3528 *pcbWritten = cbWritten;
3529 }
3530 RTVfsLockReleaseWrite(pThis->Base.hLock);
3531 return rc;
3532}
3533
3534
3535RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
3536{
3537 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3538 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3539 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3540
3541 RTVfsLockAcquireWrite(pThis->Base.hLock);
3542 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
3543 RTVfsLockReleaseWrite(pThis->Base.hLock);
3544 return rc;
3545}
3546
3547
3548RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3549 uint32_t *pfRetEvents)
3550{
3551 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3552 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3553 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3554
3555 RTVfsLockAcquireWrite(pThis->Base.hLock);
3556 int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
3557 RTVfsLockReleaseWrite(pThis->Base.hLock);
3558 return rc;
3559}
3560
3561
3562RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
3563{
3564 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3565 AssertPtrReturn(pThis, -1);
3566 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3567
3568 RTFOFF off;
3569 RTVfsLockAcquireRead(pThis->Base.hLock);
3570 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
3571 RTVfsLockReleaseRead(pThis->Base.hLock);
3572 if (RT_FAILURE(rc))
3573 off = rc;
3574 return off;
3575}
3576
3577
3578RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3579{
3580 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3581 AssertPtrReturn(pThis, -1);
3582 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3583 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
3584
3585 int rc;
3586 if (pThis->pOps->pfnSkip)
3587 {
3588 RTVfsLockAcquireWrite(pThis->Base.hLock);
3589 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
3590 RTVfsLockReleaseWrite(pThis->Base.hLock);
3591 }
3592 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3593 {
3594 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3595 RTFOFF offIgnored;
3596
3597 RTVfsLockAcquireWrite(pThis->Base.hLock);
3598 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
3599 RTVfsLockReleaseWrite(pThis->Base.hLock);
3600 }
3601 else
3602 {
3603 void *pvBuf = RTMemTmpAlloc(_64K);
3604 if (pvBuf)
3605 {
3606 rc = VINF_SUCCESS;
3607 while (cb > 0)
3608 {
3609 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
3610 RTVfsLockAcquireWrite(pThis->Base.hLock);
3611 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
3612 RTVfsLockReleaseWrite(pThis->Base.hLock);
3613 if (RT_FAILURE(rc))
3614 break;
3615 cb -= cbToRead;
3616 }
3617
3618 RTMemTmpFree(pvBuf);
3619 }
3620 else
3621 rc = VERR_NO_TMP_MEMORY;
3622 }
3623 return rc;
3624}
3625
3626
3627RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3628{
3629 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3630 AssertPtrReturn(pThis, -1);
3631 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3632
3633 int rc;
3634 if (pThis->pOps->pfnZeroFill)
3635 {
3636 RTVfsLockAcquireWrite(pThis->Base.hLock);
3637 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
3638 RTVfsLockReleaseWrite(pThis->Base.hLock);
3639 }
3640 else
3641 {
3642 rc = VINF_SUCCESS;
3643 while (cb > 0)
3644 {
3645 size_t cbToWrite = (size_t)RT_MIN(cb, (ssize_t)sizeof(g_abRTZero64K));
3646 RTVfsLockAcquireWrite(pThis->Base.hLock);
3647 rc = RTVfsIoStrmWrite(hVfsIos, g_abRTZero64K, cbToWrite, true /*fBlocking*/, NULL);
3648 RTVfsLockReleaseWrite(pThis->Base.hLock);
3649 if (RT_FAILURE(rc))
3650 break;
3651 cb -= cbToWrite;
3652 }
3653 }
3654 return rc;
3655}
3656
3657
3658RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
3659{
3660 /*
3661 * There is where the zero read behavior comes in handy.
3662 */
3663 char bDummy;
3664 size_t cbRead;
3665 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
3666 return rc == VINF_EOF;
3667}
3668
3669
3670
3671RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos)
3672{
3673 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3674 AssertPtrReturn(pThis, 0);
3675 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, 0);
3676 return pThis->fFlags;
3677}
3678
3679
3680
3681/*
3682 *
3683 * F I L E F I L E F I L E
3684 * F I L E F I L E F I L E
3685 * F I L E F I L E F I L E
3686 *
3687 */
3688
3689RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3690 PRTVFSFILE phVfsFile, void **ppvInstance)
3691{
3692 /*
3693 * Validate the input, be extra strict in strict builds.
3694 */
3695 AssertPtr(pFileOps);
3696 AssertReturn(pFileOps->uVersion == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3697 AssertReturn(pFileOps->uEndMarker == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3698 Assert(!pFileOps->fReserved);
3699 RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
3700 Assert(cbInstance > 0);
3701 Assert(fOpen & (RTFILE_O_ACCESS_MASK | RTFILE_O_ACCESS_ATTR_MASK));
3702 AssertPtr(ppvInstance);
3703 AssertPtr(phVfsFile);
3704 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3705
3706 /*
3707 * Allocate the handle + instance data.
3708 */
3709 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
3710 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3711 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
3712 if (!pThis)
3713 return VERR_NO_MEMORY;
3714
3715 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, false /*fNoVfsRef*/, hLock,
3716 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3717 if (RT_FAILURE(rc))
3718 {
3719 RTMemFree(pThis);
3720 return rc;
3721 }
3722
3723 pThis->uMagic = RTVFSFILE_MAGIC;
3724 pThis->fReserved = 0;
3725 pThis->pOps = pFileOps;
3726 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
3727 pThis->Stream.fFlags = fOpen;
3728 pThis->Stream.pOps = &pFileOps->Stream;
3729
3730 *phVfsFile = pThis;
3731 *ppvInstance = pThis->Stream.Base.pvThis;
3732 return VINF_SUCCESS;
3733}
3734
3735
3736RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
3737{
3738 /*
3739 * Validate input.
3740 */
3741 RTVFSINTERNAL *pThis = hVfs;
3742 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3743 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
3744 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
3745 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
3746
3747 int rc = rtFileRecalcAndValidateFlags(&fOpen);
3748 if (RT_FAILURE(rc))
3749 return rc;
3750
3751 /*
3752 * Parse the path, assume current directory is root since we've got no
3753 * caller context here.
3754 */
3755 PRTVFSPARSEDPATH pPath;
3756 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
3757 if (RT_SUCCESS(rc))
3758 {
3759 if ( !pPath->fDirSlash
3760 && pPath->cComponents > 0)
3761 {
3762 /*
3763 * Tranverse the path, resolving the parent node and any symlinks
3764 * in the final element, and ask the directory to open the file.
3765 */
3766 RTVFSDIRINTERNAL *pVfsParentDir;
3767 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
3768 if (RT_SUCCESS(rc))
3769 {
3770 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3771
3772 /** @todo there is a symlink creation race here. */
3773 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3774 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
3775 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3776
3777 RTVfsDirRelease(pVfsParentDir);
3778
3779 if (RT_SUCCESS(rc))
3780 {
3781 AssertPtr(*phVfsFile);
3782 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
3783 }
3784 }
3785 }
3786 else
3787 rc = VERR_NOT_A_FILE;
3788 RTVfsParsePathFree(pPath);
3789 }
3790 return rc;
3791}
3792
3793
3794#ifdef DEBUG
3795# undef RTVfsFileRetain
3796#endif
3797RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
3798{
3799 RTVFSFILEINTERNAL *pThis = hVfsFile;
3800 AssertPtrReturn(pThis, UINT32_MAX);
3801 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3802 return rtVfsObjRetain(&pThis->Stream.Base);
3803}
3804#ifdef DEBUG
3805# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS)
3806#endif
3807
3808
3809RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL)
3810{
3811 RTVFSFILEINTERNAL *pThis = hVfsFile;
3812 AssertPtrReturn(pThis, UINT32_MAX);
3813 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3814 return rtVfsObjRetainDebug(&pThis->Stream.Base, "RTVFsFileRetainDebug", RT_SRC_POS_ARGS);
3815}
3816
3817
3818RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
3819{
3820 RTVFSFILEINTERNAL *pThis = hVfsFile;
3821 if (pThis == NIL_RTVFSFILE)
3822 return 0;
3823 AssertPtrReturn(pThis, UINT32_MAX);
3824 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3825 return rtVfsObjRelease(&pThis->Stream.Base);
3826}
3827
3828
3829RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
3830{
3831 RTVFSFILEINTERNAL *pThis = hVfsFile;
3832 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
3833 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
3834
3835 rtVfsObjRetainVoid(&pThis->Stream.Base, "RTVfsFileToIoStream");
3836 return &pThis->Stream;
3837}
3838
3839
3840RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3841{
3842 RTVFSFILEINTERNAL *pThis = hVfsFile;
3843 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3844 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3845 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
3846}
3847
3848
3849RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3850{
3851 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3852 if (pcbRead)
3853 *pcbRead = 0;
3854 RTVFSFILEINTERNAL *pThis = hVfsFile;
3855 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3856 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3857 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3858}
3859
3860
3861RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3862{
3863 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3864 if (pcbWritten)
3865 *pcbWritten = 0;
3866 RTVFSFILEINTERNAL *pThis = hVfsFile;
3867 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3868 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3869 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3870}
3871
3872
3873RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3874{
3875 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3876 if (pcbWritten)
3877 *pcbWritten = 0;
3878 RTVFSFILEINTERNAL *pThis = hVfsFile;
3879 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3880 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3881
3882 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3883 if (RT_SUCCESS(rc))
3884 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3885
3886 return rc;
3887}
3888
3889
3890RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3891{
3892 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3893 if (pcbRead)
3894 *pcbRead = 0;
3895 RTVFSFILEINTERNAL *pThis = hVfsFile;
3896 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3897 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3898
3899 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3900 if (RT_SUCCESS(rc))
3901 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3902
3903 return rc;
3904}
3905
3906
3907RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3908{
3909 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3910 if (pcbRead)
3911 *pcbRead = 0;
3912 RTVFSFILEINTERNAL *pThis = hVfsFile;
3913 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3914 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3915
3916 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
3917}
3918
3919
3920RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3921{
3922 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3923 if (pcbWritten)
3924 *pcbWritten = 0;
3925 RTVFSFILEINTERNAL *pThis = hVfsFile;
3926 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3927 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3928
3929 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
3930}
3931
3932
3933RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
3934{
3935 RTVFSFILEINTERNAL *pThis = hVfsFile;
3936 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3937 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3938 return RTVfsIoStrmFlush(&pThis->Stream);
3939}
3940
3941
3942RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3943 uint32_t *pfRetEvents)
3944{
3945 RTVFSFILEINTERNAL *pThis = hVfsFile;
3946 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3947 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3948 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
3949}
3950
3951
3952RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
3953{
3954 RTVFSFILEINTERNAL *pThis = hVfsFile;
3955 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3956 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3957 return RTVfsIoStrmTell(&pThis->Stream);
3958}
3959
3960
3961RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
3962{
3963 RTVFSFILEINTERNAL *pThis = hVfsFile;
3964 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3965 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3966
3967 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
3968 || uMethod == RTFILE_SEEK_CURRENT
3969 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
3970 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
3971
3972 RTFOFF offActual = 0;
3973 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3974 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
3975 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3976 if (RT_SUCCESS(rc) && poffActual)
3977 {
3978 Assert(offActual >= 0);
3979 *poffActual = offActual;
3980 }
3981
3982 return rc;
3983}
3984
3985
3986RTDECL(int) RTVfsFileGetSize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
3987{
3988 RTVFSFILEINTERNAL *pThis = hVfsFile;
3989 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3990 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3991 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
3992
3993 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3994 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
3995 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3996
3997 return rc;
3998}
3999
4000
4001RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile)
4002{
4003 RTVFSFILEINTERNAL *pThis = hVfsFile;
4004 AssertPtrReturn(pThis, 0);
4005 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, 0);
4006 return pThis->Stream.fFlags;
4007}
4008
Note: See TracBrowser for help on using the repository browser.

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