VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/path/RTPathFindCommon.cpp.h

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 Author Date Id Revision
File size: 9.4 KB
Line 
1/* $Id: RTPathFindCommon.cpp.h 98103 2023-01-17 14:15:46Z vboxsync $ */
2/** @file
3 * IPRT - RTPathFindCommon - Code Template.
4 *
5 * This file included multiple times with different path style macros.
6 */
7
8/*
9 * Copyright (C) 2020-2023 Oracle and/or its affiliates.
10 *
11 * This file is part of VirtualBox base platform packages, as
12 * available from https://www.virtualbox.org.
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation, in version 3 of the
17 * License.
18 *
19 * This program is distributed in the hope that it will be useful, but
20 * WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, see <https://www.gnu.org/licenses>.
26 *
27 * The contents of this file may alternatively be used under the terms
28 * of the Common Development and Distribution License Version 1.0
29 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
30 * in the VirtualBox distribution, in which case the provisions of the
31 * CDDL are applicable instead of those of the GPL.
32 *
33 * You may elect to license modified versions of this file under the
34 * terms and conditions of either the GPL or the CDDL or both.
35 *
36 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
37 */
38
39#include "rtpath-root-length-template.cpp.h"
40
41
42/** Helper for skipping slashes, given a pointer to the first one. */
43DECLINLINE(const char *) RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(const char *pszSlash)
44{
45 for (;;)
46 {
47 char ch;
48 do
49 ch = *++pszSlash;
50 while (RTPATH_IS_SLASH(ch));
51
52 /* Also skip '/./' sequences. */
53 if ( ch != '.'
54 || !RTPATH_IS_SLASH(pszSlash[1]))
55 break;
56 pszSlash++;
57 }
58 return pszSlash;
59}
60
61
62static size_t RTPATH_STYLE_FN(rtPathFindCommon)(size_t cPaths, const char **papszPaths, uint32_t fFlags)
63{
64 /*
65 * Check for '..' elements before we start doing anything.
66 *
67 * They are currently not supported at all (lazy) and we shun them for
68 * security reasons. Iff we want to support them properly, we'd have to:
69 * 1. Note down exactly where the root specification ends for each of
70 * the paths so we can prevent '..' from messing with it.
71 * 2. When encountering '..', we'd have to ascend all paths.
72 * 3. When encountering a difference, we'd have to see if it's eliminated
73 * by a following '..' sequence.
74 * 4. When returning anything, we'd have to see if it could be affected by
75 * a '..' sequence later in any of the paths.
76 *
77 * We could kind of RTAbsPath the secondary paths, however it wouldn't work
78 * for the primary path we use as reference.
79 *
80 * Summa summarum: Annoyingly tedious, so just forget it.
81 */
82 if (!(fFlags & RTPATHFINDCOMMON_F_IGNORE_DOTDOT))
83 for (size_t i = 0; i < cPaths; i++)
84 {
85 const char * const psz = papszPaths[i];
86 const char *pszDot = strchr(psz, '.');
87 while (pszDot)
88 {
89 if ( pszDot[1] == '.'
90 && (RTPATH_IS_SLASH(pszDot[2]) || pszDot[2] == '\0')
91 && ( pszDot == psz
92 || RTPATH_IS_SLASH(pszDot[-1])
93#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
94 || (pszDot[-1] == ':' && psz + 2 == pszDot && !(fFlags & RTPATH_STR_F_NO_START))
95#endif
96 )
97 )
98 return 0;
99 pszDot = strchr(pszDot + 1, '.');
100 }
101 }
102
103 /*
104 * We use the first path as the reference for the return length.
105 */
106 const char * pszPath0 = papszPaths[0];
107 const char * pszPath0EndLastComp = pszPath0;
108 const char * const pszPath0Start = pszPath0;
109
110 /*
111 * Deal with root stuff as appropriate.
112 */
113 if (fFlags & RTPATH_STR_F_NO_START)
114 {
115 /* We ignore leading slashes when RTPATH_STR_F_NO_START is specified: */
116 for (size_t i = 0; i < cPaths; i++)
117 {
118 const char *psz = papszPaths[i];
119 papszPaths[i] = RTPATH_IS_SLASH(*psz) ? RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(psz) : psz;
120 }
121 pszPath0EndLastComp = pszPath0 = papszPaths[0];
122 }
123#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
124 else if (RTPATH_IS_SLASH(pszPath0[0]))
125 {
126 /* UNC requires a little bit of special magic to make sure we have
127 exactly two slashes in each path and don't mix things up. */
128 char ch;
129 if ( RTPATH_IS_SLASH(pszPath0[1])
130 && (ch = pszPath0[2]) != '\0'
131 && !RTPATH_IS_SLASH(ch))
132 {
133 pszPath0 += 2;
134 for (size_t i = 1; i < cPaths; i++)
135 {
136 const char *psz = papszPaths[i];
137 if ( RTPATH_IS_SLASH(psz[0])
138 && RTPATH_IS_SLASH(psz[1])
139 && (ch = psz[2]) != '\0'
140 && !RTPATH_IS_SLASH(ch))
141 papszPaths[i] = psz + 2;
142 else
143 return 0;
144 }
145 }
146 else
147 {
148 for (size_t i = 1; i < cPaths; i++)
149 {
150 const char *psz = papszPaths[i];
151 if ( RTPATH_IS_SLASH(psz[0])
152 && RTPATH_IS_SLASH(psz[1])
153 && (ch = psz[2]) != '\0'
154 && !RTPATH_IS_SLASH(ch))
155 return 0;
156 if (!RTPATH_IS_SLASH(psz[0]))
157 return 0;
158 papszPaths[i] = RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(psz);
159 }
160 pszPath0EndLastComp = pszPath0 = RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(pszPath0);
161 }
162 }
163 /* Skip past the drive letter if there is one, as that eliminates the need
164 to handle ':' in the main loop below. */
165 else if ( RT_C_IS_ALPHA(pszPath0[0])
166 && pszPath0[1] == ':')
167 {
168 /* Drive letter part first: */
169 char const chDrv = RT_C_TO_UPPER(pszPath0[0]);
170 pszPath0 += 2;
171 pszPath0EndLastComp = pszPath0;
172
173 for (size_t i = 1; i < cPaths; i++)
174 {
175 const char *psz = papszPaths[i];
176 if ( ( psz[0] != chDrv
177 && RT_C_TO_UPPER(psz[0]) != chDrv)
178 || psz[1] != ':')
179 return 0;
180 papszPaths[i] = psz + 2;
181 }
182
183 /* Subsequent slashes or lack thereof. */
184 if (RTPATH_IS_SLASH(*pszPath0))
185 {
186 for (size_t i = 1; i < cPaths; i++)
187 {
188 const char *psz = papszPaths[i];
189 if (!RTPATH_IS_SLASH(*psz))
190 return pszPath0EndLastComp - pszPath0Start;
191 papszPaths[i] = RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(psz);
192 }
193 pszPath0EndLastComp = pszPath0 = RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(pszPath0);
194 }
195 else
196 for (size_t i = 1; i < cPaths; i++)
197 if (RTPATH_IS_SLASH(*papszPaths[i]))
198 return pszPath0EndLastComp - pszPath0Start;
199 }
200#endif
201
202 /*
203 * Main compare loop.
204 */
205 for (;;)
206 {
207 RTUNICP uc0;
208 int rc = RTStrGetCpEx(&pszPath0, &uc0);
209 AssertRCReturn(rc, 0);
210 if (!RTPATH_IS_SLASH(uc0))
211 {
212 if (uc0 != 0)
213 {
214 for (size_t i = 1; i < cPaths; i++)
215 {
216 RTUNICP uc;
217 rc = RTStrGetCpEx(&papszPaths[i], &uc);
218 AssertRCReturn(rc, 0);
219 if (uc == uc0)
220 { /* likely */}
221#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
222 else if ( RTUniCpToUpper(uc) == RTUniCpToUpper(uc0)
223 || RTUniCpToLower(uc) == RTUniCpToLower(uc0))
224 { /* less likely */}
225#endif
226 else
227 return pszPath0EndLastComp - pszPath0Start;
228 }
229 }
230 else
231 {
232 /* pszPath0 is at an end. Check the state of the others as we must
233 return the whole pszPath0 length if their are also at the end of
234 at a slash. */
235 for (size_t i = 1; i < cPaths; i++)
236 {
237 char ch = *papszPaths[i];
238 if ( ch != '\0'
239 && !RTPATH_IS_SLASH(ch))
240 return pszPath0EndLastComp - pszPath0Start;
241 }
242 return pszPath0 - 1 - pszPath0Start;
243 }
244 }
245 else
246 {
247 /* pszPath0 is at a slash. Check whether all the other are too or are at
248 the end of the string. If any other string ends here, we can return
249 the length up to but not including the slash. */
250 bool fDone = false;
251 for (size_t i = 1; i < cPaths; i++)
252 {
253 char ch = *papszPaths[i];
254 if (ch == '\0')
255 fDone = true;
256 else if (RTPATH_IS_SLASH(ch))
257 papszPaths[i] = RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(papszPaths[i]);
258 else
259 return pszPath0EndLastComp - pszPath0Start;
260 }
261 if (fDone)
262 return pszPath0 - pszPath0Start;
263 pszPath0EndLastComp = pszPath0 = RTPATH_STYLE_FN(rtPathHlpSkipSlashes)(pszPath0 - 1);
264 }
265 }
266}
267
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use