VirtualBox

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

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

vfsbase.cpp: RTVfs*Release - Ignore NIL handles.

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