VirtualBox

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

Last change on this file since 34407 was 34407, checked in by vboxsync, 14 years ago

vfsmemory.cpp: initial coding.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.4 KB
Line 
1/* $Id: vfsbase.cpp 34407 2010-11-26 16:45:50Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Base.
4 */
5
6/*
7 * Copyright (C) 2010 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#include <iprt/vfs.h>
32#include <iprt/vfslowlevel.h>
33
34#include <iprt/asm.h>
35#include <iprt/err.h>
36#include <iprt/file.h>
37#include <iprt/mem.h>
38#include <iprt/param.h>
39#include <iprt/path.h>
40#include <iprt/semaphore.h>
41
42#include "internal/file.h"
43#include "internal/fs.h"
44#include "internal/magics.h"
45//#include "internal/vfs.h"
46
47
48/*******************************************************************************
49* Defined Constants And Macros *
50*******************************************************************************/
51#define RTVFSOBJ_MAGIC UINT32_C(0x20109901)
52#define RTVFSOBJ_MAGIC_DEAD (~RTVFSOBJ_MAGIC)
53#define RTVFS_MAGIC UINT32_C(0x20109902)
54#define RTVFS_MAGIC_DEAD (~RTVFS_MAGIC)
55#define RTVFSFSSTREAM_MAGIC UINT32_C(0x20109903)
56#define RTVFSFSSTREAM_MAGIC_DEAD (~RTVFSFSSTREAM_MAGIC)
57#define RTVFSDIR_MAGIC UINT32_C(0x20109904)
58#define RTVFSDIR_MAGIC_DEAD (~RTVFSDIR_MAGIC)
59#define RTVFSFILE_MAGIC UINT32_C(0x20109905)
60#define RTVFSFILE_MAGIC_DEAD (~RTVFSFILE_MAGIC)
61#define RTVFSIOSTREAM_MAGIC UINT32_C(0x20109906)
62#define RTVFSIOSTREAM_MAGIC_DEAD (~RTVFSIOSTREAM_MAGIC)
63#define RTVFSSYMLINK_MAGIC UINT32_C(0x20109907)
64#define RTVFSSYMLINK_MAGIC_DEAD (~RTVFSSYMLINK_MAGIC)
65
66/** The instance data alignment. */
67#define RTVFS_INST_ALIGNMENT 16U
68
69/** The max number of symbolic links to resolve in a path. */
70#define RTVFS_MAX_LINKS 20U
71
72
73/** Asserts that the VFS base object vtable is valid. */
74#define RTVFSOBJ_ASSERT_OPS(a_pObjOps, a_enmType) \
75 do \
76 { \
77 Assert((a_pObjOps)->uVersion == RTVFSOBJOPS_VERSION); \
78 Assert((a_pObjOps)->enmType == (a_enmType) || (a_enmType) == RTVFSOBJTYPE_INVALID); \
79 AssertPtr((a_pObjOps)->pszName); \
80 Assert(*(a_pObjOps)->pszName); \
81 AssertPtr((a_pObjOps)->pfnClose); \
82 AssertPtr((a_pObjOps)->pfnQueryInfo); \
83 Assert((a_pObjOps)->uEndMarker == RTVFSOBJOPS_VERSION); \
84 } while (0)
85
86/** Asserts that the VFS set object vtable is valid. */
87#define RTVFSOBJSET_ASSERT_OPS(a_pSetOps, a_offObjOps) \
88 do \
89 { \
90 Assert((a_pSetOps)->uVersion == RTVFSOBJSETOPS_VERSION); \
91 Assert((a_pSetOps)->offObjOps == (a_offObjOps)); \
92 AssertPtr((a_pSetOps)->pfnSetMode); \
93 AssertPtr((a_pSetOps)->pfnSetTimes); \
94 AssertPtr((a_pSetOps)->pfnSetOwner); \
95 Assert((a_pSetOps)->uEndMarker == RTVFSOBJSETOPS_VERSION); \
96 } while (0)
97
98/** Asserts that the VFS I/O stream vtable is valid. */
99#define RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, a_enmType) \
100 do { \
101 RTVFSOBJ_ASSERT_OPS(&(pIoStreamOps)->Obj, a_enmType); \
102 Assert((pIoStreamOps)->uVersion == RTVFSIOSTREAMOPS_VERSION); \
103 Assert(!((pIoStreamOps)->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); \
104 AssertPtr((pIoStreamOps)->pfnRead); \
105 AssertPtr((pIoStreamOps)->pfnWrite); \
106 AssertPtr((pIoStreamOps)->pfnFlush); \
107 AssertPtr((pIoStreamOps)->pfnPollOne); \
108 AssertPtr((pIoStreamOps)->pfnTell); \
109 AssertPtrNull((pIoStreamOps)->pfnSkip); \
110 AssertPtrNull((pIoStreamOps)->pfnZeroFill); \
111 Assert((pIoStreamOps)->uEndMarker == RTVFSIOSTREAMOPS_VERSION); \
112 } while (0)
113
114/** Asserts that the VFS symlink vtable is valid. */
115#define RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, a_enmType) \
116 do { \
117 RTVFSOBJ_ASSERT_OPS(&(pSymlinkOps)->Obj, a_enmType); \
118 RTVFSOBJSET_ASSERT_OPS(&(pSymlinkOps)->ObjSet, \
119 RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet)); \
120 Assert((pSymlinkOps)->uVersion == RTVFSSYMLINKOPS_VERSION); \
121 Assert(!(pSymlinkOps)->fReserved); \
122 AssertPtr((pSymlinkOps)->pfnRead); \
123 Assert((pSymlinkOps)->uEndMarker == RTVFSSYMLINKOPS_VERSION); \
124 } while (0)
125
126
127/** Validates a VFS handle and returns @a rcRet if it's invalid. */
128#define RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, rcRet) \
129 do { \
130 if ((hVfs) != NIL_RTVFS) \
131 { \
132 AssertPtrReturn((hVfs), (rcRet)); \
133 AssertReturn((hVfs)->uMagic == RTVFS_MAGIC, (rcRet)); \
134 } \
135 } while (0)
136
137
138/*******************************************************************************
139* Structures and Typedefs *
140*******************************************************************************/
141/** @todo Move all this stuff to internal/vfs.h */
142
143
144/**
145 * The VFS internal lock data.
146 */
147typedef struct RTVFSLOCKINTERNAL
148{
149 /** The number of references to the this lock. */
150 uint32_t volatile cRefs;
151 /** The lock type. */
152 RTVFSLOCKTYPE enmType;
153 /** Type specific data. */
154 union
155 {
156 /** Read/Write semaphore handle. */
157 RTSEMRW hSemRW;
158 /** Fast mutex semaphore handle. */
159 RTSEMFASTMUTEX hFastMtx;
160 /** Regular mutex semaphore handle. */
161 RTSEMMUTEX hMtx;
162 } u;
163} RTVFSLOCKINTERNAL;
164
165
166/**
167 * The VFS base object handle data.
168 *
169 * All other VFS handles are derived from this one. The final handle type is
170 * indicated by RTVFSOBJOPS::enmType via the RTVFSOBJINTERNAL::pOps member.
171 */
172typedef struct RTVFSOBJINTERNAL
173{
174 /** The VFS magic (RTVFSOBJ_MAGIC). */
175 uint32_t uMagic;
176 /** The number of references to this VFS object. */
177 uint32_t volatile cRefs;
178 /** Pointer to the instance data. */
179 void *pvThis;
180 /** The vtable. */
181 PCRTVFSOBJOPS pOps;
182 /** The lock protecting all access to the VFS.
183 * Only valid RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTVFSLOCK. */
184 RTVFSLOCK hLock;
185 /** Reference back to the VFS containing this object. */
186 RTVFS hVfs;
187} RTVFSOBJINTERNAL;
188
189
190/**
191 * The VFS filesystem stream handle data.
192 *
193 * @extends RTVFSOBJINTERNAL
194 */
195typedef struct RTVFSFSSTREAMINTERNAL
196{
197 /** The VFS magic (RTVFSFSTREAM_MAGIC). */
198 uint32_t uMagic;
199 /** File open flags, at a minimum the access mask. */
200 uint32_t fFlags;
201 /** The vtable. */
202 PCRTVFSFSSTREAMOPS pOps;
203 /** The base object handle data. */
204 RTVFSOBJINTERNAL Base;
205} RTVFSFSSTREAMINTERNAL;
206
207
208/**
209 * The VFS handle data.
210 *
211 * @extends RTVFSOBJINTERNAL
212 */
213typedef struct RTVFSINTERNAL
214{
215 /** The VFS magic (RTVFS_MAGIC). */
216 uint32_t uMagic;
217 /** Creation flags (RTVFS_C_XXX). */
218 uint32_t fFlags;
219 /** The vtable. */
220 PCRTVFSOPS pOps;
221 /** The base object handle data. */
222 RTVFSOBJINTERNAL Base;
223} RTVFSINTERNAL;
224
225
226/**
227 * The VFS directory handle data.
228 *
229 * @extends RTVFSOBJINTERNAL
230 */
231typedef struct RTVFSDIRINTERNAL
232{
233 /** The VFS magic (RTVFSDIR_MAGIC). */
234 uint32_t uMagic;
235 /** Reserved for flags or something. */
236 uint32_t fReserved;
237 /** The vtable. */
238 PCRTVFSDIROPS pOps;
239 /** The base object handle data. */
240 RTVFSOBJINTERNAL Base;
241} RTVFSDIRINTERNAL;
242
243
244/**
245 * The VFS symbolic link handle data.
246 *
247 * @extends RTVFSOBJINTERNAL
248 */
249typedef struct RTVFSSYMLINKINTERNAL
250{
251 /** The VFS magic (RTVFSSYMLINK_MAGIC). */
252 uint32_t uMagic;
253 /** Reserved for flags or something. */
254 uint32_t fReserved;
255 /** The vtable. */
256 PCRTVFSSYMLINKOPS pOps;
257 /** The base object handle data. */
258 RTVFSOBJINTERNAL Base;
259} RTVFSSYMLINKINTERNAL;
260
261
262/**
263 * The VFS I/O stream handle data.
264 *
265 * This is often part of a type specific handle, like a file or pipe.
266 *
267 * @extends RTVFSOBJINTERNAL
268 */
269typedef struct RTVFSIOSTREAMINTERNAL
270{
271 /** The VFS magic (RTVFSIOSTREAM_MAGIC). */
272 uint32_t uMagic;
273 /** File open flags, at a minimum the access mask. */
274 uint32_t fFlags;
275 /** The vtable. */
276 PCRTVFSIOSTREAMOPS pOps;
277 /** The base object handle data. */
278 RTVFSOBJINTERNAL Base;
279} RTVFSIOSTREAMINTERNAL;
280
281
282/**
283 * The VFS file handle data.
284 *
285 * @extends RTVFSIOSTREAMINTERNAL
286 */
287typedef struct RTVFSFILEINTERNAL
288{
289 /** The VFS magic (RTVFSFILE_MAGIC). */
290 uint32_t uMagic;
291 /** Reserved for flags or something. */
292 uint32_t fReserved;
293 /** The vtable. */
294 PCRTVFSFILEOPS pOps;
295 /** The stream handle data. */
296 RTVFSIOSTREAMINTERNAL Stream;
297} RTVFSFILEINTERNAL;
298
299#if 0 /* later */
300
301/**
302 * The VFS pipe handle data.
303 *
304 * @extends RTVFSIOSTREAMINTERNAL
305 */
306typedef struct RTVFSPIPEINTERNAL
307{
308 /** The VFS magic (RTVFSPIPE_MAGIC). */
309 uint32_t uMagic;
310 /** Reserved for flags or something. */
311 uint32_t fReserved;
312 /** The vtable. */
313 PCRTVFSPIPEOPS pOps;
314 /** The stream handle data. */
315 RTVFSIOSTREAMINTERNAL Stream;
316} RTVFSPIPEINTERNAL;
317
318
319/**
320 * The VFS socket handle data.
321 *
322 * @extends RTVFSIOSTREAMINTERNAL
323 */
324typedef struct RTVFSSOCKETINTERNAL
325{
326 /** The VFS magic (RTVFSSOCKET_MAGIC). */
327 uint32_t uMagic;
328 /** Reserved for flags or something. */
329 uint32_t fReserved;
330 /** The vtable. */
331 PCRTVFSSOCKETOPS pOps;
332 /** The stream handle data. */
333 RTVFSIOSTREAMINTERNAL Stream;
334} RTVFSSOCKETINTERNAL;
335
336#endif /* later */
337
338
339
340/*
341 *
342 * V F S L o c k A b s t r a c t i o n
343 * V F S L o c k A b s t r a c t i o n
344 * V F S L o c k A b s t r a c t i o n
345 *
346 *
347 */
348
349
350RTDECL(uint32_t) RTVfsLockRetain(RTVFSLOCK hLock)
351{
352 RTVFSLOCKINTERNAL *pThis = hLock;
353 AssertPtrReturn(pThis, UINT32_MAX);
354 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
355
356 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
357 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
358 return cRefs;
359}
360
361
362/**
363 * Destroys a VFS lock handle.
364 *
365 * @param pThis The lock to destroy.
366 */
367static void rtVfsLockDestroy(RTVFSLOCKINTERNAL *pThis)
368{
369 switch (pThis->enmType)
370 {
371 case RTVFSLOCKTYPE_RW:
372 RTSemRWDestroy(pThis->u.hSemRW);
373 pThis->u.hSemRW = NIL_RTSEMRW;
374 break;
375
376 case RTVFSLOCKTYPE_FASTMUTEX:
377 RTSemFastMutexDestroy(pThis->u.hFastMtx);
378 pThis->u.hFastMtx = NIL_RTSEMFASTMUTEX;
379 break;
380
381 case RTVFSLOCKTYPE_MUTEX:
382 RTSemMutexDestroy(pThis->u.hMtx);
383 pThis->u.hFastMtx = NIL_RTSEMMUTEX;
384 break;
385
386 default:
387 AssertMsgFailedReturnVoid(("%p %d\n", pThis, pThis->enmType));
388 }
389
390 pThis->enmType = RTVFSLOCKTYPE_INVALID;
391 RTMemFree(pThis);
392}
393
394
395RTDECL(uint32_t) RTVfsLockRelease(RTVFSLOCK hLock)
396{
397 RTVFSLOCKINTERNAL *pThis = hLock;
398 AssertPtrReturn(pThis, UINT32_MAX);
399 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
400
401 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
402 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
403 if (cRefs == 0)
404 rtVfsLockDestroy(pThis);
405 return cRefs;
406}
407
408
409/**
410 * Creates a read/write lock.
411 *
412 * @returns IPRT status code
413 * @param phLock Where to return the lock handle.
414 */
415static int rtVfsLockCreateRW(PRTVFSLOCK phLock)
416{
417 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
418 if (!pThis)
419 return VERR_NO_MEMORY;
420
421 pThis->cRefs = 1;
422 pThis->enmType = RTVFSLOCKTYPE_RW;
423
424 int rc = RTSemRWCreate(&pThis->u.hSemRW);
425 if (RT_FAILURE(rc))
426 {
427 RTMemFree(pThis);
428 return rc;
429 }
430
431 *phLock = pThis;
432 return VINF_SUCCESS;
433}
434
435
436/**
437 * Creates a fast mutex lock.
438 *
439 * @returns IPRT status code
440 * @param phLock Where to return the lock handle.
441 */
442static int rtVfsLockCreateFastMutex(PRTVFSLOCK phLock)
443{
444 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
445 if (!pThis)
446 return VERR_NO_MEMORY;
447
448 pThis->cRefs = 1;
449 pThis->enmType = RTVFSLOCKTYPE_FASTMUTEX;
450
451 int rc = RTSemFastMutexCreate(&pThis->u.hFastMtx);
452 if (RT_FAILURE(rc))
453 {
454 RTMemFree(pThis);
455 return rc;
456 }
457
458 *phLock = pThis;
459 return VINF_SUCCESS;
460
461}
462
463
464/**
465 * Creates a mutex lock.
466 *
467 * @returns IPRT status code
468 * @param phLock Where to return the lock handle.
469 */
470static int rtVfsLockCreateMutex(PRTVFSLOCK phLock)
471{
472 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
473 if (!pThis)
474 return VERR_NO_MEMORY;
475
476 pThis->cRefs = 1;
477 pThis->enmType = RTVFSLOCKTYPE_MUTEX;
478
479 int rc = RTSemMutexCreate(&pThis->u.hMtx);
480 if (RT_FAILURE(rc))
481 {
482 RTMemFree(pThis);
483 return rc;
484 }
485
486 *phLock = pThis;
487 return VINF_SUCCESS;
488}
489
490
491/**
492 * Acquires the lock for reading.
493 *
494 * @param hLock Non-nil lock handle.
495 * @internal
496 */
497RTDECL(void) RTVfsLockAcquireReadSlow(RTVFSLOCK hLock)
498{
499 RTVFSLOCKINTERNAL *pThis = hLock;
500 int rc;
501
502 AssertPtr(pThis);
503 switch (pThis->enmType)
504 {
505 case RTVFSLOCKTYPE_RW:
506 rc = RTSemRWRequestRead(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
507 AssertRC(rc);
508 break;
509
510 case RTVFSLOCKTYPE_FASTMUTEX:
511 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
512 AssertRC(rc);
513 break;
514
515 case RTVFSLOCKTYPE_MUTEX:
516 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
517 AssertRC(rc);
518 break;
519 default:
520 AssertFailed();
521 }
522}
523
524
525/**
526 * Release a lock held for reading.
527 *
528 * @param hLock Non-nil lock handle.
529 * @internal
530 */
531RTDECL(void) RTVfsLockReleaseReadSlow(RTVFSLOCK hLock)
532{
533 RTVFSLOCKINTERNAL *pThis = hLock;
534 int rc;
535
536 AssertPtr(pThis);
537 switch (pThis->enmType)
538 {
539 case RTVFSLOCKTYPE_RW:
540 rc = RTSemRWReleaseRead(pThis->u.hSemRW);
541 AssertRC(rc);
542 break;
543
544 case RTVFSLOCKTYPE_FASTMUTEX:
545 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
546 AssertRC(rc);
547 break;
548
549 case RTVFSLOCKTYPE_MUTEX:
550 rc = RTSemMutexRelease(pThis->u.hMtx);
551 AssertRC(rc);
552 break;
553 default:
554 AssertFailed();
555 }
556}
557
558
559/**
560 * Acquires the lock for writing.
561 *
562 * @param hLock Non-nil lock handle.
563 * @internal
564 */
565RTDECL(void) RTVfsLockAcquireWriteSlow(RTVFSLOCK hLock)
566{
567 RTVFSLOCKINTERNAL *pThis = hLock;
568 int rc;
569
570 AssertPtr(pThis);
571 switch (pThis->enmType)
572 {
573 case RTVFSLOCKTYPE_RW:
574 rc = RTSemRWRequestWrite(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
575 AssertRC(rc);
576 break;
577
578 case RTVFSLOCKTYPE_FASTMUTEX:
579 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
580 AssertRC(rc);
581 break;
582
583 case RTVFSLOCKTYPE_MUTEX:
584 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
585 AssertRC(rc);
586 break;
587 default:
588 AssertFailed();
589 }
590}
591
592
593/**
594 * Release a lock held for writing.
595 *
596 * @param hLock Non-nil lock handle.
597 * @internal
598 */
599RTDECL(void) RTVfsLockReleaseWriteSlow(RTVFSLOCK hLock)
600{
601 RTVFSLOCKINTERNAL *pThis = hLock;
602 int rc;
603
604 AssertPtr(pThis);
605 switch (pThis->enmType)
606 {
607 case RTVFSLOCKTYPE_RW:
608 rc = RTSemRWReleaseWrite(pThis->u.hSemRW);
609 AssertRC(rc);
610 break;
611
612 case RTVFSLOCKTYPE_FASTMUTEX:
613 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
614 AssertRC(rc);
615 break;
616
617 case RTVFSLOCKTYPE_MUTEX:
618 rc = RTSemMutexRelease(pThis->u.hMtx);
619 AssertRC(rc);
620 break;
621 default:
622 AssertFailed();
623 }
624}
625
626
627
628/*
629 *
630 * B A S E O B J E C T
631 * B A S E O B J E C T
632 * B A S E O B J E C T
633 *
634 */
635
636/**
637 * Internal object retainer that asserts sanity in strict builds.
638 *
639 * @param pThis The base object handle data.
640 */
641DECLINLINE(void) rtVfsObjRetainVoid(RTVFSOBJINTERNAL *pThis)
642{
643 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
644 AssertMsg(cRefs > 1 && cRefs < _1M,
645 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
646 NOREF(cRefs);
647}
648
649
650/**
651 * Initializes the base object part of a new object.
652 *
653 * @returns IPRT status code.
654 * @param pThis Pointer to the base object part.
655 * @param pObjOps The base object vtable.
656 * @param hVfs The VFS handle to associate with.
657 * @param hLock The lock handle, pseudo handle or nil.
658 * @param pvThis Pointer to the private data.
659 */
660static int rtVfsObjInitNewObject(RTVFSOBJINTERNAL *pThis, PCRTVFSOBJOPS pObjOps, RTVFS hVfs, RTVFSLOCK hLock, void *pvThis)
661{
662 /*
663 * Deal with the lock first as that's the most complicated matter.
664 */
665 if (hLock != NIL_RTVFSLOCK)
666 {
667 int rc;
668 if (hLock == RTVFSLOCK_CREATE_RW)
669 {
670 rc = rtVfsLockCreateRW(&hLock);
671 AssertRCReturn(rc, rc);
672 }
673 else if (hLock == RTVFSLOCK_CREATE_FASTMUTEX)
674 {
675 rc = rtVfsLockCreateFastMutex(&hLock);
676 AssertRCReturn(rc, rc);
677 }
678 else if (hLock == RTVFSLOCK_CREATE_MUTEX)
679 {
680 rc = rtVfsLockCreateMutex(&hLock);
681 AssertRCReturn(rc, rc);
682 }
683 else
684 {
685 /*
686 * The caller specified a lock, we consume the this reference.
687 */
688 AssertPtrReturn(hLock, VERR_INVALID_HANDLE);
689 AssertReturn(hLock->enmType > RTVFSLOCKTYPE_INVALID && hLock->enmType < RTVFSLOCKTYPE_END, VERR_INVALID_HANDLE);
690 AssertReturn(hLock->cRefs > 0, VERR_INVALID_HANDLE);
691 }
692 }
693 else if (hVfs != NIL_RTVFS)
694 {
695 /*
696 * Retain a reference to the VFS lock, if there is one.
697 */
698 hLock = hVfs->Base.hLock;
699 if (hLock != NIL_RTVFSLOCK)
700 {
701 uint32_t cRefs = RTVfsLockRetain(hLock);
702 if (RT_UNLIKELY(cRefs == UINT32_MAX))
703 return VERR_INVALID_HANDLE;
704 }
705 }
706
707
708 /*
709 * Do the actual initializing.
710 */
711 pThis->uMagic = RTVFSOBJ_MAGIC;
712 pThis->pvThis = pvThis;
713 pThis->pOps = pObjOps;
714 pThis->cRefs = 1;
715 pThis->hVfs = hVfs;
716 pThis->hLock = hLock;
717 if (hVfs != NIL_RTVFS)
718 rtVfsObjRetainVoid(&hVfs->Base);
719
720 return VINF_SUCCESS;
721}
722
723
724RTDECL(int) RTVfsNewBaseObj(PCRTVFSOBJOPS pObjOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
725 PRTVFSOBJ phVfsObj, void **ppvInstance)
726{
727 /*
728 * Validate the input, be extra strict in strict builds.
729 */
730 AssertPtr(pObjOps);
731 AssertReturn(pObjOps->uVersion == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
732 AssertReturn(pObjOps->uEndMarker == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
733 RTVFSOBJ_ASSERT_OPS(pObjOps, RTVFSOBJTYPE_BASE);
734 Assert(cbInstance > 0);
735 AssertPtr(ppvInstance);
736 AssertPtr(phVfsObj);
737 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
738
739 /*
740 * Allocate the handle + instance data.
741 */
742 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSOBJINTERNAL), RTVFS_INST_ALIGNMENT)
743 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
744 RTVFSOBJINTERNAL *pThis = (RTVFSOBJINTERNAL *)RTMemAllocZ(cbThis);
745 if (!pThis)
746 return VERR_NO_MEMORY;
747
748 int rc = rtVfsObjInitNewObject(pThis, pObjOps, hVfs, hLock,
749 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
750 if (RT_FAILURE(rc))
751 {
752 RTMemFree(pThis);
753 return rc;
754 }
755
756 *phVfsObj = pThis;
757 *ppvInstance = pThis->pvThis;
758 return VINF_SUCCESS;
759}
760
761
762/**
763 * Internal object retainer that asserts sanity in strict builds.
764 *
765 * @returns The new reference count.
766 * @param pThis The base object handle data.
767 */
768DECLINLINE(uint32_t) rtVfsObjRetain(RTVFSOBJINTERNAL *pThis)
769{
770 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
771 AssertMsg(cRefs > 1 && cRefs < _1M,
772 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
773 return cRefs;
774}
775
776
777RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj)
778{
779 RTVFSOBJINTERNAL *pThis = hVfsObj;
780 AssertPtrReturn(pThis, UINT32_MAX);
781 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
782
783 return rtVfsObjRetain(pThis);
784}
785
786
787/**
788 * Does the actual object destruction for rtVfsObjRelease().
789 *
790 * @param pThis The object to destroy.
791 */
792static void rtVfsObjDestroy(RTVFSOBJINTERNAL *pThis)
793{
794 RTVFSOBJTYPE const enmType = pThis->pOps->enmType;
795
796 /*
797 * Invalidate the object.
798 */
799 RTVfsLockAcquireWrite(pThis->hLock); /* paranoia */
800 void *pvToFree = NULL;
801 switch (enmType)
802 {
803 case RTVFSOBJTYPE_BASE:
804 pvToFree = pThis;
805 break;
806
807 case RTVFSOBJTYPE_VFS:
808 pvToFree = RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
809 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)->uMagic, RTVFS_MAGIC_DEAD);
810 break;
811
812 case RTVFSOBJTYPE_FS_STREAM:
813 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
814 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base)->uMagic, RTVFSFSSTREAM_MAGIC_DEAD);
815 break;
816
817 case RTVFSOBJTYPE_IO_STREAM:
818 pvToFree = RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
819 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
820 break;
821
822 case RTVFSOBJTYPE_DIR:
823 pvToFree = RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
824 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->uMagic, RTVFSDIR_MAGIC_DEAD);
825 break;
826
827 case RTVFSOBJTYPE_FILE:
828 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
829 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->uMagic, RTVFSFILE_MAGIC_DEAD);
830 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
831 break;
832
833 case RTVFSOBJTYPE_SYMLINK:
834 pvToFree = RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
835 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
836 break;
837
838 case RTVFSOBJTYPE_INVALID:
839 case RTVFSOBJTYPE_END:
840 case RTVFSOBJTYPE_32BIT_HACK:
841 AssertMsgFailed(("enmType=%d ops=%p %s\n", enmType, pThis->pOps, pThis->pOps->pszName));
842 break;
843 /* no default as we want gcc warnings. */
844 }
845 ASMAtomicWriteU32(&pThis->uMagic, RTVFSOBJ_MAGIC_DEAD);
846 RTVfsLockReleaseWrite(pThis->hLock);
847
848 /*
849 * Close the object and free the handle.
850 */
851 int rc = pThis->pOps->pfnClose(pThis->pvThis);
852 AssertRC(rc);
853 RTMemFree(pvToFree);
854}
855
856
857/**
858 * Internal object releaser that asserts sanity in strict builds.
859 *
860 * @returns The new reference count.
861 * @param pcRefs The reference counter.
862 */
863DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis)
864{
865 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
866 AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
867 if (cRefs == 0)
868 rtVfsObjDestroy(pThis);
869 return cRefs;
870}
871
872
873RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj)
874{
875 RTVFSOBJINTERNAL *pThis = hVfsObj;
876 AssertPtrReturn(pThis, UINT32_MAX);
877 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
878 return rtVfsObjRelease(pThis);
879}
880
881
882RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj)
883{
884 RTVFSOBJINTERNAL *pThis = hVfsObj;
885 if (pThis != NIL_RTVFSOBJ)
886 {
887 AssertPtrReturn(pThis, NIL_RTVFS);
888 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFS);
889
890 if (pThis->pOps->enmType == RTVFSOBJTYPE_VFS)
891 {
892 rtVfsObjRetainVoid(pThis);
893 return RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
894 }
895 }
896 return NIL_RTVFS;
897}
898
899
900RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj)
901{
902 RTVFSOBJINTERNAL *pThis = hVfsObj;
903 if (pThis != NIL_RTVFSOBJ)
904 {
905 AssertPtrReturn(pThis, NIL_RTVFSFSSTREAM);
906 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFSSTREAM);
907
908 if (pThis->pOps->enmType == RTVFSOBJTYPE_FS_STREAM)
909 {
910 rtVfsObjRetainVoid(pThis);
911 return RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
912 }
913 }
914 return NIL_RTVFSFSSTREAM;
915}
916
917
918RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj)
919{
920 RTVFSOBJINTERNAL *pThis = hVfsObj;
921 if (pThis != NIL_RTVFSOBJ)
922 {
923 AssertPtrReturn(pThis, NIL_RTVFSDIR);
924 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSDIR);
925
926 if (pThis->pOps->enmType == RTVFSOBJTYPE_DIR)
927 {
928 rtVfsObjRetainVoid(pThis);
929 return RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
930 }
931 }
932 return NIL_RTVFSDIR;
933}
934
935
936RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj)
937{
938 RTVFSOBJINTERNAL *pThis = hVfsObj;
939 if (pThis != NIL_RTVFSOBJ)
940 {
941 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
942 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSIOSTREAM);
943
944 if (pThis->pOps->enmType == RTVFSOBJTYPE_IO_STREAM)
945 {
946 rtVfsObjRetainVoid(pThis);
947 return RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
948 }
949 }
950 return NIL_RTVFSIOSTREAM;
951}
952
953
954RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj)
955{
956 RTVFSOBJINTERNAL *pThis = hVfsObj;
957 if (pThis != NIL_RTVFSOBJ)
958 {
959 AssertPtrReturn(pThis, NIL_RTVFSFILE);
960 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFILE);
961
962 if (pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
963 {
964 rtVfsObjRetainVoid(pThis);
965 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
966 }
967 }
968 return NIL_RTVFSFILE;
969}
970
971
972RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj)
973{
974 RTVFSOBJINTERNAL *pThis = hVfsObj;
975 if (pThis != NIL_RTVFSOBJ)
976 {
977 AssertPtrReturn(pThis, NIL_RTVFSSYMLINK);
978 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSSYMLINK);
979
980 if (pThis->pOps->enmType == RTVFSOBJTYPE_SYMLINK)
981 {
982 rtVfsObjRetainVoid(pThis);
983 return RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
984 }
985 }
986 return NIL_RTVFSSYMLINK;
987}
988
989
990RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs)
991{
992 if (hVfs != NIL_RTVFS)
993 {
994 RTVFSOBJINTERNAL *pThis = &hVfs->Base;
995 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
996 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
997
998 rtVfsObjRetainVoid(pThis);
999 return pThis;
1000 }
1001 return NIL_RTVFSOBJ;
1002}
1003
1004
1005RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss)
1006{
1007 if (hVfsFss != NIL_RTVFSFSSTREAM)
1008 {
1009 RTVFSOBJINTERNAL *pThis = &hVfsFss->Base;
1010 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1011 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1012
1013 rtVfsObjRetainVoid(pThis);
1014 return pThis;
1015 }
1016 return NIL_RTVFSOBJ;
1017}
1018
1019
1020RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir)
1021{
1022 if (hVfsDir != NIL_RTVFSDIR)
1023 {
1024 RTVFSOBJINTERNAL *pThis = &hVfsDir->Base;
1025 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1026 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1027
1028 rtVfsObjRetainVoid(pThis);
1029 return pThis;
1030 }
1031 return NIL_RTVFSOBJ;
1032}
1033
1034
1035RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos)
1036{
1037 if (hVfsIos != NIL_RTVFSIOSTREAM)
1038 {
1039 RTVFSOBJINTERNAL *pThis = &hVfsIos->Base;
1040 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1041 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1042
1043 rtVfsObjRetainVoid(pThis);
1044 return pThis;
1045 }
1046 return NIL_RTVFSOBJ;
1047}
1048
1049
1050RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile)
1051{
1052 if (hVfsFile != NIL_RTVFSFILE)
1053 {
1054 RTVFSOBJINTERNAL *pThis = &hVfsFile->Stream.Base;
1055 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1056 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1057
1058 rtVfsObjRetainVoid(pThis);
1059 return pThis;
1060 }
1061 return NIL_RTVFSOBJ;
1062}
1063
1064
1065RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym)
1066{
1067 if (hVfsSym != NIL_RTVFSSYMLINK)
1068 {
1069 RTVFSOBJINTERNAL *pThis = &hVfsSym->Base;
1070 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1071 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1072
1073 rtVfsObjRetainVoid(pThis);
1074 return pThis;
1075 }
1076 return NIL_RTVFSOBJ;
1077}
1078
1079
1080
1081RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1082{
1083 RTVFSOBJINTERNAL *pThis = hVfsObj;
1084 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1085 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1086
1087 RTVfsLockAcquireRead(pThis->hLock);
1088 int rc = pThis->pOps->pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
1089 RTVfsLockReleaseRead(pThis->hLock);
1090 return rc;
1091}
1092
1093
1094
1095/*
1096 *
1097 * U T I L U T I L U T I L
1098 * U T I L U T I L U T I L
1099 * U T I L U T I L U T I L
1100 *
1101 */
1102
1103
1104
1105/**
1106 * Removes dots from the path.
1107 *
1108 * @returns The new @a pszDst value.
1109 * @param pPath The path parsing buffer.
1110 * @param pszDst The current szPath position. This will be
1111 * updated and returned.
1112 * @param fTheEnd Indicates whether we're at the end of the path
1113 * or not.
1114 * @param piRestartComp The component to restart parsing at.
1115 */
1116static char *rtVfsParsePathHandleDots(PRTVFSPARSEDPATH pPath, char *pszDst, bool fTheEnd, uint16_t *piRestartComp)
1117{
1118 if (pszDst[-1] != '.')
1119 return pszDst;
1120
1121 if (pszDst[-2] == '/')
1122 {
1123 pPath->cComponents--;
1124 pszDst = &pPath->szPath[pPath->aoffComponents[pPath->cComponents]];
1125 }
1126 else if (pszDst[-2] == '.' && pszDst[-3] == '/')
1127 {
1128 pPath->cComponents -= pPath->cComponents > 1 ? 2 : 1;
1129 pszDst = &pPath->szPath[pPath->aoffComponents[pPath->cComponents]];
1130 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1131 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1132 }
1133 else
1134 return pszDst;
1135
1136 /*
1137 * Drop the trailing slash if we're at the end of the source path.
1138 */
1139 if (fTheEnd && pPath->cComponents == 0)
1140 pszDst--;
1141 return pszDst;
1142}
1143
1144
1145RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
1146{
1147 AssertReturn(*pszPath != '/', VERR_INTERNAL_ERROR_4);
1148
1149 /* In case *piRestartComp was set higher than the number of components
1150 before making the call to this function. */
1151 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1152 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1153
1154 /*
1155 * Append a slash to the destination path if necessary.
1156 */
1157 char *pszDst = &pPath->szPath[pPath->cch];
1158 if (pPath->cComponents > 0)
1159 {
1160 *pszDst++ = '/';
1161 if (pszDst - &pPath->szPath[0] >= RTVFSPARSEDPATH_MAX)
1162 return VERR_FILENAME_TOO_LONG;
1163 }
1164 Assert(pszDst[-1] == '/');
1165
1166 /*
1167 * Parse and append the relative path.
1168 */
1169 const char *pszSrc = pszPath;
1170 pPath->fDirSlash = false;
1171 while (pszSrc[0])
1172 {
1173 /* Skip unncessary slashes. */
1174 while (pszSrc[0] == '/')
1175 pszSrc++;
1176
1177 /* Copy until we encounter the next slash. */
1178 pPath->aoffComponents[pPath->cComponents++] = pszDst - &pPath->szPath[0];
1179 while (pszSrc[0])
1180 {
1181 if (pszSrc[0] == '/')
1182 {
1183 pszSrc++;
1184 if (pszSrc[0])
1185 *pszDst++ = '/';
1186 else
1187 pPath->fDirSlash = true;
1188 pszDst = rtVfsParsePathHandleDots(pPath, pszDst, pszSrc[0] == '\0', piRestartComp);
1189 break;
1190 }
1191
1192 *pszDst++ = *pszSrc++;
1193 if (pszDst - &pPath->szPath[0] >= RTVFSPARSEDPATH_MAX)
1194 return VERR_FILENAME_TOO_LONG;
1195 }
1196 }
1197 pszDst = rtVfsParsePathHandleDots(pPath, pszDst, true /*fTheEnd*/, piRestartComp);
1198
1199 /* Terminate the string and enter its length. */
1200 pszDst[0] = '\0';
1201 pszDst[1] = '\0'; /* for aoffComponents */
1202 pPath->cch = (uint16_t)(pszDst - &pPath->szPath[0]);
1203 pPath->aoffComponents[pPath->cComponents] = pPath->cch + 1;
1204
1205 return VINF_SUCCESS;
1206}
1207
1208
1209RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
1210{
1211 if (*pszPath != '/')
1212 {
1213 /*
1214 * Relative, recurse and parse pszCwd first.
1215 */
1216 int rc = RTVfsParsePath(pPath, pszCwd, NULL /*crash if pszCwd is not absolute*/);
1217 if (RT_FAILURE(rc))
1218 return rc;
1219 }
1220 else
1221 {
1222 /*
1223 * Make pszPath relative, i.e. set up pPath for the root and skip
1224 * leading slashes in pszPath before appending it.
1225 */
1226 pPath->cch = 1;
1227 pPath->cComponents = 0;
1228 pPath->fDirSlash = false;
1229 pPath->aoffComponents[0] = 1;
1230 pPath->aoffComponents[1] = 2;
1231 pPath->szPath[0] = '/';
1232 pPath->szPath[1] = '\0';
1233 pPath->szPath[2] = '\0';
1234 while (pszPath[0] == '/')
1235 pszPath++;
1236 if (!pszPath[0])
1237 return VINF_SUCCESS;
1238 }
1239 return RTVfsParsePathAppend(pPath, pszPath, NULL);
1240}
1241
1242
1243
1244RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath)
1245{
1246 /*
1247 * Allocate the output buffer and hand the problem to rtVfsParsePath.
1248 */
1249 int rc;
1250 PRTVFSPARSEDPATH pPath = (PRTVFSPARSEDPATH)RTMemTmpAlloc(sizeof(RTVFSPARSEDPATH));
1251 if (pPath)
1252 {
1253 rc = RTVfsParsePath(pPath, pszPath, pszCwd);
1254 if (RT_FAILURE(rc))
1255 {
1256 RTMemTmpFree(pPath);
1257 pPath = NULL;
1258 }
1259 }
1260 else
1261 rc = VERR_NO_TMP_MEMORY;
1262 *ppPath = pPath; /* always set it */
1263 return rc;
1264}
1265
1266
1267RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath)
1268{
1269 if (pPath)
1270 {
1271 pPath->cch = UINT16_MAX;
1272 pPath->cComponents = UINT16_MAX;
1273 pPath->aoffComponents[0] = UINT16_MAX;
1274 pPath->aoffComponents[1] = UINT16_MAX;
1275 RTMemTmpFree(pPath);
1276 }
1277}
1278
1279
1280/**
1281 * Handles a symbolic link, adding it to
1282 *
1283 * @returns IPRT status code.
1284 * @param pPath The parsed path to update.
1285 * @param piComponent The component iterator to update.
1286 * @param hSymlink The symbolic link to process.
1287 */
1288static int rtVfsTraverseHandleSymlink(PRTVFSPARSEDPATH pPath, uint16_t *piComponent, RTVFSSYMLINK hSymlink)
1289{
1290 /*
1291 * Read the link.
1292 */
1293 char szPath[RTPATH_MAX];
1294 int rc = RTVfsSymlinkRead(hSymlink, szPath, sizeof(szPath) - 1);
1295 if (RT_SUCCESS(rc))
1296 {
1297 szPath[sizeof(szPath) - 1] = '\0';
1298 if (szPath[0] == '/')
1299 {
1300 /*
1301 * Absolute symlink.
1302 */
1303 rc = RTVfsParsePath(pPath, szPath, NULL);
1304 if (RT_SUCCESS(rc))
1305 {
1306 *piComponent = 0;
1307 return VINF_SUCCESS;
1308 }
1309 }
1310 else
1311 {
1312 /*
1313 * Relative symlink, must replace the current component with the
1314 * link value. We do that by using the remainder of the symlink
1315 * buffer as temporary storage.
1316 */
1317 uint16_t iComponent = *piComponent;
1318 if (iComponent + 1 < pPath->cComponents)
1319 rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iComponent + 1]]);
1320 if (RT_SUCCESS(rc))
1321 {
1322 pPath->cch = pPath->aoffComponents[iComponent] - (iComponent > 0);
1323 pPath->aoffComponents[iComponent + 1] = pPath->cch + 1;
1324 pPath->szPath[pPath->cch] = '\0';
1325 pPath->szPath[pPath->cch + 1] = '\0';
1326
1327 rc = RTVfsParsePathAppend(pPath, szPath, &iComponent);
1328 if (RT_SUCCESS(rc))
1329 {
1330 *piComponent = iComponent;
1331 return VINF_SUCCESS;
1332 }
1333 }
1334 }
1335 }
1336 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
1337}
1338
1339
1340/**
1341 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1342 *
1343 * @returns IPRT status code.
1344 * @param pThis The VFS.
1345 * @param pPath The parsed path. This may be changed as symbolic
1346 * links are processed during the path traversal.
1347 * @param fFollowSymlink Whether to follow the final component if it is a
1348 * symbolic link.
1349 * @param ppVfsParentDir Where to return the parent directory handle
1350 * (referenced).
1351 */
1352static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, bool fFollowSymlink,
1353 RTVFSDIRINTERNAL **ppVfsParentDir)
1354{
1355 /*
1356 * Assert sanity.
1357 */
1358 AssertPtr(pThis);
1359 Assert(pThis->uMagic == RTVFS_MAGIC);
1360 Assert(pThis->Base.cRefs > 0);
1361 AssertPtr(pPath);
1362 AssertPtr(ppVfsParentDir);
1363 *ppVfsParentDir = NULL;
1364 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1365
1366 /*
1367 * Open the root directory.
1368 */
1369 /** @todo Union mounts, traversal optimization methods, races, ++ */
1370 RTVFSDIRINTERNAL *pCurDir;
1371 RTVfsLockAcquireRead(pThis->Base.hLock);
1372 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pCurDir);
1373 RTVfsLockReleaseRead(pThis->Base.hLock);
1374 if (RT_FAILURE(rc))
1375 return rc;
1376 Assert(pCurDir->uMagic == RTVFSDIR_MAGIC);
1377
1378 /*
1379 * The traversal loop.
1380 */
1381 unsigned cLinks = 0;
1382 uint16_t iComponent = 0;
1383 for (;;)
1384 {
1385 /*
1386 * Are we done yet?
1387 */
1388 bool fFinal = iComponent + 1 >= pPath->cComponents;
1389 if (fFinal && !fFollowSymlink)
1390 {
1391 *ppVfsParentDir = pCurDir;
1392 return VINF_SUCCESS;
1393 }
1394
1395 /*
1396 * Try open the next entry.
1397 */
1398 const char *pszEntry = &pPath->szPath[pPath->aoffComponents[iComponent]];
1399 char *pszEntryEnd = &pPath->szPath[pPath->aoffComponents[iComponent + 1] - 1];
1400 *pszEntryEnd = '\0';
1401 RTVFSDIR hDir = NIL_RTVFSDIR;
1402 RTVFSSYMLINK hSymlink = NIL_RTVFSSYMLINK;
1403 RTVFS hVfsMnt = NIL_RTVFS;
1404 if (fFinal)
1405 {
1406 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1407 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, NULL, &hSymlink, NULL);
1408 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1409 *pszEntryEnd = '\0';
1410 if (rc == VERR_PATH_NOT_FOUND)
1411 rc = VINF_SUCCESS;
1412 if (RT_FAILURE(rc))
1413 break;
1414
1415 if (hSymlink == NIL_RTVFSSYMLINK)
1416 {
1417 *ppVfsParentDir = pCurDir;
1418 return VINF_SUCCESS;
1419 }
1420 }
1421 else
1422 {
1423 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1424 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, &hDir, &hSymlink, &hVfsMnt);
1425 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1426 *pszEntryEnd = '/';
1427 if (RT_FAILURE(rc))
1428 break;
1429
1430 if ( hDir == NIL_RTVFSDIR
1431 && hSymlink == NIL_RTVFSSYMLINK
1432 && hVfsMnt == NIL_RTVFS)
1433 {
1434 rc = VERR_NOT_A_DIRECTORY;
1435 break;
1436 }
1437 }
1438 Assert( (hDir != NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1439 || (hDir == NIL_RTVFSDIR && hSymlink != NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1440 || (hDir == NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt != NIL_RTVFS));
1441
1442 if (hDir != NIL_RTVFSDIR)
1443 {
1444 /*
1445 * Directory - advance down the path.
1446 */
1447 AssertPtr(hDir);
1448 Assert(hDir->uMagic == RTVFSDIR_MAGIC);
1449 RTVfsDirRelease(pCurDir);
1450 pCurDir = hDir;
1451 iComponent++;
1452 }
1453 else if (hSymlink != NIL_RTVFSSYMLINK)
1454 {
1455 /*
1456 * Symbolic link - deal with it and retry the current component.
1457 */
1458 AssertPtr(hSymlink);
1459 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
1460 cLinks++;
1461 if (cLinks >= RTVFS_MAX_LINKS)
1462 {
1463 rc = VERR_TOO_MANY_SYMLINKS;
1464 break;
1465 }
1466 uint16_t iRestartComp = iComponent;
1467 rc = rtVfsTraverseHandleSymlink(pPath, &iRestartComp, hSymlink);
1468 if (RT_FAILURE(rc))
1469 break;
1470 if (iRestartComp != iComponent)
1471 {
1472 /* Must restart from the root (optimize this). */
1473 RTVfsDirRelease(pCurDir);
1474 RTVfsLockAcquireRead(pThis->Base.hLock);
1475 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pCurDir);
1476 RTVfsLockReleaseRead(pThis->Base.hLock);
1477 if (RT_FAILURE(rc))
1478 {
1479 pCurDir = NULL;
1480 break;
1481 }
1482 iComponent = 0;
1483 }
1484 }
1485 else
1486 {
1487 /*
1488 * Mount point - deal with it and retry the current component.
1489 */
1490 RTVfsDirRelease(pCurDir);
1491 RTVfsLockAcquireRead(hVfsMnt->Base.hLock);
1492 rc = pThis->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
1493 RTVfsLockReleaseRead(hVfsMnt->Base.hLock);
1494 if (RT_FAILURE(rc))
1495 {
1496 pCurDir = NULL;
1497 break;
1498 }
1499 iComponent = 0;
1500 /** @todo union mounts. */
1501 }
1502 }
1503
1504 if (pCurDir)
1505 RTVfsDirRelease(pCurDir);
1506
1507 return rc;
1508}
1509
1510
1511RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
1512{
1513 int rc;
1514 if (fIntr)
1515 rc = RTThreadSleep(cMillies);
1516 else
1517 {
1518 uint64_t uMsStart = RTTimeMilliTS();
1519 do
1520 rc = RTThreadSleep(cMillies);
1521 while ( rc == VERR_INTERRUPTED
1522 && !fIntr
1523 && RTTimeMilliTS() - uMsStart < cMillies);
1524 if (rc == VERR_INTERRUPTED)
1525 rc = VERR_TIMEOUT;
1526 }
1527
1528 *pfRetEvents = 0;
1529 return rc;
1530}
1531
1532
1533RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
1534{
1535 /*
1536 * Allocate a temporary buffer.
1537 */
1538 size_t cbBuf = cbBufHint;
1539 if (!cbBuf)
1540 cbBuf = _64K;
1541 else if (cbBuf < _4K)
1542 cbBuf = _4K;
1543 else if (cbBuf > _1M)
1544 cbBuf = _1M;
1545
1546 void *pvBuf = RTMemTmpAlloc(cbBuf);
1547 if (!pvBuf)
1548 {
1549 cbBuf = _4K;
1550 pvBuf = RTMemTmpAlloc(cbBuf);
1551 if (!pvBuf)
1552 return VERR_NO_TMP_MEMORY;
1553 }
1554
1555 /*
1556 * Pump loop.
1557 */
1558 int rc;
1559 for (;;)
1560 {
1561 size_t cbRead;
1562 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
1563 if (RT_FAILURE(rc))
1564 break;
1565 if (rc == VINF_EOF && cbRead == 0)
1566 break;
1567
1568 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
1569 if (RT_FAILURE(rc))
1570 break;
1571 }
1572
1573 RTMemTmpFree(pvBuf);
1574 return rc;
1575}
1576
1577
1578
1579
1580
1581/*
1582 *
1583 * F I L E S Y S T E M S T R E A M
1584 * F I L E S Y S T E M S T R E A M
1585 * F I L E S Y S T E M S T R E A M
1586 *
1587 */
1588
1589
1590RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
1591 PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
1592{
1593 /*
1594 * Validate the input, be extra strict in strict builds.
1595 */
1596 AssertPtr(pFsStreamOps);
1597 AssertReturn(pFsStreamOps->uVersion == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1598 AssertReturn(pFsStreamOps->uEndMarker == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1599 Assert(!pFsStreamOps->fReserved);
1600 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
1601 AssertPtr(pFsStreamOps->pfnNext);
1602 Assert(cbInstance > 0);
1603 AssertPtr(ppvInstance);
1604 AssertPtr(phVfsFss);
1605 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
1606
1607 /*
1608 * Allocate the handle + instance data.
1609 */
1610 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFSSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
1611 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1612 RTVFSFSSTREAMINTERNAL *pThis = (RTVFSFSSTREAMINTERNAL *)RTMemAllocZ(cbThis);
1613 if (!pThis)
1614 return VERR_NO_MEMORY;
1615
1616 int rc = rtVfsObjInitNewObject(&pThis->Base, &pFsStreamOps->Obj, hVfs, hLock,
1617 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1618
1619 if (RT_FAILURE(rc))
1620 {
1621 RTMemFree(pThis);
1622 return rc;
1623 }
1624
1625 pThis->uMagic = RTVFSFSSTREAM_MAGIC;
1626 pThis->fFlags = RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
1627 pThis->pOps = pFsStreamOps;
1628
1629 *phVfsFss = pThis;
1630 *ppvInstance = pThis->Base.pvThis;
1631 return VINF_SUCCESS;
1632}
1633
1634
1635RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss)
1636{
1637 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1638 AssertPtrReturn(pThis, UINT32_MAX);
1639 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
1640 return rtVfsObjRetain(&pThis->Base);
1641}
1642
1643
1644RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss)
1645{
1646 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1647 AssertPtrReturn(pThis, UINT32_MAX);
1648 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
1649 return rtVfsObjRelease(&pThis->Base);
1650}
1651
1652
1653RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1654{
1655 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1656 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1657 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
1658 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
1659}
1660
1661
1662RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
1663{
1664 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
1665 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1666 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
1667 AssertPtrNullReturn(ppszName, VERR_INVALID_POINTER);
1668 if (ppszName)
1669 *ppszName = NULL;
1670 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
1671 if (penmType)
1672 *penmType = RTVFSOBJTYPE_INVALID;
1673 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
1674 if (phVfsObj)
1675 *phVfsObj = NIL_RTVFSOBJ;
1676
1677 return pThis->pOps->pfnNext(pThis->Base.pvThis, ppszName, penmType, phVfsObj);
1678}
1679
1680
1681
1682
1683/*
1684 *
1685 * D I R D I R D I R
1686 * D I R D I R D I R
1687 * D I R D I R D I R
1688 *
1689 */
1690
1691RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir)
1692{
1693 RTVFSDIRINTERNAL *pThis = hVfsDir;
1694 AssertPtrReturn(pThis, UINT32_MAX);
1695 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
1696 return rtVfsObjRetain(&pThis->Base);
1697}
1698
1699
1700RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir)
1701{
1702 RTVFSDIRINTERNAL *pThis = hVfsDir;
1703 AssertPtrReturn(pThis, UINT32_MAX);
1704 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
1705 return rtVfsObjRelease(&pThis->Base);
1706}
1707
1708
1709
1710/*
1711 *
1712 * S Y M B O L I C L I N K
1713 * S Y M B O L I C L I N K
1714 * S Y M B O L I C L I N K
1715 *
1716 */
1717
1718RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
1719 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
1720{
1721 /*
1722 * Validate the input, be extra strict in strict builds.
1723 */
1724 AssertPtr(pSymlinkOps);
1725 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
1726 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
1727 Assert(!pSymlinkOps->fReserved);
1728 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
1729 Assert(cbInstance > 0);
1730 AssertPtr(ppvInstance);
1731 AssertPtr(phVfsSym);
1732 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
1733
1734 /*
1735 * Allocate the handle + instance data.
1736 */
1737 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
1738 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1739 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
1740 if (!pThis)
1741 return VERR_NO_MEMORY;
1742
1743 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, hLock,
1744 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1745 if (RT_FAILURE(rc))
1746 {
1747 RTMemFree(pThis);
1748 return rc;
1749 }
1750
1751 pThis->uMagic = RTVFSSYMLINK_MAGIC;
1752 pThis->pOps = pSymlinkOps;
1753
1754 *phVfsSym = pThis;
1755 *ppvInstance = pThis->Base.pvThis;
1756 return VINF_SUCCESS;
1757}
1758
1759
1760RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
1761{
1762 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
1763 AssertPtrReturn(pThis, UINT32_MAX);
1764 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
1765 return rtVfsObjRetain(&pThis->Base);
1766}
1767
1768
1769RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
1770{
1771 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
1772 AssertPtrReturn(pThis, UINT32_MAX);
1773 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
1774 return rtVfsObjRelease(&pThis->Base);
1775}
1776
1777
1778RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1779{
1780 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
1781 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1782 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
1783 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
1784}
1785
1786
1787RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
1788{
1789 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
1790 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1791 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
1792
1793 fMode = rtFsModeNormalize(fMode, NULL, 0);
1794 if (!rtFsModeIsValid(fMode))
1795 return VERR_INVALID_PARAMETER;
1796
1797 RTVfsLockAcquireWrite(pThis->Base.hLock);
1798 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
1799 RTVfsLockReleaseWrite(pThis->Base.hLock);
1800 return rc;
1801}
1802
1803
1804RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1805 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1806{
1807 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
1808 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1809 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
1810
1811 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
1812 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
1813 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
1814 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
1815
1816 RTVfsLockAcquireWrite(pThis->Base.hLock);
1817 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1818 RTVfsLockReleaseWrite(pThis->Base.hLock);
1819 return rc;
1820}
1821
1822
1823RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
1824{
1825 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
1826 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1827 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
1828
1829 RTVfsLockAcquireWrite(pThis->Base.hLock);
1830 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
1831 RTVfsLockReleaseWrite(pThis->Base.hLock);
1832 return rc;
1833}
1834
1835
1836RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
1837{
1838 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
1839 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1840 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
1841
1842 RTVfsLockAcquireWrite(pThis->Base.hLock);
1843 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
1844 RTVfsLockReleaseWrite(pThis->Base.hLock);
1845
1846 return rc;
1847}
1848
1849
1850
1851/*
1852 *
1853 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
1854 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
1855 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
1856 *
1857 */
1858
1859RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
1860 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
1861{
1862 /*
1863 * Validate the input, be extra strict in strict builds.
1864 */
1865 AssertPtr(pIoStreamOps);
1866 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1867 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1868 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
1869 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
1870 Assert(cbInstance > 0);
1871 Assert(fOpen & RTFILE_O_ACCESS_MASK);
1872 AssertPtr(ppvInstance);
1873 AssertPtr(phVfsIos);
1874 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
1875
1876 /*
1877 * Allocate the handle + instance data.
1878 */
1879 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
1880 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1881 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
1882 if (!pThis)
1883 return VERR_NO_MEMORY;
1884
1885 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, hLock,
1886 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1887 if (RT_FAILURE(rc))
1888 {
1889 RTMemFree(pThis);
1890 return rc;
1891 }
1892
1893 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
1894 pThis->fFlags = fOpen;
1895 pThis->pOps = pIoStreamOps;
1896
1897 *phVfsIos = pThis;
1898 *ppvInstance = pThis->Base.pvThis;
1899 return VINF_SUCCESS;
1900}
1901
1902
1903RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
1904{
1905 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
1906 AssertPtrReturn(pThis, UINT32_MAX);
1907 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
1908 return rtVfsObjRetain(&pThis->Base);
1909}
1910
1911
1912RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
1913{
1914 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
1915 AssertPtrReturn(pThis, UINT32_MAX);
1916 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
1917 return rtVfsObjRelease(&pThis->Base);
1918}
1919
1920
1921RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
1922{
1923 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
1924 AssertPtrReturn(pThis, NIL_RTVFSFILE);
1925 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
1926
1927 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
1928 {
1929 rtVfsObjRetainVoid(&pThis->Base);
1930 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
1931 }
1932
1933 /* this is no crime, so don't assert. */
1934 return NIL_RTVFSFILE;
1935}
1936
1937
1938RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1939{
1940 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
1941 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1942 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
1943 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
1944}
1945
1946
1947RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
1948{
1949 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
1950 if (pcbRead)
1951 *pcbRead = 0;
1952 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
1953 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1954 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
1955 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
1956 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
1957
1958 RTSGSEG Seg = { pvBuf, cbToRead };
1959 RTSGBUF SgBuf;
1960 RTSgBufInit(&SgBuf, &Seg, 1);
1961
1962 RTVfsLockAcquireWrite(pThis->Base.hLock);
1963 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
1964 RTVfsLockReleaseWrite(pThis->Base.hLock);
1965 return rc;
1966}
1967
1968
1969RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
1970{
1971 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
1972 if (pcbWritten)
1973 *pcbWritten = 0;
1974 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
1975 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1976 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
1977 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
1978 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
1979
1980 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
1981 RTSGBUF SgBuf;
1982 RTSgBufInit(&SgBuf, &Seg, 1);
1983
1984 RTVfsLockAcquireWrite(pThis->Base.hLock);
1985 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
1986 RTVfsLockReleaseWrite(pThis->Base.hLock);
1987 return rc;
1988}
1989
1990
1991RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
1992{
1993 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
1994 if (pcbRead)
1995 *pcbRead = 0;
1996 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
1997 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1998 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
1999 AssertPtr(pSgBuf);
2000 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2001 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2002
2003 RTVfsLockAcquireWrite(pThis->Base.hLock);
2004 int rc;
2005 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
2006 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbRead);
2007 else
2008 {
2009 size_t cbRead = 0;
2010 rc = VINF_SUCCESS;
2011
2012 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
2013 {
2014 RTSGBUF SgBuf;
2015 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
2016
2017 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
2018 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
2019 if (RT_FAILURE(rc))
2020 break;
2021 cbRead += cbReadSeg;
2022 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
2023 break;
2024 }
2025
2026 if (pcbRead)
2027 *pcbRead = cbRead;
2028 }
2029 RTVfsLockReleaseWrite(pThis->Base.hLock);
2030 return rc;
2031}
2032
2033
2034RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
2035{
2036 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2037 if (pcbWritten)
2038 *pcbWritten = 0;
2039 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2040 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2041 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2042 AssertPtr(pSgBuf);
2043 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2044 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2045
2046 RTVfsLockAcquireWrite(pThis->Base.hLock);
2047 int rc;
2048 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
2049 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, pSgBuf, fBlocking, pcbWritten);
2050 else
2051 {
2052 size_t cbWritten = 0;
2053 rc = VINF_SUCCESS;
2054
2055 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
2056 {
2057 RTSGBUF SgBuf;
2058 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
2059
2060 size_t cbWrittenSeg = 0;
2061 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
2062 if (RT_FAILURE(rc))
2063 break;
2064 if (pcbWritten)
2065 {
2066 cbWritten += cbWrittenSeg;
2067 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
2068 break;
2069 }
2070 }
2071
2072 if (pcbWritten)
2073 *pcbWritten = cbWritten;
2074 }
2075 RTVfsLockReleaseWrite(pThis->Base.hLock);
2076 return rc;
2077}
2078
2079
2080RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
2081{
2082 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2083 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2084 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2085
2086 RTVfsLockAcquireWrite(pThis->Base.hLock);
2087 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
2088 RTVfsLockReleaseWrite(pThis->Base.hLock);
2089 return rc;
2090}
2091
2092
2093RTDECL(RTFOFF) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
2094 uint32_t *pfRetEvents)
2095{
2096 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2097 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2098 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2099
2100 RTVfsLockAcquireWrite(pThis->Base.hLock);
2101 int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
2102 RTVfsLockReleaseWrite(pThis->Base.hLock);
2103 return rc;
2104}
2105
2106
2107RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
2108{
2109 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2110 AssertPtrReturn(pThis, -1);
2111 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2112
2113 RTFOFF off;
2114 RTVfsLockAcquireRead(pThis->Base.hLock);
2115 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
2116 RTVfsLockReleaseRead(pThis->Base.hLock);
2117 if (RT_FAILURE(rc))
2118 off = rc;
2119 return off;
2120}
2121
2122
2123RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
2124{
2125 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2126 AssertPtrReturn(pThis, -1);
2127 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2128 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
2129
2130 int rc;
2131 if (pThis->pOps->pfnSkip)
2132 {
2133 RTVfsLockAcquireWrite(pThis->Base.hLock);
2134 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
2135 RTVfsLockReleaseWrite(pThis->Base.hLock);
2136 }
2137 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
2138 {
2139 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
2140 RTFOFF offIgnored;
2141
2142 RTVfsLockAcquireWrite(pThis->Base.hLock);
2143 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
2144 RTVfsLockReleaseWrite(pThis->Base.hLock);
2145 }
2146 else
2147 {
2148 void *pvBuf = RTMemTmpAlloc(_64K);
2149 if (pvBuf)
2150 {
2151 rc = VINF_SUCCESS;
2152 while (cb > 0)
2153 {
2154 size_t cbToRead = RT_MIN(cb, _64K);
2155 RTVfsLockAcquireWrite(pThis->Base.hLock);
2156 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
2157 RTVfsLockReleaseWrite(pThis->Base.hLock);
2158 if (RT_FAILURE(rc))
2159 break;
2160 cb -= cbToRead;
2161 }
2162
2163 RTMemTmpFree(pvBuf);
2164 }
2165 else
2166 rc = VERR_NO_TMP_MEMORY;
2167 }
2168 return rc;
2169}
2170
2171
2172RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
2173{
2174 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2175 AssertPtrReturn(pThis, -1);
2176 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
2177
2178 int rc;
2179 if (pThis->pOps->pfnSkip)
2180 {
2181 RTVfsLockAcquireWrite(pThis->Base.hLock);
2182 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
2183 RTVfsLockReleaseWrite(pThis->Base.hLock);
2184 }
2185 else
2186 {
2187 void *pvBuf = RTMemTmpAllocZ(_64K);
2188 if (pvBuf)
2189 {
2190 rc = VINF_SUCCESS;
2191 while (cb > 0)
2192 {
2193 size_t cbToWrite = RT_MIN(cb, _64K);
2194 RTVfsLockAcquireWrite(pThis->Base.hLock);
2195 rc = RTVfsIoStrmWrite(hVfsIos, pvBuf, cbToWrite, true /*fBlocking*/, NULL);
2196 RTVfsLockReleaseWrite(pThis->Base.hLock);
2197 if (RT_FAILURE(rc))
2198 break;
2199 cb -= cbToWrite;
2200 }
2201
2202 RTMemTmpFree(pvBuf);
2203 }
2204 else
2205 rc = VERR_NO_TMP_MEMORY;
2206 }
2207 return rc;
2208}
2209
2210
2211RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
2212{
2213 /*
2214 * There is where the zero read behavior comes in handy.
2215 */
2216 char bDummy;
2217 size_t cbRead;
2218 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
2219 return rc == VINF_EOF;
2220}
2221
2222
2223
2224
2225
2226
2227
2228/*
2229 *
2230 * F I L E F I L E F I L E
2231 * F I L E F I L E F I L E
2232 * F I L E F I L E F I L E
2233 *
2234 */
2235
2236RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
2237 PRTVFSFILE phVfsFile, void **ppvInstance)
2238{
2239 /*
2240 * Validate the input, be extra strict in strict builds.
2241 */
2242 AssertPtr(pFileOps);
2243 AssertReturn(pFileOps->uVersion == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
2244 AssertReturn(pFileOps->uEndMarker == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
2245 Assert(!pFileOps->fReserved);
2246 RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
2247 Assert(cbInstance > 0);
2248 Assert(fOpen & RTFILE_O_ACCESS_MASK);
2249 AssertPtr(ppvInstance);
2250 AssertPtr(phVfsFile);
2251 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2252
2253 /*
2254 * Allocate the handle + instance data.
2255 */
2256 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
2257 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2258 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
2259 if (!pThis)
2260 return VERR_NO_MEMORY;
2261
2262 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, hLock,
2263 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2264 if (RT_FAILURE(rc))
2265 {
2266 RTMemFree(pThis);
2267 return rc;
2268 }
2269
2270 pThis->uMagic = RTVFSFILE_MAGIC;
2271 pThis->fReserved = 0;
2272 pThis->pOps = pFileOps;
2273 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
2274 pThis->Stream.fFlags = fOpen;
2275 pThis->Stream.pOps = &pFileOps->Stream;
2276
2277 *phVfsFile = pThis;
2278 *ppvInstance = pThis->Stream.Base.pvThis;
2279 return VINF_SUCCESS;
2280}
2281
2282
2283RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint32_t fOpen, PRTVFSFILE phVfsFile)
2284{
2285 /*
2286 * Validate input.
2287 */
2288 RTVFSINTERNAL *pThis = hVfs;
2289 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2290 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2291 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
2292 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2293
2294 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2295 if (RT_FAILURE(rc))
2296 return rc;
2297
2298 /*
2299 * Parse the path, assume current directory is root since we've got no
2300 * caller context here.
2301 */
2302 PRTVFSPARSEDPATH pPath;
2303 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
2304 if (RT_SUCCESS(rc))
2305 {
2306 if (!pPath->fDirSlash)
2307 {
2308 /*
2309 * Tranverse the path, resolving the parent node and any symlinks
2310 * in the final element, and ask the directory to open the file.
2311 */
2312 RTVFSDIRINTERNAL *pVfsParentDir;
2313 rc = rtVfsTraverseToParent(pThis, pPath, true /*fFollowSymlink*/, &pVfsParentDir);
2314 if (RT_SUCCESS(rc))
2315 {
2316 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2317
2318 /** @todo there is a symlink creation race here. */
2319 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2320 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2321 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2322
2323 RTVfsDirRelease(pVfsParentDir);
2324
2325 if (RT_SUCCESS(rc))
2326 {
2327 AssertPtr(*phVfsFile);
2328 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2329 }
2330 }
2331 }
2332 else
2333 rc = VERR_INVALID_PARAMETER;
2334 RTVfsParsePathFree(pPath);
2335 }
2336 return rc;
2337}
2338
2339
2340RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
2341{
2342 RTVFSFILEINTERNAL *pThis = hVfsFile;
2343 AssertPtrReturn(pThis, UINT32_MAX);
2344 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
2345 return rtVfsObjRetain(&pThis->Stream.Base);
2346}
2347
2348
2349RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
2350{
2351 RTVFSFILEINTERNAL *pThis = hVfsFile;
2352 AssertPtrReturn(pThis, UINT32_MAX);
2353 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
2354 return rtVfsObjRelease(&pThis->Stream.Base);
2355}
2356
2357
2358RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
2359{
2360 RTVFSFILEINTERNAL *pThis = hVfsFile;
2361 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
2362 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
2363
2364 rtVfsObjRetainVoid(&pThis->Stream.Base);
2365 return &pThis->Stream;
2366}
2367
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