VirtualBox

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

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

Manifest comparison.

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