VirtualBox

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

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

IPRT/VFS: Reimplemented RTVfsDirCreate, RTVfsDirOpenFile and RTVfsFileOpen to use pfnOpen, making pfnCreateDir and pfnOpenFile optional. Could of fixes for previous changes.

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