VirtualBox

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

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

iprt/vfs: Made RTVFSFILEOPS::pfnPollOne optional.

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

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