VirtualBox

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

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

Assigned real values to the RTVFS*_MAGIC[_DEAD] constants.

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