VirtualBox

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

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

IPRT/vfs: Implemented RTVFsFileSetSize, RTVfsFileGetMaxSize and RTvfsFileQueryMaxSize.

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