[67186] | 1 | /* $Id: vfsfss2dir.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * IPRT - Virtual File System, FS write stream dumping in a normal directory.
|
---|
| 4 | *
|
---|
| 5 | * This is just a simple mechanism to provide a drop in for the TAR creator
|
---|
| 6 | * that writes files individually to the disk instead of a TAR archive. It
|
---|
| 7 | * has an additional feature for removing the files to help bail out on error.
|
---|
| 8 | */
|
---|
| 9 |
|
---|
| 10 | /*
|
---|
[98103] | 11 | * Copyright (C) 2010-2023 Oracle and/or its affiliates.
|
---|
[67186] | 12 | *
|
---|
[96407] | 13 | * This file is part of VirtualBox base platform packages, as
|
---|
| 14 | * available from https://www.virtualbox.org.
|
---|
[67186] | 15 | *
|
---|
[96407] | 16 | * This program is free software; you can redistribute it and/or
|
---|
| 17 | * modify it under the terms of the GNU General Public License
|
---|
| 18 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 19 | * License.
|
---|
| 20 | *
|
---|
| 21 | * This program is distributed in the hope that it will be useful, but
|
---|
| 22 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 24 | * General Public License for more details.
|
---|
| 25 | *
|
---|
| 26 | * You should have received a copy of the GNU General Public License
|
---|
| 27 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 28 | *
|
---|
[67186] | 29 | * The contents of this file may alternatively be used under the terms
|
---|
| 30 | * of the Common Development and Distribution License Version 1.0
|
---|
[96407] | 31 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
| 32 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
[67186] | 33 | * CDDL are applicable instead of those of the GPL.
|
---|
| 34 | *
|
---|
| 35 | * You may elect to license modified versions of this file under the
|
---|
| 36 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
[96407] | 37 | *
|
---|
| 38 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
[67186] | 39 | */
|
---|
| 40 |
|
---|
| 41 |
|
---|
| 42 | /*********************************************************************************************************************************
|
---|
| 43 | * Header Files *
|
---|
| 44 | *********************************************************************************************************************************/
|
---|
| 45 | /// @todo #define RTVFSFSS2DIR_USE_DIR
|
---|
| 46 | #include "internal/iprt.h"
|
---|
| 47 | #include <iprt/vfs.h>
|
---|
| 48 |
|
---|
| 49 | #include <iprt/assert.h>
|
---|
| 50 | #include <iprt/err.h>
|
---|
| 51 | #include <iprt/file.h>
|
---|
| 52 | #include <iprt/mem.h>
|
---|
| 53 | #ifndef RTVFSFSS2DIR_USE_DIR
|
---|
| 54 | # include <iprt/path.h>
|
---|
| 55 | #endif
|
---|
| 56 | #include <iprt/string.h>
|
---|
| 57 | #include <iprt/vfslowlevel.h>
|
---|
| 58 |
|
---|
| 59 |
|
---|
| 60 | /*********************************************************************************************************************************
|
---|
| 61 | * Structures and Typedefs *
|
---|
| 62 | *********************************************************************************************************************************/
|
---|
| 63 | /**
|
---|
| 64 | * Undo entry for RTVFSFSSWRITE2DIR.
|
---|
| 65 | */
|
---|
| 66 | typedef struct RTVFSFSSWRITE2DIRENTRY
|
---|
| 67 | {
|
---|
| 68 | /** The list entry (head is RTVFSFSSWRITE2DIR::Entries). */
|
---|
| 69 | RTLISTNODE Entry;
|
---|
| 70 | /** The file mode mask. */
|
---|
| 71 | RTFMODE fMode;
|
---|
| 72 | #ifdef RTVFSFSS2DIR_USE_DIR
|
---|
| 73 | /** The name (relative to RTVFSFSSWRITE2DIR::hVfsBaseDir). */
|
---|
| 74 | #else
|
---|
| 75 | /** The name (relative to RTVFSFSSWRITE2DIR::szBaseDir). */
|
---|
| 76 | #endif
|
---|
[84509] | 77 | RT_FLEXIBLE_ARRAY_EXTENSION
|
---|
[67186] | 78 | char szName[RT_FLEXIBLE_ARRAY];
|
---|
| 79 | } RTVFSFSSWRITE2DIRENTRY;
|
---|
| 80 | /** Pointer to a RTVFSFSSWRITE2DIR undo entry. */
|
---|
| 81 | typedef RTVFSFSSWRITE2DIRENTRY *PRTVFSFSSWRITE2DIRENTRY;
|
---|
| 82 |
|
---|
| 83 | /**
|
---|
| 84 | * FSS write to directory instance.
|
---|
| 85 | */
|
---|
| 86 | typedef struct RTVFSFSSWRITE2DIR
|
---|
| 87 | {
|
---|
| 88 | /** Flags (RTVFSFSS2DIR_F_XXX). */
|
---|
| 89 | uint32_t fFlags;
|
---|
| 90 | /** Number of files and stuff we've created. */
|
---|
| 91 | uint32_t cEntries;
|
---|
| 92 | /** Files and stuff we've created (RTVFSFSSWRITE2DIRENTRY).
|
---|
| 93 | * This is used for reverting changes on failure. */
|
---|
| 94 | RTLISTANCHOR Entries;
|
---|
| 95 | #ifdef RTVFSFSS2DIR_USE_DIR
|
---|
| 96 | /** The handle of the base directory. */
|
---|
| 97 | RTVFSDIR hVfsBaseDir;
|
---|
| 98 | #else
|
---|
| 99 | /** Path to the directory that all operations are relative to. */
|
---|
[84509] | 100 | RT_FLEXIBLE_ARRAY_EXTENSION
|
---|
[67186] | 101 | char szBaseDir[RT_FLEXIBLE_ARRAY];
|
---|
| 102 | #endif
|
---|
| 103 | } RTVFSFSSWRITE2DIR;
|
---|
| 104 | /** Pointer to a write-to-directory FSS instance. */
|
---|
| 105 | typedef RTVFSFSSWRITE2DIR *PRTVFSFSSWRITE2DIR;
|
---|
| 106 |
|
---|
| 107 |
|
---|
| 108 | /*********************************************************************************************************************************
|
---|
| 109 | * Internal Functions *
|
---|
| 110 | *********************************************************************************************************************************/
|
---|
| 111 | static DECLCALLBACK(int) rtVfsFssToDir_PushFile(void *pvThis, const char *pszPath, uint64_t cbFile, PCRTFSOBJINFO paObjInfo,
|
---|
| 112 | uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos);
|
---|
| 113 |
|
---|
| 114 |
|
---|
| 115 | /**
|
---|
| 116 | * @interface_method_impl{RTVFSOBJOPS,pfnClose}
|
---|
| 117 | */
|
---|
| 118 | static DECLCALLBACK(int) rtVfsFssToDir_Close(void *pvThis)
|
---|
| 119 | {
|
---|
| 120 | PRTVFSFSSWRITE2DIR pThis = (PRTVFSFSSWRITE2DIR)pvThis;
|
---|
| 121 |
|
---|
| 122 | #ifdef RTVFSFSS2DIR_USE_DIR
|
---|
| 123 | RTVfsDirRelease(pThis->hVfsBaseDir);
|
---|
| 124 | pThis->hVfsBaseDir = NIL_RTVFSDIR;
|
---|
| 125 | #endif
|
---|
| 126 |
|
---|
| 127 | PRTVFSFSSWRITE2DIRENTRY pCur;
|
---|
| 128 | PRTVFSFSSWRITE2DIRENTRY pNext;
|
---|
| 129 | RTListForEachSafe(&pThis->Entries, pCur, pNext, RTVFSFSSWRITE2DIRENTRY, Entry)
|
---|
| 130 | {
|
---|
| 131 | RTMemFree(pCur);
|
---|
| 132 | }
|
---|
| 133 | return VINF_SUCCESS;
|
---|
| 134 | }
|
---|
| 135 |
|
---|
| 136 |
|
---|
| 137 | /**
|
---|
| 138 | * @interface_method_impl{RTVFSOBJOPS,pfnQueryInfo}
|
---|
| 139 | */
|
---|
| 140 | static DECLCALLBACK(int) rtVfsFssToDir_QueryInfo(void *pvThis, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAddAttr)
|
---|
| 141 | {
|
---|
| 142 | RT_NOREF(pvThis);
|
---|
| 143 |
|
---|
| 144 | /* no info here, sorry. */
|
---|
| 145 | RT_ZERO(*pObjInfo);
|
---|
| 146 | pObjInfo->Attr.enmAdditional = enmAddAttr;
|
---|
| 147 |
|
---|
| 148 | return VINF_SUCCESS;
|
---|
| 149 | }
|
---|
| 150 |
|
---|
| 151 |
|
---|
| 152 | /**
|
---|
| 153 | * @interface_method_impl{RTVFSFSSTREAMOPS,pfnAdd}
|
---|
| 154 | */
|
---|
| 155 | static DECLCALLBACK(int) rtVfsFssToDir_Add(void *pvThis, const char *pszPath, RTVFSOBJ hVfsObj, uint32_t fFlags)
|
---|
| 156 | {
|
---|
| 157 | PRTVFSFSSWRITE2DIR pThis = (PRTVFSFSSWRITE2DIR)pvThis;
|
---|
| 158 | RT_NOREF(fFlags);
|
---|
| 159 |
|
---|
| 160 | /*
|
---|
| 161 | * Query information about the object.
|
---|
| 162 | */
|
---|
| 163 | RTFSOBJINFO ObjInfo;
|
---|
| 164 | int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_UNIX);
|
---|
| 165 | AssertRCReturn(rc, rc);
|
---|
| 166 |
|
---|
| 167 | /*
|
---|
| 168 | * Deal with files.
|
---|
| 169 | */
|
---|
| 170 | if (RTFS_IS_FILE(ObjInfo.Attr.fMode))
|
---|
| 171 | {
|
---|
| 172 | RTVFSIOSTREAM hVfsIosSrc = RTVfsObjToIoStream(hVfsObj);
|
---|
| 173 | AssertReturn(hVfsIosSrc != NIL_RTVFSIOSTREAM, VERR_WRONG_TYPE);
|
---|
| 174 |
|
---|
| 175 | RTVFSIOSTREAM hVfsIosDst;
|
---|
| 176 | rc = rtVfsFssToDir_PushFile(pvThis, pszPath, ObjInfo.cbObject, &ObjInfo, 1, 0 /*fFlags*/, &hVfsIosDst);
|
---|
| 177 | if (RT_SUCCESS(rc))
|
---|
| 178 | {
|
---|
| 179 | rc = RTVfsUtilPumpIoStreams(hVfsIosSrc, hVfsIosDst, (size_t)RT_ALIGN(ObjInfo.cbObject, _4K));
|
---|
| 180 | RTVfsIoStrmRelease(hVfsIosDst);
|
---|
| 181 | }
|
---|
| 182 | RTVfsIoStrmRelease(hVfsIosSrc);
|
---|
| 183 | }
|
---|
| 184 | /*
|
---|
| 185 | * Symbolic links.
|
---|
| 186 | */
|
---|
| 187 | else if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
|
---|
| 188 | {
|
---|
| 189 | RTVFSSYMLINK hVfsSymlink = RTVfsObjToSymlink(hVfsObj);
|
---|
| 190 | AssertReturn(hVfsSymlink != NIL_RTVFSSYMLINK, VERR_WRONG_TYPE);
|
---|
| 191 |
|
---|
| 192 | AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
|
---|
| 193 | RT_NOREF(pThis);
|
---|
| 194 |
|
---|
| 195 | RTVfsSymlinkRelease(hVfsSymlink);
|
---|
| 196 | }
|
---|
| 197 | /*
|
---|
| 198 | * Directories.
|
---|
| 199 | */
|
---|
| 200 | else if (RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 201 | AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
|
---|
| 202 | /*
|
---|
| 203 | * And whatever else we need when we need it...
|
---|
| 204 | */
|
---|
| 205 | else
|
---|
| 206 | AssertFailedStmt(rc = VERR_NOT_IMPLEMENTED);
|
---|
| 207 |
|
---|
| 208 | return rc;
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 |
|
---|
| 212 | /**
|
---|
| 213 | * @interface_method_impl{RTVFSFSSTREAMOPS,pfnPushFile}
|
---|
| 214 | */
|
---|
| 215 | static DECLCALLBACK(int) rtVfsFssToDir_PushFile(void *pvThis, const char *pszPath, uint64_t cbFile, PCRTFSOBJINFO paObjInfo,
|
---|
| 216 | uint32_t cObjInfo, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos)
|
---|
| 217 | {
|
---|
| 218 | PRTVFSFSSWRITE2DIR pThis = (PRTVFSFSSWRITE2DIR)pvThis;
|
---|
| 219 | RT_NOREF(cbFile, fFlags);
|
---|
| 220 | int rc;
|
---|
| 221 |
|
---|
| 222 | #ifndef RTVFSFSS2DIR_USE_DIR
|
---|
| 223 | /*
|
---|
| 224 | * Join up the path with the base dir and make sure it fits.
|
---|
| 225 | */
|
---|
| 226 | char szFullPath[RTPATH_MAX];
|
---|
| 227 | rc = RTPathJoin(szFullPath, sizeof(szFullPath), pThis->szBaseDir, pszPath);
|
---|
| 228 | if (RT_SUCCESS(rc))
|
---|
| 229 | {
|
---|
| 230 | #endif
|
---|
| 231 | /*
|
---|
| 232 | * Create an undo entry for it.
|
---|
| 233 | */
|
---|
| 234 | size_t const cbRelativePath = strlen(pszPath);
|
---|
| 235 | PRTVFSFSSWRITE2DIRENTRY pEntry;
|
---|
[73097] | 236 | pEntry = (PRTVFSFSSWRITE2DIRENTRY)RTMemAllocVar(RT_UOFFSETOF_DYN(RTVFSFSSWRITE2DIRENTRY, szName[cbRelativePath]));
|
---|
[67186] | 237 | if (pEntry)
|
---|
| 238 | {
|
---|
| 239 | if (cObjInfo)
|
---|
| 240 | pEntry->fMode = (paObjInfo[0].Attr.fMode & ~RTFS_TYPE_MASK) | RTFS_TYPE_FILE;
|
---|
| 241 | else
|
---|
| 242 | pEntry->fMode = RTFS_TYPE_FILE | 0664;
|
---|
| 243 | memcpy(pEntry->szName, pszPath, cbRelativePath);
|
---|
| 244 |
|
---|
| 245 | /*
|
---|
| 246 | * Create the file.
|
---|
| 247 | */
|
---|
| 248 | uint64_t fOpen = RTFILE_O_WRITE | RTFILE_O_DENY_WRITE;
|
---|
| 249 | fOpen |= ((pEntry->fMode & RTFS_UNIX_ALL_ACCESS_PERMS) << RTFILE_O_CREATE_MODE_SHIFT);
|
---|
| 250 | if (!(pThis->fFlags & RTVFSFSS2DIR_F_OVERWRITE_FILES))
|
---|
| 251 | fOpen |= RTFILE_O_CREATE;
|
---|
| 252 | else
|
---|
| 253 | fOpen |= RTFILE_O_CREATE_REPLACE;
|
---|
| 254 | #ifdef RTVFSFSS2DIR_USE_DIR
|
---|
| 255 | rc = RTVfsDirOpenFileAsIoStream(pThis->hVfsBaseDir, pszPath, fOpen, phVfsIos);
|
---|
| 256 | #else
|
---|
| 257 | rc = RTVfsIoStrmOpenNormal(szFullPath, fOpen, phVfsIos);
|
---|
| 258 | #endif
|
---|
| 259 | if (RT_SUCCESS(rc))
|
---|
| 260 | RTListAppend(&pThis->Entries, &pEntry->Entry);
|
---|
| 261 | else
|
---|
| 262 | RTMemFree(pEntry);
|
---|
| 263 | }
|
---|
| 264 | else
|
---|
| 265 | rc = VERR_NO_MEMORY;
|
---|
| 266 | #ifndef RTVFSFSS2DIR_USE_DIR
|
---|
| 267 | }
|
---|
| 268 | else if (rc == VERR_BUFFER_OVERFLOW)
|
---|
| 269 | rc = VERR_FILENAME_TOO_LONG;
|
---|
| 270 | #endif
|
---|
| 271 | return rc;
|
---|
| 272 | }
|
---|
| 273 |
|
---|
| 274 |
|
---|
| 275 | /**
|
---|
| 276 | * @interface_method_impl{RTVFSFSSTREAMOPS,pfnEnd}
|
---|
| 277 | */
|
---|
| 278 | static DECLCALLBACK(int) rtVfsFssToDir_End(void *pvThis)
|
---|
| 279 | {
|
---|
| 280 | RT_NOREF(pvThis);
|
---|
| 281 | return VINF_SUCCESS;
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 |
|
---|
| 285 | /**
|
---|
| 286 | * The write-to-directory FSS operations.
|
---|
| 287 | */
|
---|
| 288 | static const RTVFSFSSTREAMOPS g_rtVfsFssToDirOps =
|
---|
| 289 | {
|
---|
| 290 | { /* Obj */
|
---|
| 291 | RTVFSOBJOPS_VERSION,
|
---|
| 292 | RTVFSOBJTYPE_FS_STREAM,
|
---|
| 293 | "TarFsStreamWriter",
|
---|
| 294 | rtVfsFssToDir_Close,
|
---|
| 295 | rtVfsFssToDir_QueryInfo,
|
---|
[94291] | 296 | NULL,
|
---|
[67186] | 297 | RTVFSOBJOPS_VERSION
|
---|
| 298 | },
|
---|
| 299 | RTVFSFSSTREAMOPS_VERSION,
|
---|
| 300 | 0,
|
---|
| 301 | NULL,
|
---|
| 302 | rtVfsFssToDir_Add,
|
---|
| 303 | rtVfsFssToDir_PushFile,
|
---|
| 304 | rtVfsFssToDir_End,
|
---|
| 305 | RTVFSFSSTREAMOPS_VERSION
|
---|
| 306 | };
|
---|
| 307 |
|
---|
| 308 |
|
---|
| 309 | #ifdef RTVFSFSS2DIR_USE_DIR
|
---|
| 310 | RTDECL(int) RTVfsFsStrmToDir(RTVFSDIR hVfsBaseDir, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
|
---|
| 311 | {
|
---|
| 312 | /*
|
---|
| 313 | * Input validation.
|
---|
| 314 | */
|
---|
| 315 | AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
|
---|
| 316 | *phVfsFss = NIL_RTVFSFSSTREAM;
|
---|
| 317 | AssertReturn(!(fFlags & ~RTVFSFSS2DIR_F_VALID_MASK), VERR_INVALID_FLAGS);
|
---|
| 318 | uint32_t cRefs = RTVfsDirRetain(hVfsBaseDir);
|
---|
| 319 | AssertReturn(cRefs != UINT32_MAX, VERR_INVALID_HANDLE);
|
---|
| 320 |
|
---|
| 321 | /*
|
---|
| 322 | * Create the file system stream handle and init our data.
|
---|
| 323 | */
|
---|
| 324 | PRTVFSFSSWRITE2DIR pThis;
|
---|
| 325 | RTVFSFSSTREAM hVfsFss;
|
---|
[84192] | 326 | int rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, sizeof(*pThis), NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE,
|
---|
[67186] | 327 | &hVfsFss, (void **)&pThis);
|
---|
| 328 | if (RT_SUCCESS(rc))
|
---|
| 329 | {
|
---|
| 330 | pThis->fFlags = fFlags;
|
---|
| 331 | pThis->cEntries = 0;
|
---|
| 332 | pThis->hVfsBaseDir = hVfsBaseDir;
|
---|
| 333 | RTListInit(&pThis->Entries);
|
---|
| 334 |
|
---|
| 335 | *phVfsFss = hVfsFss;
|
---|
| 336 | return VINF_SUCCESS;
|
---|
| 337 | }
|
---|
| 338 | RTVfsDirRelease(hVfsBaseDir);
|
---|
| 339 |
|
---|
| 340 | }
|
---|
| 341 | #endif /* RTVFSFSS2DIR_USE_DIR */
|
---|
| 342 |
|
---|
| 343 |
|
---|
| 344 | RTDECL(int) RTVfsFsStrmToNormalDir(const char *pszBaseDir, uint32_t fFlags, PRTVFSFSSTREAM phVfsFss)
|
---|
| 345 | {
|
---|
| 346 | #ifdef RTVFSFSS2DIR_USE_DIR
|
---|
| 347 | RTVFSDIR hVfsBaseDir;
|
---|
| 348 | int rc = RTVfsDirOpenNormal(pszBaseDir, 0 /*fFlags*/, &hVfsBaseDir);
|
---|
| 349 | if (RT_SUCCESS(rc))
|
---|
| 350 | {
|
---|
| 351 | rc = RTVfsFsStrmToDir(hVfsBaseDir, fFlags, phVfsFss);
|
---|
| 352 | RTVfsDirRelease(hVfsBaseDir);
|
---|
| 353 | }
|
---|
| 354 | #else
|
---|
| 355 |
|
---|
| 356 | /*
|
---|
| 357 | * Input validation.
|
---|
| 358 | */
|
---|
| 359 | AssertPtrReturn(phVfsFss, VERR_INVALID_HANDLE);
|
---|
| 360 | *phVfsFss = NIL_RTVFSFSSTREAM;
|
---|
| 361 | AssertReturn(!(fFlags & ~RTVFSFSS2DIR_F_VALID_MASK), VERR_INVALID_FLAGS);
|
---|
| 362 | AssertPtrReturn(pszBaseDir, VERR_INVALID_POINTER);
|
---|
| 363 | AssertReturn(*pszBaseDir != '\0', VERR_INVALID_NAME);
|
---|
| 364 |
|
---|
| 365 | /*
|
---|
| 366 | * Straighten the path and make sure it's an existing directory.
|
---|
| 367 | */
|
---|
| 368 | char szAbsPath[RTPATH_MAX];
|
---|
| 369 | int rc = RTPathAbs(pszBaseDir, szAbsPath, sizeof(szAbsPath));
|
---|
| 370 | if (RT_SUCCESS(rc))
|
---|
| 371 | {
|
---|
| 372 | RTFSOBJINFO ObjInfo;
|
---|
| 373 | rc = RTPathQueryInfo(szAbsPath, &ObjInfo, RTFSOBJATTRADD_NOTHING);
|
---|
| 374 | if (RT_SUCCESS(rc))
|
---|
| 375 | {
|
---|
| 376 | if (RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
|
---|
| 377 | {
|
---|
| 378 | /*
|
---|
| 379 | * Create the file system stream handle and init our data.
|
---|
| 380 | */
|
---|
| 381 | size_t const cbBaseDir = strlen(szAbsPath) + 1;
|
---|
| 382 | PRTVFSFSSWRITE2DIR pThis;
|
---|
| 383 | RTVFSFSSTREAM hVfsFss;
|
---|
[73097] | 384 | rc = RTVfsNewFsStream(&g_rtVfsFssToDirOps, RT_UOFFSETOF_DYN(RTVFSFSSWRITE2DIR, szBaseDir[cbBaseDir]),
|
---|
[84192] | 385 | NIL_RTVFS, NIL_RTVFSLOCK, RTFILE_O_WRITE, &hVfsFss, (void **)&pThis);
|
---|
[67186] | 386 | if (RT_SUCCESS(rc))
|
---|
| 387 | {
|
---|
| 388 | pThis->fFlags = fFlags;
|
---|
| 389 | pThis->cEntries = 0;
|
---|
| 390 | RTListInit(&pThis->Entries);
|
---|
| 391 | memcpy(pThis->szBaseDir, szAbsPath, cbBaseDir);
|
---|
| 392 |
|
---|
| 393 | *phVfsFss = hVfsFss;
|
---|
| 394 | return VINF_SUCCESS;
|
---|
| 395 | }
|
---|
| 396 | }
|
---|
| 397 | else
|
---|
| 398 | rc = VERR_NOT_A_DIRECTORY;
|
---|
| 399 | }
|
---|
| 400 | }
|
---|
| 401 | #endif
|
---|
| 402 | return rc;
|
---|
| 403 | }
|
---|
| 404 |
|
---|
| 405 |
|
---|
| 406 | RTDECL(int) RTVfsFsStrmToDirUndo(RTVFSFSSTREAM hVfsFss)
|
---|
| 407 | {
|
---|
| 408 | /*
|
---|
| 409 | * Validate input.
|
---|
| 410 | */
|
---|
| 411 | PRTVFSFSSWRITE2DIR pThis = (PRTVFSFSSWRITE2DIR)RTVfsFsStreamToPrivate(hVfsFss, &g_rtVfsFssToDirOps);
|
---|
| 412 | AssertReturn(pThis, VERR_WRONG_TYPE);
|
---|
| 413 |
|
---|
| 414 | /*
|
---|
| 415 | * Do the job, in reverse order. Dropping stuff we
|
---|
| 416 | * successfully remove from the list.
|
---|
| 417 | */
|
---|
| 418 | int rc = VINF_SUCCESS;
|
---|
| 419 | PRTVFSFSSWRITE2DIRENTRY pCur;
|
---|
| 420 | PRTVFSFSSWRITE2DIRENTRY pPrev;
|
---|
| 421 | RTListForEachReverseSafe(&pThis->Entries, pCur, pPrev, RTVFSFSSWRITE2DIRENTRY, Entry)
|
---|
| 422 | {
|
---|
| 423 | #ifdef RTVFSFSS2DIR_USE_DIR
|
---|
| 424 | int rc2 = RTVfsDirUnlinkEntry(pThis->hVfsBaseDir, pCur->szName);
|
---|
| 425 | #else
|
---|
| 426 | char szFullPath[RTPATH_MAX];
|
---|
| 427 | int rc2 = RTPathJoin(szFullPath, sizeof(szFullPath), pThis->szBaseDir, pCur->szName);
|
---|
| 428 | AssertRC(rc2);
|
---|
| 429 | if (RT_SUCCESS(rc2))
|
---|
| 430 | rc2 = RTPathUnlink(szFullPath, 0 /*fUnlink*/);
|
---|
| 431 | #endif
|
---|
| 432 | if ( RT_SUCCESS(rc2)
|
---|
| 433 | || rc2 == VERR_PATH_NOT_FOUND
|
---|
| 434 | || rc2 == VERR_FILE_NOT_FOUND
|
---|
| 435 | || rc2 == VERR_NOT_FOUND)
|
---|
| 436 | {
|
---|
| 437 | RTListNodeRemove(&pCur->Entry);
|
---|
| 438 | RTMemFree(pCur);
|
---|
| 439 | }
|
---|
| 440 | else if (RT_SUCCESS(rc))
|
---|
| 441 | rc = rc2;
|
---|
| 442 | }
|
---|
| 443 | return rc;
|
---|
| 444 | }
|
---|
| 445 |
|
---|