VirtualBox

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

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

vfs/tar: symlink fixes.

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