1
/* $Id: RTPathCalcRelative.cpp $ */
3
* IPRT - RTPathCreateRelative.
7
* Copyright (C) 2013 Oracle Corporation
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.
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.
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.
28
/*******************************************************************************
30
*******************************************************************************/
31
#include "internal/iprt.h"
32
#include <iprt/path.h>
33
#include <iprt/assert.h>
35
#include <iprt/string.h>
36
#include "internal/path.h"
40
RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
41
const char *pszPathFrom,
42
const char *pszPathTo)
44
int rc = VINF_SUCCESS;
46
AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER);
47
AssertReturn(cbPathDst, VERR_INVALID_PARAMETER);
48
AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER);
49
AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER);
50
AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER);
51
AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER);
52
AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER);
55
* Check for different root specifiers (drive letters), creating a relative path doesn't work here.
56
* @todo: How to handle case insensitive root specifiers correctly?
58
size_t offRootFrom = rtPathRootSpecLen(pszPathFrom);
59
size_t offRootTo = rtPathRootSpecLen(pszPathTo);
61
if ( offRootFrom != offRootTo
62
|| RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom))
63
return VERR_NOT_SUPPORTED;
65
/* Filter out the parent path which is equal to both paths. */
66
while ( *pszPathFrom == *pszPathTo
67
&& *pszPathFrom != '\0'
68
&& *pszPathTo != '\0')
75
* Because path components can start with an equal string but differ afterwards we
76
* need to go back to the beginning of the current component.
78
while (!RTPATH_IS_SEP(*pszPathFrom))
81
pszPathFrom++; /* Skip path separator. */
83
while (!RTPATH_IS_SEP(*pszPathTo))
86
pszPathTo++; /* Skip path separator. */
88
/* Paths point to the first non equal component now. */
89
char aszPathTmp[RTPATH_MAX + 1];
90
unsigned offPathTmp = 0;
92
/* Create the part to go up from pszPathFrom. */
93
while (*pszPathFrom != '\0')
95
while ( !RTPATH_IS_SEP(*pszPathFrom)
96
&& *pszPathFrom != '\0')
99
if (RTPATH_IS_SEP(*pszPathFrom))
101
if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1)
102
return VERR_FILENAME_TOO_LONG;
103
aszPathTmp[offPathTmp++] = '.';
104
aszPathTmp[offPathTmp++] = '.';
105
aszPathTmp[offPathTmp++] = RTPATH_SLASH;
110
aszPathTmp[offPathTmp] = '\0';
112
/* Now append the rest of pszPathTo to the final path. */
113
char *pszPathTmp = &aszPathTmp[offPathTmp];
114
size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1;
115
rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo);
120
size_t cchPathTmp = strlen(aszPathTmp);
121
if (cchPathTmp >= cbPathDst)
122
return VERR_BUFFER_OVERFLOW;
123
memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1);
126
rc = VERR_FILENAME_TOO_LONG;