[1] | 1 | /* $Id: dir2.cpp 76553 2019-01-01 01:45:53Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
[34015] | 3 | * IPRT - Directory Manipulation, Part 2.
|
---|
[1] | 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[76553] | 7 | * Copyright (C) 2006-2019 Oracle Corporation
|
---|
[1] | 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
|
---|
[5999] | 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.
|
---|
[1] | 25 | */
|
---|
| 26 |
|
---|
| 27 |
|
---|
[57358] | 28 | /*********************************************************************************************************************************
|
---|
| 29 | * Header Files *
|
---|
| 30 | *********************************************************************************************************************************/
|
---|
[1] | 31 | #define LOG_GROUP RTLOGGROUP_DIR
|
---|
| 32 | #include <iprt/dir.h>
|
---|
[28688] | 33 | #include "internal/iprt.h"
|
---|
| 34 |
|
---|
| 35 | #include <iprt/assert.h>
|
---|
[19211] | 36 | #include <iprt/file.h>
|
---|
[28688] | 37 | #include <iprt/err.h>
|
---|
[1] | 38 | #include <iprt/log.h>
|
---|
[28688] | 39 | #include <iprt/mem.h>
|
---|
[1] | 40 | #include <iprt/param.h>
|
---|
[28688] | 41 | #include <iprt/path.h>
|
---|
[1] | 42 | #include <iprt/string.h>
|
---|
[21675] | 43 | #include "internal/path.h"
|
---|
[1] | 44 |
|
---|
| 45 |
|
---|
| 46 | /**
|
---|
[27246] | 47 | * Recursion worker for RTDirRemoveRecursive.
|
---|
| 48 | *
|
---|
| 49 | * @returns IPRT status code.
|
---|
| 50 | * @param pszBuf The path buffer. Contains the abs path to the
|
---|
| 51 | * directory to recurse into. Trailing slash.
|
---|
| 52 | * @param cchDir The length of the directory we're cursing into,
|
---|
| 53 | * including the trailing slash.
|
---|
| 54 | * @param pDirEntry The dir entry buffer. (Shared to save stack.)
|
---|
| 55 | * @param pObjInfo The object info buffer. (ditto)
|
---|
| 56 | */
|
---|
| 57 | static int rtDirRemoveRecursiveSub(char *pszBuf, size_t cchDir, PRTDIRENTRY pDirEntry, PRTFSOBJINFO pObjInfo)
|
---|
[19211] | 58 | {
|
---|
[27246] | 59 | AssertReturn(RTPATH_IS_SLASH(pszBuf[cchDir - 1]), VERR_INTERNAL_ERROR_4);
|
---|
[19211] | 60 |
|
---|
[27246] | 61 | /*
|
---|
| 62 | * Enumerate the directory content and dispose of it.
|
---|
| 63 | */
|
---|
[69753] | 64 | RTDIR hDir;
|
---|
| 65 | int rc = RTDirOpen(&hDir, pszBuf);
|
---|
[19211] | 66 | if (RT_FAILURE(rc))
|
---|
| 67 | return rc;
|
---|
[69753] | 68 | while (RT_SUCCESS(rc = RTDirRead(hDir, pDirEntry, NULL)))
|
---|
[19211] | 69 | {
|
---|
[69753] | 70 | if (!RTDirEntryIsStdDotLink(pDirEntry))
|
---|
[19211] | 71 | {
|
---|
[27246] | 72 | /* Construct the full name of the entry. */
|
---|
| 73 | if (cchDir + pDirEntry->cbName + 1 /* dir slash */ >= RTPATH_MAX)
|
---|
[19211] | 74 | {
|
---|
[27246] | 75 | rc = VERR_FILENAME_TOO_LONG;
|
---|
| 76 | break;
|
---|
| 77 | }
|
---|
| 78 | memcpy(&pszBuf[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
|
---|
[19211] | 79 |
|
---|
[27246] | 80 | /* Deal with the unknown type. */
|
---|
| 81 | if (pDirEntry->enmType == RTDIRENTRYTYPE_UNKNOWN)
|
---|
| 82 | {
|
---|
| 83 | rc = RTPathQueryInfoEx(pszBuf, pObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
| 84 | if (RT_SUCCESS(rc) && RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
|
---|
| 85 | pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
|
---|
| 86 | else if (RT_SUCCESS(rc) && RTFS_IS_FILE(pObjInfo->Attr.fMode))
|
---|
| 87 | pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
|
---|
| 88 | else if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(pObjInfo->Attr.fMode))
|
---|
| 89 | pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
|
---|
| 90 | }
|
---|
[19211] | 91 |
|
---|
[27246] | 92 | /* Try the delete the fs object. */
|
---|
| 93 | switch (pDirEntry->enmType)
|
---|
| 94 | {
|
---|
| 95 | case RTDIRENTRYTYPE_FILE:
|
---|
| 96 | rc = RTFileDelete(pszBuf);
|
---|
| 97 | break;
|
---|
[19211] | 98 |
|
---|
[27246] | 99 | case RTDIRENTRYTYPE_DIRECTORY:
|
---|
| 100 | {
|
---|
| 101 | size_t cchSubDir = cchDir + pDirEntry->cbName;
|
---|
| 102 | pszBuf[cchSubDir++] = '/';
|
---|
| 103 | pszBuf[cchSubDir] = '\0';
|
---|
| 104 | rc = rtDirRemoveRecursiveSub(pszBuf, cchSubDir, pDirEntry, pObjInfo);
|
---|
| 105 | if (RT_SUCCESS(rc))
|
---|
| 106 | {
|
---|
| 107 | pszBuf[cchSubDir] = '\0';
|
---|
| 108 | rc = RTDirRemove(pszBuf);
|
---|
| 109 | }
|
---|
| 110 | break;
|
---|
[19211] | 111 | }
|
---|
| 112 |
|
---|
[27246] | 113 | //case RTDIRENTRYTYPE_SYMLINK:
|
---|
[39612] | 114 | // rc = RTSymlinkDelete(pszBuf, 0);
|
---|
[27246] | 115 | // break;
|
---|
| 116 |
|
---|
| 117 | default:
|
---|
| 118 | /** @todo not implemented yet. */
|
---|
| 119 | rc = VINF_SUCCESS;
|
---|
| 120 | break;
|
---|
[19211] | 121 | }
|
---|
| 122 | if (RT_FAILURE(rc))
|
---|
| 123 | break;
|
---|
| 124 | }
|
---|
[27246] | 125 | }
|
---|
| 126 | if (rc == VERR_NO_MORE_FILES)
|
---|
| 127 | rc = VINF_SUCCESS;
|
---|
[69753] | 128 | RTDirClose(hDir);
|
---|
[27246] | 129 | return rc;
|
---|
| 130 | }
|
---|
[19211] | 131 |
|
---|
[27246] | 132 |
|
---|
| 133 | RTDECL(int) RTDirRemoveRecursive(const char *pszPath, uint32_t fFlags)
|
---|
| 134 | {
|
---|
| 135 | AssertReturn(!(fFlags & ~RTDIRRMREC_F_VALID_MASK), VERR_INVALID_PARAMETER);
|
---|
| 136 |
|
---|
| 137 | /* Get an absolute path because this is easier to work with. */
|
---|
| 138 | /** @todo use RTPathReal here instead? */
|
---|
| 139 | char szAbsPath[RTPATH_MAX];
|
---|
| 140 | int rc = RTPathAbs(pszPath, szAbsPath, sizeof(szAbsPath));
|
---|
| 141 | if (RT_FAILURE(rc))
|
---|
| 142 | return rc;
|
---|
| 143 |
|
---|
| 144 | /* This API is not permitted applied to the root of anything. */
|
---|
| 145 | if (RTPathCountComponents(szAbsPath) <= 1)
|
---|
| 146 | return VERR_ACCESS_DENIED;
|
---|
| 147 |
|
---|
| 148 | /* Because of the above restriction, we never have to deal with the root
|
---|
| 149 | slash problem and can safely strip any trailing slashes and add a
|
---|
| 150 | definite one. */
|
---|
| 151 | RTPathStripTrailingSlash(szAbsPath);
|
---|
| 152 | size_t cchAbsPath = strlen(szAbsPath);
|
---|
| 153 | if (cchAbsPath + 1 >= RTPATH_MAX)
|
---|
| 154 | return VERR_FILENAME_TOO_LONG;
|
---|
| 155 | szAbsPath[cchAbsPath++] = '/';
|
---|
| 156 | szAbsPath[cchAbsPath] = 0;
|
---|
| 157 |
|
---|
| 158 | /* Check if it exists so we can return quietly if it doesn't. */
|
---|
| 159 | RTFSOBJINFO SharedObjInfoBuf;
|
---|
| 160 | rc = RTPathQueryInfoEx(szAbsPath, &SharedObjInfoBuf, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
|
---|
| 161 | if ( rc == VERR_PATH_NOT_FOUND
|
---|
| 162 | || rc == VERR_FILE_NOT_FOUND)
|
---|
| 163 | return VINF_SUCCESS;
|
---|
| 164 | if (RT_FAILURE(rc))
|
---|
| 165 | return rc;
|
---|
| 166 | if (!RTFS_IS_DIRECTORY(SharedObjInfoBuf.Attr.fMode))
|
---|
| 167 | return VERR_NOT_A_DIRECTORY;
|
---|
| 168 |
|
---|
| 169 | /* We're all set for the recursion now, so get going. */
|
---|
| 170 | RTDIRENTRY SharedDirEntryBuf;
|
---|
| 171 | rc = rtDirRemoveRecursiveSub(szAbsPath, cchAbsPath, &SharedDirEntryBuf, &SharedObjInfoBuf);
|
---|
| 172 |
|
---|
| 173 | /* Remove the specified directory if desired and removing the content was
|
---|
| 174 | successful. */
|
---|
| 175 | if ( RT_SUCCESS(rc)
|
---|
| 176 | && !(fFlags & RTDIRRMREC_F_CONTENT_ONLY))
|
---|
| 177 | {
|
---|
| 178 | szAbsPath[cchAbsPath] = 0;
|
---|
[21486] | 179 | rc = RTDirRemove(szAbsPath);
|
---|
[19211] | 180 | }
|
---|
| 181 | return rc;
|
---|
| 182 | }
|
---|
| 183 |
|
---|