VirtualBox

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

最後變更 在這個檔案從69716是 69716,由 vboxsync 提交於 7 年 前

IPRT: More work on directory relative APIs (NT mainly) and VFS; introducing RTMkDir (test) tool.

  • Added RTVfsDirCreateDir
  • Added RTVfsChainOpenParentDir and RTVfsChainSplitOffFinalPath.
  • Added new tool for testing this called RTMkDir.
  • Fixed directory traversal problem with stddir by making it okay to return VERR_FILE_NOT_FOUND as well.
  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 110.5 KB
 
1/* $Id: vfsbase.cpp 69716 2017-11-16 14:31:25Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Base.
4 */
5
6/*
7 * Copyright (C) 2010-2017 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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#define LOG_GROUP RTLOGGROUP_FS
32#include <iprt/vfs.h>
33#include <iprt/vfslowlevel.h>
34
35#include <iprt/asm.h>
36#include <iprt/err.h>
37#include <iprt/file.h>
38#include <iprt/log.h>
39#include <iprt/mem.h>
40#include <iprt/param.h>
41#include <iprt/path.h>
42#include <iprt/semaphore.h>
43#include <iprt/thread.h>
44#include <iprt/zero.h>
45
46#include "internal/file.h"
47#include "internal/fs.h"
48#include "internal/magics.h"
49//#include "internal/vfs.h"
50
51
52/*********************************************************************************************************************************
53* Defined Constants And Macros *
54*********************************************************************************************************************************/
55/** The instance data alignment. */
56#define RTVFS_INST_ALIGNMENT 16U
57
58/** The max number of symbolic links to resolve in a path. */
59#define RTVFS_MAX_LINKS 20U
60
61
62/** Asserts that the VFS base object vtable is valid. */
63#define RTVFSOBJ_ASSERT_OPS(a_pObjOps, a_enmType) \
64 do \
65 { \
66 Assert((a_pObjOps)->uVersion == RTVFSOBJOPS_VERSION); \
67 Assert((a_pObjOps)->enmType == (a_enmType) || (a_enmType) == RTVFSOBJTYPE_INVALID); \
68 AssertPtr((a_pObjOps)->pszName); \
69 Assert(*(a_pObjOps)->pszName); \
70 AssertPtr((a_pObjOps)->pfnClose); \
71 AssertPtr((a_pObjOps)->pfnQueryInfo); \
72 Assert((a_pObjOps)->uEndMarker == RTVFSOBJOPS_VERSION); \
73 } while (0)
74
75/** Asserts that the VFS set object vtable is valid. */
76#define RTVFSOBJSET_ASSERT_OPS(a_pSetOps, a_offObjOps) \
77 do \
78 { \
79 Assert((a_pSetOps)->uVersion == RTVFSOBJSETOPS_VERSION); \
80 Assert((a_pSetOps)->offObjOps == (a_offObjOps)); \
81 AssertPtr((a_pSetOps)->pfnSetMode); \
82 AssertPtr((a_pSetOps)->pfnSetTimes); \
83 AssertPtr((a_pSetOps)->pfnSetOwner); \
84 Assert((a_pSetOps)->uEndMarker == RTVFSOBJSETOPS_VERSION); \
85 } while (0)
86
87/** Asserts that the VFS directory vtable is valid. */
88#define RTVFSDIR_ASSERT_OPS(pDirOps, a_enmType) \
89 do { \
90 RTVFSOBJ_ASSERT_OPS(&(pDirOps)->Obj, a_enmType); \
91 RTVFSOBJSET_ASSERT_OPS(&(pDirOps)->ObjSet, RT_OFFSETOF(RTVFSDIROPS, Obj) - RT_OFFSETOF(RTVFSDIROPS, ObjSet)); \
92 Assert((pDirOps)->uVersion == RTVFSDIROPS_VERSION); \
93 Assert(!(pDirOps)->fReserved); \
94 AssertPtr((pDirOps)->pfnTraversalOpen); \
95 AssertPtr((pDirOps)->pfnOpenFile); \
96 AssertPtr((pDirOps)->pfnOpenDir); \
97 AssertPtr((pDirOps)->pfnCreateDir); \
98 AssertPtr((pDirOps)->pfnOpenSymlink); \
99 AssertPtr((pDirOps)->pfnCreateSymlink); \
100 AssertPtr((pDirOps)->pfnUnlinkEntry); \
101 AssertPtr((pDirOps)->pfnRewindDir); \
102 AssertPtr((pDirOps)->pfnReadDir); \
103 Assert((pDirOps)->uEndMarker == RTVFSDIROPS_VERSION); \
104 } while (0)
105
106/** Asserts that the VFS I/O stream vtable is valid. */
107#define RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, a_enmType) \
108 do { \
109 RTVFSOBJ_ASSERT_OPS(&(pIoStreamOps)->Obj, a_enmType); \
110 Assert((pIoStreamOps)->uVersion == RTVFSIOSTREAMOPS_VERSION); \
111 Assert(!((pIoStreamOps)->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); \
112 AssertPtr((pIoStreamOps)->pfnRead); \
113 AssertPtr((pIoStreamOps)->pfnWrite); \
114 AssertPtr((pIoStreamOps)->pfnFlush); \
115 AssertPtr((pIoStreamOps)->pfnPollOne); \
116 AssertPtr((pIoStreamOps)->pfnTell); \
117 AssertPtrNull((pIoStreamOps)->pfnSkip); \
118 AssertPtrNull((pIoStreamOps)->pfnZeroFill); \
119 Assert((pIoStreamOps)->uEndMarker == RTVFSIOSTREAMOPS_VERSION); \
120 } while (0)
121
122/** Asserts that the VFS symlink vtable is valid. */
123#define RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, a_enmType) \
124 do { \
125 RTVFSOBJ_ASSERT_OPS(&(pSymlinkOps)->Obj, a_enmType); \
126 RTVFSOBJSET_ASSERT_OPS(&(pSymlinkOps)->ObjSet, \
127 RT_OFFSETOF(RTVFSSYMLINKOPS, Obj) - RT_OFFSETOF(RTVFSSYMLINKOPS, ObjSet)); \
128 Assert((pSymlinkOps)->uVersion == RTVFSSYMLINKOPS_VERSION); \
129 Assert(!(pSymlinkOps)->fReserved); \
130 AssertPtr((pSymlinkOps)->pfnRead); \
131 Assert((pSymlinkOps)->uEndMarker == RTVFSSYMLINKOPS_VERSION); \
132 } while (0)
133
134
135/** Validates a VFS handle and returns @a rcRet if it's invalid. */
136#define RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, rcRet) \
137 do { \
138 if ((hVfs) != NIL_RTVFS) \
139 { \
140 AssertPtrReturn((hVfs), (rcRet)); \
141 AssertReturn((hVfs)->uMagic == RTVFS_MAGIC, (rcRet)); \
142 } \
143 } while (0)
144
145
146/*********************************************************************************************************************************
147* Structures and Typedefs *
148*********************************************************************************************************************************/
149/** @todo Move all this stuff to internal/vfs.h */
150
151
152/**
153 * The VFS internal lock data.
154 */
155typedef struct RTVFSLOCKINTERNAL
156{
157 /** The number of references to the this lock. */
158 uint32_t volatile cRefs;
159 /** The lock type. */
160 RTVFSLOCKTYPE enmType;
161 /** Type specific data. */
162 union
163 {
164 /** Read/Write semaphore handle. */
165 RTSEMRW hSemRW;
166 /** Fast mutex semaphore handle. */
167 RTSEMFASTMUTEX hFastMtx;
168 /** Regular mutex semaphore handle. */
169 RTSEMMUTEX hMtx;
170 } u;
171} RTVFSLOCKINTERNAL;
172
173
174/**
175 * The VFS base object handle data.
176 *
177 * All other VFS handles are derived from this one. The final handle type is
178 * indicated by RTVFSOBJOPS::enmType via the RTVFSOBJINTERNAL::pOps member.
179 */
180typedef struct RTVFSOBJINTERNAL
181{
182 /** The VFS magic (RTVFSOBJ_MAGIC). */
183 uint32_t uMagic : 31;
184 /** Set if we've got no VFS reference but still got a valid hVfs.
185 * This is hack for permanent root directory objects. */
186 uint32_t fNoVfsRef : 1;
187 /** The number of references to this VFS object. */
188 uint32_t volatile cRefs;
189 /** Pointer to the instance data. */
190 void *pvThis;
191 /** The vtable. */
192 PCRTVFSOBJOPS pOps;
193 /** The lock protecting all access to the VFS.
194 * Only valid if RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTVFSLOCK. */
195 RTVFSLOCK hLock;
196 /** Reference back to the VFS containing this object. */
197 RTVFS hVfs;
198} RTVFSOBJINTERNAL;
199
200
201/**
202 * The VFS filesystem stream handle data.
203 *
204 * @extends RTVFSOBJINTERNAL
205 */
206typedef struct RTVFSFSSTREAMINTERNAL
207{
208 /** The VFS magic (RTVFSFSTREAM_MAGIC). */
209 uint32_t uMagic;
210 /** File open flags, at a minimum the access mask. */
211 uint32_t fFlags;
212 /** The vtable. */
213 PCRTVFSFSSTREAMOPS pOps;
214 /** The base object handle data. */
215 RTVFSOBJINTERNAL Base;
216} RTVFSFSSTREAMINTERNAL;
217
218
219/**
220 * The VFS handle data.
221 *
222 * @extends RTVFSOBJINTERNAL
223 */
224typedef struct RTVFSINTERNAL
225{
226 /** The VFS magic (RTVFS_MAGIC). */
227 uint32_t uMagic;
228 /** Creation flags (RTVFS_C_XXX). */
229 uint32_t fFlags;
230 /** The vtable. */
231 PCRTVFSOPS pOps;
232 /** The base object handle data. */
233 RTVFSOBJINTERNAL Base;
234} RTVFSINTERNAL;
235
236
237/**
238 * The VFS directory handle data.
239 *
240 * @extends RTVFSOBJINTERNAL
241 */
242typedef struct RTVFSDIRINTERNAL
243{
244 /** The VFS magic (RTVFSDIR_MAGIC). */
245 uint32_t uMagic;
246 /** Reserved for flags or something. */
247 uint32_t fReserved;
248 /** The vtable. */
249 PCRTVFSDIROPS pOps;
250 /** The base object handle data. */
251 RTVFSOBJINTERNAL Base;
252} RTVFSDIRINTERNAL;
253
254
255/**
256 * The VFS symbolic link handle data.
257 *
258 * @extends RTVFSOBJINTERNAL
259 */
260typedef struct RTVFSSYMLINKINTERNAL
261{
262 /** The VFS magic (RTVFSSYMLINK_MAGIC). */
263 uint32_t uMagic;
264 /** Reserved for flags or something. */
265 uint32_t fReserved;
266 /** The vtable. */
267 PCRTVFSSYMLINKOPS pOps;
268 /** The base object handle data. */
269 RTVFSOBJINTERNAL Base;
270} RTVFSSYMLINKINTERNAL;
271
272
273/**
274 * The VFS I/O stream handle data.
275 *
276 * This is often part of a type specific handle, like a file or pipe.
277 *
278 * @extends RTVFSOBJINTERNAL
279 */
280typedef struct RTVFSIOSTREAMINTERNAL
281{
282 /** The VFS magic (RTVFSIOSTREAM_MAGIC). */
283 uint32_t uMagic;
284 /** File open flags, at a minimum the access mask. */
285 uint32_t fFlags;
286 /** The vtable. */
287 PCRTVFSIOSTREAMOPS pOps;
288 /** The base object handle data. */
289 RTVFSOBJINTERNAL Base;
290} RTVFSIOSTREAMINTERNAL;
291
292
293/**
294 * The VFS file handle data.
295 *
296 * @extends RTVFSIOSTREAMINTERNAL
297 */
298typedef struct RTVFSFILEINTERNAL
299{
300 /** The VFS magic (RTVFSFILE_MAGIC). */
301 uint32_t uMagic;
302 /** Reserved for flags or something. */
303 uint32_t fReserved;
304 /** The vtable. */
305 PCRTVFSFILEOPS pOps;
306 /** The stream handle data. */
307 RTVFSIOSTREAMINTERNAL Stream;
308} RTVFSFILEINTERNAL;
309
310#if 0 /* later */
311
312/**
313 * The VFS pipe handle data.
314 *
315 * @extends RTVFSIOSTREAMINTERNAL
316 */
317typedef struct RTVFSPIPEINTERNAL
318{
319 /** The VFS magic (RTVFSPIPE_MAGIC). */
320 uint32_t uMagic;
321 /** Reserved for flags or something. */
322 uint32_t fReserved;
323 /** The vtable. */
324 PCRTVFSPIPEOPS pOps;
325 /** The stream handle data. */
326 RTVFSIOSTREAMINTERNAL Stream;
327} RTVFSPIPEINTERNAL;
328
329
330/**
331 * The VFS socket handle data.
332 *
333 * @extends RTVFSIOSTREAMINTERNAL
334 */
335typedef struct RTVFSSOCKETINTERNAL
336{
337 /** The VFS magic (RTVFSSOCKET_MAGIC). */
338 uint32_t uMagic;
339 /** Reserved for flags or something. */
340 uint32_t fReserved;
341 /** The vtable. */
342 PCRTVFSSOCKETOPS pOps;
343 /** The stream handle data. */
344 RTVFSIOSTREAMINTERNAL Stream;
345} RTVFSSOCKETINTERNAL;
346
347#endif /* later */
348
349
350/*********************************************************************************************************************************
351* Internal Functions *
352*********************************************************************************************************************************/
353DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis);
354
355
356
357/*
358 *
359 * V F S L o c k A b s t r a c t i o n
360 * V F S L o c k A b s t r a c t i o n
361 * V F S L o c k A b s t r a c t i o n
362 *
363 *
364 */
365
366
367RTDECL(uint32_t) RTVfsLockRetain(RTVFSLOCK hLock)
368{
369 RTVFSLOCKINTERNAL *pThis = hLock;
370 AssertPtrReturn(pThis, UINT32_MAX);
371 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
372
373 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
374 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
375 return cRefs;
376}
377
378
379RTDECL(uint32_t) RTVfsLockRetainDebug(RTVFSLOCK hLock, RT_SRC_POS_DECL)
380{
381 RTVFSLOCKINTERNAL *pThis = hLock;
382 AssertPtrReturn(pThis, UINT32_MAX);
383 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
384
385 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
386 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
387 LogFlow(("RTVfsLockRetainDebug(%p) -> %d; caller: %s %s(%u)\n", hLock, cRefs, pszFunction, pszFile, iLine));
388 RT_SRC_POS_NOREF();
389 return cRefs;
390}
391
392
393/**
394 * Destroys a VFS lock handle.
395 *
396 * @param pThis The lock to destroy.
397 */
398static void rtVfsLockDestroy(RTVFSLOCKINTERNAL *pThis)
399{
400 switch (pThis->enmType)
401 {
402 case RTVFSLOCKTYPE_RW:
403 RTSemRWDestroy(pThis->u.hSemRW);
404 pThis->u.hSemRW = NIL_RTSEMRW;
405 break;
406
407 case RTVFSLOCKTYPE_FASTMUTEX:
408 RTSemFastMutexDestroy(pThis->u.hFastMtx);
409 pThis->u.hFastMtx = NIL_RTSEMFASTMUTEX;
410 break;
411
412 case RTVFSLOCKTYPE_MUTEX:
413 RTSemMutexDestroy(pThis->u.hMtx);
414 pThis->u.hFastMtx = NIL_RTSEMMUTEX;
415 break;
416
417 default:
418 AssertMsgFailedReturnVoid(("%p %d\n", pThis, pThis->enmType));
419 }
420
421 pThis->enmType = RTVFSLOCKTYPE_INVALID;
422 RTMemFree(pThis);
423}
424
425
426RTDECL(uint32_t) RTVfsLockRelease(RTVFSLOCK hLock)
427{
428 RTVFSLOCKINTERNAL *pThis = hLock;
429 if (pThis == NIL_RTVFSLOCK)
430 return 0;
431 AssertPtrReturn(pThis, UINT32_MAX);
432 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
433
434 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
435 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
436 if (cRefs == 0)
437 rtVfsLockDestroy(pThis);
438 return cRefs;
439}
440
441
442/**
443 * Creates a read/write lock.
444 *
445 * @returns IPRT status code
446 * @param phLock Where to return the lock handle.
447 */
448static int rtVfsLockCreateRW(PRTVFSLOCK phLock)
449{
450 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
451 if (!pThis)
452 return VERR_NO_MEMORY;
453
454 pThis->cRefs = 1;
455 pThis->enmType = RTVFSLOCKTYPE_RW;
456
457 int rc = RTSemRWCreate(&pThis->u.hSemRW);
458 if (RT_FAILURE(rc))
459 {
460 RTMemFree(pThis);
461 return rc;
462 }
463
464 *phLock = pThis;
465 return VINF_SUCCESS;
466}
467
468
469/**
470 * Creates a fast mutex lock.
471 *
472 * @returns IPRT status code
473 * @param phLock Where to return the lock handle.
474 */
475static int rtVfsLockCreateFastMutex(PRTVFSLOCK phLock)
476{
477 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
478 if (!pThis)
479 return VERR_NO_MEMORY;
480
481 pThis->cRefs = 1;
482 pThis->enmType = RTVFSLOCKTYPE_FASTMUTEX;
483
484 int rc = RTSemFastMutexCreate(&pThis->u.hFastMtx);
485 if (RT_FAILURE(rc))
486 {
487 RTMemFree(pThis);
488 return rc;
489 }
490
491 *phLock = pThis;
492 return VINF_SUCCESS;
493
494}
495
496
497/**
498 * Creates a mutex lock.
499 *
500 * @returns IPRT status code
501 * @param phLock Where to return the lock handle.
502 */
503static int rtVfsLockCreateMutex(PRTVFSLOCK phLock)
504{
505 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
506 if (!pThis)
507 return VERR_NO_MEMORY;
508
509 pThis->cRefs = 1;
510 pThis->enmType = RTVFSLOCKTYPE_MUTEX;
511
512 int rc = RTSemMutexCreate(&pThis->u.hMtx);
513 if (RT_FAILURE(rc))
514 {
515 RTMemFree(pThis);
516 return rc;
517 }
518
519 *phLock = pThis;
520 return VINF_SUCCESS;
521}
522
523
524/**
525 * Acquires the lock for reading.
526 *
527 * @param hLock Non-nil lock handle.
528 * @internal
529 */
530RTDECL(void) RTVfsLockAcquireReadSlow(RTVFSLOCK hLock)
531{
532 RTVFSLOCKINTERNAL *pThis = hLock;
533 int rc;
534
535 AssertPtr(pThis);
536 switch (pThis->enmType)
537 {
538 case RTVFSLOCKTYPE_RW:
539 rc = RTSemRWRequestRead(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
540 AssertRC(rc);
541 break;
542
543 case RTVFSLOCKTYPE_FASTMUTEX:
544 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
545 AssertRC(rc);
546 break;
547
548 case RTVFSLOCKTYPE_MUTEX:
549 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
550 AssertRC(rc);
551 break;
552 default:
553 AssertFailed();
554 }
555}
556
557
558/**
559 * Release a lock held for reading.
560 *
561 * @param hLock Non-nil lock handle.
562 * @internal
563 */
564RTDECL(void) RTVfsLockReleaseReadSlow(RTVFSLOCK hLock)
565{
566 RTVFSLOCKINTERNAL *pThis = hLock;
567 int rc;
568
569 AssertPtr(pThis);
570 switch (pThis->enmType)
571 {
572 case RTVFSLOCKTYPE_RW:
573 rc = RTSemRWReleaseRead(pThis->u.hSemRW);
574 AssertRC(rc);
575 break;
576
577 case RTVFSLOCKTYPE_FASTMUTEX:
578 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
579 AssertRC(rc);
580 break;
581
582 case RTVFSLOCKTYPE_MUTEX:
583 rc = RTSemMutexRelease(pThis->u.hMtx);
584 AssertRC(rc);
585 break;
586 default:
587 AssertFailed();
588 }
589}
590
591
592/**
593 * Acquires the lock for writing.
594 *
595 * @param hLock Non-nil lock handle.
596 * @internal
597 */
598RTDECL(void) RTVfsLockAcquireWriteSlow(RTVFSLOCK hLock)
599{
600 RTVFSLOCKINTERNAL *pThis = hLock;
601 int rc;
602
603 AssertPtr(pThis);
604 switch (pThis->enmType)
605 {
606 case RTVFSLOCKTYPE_RW:
607 rc = RTSemRWRequestWrite(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
608 AssertRC(rc);
609 break;
610
611 case RTVFSLOCKTYPE_FASTMUTEX:
612 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
613 AssertRC(rc);
614 break;
615
616 case RTVFSLOCKTYPE_MUTEX:
617 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
618 AssertRC(rc);
619 break;
620 default:
621 AssertFailed();
622 }
623}
624
625
626/**
627 * Release a lock held for writing.
628 *
629 * @param hLock Non-nil lock handle.
630 * @internal
631 */
632RTDECL(void) RTVfsLockReleaseWriteSlow(RTVFSLOCK hLock)
633{
634 RTVFSLOCKINTERNAL *pThis = hLock;
635 int rc;
636
637 AssertPtr(pThis);
638 switch (pThis->enmType)
639 {
640 case RTVFSLOCKTYPE_RW:
641 rc = RTSemRWReleaseWrite(pThis->u.hSemRW);
642 AssertRC(rc);
643 break;
644
645 case RTVFSLOCKTYPE_FASTMUTEX:
646 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
647 AssertRC(rc);
648 break;
649
650 case RTVFSLOCKTYPE_MUTEX:
651 rc = RTSemMutexRelease(pThis->u.hMtx);
652 AssertRC(rc);
653 break;
654 default:
655 AssertFailed();
656 }
657}
658
659
660
661/*
662 *
663 * B A S E O B J E C T
664 * B A S E O B J E C T
665 * B A S E O B J E C T
666 *
667 */
668
669/**
670 * Internal object retainer that asserts sanity in strict builds.
671 *
672 * @param pThis The base object handle data.
673 * @param pszCaller Where we're called from.
674 */
675DECLINLINE(void) rtVfsObjRetainVoid(RTVFSOBJINTERNAL *pThis, const char *pszCaller)
676{
677 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
678LogFlow(("rtVfsObjRetainVoid(%p/%p) -> %d; caller=%s\n", pThis, pThis->pvThis, cRefs, pszCaller)); RT_NOREF(pszCaller);
679 AssertMsg(cRefs > 1 && cRefs < _1M,
680 ("%#x %p ops=%p %s (%d); caller=%s\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType, pszCaller));
681 NOREF(cRefs);
682}
683
684
685/**
686 * Initializes the base object part of a new object.
687 *
688 * @returns IPRT status code.
689 * @param pThis Pointer to the base object part.
690 * @param pObjOps The base object vtable.
691 * @param hVfs The VFS handle to associate with.
692 * @param fNoVfsRef If set, do not retain an additional reference to
693 * @a hVfs. Permanent root dir hack.
694 * @param hLock The lock handle, pseudo handle or nil.
695 * @param pvThis Pointer to the private data.
696 */
697static int rtVfsObjInitNewObject(RTVFSOBJINTERNAL *pThis, PCRTVFSOBJOPS pObjOps, RTVFS hVfs, bool fNoVfsRef,
698 RTVFSLOCK hLock, void *pvThis)
699{
700 /*
701 * Deal with the lock first as that's the most complicated matter.
702 */
703 if (hLock != NIL_RTVFSLOCK)
704 {
705 int rc;
706 if (hLock == RTVFSLOCK_CREATE_RW)
707 {
708 rc = rtVfsLockCreateRW(&hLock);
709 AssertRCReturn(rc, rc);
710 }
711 else if (hLock == RTVFSLOCK_CREATE_FASTMUTEX)
712 {
713 rc = rtVfsLockCreateFastMutex(&hLock);
714 AssertRCReturn(rc, rc);
715 }
716 else if (hLock == RTVFSLOCK_CREATE_MUTEX)
717 {
718 rc = rtVfsLockCreateMutex(&hLock);
719 AssertRCReturn(rc, rc);
720 }
721 else
722 {
723 /*
724 * The caller specified a lock, we consume the this reference.
725 */
726 AssertPtrReturn(hLock, VERR_INVALID_HANDLE);
727 AssertReturn(hLock->enmType > RTVFSLOCKTYPE_INVALID && hLock->enmType < RTVFSLOCKTYPE_END, VERR_INVALID_HANDLE);
728 AssertReturn(hLock->cRefs > 0, VERR_INVALID_HANDLE);
729 }
730 }
731 else if (hVfs != NIL_RTVFS)
732 {
733 /*
734 * Retain a reference to the VFS lock, if there is one.
735 */
736 hLock = hVfs->Base.hLock;
737 if (hLock != NIL_RTVFSLOCK)
738 {
739 uint32_t cRefs = RTVfsLockRetain(hLock);
740 if (RT_UNLIKELY(cRefs == UINT32_MAX))
741 return VERR_INVALID_HANDLE;
742 }
743 }
744
745
746 /*
747 * Do the actual initializing.
748 */
749 pThis->uMagic = RTVFSOBJ_MAGIC;
750 pThis->fNoVfsRef = fNoVfsRef;
751 pThis->pvThis = pvThis;
752 pThis->pOps = pObjOps;
753 pThis->cRefs = 1;
754 pThis->hVfs = hVfs;
755 pThis->hLock = hLock;
756 if (hVfs != NIL_RTVFS && !fNoVfsRef)
757 rtVfsObjRetainVoid(&hVfs->Base, "rtVfsObjInitNewObject");
758
759 return VINF_SUCCESS;
760}
761
762
763RTDECL(int) RTVfsNewBaseObj(PCRTVFSOBJOPS pObjOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
764 PRTVFSOBJ phVfsObj, void **ppvInstance)
765{
766 /*
767 * Validate the input, be extra strict in strict builds.
768 */
769 AssertPtr(pObjOps);
770 AssertReturn(pObjOps->uVersion == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
771 AssertReturn(pObjOps->uEndMarker == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
772 RTVFSOBJ_ASSERT_OPS(pObjOps, RTVFSOBJTYPE_BASE);
773 Assert(cbInstance > 0);
774 AssertPtr(ppvInstance);
775 AssertPtr(phVfsObj);
776 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
777
778 /*
779 * Allocate the handle + instance data.
780 */
781 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSOBJINTERNAL), RTVFS_INST_ALIGNMENT)
782 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
783 RTVFSOBJINTERNAL *pThis = (RTVFSOBJINTERNAL *)RTMemAllocZ(cbThis);
784 if (!pThis)
785 return VERR_NO_MEMORY;
786
787 int rc = rtVfsObjInitNewObject(pThis, pObjOps, hVfs, false /*fNoVfsRef*/, hLock,
788 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
789 if (RT_FAILURE(rc))
790 {
791 RTMemFree(pThis);
792 return rc;
793 }
794
795 *phVfsObj = pThis;
796 *ppvInstance = pThis->pvThis;
797 return VINF_SUCCESS;
798}
799
800
801/**
802 * Internal object retainer that asserts sanity in strict builds.
803 *
804 * @returns The new reference count.
805 * @param pThis The base object handle data.
806 */
807DECLINLINE(uint32_t) rtVfsObjRetain(RTVFSOBJINTERNAL *pThis)
808{
809 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
810LogFlow(("rtVfsObjRetain(%p/%p) -> %d\n", pThis, pThis->pvThis, cRefs));
811 AssertMsg(cRefs > 1 && cRefs < _1M,
812 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
813 return cRefs;
814}
815
816/**
817 * Internal object retainer that asserts sanity in strict builds.
818 *
819 * @returns The new reference count.
820 * @param pThis The base object handle data.
821 */
822DECLINLINE(uint32_t) rtVfsObjRetainDebug(RTVFSOBJINTERNAL *pThis, const char *pszApi, RT_SRC_POS_DECL)
823{
824 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
825 AssertMsg(cRefs > 1 && cRefs < _1M,
826 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
827 LogFlow(("%s(%p/%p) -> %2d; caller: %s %s(%d) \n", pszApi, pThis, pThis->pvThis, cRefs, pszFunction, pszFile, iLine));
828 RT_SRC_POS_NOREF(); RT_NOREF(pszApi);
829 return cRefs;
830}
831
832
833#ifdef DEBUG
834# undef RTVfsObjRetain
835#endif
836RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj)
837{
838 RTVFSOBJINTERNAL *pThis = hVfsObj;
839 AssertPtrReturn(pThis, UINT32_MAX);
840 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
841
842 return rtVfsObjRetain(pThis);
843}
844#ifdef DEBUG
845# define RTVfsObjRetain(hVfsObj) RTVfsObjRetainDebug(hVfsObj, RT_SRC_POS)
846#endif
847
848
849RTDECL(uint32_t) RTVfsObjRetainDebug(RTVFSOBJ hVfsObj, RT_SRC_POS_DECL)
850{
851 RTVFSOBJINTERNAL *pThis = hVfsObj;
852 AssertPtrReturn(pThis, UINT32_MAX);
853 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
854
855 return rtVfsObjRetainDebug(pThis, "RTVfsObjRetainDebug", RT_SRC_POS_ARGS);
856}
857
858
859/**
860 * Does the actual object destruction for rtVfsObjRelease().
861 *
862 * @param pThis The object to destroy.
863 */
864static void rtVfsObjDestroy(RTVFSOBJINTERNAL *pThis)
865{
866 RTVFSOBJTYPE const enmType = pThis->pOps->enmType;
867
868 /*
869 * Invalidate the object.
870 */
871 RTVfsLockAcquireWrite(pThis->hLock); /* paranoia */
872 void *pvToFree = NULL;
873 switch (enmType)
874 {
875 case RTVFSOBJTYPE_BASE:
876 pvToFree = pThis;
877 break;
878
879 case RTVFSOBJTYPE_VFS:
880 pvToFree = RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
881 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)->uMagic, RTVFS_MAGIC_DEAD);
882 break;
883
884 case RTVFSOBJTYPE_FS_STREAM:
885 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
886 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base)->uMagic, RTVFSFSSTREAM_MAGIC_DEAD);
887 break;
888
889 case RTVFSOBJTYPE_IO_STREAM:
890 pvToFree = RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
891 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
892 break;
893
894 case RTVFSOBJTYPE_DIR:
895 pvToFree = RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
896 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->uMagic, RTVFSDIR_MAGIC_DEAD);
897 break;
898
899 case RTVFSOBJTYPE_FILE:
900 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
901 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->uMagic, RTVFSFILE_MAGIC_DEAD);
902 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
903 break;
904
905 case RTVFSOBJTYPE_SYMLINK:
906 pvToFree = RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
907 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
908 break;
909
910 case RTVFSOBJTYPE_INVALID:
911 case RTVFSOBJTYPE_END:
912 case RTVFSOBJTYPE_32BIT_HACK:
913 AssertMsgFailed(("enmType=%d ops=%p %s\n", enmType, pThis->pOps, pThis->pOps->pszName));
914 break;
915 /* no default as we want gcc warnings. */
916 }
917 pThis->uMagic = RTVFSOBJ_MAGIC_DEAD;
918 RTVfsLockReleaseWrite(pThis->hLock);
919
920 /*
921 * Close the object and free the handle.
922 */
923 int rc = pThis->pOps->pfnClose(pThis->pvThis);
924 AssertRC(rc);
925 if (pThis->hVfs != NIL_RTVFS)
926 {
927 if (!pThis->fNoVfsRef)
928 rtVfsObjRelease(&pThis->hVfs->Base);
929 pThis->hVfs = NIL_RTVFS;
930 }
931 if (pThis->hLock != NIL_RTVFSLOCK)
932 {
933 RTVfsLockRelease(pThis->hLock);
934 pThis->hLock = NIL_RTVFSLOCK;
935 }
936 RTMemFree(pvToFree);
937}
938
939
940/**
941 * Internal object releaser that asserts sanity in strict builds.
942 *
943 * @returns The new reference count.
944 * @param pcRefs The reference counter.
945 */
946DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis)
947{
948 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
949 AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
950 LogFlow(("rtVfsObjRelease(%p/%p) -> %d\n", pThis, pThis->pvThis, cRefs));
951 if (cRefs == 0)
952 rtVfsObjDestroy(pThis);
953 return cRefs;
954}
955
956
957RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj)
958{
959 RTVFSOBJINTERNAL *pThis = hVfsObj;
960 if (pThis == NIL_RTVFSOBJ)
961 return 0;
962 AssertPtrReturn(pThis, UINT32_MAX);
963 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
964 return rtVfsObjRelease(pThis);
965}
966
967
968RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj)
969{
970 RTVFSOBJINTERNAL *pThis = hVfsObj;
971 if (pThis != NIL_RTVFSOBJ)
972 {
973 AssertPtrReturn(pThis, NIL_RTVFS);
974 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFS);
975
976 if (pThis->pOps->enmType == RTVFSOBJTYPE_VFS)
977 {
978 rtVfsObjRetainVoid(pThis, "RTVfsObjToVfs");
979 LogFlow(("RTVfsObjToVfs(%p) -> %p\n", pThis, RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)));
980 return RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
981 }
982 }
983 return NIL_RTVFS;
984}
985
986
987RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj)
988{
989 RTVFSOBJINTERNAL *pThis = hVfsObj;
990 if (pThis != NIL_RTVFSOBJ)
991 {
992 AssertPtrReturn(pThis, NIL_RTVFSFSSTREAM);
993 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFSSTREAM);
994
995 if (pThis->pOps->enmType == RTVFSOBJTYPE_FS_STREAM)
996 {
997 rtVfsObjRetainVoid(pThis, "RTVfsObjToFsStream");
998 return RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
999 }
1000 }
1001 return NIL_RTVFSFSSTREAM;
1002}
1003
1004
1005RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj)
1006{
1007 RTVFSOBJINTERNAL *pThis = hVfsObj;
1008 if (pThis != NIL_RTVFSOBJ)
1009 {
1010 AssertPtrReturn(pThis, NIL_RTVFSDIR);
1011 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSDIR);
1012
1013 if (pThis->pOps->enmType == RTVFSOBJTYPE_DIR)
1014 {
1015 rtVfsObjRetainVoid(pThis, "RTVfsObjToDir");
1016 return RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
1017 }
1018 }
1019 return NIL_RTVFSDIR;
1020}
1021
1022
1023RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj)
1024{
1025 RTVFSOBJINTERNAL *pThis = hVfsObj;
1026 if (pThis != NIL_RTVFSOBJ)
1027 {
1028 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
1029 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSIOSTREAM);
1030
1031 if ( pThis->pOps->enmType == RTVFSOBJTYPE_IO_STREAM
1032 || pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1033 {
1034 rtVfsObjRetainVoid(pThis, "RTVfsObjToIoStream");
1035 return RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
1036 }
1037 }
1038 return NIL_RTVFSIOSTREAM;
1039}
1040
1041
1042RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj)
1043{
1044 RTVFSOBJINTERNAL *pThis = hVfsObj;
1045 if (pThis != NIL_RTVFSOBJ)
1046 {
1047 AssertPtrReturn(pThis, NIL_RTVFSFILE);
1048 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFILE);
1049
1050 if (pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1051 {
1052 rtVfsObjRetainVoid(pThis, "RTVfsObjToFile");
1053 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
1054 }
1055 }
1056 return NIL_RTVFSFILE;
1057}
1058
1059
1060RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj)
1061{
1062 RTVFSOBJINTERNAL *pThis = hVfsObj;
1063 if (pThis != NIL_RTVFSOBJ)
1064 {
1065 AssertPtrReturn(pThis, NIL_RTVFSSYMLINK);
1066 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSSYMLINK);
1067
1068 if (pThis->pOps->enmType == RTVFSOBJTYPE_SYMLINK)
1069 {
1070 rtVfsObjRetainVoid(pThis, "RTVfsObjToSymlink");
1071 return RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
1072 }
1073 }
1074 return NIL_RTVFSSYMLINK;
1075}
1076
1077
1078RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs)
1079{
1080 if (hVfs != NIL_RTVFS)
1081 {
1082 RTVFSOBJINTERNAL *pThis = &hVfs->Base;
1083 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1084 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1085
1086 rtVfsObjRetainVoid(pThis, "RTVfsObjFromVfs");
1087 LogFlow(("RTVfsObjFromVfs(%p) -> %p\n", hVfs, pThis));
1088 return pThis;
1089 }
1090 return NIL_RTVFSOBJ;
1091}
1092
1093
1094RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss)
1095{
1096 if (hVfsFss != NIL_RTVFSFSSTREAM)
1097 {
1098 RTVFSOBJINTERNAL *pThis = &hVfsFss->Base;
1099 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1100 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1101
1102 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFsStream");
1103 return pThis;
1104 }
1105 return NIL_RTVFSOBJ;
1106}
1107
1108
1109RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir)
1110{
1111 if (hVfsDir != NIL_RTVFSDIR)
1112 {
1113 RTVFSOBJINTERNAL *pThis = &hVfsDir->Base;
1114 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1115 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1116
1117 rtVfsObjRetainVoid(pThis, "RTVfsObjFromDir");
1118 return pThis;
1119 }
1120 return NIL_RTVFSOBJ;
1121}
1122
1123
1124RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos)
1125{
1126 if (hVfsIos != NIL_RTVFSIOSTREAM)
1127 {
1128 RTVFSOBJINTERNAL *pThis = &hVfsIos->Base;
1129 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1130 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1131
1132 rtVfsObjRetainVoid(pThis, "RTVfsObjFromIoStream");
1133 return pThis;
1134 }
1135 return NIL_RTVFSOBJ;
1136}
1137
1138
1139RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile)
1140{
1141 if (hVfsFile != NIL_RTVFSFILE)
1142 {
1143 RTVFSOBJINTERNAL *pThis = &hVfsFile->Stream.Base;
1144 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1145 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1146
1147 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFile");
1148 return pThis;
1149 }
1150 return NIL_RTVFSOBJ;
1151}
1152
1153
1154RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym)
1155{
1156 if (hVfsSym != NIL_RTVFSSYMLINK)
1157 {
1158 RTVFSOBJINTERNAL *pThis = &hVfsSym->Base;
1159 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1160 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1161
1162 rtVfsObjRetainVoid(pThis, "RTVfsObjFromSymlink");
1163 return pThis;
1164 }
1165 return NIL_RTVFSOBJ;
1166}
1167
1168
1169
1170RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1171{
1172 RTVFSOBJINTERNAL *pThis = hVfsObj;
1173 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1174 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1175
1176 RTVfsLockAcquireRead(pThis->hLock);
1177 int rc = pThis->pOps->pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
1178 RTVfsLockReleaseRead(pThis->hLock);
1179 return rc;
1180}
1181
1182
1183
1184/*
1185 *
1186 * U T I L U T I L U T I L
1187 * U T I L U T I L U T I L
1188 * U T I L U T I L U T I L
1189 *
1190 */
1191
1192
1193RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
1194{
1195 AssertReturn(*pszPath != '/' && *pszPath != '\\', VERR_INTERNAL_ERROR_4);
1196
1197 /* In case *piRestartComp was set higher than the number of components
1198 before making the call to this function. */
1199 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1200 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1201
1202 /*
1203 * Append a slash to the destination path if necessary.
1204 */
1205 char * const pszDst = pPath->szPath;
1206 size_t offDst = pPath->cch;
1207 if (pPath->cComponents > 0)
1208 {
1209 pszDst[offDst++] = '/';
1210 if (offDst >= RTVFSPARSEDPATH_MAX)
1211 return VERR_FILENAME_TOO_LONG;
1212 }
1213 if (pPath->fAbsolute)
1214 Assert(pszDst[offDst - 1] == '/' && pszDst[0] == '/');
1215 else
1216 Assert(offDst == 0 || (pszDst[0] != '/' && pszDst[offDst - 1] == '/'));
1217
1218 /*
1219 * Parse and append the relative path.
1220 */
1221 const char *pszSrc = pszPath;
1222 pPath->fDirSlash = false;
1223 for (;;)
1224 {
1225 /* Copy until we encounter the next slash. */
1226 pPath->aoffComponents[pPath->cComponents++] = (uint16_t)offDst;
1227 for (;;)
1228 {
1229 char ch = *pszSrc++;
1230 if ( ch != '/'
1231 && ch != '\\'
1232 && ch != '\0')
1233 {
1234 pszDst[offDst++] = ch;
1235 if (offDst < RTVFSPARSEDPATH_MAX)
1236 { /* likely */ }
1237 else
1238 return VERR_FILENAME_TOO_LONG;
1239 }
1240 else
1241 {
1242 /* Deal with dot components before we processes the slash/end. */
1243 if (pszDst[offDst - 1] == '.')
1244 {
1245 if ( offDst == 1
1246 || pszDst[offDst - 2] == '/')
1247 {
1248 pPath->cComponents--;
1249 offDst = pPath->aoffComponents[pPath->cComponents];
1250 }
1251 else if ( offDst > 3
1252 && pszDst[offDst - 2] == '.'
1253 && pszDst[offDst - 3] == '/')
1254 {
1255 if ( pPath->fAbsolute
1256 || offDst < 5
1257 || pszDst[offDst - 4] != '.'
1258 || pszDst[offDst - 5] != '.'
1259 || (offDst >= 6 && pszDst[offDst - 6] != '/') )
1260 {
1261 pPath->cComponents -= pPath->cComponents > 1 ? 2 : 1;
1262 offDst = pPath->aoffComponents[pPath->cComponents];
1263 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1264 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1265 }
1266 }
1267 }
1268
1269 if (ch != '\0')
1270 {
1271 /* Skip unnecessary slashes and check for end of path. */
1272 while ((ch = *pszSrc) == '/' || ch == '\\')
1273 pszSrc++;
1274
1275 if (ch == '\0')
1276 pPath->fDirSlash = true;
1277 }
1278
1279 if (ch == '\0')
1280 {
1281 /* Drop trailing slash unless it's the root slash. */
1282 if ( offDst > 0
1283 && pszDst[offDst - 1] == '/'
1284 && ( !pPath->fAbsolute
1285 || offDst > 1))
1286 offDst--;
1287
1288 /* Terminate the string and enter its length. */
1289 pszDst[offDst] = '\0';
1290 pszDst[offDst + 1] = '\0'; /* for aoffComponents[pPath->cComponents] */
1291 pPath->cch = (uint16_t)offDst;
1292 pPath->aoffComponents[pPath->cComponents] = (uint16_t)(offDst + 1);
1293 return VINF_SUCCESS;
1294 }
1295
1296 /* Append component separator before continuing with the next component. */
1297 if (offDst > 0 && pszDst[offDst - 1] != '/')
1298 pszDst[offDst++] = '/';
1299 if (offDst >= RTVFSPARSEDPATH_MAX)
1300 return VERR_FILENAME_TOO_LONG;
1301 break;
1302 }
1303 }
1304 }
1305}
1306
1307
1308/** @todo Replace RTVfsParsePath with RTPathParse and friends? */
1309RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
1310{
1311 if (*pszPath != '/')
1312 {
1313 if (pszCwd)
1314 {
1315 /*
1316 * Relative with a CWD.
1317 */
1318 int rc = RTVfsParsePath(pPath, pszCwd, NULL /*crash if pszCwd is not absolute*/);
1319 if (RT_FAILURE(rc))
1320 return rc;
1321 }
1322 else
1323 {
1324 /*
1325 * Relative.
1326 */
1327 pPath->cch = 0;
1328 pPath->cComponents = 0;
1329 pPath->fDirSlash = false;
1330 pPath->fAbsolute = false;
1331 pPath->aoffComponents[0] = 0;
1332 pPath->aoffComponents[1] = 1;
1333 pPath->szPath[0] = '\0';
1334 pPath->szPath[1] = '\0';
1335 }
1336 }
1337 else
1338 {
1339 /*
1340 * Make pszPath relative, i.e. set up pPath for the root and skip
1341 * leading slashes in pszPath before appending it.
1342 */
1343 pPath->cch = 1;
1344 pPath->cComponents = 0;
1345 pPath->fDirSlash = false;
1346 pPath->fAbsolute = true;
1347 pPath->aoffComponents[0] = 1;
1348 pPath->aoffComponents[1] = 2;
1349 pPath->szPath[0] = '/';
1350 pPath->szPath[1] = '\0';
1351 pPath->szPath[2] = '\0';
1352 while (pszPath[0] == '/')
1353 pszPath++;
1354 if (!pszPath[0])
1355 return VINF_SUCCESS;
1356 }
1357 return RTVfsParsePathAppend(pPath, pszPath, NULL);
1358}
1359
1360
1361
1362RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath)
1363{
1364 /*
1365 * Allocate the output buffer and hand the problem to rtVfsParsePath.
1366 */
1367 int rc;
1368 PRTVFSPARSEDPATH pPath = (PRTVFSPARSEDPATH)RTMemTmpAlloc(sizeof(RTVFSPARSEDPATH));
1369 if (pPath)
1370 {
1371 rc = RTVfsParsePath(pPath, pszPath, pszCwd);
1372 if (RT_FAILURE(rc))
1373 {
1374 RTMemTmpFree(pPath);
1375 pPath = NULL;
1376 }
1377 }
1378 else
1379 rc = VERR_NO_TMP_MEMORY;
1380 *ppPath = pPath; /* always set it */
1381 return rc;
1382}
1383
1384
1385RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath)
1386{
1387 if (pPath)
1388 {
1389 pPath->cch = UINT16_MAX;
1390 pPath->cComponents = UINT16_MAX;
1391 pPath->aoffComponents[0] = UINT16_MAX;
1392 pPath->aoffComponents[1] = UINT16_MAX;
1393 RTMemTmpFree(pPath);
1394 }
1395}
1396
1397
1398/**
1399 * Handles a symbolic link, adding it to
1400 *
1401 * @returns IPRT status code.
1402 * @param pPath The parsed path to update.
1403 * @param piComponent The component iterator to update.
1404 * @param hSymlink The symbolic link to process.
1405 */
1406static int rtVfsTraverseHandleSymlink(PRTVFSPARSEDPATH pPath, uint16_t *piComponent, RTVFSSYMLINK hSymlink)
1407{
1408 /*
1409 * Read the link.
1410 */
1411 char szPath[RTPATH_MAX];
1412 int rc = RTVfsSymlinkRead(hSymlink, szPath, sizeof(szPath) - 1);
1413 if (RT_SUCCESS(rc))
1414 {
1415 szPath[sizeof(szPath) - 1] = '\0';
1416 if (szPath[0] == '/')
1417 {
1418 /*
1419 * Absolute symlink.
1420 */
1421 rc = RTVfsParsePath(pPath, szPath, NULL);
1422 if (RT_SUCCESS(rc))
1423 {
1424 *piComponent = 0;
1425 return VINF_SUCCESS;
1426 }
1427 }
1428 else
1429 {
1430 /*
1431 * Relative symlink, must replace the current component with the
1432 * link value. We do that by using the remainder of the symlink
1433 * buffer as temporary storage.
1434 */
1435 uint16_t iComponent = *piComponent;
1436 if (iComponent + 1 < pPath->cComponents)
1437 rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iComponent + 1]]);
1438 if (RT_SUCCESS(rc))
1439 {
1440 pPath->cch = pPath->aoffComponents[iComponent] - (iComponent > 0);
1441 pPath->aoffComponents[iComponent + 1] = pPath->cch + 1;
1442 pPath->szPath[pPath->cch] = '\0';
1443 pPath->szPath[pPath->cch + 1] = '\0';
1444
1445 rc = RTVfsParsePathAppend(pPath, szPath, &iComponent);
1446 if (RT_SUCCESS(rc))
1447 {
1448 *piComponent = iComponent;
1449 return VINF_SUCCESS;
1450 }
1451 }
1452 }
1453 }
1454 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
1455}
1456
1457
1458/**
1459 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1460 *
1461 * @returns IPRT status code.
1462 * @param pThis The VFS.
1463 * @param pPath The parsed path. This may be changed as symbolic
1464 * links are processed during the path traversal.
1465 * @param fFlags RTPATH_F_XXX.
1466 * @param ppVfsParentDir Where to return the parent directory handle
1467 * (referenced).
1468 */
1469static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags,
1470 RTVFSDIRINTERNAL **ppVfsParentDir)
1471{
1472 /*
1473 * Assert sanity.
1474 */
1475 AssertPtr(pThis);
1476 Assert(pThis->uMagic == RTVFSDIR_MAGIC);
1477 Assert(pThis->Base.cRefs > 0);
1478 AssertPtr(pPath);
1479 AssertPtr(ppVfsParentDir);
1480 *ppVfsParentDir = NULL;
1481 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1482 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1483
1484 /*
1485 * Start with the pThis directory.
1486 */
1487 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1488 return VERR_INVALID_HANDLE;
1489 RTVFSDIRINTERNAL *pCurDir = pThis;
1490
1491 /*
1492 * The traversal loop.
1493 */
1494 int rc = VINF_SUCCESS;
1495 unsigned cLinks = 0;
1496 uint16_t iComponent = 0;
1497 for (;;)
1498 {
1499 /*
1500 * Are we done yet?
1501 */
1502 bool fFinal = iComponent + 1 >= pPath->cComponents;
1503 if (fFinal && (fFlags & RTPATH_F_ON_LINK))
1504 {
1505 *ppVfsParentDir = pCurDir;
1506 return VINF_SUCCESS;
1507 }
1508
1509 /*
1510 * Try open the next entry.
1511 */
1512 const char *pszEntry = &pPath->szPath[pPath->aoffComponents[iComponent]];
1513 char *pszEntryEnd = &pPath->szPath[pPath->aoffComponents[iComponent + 1] - 1];
1514 *pszEntryEnd = '\0';
1515 RTVFSDIR hDir = NIL_RTVFSDIR;
1516 RTVFSSYMLINK hSymlink = NIL_RTVFSSYMLINK;
1517 RTVFS hVfsMnt = NIL_RTVFS;
1518 if (fFinal)
1519 {
1520 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1521 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, NULL, &hSymlink, NULL);
1522 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1523 *pszEntryEnd = '\0';
1524 if ( rc == VERR_PATH_NOT_FOUND
1525 || rc == VERR_FILE_NOT_FOUND
1526 || rc == VERR_NOT_A_DIRECTORY
1527 || rc == VERR_NOT_SYMLINK)
1528 rc = VINF_SUCCESS;
1529 if (RT_FAILURE(rc))
1530 break;
1531
1532 if (hSymlink == NIL_RTVFSSYMLINK)
1533 {
1534 *ppVfsParentDir = pCurDir;
1535 return VINF_SUCCESS;
1536 }
1537 }
1538 else
1539 {
1540 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1541 rc = pCurDir->pOps->pfnTraversalOpen(pCurDir->Base.pvThis, pszEntry, &hDir, &hSymlink, &hVfsMnt);
1542 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1543 *pszEntryEnd = '/';
1544 if (RT_FAILURE(rc))
1545 break;
1546
1547 if ( hDir == NIL_RTVFSDIR
1548 && hSymlink == NIL_RTVFSSYMLINK
1549 && hVfsMnt == NIL_RTVFS)
1550 {
1551 rc = VERR_NOT_A_DIRECTORY;
1552 break;
1553 }
1554 }
1555 Assert( (hDir != NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1556 || (hDir == NIL_RTVFSDIR && hSymlink != NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1557 || (hDir == NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt != NIL_RTVFS));
1558
1559 if (hDir != NIL_RTVFSDIR)
1560 {
1561 /*
1562 * Directory - advance down the path.
1563 */
1564 AssertPtr(hDir);
1565 Assert(hDir->uMagic == RTVFSDIR_MAGIC);
1566 RTVfsDirRelease(pCurDir);
1567 pCurDir = hDir;
1568 iComponent++;
1569 }
1570 else if (hSymlink != NIL_RTVFSSYMLINK)
1571 {
1572 /*
1573 * Symbolic link - deal with it and retry the current component.
1574 */
1575 AssertPtr(hSymlink);
1576 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
1577 if (fFlags & RTPATH_F_NO_SYMLINKS)
1578 {
1579 rc = VERR_SYMLINK_NOT_ALLOWED;
1580 break;
1581 }
1582 cLinks++;
1583 if (cLinks >= RTVFS_MAX_LINKS)
1584 {
1585 rc = VERR_TOO_MANY_SYMLINKS;
1586 break;
1587 }
1588 uint16_t iRestartComp = iComponent;
1589 rc = rtVfsTraverseHandleSymlink(pPath, &iRestartComp, hSymlink);
1590 if (RT_FAILURE(rc))
1591 break;
1592 if (iRestartComp != iComponent)
1593 {
1594 /* Must restart from the root. */
1595 RTVfsDirRelease(pCurDir);
1596 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1597 {
1598 rc = VERR_INVALID_HANDLE;
1599 pCurDir = NULL;
1600 break;
1601 }
1602 pCurDir = pThis;
1603 iComponent = 0;
1604 }
1605 }
1606 else
1607 {
1608 /*
1609 * Mount point - deal with it and retry the current component.
1610 */
1611 RTVfsDirRelease(pCurDir);
1612 RTVfsLockAcquireRead(hVfsMnt->Base.hLock);
1613 rc = hVfsMnt->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
1614 RTVfsLockReleaseRead(hVfsMnt->Base.hLock);
1615 if (RT_FAILURE(rc))
1616 {
1617 pCurDir = NULL;
1618 break;
1619 }
1620 iComponent = 0;
1621 /** @todo union mounts. */
1622 }
1623 }
1624
1625 if (pCurDir)
1626 RTVfsDirRelease(pCurDir);
1627
1628 return rc;
1629}
1630
1631
1632/**
1633 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1634 *
1635 * @returns IPRT status code.
1636 * @param pThis The VFS.
1637 * @param pPath The parsed path. This may be changed as symbolic
1638 * links are processed during the path traversal.
1639 * @param fFlags RTPATH_F_XXX.
1640 * @param ppVfsParentDir Where to return the parent directory handle
1641 * (referenced).
1642 */
1643static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir)
1644{
1645 /*
1646 * Assert sanity.
1647 */
1648 AssertPtr(pThis);
1649 Assert(pThis->uMagic == RTVFS_MAGIC);
1650 Assert(pThis->Base.cRefs > 0);
1651 AssertPtr(pPath);
1652 AssertPtr(ppVfsParentDir);
1653 *ppVfsParentDir = NULL;
1654 AssertReturn(pPath->cComponents > 0, VERR_INTERNAL_ERROR_3);
1655 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1656
1657 /*
1658 * Open the root directory and join paths with the directory traversal.
1659 */
1660 /** @todo Union mounts, traversal optimization methods, races, ++ */
1661 RTVFSDIRINTERNAL *pRootDir;
1662 RTVfsLockAcquireRead(pThis->Base.hLock);
1663 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pRootDir);
1664 RTVfsLockReleaseRead(pThis->Base.hLock);
1665 if (RT_SUCCESS(rc))
1666 {
1667 rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFlags, ppVfsParentDir);
1668 RTVfsDirRelease(pRootDir);
1669 }
1670 return rc;
1671}
1672
1673
1674RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
1675{
1676 NOREF(fEvents);
1677 int rc;
1678 if (fIntr)
1679 rc = RTThreadSleep(cMillies);
1680 else
1681 {
1682 uint64_t uMsStart = RTTimeMilliTS();
1683 do
1684 rc = RTThreadSleep(cMillies);
1685 while ( rc == VERR_INTERRUPTED
1686 && !fIntr
1687 && RTTimeMilliTS() - uMsStart < cMillies);
1688 if (rc == VERR_INTERRUPTED)
1689 rc = VERR_TIMEOUT;
1690 }
1691
1692 *pfRetEvents = 0;
1693 return rc;
1694}
1695
1696
1697RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
1698{
1699 /*
1700 * Allocate a temporary buffer.
1701 */
1702 size_t cbBuf = cbBufHint;
1703 if (!cbBuf)
1704 cbBuf = _64K;
1705 else if (cbBuf < _4K)
1706 cbBuf = _4K;
1707 else if (cbBuf > _1M)
1708 cbBuf = _1M;
1709
1710 void *pvBuf = RTMemTmpAlloc(cbBuf);
1711 if (!pvBuf)
1712 {
1713 cbBuf = _4K;
1714 pvBuf = RTMemTmpAlloc(cbBuf);
1715 if (!pvBuf)
1716 return VERR_NO_TMP_MEMORY;
1717 }
1718
1719 /*
1720 * Pump loop.
1721 */
1722 int rc;
1723 for (;;)
1724 {
1725 size_t cbRead;
1726 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
1727 if (RT_FAILURE(rc))
1728 break;
1729 if (rc == VINF_EOF && cbRead == 0)
1730 break;
1731
1732 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
1733 if (RT_FAILURE(rc))
1734 break;
1735 }
1736
1737 RTMemTmpFree(pvBuf);
1738
1739 /*
1740 * Flush the destination stream on success to make sure we've caught
1741 * errors caused by buffering delays.
1742 */
1743 if (RT_SUCCESS(rc))
1744 rc = RTVfsIoStrmFlush(hVfsIosDst);
1745
1746 return rc;
1747}
1748
1749
1750
1751
1752
1753/*
1754 * F I L E S Y S T E M R O O T
1755 * F I L E S Y S T E M R O O T
1756 * F I L E S Y S T E M R O O T
1757 */
1758
1759
1760RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
1761 PRTVFS phVfs, void **ppvInstance)
1762{
1763 /*
1764 * Validate the input, be extra strict in strict builds.
1765 */
1766 AssertPtr(pVfsOps);
1767 AssertReturn(pVfsOps->uVersion == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
1768 AssertReturn(pVfsOps->uEndMarker == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
1769 RTVFSOBJ_ASSERT_OPS(&pVfsOps->Obj, RTVFSOBJTYPE_VFS);
1770 Assert(cbInstance > 0);
1771 AssertPtr(ppvInstance);
1772 AssertPtr(phVfs);
1773
1774 /*
1775 * Allocate the handle + instance data.
1776 */
1777 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSINTERNAL), RTVFS_INST_ALIGNMENT)
1778 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1779 RTVFSINTERNAL *pThis = (RTVFSINTERNAL *)RTMemAllocZ(cbThis);
1780 if (!pThis)
1781 return VERR_NO_MEMORY;
1782
1783 int rc = rtVfsObjInitNewObject(&pThis->Base, &pVfsOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
1784 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1785 if (RT_FAILURE(rc))
1786 {
1787 RTMemFree(pThis);
1788 return rc;
1789 }
1790
1791 pThis->uMagic = RTVFS_MAGIC;
1792 pThis->pOps = pVfsOps;
1793
1794 *phVfs = pThis;
1795 *ppvInstance = pThis->Base.pvThis;
1796
1797 LogFlow(("RTVfsNew -> VINF_SUCCESS; hVfs=%p pvThis=%p\n", pThis, pThis->Base.pvThis));
1798 return VINF_SUCCESS;
1799}
1800
1801#ifdef DEBUG
1802# undef RTVfsRetain
1803#endif
1804RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs)
1805{
1806 RTVFSINTERNAL *pThis = hVfs;
1807 AssertPtrReturn(pThis, UINT32_MAX);
1808 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1809 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
1810 LogFlow(("RTVfsRetain(%p/%p) -> %d\n", pThis, pThis->Base.pvThis, cRefs));
1811 return cRefs;
1812}
1813#ifdef DEBUG
1814# define RTVfsRetain(hVfs) RTVfsRetainDebug(hVfs, RT_SRC_POS)
1815#endif
1816
1817
1818RTDECL(uint32_t) RTVfsRetainDebug(RTVFS hVfs, RT_SRC_POS_DECL)
1819{
1820 RTVFSINTERNAL *pThis = hVfs;
1821 AssertPtrReturn(pThis, UINT32_MAX);
1822 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1823 RT_SRC_POS_NOREF();
1824 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsRetainDebug", RT_SRC_POS_ARGS);
1825}
1826
1827
1828RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs)
1829{
1830 RTVFSINTERNAL *pThis = hVfs;
1831 if (pThis == NIL_RTVFS)
1832 return 0;
1833 AssertPtrReturn(pThis, UINT32_MAX);
1834 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
1835#ifdef LOG_ENABLED
1836 void *pvThis = pThis->Base.pvThis;
1837#endif
1838 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
1839 Log(("RTVfsRelease(%p/%p) -> %d\n", pThis, pvThis, cRefs));
1840 return cRefs;
1841}
1842
1843
1844RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir)
1845{
1846 RTVFSINTERNAL *pThis = hVfs;
1847 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1848 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1849 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
1850 *phDir = NIL_RTVFSDIR;
1851
1852 if (!pThis->pOps->pfnIsRangeInUse)
1853 return VERR_NOT_SUPPORTED;
1854 RTVfsLockAcquireRead(pThis->Base.hLock);
1855 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phDir);
1856 RTVfsLockReleaseRead(pThis->Base.hLock);
1857
1858 return rc;
1859}
1860
1861
1862RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
1863{
1864 RTVFSINTERNAL *pThis = hVfs;
1865 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1866 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1867 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1868 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
1869 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
1870 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
1871 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
1872
1873 /*
1874 * Parse the path, assume current directory is root since we've got no
1875 * caller context here. Then traverse to the parent directory.
1876 */
1877 PRTVFSPARSEDPATH pPath;
1878 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
1879 if (RT_SUCCESS(rc))
1880 {
1881 RTVFSDIRINTERNAL *pVfsParentDir;
1882 if (pPath->cComponents > 0)
1883 {
1884 rc = rtVfsTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
1885 if (RT_SUCCESS(rc))
1886 {
1887 /*
1888 * Call the query method on the parent directory.
1889 */
1890 /** @todo race condition here :/ */
1891 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
1892 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
1893 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
1894 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
1895
1896 RTVfsDirRelease(pVfsParentDir);
1897 }
1898 }
1899 /*
1900 * The path boils down to '.', open the root dir and query its info.
1901 */
1902 else
1903 {
1904 RTVfsLockAcquireRead(pThis->Base.hLock);
1905 RTVFSDIR hRootDir = NIL_RTVFSDIR;
1906 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &hRootDir);
1907 RTVfsLockReleaseRead(pThis->Base.hLock);
1908 if (RT_SUCCESS(rc))
1909 {
1910 RTVfsLockAcquireRead(hRootDir->Base.hLock);
1911 rc = hRootDir->Base.pOps->pfnQueryInfo(hRootDir->Base.pvThis, pObjInfo, enmAddAttr);
1912 RTVfsLockReleaseRead(hRootDir->Base.hLock);
1913 RTVfsDirRelease(hRootDir);
1914 }
1915 }
1916
1917 RTVfsParsePathFree(pPath);
1918 }
1919 return rc;
1920}
1921
1922
1923
1924RTDECL(int) RTVfsIsRangeInUse(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed)
1925{
1926 RTVFSINTERNAL *pThis = hVfs;
1927 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1928 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1929
1930 if (!pThis->pOps->pfnIsRangeInUse)
1931 return VERR_NOT_SUPPORTED;
1932 RTVfsLockAcquireRead(pThis->Base.hLock);
1933 int rc = pThis->pOps->pfnIsRangeInUse(pThis->Base.pvThis, off, cb, pfUsed);
1934 RTVfsLockReleaseRead(pThis->Base.hLock);
1935
1936 return rc;
1937}
1938
1939
1940
1941
1942/*
1943 *
1944 * F I L E S Y S T E M S T R E A M
1945 * F I L E S Y S T E M S T R E A M
1946 * F I L E S Y S T E M S T R E A M
1947 *
1948 */
1949
1950
1951RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, bool fReadOnly,
1952 PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
1953{
1954 /*
1955 * Validate the input, be extra strict in strict builds.
1956 */
1957 AssertPtr(pFsStreamOps);
1958 AssertReturn(pFsStreamOps->uVersion == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1959 AssertReturn(pFsStreamOps->uEndMarker == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
1960 Assert(!pFsStreamOps->fReserved);
1961 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
1962 if (fReadOnly)
1963 AssertPtr(pFsStreamOps->pfnNext);
1964 else
1965 {
1966 AssertPtr(pFsStreamOps->pfnAdd);
1967 AssertPtr(pFsStreamOps->pfnEnd);
1968 }
1969 Assert(cbInstance > 0);
1970 AssertPtr(ppvInstance);
1971 AssertPtr(phVfsFss);
1972 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
1973
1974 /*
1975 * Allocate the handle + instance data.
1976 */
1977 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFSSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
1978 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
1979 RTVFSFSSTREAMINTERNAL *pThis = (RTVFSFSSTREAMINTERNAL *)RTMemAllocZ(cbThis);
1980 if (!pThis)
1981 return VERR_NO_MEMORY;
1982
1983 int rc = rtVfsObjInitNewObject(&pThis->Base, &pFsStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
1984 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
1985
1986 if (RT_FAILURE(rc))
1987 {
1988 RTMemFree(pThis);
1989 return rc;
1990 }
1991
1992 pThis->uMagic = RTVFSFSSTREAM_MAGIC;
1993 pThis->fFlags = fReadOnly
1994 ? RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE
1995 : RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL;
1996 pThis->pOps = pFsStreamOps;
1997
1998 *phVfsFss = pThis;
1999 *ppvInstance = pThis->Base.pvThis;
2000 return VINF_SUCCESS;
2001}
2002
2003
2004#ifdef DEBUG
2005# undef RTVfsFsStrmRetain
2006#endif
2007RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss)
2008{
2009 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2010 AssertPtrReturn(pThis, UINT32_MAX);
2011 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2012 return rtVfsObjRetain(&pThis->Base);
2013}
2014#ifdef DEBUG
2015# define RTVfsFsStrmRetain(hVfsFss) RTVfsFsStrmRetainDebug(hVfsFss, RT_SRC_POS)
2016#endif
2017
2018
2019RTDECL(uint32_t) RTVfsFsStrmRetainDebug(RTVFSFSSTREAM hVfsFss, RT_SRC_POS_DECL)
2020{
2021 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2022 AssertPtrReturn(pThis, UINT32_MAX);
2023 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2024 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsFsStrmRetain", RT_SRC_POS_ARGS);
2025}
2026
2027
2028RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss)
2029{
2030 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2031 if (pThis == NIL_RTVFSFSSTREAM)
2032 return 0;
2033 AssertPtrReturn(pThis, UINT32_MAX);
2034 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2035 return rtVfsObjRelease(&pThis->Base);
2036}
2037
2038
2039RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2040{
2041 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2042 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2043 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2044 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2045}
2046
2047
2048RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
2049{
2050 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2051 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2052 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2053 AssertPtrNullReturn(ppszName, VERR_INVALID_POINTER);
2054 if (ppszName)
2055 *ppszName = NULL;
2056 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2057 if (penmType)
2058 *penmType = RTVFSOBJTYPE_INVALID;
2059 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2060 if (phVfsObj)
2061 *phVfsObj = NIL_RTVFSOBJ;
2062
2063 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_INVALID_FUNCTION);
2064
2065 return pThis->pOps->pfnNext(pThis->Base.pvThis, ppszName, penmType, phVfsObj);
2066}
2067
2068
2069RTDECL(int) RTVfsFsStrmAdd(RTVFSFSSTREAM hVfsFss, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)
2070{
2071 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2072 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2073 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2074 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2075 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2076 AssertPtrReturn(hVfsObj, VERR_INVALID_HANDLE);
2077 AssertReturn(hVfsObj->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
2078 AssertReturn(!(fFlags & ~RTVFSFSSTRM_ADD_F_VALID_MASK), VERR_INVALID_FLAGS);
2079 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2080
2081 return pThis->pOps->pfnAdd(pThis->Base.pvThis, pszPath, hVfsObj, fFlags);
2082}
2083
2084
2085RTDECL(int) RTVfsFsStrmPushFile(RTVFSFSSTREAM hVfsFss, const char *pszPath, uint64_t cbFile,
2086 PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
2087{
2088 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2089 AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
2090 *phVfsIos = NIL_RTVFSIOSTREAM;
2091
2092 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2093 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2094
2095 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2096 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2097
2098 AssertReturn(!(fFlags & ~RTVFSFSSTRM_PUSH_F_VALID_MASK), VERR_INVALID_FLAGS);
2099 AssertReturn(RT_BOOL(cbFile == UINT64_MAX) == RT_BOOL(fFlags & RTVFSFSSTRM_PUSH_F_STREAM), VERR_INVALID_FLAGS);
2100
2101 if (cObjInfo)
2102 {
2103 AssertPtrReturn(paObjInfo, VERR_INVALID_POINTER);
2104 AssertReturn(paObjInfo[0].Attr.enmAdditional == RTFSOBJATTRADD_UNIX, VERR_INVALID_PARAMETER);
2105 }
2106
2107 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2108 if (pThis->pOps->pfnPushFile)
2109 return pThis->pOps->pfnPushFile(pThis->Base.pvThis, pszPath, cbFile, paObjInfo, cObjInfo, fFlags, phVfsIos);
2110 return VERR_NOT_SUPPORTED;
2111}
2112
2113
2114RTDECL(int) RTVfsFsStrmEnd(RTVFSFSSTREAM hVfsFss)
2115{
2116 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2117 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2118 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2119
2120 return pThis->pOps->pfnEnd(pThis->Base.pvThis);
2121}
2122
2123
2124RTDECL(void *) RTVfsFsStreamToPrivate(RTVFSFSSTREAM hVfsFss, PCRTVFSFSSTREAMOPS pFsStreamOps)
2125{
2126 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2127 AssertPtrReturn(pThis, NULL);
2128 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, NULL);
2129 if (pThis->pOps != pFsStreamOps)
2130 return NULL;
2131 return pThis->Base.pvThis;
2132}
2133
2134
2135/*
2136 *
2137 * D I R D I R D I R
2138 * D I R D I R D I R
2139 * D I R D I R D I R
2140 *
2141 */
2142
2143
2144RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock,
2145 PRTVFSDIR phVfsDir, void **ppvInstance)
2146{
2147 /*
2148 * Validate the input, be extra strict in strict builds.
2149 */
2150 AssertPtr(pDirOps);
2151 AssertReturn(pDirOps->uVersion == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2152 AssertReturn(pDirOps->uEndMarker == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2153 Assert(!pDirOps->fReserved);
2154 RTVFSDIR_ASSERT_OPS(pDirOps, RTVFSOBJTYPE_DIR);
2155 Assert(cbInstance > 0);
2156 AssertReturn(!(fFlags & ~RTVFSDIR_F_NO_VFS_REF), VERR_INVALID_FLAGS);
2157 AssertPtr(ppvInstance);
2158 AssertPtr(phVfsDir);
2159 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2160
2161 /*
2162 * Allocate the handle + instance data.
2163 */
2164 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSDIRINTERNAL), RTVFS_INST_ALIGNMENT)
2165 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2166 RTVFSDIRINTERNAL *pThis = (RTVFSDIRINTERNAL *)RTMemAllocZ(cbThis);
2167 if (!pThis)
2168 return VERR_NO_MEMORY;
2169
2170 int rc = rtVfsObjInitNewObject(&pThis->Base, &pDirOps->Obj, hVfs, RT_BOOL(fFlags & RTVFSDIR_F_NO_VFS_REF), hLock,
2171 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2172 if (RT_FAILURE(rc))
2173 {
2174 RTMemFree(pThis);
2175 return rc;
2176 }
2177
2178 pThis->uMagic = RTVFSDIR_MAGIC;
2179 pThis->fReserved = 0;
2180 pThis->pOps = pDirOps;
2181
2182 *phVfsDir = pThis;
2183 *ppvInstance = pThis->Base.pvThis;
2184 return VINF_SUCCESS;
2185}
2186
2187
2188#ifdef DEBUG
2189# undef RTVfsDirRetain
2190#endif
2191RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir)
2192{
2193 RTVFSDIRINTERNAL *pThis = hVfsDir;
2194 AssertPtrReturn(pThis, UINT32_MAX);
2195 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2196 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2197 LogFlow(("RTVfsDirRetain(%p/%p) -> %#x\n", pThis, pThis->Base.pvThis, cRefs));
2198 return cRefs;
2199}
2200#ifdef DEBUG
2201# define RTVfsDirRetain(hVfsDir) RTVfsDirRetainDebug(hVfsDir, RT_SRC_POS)
2202#endif
2203
2204
2205RTDECL(uint32_t) RTVfsDirRetainDebug(RTVFSDIR hVfsDir, RT_SRC_POS_DECL)
2206{
2207 RTVFSDIRINTERNAL *pThis = hVfsDir;
2208 AssertPtrReturn(pThis, UINT32_MAX);
2209 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2210 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsDirRetain", RT_SRC_POS_ARGS);
2211}
2212
2213
2214RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir)
2215{
2216 RTVFSDIRINTERNAL *pThis = hVfsDir;
2217 if (pThis == NIL_RTVFSDIR)
2218 return 0;
2219 AssertPtrReturn(pThis, UINT32_MAX);
2220 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2221#ifdef LOG_ENABLED
2222 void *pvThis = pThis->Base.pvThis;
2223#endif
2224 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2225 LogFlow(("RTVfsDirRelease(%p/%p) -> %#x\n", pThis, pvThis, cRefs));
2226 return cRefs;
2227}
2228
2229
2230RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2231{
2232 /*
2233 * Validate input.
2234 */
2235 RTVFSINTERNAL *pThis = hVfs;
2236 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2237 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2238 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2239 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2240 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2241
2242 /*
2243 * Parse the path, assume current directory is root since we've got no
2244 * caller context here.
2245 */
2246 PRTVFSPARSEDPATH pPath;
2247 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2248 if (RT_SUCCESS(rc))
2249 {
2250 if (pPath->cComponents > 0)
2251 {
2252 /*
2253 * Tranverse the path, resolving the parent node and any symlinks
2254 * in the final element, and ask the directory to open the subdir.
2255 */
2256 RTVFSDIRINTERNAL *pVfsParentDir;
2257 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2258 if (RT_SUCCESS(rc))
2259 {
2260 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2261
2262 /** @todo there is a symlink creation race here. */
2263 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2264 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2265 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2266
2267 RTVfsDirRelease(pVfsParentDir);
2268
2269 if (RT_SUCCESS(rc))
2270 {
2271 AssertPtr(*phVfsDir);
2272 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2273 }
2274 }
2275 }
2276 /*
2277 * If the path boils down to '.' return the root directory.
2278 */
2279 else
2280 {
2281 RTVfsLockAcquireRead(pThis->Base.hLock);
2282 rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phVfsDir);
2283 RTVfsLockReleaseRead(pThis->Base.hLock);
2284 }
2285 RTVfsParsePathFree(pPath);
2286 }
2287 return rc;
2288}
2289
2290
2291RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2292{
2293 /*
2294 * Validate input.
2295 */
2296 RTVFSDIRINTERNAL *pThis = hVfsDir;
2297 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2298 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2299 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2300 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2301 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
2302
2303 /*
2304 * Parse the path, it's always relative to the given directory.
2305 */
2306 PRTVFSPARSEDPATH pPath;
2307 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2308 if (RT_SUCCESS(rc))
2309 {
2310 if (pPath->cComponents > 0)
2311 {
2312 /*
2313 * Tranverse the path, resolving the parent node and any symlinks
2314 * in the final element, and ask the directory to open the subdir.
2315 */
2316 RTVFSDIRINTERNAL *pVfsParentDir;
2317 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2318 if (RT_SUCCESS(rc))
2319 {
2320 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2321
2322 /** @todo there is a symlink creation race here. */
2323 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2324 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2325 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2326
2327 RTVfsDirRelease(pVfsParentDir);
2328
2329 if (RT_SUCCESS(rc))
2330 {
2331 AssertPtr(*phVfsDir);
2332 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2333 }
2334 }
2335 }
2336 /*
2337 * The path boils down to '.', call pfnOpenDir on pThis with '.' as input.
2338 * The caller may wish for a new directory instance to enumerate the entries
2339 * in parallel or some such thing.
2340 */
2341 else
2342 {
2343 RTVfsLockAcquireWrite(pThis->Base.hLock);
2344 rc = pThis->pOps->pfnOpenDir(pThis->Base.pvThis, ".", fFlags, phVfsDir);
2345 RTVfsLockReleaseWrite(pThis->Base.hLock);
2346 }
2347 RTVfsParsePathFree(pPath);
2348 }
2349 return rc;
2350}
2351
2352
2353RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir)
2354{
2355 /*
2356 * Validate input.
2357 */
2358 RTVFSDIRINTERNAL *pThis = hVfsDir;
2359 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2360 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2361 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2362 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2363 AssertReturn(!(fFlags & ~RTDIRCREATE_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
2364 fMode = rtFsModeNormalize(fMode, pszRelPath, 0);
2365 AssertReturn(rtFsModeIsValidPermissions(fMode), VERR_INVALID_FMODE);
2366 if (!(fFlags & RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET))
2367 fMode |= RTFS_DOS_NT_NOT_CONTENT_INDEXED;
2368
2369 /*
2370 * Parse the path, it's always relative to the given directory.
2371 */
2372 PRTVFSPARSEDPATH pPath;
2373 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2374 if (RT_SUCCESS(rc))
2375 {
2376 if (pPath->cComponents > 0)
2377 {
2378 /*
2379 * Tranverse the path, resolving the parent node, not checking for symbolic
2380 * links in the final element, and ask the directory to create the subdir.
2381 */
2382 RTVFSDIRINTERNAL *pVfsParentDir;
2383 rc = rtVfsDirTraverseToParent(pThis, pPath,
2384 fFlags & RTDIRCREATE_FLAGS_NO_SYMLINKS
2385 ? RTPATH_F_NO_SYMLINKS | RTPATH_F_ON_LINK : RTPATH_F_FOLLOW_LINK,
2386 &pVfsParentDir);
2387 if (RT_SUCCESS(rc))
2388 {
2389 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2390
2391 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2392 rc = pVfsParentDir->pOps->pfnCreateDir(pVfsParentDir->Base.pvThis, pszEntryName, fMode, phVfsDir);
2393 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2394
2395 RTVfsDirRelease(pVfsParentDir);
2396
2397 if (RT_SUCCESS(rc) && phVfsDir)
2398 {
2399 AssertPtr(*phVfsDir);
2400 Assert((*phVfsDir)->uMagic == RTVFSDIR_MAGIC);
2401 }
2402 }
2403 }
2404 else
2405 rc = VERR_PATH_ZERO_LENGTH;
2406 RTVfsParsePathFree(pPath);
2407 }
2408 return rc;
2409}
2410
2411
2412RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2413{
2414 /*
2415 * Validate input.
2416 */
2417 RTVFSDIRINTERNAL *pThis = hVfsDir;
2418 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2419 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2420 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2421 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2422
2423 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2424 if (RT_FAILURE(rc))
2425 return rc;
2426
2427 /*
2428 * Parse the path, assume current directory is root since we've got no
2429 * caller context here.
2430 */
2431 PRTVFSPARSEDPATH pPath;
2432 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2433 if (RT_SUCCESS(rc))
2434 {
2435 if ( !pPath->fDirSlash
2436 && pPath->cComponents > 0)
2437 {
2438 /*
2439 * Tranverse the path, resolving the parent node and any symlinks
2440 * in the final element, and ask the directory to open the file.
2441 */
2442 RTVFSDIRINTERNAL *pVfsParentDir;
2443 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
2444 if (RT_SUCCESS(rc))
2445 {
2446 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2447
2448 /** @todo there is a symlink creation race here. */
2449 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2450 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2451 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2452
2453 RTVfsDirRelease(pVfsParentDir);
2454
2455 if (RT_SUCCESS(rc))
2456 {
2457 AssertPtr(*phVfsFile);
2458 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
2459 }
2460 }
2461 }
2462 else
2463 rc = VERR_NOT_A_FILE;
2464 RTVfsParsePathFree(pPath);
2465 }
2466 return rc;
2467}
2468
2469
2470RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
2471{
2472 RTVFSFILE hVfsFile;
2473 int rc = RTVfsDirOpenFile(hVfsDir, pszPath, fOpen, &hVfsFile);
2474 if (RT_SUCCESS(rc))
2475 {
2476 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
2477 AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
2478 RTVfsFileRelease(hVfsFile);
2479 }
2480 return rc;
2481}
2482
2483
2484
2485RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo,
2486 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2487{
2488 /*
2489 * Validate input.
2490 */
2491 RTVFSDIRINTERNAL *pThis = hVfsDir;
2492 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2493 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2494 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2495 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2496 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2497 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2498 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2499
2500 /*
2501 * Parse the relative path. Then traverse to the parent directory.
2502 */
2503 PRTVFSPARSEDPATH pPath;
2504 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2505 if (RT_SUCCESS(rc))
2506 {
2507 if (pPath->cComponents > 0)
2508 {
2509 RTVFSDIRINTERNAL *pVfsParentDir;
2510 rc = rtVfsDirTraverseToParent(pThis, pPath, fFlags, &pVfsParentDir);
2511 if (RT_SUCCESS(rc))
2512 {
2513 /*
2514 * Call the query method on the parent directory.
2515 */
2516 /** @todo symlink race condition here :/ */
2517 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2518 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2519 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2520 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2521
2522 RTVfsDirRelease(pVfsParentDir);
2523 }
2524 else
2525 rc = VERR_INVALID_PARAMETER;
2526 }
2527 /*
2528 * The path boils down to '.' so just query the directory.
2529 */
2530 else
2531 {
2532 RTVfsLockAcquireRead(pThis->Base.hLock);
2533 rc = pThis->Base.pOps->pfnQueryInfo(pThis->Base.pvThis, pObjInfo, enmAddAttr);
2534 RTVfsLockReleaseRead(pThis->Base.hLock);
2535 }
2536 RTVfsParsePathFree(pPath);
2537 }
2538 return rc;
2539}
2540
2541
2542RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
2543{
2544 /*
2545 * Validate input.
2546 */
2547 RTVFSDIRINTERNAL *pThis = hVfsDir;
2548 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2549 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2550 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
2551 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2552
2553 size_t cbDirEntry = sizeof(*pDirEntry);
2554 if (!pcbDirEntry)
2555 pcbDirEntry = &cbDirEntry;
2556 else
2557 {
2558 cbDirEntry = *pcbDirEntry;
2559 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
2560 ("Invalid *pcbDirEntry=%d (min %d)\n", *pcbDirEntry, RT_OFFSETOF(RTDIRENTRYEX, szName[2])),
2561 VERR_INVALID_PARAMETER);
2562 }
2563
2564 /*
2565 * Call the directory method.
2566 */
2567 RTVfsLockAcquireRead(pThis->Base.hLock);
2568 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
2569 RTVfsLockReleaseRead(pThis->Base.hLock);
2570 return rc;
2571}
2572
2573
2574/*
2575 *
2576 * S Y M B O L I C L I N K
2577 * S Y M B O L I C L I N K
2578 * S Y M B O L I C L I N K
2579 *
2580 */
2581
2582RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
2583 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
2584{
2585 /*
2586 * Validate the input, be extra strict in strict builds.
2587 */
2588 AssertPtr(pSymlinkOps);
2589 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
2590 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
2591 Assert(!pSymlinkOps->fReserved);
2592 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
2593 Assert(cbInstance > 0);
2594 AssertPtr(ppvInstance);
2595 AssertPtr(phVfsSym);
2596 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2597
2598 /*
2599 * Allocate the handle + instance data.
2600 */
2601 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
2602 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2603 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
2604 if (!pThis)
2605 return VERR_NO_MEMORY;
2606
2607 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2608 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2609 if (RT_FAILURE(rc))
2610 {
2611 RTMemFree(pThis);
2612 return rc;
2613 }
2614
2615 pThis->uMagic = RTVFSSYMLINK_MAGIC;
2616 pThis->pOps = pSymlinkOps;
2617
2618 *phVfsSym = pThis;
2619 *ppvInstance = pThis->Base.pvThis;
2620 return VINF_SUCCESS;
2621}
2622
2623
2624RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
2625{
2626 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2627 AssertPtrReturn(pThis, UINT32_MAX);
2628 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2629 return rtVfsObjRetain(&pThis->Base);
2630}
2631
2632
2633RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL)
2634{
2635 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2636 AssertPtrReturn(pThis, UINT32_MAX);
2637 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2638 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsSymlinkRetainDebug", RT_SRC_POS_ARGS);
2639}
2640
2641
2642RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
2643{
2644 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2645 if (pThis == NIL_RTVFSSYMLINK)
2646 return 0;
2647 AssertPtrReturn(pThis, UINT32_MAX);
2648 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
2649 return rtVfsObjRelease(&pThis->Base);
2650}
2651
2652
2653RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2654{
2655 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2656 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2657 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2658 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2659}
2660
2661
2662RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
2663{
2664 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2665 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2666 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2667
2668 fMode = rtFsModeNormalize(fMode, NULL, 0);
2669 if (!rtFsModeIsValid(fMode))
2670 return VERR_INVALID_PARAMETER;
2671
2672 RTVfsLockAcquireWrite(pThis->Base.hLock);
2673 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
2674 RTVfsLockReleaseWrite(pThis->Base.hLock);
2675 return rc;
2676}
2677
2678
2679RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
2680 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
2681{
2682 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2683 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2684 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2685
2686 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
2687 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
2688 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
2689 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
2690
2691 RTVfsLockAcquireWrite(pThis->Base.hLock);
2692 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
2693 RTVfsLockReleaseWrite(pThis->Base.hLock);
2694 return rc;
2695}
2696
2697
2698RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
2699{
2700 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2701 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2702 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2703
2704 RTVfsLockAcquireWrite(pThis->Base.hLock);
2705 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
2706 RTVfsLockReleaseWrite(pThis->Base.hLock);
2707 return rc;
2708}
2709
2710
2711RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
2712{
2713 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
2714 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2715 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
2716
2717 RTVfsLockAcquireWrite(pThis->Base.hLock);
2718 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
2719 RTVfsLockReleaseWrite(pThis->Base.hLock);
2720
2721 return rc;
2722}
2723
2724
2725
2726/*
2727 *
2728 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2729 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2730 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
2731 *
2732 */
2733
2734RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
2735 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
2736{
2737 /*
2738 * Validate the input, be extra strict in strict builds.
2739 */
2740 AssertPtr(pIoStreamOps);
2741 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2742 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2743 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
2744 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
2745 Assert(cbInstance > 0);
2746 Assert(fOpen & RTFILE_O_ACCESS_MASK);
2747 AssertPtr(ppvInstance);
2748 AssertPtr(phVfsIos);
2749 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2750
2751 /*
2752 * Allocate the handle + instance data.
2753 */
2754 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
2755 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2756 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
2757 if (!pThis)
2758 return VERR_NO_MEMORY;
2759
2760 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2761 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2762 if (RT_FAILURE(rc))
2763 {
2764 RTMemFree(pThis);
2765 return rc;
2766 }
2767
2768 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
2769 pThis->fFlags = fOpen;
2770 pThis->pOps = pIoStreamOps;
2771
2772 *phVfsIos = pThis;
2773 *ppvInstance = pThis->Base.pvThis;
2774 return VINF_SUCCESS;
2775}
2776
2777
2778RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
2779{
2780 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2781 AssertPtrReturn(pThis, NULL);
2782 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
2783 if (pThis->pOps != pIoStreamOps)
2784 return NULL;
2785 return pThis->Base.pvThis;
2786}
2787
2788
2789#ifdef DEBUG
2790# undef RTVfsIoStrmRetain
2791#endif
2792RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
2793{
2794 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2795 AssertPtrReturn(pThis, UINT32_MAX);
2796 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2797 return rtVfsObjRetain(&pThis->Base);
2798}
2799#ifdef DEBUG
2800# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS)
2801#endif
2802
2803
2804RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL)
2805{
2806 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2807 AssertPtrReturn(pThis, UINT32_MAX);
2808 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2809 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsIoStrmRetainDebug", RT_SRC_POS_ARGS);
2810}
2811
2812
2813RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
2814{
2815 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2816 if (pThis == NIL_RTVFSIOSTREAM)
2817 return 0;
2818 AssertPtrReturn(pThis, UINT32_MAX);
2819 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
2820 return rtVfsObjRelease(&pThis->Base);
2821}
2822
2823
2824RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
2825{
2826 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2827 AssertPtrReturn(pThis, NIL_RTVFSFILE);
2828 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
2829
2830 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
2831 {
2832 rtVfsObjRetainVoid(&pThis->Base, "RTVfsIoStrmToFile");
2833 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
2834 }
2835
2836 /* this is no crime, so don't assert. */
2837 return NIL_RTVFSFILE;
2838}
2839
2840
2841RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2842{
2843 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2844 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2845 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2846 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2847}
2848
2849
2850RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
2851{
2852 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2853 if (pcbRead)
2854 *pcbRead = 0;
2855 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2856 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2857 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2858 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2859 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2860
2861 RTSGSEG Seg = { pvBuf, cbToRead };
2862 RTSGBUF SgBuf;
2863 RTSgBufInit(&SgBuf, &Seg, 1);
2864
2865 RTVfsLockAcquireWrite(pThis->Base.hLock);
2866 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
2867 RTVfsLockReleaseWrite(pThis->Base.hLock);
2868 return rc;
2869}
2870
2871
2872RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
2873 bool fBlocking, size_t *pcbRead)
2874{
2875 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2876 if (pcbRead)
2877 *pcbRead = 0;
2878 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2879 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2880 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2881 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2882 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2883
2884 RTSGSEG Seg = { pvBuf, cbToRead };
2885 RTSGBUF SgBuf;
2886 RTSgBufInit(&SgBuf, &Seg, 1);
2887
2888 RTVfsLockAcquireWrite(pThis->Base.hLock);
2889 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
2890 RTVfsLockReleaseWrite(pThis->Base.hLock);
2891 return rc;
2892}
2893
2894
2895RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
2896{
2897 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2898 if (pcbWritten)
2899 *pcbWritten = 0;
2900 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2901 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2902 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2903 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2904 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2905
2906 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
2907 RTSGBUF SgBuf;
2908 RTSgBufInit(&SgBuf, &Seg, 1);
2909
2910 RTVfsLockAcquireWrite(pThis->Base.hLock);
2911 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
2912 RTVfsLockReleaseWrite(pThis->Base.hLock);
2913 return rc;
2914}
2915
2916
2917RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
2918 bool fBlocking, size_t *pcbWritten)
2919{
2920 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2921 if (pcbWritten)
2922 *pcbWritten = 0;
2923 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2924 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2925 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2926 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2927 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2928
2929 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
2930 RTSGBUF SgBuf;
2931 RTSgBufInit(&SgBuf, &Seg, 1);
2932
2933 RTVfsLockAcquireWrite(pThis->Base.hLock);
2934 int rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
2935 RTVfsLockReleaseWrite(pThis->Base.hLock);
2936 return rc;
2937}
2938
2939
2940RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
2941{
2942 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
2943 if (pcbRead)
2944 *pcbRead = 0;
2945 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2946 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2947 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2948 AssertPtr(pSgBuf);
2949 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
2950 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
2951
2952 RTVfsLockAcquireWrite(pThis->Base.hLock);
2953 int rc;
2954 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
2955 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
2956 else
2957 {
2958 size_t cbRead = 0;
2959 rc = VINF_SUCCESS;
2960
2961 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
2962 {
2963 RTSGBUF SgBuf;
2964 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
2965
2966 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
2967 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
2968 if (RT_FAILURE(rc))
2969 break;
2970 cbRead += cbReadSeg;
2971 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
2972 break;
2973 if (off != -1)
2974 off += cbReadSeg;
2975 }
2976
2977 if (pcbRead)
2978 *pcbRead = cbRead;
2979 }
2980 RTVfsLockReleaseWrite(pThis->Base.hLock);
2981 return rc;
2982}
2983
2984
2985RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
2986{
2987 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
2988 if (pcbWritten)
2989 *pcbWritten = 0;
2990 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
2991 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2992 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
2993 AssertPtr(pSgBuf);
2994 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
2995 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
2996
2997 RTVfsLockAcquireWrite(pThis->Base.hLock);
2998 int rc;
2999 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3000 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
3001 else
3002 {
3003 size_t cbWritten = 0;
3004 rc = VINF_SUCCESS;
3005
3006 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3007 {
3008 RTSGBUF SgBuf;
3009 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3010
3011 size_t cbWrittenSeg = 0;
3012 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
3013 if (RT_FAILURE(rc))
3014 break;
3015 if (pcbWritten)
3016 {
3017 cbWritten += cbWrittenSeg;
3018 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
3019 break;
3020 if (off != -1)
3021 off += cbWrittenSeg;
3022 }
3023 else if (off != -1)
3024 off += pSgBuf->paSegs[iSeg].cbSeg;
3025 }
3026
3027 if (pcbWritten)
3028 *pcbWritten = cbWritten;
3029 }
3030 RTVfsLockReleaseWrite(pThis->Base.hLock);
3031 return rc;
3032}
3033
3034
3035RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
3036{
3037 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3038 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3039 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3040
3041 RTVfsLockAcquireWrite(pThis->Base.hLock);
3042 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
3043 RTVfsLockReleaseWrite(pThis->Base.hLock);
3044 return rc;
3045}
3046
3047
3048RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3049 uint32_t *pfRetEvents)
3050{
3051 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3052 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3053 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3054
3055 RTVfsLockAcquireWrite(pThis->Base.hLock);
3056 int rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
3057 RTVfsLockReleaseWrite(pThis->Base.hLock);
3058 return rc;
3059}
3060
3061
3062RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
3063{
3064 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3065 AssertPtrReturn(pThis, -1);
3066 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3067
3068 RTFOFF off;
3069 RTVfsLockAcquireRead(pThis->Base.hLock);
3070 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
3071 RTVfsLockReleaseRead(pThis->Base.hLock);
3072 if (RT_FAILURE(rc))
3073 off = rc;
3074 return off;
3075}
3076
3077
3078RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3079{
3080 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3081 AssertPtrReturn(pThis, -1);
3082 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3083 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
3084
3085 int rc;
3086 if (pThis->pOps->pfnSkip)
3087 {
3088 RTVfsLockAcquireWrite(pThis->Base.hLock);
3089 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
3090 RTVfsLockReleaseWrite(pThis->Base.hLock);
3091 }
3092 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3093 {
3094 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3095 RTFOFF offIgnored;
3096
3097 RTVfsLockAcquireWrite(pThis->Base.hLock);
3098 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
3099 RTVfsLockReleaseWrite(pThis->Base.hLock);
3100 }
3101 else
3102 {
3103 void *pvBuf = RTMemTmpAlloc(_64K);
3104 if (pvBuf)
3105 {
3106 rc = VINF_SUCCESS;
3107 while (cb > 0)
3108 {
3109 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
3110 RTVfsLockAcquireWrite(pThis->Base.hLock);
3111 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
3112 RTVfsLockReleaseWrite(pThis->Base.hLock);
3113 if (RT_FAILURE(rc))
3114 break;
3115 cb -= cbToRead;
3116 }
3117
3118 RTMemTmpFree(pvBuf);
3119 }
3120 else
3121 rc = VERR_NO_TMP_MEMORY;
3122 }
3123 return rc;
3124}
3125
3126
3127RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3128{
3129 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3130 AssertPtrReturn(pThis, -1);
3131 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3132
3133 int rc;
3134 if (pThis->pOps->pfnZeroFill)
3135 {
3136 RTVfsLockAcquireWrite(pThis->Base.hLock);
3137 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
3138 RTVfsLockReleaseWrite(pThis->Base.hLock);
3139 }
3140 else
3141 {
3142 rc = VINF_SUCCESS;
3143 while (cb > 0)
3144 {
3145 size_t cbToWrite = (size_t)RT_MIN(cb, (ssize_t)sizeof(g_abRTZero64K));
3146 RTVfsLockAcquireWrite(pThis->Base.hLock);
3147 rc = RTVfsIoStrmWrite(hVfsIos, g_abRTZero64K, cbToWrite, true /*fBlocking*/, NULL);
3148 RTVfsLockReleaseWrite(pThis->Base.hLock);
3149 if (RT_FAILURE(rc))
3150 break;
3151 cb -= cbToWrite;
3152 }
3153 }
3154 return rc;
3155}
3156
3157
3158RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
3159{
3160 /*
3161 * There is where the zero read behavior comes in handy.
3162 */
3163 char bDummy;
3164 size_t cbRead;
3165 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
3166 return rc == VINF_EOF;
3167}
3168
3169
3170
3171RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos)
3172{
3173 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3174 AssertPtrReturn(pThis, 0);
3175 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, 0);
3176 return pThis->fFlags;
3177}
3178
3179
3180
3181/*
3182 *
3183 * F I L E F I L E F I L E
3184 * F I L E F I L E F I L E
3185 * F I L E F I L E F I L E
3186 *
3187 */
3188
3189RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3190 PRTVFSFILE phVfsFile, void **ppvInstance)
3191{
3192 /*
3193 * Validate the input, be extra strict in strict builds.
3194 */
3195 AssertPtr(pFileOps);
3196 AssertReturn(pFileOps->uVersion == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3197 AssertReturn(pFileOps->uEndMarker == RTVFSFILEOPS_VERSION, VERR_VERSION_MISMATCH);
3198 Assert(!pFileOps->fReserved);
3199 RTVFSIOSTREAM_ASSERT_OPS(&pFileOps->Stream, RTVFSOBJTYPE_FILE);
3200 Assert(cbInstance > 0);
3201 Assert(fOpen & RTFILE_O_ACCESS_MASK);
3202 AssertPtr(ppvInstance);
3203 AssertPtr(phVfsFile);
3204 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3205
3206 /*
3207 * Allocate the handle + instance data.
3208 */
3209 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
3210 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3211 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
3212 if (!pThis)
3213 return VERR_NO_MEMORY;
3214
3215 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, false /*fNoVfsRef*/, hLock,
3216 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3217 if (RT_FAILURE(rc))
3218 {
3219 RTMemFree(pThis);
3220 return rc;
3221 }
3222
3223 pThis->uMagic = RTVFSFILE_MAGIC;
3224 pThis->fReserved = 0;
3225 pThis->pOps = pFileOps;
3226 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
3227 pThis->Stream.fFlags = fOpen;
3228 pThis->Stream.pOps = &pFileOps->Stream;
3229
3230 *phVfsFile = pThis;
3231 *ppvInstance = pThis->Stream.Base.pvThis;
3232 return VINF_SUCCESS;
3233}
3234
3235
3236RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
3237{
3238 /*
3239 * Validate input.
3240 */
3241 RTVFSINTERNAL *pThis = hVfs;
3242 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3243 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
3244 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
3245 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
3246
3247 int rc = rtFileRecalcAndValidateFlags(&fOpen);
3248 if (RT_FAILURE(rc))
3249 return rc;
3250
3251 /*
3252 * Parse the path, assume current directory is root since we've got no
3253 * caller context here.
3254 */
3255 PRTVFSPARSEDPATH pPath;
3256 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
3257 if (RT_SUCCESS(rc))
3258 {
3259 if ( !pPath->fDirSlash
3260 && pPath->cComponents > 0)
3261 {
3262 /*
3263 * Tranverse the path, resolving the parent node and any symlinks
3264 * in the final element, and ask the directory to open the file.
3265 */
3266 RTVFSDIRINTERNAL *pVfsParentDir;
3267 rc = rtVfsTraverseToParent(pThis, pPath, RTPATH_F_FOLLOW_LINK, &pVfsParentDir);
3268 if (RT_SUCCESS(rc))
3269 {
3270 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3271
3272 /** @todo there is a symlink creation race here. */
3273 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3274 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
3275 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3276
3277 RTVfsDirRelease(pVfsParentDir);
3278
3279 if (RT_SUCCESS(rc))
3280 {
3281 AssertPtr(*phVfsFile);
3282 Assert((*phVfsFile)->uMagic == RTVFSFILE_MAGIC);
3283 }
3284 }
3285 }
3286 else
3287 rc = VERR_NOT_A_FILE;
3288 RTVfsParsePathFree(pPath);
3289 }
3290 return rc;
3291}
3292
3293
3294#ifdef DEBUG
3295# undef RTVfsFileRetain
3296#endif
3297RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
3298{
3299 RTVFSFILEINTERNAL *pThis = hVfsFile;
3300 AssertPtrReturn(pThis, UINT32_MAX);
3301 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3302 return rtVfsObjRetain(&pThis->Stream.Base);
3303}
3304#ifdef DEBUG
3305# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS)
3306#endif
3307
3308
3309RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL)
3310{
3311 RTVFSFILEINTERNAL *pThis = hVfsFile;
3312 AssertPtrReturn(pThis, UINT32_MAX);
3313 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3314 return rtVfsObjRetainDebug(&pThis->Stream.Base, "RTVFsFileRetainDebug", RT_SRC_POS_ARGS);
3315}
3316
3317
3318RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
3319{
3320 RTVFSFILEINTERNAL *pThis = hVfsFile;
3321 if (pThis == NIL_RTVFSFILE)
3322 return 0;
3323 AssertPtrReturn(pThis, UINT32_MAX);
3324 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
3325 return rtVfsObjRelease(&pThis->Stream.Base);
3326}
3327
3328
3329RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
3330{
3331 RTVFSFILEINTERNAL *pThis = hVfsFile;
3332 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
3333 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
3334
3335 rtVfsObjRetainVoid(&pThis->Stream.Base, "RTVfsFileToIoStream");
3336 return &pThis->Stream;
3337}
3338
3339
3340RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3341{
3342 RTVFSFILEINTERNAL *pThis = hVfsFile;
3343 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3344 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3345 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
3346}
3347
3348
3349RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3350{
3351 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3352 if (pcbRead)
3353 *pcbRead = 0;
3354 RTVFSFILEINTERNAL *pThis = hVfsFile;
3355 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3356 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3357 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3358}
3359
3360
3361RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3362{
3363 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3364 if (pcbWritten)
3365 *pcbWritten = 0;
3366 RTVFSFILEINTERNAL *pThis = hVfsFile;
3367 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3368 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3369 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3370}
3371
3372
3373RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
3374{
3375 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3376 if (pcbWritten)
3377 *pcbWritten = 0;
3378 RTVFSFILEINTERNAL *pThis = hVfsFile;
3379 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3380 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3381
3382 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3383 if (RT_SUCCESS(rc))
3384 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
3385
3386 return rc;
3387}
3388
3389
3390RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
3391{
3392 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3393 if (pcbRead)
3394 *pcbRead = 0;
3395 RTVFSFILEINTERNAL *pThis = hVfsFile;
3396 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3397 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3398
3399 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
3400 if (RT_SUCCESS(rc))
3401 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
3402
3403 return rc;
3404}
3405
3406
3407RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3408{
3409 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3410 if (pcbRead)
3411 *pcbRead = 0;
3412 RTVFSFILEINTERNAL *pThis = hVfsFile;
3413 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3414 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3415
3416 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
3417}
3418
3419
3420RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3421{
3422 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3423 if (pcbWritten)
3424 *pcbWritten = 0;
3425 RTVFSFILEINTERNAL *pThis = hVfsFile;
3426 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3427 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3428
3429 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
3430}
3431
3432
3433RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
3434{
3435 RTVFSFILEINTERNAL *pThis = hVfsFile;
3436 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3437 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3438 return RTVfsIoStrmFlush(&pThis->Stream);
3439}
3440
3441
3442RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3443 uint32_t *pfRetEvents)
3444{
3445 RTVFSFILEINTERNAL *pThis = hVfsFile;
3446 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3447 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3448 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
3449}
3450
3451
3452RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
3453{
3454 RTVFSFILEINTERNAL *pThis = hVfsFile;
3455 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3456 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3457 return RTVfsIoStrmTell(&pThis->Stream);
3458}
3459
3460
3461RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
3462{
3463 RTVFSFILEINTERNAL *pThis = hVfsFile;
3464 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3465 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3466
3467 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
3468 || uMethod == RTFILE_SEEK_CURRENT
3469 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
3470 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
3471
3472 RTFOFF offActual = 0;
3473 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3474 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
3475 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3476 if (RT_SUCCESS(rc) && poffActual)
3477 {
3478 Assert(offActual >= 0);
3479 *poffActual = offActual;
3480 }
3481
3482 return rc;
3483}
3484
3485
3486RTDECL(int) RTVfsFileGetSize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
3487{
3488 RTVFSFILEINTERNAL *pThis = hVfsFile;
3489 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3490 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
3491 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
3492
3493 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
3494 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
3495 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
3496
3497 return rc;
3498}
3499
3500
3501RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile)
3502{
3503 RTVFSFILEINTERNAL *pThis = hVfsFile;
3504 AssertPtrReturn(pThis, 0);
3505 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, 0);
3506 return pThis->Stream.fFlags;
3507}
3508
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette