VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/path/RTPathAbsEx.cpp@ 84207

Last change on this file since 84207 was 82968, checked in by vboxsync, 5 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: 25.2 KB
Line 
1/* $Id: RTPathAbsEx.cpp 82968 2020-02-04 10:35:17Z vboxsync $ */
2/** @file
3 * IPRT - RTPathAbsEx and RTPathAbs.
4 */
5
6/*
7 * Copyright (C) 2019-2020 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#define LOG_GROUP RTLOGGROUP_PATH
32#include "internal/iprt.h"
33#include <iprt/path.h>
34
35#include <iprt/err.h>
36#include <iprt/ctype.h>
37#include <iprt/log.h>
38#include <iprt/mem.h>
39#include <iprt/param.h>
40#include <iprt/string.h>
41#include "internal/path.h"
42
43
44
45/**
46 * Ensures that the drive letter is capitalized (prereq: RTPATH_PROP_VOLUME).
47 */
48DECLINLINE(void) rtPathAbsExUpperCaseDriveLetter(char *pszAbsPath)
49{
50 AssertReturnVoid(pszAbsPath[1] == ':');
51 char ch = *pszAbsPath;
52 AssertReturnVoid(RT_C_IS_ALPHA(ch));
53 *pszAbsPath = RT_C_TO_UPPER(ch);
54}
55
56
57/**
58 * Common worker for relative paths.
59 *
60 * Uses RTPATHABS_F_STOP_AT_BASE for RTPATHABS_F_STOP_AT_CWD.
61 */
62static int rtPathAbsExWithCwdOrBaseCommon(const char *pszBase, size_t cchBaseInPlace, PRTPATHPARSED pBaseParsed,
63 const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags,
64 char *pszAbsPath, size_t *pcbAbsPath)
65{
66 AssertReturn(pBaseParsed->cComps > 0, VERR_INVALID_PARAMETER);
67
68 /*
69 * Clean up the base path first if necessary.
70 *
71 * Note! UNC tries to preserve the first two elements in the base path,
72 * unless it's a \\.\ or \\?\ prefix.
73 */
74 uint32_t const iBaseStop = (pBaseParsed->fProps & (RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC)) != RTPATH_PROP_UNC
75 || pBaseParsed->cComps < 2 ? 0 : 1;
76 uint32_t iBaseLast = iBaseStop;
77 if (pBaseParsed->fProps & (RTPATH_PROP_DOT_REFS | RTPATH_PROP_DOTDOT_REFS))
78 {
79 uint32_t const cComps = pBaseParsed->cComps;
80 uint32_t i = iBaseStop + 1;
81 while (i < cComps)
82 {
83 uint32_t const cchComp = pBaseParsed->aComps[i].cch;
84 if ( cchComp > 2
85 || pszPath[pBaseParsed->aComps[i].off] != '.'
86 || (cchComp == 2 && pszPath[pBaseParsed->aComps[i].off + 1] != '.') )
87 iBaseLast = i;
88 else
89 {
90 Assert(cchComp == 1 || cchComp == 2);
91 pBaseParsed->aComps[i].cch = 0;
92 if (cchComp == 2)
93 {
94 while (iBaseLast > 0 && pBaseParsed->aComps[iBaseLast].cch == 0)
95 iBaseLast--;
96 if (iBaseLast > iBaseStop)
97 {
98 Assert(pBaseParsed->aComps[iBaseLast].cch != 0);
99 pBaseParsed->aComps[iBaseLast].cch = 0;
100 iBaseLast--;
101 }
102 }
103 }
104 i++;
105 }
106 Assert(iBaseLast < cComps);
107 }
108 else
109 iBaseLast = pBaseParsed->cComps - 1;
110
111 /*
112 * Clean up the path next if needed.
113 */
114 int32_t iLast = -1; /* Is signed here! */
115 if (pParsed->fProps & (RTPATH_PROP_DOT_REFS | RTPATH_PROP_DOTDOT_REFS))
116 {
117 uint32_t const cComps = pParsed->cComps;
118 uint32_t i = 0;
119
120 /* If we have a volume specifier, take it from the base path. */
121 if (pParsed->fProps & RTPATH_PROP_VOLUME)
122 pParsed->aComps[i++].cch = 0;
123
124 while (i < cComps)
125 {
126 uint32_t const cchComp = pParsed->aComps[i].cch;
127 if ( cchComp > 2
128 || pszPath[pParsed->aComps[i].off] != '.'
129 || (cchComp == 2 && pszPath[pParsed->aComps[i].off + 1] != '.') )
130 iLast = i;
131 else
132 {
133 Assert(cchComp == 1 || cchComp == 2);
134 pParsed->aComps[i].cch = 0;
135 if (cchComp == 2)
136 {
137 while (iLast >= 0 && pParsed->aComps[iLast].cch == 0)
138 iLast--;
139 if (iLast >= 0)
140 {
141 Assert(pParsed->aComps[iLast].cch != 0);
142 pParsed->aComps[iLast].cch = 0;
143 iLast--;
144 }
145 else if ( iBaseLast > iBaseStop
146 && !(fFlags & RTPATHABS_F_STOP_AT_BASE))
147 {
148 while (iBaseLast > iBaseStop && pBaseParsed->aComps[iBaseLast].cch == 0)
149 iBaseLast--;
150 if (iBaseLast > iBaseStop)
151 {
152 Assert(pBaseParsed->aComps[iBaseLast].cch != 0);
153 pBaseParsed->aComps[iBaseLast].cch = 0;
154 iBaseLast--;
155 }
156 }
157 }
158 }
159 i++;
160 }
161 Assert(iLast < (int32_t)cComps);
162 }
163 else
164 {
165 /* If we have a volume specifier, take it from the base path. */
166 iLast = pParsed->cComps - 1;
167 if (pParsed->fProps & RTPATH_PROP_VOLUME)
168 {
169 pParsed->aComps[0].cch = 0;
170 if (iLast == 0)
171 iLast = -1;
172 }
173 }
174
175 /*
176 * Do we need a trailing slash in the base?
177 * If nothing is taken from pszPath, preserve its trailing slash,
178 * otherwise make sure there is a slash for joining the two.
179 */
180 Assert(!(pParsed->fProps & RTPATH_PROP_ROOT_SLASH));
181 if (pBaseParsed->cComps == 1)
182 {
183 AssertReturn(pBaseParsed->fProps & RTPATH_PROP_ROOT_SLASH, VERR_PATH_DOES_NOT_START_WITH_ROOT);
184 Assert(!(pBaseParsed->fProps & RTPATH_PROP_DIR_SLASH));
185 }
186 else
187 {
188 Assert(pBaseParsed->cComps > 1);
189 if ( iLast >= 0
190 || (pParsed->fProps & RTPATH_PROP_DIR_SLASH)
191 || (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH) )
192 pBaseParsed->fProps |= RTPATH_PROP_DIR_SLASH;
193 else
194 pBaseParsed->fProps &= ~RTPATH_PROP_DIR_SLASH;
195 }
196
197 /* Apply the trailing flash flag to the input path: */
198 if ( iLast >= 0
199 && (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH))
200 pParsed->fProps |= RTPATH_PROP_DIR_SLASH;
201
202 /*
203 * Combine the two. RTPathParsedReassemble can handle in place stuff, as
204 * long as the path doesn't grow.
205 */
206 int rc = RTPathParsedReassemble(pszBase, pBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, *pcbAbsPath);
207 if (RT_SUCCESS(rc))
208 {
209 if (pBaseParsed->fProps & RTPATH_PROP_VOLUME)
210 rtPathAbsExUpperCaseDriveLetter(pszAbsPath);
211
212 cchBaseInPlace = pBaseParsed->cchPath;
213 Assert(cchBaseInPlace == strlen(pszAbsPath));
214 if (iLast >= 0)
215 {
216 rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK,
217 &pszAbsPath[cchBaseInPlace], *pcbAbsPath - cchBaseInPlace);
218 if (RT_SUCCESS(rc))
219 {
220 *pcbAbsPath = cchBaseInPlace + pParsed->cchPath;
221 Assert(*pcbAbsPath == strlen(pszAbsPath));
222 }
223 else
224 *pcbAbsPath = cchBaseInPlace + pParsed->cchPath + 1;
225 }
226 else
227 *pcbAbsPath = cchBaseInPlace;
228 }
229 else if (rc == VERR_BUFFER_OVERFLOW)
230 {
231 if (iLast >= 0)
232 {
233 RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
234 *pcbAbsPath = pBaseParsed->cchPath + pParsed->cchPath + 1;
235 }
236 else
237 *pcbAbsPath = pBaseParsed->cchPath + 1;
238 }
239
240 return rc;
241}
242
243
244/**
245 * Handles the no-root-path scenario where we do CWD prefixing.
246 */
247static int rtPathAbsExWithCwd(const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
248{
249 /*
250 * Get the current directory and place it in the output buffer.
251 */
252 size_t cchInPlace;
253 size_t cbCwd = *pcbAbsPath;
254 char *pszCwdFree = NULL;
255 char *pszCwd = pszAbsPath;
256 int rc;
257 if ( !(fFlags & RTPATH_STR_F_STYLE_DOS)
258 || (pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH)) != RTPATH_PROP_VOLUME )
259 rc = RTPathGetCurrent(pszCwd, cbCwd);
260 else
261 rc = RTPathGetCurrentOnDrive(pszPath[0], pszCwd, cbCwd);
262 if (RT_SUCCESS(rc))
263 cchInPlace = strlen(pszCwd);
264 else if (rc == VERR_BUFFER_OVERFLOW)
265 {
266 /* Allocate a big temporary buffer so we can return the correct length
267 (the destination buffer might even be big enough if pszPath includes
268 sufficient '..' entries). */
269 cchInPlace = 0;
270 cbCwd = RT_MAX(cbCwd * 4, RTPATH_BIG_MAX);
271 pszCwdFree = pszCwd = (char *)RTMemTmpAlloc(cbCwd);
272 if (pszCwdFree)
273 {
274 if ( !(fFlags & RTPATH_STR_F_STYLE_DOS)
275 || (pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH)) != RTPATH_PROP_VOLUME )
276 rc = RTPathGetCurrent(pszCwd, cbCwd);
277 else
278 rc = RTPathGetCurrentOnDrive(pszPath[0], pszCwd, cbCwd);
279 if (RT_FAILURE(rc))
280 {
281 if (rc == VERR_BUFFER_OVERFLOW)
282 rc = VERR_FILENAME_TOO_LONG;
283 RTMemTmpFree(pszCwdFree);
284 return rc;
285 }
286 }
287 else
288 {
289 *pcbAbsPath = cbCwd + 1 + pParsed->cchPath + 1;
290 return rc;
291 }
292 }
293 else
294 return rc;
295
296 /*
297 * Parse the path.
298 */
299 union
300 {
301 RTPATHPARSED Parsed;
302 uint8_t abPadding[1024];
303 } uCwd;
304 PRTPATHPARSED pCwdParsedFree = NULL;
305 PRTPATHPARSED pCwdParsed = &uCwd.Parsed;
306 size_t cbCwdParsed = sizeof(uCwd);
307 rc = RTPathParse(pszCwd, pCwdParsed, cbCwdParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
308 if (RT_SUCCESS(rc))
309 { /* likely */ }
310 else if (rc == VERR_BUFFER_OVERFLOW)
311 {
312 cbCwdParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pCwdParsed->cComps + 2]);
313 pCwdParsedFree = pCwdParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbCwdParsed);
314 AssertReturnStmt(pCwdParsed, RTMemTmpFree(pszCwdFree), VERR_NO_TMP_MEMORY);
315 rc = RTPathParse(pszCwd, pCwdParsed, cbCwdParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
316 AssertRCReturnStmt(rc, RTMemTmpFree(pCwdParsedFree); RTMemTmpFree(pszCwdFree), rc);
317 }
318 else
319 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
320
321 /*
322 * Join paths with the base-path code.
323 */
324 if (fFlags & RTPATHABS_F_STOP_AT_CWD)
325 fFlags |= RTPATHABS_F_STOP_AT_BASE;
326 else
327 fFlags &= ~RTPATHABS_F_STOP_AT_BASE;
328 rc = rtPathAbsExWithCwdOrBaseCommon(pszCwd, cchInPlace, pCwdParsed, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
329 if (pCwdParsedFree)
330 RTMemTmpFree(pCwdParsedFree);
331 if (pszCwdFree)
332 RTMemTmpFree(pszCwdFree);
333 return rc;
334}
335
336
337/**
338 * Handles the no-root-path scenario where we've got a base path.
339 */
340static int rtPathAbsExWithBase(const char *pszBase, const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags,
341 char *pszAbsPath, size_t *pcbAbsPath)
342{
343 /*
344 * Parse the base path.
345 */
346 union
347 {
348 RTPATHPARSED Parsed;
349 uint8_t abPadding[1024];
350 } uBase;
351 PRTPATHPARSED pBaseParsedFree = NULL;
352 PRTPATHPARSED pBaseParsed = &uBase.Parsed;
353 size_t cbBaseParsed = sizeof(uBase);
354 int rc = RTPathParse(pszBase, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
355 if (RT_SUCCESS(rc))
356 { /* likely */ }
357 else if (rc == VERR_BUFFER_OVERFLOW)
358 {
359 cbBaseParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pBaseParsed->cComps + 2]);
360 pBaseParsedFree = pBaseParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbBaseParsed);
361 AssertReturn(pBaseParsed, VERR_NO_TMP_MEMORY);
362 rc = RTPathParse(pszBase, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
363 AssertRCReturnStmt(rc, RTMemTmpFree(pBaseParsedFree), rc);
364 }
365 else
366 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
367
368 /*
369 * If the base path isn't absolute, we need to deal with that.
370 */
371 size_t cchInPlace = 0;
372 if ((pBaseParsed->fProps & (RTPATH_PROP_ABSOLUTE | RTPATH_PROP_EXTRA_SLASHES | RTPATH_PROP_DOT_REFS)) == RTPATH_PROP_ABSOLUTE)
373 { /* likely */ }
374 else
375 {
376 cchInPlace = *pcbAbsPath;
377 rc = RTPathAbsEx(NULL, pszBase, fFlags, pszAbsPath, &cchInPlace);
378 if (RT_SUCCESS(rc))
379 {
380 Assert(strlen(pszAbsPath) == cchInPlace);
381 Assert(cchInPlace > 0);
382 }
383 else
384 {
385/** @todo Allocate temp buffer like we do for CWD? */
386 /* This is over generious, but don't want to put too much effort into it yet. */
387 if (rc == VERR_BUFFER_OVERFLOW)
388 *pcbAbsPath = cchInPlace + 1 + pParsed->cchPath + 1;
389 return rc;
390 }
391
392 /*
393 * Reparse it.
394 */
395 rc = RTPathParse(pszAbsPath, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
396 if (RT_SUCCESS(rc))
397 { /* likely */ }
398 else if (rc == VERR_BUFFER_OVERFLOW)
399 {
400 if (pBaseParsedFree)
401 RTMemTmpFree(pBaseParsedFree);
402 cbBaseParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pBaseParsed->cComps + 2]);
403 pBaseParsedFree = pBaseParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbBaseParsed);
404 AssertReturn(pBaseParsed, VERR_NO_TMP_MEMORY);
405 rc = RTPathParse(pszAbsPath, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
406 AssertRCReturnStmt(rc, RTMemTmpFree(pBaseParsedFree), rc);
407 }
408 else
409 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
410 }
411
412 /*
413 * Join paths with the CWD code.
414 */
415 rc = rtPathAbsExWithCwdOrBaseCommon(cchInPlace ? pszAbsPath : pszBase, cchInPlace, pBaseParsed,
416 pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
417 if (pBaseParsedFree)
418 RTMemTmpFree(pBaseParsedFree);
419 return rc;
420}
421
422
423/**
424 * Handles the RTPATH_PROP_ROOT_SLASH case.
425 */
426static int rtPathAbsExRootSlash(const char *pszBase, const char *pszPath, PRTPATHPARSED pParsed,
427 uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
428{
429 /*
430 * Eliminate dot and dot-dot components.
431 * Note! aComp[0] is the root stuff and must never be dropped.
432 */
433 uint32_t const cComps = pParsed->cComps;
434 uint32_t const iStop = (pParsed->fProps & (RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC)) != RTPATH_PROP_UNC
435 || pParsed->cComps < 2 ? 0 : 1;
436 uint32_t iLast = iStop;
437 uint32_t i = iStop + 1;
438 while (i < cComps)
439 {
440 uint32_t const cchComp = pParsed->aComps[i].cch;
441 if ( cchComp > 2
442 || pszPath[pParsed->aComps[i].off] != '.'
443 || (cchComp == 2 && pszPath[pParsed->aComps[i].off + 1] != '.') )
444 iLast = i;
445 else
446 {
447 Assert(cchComp == 1 || cchComp == 2);
448 pParsed->aComps[i].cch = 0;
449 if (cchComp == 2)
450 {
451 while (iLast > iStop && pParsed->aComps[iLast].cch == 0)
452 iLast--;
453 if (iLast > iStop)
454 {
455 Assert(pParsed->aComps[iLast].cch > 0);
456 pParsed->aComps[iLast].cch = 0;
457 iLast--;
458 }
459 }
460 }
461 i++;
462 }
463
464 /*
465 * Before we continue, ensure trailing slash if requested.
466 */
467 if ( (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH)
468 && iLast > 0)
469 pParsed->fProps |= RTPATH_PROP_DIR_SLASH;
470
471 /*
472 * DOS-style: Do we need to supply a drive letter or UNC root?
473 */
474 size_t cchRootPrefix = 0;
475 if ( (fFlags & RTPATH_STR_F_STYLE_DOS)
476 && !(pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_UNC)) )
477 {
478 /* Use the drive/UNC from the base path if we have one and it has such a component: */
479 if (pszBase)
480 {
481 union
482 {
483 RTPATHPARSED Parsed;
484 uint8_t abPadding[sizeof(RTPATHPARSED) + sizeof(pParsed->aComps[0]) * 2];
485 } uBase;
486 int rc = RTPathParse(pszBase, &uBase.Parsed, sizeof(uBase), fFlags & RTPATH_STR_F_STYLE_MASK);
487 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW, ("%Rrc - '%s'\n", rc, pszBase), rc);
488
489 if (uBase.Parsed.fProps & RTPATH_PROP_VOLUME)
490 {
491 /* get the drive letter. */
492 Assert(uBase.Parsed.aComps[0].cch == 2 || uBase.Parsed.aComps[0].cch == 3);
493 cchRootPrefix = RT_MIN(uBase.Parsed.aComps[0].cch, 2);
494 if (cchRootPrefix < *pcbAbsPath)
495 memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchRootPrefix);
496 else
497 {
498 rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
499 Assert(rc == VERR_BUFFER_OVERFLOW);
500
501 *pcbAbsPath = cchRootPrefix + pParsed->cchPath + 1;
502 return VERR_BUFFER_OVERFLOW;
503 }
504 rtPathAbsExUpperCaseDriveLetter(pszAbsPath);
505 }
506 else if (uBase.Parsed.fProps & RTPATH_PROP_UNC)
507 {
508 /* Include the share if we've got one. */
509 cchRootPrefix = uBase.Parsed.aComps[0].cch;
510 if (uBase.Parsed.cComps >= 2 && !(uBase.Parsed.fProps & RTPATH_PROP_SPECIAL_UNC))
511 cchRootPrefix += uBase.Parsed.aComps[1].cch;
512 else if (uBase.Parsed.fProps & RTPATH_PROP_ROOT_SLASH)
513 cchRootPrefix--;
514 if (cchRootPrefix < *pcbAbsPath)
515 {
516 if (uBase.Parsed.cComps < 2 || (uBase.Parsed.fProps & RTPATH_PROP_SPECIAL_UNC))
517 memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchRootPrefix);
518 else
519 {
520 size_t cchFirst = uBase.Parsed.aComps[0].cch;
521 memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchFirst);
522 memcpy(&pszAbsPath[cchFirst], &pszBase[uBase.Parsed.aComps[1].off], uBase.Parsed.aComps[1].cch);
523 }
524 }
525 else
526 {
527 rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
528 Assert(rc == VERR_BUFFER_OVERFLOW);
529
530 *pcbAbsPath = cchRootPrefix + pParsed->cchPath + 1;
531 return VERR_BUFFER_OVERFLOW;
532 }
533 }
534 else
535 pszBase = NULL;
536 }
537
538 /* Otherwise, query the current drive: */
539 if (!pszBase)
540 {
541 int rc = RTPathGetCurrentDrive(pszAbsPath, *pcbAbsPath);
542 if (RT_SUCCESS(rc))
543 cchRootPrefix = strlen(pszAbsPath);
544 else
545 {
546 if (rc == VERR_BUFFER_OVERFLOW)
547 {
548 int rc2 = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
549 Assert(rc2 == VERR_BUFFER_OVERFLOW);
550
551 char *pszTmp = (char *)RTMemTmpAlloc(RTPATH_BIG_MAX);
552 if (pszTmp)
553 {
554 rc2 = RTPathGetCurrentDrive(pszTmp, RTPATH_BIG_MAX);
555 if (RT_SUCCESS(rc2))
556 *pcbAbsPath = strlen(pszTmp) + pParsed->cchPath + 1;
557 else
558 *pcbAbsPath = RT_MAX(*pcbAbsPath * 2, (size_t)RTPATH_BIG_MAX * 3 + pParsed->cchPath + 1);
559 RTMemTmpFree(pszTmp);
560 }
561 else
562 rc = VERR_NO_TMP_MEMORY;
563 }
564 return rc;
565 }
566 }
567 }
568
569 /*
570 * Reassemble the path and return.
571 */
572 int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK,
573 pszAbsPath + cchRootPrefix, *pcbAbsPath - cchRootPrefix);
574 *pcbAbsPath = cchRootPrefix + pParsed->cchPath + (rc == VERR_BUFFER_OVERFLOW);
575 return rc;
576}
577
578
579/**
580 * Handles the RTPATH_PROP_ABSOLUTE case.
581 */
582static int rtPathAbsExAbsolute(const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
583{
584 if (pParsed->fProps & RTPATH_PROP_DOT_REFS)
585 {
586 uint32_t i = pParsed->cComps;
587 while (i-- > 0)
588 if ( pParsed->aComps[i].cch == 1
589 && pszPath[pParsed->aComps[i].off] == '.')
590 pParsed->aComps[i].cch = 0;
591 }
592
593 if ( (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH)
594 && pParsed->cComps > 1)
595 pParsed->fProps |= RTPATH_PROP_DIR_SLASH;
596
597 int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, *pcbAbsPath);
598 *pcbAbsPath = pParsed->cchPath + (rc == VERR_BUFFER_OVERFLOW);
599 if (RT_SUCCESS(rc) && (pParsed->fProps & RTPATH_PROP_VOLUME))
600 rtPathAbsExUpperCaseDriveLetter(pszAbsPath);
601 return rc;
602}
603
604
605RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
606{
607 LogFlow(("RTPathAbsEx: pszBase=%s pszPath=%s fFlags=%#x\n", pszBase, pszPath, fFlags));
608
609 /*
610 * Some input validation.
611 */
612 AssertPtr(pszPath);
613 AssertPtr(pszAbsPath);
614 AssertPtr(pcbAbsPath);
615 AssertReturn(*pszPath != '\0', VERR_PATH_ZERO_LENGTH);
616
617 AssertCompile(RTPATH_STR_F_STYLE_HOST == 0);
618 AssertReturn( RTPATH_STR_F_IS_VALID(fFlags, RTPATHABS_F_STOP_AT_BASE | RTPATHABS_F_STOP_AT_CWD | RTPATHABS_F_ENSURE_TRAILING_SLASH)
619 && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
620 if ((fFlags & RTPATH_STR_F_STYLE_MASK) == RTPATH_STR_F_STYLE_HOST)
621 fFlags |= RTPATH_STYLE;
622
623 /*
624 * Parse the path we're to straigthen out.
625 */
626 union
627 {
628 RTPATHPARSED Parsed;
629 uint8_t abPadding[1024];
630 } uBuf;
631 PRTPATHPARSED pParsedFree = NULL;
632 PRTPATHPARSED pParsed = &uBuf.Parsed;
633 size_t cbParsed = sizeof(uBuf);
634 int rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
635 if (RT_SUCCESS(rc))
636 { /* likely */ }
637 else if (rc == VERR_BUFFER_OVERFLOW)
638 {
639 cbParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pParsed->cComps + 2]);
640 pParsedFree = pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
641 AssertReturn(pParsed, VERR_NO_TMP_MEMORY);
642 rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
643 AssertRCReturnStmt(rc, RTMemTmpFree(pParsedFree), rc);
644 }
645 else
646 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
647
648 /*
649 * Check if the input is more or less perfect as it is.
650 */
651 if (pParsed->fProps & RTPATH_PROP_ABSOLUTE)
652 rc = rtPathAbsExAbsolute(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
653 /*
654 * What about relative but with a root slash.
655 */
656 else if (pParsed->fProps & RTPATH_PROP_ROOT_SLASH)
657 rc = rtPathAbsExRootSlash(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
658 /*
659 * Not exactly perfect. No root slash.
660 *
661 * If we have a base path, we use it unless we're into drive letters and
662 * pszPath refers to a different drive letter.
663 */
664 else if ( pszBase
665 && ( !(fFlags & RTPATH_STR_F_STYLE_DOS)
666 /** @todo add flag for skipping this and always using the base path? */
667 || !(pParsed->fProps & RTPATH_PROP_VOLUME)
668 || ( RT_C_IS_ALPHA(pszBase[0])
669 && pszBase[1] == ':'
670 && RT_C_TO_UPPER(pszBase[0]) == RT_C_TO_UPPER(pszPath[0])
671 )
672 )
673 )
674 rc = rtPathAbsExWithBase(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
675 else
676 rc = rtPathAbsExWithCwd(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
677
678 if (pParsedFree)
679 RTMemTmpFree(pParsedFree);
680 LogFlow(("RTPathAbsEx: returns %Rrc *pcbAbsPath=%#zx\n", rc, *pcbAbsPath));
681 return rc;
682}
683
684
685RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cbAbsPath)
686{
687 return RTPathAbsEx(NULL, pszPath, RTPATH_STR_F_STYLE_HOST, pszAbsPath, &cbAbsPath);
688}
689
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