VirtualBox

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

Last change on this file since 82866 was 80585, checked in by vboxsync, 5 years ago

Runtime: Some renaming to stay consistent (*Get* always returns what is asked for while *Query* returns a status code and where to store the value on success is given as a pointer)

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