VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp@ 76595

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

IPRT: Attempted to address some the more obvious shortcomings of RTPathCalcRelative. Had to add a parameter that clearifies whether the from path is a file (VHD usage) or directory (rest). [scm fix]

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.9 KB
Line 
1/* $Id: RTPathCalcRelative.cpp 76595 2019-01-01 22:25:16Z vboxsync $ */
2/** @file
3 * IPRT - RTPathCreateRelative.
4 */
5
6/*
7 * Copyright (C) 2013-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#include "internal/iprt.h"
32#include <iprt/path.h>
33
34#include <iprt/assert.h>
35#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
36# include <iprt/ctype.h>
37#endif
38#include <iprt/errcore.h>
39#include <iprt/string.h>
40#include "internal/path.h"
41
42
43
44RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
45 const char *pszPathFrom, bool fFromFile,
46 const char *pszPathTo)
47{
48 AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER);
49 AssertReturn(cbPathDst, VERR_INVALID_PARAMETER);
50 AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER);
51 AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER);
52
53 /*
54 * Check for different root specifiers (drive letters), creating a relative path doesn't work here.
55 */
56 size_t offRootFrom = rtPathRootSpecLen(pszPathFrom);
57 AssertReturn(offRootFrom > 0, VERR_INVALID_PARAMETER);
58
59 size_t offRootTo = rtPathRootSpecLen(pszPathTo);
60 AssertReturn(offRootTo > 0, VERR_INVALID_PARAMETER);
61
62
63 /** @todo correctly deal with extra root slashes! */
64 if (offRootFrom != offRootTo)
65 return VERR_NOT_SUPPORTED;
66
67#if RTPATH_STYLE != RTPATH_STR_F_STYLE_DOS
68 if (RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom))
69 return VERR_NOT_SUPPORTED;
70#else
71 if (RTStrNICmp(pszPathFrom, pszPathTo, offRootFrom))
72 for (size_t off = 0; off < offRootFrom; off++)
73 {
74 char const chFrom = pszPathFrom[off];
75 char const chTo = pszPathTo[off];
76 if ( chFrom != chTo
77 && RT_C_TO_LOWER(chFrom) != RT_C_TO_LOWER(chTo) /** @todo proper case insensitivity! */
78 && (!RTPATH_IS_SLASH(chFrom) || !RTPATH_IS_SLASH(chTo)) )
79 return VERR_NOT_SUPPORTED;
80 }
81#endif
82
83 pszPathFrom += offRootFrom;
84 pszPathTo += offRootTo;
85
86 /*
87 * Skip out the part of the path which is equal to both.
88 */
89 const char *pszStartOfFromComp = pszPathFrom;
90 for (;;)
91 {
92 char const chFrom = *pszPathFrom;
93 char const chTo = *pszPathTo;
94 if (!RTPATH_IS_SLASH(chFrom))
95 {
96 if (chFrom == chTo)
97 {
98 if (chFrom)
99 { /* likely */ }
100 else
101 {
102 /* Special case: The two paths are equal. */
103 if (fFromFile)
104 {
105 size_t cchComp = pszPathFrom - pszStartOfFromComp;
106 if (cchComp < cbPathDst)
107 {
108 memcpy(pszPathDst, pszStartOfFromComp, cchComp);
109 pszPathDst[cchComp] = '\0';
110 return VINF_SUCCESS;
111 }
112 }
113 else if (sizeof(".") <= cbPathDst)
114 {
115 memcpy(pszPathDst, ".", sizeof("."));
116 return VINF_SUCCESS;
117 }
118 return VERR_BUFFER_OVERFLOW;
119 }
120 }
121#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
122 else if (RT_C_TO_LOWER(chFrom) == RT_C_TO_LOWER(chTo))
123 { /* if not likely, then simpler code structure wise. */ }
124#endif
125 else if (chFrom != '\0' || !RTPATH_IS_SLASH(chTo) || fFromFile)
126 break;
127 else
128 {
129 pszStartOfFromComp = pszPathFrom;
130 do
131 pszPathTo++;
132 while (RTPATH_IS_SLASH(*pszPathTo));
133 break;
134 }
135 pszPathFrom++;
136 pszPathTo++;
137 }
138 else if (RTPATH_IS_SLASH(chTo))
139 {
140 /* Both have slashes. Skip any additional ones before taking down
141 the start of the component for rewinding purposes. */
142 do
143 pszPathTo++;
144 while (RTPATH_IS_SLASH(*pszPathTo));
145 do
146 pszPathFrom++;
147 while (RTPATH_IS_SLASH(*pszPathFrom));
148 pszStartOfFromComp = pszPathFrom;
149 }
150 else
151 break;
152 }
153
154 /* Rewind to the start of the current component. */
155 pszPathTo -= pszPathFrom - pszStartOfFromComp;
156 pszPathFrom = pszStartOfFromComp;
157
158 /* Paths point to the first non equal component now. */
159
160 /*
161 * Constructure the relative path.
162 */
163
164 /* Create the part to go up from pszPathFrom. */
165 unsigned offDst = 0;
166
167 if (!fFromFile && *pszPathFrom != '\0')
168 {
169 if (offDst + 3 < cbPathDst)
170 {
171 pszPathDst[offDst++] = '.';
172 pszPathDst[offDst++] = '.';
173 pszPathDst[offDst++] = RTPATH_SLASH;
174 }
175 else
176 return VERR_BUFFER_OVERFLOW;
177 }
178
179 while (*pszPathFrom != '\0')
180 {
181 char ch;
182 while ( (ch = *pszPathFrom) != '\0'
183 && !RTPATH_IS_SLASH(*pszPathFrom))
184 pszPathFrom++;
185 while ( (ch = *pszPathFrom) != '\0'
186 && RTPATH_IS_SLASH(ch))
187 pszPathFrom++;
188 if (!ch)
189 break;
190
191 if (offDst + 3 < cbPathDst)
192 {
193 pszPathDst[offDst++] = '.';
194 pszPathDst[offDst++] = '.';
195 pszPathDst[offDst++] = RTPATH_SLASH;
196 }
197 else
198 return VERR_BUFFER_OVERFLOW;
199 }
200
201 /* Now append the rest of pszPathTo to the final path. */
202 size_t cchTo = strlen(pszPathTo);
203 if (offDst + cchTo <= cbPathDst)
204 {
205 memcpy(&pszPathDst[offDst], pszPathTo, cchTo);
206 pszPathDst[offDst + cchTo] = '\0';
207 return VINF_SUCCESS;
208 }
209 return VERR_BUFFER_OVERFLOW;
210}
211
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