VirtualBox

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

Last change on this file since 96563 was 96407, checked in by vboxsync, 2 years ago

scm copyright and license note update

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 146.3 KB
Line 
1/* $Id: vfsbase.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Base.
4 */
5
6/*
7 * Copyright (C) 2010-2022 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_FS
42#include <iprt/vfs.h>
43#include <iprt/vfslowlevel.h>
44
45#include <iprt/asm.h>
46#include <iprt/err.h>
47#include <iprt/file.h>
48#include <iprt/log.h>
49#include <iprt/mem.h>
50#include <iprt/param.h>
51#include <iprt/path.h>
52#include <iprt/poll.h>
53#include <iprt/semaphore.h>
54#include <iprt/thread.h>
55#include <iprt/zero.h>
56
57#include "internal/file.h"
58#include "internal/fs.h"
59#include "internal/magics.h"
60#include "internal/path.h"
61//#include "internal/vfs.h"
62
63
64/*********************************************************************************************************************************
65* Defined Constants And Macros *
66*********************************************************************************************************************************/
67/** The instance data alignment. */
68#define RTVFS_INST_ALIGNMENT 16U
69
70/** The max number of symbolic links to resolve in a path. */
71#define RTVFS_MAX_LINKS 20U
72
73
74/** Asserts that the VFS base object vtable is valid. */
75#define RTVFSOBJ_ASSERT_OPS(a_pObjOps, a_enmType) \
76 do \
77 { \
78 Assert((a_pObjOps)->uVersion == RTVFSOBJOPS_VERSION); \
79 Assert((a_pObjOps)->enmType == (a_enmType) || (a_enmType) == RTVFSOBJTYPE_INVALID); \
80 AssertPtr((a_pObjOps)->pszName); \
81 Assert(*(a_pObjOps)->pszName); \
82 AssertPtr((a_pObjOps)->pfnClose); \
83 AssertPtr((a_pObjOps)->pfnQueryInfo); \
84 AssertPtrNull((a_pObjOps)->pfnQueryInfoEx); \
85 Assert((a_pObjOps)->uEndMarker == RTVFSOBJOPS_VERSION); \
86 } while (0)
87
88/** Asserts that the VFS set object vtable is valid. */
89#define RTVFSOBJSET_ASSERT_OPS(a_pSetOps, a_offObjOps) \
90 do \
91 { \
92 Assert((a_pSetOps)->uVersion == RTVFSOBJSETOPS_VERSION); \
93 Assert((a_pSetOps)->offObjOps == (a_offObjOps)); \
94 AssertPtrNull((a_pSetOps)->pfnSetMode); \
95 AssertPtrNull((a_pSetOps)->pfnSetTimes); \
96 AssertPtrNull((a_pSetOps)->pfnSetOwner); \
97 Assert((a_pSetOps)->uEndMarker == RTVFSOBJSETOPS_VERSION); \
98 } while (0)
99
100/** Asserts that the VFS directory vtable is valid. */
101#define RTVFSDIR_ASSERT_OPS(pDirOps, a_enmType) \
102 do { \
103 RTVFSOBJ_ASSERT_OPS(&(pDirOps)->Obj, a_enmType); \
104 RTVFSOBJSET_ASSERT_OPS(&(pDirOps)->ObjSet, RT_UOFFSETOF(RTVFSDIROPS, ObjSet) - RT_UOFFSETOF(RTVFSDIROPS, Obj)); \
105 Assert((pDirOps)->uVersion == RTVFSDIROPS_VERSION); \
106 Assert(!(pDirOps)->fReserved); \
107 AssertPtr((pDirOps)->pfnOpen); \
108 AssertPtrNull((pDirOps)->pfnOpenFile); \
109 AssertPtrNull((pDirOps)->pfnOpenDir); \
110 AssertPtrNull((pDirOps)->pfnCreateDir); \
111 AssertPtrNull((pDirOps)->pfnOpenSymlink); \
112 AssertPtr((pDirOps)->pfnCreateSymlink); \
113 AssertPtr((pDirOps)->pfnUnlinkEntry); \
114 AssertPtr((pDirOps)->pfnRewindDir); \
115 AssertPtr((pDirOps)->pfnReadDir); \
116 Assert((pDirOps)->uEndMarker == RTVFSDIROPS_VERSION); \
117 } while (0)
118
119/** Asserts that the VFS I/O stream vtable is valid. */
120#define RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, a_enmType) \
121 do { \
122 RTVFSOBJ_ASSERT_OPS(&(pIoStreamOps)->Obj, a_enmType); \
123 Assert((pIoStreamOps)->uVersion == RTVFSIOSTREAMOPS_VERSION); \
124 Assert(!((pIoStreamOps)->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK)); \
125 AssertPtr((pIoStreamOps)->pfnRead); \
126 AssertPtrNull((pIoStreamOps)->pfnWrite); \
127 AssertPtr((pIoStreamOps)->pfnFlush); \
128 AssertPtrNull((pIoStreamOps)->pfnPollOne); \
129 AssertPtr((pIoStreamOps)->pfnTell); \
130 AssertPtrNull((pIoStreamOps)->pfnSkip); \
131 AssertPtrNull((pIoStreamOps)->pfnZeroFill); \
132 Assert((pIoStreamOps)->uEndMarker == RTVFSIOSTREAMOPS_VERSION); \
133 } while (0)
134
135/** Asserts that the VFS I/O stream vtable is valid. */
136#define RTVFSFILE_ASSERT_OPS(pFileOps, a_enmType) \
137 do { \
138 RTVFSIOSTREAM_ASSERT_OPS(&(pFileOps)->Stream, a_enmType); \
139 Assert((pFileOps)->uVersion == RTVFSFILEOPS_VERSION); \
140 Assert((pFileOps)->fReserved == 0); \
141 AssertPtr((pFileOps)->pfnSeek); \
142 AssertPtrNull((pFileOps)->pfnQuerySize); \
143 AssertPtrNull((pFileOps)->pfnSetSize); \
144 AssertPtrNull((pFileOps)->pfnQueryMaxSize); \
145 Assert((pFileOps)->uEndMarker == RTVFSFILEOPS_VERSION); \
146 } while (0)
147
148/** Asserts that the VFS symlink vtable is valid. */
149#define RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, a_enmType) \
150 do { \
151 RTVFSOBJ_ASSERT_OPS(&(pSymlinkOps)->Obj, a_enmType); \
152 RTVFSOBJSET_ASSERT_OPS(&(pSymlinkOps)->ObjSet, RT_UOFFSETOF(RTVFSSYMLINKOPS, ObjSet) - RT_UOFFSETOF(RTVFSSYMLINKOPS, Obj)); \
153 Assert((pSymlinkOps)->uVersion == RTVFSSYMLINKOPS_VERSION); \
154 Assert(!(pSymlinkOps)->fReserved); \
155 AssertPtr((pSymlinkOps)->pfnRead); \
156 Assert((pSymlinkOps)->uEndMarker == RTVFSSYMLINKOPS_VERSION); \
157 } while (0)
158
159
160/** Validates a VFS handle and returns @a rcRet if it's invalid. */
161#define RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, rcRet) \
162 do { \
163 if ((hVfs) != NIL_RTVFS) \
164 { \
165 AssertPtrReturn((hVfs), (rcRet)); \
166 AssertReturn((hVfs)->uMagic == RTVFS_MAGIC, (rcRet)); \
167 } \
168 } while (0)
169
170
171/*********************************************************************************************************************************
172* Structures and Typedefs *
173*********************************************************************************************************************************/
174/** @todo Move all this stuff to internal/vfs.h */
175
176
177/**
178 * The VFS internal lock data.
179 */
180typedef struct RTVFSLOCKINTERNAL
181{
182 /** The number of references to the this lock. */
183 uint32_t volatile cRefs;
184 /** The lock type. */
185 RTVFSLOCKTYPE enmType;
186 /** Type specific data. */
187 union
188 {
189 /** Read/Write semaphore handle. */
190 RTSEMRW hSemRW;
191 /** Fast mutex semaphore handle. */
192 RTSEMFASTMUTEX hFastMtx;
193 /** Regular mutex semaphore handle. */
194 RTSEMMUTEX hMtx;
195 } u;
196} RTVFSLOCKINTERNAL;
197
198
199/**
200 * The VFS base object handle data.
201 *
202 * All other VFS handles are derived from this one. The final handle type is
203 * indicated by RTVFSOBJOPS::enmType via the RTVFSOBJINTERNAL::pOps member.
204 */
205typedef struct RTVFSOBJINTERNAL
206{
207 /** The VFS magic (RTVFSOBJ_MAGIC). */
208 uint32_t uMagic : 31;
209 /** Set if we've got no VFS reference but still got a valid hVfs.
210 * This is hack for permanent root directory objects. */
211 uint32_t fNoVfsRef : 1;
212 /** The number of references to this VFS object. */
213 uint32_t volatile cRefs;
214 /** Pointer to the instance data. */
215 void *pvThis;
216 /** The vtable. */
217 PCRTVFSOBJOPS pOps;
218 /** The lock protecting all access to the VFS.
219 * Only valid if RTVFS_C_THREAD_SAFE is set, otherwise it is NIL_RTVFSLOCK. */
220 RTVFSLOCK hLock;
221 /** Reference back to the VFS containing this object. */
222 RTVFS hVfs;
223} RTVFSOBJINTERNAL;
224
225
226/**
227 * The VFS filesystem stream handle data.
228 *
229 * @extends RTVFSOBJINTERNAL
230 */
231typedef struct RTVFSFSSTREAMINTERNAL
232{
233 /** The VFS magic (RTVFSFSTREAM_MAGIC). */
234 uint32_t uMagic;
235 /** File open flags, at a minimum the access mask. */
236 uint32_t fFlags;
237 /** The vtable. */
238 PCRTVFSFSSTREAMOPS pOps;
239 /** The base object handle data. */
240 RTVFSOBJINTERNAL Base;
241} RTVFSFSSTREAMINTERNAL;
242
243
244/**
245 * The VFS handle data.
246 *
247 * @extends RTVFSOBJINTERNAL
248 */
249typedef struct RTVFSINTERNAL
250{
251 /** The VFS magic (RTVFS_MAGIC). */
252 uint32_t uMagic;
253 /** Creation flags (RTVFS_C_XXX). */
254 uint32_t fFlags;
255 /** The vtable. */
256 PCRTVFSOPS pOps;
257 /** The base object handle data. */
258 RTVFSOBJINTERNAL Base;
259} RTVFSINTERNAL;
260
261
262/**
263 * The VFS directory handle data.
264 *
265 * @extends RTVFSOBJINTERNAL
266 */
267typedef struct RTVFSDIRINTERNAL
268{
269 /** The VFS magic (RTVFSDIR_MAGIC). */
270 uint32_t uMagic;
271 /** Reserved for flags or something. */
272 uint32_t fReserved;
273 /** The vtable. */
274 PCRTVFSDIROPS pOps;
275 /** The base object handle data. */
276 RTVFSOBJINTERNAL Base;
277} RTVFSDIRINTERNAL;
278
279
280/**
281 * The VFS symbolic link handle data.
282 *
283 * @extends RTVFSOBJINTERNAL
284 */
285typedef struct RTVFSSYMLINKINTERNAL
286{
287 /** The VFS magic (RTVFSSYMLINK_MAGIC). */
288 uint32_t uMagic;
289 /** Reserved for flags or something. */
290 uint32_t fReserved;
291 /** The vtable. */
292 PCRTVFSSYMLINKOPS pOps;
293 /** The base object handle data. */
294 RTVFSOBJINTERNAL Base;
295} RTVFSSYMLINKINTERNAL;
296
297
298/**
299 * The VFS I/O stream handle data.
300 *
301 * This is often part of a type specific handle, like a file or pipe.
302 *
303 * @extends RTVFSOBJINTERNAL
304 */
305typedef struct RTVFSIOSTREAMINTERNAL
306{
307 /** The VFS magic (RTVFSIOSTREAM_MAGIC). */
308 uint32_t uMagic;
309 /** File open flags, at a minimum the access mask. */
310 uint32_t fFlags;
311 /** The vtable. */
312 PCRTVFSIOSTREAMOPS pOps;
313 /** The base object handle data. */
314 RTVFSOBJINTERNAL Base;
315} RTVFSIOSTREAMINTERNAL;
316
317
318/**
319 * The VFS file handle data.
320 *
321 * @extends RTVFSIOSTREAMINTERNAL
322 */
323typedef struct RTVFSFILEINTERNAL
324{
325 /** The VFS magic (RTVFSFILE_MAGIC). */
326 uint32_t uMagic;
327 /** Reserved for flags or something. */
328 uint32_t fReserved;
329 /** The vtable. */
330 PCRTVFSFILEOPS pOps;
331 /** The stream handle data. */
332 RTVFSIOSTREAMINTERNAL Stream;
333} RTVFSFILEINTERNAL;
334
335#if 0 /* later */
336
337/**
338 * The VFS pipe handle data.
339 *
340 * @extends RTVFSIOSTREAMINTERNAL
341 */
342typedef struct RTVFSPIPEINTERNAL
343{
344 /** The VFS magic (RTVFSPIPE_MAGIC). */
345 uint32_t uMagic;
346 /** Reserved for flags or something. */
347 uint32_t fReserved;
348 /** The vtable. */
349 PCRTVFSPIPEOPS pOps;
350 /** The stream handle data. */
351 RTVFSIOSTREAMINTERNAL Stream;
352} RTVFSPIPEINTERNAL;
353
354
355/**
356 * The VFS socket handle data.
357 *
358 * @extends RTVFSIOSTREAMINTERNAL
359 */
360typedef struct RTVFSSOCKETINTERNAL
361{
362 /** The VFS magic (RTVFSSOCKET_MAGIC). */
363 uint32_t uMagic;
364 /** Reserved for flags or something. */
365 uint32_t fReserved;
366 /** The vtable. */
367 PCRTVFSSOCKETOPS pOps;
368 /** The stream handle data. */
369 RTVFSIOSTREAMINTERNAL Stream;
370} RTVFSSOCKETINTERNAL;
371
372#endif /* later */
373
374
375/*********************************************************************************************************************************
376* Internal Functions *
377*********************************************************************************************************************************/
378DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis);
379static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir);
380static int rtVfsDirFollowSymlinkObjToParent(RTVFSDIRINTERNAL **ppVfsParentDir, RTVFSOBJ hVfsObj,
381 PRTVFSPARSEDPATH pPath, uint32_t fFlags);
382
383
384
385/**
386 * Translates a RTVFSOBJTYPE value into a string.
387 *
388 * @returns Pointer to readonly name.
389 * @param enmType The object type to name.
390 */
391RTDECL(const char *) RTVfsTypeName(RTVFSOBJTYPE enmType)
392{
393 switch (enmType)
394 {
395 case RTVFSOBJTYPE_INVALID: return "invalid";
396 case RTVFSOBJTYPE_BASE: return "base";
397 case RTVFSOBJTYPE_VFS: return "VFS";
398 case RTVFSOBJTYPE_FS_STREAM: return "FS stream";
399 case RTVFSOBJTYPE_IO_STREAM: return "I/O stream";
400 case RTVFSOBJTYPE_DIR: return "directory";
401 case RTVFSOBJTYPE_FILE: return "file";
402 case RTVFSOBJTYPE_SYMLINK: return "symlink";
403 case RTVFSOBJTYPE_END: return "end";
404 case RTVFSOBJTYPE_32BIT_HACK:
405 break;
406 }
407 return "unknown";
408}
409
410
411/*
412 *
413 * V F S L o c k A b s t r a c t i o n
414 * V F S L o c k A b s t r a c t i o n
415 * V F S L o c k A b s t r a c t i o n
416 *
417 *
418 */
419
420
421RTDECL(uint32_t) RTVfsLockRetain(RTVFSLOCK hLock)
422{
423 RTVFSLOCKINTERNAL *pThis = hLock;
424 AssertPtrReturn(pThis, UINT32_MAX);
425 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
426
427 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
428 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
429 return cRefs;
430}
431
432
433RTDECL(uint32_t) RTVfsLockRetainDebug(RTVFSLOCK hLock, RT_SRC_POS_DECL)
434{
435 RTVFSLOCKINTERNAL *pThis = hLock;
436 AssertPtrReturn(pThis, UINT32_MAX);
437 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
438
439 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
440 AssertMsg(cRefs > 1 && cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
441 LogFlow(("RTVfsLockRetainDebug(%p) -> %d; caller: %s %s(%u)\n", hLock, cRefs, pszFunction, pszFile, iLine));
442 RT_SRC_POS_NOREF();
443 return cRefs;
444}
445
446
447/**
448 * Destroys a VFS lock handle.
449 *
450 * @param pThis The lock to destroy.
451 */
452static void rtVfsLockDestroy(RTVFSLOCKINTERNAL *pThis)
453{
454 switch (pThis->enmType)
455 {
456 case RTVFSLOCKTYPE_RW:
457 RTSemRWDestroy(pThis->u.hSemRW);
458 pThis->u.hSemRW = NIL_RTSEMRW;
459 break;
460
461 case RTVFSLOCKTYPE_FASTMUTEX:
462 RTSemFastMutexDestroy(pThis->u.hFastMtx);
463 pThis->u.hFastMtx = NIL_RTSEMFASTMUTEX;
464 break;
465
466 case RTVFSLOCKTYPE_MUTEX:
467 RTSemMutexDestroy(pThis->u.hMtx);
468 pThis->u.hFastMtx = NIL_RTSEMMUTEX;
469 break;
470
471 default:
472 AssertMsgFailedReturnVoid(("%p %d\n", pThis, pThis->enmType));
473 }
474
475 pThis->enmType = RTVFSLOCKTYPE_INVALID;
476 RTMemFree(pThis);
477}
478
479
480RTDECL(uint32_t) RTVfsLockRelease(RTVFSLOCK hLock)
481{
482 RTVFSLOCKINTERNAL *pThis = hLock;
483 if (pThis == NIL_RTVFSLOCK)
484 return 0;
485 AssertPtrReturn(pThis, UINT32_MAX);
486 AssertReturn(pThis->enmType > RTVFSLOCKTYPE_INVALID && pThis->enmType < RTVFSLOCKTYPE_END, UINT32_MAX);
487
488 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
489 AssertMsg(cRefs < _1M, ("%#x %p %d\n", cRefs, pThis, pThis->enmType));
490 if (cRefs == 0)
491 rtVfsLockDestroy(pThis);
492 return cRefs;
493}
494
495
496/**
497 * Creates a read/write lock.
498 *
499 * @returns IPRT status code
500 * @param phLock Where to return the lock handle.
501 */
502static int rtVfsLockCreateRW(PRTVFSLOCK phLock)
503{
504 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
505 if (!pThis)
506 return VERR_NO_MEMORY;
507
508 pThis->cRefs = 1;
509 pThis->enmType = RTVFSLOCKTYPE_RW;
510
511 int rc = RTSemRWCreate(&pThis->u.hSemRW);
512 if (RT_FAILURE(rc))
513 {
514 RTMemFree(pThis);
515 return rc;
516 }
517
518 *phLock = pThis;
519 return VINF_SUCCESS;
520}
521
522
523/**
524 * Creates a fast mutex lock.
525 *
526 * @returns IPRT status code
527 * @param phLock Where to return the lock handle.
528 */
529static int rtVfsLockCreateFastMutex(PRTVFSLOCK phLock)
530{
531 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
532 if (!pThis)
533 return VERR_NO_MEMORY;
534
535 pThis->cRefs = 1;
536 pThis->enmType = RTVFSLOCKTYPE_FASTMUTEX;
537
538 int rc = RTSemFastMutexCreate(&pThis->u.hFastMtx);
539 if (RT_FAILURE(rc))
540 {
541 RTMemFree(pThis);
542 return rc;
543 }
544
545 *phLock = pThis;
546 return VINF_SUCCESS;
547
548}
549
550
551/**
552 * Creates a mutex lock.
553 *
554 * @returns IPRT status code
555 * @param phLock Where to return the lock handle.
556 */
557static int rtVfsLockCreateMutex(PRTVFSLOCK phLock)
558{
559 RTVFSLOCKINTERNAL *pThis = (RTVFSLOCKINTERNAL *)RTMemAlloc(sizeof(*pThis));
560 if (!pThis)
561 return VERR_NO_MEMORY;
562
563 pThis->cRefs = 1;
564 pThis->enmType = RTVFSLOCKTYPE_MUTEX;
565
566 int rc = RTSemMutexCreate(&pThis->u.hMtx);
567 if (RT_FAILURE(rc))
568 {
569 RTMemFree(pThis);
570 return rc;
571 }
572
573 *phLock = pThis;
574 return VINF_SUCCESS;
575}
576
577
578/**
579 * Acquires the lock for reading.
580 *
581 * @param hLock Non-nil lock handle.
582 * @internal
583 */
584RTDECL(void) RTVfsLockAcquireReadSlow(RTVFSLOCK hLock)
585{
586 RTVFSLOCKINTERNAL *pThis = hLock;
587 int rc;
588
589 AssertPtr(pThis);
590 switch (pThis->enmType)
591 {
592 case RTVFSLOCKTYPE_RW:
593 rc = RTSemRWRequestRead(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
594 AssertRC(rc);
595 break;
596
597 case RTVFSLOCKTYPE_FASTMUTEX:
598 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
599 AssertRC(rc);
600 break;
601
602 case RTVFSLOCKTYPE_MUTEX:
603 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
604 AssertRC(rc);
605 break;
606 default:
607 AssertFailed();
608 }
609}
610
611
612/**
613 * Release a lock held for reading.
614 *
615 * @param hLock Non-nil lock handle.
616 * @internal
617 */
618RTDECL(void) RTVfsLockReleaseReadSlow(RTVFSLOCK hLock)
619{
620 RTVFSLOCKINTERNAL *pThis = hLock;
621 int rc;
622
623 AssertPtr(pThis);
624 switch (pThis->enmType)
625 {
626 case RTVFSLOCKTYPE_RW:
627 rc = RTSemRWReleaseRead(pThis->u.hSemRW);
628 AssertRC(rc);
629 break;
630
631 case RTVFSLOCKTYPE_FASTMUTEX:
632 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
633 AssertRC(rc);
634 break;
635
636 case RTVFSLOCKTYPE_MUTEX:
637 rc = RTSemMutexRelease(pThis->u.hMtx);
638 AssertRC(rc);
639 break;
640 default:
641 AssertFailed();
642 }
643}
644
645
646/**
647 * Acquires the lock for writing.
648 *
649 * @param hLock Non-nil lock handle.
650 * @internal
651 */
652RTDECL(void) RTVfsLockAcquireWriteSlow(RTVFSLOCK hLock)
653{
654 RTVFSLOCKINTERNAL *pThis = hLock;
655 int rc;
656
657 AssertPtr(pThis);
658 switch (pThis->enmType)
659 {
660 case RTVFSLOCKTYPE_RW:
661 rc = RTSemRWRequestWrite(pThis->u.hSemRW, RT_INDEFINITE_WAIT);
662 AssertRC(rc);
663 break;
664
665 case RTVFSLOCKTYPE_FASTMUTEX:
666 rc = RTSemFastMutexRequest(pThis->u.hFastMtx);
667 AssertRC(rc);
668 break;
669
670 case RTVFSLOCKTYPE_MUTEX:
671 rc = RTSemMutexRequest(pThis->u.hMtx, RT_INDEFINITE_WAIT);
672 AssertRC(rc);
673 break;
674 default:
675 AssertFailed();
676 }
677}
678
679
680/**
681 * Release a lock held for writing.
682 *
683 * @param hLock Non-nil lock handle.
684 * @internal
685 */
686RTDECL(void) RTVfsLockReleaseWriteSlow(RTVFSLOCK hLock)
687{
688 RTVFSLOCKINTERNAL *pThis = hLock;
689 int rc;
690
691 AssertPtr(pThis);
692 switch (pThis->enmType)
693 {
694 case RTVFSLOCKTYPE_RW:
695 rc = RTSemRWReleaseWrite(pThis->u.hSemRW);
696 AssertRC(rc);
697 break;
698
699 case RTVFSLOCKTYPE_FASTMUTEX:
700 rc = RTSemFastMutexRelease(pThis->u.hFastMtx);
701 AssertRC(rc);
702 break;
703
704 case RTVFSLOCKTYPE_MUTEX:
705 rc = RTSemMutexRelease(pThis->u.hMtx);
706 AssertRC(rc);
707 break;
708 default:
709 AssertFailed();
710 }
711}
712
713
714
715/*
716 *
717 * B A S E O B J E C T
718 * B A S E O B J E C T
719 * B A S E O B J E C T
720 *
721 */
722
723/**
724 * Internal object retainer that asserts sanity in strict builds.
725 *
726 * @param pThis The base object handle data.
727 * @param pszCaller Where we're called from.
728 */
729DECLINLINE(void) rtVfsObjRetainVoid(RTVFSOBJINTERNAL *pThis, const char *pszCaller)
730{
731 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
732LogFlow(("rtVfsObjRetainVoid(%p/%p) -> %d; caller=%s\n", pThis, pThis->pvThis, cRefs, pszCaller)); RT_NOREF(pszCaller);
733 AssertMsg(cRefs > 1 && cRefs < _1M,
734 ("%#x %p ops=%p %s (%d); caller=%s\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType, pszCaller));
735 NOREF(cRefs);
736}
737
738
739/**
740 * Initializes the base object part of a new object.
741 *
742 * @returns IPRT status code.
743 * @param pThis Pointer to the base object part.
744 * @param pObjOps The base object vtable.
745 * @param hVfs The VFS handle to associate with.
746 * @param fNoVfsRef If set, do not retain an additional reference to
747 * @a hVfs. Permanent root dir hack.
748 * @param hLock The lock handle, pseudo handle or nil.
749 * @param pvThis Pointer to the private data.
750 */
751static int rtVfsObjInitNewObject(RTVFSOBJINTERNAL *pThis, PCRTVFSOBJOPS pObjOps, RTVFS hVfs, bool fNoVfsRef,
752 RTVFSLOCK hLock, void *pvThis)
753{
754 /*
755 * Deal with the lock first as that's the most complicated matter.
756 */
757 if (hLock != NIL_RTVFSLOCK)
758 {
759 int rc;
760 if (hLock == RTVFSLOCK_CREATE_RW)
761 {
762 rc = rtVfsLockCreateRW(&hLock);
763 AssertRCReturn(rc, rc);
764 }
765 else if (hLock == RTVFSLOCK_CREATE_FASTMUTEX)
766 {
767 rc = rtVfsLockCreateFastMutex(&hLock);
768 AssertRCReturn(rc, rc);
769 }
770 else if (hLock == RTVFSLOCK_CREATE_MUTEX)
771 {
772 rc = rtVfsLockCreateMutex(&hLock);
773 AssertRCReturn(rc, rc);
774 }
775 else
776 {
777 /*
778 * The caller specified a lock, we consume the this reference.
779 */
780 AssertPtrReturn(hLock, VERR_INVALID_HANDLE);
781 AssertReturn(hLock->enmType > RTVFSLOCKTYPE_INVALID && hLock->enmType < RTVFSLOCKTYPE_END, VERR_INVALID_HANDLE);
782 AssertReturn(hLock->cRefs > 0, VERR_INVALID_HANDLE);
783 }
784 }
785 else if (hVfs != NIL_RTVFS)
786 {
787 /*
788 * Retain a reference to the VFS lock, if there is one.
789 */
790 hLock = hVfs->Base.hLock;
791 if (hLock != NIL_RTVFSLOCK)
792 {
793 uint32_t cRefs = RTVfsLockRetain(hLock);
794 if (RT_UNLIKELY(cRefs == UINT32_MAX))
795 return VERR_INVALID_HANDLE;
796 }
797 }
798
799
800 /*
801 * Do the actual initializing.
802 */
803 pThis->uMagic = RTVFSOBJ_MAGIC;
804 pThis->fNoVfsRef = fNoVfsRef;
805 pThis->pvThis = pvThis;
806 pThis->pOps = pObjOps;
807 pThis->cRefs = 1;
808 pThis->hVfs = hVfs;
809 pThis->hLock = hLock;
810 if (hVfs != NIL_RTVFS && !fNoVfsRef)
811 rtVfsObjRetainVoid(&hVfs->Base, "rtVfsObjInitNewObject");
812
813 return VINF_SUCCESS;
814}
815
816
817RTDECL(int) RTVfsNewBaseObj(PCRTVFSOBJOPS pObjOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
818 PRTVFSOBJ phVfsObj, void **ppvInstance)
819{
820 /*
821 * Validate the input, be extra strict in strict builds.
822 */
823 AssertPtr(pObjOps);
824 AssertReturn(pObjOps->uVersion == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
825 AssertReturn(pObjOps->uEndMarker == RTVFSOBJOPS_VERSION, VERR_VERSION_MISMATCH);
826 RTVFSOBJ_ASSERT_OPS(pObjOps, RTVFSOBJTYPE_BASE);
827 Assert(cbInstance > 0);
828 AssertPtr(ppvInstance);
829 AssertPtr(phVfsObj);
830 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
831
832 /*
833 * Allocate the handle + instance data.
834 */
835 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSOBJINTERNAL), RTVFS_INST_ALIGNMENT)
836 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
837 RTVFSOBJINTERNAL *pThis = (RTVFSOBJINTERNAL *)RTMemAllocZ(cbThis);
838 if (!pThis)
839 return VERR_NO_MEMORY;
840
841 int rc = rtVfsObjInitNewObject(pThis, pObjOps, hVfs, false /*fNoVfsRef*/, hLock,
842 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
843 if (RT_FAILURE(rc))
844 {
845 RTMemFree(pThis);
846 return rc;
847 }
848
849 *phVfsObj = pThis;
850 *ppvInstance = pThis->pvThis;
851 return VINF_SUCCESS;
852}
853
854
855RTDECL(void *) RTVfsObjToPrivate(RTVFSOBJ hVfsObj, PCRTVFSOBJOPS pObjOps)
856{
857 RTVFSOBJINTERNAL *pThis = hVfsObj;
858 AssertPtrReturn(pThis, NULL);
859 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NULL);
860 if (pThis->pOps != pObjOps)
861 return NULL;
862 return pThis->pvThis;
863}
864
865
866/**
867 * Internal object retainer that asserts sanity in strict builds.
868 *
869 * @returns The new reference count.
870 * @param pThis The base object handle data.
871 */
872DECLINLINE(uint32_t) rtVfsObjRetain(RTVFSOBJINTERNAL *pThis)
873{
874 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
875LogFlow(("rtVfsObjRetain(%p/%p) -> %d\n", pThis, pThis->pvThis, cRefs));
876 AssertMsg(cRefs > 1 && cRefs < _1M,
877 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
878 return cRefs;
879}
880
881/**
882 * Internal object retainer that asserts sanity in strict builds.
883 *
884 * @returns The new reference count.
885 * @param pThis The base object handle data.
886 */
887DECLINLINE(uint32_t) rtVfsObjRetainDebug(RTVFSOBJINTERNAL *pThis, const char *pszApi, RT_SRC_POS_DECL)
888{
889 uint32_t cRefs = ASMAtomicIncU32(&pThis->cRefs);
890 AssertMsg(cRefs > 1 && cRefs < _1M,
891 ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
892 LogFlow(("%s(%p/%p) -> %2d; caller: %s %s(%d) \n", pszApi, pThis, pThis->pvThis, cRefs, pszFunction, pszFile, iLine));
893 RT_SRC_POS_NOREF(); RT_NOREF(pszApi);
894 return cRefs;
895}
896
897
898#ifdef DEBUG
899# undef RTVfsObjRetain
900#endif
901RTDECL(uint32_t) RTVfsObjRetain(RTVFSOBJ hVfsObj)
902{
903 RTVFSOBJINTERNAL *pThis = hVfsObj;
904 AssertPtrReturn(pThis, UINT32_MAX);
905 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
906
907 return rtVfsObjRetain(pThis);
908}
909#ifdef DEBUG
910# define RTVfsObjRetain(hVfsObj) RTVfsObjRetainDebug(hVfsObj, RT_SRC_POS)
911#endif
912
913
914RTDECL(uint32_t) RTVfsObjRetainDebug(RTVFSOBJ hVfsObj, RT_SRC_POS_DECL)
915{
916 RTVFSOBJINTERNAL *pThis = hVfsObj;
917 AssertPtrReturn(pThis, UINT32_MAX);
918 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
919
920 return rtVfsObjRetainDebug(pThis, "RTVfsObjRetainDebug", RT_SRC_POS_ARGS);
921}
922
923
924/**
925 * Does the actual object destruction for rtVfsObjRelease().
926 *
927 * @param pThis The object to destroy.
928 */
929static void rtVfsObjDestroy(RTVFSOBJINTERNAL *pThis)
930{
931 RTVFSOBJTYPE const enmType = pThis->pOps->enmType;
932
933 /*
934 * Invalidate the object.
935 */
936 RTVfsLockAcquireWrite(pThis->hLock); /* paranoia */
937 void *pvToFree = NULL;
938 switch (enmType)
939 {
940 case RTVFSOBJTYPE_BASE:
941 pvToFree = pThis;
942 break;
943
944 case RTVFSOBJTYPE_VFS:
945 pvToFree = RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
946 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)->uMagic, RTVFS_MAGIC_DEAD);
947 break;
948
949 case RTVFSOBJTYPE_FS_STREAM:
950 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
951 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base)->uMagic, RTVFSFSSTREAM_MAGIC_DEAD);
952 break;
953
954 case RTVFSOBJTYPE_IO_STREAM:
955 pvToFree = RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
956 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
957 break;
958
959 case RTVFSOBJTYPE_DIR:
960 pvToFree = RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
961 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->uMagic, RTVFSDIR_MAGIC_DEAD);
962 break;
963
964 case RTVFSOBJTYPE_FILE:
965 pvToFree = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
966 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->uMagic, RTVFSFILE_MAGIC_DEAD);
967 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base)->uMagic, RTVFSIOSTREAM_MAGIC_DEAD);
968 break;
969
970 case RTVFSOBJTYPE_SYMLINK:
971 pvToFree = RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
972 ASMAtomicWriteU32(&RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->uMagic, RTVFSSYMLINK_MAGIC_DEAD);
973 break;
974
975 case RTVFSOBJTYPE_INVALID:
976 case RTVFSOBJTYPE_END:
977 case RTVFSOBJTYPE_32BIT_HACK:
978 AssertMsgFailed(("enmType=%d ops=%p %s\n", enmType, pThis->pOps, pThis->pOps->pszName));
979 break;
980 /* no default as we want gcc warnings. */
981 }
982 pThis->uMagic = RTVFSOBJ_MAGIC_DEAD;
983 RTVfsLockReleaseWrite(pThis->hLock);
984
985 /*
986 * Close the object and free the handle.
987 */
988 int rc = pThis->pOps->pfnClose(pThis->pvThis);
989 AssertRC(rc);
990 if (pThis->hVfs != NIL_RTVFS)
991 {
992 if (!pThis->fNoVfsRef)
993 rtVfsObjRelease(&pThis->hVfs->Base);
994 pThis->hVfs = NIL_RTVFS;
995 }
996 if (pThis->hLock != NIL_RTVFSLOCK)
997 {
998 RTVfsLockRelease(pThis->hLock);
999 pThis->hLock = NIL_RTVFSLOCK;
1000 }
1001 RTMemFree(pvToFree);
1002}
1003
1004
1005/**
1006 * Internal object releaser that asserts sanity in strict builds.
1007 *
1008 * @returns The new reference count.
1009 * @param pcRefs The reference counter.
1010 */
1011DECLINLINE(uint32_t) rtVfsObjRelease(RTVFSOBJINTERNAL *pThis)
1012{
1013 uint32_t cRefs = ASMAtomicDecU32(&pThis->cRefs);
1014 AssertMsg(cRefs < _1M, ("%#x %p ops=%p %s (%d)\n", cRefs, pThis, pThis->pOps, pThis->pOps->pszName, pThis->pOps->enmType));
1015 LogFlow(("rtVfsObjRelease(%p/%p) -> %d\n", pThis, pThis->pvThis, cRefs));
1016 if (cRefs == 0)
1017 rtVfsObjDestroy(pThis);
1018 return cRefs;
1019}
1020
1021
1022RTDECL(uint32_t) RTVfsObjRelease(RTVFSOBJ hVfsObj)
1023{
1024 RTVFSOBJINTERNAL *pThis = hVfsObj;
1025 if (pThis == NIL_RTVFSOBJ)
1026 return 0;
1027 AssertPtrReturn(pThis, UINT32_MAX);
1028 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, UINT32_MAX);
1029 return rtVfsObjRelease(pThis);
1030}
1031
1032
1033RTDECL(RTVFSOBJTYPE) RTVfsObjGetType(RTVFSOBJ hVfsObj)
1034{
1035 RTVFSOBJINTERNAL *pThis = hVfsObj;
1036 if (pThis != NIL_RTVFSOBJ)
1037 {
1038 AssertPtrReturn(pThis, RTVFSOBJTYPE_INVALID);
1039 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, RTVFSOBJTYPE_INVALID);
1040 return pThis->pOps->enmType;
1041 }
1042 return RTVFSOBJTYPE_INVALID;
1043}
1044
1045
1046RTDECL(RTVFS) RTVfsObjToVfs(RTVFSOBJ hVfsObj)
1047{
1048 RTVFSOBJINTERNAL *pThis = hVfsObj;
1049 if (pThis != NIL_RTVFSOBJ)
1050 {
1051 AssertPtrReturn(pThis, NIL_RTVFS);
1052 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFS);
1053
1054 if (pThis->pOps->enmType == RTVFSOBJTYPE_VFS)
1055 {
1056 rtVfsObjRetainVoid(pThis, "RTVfsObjToVfs");
1057 LogFlow(("RTVfsObjToVfs(%p) -> %p\n", pThis, RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base)));
1058 return RT_FROM_MEMBER(pThis, RTVFSINTERNAL, Base);
1059 }
1060 }
1061 return NIL_RTVFS;
1062}
1063
1064
1065RTDECL(RTVFSFSSTREAM) RTVfsObjToFsStream(RTVFSOBJ hVfsObj)
1066{
1067 RTVFSOBJINTERNAL *pThis = hVfsObj;
1068 if (pThis != NIL_RTVFSOBJ)
1069 {
1070 AssertPtrReturn(pThis, NIL_RTVFSFSSTREAM);
1071 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFSSTREAM);
1072
1073 if (pThis->pOps->enmType == RTVFSOBJTYPE_FS_STREAM)
1074 {
1075 rtVfsObjRetainVoid(pThis, "RTVfsObjToFsStream");
1076 return RT_FROM_MEMBER(pThis, RTVFSFSSTREAMINTERNAL, Base);
1077 }
1078 }
1079 return NIL_RTVFSFSSTREAM;
1080}
1081
1082
1083RTDECL(RTVFSDIR) RTVfsObjToDir(RTVFSOBJ hVfsObj)
1084{
1085 RTVFSOBJINTERNAL *pThis = hVfsObj;
1086 if (pThis != NIL_RTVFSOBJ)
1087 {
1088 AssertPtrReturn(pThis, NIL_RTVFSDIR);
1089 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSDIR);
1090
1091 if (pThis->pOps->enmType == RTVFSOBJTYPE_DIR)
1092 {
1093 rtVfsObjRetainVoid(pThis, "RTVfsObjToDir");
1094 return RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base);
1095 }
1096 }
1097 return NIL_RTVFSDIR;
1098}
1099
1100
1101RTDECL(RTVFSIOSTREAM) RTVfsObjToIoStream(RTVFSOBJ hVfsObj)
1102{
1103 RTVFSOBJINTERNAL *pThis = hVfsObj;
1104 if (pThis != NIL_RTVFSOBJ)
1105 {
1106 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
1107 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSIOSTREAM);
1108
1109 if ( pThis->pOps->enmType == RTVFSOBJTYPE_IO_STREAM
1110 || pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1111 {
1112 rtVfsObjRetainVoid(pThis, "RTVfsObjToIoStream");
1113 return RT_FROM_MEMBER(pThis, RTVFSIOSTREAMINTERNAL, Base);
1114 }
1115 }
1116 return NIL_RTVFSIOSTREAM;
1117}
1118
1119
1120RTDECL(RTVFSFILE) RTVfsObjToFile(RTVFSOBJ hVfsObj)
1121{
1122 RTVFSOBJINTERNAL *pThis = hVfsObj;
1123 if (pThis != NIL_RTVFSOBJ)
1124 {
1125 AssertPtrReturn(pThis, NIL_RTVFSFILE);
1126 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSFILE);
1127
1128 if (pThis->pOps->enmType == RTVFSOBJTYPE_FILE)
1129 {
1130 rtVfsObjRetainVoid(pThis, "RTVfsObjToFile");
1131 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base);
1132 }
1133 }
1134 return NIL_RTVFSFILE;
1135}
1136
1137
1138RTDECL(RTVFSSYMLINK) RTVfsObjToSymlink(RTVFSOBJ hVfsObj)
1139{
1140 RTVFSOBJINTERNAL *pThis = hVfsObj;
1141 if (pThis != NIL_RTVFSOBJ)
1142 {
1143 AssertPtrReturn(pThis, NIL_RTVFSSYMLINK);
1144 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSSYMLINK);
1145
1146 if (pThis->pOps->enmType == RTVFSOBJTYPE_SYMLINK)
1147 {
1148 rtVfsObjRetainVoid(pThis, "RTVfsObjToSymlink");
1149 return RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base);
1150 }
1151 }
1152 return NIL_RTVFSSYMLINK;
1153}
1154
1155
1156RTDECL(RTVFSOBJ) RTVfsObjFromVfs(RTVFS hVfs)
1157{
1158 if (hVfs != NIL_RTVFS)
1159 {
1160 RTVFSOBJINTERNAL *pThis = &hVfs->Base;
1161 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1162 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1163
1164 rtVfsObjRetainVoid(pThis, "RTVfsObjFromVfs");
1165 LogFlow(("RTVfsObjFromVfs(%p) -> %p\n", hVfs, pThis));
1166 return pThis;
1167 }
1168 return NIL_RTVFSOBJ;
1169}
1170
1171
1172RTDECL(RTVFSOBJ) RTVfsObjFromFsStream(RTVFSFSSTREAM hVfsFss)
1173{
1174 if (hVfsFss != NIL_RTVFSFSSTREAM)
1175 {
1176 RTVFSOBJINTERNAL *pThis = &hVfsFss->Base;
1177 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1178 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1179
1180 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFsStream");
1181 return pThis;
1182 }
1183 return NIL_RTVFSOBJ;
1184}
1185
1186
1187RTDECL(RTVFSOBJ) RTVfsObjFromDir(RTVFSDIR hVfsDir)
1188{
1189 if (hVfsDir != NIL_RTVFSDIR)
1190 {
1191 RTVFSOBJINTERNAL *pThis = &hVfsDir->Base;
1192 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1193 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1194
1195 rtVfsObjRetainVoid(pThis, "RTVfsObjFromDir");
1196 return pThis;
1197 }
1198 return NIL_RTVFSOBJ;
1199}
1200
1201
1202RTDECL(RTVFSOBJ) RTVfsObjFromIoStream(RTVFSIOSTREAM hVfsIos)
1203{
1204 if (hVfsIos != NIL_RTVFSIOSTREAM)
1205 {
1206 RTVFSOBJINTERNAL *pThis = &hVfsIos->Base;
1207 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1208 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1209
1210 rtVfsObjRetainVoid(pThis, "RTVfsObjFromIoStream");
1211 return pThis;
1212 }
1213 return NIL_RTVFSOBJ;
1214}
1215
1216
1217RTDECL(RTVFSOBJ) RTVfsObjFromFile(RTVFSFILE hVfsFile)
1218{
1219 if (hVfsFile != NIL_RTVFSFILE)
1220 {
1221 RTVFSOBJINTERNAL *pThis = &hVfsFile->Stream.Base;
1222 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1223 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1224
1225 rtVfsObjRetainVoid(pThis, "RTVfsObjFromFile");
1226 return pThis;
1227 }
1228 return NIL_RTVFSOBJ;
1229}
1230
1231
1232RTDECL(RTVFSOBJ) RTVfsObjFromSymlink(RTVFSSYMLINK hVfsSym)
1233{
1234 if (hVfsSym != NIL_RTVFSSYMLINK)
1235 {
1236 RTVFSOBJINTERNAL *pThis = &hVfsSym->Base;
1237 AssertPtrReturn(pThis, NIL_RTVFSOBJ);
1238 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, NIL_RTVFSOBJ);
1239
1240 rtVfsObjRetainVoid(pThis, "RTVfsObjFromSymlink");
1241 return pThis;
1242 }
1243 return NIL_RTVFSOBJ;
1244}
1245
1246
1247RTDECL(int) RTVfsObjOpen(RTVFS hVfs, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
1248{
1249 /*
1250 * Validate input.
1251 */
1252 RTVFSINTERNAL *pThis = hVfs;
1253 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1254 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
1255 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1256 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
1257
1258 int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
1259 if (RT_FAILURE(rc))
1260 return rc;
1261 AssertMsgReturn( RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
1262 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
1263 ("fObjFlags=%#x\n", fObjFlags),
1264 VERR_INVALID_FLAGS);
1265 /*
1266 * Parse the path, assume current directory is root since we've got no
1267 * caller context here.
1268 */
1269 PRTVFSPARSEDPATH pPath;
1270 rc = RTVfsParsePathA(pszPath, "/", &pPath);
1271 if (RT_SUCCESS(rc))
1272 {
1273 /*
1274 * Tranverse the path, resolving the parent node.
1275 * We'll do the symbolic link checking here with help of pfnOpen.
1276 */
1277 RTVFSDIRINTERNAL *pVfsParentDir;
1278 rc = rtVfsTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
1279 if (RT_SUCCESS(rc))
1280 {
1281
1282 /*
1283 * Do the opening. Loop if we need to follow symbolic links.
1284 */
1285 for (uint32_t cLoops = 1; ; cLoops++)
1286 {
1287 /* If we end with a directory slash, adjust open flags. */
1288 if (pPath->fDirSlash)
1289 {
1290 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
1291 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
1292 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
1293 }
1294 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
1295 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
1296
1297 /* Open it. */
1298 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
1299 RTVFSOBJ hVfsObj;
1300 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
1301 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
1302 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
1303 if (RT_FAILURE(rc))
1304 break;
1305
1306 /* We're done if we don't follow links or this wasn't a link. */
1307 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
1308 || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
1309 {
1310 *phVfsObj = hVfsObj;
1311 break;
1312 }
1313
1314 /* Follow symbolic link. */
1315 if (cLoops < RTVFS_MAX_LINKS)
1316 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
1317 else
1318 rc = VERR_TOO_MANY_SYMLINKS;
1319 RTVfsObjRelease(hVfsObj);
1320 if (RT_FAILURE(rc))
1321 break;
1322 }
1323 RTVfsDirRelease(pVfsParentDir);
1324 }
1325 RTVfsParsePathFree(pPath);
1326 }
1327 return rc;
1328}
1329
1330
1331RTDECL(int) RTVfsObjQueryInfo(RTVFSOBJ hVfsObj, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
1332{
1333 RTVFSOBJINTERNAL *pThis = hVfsObj;
1334 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1335 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1336
1337 RTVfsLockAcquireRead(pThis->hLock);
1338 int rc = pThis->pOps->pfnQueryInfo(pThis->pvThis, pObjInfo, enmAddAttr);
1339 RTVfsLockReleaseRead(pThis->hLock);
1340 return rc;
1341}
1342
1343
1344/**
1345 * Gets the RTVFSOBJSETOPS for the given base object.
1346 *
1347 * @returns Pointer to the vtable if supported by the type, otherwise NULL.
1348 * @param pThis The base object.
1349 */
1350static PCRTVFSOBJSETOPS rtVfsObjGetSetOps(RTVFSOBJINTERNAL *pThis)
1351{
1352 switch (pThis->pOps->enmType)
1353 {
1354 case RTVFSOBJTYPE_DIR:
1355 return &RT_FROM_MEMBER(pThis, RTVFSDIRINTERNAL, Base)->pOps->ObjSet;
1356 case RTVFSOBJTYPE_FILE:
1357 return &RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream.Base)->pOps->ObjSet;
1358 case RTVFSOBJTYPE_SYMLINK:
1359 return &RT_FROM_MEMBER(pThis, RTVFSSYMLINKINTERNAL, Base)->pOps->ObjSet;
1360 default:
1361 return NULL;
1362 }
1363}
1364
1365
1366RTDECL(int) RTVfsObjSetMode(RTVFSOBJ hVfsObj, RTFMODE fMode, RTFMODE fMask)
1367{
1368 RTVFSOBJINTERNAL *pThis = hVfsObj;
1369 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1370 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1371
1372 fMode = rtFsModeNormalize(fMode, NULL, 0, 0);
1373 if (!rtFsModeIsValid(fMode))
1374 return VERR_INVALID_PARAMETER;
1375
1376 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1377 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1378
1379 int rc;
1380 if (pObjSetOps->pfnSetMode)
1381 {
1382 RTVfsLockAcquireWrite(pThis->hLock);
1383 rc = pObjSetOps->pfnSetMode(pThis->pvThis, fMode, fMask);
1384 RTVfsLockReleaseWrite(pThis->hLock);
1385 }
1386 else
1387 rc = VERR_WRITE_PROTECT;
1388 return rc;
1389}
1390
1391
1392RTDECL(int) RTVfsObjSetTimes(RTVFSOBJ hVfsObj, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
1393 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
1394{
1395 RTVFSOBJINTERNAL *pThis = hVfsObj;
1396 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1397 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1398
1399 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
1400 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
1401 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
1402 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
1403
1404 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1405 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1406
1407 int rc;
1408 if (pObjSetOps->pfnSetTimes)
1409 {
1410 RTVfsLockAcquireWrite(pThis->hLock);
1411 rc = pObjSetOps->pfnSetTimes(pThis->pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
1412 RTVfsLockReleaseWrite(pThis->hLock);
1413 }
1414 else
1415 rc = VERR_WRITE_PROTECT;
1416 return rc;
1417}
1418
1419
1420RTDECL(int) RTVfsObjSetOwner(RTVFSOBJ hVfsObj, RTUID uid, RTGID gid)
1421{
1422 RTVFSOBJINTERNAL *pThis = hVfsObj;
1423 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
1424 AssertReturn(pThis->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
1425
1426 PCRTVFSOBJSETOPS pObjSetOps = rtVfsObjGetSetOps(pThis);
1427 AssertReturn(pObjSetOps, VERR_INVALID_FUNCTION);
1428
1429 int rc;
1430 if (pObjSetOps->pfnSetOwner)
1431 {
1432 RTVfsLockAcquireWrite(pThis->hLock);
1433 rc = pObjSetOps->pfnSetOwner(pThis->pvThis, uid, gid);
1434 RTVfsLockReleaseWrite(pThis->hLock);
1435 }
1436 else
1437 rc = VERR_WRITE_PROTECT;
1438 return rc;
1439}
1440
1441
1442/*
1443 *
1444 * U T I L U T I L U T I L
1445 * U T I L U T I L U T I L
1446 * U T I L U T I L U T I L
1447 *
1448 */
1449
1450
1451RTDECL(int) RTVfsParsePathAppend(PRTVFSPARSEDPATH pPath, const char *pszPath, uint16_t *piRestartComp)
1452{
1453 AssertReturn(*pszPath != '/' && *pszPath != '\\', VERR_INTERNAL_ERROR_4);
1454
1455 /* In case *piRestartComp was set higher than the number of components
1456 before making the call to this function. */
1457 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1458 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1459
1460/** @todo The '..' handling doesn't really work wrt to symbolic links in the
1461 * path. */
1462
1463 /*
1464 * Append a slash to the destination path if necessary.
1465 */
1466 char * const pszDst = pPath->szPath;
1467 size_t offDst = pPath->cch;
1468 if (pPath->cComponents > 0)
1469 {
1470 pszDst[offDst++] = '/';
1471 if (offDst >= RTVFSPARSEDPATH_MAX)
1472 return VERR_FILENAME_TOO_LONG;
1473 }
1474 if (pPath->fAbsolute)
1475 Assert(pszDst[offDst - 1] == '/' && pszDst[0] == '/');
1476 else
1477 Assert(offDst == 0 || (pszDst[0] != '/' && pszDst[offDst - 1] == '/'));
1478
1479 /*
1480 * Parse and append the relative path.
1481 */
1482 const char *pszSrc = pszPath;
1483 pPath->fDirSlash = false;
1484 for (;;)
1485 {
1486 /* Copy until we encounter the next slash. */
1487 pPath->aoffComponents[pPath->cComponents++] = (uint16_t)offDst;
1488 for (;;)
1489 {
1490 char ch = *pszSrc++;
1491 if ( ch != '/'
1492 && ch != '\\'
1493 && ch != '\0')
1494 {
1495 pszDst[offDst++] = ch;
1496 if (offDst < RTVFSPARSEDPATH_MAX)
1497 { /* likely */ }
1498 else
1499 return VERR_FILENAME_TOO_LONG;
1500 }
1501 else
1502 {
1503 /* Deal with dot components before we processes the slash/end. */
1504 if (pszDst[offDst - 1] == '.')
1505 {
1506 if ( offDst == 1
1507 || pszDst[offDst - 2] == '/')
1508 {
1509 pPath->cComponents--;
1510 offDst = pPath->aoffComponents[pPath->cComponents];
1511 }
1512 else if ( offDst > 3
1513 && pszDst[offDst - 2] == '.'
1514 && pszDst[offDst - 3] == '/')
1515 {
1516 if ( pPath->fAbsolute
1517 || offDst < 5
1518 || pszDst[offDst - 4] != '.'
1519 || pszDst[offDst - 5] != '.'
1520 || (offDst >= 6 && pszDst[offDst - 6] != '/') )
1521 {
1522 pPath->cComponents -= pPath->cComponents > 1 ? 2 : 1;
1523 offDst = pPath->aoffComponents[pPath->cComponents];
1524 if (piRestartComp && *piRestartComp + 1 >= pPath->cComponents)
1525 *piRestartComp = pPath->cComponents > 0 ? pPath->cComponents - 1 : 0;
1526 }
1527 }
1528 }
1529
1530 if (ch != '\0')
1531 {
1532 /* Skip unnecessary slashes and check for end of path. */
1533 while ((ch = *pszSrc) == '/' || ch == '\\')
1534 pszSrc++;
1535
1536 if (ch == '\0')
1537 pPath->fDirSlash = true;
1538 }
1539
1540 if (ch == '\0')
1541 {
1542 /* Drop trailing slash unless it's the root slash. */
1543 if ( offDst > 0
1544 && pszDst[offDst - 1] == '/'
1545 && ( !pPath->fAbsolute
1546 || offDst > 1))
1547 offDst--;
1548
1549 /* Terminate the string and enter its length. */
1550 pszDst[offDst] = '\0';
1551 pszDst[offDst + 1] = '\0'; /* for aoffComponents[pPath->cComponents] */
1552 pPath->cch = (uint16_t)offDst;
1553 pPath->aoffComponents[pPath->cComponents] = (uint16_t)(offDst + 1);
1554 return VINF_SUCCESS;
1555 }
1556
1557 /* Append component separator before continuing with the next component. */
1558 if (offDst > 0 && pszDst[offDst - 1] != '/')
1559 pszDst[offDst++] = '/';
1560 if (offDst >= RTVFSPARSEDPATH_MAX)
1561 return VERR_FILENAME_TOO_LONG;
1562 break;
1563 }
1564 }
1565 }
1566}
1567
1568
1569/** @todo Replace RTVfsParsePath with RTPathParse and friends? */
1570RTDECL(int) RTVfsParsePath(PRTVFSPARSEDPATH pPath, const char *pszPath, const char *pszCwd)
1571{
1572 if (*pszPath != '/' && *pszPath != '\\')
1573 {
1574 if (pszCwd)
1575 {
1576 /*
1577 * Relative with a CWD.
1578 */
1579 int rc = RTVfsParsePath(pPath, pszCwd, NULL /*crash if pszCwd is not absolute*/);
1580 if (RT_FAILURE(rc))
1581 return rc;
1582 }
1583 else
1584 {
1585 /*
1586 * Relative.
1587 */
1588 pPath->cch = 0;
1589 pPath->cComponents = 0;
1590 pPath->fDirSlash = false;
1591 pPath->fAbsolute = false;
1592 pPath->aoffComponents[0] = 0;
1593 pPath->aoffComponents[1] = 1;
1594 pPath->szPath[0] = '\0';
1595 pPath->szPath[1] = '\0';
1596 }
1597 }
1598 else
1599 {
1600 /*
1601 * Make pszPath relative, i.e. set up pPath for the root and skip
1602 * leading slashes in pszPath before appending it.
1603 */
1604 pPath->cch = 1;
1605 pPath->cComponents = 0;
1606 pPath->fDirSlash = false;
1607 pPath->fAbsolute = true;
1608 pPath->aoffComponents[0] = 1;
1609 pPath->aoffComponents[1] = 2;
1610 pPath->szPath[0] = '/';
1611 pPath->szPath[1] = '\0';
1612 pPath->szPath[2] = '\0';
1613 while (pszPath[0] == '/' || pszPath[0] == '\\')
1614 pszPath++;
1615 if (!pszPath[0])
1616 return VINF_SUCCESS;
1617 }
1618 return RTVfsParsePathAppend(pPath, pszPath, NULL);
1619}
1620
1621
1622
1623RTDECL(int) RTVfsParsePathA(const char *pszPath, const char *pszCwd, PRTVFSPARSEDPATH *ppPath)
1624{
1625 /*
1626 * Allocate the output buffer and hand the problem to rtVfsParsePath.
1627 */
1628 int rc;
1629 PRTVFSPARSEDPATH pPath = (PRTVFSPARSEDPATH)RTMemTmpAlloc(sizeof(RTVFSPARSEDPATH));
1630 if (pPath)
1631 {
1632 rc = RTVfsParsePath(pPath, pszPath, pszCwd);
1633 if (RT_FAILURE(rc))
1634 {
1635 RTMemTmpFree(pPath);
1636 pPath = NULL;
1637 }
1638 }
1639 else
1640 rc = VERR_NO_TMP_MEMORY;
1641 *ppPath = pPath; /* always set it */
1642 return rc;
1643}
1644
1645
1646RTDECL(void) RTVfsParsePathFree(PRTVFSPARSEDPATH pPath)
1647{
1648 if (pPath)
1649 {
1650 pPath->cch = UINT16_MAX;
1651 pPath->cComponents = UINT16_MAX;
1652 pPath->aoffComponents[0] = UINT16_MAX;
1653 pPath->aoffComponents[1] = UINT16_MAX;
1654 RTMemTmpFree(pPath);
1655 }
1656}
1657
1658
1659/**
1660 * Handles a symbolic link, adding it to
1661 *
1662 * @returns IPRT status code.
1663 * @param ppCurDir The current directory variable. We change it if
1664 * the symbolic links is absolute.
1665 * @param pPath The parsed path to update.
1666 * @param iPathComponent The current path component.
1667 * @param hSymlink The symbolic link to process.
1668 */
1669static int rtVfsTraverseHandleSymlink(RTVFSDIRINTERNAL **ppCurDir, PRTVFSPARSEDPATH pPath,
1670 uint16_t iPathComponent, RTVFSSYMLINK hSymlink)
1671{
1672 /*
1673 * Read the link and append the trailing path to it.
1674 */
1675 char szPath[RTPATH_MAX];
1676 int rc = RTVfsSymlinkRead(hSymlink, szPath, sizeof(szPath) - 1);
1677 if (RT_SUCCESS(rc))
1678 {
1679 szPath[sizeof(szPath) - 1] = '\0';
1680 if (iPathComponent + 1 < pPath->cComponents)
1681 rc = RTPathAppend(szPath, sizeof(szPath), &pPath->szPath[pPath->aoffComponents[iPathComponent + 1]]);
1682 }
1683 if (RT_SUCCESS(rc))
1684 {
1685 /*
1686 * Special hack help vfsstddir.cpp deal with symbolic links.
1687 */
1688 RTVFSDIRINTERNAL *pCurDir = *ppCurDir;
1689 char *pszPath = szPath;
1690 if (pCurDir->pOps->pfnFollowAbsoluteSymlink)
1691 {
1692 size_t cchRoot = rtPathRootSpecLen(szPath);
1693 if (cchRoot > 0)
1694 {
1695 pszPath = &szPath[cchRoot];
1696 char const chSaved = *pszPath;
1697 *pszPath = '\0';
1698 RTVFSDIRINTERNAL *pVfsRootDir;
1699 RTVfsLockAcquireWrite(pCurDir->Base.hLock);
1700 rc = pCurDir->pOps->pfnFollowAbsoluteSymlink(pCurDir, szPath, &pVfsRootDir);
1701 RTVfsLockAcquireWrite(pCurDir->Base.hLock);
1702 *pszPath = chSaved;
1703 if (RT_SUCCESS(rc))
1704 {
1705 RTVfsDirRelease(pCurDir);
1706 *ppCurDir = pCurDir = pVfsRootDir;
1707 }
1708 else if (rc == VERR_PATH_IS_RELATIVE)
1709 pszPath = szPath;
1710 else
1711 return rc;
1712 }
1713 }
1714
1715 rc = RTVfsParsePath(pPath, pszPath, NULL);
1716 if (RT_SUCCESS(rc))
1717 {
1718 /*
1719 * Deal with absolute references in a VFS setup.
1720 * Note! The current approach only correctly handles this on root volumes.
1721 */
1722 if ( pPath->fAbsolute
1723 && pCurDir->Base.hVfs != NIL_RTVFS) /** @todo This needs fixing once we implement mount points. */
1724 {
1725 RTVFSINTERNAL *pVfs = pCurDir->Base.hVfs;
1726 RTVFSDIRINTERNAL *pVfsRootDir;
1727 RTVfsLockAcquireRead(pVfs->Base.hLock);
1728 rc = pVfs->pOps->pfnOpenRoot(pVfs->Base.pvThis, &pVfsRootDir);
1729 RTVfsLockReleaseRead(pVfs->Base.hLock);
1730 if (RT_SUCCESS(rc))
1731 {
1732 RTVfsDirRelease(pCurDir);
1733 *ppCurDir = pCurDir = pVfsRootDir;
1734 }
1735 else
1736 return rc;
1737 }
1738 }
1739 }
1740 else if (rc == VERR_BUFFER_OVERFLOW)
1741 rc = VERR_FILENAME_TOO_LONG;
1742 return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;
1743}
1744
1745
1746/**
1747 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1748 *
1749 *
1750 * @returns IPRT status code.
1751 * @param pThis The VFS.
1752 * @param pPath The parsed path. This may be changed as symbolic
1753 * links are processed during the path traversal. If
1754 * it contains zero components, a dummy component is
1755 * added to assist the caller.
1756 * @param fFlags RTPATH_F_XXX.
1757 * @param ppVfsParentDir Where to return the parent directory handle
1758 * (referenced).
1759 */
1760static int rtVfsDirTraverseToParent(RTVFSDIRINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags,
1761 RTVFSDIRINTERNAL **ppVfsParentDir)
1762{
1763 /*
1764 * Assert sanity.
1765 */
1766 AssertPtr(pThis);
1767 Assert(pThis->uMagic == RTVFSDIR_MAGIC);
1768 Assert(pThis->Base.cRefs > 0);
1769 AssertPtr(pPath);
1770 AssertPtr(ppVfsParentDir);
1771 *ppVfsParentDir = NULL;
1772 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1773
1774 /*
1775 * Start with the pThis directory.
1776 */
1777 if (RTVfsDirRetain(pThis) == UINT32_MAX)
1778 return VERR_INVALID_HANDLE;
1779 RTVFSDIRINTERNAL *pCurDir = pThis;
1780
1781 /*
1782 * Special case for traversing zero components.
1783 * We fake up a "./" in the pPath to help the caller along.
1784 */
1785 if (pPath->cComponents == 0)
1786 {
1787 pPath->fDirSlash = true;
1788 pPath->szPath[0] = '.';
1789 pPath->szPath[1] = '\0';
1790 pPath->szPath[2] = '\0';
1791 pPath->cch = 1;
1792 pPath->cComponents = 1;
1793 pPath->aoffComponents[0] = 0;
1794 pPath->aoffComponents[1] = 1;
1795 pPath->aoffComponents[2] = 1;
1796
1797 *ppVfsParentDir = pCurDir;
1798 return VINF_SUCCESS;
1799 }
1800
1801
1802 /*
1803 * The traversal loop.
1804 */
1805 int rc = VINF_SUCCESS;
1806 unsigned cLinks = 0;
1807 uint16_t iComponent = 0;
1808 for (;;)
1809 {
1810 /*
1811 * Are we done yet?
1812 */
1813 bool fFinal = iComponent + 1 >= pPath->cComponents;
1814 if (fFinal && (fFlags & RTPATH_F_ON_LINK))
1815 {
1816 *ppVfsParentDir = pCurDir;
1817 return VINF_SUCCESS;
1818 }
1819
1820 /*
1821 * Try open the next entry.
1822 */
1823 const char *pszEntry = &pPath->szPath[pPath->aoffComponents[iComponent]];
1824 char *pszEntryEnd = &pPath->szPath[pPath->aoffComponents[iComponent + 1] - 1];
1825 *pszEntryEnd = '\0';
1826 RTVFSDIR hDir = NIL_RTVFSDIR;
1827 RTVFSSYMLINK hSymlink = NIL_RTVFSSYMLINK;
1828 RTVFS hVfsMnt = NIL_RTVFS;
1829 RTVFSOBJ hVfsObj = NIL_RTVFSOBJ;
1830 if (fFinal)
1831 {
1832 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1833 rc = pCurDir->pOps->pfnOpen(pCurDir->Base.pvThis, pszEntry,
1834 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1835 RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING
1836 | RTVFSOBJ_F_TRAVERSAL | RTPATH_F_ON_LINK,
1837 &hVfsObj);
1838 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1839 *pszEntryEnd = '\0';
1840 if (RT_FAILURE(rc))
1841 {
1842 if ( rc == VERR_PATH_NOT_FOUND
1843 || rc == VERR_FILE_NOT_FOUND
1844 || rc == VERR_IS_A_DIRECTORY
1845 || rc == VERR_IS_A_FILE
1846 || rc == VERR_IS_A_FIFO
1847 || rc == VERR_IS_A_SOCKET
1848 || rc == VERR_IS_A_CHAR_DEVICE
1849 || rc == VERR_IS_A_BLOCK_DEVICE
1850 || rc == VERR_NOT_SYMLINK)
1851 {
1852 *ppVfsParentDir = pCurDir;
1853 return VINF_SUCCESS;
1854 }
1855 break;
1856 }
1857 hSymlink = RTVfsObjToSymlink(hVfsObj);
1858 Assert(hSymlink != NIL_RTVFSSYMLINK);
1859 }
1860 else
1861 {
1862 RTVfsLockAcquireRead(pCurDir->Base.hLock);
1863 rc = pCurDir->pOps->pfnOpen(pCurDir->Base.pvThis, pszEntry,
1864 RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
1865 RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_OPEN_MOUNT
1866 | RTVFSOBJ_F_CREATE_NOTHING | RTVFSOBJ_F_TRAVERSAL | RTPATH_F_ON_LINK,
1867 &hVfsObj);
1868 RTVfsLockReleaseRead(pCurDir->Base.hLock);
1869 *pszEntryEnd = '/';
1870 if (RT_FAILURE(rc))
1871 {
1872 if (rc == VERR_FILE_NOT_FOUND)
1873 rc = VERR_PATH_NOT_FOUND;
1874 break;
1875 }
1876 hDir = RTVfsObjToDir(hVfsObj);
1877 hSymlink = RTVfsObjToSymlink(hVfsObj);
1878 hVfsMnt = RTVfsObjToVfs(hVfsObj);
1879 }
1880 Assert( (hDir != NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1881 || (hDir == NIL_RTVFSDIR && hSymlink != NIL_RTVFSSYMLINK && hVfsMnt == NIL_RTVFS)
1882 || (hDir == NIL_RTVFSDIR && hSymlink == NIL_RTVFSSYMLINK && hVfsMnt != NIL_RTVFS));
1883 RTVfsObjRelease(hVfsObj);
1884
1885 if (hDir != NIL_RTVFSDIR)
1886 {
1887 /*
1888 * Directory - advance down the path.
1889 */
1890 AssertPtr(hDir);
1891 Assert(hDir->uMagic == RTVFSDIR_MAGIC);
1892 RTVfsDirRelease(pCurDir);
1893 pCurDir = hDir;
1894 iComponent++;
1895 }
1896 else if (hSymlink != NIL_RTVFSSYMLINK)
1897 {
1898 /*
1899 * Symbolic link - deal with it and retry the current component.
1900 */
1901 AssertPtr(hSymlink);
1902 Assert(hSymlink->uMagic == RTVFSSYMLINK_MAGIC);
1903 if (fFlags & RTPATH_F_NO_SYMLINKS)
1904 {
1905 rc = VERR_SYMLINK_NOT_ALLOWED;
1906 break;
1907 }
1908 cLinks++;
1909 if (cLinks >= RTVFS_MAX_LINKS)
1910 {
1911 rc = VERR_TOO_MANY_SYMLINKS;
1912 break;
1913 }
1914 rc = rtVfsTraverseHandleSymlink(&pCurDir, pPath, iComponent, hSymlink);
1915 if (RT_FAILURE(rc))
1916 break;
1917 iComponent = 0;
1918 }
1919 else
1920 {
1921 /*
1922 * Mount point - deal with it and retry the current component.
1923 */
1924 RTVfsDirRelease(pCurDir);
1925 RTVfsLockAcquireRead(hVfsMnt->Base.hLock);
1926 rc = hVfsMnt->pOps->pfnOpenRoot(hVfsMnt->Base.pvThis, &pCurDir);
1927 RTVfsLockReleaseRead(hVfsMnt->Base.hLock);
1928 if (RT_FAILURE(rc))
1929 {
1930 pCurDir = NULL;
1931 break;
1932 }
1933 iComponent = 0;
1934 /** @todo union mounts. */
1935 }
1936 }
1937
1938 if (pCurDir)
1939 RTVfsDirRelease(pCurDir);
1940
1941 return rc;
1942}
1943
1944
1945/**
1946 * Internal worker for various open functions as well as RTVfsTraverseToParent.
1947 *
1948 * @returns IPRT status code.
1949 * @param pThis The VFS.
1950 * @param pPath The parsed path. This may be changed as symbolic
1951 * links are processed during the path traversal.
1952 * @param fFlags RTPATH_F_XXX.
1953 * @param ppVfsParentDir Where to return the parent directory handle
1954 * (referenced).
1955 */
1956static int rtVfsTraverseToParent(RTVFSINTERNAL *pThis, PRTVFSPARSEDPATH pPath, uint32_t fFlags, RTVFSDIRINTERNAL **ppVfsParentDir)
1957{
1958 /*
1959 * Assert sanity.
1960 */
1961 AssertPtr(pThis);
1962 Assert(pThis->uMagic == RTVFS_MAGIC);
1963 Assert(pThis->Base.cRefs > 0);
1964 AssertPtr(pPath);
1965 AssertPtr(ppVfsParentDir);
1966 *ppVfsParentDir = NULL;
1967 Assert(RTPATH_F_IS_VALID(fFlags, 0));
1968
1969 /*
1970 * Open the root directory and join paths with the directory traversal.
1971 */
1972 /** @todo Union mounts, traversal optimization methods, races, ++ */
1973 RTVFSDIRINTERNAL *pRootDir;
1974 RTVfsLockAcquireRead(pThis->Base.hLock);
1975 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, &pRootDir);
1976 RTVfsLockReleaseRead(pThis->Base.hLock);
1977 if (RT_SUCCESS(rc))
1978 {
1979 rc = rtVfsDirTraverseToParent(pRootDir, pPath, fFlags, ppVfsParentDir);
1980 RTVfsDirRelease(pRootDir);
1981 }
1982 return rc;
1983}
1984
1985
1986
1987/**
1988 * Follows a symbolic link object to the next parent directory.
1989 *
1990 * @returns IPRT status code
1991 * @param ppVfsParentDir Pointer to the parent directory of @a hVfsObj on
1992 * input, the parent directory of the link target on
1993 * return.
1994 * @param hVfsObj Symbolic link object handle.
1995 * @param pPath Path buffer to use parse the symbolic link target.
1996 * @param fFlags See rtVfsDirTraverseToParent.
1997 */
1998static int rtVfsDirFollowSymlinkObjToParent(RTVFSDIRINTERNAL **ppVfsParentDir, RTVFSOBJ hVfsObj,
1999 PRTVFSPARSEDPATH pPath, uint32_t fFlags)
2000{
2001 RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
2002 AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, VERR_INTERNAL_ERROR_3);
2003
2004 int rc = rtVfsTraverseHandleSymlink(ppVfsParentDir, pPath, pPath->cComponents, hVfsSymlink);
2005 if (RT_SUCCESS(rc))
2006 {
2007 RTVFSDIRINTERNAL *pVfsStartDir = *ppVfsParentDir;
2008 rc = rtVfsDirTraverseToParent(pVfsStartDir, pPath, fFlags, ppVfsParentDir);
2009 RTVfsDirRelease(pVfsStartDir);
2010 }
2011
2012 RTVfsSymlinkRelease(hVfsSymlink);
2013 return rc;
2014}
2015
2016
2017
2018RTDECL(int) RTVfsUtilDummyPollOne(uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr, uint32_t *pfRetEvents)
2019{
2020 NOREF(fEvents);
2021 int rc;
2022 if (fIntr)
2023 rc = RTThreadSleep(cMillies);
2024 else
2025 {
2026 uint64_t uMsStart = RTTimeMilliTS();
2027 do
2028 rc = RTThreadSleep(cMillies);
2029 while ( rc == VERR_INTERRUPTED
2030 && !fIntr
2031 && RTTimeMilliTS() - uMsStart < cMillies);
2032 if (rc == VERR_INTERRUPTED)
2033 rc = VERR_TIMEOUT;
2034 }
2035
2036 *pfRetEvents = 0;
2037 return rc;
2038}
2039
2040
2041RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
2042{
2043 /*
2044 * Allocate a temporary buffer.
2045 */
2046 size_t cbBuf = cbBufHint;
2047 if (!cbBuf)
2048 cbBuf = _64K;
2049 else if (cbBuf < _4K)
2050 cbBuf = _4K;
2051 else if (cbBuf > _1M)
2052 cbBuf = _1M;
2053
2054 void *pvBuf = RTMemTmpAlloc(cbBuf);
2055 if (!pvBuf)
2056 {
2057 cbBuf = _4K;
2058 pvBuf = RTMemTmpAlloc(cbBuf);
2059 if (!pvBuf)
2060 return VERR_NO_TMP_MEMORY;
2061 }
2062
2063 /*
2064 * Pump loop.
2065 */
2066 int rc;
2067 for (;;)
2068 {
2069 size_t cbRead;
2070 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
2071 if (RT_FAILURE(rc))
2072 break;
2073 if (rc == VINF_EOF && cbRead == 0)
2074 break;
2075
2076 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
2077 if (RT_FAILURE(rc))
2078 break;
2079 }
2080
2081 RTMemTmpFree(pvBuf);
2082
2083 /*
2084 * Flush the destination stream on success to make sure we've caught
2085 * errors caused by buffering delays.
2086 */
2087 if (RT_SUCCESS(rc))
2088 rc = RTVfsIoStrmFlush(hVfsIosDst);
2089
2090 return rc;
2091}
2092
2093
2094
2095
2096
2097/*
2098 * F I L E S Y S T E M R O O T
2099 * F I L E S Y S T E M R O O T
2100 * F I L E S Y S T E M R O O T
2101 */
2102
2103
2104RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
2105 PRTVFS phVfs, void **ppvInstance)
2106{
2107 /*
2108 * Validate the input, be extra strict in strict builds.
2109 */
2110 AssertPtr(pVfsOps);
2111 AssertReturn(pVfsOps->uVersion == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
2112 AssertReturn(pVfsOps->uEndMarker == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
2113 RTVFSOBJ_ASSERT_OPS(&pVfsOps->Obj, RTVFSOBJTYPE_VFS);
2114 Assert(cbInstance > 0);
2115 AssertPtr(ppvInstance);
2116 AssertPtr(phVfs);
2117
2118 /*
2119 * Allocate the handle + instance data.
2120 */
2121 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSINTERNAL), RTVFS_INST_ALIGNMENT)
2122 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2123 RTVFSINTERNAL *pThis = (RTVFSINTERNAL *)RTMemAllocZ(cbThis);
2124 if (!pThis)
2125 return VERR_NO_MEMORY;
2126
2127 int rc = rtVfsObjInitNewObject(&pThis->Base, &pVfsOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2128 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2129 if (RT_FAILURE(rc))
2130 {
2131 RTMemFree(pThis);
2132 return rc;
2133 }
2134
2135 pThis->uMagic = RTVFS_MAGIC;
2136 pThis->pOps = pVfsOps;
2137
2138 *phVfs = pThis;
2139 *ppvInstance = pThis->Base.pvThis;
2140
2141 LogFlow(("RTVfsNew -> VINF_SUCCESS; hVfs=%p pvThis=%p\n", pThis, pThis->Base.pvThis));
2142 return VINF_SUCCESS;
2143}
2144
2145#ifdef DEBUG
2146# undef RTVfsRetain
2147#endif
2148RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs)
2149{
2150 RTVFSINTERNAL *pThis = hVfs;
2151 AssertPtrReturn(pThis, UINT32_MAX);
2152 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2153 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2154 LogFlow(("RTVfsRetain(%p/%p) -> %d\n", pThis, pThis->Base.pvThis, cRefs));
2155 return cRefs;
2156}
2157#ifdef DEBUG
2158# define RTVfsRetain(hVfs) RTVfsRetainDebug(hVfs, RT_SRC_POS)
2159#endif
2160
2161
2162RTDECL(uint32_t) RTVfsRetainDebug(RTVFS hVfs, RT_SRC_POS_DECL)
2163{
2164 RTVFSINTERNAL *pThis = hVfs;
2165 AssertPtrReturn(pThis, UINT32_MAX);
2166 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2167 RT_SRC_POS_NOREF();
2168 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsRetainDebug", RT_SRC_POS_ARGS);
2169}
2170
2171
2172RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs)
2173{
2174 RTVFSINTERNAL *pThis = hVfs;
2175 if (pThis == NIL_RTVFS)
2176 return 0;
2177 AssertPtrReturn(pThis, UINT32_MAX);
2178 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2179#ifdef LOG_ENABLED
2180 void *pvThis = pThis->Base.pvThis;
2181#endif
2182 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2183 Log(("RTVfsRelease(%p/%p) -> %d\n", pThis, pvThis, cRefs));
2184 return cRefs;
2185}
2186
2187
2188RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir)
2189{
2190 RTVFSINTERNAL *pThis = hVfs;
2191 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2192 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2193 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
2194 *phDir = NIL_RTVFSDIR;
2195
2196 if (!pThis->pOps->pfnOpenRoot)
2197 return VERR_NOT_SUPPORTED;
2198 RTVfsLockAcquireRead(pThis->Base.hLock);
2199 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phDir);
2200 RTVfsLockReleaseRead(pThis->Base.hLock);
2201
2202 return rc;
2203}
2204
2205
2206RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2207{
2208 RTVFSINTERNAL *pThis = hVfs;
2209 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2210 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2211 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2212 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2213 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2214 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2215 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2216
2217 /*
2218 * Parse the path, assume current directory is root since we've got no
2219 * caller context here. Then traverse to the parent directory.
2220 */
2221 PRTVFSPARSEDPATH pPath;
2222 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2223 if (RT_SUCCESS(rc))
2224 {
2225 /*
2226 * Tranverse the path, resolving the parent node.
2227 * We'll do the symbolic link checking here with help of pfnOpen/pfnQueryEntryInfo.
2228 */
2229 RTVFSDIRINTERNAL *pVfsParentDir;
2230 rc = rtVfsTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2231 if (RT_SUCCESS(rc))
2232 {
2233 /*
2234 * Do the opening. Loop if we need to follow symbolic links.
2235 */
2236 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING;
2237 for (uint32_t cLoops = 1; ; cLoops++)
2238 {
2239 /* If we end with a directory slash, adjust open flags. */
2240 if (pPath->fDirSlash)
2241 {
2242 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
2243 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
2244 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
2245 }
2246 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
2247 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
2248
2249 /* Do the querying. If pfnQueryEntryInfo is available, we use it first,
2250 falling back on pfnOpen in case of symbolic links that needs following. */
2251 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2252 if (pVfsParentDir->pOps->pfnQueryEntryInfo)
2253 {
2254 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2255 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2256 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2257 if (RT_FAILURE(rc))
2258 break;
2259 if ( !RTFS_IS_SYMLINK(pObjInfo->Attr.fMode)
2260 || !(fFlags & RTPATH_F_FOLLOW_LINK))
2261 {
2262 if ( (fObjFlags & RTVFSOBJ_F_OPEN_MASK) != RTVFSOBJ_F_OPEN_ANY
2263 && !RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
2264 rc = VERR_NOT_A_DIRECTORY;
2265 break;
2266 }
2267 }
2268
2269 RTVFSOBJ hVfsObj;
2270 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2271 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName,
2272 RTFILE_O_ACCESS_ATTR_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
2273 fObjFlags, &hVfsObj);
2274 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2275 if (RT_FAILURE(rc))
2276 break;
2277
2278 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2279 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2280 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2281 {
2282 rc = RTVfsObjQueryInfo(hVfsObj, pObjInfo, enmAddAttr);
2283 RTVfsObjRelease(hVfsObj);
2284 break;
2285 }
2286
2287 /* Follow symbolic link. */
2288 if (cLoops < RTVFS_MAX_LINKS)
2289 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2290 else
2291 rc = VERR_TOO_MANY_SYMLINKS;
2292 RTVfsObjRelease(hVfsObj);
2293 if (RT_FAILURE(rc))
2294 break;
2295 }
2296 RTVfsDirRelease(pVfsParentDir);
2297 }
2298 RTVfsParsePathFree(pPath);
2299 }
2300 return rc;
2301}
2302
2303
2304
2305RTDECL(int) RTVfsQueryRangeState(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed)
2306{
2307 RTVFSINTERNAL *pThis = hVfs;
2308 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2309 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2310
2311 if (!pThis->pOps->pfnQueryRangeState)
2312 return VERR_NOT_SUPPORTED;
2313 RTVfsLockAcquireRead(pThis->Base.hLock);
2314 int rc = pThis->pOps->pfnQueryRangeState(pThis->Base.pvThis, off, cb, pfUsed);
2315 RTVfsLockReleaseRead(pThis->Base.hLock);
2316
2317 return rc;
2318}
2319
2320
2321RTDECL(int) RTVfsQueryLabel(RTVFS hVfs, char *pszLabel, size_t cbLabel, size_t *pcbActual)
2322{
2323 RTVFSINTERNAL *pThis = hVfs;
2324 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2325 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2326
2327 if (cbLabel > 0)
2328 AssertPtrReturn(pszLabel, VERR_INVALID_POINTER);
2329
2330 int rc;
2331 if (pThis->pOps->Obj.pfnQueryInfoEx)
2332 {
2333 size_t cbActualIgn;
2334 if (!pcbActual)
2335 pcbActual = &cbActualIgn;
2336
2337 RTVfsLockAcquireRead(pThis->Base.hLock);
2338 rc = pThis->pOps->Obj.pfnQueryInfoEx(pThis->Base.pvThis, RTVFSQIEX_VOL_LABEL, pszLabel, cbLabel, pcbActual);
2339 RTVfsLockReleaseRead(pThis->Base.hLock);
2340 }
2341 else
2342 rc = VERR_NOT_SUPPORTED;
2343 return rc;
2344}
2345
2346
2347
2348/*
2349 *
2350 * F I L E S Y S T E M S T R E A M
2351 * F I L E S Y S T E M S T R E A M
2352 * F I L E S Y S T E M S T R E A M
2353 *
2354 */
2355
2356
2357RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess,
2358 PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
2359{
2360 /*
2361 * Validate the input, be extra strict in strict builds.
2362 */
2363 AssertPtr(pFsStreamOps);
2364 AssertReturn(pFsStreamOps->uVersion == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2365 AssertReturn(pFsStreamOps->uEndMarker == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2366 Assert(!pFsStreamOps->fReserved);
2367 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
2368 Assert((fAccess & (RTFILE_O_READ | RTFILE_O_WRITE)) == fAccess);
2369 Assert(fAccess);
2370 if (fAccess & RTFILE_O_READ)
2371 AssertPtr(pFsStreamOps->pfnNext);
2372 if (fAccess & RTFILE_O_WRITE)
2373 {
2374 AssertPtr(pFsStreamOps->pfnAdd);
2375 AssertPtr(pFsStreamOps->pfnEnd);
2376 }
2377 Assert(cbInstance > 0);
2378 AssertPtr(ppvInstance);
2379 AssertPtr(phVfsFss);
2380 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2381
2382 /*
2383 * Allocate the handle + instance data.
2384 */
2385 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFSSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
2386 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2387 RTVFSFSSTREAMINTERNAL *pThis = (RTVFSFSSTREAMINTERNAL *)RTMemAllocZ(cbThis);
2388 if (!pThis)
2389 return VERR_NO_MEMORY;
2390
2391 int rc = rtVfsObjInitNewObject(&pThis->Base, &pFsStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2392 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2393
2394 if (RT_FAILURE(rc))
2395 {
2396 RTMemFree(pThis);
2397 return rc;
2398 }
2399
2400 pThis->uMagic = RTVFSFSSTREAM_MAGIC;
2401 pThis->pOps = pFsStreamOps;
2402 pThis->fFlags = fAccess;
2403 if (fAccess == RTFILE_O_READ)
2404 pThis->fFlags |= RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
2405 else if (fAccess == RTFILE_O_WRITE)
2406 pThis->fFlags |= RTFILE_O_CREATE | RTFILE_O_DENY_ALL;
2407 else
2408 pThis->fFlags |= RTFILE_O_OPEN | RTFILE_O_DENY_ALL;
2409
2410 *phVfsFss = pThis;
2411 *ppvInstance = pThis->Base.pvThis;
2412 return VINF_SUCCESS;
2413}
2414
2415
2416#ifdef DEBUG
2417# undef RTVfsFsStrmRetain
2418#endif
2419RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss)
2420{
2421 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2422 AssertPtrReturn(pThis, UINT32_MAX);
2423 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2424 return rtVfsObjRetain(&pThis->Base);
2425}
2426#ifdef DEBUG
2427# define RTVfsFsStrmRetain(hVfsFss) RTVfsFsStrmRetainDebug(hVfsFss, RT_SRC_POS)
2428#endif
2429
2430
2431RTDECL(uint32_t) RTVfsFsStrmRetainDebug(RTVFSFSSTREAM hVfsFss, RT_SRC_POS_DECL)
2432{
2433 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2434 AssertPtrReturn(pThis, UINT32_MAX);
2435 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2436 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsFsStrmRetain", RT_SRC_POS_ARGS);
2437}
2438
2439
2440RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss)
2441{
2442 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2443 if (pThis == NIL_RTVFSFSSTREAM)
2444 return 0;
2445 AssertPtrReturn(pThis, UINT32_MAX);
2446 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2447 return rtVfsObjRelease(&pThis->Base);
2448}
2449
2450
2451RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2452{
2453 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2454 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2455 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2456 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2457}
2458
2459
2460RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
2461{
2462 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2463 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2464 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2465 AssertPtrNullReturn(ppszName, VERR_INVALID_POINTER);
2466 if (ppszName)
2467 *ppszName = NULL;
2468 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2469 if (penmType)
2470 *penmType = RTVFSOBJTYPE_INVALID;
2471 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2472 if (phVfsObj)
2473 *phVfsObj = NIL_RTVFSOBJ;
2474
2475 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_INVALID_FUNCTION);
2476
2477 return pThis->pOps->pfnNext(pThis->Base.pvThis, ppszName, penmType, phVfsObj);
2478}
2479
2480
2481RTDECL(int) RTVfsFsStrmAdd(RTVFSFSSTREAM hVfsFss, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)
2482{
2483 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2484 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2485 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2486 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2487 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2488 AssertPtrReturn(hVfsObj, VERR_INVALID_HANDLE);
2489 AssertReturn(hVfsObj->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
2490 AssertReturn(!(fFlags & ~RTVFSFSSTRM_ADD_F_VALID_MASK), VERR_INVALID_FLAGS);
2491 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2492
2493 return pThis->pOps->pfnAdd(pThis->Base.pvThis, pszPath, hVfsObj, fFlags);
2494}
2495
2496
2497RTDECL(int) RTVfsFsStrmPushFile(RTVFSFSSTREAM hVfsFss, const char *pszPath, uint64_t cbFile,
2498 PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
2499{
2500 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2501 AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
2502 *phVfsIos = NIL_RTVFSIOSTREAM;
2503
2504 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2505 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2506
2507 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2508 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2509
2510 AssertReturn(!(fFlags & ~RTVFSFSSTRM_PUSH_F_VALID_MASK), VERR_INVALID_FLAGS);
2511 AssertReturn(RT_BOOL(cbFile == UINT64_MAX) == RT_BOOL(fFlags & RTVFSFSSTRM_PUSH_F_STREAM), VERR_INVALID_FLAGS);
2512
2513 if (cObjInfo)
2514 {
2515 AssertPtrReturn(paObjInfo, VERR_INVALID_POINTER);
2516 AssertReturn(paObjInfo[0].Attr.enmAdditional == RTFSOBJATTRADD_UNIX, VERR_INVALID_PARAMETER);
2517 }
2518
2519 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2520 if (pThis->pOps->pfnPushFile)
2521 return pThis->pOps->pfnPushFile(pThis->Base.pvThis, pszPath, cbFile, paObjInfo, cObjInfo, fFlags, phVfsIos);
2522 return VERR_NOT_SUPPORTED;
2523}
2524
2525
2526RTDECL(int) RTVfsFsStrmEnd(RTVFSFSSTREAM hVfsFss)
2527{
2528 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2529 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2530 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2531
2532 return pThis->pOps->pfnEnd(pThis->Base.pvThis);
2533}
2534
2535
2536RTDECL(void *) RTVfsFsStreamToPrivate(RTVFSFSSTREAM hVfsFss, PCRTVFSFSSTREAMOPS pFsStreamOps)
2537{
2538 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2539 AssertPtrReturn(pThis, NULL);
2540 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, NULL);
2541 if (pThis->pOps != pFsStreamOps)
2542 return NULL;
2543 return pThis->Base.pvThis;
2544}
2545
2546
2547/*
2548 *
2549 * D I R D I R D I R
2550 * D I R D I R D I R
2551 * D I R D I R D I R
2552 *
2553 */
2554
2555
2556RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock,
2557 PRTVFSDIR phVfsDir, void **ppvInstance)
2558{
2559 /*
2560 * Validate the input, be extra strict in strict builds.
2561 */
2562 AssertPtr(pDirOps);
2563 AssertReturn(pDirOps->uVersion == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2564 AssertReturn(pDirOps->uEndMarker == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2565 Assert(!pDirOps->fReserved);
2566 RTVFSDIR_ASSERT_OPS(pDirOps, RTVFSOBJTYPE_DIR);
2567 Assert(cbInstance > 0);
2568 AssertReturn(!(fFlags & ~RTVFSDIR_F_NO_VFS_REF), VERR_INVALID_FLAGS);
2569 AssertPtr(ppvInstance);
2570 AssertPtr(phVfsDir);
2571 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2572
2573 /*
2574 * Allocate the handle + instance data.
2575 */
2576 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSDIRINTERNAL), RTVFS_INST_ALIGNMENT)
2577 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2578 RTVFSDIRINTERNAL *pThis = (RTVFSDIRINTERNAL *)RTMemAllocZ(cbThis);
2579 if (!pThis)
2580 return VERR_NO_MEMORY;
2581
2582 int rc = rtVfsObjInitNewObject(&pThis->Base, &pDirOps->Obj, hVfs, RT_BOOL(fFlags & RTVFSDIR_F_NO_VFS_REF), hLock,
2583 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2584 if (RT_FAILURE(rc))
2585 {
2586 RTMemFree(pThis);
2587 return rc;
2588 }
2589
2590 pThis->uMagic = RTVFSDIR_MAGIC;
2591 pThis->fReserved = 0;
2592 pThis->pOps = pDirOps;
2593
2594 *phVfsDir = pThis;
2595 *ppvInstance = pThis->Base.pvThis;
2596 return VINF_SUCCESS;
2597}
2598
2599
2600RTDECL(void *) RTVfsDirToPrivate(RTVFSDIR hVfsDir, PCRTVFSDIROPS pDirOps)
2601{
2602 RTVFSDIRINTERNAL *pThis = hVfsDir;
2603 AssertPtrReturn(pThis, NULL);
2604 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, NULL);
2605 if (pThis->pOps != pDirOps)
2606 return NULL;
2607 return pThis->Base.pvThis;
2608}
2609
2610
2611#ifdef DEBUG
2612# undef RTVfsDirRetain
2613#endif
2614RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir)
2615{
2616 RTVFSDIRINTERNAL *pThis = hVfsDir;
2617 AssertPtrReturn(pThis, UINT32_MAX);
2618 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2619 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2620 LogFlow(("RTVfsDirRetain(%p/%p) -> %#x\n", pThis, pThis->Base.pvThis, cRefs));
2621 return cRefs;
2622}
2623#ifdef DEBUG
2624# define RTVfsDirRetain(hVfsDir) RTVfsDirRetainDebug(hVfsDir, RT_SRC_POS)
2625#endif
2626
2627
2628RTDECL(uint32_t) RTVfsDirRetainDebug(RTVFSDIR hVfsDir, RT_SRC_POS_DECL)
2629{
2630 RTVFSDIRINTERNAL *pThis = hVfsDir;
2631 AssertPtrReturn(pThis, UINT32_MAX);
2632 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2633 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsDirRetain", RT_SRC_POS_ARGS);
2634}
2635
2636
2637RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir)
2638{
2639 RTVFSDIRINTERNAL *pThis = hVfsDir;
2640 if (pThis == NIL_RTVFSDIR)
2641 return 0;
2642 AssertPtrReturn(pThis, UINT32_MAX);
2643 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2644#ifdef LOG_ENABLED
2645 void *pvThis = pThis->Base.pvThis;
2646#endif
2647 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2648 LogFlow(("RTVfsDirRelease(%p/%p) -> %#x\n", pThis, pvThis, cRefs));
2649 return cRefs;
2650}
2651
2652
2653RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2654{
2655 /*
2656 * Validate input.
2657 */
2658 RTVFSINTERNAL *pThis = hVfs;
2659 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2660 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2661 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2662 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2663 AssertReturn(!fFlags, VERR_INVALID_FLAGS); /** @todo sort out flags! */
2664
2665 /*
2666 * Parse the path, assume current directory is root since we've got no
2667 * caller context here.
2668 */
2669 PRTVFSPARSEDPATH pPath;
2670 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2671 if (RT_SUCCESS(rc))
2672 {
2673 /*
2674 * Tranverse the path, resolving the parent node.
2675 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenDir.
2676 */
2677 RTVFSDIRINTERNAL *pVfsParentDir;
2678 rc = rtVfsTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2679 if (RT_SUCCESS(rc))
2680 {
2681 /*
2682 * Do the opening. Loop if we need to follow symbolic links.
2683 */
2684 uint64_t fOpenFlags = RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN;
2685 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING;
2686 for (uint32_t cLoops = 1; ; cLoops++)
2687 {
2688 /* Do the querying. If pfnOpenDir is available, we use it first, falling
2689 back on pfnOpen in case of symbolic links that needs following. */
2690 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2691 if (pVfsParentDir->pOps->pfnOpenDir)
2692 {
2693 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2694 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2695 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2696 if ( RT_SUCCESS(rc)
2697 || ( rc != VERR_NOT_A_DIRECTORY
2698 && rc != VERR_IS_A_SYMLINK))
2699 break;
2700 }
2701
2702 RTVFSOBJ hVfsObj;
2703 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2704 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpenFlags, fObjFlags, &hVfsObj);
2705 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2706 if (RT_FAILURE(rc))
2707 break;
2708
2709 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2710 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2711 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2712 {
2713 *phVfsDir = RTVfsObjToDir(hVfsObj);
2714 AssertStmt(*phVfsDir != NIL_RTVFSDIR, rc = VERR_INTERNAL_ERROR_3);
2715 RTVfsObjRelease(hVfsObj);
2716 break;
2717 }
2718
2719 /* Follow symbolic link. */
2720 if (cLoops < RTVFS_MAX_LINKS)
2721 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2722 else
2723 rc = VERR_TOO_MANY_SYMLINKS;
2724 RTVfsObjRelease(hVfsObj);
2725 if (RT_FAILURE(rc))
2726 break;
2727 }
2728 RTVfsDirRelease(pVfsParentDir);
2729 }
2730 RTVfsParsePathFree(pPath);
2731 }
2732 return rc;
2733}
2734
2735
2736RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2737{
2738 /*
2739 * Validate input.
2740 */
2741 RTVFSDIRINTERNAL *pThis = hVfsDir;
2742 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2743 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2744 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2745 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2746 AssertReturn(!fFlags, VERR_INVALID_FLAGS); /** @todo sort out flags! */
2747
2748 /*
2749 * Parse the path, it's always relative to the given directory.
2750 */
2751 PRTVFSPARSEDPATH pPath;
2752 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2753 if (RT_SUCCESS(rc))
2754 {
2755 /*
2756 * Tranverse the path, resolving the parent node.
2757 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenDir.
2758 */
2759 RTVFSDIRINTERNAL *pVfsParentDir;
2760 uint32_t const fTraverse = (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK;
2761 rc = rtVfsDirTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
2762 if (RT_SUCCESS(rc))
2763 {
2764 /*
2765 * Do the opening. Loop if we need to follow symbolic links.
2766 */
2767 uint64_t fOpenFlags = RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN;
2768 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING | fTraverse;
2769 for (uint32_t cLoops = 1; ; cLoops++)
2770 {
2771 /* Do the querying. If pfnOpenDir is available, we use it first, falling
2772 back on pfnOpen in case of symbolic links that needs following. */
2773 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2774 if (pVfsParentDir->pOps->pfnOpenDir)
2775 {
2776 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2777 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2778 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2779 if ( RT_SUCCESS(rc)
2780 || ( rc != VERR_NOT_A_DIRECTORY
2781 && rc != VERR_IS_A_SYMLINK))
2782 break;
2783 }
2784
2785 RTVFSOBJ hVfsObj;
2786 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2787 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpenFlags, fObjFlags, &hVfsObj);
2788 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2789 if (RT_FAILURE(rc))
2790 break;
2791
2792 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2793 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2794 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2795 {
2796 *phVfsDir = RTVfsObjToDir(hVfsObj);
2797 AssertStmt(*phVfsDir != NIL_RTVFSDIR, rc = VERR_INTERNAL_ERROR_3);
2798 RTVfsObjRelease(hVfsObj);
2799 break;
2800 }
2801
2802 /* Follow symbolic link. */
2803 if (cLoops < RTVFS_MAX_LINKS)
2804 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
2805 else
2806 rc = VERR_TOO_MANY_SYMLINKS;
2807 RTVfsObjRelease(hVfsObj);
2808 if (RT_FAILURE(rc))
2809 break;
2810 }
2811 RTVfsDirRelease(pVfsParentDir);
2812 }
2813 RTVfsParsePathFree(pPath);
2814 }
2815 return rc;
2816}
2817
2818
2819RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir)
2820{
2821 /*
2822 * Validate input.
2823 */
2824 RTVFSDIRINTERNAL *pThis = hVfsDir;
2825 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2826 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2827 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2828 AssertPtrNullReturn(phVfsDir, VERR_INVALID_POINTER);
2829 AssertReturn(!(fFlags & ~RTDIRCREATE_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
2830 fMode = rtFsModeNormalize(fMode, pszRelPath, 0, RTFS_TYPE_DIRECTORY);
2831 AssertReturn(rtFsModeIsValidPermissions(fMode), VERR_INVALID_FMODE);
2832 if (!(fFlags & RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET))
2833 fMode |= RTFS_DOS_NT_NOT_CONTENT_INDEXED;
2834
2835 /*
2836 * Parse the path, it's always relative to the given directory.
2837 */
2838 PRTVFSPARSEDPATH pPath;
2839 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2840 if (RT_SUCCESS(rc))
2841 {
2842 /*
2843 * Tranverse the path, resolving the parent node.
2844 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenDir.
2845 */
2846 RTVFSDIRINTERNAL *pVfsParentDir;
2847 uint32_t fTraverse = (fFlags & RTDIRCREATE_FLAGS_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_ON_LINK;
2848 rc = rtVfsDirTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
2849 if (RT_SUCCESS(rc))
2850 {
2851 /*
2852 * Do the opening. Loop if we need to follow symbolic links.
2853 */
2854 uint64_t fOpenFlags = RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_CREATE
2855 | ((fMode << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK);
2856 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_DIRECTORY | fTraverse;
2857 for (uint32_t cLoops = 1; ; cLoops++)
2858 {
2859 /* Do the querying. If pfnOpenDir is available, we use it first, falling
2860 back on pfnOpen in case of symbolic links that needs following. */
2861 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2862 if (pVfsParentDir->pOps->pfnCreateDir)
2863 {
2864 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2865 rc = pVfsParentDir->pOps->pfnCreateDir(pVfsParentDir->Base.pvThis, pszEntryName, fMode, phVfsDir);
2866 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2867 if ( RT_SUCCESS(rc)
2868 || ( rc != VERR_NOT_A_DIRECTORY
2869 && rc != VERR_IS_A_SYMLINK))
2870 break;
2871 }
2872
2873 RTVFSOBJ hVfsObj;
2874 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2875 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpenFlags, fObjFlags, &hVfsObj);
2876 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2877 if (RT_FAILURE(rc))
2878 break;
2879
2880 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2881 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2882 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2883 {
2884 if (phVfsDir)
2885 {
2886 *phVfsDir = RTVfsObjToDir(hVfsObj);
2887 AssertStmt(*phVfsDir != NIL_RTVFSDIR, rc = VERR_INTERNAL_ERROR_3);
2888 }
2889 RTVfsObjRelease(hVfsObj);
2890 break;
2891 }
2892
2893 /* Follow symbolic link. */
2894 if (cLoops < RTVFS_MAX_LINKS)
2895 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
2896 else
2897 rc = VERR_TOO_MANY_SYMLINKS;
2898 RTVfsObjRelease(hVfsObj);
2899 if (RT_FAILURE(rc))
2900 break;
2901 }
2902 RTVfsDirRelease(pVfsParentDir);
2903 }
2904 RTVfsParsePathFree(pPath);
2905 }
2906 return rc;
2907}
2908
2909
2910RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2911{
2912 /*
2913 * Validate input.
2914 */
2915 RTVFSDIRINTERNAL *pThis = hVfsDir;
2916 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2917 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2918 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2919 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2920
2921 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2922 if (RT_FAILURE(rc))
2923 return rc;
2924
2925 /*
2926 * Parse the path, it's always relative to the given directory.
2927 */
2928 PRTVFSPARSEDPATH pPath;
2929 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2930 if (RT_SUCCESS(rc))
2931 {
2932 /*
2933 * Tranverse the path, resolving the parent node.
2934 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenFile.
2935 */
2936 RTVFSDIRINTERNAL *pVfsParentDir;
2937 uint32_t const fTraverse = (fOpen & RTFILE_O_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_ON_LINK;
2938 rc = rtVfsDirTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
2939 if (RT_SUCCESS(rc))
2940 {
2941 /** @todo join path with RTVfsFileOpen. */
2942
2943 /*
2944 * Do the opening. Loop if we need to follow symbolic links.
2945 */
2946 bool fDirSlash = pPath->fDirSlash;
2947
2948 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY_FILE | RTVFSOBJ_F_OPEN_SYMLINK;
2949 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
2950 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
2951 fObjFlags |= RTVFSOBJ_F_CREATE_FILE;
2952 else
2953 fObjFlags |= RTVFSOBJ_F_CREATE_NOTHING;
2954 fObjFlags |= fTraverse & RTPATH_F_MASK;
2955
2956 for (uint32_t cLoops = 1;; cLoops++)
2957 {
2958 /* Do the querying. If pfnOpenFile is available, we use it first, falling
2959 back on pfnOpen in case of symbolic links that needs following or we got
2960 a trailing directory slash (to get file-not-found error). */
2961 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2962 if ( pVfsParentDir->pOps->pfnOpenFile
2963 && !fDirSlash)
2964 {
2965 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2966 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2967 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2968 if ( RT_SUCCESS(rc)
2969 || ( rc != VERR_NOT_A_FILE
2970 && rc != VERR_IS_A_SYMLINK))
2971 break;
2972 }
2973
2974 RTVFSOBJ hVfsObj;
2975 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2976 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, fObjFlags, &hVfsObj);
2977 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2978 if (RT_FAILURE(rc))
2979 break;
2980
2981 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2982 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2983 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2984 {
2985 *phVfsFile = RTVfsObjToFile(hVfsObj);
2986 AssertStmt(*phVfsFile != NIL_RTVFSFILE, rc = VERR_INTERNAL_ERROR_3);
2987 RTVfsObjRelease(hVfsObj);
2988 break;
2989 }
2990
2991 /* Follow symbolic link. */
2992 if (cLoops < RTVFS_MAX_LINKS)
2993 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
2994 else
2995 rc = VERR_TOO_MANY_SYMLINKS;
2996 RTVfsObjRelease(hVfsObj);
2997 if (RT_FAILURE(rc))
2998 break;
2999 fDirSlash |= pPath->fDirSlash;
3000 }
3001 RTVfsDirRelease(pVfsParentDir);
3002 }
3003 RTVfsParsePathFree(pPath);
3004 }
3005 return rc;
3006}
3007
3008
3009RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
3010{
3011 RTVFSFILE hVfsFile;
3012 int rc = RTVfsDirOpenFile(hVfsDir, pszPath, fOpen, &hVfsFile);
3013 if (RT_SUCCESS(rc))
3014 {
3015 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
3016 AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
3017 RTVfsFileRelease(hVfsFile);
3018 }
3019 return rc;
3020}
3021
3022
3023RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
3024{
3025 /*
3026 * Validate input.
3027 */
3028 RTVFSDIRINTERNAL *pThis = hVfsDir;
3029 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3030 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3031 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
3032 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
3033
3034 int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
3035 if (RT_FAILURE(rc))
3036 return rc;
3037 AssertMsgReturn( RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
3038 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
3039 ("fObjFlags=%#x\n", fObjFlags),
3040 VERR_INVALID_FLAGS);
3041
3042 /*
3043 * Parse the relative path. If it ends with a directory slash or it boils
3044 * down to an empty path (i.e. re-opening hVfsDir), adjust the flags to only
3045 * open/create directories.
3046 */
3047 PRTVFSPARSEDPATH pPath;
3048 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
3049 if (RT_SUCCESS(rc))
3050 {
3051 /*
3052 * Tranverse the path, resolving the parent node.
3053 * We'll do the symbolic link checking here with help of pfnOpen.
3054 */
3055 RTVFSDIRINTERNAL *pVfsParentDir;
3056 rc = rtVfsDirTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
3057 if (RT_SUCCESS(rc))
3058 {
3059 /*
3060 * Do the opening. Loop if we need to follow symbolic links.
3061 */
3062 for (uint32_t cLoops = 1;; cLoops++)
3063 {
3064 /* If we end with a directory slash, adjust open flags. */
3065 if (pPath->fDirSlash)
3066 {
3067 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
3068 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
3069 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
3070 }
3071 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
3072 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
3073
3074 /* Open it. */
3075 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3076 RTVFSOBJ hVfsObj;
3077 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3078 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
3079 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3080 if (RT_FAILURE(rc))
3081 break;
3082
3083 /* We're done if we don't follow links or this wasn't a link. */
3084 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
3085 || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
3086 {
3087 *phVfsObj = hVfsObj;
3088 break;
3089 }
3090
3091 /* Follow symbolic link. */
3092 if (cLoops < RTVFS_MAX_LINKS)
3093 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
3094 else
3095 rc = VERR_TOO_MANY_SYMLINKS;
3096 RTVfsObjRelease(hVfsObj);
3097 if (RT_FAILURE(rc))
3098 break;
3099 }
3100
3101 RTVfsDirRelease(pVfsParentDir);
3102 }
3103 RTVfsParsePathFree(pPath);
3104 }
3105 return rc;
3106}
3107
3108
3109RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo,
3110 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
3111{
3112 /*
3113 * Validate input.
3114 */
3115 RTVFSDIRINTERNAL *pThis = hVfsDir;
3116 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3117 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3118 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
3119 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
3120 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
3121 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
3122 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
3123
3124 /*
3125 * Parse the relative path. Then traverse to the parent directory.
3126 */
3127 PRTVFSPARSEDPATH pPath;
3128 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
3129 if (RT_SUCCESS(rc))
3130 {
3131 /*
3132 * Tranverse the path, resolving the parent node.
3133 * We'll do the symbolic link checking here with help of pfnOpen.
3134 */
3135 RTVFSDIRINTERNAL *pVfsParentDir;
3136 rc = rtVfsDirTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
3137 if (RT_SUCCESS(rc))
3138 {
3139 /*
3140 * Do the opening. Loop if we need to follow symbolic links.
3141 */
3142 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING;
3143 for (uint32_t cLoops = 1;; cLoops++)
3144 {
3145 /* If we end with a directory slash, adjust open flags. */
3146 if (pPath->fDirSlash)
3147 {
3148 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
3149 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
3150 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
3151 }
3152 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
3153 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
3154
3155 /* Do the querying. If pfnQueryEntryInfo is available, we use it first,
3156 falling back on pfnOpen in case of symbolic links that needs following. */
3157 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3158 if (pVfsParentDir->pOps->pfnQueryEntryInfo)
3159 {
3160 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
3161 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
3162 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
3163 if (RT_FAILURE(rc))
3164 break;
3165 if ( !RTFS_IS_SYMLINK(pObjInfo->Attr.fMode)
3166 || !(fFlags & RTPATH_F_FOLLOW_LINK))
3167 {
3168 if ( (fObjFlags & RTVFSOBJ_F_OPEN_MASK) != RTVFSOBJ_F_OPEN_ANY
3169 && !RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
3170 rc = VERR_NOT_A_DIRECTORY;
3171 break;
3172 }
3173 }
3174
3175 RTVFSOBJ hVfsObj;
3176 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3177 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName,
3178 RTFILE_O_ACCESS_ATTR_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
3179 fObjFlags, &hVfsObj);
3180 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3181 if (RT_FAILURE(rc))
3182 break;
3183
3184 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
3185 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
3186 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
3187 {
3188 rc = RTVfsObjQueryInfo(hVfsObj, pObjInfo, enmAddAttr);
3189 RTVfsObjRelease(hVfsObj);
3190 break;
3191 }
3192
3193 /* Follow symbolic link. */
3194 if (cLoops < RTVFS_MAX_LINKS)
3195 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
3196 else
3197 rc = VERR_TOO_MANY_SYMLINKS;
3198 RTVfsObjRelease(hVfsObj);
3199 if (RT_FAILURE(rc))
3200 break;
3201 }
3202
3203 RTVfsDirRelease(pVfsParentDir);
3204 }
3205 RTVfsParsePathFree(pPath);
3206 }
3207 return rc;
3208}
3209
3210
3211RTDECL(int) RTVfsDirRemoveDir(RTVFSDIR hVfsDir, const char *pszRelPath, uint32_t fFlags)
3212{
3213 /*
3214 * Validate input.
3215 */
3216 RTVFSDIRINTERNAL *pThis = hVfsDir;
3217 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3218 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3219 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
3220 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
3221
3222 /*
3223 * Parse the path, it's always relative to the given directory.
3224 */
3225 PRTVFSPARSEDPATH pPath;
3226 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
3227 if (RT_SUCCESS(rc))
3228 {
3229 if (pPath->cComponents > 0)
3230 {
3231 /*
3232 * Tranverse the path, resolving the parent node, not checking for symbolic
3233 * links in the final element, and ask the directory to remove the subdir.
3234 */
3235 RTVFSDIRINTERNAL *pVfsParentDir;
3236 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
3237 if (RT_SUCCESS(rc))
3238 {
3239 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3240
3241 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3242 rc = pVfsParentDir->pOps->pfnUnlinkEntry(pVfsParentDir->Base.pvThis, pszEntryName, RTFS_TYPE_DIRECTORY);
3243 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3244
3245 RTVfsDirRelease(pVfsParentDir);
3246 }
3247 }
3248 else
3249 rc = VERR_PATH_ZERO_LENGTH;
3250 RTVfsParsePathFree(pPath);
3251 }
3252 return rc;
3253}
3254
3255
3256
3257RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
3258{
3259 /*
3260 * Validate input.
3261 */
3262 RTVFSDIRINTERNAL *pThis = hVfsDir;
3263 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3264 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3265 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
3266 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
3267
3268 size_t cbDirEntry = sizeof(*pDirEntry);
3269 if (!pcbDirEntry)
3270 pcbDirEntry = &cbDirEntry;
3271 else
3272 {
3273 cbDirEntry = *pcbDirEntry;
3274 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
3275 ("Invalid *pcbDirEntry=%d (min %zu)\n", *pcbDirEntry, RT_UOFFSETOF(RTDIRENTRYEX, szName[2])),
3276 VERR_INVALID_PARAMETER);
3277 }
3278
3279 /*
3280 * Call the directory method.
3281 */
3282 RTVfsLockAcquireRead(pThis->Base.hLock);
3283 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
3284 RTVfsLockReleaseRead(pThis->Base.hLock);
3285 return rc;
3286}
3287
3288
3289RTDECL(int) RTVfsDirRewind(RTVFSDIR hVfsDir)
3290{
3291 /*
3292 * Validate input.
3293 */
3294 RTVFSDIRINTERNAL *pThis = hVfsDir;
3295 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3296 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3297
3298 /*
3299 * Call the directory method.
3300 */
3301 RTVfsLockAcquireRead(pThis->Base.hLock);
3302 int rc = pThis->pOps->pfnRewindDir(pThis->Base.pvThis);
3303 RTVfsLockReleaseRead(pThis->Base.hLock);
3304 return rc;
3305}
3306
3307
3308/*
3309 *
3310 * S Y M B O L I C L I N K
3311 * S Y M B O L I C L I N K
3312 * S Y M B O L I C L I N K
3313 *
3314 */
3315
3316RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
3317 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
3318{
3319 /*
3320 * Validate the input, be extra strict in strict builds.
3321 */
3322 AssertPtr(pSymlinkOps);
3323 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3324 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3325 Assert(!pSymlinkOps->fReserved);
3326 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
3327 Assert(cbInstance > 0);
3328 AssertPtr(ppvInstance);
3329 AssertPtr(phVfsSym);
3330 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3331
3332 /*
3333 * Allocate the handle + instance data.
3334 */
3335 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
3336 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3337 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
3338 if (!pThis)
3339 return VERR_NO_MEMORY;
3340
3341 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3342 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3343 if (RT_FAILURE(rc))
3344 {
3345 RTMemFree(pThis);
3346 return rc;
3347 }
3348
3349 pThis->uMagic = RTVFSSYMLINK_MAGIC;
3350 pThis->pOps = pSymlinkOps;
3351
3352 *phVfsSym = pThis;
3353 *ppvInstance = pThis->Base.pvThis;
3354 return VINF_SUCCESS;
3355}
3356
3357
3358RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps)
3359{
3360 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3361 AssertPtrReturn(pThis, NULL);
3362 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, NULL);
3363 if (pThis->pOps != pSymlinkOps)
3364 return NULL;
3365 return pThis->Base.pvThis;
3366}
3367
3368
3369RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
3370{
3371 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3372 AssertPtrReturn(pThis, UINT32_MAX);
3373 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3374 return rtVfsObjRetain(&pThis->Base);
3375}
3376
3377
3378RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL)
3379{
3380 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3381 AssertPtrReturn(pThis, UINT32_MAX);
3382 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3383 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsSymlinkRetainDebug", RT_SRC_POS_ARGS);
3384}
3385
3386
3387RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
3388{
3389 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3390 if (pThis == NIL_RTVFSSYMLINK)
3391 return 0;
3392 AssertPtrReturn(pThis, UINT32_MAX);
3393 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3394 return rtVfsObjRelease(&pThis->Base);
3395}
3396
3397
3398RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3399{
3400 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3401 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3402 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3403 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3404}
3405
3406
3407RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
3408{
3409 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3410 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3411 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3412
3413 fMode = rtFsModeNormalize(fMode, NULL, 0, RTFS_TYPE_SYMLINK);
3414 if (!rtFsModeIsValid(fMode))
3415 return VERR_INVALID_PARAMETER;
3416
3417 RTVfsLockAcquireWrite(pThis->Base.hLock);
3418 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
3419 RTVfsLockReleaseWrite(pThis->Base.hLock);
3420 return rc;
3421}
3422
3423
3424RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
3425 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
3426{
3427 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3428 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3429 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3430
3431 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
3432 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
3433 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
3434 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
3435
3436 RTVfsLockAcquireWrite(pThis->Base.hLock);
3437 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
3438 RTVfsLockReleaseWrite(pThis->Base.hLock);
3439 return rc;
3440}
3441
3442
3443RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
3444{
3445 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3446 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3447 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3448
3449 RTVfsLockAcquireWrite(pThis->Base.hLock);
3450 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
3451 RTVfsLockReleaseWrite(pThis->Base.hLock);
3452 return rc;
3453}
3454
3455
3456RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
3457{
3458 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3459 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3460 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3461
3462 RTVfsLockAcquireWrite(pThis->Base.hLock);
3463 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
3464 RTVfsLockReleaseWrite(pThis->Base.hLock);
3465
3466 return rc;
3467}
3468
3469
3470
3471/*
3472 *
3473 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3474 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3475 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
3476 *
3477 */
3478
3479RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3480 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
3481{
3482 /*
3483 * Validate the input, be extra strict in strict builds.
3484 */
3485 AssertPtr(pIoStreamOps);
3486 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3487 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3488 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
3489 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
3490 Assert(cbInstance > 0);
3491 Assert(fOpen & RTFILE_O_ACCESS_MASK);
3492 AssertPtr(ppvInstance);
3493 AssertPtr(phVfsIos);
3494 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3495
3496 /*
3497 * Allocate the handle + instance data.
3498 */
3499 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
3500 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3501 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
3502 if (!pThis)
3503 return VERR_NO_MEMORY;
3504
3505 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3506 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3507 if (RT_FAILURE(rc))
3508 {
3509 RTMemFree(pThis);
3510 return rc;
3511 }
3512
3513 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
3514 pThis->fFlags = fOpen;
3515 pThis->pOps = pIoStreamOps;
3516
3517 *phVfsIos = pThis;
3518 *ppvInstance = pThis->Base.pvThis;
3519 return VINF_SUCCESS;
3520}
3521
3522
3523RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
3524{
3525 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3526 AssertPtrReturn(pThis, NULL);
3527 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
3528 if (pThis->pOps != pIoStreamOps)
3529 return NULL;
3530 return pThis->Base.pvThis;
3531}
3532
3533
3534#ifdef DEBUG
3535# undef RTVfsIoStrmRetain
3536#endif
3537RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
3538{
3539 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3540 AssertPtrReturn(pThis, UINT32_MAX);
3541 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3542 return rtVfsObjRetain(&pThis->Base);
3543}
3544#ifdef DEBUG
3545# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS)
3546#endif
3547
3548
3549RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL)
3550{
3551 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3552 AssertPtrReturn(pThis, UINT32_MAX);
3553 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3554 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsIoStrmRetainDebug", RT_SRC_POS_ARGS);
3555}
3556
3557
3558RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
3559{
3560 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3561 if (pThis == NIL_RTVFSIOSTREAM)
3562 return 0;
3563 AssertPtrReturn(pThis, UINT32_MAX);
3564 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3565 return rtVfsObjRelease(&pThis->Base);
3566}
3567
3568
3569RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
3570{
3571 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3572 AssertPtrReturn(pThis, NIL_RTVFSFILE);
3573 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
3574
3575 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3576 {
3577 rtVfsObjRetainVoid(&pThis->Base, "RTVfsIoStrmToFile");
3578 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3579 }
3580
3581 /* this is no crime, so don't assert. */
3582 return NIL_RTVFSFILE;
3583}
3584
3585
3586RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3587{
3588 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3589 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3590 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3591 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3592}
3593
3594
3595RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
3596{
3597 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3598 if (pcbRead)
3599 *pcbRead = 0;
3600 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3601 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3602 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3603 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3604 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3605
3606 RTSGSEG Seg = { pvBuf, cbToRead };
3607 RTSGBUF SgBuf;
3608 RTSgBufInit(&SgBuf, &Seg, 1);
3609
3610 RTVfsLockAcquireWrite(pThis->Base.hLock);
3611 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
3612 RTVfsLockReleaseWrite(pThis->Base.hLock);
3613 return rc;
3614}
3615
3616
3617RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
3618 bool fBlocking, size_t *pcbRead)
3619{
3620 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3621 if (pcbRead)
3622 *pcbRead = 0;
3623 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3624 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3625 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3626 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3627 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3628
3629 RTSGSEG Seg = { pvBuf, cbToRead };
3630 RTSGBUF SgBuf;
3631 RTSgBufInit(&SgBuf, &Seg, 1);
3632
3633 RTVfsLockAcquireWrite(pThis->Base.hLock);
3634 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
3635 RTVfsLockReleaseWrite(pThis->Base.hLock);
3636 return rc;
3637}
3638
3639
3640RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
3641{
3642 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3643 if (pcbWritten)
3644 *pcbWritten = 0;
3645 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3646 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3647 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3648 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3649 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3650
3651 int rc;
3652 if (pThis->pOps->pfnWrite)
3653 {
3654 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3655 RTSGBUF SgBuf;
3656 RTSgBufInit(&SgBuf, &Seg, 1);
3657
3658 RTVfsLockAcquireWrite(pThis->Base.hLock);
3659 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
3660 RTVfsLockReleaseWrite(pThis->Base.hLock);
3661 }
3662 else
3663 rc = VERR_WRITE_PROTECT;
3664 return rc;
3665}
3666
3667
3668RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
3669 bool fBlocking, size_t *pcbWritten)
3670{
3671 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3672 if (pcbWritten)
3673 *pcbWritten = 0;
3674 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3675 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3676 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3677 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3678 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3679
3680 int rc;
3681 if (pThis->pOps->pfnWrite)
3682 {
3683 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3684 RTSGBUF SgBuf;
3685 RTSgBufInit(&SgBuf, &Seg, 1);
3686
3687 RTVfsLockAcquireWrite(pThis->Base.hLock);
3688 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
3689 RTVfsLockReleaseWrite(pThis->Base.hLock);
3690 }
3691 else
3692 rc = VERR_WRITE_PROTECT;
3693 return rc;
3694}
3695
3696
3697RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3698{
3699 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3700 if (pcbRead)
3701 *pcbRead = 0;
3702 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3703 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3704 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3705 AssertPtr(pSgBuf);
3706 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3707 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3708
3709 RTVfsLockAcquireWrite(pThis->Base.hLock);
3710 int rc;
3711 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3712 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
3713 else
3714 {
3715 size_t cbRead = 0;
3716 rc = VINF_SUCCESS;
3717
3718 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3719 {
3720 RTSGBUF SgBuf;
3721 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3722
3723 size_t cbReadSeg = pcbRead ? 0 : pSgBuf->paSegs[iSeg].cbSeg;
3724 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
3725 if (RT_FAILURE(rc))
3726 break;
3727 cbRead += cbReadSeg;
3728 if ((pcbRead && cbReadSeg != SgBuf.paSegs[0].cbSeg) || rc != VINF_SUCCESS)
3729 break;
3730 if (off != -1)
3731 off += cbReadSeg;
3732 }
3733
3734 if (pcbRead)
3735 *pcbRead = cbRead;
3736 }
3737 RTVfsLockReleaseWrite(pThis->Base.hLock);
3738 return rc;
3739}
3740
3741
3742RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3743{
3744 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3745 if (pcbWritten)
3746 *pcbWritten = 0;
3747 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3748 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3749 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3750 AssertPtr(pSgBuf);
3751 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3752 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3753
3754 int rc;
3755 if (pThis->pOps->pfnWrite)
3756 {
3757 RTVfsLockAcquireWrite(pThis->Base.hLock);
3758 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3759 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
3760 else
3761 {
3762 size_t cbWritten = 0;
3763 rc = VINF_SUCCESS;
3764
3765 for (uint32_t iSeg = 0; iSeg < pSgBuf->cSegs; iSeg++)
3766 {
3767 RTSGBUF SgBuf;
3768 RTSgBufInit(&SgBuf, &pSgBuf->paSegs[iSeg], 1);
3769
3770 size_t cbWrittenSeg = 0;
3771 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
3772 if (RT_FAILURE(rc))
3773 break;
3774 if (pcbWritten)
3775 {
3776 cbWritten += cbWrittenSeg;
3777 if (cbWrittenSeg != SgBuf.paSegs[0].cbSeg)
3778 break;
3779 if (off != -1)
3780 off += cbWrittenSeg;
3781 }
3782 else if (off != -1)
3783 off += pSgBuf->paSegs[iSeg].cbSeg;
3784 }
3785
3786 if (pcbWritten)
3787 *pcbWritten = cbWritten;
3788 }
3789 RTVfsLockReleaseWrite(pThis->Base.hLock);
3790 }
3791 else
3792 rc = VERR_WRITE_PROTECT;
3793 return rc;
3794}
3795
3796
3797RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
3798{
3799 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3800 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3801 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3802
3803 RTVfsLockAcquireWrite(pThis->Base.hLock);
3804 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
3805 RTVfsLockReleaseWrite(pThis->Base.hLock);
3806 return rc;
3807}
3808
3809
3810RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3811 uint32_t *pfRetEvents)
3812{
3813 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3814 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3815 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3816
3817 int rc;
3818 if (pThis->pOps->pfnPollOne)
3819 {
3820 RTVfsLockAcquireWrite(pThis->Base.hLock);
3821 rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
3822 RTVfsLockReleaseWrite(pThis->Base.hLock);
3823 }
3824 /*
3825 * Default implementation. Polling for non-error events returns
3826 * immediately, waiting for errors will work like sleep.
3827 */
3828 else if (fEvents != RTPOLL_EVT_ERROR)
3829 {
3830 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
3831 rc = VINF_SUCCESS;
3832 }
3833 else if (fIntr)
3834 rc = RTThreadSleep(cMillies);
3835 else
3836 {
3837 uint64_t uMsStart = RTTimeMilliTS();
3838 do
3839 rc = RTThreadSleep(cMillies);
3840 while ( rc == VERR_INTERRUPTED
3841 && !fIntr
3842 && RTTimeMilliTS() - uMsStart < cMillies);
3843 if (rc == VERR_INTERRUPTED)
3844 rc = VERR_TIMEOUT;
3845 }
3846 return rc;
3847}
3848
3849
3850RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
3851{
3852 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3853 AssertPtrReturn(pThis, -1);
3854 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3855
3856 RTFOFF off;
3857 RTVfsLockAcquireRead(pThis->Base.hLock);
3858 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
3859 RTVfsLockReleaseRead(pThis->Base.hLock);
3860 if (RT_FAILURE(rc))
3861 off = rc;
3862 return off;
3863}
3864
3865
3866RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3867{
3868 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3869 AssertPtrReturn(pThis, -1);
3870 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3871 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
3872
3873 int rc;
3874 if (pThis->pOps->pfnSkip)
3875 {
3876 RTVfsLockAcquireWrite(pThis->Base.hLock);
3877 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
3878 RTVfsLockReleaseWrite(pThis->Base.hLock);
3879 }
3880 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3881 {
3882 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3883 RTFOFF offIgnored;
3884
3885 RTVfsLockAcquireWrite(pThis->Base.hLock);
3886 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
3887 RTVfsLockReleaseWrite(pThis->Base.hLock);
3888 }
3889 else
3890 {
3891 void *pvBuf = RTMemTmpAlloc(_64K);
3892 if (pvBuf)
3893 {
3894 rc = VINF_SUCCESS;
3895 while (cb > 0)
3896 {
3897 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
3898 RTVfsLockAcquireWrite(pThis->Base.hLock);
3899 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
3900 RTVfsLockReleaseWrite(pThis->Base.hLock);
3901 if (RT_FAILURE(rc))
3902 break;
3903 cb -= cbToRead;
3904 }
3905
3906 RTMemTmpFree(pvBuf);
3907 }
3908 else
3909 rc = VERR_NO_TMP_MEMORY;
3910 }
3911 return rc;
3912}
3913
3914
3915RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3916{
3917 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3918 AssertPtrReturn(pThis, -1);
3919 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3920
3921 int rc;
3922 if (pThis->pOps->pfnZeroFill)
3923 {
3924 RTVfsLockAcquireWrite(pThis->Base.hLock);
3925 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
3926 RTVfsLockReleaseWrite(pThis->Base.hLock);
3927 }
3928 else
3929 {
3930 rc = VINF_SUCCESS;
3931 while (cb > 0)
3932 {
3933 size_t cbToWrite = (size_t)RT_MIN(cb, (ssize_t)sizeof(g_abRTZero64K));
3934 RTVfsLockAcquireWrite(pThis->Base.hLock);
3935 rc = RTVfsIoStrmWrite(hVfsIos, g_abRTZero64K, cbToWrite, true /*fBlocking*/, NULL);
3936 RTVfsLockReleaseWrite(pThis->Base.hLock);
3937 if (RT_FAILURE(rc))
3938 break;
3939 cb -= cbToWrite;
3940 }
3941 }
3942 return rc;
3943}
3944
3945
3946RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
3947{
3948 /*
3949 * There is where the zero read behavior comes in handy.
3950 */
3951 char bDummy;
3952 size_t cbRead;
3953 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
3954 return rc == VINF_EOF;
3955}
3956
3957
3958
3959RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos)
3960{
3961 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3962 AssertPtrReturn(pThis, 0);
3963 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, 0);
3964 return pThis->fFlags;
3965}
3966
3967
3968
3969/*
3970 *
3971 * F I L E F I L E F I L E
3972 * F I L E F I L E F I L E
3973 * F I L E F I L E F I L E
3974 *
3975 */
3976
3977RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3978 PRTVFSFILE phVfsFile, void **ppvInstance)
3979{
3980 /*
3981 * Validate the input, be extra strict in strict builds.
3982 */
3983 RTVFSFILE_ASSERT_OPS(pFileOps, RTVFSOBJTYPE_FILE);
3984 Assert(cbInstance > 0);
3985 Assert(fOpen & (RTFILE_O_ACCESS_MASK | RTFILE_O_ACCESS_ATTR_MASK));
3986 AssertPtr(ppvInstance);
3987 AssertPtr(phVfsFile);
3988 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3989
3990 /*
3991 * Allocate the handle + instance data.
3992 */
3993 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
3994 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3995 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
3996 if (!pThis)
3997 return VERR_NO_MEMORY;
3998
3999 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, false /*fNoVfsRef*/, hLock,
4000 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
4001 if (RT_FAILURE(rc))
4002 {
4003 RTMemFree(pThis);
4004 return rc;
4005 }
4006
4007 pThis->uMagic = RTVFSFILE_MAGIC;
4008 pThis->fReserved = 0;
4009 pThis->pOps = pFileOps;
4010 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
4011 pThis->Stream.fFlags = fOpen;
4012 pThis->Stream.pOps = &pFileOps->Stream;
4013
4014 *phVfsFile = pThis;
4015 *ppvInstance = pThis->Stream.Base.pvThis;
4016 return VINF_SUCCESS;
4017}
4018
4019
4020RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
4021{
4022 /*
4023 * Validate input.
4024 */
4025 RTVFSINTERNAL *pThis = hVfs;
4026 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4027 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
4028 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
4029 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
4030
4031 int rc = rtFileRecalcAndValidateFlags(&fOpen);
4032 if (RT_FAILURE(rc))
4033 return rc;
4034
4035 /*
4036 * Parse the path, assume current directory is root since we've got no
4037 * caller context here.
4038 */
4039 PRTVFSPARSEDPATH pPath;
4040 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
4041 if (RT_SUCCESS(rc))
4042 {
4043 /*
4044 * Tranverse the path, resolving the parent node.
4045 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenFile.
4046 */
4047 RTVFSDIRINTERNAL *pVfsParentDir;
4048 uint32_t const fTraverse = (fOpen & RTFILE_O_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_ON_LINK;
4049 rc = rtVfsTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
4050 if (RT_SUCCESS(rc))
4051 {
4052 /** @todo join path with RTVfsDirOpenFile. */
4053 /*
4054 * Do the opening. Loop if we need to follow symbolic links.
4055 */
4056 bool fDirSlash = pPath->fDirSlash;
4057
4058 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY_FILE | RTVFSOBJ_F_OPEN_SYMLINK;
4059 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
4060 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
4061 fObjFlags |= RTVFSOBJ_F_CREATE_FILE;
4062 else
4063 fObjFlags |= RTVFSOBJ_F_CREATE_NOTHING;
4064 fObjFlags |= fTraverse & RTPATH_F_MASK;
4065
4066 for (uint32_t cLoops = 1;; cLoops++)
4067 {
4068 /* Do the querying. If pfnOpenFile is available, we use it first, falling
4069 back on pfnOpen in case of symbolic links that needs following or we got
4070 a trailing directory slash (to get file-not-found error). */
4071 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
4072 if ( pVfsParentDir->pOps->pfnOpenFile
4073 && !fDirSlash)
4074 {
4075 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
4076 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
4077 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
4078 if ( RT_SUCCESS(rc)
4079 || ( rc != VERR_NOT_A_FILE
4080 && rc != VERR_IS_A_SYMLINK))
4081 break;
4082 }
4083
4084 RTVFSOBJ hVfsObj;
4085 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
4086 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, fObjFlags, &hVfsObj);
4087 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
4088 if (RT_FAILURE(rc))
4089 break;
4090
4091 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
4092 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
4093 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
4094 {
4095 *phVfsFile = RTVfsObjToFile(hVfsObj);
4096 AssertStmt(*phVfsFile != NIL_RTVFSFILE, rc = VERR_INTERNAL_ERROR_3);
4097 RTVfsObjRelease(hVfsObj);
4098 break;
4099 }
4100
4101 /* Follow symbolic link. */
4102 if (cLoops < RTVFS_MAX_LINKS)
4103 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
4104 else
4105 rc = VERR_TOO_MANY_SYMLINKS;
4106 RTVfsObjRelease(hVfsObj);
4107 if (RT_FAILURE(rc))
4108 break;
4109 fDirSlash |= pPath->fDirSlash;
4110 }
4111 RTVfsDirRelease(pVfsParentDir);
4112 }
4113 RTVfsParsePathFree(pPath);
4114 }
4115 return rc;
4116
4117}
4118
4119
4120#ifdef DEBUG
4121# undef RTVfsFileRetain
4122#endif
4123RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
4124{
4125 RTVFSFILEINTERNAL *pThis = hVfsFile;
4126 AssertPtrReturn(pThis, UINT32_MAX);
4127 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
4128 return rtVfsObjRetain(&pThis->Stream.Base);
4129}
4130#ifdef DEBUG
4131# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS)
4132#endif
4133
4134
4135RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL)
4136{
4137 RTVFSFILEINTERNAL *pThis = hVfsFile;
4138 AssertPtrReturn(pThis, UINT32_MAX);
4139 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
4140 return rtVfsObjRetainDebug(&pThis->Stream.Base, "RTVFsFileRetainDebug", RT_SRC_POS_ARGS);
4141}
4142
4143
4144RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
4145{
4146 RTVFSFILEINTERNAL *pThis = hVfsFile;
4147 if (pThis == NIL_RTVFSFILE)
4148 return 0;
4149 AssertPtrReturn(pThis, UINT32_MAX);
4150 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
4151 return rtVfsObjRelease(&pThis->Stream.Base);
4152}
4153
4154
4155RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
4156{
4157 RTVFSFILEINTERNAL *pThis = hVfsFile;
4158 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
4159 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
4160
4161 rtVfsObjRetainVoid(&pThis->Stream.Base, "RTVfsFileToIoStream");
4162 return &pThis->Stream;
4163}
4164
4165
4166RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
4167{
4168 RTVFSFILEINTERNAL *pThis = hVfsFile;
4169 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4170 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4171 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
4172}
4173
4174
4175RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
4176{
4177 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
4178 if (pcbRead)
4179 *pcbRead = 0;
4180 RTVFSFILEINTERNAL *pThis = hVfsFile;
4181 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4182 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4183 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
4184}
4185
4186
4187RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
4188{
4189 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
4190 if (pcbWritten)
4191 *pcbWritten = 0;
4192 RTVFSFILEINTERNAL *pThis = hVfsFile;
4193 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4194 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4195 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
4196}
4197
4198
4199RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
4200{
4201 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
4202 if (pcbWritten)
4203 *pcbWritten = 0;
4204 RTVFSFILEINTERNAL *pThis = hVfsFile;
4205 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4206 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4207
4208 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
4209 if (RT_SUCCESS(rc))
4210 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
4211
4212 return rc;
4213}
4214
4215
4216RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
4217{
4218 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
4219 if (pcbRead)
4220 *pcbRead = 0;
4221 RTVFSFILEINTERNAL *pThis = hVfsFile;
4222 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4223 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4224
4225 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
4226 if (RT_SUCCESS(rc))
4227 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
4228
4229 return rc;
4230}
4231
4232
4233RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
4234{
4235 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
4236 if (pcbRead)
4237 *pcbRead = 0;
4238 RTVFSFILEINTERNAL *pThis = hVfsFile;
4239 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4240 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4241
4242 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
4243}
4244
4245
4246RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PCRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
4247{
4248 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
4249 if (pcbWritten)
4250 *pcbWritten = 0;
4251 RTVFSFILEINTERNAL *pThis = hVfsFile;
4252 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4253 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4254
4255 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
4256}
4257
4258
4259RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
4260{
4261 RTVFSFILEINTERNAL *pThis = hVfsFile;
4262 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4263 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4264 return RTVfsIoStrmFlush(&pThis->Stream);
4265}
4266
4267
4268RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
4269 uint32_t *pfRetEvents)
4270{
4271 RTVFSFILEINTERNAL *pThis = hVfsFile;
4272 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4273 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4274 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
4275}
4276
4277
4278RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
4279{
4280 RTVFSFILEINTERNAL *pThis = hVfsFile;
4281 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4282 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4283 return RTVfsIoStrmTell(&pThis->Stream);
4284}
4285
4286
4287RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
4288{
4289 RTVFSFILEINTERNAL *pThis = hVfsFile;
4290 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4291 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4292
4293 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
4294 || uMethod == RTFILE_SEEK_CURRENT
4295 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
4296 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
4297
4298 RTFOFF offActual = 0;
4299 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4300 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
4301 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4302 if (RT_SUCCESS(rc) && poffActual)
4303 {
4304 Assert(offActual >= 0);
4305 *poffActual = offActual;
4306 }
4307
4308 return rc;
4309}
4310
4311
4312RTDECL(int) RTVfsFileQuerySize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
4313{
4314 RTVFSFILEINTERNAL *pThis = hVfsFile;
4315 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4316 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4317 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
4318
4319 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4320 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
4321 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4322
4323 return rc;
4324}
4325
4326
4327RTDECL(int) RTVfsFileSetSize(RTVFSFILE hVfsFile, uint64_t cbSize, uint32_t fFlags)
4328{
4329 RTVFSFILEINTERNAL *pThis = hVfsFile;
4330 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4331 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4332 AssertReturn(RTVFSFILE_SIZE_F_IS_VALID(fFlags), VERR_INVALID_FLAGS);
4333 AssertReturn(pThis->Stream.fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
4334
4335 int rc;
4336 if (pThis->pOps->pfnSetSize)
4337 {
4338 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4339 rc = pThis->pOps->pfnSetSize(pThis->Stream.Base.pvThis, cbSize, fFlags);
4340 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4341 }
4342 else
4343 rc = VERR_WRITE_PROTECT;
4344 return rc;
4345}
4346
4347
4348RTDECL(RTFOFF) RTVfsFileGetMaxSize(RTVFSFILE hVfsFile)
4349{
4350 uint64_t cbMax;
4351 int rc = RTVfsFileQueryMaxSize(hVfsFile, &cbMax);
4352 return RT_SUCCESS(rc) ? (RTFOFF)RT_MIN(cbMax, (uint64_t)RTFOFF_MAX) : -1;
4353}
4354
4355
4356RTDECL(int) RTVfsFileQueryMaxSize(RTVFSFILE hVfsFile, uint64_t *pcbMax)
4357{
4358 RTVFSFILEINTERNAL *pThis = hVfsFile;
4359 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4360 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4361 AssertPtrReturn(pcbMax, VERR_INVALID_POINTER);
4362 *pcbMax = RTFOFF_MAX;
4363
4364 int rc;
4365 if (pThis->pOps->pfnQueryMaxSize)
4366 {
4367 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4368 rc = pThis->pOps->pfnQueryMaxSize(pThis->Stream.Base.pvThis, pcbMax);
4369 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4370 }
4371 else
4372 rc = VERR_WRITE_PROTECT;
4373 return rc;
4374}
4375
4376
4377RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile)
4378{
4379 RTVFSFILEINTERNAL *pThis = hVfsFile;
4380 AssertPtrReturn(pThis, 0);
4381 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, 0);
4382 return pThis->Stream.fFlags;
4383}
4384
Note: See TracBrowser for help on using the repository browser.

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