path-posix.cpp revision c58f1213e628a545081c70e26c6b67a841cff880
/* $Id$ */
/** @file
* IPRT - Path Manipulation, POSIX, Part 1.
*/
/*
* 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;
* 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 *
*******************************************************************************/
#define LOG_GROUP RTLOGGROUP_PATH
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <pwd.h>
#ifdef RT_OS_L4
#endif
{
/*
* Convert input.
*/
char const *pszNativePath;
if (RT_SUCCESS(rc))
{
/*
* On POSIX platforms the API doesn't take a length parameter, which makes it
* a little bit more work.
*/
if (psz)
else
}
return rc;
}
/**
* Cleans up a path specifier a little bit.
* This includes removing duplicate slashes, unnecessary single dots, and
* trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
*
* @returns Number of bytes in the clean path.
* @param pszPath The path to cleanup.
*/
static int fsCleanPath(char *pszPath)
{
/*
* Change to '/' and remove duplicates.
*/
#ifdef HAVE_UNC
int fUnc = 0;
if ( RTPATH_IS_SLASH(pszPath[0])
{ /* Skip first slash in a unc path. */
pszSrc++;
*pszTrg++ = '/';
fUnc = 1;
}
#endif
for (;;)
{
if (RTPATH_IS_SLASH(ch))
{
*pszTrg++ = '/';
for (;;)
{
while (RTPATH_IS_SLASH(ch));
/* Remove '/./' and '/.'. */
break;
}
}
if (!ch)
break;
pszTrg++;
}
/*
* Remove trailing slash if the path may be pointing to a directory.
*/
if ( cch > 1
#ifdef HAVE_DRIVE
#endif
return cch;
}
{
int rc;
/*
* Validation.
*/
if (RT_UNLIKELY(!*pszPath))
return VERR_INVALID_PARAMETER;
/*
* Make a clean working copy of the input.
*/
{
LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
return VERR_FILENAME_TOO_LONG;
}
/*
* Handle "." specially (fsCleanPath does).
*/
/*
* Do we have a root slash?
*/
#ifdef HAVE_DRIVE
pszCur += 3;
# ifdef HAVE_UNC
pszCur += 2;
# endif
#else /* !HAVE_DRIVE */
if (pszCur[0] == '/')
pszCur += 1;
#endif /* !HAVE_DRIVE */
else
{
/*
* No, prepend the current directory to the relative path.
*/
char szCurDir[RTPATH_MAX];
{
LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
return VERR_FILENAME_TOO_LONG;
}
#ifdef HAVE_DRIVE
pszCur += 3;
# ifdef HAVE_UNC
pszCur += 2;
# endif
#else
if (pszCur[0] == '/')
pszCur += 1;
#endif
else
}
/*
* Get rid of double dot path components by evaluating them.
*/
for (;;)
{
if ( pszCur[0] == '.'
{
/* rewind to the previous component if any */
while (*--pszPrev != '/')
;
}
else
{
/* advance to end of component. */
pszCur++;
}
if (!*pszCur)
break;
/* skip the slash */
++pszCur;
}
{
/*
* We overwrote the root slash with '\0', restore it.
*/
*pszCur++ = '/';
*pszCur = '\0';
}
{
/*
* Extra trailing slash in a non-root path, remove it.
* (A bit questionable...)
*/
*--pszCur = '\0';
}
/*
* Copy the result to the user buffer.
*/
if (cchTmpPath < cchAbsPath)
{
rc = VINF_SUCCESS;
}
else
return rc;
}
{
int rc;
{
char const *pszNativePath;
if (RT_SUCCESS(rc))
{
}
}
else
{
}
return rc;
}
/**
* Checks if two files are the one and same file.
*/
{
return false;
return false;
return true;
return false;
}
/**
* Worker for RTPathRename, RTDirRename, RTFileRename.
*
* @returns IPRT status code.
* @param pszSrc The source path.
* @param pszDst The destination path.
* @param fRename The rename flags.
* @param fFileType The filetype. We use the RTFMODE filetypes here. If it's 0,
* anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the
* source is a directory. If Its RTFS_TYPE_FILE we'll check that it's
* not a directory (we are NOT checking whether it's a file).
*/
DECLHIDDEN(int) rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)
{
/*
* Convert the paths.
*/
char const *pszNativeSrc;
if (RT_SUCCESS(rc))
{
char const *pszNativeDst;
if (RT_SUCCESS(rc))
{
/*
* Check that the source exists and that any types that's specified matches.
* We have to check this first to avoid getting errnous VERR_ALREADY_EXISTS
* errors from the next step.
*
* There are race conditions here (perhaps unlikely ones, but still), but I'm
* afraid there is little with can do to fix that.
*/
else if (!fFileType)
rc = VINF_SUCCESS;
else if (RTFS_IS_DIRECTORY(fFileType))
else
if (RT_SUCCESS(rc))
{
bool fSameFile = false;
/*
* Check if the target exists, rename is rather destructive.
* We'll have to make sure we don't overwrite the source!
* Another race condition btw.
*/
else
{
{
/*
* It's likely that we're talking about the same file here.
* We should probably check paths or whatever, but for now this'll have to be enough.
*/
fSameFile = true;
}
if (fSameFile)
rc = VINF_SUCCESS;
else
rc = VINF_SUCCESS;
}
if (RT_SUCCESS(rc))
{
rc = VINF_SUCCESS;
else if ( (fRename & RTPATHRENAME_FLAGS_REPLACE)
{
/*
* Check that the destination isn't a directory.
* Yet another race condition.
*/
{
rc = VINF_SUCCESS;
Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): appears to be the same file... (errno=%d)\n",
}
else
{
else
rc = VINF_SUCCESS;
if (RT_SUCCESS(rc))
{
if (!unlink(pszNativeDst))
{
rc = VINF_SUCCESS;
else
{
Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
}
}
else
{
Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): failed to unlink dst rc=%Rrc errno=%d\n",
}
}
else
Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n",
}
}
else
{
Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
}
}
else
Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n",
}
else
Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): source type check failed rc=%Rrc errno=%d\n",
}
}
return rc;
}
{
/*
* Validate input.
*/
AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
/*
* Hand it to the worker.
*/
Log(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
return rc;
}
{
return VERR_NOT_IMPLEMENTED;
}
{
}
{
/*
* Validate input.
*/
AssertPtrReturn(pszPath, false);
AssertReturn(*pszPath, false);
/*
* Convert the path and check if it exists using stat().
*/
char const *pszNativePath;
if (RT_SUCCESS(rc))
{
if (fFlags & RTPATH_F_FOLLOW_LINK)
else
if (!rc)
rc = VINF_SUCCESS;
else
}
return RT_SUCCESS(rc);
}
{
int rc;
char szNativeCurDir[RTPATH_MAX];
else
return rc;
}
{
/*
* Validate input.
*/
/*
* Change the directory.
*/
char const *pszNativePath;
if (RT_SUCCESS(rc))
{
if (chdir(pszNativePath))
}
return rc;
}