VirtualBox

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

Last change on this file was 101108, checked in by vboxsync, 8 months ago

IPRT: Fixing assertions (from r158845) related to VFS pfnRead/pfnWrite operations.

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

© 2023 Oracle
ContactPrivacy policyTerms of Use