VirtualBox

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

Last change on this file since 42072 was 41549, checked in by vboxsync, 13 years ago

VFS/Filesystem: Convert the filesystem specific code to the VFS framework and make it work

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