VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/dir2.cpp

Last change on this file was 98103, checked in by vboxsync, 16 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 8.8 KB
Line 
1/* $Id: dir2.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Directory Manipulation, Part 2.
4 */
5
6/*
7 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_DIR
42#include <iprt/dir.h>
43#include "internal/iprt.h"
44
45#include <iprt/alloca.h>
46#include <iprt/assert.h>
47#include <iprt/file.h>
48#include <iprt/err.h>
49#include <iprt/log.h>
50#include <iprt/mem.h>
51#include <iprt/param.h>
52#include <iprt/path.h>
53#include <iprt/string.h>
54#include "internal/path.h"
55
56
57/**
58 * Recursion worker for RTDirRemoveRecursive.
59 *
60 * @returns IPRT status code.
61 * @param pszBuf The path buffer. Contains the abs path to the
62 * directory to recurse into. Trailing slash.
63 * @param cchDir The length of the directory we're recursing into,
64 * including the trailing slash.
65 * @param cbBuf Size of the buffer @a pszBuf points to.
66 * @param pDirEntry The dir entry buffer. (Shared to save stack.)
67 * @param pObjInfo The object info buffer. (ditto)
68 * @param fFlags RTDIRRMREC_F_XXX.
69 */
70static int rtDirRemoveRecursiveSub(char *pszBuf, size_t cchDir, size_t cbBuf, PRTDIRENTRY pDirEntry, PRTFSOBJINFO pObjInfo,
71 uint32_t fFlags)
72{
73 AssertReturn(RTPATH_IS_SLASH(pszBuf[cchDir - 1]), VERR_INTERNAL_ERROR_4);
74
75 /*
76 * Enumerate the directory content and dispose of it.
77 */
78 RTDIR hDir;
79 int rc = RTDirOpenFiltered(&hDir, pszBuf, RTDIRFILTER_NONE, fFlags & RTDIRRMREC_F_NO_ABS_PATH ? RTDIR_F_NO_ABS_PATH : 0);
80 if (RT_FAILURE(rc))
81 return rc;
82 while (RT_SUCCESS(rc = RTDirRead(hDir, pDirEntry, NULL)))
83 {
84 if (!RTDirEntryIsStdDotLink(pDirEntry))
85 {
86 /* Construct the full name of the entry. */
87 if (cchDir + pDirEntry->cbName + 1 /* dir slash */ >= cbBuf)
88 {
89 rc = VERR_FILENAME_TOO_LONG;
90 break;
91 }
92 memcpy(&pszBuf[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);
93
94 /* Deal with the unknown type. */
95 if (pDirEntry->enmType == RTDIRENTRYTYPE_UNKNOWN)
96 {
97 rc = RTPathQueryInfoEx(pszBuf, pObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
98 if (RT_SUCCESS(rc) && RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
99 pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
100 else if (RT_SUCCESS(rc) && RTFS_IS_FILE(pObjInfo->Attr.fMode))
101 pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
102 else if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(pObjInfo->Attr.fMode))
103 pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
104 }
105
106 /* Try the delete the fs object. */
107 switch (pDirEntry->enmType)
108 {
109 case RTDIRENTRYTYPE_FILE:
110 rc = RTFileDelete(pszBuf);
111 break;
112
113 case RTDIRENTRYTYPE_DIRECTORY:
114 {
115 size_t cchSubDir = cchDir + pDirEntry->cbName;
116 pszBuf[cchSubDir++] = '/';
117 pszBuf[cchSubDir] = '\0';
118 rc = rtDirRemoveRecursiveSub(pszBuf, cchSubDir, cbBuf, pDirEntry, pObjInfo, fFlags);
119 if (RT_SUCCESS(rc))
120 {
121 pszBuf[cchSubDir] = '\0';
122 rc = RTDirRemove(pszBuf);
123 }
124 break;
125 }
126
127 //case RTDIRENTRYTYPE_SYMLINK:
128 // rc = RTSymlinkDelete(pszBuf, 0);
129 // break;
130
131 default:
132 /** @todo not implemented yet. */
133 rc = VINF_SUCCESS;
134 break;
135 }
136 if (RT_FAILURE(rc))
137 break;
138 }
139 }
140 if (rc == VERR_NO_MORE_FILES)
141 rc = VINF_SUCCESS;
142 RTDirClose(hDir);
143 return rc;
144}
145
146
147RTDECL(int) RTDirRemoveRecursive(const char *pszPath, uint32_t fFlags)
148{
149 AssertReturn(!(fFlags & ~RTDIRRMREC_F_VALID_MASK), VERR_INVALID_PARAMETER);
150
151 /*
152 * Allocate path buffer.
153 */
154 char *pszAbsPath;
155 size_t cbAbsPathBuf = RTPATH_BIG_MAX;
156 char *pszAbsPathFree = pszAbsPath = (char *)RTMemTmpAlloc(cbAbsPathBuf);
157 if (!pszAbsPath)
158 {
159 cbAbsPathBuf = RTPATH_MAX;
160 pszAbsPath = (char *)alloca(RTPATH_MAX);
161 }
162
163 /*
164 * Get an absolute path because this is easier to work with and
165 * eliminates any races with changing CWD.
166 */
167 int rc;
168 if (!(fFlags & RTDIRRMREC_F_NO_ABS_PATH))
169 rc = RTPathAbs(pszPath, pszAbsPath, cbAbsPathBuf);
170 else if (*pszPath != '\0')
171 rc = RTStrCopy(pszAbsPath, cbAbsPathBuf, pszPath);
172 else
173 rc = VERR_PATH_ZERO_LENGTH;
174 if (RT_SUCCESS(rc))
175 {
176 /*
177 * This API is not permitted applied to the root of anything.
178 */
179 union
180 {
181 RTPATHPARSED Parsed;
182 uint8_t abParsed[RTPATHPARSED_MIN_SIZE];
183 } uBuf;
184 RTPathParse(pszPath, &uBuf.Parsed, sizeof(uBuf), RTPATH_STR_F_STYLE_HOST);
185 if ( uBuf.Parsed.cComps <= 1
186 && (uBuf.Parsed.fProps & RTPATH_PROP_ROOT_SLASH))
187 rc = VERR_ACCESS_DENIED;
188 else
189 {
190 /*
191 * Because of the above restriction, we never have to deal with the root
192 * slash problem and can safely strip any trailing slashes and add a
193 * definite one.
194 */
195 RTPathStripTrailingSlash(pszAbsPath);
196 size_t cchAbsPath = strlen(pszAbsPath);
197 if (cchAbsPath + 1 < cbAbsPathBuf)
198 {
199 pszAbsPath[cchAbsPath++] = RTPATH_SLASH;
200 pszAbsPath[cchAbsPath] = '\0';
201
202 /*
203 * Check if it exists so we can return quietly if it doesn't.
204 */
205 RTFSOBJINFO SharedObjInfoBuf;
206 rc = RTPathQueryInfoEx(pszAbsPath, &SharedObjInfoBuf, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
207 if ( rc == VERR_PATH_NOT_FOUND
208 || rc == VERR_FILE_NOT_FOUND)
209 rc = VINF_SUCCESS;
210 else if ( RT_SUCCESS(rc)
211 && RTFS_IS_DIRECTORY(SharedObjInfoBuf.Attr.fMode))
212 {
213 /*
214 * We're all set for the recursion now, so get going.
215 */
216 RTDIRENTRY SharedDirEntryBuf;
217 rc = rtDirRemoveRecursiveSub(pszAbsPath, cchAbsPath, cbAbsPathBuf,
218 &SharedDirEntryBuf, &SharedObjInfoBuf, fFlags);
219
220 /*
221 * Remove the specified directory if desired and removing the content was successful.
222 */
223 if ( RT_SUCCESS(rc)
224 && !(fFlags & RTDIRRMREC_F_CONTENT_ONLY))
225 {
226 pszAbsPath[cchAbsPath] = 0;
227 rc = RTDirRemove(pszAbsPath);
228 }
229 }
230 else if (RT_SUCCESS(rc))
231 rc = VERR_NOT_A_DIRECTORY;
232
233 }
234 else
235 rc = VERR_FILENAME_TOO_LONG;
236 }
237 }
238 if (pszAbsPathFree)
239 RTMemTmpFree(pszAbsPathFree);
240 return rc;
241}
242
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use