VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/path/RTPathAbsExEx.cpp@ 78048

最後變更 在這個檔案從78048是 78048,由 vboxsync 提交於 6 年 前

IPRT: Working on new RTPathAbsEx implementation, temporarily called RTPathAbsExEx. This should fix most of the bugs in the current RTPathAbs/Ex code and do away with the fixed path buffer limitations. Also introduces a RTPATH_BIG_MAX, given that RTPATH_MAX is just a reasonable and not absolute MAX value. The new one is more or less absolute and must never be used for stack buffers. bugref:9172

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 24.2 KB
 
1/* $Id: RTPathAbsExEx.cpp 78048 2019-04-09 01:21:09Z vboxsync $ */
2/** @file
3 * IPRT - RTPathAbsExEx
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.alldomusa.eu.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) rtPathAbsExExUpperCaseDriveLetter(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 rtPathAbsExExWithCwdOrBaseCommon(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 rtPathAbsExExUpperCaseDriveLetter(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 rtPathAbsExExWithCwd(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 = rtPathAbsExExWithCwdOrBaseCommon(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 rtPathAbsExExWithBase(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 = RTPathAbsExEx(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 = rtPathAbsExExWithCwdOrBaseCommon(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 rtPathAbsExExRootSlash(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 int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
479 Assert(rc == VERR_BUFFER_OVERFLOW); RT_NOREF(rc);
480
481 *pcbAbsPath = cchRootPrefix + pParsed->cchPath + 1;
482 return VERR_BUFFER_OVERFLOW;
483 }
484 rtPathAbsExExUpperCaseDriveLetter(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 int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
508 Assert(rc == VERR_BUFFER_OVERFLOW); RT_NOREF(rc);
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 rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, 0);
529 Assert(rc == VERR_BUFFER_OVERFLOW); RT_NOREF(rc);
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 rtPathAbsExExAbsolute(const char *pszPath, PRTPATHPARSED pParsed,
563 uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
564{
565 if (pParsed->fProps & RTPATH_PROP_DOT_REFS)
566 {
567 uint32_t i = pParsed->cComps;
568 while (i-- > 0)
569 if ( pParsed->aComps[i].cch == 1
570 && pszPath[pParsed->aComps[i].off] == '.')
571 pParsed->aComps[i].cch = 0;
572 }
573 int rc = RTPathParsedReassemble(pszPath, pParsed, fFlags & RTPATH_STR_F_STYLE_MASK, pszAbsPath, *pcbAbsPath);
574 *pcbAbsPath = pParsed->cchPath + (rc == VERR_BUFFER_OVERFLOW);
575 if (RT_SUCCESS(rc) && (pParsed->fProps & RTPATH_PROP_VOLUME))
576 rtPathAbsExExUpperCaseDriveLetter(pszAbsPath);
577 return rc;
578}
579
580
581RTDECL(int) RTPathAbsExEx(const char *pszBase, const char *pszPath, uint32_t fFlags, char *pszAbsPath, size_t *pcbAbsPath)
582{
583 /*
584 * Some input validation.
585 */
586 AssertPtr(pszPath);
587 AssertPtr(pszAbsPath);
588 AssertPtr(pcbAbsPath);
589 AssertReturn(*pszPath != '\0', VERR_PATH_ZERO_LENGTH);
590
591 AssertCompile(RTPATH_STR_F_STYLE_HOST == 0);
592 AssertReturn( RTPATH_STR_F_IS_VALID(fFlags, RTPATHABS_F_STOP_AT_BASE | RTPATHABS_F_STOP_AT_CWD)
593 && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
594 if ((fFlags & RTPATH_STR_F_STYLE_MASK) == RTPATH_STR_F_STYLE_HOST)
595 fFlags |= RTPATH_STYLE;
596
597 /*
598 * Parse the path we're to straigthen out.
599 */
600 union
601 {
602 RTPATHPARSED Parsed;
603 uint8_t abPadding[1024];
604 } uBuf;
605 PRTPATHPARSED pParsedFree = NULL;
606 PRTPATHPARSED pParsed = &uBuf.Parsed;
607 size_t cbParsed = sizeof(uBuf);
608 int rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
609 if (RT_SUCCESS(rc))
610 { /* likely */ }
611 else if (rc == VERR_BUFFER_OVERFLOW)
612 {
613 cbParsed = RT_UOFFSETOF_DYN(RTPATHPARSED, aComps[pParsed->cComps + 2]);
614 pParsedFree = pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
615 AssertReturn(pParsed, VERR_NO_TMP_MEMORY);
616 rc = RTPathParse(pszPath, pParsed, cbParsed, fFlags & RTPATH_STR_F_STYLE_MASK);
617 AssertRCReturnStmt(rc, RTMemTmpFree(pParsedFree), rc);
618 }
619 else
620 AssertMsgFailedReturn(("rc=%Rrc '%s'\n", rc, pszPath), rc);
621
622 /*
623 * Check if the input is more or less perfect as it is.
624 */
625 if (pParsed->fProps & RTPATH_PROP_ABSOLUTE)
626 rc = rtPathAbsExExAbsolute(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
627 /*
628 * What about relative but with a root slash.
629 */
630 else if (pParsed->fProps & RTPATH_PROP_ROOT_SLASH)
631 rc = rtPathAbsExExRootSlash(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
632 /*
633 * Not exactly perfect. No root slash.
634 *
635 * If we have a base path, we use it unless we're into drive letters and
636 * pszPath refers to a different drive letter.
637 */
638 else if ( pszBase
639 && ( !(fFlags & RTPATH_STR_F_STYLE_DOS)
640 /** @todo add flag for skipping this and always using the base path? */
641 || !(pParsed->fProps & RTPATH_PROP_VOLUME)
642 || ( RT_C_IS_ALPHA(pszBase[0])
643 && pszBase[1] == ':'
644 && RT_C_TO_UPPER(pszBase[0]) == RT_C_TO_UPPER(pszPath[0])
645 )
646 )
647 )
648 rc = rtPathAbsExExWithBase(pszBase, pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
649 else
650 rc = rtPathAbsExExWithCwd(pszPath, pParsed, fFlags, pszAbsPath, pcbAbsPath);
651
652 if (pParsedFree)
653 RTMemTmpFree(pParsedFree);
654 return rc;
655}
656
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette