summaryrefslogtreecommitdiff
path: root/src/VBox/Runtime/common/path
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2014-03-26 19:21:20 +0000
committer <>2014-05-08 15:03:54 +0000
commitfb123f93f9f5ce42c8e5785d2f8e0edaf951740e (patch)
treec2103d76aec5f1f10892cd1d3a38e24f665ae5db /src/VBox/Runtime/common/path
parent58ed4748338f9466599adfc8a9171280ed99e23f (diff)
downloadVirtualBox-master.tar.gz
Imported from /home/lorry/working-area/delta_VirtualBox/VirtualBox-4.3.10.tar.bz2.HEADVirtualBox-4.3.10master
Diffstat (limited to 'src/VBox/Runtime/common/path')
-rw-r--r--src/VBox/Runtime/common/path/RTPathAbsDup.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAbsEx.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAbsExDup.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAppend.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathAppendEx.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathCalcRelative.cpp130
-rw-r--r--src/VBox/Runtime/common/path/RTPathExt.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathFilename.cpp76
-rw-r--r--src/VBox/Runtime/common/path/RTPathParse.cpp109
-rw-r--r--src/VBox/Runtime/common/path/RTPathParse.cpp.h250
-rw-r--r--src/VBox/Runtime/common/path/RTPathParseSimple.cpp118
-rw-r--r--src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp122
-rw-r--r--src/VBox/Runtime/common/path/RTPathRealDup.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathRmCmd.cpp648
-rw-r--r--src/VBox/Runtime/common/path/RTPathSplit.cpp133
-rw-r--r--src/VBox/Runtime/common/path/RTPathSplitA.cpp91
-rw-r--r--src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp120
-rw-r--r--src/VBox/Runtime/common/path/RTPathStripExt.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathStripFilename.cpp2
-rw-r--r--src/VBox/Runtime/common/path/RTPathTraverseList.cpp2
-rw-r--r--src/VBox/Runtime/common/path/comparepaths.cpp2
-rw-r--r--src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp4
-rw-r--r--src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp2
-rw-r--r--src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h82
24 files changed, 1791 insertions, 116 deletions
diff --git a/src/VBox/Runtime/common/path/RTPathAbsDup.cpp b/src/VBox/Runtime/common/path/RTPathAbsDup.cpp
index b9f217f9..337ce128 100644
--- a/src/VBox/Runtime/common/path/RTPathAbsDup.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAbsDup.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAbsEx.cpp b/src/VBox/Runtime/common/path/RTPathAbsEx.cpp
index c647b547..86ce86a0 100644
--- a/src/VBox/Runtime/common/path/RTPathAbsEx.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAbsEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp b/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp
index 8bb8cd17..9247d899 100644
--- a/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAbsExDup.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAppend.cpp b/src/VBox/Runtime/common/path/RTPathAppend.cpp
index 5bad6483..af3e5917 100644
--- a/src/VBox/Runtime/common/path/RTPathAppend.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAppend.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathAppendEx.cpp b/src/VBox/Runtime/common/path/RTPathAppendEx.cpp
index e5de4ffe..ebed3864 100644
--- a/src/VBox/Runtime/common/path/RTPathAppendEx.cpp
+++ b/src/VBox/Runtime/common/path/RTPathAppendEx.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009-2010 Oracle Corporation
+ * Copyright (C) 2009-2011 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp b/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
new file mode 100644
index 00000000..fbb6b64c
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathCalcRelative.cpp
@@ -0,0 +1,130 @@
+/* $Id: RTPathCalcRelative.cpp $ */
+/** @file
+ * IPRT - RTPathCreateRelative.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include "internal/path.h"
+
+
+
+RTDECL(int) RTPathCalcRelative(char *pszPathDst, size_t cbPathDst,
+ const char *pszPathFrom,
+ const char *pszPathTo)
+{
+ int rc = VINF_SUCCESS;
+
+ AssertPtrReturn(pszPathDst, VERR_INVALID_POINTER);
+ AssertReturn(cbPathDst, VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pszPathFrom, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPathTo, VERR_INVALID_POINTER);
+ AssertReturn(RTPathStartsWithRoot(pszPathFrom), VERR_INVALID_PARAMETER);
+ AssertReturn(RTPathStartsWithRoot(pszPathTo), VERR_INVALID_PARAMETER);
+ AssertReturn(RTStrCmp(pszPathFrom, pszPathTo), VERR_INVALID_PARAMETER);
+
+ /*
+ * Check for different root specifiers (drive letters), creating a relative path doesn't work here.
+ * @todo: How to handle case insensitive root specifiers correctly?
+ */
+ size_t offRootFrom = rtPathRootSpecLen(pszPathFrom);
+ size_t offRootTo = rtPathRootSpecLen(pszPathTo);
+
+ if ( offRootFrom != offRootTo
+ || RTStrNCmp(pszPathFrom, pszPathTo, offRootFrom))
+ return VERR_NOT_SUPPORTED;
+
+ /* Filter out the parent path which is equal to both paths. */
+ while ( *pszPathFrom == *pszPathTo
+ && *pszPathFrom != '\0'
+ && *pszPathTo != '\0')
+ {
+ pszPathFrom++;
+ pszPathTo++;
+ }
+
+ /*
+ * Because path components can start with an equal string but differ afterwards we
+ * need to go back to the beginning of the current component.
+ */
+ while (!RTPATH_IS_SEP(*pszPathFrom))
+ pszPathFrom--;
+
+ pszPathFrom++; /* Skip path separator. */
+
+ while (!RTPATH_IS_SEP(*pszPathTo))
+ pszPathTo--;
+
+ pszPathTo++; /* Skip path separator. */
+
+ /* Paths point to the first non equal component now. */
+ char aszPathTmp[RTPATH_MAX + 1];
+ unsigned offPathTmp = 0;
+
+ /* Create the part to go up from pszPathFrom. */
+ while (*pszPathFrom != '\0')
+ {
+ while ( !RTPATH_IS_SEP(*pszPathFrom)
+ && *pszPathFrom != '\0')
+ pszPathFrom++;
+
+ if (RTPATH_IS_SEP(*pszPathFrom))
+ {
+ if (offPathTmp + 3 >= sizeof(aszPathTmp) - 1)
+ return VERR_FILENAME_TOO_LONG;
+ aszPathTmp[offPathTmp++] = '.';
+ aszPathTmp[offPathTmp++] = '.';
+ aszPathTmp[offPathTmp++] = RTPATH_SLASH;
+ pszPathFrom++;
+ }
+ }
+
+ aszPathTmp[offPathTmp] = '\0';
+
+ /* Now append the rest of pszPathTo to the final path. */
+ char *pszPathTmp = &aszPathTmp[offPathTmp];
+ size_t cbPathTmp = sizeof(aszPathTmp) - offPathTmp - 1;
+ rc = RTStrCatP(&pszPathTmp, &cbPathTmp, pszPathTo);
+ if (RT_SUCCESS(rc))
+ {
+ *pszPathTmp = '\0';
+
+ size_t cchPathTmp = strlen(aszPathTmp);
+ if (cchPathTmp >= cbPathDst)
+ return VERR_BUFFER_OVERFLOW;
+ memcpy(pszPathDst, aszPathTmp, cchPathTmp + 1);
+ }
+ else
+ rc = VERR_FILENAME_TOO_LONG;
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathExt.cpp b/src/VBox/Runtime/common/path/RTPathExt.cpp
index 292c5f2f..bb2ee52e 100644
--- a/src/VBox/Runtime/common/path/RTPathExt.cpp
+++ b/src/VBox/Runtime/common/path/RTPathExt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathFilename.cpp b/src/VBox/Runtime/common/path/RTPathFilename.cpp
index 2eeaba5e..3278383d 100644
--- a/src/VBox/Runtime/common/path/RTPathFilename.cpp
+++ b/src/VBox/Runtime/common/path/RTPathFilename.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -30,46 +30,70 @@
*******************************************************************************/
#include "internal/iprt.h"
#include <iprt/path.h>
-#include <iprt/string.h>
+
+#include <iprt/assert.h>
-/**
- * Finds the filename in a path.
- *
- * @returns Pointer to filename within pszPath.
- * @returns NULL if no filename (i.e. empty string or ends with a slash).
- * @param pszPath Path to find filename in.
- */
RTDECL(char *) RTPathFilename(const char *pszPath)
{
+ return RTPathFilenameEx(pszPath, RTPATH_STYLE);
+}
+RT_EXPORT_SYMBOL(RTPathFilename);
+
+
+RTDECL(char *) RTPathFilenameEx(const char *pszPath, uint32_t fFlags)
+{
const char *psz = pszPath;
const char *pszName = pszPath;
- for (;; psz++)
+ Assert(RTPATH_STR_F_IS_VALID(fFlags, 0 /*no extra flags*/));
+ fFlags &= RTPATH_STR_F_STYLE_MASK;
+ if (fFlags == RTPATH_STR_F_STYLE_HOST)
+ fFlags = RTPATH_STYLE;
+ if (fFlags == RTPATH_STR_F_STYLE_DOS)
{
- switch (*psz)
+ for (;; psz++)
{
- /* handle separators. */
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
- case ':':
- pszName = psz + 1;
- break;
+ switch (*psz)
+ {
+ /* handle separators. */
+ case ':':
+ case '\\':
+ case '/':
+ pszName = psz + 1;
+ break;
- case '\\':
-#endif
- case '/':
- pszName = psz + 1;
- break;
+ /* the end */
+ case '\0':
+ if (*pszName)
+ return (char *)(void *)pszName;
+ return NULL;
+ }
+ }
+ }
+ else
+ {
+ Assert(fFlags == RTPATH_STR_F_STYLE_UNIX);
+ for (;; psz++)
+ {
+ switch (*psz)
+ {
+ /* handle separators. */
+ case '/':
+ pszName = psz + 1;
+ break;
- /* the end */
- case '\0':
- if (*pszName)
- return (char *)(void *)pszName;
- return NULL;
+ /* the end */
+ case '\0':
+ if (*pszName)
+ return (char *)(void *)pszName;
+ return NULL;
+ }
}
}
/* not reached */
}
+RT_EXPORT_SYMBOL(RTPathFilenameEx);
diff --git a/src/VBox/Runtime/common/path/RTPathParse.cpp b/src/VBox/Runtime/common/path/RTPathParse.cpp
index ce42e330..3ead6908 100644
--- a/src/VBox/Runtime/common/path/RTPathParse.cpp
+++ b/src/VBox/Runtime/common/path/RTPathParse.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2013 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
@@ -31,88 +31,45 @@
#include "internal/iprt.h"
#include <iprt/path.h>
+#include <iprt/assert.h>
+#include <iprt/ctype.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
-/**
- * Parses a path.
- *
- * It figures the length of the directory component, the offset of
- * the file name and the location of the suffix dot.
- *
- * @returns The path length.
- *
- * @param pszPath Path to find filename in.
- * @param pcchDir Where to put the length of the directory component. If
- * no directory, this will be 0. Optional.
- * @param poffName Where to store the filename offset.
- * If empty string or if it's ending with a slash this
- * will be set to -1. Optional.
- * @param poffSuff Where to store the suffix offset (the last dot).
- * If empty string or if it's ending with a slash this
- * will be set to -1. Optional.
- */
-RTDECL(size_t) RTPathParse(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff)
+#define RTPATH_TEMPLATE_CPP_H "RTPathParse.cpp.h"
+#include "rtpath-expand-template.cpp.h"
+
+
+RTDECL(int) RTPathParse(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags)
{
- const char *psz = pszPath;
- ssize_t offRoot = 0;
- const char *pszName = pszPath;
- const char *pszLastDot = NULL;
+ /*
+ * Input validation.
+ */
+ AssertReturn(cbParsed >= RT_UOFFSETOF(RTPATHPARSED, aComps), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(*pszPath, VERR_PATH_ZERO_LENGTH);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0), VERR_INVALID_FLAGS);
- for (;; psz++)
+ /*
+ * Invoke the worker for the selected path style.
+ */
+ switch (fFlags & RTPATH_STR_F_STYLE_MASK)
{
- switch (*psz)
- {
- /* handle separators. */
-#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
- case ':':
- pszName = psz + 1;
- offRoot = pszName - psz;
- break;
-
- case '\\':
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+ case RTPATH_STR_F_STYLE_HOST:
#endif
- case '/':
- pszName = psz + 1;
- break;
-
- case '.':
- pszLastDot = psz;
- break;
-
- /*
- * The end. Complete the results.
- */
- case '\0':
- {
- ssize_t offName = *pszName != '\0' ? pszName - pszPath : -1;
- if (poffName)
- *poffName = offName;
+ case RTPATH_STR_F_STYLE_DOS:
+ return rtPathParseStyleDos(pszPath, pParsed, cbParsed, fFlags);
- if (poffSuff)
- {
- ssize_t offSuff = -1;
- if (pszLastDot)
- {
- offSuff = pszLastDot - pszPath;
- if (offSuff <= offName)
- offSuff = -1;
- }
- *poffSuff = offSuff;
- }
-
- if (pcchDir)
- {
- ssize_t off = offName - 1;
- while (off >= offRoot && RTPATH_IS_SLASH(pszPath[off]))
- off--;
- *pcchDir = RT_MAX(off, offRoot) + 1;
- }
+#if !defined(RT_OS_OS2) && !defined(RT_OS_WINDOWS)
+ case RTPATH_STR_F_STYLE_HOST:
+#endif
+ case RTPATH_STR_F_STYLE_UNIX:
+ return rtPathParseStyleUnix(pszPath, pParsed, cbParsed, fFlags);
- return psz - pszPath;
- }
- }
+ default:
+ AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */
}
-
- /* will never get here */
- return 0;
}
diff --git a/src/VBox/Runtime/common/path/RTPathParse.cpp.h b/src/VBox/Runtime/common/path/RTPathParse.cpp.h
new file mode 100644
index 00000000..bef8e7a1
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathParse.cpp.h
@@ -0,0 +1,250 @@
+/* $Id: RTPathParse.cpp.h $ */
+/** @file
+ * IPRT - RTPathParse - Code Template.
+ *
+ * This file included multiple times with different path style macros.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+
+/**
+ * @copydoc RTPathParse
+ */
+static int RTPATH_STYLE_FN(rtPathParse)(const char *pszPath, PRTPATHPARSED pParsed, size_t cbParsed, uint32_t fFlags)
+{
+ /*
+ * Parse the root specification if present and initialize the parser state
+ * (keep it on the stack for speed).
+ */
+ uint32_t const cMaxComps = cbParsed < RT_UOFFSETOF(RTPATHPARSED, aComps[0xfff0])
+ ? (uint32_t)((cbParsed - RT_UOFFSETOF(RTPATHPARSED, aComps)) / sizeof(pParsed->aComps[0]))
+ : 0xfff0;
+ uint32_t idxComp = 0;
+ uint32_t cchPath;
+ uint32_t offCur;
+ uint16_t fProps;
+
+ if (RTPATH_IS_SLASH(pszPath[0]))
+ {
+ if (fFlags & RTPATH_STR_F_NO_START)
+ {
+ offCur = 1;
+ while (RTPATH_IS_SLASH(pszPath[offCur]))
+ offCur++;
+ if (!pszPath[offCur])
+ return VERR_PATH_ZERO_LENGTH;
+ fProps = RTPATH_PROP_RELATIVE | RTPATH_PROP_EXTRA_SLASHES;
+ cchPath = 0;
+ }
+#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+ else if ( RTPATH_IS_SLASH(pszPath[1])
+ && !RTPATH_IS_SLASH(pszPath[2])
+ && pszPath[2])
+ {
+ /* UNC - skip to the end of the potential namespace or computer name. */
+ offCur = 2;
+ while (!RTPATH_IS_SLASH(pszPath[offCur]) && pszPath[offCur])
+ offCur++;
+
+ /* If there is another slash, we considered it a valid UNC path, if
+ not it's just a root path with an extra slash thrown in. */
+ if (RTPATH_IS_SLASH(pszPath[offCur]))
+ {
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_UNC | RTPATH_PROP_ABSOLUTE;
+ offCur++;
+ cchPath = offCur;
+ }
+ else
+ {
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE;
+ offCur = 1;
+ cchPath = 1;
+ }
+ }
+#endif
+ else
+ {
+#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_RELATIVE;
+#else
+ fProps = RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE;
+#endif
+ offCur = 1;
+ cchPath = 1;
+ }
+ }
+#if RTPATH_STYLE == RTPATH_STR_F_STYLE_DOS
+ else if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
+ {
+ if (!RTPATH_IS_SLASH(pszPath[2]))
+ {
+ fProps = RTPATH_PROP_VOLUME | RTPATH_PROP_RELATIVE;
+ offCur = 2;
+ }
+ else
+ {
+ fProps = RTPATH_PROP_VOLUME | RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_ABSOLUTE;
+ offCur = 3;
+ }
+ cchPath = offCur;
+ }
+#endif
+ else
+ {
+ fProps = RTPATH_PROP_RELATIVE;
+ offCur = 0;
+ cchPath = 0;
+ }
+
+ /* Add it to the component array . */
+ if (offCur && !(fFlags & RTPATH_STR_F_NO_START))
+ {
+ cchPath = offCur;
+ if (idxComp < cMaxComps)
+ {
+ pParsed->aComps[idxComp].off = 0;
+ pParsed->aComps[idxComp].cch = offCur;
+ }
+ idxComp++;
+
+ /* Skip unnecessary slashes following the root-spec. */
+ if (RTPATH_IS_SLASH(pszPath[offCur]))
+ {
+ fProps |= RTPATH_PROP_EXTRA_SLASHES;
+ do
+ offCur++;
+ while (RTPATH_IS_SLASH(pszPath[offCur]));
+ }
+ }
+
+ /*
+ * Parse the rest.
+ */
+ if (pszPath[offCur])
+ {
+ for (;;)
+ {
+ Assert(!RTPATH_IS_SLASH(pszPath[offCur]));
+
+ /* Find the end of the component. */
+ uint32_t offStart = offCur;
+ char ch;
+ while ((ch = pszPath[offCur]) != '\0' && !RTPATH_IS_SLASH(ch))
+ offCur++;
+ if (offCur >= _64K)
+ return VERR_FILENAME_TOO_LONG;
+
+ /* Add it. */
+ uint32_t cchComp = offCur - offStart;
+ if (idxComp < cMaxComps)
+ {
+ pParsed->aComps[idxComp].off = offStart;
+ pParsed->aComps[idxComp].cch = cchComp;
+ }
+ idxComp++;
+ cchPath += cchComp;
+
+ /* Look for '.' and '..' references. */
+ if (cchComp == 1 && pszPath[offCur - 1] == '.')
+ fProps |= RTPATH_PROP_DOT_REFS;
+ else if (cchComp == 2 && pszPath[offCur - 1] == '.' && pszPath[offCur - 2] == '.')
+ {
+ fProps &= ~RTPATH_PROP_ABSOLUTE;
+ fProps |= RTPATH_PROP_DOTDOT_REFS | RTPATH_PROP_RELATIVE;
+ }
+
+ /* Skip unnecessary slashes. Leave ch unchanged! */
+ char ch2 = ch;
+ if (ch2)
+ {
+ ch2 = pszPath[++offCur];
+ if (RTPATH_IS_SLASH(ch2))
+ {
+ fProps |= RTPATH_PROP_EXTRA_SLASHES;
+ do
+ ch2 = pszPath[++offCur];
+ while (RTPATH_IS_SLASH(ch2));
+ }
+ }
+
+ /* The end? */
+ if (ch2 == '\0')
+ {
+ pParsed->offSuffix = offCur;
+ pParsed->cchSuffix = 0;
+ if (ch)
+ {
+ if (!(fFlags & RTPATH_STR_F_NO_END))
+ {
+ fProps |= RTPATH_PROP_DIR_SLASH; /* (not counted in component, but in cchPath) */
+ cchPath++;
+ }
+ else
+ fProps |= RTPATH_PROP_EXTRA_SLASHES;
+ }
+ else if (!(fFlags & RTPATH_STR_F_NO_END))
+ {
+ fProps |= RTPATH_PROP_FILENAME;
+
+ /* look for an ? */
+ uint16_t cDots = 0;
+ uint32_t offSuffix = offStart + cchComp;
+ while (offSuffix-- > offStart)
+ if (pszPath[offSuffix] == '.')
+ {
+ uint32_t cchSuffix = offStart + cchComp - offSuffix;
+ if (cchSuffix > 1 && offStart != offSuffix)
+ {
+ pParsed->cchSuffix = cchSuffix;
+ pParsed->offSuffix = offSuffix;
+ fProps |= RTPATH_PROP_SUFFIX;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ /* No, not the end. Account for an separator before we restart the loop. */
+ cchPath += sizeof(RTPATH_SLASH_STR) - 1;
+ }
+ }
+ else
+ {
+ pParsed->offSuffix = offCur;
+ pParsed->cchSuffix = 0;
+ }
+ if (offCur >= _64K)
+ return VERR_FILENAME_TOO_LONG;
+
+ /*
+ * Store the remainder of the state and we're done.
+ */
+ pParsed->fProps = fProps;
+ pParsed->cchPath = cchPath;
+ pParsed->cComps = idxComp;
+
+ return idxComp <= cMaxComps ? VINF_SUCCESS : VERR_BUFFER_OVERFLOW;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathParseSimple.cpp b/src/VBox/Runtime/common/path/RTPathParseSimple.cpp
new file mode 100644
index 00000000..f6de9aa2
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathParseSimple.cpp
@@ -0,0 +1,118 @@
+/* $Id: RTPathParseSimple.cpp $ */
+/** @file
+ * IPRT - RTPathParseSimple
+ */
+
+/*
+ * Copyright (C) 2006-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+
+/**
+ * Parses a path.
+ *
+ * It figures the length of the directory component, the offset of
+ * the file name and the location of the suffix dot.
+ *
+ * @returns The path length.
+ *
+ * @param pszPath Path to find filename in.
+ * @param pcchDir Where to put the length of the directory component. If
+ * no directory, this will be 0. Optional.
+ * @param poffName Where to store the filename offset.
+ * If empty string or if it's ending with a slash this
+ * will be set to -1. Optional.
+ * @param poffSuff Where to store the suffix offset (the last dot).
+ * If empty string or if it's ending with a slash this
+ * will be set to -1. Optional.
+ */
+RTDECL(size_t) RTPathParseSimple(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff)
+{
+ const char *psz = pszPath;
+ ssize_t offRoot = 0;
+ const char *pszName = pszPath;
+ const char *pszLastDot = NULL;
+
+ for (;; psz++)
+ {
+ switch (*psz)
+ {
+ /* handle separators. */
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+ case ':':
+ pszName = psz + 1;
+ offRoot = pszName - psz;
+ break;
+
+ case '\\':
+#endif
+ case '/':
+ pszName = psz + 1;
+ break;
+
+ case '.':
+ pszLastDot = psz;
+ break;
+
+ /*
+ * The end. Complete the results.
+ */
+ case '\0':
+ {
+ ssize_t offName = *pszName != '\0' ? pszName - pszPath : -1;
+ if (poffName)
+ *poffName = offName;
+
+ if (poffSuff)
+ {
+ ssize_t offSuff = -1;
+ if (pszLastDot)
+ {
+ offSuff = pszLastDot - pszPath;
+ if (offSuff <= offName)
+ offSuff = -1;
+ }
+ *poffSuff = offSuff;
+ }
+
+ if (pcchDir)
+ {
+ ssize_t off = offName - 1;
+ while (off >= offRoot && RTPATH_IS_SLASH(pszPath[off]))
+ off--;
+ *pcchDir = RT_MAX(off, offRoot) + 1;
+ }
+
+ return psz - pszPath;
+ }
+ }
+ }
+
+ /* will never get here */
+ return 0;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp b/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp
new file mode 100644
index 00000000..5ba842c0
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathParsedReassemble.cpp
@@ -0,0 +1,122 @@
+/* $Id: RTPathParsedReassemble.cpp $ */
+/** @file
+ * IPRT - RTPathParsedReassemble.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTPathParsedReassemble(const char *pszSrcPath, PRTPATHPARSED pParsed, uint32_t fFlags,
+ char *pszDstPath, size_t cbDstPath)
+{
+ /*
+ * Input validation.
+ */
+ AssertPtrReturn(pszSrcPath, VERR_INVALID_POINTER);
+ AssertPtrReturn(pParsed, VERR_INVALID_POINTER);
+ AssertReturn(pParsed->cComps > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0) && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
+ AssertPtrReturn(pszDstPath, VERR_INVALID_POINTER);
+ AssertReturn(cbDstPath > pParsed->cchPath, VERR_BUFFER_OVERFLOW);
+
+ /*
+ * Figure which slash to use.
+ */
+ char chSlash;
+ switch (fFlags & RTPATH_STR_F_STYLE_MASK)
+ {
+ case RTPATH_STR_F_STYLE_HOST:
+ chSlash = RTPATH_SLASH;
+ break;
+
+ case RTPATH_STR_F_STYLE_DOS:
+ chSlash = '\\';
+ break;
+
+ case RTPATH_STR_F_STYLE_UNIX:
+ chSlash = '/';
+ break;
+
+ default:
+ AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */
+ }
+
+ /*
+ * Do the joining.
+ */
+ uint32_t const cchOrgPath = pParsed->cchPath;
+ uint32_t cchDstPath = 0;
+ uint32_t const cComps = pParsed->cComps;
+ uint32_t idxComp = 0;
+ char *pszDst = pszDstPath;
+ uint32_t cchComp;
+
+ if (RTPATH_PROP_HAS_ROOT_SPEC(pParsed->fProps))
+ {
+ cchComp = pParsed->aComps[0].cch;
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, &pszSrcPath[pParsed->aComps[0].off], cchComp);
+
+ /* fix the slashes */
+ char chOtherSlash = chSlash == '\\' ? '/' : '\\';
+ while (cchComp-- > 0)
+ {
+ if (*pszDst == chOtherSlash)
+ *pszDst = chSlash;
+ pszDst++;
+ }
+ idxComp = 1;
+ }
+
+ while (idxComp < cComps)
+ {
+ cchComp = pParsed->aComps[idxComp].cch;
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, &pszSrcPath[pParsed->aComps[idxComp].off], cchComp);
+ pszDst += cchComp;
+ idxComp++;
+ if (idxComp != cComps || (pParsed->fProps & RTPATH_PROP_DIR_SLASH))
+ {
+ cchDstPath++;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ *pszDst++ = chSlash;
+ }
+ }
+
+ *pszDst = '\0';
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathRealDup.cpp b/src/VBox/Runtime/common/path/RTPathRealDup.cpp
index 18ce0a82..c0d84e40 100644
--- a/src/VBox/Runtime/common/path/RTPathRealDup.cpp
+++ b/src/VBox/Runtime/common/path/RTPathRealDup.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathRmCmd.cpp b/src/VBox/Runtime/common/path/RTPathRmCmd.cpp
new file mode 100644
index 00000000..cfb9b73b
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathRmCmd.cpp
@@ -0,0 +1,648 @@
+/* $Id: RTPathRmCmd.cpp $ */
+/** @file
+ * IPRT - TAR Command.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include <iprt/path.h>
+
+#include <iprt/buildconfig.h>
+#include <iprt/ctype.h>
+#include <iprt/file.h>
+#include <iprt/dir.h>
+#include <iprt/getopt.h>
+#include <iprt/initterm.h>
+#include <iprt/message.h>
+#include <iprt/stream.h>
+#include <iprt/string.h>
+#include <iprt/symlink.h>
+
+
+/*******************************************************************************
+* Defined Constants And Macros *
+*******************************************************************************/
+#define RTPATHRMCMD_OPT_INTERACTIVE 1000
+#define RTPATHRMCMD_OPT_ONE_FILE_SYSTEM 1001
+#define RTPATHRMCMD_OPT_PRESERVE_ROOT 1002
+#define RTPATHRMCMD_OPT_NO_PRESERVE_ROOT 1003
+#define RTPATHRMCMD_OPT_MACHINE_READABLE 1004
+
+/** The max directory entry size. */
+#define RTPATHRM_DIR_MAX_ENTRY_SIZE (sizeof(RTDIRENTRYEX) + 4096)
+
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+/** Interactive option. */
+typedef enum
+{
+ RTPATHRMCMDINTERACTIVE_NONE = 1,
+ RTPATHRMCMDINTERACTIVE_ALL,
+ RTPATHRMCMDINTERACTIVE_ONCE
+ /** @todo possible that we should by default prompt if removing read-only
+ * files or files owned by someone else. We currently don't. */
+} RTPATHRMCMDINTERACTIVE;
+
+/**
+ * IPRT rm option structure.
+ */
+typedef struct RTPATHRMCMDOPTS
+{
+ /** Whether to delete recursively. */
+ bool fRecursive;
+ /** Whether to delete directories as well as other kinds of files. */
+ bool fDirsAndOther;
+ /** Whether to remove files without prompting and ignoring non-existing
+ * files. */
+ bool fForce;
+ /** Machine readable output. */
+ bool fMachineReadable;
+ /** Don't try remove root ('/') if set, otherwise don't treat root specially. */
+ bool fPreserveRoot;
+ /** Whether to keep to one file system. */
+ bool fOneFileSystem;
+ /** Whether to safely delete files (overwrite 3x before unlinking). */
+ bool fSafeDelete;
+ /** Whether to be verbose about the operation. */
+ bool fVerbose;
+ /** The interactive setting. */
+ RTPATHRMCMDINTERACTIVE enmInteractive;
+} RTPATHRMCMDOPTS;
+/** Pointer to the IPRT rm options. */
+typedef RTPATHRMCMDOPTS *PRTPATHRMCMDOPTS;
+
+
+/*******************************************************************************
+* Global Variables *
+*******************************************************************************/
+/** A bunch of zeros. */
+static uint8_t const g_abZeros[16384] = { 0 };
+/** A bunch of 0xFF bytes. (lazy init) */
+static uint8_t g_ab0xFF[16384];
+
+
+static void rtPathRmVerbose(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ if (!pOpts->fMachineReadable)
+ RTPrintf("%s\n", pszPath);
+}
+
+
+static int rtPathRmError(PRTPATHRMCMDOPTS pOpts, const char *pszPath, int rc,
+ const char *pszFormat, ...)
+{
+ if (pOpts->fMachineReadable)
+ RTPrintf("fname=%s%crc=%d%c", pszPath, rc);
+ else
+ {
+ va_list va;
+ va_start(va, pszFormat);
+ RTMsgErrorV(pszFormat, va);
+ va_end(va);
+ }
+ return rc;
+}
+
+
+/**
+ * Worker that removes a symbolic link.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the symbolic link.
+ */
+static int rtPathRmOneSymlink(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ if (pOpts->fVerbose)
+ rtPathRmVerbose(pOpts, pszPath);
+ int rc = RTSymlinkDelete(pszPath, 0);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error removing symbolic link '%s': %Rrc\n", pszPath, rc);
+ return rc;
+}
+
+
+/**
+ * Worker that removes a file.
+ *
+ * Currently used to delete both regular and special files.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the file.
+ * @param pObjInfo The FS object info for the file.
+ */
+static int rtPathRmOneFile(PRTPATHRMCMDOPTS pOpts, const char *pszPath, PRTFSOBJINFO pObjInfo)
+{
+ int rc;
+ if (pOpts->fVerbose)
+ rtPathRmVerbose(pOpts, pszPath);
+
+ /*
+ * Wipe the file if requested and possible.
+ */
+ if (pOpts->fSafeDelete && RTFS_IS_FILE(pObjInfo->Attr.fMode))
+ {
+ /* Lazy init of the 0xff buffer. */
+ if (g_ab0xFF[0] != 0xff || g_ab0xFF[sizeof(g_ab0xFF) - 1] != 0xff)
+ memset(g_ab0xFF, 0xff, sizeof(g_ab0xFF));
+
+ RTFILE hFile;
+ rc = RTFileOpen(&hFile, pszPath, RTFILE_O_WRITE);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Opening '%s' for overwriting: %Rrc\n", pszPath, rc);
+
+ for (unsigned iPass = 0; iPass < 3; iPass++)
+ {
+ uint8_t const *pabFiller = iPass == 1 ? g_abZeros : g_ab0xFF;
+ size_t const cbFiller = iPass == 1 ? sizeof(g_abZeros) : sizeof(g_ab0xFF);
+
+ rc = RTFileSeek(hFile, 0, RTFILE_SEEK_BEGIN, NULL);
+ if (RT_FAILURE(rc))
+ {
+ rc = rtPathRmError(pOpts, pszPath, rc, "Error seeking to start of '%s': %Rrc\n", pszPath, rc);
+ break;
+ }
+ for (RTFOFF cbLeft = pObjInfo->cbObject; cbLeft > 0; cbLeft -= cbFiller)
+ {
+ size_t cbToWrite = cbFiller;
+ if (cbLeft < (RTFOFF)cbToWrite)
+ cbToWrite = (size_t)cbLeft;
+ rc = RTFileWrite(hFile, pabFiller, cbToWrite, NULL);
+ if (RT_FAILURE(rc))
+ {
+ rc = rtPathRmError(pOpts, pszPath, rc, "Error writing to '%s': %Rrc\n", pszPath, rc);
+ break;
+ }
+ }
+ }
+
+ int rc2 = RTFileClose(hFile);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+ return rtPathRmError(pOpts, pszPath, rc2, "Closing '%s' failed: %Rrc\n", pszPath, rc);
+ if (RT_FAILURE(rc))
+ return rc;
+ }
+
+ /*
+ * Remove the file.
+ */
+ rc = RTFileDelete(pszPath);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc,
+ RTFS_IS_FILE(pObjInfo->Attr.fMode)
+ ? "Error removing regular file '%s': %Rrc\n"
+ : "Error removing special file '%s': %Rrc\n",
+ pszPath, rc);
+ return rc;
+}
+
+
+/**
+ * Deletes one directory (if it's empty).
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the directory.
+ */
+static int rtPathRmOneDir(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ if (pOpts->fVerbose)
+ rtPathRmVerbose(pOpts, pszPath);
+
+ int rc = RTDirRemove(pszPath);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error removing directory '%s': %Rrc", pszPath, rc);
+ return rc;
+}
+
+
+/**
+ * Recursively delete a directory.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath Pointer to a writable buffer holding the path to
+ * the directory.
+ * @param cchPath The length of the path (avoid strlen).
+ * @param pDirEntry Pointer to a directory entry buffer that is
+ * RTPATHRM_DIR_MAX_ENTRY_SIZE bytes big.
+ */
+static int rtPathRmRecursive(PRTPATHRMCMDOPTS pOpts, char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry)
+{
+ /*
+ * Make sure the path ends with a slash.
+ */
+ if (!cchPath || !RTPATH_IS_SLASH(pszPath[cchPath - 1]))
+ {
+ if (cchPath + 1 >= RTPATH_MAX)
+ return rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Buffer overflow fixing up '%s'.\n", pszPath);
+ pszPath[cchPath++] = RTPATH_SLASH;
+ pszPath[cchPath] = '\0';
+ }
+
+ /*
+ * Traverse the directory.
+ */
+ PRTDIR hDir;
+ int rc = RTDirOpen(&hDir, pszPath);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error opening directory '%s': %Rrc", pszPath, rc);
+ int rcRet = VINF_SUCCESS;
+ for (;;)
+ {
+ /*
+ * Read the next entry, constructing an full path for it.
+ */
+ size_t cbEntry = RTPATHRM_DIR_MAX_ENTRY_SIZE;
+ rc = RTDirReadEx(hDir, pDirEntry, &cbEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+ if (rc == VERR_NO_MORE_FILES)
+ {
+ /*
+ * Reached the end of the directory.
+ */
+ pszPath[cchPath] = '\0';
+ rc = RTDirClose(hDir);
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "Error closing directory '%s': %Rrc", pszPath, rc);
+
+ /* Delete the directory. */
+ int rc2 = rtPathRmOneDir(pOpts, pszPath);
+ if (RT_FAILURE(rc2) && RT_SUCCESS(rcRet))
+ return rc2;
+ return rcRet;
+ }
+
+ if (RT_FAILURE(rc))
+ {
+ rc = rtPathRmError(pOpts, pszPath, rc, "Error reading directory '%s': %Rrc", pszPath, rc);
+ break;
+ }
+
+ /* Skip '.' and '..'. */
+ if ( pDirEntry->szName[0] == '.'
+ && ( pDirEntry->cbName == 1
+ || ( pDirEntry->cbName == 2
+ && pDirEntry->szName[1] == '.')))
+ continue;
+
+ /* Construct full path. */
+ if (cchPath + pDirEntry->cbName >= RTPATH_MAX)
+ {
+ pszPath[cchPath] = '\0';
+ rc = rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Path buffer overflow in directory '%s'.", pszPath);
+ break;
+ }
+ memcpy(pszPath + cchPath, pDirEntry->szName, pDirEntry->cbName + 1);
+
+ /*
+ * Take action according to the type.
+ */
+ switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FILE:
+ rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
+ break;
+
+ case RTFS_TYPE_DIRECTORY:
+ rc = rtPathRmRecursive(pOpts, pszPath, cchPath + pDirEntry->cbName, pDirEntry);
+ break;
+
+ case RTFS_TYPE_SYMLINK:
+ rc = rtPathRmOneSymlink(pOpts, pszPath);
+ break;
+
+ case RTFS_TYPE_FIFO:
+ case RTFS_TYPE_DEV_CHAR:
+ case RTFS_TYPE_DEV_BLOCK:
+ case RTFS_TYPE_SOCKET:
+ rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
+ break;
+
+ case RTFS_TYPE_WHITEOUT:
+ default:
+ rc = rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE,
+ "Object '%s' has an unknown file type: %o\n",
+ pszPath, pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK);
+ break;
+ }
+ if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
+ rcRet = rc;
+ }
+
+ /*
+ * Some error occured, close and return.
+ */
+ RTDirClose(hDir);
+ return rc;
+}
+
+/**
+ * Validates the specified file or directory.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the file, directory, whatever.
+ */
+static int rtPathRmOneValidate(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ /*
+ * RTPathFilename doesn't do the trailing slash thing the way we need it to.
+ * E.g. both '..' and '../' should be rejected.
+ */
+ size_t cchPath = strlen(pszPath);
+ while (cchPath > 0 && RTPATH_IS_SLASH(pszPath[cchPath - 1]))
+ cchPath--;
+
+ if ( ( cchPath == 0
+ || 0 /** @todo drive letter + UNC crap */)
+ && pOpts->fPreserveRoot)
+ return rtPathRmError(pOpts, pszPath, VERR_CANT_DELETE_DIRECTORY, "Cannot remove root directory ('%s').\n", pszPath);
+
+ size_t offLast = cchPath - 1;
+ while (offLast > 0 && !RTPATH_IS_SEP(pszPath[offLast - 1]))
+ offLast--;
+
+ size_t cchLast = cchPath - offLast;
+ if ( pszPath[offLast] == '.'
+ && ( cchLast == 1
+ || (cchLast == 2 && pszPath[offLast + 1] == '.')))
+ return rtPathRmError(pOpts, pszPath, VERR_CANT_DELETE_DIRECTORY, "Cannot remove special directory '%s'.\n", pszPath);
+
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * Remove one user specified file or directory.
+ *
+ * @returns IPRT status code, errors go via rtPathRmError.
+ * @param pOpts The RM options.
+ * @param pszPath The path to the file, directory, whatever.
+ */
+static int rtPathRmOne(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
+{
+ /*
+ * RM refuses to delete some directories.
+ */
+ int rc = rtPathRmOneValidate(pOpts, pszPath);
+ if (RT_FAILURE(rc))
+ return rc;
+
+ /*
+ * Query file system object info.
+ */
+ RTFSOBJINFO ObjInfo;
+ rc = RTPathQueryInfoEx(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
+ if (RT_FAILURE(rc))
+ {
+ if (pOpts->fForce && (rc == VERR_FILE_NOT_FOUND || rc == VERR_PATH_NOT_FOUND))
+ return VINF_SUCCESS;
+ return rtPathRmError(pOpts, pszPath, rc, "Error deleting '%s': %Rrc", pszPath, rc);
+ }
+
+ /*
+ * Take type specific action.
+ */
+ switch (ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+ {
+ case RTFS_TYPE_FILE:
+ return rtPathRmOneFile(pOpts, pszPath, &ObjInfo);
+
+ case RTFS_TYPE_DIRECTORY:
+ if (pOpts->fRecursive)
+ {
+ char szPath[RTPATH_MAX];
+ rc = RTPathAbs(pszPath, szPath, sizeof(szPath));
+ if (RT_FAILURE(rc))
+ return rtPathRmError(pOpts, pszPath, rc, "RTPathAbs failed on '%s': %Rrc\n", pszPath, rc);
+
+ union
+ {
+ RTDIRENTRYEX Core;
+ uint8_t abPadding[RTPATHRM_DIR_MAX_ENTRY_SIZE];
+ } DirEntry;
+
+ return rtPathRmRecursive(pOpts, szPath, strlen(szPath), &DirEntry.Core);
+ }
+ if (pOpts->fDirsAndOther)
+ return rtPathRmOneDir(pOpts, pszPath);
+ return rtPathRmError(pOpts, pszPath, VERR_IS_A_DIRECTORY, "Cannot remove '%s': %Rrc\n", pszPath, VERR_IS_A_DIRECTORY);
+
+ case RTFS_TYPE_SYMLINK:
+ return rtPathRmOneSymlink(pOpts, pszPath);
+
+ case RTFS_TYPE_FIFO:
+ case RTFS_TYPE_DEV_CHAR:
+ case RTFS_TYPE_DEV_BLOCK:
+ case RTFS_TYPE_SOCKET:
+ return rtPathRmOneFile(pOpts, pszPath, &ObjInfo);
+
+ case RTFS_TYPE_WHITEOUT:
+ default:
+ return rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE,
+ "Object '%s' has an unknown file type: %o\n", pszPath, ObjInfo.Attr.fMode & RTFS_TYPE_MASK);
+
+ }
+}
+
+
+RTDECL(RTEXITCODE) RTPathRmCmd(unsigned cArgs, char **papszArgs)
+{
+ /*
+ * Parse the command line.
+ */
+ static const RTGETOPTDEF s_aOptions[] =
+ {
+ /* operations */
+ { "--dirs-and-more", 'd', RTGETOPT_REQ_NOTHING },
+ { "--force", 'f', RTGETOPT_REQ_NOTHING },
+ { "--prompt", 'i', RTGETOPT_REQ_NOTHING },
+ { "--prompt-once", 'I', RTGETOPT_REQ_NOTHING },
+ { "--interactive", RTPATHRMCMD_OPT_INTERACTIVE, RTGETOPT_REQ_STRING },
+ { "--one-file-system", RTPATHRMCMD_OPT_ONE_FILE_SYSTEM, RTGETOPT_REQ_NOTHING },
+ { "--preserve-root", RTPATHRMCMD_OPT_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING },
+ { "--no-preserve-root", RTPATHRMCMD_OPT_NO_PRESERVE_ROOT, RTGETOPT_REQ_NOTHING },
+ { "--recursive", 'R', RTGETOPT_REQ_NOTHING },
+ { "--recursive", 'r', RTGETOPT_REQ_NOTHING },
+ { "--safe-delete", 'P', RTGETOPT_REQ_NOTHING },
+ { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+
+ /* IPRT extensions */
+ { "--machine-readable", RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING },
+ { "--machinereadable", RTPATHRMCMD_OPT_MACHINE_READABLE, RTGETOPT_REQ_NOTHING }, /* bad long option style */
+ };
+
+ RTGETOPTSTATE GetState;
+ int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1,
+ RTGETOPTINIT_FLAGS_OPTS_FIRST);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTGetOpt failed: %Rrc", rc);
+
+ RTPATHRMCMDOPTS Opts;
+ RT_ZERO(Opts);
+ Opts.fPreserveRoot = true;
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE;
+
+ RTGETOPTUNION ValueUnion;
+ while ( (rc = RTGetOpt(&GetState, &ValueUnion)) != 0
+ && rc != VINF_GETOPT_NOT_OPTION)
+ {
+ switch (rc)
+ {
+ case 'd':
+ Opts.fDirsAndOther = true;
+ break;
+
+ case 'f':
+ Opts.fForce = true;
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_NONE;
+ break;
+
+ case 'i':
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL;
+ break;
+
+ case 'I':
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE;
+ break;
+
+ case RTPATHRMCMD_OPT_INTERACTIVE:
+ if (!strcmp(ValueUnion.psz, "always"))
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ALL;
+ else if (!strcmp(ValueUnion.psz, "once"))
+ Opts.enmInteractive = RTPATHRMCMDINTERACTIVE_ONCE;
+ else
+ return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown --interactive option value: '%s'\n", ValueUnion.psz);
+ break;
+
+ case RTPATHRMCMD_OPT_ONE_FILE_SYSTEM:
+ Opts.fOneFileSystem = true;
+ break;
+
+ case RTPATHRMCMD_OPT_PRESERVE_ROOT:
+ Opts.fPreserveRoot = true;
+ break;
+
+ case RTPATHRMCMD_OPT_NO_PRESERVE_ROOT:
+ Opts.fPreserveRoot = false;
+ break;
+
+ case 'R':
+ case 'r':
+ Opts.fRecursive = true;
+ Opts.fDirsAndOther = true;
+ break;
+
+ case 'P':
+ Opts.fSafeDelete = true;
+ break;
+
+ case 'v':
+ Opts.fVerbose = true;
+ break;
+
+
+ case RTPATHRMCMD_OPT_MACHINE_READABLE:
+ Opts.fMachineReadable = true;
+ break;
+
+ case 'h':
+ RTPrintf("Usage: to be written\nOption dump:\n");
+ for (unsigned i = 0; i < RT_ELEMENTS(s_aOptions); i++)
+ if (RT_C_IS_PRINT(s_aOptions[i].iShort))
+ RTPrintf(" -%c,%s\n", s_aOptions[i].iShort, s_aOptions[i].pszLong);
+ else
+ RTPrintf(" %s\n", s_aOptions[i].pszLong);
+ return RTEXITCODE_SUCCESS;
+
+ case 'V':
+ RTPrintf("%sr%d\n", RTBldCfgVersion(), RTBldCfgRevision());
+ return RTEXITCODE_SUCCESS;
+
+ default:
+ return RTGetOptPrintError(rc, &ValueUnion);
+ }
+ }
+
+ /*
+ * Options we don't support.
+ */
+ if (Opts.fOneFileSystem)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --one-file-system option is not yet implemented.\n");
+ if (Opts.enmInteractive != RTPATHRMCMDINTERACTIVE_NONE)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "The -i, -I and --interactive options are not implemented yet.\n");
+
+ /*
+ * No files means error.
+ */
+ if (rc != VINF_GETOPT_NOT_OPTION && !Opts.fForce)
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "No files or directories specified.\n");
+
+ /*
+ * Machine readable init + header.
+ */
+ if (Opts.fMachineReadable)
+ {
+ rc = RTStrmSetMode(g_pStdOut, true /*fBinary*/, false /*fCurrentCodeSet*/);
+ if (RT_FAILURE(rc))
+ return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTStrmSetMode failed: %Rrc.\n", rc);
+ static const char s_achHeader[] = "hdr_id=rm\0hdr_ver=1";
+ RTStrmWrite(g_pStdOut, s_achHeader, sizeof(s_achHeader));
+ }
+
+ /*
+ * Delete the specified files/dirs/whatever.
+ */
+ RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+ while (rc == VINF_GETOPT_NOT_OPTION)
+ {
+ rc = rtPathRmOne(&Opts, ValueUnion.psz);
+ if (RT_FAILURE(rc))
+ rcExit = RTEXITCODE_FAILURE;
+
+ /* next */
+ rc = RTGetOpt(&GetState, &ValueUnion);
+ }
+ if (rc != 0)
+ rcExit = RTGetOptPrintError(rc, &ValueUnion);
+
+ /*
+ * Terminate the machine readable stuff.
+ */
+ if (Opts.fMachineReadable)
+ {
+ RTStrmWrite(g_pStdOut, "\0\0\0", 4);
+ rc = RTStrmFlush(g_pStdOut);
+ if (RT_FAILURE(rc) && rcExit == RTEXITCODE_SUCCESS)
+ rcExit = RTEXITCODE_FAILURE;
+ }
+
+ return rcExit;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathSplit.cpp b/src/VBox/Runtime/common/path/RTPathSplit.cpp
new file mode 100644
index 00000000..6c528ce1
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathSplit.cpp
@@ -0,0 +1,133 @@
+/* $Id: RTPathSplit.cpp $ */
+/** @file
+ * IPRT - RTPathSplit
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+
+RTDECL(int) RTPathSplit(const char *pszPath, PRTPATHSPLIT pSplit, size_t cbSplit, uint32_t fFlags)
+{
+ /*
+ * Input validation.
+ */
+ AssertReturn(cbSplit >= RT_UOFFSETOF(RTPATHSPLIT, apszComps), VERR_INVALID_PARAMETER);
+ AssertPtrReturn(pSplit, VERR_INVALID_POINTER);
+ AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
+ AssertReturn(*pszPath, VERR_PATH_ZERO_LENGTH);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0), VERR_INVALID_FLAGS);
+
+ /*
+ * Use RTPathParse to do the parsing.
+ * - This makes the ASSUMPTION that the output of this function is greater
+ * or equal to that of RTPathParsed.
+ * - We're aliasing the buffer here, so use volatile to avoid issues due to
+ * compiler optimizations.
+ */
+ RTPATHPARSED volatile *pParsedVolatile = (RTPATHPARSED volatile *)pSplit;
+ RTPATHSPLIT volatile *pSplitVolatile = (RTPATHSPLIT volatile *)pSplit;
+
+ AssertCompile(sizeof(*pParsedVolatile) <= sizeof(*pSplitVolatile));
+ AssertCompile(sizeof(pParsedVolatile->aComps[0]) <= sizeof(pSplitVolatile->apszComps[0]));
+
+ int rc = RTPathParse(pszPath, (PRTPATHPARSED)pParsedVolatile, cbSplit, fFlags);
+ if (RT_FAILURE(rc) && rc != VERR_BUFFER_OVERFLOW)
+ return rc;
+
+ /*
+ * Calculate the required buffer space.
+ */
+ uint16_t const cComps = pParsedVolatile->cComps;
+ uint16_t const fProps = pParsedVolatile->fProps;
+ uint16_t const cchPath = pParsedVolatile->cchPath;
+ uint16_t const offSuffix = pParsedVolatile->offSuffix;
+ uint32_t cbNeeded = RT_OFFSETOF(RTPATHSPLIT, apszComps[cComps])
+ + cchPath
+ + RTPATH_PROP_FIRST_NEEDS_NO_SLASH(fProps) /* zero terminator for root spec. */
+ - RT_BOOL(fProps & RTPATH_PROP_DIR_SLASH) /* counted by cchPath, not included in the comp str. */
+ + 1; /* zero terminator. */
+ if (cbNeeded > cbSplit)
+ {
+ pSplitVolatile->cbNeeded = cbNeeded;
+ return VERR_BUFFER_OVERFLOW;
+ }
+ Assert(RT_SUCCESS(rc));
+
+ /*
+ * Convert the array and copy the strings, both backwards.
+ */
+ char *psz = (char *)pSplit + cbNeeded;
+ uint32_t idxComp = cComps - 1;
+
+ /* the final component first (because of suffix handling). */
+ uint16_t offComp = pParsedVolatile->aComps[idxComp].off;
+ uint16_t cchComp = pParsedVolatile->aComps[idxComp].cch;
+
+ *--psz = '\0';
+ psz -= cchComp;
+ memcpy(psz, &pszPath[offComp], cchComp);
+ pSplitVolatile->apszComps[idxComp] = psz;
+
+ char *pszSuffix;
+ if (offSuffix >= offComp + cchComp)
+ pszSuffix = &psz[cchComp];
+ else
+ pszSuffix = &psz[offSuffix - offComp];
+
+ /* the remainder */
+ while (idxComp-- > 0)
+ {
+ offComp = pParsedVolatile->aComps[idxComp].off;
+ cchComp = pParsedVolatile->aComps[idxComp].cch;
+ *--psz = '\0';
+ psz -= cchComp;
+ memcpy(psz, &pszPath[offComp], cchComp);
+ pSplitVolatile->apszComps[idxComp] = psz;
+ }
+
+ /*
+ * Store / reshuffle the non-array bits. This MUST be done after finishing
+ * the array processing because there may be members in RTPATHSPLIT
+ * overlapping the array of RTPATHPARSED.
+ */
+ AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, cComps, RTPATHSPLIT, cComps); Assert(pSplitVolatile->cComps == cComps);
+ AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, fProps, RTPATHSPLIT, fProps); Assert(pSplitVolatile->fProps == fProps);
+ AssertCompileMembersSameSizeAndOffset(RTPATHPARSED, cchPath, RTPATHSPLIT, cchPath); Assert(pSplitVolatile->cchPath == cchPath);
+ pSplitVolatile->u16Reserved = 0;
+ pSplitVolatile->cbNeeded = cbNeeded;
+ pSplitVolatile->pszSuffix = pszSuffix;
+
+ return rc;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathSplitA.cpp b/src/VBox/Runtime/common/path/RTPathSplitA.cpp
new file mode 100644
index 00000000..e29d315d
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathSplitA.cpp
@@ -0,0 +1,91 @@
+/* $Id: RTPathSplitA.cpp $ */
+/** @file
+ * IPRT - RTPathSplitA and RTPathSplitFree.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+
+
+
+RTDECL(int) RTPathSplitATag(const char *pszPath, PRTPATHSPLIT *ppSplit, uint32_t fFlags, const char *pszTag)
+{
+ AssertPtrReturn(ppSplit, VERR_INVALID_POINTER);
+ *ppSplit = NULL;
+
+ /*
+ * Try estimate a reasonable buffer size based on the path length.
+ * Note! No point in trying very hard to get it right.
+ */
+ size_t cbSplit = strlen(pszPath);
+ cbSplit += RT_OFFSETOF(RTPATHSPLIT, apszComps[cbSplit / 8]) + cbSplit / 8 + 8;
+ cbSplit = RT_ALIGN(cbSplit, 64);
+ PRTPATHSPLIT pSplit = (PRTPATHSPLIT)RTMemAllocTag(cbSplit, pszTag);
+ if (pSplit == NULL)
+ return VERR_NO_MEMORY;
+
+ /*
+ * First try. If it fails due to buffer, reallocate the buffer and try again.
+ */
+ int rc = RTPathSplit(pszPath, pSplit, cbSplit, fFlags);
+ if (rc == VERR_BUFFER_OVERFLOW)
+ {
+ cbSplit = RT_ALIGN(pSplit->cbNeeded, 64);
+ RTMemFree(pSplit);
+
+ pSplit = (PRTPATHSPLIT)RTMemAllocTag(cbSplit, pszTag);
+ if (pSplit == NULL)
+ return VERR_NO_MEMORY;
+ rc = RTPathSplit(pszPath, pSplit, cbSplit, fFlags);
+ }
+
+ /*
+ * Done (one way or the other).
+ */
+ if (RT_SUCCESS(rc))
+ *ppSplit = pSplit;
+ else
+ RTMemFree(pSplit);
+ return rc;
+}
+
+
+RTDECL(void) RTPathSplitFree(PRTPATHSPLIT pSplit)
+{
+ if (pSplit)
+ {
+ Assert(pSplit->u16Reserved = UINT16_C(0xbeef));
+ RTMemFree(pSplit);
+ }
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp b/src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp
new file mode 100644
index 00000000..8d703171
--- /dev/null
+++ b/src/VBox/Runtime/common/path/RTPathSplitReassemble.cpp
@@ -0,0 +1,120 @@
+/* $Id: RTPathSplitReassemble.cpp $ */
+/** @file
+ * IPRT - RTPathSplitReassemble.
+ */
+
+/*
+ * Copyright (C) 2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+
+
+RTDECL(int) RTPathSplitReassemble(PRTPATHSPLIT pSplit, uint32_t fFlags, char *pszDstPath, size_t cbDstPath)
+{
+ /*
+ * Input validation.
+ */
+ AssertPtrReturn(pSplit, VERR_INVALID_POINTER);
+ AssertReturn(pSplit->cComps > 0, VERR_INVALID_PARAMETER);
+ AssertReturn(RTPATH_STR_F_IS_VALID(fFlags, 0) && !(fFlags & RTPATH_STR_F_MIDDLE), VERR_INVALID_FLAGS);
+ AssertPtrReturn(pszDstPath, VERR_INVALID_POINTER);
+ AssertReturn(cbDstPath > pSplit->cchPath, VERR_BUFFER_OVERFLOW);
+
+ /*
+ * Figure which slash to use.
+ */
+ char chSlash;
+ switch (fFlags & RTPATH_STR_F_STYLE_MASK)
+ {
+ case RTPATH_STR_F_STYLE_HOST:
+ chSlash = RTPATH_SLASH;
+ break;
+
+ case RTPATH_STR_F_STYLE_DOS:
+ chSlash = '\\';
+ break;
+
+ case RTPATH_STR_F_STYLE_UNIX:
+ chSlash = '/';
+ break;
+
+ default:
+ AssertFailedReturn(VERR_INVALID_FLAGS); /* impossible */
+ }
+
+ /*
+ * Do the joining.
+ */
+ uint32_t const cchOrgPath = pSplit->cchPath;
+ size_t cchDstPath = 0;
+ uint32_t const cComps = pSplit->cComps;
+ uint32_t idxComp = 0;
+ char *pszDst = pszDstPath;
+ size_t cchComp;
+
+ if (RTPATH_PROP_HAS_ROOT_SPEC(pSplit->fProps))
+ {
+ cchComp = strlen(pSplit->apszComps[0]);
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, pSplit->apszComps[0], cchComp);
+
+ /* fix the slashes */
+ char chOtherSlash = chSlash == '\\' ? '/' : '\\';
+ while (cchComp-- > 0)
+ {
+ if (*pszDst == chOtherSlash)
+ *pszDst = chSlash;
+ pszDst++;
+ }
+ idxComp = 1;
+ }
+
+ while (idxComp < cComps)
+ {
+ cchComp = strlen(pSplit->apszComps[idxComp]);
+ cchDstPath += cchComp;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ memcpy(pszDst, pSplit->apszComps[idxComp], cchComp);
+ pszDst += cchComp;
+ idxComp++;
+ if (idxComp != cComps || (pSplit->fProps & RTPATH_PROP_DIR_SLASH))
+ {
+ cchDstPath++;
+ AssertReturn(cchDstPath <= cchOrgPath, VERR_INVALID_PARAMETER);
+ *pszDst++ = chSlash;
+ }
+ }
+
+ *pszDst = '\0';
+
+ return VINF_SUCCESS;
+}
+
diff --git a/src/VBox/Runtime/common/path/RTPathStripExt.cpp b/src/VBox/Runtime/common/path/RTPathStripExt.cpp
index 789bb3e9..8156f6a0 100644
--- a/src/VBox/Runtime/common/path/RTPathStripExt.cpp
+++ b/src/VBox/Runtime/common/path/RTPathStripExt.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathStripFilename.cpp b/src/VBox/Runtime/common/path/RTPathStripFilename.cpp
index 3db34165..b2647833 100644
--- a/src/VBox/Runtime/common/path/RTPathStripFilename.cpp
+++ b/src/VBox/Runtime/common/path/RTPathStripFilename.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/RTPathTraverseList.cpp b/src/VBox/Runtime/common/path/RTPathTraverseList.cpp
index daa88dce..361b0f82 100644
--- a/src/VBox/Runtime/common/path/RTPathTraverseList.cpp
+++ b/src/VBox/Runtime/common/path/RTPathTraverseList.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/comparepaths.cpp b/src/VBox/Runtime/common/path/comparepaths.cpp
index 40271362..bfa5e71c 100644
--- a/src/VBox/Runtime/common/path/comparepaths.cpp
+++ b/src/VBox/Runtime/common/path/comparepaths.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp b/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp
index 92c91136..9cdbb400 100644
--- a/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp
+++ b/src/VBox/Runtime/common/path/rtPathRootSpecLen.cpp
@@ -54,7 +54,7 @@ DECLHIDDEN(size_t) rtPathRootSpecLen(const char *pszPath)
size_t off = 0;
if (RTPATH_IS_SLASH(pszPath[0]))
{
-#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
if ( RTPATH_IS_SLASH(pszPath[1])
&& !RTPATH_IS_SLASH(pszPath[2])
&& pszPath[2])
@@ -78,7 +78,7 @@ DECLHIDDEN(size_t) rtPathRootSpecLen(const char *pszPath)
while (RTPATH_IS_SLASH(pszPath[off]))
off++;
}
-#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
else if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
{
off = 2;
diff --git a/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp b/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp
index c80c7976..5e95e5d9 100644
--- a/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp
+++ b/src/VBox/Runtime/common/path/rtPathVolumeSpecLen.cpp
@@ -4,7 +4,7 @@
*/
/*
- * Copyright (C) 2006-2007 Oracle Corporation
+ * Copyright (C) 2006-2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
diff --git a/src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h b/src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h
new file mode 100644
index 00000000..3797733a
--- /dev/null
+++ b/src/VBox/Runtime/common/path/rtpath-expand-template.cpp.h
@@ -0,0 +1,82 @@
+/* $Id: rtpath-expand-template.cpp.h $ */
+/** @file
+ * IPRT - RTPath - Internal header that includes RTPATH_TEMPLATE_CPP_H multiple
+ * times to expand the code for different path styles.
+ */
+
+/*
+ * Copyright (C) 2006-2013 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#undef RTPATH_DELIMITER
+
+/*
+ * DOS style
+ */
+#undef RTPATH_STYLE
+#undef RTPATH_SLASH
+#undef RTPATH_SLASH_STR
+#undef RTPATH_IS_SLASH
+#undef RTPATH_IS_VOLSEP
+#undef RTPATH_STYLE_FN
+
+#define RTPATH_STYLE RTPATH_STR_F_STYLE_DOS
+#define RTPATH_SLASH '\\'
+#define RTPATH_SLASH_STR "\\"
+#define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '\\' || (a_ch) == '/' )
+#define RTPATH_IS_VOLSEP(a_ch) ( (a_ch) == ':' )
+#define RTPATH_STYLE_FN(a_Name) a_Name ## StyleDos
+#include RTPATH_TEMPLATE_CPP_H
+
+/*
+ * Unix style.
+ */
+#undef RTPATH_STYLE
+#undef RTPATH_SLASH
+#undef RTPATH_SLASH_STR
+#undef RTPATH_IS_SLASH
+#undef RTPATH_IS_VOLSEP
+#undef RTPATH_STYLE_FN
+
+#define RTPATH_STYLE RTPATH_STR_F_STYLE_UNIX
+#define RTPATH_SLASH '/'
+#define RTPATH_SLASH_STR "/"
+#define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '/' )
+#define RTPATH_IS_VOLSEP(a_ch) ( false )
+#define RTPATH_STYLE_FN(a_Name) a_Name ## StyleUnix
+#include RTPATH_TEMPLATE_CPP_H
+
+/*
+ * Clean up and restore the host style.
+ */
+#undef RTPATH_STYLE_FN
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+# undef RTPATH_STYLE
+# undef RTPATH_SLASH
+# undef RTPATH_SLASH_STR
+# undef RTPATH_IS_SLASH
+# undef RTPATH_IS_VOLSEP
+# define RTPATH_STYLE RTPATH_STR_F_STYLE_DOS
+# define RTPATH_SLASH '\\'
+# define RTPATH_SLASH_STR "\\"
+# define RTPATH_IS_SLASH(a_ch) ( (a_ch) == '\\' || (a_ch) == '/' )
+# define RTPATH_IS_VOLSEP(a_ch) ( (a_ch) == ':' )
+#endif
+