VirtualBox

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

Last change on this file since 107378 was 106061, checked in by vboxsync, 5 months ago

Copyright year updates by scm.

  • 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 106061 2024-09-16 14:03:52Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Base.
4 */
5
6/*
7 * Copyright (C) 2010-2024 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 && RTTimeMilliTS() - uMsStart < cMillies);
2032 if (rc == VERR_INTERRUPTED)
2033 rc = VERR_TIMEOUT;
2034 }
2035
2036 *pfRetEvents = 0;
2037 return rc;
2038}
2039
2040
2041RTDECL(int) RTVfsUtilPumpIoStreams(RTVFSIOSTREAM hVfsIosSrc, RTVFSIOSTREAM hVfsIosDst, size_t cbBufHint)
2042{
2043 /*
2044 * Allocate a temporary buffer.
2045 */
2046 size_t cbBuf = cbBufHint;
2047 if (!cbBuf)
2048 cbBuf = _64K;
2049 else if (cbBuf < _4K)
2050 cbBuf = _4K;
2051 else if (cbBuf > _1M)
2052 cbBuf = _1M;
2053
2054 void *pvBuf = RTMemTmpAlloc(cbBuf);
2055 if (!pvBuf)
2056 {
2057 cbBuf = _4K;
2058 pvBuf = RTMemTmpAlloc(cbBuf);
2059 if (!pvBuf)
2060 return VERR_NO_TMP_MEMORY;
2061 }
2062
2063 /*
2064 * Pump loop.
2065 */
2066 int rc;
2067 for (;;)
2068 {
2069 size_t cbRead;
2070 rc = RTVfsIoStrmRead(hVfsIosSrc, pvBuf, cbBuf, true /*fBlocking*/, &cbRead);
2071 if (RT_FAILURE(rc))
2072 break;
2073 if (rc == VINF_EOF && cbRead == 0)
2074 break;
2075
2076 rc = RTVfsIoStrmWrite(hVfsIosDst, pvBuf, cbRead, true /*fBlocking*/, NULL /*cbWritten*/);
2077 if (RT_FAILURE(rc))
2078 break;
2079 }
2080
2081 RTMemTmpFree(pvBuf);
2082
2083 /*
2084 * Flush the destination stream on success to make sure we've caught
2085 * errors caused by buffering delays.
2086 */
2087 if (RT_SUCCESS(rc))
2088 rc = RTVfsIoStrmFlush(hVfsIosDst);
2089
2090 return rc;
2091}
2092
2093
2094
2095
2096
2097/*
2098 * F I L E S Y S T E M R O O T
2099 * F I L E S Y S T E M R O O T
2100 * F I L E S Y S T E M R O O T
2101 */
2102
2103
2104RTDECL(int) RTVfsNew(PCRTVFSOPS pVfsOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
2105 PRTVFS phVfs, void **ppvInstance)
2106{
2107 /*
2108 * Validate the input, be extra strict in strict builds.
2109 */
2110 AssertPtr(pVfsOps);
2111 AssertReturn(pVfsOps->uVersion == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
2112 AssertReturn(pVfsOps->uEndMarker == RTVFSOPS_VERSION, VERR_VERSION_MISMATCH);
2113 RTVFSOBJ_ASSERT_OPS(&pVfsOps->Obj, RTVFSOBJTYPE_VFS);
2114 Assert(cbInstance > 0);
2115 AssertPtr(ppvInstance);
2116 AssertPtr(phVfs);
2117
2118 /*
2119 * Allocate the handle + instance data.
2120 */
2121 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSINTERNAL), RTVFS_INST_ALIGNMENT)
2122 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2123 RTVFSINTERNAL *pThis = (RTVFSINTERNAL *)RTMemAllocZ(cbThis);
2124 if (!pThis)
2125 return VERR_NO_MEMORY;
2126
2127 int rc = rtVfsObjInitNewObject(&pThis->Base, &pVfsOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2128 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2129 if (RT_FAILURE(rc))
2130 {
2131 RTMemFree(pThis);
2132 return rc;
2133 }
2134
2135 pThis->uMagic = RTVFS_MAGIC;
2136 pThis->pOps = pVfsOps;
2137
2138 *phVfs = pThis;
2139 *ppvInstance = pThis->Base.pvThis;
2140
2141 LogFlow(("RTVfsNew -> VINF_SUCCESS; hVfs=%p pvThis=%p\n", pThis, pThis->Base.pvThis));
2142 return VINF_SUCCESS;
2143}
2144
2145#ifdef DEBUG
2146# undef RTVfsRetain
2147#endif
2148RTDECL(uint32_t) RTVfsRetain(RTVFS hVfs)
2149{
2150 RTVFSINTERNAL *pThis = hVfs;
2151 AssertPtrReturn(pThis, UINT32_MAX);
2152 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2153 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2154 LogFlow(("RTVfsRetain(%p/%p) -> %d\n", pThis, pThis->Base.pvThis, cRefs));
2155 return cRefs;
2156}
2157#ifdef DEBUG
2158# define RTVfsRetain(hVfs) RTVfsRetainDebug(hVfs, RT_SRC_POS)
2159#endif
2160
2161
2162RTDECL(uint32_t) RTVfsRetainDebug(RTVFS hVfs, RT_SRC_POS_DECL)
2163{
2164 RTVFSINTERNAL *pThis = hVfs;
2165 AssertPtrReturn(pThis, UINT32_MAX);
2166 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2167 RT_SRC_POS_NOREF();
2168 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsRetainDebug", RT_SRC_POS_ARGS);
2169}
2170
2171
2172RTDECL(uint32_t) RTVfsRelease(RTVFS hVfs)
2173{
2174 RTVFSINTERNAL *pThis = hVfs;
2175 if (pThis == NIL_RTVFS)
2176 return 0;
2177 AssertPtrReturn(pThis, UINT32_MAX);
2178 AssertReturn(pThis->uMagic == RTVFS_MAGIC, UINT32_MAX);
2179#ifdef LOG_ENABLED
2180 void *pvThis = pThis->Base.pvThis;
2181#endif
2182 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2183 Log(("RTVfsRelease(%p/%p) -> %d\n", pThis, pvThis, cRefs));
2184 return cRefs;
2185}
2186
2187
2188RTDECL(int) RTVfsOpenRoot(RTVFS hVfs, PRTVFSDIR phDir)
2189{
2190 RTVFSINTERNAL *pThis = hVfs;
2191 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2192 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2193 AssertPtrReturn(phDir, VERR_INVALID_POINTER);
2194 *phDir = NIL_RTVFSDIR;
2195
2196 if (!pThis->pOps->pfnOpenRoot)
2197 return VERR_NOT_SUPPORTED;
2198 RTVfsLockAcquireRead(pThis->Base.hLock);
2199 int rc = pThis->pOps->pfnOpenRoot(pThis->Base.pvThis, phDir);
2200 RTVfsLockReleaseRead(pThis->Base.hLock);
2201
2202 return rc;
2203}
2204
2205
2206RTDECL(int) RTVfsQueryPathInfo(RTVFS hVfs, const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
2207{
2208 RTVFSINTERNAL *pThis = hVfs;
2209 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2210 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2211 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2212 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
2213 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
2214 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
2215 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
2216
2217 /*
2218 * Parse the path, assume current directory is root since we've got no
2219 * caller context here. Then traverse to the parent directory.
2220 */
2221 PRTVFSPARSEDPATH pPath;
2222 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2223 if (RT_SUCCESS(rc))
2224 {
2225 /*
2226 * Tranverse the path, resolving the parent node.
2227 * We'll do the symbolic link checking here with help of pfnOpen/pfnQueryEntryInfo.
2228 */
2229 RTVFSDIRINTERNAL *pVfsParentDir;
2230 rc = rtVfsTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2231 if (RT_SUCCESS(rc))
2232 {
2233 /*
2234 * Do the opening. Loop if we need to follow symbolic links.
2235 */
2236 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING;
2237 for (uint32_t cLoops = 1; ; cLoops++)
2238 {
2239 /* If we end with a directory slash, adjust open flags. */
2240 if (pPath->fDirSlash)
2241 {
2242 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
2243 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
2244 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
2245 }
2246 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
2247 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
2248
2249 /* Do the querying. If pfnQueryEntryInfo is available, we use it first,
2250 falling back on pfnOpen in case of symbolic links that needs following. */
2251 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2252 if (pVfsParentDir->pOps->pfnQueryEntryInfo)
2253 {
2254 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2255 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
2256 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2257 if (RT_FAILURE(rc))
2258 break;
2259 if ( !RTFS_IS_SYMLINK(pObjInfo->Attr.fMode)
2260 || !(fFlags & RTPATH_F_FOLLOW_LINK))
2261 {
2262 if ( (fObjFlags & RTVFSOBJ_F_OPEN_MASK) != RTVFSOBJ_F_OPEN_ANY
2263 && !RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
2264 rc = VERR_NOT_A_DIRECTORY;
2265 break;
2266 }
2267 }
2268
2269 RTVFSOBJ hVfsObj;
2270 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2271 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName,
2272 RTFILE_O_ACCESS_ATTR_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
2273 fObjFlags, &hVfsObj);
2274 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2275 if (RT_FAILURE(rc))
2276 break;
2277
2278 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2279 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2280 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2281 {
2282 rc = RTVfsObjQueryInfo(hVfsObj, pObjInfo, enmAddAttr);
2283 RTVfsObjRelease(hVfsObj);
2284 break;
2285 }
2286
2287 /* Follow symbolic link. */
2288 if (cLoops < RTVFS_MAX_LINKS)
2289 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2290 else
2291 rc = VERR_TOO_MANY_SYMLINKS;
2292 RTVfsObjRelease(hVfsObj);
2293 if (RT_FAILURE(rc))
2294 break;
2295 }
2296 RTVfsDirRelease(pVfsParentDir);
2297 }
2298 RTVfsParsePathFree(pPath);
2299 }
2300 return rc;
2301}
2302
2303
2304
2305RTDECL(int) RTVfsQueryRangeState(RTVFS hVfs, uint64_t off, size_t cb, bool *pfUsed)
2306{
2307 RTVFSINTERNAL *pThis = hVfs;
2308 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2309 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2310
2311 if (!pThis->pOps->pfnQueryRangeState)
2312 return VERR_NOT_SUPPORTED;
2313 RTVfsLockAcquireRead(pThis->Base.hLock);
2314 int rc = pThis->pOps->pfnQueryRangeState(pThis->Base.pvThis, off, cb, pfUsed);
2315 RTVfsLockReleaseRead(pThis->Base.hLock);
2316
2317 return rc;
2318}
2319
2320
2321RTDECL(int) RTVfsQueryLabel(RTVFS hVfs, bool fAlternative, char *pszLabel, size_t cbLabel, size_t *pcbActual)
2322{
2323 RTVFSINTERNAL *pThis = hVfs;
2324 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2325 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2326
2327 if (cbLabel > 0)
2328 AssertPtrReturn(pszLabel, VERR_INVALID_POINTER);
2329
2330 int rc;
2331 if (pThis->pOps->Obj.pfnQueryInfoEx)
2332 {
2333 size_t cbActualIgn;
2334 if (!pcbActual)
2335 pcbActual = &cbActualIgn;
2336
2337 RTVfsLockAcquireRead(pThis->Base.hLock);
2338 rc = pThis->pOps->Obj.pfnQueryInfoEx(pThis->Base.pvThis, !fAlternative ? RTVFSQIEX_VOL_LABEL : RTVFSQIEX_VOL_LABEL_ALT,
2339 pszLabel, cbLabel, pcbActual);
2340 RTVfsLockReleaseRead(pThis->Base.hLock);
2341 }
2342 else
2343 rc = VERR_NOT_SUPPORTED;
2344 return rc;
2345}
2346
2347
2348
2349/*
2350 *
2351 * F I L E S Y S T E M S T R E A M
2352 * F I L E S Y S T E M S T R E A M
2353 * F I L E S Y S T E M S T R E A M
2354 *
2355 */
2356
2357
2358RTDECL(int) RTVfsNewFsStream(PCRTVFSFSSTREAMOPS pFsStreamOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock, uint32_t fAccess,
2359 PRTVFSFSSTREAM phVfsFss, void **ppvInstance)
2360{
2361 /*
2362 * Validate the input, be extra strict in strict builds.
2363 */
2364 AssertPtr(pFsStreamOps);
2365 AssertReturn(pFsStreamOps->uVersion == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2366 AssertReturn(pFsStreamOps->uEndMarker == RTVFSFSSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
2367 Assert(!pFsStreamOps->fReserved);
2368 RTVFSOBJ_ASSERT_OPS(&pFsStreamOps->Obj, RTVFSOBJTYPE_FS_STREAM);
2369 Assert((fAccess & (RTFILE_O_READ | RTFILE_O_WRITE)) == fAccess);
2370 Assert(fAccess);
2371 if (fAccess & RTFILE_O_READ)
2372 AssertPtr(pFsStreamOps->pfnNext);
2373 if (fAccess & RTFILE_O_WRITE)
2374 {
2375 AssertPtr(pFsStreamOps->pfnAdd);
2376 AssertPtr(pFsStreamOps->pfnEnd);
2377 }
2378 Assert(cbInstance > 0);
2379 AssertPtr(ppvInstance);
2380 AssertPtr(phVfsFss);
2381 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2382
2383 /*
2384 * Allocate the handle + instance data.
2385 */
2386 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFSSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
2387 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2388 RTVFSFSSTREAMINTERNAL *pThis = (RTVFSFSSTREAMINTERNAL *)RTMemAllocZ(cbThis);
2389 if (!pThis)
2390 return VERR_NO_MEMORY;
2391
2392 int rc = rtVfsObjInitNewObject(&pThis->Base, &pFsStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
2393 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2394
2395 if (RT_FAILURE(rc))
2396 {
2397 RTMemFree(pThis);
2398 return rc;
2399 }
2400
2401 pThis->uMagic = RTVFSFSSTREAM_MAGIC;
2402 pThis->pOps = pFsStreamOps;
2403 pThis->fFlags = fAccess;
2404 if (fAccess == RTFILE_O_READ)
2405 pThis->fFlags |= RTFILE_O_OPEN | RTFILE_O_DENY_NONE;
2406 else if (fAccess == RTFILE_O_WRITE)
2407 pThis->fFlags |= RTFILE_O_CREATE | RTFILE_O_DENY_ALL;
2408 else
2409 pThis->fFlags |= RTFILE_O_OPEN | RTFILE_O_DENY_ALL;
2410
2411 *phVfsFss = pThis;
2412 *ppvInstance = pThis->Base.pvThis;
2413 return VINF_SUCCESS;
2414}
2415
2416
2417#ifdef DEBUG
2418# undef RTVfsFsStrmRetain
2419#endif
2420RTDECL(uint32_t) RTVfsFsStrmRetain(RTVFSFSSTREAM hVfsFss)
2421{
2422 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2423 AssertPtrReturn(pThis, UINT32_MAX);
2424 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2425 return rtVfsObjRetain(&pThis->Base);
2426}
2427#ifdef DEBUG
2428# define RTVfsFsStrmRetain(hVfsFss) RTVfsFsStrmRetainDebug(hVfsFss, RT_SRC_POS)
2429#endif
2430
2431
2432RTDECL(uint32_t) RTVfsFsStrmRetainDebug(RTVFSFSSTREAM hVfsFss, RT_SRC_POS_DECL)
2433{
2434 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2435 AssertPtrReturn(pThis, UINT32_MAX);
2436 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2437 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsFsStrmRetain", RT_SRC_POS_ARGS);
2438}
2439
2440
2441RTDECL(uint32_t) RTVfsFsStrmRelease(RTVFSFSSTREAM hVfsFss)
2442{
2443 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2444 if (pThis == NIL_RTVFSFSSTREAM)
2445 return 0;
2446 AssertPtrReturn(pThis, UINT32_MAX);
2447 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, UINT32_MAX);
2448 return rtVfsObjRelease(&pThis->Base);
2449}
2450
2451
2452RTDECL(int) RTVfsFsStrmQueryInfo(RTVFSFSSTREAM hVfsFss, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
2453{
2454 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2455 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2456 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2457 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
2458}
2459
2460
2461RTDECL(int) RTVfsFsStrmNext(RTVFSFSSTREAM hVfsFss, char **ppszName, RTVFSOBJTYPE *penmType, PRTVFSOBJ phVfsObj)
2462{
2463 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2464 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2465 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2466 AssertPtrNullReturn(ppszName, VERR_INVALID_POINTER);
2467 if (ppszName)
2468 *ppszName = NULL;
2469 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2470 if (penmType)
2471 *penmType = RTVFSOBJTYPE_INVALID;
2472 AssertPtrNullReturn(penmType, VERR_INVALID_POINTER);
2473 if (phVfsObj)
2474 *phVfsObj = NIL_RTVFSOBJ;
2475
2476 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_INVALID_FUNCTION);
2477
2478 return pThis->pOps->pfnNext(pThis->Base.pvThis, ppszName, penmType, phVfsObj);
2479}
2480
2481
2482RTDECL(int) RTVfsFsStrmAdd(RTVFSFSSTREAM hVfsFss, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)
2483{
2484 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2485 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2486 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2487 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2488 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2489 AssertPtrReturn(hVfsObj, VERR_INVALID_HANDLE);
2490 AssertReturn(hVfsObj->uMagic == RTVFSOBJ_MAGIC, VERR_INVALID_HANDLE);
2491 AssertReturn(!(fFlags & ~RTVFSFSSTRM_ADD_F_VALID_MASK), VERR_INVALID_FLAGS);
2492 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2493
2494 return pThis->pOps->pfnAdd(pThis->Base.pvThis, pszPath, hVfsObj, fFlags);
2495}
2496
2497
2498RTDECL(int) RTVfsFsStrmPushFile(RTVFSFSSTREAM hVfsFss, const char *pszPath, uint64_t cbFile,
2499 PCRTFSOBJINFO paObjInfo, uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
2500{
2501 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2502 AssertPtrReturn(phVfsIos, VERR_INVALID_POINTER);
2503 *phVfsIos = NIL_RTVFSIOSTREAM;
2504
2505 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2506 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2507
2508 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2509 AssertReturn(*pszPath != '\0', VERR_INVALID_NAME);
2510
2511 AssertReturn(!(fFlags & ~RTVFSFSSTRM_PUSH_F_VALID_MASK), VERR_INVALID_FLAGS);
2512 AssertReturn(RT_BOOL(cbFile == UINT64_MAX) == RT_BOOL(fFlags & RTVFSFSSTRM_PUSH_F_STREAM), VERR_INVALID_FLAGS);
2513
2514 if (cObjInfo)
2515 {
2516 AssertPtrReturn(paObjInfo, VERR_INVALID_POINTER);
2517 AssertReturn(paObjInfo[0].Attr.enmAdditional == RTFSOBJATTRADD_UNIX, VERR_INVALID_PARAMETER);
2518 }
2519
2520 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_INVALID_FUNCTION);
2521 if (pThis->pOps->pfnPushFile)
2522 return pThis->pOps->pfnPushFile(pThis->Base.pvThis, pszPath, cbFile, paObjInfo, cObjInfo, fFlags, phVfsIos);
2523 return VERR_NOT_SUPPORTED;
2524}
2525
2526
2527RTDECL(int) RTVfsFsStrmEnd(RTVFSFSSTREAM hVfsFss)
2528{
2529 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2530 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2531 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, VERR_INVALID_HANDLE);
2532
2533 return pThis->pOps->pfnEnd(pThis->Base.pvThis);
2534}
2535
2536
2537RTDECL(void *) RTVfsFsStreamToPrivate(RTVFSFSSTREAM hVfsFss, PCRTVFSFSSTREAMOPS pFsStreamOps)
2538{
2539 RTVFSFSSTREAMINTERNAL *pThis = hVfsFss;
2540 AssertPtrReturn(pThis, NULL);
2541 AssertReturn(pThis->uMagic == RTVFSFSSTREAM_MAGIC, NULL);
2542 if (pThis->pOps != pFsStreamOps)
2543 return NULL;
2544 return pThis->Base.pvThis;
2545}
2546
2547
2548/*
2549 *
2550 * D I R D I R D I R
2551 * D I R D I R D I R
2552 * D I R D I R D I R
2553 *
2554 */
2555
2556
2557RTDECL(int) RTVfsNewDir(PCRTVFSDIROPS pDirOps, size_t cbInstance, uint32_t fFlags, RTVFS hVfs, RTVFSLOCK hLock,
2558 PRTVFSDIR phVfsDir, void **ppvInstance)
2559{
2560 /*
2561 * Validate the input, be extra strict in strict builds.
2562 */
2563 AssertPtr(pDirOps);
2564 AssertReturn(pDirOps->uVersion == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2565 AssertReturn(pDirOps->uEndMarker == RTVFSDIROPS_VERSION, VERR_VERSION_MISMATCH);
2566 Assert(!pDirOps->fReserved);
2567 RTVFSDIR_ASSERT_OPS(pDirOps, RTVFSOBJTYPE_DIR);
2568 Assert(cbInstance > 0);
2569 AssertReturn(!(fFlags & ~RTVFSDIR_F_NO_VFS_REF), VERR_INVALID_FLAGS);
2570 AssertPtr(ppvInstance);
2571 AssertPtr(phVfsDir);
2572 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
2573
2574 /*
2575 * Allocate the handle + instance data.
2576 */
2577 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSDIRINTERNAL), RTVFS_INST_ALIGNMENT)
2578 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
2579 RTVFSDIRINTERNAL *pThis = (RTVFSDIRINTERNAL *)RTMemAllocZ(cbThis);
2580 if (!pThis)
2581 return VERR_NO_MEMORY;
2582
2583 int rc = rtVfsObjInitNewObject(&pThis->Base, &pDirOps->Obj, hVfs, RT_BOOL(fFlags & RTVFSDIR_F_NO_VFS_REF), hLock,
2584 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
2585 if (RT_FAILURE(rc))
2586 {
2587 RTMemFree(pThis);
2588 return rc;
2589 }
2590
2591 pThis->uMagic = RTVFSDIR_MAGIC;
2592 pThis->fReserved = 0;
2593 pThis->pOps = pDirOps;
2594
2595 *phVfsDir = pThis;
2596 *ppvInstance = pThis->Base.pvThis;
2597 return VINF_SUCCESS;
2598}
2599
2600
2601RTDECL(void *) RTVfsDirToPrivate(RTVFSDIR hVfsDir, PCRTVFSDIROPS pDirOps)
2602{
2603 RTVFSDIRINTERNAL *pThis = hVfsDir;
2604 AssertPtrReturn(pThis, NULL);
2605 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, NULL);
2606 if (pThis->pOps != pDirOps)
2607 return NULL;
2608 return pThis->Base.pvThis;
2609}
2610
2611
2612#ifdef DEBUG
2613# undef RTVfsDirRetain
2614#endif
2615RTDECL(uint32_t) RTVfsDirRetain(RTVFSDIR hVfsDir)
2616{
2617 RTVFSDIRINTERNAL *pThis = hVfsDir;
2618 AssertPtrReturn(pThis, UINT32_MAX);
2619 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2620 uint32_t cRefs = rtVfsObjRetain(&pThis->Base);
2621 LogFlow(("RTVfsDirRetain(%p/%p) -> %#x\n", pThis, pThis->Base.pvThis, cRefs));
2622 return cRefs;
2623}
2624#ifdef DEBUG
2625# define RTVfsDirRetain(hVfsDir) RTVfsDirRetainDebug(hVfsDir, RT_SRC_POS)
2626#endif
2627
2628
2629RTDECL(uint32_t) RTVfsDirRetainDebug(RTVFSDIR hVfsDir, RT_SRC_POS_DECL)
2630{
2631 RTVFSDIRINTERNAL *pThis = hVfsDir;
2632 AssertPtrReturn(pThis, UINT32_MAX);
2633 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2634 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsDirRetain", RT_SRC_POS_ARGS);
2635}
2636
2637
2638RTDECL(uint32_t) RTVfsDirRelease(RTVFSDIR hVfsDir)
2639{
2640 RTVFSDIRINTERNAL *pThis = hVfsDir;
2641 if (pThis == NIL_RTVFSDIR)
2642 return 0;
2643 AssertPtrReturn(pThis, UINT32_MAX);
2644 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, UINT32_MAX);
2645#ifdef LOG_ENABLED
2646 void *pvThis = pThis->Base.pvThis;
2647#endif
2648 uint32_t cRefs = rtVfsObjRelease(&pThis->Base);
2649 LogFlow(("RTVfsDirRelease(%p/%p) -> %#x\n", pThis, pvThis, cRefs));
2650 return cRefs;
2651}
2652
2653
2654RTDECL(int) RTVfsDirOpen(RTVFS hVfs, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2655{
2656 /*
2657 * Validate input.
2658 */
2659 RTVFSINTERNAL *pThis = hVfs;
2660 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2661 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
2662 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2663 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2664 AssertReturn(!fFlags, VERR_INVALID_FLAGS); /** @todo sort out flags! */
2665
2666 /*
2667 * Parse the path, assume current directory is root since we've got no
2668 * caller context here.
2669 */
2670 PRTVFSPARSEDPATH pPath;
2671 int rc = RTVfsParsePathA(pszPath, "/", &pPath);
2672 if (RT_SUCCESS(rc))
2673 {
2674 /*
2675 * Tranverse the path, resolving the parent node.
2676 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenDir.
2677 */
2678 RTVFSDIRINTERNAL *pVfsParentDir;
2679 rc = rtVfsTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
2680 if (RT_SUCCESS(rc))
2681 {
2682 /*
2683 * Do the opening. Loop if we need to follow symbolic links.
2684 */
2685 uint64_t fOpenFlags = RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN;
2686 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING;
2687 for (uint32_t cLoops = 1; ; cLoops++)
2688 {
2689 /* Do the querying. If pfnOpenDir is available, we use it first, falling
2690 back on pfnOpen in case of symbolic links that needs following. */
2691 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2692 if (pVfsParentDir->pOps->pfnOpenDir)
2693 {
2694 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2695 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2696 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2697 if ( RT_SUCCESS(rc)
2698 || ( rc != VERR_NOT_A_DIRECTORY
2699 && rc != VERR_IS_A_SYMLINK))
2700 break;
2701 }
2702
2703 RTVFSOBJ hVfsObj;
2704 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2705 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpenFlags, fObjFlags, &hVfsObj);
2706 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2707 if (RT_FAILURE(rc))
2708 break;
2709
2710 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2711 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2712 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2713 {
2714 *phVfsDir = RTVfsObjToDir(hVfsObj);
2715 AssertStmt(*phVfsDir != NIL_RTVFSDIR, rc = VERR_INTERNAL_ERROR_3);
2716 RTVfsObjRelease(hVfsObj);
2717 break;
2718 }
2719
2720 /* Follow symbolic link. */
2721 if (cLoops < RTVFS_MAX_LINKS)
2722 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
2723 else
2724 rc = VERR_TOO_MANY_SYMLINKS;
2725 RTVfsObjRelease(hVfsObj);
2726 if (RT_FAILURE(rc))
2727 break;
2728 }
2729 RTVfsDirRelease(pVfsParentDir);
2730 }
2731 RTVfsParsePathFree(pPath);
2732 }
2733 return rc;
2734}
2735
2736
2737RTDECL(int) RTVfsDirOpenDir(RTVFSDIR hVfsDir, const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
2738{
2739 /*
2740 * Validate input.
2741 */
2742 RTVFSDIRINTERNAL *pThis = hVfsDir;
2743 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2744 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2745 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2746 AssertPtrReturn(phVfsDir, VERR_INVALID_POINTER);
2747 AssertReturn(!fFlags, VERR_INVALID_FLAGS); /** @todo sort out flags! */
2748
2749 /*
2750 * Parse the path, it's always relative to the given directory.
2751 */
2752 PRTVFSPARSEDPATH pPath;
2753 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2754 if (RT_SUCCESS(rc))
2755 {
2756 /*
2757 * Tranverse the path, resolving the parent node.
2758 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenDir.
2759 */
2760 RTVFSDIRINTERNAL *pVfsParentDir;
2761 uint32_t const fTraverse = (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK;
2762 rc = rtVfsDirTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
2763 if (RT_SUCCESS(rc))
2764 {
2765 /*
2766 * Do the opening. Loop if we need to follow symbolic links.
2767 */
2768 uint64_t fOpenFlags = RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN;
2769 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_DIRECTORY | RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_NOTHING | fTraverse;
2770 for (uint32_t cLoops = 1; ; cLoops++)
2771 {
2772 /* Do the querying. If pfnOpenDir is available, we use it first, falling
2773 back on pfnOpen in case of symbolic links that needs following. */
2774 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2775 if (pVfsParentDir->pOps->pfnOpenDir)
2776 {
2777 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2778 rc = pVfsParentDir->pOps->pfnOpenDir(pVfsParentDir->Base.pvThis, pszEntryName, fFlags, phVfsDir);
2779 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2780 if ( RT_SUCCESS(rc)
2781 || ( rc != VERR_NOT_A_DIRECTORY
2782 && rc != VERR_IS_A_SYMLINK))
2783 break;
2784 }
2785
2786 RTVFSOBJ hVfsObj;
2787 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2788 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpenFlags, fObjFlags, &hVfsObj);
2789 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2790 if (RT_FAILURE(rc))
2791 break;
2792
2793 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2794 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2795 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2796 {
2797 *phVfsDir = RTVfsObjToDir(hVfsObj);
2798 AssertStmt(*phVfsDir != NIL_RTVFSDIR, rc = VERR_INTERNAL_ERROR_3);
2799 RTVfsObjRelease(hVfsObj);
2800 break;
2801 }
2802
2803 /* Follow symbolic link. */
2804 if (cLoops < RTVFS_MAX_LINKS)
2805 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
2806 else
2807 rc = VERR_TOO_MANY_SYMLINKS;
2808 RTVfsObjRelease(hVfsObj);
2809 if (RT_FAILURE(rc))
2810 break;
2811 }
2812 RTVfsDirRelease(pVfsParentDir);
2813 }
2814 RTVfsParsePathFree(pPath);
2815 }
2816 return rc;
2817}
2818
2819
2820RTDECL(int) RTVfsDirCreateDir(RTVFSDIR hVfsDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags, PRTVFSDIR phVfsDir)
2821{
2822 /*
2823 * Validate input.
2824 */
2825 RTVFSDIRINTERNAL *pThis = hVfsDir;
2826 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2827 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2828 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
2829 AssertPtrNullReturn(phVfsDir, VERR_INVALID_POINTER);
2830 AssertReturn(!(fFlags & ~RTDIRCREATE_FLAGS_VALID_MASK), VERR_INVALID_FLAGS);
2831 fMode = rtFsModeNormalize(fMode, pszRelPath, 0, RTFS_TYPE_DIRECTORY);
2832 AssertReturn(rtFsModeIsValidPermissions(fMode), VERR_INVALID_FMODE);
2833 if (!(fFlags & RTDIRCREATE_FLAGS_NOT_CONTENT_INDEXED_DONT_SET))
2834 fMode |= RTFS_DOS_NT_NOT_CONTENT_INDEXED;
2835
2836 /*
2837 * Parse the path, it's always relative to the given directory.
2838 */
2839 PRTVFSPARSEDPATH pPath;
2840 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
2841 if (RT_SUCCESS(rc))
2842 {
2843 /*
2844 * Tranverse the path, resolving the parent node.
2845 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenDir.
2846 */
2847 RTVFSDIRINTERNAL *pVfsParentDir;
2848 uint32_t fTraverse = (fFlags & RTDIRCREATE_FLAGS_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_ON_LINK;
2849 rc = rtVfsDirTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
2850 if (RT_SUCCESS(rc))
2851 {
2852 /*
2853 * Do the opening. Loop if we need to follow symbolic links.
2854 */
2855 uint64_t fOpenFlags = RTFILE_O_READ | RTFILE_O_DENY_NONE | RTFILE_O_CREATE
2856 | ((fMode << RTFILE_O_CREATE_MODE_SHIFT) & RTFILE_O_CREATE_MODE_MASK);
2857 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_SYMLINK | RTVFSOBJ_F_CREATE_DIRECTORY | fTraverse;
2858 for (uint32_t cLoops = 1; ; cLoops++)
2859 {
2860 /* Do the querying. If pfnOpenDir is available, we use it first, falling
2861 back on pfnOpen in case of symbolic links that needs following. */
2862 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2863 if (pVfsParentDir->pOps->pfnCreateDir)
2864 {
2865 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2866 rc = pVfsParentDir->pOps->pfnCreateDir(pVfsParentDir->Base.pvThis, pszEntryName, fMode, phVfsDir);
2867 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2868 if ( RT_SUCCESS(rc)
2869 || ( rc != VERR_NOT_A_DIRECTORY
2870 && rc != VERR_IS_A_SYMLINK))
2871 break;
2872 }
2873
2874 RTVFSOBJ hVfsObj;
2875 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2876 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpenFlags, fObjFlags, &hVfsObj);
2877 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2878 if (RT_FAILURE(rc))
2879 break;
2880
2881 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2882 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2883 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2884 {
2885 if (phVfsDir)
2886 {
2887 *phVfsDir = RTVfsObjToDir(hVfsObj);
2888 AssertStmt(*phVfsDir != NIL_RTVFSDIR, rc = VERR_INTERNAL_ERROR_3);
2889 }
2890 RTVfsObjRelease(hVfsObj);
2891 break;
2892 }
2893
2894 /* Follow symbolic link. */
2895 if (cLoops < RTVFS_MAX_LINKS)
2896 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
2897 else
2898 rc = VERR_TOO_MANY_SYMLINKS;
2899 RTVfsObjRelease(hVfsObj);
2900 if (RT_FAILURE(rc))
2901 break;
2902 }
2903 RTVfsDirRelease(pVfsParentDir);
2904 }
2905 RTVfsParsePathFree(pPath);
2906 }
2907 return rc;
2908}
2909
2910
2911RTDECL(int) RTVfsDirOpenFile(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSFILE phVfsFile)
2912{
2913 /*
2914 * Validate input.
2915 */
2916 RTVFSDIRINTERNAL *pThis = hVfsDir;
2917 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
2918 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
2919 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
2920 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
2921
2922 int rc = rtFileRecalcAndValidateFlags(&fOpen);
2923 if (RT_FAILURE(rc))
2924 return rc;
2925
2926 /*
2927 * Parse the path, it's always relative to the given directory.
2928 */
2929 PRTVFSPARSEDPATH pPath;
2930 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
2931 if (RT_SUCCESS(rc))
2932 {
2933 /*
2934 * Tranverse the path, resolving the parent node.
2935 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenFile.
2936 */
2937 RTVFSDIRINTERNAL *pVfsParentDir;
2938 uint32_t const fTraverse = (fOpen & RTFILE_O_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_ON_LINK;
2939 rc = rtVfsDirTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
2940 if (RT_SUCCESS(rc))
2941 {
2942 /** @todo join path with RTVfsFileOpen. */
2943
2944 /*
2945 * Do the opening. Loop if we need to follow symbolic links.
2946 */
2947 bool fDirSlash = pPath->fDirSlash;
2948
2949 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY_FILE | RTVFSOBJ_F_OPEN_SYMLINK;
2950 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
2951 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
2952 fObjFlags |= RTVFSOBJ_F_CREATE_FILE;
2953 else
2954 fObjFlags |= RTVFSOBJ_F_CREATE_NOTHING;
2955 fObjFlags |= fTraverse & RTPATH_F_MASK;
2956
2957 for (uint32_t cLoops = 1;; cLoops++)
2958 {
2959 /* Do the querying. If pfnOpenFile is available, we use it first, falling
2960 back on pfnOpen in case of symbolic links that needs following or we got
2961 a trailing directory slash (to get file-not-found error). */
2962 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
2963 if ( pVfsParentDir->pOps->pfnOpenFile
2964 && !fDirSlash)
2965 {
2966 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
2967 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
2968 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
2969 if ( RT_SUCCESS(rc)
2970 || ( rc != VERR_NOT_A_FILE
2971 && rc != VERR_IS_A_SYMLINK))
2972 break;
2973 }
2974
2975 RTVFSOBJ hVfsObj;
2976 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
2977 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, fObjFlags, &hVfsObj);
2978 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
2979 if (RT_FAILURE(rc))
2980 break;
2981
2982 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
2983 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
2984 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
2985 {
2986 *phVfsFile = RTVfsObjToFile(hVfsObj);
2987 AssertStmt(*phVfsFile != NIL_RTVFSFILE, rc = VERR_INTERNAL_ERROR_3);
2988 RTVfsObjRelease(hVfsObj);
2989 break;
2990 }
2991
2992 /* Follow symbolic link. */
2993 if (cLoops < RTVFS_MAX_LINKS)
2994 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
2995 else
2996 rc = VERR_TOO_MANY_SYMLINKS;
2997 RTVfsObjRelease(hVfsObj);
2998 if (RT_FAILURE(rc))
2999 break;
3000 fDirSlash |= pPath->fDirSlash;
3001 }
3002 RTVfsDirRelease(pVfsParentDir);
3003 }
3004 RTVfsParsePathFree(pPath);
3005 }
3006 return rc;
3007}
3008
3009
3010RTDECL(int) RTVfsDirOpenFileAsIoStream(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fOpen, PRTVFSIOSTREAM phVfsIos)
3011{
3012 RTVFSFILE hVfsFile;
3013 int rc = RTVfsDirOpenFile(hVfsDir, pszPath, fOpen, &hVfsFile);
3014 if (RT_SUCCESS(rc))
3015 {
3016 *phVfsIos = RTVfsFileToIoStream(hVfsFile);
3017 AssertStmt(*phVfsIos != NIL_RTVFSIOSTREAM, rc = VERR_INTERNAL_ERROR_2);
3018 RTVfsFileRelease(hVfsFile);
3019 }
3020 return rc;
3021}
3022
3023
3024RTDECL(int) RTVfsDirOpenObj(RTVFSDIR hVfsDir, const char *pszPath, uint64_t fFileOpen, uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
3025{
3026 /*
3027 * Validate input.
3028 */
3029 RTVFSDIRINTERNAL *pThis = hVfsDir;
3030 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3031 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3032 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
3033 AssertPtrReturn(phVfsObj, VERR_INVALID_POINTER);
3034
3035 int rc = rtFileRecalcAndValidateFlags(&fFileOpen);
3036 if (RT_FAILURE(rc))
3037 return rc;
3038 AssertMsgReturn( RTPATH_F_IS_VALID(fObjFlags, RTVFSOBJ_F_VALID_MASK)
3039 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) <= RTVFSOBJ_F_CREATE_DIRECTORY,
3040 ("fObjFlags=%#x\n", fObjFlags),
3041 VERR_INVALID_FLAGS);
3042
3043 /*
3044 * Parse the relative path. If it ends with a directory slash or it boils
3045 * down to an empty path (i.e. re-opening hVfsDir), adjust the flags to only
3046 * open/create directories.
3047 */
3048 PRTVFSPARSEDPATH pPath;
3049 rc = RTVfsParsePathA(pszPath, NULL, &pPath);
3050 if (RT_SUCCESS(rc))
3051 {
3052 /*
3053 * Tranverse the path, resolving the parent node.
3054 * We'll do the symbolic link checking here with help of pfnOpen.
3055 */
3056 RTVFSDIRINTERNAL *pVfsParentDir;
3057 rc = rtVfsDirTraverseToParent(pThis, pPath, (fObjFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
3058 if (RT_SUCCESS(rc))
3059 {
3060 /*
3061 * Do the opening. Loop if we need to follow symbolic links.
3062 */
3063 for (uint32_t cLoops = 1;; cLoops++)
3064 {
3065 /* If we end with a directory slash, adjust open flags. */
3066 if (pPath->fDirSlash)
3067 {
3068 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
3069 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
3070 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
3071 }
3072 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
3073 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
3074
3075 /* Open it. */
3076 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3077 RTVFSOBJ hVfsObj;
3078 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3079 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fFileOpen, fObjFlags, &hVfsObj);
3080 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3081 if (RT_FAILURE(rc))
3082 break;
3083
3084 /* We're done if we don't follow links or this wasn't a link. */
3085 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
3086 || RTVfsObjGetType(*phVfsObj) != RTVFSOBJTYPE_SYMLINK)
3087 {
3088 *phVfsObj = hVfsObj;
3089 break;
3090 }
3091
3092 /* Follow symbolic link. */
3093 if (cLoops < RTVFS_MAX_LINKS)
3094 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
3095 else
3096 rc = VERR_TOO_MANY_SYMLINKS;
3097 RTVfsObjRelease(hVfsObj);
3098 if (RT_FAILURE(rc))
3099 break;
3100 }
3101
3102 RTVfsDirRelease(pVfsParentDir);
3103 }
3104 RTVfsParsePathFree(pPath);
3105 }
3106 return rc;
3107}
3108
3109
3110RTDECL(int) RTVfsDirQueryPathInfo(RTVFSDIR hVfsDir, const char *pszPath, PRTFSOBJINFO pObjInfo,
3111 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
3112{
3113 /*
3114 * Validate input.
3115 */
3116 RTVFSDIRINTERNAL *pThis = hVfsDir;
3117 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3118 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3119 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
3120 AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
3121 AssertPtrReturn(pObjInfo, VERR_INVALID_POINTER);
3122 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
3123 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
3124
3125 /*
3126 * Parse the relative path. Then traverse to the parent directory.
3127 */
3128 PRTVFSPARSEDPATH pPath;
3129 int rc = RTVfsParsePathA(pszPath, NULL, &pPath);
3130 if (RT_SUCCESS(rc))
3131 {
3132 /*
3133 * Tranverse the path, resolving the parent node.
3134 * We'll do the symbolic link checking here with help of pfnOpen.
3135 */
3136 RTVFSDIRINTERNAL *pVfsParentDir;
3137 rc = rtVfsDirTraverseToParent(pThis, pPath, (fFlags & RTPATH_F_NO_SYMLINKS) | RTPATH_F_ON_LINK, &pVfsParentDir);
3138 if (RT_SUCCESS(rc))
3139 {
3140 /*
3141 * Do the opening. Loop if we need to follow symbolic links.
3142 */
3143 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_CREATE_NOTHING;
3144 for (uint32_t cLoops = 1;; cLoops++)
3145 {
3146 /* If we end with a directory slash, adjust open flags. */
3147 if (pPath->fDirSlash)
3148 {
3149 fObjFlags &= ~RTVFSOBJ_F_OPEN_ANY | RTVFSOBJ_F_OPEN_DIRECTORY;
3150 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_DIRECTORY)
3151 fObjFlags = (fObjFlags & ~RTVFSOBJ_F_CREATE_MASK) | RTVFSOBJ_F_CREATE_NOTHING;
3152 }
3153 if (fObjFlags & RTPATH_F_FOLLOW_LINK)
3154 fObjFlags |= RTVFSOBJ_F_OPEN_SYMLINK;
3155
3156 /* Do the querying. If pfnQueryEntryInfo is available, we use it first,
3157 falling back on pfnOpen in case of symbolic links that needs following. */
3158 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3159 if (pVfsParentDir->pOps->pfnQueryEntryInfo)
3160 {
3161 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
3162 rc = pVfsParentDir->pOps->pfnQueryEntryInfo(pVfsParentDir->Base.pvThis, pszEntryName, pObjInfo, enmAddAttr);
3163 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
3164 if (RT_FAILURE(rc))
3165 break;
3166 if ( !RTFS_IS_SYMLINK(pObjInfo->Attr.fMode)
3167 || !(fFlags & RTPATH_F_FOLLOW_LINK))
3168 {
3169 if ( (fObjFlags & RTVFSOBJ_F_OPEN_MASK) != RTVFSOBJ_F_OPEN_ANY
3170 && !RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
3171 rc = VERR_NOT_A_DIRECTORY;
3172 break;
3173 }
3174 }
3175
3176 RTVFSOBJ hVfsObj;
3177 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3178 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName,
3179 RTFILE_O_ACCESS_ATTR_READ | RTFILE_O_DENY_NONE | RTFILE_O_OPEN,
3180 fObjFlags, &hVfsObj);
3181 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3182 if (RT_FAILURE(rc))
3183 break;
3184
3185 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
3186 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
3187 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
3188 {
3189 rc = RTVfsObjQueryInfo(hVfsObj, pObjInfo, enmAddAttr);
3190 RTVfsObjRelease(hVfsObj);
3191 break;
3192 }
3193
3194 /* Follow symbolic link. */
3195 if (cLoops < RTVFS_MAX_LINKS)
3196 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fObjFlags & RTPATH_F_MASK);
3197 else
3198 rc = VERR_TOO_MANY_SYMLINKS;
3199 RTVfsObjRelease(hVfsObj);
3200 if (RT_FAILURE(rc))
3201 break;
3202 }
3203
3204 RTVfsDirRelease(pVfsParentDir);
3205 }
3206 RTVfsParsePathFree(pPath);
3207 }
3208 return rc;
3209}
3210
3211
3212RTDECL(int) RTVfsDirRemoveDir(RTVFSDIR hVfsDir, const char *pszRelPath, uint32_t fFlags)
3213{
3214 /*
3215 * Validate input.
3216 */
3217 RTVFSDIRINTERNAL *pThis = hVfsDir;
3218 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3219 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3220 AssertPtrReturn(pszRelPath, VERR_INVALID_POINTER);
3221 AssertReturn(!fFlags, VERR_INVALID_FLAGS);
3222
3223 /*
3224 * Parse the path, it's always relative to the given directory.
3225 */
3226 PRTVFSPARSEDPATH pPath;
3227 int rc = RTVfsParsePathA(pszRelPath, NULL, &pPath);
3228 if (RT_SUCCESS(rc))
3229 {
3230 if (pPath->cComponents > 0)
3231 {
3232 /*
3233 * Tranverse the path, resolving the parent node, not checking for symbolic
3234 * links in the final element, and ask the directory to remove the subdir.
3235 */
3236 RTVFSDIRINTERNAL *pVfsParentDir;
3237 rc = rtVfsDirTraverseToParent(pThis, pPath, RTPATH_F_ON_LINK, &pVfsParentDir);
3238 if (RT_SUCCESS(rc))
3239 {
3240 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
3241
3242 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
3243 if (pVfsParentDir->pOps->pfnUnlinkEntry)
3244 rc = pVfsParentDir->pOps->pfnUnlinkEntry(pVfsParentDir->Base.pvThis, pszEntryName, RTFS_TYPE_DIRECTORY);
3245 else
3246 rc = VERR_NOT_SUPPORTED;
3247 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
3248
3249 RTVfsDirRelease(pVfsParentDir);
3250 }
3251 }
3252 else
3253 rc = VERR_PATH_ZERO_LENGTH;
3254 RTVfsParsePathFree(pPath);
3255 }
3256 return rc;
3257}
3258
3259
3260
3261RTDECL(int) RTVfsDirReadEx(RTVFSDIR hVfsDir, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
3262{
3263 /*
3264 * Validate input.
3265 */
3266 RTVFSDIRINTERNAL *pThis = hVfsDir;
3267 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3268 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3269 AssertPtrReturn(pDirEntry, VERR_INVALID_POINTER);
3270 AssertReturn(enmAddAttr >= RTFSOBJATTRADD_NOTHING && enmAddAttr <= RTFSOBJATTRADD_LAST, VERR_INVALID_PARAMETER);
3271
3272 size_t cbDirEntry = sizeof(*pDirEntry);
3273 if (!pcbDirEntry)
3274 pcbDirEntry = &cbDirEntry;
3275 else
3276 {
3277 cbDirEntry = *pcbDirEntry;
3278 AssertMsgReturn(cbDirEntry >= RT_UOFFSETOF(RTDIRENTRYEX, szName[2]),
3279 ("Invalid *pcbDirEntry=%d (min %zu)\n", *pcbDirEntry, RT_UOFFSETOF(RTDIRENTRYEX, szName[2])),
3280 VERR_INVALID_PARAMETER);
3281 }
3282
3283 /*
3284 * Call the directory method.
3285 */
3286 RTVfsLockAcquireRead(pThis->Base.hLock);
3287 int rc = pThis->pOps->pfnReadDir(pThis->Base.pvThis, pDirEntry, pcbDirEntry, enmAddAttr);
3288 RTVfsLockReleaseRead(pThis->Base.hLock);
3289 return rc;
3290}
3291
3292
3293RTDECL(int) RTVfsDirRewind(RTVFSDIR hVfsDir)
3294{
3295 /*
3296 * Validate input.
3297 */
3298 RTVFSDIRINTERNAL *pThis = hVfsDir;
3299 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3300 AssertReturn(pThis->uMagic == RTVFSDIR_MAGIC, VERR_INVALID_HANDLE);
3301
3302 /*
3303 * Call the directory method.
3304 */
3305 RTVfsLockAcquireRead(pThis->Base.hLock);
3306 int rc = pThis->pOps->pfnRewindDir(pThis->Base.pvThis);
3307 RTVfsLockReleaseRead(pThis->Base.hLock);
3308 return rc;
3309}
3310
3311
3312/*
3313 *
3314 * S Y M B O L I C L I N K
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 *
3318 */
3319
3320RTDECL(int) RTVfsNewSymlink(PCRTVFSSYMLINKOPS pSymlinkOps, size_t cbInstance, RTVFS hVfs, RTVFSLOCK hLock,
3321 PRTVFSSYMLINK phVfsSym, void **ppvInstance)
3322{
3323 /*
3324 * Validate the input, be extra strict in strict builds.
3325 */
3326 AssertPtr(pSymlinkOps);
3327 AssertReturn(pSymlinkOps->uVersion == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3328 AssertReturn(pSymlinkOps->uEndMarker == RTVFSSYMLINKOPS_VERSION, VERR_VERSION_MISMATCH);
3329 Assert(!pSymlinkOps->fReserved);
3330 RTVFSSYMLINK_ASSERT_OPS(pSymlinkOps, RTVFSOBJTYPE_SYMLINK);
3331 Assert(cbInstance > 0);
3332 AssertPtr(ppvInstance);
3333 AssertPtr(phVfsSym);
3334 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3335
3336 /*
3337 * Allocate the handle + instance data.
3338 */
3339 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSSYMLINKINTERNAL), RTVFS_INST_ALIGNMENT)
3340 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3341 RTVFSSYMLINKINTERNAL *pThis = (RTVFSSYMLINKINTERNAL *)RTMemAllocZ(cbThis);
3342 if (!pThis)
3343 return VERR_NO_MEMORY;
3344
3345 int rc = rtVfsObjInitNewObject(&pThis->Base, &pSymlinkOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3346 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3347 if (RT_FAILURE(rc))
3348 {
3349 RTMemFree(pThis);
3350 return rc;
3351 }
3352
3353 pThis->uMagic = RTVFSSYMLINK_MAGIC;
3354 pThis->pOps = pSymlinkOps;
3355
3356 *phVfsSym = pThis;
3357 *ppvInstance = pThis->Base.pvThis;
3358 return VINF_SUCCESS;
3359}
3360
3361
3362RTDECL(void *) RTVfsSymlinkToPrivate(RTVFSSYMLINK hVfsSym, PCRTVFSSYMLINKOPS pSymlinkOps)
3363{
3364 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3365 AssertPtrReturn(pThis, NULL);
3366 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, NULL);
3367 if (pThis->pOps != pSymlinkOps)
3368 return NULL;
3369 return pThis->Base.pvThis;
3370}
3371
3372
3373RTDECL(uint32_t) RTVfsSymlinkRetain(RTVFSSYMLINK hVfsSym)
3374{
3375 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3376 AssertPtrReturn(pThis, UINT32_MAX);
3377 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3378 return rtVfsObjRetain(&pThis->Base);
3379}
3380
3381
3382RTDECL(uint32_t) RTVfsSymlinkRetainDebug(RTVFSSYMLINK hVfsSym, RT_SRC_POS_DECL)
3383{
3384 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3385 AssertPtrReturn(pThis, UINT32_MAX);
3386 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3387 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsSymlinkRetainDebug", RT_SRC_POS_ARGS);
3388}
3389
3390
3391RTDECL(uint32_t) RTVfsSymlinkRelease(RTVFSSYMLINK hVfsSym)
3392{
3393 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3394 if (pThis == NIL_RTVFSSYMLINK)
3395 return 0;
3396 AssertPtrReturn(pThis, UINT32_MAX);
3397 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, UINT32_MAX);
3398 return rtVfsObjRelease(&pThis->Base);
3399}
3400
3401
3402RTDECL(int) RTVfsSymlinkQueryInfo(RTVFSSYMLINK hVfsSym, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3403{
3404 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3405 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3406 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3407 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3408}
3409
3410
3411RTDECL(int) RTVfsSymlinkSetMode(RTVFSSYMLINK hVfsSym, RTFMODE fMode, RTFMODE fMask)
3412{
3413 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3414 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3415 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3416
3417 fMode = rtFsModeNormalize(fMode, NULL, 0, RTFS_TYPE_SYMLINK);
3418 if (!rtFsModeIsValid(fMode))
3419 return VERR_INVALID_PARAMETER;
3420
3421 RTVfsLockAcquireWrite(pThis->Base.hLock);
3422 int rc = pThis->pOps->ObjSet.pfnSetMode(pThis->Base.pvThis, fMode, fMask);
3423 RTVfsLockReleaseWrite(pThis->Base.hLock);
3424 return rc;
3425}
3426
3427
3428RTDECL(int) RTVfsSymlinkSetTimes(RTVFSSYMLINK hVfsSym, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
3429 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
3430{
3431 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3432 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3433 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3434
3435 AssertPtrNullReturn(pAccessTime, VERR_INVALID_POINTER);
3436 AssertPtrNullReturn(pModificationTime, VERR_INVALID_POINTER);
3437 AssertPtrNullReturn(pChangeTime, VERR_INVALID_POINTER);
3438 AssertPtrNullReturn(pBirthTime, VERR_INVALID_POINTER);
3439
3440 RTVfsLockAcquireWrite(pThis->Base.hLock);
3441 int rc = pThis->pOps->ObjSet.pfnSetTimes(pThis->Base.pvThis, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
3442 RTVfsLockReleaseWrite(pThis->Base.hLock);
3443 return rc;
3444}
3445
3446
3447RTDECL(int) RTVfsSymlinkSetOwner(RTVFSSYMLINK hVfsSym, RTUID uid, RTGID gid)
3448{
3449 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3450 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3451 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3452
3453 RTVfsLockAcquireWrite(pThis->Base.hLock);
3454 int rc = pThis->pOps->ObjSet.pfnSetOwner(pThis->Base.pvThis, uid, gid);
3455 RTVfsLockReleaseWrite(pThis->Base.hLock);
3456 return rc;
3457}
3458
3459
3460RTDECL(int) RTVfsSymlinkRead(RTVFSSYMLINK hVfsSym, char *pszTarget, size_t cbTarget)
3461{
3462 RTVFSSYMLINKINTERNAL *pThis = hVfsSym;
3463 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3464 AssertReturn(pThis->uMagic == RTVFSSYMLINK_MAGIC, VERR_INVALID_HANDLE);
3465
3466 RTVfsLockAcquireWrite(pThis->Base.hLock);
3467 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, pszTarget, cbTarget);
3468 RTVfsLockReleaseWrite(pThis->Base.hLock);
3469
3470 return rc;
3471}
3472
3473
3474
3475/*
3476 *
3477 * I / O S T R E A M I / O S T R E A M I / O S T R E A M
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 *
3481 */
3482
3483RTDECL(int) RTVfsNewIoStream(PCRTVFSIOSTREAMOPS pIoStreamOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
3484 PRTVFSIOSTREAM phVfsIos, void **ppvInstance)
3485{
3486 /*
3487 * Validate the input, be extra strict in strict builds.
3488 */
3489 AssertPtr(pIoStreamOps);
3490 AssertReturn(pIoStreamOps->uVersion == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3491 AssertReturn(pIoStreamOps->uEndMarker == RTVFSIOSTREAMOPS_VERSION, VERR_VERSION_MISMATCH);
3492 Assert(!(pIoStreamOps->fFeatures & ~RTVFSIOSTREAMOPS_FEAT_VALID_MASK));
3493 RTVFSIOSTREAM_ASSERT_OPS(pIoStreamOps, RTVFSOBJTYPE_IO_STREAM);
3494 Assert(cbInstance > 0);
3495 Assert(fOpen & RTFILE_O_ACCESS_MASK);
3496 AssertPtr(ppvInstance);
3497 AssertPtr(phVfsIos);
3498 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
3499
3500 /*
3501 * Allocate the handle + instance data.
3502 */
3503 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSIOSTREAMINTERNAL), RTVFS_INST_ALIGNMENT)
3504 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
3505 RTVFSIOSTREAMINTERNAL *pThis = (RTVFSIOSTREAMINTERNAL *)RTMemAllocZ(cbThis);
3506 if (!pThis)
3507 return VERR_NO_MEMORY;
3508
3509 int rc = rtVfsObjInitNewObject(&pThis->Base, &pIoStreamOps->Obj, hVfs, false /*fNoVfsRef*/, hLock,
3510 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
3511 if (RT_FAILURE(rc))
3512 {
3513 RTMemFree(pThis);
3514 return rc;
3515 }
3516
3517 pThis->uMagic = RTVFSIOSTREAM_MAGIC;
3518 pThis->fFlags = fOpen;
3519 pThis->pOps = pIoStreamOps;
3520
3521 *phVfsIos = pThis;
3522 *ppvInstance = pThis->Base.pvThis;
3523 return VINF_SUCCESS;
3524}
3525
3526
3527RTDECL(void *) RTVfsIoStreamToPrivate(RTVFSIOSTREAM hVfsIos, PCRTVFSIOSTREAMOPS pIoStreamOps)
3528{
3529 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3530 AssertPtrReturn(pThis, NULL);
3531 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NULL);
3532 if (pThis->pOps != pIoStreamOps)
3533 return NULL;
3534 return pThis->Base.pvThis;
3535}
3536
3537
3538#ifdef DEBUG
3539# undef RTVfsIoStrmRetain
3540#endif
3541RTDECL(uint32_t) RTVfsIoStrmRetain(RTVFSIOSTREAM hVfsIos)
3542{
3543 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3544 AssertPtrReturn(pThis, UINT32_MAX);
3545 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3546 return rtVfsObjRetain(&pThis->Base);
3547}
3548#ifdef DEBUG
3549# define RTVfsIoStrmRetain(hVfsIos) RTVfsIoStrmRetainDebug(hVfsIos, RT_SRC_POS)
3550#endif
3551
3552
3553RTDECL(uint32_t) RTVfsIoStrmRetainDebug(RTVFSIOSTREAM hVfsIos, RT_SRC_POS_DECL)
3554{
3555 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3556 AssertPtrReturn(pThis, UINT32_MAX);
3557 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3558 return rtVfsObjRetainDebug(&pThis->Base, "RTVfsIoStrmRetainDebug", RT_SRC_POS_ARGS);
3559}
3560
3561
3562RTDECL(uint32_t) RTVfsIoStrmRelease(RTVFSIOSTREAM hVfsIos)
3563{
3564 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3565 if (pThis == NIL_RTVFSIOSTREAM)
3566 return 0;
3567 AssertPtrReturn(pThis, UINT32_MAX);
3568 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, UINT32_MAX);
3569 return rtVfsObjRelease(&pThis->Base);
3570}
3571
3572
3573RTDECL(RTVFSFILE) RTVfsIoStrmToFile(RTVFSIOSTREAM hVfsIos)
3574{
3575 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3576 AssertPtrReturn(pThis, NIL_RTVFSFILE);
3577 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, NIL_RTVFSFILE);
3578
3579 if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3580 {
3581 rtVfsObjRetainVoid(&pThis->Base, "RTVfsIoStrmToFile");
3582 return RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3583 }
3584
3585 /* this is no crime, so don't assert. */
3586 return NIL_RTVFSFILE;
3587}
3588
3589
3590RTDECL(int) RTVfsIoStrmQueryInfo(RTVFSIOSTREAM hVfsIos, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
3591{
3592 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3593 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3594 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3595 return RTVfsObjQueryInfo(&pThis->Base, pObjInfo, enmAddAttr);
3596}
3597
3598
3599RTDECL(int) RTVfsIoStrmRead(RTVFSIOSTREAM hVfsIos, void *pvBuf, size_t cbToRead, bool fBlocking, size_t *pcbRead)
3600{
3601 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3602 if (pcbRead)
3603 *pcbRead = 0;
3604 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3605 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3606 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3607 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3608 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3609
3610 RTSGSEG Seg = { pvBuf, cbToRead };
3611 RTSGBUF SgBuf;
3612 RTSgBufInit(&SgBuf, &Seg, 1);
3613
3614 RTVfsLockAcquireWrite(pThis->Base.hLock);
3615 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbRead);
3616 RTVfsLockReleaseWrite(pThis->Base.hLock);
3617
3618 Assert( rc != VINF_SUCCESS
3619 || RTSgBufIsAtEnd(&SgBuf)
3620 || (pcbRead && cbToRead == *pcbRead + RTSgBufCalcLengthLeft(&SgBuf)));
3621 Assert(!pcbRead || *pcbRead + RTSgBufCalcLengthLeft(&SgBuf) == cbToRead || RT_FAILURE(rc));
3622 return rc;
3623}
3624
3625
3626RTDECL(int) RTVfsIoStrmReadAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, void *pvBuf, size_t cbToRead,
3627 bool fBlocking, size_t *pcbRead)
3628{
3629 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3630 if (pcbRead)
3631 *pcbRead = 0;
3632 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3633 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3634 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3635 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3636 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3637
3638 RTSGSEG Seg = { pvBuf, cbToRead };
3639 RTSGBUF SgBuf;
3640 RTSgBufInit(&SgBuf, &Seg, 1);
3641
3642 RTVfsLockAcquireWrite(pThis->Base.hLock);
3643 int rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead);
3644 RTVfsLockReleaseWrite(pThis->Base.hLock);
3645
3646 Assert( rc != VINF_SUCCESS
3647 || RTSgBufIsAtEnd(&SgBuf)
3648 || (pcbRead && cbToRead == *pcbRead + RTSgBufCalcLengthLeft(&SgBuf)));
3649 Assert(!pcbRead || *pcbRead + RTSgBufCalcLengthLeft(&SgBuf) == cbToRead || RT_FAILURE(rc));
3650 return rc;
3651}
3652
3653
3654RTDECL(int) RTVfsIoStrmWrite(RTVFSIOSTREAM hVfsIos, const void *pvBuf, size_t cbToWrite, bool fBlocking, size_t *pcbWritten)
3655{
3656 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3657 if (pcbWritten)
3658 *pcbWritten = 0;
3659 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3660 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3661 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3662 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3663 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3664
3665 int rc;
3666 if (pThis->pOps->pfnWrite)
3667 {
3668 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3669 RTSGBUF SgBuf;
3670 RTSgBufInit(&SgBuf, &Seg, 1);
3671
3672 RTVfsLockAcquireWrite(pThis->Base.hLock);
3673 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, -1 /*off*/, &SgBuf, fBlocking, pcbWritten);
3674 RTVfsLockReleaseWrite(pThis->Base.hLock);
3675
3676 Assert(!pcbWritten || *pcbWritten + RTSgBufCalcLengthLeft(&SgBuf) == cbToWrite || RT_FAILURE(rc));
3677 }
3678 else
3679 rc = VERR_WRITE_PROTECT;
3680 return rc;
3681}
3682
3683
3684RTDECL(int) RTVfsIoStrmWriteAt(RTVFSIOSTREAM hVfsIos, RTFOFF off, const void *pvBuf, size_t cbToWrite,
3685 bool fBlocking, size_t *pcbWritten)
3686{
3687 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3688 if (pcbWritten)
3689 *pcbWritten = 0;
3690 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3691 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3692 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3693 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3694 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3695
3696 int rc;
3697 if (pThis->pOps->pfnWrite)
3698 {
3699 RTSGSEG Seg = { (void *)pvBuf, cbToWrite };
3700 RTSGBUF SgBuf;
3701 RTSgBufInit(&SgBuf, &Seg, 1);
3702
3703 RTVfsLockAcquireWrite(pThis->Base.hLock);
3704 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten);
3705 RTVfsLockReleaseWrite(pThis->Base.hLock);
3706
3707 Assert(!pcbWritten || *pcbWritten + RTSgBufCalcLengthLeft(&SgBuf) == cbToWrite || RT_FAILURE(rc));
3708 }
3709 else
3710 rc = VERR_WRITE_PROTECT;
3711 return rc;
3712}
3713
3714
3715RTDECL(int) RTVfsIoStrmSgRead(RTVFSIOSTREAM hVfsIos, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
3716{
3717 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
3718 if (pcbRead)
3719 *pcbRead = 0;
3720 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3721 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3722 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3723 AssertPtr(pSgBuf);
3724 AssertReturn(fBlocking || pcbRead, VERR_INVALID_PARAMETER);
3725 AssertReturn(pThis->fFlags & RTFILE_O_READ, VERR_ACCESS_DENIED);
3726#ifdef RT_STRICT
3727 size_t const cbToReadAssert = RTSgBufCalcLengthLeft(pSgBuf);
3728#endif
3729
3730 RTVfsLockAcquireWrite(pThis->Base.hLock);
3731 int rc;
3732 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3733 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbRead);
3734 else
3735 {
3736 size_t cbRead = 0;
3737 rc = VINF_SUCCESS;
3738
3739 while (!RTSgBufIsAtEnd(pSgBuf))
3740 {
3741 RTSGBUF SgBuf;
3742 RTSGSEG SgSeg;
3743 SgSeg.pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &SgSeg.cbSeg);
3744 RTSgBufInit(&SgBuf, &SgSeg, 1);
3745
3746 size_t cbReadSeg = pcbRead ? 0 : SgSeg.cbSeg;
3747 rc = pThis->pOps->pfnRead(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbRead ? &cbReadSeg : NULL);
3748 if (RT_FAILURE(rc))
3749 break;
3750 cbRead += cbReadSeg;
3751 RTSgBufAdvance(pSgBuf, cbReadSeg);
3752 if ((pcbRead && cbReadSeg != SgSeg.cbSeg) || rc != VINF_SUCCESS)
3753 break;
3754 if (off != -1)
3755 off += cbReadSeg;
3756 }
3757
3758 if (pcbRead)
3759 *pcbRead = cbRead;
3760 }
3761 RTVfsLockReleaseWrite(pThis->Base.hLock);
3762
3763 Assert( rc != VINF_SUCCESS
3764 || RTSgBufIsAtEnd(pSgBuf)
3765 || (pcbRead && cbToReadAssert == *pcbRead + RTSgBufCalcLengthLeft(pSgBuf)));
3766 Assert(!pcbRead || *pcbRead + RTSgBufCalcLengthLeft(pSgBuf) == cbToReadAssert || RT_FAILURE(rc));
3767 return rc;
3768}
3769
3770
3771RTDECL(int) RTVfsIoStrmSgWrite(RTVFSIOSTREAM hVfsIos, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
3772{
3773 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
3774 if (pcbWritten)
3775 *pcbWritten = 0;
3776 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3777 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3778 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3779 AssertPtr(pSgBuf);
3780 AssertReturn(fBlocking || pcbWritten, VERR_INVALID_PARAMETER);
3781 AssertReturn(pThis->fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
3782
3783 int rc;
3784 if (pThis->pOps->pfnWrite)
3785 {
3786 RTVfsLockAcquireWrite(pThis->Base.hLock);
3787 if (!(pThis->pOps->fFeatures & RTVFSIOSTREAMOPS_FEAT_NO_SG))
3788 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, pSgBuf, fBlocking, pcbWritten);
3789 else
3790 {
3791 size_t cbWritten = 0;
3792 rc = VINF_SUCCESS;
3793
3794 while (!RTSgBufIsAtEnd(pSgBuf))
3795 {
3796 RTSGBUF SgBuf;
3797 RTSGSEG SgSeg;
3798 SgSeg.pvSeg = RTSgBufGetCurrentSegment(pSgBuf, ~(size_t)0, &SgSeg.cbSeg);
3799 RTSgBufInit(&SgBuf, &SgSeg, 1);
3800
3801 size_t cbWrittenSeg = 0;
3802 rc = pThis->pOps->pfnWrite(pThis->Base.pvThis, off, &SgBuf, fBlocking, pcbWritten ? &cbWrittenSeg : NULL);
3803 if (RT_FAILURE(rc))
3804 break;
3805 if (pcbWritten)
3806 {
3807 cbWritten += cbWrittenSeg;
3808 RTSgBufAdvance(pSgBuf, cbWrittenSeg);
3809 if (cbWrittenSeg != SgSeg.cbSeg)
3810 break;
3811 if (off != -1)
3812 off += cbWrittenSeg;
3813 }
3814 else
3815 {
3816 RTSgBufAdvance(pSgBuf, SgSeg.cbSeg);
3817 if (off != -1)
3818 off += SgSeg.cbSeg;
3819 }
3820 }
3821
3822 if (pcbWritten)
3823 *pcbWritten = cbWritten;
3824 }
3825 RTVfsLockReleaseWrite(pThis->Base.hLock);
3826 }
3827 else
3828 rc = VERR_WRITE_PROTECT;
3829 return rc;
3830}
3831
3832
3833RTDECL(int) RTVfsIoStrmFlush(RTVFSIOSTREAM hVfsIos)
3834{
3835 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3836 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3837 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3838
3839 RTVfsLockAcquireWrite(pThis->Base.hLock);
3840 int rc = pThis->pOps->pfnFlush(pThis->Base.pvThis);
3841 RTVfsLockReleaseWrite(pThis->Base.hLock);
3842 return rc;
3843}
3844
3845
3846RTDECL(int) RTVfsIoStrmPoll(RTVFSIOSTREAM hVfsIos, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
3847 uint32_t *pfRetEvents)
3848{
3849 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3850 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
3851 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, VERR_INVALID_HANDLE);
3852
3853 int rc;
3854 if (pThis->pOps->pfnPollOne)
3855 {
3856 RTVfsLockAcquireWrite(pThis->Base.hLock);
3857 rc = pThis->pOps->pfnPollOne(pThis->Base.pvThis, fEvents, cMillies, fIntr, pfRetEvents);
3858 RTVfsLockReleaseWrite(pThis->Base.hLock);
3859 }
3860 /*
3861 * Default implementation. Polling for non-error events returns
3862 * immediately, waiting for errors will work like sleep.
3863 */
3864 else if (fEvents != RTPOLL_EVT_ERROR)
3865 {
3866 *pfRetEvents = fEvents & ~RTPOLL_EVT_ERROR;
3867 rc = VINF_SUCCESS;
3868 }
3869 else if (fIntr)
3870 rc = RTThreadSleep(cMillies);
3871 else
3872 {
3873 uint64_t uMsStart = RTTimeMilliTS();
3874 do
3875 rc = RTThreadSleep(cMillies);
3876 while ( rc == VERR_INTERRUPTED
3877 && RTTimeMilliTS() - uMsStart < cMillies);
3878 if (rc == VERR_INTERRUPTED)
3879 rc = VERR_TIMEOUT;
3880 }
3881 return rc;
3882}
3883
3884
3885RTDECL(RTFOFF) RTVfsIoStrmTell(RTVFSIOSTREAM hVfsIos)
3886{
3887 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3888 AssertPtrReturn(pThis, -1);
3889 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3890
3891 RTFOFF off;
3892 RTVfsLockAcquireRead(pThis->Base.hLock);
3893 int rc = pThis->pOps->pfnTell(pThis->Base.pvThis, &off);
3894 RTVfsLockReleaseRead(pThis->Base.hLock);
3895 if (RT_FAILURE(rc))
3896 off = rc;
3897 return off;
3898}
3899
3900
3901RTDECL(int) RTVfsIoStrmSkip(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3902{
3903 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3904 AssertPtrReturn(pThis, -1);
3905 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3906 AssertReturn(cb >= 0, VERR_INVALID_PARAMETER);
3907
3908 int rc;
3909 if (pThis->pOps->pfnSkip)
3910 {
3911 RTVfsLockAcquireWrite(pThis->Base.hLock);
3912 rc = pThis->pOps->pfnSkip(pThis->Base.pvThis, cb);
3913 RTVfsLockReleaseWrite(pThis->Base.hLock);
3914 }
3915 else if (pThis->pOps->Obj.enmType == RTVFSOBJTYPE_FILE)
3916 {
3917 RTVFSFILEINTERNAL *pThisFile = RT_FROM_MEMBER(pThis, RTVFSFILEINTERNAL, Stream);
3918 RTFOFF offIgnored;
3919
3920 RTVfsLockAcquireWrite(pThis->Base.hLock);
3921 rc = pThisFile->pOps->pfnSeek(pThis->Base.pvThis, cb, RTFILE_SEEK_CURRENT, &offIgnored);
3922 RTVfsLockReleaseWrite(pThis->Base.hLock);
3923 }
3924 else
3925 {
3926 void *pvBuf = RTMemTmpAlloc(_64K);
3927 if (pvBuf)
3928 {
3929 rc = VINF_SUCCESS;
3930 while (cb > 0)
3931 {
3932 size_t cbToRead = (size_t)RT_MIN(cb, _64K);
3933 RTVfsLockAcquireWrite(pThis->Base.hLock);
3934 rc = RTVfsIoStrmRead(hVfsIos, pvBuf, cbToRead, true /*fBlocking*/, NULL);
3935 RTVfsLockReleaseWrite(pThis->Base.hLock);
3936 if (RT_FAILURE(rc))
3937 break;
3938 cb -= cbToRead;
3939 }
3940
3941 RTMemTmpFree(pvBuf);
3942 }
3943 else
3944 rc = VERR_NO_TMP_MEMORY;
3945 }
3946 return rc;
3947}
3948
3949
3950RTDECL(int) RTVfsIoStrmZeroFill(RTVFSIOSTREAM hVfsIos, RTFOFF cb)
3951{
3952 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3953 AssertPtrReturn(pThis, -1);
3954 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, -1);
3955
3956 int rc;
3957 if (pThis->pOps->pfnZeroFill)
3958 {
3959 RTVfsLockAcquireWrite(pThis->Base.hLock);
3960 rc = pThis->pOps->pfnZeroFill(pThis->Base.pvThis, cb);
3961 RTVfsLockReleaseWrite(pThis->Base.hLock);
3962 }
3963 else
3964 {
3965 rc = VINF_SUCCESS;
3966 while (cb > 0)
3967 {
3968 size_t cbToWrite = (size_t)RT_MIN(cb, (ssize_t)sizeof(g_abRTZero64K));
3969 RTVfsLockAcquireWrite(pThis->Base.hLock);
3970 rc = RTVfsIoStrmWrite(hVfsIos, g_abRTZero64K, cbToWrite, true /*fBlocking*/, NULL);
3971 RTVfsLockReleaseWrite(pThis->Base.hLock);
3972 if (RT_FAILURE(rc))
3973 break;
3974 cb -= cbToWrite;
3975 }
3976 }
3977 return rc;
3978}
3979
3980
3981RTDECL(bool) RTVfsIoStrmIsAtEnd(RTVFSIOSTREAM hVfsIos)
3982{
3983 /*
3984 * There is where the zero read behavior comes in handy.
3985 */
3986 char bDummy;
3987 size_t cbRead;
3988 int rc = RTVfsIoStrmRead(hVfsIos, &bDummy, 0 /*cbToRead*/, false /*fBlocking*/, &cbRead);
3989 return rc == VINF_EOF;
3990}
3991
3992
3993
3994RTDECL(uint64_t) RTVfsIoStrmGetOpenFlags(RTVFSIOSTREAM hVfsIos)
3995{
3996 RTVFSIOSTREAMINTERNAL *pThis = hVfsIos;
3997 AssertPtrReturn(pThis, 0);
3998 AssertReturn(pThis->uMagic == RTVFSIOSTREAM_MAGIC, 0);
3999 return pThis->fFlags;
4000}
4001
4002
4003
4004/*
4005 *
4006 * F I L E F I L E F I L E
4007 * F I L E F I L E F I L E
4008 * F I L E F I L E F I L E
4009 *
4010 */
4011
4012RTDECL(int) RTVfsNewFile(PCRTVFSFILEOPS pFileOps, size_t cbInstance, uint32_t fOpen, RTVFS hVfs, RTVFSLOCK hLock,
4013 PRTVFSFILE phVfsFile, void **ppvInstance)
4014{
4015 /*
4016 * Validate the input, be extra strict in strict builds.
4017 */
4018 RTVFSFILE_ASSERT_OPS(pFileOps, RTVFSOBJTYPE_FILE);
4019 Assert(cbInstance > 0);
4020 Assert(fOpen & (RTFILE_O_ACCESS_MASK | RTFILE_O_ACCESS_ATTR_MASK));
4021 AssertPtr(ppvInstance);
4022 AssertPtr(phVfsFile);
4023 RTVFS_ASSERT_VALID_HANDLE_OR_NIL_RETURN(hVfs, VERR_INVALID_HANDLE);
4024
4025 /*
4026 * Allocate the handle + instance data.
4027 */
4028 size_t const cbThis = RT_ALIGN_Z(sizeof(RTVFSFILEINTERNAL), RTVFS_INST_ALIGNMENT)
4029 + RT_ALIGN_Z(cbInstance, RTVFS_INST_ALIGNMENT);
4030 RTVFSFILEINTERNAL *pThis = (RTVFSFILEINTERNAL *)RTMemAllocZ(cbThis);
4031 if (!pThis)
4032 return VERR_NO_MEMORY;
4033
4034 int rc = rtVfsObjInitNewObject(&pThis->Stream.Base, &pFileOps->Stream.Obj, hVfs, false /*fNoVfsRef*/, hLock,
4035 (char *)pThis + RT_ALIGN_Z(sizeof(*pThis), RTVFS_INST_ALIGNMENT));
4036 if (RT_FAILURE(rc))
4037 {
4038 RTMemFree(pThis);
4039 return rc;
4040 }
4041
4042 pThis->uMagic = RTVFSFILE_MAGIC;
4043 pThis->fReserved = 0;
4044 pThis->pOps = pFileOps;
4045 pThis->Stream.uMagic = RTVFSIOSTREAM_MAGIC;
4046 pThis->Stream.fFlags = fOpen;
4047 pThis->Stream.pOps = &pFileOps->Stream;
4048
4049 *phVfsFile = pThis;
4050 *ppvInstance = pThis->Stream.Base.pvThis;
4051 return VINF_SUCCESS;
4052}
4053
4054
4055RTDECL(int) RTVfsFileOpen(RTVFS hVfs, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
4056{
4057 /*
4058 * Validate input.
4059 */
4060 RTVFSINTERNAL *pThis = hVfs;
4061 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4062 AssertReturn(pThis->uMagic == RTVFS_MAGIC, VERR_INVALID_HANDLE);
4063 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
4064 AssertPtrReturn(phVfsFile, VERR_INVALID_POINTER);
4065
4066 int rc = rtFileRecalcAndValidateFlags(&fOpen);
4067 if (RT_FAILURE(rc))
4068 return rc;
4069
4070 /*
4071 * Parse the path, assume current directory is root since we've got no
4072 * caller context here.
4073 */
4074 PRTVFSPARSEDPATH pPath;
4075 rc = RTVfsParsePathA(pszFilename, "/", &pPath);
4076 if (RT_SUCCESS(rc))
4077 {
4078 /*
4079 * Tranverse the path, resolving the parent node.
4080 * We'll do the symbolic link checking here with help of pfnOpen/pfnOpenFile.
4081 */
4082 RTVFSDIRINTERNAL *pVfsParentDir;
4083 uint32_t const fTraverse = (fOpen & RTFILE_O_NO_SYMLINKS ? RTPATH_F_NO_SYMLINKS : 0) | RTPATH_F_ON_LINK;
4084 rc = rtVfsTraverseToParent(pThis, pPath, fTraverse, &pVfsParentDir);
4085 if (RT_SUCCESS(rc))
4086 {
4087 /** @todo join path with RTVfsDirOpenFile. */
4088 /*
4089 * Do the opening. Loop if we need to follow symbolic links.
4090 */
4091 bool fDirSlash = pPath->fDirSlash;
4092
4093 uint32_t fObjFlags = RTVFSOBJ_F_OPEN_ANY_FILE | RTVFSOBJ_F_OPEN_SYMLINK;
4094 if ( (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
4095 || (fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
4096 fObjFlags |= RTVFSOBJ_F_CREATE_FILE;
4097 else
4098 fObjFlags |= RTVFSOBJ_F_CREATE_NOTHING;
4099 fObjFlags |= fTraverse & RTPATH_F_MASK;
4100
4101 for (uint32_t cLoops = 1;; cLoops++)
4102 {
4103 /* Do the querying. If pfnOpenFile is available, we use it first, falling
4104 back on pfnOpen in case of symbolic links that needs following or we got
4105 a trailing directory slash (to get file-not-found error). */
4106 const char *pszEntryName = &pPath->szPath[pPath->aoffComponents[pPath->cComponents - 1]];
4107 if ( pVfsParentDir->pOps->pfnOpenFile
4108 && !fDirSlash)
4109 {
4110 RTVfsLockAcquireRead(pVfsParentDir->Base.hLock);
4111 rc = pVfsParentDir->pOps->pfnOpenFile(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, phVfsFile);
4112 RTVfsLockReleaseRead(pVfsParentDir->Base.hLock);
4113 if ( RT_SUCCESS(rc)
4114 || ( rc != VERR_NOT_A_FILE
4115 && rc != VERR_IS_A_SYMLINK))
4116 break;
4117 }
4118
4119 RTVFSOBJ hVfsObj;
4120 RTVfsLockAcquireWrite(pVfsParentDir->Base.hLock);
4121 rc = pVfsParentDir->pOps->pfnOpen(pVfsParentDir->Base.pvThis, pszEntryName, fOpen, fObjFlags, &hVfsObj);
4122 RTVfsLockReleaseWrite(pVfsParentDir->Base.hLock);
4123 if (RT_FAILURE(rc))
4124 break;
4125
4126 /* If we don't follow links or this wasn't a link we just have to do the query and we're done. */
4127 if ( !(fObjFlags & RTPATH_F_FOLLOW_LINK)
4128 || RTVfsObjGetType(hVfsObj) != RTVFSOBJTYPE_SYMLINK)
4129 {
4130 *phVfsFile = RTVfsObjToFile(hVfsObj);
4131 AssertStmt(*phVfsFile != NIL_RTVFSFILE, rc = VERR_INTERNAL_ERROR_3);
4132 RTVfsObjRelease(hVfsObj);
4133 break;
4134 }
4135
4136 /* Follow symbolic link. */
4137 if (cLoops < RTVFS_MAX_LINKS)
4138 rc = rtVfsDirFollowSymlinkObjToParent(&pVfsParentDir, hVfsObj, pPath, fTraverse);
4139 else
4140 rc = VERR_TOO_MANY_SYMLINKS;
4141 RTVfsObjRelease(hVfsObj);
4142 if (RT_FAILURE(rc))
4143 break;
4144 fDirSlash |= pPath->fDirSlash;
4145 }
4146 RTVfsDirRelease(pVfsParentDir);
4147 }
4148 RTVfsParsePathFree(pPath);
4149 }
4150 return rc;
4151
4152}
4153
4154
4155#ifdef DEBUG
4156# undef RTVfsFileRetain
4157#endif
4158RTDECL(uint32_t) RTVfsFileRetain(RTVFSFILE hVfsFile)
4159{
4160 RTVFSFILEINTERNAL *pThis = hVfsFile;
4161 AssertPtrReturn(pThis, UINT32_MAX);
4162 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
4163 return rtVfsObjRetain(&pThis->Stream.Base);
4164}
4165#ifdef DEBUG
4166# define RTVfsFileRetain(hVfsFile) RTVfsFileRetainDebug(hVfsFile, RT_SRC_POS)
4167#endif
4168
4169
4170RTDECL(uint32_t) RTVfsFileRetainDebug(RTVFSFILE hVfsFile, RT_SRC_POS_DECL)
4171{
4172 RTVFSFILEINTERNAL *pThis = hVfsFile;
4173 AssertPtrReturn(pThis, UINT32_MAX);
4174 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
4175 return rtVfsObjRetainDebug(&pThis->Stream.Base, "RTVFsFileRetainDebug", RT_SRC_POS_ARGS);
4176}
4177
4178
4179RTDECL(uint32_t) RTVfsFileRelease(RTVFSFILE hVfsFile)
4180{
4181 RTVFSFILEINTERNAL *pThis = hVfsFile;
4182 if (pThis == NIL_RTVFSFILE)
4183 return 0;
4184 AssertPtrReturn(pThis, UINT32_MAX);
4185 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, UINT32_MAX);
4186 return rtVfsObjRelease(&pThis->Stream.Base);
4187}
4188
4189
4190RTDECL(RTVFSIOSTREAM) RTVfsFileToIoStream(RTVFSFILE hVfsFile)
4191{
4192 RTVFSFILEINTERNAL *pThis = hVfsFile;
4193 AssertPtrReturn(pThis, NIL_RTVFSIOSTREAM);
4194 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, NIL_RTVFSIOSTREAM);
4195
4196 rtVfsObjRetainVoid(&pThis->Stream.Base, "RTVfsFileToIoStream");
4197 return &pThis->Stream;
4198}
4199
4200
4201RTDECL(int) RTVfsFileQueryInfo(RTVFSFILE hVfsFile, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
4202{
4203 RTVFSFILEINTERNAL *pThis = hVfsFile;
4204 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4205 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4206 return RTVfsObjQueryInfo(&pThis->Stream.Base, pObjInfo, enmAddAttr);
4207}
4208
4209
4210RTDECL(int) RTVfsFileRead(RTVFSFILE hVfsFile, void *pvBuf, size_t cbToRead, size_t *pcbRead)
4211{
4212 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
4213 if (pcbRead)
4214 *pcbRead = 0;
4215 RTVFSFILEINTERNAL *pThis = hVfsFile;
4216 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4217 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4218 return RTVfsIoStrmRead(&pThis->Stream, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
4219}
4220
4221
4222RTDECL(int) RTVfsFileWrite(RTVFSFILE hVfsFile, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
4223{
4224 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
4225 if (pcbWritten)
4226 *pcbWritten = 0;
4227 RTVFSFILEINTERNAL *pThis = hVfsFile;
4228 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4229 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4230 return RTVfsIoStrmWrite(&pThis->Stream, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
4231}
4232
4233
4234RTDECL(int) RTVfsFileWriteAt(RTVFSFILE hVfsFile, RTFOFF off, const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)
4235{
4236 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
4237 if (pcbWritten)
4238 *pcbWritten = 0;
4239 RTVFSFILEINTERNAL *pThis = hVfsFile;
4240 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4241 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4242
4243 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
4244 if (RT_SUCCESS(rc))
4245 rc = RTVfsIoStrmWriteAt(&pThis->Stream, off, pvBuf, cbToWrite, true /*fBlocking*/, pcbWritten);
4246
4247 return rc;
4248}
4249
4250
4251RTDECL(int) RTVfsFileReadAt(RTVFSFILE hVfsFile, RTFOFF off, void *pvBuf, size_t cbToRead, size_t *pcbRead)
4252{
4253 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
4254 if (pcbRead)
4255 *pcbRead = 0;
4256 RTVFSFILEINTERNAL *pThis = hVfsFile;
4257 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4258 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4259
4260 int rc = RTVfsFileSeek(hVfsFile, off, RTFILE_SEEK_BEGIN, NULL);
4261 if (RT_SUCCESS(rc))
4262 rc = RTVfsIoStrmReadAt(&pThis->Stream, off, pvBuf, cbToRead, true /*fBlocking*/, pcbRead);
4263
4264 return rc;
4265}
4266
4267
4268RTDECL(int) RTVfsFileSgRead(RTVFSFILE hVfsFile, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbRead)
4269{
4270 AssertPtrNullReturn(pcbRead, VERR_INVALID_POINTER);
4271 if (pcbRead)
4272 *pcbRead = 0;
4273 RTVFSFILEINTERNAL *pThis = hVfsFile;
4274 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4275 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4276
4277 return RTVfsIoStrmSgRead(&pThis->Stream, off, pSgBuf, fBlocking, pcbRead);
4278}
4279
4280
4281RTDECL(int) RTVfsFileSgWrite(RTVFSFILE hVfsFile, RTFOFF off, PRTSGBUF pSgBuf, bool fBlocking, size_t *pcbWritten)
4282{
4283 AssertPtrNullReturn(pcbWritten, VERR_INVALID_POINTER);
4284 if (pcbWritten)
4285 *pcbWritten = 0;
4286 RTVFSFILEINTERNAL *pThis = hVfsFile;
4287 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4288 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4289
4290 return RTVfsIoStrmSgWrite(&pThis->Stream, off, pSgBuf, fBlocking, pcbWritten);
4291}
4292
4293
4294RTDECL(int) RTVfsFileFlush(RTVFSFILE hVfsFile)
4295{
4296 RTVFSFILEINTERNAL *pThis = hVfsFile;
4297 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4298 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4299 return RTVfsIoStrmFlush(&pThis->Stream);
4300}
4301
4302
4303RTDECL(RTFOFF) RTVfsFilePoll(RTVFSFILE hVfsFile, uint32_t fEvents, RTMSINTERVAL cMillies, bool fIntr,
4304 uint32_t *pfRetEvents)
4305{
4306 RTVFSFILEINTERNAL *pThis = hVfsFile;
4307 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4308 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4309 return RTVfsIoStrmPoll(&pThis->Stream, fEvents, cMillies, fIntr, pfRetEvents);
4310}
4311
4312
4313RTDECL(RTFOFF) RTVfsFileTell(RTVFSFILE hVfsFile)
4314{
4315 RTVFSFILEINTERNAL *pThis = hVfsFile;
4316 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4317 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4318 return RTVfsIoStrmTell(&pThis->Stream);
4319}
4320
4321
4322RTDECL(int) RTVfsFileSeek(RTVFSFILE hVfsFile, RTFOFF offSeek, uint32_t uMethod, uint64_t *poffActual)
4323{
4324 RTVFSFILEINTERNAL *pThis = hVfsFile;
4325 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4326 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4327
4328 AssertReturn( uMethod == RTFILE_SEEK_BEGIN
4329 || uMethod == RTFILE_SEEK_CURRENT
4330 || uMethod == RTFILE_SEEK_END, VERR_INVALID_PARAMETER);
4331 AssertPtrNullReturn(poffActual, VERR_INVALID_POINTER);
4332
4333 RTFOFF offActual = 0;
4334 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4335 int rc = pThis->pOps->pfnSeek(pThis->Stream.Base.pvThis, offSeek, uMethod, &offActual);
4336 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4337 if (RT_SUCCESS(rc) && poffActual)
4338 {
4339 Assert(offActual >= 0);
4340 *poffActual = offActual;
4341 }
4342
4343 return rc;
4344}
4345
4346
4347RTDECL(int) RTVfsFileQuerySize(RTVFSFILE hVfsFile, uint64_t *pcbSize)
4348{
4349 RTVFSFILEINTERNAL *pThis = hVfsFile;
4350 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4351 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4352 AssertPtrReturn(pcbSize, VERR_INVALID_POINTER);
4353
4354 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4355 int rc = pThis->pOps->pfnQuerySize(pThis->Stream.Base.pvThis, pcbSize);
4356 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4357
4358 return rc;
4359}
4360
4361
4362RTDECL(int) RTVfsFileSetSize(RTVFSFILE hVfsFile, uint64_t cbSize, uint32_t fFlags)
4363{
4364 RTVFSFILEINTERNAL *pThis = hVfsFile;
4365 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4366 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4367 AssertReturn(RTVFSFILE_SIZE_F_IS_VALID(fFlags), VERR_INVALID_FLAGS);
4368 AssertReturn(pThis->Stream.fFlags & RTFILE_O_WRITE, VERR_ACCESS_DENIED);
4369
4370 int rc;
4371 if (pThis->pOps->pfnSetSize)
4372 {
4373 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4374 rc = pThis->pOps->pfnSetSize(pThis->Stream.Base.pvThis, cbSize, fFlags);
4375 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4376 }
4377 else
4378 rc = VERR_WRITE_PROTECT;
4379 return rc;
4380}
4381
4382
4383RTDECL(RTFOFF) RTVfsFileGetMaxSize(RTVFSFILE hVfsFile)
4384{
4385 uint64_t cbMax;
4386 int rc = RTVfsFileQueryMaxSize(hVfsFile, &cbMax);
4387 return RT_SUCCESS(rc) ? (RTFOFF)RT_MIN(cbMax, (uint64_t)RTFOFF_MAX) : -1;
4388}
4389
4390
4391RTDECL(int) RTVfsFileQueryMaxSize(RTVFSFILE hVfsFile, uint64_t *pcbMax)
4392{
4393 RTVFSFILEINTERNAL *pThis = hVfsFile;
4394 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
4395 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, VERR_INVALID_HANDLE);
4396 AssertPtrReturn(pcbMax, VERR_INVALID_POINTER);
4397 *pcbMax = RTFOFF_MAX;
4398
4399 int rc;
4400 if (pThis->pOps->pfnQueryMaxSize)
4401 {
4402 RTVfsLockAcquireWrite(pThis->Stream.Base.hLock);
4403 rc = pThis->pOps->pfnQueryMaxSize(pThis->Stream.Base.pvThis, pcbMax);
4404 RTVfsLockReleaseWrite(pThis->Stream.Base.hLock);
4405 }
4406 else
4407 rc = VERR_WRITE_PROTECT;
4408 return rc;
4409}
4410
4411
4412RTDECL(uint64_t) RTVfsFileGetOpenFlags(RTVFSFILE hVfsFile)
4413{
4414 RTVFSFILEINTERNAL *pThis = hVfsFile;
4415 AssertPtrReturn(pThis, 0);
4416 AssertReturn(pThis->uMagic == RTVFSFILE_MAGIC, 0);
4417 return pThis->Stream.fFlags;
4418}
4419
Note: See TracBrowser for help on using the repository browser.

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