VirtualBox

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

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

IPRT/VFS: rewrote RTVfsQueryPathInfo to new path handling.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 129.4 KB
Line 
1/* $Id: vfsbase.cpp 69827 2017-11-24 16:30:56Z 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 }
1263 RTVfsParsePathFree(pPath);
1264 }
1265 return rc;
1266}
1267
1268
1269RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1270{
1271 RTVFSOBJINTERNAL *pThis = hVfsObj;
1272 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1273 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1274
1275 RTVfsLockAcquireRead(pThis->hLock);
1276 int rc = pThis->pOps->pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
1277 RTVfsLockReleaseRead(pThis->hLock);
1278 return rc;
1279}
1280
1281
1282/**
1283 * Gets the RTVFSOBJSETOPS for the given base object.
1284 *
1285 * @returns Pointer to the vtable if supported by the type, otherwise NULL.
1286 * @param pThis The base object.
1287 */
1288static PCRTVFSOBJSETOPS rtVfsObjGetSetOps(RTVFSOBJINTERNAL *pThis)
1289{
1290 switch (pThis->pOps->enmType)
1291 {
1292 case RTVFSOBJTYPE_DIR:
1293 return &RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->pOps->ObjSet;
1294 case RTVFSOBJTYPE_FILE:
1295 return &RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->pOps->ObjSet;
1296 case RTVFSOBJTYPE_SYMLINK:
1297 return &RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->pOps->ObjSet;
1298 default:
1299 return NULL;
1300 }
1301}
1302
1303
1304RTDECL(int) RTVfsObjSetMode(RTVFSOBJ hVfsObj, RTFMODE fMode, RTFMODE fMask)
1305{
1306 RTVFSOBJINTERNAL *pThis = hVfsObj;
1307 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1308 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1309
1310 fMode = rtFsModeNormalize(fMode, NULL, 0);
1311 if (!rtFsModeIsValid(fMode))
1312 return VERR_INVALID_PARAMETER;
1313
1314 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1315 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1316
1317 RTVfsLockAcquireWrite(pThis->hLock);
1318 int rc = pObjSetOps->pfnSetMode(pThis->pvThis, fMode, fMask);
1319 RTVfsLockReleaseWrite(pThis->hLock);
1320 return rc;
1321}
1322
1323
1324RTDECL(int) RTVfsObjSetTimes(RTVFSOBJ hVfsObj, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1325 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1326{
1327 RTVFSOBJINTERNAL *pThis = hVfsObj;
1328 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1329 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1330
1331 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
1332 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
1333 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
1334 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
1335
1336 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1337 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1338
1339 RTVfsLockAcquireWrite(pThis->hLock);
1340 int rc = pObjSetOps->pfnSetTimes(pThis->pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1341 RTVfsLockReleaseWrite(pThis->hLock);
1342 return rc;
1343}
1344
1345
1346RTDECL(int) RTVfsObjSetOwner(RTVFSOBJ hVfsObj, RTUID uid, RTGID gid)
1347{
1348 RTVFSOBJINTERNAL *pThis = hVfsObj;
1349 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1350 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1351
1352 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1353 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1354
1355 RTVfsLockAcquireWrite(pThis->hLock);
1356 int rc = pObjSetOps->pfnSetOwner(pThis->pvThis, uid, gid);
1357 RTVfsLockReleaseWrite(pThis->hLock);
1358 return rc;
1359}
1360
1361
1362/*
1363 *
1364 * U T I L U T I L U T I L
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 *
1368 */
1369
1370
1371RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
1372{
1373 AssertReturn(*pszPath != '/' && *pszPath != '\\', VERR_INTERNAL_ERROR_4);
1374
1375 /* In case *piRestartComp was set higher than the number of components
1376 before making the call to this function. */
1377 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1378 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1379
1380/** @todo The '..' handling doesn't really work wrt to symbolic links in the
1381 * path. */
1382
1383 /*
1384 * Append a slash to the destination path if necessary.
1385 */
1386 char * const pszDst = pPath->szPath;
1387 size_t offDst = pPath->cch;
1388 if (pPath->cComponents > 0)
1389 {
1390 pszDst[offDst++] = '/';
1391 if (offDst >= RTVFSPARSEDPATH_MAX)
1392 return VERR_FILENAME_TOO_LONG;
1393 }
1394 if (pPath->fAbsolute)
1395 Assert(pszDst[offDst - 1] == '/' && pszDst[0] == '/');
1396 else
1397 Assert(offDst == 0 || (pszDst[0] != '/' && pszDst[offDst - 1] == '/'));
1398
1399 /*
1400 * Parse and append the relative path.
1401 */
1402 const char *pszSrc = pszPath;
1403 pPath->fDirSlash = false;
1404 for (;;)
1405 {
1406 /* Copy until we encounter the next slash. */
1407 pPath->aoffComponents[pPath->cComponents++] = (uint16_t)offDst;
1408 for (;;)
1409 {
1410 char ch = *pszSrc++;
1411 if ( ch != '/'
1412 && ch != '\\'
1413 && ch != '\0')
1414 {
1415 pszDst[offDst++] = ch;
1416 if (offDst < RTVFSPARSEDPATH_MAX)
1417 { /* likely */ }
1418 else
1419 return VERR_FILENAME_TOO_LONG;
1420 }
1421 else
1422 {
1423 /* Deal with dot components before we processes the slash/end. */
1424 if (pszDst[offDst - 1] == '.')
1425 {
1426 if ( offDst == 1
1427 || pszDst[offDst - 2] == '/')
1428 {
1429 pPath->cComponents--;
1430 offDst = pPath->aoffComponents[pPath->cComponents];
1431 }
1432 else if ( offDst > 3
1433 && pszDst[offDst - 2] == '.'
1434 && pszDst[offDst - 3] == '/')
1435 {
1436 if ( pPath->fAbsolute
1437 || offDst < 5
1438 || pszDst[offDst - 4] != '.'
1439 || pszDst[offDst - 5] != '.'
1440 || (offDst >= 6 && pszDst[offDst - 6] != '/') )
1441 {
1442 pPath->cComponents -= pPath->cComponents > 1 ? 2 : 1;
1443 offDst = pPath->aoffComponents[pPath->cComponents];
1444 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1445 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1446 }
1447 }
1448 }
1449
1450 if (ch != '\0')
1451 {
1452 /* Skip unnecessary slashes and check for end of path. */
1453 while ((ch = *pszSrc) == '/' || ch == '\\')
1454 pszSrc++;
1455
1456 if (ch == '\0')
1457 pPath->fDirSlash = true;
1458 }
1459
1460 if (ch == '\0')
1461 {
1462 /* Drop trailing slash unless it's the root slash. */
1463 if ( offDst > 0
1464 && pszDst[offDst - 1] == '/'
1465 && ( !pPath->fAbsolute
1466 || offDst > 1))
1467 offDst--;
1468
1469 /* Terminate the string and enter its length. */
1470 pszDst[offDst] = '\0';
1471 pszDst[offDst + 1] = '\0'; /* for aoffComponents[pPath->cComponents] */
1472 pPath->cch = (uint16_t)offDst;
1473 pPath->aoffComponents[pPath->cComponents] = (uint16_t)(offDst + 1);
1474 return VINF_SUCCESS;
1475 }
1476
1477 /* Append component separator before continuing with the next component. */
1478 if (offDst > 0 && pszDst[offDst - 1] != '/')
1479 pszDst[offDst++] = '/';
1480 if (offDst >= RTVFSPARSEDPATH_MAX)
1481 return VERR_FILENAME_TOO_LONG;
1482 break;
1483 }
1484 }
1485 }
1486}
1487
1488
1489/** @todo Replace RTVfsParsePath with RTPathParse and friends? */
1490RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
1491{
1492 if (*pszPath != '/' && *pszPath != '\\')
1493 {
1494 if (pszCwd)
1495 {
1496 /*
1497 * Relative with a CWD.
1498 */
1499 int rc = RTVfsParsePath(pPath, pszCwd, NULL /*crash if pszCwd is not absolute*/);
1500 if (RT_FAILURE(rc))
1501 return rc;
1502 }
1503 else
1504 {
1505 /*
1506 * Relative.
1507 */
1508 pPath->cch = 0;
1509 pPath->cComponents = 0;
1510 pPath->fDirSlash = false;
1511 pPath->fAbsolute = false;
1512 pPath->aoffComponents[0] = 0;
1513 pPath->aoffComponents[1] = 1;
1514 pPath->szPath[0] = '\0';
1515 pPath->szPath[1] = '\0';
1516 }
1517 }
1518 else
1519 {
1520 /*
1521 * Make pszPath relative, i.e. set up pPath for the root and skip
1522 * leading slashes in pszPath before appending it.
1523 */
1524 pPath->cch = 1;
1525 pPath->cComponents = 0;
1526 pPath->fDirSlash = false;
1527 pPath->fAbsolute = true;
1528 pPath->aoffComponents[0] = 1;
1529 pPath->aoffComponents[1] = 2;
1530 pPath->szPath[0] = '/';
1531 pPath->szPath[1] = '\0';
1532 pPath->szPath[2] = '\0';
1533 while (pszPath[0] == '/' || pszPath[0] == '\\')
1534 pszPath++;
1535 if (!pszPath[0])
1536 return VINF_SUCCESS;
1537 }
1538 return RTVfsParsePathAppend(pPath, pszPath, NULL);
1539}
1540
1541
1542
1543RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath)
1544{
1545 /*
1546 * Allocate the output buffer and hand the problem to rtVfsParsePath.
1547 */
1548 int rc;
1549 PRTVFSPARSEDPATH pPath = (PRTVFSPARSEDPATH)RTMemTmpAlloc(sizeof(RTVFSPARSEDPATH));
1550 if (pPath)
1551 {
1552 rc = RTVfsParsePath(pPath, pszPath, pszCwd);
1553 if (RT_FAILURE(rc))
1554 {
1555 RTMemTmpFree(pPath);
1556 pPath = NULL;
1557 }
1558 }
1559 else
1560 rc = VERR_NO_TMP_MEMORY;
1561 *ppPath = pPath; /* always set it */
1562 return rc;
1563}
1564
1565
1566RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath)
1567{
1568 if (pPath)
1569 {
1570 pPath->cch = UINT16_MAX;
1571 pPath->cComponents = UINT16_MAX;
1572 pPath->aoffComponents[0] = UINT16_MAX;
1573 pPath->aoffComponents[1] = UINT16_MAX;
1574 RTMemTmpFree(pPath);
1575 }
1576}
1577
1578
1579/**
1580 * Handles a symbolic link, adding it to
1581 *
1582 * @returns IPRT status code.
1583 * @param ppCurDir The current directory variable. We change it if
1584 * the symbolic links is absolute.
1585 * @param pPath The parsed path to update.
1586 * @param iPathComponent The current path component.
1587 * @param hSymlink The symbolic link to process.
1588 */
1589static int rtVfsTraverseHandleSymlink(RTVFSDIRINTERNAL **ppCurDir, PRTVFSPARSEDPATH pPath,
1590 uint16_t iPathComponent, RTVFSSYMLINK hSymlink)
1591{
1592 /*
1593 * Read the link and append the trailing path to it.
1594 */
1595 char szPath[RTPATH_MAX];
1596 int rc = RTVfsSymlinkRead(hSymlink, szPath, sizeof(szPath) - 1);
1597 if (RT_SUCCESS(rc))
1598 {
1599 szPath[sizeof(szPath) - 1] = '\0';
1600 if (iPathComponent + 1 < pPath->cComponents)
1601 rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iPathComponent + 1]]);
1602 }
1603 if (RT_SUCCESS(rc))
1604 {
1605 /*
1606 * Special hack help vfsstddir.cpp deal with symbolic links.
1607 */
1608 RTVFSDIRINTERNAL *pCurDir = *ppCurDir;
1609 char *pszPath = szPath;
1610 if (pCurDir->pOps->pfnFollowAbsoluteSymlink)
1611 {
1612 size_t cchRoot = rtPathRootSpecLen(szPath);
1613 if (cchRoot > 0)
1614 {
1615 pszPath = &szPath[cchRoot];
1616 char const chSaved = *pszPath;
1617 *pszPath = '\0';
1618 RTVFSDIRINTERNAL *pVfsRootDir;
1619 RTVfsLockAcquireWrite(pCurDir->Base.hLock);
1620 rc = pCurDir->pOps->pfnFollowAbsoluteSymlink(pCurDir, szPath, &pVfsRootDir);
1621 RTVfsLockAcquireWrite(pCurDir->Base.hLock);
1622 *pszPath = chSaved;
1623 if (RT_SUCCESS(rc))
1624 {
1625 RTVfsDirRelease(pCurDir);
1626 *ppCurDir = pCurDir = pVfsRootDir;
1627 }
1628 else if (rc == VERR_PATH_IS_RELATIVE)
1629 pszPath = szPath;
1630 else
1631 return rc;
1632 }
1633 }
1634
1635 rc = RTVfsParsePath(pPath, pszPath, NULL);
1636 if (RT_SUCCESS(rc))
1637 {
1638 /*
1639 * Deal with absolute references in a VFS setup.
1640 * Note! The current approach only correctly handles this on root volumes.
1641 */
1642 if ( pPath->fAbsolute
1643 && pCurDir->Base.hVfs != NIL_RTVFS) /** @todo This needs fixing once we implement mount points. */
1644 {
1645 RTVFSINTERNAL *pVfs = pCurDir->Base.hVfs;
1646 RTVFSDIRINTERNAL *pVfsRootDir;
1647 RTVfsLockAcquireRead(pVfs->Base.hLock);
1648 rc = pVfs->pOps->pfnOpenRoot(pVfs->Base.pvThis, &pVfsRootDir);
1649 RTVfsLockReleaseRead(pVfs->Base.hLock);
1650 if (RT_SUCCESS(rc))
1651 {
1652 RTVfsDirRelease(pCurDir);
1653 *ppCurDir = pCurDir = pVfsRootDir;
1654 }
1655 else
1656 return rc;
1657 }
1658 }
1659 }
1660 else if (rc == VERR_BUFFER_OVERFLOW)
1661 rc = VERR_FILENAME_TOO_LONG;
1662 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
1663}
1664
1665
1666/**
1667 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1668 *
1669 *
1670 * @returns IPRT status code.
1671 * @param pThis The VFS.
1672 * @param pPath The parsed path. This may be changed as symbolic
1673 * links are processed during the path traversal. If
1674 * it contains zero components, a dummy component is
1675 * added to assist the caller.
1676 * @param fFlags RTPATH_F_XXX.
1677 * @param ppVfsParentDir Where to return the parent directory handle
1678 * (referenced).
1679 */
1680static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags,
1681 RTVFSDIRINTERNAL **ppVfsParentDir)
1682{
1683 /*
1684 * Assert sanity.
1685 */
1686 AssertPtr(pThis);
1687 Assert(pThis->uMagic == RTVFSDIR_MAGIC);
1688 Assert(pThis->Base.cRefs > 0);
1689 AssertPtr(pPath);
1690 AssertPtr(ppVfsParentDir);
1691 *ppVfsParentDir = NULL;
1692 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1693
1694 /*
1695 * Start with the pThis directory.
1696 */
1697 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1698 return VERR_INVALID_HANDLE;
1699 RTVFSDIRINTERNAL *pCurDir = pThis;
1700
1701 /*
1702 * Special case for traversing zero components.
1703 * We fake up a "./" in the pPath to help the caller along.
1704 */
1705 if (pPath->cComponents == 0)
1706 {
1707 pPath->fDirSlash = true;
1708 pPath->szPath[0] = '.';
1709 pPath->szPath[1] = '\0';
1710 pPath->szPath[2] = '\0';
1711 pPath->cch = 1;
1712 pPath->cComponents = 1;
1713 pPath->aoffComponents[0] = 0;
1714 pPath->aoffComponents[1] = 1;
1715 pPath->aoffComponents[2] = 1;
1716
1717 *ppVfsParentDir = pCurDir;
1718 return VINF_SUCCESS;
1719 }
1720
1721
1722 /*
1723 * The traversal loop.
1724 */
1725 int rc = VINF_SUCCESS;
1726 unsigned cLinks = 0;
1727 uint16_t iComponent = 0;
1728 for (;;)
1729 {
1730 /*
1731 * Are we done yet?
1732 */
1733 bool fFinal = iComponent + 1 >= pPath->cComponents;
1734 if (fFinal && (fFlags & RTPATH_F_ON_LINK))
1735 {
1736 *ppVfsParentDir = pCurDir;
1737 return VINF_SUCCESS;
1738 }
1739
1740 /*
1741 * Try open the next entry.
1742 */
1743 const char *pszEntry = &pPath->szPath[pPath->aoffComponents[iComponent]];
1744 char *pszEntryEnd = &pPath->szPath[pPath->aoffComponents[iComponent + 1] - 1];
1745 *pszEntryEnd = '\0';
1746 RTVFSDIR hDir = NIL_RTVFSDIR;
1747 RTVFSSYMLINK hSymlink = NIL_RTVFSSYMLINK;
1748 RTVFS hVfsMnt = NIL_RTVFS;
1749 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ;
1750 if (fFinal)
1751 {
1752 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1753 rc = pCurDir->pOps->pfnOpen(pCurDir->Base.pvThis, pszEntry,
1754 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1755 RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING
1756 | RTVFSOBJ_F_TRAVERSAL | RTPATH_F_ON_LINK,
1757 &hVfsObj);
1758 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1759 *pszEntryEnd = '\0';
1760 if (RT_FAILURE(rc))
1761 {
1762 if ( rc == VERR_PATH_NOT_FOUND
1763 || rc == VERR_FILE_NOT_FOUND
1764 || rc == VERR_IS_A_DIRECTORY
1765 || rc == VERR_IS_A_FILE
1766 || rc == VERR_IS_A_FIFO
1767 || rc == VERR_IS_A_SOCKET
1768 || rc == VERR_IS_A_CHAR_DEVICE
1769 || rc == VERR_IS_A_BLOCK_DEVICE
1770 || rc == VERR_NOT_SYMLINK)
1771 {
1772 *ppVfsParentDir = pCurDir;
1773 return VINF_SUCCESS;
1774 }
1775 break;
1776 }
1777 hSymlink = RTVfsObjToSymlink(hVfsObj);
1778 Assert(hSymlink != NIL_RTVFSSYMLINK);
1779 }
1780 else
1781 {
1782 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1783 rc = pCurDir->pOps->pfnOpen(pCurDir->Base.pvThis, pszEntry,
1784 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1785 RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_OPEN_MOUNT
1786 | RTVFSOBJ_F_CREATE_NOTHING | RTVFSOBJ_F_TRAVERSAL | RTPATH_F_ON_LINK,
1787 &hVfsObj);
1788 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1789 *pszEntryEnd = '/';
1790 if (RT_FAILURE(rc))
1791 {
1792 if (rc == VERR_FILE_NOT_FOUND)
1793 rc = VERR_PATH_NOT_FOUND;
1794 break;
1795 }
1796 hDir = RTVfsObjToDir(hVfsObj);
1797 hSymlink = RTVfsObjToSymlink(hVfsObj);
1798 hVfsMnt = RTVfsObjToVfs(hVfsObj);
1799 }
1800 Assert( (hDir != NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1801 || (hDir == NIL_RTVFSDIR && hSymlink != NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1802 || (hDir == NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt != NIL_RTVFS));
1803 RTVfsObjRelease(hVfsObj);
1804
1805 if (hDir != NIL_RTVFSDIR)
1806 {
1807 /*
1808 * Directory - advance down the path.
1809 */
1810 AssertPtr(hDir);
1811 Assert(hDir->uMagic == RTVFSDIR_MAGIC);
1812 RTVfsDirRelease(pCurDir);
1813 pCurDir = hDir;
1814 iComponent++;
1815 }
1816 else if (hSymlink != NIL_RTVFSSYMLINK)
1817 {
1818 /*
1819 * Symbolic link - deal with it and retry the current component.
1820 */
1821 AssertPtr(hSymlink);
1822 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
1823 if (fFlags & RTPATH_F_NO_SYMLINKS)
1824 {
1825 rc = VERR_SYMLINK_NOT_ALLOWED;
1826 break;
1827 }
1828 cLinks++;
1829 if (cLinks >= RTVFS_MAX_LINKS)
1830 {
1831 rc = VERR_TOO_MANY_SYMLINKS;
1832 break;
1833 }
1834 rc = rtVfsTraverseHandleSymlink(&pCurDir, pPath, iComponent, hSymlink);
1835 if (RT_FAILURE(rc))
1836 break;
1837 iComponent = 0;
1838 }
1839 else
1840 {
1841 /*
1842 * Mount point - deal with it and retry the current component.
1843 */
1844 RTVfsDirRelease(pCurDir);
1845 RTVfsLockAcquireRead(hVfsMnt->Base.hLock);
1846 rc = hVfsMnt->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
1847 RTVfsLockReleaseRead(hVfsMnt->Base.hLock);
1848 if (RT_FAILURE(rc))
1849 {
1850 pCurDir = NULL;
1851 break;
1852 }
1853 iComponent = 0;
1854 /** @todo union mounts. */
1855 }
1856 }
1857
1858 if (pCurDir)
1859 RTVfsDirRelease(pCurDir);
1860
1861 return rc;
1862}
1863
1864
1865/**
1866 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1867 *
1868 * @returns IPRT status code.
1869 * @param pThis The VFS.
1870 * @param pPath The parsed path. This may be changed as symbolic
1871 * links are processed during the path traversal.
1872 * @param fFlags RTPATH_F_XXX.
1873 * @param ppVfsParentDir Where to return the parent directory handle
1874 * (referenced).
1875 */
1876static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir)
1877{
1878 /*
1879 * Assert sanity.
1880 */
1881 AssertPtr(pThis);
1882 Assert(pThis->uMagic == RTVFS_MAGIC);
1883 Assert(pThis->Base.cRefs > 0);
1884 AssertPtr(pPath);
1885 AssertPtr(ppVfsParentDir);
1886 *ppVfsParentDir = NULL;
1887 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
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 RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING, &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 }
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);
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 if (pPath->cComponents > 0)
2553 {
2554 /*
2555 * Tranverse the path, resolving the parent node and any symlinks
2556 * in the final element, and ask the directory to open the subdir.
2557 */
2558 RTVFSDIRINTERNAL *pVfsParentDir;
2559 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2560 if (RT_SUCCESS(rc))
2561 {
2562 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2563
2564 /** @todo there is a symlink creation race here. */
2565 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2566 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2567 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2568
2569 RTVfsDirRelease(pVfsParentDir);
2570
2571 if (RT_SUCCESS(rc))
2572 {
2573 AssertPtr(*phVfsDir);
2574 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2575 }
2576 }
2577 }
2578 /*
2579 * If the path boils down to '.' return the root directory.
2580 */
2581 else
2582 {
2583 RTVfsLockAcquireRead(pThis->Base.hLock);
2584 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phVfsDir);
2585 RTVfsLockReleaseRead(pThis->Base.hLock);
2586 }
2587 RTVfsParsePathFree(pPath);
2588 }
2589 return rc;
2590}
2591
2592
2593RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2594{
2595 /*
2596 * Validate input.
2597 */
2598 RTVFSDIRINTERNAL *pThis = hVfsDir;
2599 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2600 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2601 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2602 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2603 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2604
2605 /*
2606 * Parse the path, it's always relative to the given directory.
2607 */
2608 PRTVFSPARSEDPATH pPath;
2609 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2610 if (RT_SUCCESS(rc))
2611 {
2612 if (pPath->cComponents > 0)
2613 {
2614 /*
2615 * Tranverse the path, resolving the parent node and any symlinks
2616 * in the final element, and ask the directory to open the subdir.
2617 */
2618 RTVFSDIRINTERNAL *pVfsParentDir;
2619 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2620 if (RT_SUCCESS(rc))
2621 {
2622 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2623
2624 /** @todo there is a symlink creation race here. */
2625 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2626 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2627 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2628
2629 RTVfsDirRelease(pVfsParentDir);
2630
2631 if (RT_SUCCESS(rc))
2632 {
2633 AssertPtr(*phVfsDir);
2634 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2635 }
2636 }
2637 }
2638 /*
2639 * The path boils down to '.', call pfnOpenDir on pThis with '.' as input.
2640 * The caller may wish for a new directory instance to enumerate the entries
2641 * in parallel or some such thing.
2642 */
2643 else
2644 {
2645 RTVfsLockAcquireWrite(pThis->Base.hLock);
2646 rc = pThis->pOps->pfnOpenDir(pThis->Base.pvThis, ".", fFlags, phVfsDir);
2647 RTVfsLockReleaseWrite(pThis->Base.hLock);
2648 }
2649 RTVfsParsePathFree(pPath);
2650 }
2651 return rc;
2652}
2653
2654
2655RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir)
2656{
2657 /*
2658 * Validate input.
2659 */
2660 RTVFSDIRINTERNAL *pThis = hVfsDir;
2661 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2662 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2663 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2664 AssertPtrNullReturn(phVfsDir, VERR_INVALID_POINTER);
2665 AssertReturn(!(fFlags & ~RTDIRCREATE_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
2666 fMode = rtFsModeNormalize(fMode, pszRelPath, 0);
2667 AssertReturn(rtFsModeIsValidPermissions(fMode), VERR_INVALID_FMODE);
2668 if (!(fFlags & RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET))
2669 fMode |= RTFS_DOS_NT_NOT_CONTENT_INDEXED;
2670
2671 /*
2672 * Parse the path, it's always relative to the given directory.
2673 */
2674 PRTVFSPARSEDPATH pPath;
2675 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2676 if (RT_SUCCESS(rc))
2677 {
2678 if (pPath->cComponents > 0)
2679 {
2680 /*
2681 * Tranverse the path, resolving the parent node, not checking for symbolic
2682 * links in the final element, and ask the directory to create the subdir.
2683 */
2684 RTVFSDIRINTERNAL *pVfsParentDir;
2685 rc = rtVfsDirTraverseToParent(pThis, pPath,
2686 fFlags & RTDIRCREATE_FLAGS_NO_SYMLINKS
2687 ? RTPATH_F_NO_SYMLINKS | RTPATH_F_ON_LINK : RTPATH_F_FOLLOW_LINK,
2688 &pVfsParentDir);
2689 if (RT_SUCCESS(rc))
2690 {
2691 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2692
2693 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2694 rc = pVfsParentDir->pOps->pfnCreateDir(pVfsParentDir->Base.pvThis, pszEntryName, fMode, phVfsDir);
2695 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2696
2697 RTVfsDirRelease(pVfsParentDir);
2698
2699 if (RT_SUCCESS(rc) && phVfsDir)
2700 {
2701 AssertPtr(*phVfsDir);
2702 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2703 }
2704 }
2705 }
2706 else
2707 rc = VERR_PATH_ZERO_LENGTH;
2708 RTVfsParsePathFree(pPath);
2709 }
2710 return rc;
2711}
2712
2713
2714RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2715{
2716 /*
2717 * Validate input.
2718 */
2719 RTVFSDIRINTERNAL *pThis = hVfsDir;
2720 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2721 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2722 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2723 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2724
2725 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2726 if (RT_FAILURE(rc))
2727 return rc;
2728
2729 /*
2730 * Parse the relative path.
2731 */
2732 PRTVFSPARSEDPATH pPath;
2733 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2734 if (RT_SUCCESS(rc))
2735 {
2736 if (pPath->cComponents > 0)
2737 {
2738 /*
2739 * Tranverse the path, resolving the parent node and any symlinks
2740 * in the final element, and ask the directory to open the file.
2741 */
2742 RTVFSDIRINTERNAL *pVfsParentDir;
2743 rc = rtVfsDirTraverseToParent(pThis, pPath,
2744 (fOpen & RTFILE_O_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_FOLLOW_LINK,
2745 &pVfsParentDir);
2746 if (RT_SUCCESS(rc))
2747 {
2748 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2749
2750 if ( pVfsParentDir->pOps->pfnOpenFile == NULL
2751 || pPath->fDirSlash)
2752 {
2753 RTVFSOBJ hVfsObj;
2754 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2755 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpen,
2756 RTVFSOBJ_F_OPEN_ANY_FILE | RTVFSOBJ_F_CREATE_FILE
2757 | RTPATH_F_FOLLOW_LINK, &hVfsObj);
2758 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2759 if (RT_SUCCESS(rc))
2760 {
2761 if (RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2762 *phVfsFile = RTVfsObjToFile(hVfsObj);
2763 else
2764 {
2765 /** @todo parse symbolic links. */
2766 AssertFailed();
2767 rc = VERR_NOT_IMPLEMENTED;
2768 }
2769 RTVfsObjRelease(hVfsObj);
2770 }
2771 }
2772 else
2773 {
2774 /** @todo there is a symlink creation race here. */
2775 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2776 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2777 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2778 }
2779
2780 if (RT_SUCCESS(rc))
2781 {
2782 AssertPtr(*phVfsFile);
2783 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2784 }
2785
2786 RTVfsDirRelease(pVfsParentDir);
2787 }
2788 }
2789 else
2790 rc = VERR_NOT_A_FILE;
2791 RTVfsParsePathFree(pPath);
2792 }
2793 return rc;
2794}
2795
2796
2797RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
2798{
2799 RTVFSFILE hVfsFile;
2800 int rc = RTVfsDirOpenFile(hVfsDir, pszPath, fOpen, &hVfsFile);
2801 if (RT_SUCCESS(rc))
2802 {
2803 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
2804 AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
2805 RTVfsFileRelease(hVfsFile);
2806 }
2807 return rc;
2808}
2809
2810
2811RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
2812{
2813 /*
2814 * Validate input.
2815 */
2816 RTVFSDIRINTERNAL *pThis = hVfsDir;
2817 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2818 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2819 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2820 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
2821
2822 int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
2823 if (RT_FAILURE(rc))
2824 return rc;
2825 AssertMsgReturn( RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
2826 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
2827 ("fObjFlags=%#x\n", fObjFlags),
2828 VERR_INVALID_FLAGS);
2829
2830 /*
2831 * Parse the relative path. If it ends with a directory slash or it boils
2832 * down to an empty path (i.e. re-opening hVfsDir), adjust the flags to only
2833 * open/create directories.
2834 */
2835 PRTVFSPARSEDPATH pPath;
2836 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2837 if (RT_SUCCESS(rc))
2838 {
2839 /*
2840 * Tranverse the path, resolving the parent node.
2841 * We'll do the symbolic link checking here with help of pfnOpen.
2842 */
2843 RTVFSDIRINTERNAL *pVfsParentDir;
2844 rc = rtVfsDirTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2845 if (RT_SUCCESS(rc))
2846 {
2847 /*
2848 * Do the opening. Loop if we need to follow symbolic links.
2849 */
2850 for (uint32_t cLoops = 1;; cLoops++)
2851 {
2852 /* If we end with a directory slash, adjust open flags. */
2853 if (pPath->fDirSlash)
2854 {
2855 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
2856 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
2857 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
2858 }
2859 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
2860 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
2861
2862 /* Open it. */
2863 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2864 RTVFSOBJ hVfsObj;
2865 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2866 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
2867 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2868 if (RT_FAILURE(rc))
2869 break;
2870
2871 /* We're done if we don't follow links or this wasn't a link. */
2872 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2873 || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
2874 {
2875 *phVfsObj = hVfsObj;
2876 break;
2877 }
2878
2879 /* Follow symbolic link. */
2880 if (cLoops < RTVFS_MAX_LINKS)
2881 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2882 else
2883 rc = VERR_TOO_MANY_SYMLINKS;
2884 RTVfsObjRelease(hVfsObj);
2885 if (RT_FAILURE(rc))
2886 break;
2887 }
2888
2889 RTVfsDirRelease(pVfsParentDir);
2890 }
2891 RTVfsParsePathFree(pPath);
2892 }
2893 return rc;
2894}
2895
2896
2897RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo,
2898 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2899{
2900 /*
2901 * Validate input.
2902 */
2903 RTVFSDIRINTERNAL *pThis = hVfsDir;
2904 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2905 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2906 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2907 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2908 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2909 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2910 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2911
2912 /*
2913 * Parse the relative path. Then traverse to the parent directory.
2914 */
2915 PRTVFSPARSEDPATH pPath;
2916 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2917 if (RT_SUCCESS(rc))
2918 {
2919 if (pPath->cComponents > 0)
2920 {
2921 RTVFSDIRINTERNAL *pVfsParentDir;
2922 rc = rtVfsDirTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
2923 if (RT_SUCCESS(rc))
2924 {
2925 /*
2926 * Call the query method on the parent directory.
2927 */
2928 /** @todo symlink race condition here :/ */
2929 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2930 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2931 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2932 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2933
2934 RTVfsDirRelease(pVfsParentDir);
2935 }
2936 else
2937 rc = VERR_INVALID_PARAMETER;
2938 }
2939 /*
2940 * The path boils down to '.' so just query the directory.
2941 */
2942 else
2943 {
2944 RTVfsLockAcquireRead(pThis->Base.hLock);
2945 rc = pThis->Base.pOps->pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr);
2946 RTVfsLockReleaseRead(pThis->Base.hLock);
2947 }
2948 RTVfsParsePathFree(pPath);
2949 }
2950 return rc;
2951}
2952
2953
2954RTDECL(int) RTVfsDirRemoveDir(RTVFSDIR hVfsDir, const char *pszRelPath, uint32_t fFlags)
2955{
2956 /*
2957 * Validate input.
2958 */
2959 RTVFSDIRINTERNAL *pThis = hVfsDir;
2960 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2961 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2962 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2963 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2964
2965 /*
2966 * Parse the path, it's always relative to the given directory.
2967 */
2968 PRTVFSPARSEDPATH pPath;
2969 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2970 if (RT_SUCCESS(rc))
2971 {
2972 if (pPath->cComponents > 0)
2973 {
2974 /*
2975 * Tranverse the path, resolving the parent node, not checking for symbolic
2976 * links in the final element, and ask the directory to remove the subdir.
2977 */
2978 RTVFSDIRINTERNAL *pVfsParentDir;
2979 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
2980 if (RT_SUCCESS(rc))
2981 {
2982 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2983
2984 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2985 rc = pVfsParentDir->pOps->pfnUnlinkEntry(pVfsParentDir->Base.pvThis, pszEntryName, RTFS_TYPE_DIRECTORY);
2986 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2987
2988 RTVfsDirRelease(pVfsParentDir);
2989 }
2990 }
2991 else
2992 rc = VERR_PATH_ZERO_LENGTH;
2993 RTVfsParsePathFree(pPath);
2994 }
2995 return rc;
2996}
2997
2998
2999
3000RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
3001{
3002 /*
3003 * Validate input.
3004 */
3005 RTVFSDIRINTERNAL *pThis = hVfsDir;
3006 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3007 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3008 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
3009 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
3010
3011 size_t cbDirEntry = sizeof(*pDirEntry);
3012 if (!pcbDirEntry)
3013 pcbDirEntry = &cbDirEntry;
3014 else
3015 {
3016 cbDirEntry = *pcbDirEntry;
3017 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
3018 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
3019 VERR_INVALID_PARAMETER);
3020 }
3021
3022 /*
3023 * Call the directory method.
3024 */
3025 RTVfsLockAcquireRead(pThis->Base.hLock);
3026 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
3027 RTVfsLockReleaseRead(pThis->Base.hLock);
3028 return rc;
3029}
3030
3031
3032/*
3033 *
3034 * S Y M B O L I C L I N K
3035 * S Y M B O L I C L I N K
3036 * S Y M B O L I C L I N K
3037 *
3038 */
3039
3040RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
3041 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
3042{
3043 /*
3044 * Validate the input, be extra strict in strict builds.
3045 */
3046 AssertPtr(pSymlinkOps);
3047 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3048 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3049 Assert(!pSymlinkOps->fReserved);
3050 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
3051 Assert(cbInstance > 0);
3052 AssertPtr(ppvInstance);
3053 AssertPtr(phVfsSym);
3054 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3055
3056 /*
3057 * Allocate the handle + instance data.
3058 */
3059 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
3060 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3061 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
3062 if (!pThis)
3063 return VERR_NO_MEMORY;
3064
3065 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3066 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3067 if (RT_FAILURE(rc))
3068 {
3069 RTMemFree(pThis);
3070 return rc;
3071 }
3072
3073 pThis->uMagic = RTVFSSYMLINK_MAGIC;
3074 pThis->pOps = pSymlinkOps;
3075
3076 *phVfsSym = pThis;
3077 *ppvInstance = pThis->Base.pvThis;
3078 return VINF_SUCCESS;
3079}
3080
3081
3082RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
3083{
3084 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3085 AssertPtrReturn(pThis, UINT32_MAX);
3086 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3087 return rtVfsObjRetain(&pThis->Base);
3088}
3089
3090
3091RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL)
3092{
3093 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3094 AssertPtrReturn(pThis, UINT32_MAX);
3095 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3096 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsSymlinkRetainDebug", RT_SRC_POS_ARGS);
3097}
3098
3099
3100RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
3101{
3102 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3103 if (pThis == NIL_RTVFSSYMLINK)
3104 return 0;
3105 AssertPtrReturn(pThis, UINT32_MAX);
3106 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3107 return rtVfsObjRelease(&pThis->Base);
3108}
3109
3110
3111RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3112{
3113 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3114 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3115 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3116 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3117}
3118
3119
3120RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
3121{
3122 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3123 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3124 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3125
3126 fMode = rtFsModeNormalize(fMode, NULL, 0);
3127 if (!rtFsModeIsValid(fMode))
3128 return VERR_INVALID_PARAMETER;
3129
3130 RTVfsLockAcquireWrite(pThis->Base.hLock);
3131 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
3132 RTVfsLockReleaseWrite(pThis->Base.hLock);
3133 return rc;
3134}
3135
3136
3137RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
3138 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
3139{
3140 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3141 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3142 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3143
3144 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
3145 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
3146 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
3147 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
3148
3149 RTVfsLockAcquireWrite(pThis->Base.hLock);
3150 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
3151 RTVfsLockReleaseWrite(pThis->Base.hLock);
3152 return rc;
3153}
3154
3155
3156RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
3157{
3158 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3159 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3160 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3161
3162 RTVfsLockAcquireWrite(pThis->Base.hLock);
3163 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
3164 RTVfsLockReleaseWrite(pThis->Base.hLock);
3165 return rc;
3166}
3167
3168
3169RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
3170{
3171 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3172 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3173 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3174
3175 RTVfsLockAcquireWrite(pThis->Base.hLock);
3176 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
3177 RTVfsLockReleaseWrite(pThis->Base.hLock);
3178
3179 return rc;
3180}
3181
3182
3183
3184/*
3185 *
3186 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3187 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3188 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3189 *
3190 */
3191
3192RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3193 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
3194{
3195 /*
3196 * Validate the input, be extra strict in strict builds.
3197 */
3198 AssertPtr(pIoStreamOps);
3199 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3200 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3201 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
3202 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
3203 Assert(cbInstance > 0);
3204 Assert(fOpen & RTFILE_O_ACCESS_MASK);
3205 AssertPtr(ppvInstance);
3206 AssertPtr(phVfsIos);
3207 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3208
3209 /*
3210 * Allocate the handle + instance data.
3211 */
3212 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
3213 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3214 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
3215 if (!pThis)
3216 return VERR_NO_MEMORY;
3217
3218 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3219 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3220 if (RT_FAILURE(rc))
3221 {
3222 RTMemFree(pThis);
3223 return rc;
3224 }
3225
3226 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
3227 pThis->fFlags = fOpen;
3228 pThis->pOps = pIoStreamOps;
3229
3230 *phVfsIos = pThis;
3231 *ppvInstance = pThis->Base.pvThis;
3232 return VINF_SUCCESS;
3233}
3234
3235
3236RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
3237{
3238 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3239 AssertPtrReturn(pThis, NULL);
3240 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
3241 if (pThis->pOps != pIoStreamOps)
3242 return NULL;
3243 return pThis->Base.pvThis;
3244}
3245
3246
3247#ifdef DEBUG
3248# undef RTVfsIoStrmRetain
3249#endif
3250RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
3251{
3252 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3253 AssertPtrReturn(pThis, UINT32_MAX);
3254 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3255 return rtVfsObjRetain(&pThis->Base);
3256}
3257#ifdef DEBUG
3258# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS)
3259#endif
3260
3261
3262RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL)
3263{
3264 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3265 AssertPtrReturn(pThis, UINT32_MAX);
3266 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3267 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsIoStrmRetainDebug", RT_SRC_POS_ARGS);
3268}
3269
3270
3271RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
3272{
3273 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3274 if (pThis == NIL_RTVFSIOSTREAM)
3275 return 0;
3276 AssertPtrReturn(pThis, UINT32_MAX);
3277 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3278 return rtVfsObjRelease(&pThis->Base);
3279}
3280
3281
3282RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
3283{
3284 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3285 AssertPtrReturn(pThis, NIL_RTVFSFILE);
3286 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
3287
3288 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3289 {
3290 rtVfsObjRetainVoid(&pThis->Base, "RTVfsIoStrmToFile");
3291 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3292 }
3293
3294 /* this is no crime, so don't assert. */
3295 return NIL_RTVFSFILE;
3296}
3297
3298
3299RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3300{
3301 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3302 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3303 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3304 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3305}
3306
3307
3308RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
3309{
3310 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3311 if (pcbRead)
3312 *pcbRead = 0;
3313 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3314 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3315 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3316 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3317 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3318
3319 RTSGSEG Seg = { pvBuf, cbToRead };
3320 RTSGBUF SgBuf;
3321 RTSgBufInit(&SgBuf, &Seg, 1);
3322
3323 RTVfsLockAcquireWrite(pThis->Base.hLock);
3324 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
3325 RTVfsLockReleaseWrite(pThis->Base.hLock);
3326 return rc;
3327}
3328
3329
3330RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
3331 bool fBlocking, size_t *pcbRead)
3332{
3333 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3334 if (pcbRead)
3335 *pcbRead = 0;
3336 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3337 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3338 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3339 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3340 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3341
3342 RTSGSEG Seg = { pvBuf, cbToRead };
3343 RTSGBUF SgBuf;
3344 RTSgBufInit(&SgBuf, &Seg, 1);
3345
3346 RTVfsLockAcquireWrite(pThis->Base.hLock);
3347 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
3348 RTVfsLockReleaseWrite(pThis->Base.hLock);
3349 return rc;
3350}
3351
3352
3353RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
3354{
3355 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3356 if (pcbWritten)
3357 *pcbWritten = 0;
3358 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3359 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3360 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3361 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3362 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3363
3364 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3365 RTSGBUF SgBuf;
3366 RTSgBufInit(&SgBuf, &Seg, 1);
3367
3368 RTVfsLockAcquireWrite(pThis->Base.hLock);
3369 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
3370 RTVfsLockReleaseWrite(pThis->Base.hLock);
3371 return rc;
3372}
3373
3374
3375RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
3376 bool fBlocking, size_t *pcbWritten)
3377{
3378 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3379 if (pcbWritten)
3380 *pcbWritten = 0;
3381 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3382 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3383 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3384 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3385 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3386
3387 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3388 RTSGBUF SgBuf;
3389 RTSgBufInit(&SgBuf, &Seg, 1);
3390
3391 RTVfsLockAcquireWrite(pThis->Base.hLock);
3392 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
3393 RTVfsLockReleaseWrite(pThis->Base.hLock);
3394 return rc;
3395}
3396
3397
3398RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3399{
3400 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3401 if (pcbRead)
3402 *pcbRead = 0;
3403 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3404 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3405 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3406 AssertPtr(pSgBuf);
3407 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3408 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3409
3410 RTVfsLockAcquireWrite(pThis->Base.hLock);
3411 int rc;
3412 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3413 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
3414 else
3415 {
3416 size_t cbRead = 0;
3417 rc = VINF_SUCCESS;
3418
3419 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3420 {
3421 RTSGBUF SgBuf;
3422 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3423
3424 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
3425 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
3426 if (RT_FAILURE(rc))
3427 break;
3428 cbRead += cbReadSeg;
3429 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
3430 break;
3431 if (off != -1)
3432 off += cbReadSeg;
3433 }
3434
3435 if (pcbRead)
3436 *pcbRead = cbRead;
3437 }
3438 RTVfsLockReleaseWrite(pThis->Base.hLock);
3439 return rc;
3440}
3441
3442
3443RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3444{
3445 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3446 if (pcbWritten)
3447 *pcbWritten = 0;
3448 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3449 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3450 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3451 AssertPtr(pSgBuf);
3452 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3453 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3454
3455 RTVfsLockAcquireWrite(pThis->Base.hLock);
3456 int rc;
3457 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3458 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
3459 else
3460 {
3461 size_t cbWritten = 0;
3462 rc = VINF_SUCCESS;
3463
3464 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3465 {
3466 RTSGBUF SgBuf;
3467 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3468
3469 size_t cbWrittenSeg = 0;
3470 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
3471 if (RT_FAILURE(rc))
3472 break;
3473 if (pcbWritten)
3474 {
3475 cbWritten += cbWrittenSeg;
3476 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
3477 break;
3478 if (off != -1)
3479 off += cbWrittenSeg;
3480 }
3481 else if (off != -1)
3482 off += pSgBuf->paSegs[iSeg].cbSeg;
3483 }
3484
3485 if (pcbWritten)
3486 *pcbWritten = cbWritten;
3487 }
3488 RTVfsLockReleaseWrite(pThis->Base.hLock);
3489 return rc;
3490}
3491
3492
3493RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
3494{
3495 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3496 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3497 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3498
3499 RTVfsLockAcquireWrite(pThis->Base.hLock);
3500 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
3501 RTVfsLockReleaseWrite(pThis->Base.hLock);
3502 return rc;
3503}
3504
3505
3506RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3507 uint32_t *pfRetEvents)
3508{
3509 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3510 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3511 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3512
3513 RTVfsLockAcquireWrite(pThis->Base.hLock);
3514 int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
3515 RTVfsLockReleaseWrite(pThis->Base.hLock);
3516 return rc;
3517}
3518
3519
3520RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
3521{
3522 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3523 AssertPtrReturn(pThis, -1);
3524 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3525
3526 RTFOFF off;
3527 RTVfsLockAcquireRead(pThis->Base.hLock);
3528 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
3529 RTVfsLockReleaseRead(pThis->Base.hLock);
3530 if (RT_FAILURE(rc))
3531 off = rc;
3532 return off;
3533}
3534
3535
3536RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3537{
3538 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3539 AssertPtrReturn(pThis, -1);
3540 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3541 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
3542
3543 int rc;
3544 if (pThis->pOps->pfnSkip)
3545 {
3546 RTVfsLockAcquireWrite(pThis->Base.hLock);
3547 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
3548 RTVfsLockReleaseWrite(pThis->Base.hLock);
3549 }
3550 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3551 {
3552 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3553 RTFOFF offIgnored;
3554
3555 RTVfsLockAcquireWrite(pThis->Base.hLock);
3556 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
3557 RTVfsLockReleaseWrite(pThis->Base.hLock);
3558 }
3559 else
3560 {
3561 void *pvBuf = RTMemTmpAlloc(_64K);
3562 if (pvBuf)
3563 {
3564 rc = VINF_SUCCESS;
3565 while (cb > 0)
3566 {
3567 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
3568 RTVfsLockAcquireWrite(pThis->Base.hLock);
3569 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
3570 RTVfsLockReleaseWrite(pThis->Base.hLock);
3571 if (RT_FAILURE(rc))
3572 break;
3573 cb -= cbToRead;
3574 }
3575
3576 RTMemTmpFree(pvBuf);
3577 }
3578 else
3579 rc = VERR_NO_TMP_MEMORY;
3580 }
3581 return rc;
3582}
3583
3584
3585RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3586{
3587 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3588 AssertPtrReturn(pThis, -1);
3589 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3590
3591 int rc;
3592 if (pThis->pOps->pfnZeroFill)
3593 {
3594 RTVfsLockAcquireWrite(pThis->Base.hLock);
3595 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
3596 RTVfsLockReleaseWrite(pThis->Base.hLock);
3597 }
3598 else
3599 {
3600 rc = VINF_SUCCESS;
3601 while (cb > 0)
3602 {
3603 size_t cbToWrite = (size_t)RT_MIN(cb, (ssize_t)sizeof(g_abRTZero64K));
3604 RTVfsLockAcquireWrite(pThis->Base.hLock);
3605 rc = RTVfsIoStrmWrite(hVfsIos, g_abRTZero64K, cbToWrite, true /*fBlocking*/, NULL);
3606 RTVfsLockReleaseWrite(pThis->Base.hLock);
3607 if (RT_FAILURE(rc))
3608 break;
3609 cb -= cbToWrite;
3610 }
3611 }
3612 return rc;
3613}
3614
3615
3616RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
3617{
3618 /*
3619 * There is where the zero read behavior comes in handy.
3620 */
3621 char bDummy;
3622 size_t cbRead;
3623 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
3624 return rc == VINF_EOF;
3625}
3626
3627
3628
3629RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos)
3630{
3631 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3632 AssertPtrReturn(pThis, 0);
3633 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, 0);
3634 return pThis->fFlags;
3635}
3636
3637
3638
3639/*
3640 *
3641 * F I L E F I L E F I L E
3642 * F I L E F I L E F I L E
3643 * F I L E F I L E F I L E
3644 *
3645 */
3646
3647RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3648 PRTVFSFILE phVfsFile, void **ppvInstance)
3649{
3650 /*
3651 * Validate the input, be extra strict in strict builds.
3652 */
3653 AssertPtr(pFileOps);
3654 AssertReturn(pFileOps->uVersion == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3655 AssertReturn(pFileOps->uEndMarker == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3656 Assert(!pFileOps->fReserved);
3657 RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
3658 Assert(cbInstance > 0);
3659 Assert(fOpen & (RTFILE_O_ACCESS_MASK | RTFILE_O_ACCESS_ATTR_MASK));
3660 AssertPtr(ppvInstance);
3661 AssertPtr(phVfsFile);
3662 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3663
3664 /*
3665 * Allocate the handle + instance data.
3666 */
3667 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
3668 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3669 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
3670 if (!pThis)
3671 return VERR_NO_MEMORY;
3672
3673 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, false /*fNoVfsRef*/, hLock,
3674 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3675 if (RT_FAILURE(rc))
3676 {
3677 RTMemFree(pThis);
3678 return rc;
3679 }
3680
3681 pThis->uMagic = RTVFSFILE_MAGIC;
3682 pThis->fReserved = 0;
3683 pThis->pOps = pFileOps;
3684 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
3685 pThis->Stream.fFlags = fOpen;
3686 pThis->Stream.pOps = &pFileOps->Stream;
3687
3688 *phVfsFile = pThis;
3689 *ppvInstance = pThis->Stream.Base.pvThis;
3690 return VINF_SUCCESS;
3691}
3692
3693
3694RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
3695{
3696 /*
3697 * Validate input.
3698 */
3699 RTVFSINTERNAL *pThis = hVfs;
3700 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3701 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
3702 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
3703 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
3704
3705 int rc = rtFileRecalcAndValidateFlags(&fOpen);
3706 if (RT_FAILURE(rc))
3707 return rc;
3708
3709 /*
3710 * Parse the path, assume current directory is root since we've got no
3711 * caller context here.
3712 */
3713 PRTVFSPARSEDPATH pPath;
3714 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
3715 if (RT_SUCCESS(rc))
3716 {
3717 if ( !pPath->fDirSlash
3718 && pPath->cComponents > 0)
3719 {
3720 /*
3721 * Tranverse the path, resolving the parent node and any symlinks
3722 * in the final element, and ask the directory to open the file.
3723 */
3724 RTVFSDIRINTERNAL *pVfsParentDir;
3725 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
3726 if (RT_SUCCESS(rc))
3727 {
3728 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3729
3730 /** @todo there is a symlink creation race here. */
3731 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3732 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
3733 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3734
3735 RTVfsDirRelease(pVfsParentDir);
3736
3737 if (RT_SUCCESS(rc))
3738 {
3739 AssertPtr(*phVfsFile);
3740 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
3741 }
3742 }
3743 }
3744 else
3745 rc = VERR_NOT_A_FILE;
3746 RTVfsParsePathFree(pPath);
3747 }
3748 return rc;
3749}
3750
3751
3752#ifdef DEBUG
3753# undef RTVfsFileRetain
3754#endif
3755RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
3756{
3757 RTVFSFILEINTERNAL *pThis = hVfsFile;
3758 AssertPtrReturn(pThis, UINT32_MAX);
3759 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3760 return rtVfsObjRetain(&pThis->Stream.Base);
3761}
3762#ifdef DEBUG
3763# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS)
3764#endif
3765
3766
3767RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL)
3768{
3769 RTVFSFILEINTERNAL *pThis = hVfsFile;
3770 AssertPtrReturn(pThis, UINT32_MAX);
3771 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3772 return rtVfsObjRetainDebug(&pThis->Stream.Base, "RTVFsFileRetainDebug", RT_SRC_POS_ARGS);
3773}
3774
3775
3776RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
3777{
3778 RTVFSFILEINTERNAL *pThis = hVfsFile;
3779 if (pThis == NIL_RTVFSFILE)
3780 return 0;
3781 AssertPtrReturn(pThis, UINT32_MAX);
3782 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3783 return rtVfsObjRelease(&pThis->Stream.Base);
3784}
3785
3786
3787RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
3788{
3789 RTVFSFILEINTERNAL *pThis = hVfsFile;
3790 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
3791 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
3792
3793 rtVfsObjRetainVoid(&pThis->Stream.Base, "RTVfsFileToIoStream");
3794 return &pThis->Stream;
3795}
3796
3797
3798RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3799{
3800 RTVFSFILEINTERNAL *pThis = hVfsFile;
3801 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3802 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3803 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
3804}
3805
3806
3807RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3808{
3809 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3810 if (pcbRead)
3811 *pcbRead = 0;
3812 RTVFSFILEINTERNAL *pThis = hVfsFile;
3813 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3814 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3815 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3816}
3817
3818
3819RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3820{
3821 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3822 if (pcbWritten)
3823 *pcbWritten = 0;
3824 RTVFSFILEINTERNAL *pThis = hVfsFile;
3825 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3826 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3827 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3828}
3829
3830
3831RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3832{
3833 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3834 if (pcbWritten)
3835 *pcbWritten = 0;
3836 RTVFSFILEINTERNAL *pThis = hVfsFile;
3837 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3838 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3839
3840 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3841 if (RT_SUCCESS(rc))
3842 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3843
3844 return rc;
3845}
3846
3847
3848RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3849{
3850 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3851 if (pcbRead)
3852 *pcbRead = 0;
3853 RTVFSFILEINTERNAL *pThis = hVfsFile;
3854 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3855 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3856
3857 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3858 if (RT_SUCCESS(rc))
3859 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3860
3861 return rc;
3862}
3863
3864
3865RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3866{
3867 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3868 if (pcbRead)
3869 *pcbRead = 0;
3870 RTVFSFILEINTERNAL *pThis = hVfsFile;
3871 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3872 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3873
3874 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
3875}
3876
3877
3878RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3879{
3880 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3881 if (pcbWritten)
3882 *pcbWritten = 0;
3883 RTVFSFILEINTERNAL *pThis = hVfsFile;
3884 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3885 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3886
3887 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
3888}
3889
3890
3891RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
3892{
3893 RTVFSFILEINTERNAL *pThis = hVfsFile;
3894 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3895 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3896 return RTVfsIoStrmFlush(&pThis->Stream);
3897}
3898
3899
3900RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3901 uint32_t *pfRetEvents)
3902{
3903 RTVFSFILEINTERNAL *pThis = hVfsFile;
3904 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3905 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3906 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
3907}
3908
3909
3910RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
3911{
3912 RTVFSFILEINTERNAL *pThis = hVfsFile;
3913 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3914 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3915 return RTVfsIoStrmTell(&pThis->Stream);
3916}
3917
3918
3919RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
3920{
3921 RTVFSFILEINTERNAL *pThis = hVfsFile;
3922 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3923 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3924
3925 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
3926 || uMethod == RTFILE_SEEK_CURRENT
3927 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
3928 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
3929
3930 RTFOFF offActual = 0;
3931 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3932 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
3933 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3934 if (RT_SUCCESS(rc) && poffActual)
3935 {
3936 Assert(offActual >= 0);
3937 *poffActual = offActual;
3938 }
3939
3940 return rc;
3941}
3942
3943
3944RTDECL(int) RTVfsFileGetSize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
3945{
3946 RTVFSFILEINTERNAL *pThis = hVfsFile;
3947 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3948 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3949 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
3950
3951 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3952 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
3953 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3954
3955 return rc;
3956}
3957
3958
3959RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile)
3960{
3961 RTVFSFILEINTERNAL *pThis = hVfsFile;
3962 AssertPtrReturn(pThis, 0);
3963 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, 0);
3964 return pThis->Stream.fFlags;
3965}
3966
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