VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/generic/dirrel-r3-generic.cpp@ 98278

Last change on this file since 98278 was 98103, checked in by vboxsync, 2 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 19.1 KB
Line 
1/* $Id: dirrel-r3-generic.cpp 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - Directory relative base APIs, generic implementation.
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/assert.h>
46#include <iprt/file.h>
47#include <iprt/err.h>
48#include <iprt/path.h>
49#include <iprt/string.h>
50#include <iprt/symlink.h>
51#define RTDIR_AGNOSTIC
52#include "internal/dir.h"
53
54
55
56/**
57 * Helper that builds a full path for a directory relative path.
58 *
59 * @returns IPRT status code.
60 * @param pThis The directory.
61 * @param pszPathDst The destination buffer.
62 * @param cbPathDst The size of the destination buffer.
63 * @param pszRelPath The relative path.
64 */
65static int rtDirRelBuildFullPath(PRTDIRINTERNAL pThis, char *pszPathDst, size_t cbPathDst, const char *pszRelPath)
66{
67 AssertMsgReturn(!RTPathStartsWithRoot(pszRelPath), ("pszRelPath='%s'\n", pszRelPath), VERR_PATH_IS_NOT_RELATIVE);
68
69 /*
70 * Let's hope we can avoid checking for ascension.
71 *
72 * Note! We don't take symbolic links into account here. That can be
73 * done later if desired.
74 */
75 if ( !(pThis->fFlags & RTDIR_F_DENY_ASCENT)
76 || strstr(pszRelPath, "..") == NULL)
77 {
78 size_t const cchRelPath = strlen(pszRelPath);
79 size_t const cchDirPath = pThis->cchPath;
80 if (cchDirPath + cchRelPath < cbPathDst)
81 {
82 memcpy(pszPathDst, pThis->pszPath, cchDirPath);
83 memcpy(&pszPathDst[cchDirPath], pszRelPath, cchRelPath);
84 pszPathDst[cchDirPath + cchRelPath] = '\0';
85 return VINF_SUCCESS;
86 }
87 return VERR_FILENAME_TOO_LONG;
88 }
89
90 /*
91 * Calc the absolute path using the directory as a base, then check if the result
92 * still starts with the full directory path.
93 *
94 * This ASSUMES that pThis->pszPath is an absolute path.
95 */
96 int rc = RTPathAbsEx(pThis->pszPath, pszRelPath, RTPATH_STR_F_STYLE_HOST, pszPathDst, &cbPathDst);
97 if (RT_SUCCESS(rc))
98 {
99 if (RTPathStartsWith(pszPathDst, pThis->pszPath))
100 return VINF_SUCCESS;
101 return VERR_PATH_NOT_FOUND;
102 }
103 return rc;
104}
105
106
107/*
108 *
109 *
110 * RTFile stuff.
111 * RTFile stuff.
112 * RTFile stuff.
113 *
114 *
115 */
116
117
118
119
120/**
121 * Open a file relative to @a hDir.
122 *
123 * @returns IPRT status code.
124 * @param hDir The directory to open relative to.
125 * @param pszRelFilename The relative path to the file.
126 * @param fOpen Open flags, i.e a combination of the RTFILE_O_XXX
127 * defines. The ACCESS, ACTION and DENY flags are
128 * mandatory!
129 * @param phFile Where to store the handle to the opened file.
130 *
131 * @sa RTFileOpen
132 */
133RTDECL(int) RTDirRelFileOpen(RTDIR hDir, const char *pszRelFilename, uint64_t fOpen, PRTFILE phFile)
134{
135 PRTDIRINTERNAL pThis = hDir;
136 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
137 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
138
139 char szPath[RTPATH_MAX];
140 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelFilename);
141 if (RT_SUCCESS(rc))
142 rc = RTFileOpen(phFile, szPath, fOpen);
143 return rc;
144}
145
146
147
148/*
149 *
150 *
151 * RTDir stuff.
152 * RTDir stuff.
153 * RTDir stuff.
154 *
155 *
156 */
157
158
159
160/**
161 * Opens a directory relative to @a hDir.
162 *
163 * @returns IPRT status code.
164 * @param hDir The directory to open relative to.
165 * @param pszDir The relative path to the directory to open.
166 * @param phDir Where to store the directory handle.
167 *
168 * @sa RTDirOpen
169 */
170RTDECL(int) RTDirRelDirOpen(RTDIR hDir, const char *pszDir, RTDIR *phDir)
171{
172 PRTDIRINTERNAL pThis = hDir;
173 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
174 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
175
176 char szPath[RTPATH_MAX];
177 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszDir);
178 if (RT_SUCCESS(rc))
179 rc = RTDirOpen(phDir, szPath);
180 return rc;
181
182}
183
184
185/**
186 * Opens a directory relative to @a hDir, with flags and optional filtering.
187 *
188 * @returns IPRT status code.
189 * @param hDir The directory to open relative to.
190 * @param pszDirAndFilter The relative path to the directory to search, this
191 * must include wildcards.
192 * @param enmFilter The kind of filter to apply. Setting this to
193 * RTDIRFILTER_NONE makes this function behave like
194 * RTDirOpen.
195 * @param fFlags Open flags, RTDIR_F_XXX.
196 * @param phDir Where to store the directory handle.
197 *
198 * @sa RTDirOpenFiltered
199 */
200RTDECL(int) RTDirRelDirOpenFiltered(RTDIR hDir, const char *pszDirAndFilter, RTDIRFILTER enmFilter,
201 uint32_t fFlags, RTDIR *phDir)
202{
203 PRTDIRINTERNAL pThis = hDir;
204 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
205 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
206
207 char szPath[RTPATH_MAX];
208 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszDirAndFilter);
209 if (RT_SUCCESS(rc))
210 rc = RTDirOpenFiltered(phDir, szPath, enmFilter, fFlags);
211 return rc;
212}
213
214
215/**
216 * Creates a directory relative to @a hDir.
217 *
218 * @returns IPRT status code.
219 * @param hDir The directory @a pszRelPath is relative to.
220 * @param pszRelPath The relative path to the directory to create.
221 * @param fMode The mode of the new directory.
222 * @param fCreate Create flags, RTDIRCREATE_FLAGS_XXX.
223 * @param phSubDir Where to return the handle of the created directory.
224 * Optional.
225 *
226 * @sa RTDirCreate
227 */
228RTDECL(int) RTDirRelDirCreate(RTDIR hDir, const char *pszRelPath, RTFMODE fMode, uint32_t fCreate, RTDIR *phSubDir)
229{
230 PRTDIRINTERNAL pThis = hDir;
231 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
232 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
233
234 char szPath[RTPATH_MAX];
235 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath);
236 if (RT_SUCCESS(rc))
237 {
238 rc = RTDirCreate(szPath, fMode, fCreate);
239 if (RT_SUCCESS(rc) && phSubDir)
240 rc = RTDirOpen(phSubDir, szPath);
241 }
242 return rc;
243}
244
245
246/**
247 * Removes a directory relative to @a hDir if empty.
248 *
249 * @returns IPRT status code.
250 * @param hDir The directory @a pszRelPath is relative to.
251 * @param pszRelPath The relative path to the directory to remove.
252 *
253 * @sa RTDirRemove
254 */
255RTDECL(int) RTDirRelDirRemove(RTDIR hDir, const char *pszRelPath)
256{
257 PRTDIRINTERNAL pThis = hDir;
258 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
259 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
260
261 char szPath[RTPATH_MAX];
262 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath);
263 if (RT_SUCCESS(rc))
264 rc = RTDirRemove(szPath);
265 return rc;
266}
267
268
269/*
270 *
271 * RTPath stuff.
272 * RTPath stuff.
273 * RTPath stuff.
274 *
275 *
276 */
277
278
279/**
280 * Query information about a file system object relative to @a hDir.
281 *
282 * @returns IPRT status code.
283 * @retval VINF_SUCCESS if the object exists, information returned.
284 * @retval VERR_PATH_NOT_FOUND if any but the last component in the specified
285 * path was not found or was not a directory.
286 * @retval VERR_FILE_NOT_FOUND if the object does not exist (but path to the
287 * parent directory exists).
288 *
289 * @param hDir The directory @a pszRelPath is relative to.
290 * @param pszRelPath The relative path to the file system object.
291 * @param pObjInfo Object information structure to be filled on successful
292 * return.
293 * @param enmAddAttr Which set of additional attributes to request.
294 * Use RTFSOBJATTRADD_NOTHING if this doesn't matter.
295 * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
296 *
297 * @sa RTPathQueryInfoEx
298 */
299RTDECL(int) RTDirRelPathQueryInfo(RTDIR hDir, const char *pszRelPath, PRTFSOBJINFO pObjInfo,
300 RTFSOBJATTRADD enmAddAttr, uint32_t fFlags)
301{
302 PRTDIRINTERNAL pThis = hDir;
303 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
304 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
305
306 char szPath[RTPATH_MAX];
307 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath);
308 if (RT_SUCCESS(rc))
309 rc = RTPathQueryInfoEx(szPath, pObjInfo, enmAddAttr, fFlags);
310 return rc;
311}
312
313
314/**
315 * Changes the mode flags of a file system object relative to @a hDir.
316 *
317 * The API requires at least one of the mode flag sets (Unix/Dos) to
318 * be set. The type is ignored.
319 *
320 * @returns IPRT status code.
321 * @param hDir The directory @a pszRelPath is relative to.
322 * @param pszRelPath The relative path to the file system object.
323 * @param fMode The new file mode, see @ref grp_rt_fs for details.
324 * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
325 *
326 * @sa RTPathSetMode
327 */
328RTDECL(int) RTDirRelPathSetMode(RTDIR hDir, const char *pszRelPath, RTFMODE fMode, uint32_t fFlags)
329{
330 PRTDIRINTERNAL pThis = hDir;
331 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
332 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
333 AssertMsgReturn(RTPATH_F_IS_VALID(fFlags, 0), ("%#x\n", fFlags), VERR_INVALID_FLAGS);
334
335 char szPath[RTPATH_MAX];
336 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath);
337 if (RT_SUCCESS(rc))
338 {
339#ifndef RT_OS_WINDOWS
340 rc = RTPathSetMode(szPath, fMode); /** @todo fFlags is currently ignored. */
341#else
342 rc = VERR_NOT_IMPLEMENTED; /** @todo implement RTPathSetMode on windows. */
343 RT_NOREF(fMode);
344#endif
345 }
346 return rc;
347}
348
349
350/**
351 * Changes one or more of the timestamps associated of file system object
352 * relative to @a hDir.
353 *
354 * @returns IPRT status code.
355 * @param hDir The directory @a pszRelPath is relative to.
356 * @param pszRelPath The relative path to the file system object.
357 * @param pAccessTime Pointer to the new access time.
358 * @param pModificationTime Pointer to the new modification time.
359 * @param pChangeTime Pointer to the new change time. NULL if not to be changed.
360 * @param pBirthTime Pointer to the new time of birth. NULL if not to be changed.
361 * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
362 *
363 * @remark The file system might not implement all these time attributes,
364 * the API will ignore the ones which aren't supported.
365 *
366 * @remark The file system might not implement the time resolution
367 * employed by this interface, the time will be chopped to fit.
368 *
369 * @remark The file system may update the change time even if it's
370 * not specified.
371 *
372 * @remark POSIX can only set Access & Modification and will always set both.
373 *
374 * @sa RTPathSetTimesEx
375 */
376RTDECL(int) RTDirRelPathSetTimes(RTDIR hDir, const char *pszRelPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
377 PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime, uint32_t fFlags)
378{
379 PRTDIRINTERNAL pThis = hDir;
380 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
381 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
382
383 char szPath[RTPATH_MAX];
384 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath);
385 if (RT_SUCCESS(rc))
386 rc = RTPathSetTimesEx(szPath, pAccessTime, pModificationTime, pChangeTime, pBirthTime, fFlags);
387 return rc;
388}
389
390
391/**
392 * Changes the owner and/or group of a file system object relative to @a hDir.
393 *
394 * @returns IPRT status code.
395 * @param hDir The directory @a pszRelPath is relative to.
396 * @param pszRelPath The relative path to the file system object.
397 * @param uid The new file owner user id. Pass NIL_RTUID to leave
398 * this unchanged.
399 * @param gid The new group id. Pass NIL_RTGID to leave this
400 * unchanged.
401 * @param fFlags RTPATH_F_ON_LINK or RTPATH_F_FOLLOW_LINK.
402 *
403 * @sa RTPathSetOwnerEx
404 */
405RTDECL(int) RTDirRelPathSetOwner(RTDIR hDir, const char *pszRelPath, uint32_t uid, uint32_t gid, uint32_t fFlags)
406{
407 PRTDIRINTERNAL pThis = hDir;
408 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
409 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
410
411 char szPath[RTPATH_MAX];
412 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath);
413 if (RT_SUCCESS(rc))
414 {
415#ifndef RT_OS_WINDOWS
416 rc = RTPathSetOwnerEx(szPath, uid, gid, fFlags);
417#else
418 rc = VERR_NOT_IMPLEMENTED;
419 RT_NOREF(uid, gid, fFlags);
420#endif
421 }
422 return rc;
423}
424
425
426/**
427 * Renames a directory relative path within a filesystem.
428 *
429 * This will rename symbolic links. If RTPATHRENAME_FLAGS_REPLACE is used and
430 * pszDst is a symbolic link, it will be replaced and not its target.
431 *
432 * @returns IPRT status code.
433 * @param hDirSrc The directory the source path is relative to.
434 * @param pszSrc The source path, relative to @a hDirSrc.
435 * @param hDirDst The directory the destination path is relative to.
436 * @param pszDst The destination path, relative to @a hDirDst.
437 * @param fRename Rename flags, RTPATHRENAME_FLAGS_XXX.
438 *
439 * @sa RTPathRename
440 */
441RTDECL(int) RTDirRelPathRename(RTDIR hDirSrc, const char *pszSrc, RTDIR hDirDst, const char *pszDst, unsigned fRename)
442{
443 PRTDIRINTERNAL pThis = hDirSrc;
444 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
445 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
446
447 PRTDIRINTERNAL pThat = hDirDst;
448 if (pThat != pThis)
449 {
450 AssertPtrReturn(pThat, VERR_INVALID_HANDLE);
451 AssertReturn(pThat->u32Magic != RTDIR_MAGIC, VERR_INVALID_HANDLE);
452 }
453
454 char szSrcPath[RTPATH_MAX];
455 int rc = rtDirRelBuildFullPath(pThis, szSrcPath, sizeof(szSrcPath), pszSrc);
456 if (RT_SUCCESS(rc))
457 {
458 char szDstPath[RTPATH_MAX];
459 rc = rtDirRelBuildFullPath(pThis, szDstPath, sizeof(szDstPath), pszDst);
460 if (RT_SUCCESS(rc))
461 rc = RTPathRename(szSrcPath, szDstPath, fRename);
462 }
463 return rc;
464}
465
466
467/**
468 * Removes the last component of the directory relative path.
469 *
470 * @returns IPRT status code.
471 * @param hDir The directory @a pszRelPath is relative to.
472 * @param pszRelPath The relative path to the file system object.
473 * @param fUnlink Unlink flags, RTPATHUNLINK_FLAGS_XXX.
474 *
475 * @sa RTPathUnlink
476 */
477RTDECL(int) RTDirRelPathUnlink(RTDIR hDir, const char *pszRelPath, uint32_t fUnlink)
478{
479 PRTDIRINTERNAL pThis = hDir;
480 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
481 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
482
483 char szPath[RTPATH_MAX];
484 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszRelPath);
485 if (RT_SUCCESS(rc))
486 rc = RTPathUnlink(szPath, fUnlink);
487 return rc;
488}
489
490
491/*
492 *
493 * RTSymlink stuff.
494 * RTSymlink stuff.
495 * RTSymlink stuff.
496 *
497 *
498 */
499
500
501/**
502 * Creates a symbolic link (@a pszSymlink) relative to @a hDir targeting @a
503 * pszTarget.
504 *
505 * @returns IPRT status code.
506 * @param hDir The directory @a pszSymlink is relative to.
507 * @param pszSymlink The relative path of the symbolic link.
508 * @param pszTarget The path to the symbolic link target. This is
509 * relative to @a pszSymlink or an absolute path.
510 * @param enmType The symbolic link type. For Windows compatability
511 * it is very important to set this correctly. When
512 * RTSYMLINKTYPE_UNKNOWN is used, the API will try
513 * make a guess and may attempt query information
514 * about @a pszTarget in the process.
515 * @param fCreate Create flags, RTSYMLINKCREATE_FLAGS_XXX.
516 *
517 * @sa RTSymlinkCreate
518 */
519RTDECL(int) RTDirRelSymlinkCreate(RTDIR hDir, const char *pszSymlink, const char *pszTarget,
520 RTSYMLINKTYPE enmType, uint32_t fCreate)
521{
522 PRTDIRINTERNAL pThis = hDir;
523 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
524 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
525
526 char szPath[RTPATH_MAX];
527 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszSymlink);
528 if (RT_SUCCESS(rc))
529 rc = RTSymlinkCreate(szPath, pszTarget, enmType, fCreate);
530 return rc;
531}
532
533
534/**
535 * Read the symlink target relative to @a hDir.
536 *
537 * @returns IPRT status code.
538 * @retval VERR_NOT_SYMLINK if @a pszSymlink does not specify a symbolic link.
539 * @retval VERR_BUFFER_OVERFLOW if the link is larger than @a cbTarget. The
540 * buffer will contain what all we managed to read, fully terminated
541 * if @a cbTarget > 0.
542 *
543 * @param hDir The directory @a pszSymlink is relative to.
544 * @param pszSymlink The relative path to the symbolic link that should
545 * be read.
546 * @param pszTarget The target buffer.
547 * @param cbTarget The size of the target buffer.
548 * @param fRead Read flags, RTSYMLINKREAD_FLAGS_XXX.
549 *
550 * @sa RTSymlinkRead
551 */
552RTDECL(int) RTDirRelSymlinkRead(RTDIR hDir, const char *pszSymlink, char *pszTarget, size_t cbTarget, uint32_t fRead)
553{
554 PRTDIRINTERNAL pThis = hDir;
555 AssertPtrReturn(pThis, VERR_INVALID_HANDLE);
556 AssertReturn(pThis->u32Magic == RTDIR_MAGIC, VERR_INVALID_HANDLE);
557
558 char szPath[RTPATH_MAX];
559 int rc = rtDirRelBuildFullPath(pThis, szPath, sizeof(szPath), pszSymlink);
560 if (RT_SUCCESS(rc))
561 rc = RTSymlinkRead(szPath, pszTarget, cbTarget, fRead);
562 return rc;
563}
564
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