VirtualBox

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

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

IPRT: Added RTPATHABS_F_ENSURE_TRAILING_SLASH to RTPathAbsEx and fixed a couple of issues related to VERR_BUFFER_OVERFLOW code paths. bugref:9172

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.0 KB
Line 
1/* $Id: RTPathAbsEx.cpp 78153 2019-04-17 12:30:08Z 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
188 || (pParsed->fProps & RTPATH_PROP_DIR_SLASH)
189 || (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH) )
190 pBaseParsed->fProps |= RTPATH_PROP_DIR_SLASH;
191 else
192 pBaseParsed->fProps &= ~RTPATH_PROP_DIR_SLASH;
193 }
194
195 /* Apply the trailing flash flag to the input path: */
196 if ( iLast >= 0
197 && (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH))
198 pParsed->fProps |= RTPATH_PROP_DIR_SLASH;
199
200 /*
201 * Combine the two. RTPathParsedReassemble can handle in place stuff, as
202 * long as the path doesn't grow.
203 */
204 int rc = RTPathParsedReassemble(pszBase, pBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, *pcbAbsPath);
205 if (RT_SUCCESS(rc))
206 {
207 if (pBaseParsed->fProps & RTPATH_PROP_VOLUME)
208 rtPathAbsExUpperCaseDriveLetter(pszAbsPath);
209
210 cchBaseInPlace = pBaseParsed->cchPath;
211 Assert(cchBaseInPlace == strlen(pszAbsPath));
212 if (iLast >= 0)
213 {
214 rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK,
215 &pszAbsPath[cchBaseInPlace], *pcbAbsPath - cchBaseInPlace);
216 if (RT_SUCCESS(rc))
217 {
218 *pcbAbsPath = cchBaseInPlace + pParsed->cchPath;
219 Assert(*pcbAbsPath == strlen(pszAbsPath));
220 }
221 else
222 *pcbAbsPath = cchBaseInPlace + pParsed->cchPath + 1;
223 }
224 else
225 *pcbAbsPath = cchBaseInPlace;
226 }
227 else if (rc == VERR_BUFFER_OVERFLOW)
228 {
229 if (iLast >= 0)
230 {
231 RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
232 *pcbAbsPath = pBaseParsed->cchPath + pParsed->cchPath + 1;
233 }
234 else
235 *pcbAbsPath = pBaseParsed->cchPath + 1;
236 }
237
238 return rc;
239}
240
241
242/**
243 * Handles the no-root-path scenario where we do CWD prefixing.
244 */
245static int rtPathAbsExWithCwd(const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
246{
247 /*
248 * Get the current directory and place it in the output buffer.
249 */
250 size_t cchInPlace;
251 size_t cbCwd = *pcbAbsPath;
252 char *pszCwdFree = NULL;
253 char *pszCwd = pszAbsPath;
254 int rc;
255 if ( !(fFlags & RTPATH_STR_F_STYLE_DOS)
256 || (pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH)) != RTPATH_PROP_VOLUME )
257 rc = RTPathGetCurrent(pszCwd, cbCwd);
258 else
259 rc = RTPathGetCurrentOnDrive(pszPath[0], pszCwd, cbCwd);
260 if (RT_SUCCESS(rc))
261 cchInPlace = strlen(pszCwd);
262 else if (rc == VERR_BUFFER_OVERFLOW)
263 {
264 /* Allocate a big temporary buffer so we can return the correct length
265 (the destination buffer might even be big enough if pszPath includes
266 sufficient '..' entries). */
267 cchInPlace = 0;
268 cbCwd = RT_MAX(cbCwd * 4, RTPATH_BIG_MAX);
269 pszCwdFree = pszCwd = (char *)RTMemTmpAlloc(cbCwd);
270 if (pszCwdFree)
271 {
272 if ( !(fFlags & RTPATH_STR_F_STYLE_DOS)
273 || (pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH)) != RTPATH_PROP_VOLUME )
274 rc = RTPathGetCurrent(pszCwd, cbCwd);
275 else
276 rc = RTPathGetCurrentOnDrive(pszPath[0], pszCwd, cbCwd);
277 if (RT_FAILURE(rc))
278 {
279 if (rc == VERR_BUFFER_OVERFLOW)
280 rc = VERR_FILENAME_TOO_LONG;
281 RTMemTmpFree(pszCwdFree);
282 return rc;
283 }
284 }
285 else
286 {
287 *pcbAbsPath = cbCwd + 1 + pParsed->cchPath + 1;
288 return rc;
289 }
290 }
291 else
292 return rc;
293
294 /*
295 * Parse the path.
296 */
297 union
298 {
299 RTPATHPARSED Parsed;
300 uint8_t abPadding[1024];
301 } uCwd;
302 PRTPATHPARSED pCwdParsedFree = NULL;
303 PRTPATHPARSED pCwdParsed = &uCwd.Parsed;
304 size_t cbCwdParsed = sizeof(uCwd);
305 rc = RTPathParse(pszCwd, pCwdParsed, cbCwdParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
306 if (RT_SUCCESS(rc))
307 { /* likely */ }
308 else if (rc == VERR_BUFFER_OVERFLOW)
309 {
310 cbCwdParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pCwdParsed->cComps + 2]);
311 pCwdParsedFree = pCwdParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbCwdParsed);
312 AssertReturnStmt(pCwdParsed, RTMemTmpFree(pszCwdFree), VERR_NO_TMP_MEMORY);
313 rc = RTPathParse(pszCwd, pCwdParsed, cbCwdParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
314 AssertRCReturnStmt(rc, RTMemTmpFree(pCwdParsedFree); RTMemTmpFree(pszCwdFree), rc);
315 }
316 else
317 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
318
319 /*
320 * Join paths with the base-path code.
321 */
322 if (fFlags & RTPATHABS_F_STOP_AT_CWD)
323 fFlags |= RTPATHABS_F_STOP_AT_BASE;
324 else
325 fFlags &= ~RTPATHABS_F_STOP_AT_BASE;
326 rc = rtPathAbsExWithCwdOrBaseCommon(pszCwd, cchInPlace, pCwdParsed, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
327 if (pCwdParsedFree)
328 RTMemTmpFree(pCwdParsedFree);
329 if (pszCwdFree)
330 RTMemTmpFree(pszCwdFree);
331 return rc;
332}
333
334
335/**
336 * Handles the no-root-path scenario where we've got a base path.
337 */
338static int rtPathAbsExWithBase(const char *pszBase, const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags,
339 char *pszAbsPath, size_t *pcbAbsPath)
340{
341 /*
342 * Parse the base path.
343 */
344 union
345 {
346 RTPATHPARSED Parsed;
347 uint8_t abPadding[1024];
348 } uBase;
349 PRTPATHPARSED pBaseParsedFree = NULL;
350 PRTPATHPARSED pBaseParsed = &uBase.Parsed;
351 size_t cbBaseParsed = sizeof(uBase);
352 int rc = RTPathParse(pszBase, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
353 if (RT_SUCCESS(rc))
354 { /* likely */ }
355 else if (rc == VERR_BUFFER_OVERFLOW)
356 {
357 cbBaseParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pBaseParsed->cComps + 2]);
358 pBaseParsedFree = pBaseParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbBaseParsed);
359 AssertReturn(pBaseParsed, VERR_NO_TMP_MEMORY);
360 rc = RTPathParse(pszBase, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
361 AssertRCReturnStmt(rc, RTMemTmpFree(pBaseParsedFree), rc);
362 }
363 else
364 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
365
366 /*
367 * If the base path isn't absolute, we need to deal with that.
368 */
369 size_t cchInPlace = 0;
370 if ((pBaseParsed->fProps & (RTPATH_PROP_ABSOLUTE | RTPATH_PROP_EXTRA_SLASHES | RTPATH_PROP_DOT_REFS)) == RTPATH_PROP_ABSOLUTE)
371 { /* likely */ }
372 else
373 {
374 cchInPlace = *pcbAbsPath;
375 rc = RTPathAbsEx(NULL, pszBase, fFlags, pszAbsPath, &cchInPlace);
376 if (RT_SUCCESS(rc))
377 {
378 Assert(strlen(pszAbsPath) == cchInPlace);
379 Assert(cchInPlace > 0);
380 }
381 else
382 {
383/** @todo Allocate temp buffer like we do for CWD? */
384 /* This is over generious, but don't want to put too much effort into it yet. */
385 if (rc == VERR_BUFFER_OVERFLOW)
386 *pcbAbsPath = cchInPlace + 1 + pParsed->cchPath + 1;
387 return rc;
388 }
389
390 /*
391 * Reparse it.
392 */
393 rc = RTPathParse(pszAbsPath, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
394 if (RT_SUCCESS(rc))
395 { /* likely */ }
396 else if (rc == VERR_BUFFER_OVERFLOW)
397 {
398 if (pBaseParsedFree)
399 RTMemTmpFree(pBaseParsedFree);
400 cbBaseParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pBaseParsed->cComps + 2]);
401 pBaseParsedFree = pBaseParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbBaseParsed);
402 AssertReturn(pBaseParsed, VERR_NO_TMP_MEMORY);
403 rc = RTPathParse(pszAbsPath, pBaseParsed, cbBaseParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
404 AssertRCReturnStmt(rc, RTMemTmpFree(pBaseParsedFree), rc);
405 }
406 else
407 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
408 }
409
410 /*
411 * Join paths with the CWD code.
412 */
413 rc = rtPathAbsExWithCwdOrBaseCommon(cchInPlace ? pszAbsPath : pszBase, cchInPlace, pBaseParsed,
414 pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
415 if (pBaseParsedFree)
416 RTMemTmpFree(pBaseParsedFree);
417 return rc;
418}
419
420
421/**
422 * Handles the RTPATH_PROP_ROOT_SLASH case.
423 */
424static int rtPathAbsExRootSlash(const char *pszBase, const char *pszPath, PRTPATHPARSED pParsed,
425 uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
426{
427 /*
428 * Eliminate dot and dot-dot components.
429 * Note! aComp[0] is the root stuff and must never be dropped.
430 */
431 uint32_t const cComps = pParsed->cComps;
432 uint32_t const iStop = (pParsed->fProps & (RTPATH_PROP_UNC | RTPATH_PROP_SPECIAL_UNC)) != RTPATH_PROP_UNC
433 || pParsed->cComps < 2 ? 0 : 1;
434 uint32_t iLast = iStop;
435 uint32_t i = iStop + 1;
436 while (i < cComps)
437 {
438 uint32_t const cchComp = pParsed->aComps[i].cch;
439 if ( cchComp > 2
440 || pszPath[pParsed->aComps[i].off] != '.'
441 || (cchComp == 2 && pszPath[pParsed->aComps[i].off + 1] != '.') )
442 iLast = i;
443 else
444 {
445 Assert(cchComp == 1 || cchComp == 2);
446 pParsed->aComps[i].cch = 0;
447 if (cchComp == 2)
448 {
449 while (iLast > iStop && pParsed->aComps[iLast].cch == 0)
450 iLast--;
451 if (iLast > iStop)
452 {
453 Assert(pParsed->aComps[iLast].cch > 0);
454 pParsed->aComps[iLast].cch = 0;
455 iLast--;
456 }
457 }
458 }
459 i++;
460 }
461
462 /*
463 * Before we continue, ensure trailing slash if requested.
464 */
465 if ( (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH)
466 && iLast > 0)
467 pParsed->fProps |= RTPATH_PROP_DIR_SLASH;
468
469 /*
470 * DOS-style: Do we need to supply a drive letter or UNC root?
471 */
472 size_t cchRootPrefix = 0;
473 if ( (fFlags & RTPATH_STR_F_STYLE_DOS)
474 && !(pParsed->fProps & (RTPATH_PROP_VOLUME | RTPATH_PROP_UNC)) )
475 {
476 /* Use the drive/UNC from the base path if we have one and it has such a component: */
477 if (pszBase)
478 {
479 union
480 {
481 RTPATHPARSED Parsed;
482 uint8_t abPadding[sizeof(RTPATHPARSED) + sizeof(pParsed->aComps[0]) * 2];
483 } uBase;
484 int rc = RTPathParse(pszBase, &uBase.Parsed, sizeof(uBase), fFlags & RTPATH_STR_F_STYLE_MASK);
485 AssertMsgReturn(RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW, ("%Rrc - '%s'\n", rc, pszBase), rc);
486
487 if (uBase.Parsed.fProps & RTPATH_PROP_VOLUME)
488 {
489 /* get the drive letter. */
490 Assert(uBase.Parsed.aComps[0].cch == 2 || uBase.Parsed.aComps[0].cch == 3);
491 cchRootPrefix = RT_MIN(uBase.Parsed.aComps[0].cch, 2);
492 if (cchRootPrefix < *pcbAbsPath)
493 memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchRootPrefix);
494 else
495 {
496 rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
497 Assert(rc == VERR_BUFFER_OVERFLOW);
498
499 *pcbAbsPath = cchRootPrefix + pParsed->cchPath + 1;
500 return VERR_BUFFER_OVERFLOW;
501 }
502 rtPathAbsExUpperCaseDriveLetter(pszAbsPath);
503 }
504 else if (uBase.Parsed.fProps & RTPATH_PROP_UNC)
505 {
506 /* Include the share if we've got one. */
507 cchRootPrefix = uBase.Parsed.aComps[0].cch;
508 if (uBase.Parsed.cComps >= 2 && !(uBase.Parsed.fProps & RTPATH_PROP_SPECIAL_UNC))
509 cchRootPrefix += uBase.Parsed.aComps[1].cch;
510 else if (uBase.Parsed.fProps & RTPATH_PROP_ROOT_SLASH)
511 cchRootPrefix--;
512 if (cchRootPrefix < *pcbAbsPath)
513 {
514 if (uBase.Parsed.cComps < 2 || (uBase.Parsed.fProps & RTPATH_PROP_SPECIAL_UNC))
515 memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchRootPrefix);
516 else
517 {
518 size_t cchFirst = uBase.Parsed.aComps[0].cch;
519 memcpy(pszAbsPath, &pszBase[uBase.Parsed.aComps[0].off], cchFirst);
520 memcpy(&pszAbsPath[cchFirst], &pszBase[uBase.Parsed.aComps[1].off], uBase.Parsed.aComps[1].cch);
521 }
522 }
523 else
524 {
525 rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
526 Assert(rc == VERR_BUFFER_OVERFLOW);
527
528 *pcbAbsPath = cchRootPrefix + pParsed->cchPath + 1;
529 return VERR_BUFFER_OVERFLOW;
530 }
531 }
532 else
533 pszBase = NULL;
534 }
535
536 /* Otherwise, query the current drive: */
537 if (!pszBase)
538 {
539 int rc = RTPathGetCurrentDrive(pszAbsPath, *pcbAbsPath);
540 if (RT_SUCCESS(rc))
541 cchRootPrefix = strlen(pszAbsPath);
542 else
543 {
544 if (rc == VERR_BUFFER_OVERFLOW)
545 {
546 int rc2 = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
547 Assert(rc2 == VERR_BUFFER_OVERFLOW);
548
549 char *pszTmp = (char *)RTMemTmpAlloc(RTPATH_BIG_MAX);
550 if (pszTmp)
551 {
552 rc2 = RTPathGetCurrentDrive(pszTmp, RTPATH_BIG_MAX);
553 if (RT_SUCCESS(rc2))
554 *pcbAbsPath = strlen(pszTmp) + pParsed->cchPath + 1;
555 else
556 *pcbAbsPath = RT_MAX(*pcbAbsPath * 2, (size_t)RTPATH_BIG_MAX * 3 + pParsed->cchPath + 1);
557 RTMemTmpFree(pszTmp);
558 }
559 else
560 rc = VERR_NO_TMP_MEMORY;
561 }
562 return rc;
563 }
564 }
565 }
566
567 /*
568 * Reassemble the path and return.
569 */
570 int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK,
571 pszAbsPath + cchRootPrefix, *pcbAbsPath - cchRootPrefix);
572 *pcbAbsPath = cchRootPrefix + pParsed->cchPath + (rc == VERR_BUFFER_OVERFLOW);
573 return rc;
574}
575
576
577/**
578 * Handles the RTPATH_PROP_ABSOLUTE case.
579 */
580static int rtPathAbsExAbsolute(const char *pszPath, PRTPATHPARSED pParsed, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
581{
582 if (pParsed->fProps & RTPATH_PROP_DOT_REFS)
583 {
584 uint32_t i = pParsed->cComps;
585 while (i-- > 0)
586 if ( pParsed->aComps[i].cch == 1
587 && pszPath[pParsed->aComps[i].off] == '.')
588 pParsed->aComps[i].cch = 0;
589 }
590
591 if ( (fFlags & RTPATHABS_F_ENSURE_TRAILING_SLASH)
592 && pParsed->cComps > 1)
593 pParsed->fProps |= RTPATH_PROP_DIR_SLASH;
594
595 int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, *pcbAbsPath);
596 *pcbAbsPath = pParsed->cchPath + (rc == VERR_BUFFER_OVERFLOW);
597 if (RT_SUCCESS(rc) && (pParsed->fProps & RTPATH_PROP_VOLUME))
598 rtPathAbsExUpperCaseDriveLetter(pszAbsPath);
599 return rc;
600}
601
602
603RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
604{
605 /*
606 * Some input validation.
607 */
608 AssertPtr(pszPath);
609 AssertPtr(pszAbsPath);
610 AssertPtr(pcbAbsPath);
611 AssertReturn(*pszPath != '\0', VERR_PATH_ZERO_LENGTH);
612
613 AssertCompile(RTPATH_STR_F_STYLE_HOST == 0);
614 AssertReturn( RTPATH_STR_F_IS_VALID(fFlags, RTPATHABS_F_STOP_AT_BASE | RTPATHABS_F_STOP_AT_CWD | RTPATHABS_F_ENSURE_TRAILING_SLASH)
615 && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
616 if ((fFlags & RTPATH_STR_F_STYLE_MASK) == RTPATH_STR_F_STYLE_HOST)
617 fFlags |= RTPATH_STYLE;
618
619 /*
620 * Parse the path we're to straigthen out.
621 */
622 union
623 {
624 RTPATHPARSED Parsed;
625 uint8_t abPadding[1024];
626 } uBuf;
627 PRTPATHPARSED pParsedFree = NULL;
628 PRTPATHPARSED pParsed = &uBuf.Parsed;
629 size_t cbParsed = sizeof(uBuf);
630 int rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
631 if (RT_SUCCESS(rc))
632 { /* likely */ }
633 else if (rc == VERR_BUFFER_OVERFLOW)
634 {
635 cbParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pParsed->cComps + 2]);
636 pParsedFree = pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
637 AssertReturn(pParsed, VERR_NO_TMP_MEMORY);
638 rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
639 AssertRCReturnStmt(rc, RTMemTmpFree(pParsedFree), rc);
640 }
641 else
642 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
643
644 /*
645 * Check if the input is more or less perfect as it is.
646 */
647 if (pParsed->fProps & RTPATH_PROP_ABSOLUTE)
648 rc = rtPathAbsExAbsolute(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
649 /*
650 * What about relative but with a root slash.
651 */
652 else if (pParsed->fProps & RTPATH_PROP_ROOT_SLASH)
653 rc = rtPathAbsExRootSlash(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
654 /*
655 * Not exactly perfect. No root slash.
656 *
657 * If we have a base path, we use it unless we're into drive letters and
658 * pszPath refers to a different drive letter.
659 */
660 else if ( pszBase
661 && ( !(fFlags & RTPATH_STR_F_STYLE_DOS)
662 /** @todo add flag for skipping this and always using the base path? */
663 || !(pParsed->fProps & RTPATH_PROP_VOLUME)
664 || ( RT_C_IS_ALPHA(pszBase[0])
665 && pszBase[1] == ':'
666 && RT_C_TO_UPPER(pszBase[0]) == RT_C_TO_UPPER(pszPath[0])
667 )
668 )
669 )
670 rc = rtPathAbsExWithBase(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
671 else
672 rc = rtPathAbsExWithCwd(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
673
674 if (pParsedFree)
675 RTMemTmpFree(pParsedFree);
676 return rc;
677}
678
679
680RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cbAbsPath)
681{
682 return RTPathAbsEx(NULL, pszPath, RTPATH_STR_F_STYLE_HOST, pszAbsPath, &cbAbsPath);
683}
684
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