VirtualBox

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

Last change on this file since 74980 was 73108, checked in by vboxsync, 6 years ago

Corrected definition (type + docs) of RTVFSOBJSETOPS::offObjOps (no longer negative as that caused narrow warnings with gcc).

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