VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/vfs/vfsstddir.cpp@ 80346

Last change on this file since 80346 was 77047, checked in by vboxsync, 6 years ago

iprt/isomaker: Optimized native handle (file descriptor) usage when adding real directories.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.4 KB
Line 
1/* $Id: vfsstddir.cpp 77047 2019-01-30 15:38:53Z vboxsync $ */
2/** @file
3 * IPRT - Virtual File System, Standard Directory Implementation.
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_VFS
32#include <iprt/vfs.h>
33#include <iprt/vfslowlevel.h>
34
35#include <iprt/assert.h>
36#include <iprt/dir.h>
37#include <iprt/err.h>
38#include <iprt/file.h>
39#include <iprt/log.h>
40#include <iprt/path.h>
41#include <iprt/string.h>
42
43#define RTDIR_AGNOSTIC
44#include "internal/dir.h"
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50/**
51 * Private data of a standard directory.
52 */
53typedef struct RTVFSSTDDIR
54{
55 /** The directory handle. */
56 RTDIR hDir;
57 /** Whether to leave the handle open when the VFS handle is closed. */
58 bool fLeaveOpen;
59 /** Open flags, RTDIR_F_XXX. */
60 uint32_t fFlags;
61 /** Handle to the director so we can make sure it sticks around for symbolic
62 * link objects. */
63 RTVFSDIR hSelf;
64} RTVFSSTDDIR;
65/** Pointer to the private data of a standard directory. */
66typedef RTVFSSTDDIR *PRTVFSSTDDIR;
67
68
69/**
70 * Private data of a standard symbolic link.
71 */
72typedef struct RTVFSSTDSYMLINK
73{
74 /** Pointer to the VFS directory where the symbolic link lives . */
75 PRTVFSSTDDIR pDir;
76 /** The symbolic link name. */
77 char szSymlink[RT_FLEXIBLE_ARRAY];
78} RTVFSSTDSYMLINK;
79/** Pointer to the private data of a standard symbolic link. */
80typedef RTVFSSTDSYMLINK *PRTVFSSTDSYMLINK;
81
82
83/*********************************************************************************************************************************
84* Internal Functions *
85*********************************************************************************************************************************/
86static DECLCALLBACK(int) rtVfsStdDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir);
87static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink);
88static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
89 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr);
90static int rtVfsDirFromRTDir(RTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir);
91
92
93
94/**
95 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
96 */
97static DECLCALLBACK(int) rtVfsStdSym_Close(void *pvThis)
98{
99 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
100 RTVfsDirRelease(pThis->pDir->hSelf);
101 pThis->pDir = NULL;
102 return VINF_SUCCESS;
103}
104
105
106/**
107 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
108 */
109static DECLCALLBACK(int) rtVfsStdSym_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
110{
111 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
112 return rtVfsStdDir_QueryEntryInfo(pThis->pDir, pThis->szSymlink, pObjInfo, enmAddAttr);
113}
114
115/**
116 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
117 */
118static DECLCALLBACK(int) rtVfsStdSym_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
119{
120 NOREF(pvThis); NOREF(fMode); NOREF(fMask);
121 return VERR_ACCESS_DENIED;
122}
123
124
125/**
126 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
127 */
128static DECLCALLBACK(int) rtVfsStdSym_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
129 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
130{
131 NOREF(pvThis); NOREF(pAccessTime); NOREF(pModificationTime); NOREF(pChangeTime); NOREF(pBirthTime);
132 return VERR_ACCESS_DENIED;
133}
134
135
136/**
137 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
138 */
139static DECLCALLBACK(int) rtVfsStdSym_SetOwner(void *pvThis, RTUID uid, RTGID gid)
140{
141 NOREF(pvThis); NOREF(uid); NOREF(gid);
142 return VERR_ACCESS_DENIED;
143}
144
145
146/**
147 * @interface_method_impl{RTVFSSYMLINKOPS,pfnRead}
148 */
149static DECLCALLBACK(int) rtVfsStdSym_Read(void *pvThis, char *pszTarget, size_t cbTarget)
150{
151 PRTVFSSTDSYMLINK pThis = (PRTVFSSTDSYMLINK)pvThis;
152 return RTDirRelSymlinkRead(pThis->pDir->hDir, pThis->szSymlink, pszTarget, cbTarget, 0 /*fRead*/);
153}
154
155
156/**
157 * Symbolic operations for standard directory.
158 */
159static const RTVFSSYMLINKOPS g_rtVfsStdSymOps =
160{
161 { /* Obj */
162 RTVFSOBJOPS_VERSION,
163 RTVFSOBJTYPE_SYMLINK,
164 "StdSymlink",
165 rtVfsStdSym_Close,
166 rtVfsStdSym_QueryInfo,
167 RTVFSOBJOPS_VERSION
168 },
169 RTVFSSYMLINKOPS_VERSION,
170 0,
171 { /* ObjSet */
172 RTVFSOBJSETOPS_VERSION,
173 RT_UOFFSETOF(RTVFSSYMLINKOPS, ObjSet) - RT_UOFFSETOF(RTVFSSYMLINKOPS, Obj),
174 rtVfsStdSym_SetMode,
175 rtVfsStdSym_SetTimes,
176 rtVfsStdSym_SetOwner,
177 RTVFSOBJSETOPS_VERSION
178 },
179 rtVfsStdSym_Read,
180 RTVFSSYMLINKOPS_VERSION
181};
182
183
184/**
185 * @interface_method_impl{RTVFSOBJOPS,pfnClose}
186 */
187static DECLCALLBACK(int) rtVfsStdDir_Close(void *pvThis)
188{
189 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
190
191 int rc;
192 if (!pThis->fLeaveOpen)
193 rc = RTDirClose(pThis->hDir);
194 else
195 rc = VINF_SUCCESS;
196 pThis->hDir = NULL;
197
198 return rc;
199}
200
201
202/**
203 * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
204 */
205static DECLCALLBACK(int) rtVfsStdDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
206{
207 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
208 return RTDirQueryInfo(pThis->hDir, pObjInfo, enmAddAttr);
209}
210
211
212/**
213 * @interface_method_impl{RTVFSOBJSETOPS,pfnMode}
214 */
215static DECLCALLBACK(int) rtVfsStdDir_SetMode(void *pvThis, RTFMODE fMode, RTFMODE fMask)
216{
217 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
218 if (fMask != ~RTFS_TYPE_MASK)
219 {
220 RTFSOBJINFO ObjInfo;
221 int rc = RTDirQueryInfo(pThis->hDir, &ObjInfo, RTFSOBJATTRADD_NOTHING);
222 if (RT_FAILURE(rc))
223 return rc;
224 fMode |= ~fMask & ObjInfo.Attr.fMode;
225 }
226 //RTPathSetMode
227 //return RTFileSetMode(pThis->hDir, fMode);
228 return VERR_NOT_IMPLEMENTED;
229}
230
231
232/**
233 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetTimes}
234 */
235static DECLCALLBACK(int) rtVfsStdDir_SetTimes(void *pvThis, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
236 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
237{
238 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
239 return RTDirSetTimes(pThis->hDir, pAccessTime, pModificationTime, pChangeTime, pBirthTime);
240}
241
242
243/**
244 * @interface_method_impl{RTVFSOBJSETOPS,pfnSetOwner}
245 */
246static DECLCALLBACK(int) rtVfsStdDir_SetOwner(void *pvThis, RTUID uid, RTGID gid)
247{
248 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
249 return RTDirRelPathSetOwner(pThis->hDir, ".", uid, gid, RTPATH_F_FOLLOW_LINK);
250}
251
252
253/**
254 * @interface_method_impl{RTVFSDIROPS,pfnOpen}
255 */
256static DECLCALLBACK(int) rtVfsStdDir_Open(void *pvThis, const char *pszEntry, uint64_t fFileOpen,
257 uint32_t fObjFlags, PRTVFSOBJ phVfsObj)
258{
259 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
260
261 /*
262 * This is subject to race conditions, but we haven't too much of a choice
263 * without going platform specific here (we'll do that eventually).
264 */
265 RTFSOBJINFO ObjInfo;
266 int rc = RTDirRelPathQueryInfo(pThis->hDir, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
267 if (RT_SUCCESS(rc))
268 {
269 switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
270 {
271 case RTFS_TYPE_DIRECTORY:
272 if (fObjFlags & RTVFSOBJ_F_OPEN_DIRECTORY)
273 {
274 if ( (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
275 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
276 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
277 {
278 RTDIR hSubDir;
279 rc = RTDirRelDirOpenFiltered(pThis->hDir, pszEntry, RTDIRFILTER_NONE, 0 /*fFlags*/, &hSubDir);
280 if (RT_SUCCESS(rc))
281 {
282 RTVFSDIR hVfsDir;
283 rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
284 if (RT_SUCCESS(rc))
285 {
286 *phVfsObj = RTVfsObjFromDir(hVfsDir);
287 RTVfsDirRelease(hVfsDir);
288 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
289 }
290 else
291 RTDirClose(hSubDir);
292 }
293 }
294 else
295 rc = VERR_ALREADY_EXISTS;
296 }
297 else
298 rc = VERR_IS_A_DIRECTORY;
299 break;
300
301 case RTFS_TYPE_FILE:
302 case RTFS_TYPE_DEV_BLOCK:
303 case RTFS_TYPE_DEV_CHAR:
304 case RTFS_TYPE_FIFO:
305 case RTFS_TYPE_SOCKET:
306 switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
307 {
308 case RTFS_TYPE_FILE:
309 rc = fObjFlags & RTVFSOBJ_F_OPEN_FILE ? VINF_SUCCESS : VERR_IS_A_FILE;
310 break;
311 case RTFS_TYPE_DEV_BLOCK:
312 rc = fObjFlags & RTVFSOBJ_F_OPEN_DEV_BLOCK ? VINF_SUCCESS : VERR_IS_A_BLOCK_DEVICE;
313 break;
314 case RTFS_TYPE_DEV_CHAR:
315 rc = fObjFlags & RTVFSOBJ_F_OPEN_DEV_CHAR ? VINF_SUCCESS : VERR_IS_A_CHAR_DEVICE;
316 break;
317 /** @todo These two types should not result in files, but pure I/O streams.
318 * possibly char device too. */
319 case RTFS_TYPE_FIFO:
320 rc = fObjFlags & RTVFSOBJ_F_OPEN_FIFO ? VINF_SUCCESS : VERR_IS_A_FIFO;
321 break;
322 case RTFS_TYPE_SOCKET:
323 rc = fObjFlags & RTVFSOBJ_F_OPEN_SOCKET ? VINF_SUCCESS : VERR_IS_A_SOCKET;
324 break;
325 default:
326 rc = VERR_INVALID_FLAGS;
327 break;
328 }
329 if (RT_SUCCESS(rc))
330 {
331 if ( (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN
332 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
333 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
334 {
335 RTFILE hFile;
336 rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fFileOpen, &hFile);
337 if (RT_SUCCESS(rc))
338 {
339 RTVFSFILE hVfsFile;
340 rc = RTVfsFileFromRTFile(hFile, fFileOpen, false /*fLeaveOpen*/, &hVfsFile);
341 if (RT_SUCCESS(rc))
342 {
343 *phVfsObj = RTVfsObjFromFile(hVfsFile);
344 RTVfsFileRelease(hVfsFile);
345 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
346 }
347 else
348 RTFileClose(hFile);
349 }
350 }
351 else
352 rc = VERR_ALREADY_EXISTS;
353 }
354 break;
355
356 case RTFS_TYPE_SYMLINK:
357 if (fObjFlags & RTVFSOBJ_F_OPEN_SYMLINK)
358 {
359 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
360 if (cRefs != UINT32_MAX)
361 {
362 RTVFSSYMLINK hVfsSymlink;
363 PRTVFSSTDSYMLINK pNewSymlink;
364 size_t cchSymlink = strlen(pszEntry);
365 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF_DYN(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
366 NIL_RTVFS, NIL_RTVFSLOCK, &hVfsSymlink, (void **)&pNewSymlink);
367 if (RT_SUCCESS(rc))
368 {
369 memcpy(pNewSymlink->szSymlink, pszEntry, cchSymlink);
370 pNewSymlink->szSymlink[cchSymlink] = '\0';
371 pNewSymlink->pDir = pThis;
372
373 *phVfsObj = RTVfsObjFromSymlink(hVfsSymlink);
374 RTVfsSymlinkRelease(hVfsSymlink);
375 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
376 }
377 else
378 RTVfsDirRelease(pThis->hSelf);
379 }
380 else
381 rc = VERR_INTERNAL_ERROR_2;
382 }
383 else
384 rc = VERR_IS_A_SYMLINK;
385 break;
386
387 default:
388 break;
389 }
390 }
391 else if ( rc == VERR_FILE_NOT_FOUND
392 || rc == VERR_PATH_NOT_FOUND)
393 {
394 /*
395 * Consider file or directory creation.
396 */
397 if ( ( (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE
398 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_OPEN_CREATE
399 || (fFileOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE_REPLACE)
400 && (fObjFlags & RTVFSOBJ_F_CREATE_MASK) != RTVFSOBJ_F_CREATE_NOTHING)
401 {
402
403 if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_FILE)
404 {
405 RTFILE hFile;
406 rc = RTDirRelFileOpen(pThis->hDir, pszEntry, fFileOpen, &hFile);
407 if (RT_SUCCESS(rc))
408 {
409 RTVFSFILE hVfsFile;
410 rc = RTVfsFileFromRTFile(hFile, fFileOpen, false /*fLeaveOpen*/, &hVfsFile);
411 if (RT_SUCCESS(rc))
412 {
413 *phVfsObj = RTVfsObjFromFile(hVfsFile);
414 RTVfsFileRelease(hVfsFile);
415 AssertStmt(*phVfsObj != NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
416 }
417 else
418 RTFileClose(hFile);
419 }
420 }
421 else if ((fObjFlags & RTVFSOBJ_F_CREATE_MASK) == RTVFSOBJ_F_CREATE_DIRECTORY)
422 {
423 RTDIR hSubDir;
424 rc = RTDirRelDirCreate(pThis->hDir, pszEntry, (fFileOpen & RTFILE_O_CREATE_MODE_MASK) >> RTFILE_O_CREATE_MODE_SHIFT,
425 0 /* fFlags */, &hSubDir);
426 if (RT_SUCCESS(rc))
427 {
428 RTVFSDIR hVfsDir;
429 rc = rtVfsDirFromRTDir(hSubDir, 0 /** @todo subdir open/inherit flags... */, false, &hVfsDir);
430 if (RT_SUCCESS(rc))
431 {
432 *phVfsObj = RTVfsObjFromDir(hVfsDir);
433 RTVfsDirRelease(hVfsDir);
434 AssertStmt(*phVfsObj == NIL_RTVFSOBJ, rc = VERR_INTERNAL_ERROR_3);
435 }
436 else
437 RTDirClose(hSubDir);
438 }
439 }
440 else
441 rc = VERR_VFS_UNSUPPORTED_CREATE_TYPE;
442 }
443 else
444 rc = VERR_FILE_NOT_FOUND;
445 }
446 return rc;
447}
448
449
450/**
451 * @interface_method_impl{RTVFSDIROPS,pfnFollowAbsoluteSymlink}
452 */
453static DECLCALLBACK(int) rtVfsStdDir_FollowAbsoluteSymlink(void *pvThis, const char *pszRoot, PRTVFSDIR phVfsDir)
454{
455 //PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
456 RT_NOREF(pvThis);
457 /** @todo walking restriction. */
458 return RTVfsDirOpenNormal(pszRoot, 0 /*fFlags*/, phVfsDir);
459}
460
461
462/**
463 * @interface_method_impl{RTVFSDIROPS,pfnOpenFile}
464 */
465static DECLCALLBACK(int) rtVfsStdDir_OpenFile(void *pvThis, const char *pszFilename, uint64_t fOpen, PRTVFSFILE phVfsFile)
466{
467 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
468 RTFILE hFile;
469 int rc = RTDirRelFileOpen(pThis->hDir, pszFilename, fOpen, &hFile);
470 if (RT_SUCCESS(rc))
471 {
472 rc = RTVfsFileFromRTFile(hFile, fOpen, false /*fLeaveOpen*/, phVfsFile);
473 if (RT_FAILURE(rc))
474 RTFileClose(hFile);
475 }
476 return rc;
477}
478
479
480/**
481 * @interface_method_impl{RTVFSDIROPS,pfnOpenDir}
482 */
483static DECLCALLBACK(int) rtVfsStdDir_OpenDir(void *pvThis, const char *pszSubDir, uint32_t fFlags, PRTVFSDIR phVfsDir)
484{
485 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
486 /** @todo subdir open flags */
487 RTDIR hSubDir;
488 int rc = RTDirRelDirOpenFiltered(pThis->hDir, pszSubDir, RTDIRFILTER_NONE, fFlags, &hSubDir);
489 if (RT_SUCCESS(rc))
490 {
491 rc = rtVfsDirFromRTDir(hSubDir, fFlags, false, phVfsDir);
492 if (RT_FAILURE(rc))
493 RTDirClose(hSubDir);
494 }
495 return rc;
496}
497
498
499/**
500 * @interface_method_impl{RTVFSDIROPS,pfnCreateDir}
501 */
502static DECLCALLBACK(int) rtVfsStdDir_CreateDir(void *pvThis, const char *pszSubDir, RTFMODE fMode, PRTVFSDIR phVfsDir)
503{
504 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
505 int rc;
506 if (!phVfsDir)
507 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, NULL);
508 else
509 {
510 RTDIR hSubDir;
511 rc = RTDirRelDirCreate(pThis->hDir, pszSubDir, fMode, 0 /* fFlags */, &hSubDir);
512 if (RT_SUCCESS(rc))
513 {
514 /** @todo subdir open flags... */
515 rc = rtVfsDirFromRTDir(hSubDir, 0, false, phVfsDir);
516 if (RT_FAILURE(rc))
517 RTDirClose(hSubDir);
518 }
519 }
520
521 return rc;
522}
523
524
525/**
526 * @interface_method_impl{RTVFSDIROPS,pfnOpenSymlink}
527 */
528static DECLCALLBACK(int) rtVfsStdDir_OpenSymlink(void *pvThis, const char *pszSymlink, PRTVFSSYMLINK phVfsSymlink)
529{
530 RTFSOBJINFO ObjInfo;
531 int rc = rtVfsStdDir_QueryEntryInfo(pvThis, pszSymlink, &ObjInfo, RTFSOBJATTRADD_NOTHING);
532 if (RT_SUCCESS(rc))
533 {
534 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
535 {
536 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
537 uint32_t cRefs = RTVfsDirRetain(pThis->hSelf);
538 if (cRefs != UINT32_MAX)
539 {
540 PRTVFSSTDSYMLINK pNewSymlink;
541 size_t cchSymlink = strlen(pszSymlink);
542 rc = RTVfsNewSymlink(&g_rtVfsStdSymOps, RT_UOFFSETOF_DYN(RTVFSSTDSYMLINK, szSymlink[cchSymlink + 1]),
543 NIL_RTVFS, NIL_RTVFSLOCK, phVfsSymlink, (void **)&pNewSymlink);
544 if (RT_SUCCESS(rc))
545 {
546 memcpy(pNewSymlink->szSymlink, pszSymlink, cchSymlink);
547 pNewSymlink->szSymlink[cchSymlink] = '\0';
548 pNewSymlink->pDir = pThis;
549 return VINF_SUCCESS;
550 }
551
552 RTVfsDirRelease(pThis->hSelf);
553 }
554 else
555 rc = VERR_INTERNAL_ERROR_2;
556 }
557 else
558 rc = VERR_NOT_SYMLINK;
559 }
560 return rc;
561}
562
563
564/**
565 * @interface_method_impl{RTVFSDIROPS,pfnCreateSymlink}
566 */
567static DECLCALLBACK(int) rtVfsStdDir_CreateSymlink(void *pvThis, const char *pszSymlink, const char *pszTarget,
568 RTSYMLINKTYPE enmType, PRTVFSSYMLINK phVfsSymlink)
569{
570 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
571 int rc = RTDirRelSymlinkCreate(pThis->hDir, pszSymlink, pszTarget, enmType, 0 /*fCreate*/);
572 if (RT_SUCCESS(rc))
573 {
574 if (!phVfsSymlink)
575 return VINF_SUCCESS;
576 return rtVfsStdDir_OpenSymlink(pThis, pszSymlink, phVfsSymlink);
577 }
578 return rc;
579}
580
581
582/**
583 * @interface_method_impl{RTVFSDIROPS,pfnQueryEntryInfo}
584 */
585static DECLCALLBACK(int) rtVfsStdDir_QueryEntryInfo(void *pvThis, const char *pszEntry,
586 PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
587{
588 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
589 return RTDirRelPathQueryInfo(pThis->hDir, pszEntry, pObjInfo, enmAddAttr, RTPATH_F_ON_LINK);
590}
591
592
593/**
594 * @interface_method_impl{RTVFSDIROPS,pfnUnlinkEntry}
595 */
596static DECLCALLBACK(int) rtVfsStdDir_UnlinkEntry(void *pvThis, const char *pszEntry, RTFMODE fType)
597{
598 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
599 if (fType != 0)
600 {
601 if (fType == RTFS_TYPE_DIRECTORY)
602 return RTDirRelDirRemove(pThis->hDir, pszEntry);
603
604 RTFSOBJINFO ObjInfo;
605 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
606 if (RT_FAILURE(rc))
607 return rc;
608 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
609 return VERR_WRONG_TYPE;
610 }
611 return RTDirRelPathUnlink(pThis->hDir, pszEntry, 0 /*fUnlink*/);
612}
613
614
615/**
616 * @interface_method_impl{RTVFSDIROPS,pfnRenameEntry}
617 */
618static DECLCALLBACK(int) rtVfsStdDir_RenameEntry(void *pvThis, const char *pszEntry, RTFMODE fType, const char *pszNewName)
619{
620 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
621 if (fType != 0)
622 {
623 RTFSOBJINFO ObjInfo;
624 int rc = rtVfsStdDir_QueryEntryInfo(pThis, pszEntry, &ObjInfo, RTFSOBJATTRADD_NOTHING);
625 if (RT_FAILURE(rc))
626 return rc;
627 if ((fType & RTFS_TYPE_MASK) != (ObjInfo.Attr.fMode & RTFS_TYPE_MASK))
628 return VERR_WRONG_TYPE;
629 }
630
631 /** @todo RTVFSDIROPS::pfnRenameEntry doesn't really work, this must move to
632 * file system level. */
633 return RTDirRelPathRename(pThis->hDir, pszEntry, pThis->hDir, pszNewName,
634 RTPATHRENAME_FLAGS_NO_SYMLINKS | RTPATHRENAME_FLAGS_NO_REPLACE);
635}
636
637
638/**
639 * @interface_method_impl{RTVFSDIROPS,pfnRewindDir}
640 */
641static DECLCALLBACK(int) rtVfsStdDir_RewindDir(void *pvThis)
642{
643 NOREF(pvThis);
644 return VERR_NOT_SUPPORTED;
645}
646
647
648/**
649 * @interface_method_impl{RTVFSDIROPS,pfnReadDir}
650 */
651static DECLCALLBACK(int) rtVfsStdDir_ReadDir(void *pvThis, PRTDIRENTRYEX pDirEntry, size_t *pcbDirEntry, RTFSOBJATTRADD enmAddAttr)
652{
653 PRTVFSSTDDIR pThis = (PRTVFSSTDDIR)pvThis;
654 return RTDirReadEx(pThis->hDir, pDirEntry, pcbDirEntry, enmAddAttr, RTPATH_F_ON_LINK);
655}
656
657
658/**
659 * Standard file operations.
660 */
661DECL_HIDDEN_CONST(const RTVFSDIROPS) g_rtVfsStdDirOps =
662{
663 { /* Obj */
664 RTVFSOBJOPS_VERSION,
665 RTVFSOBJTYPE_DIR,
666 "StdDir",
667 rtVfsStdDir_Close,
668 rtVfsStdDir_QueryInfo,
669 RTVFSOBJOPS_VERSION
670 },
671 RTVFSDIROPS_VERSION,
672 0,
673 { /* ObjSet */
674 RTVFSOBJSETOPS_VERSION,
675 RT_UOFFSETOF(RTVFSDIROPS, ObjSet) - RT_UOFFSETOF(RTVFSDIROPS, Obj),
676 rtVfsStdDir_SetMode,
677 rtVfsStdDir_SetTimes,
678 rtVfsStdDir_SetOwner,
679 RTVFSOBJSETOPS_VERSION
680 },
681 rtVfsStdDir_Open,
682 rtVfsStdDir_FollowAbsoluteSymlink,
683 rtVfsStdDir_OpenFile,
684 rtVfsStdDir_OpenDir,
685 rtVfsStdDir_CreateDir,
686 rtVfsStdDir_OpenSymlink,
687 rtVfsStdDir_CreateSymlink,
688 rtVfsStdDir_QueryEntryInfo,
689 rtVfsStdDir_UnlinkEntry,
690 rtVfsStdDir_RenameEntry,
691 rtVfsStdDir_RewindDir,
692 rtVfsStdDir_ReadDir,
693 RTVFSDIROPS_VERSION
694};
695
696
697/**
698 * Internal worker for RTVfsDirFromRTDir and RTVfsDirOpenNormal.
699 *
700 * @returns IRPT status code.
701 * @param hDir The IPRT directory handle.
702 * @param fOpen Reserved for future.
703 * @param fLeaveOpen Whether to leave it open or close it.
704 * @param phVfsDir Where to return the handle.
705 */
706static int rtVfsDirFromRTDir(RTDIR hDir, uint32_t fFlags, bool fLeaveOpen, PRTVFSDIR phVfsDir)
707{
708 PRTVFSSTDDIR pThis;
709 RTVFSDIR hVfsDir;
710 int rc = RTVfsNewDir(&g_rtVfsStdDirOps, sizeof(RTVFSSTDDIR), 0 /*fFlags*/, NIL_RTVFS, NIL_RTVFSLOCK,
711 &hVfsDir, (void **)&pThis);
712 if (RT_SUCCESS(rc))
713 {
714 pThis->hDir = hDir;
715 pThis->fLeaveOpen = fLeaveOpen;
716 pThis->fFlags = fFlags;
717 pThis->hSelf = hVfsDir;
718
719 *phVfsDir = hVfsDir;
720 return VINF_SUCCESS;
721 }
722 return rc;
723}
724
725
726RTDECL(int) RTVfsDirFromRTDir(RTDIR hDir, bool fLeaveOpen, PRTVFSDIR phVfsDir)
727{
728 AssertReturn(RTDirIsValid(hDir), VERR_INVALID_HANDLE);
729 return rtVfsDirFromRTDir(hDir, hDir->fFlags, fLeaveOpen, phVfsDir);
730}
731
732
733RTDECL(int) RTVfsDirOpenNormal(const char *pszPath, uint32_t fFlags, PRTVFSDIR phVfsDir)
734{
735 /*
736 * Open the file the normal way and pass it to RTVfsFileFromRTFile.
737 */
738 RTDIR hDir;
739 int rc = RTDirOpenFiltered(&hDir, pszPath, RTDIRFILTER_NONE, fFlags);
740 if (RT_SUCCESS(rc))
741 {
742 /*
743 * Create a VFS file handle.
744 */
745 rc = rtVfsDirFromRTDir(hDir, fFlags, false /*fLeaveOpen*/, phVfsDir);
746 if (RT_SUCCESS(rc))
747 return VINF_SUCCESS;
748
749 RTDirClose(hDir);
750 }
751 return rc;
752}
753
754
755RTDECL(bool) RTVfsDirIsStdDir(RTVFSDIR hVfsDir)
756{
757 return RTVfsDirToPrivate(hVfsDir, &g_rtVfsStdDirOps) != NULL;
758}
759
760
761/**
762 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnValidate}
763 */
764static DECLCALLBACK(int) rtVfsChainStdDir_Validate(PCRTVFSCHAINELEMENTREG pProviderReg, PRTVFSCHAINSPEC pSpec,
765 PRTVFSCHAINELEMSPEC pElement, uint32_t *poffError, PRTERRINFO pErrInfo)
766{
767 RT_NOREF(pProviderReg, pSpec);
768
769 /*
770 * Basic checks.
771 */
772 if (pElement->enmTypeIn != RTVFSOBJTYPE_INVALID)
773 return VERR_VFS_CHAIN_MUST_BE_FIRST_ELEMENT;
774 if (pElement->enmType != RTVFSOBJTYPE_DIR)
775 return VERR_VFS_CHAIN_ONLY_DIR;
776 if (pElement->cArgs < 1)
777 return VERR_VFS_CHAIN_AT_LEAST_ONE_ARG;
778
779 /*
780 * Parse flag arguments if any, storing them in the element.
781 */
782 uint32_t fFlags = 0;
783 for (uint32_t i = 1; i < pElement->cArgs; i++)
784 if (strcmp(pElement->paArgs[i].psz, "deny-ascent") == 0)
785 fFlags |= RTDIR_F_DENY_ASCENT;
786 else if (strcmp(pElement->paArgs[i].psz, "allow-ascent") == 0)
787 fFlags &= ~RTDIR_F_DENY_ASCENT;
788 else
789 {
790 *poffError = pElement->paArgs[i].offSpec;
791 return RTErrInfoSetF(pErrInfo, VERR_VFS_CHAIN_INVALID_ARGUMENT, "Unknown flag argument: %s", pElement->paArgs[i].psz);
792 }
793 pElement->uProvider = fFlags;
794
795 return VINF_SUCCESS;
796}
797
798
799/**
800 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnInstantiate}
801 */
802static DECLCALLBACK(int) rtVfsChainStdDir_Instantiate(PCRTVFSCHAINELEMENTREG pProviderReg, PCRTVFSCHAINSPEC pSpec,
803 PCRTVFSCHAINELEMSPEC pElement, RTVFSOBJ hPrevVfsObj,
804 PRTVFSOBJ phVfsObj, uint32_t *poffError, PRTERRINFO pErrInfo)
805{
806 RT_NOREF(pProviderReg, pSpec, poffError, pErrInfo);
807 AssertReturn(hPrevVfsObj == NIL_RTVFSOBJ, VERR_VFS_CHAIN_IPE);
808
809 RTVFSDIR hVfsDir;
810 int rc = RTVfsDirOpenNormal(pElement->paArgs[0].psz, (uint32_t)pElement->uProvider, &hVfsDir);
811 if (RT_SUCCESS(rc))
812 {
813 *phVfsObj = RTVfsObjFromDir(hVfsDir);
814 RTVfsDirRelease(hVfsDir);
815 if (*phVfsObj != NIL_RTVFSOBJ)
816 return VINF_SUCCESS;
817 rc = VERR_VFS_CHAIN_CAST_FAILED;
818 }
819 return rc;
820}
821
822
823/**
824 * @interface_method_impl{RTVFSCHAINELEMENTREG,pfnCanReuseElement}
825 */
826static DECLCALLBACK(bool) rtVfsChainStdDir_CanReuseElement(PCRTVFSCHAINELEMENTREG pProviderReg,
827 PCRTVFSCHAINSPEC pSpec, PCRTVFSCHAINELEMSPEC pElement,
828 PCRTVFSCHAINSPEC pReuseSpec, PCRTVFSCHAINELEMSPEC pReuseElement)
829{
830 RT_NOREF(pProviderReg, pSpec, pReuseSpec);
831 if (strcmp(pElement->paArgs[0].psz, pReuseElement->paArgs[0].psz) == 0)
832 if (pElement->paArgs[0].uProvider == pReuseElement->paArgs[0].uProvider)
833 return true;
834 return false;
835}
836
837
838/** VFS chain element 'file'. */
839static RTVFSCHAINELEMENTREG g_rtVfsChainStdDirReg =
840{
841 /* uVersion = */ RTVFSCHAINELEMENTREG_VERSION,
842 /* fReserved = */ 0,
843 /* pszName = */ "stddir",
844 /* ListEntry = */ { NULL, NULL },
845 /* pszHelp = */ "Open a real directory. Initial element.\n"
846 "Takes zero or more flag arguments: deny-ascent, allow-ascent",
847 /* pfnValidate = */ rtVfsChainStdDir_Validate,
848 /* pfnInstantiate = */ rtVfsChainStdDir_Instantiate,
849 /* pfnCanReuseElement = */ rtVfsChainStdDir_CanReuseElement,
850 /* uEndMarker = */ RTVFSCHAINELEMENTREG_VERSION
851};
852
853RTVFSCHAIN_AUTO_REGISTER_ELEMENT_PROVIDER(&g_rtVfsChainStdDirReg, rtVfsChainStdDirReg);
854
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