VirtualBox

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

Last change on this file since 78365 was 77047, checked in by vboxsync, 6 years ago

iprt/isomaker: Optimized native handle (file descriptor) usage when adding real directories.

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