VirtualBox

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

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

IPRT,*: Cleaning up RTPathAbsExEx, renaming it to RTPathAbsEx and removing dead code. bugref:9172

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