path-posix.cpp revision b430cc494061cfa35447abc8d2230a5312f437c1
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * IPRT - Path Manipulation, POSIX.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * available from http://www.virtualbox.org. This file is free software;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * you can redistribute it and/or modify it under the terms of the GNU
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * General Public License (GPL) as published by the Free Software
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * The contents of this file may alternatively be used under the terms
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * of the Common Development and Distribution License Version 1.0
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * VirtualBox OSE distribution, in which case the provisions of the
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * CDDL are applicable instead of those of the GPL.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * You may elect to license modified versions of this file under the
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * terms and conditions of either the GPL or the CDDL or both.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * additional information or have any questions.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/*******************************************************************************
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync* Header Files *
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync*******************************************************************************/
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * On POSIX platforms the API doesn't take a length parameter, which makes it
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * a little bit more work.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync const char *psz = realpath(pszNativePath, szTmpPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert result and copy it to the return buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathFromNative(&pszUtf8RealPath, szTmpPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>", cchRealPath));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Cleans up a path specifier a little bit.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * This includes removing duplicate slashes, uncessary single dots, and
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns Number of bytes in the clean path.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pszPath The path to cleanup.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Change to '/' and remove duplicates.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync { /* Skip first slash in a unc path. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* Remove '/./' and '/.'. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Remove trailing slash if the path may be pointing to a directory.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Validation.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Make a clean working copy of the input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Handle "." specially (fsCleanPath does).
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Do we have a root slash?
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#else /* !HAVE_DRIVE */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif /* !HAVE_DRIVE */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * No, prepend the current directory to the relative path.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync * Get rid of double dot path components by evaluating them.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* rewind to the previous component if any */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* advance to end of component. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* skip the slash */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * We overwrote the root slash with '\0', restore it.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Extra trailing slash in a non-root path, remove it.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * (A bit questionable...)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Copy the result to the user buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Worker for RTPathUserHome that looks up the home directory
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * using the getpwuid_r api.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns IPRT status code.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pszPath The path buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param cchPath The size of the buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param uid The User ID to query the home directory of.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic int rtPathUserHomeByPasswd(char *pszPath, size_t cchPath, uid_t uid)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * The getpwuid_r function uses the passed in buffer to "allocate" any
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * extra memory it needs. On some systems we should probably use the
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * sysconf function to find the appropriate buffer size, but since it won't
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * work everywhere we'll settle with a 5KB buffer and ASSUME that it'll
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * suffice for even the lengthiest user descriptions...
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = getpwuid_r(uid, &Passwd, &achBuffer[0], sizeof(achBuffer), &pPasswd);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Check that it isn't empty and that it exists.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert it to UTF-8 and copy it to the return buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathFromNative(&pszUtf8Path, pPasswd->pw_dir);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Worker for RTPathUserHome that looks up the home directory
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * using the HOME environment variable.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns IPRT status code.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pszPath The path buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param cchPath The size of the buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic int rtPathUserHomeByEnv(char *pszPath, size_t cchPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Get HOME env. var it and validate it's existance.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert it to UTF-8 and copy it to the return buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * We make an exception for the root user and use the system call
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * getpwuid_r to determine their initial home path instead of
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * reading it from the $HOME variable. This is because the $HOME
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * variable does not get changed by sudo (and possibly su and others)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * which can cause root-owned files to appear in user's home folders.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * On failure, retry using the alternative method.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * (Should perhaps restrict the retry cases a bit more here...)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#else /* RT_OS_L4 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif /* RT_OS_L4 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathUserHome(%p:{%s}, %u): returns %Rrc\n", pszPath,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RT_SUCCESS(rc) ? pszPath : "<failed>", cchPath, rc));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Validate input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(VALID_PTR(pObjInfo), ("%p\n", pszPath), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the filename.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rtFsConvertStatToObjInfo(pObjInfo, &Stat, pszPath, 0);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** @todo Use SGI extended attribute interface to query EA info. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Assert(pObjInfo->Attr.enmAdditional == RTFSOBJATTRADD_UNIX);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathQueryInfo(%p:{%s}, pObjInfo=%p, %d): returns %Rrc\n",
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszPath, pszPath, pObjInfo, enmAdditionalAttribs, rc));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Validate input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(*pszPath, ("%p\n", pszPath), VERR_INVALID_PARAMETER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(!pAccessTime || VALID_PTR(pAccessTime), ("%p\n", pAccessTime), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(!pModificationTime || VALID_PTR(pModificationTime), ("%p\n", pModificationTime), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(!pChangeTime || VALID_PTR(pChangeTime), ("%p\n", pChangeTime), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(!pBirthTime || VALID_PTR(pBirthTime), ("%p\n", pBirthTime), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the paths.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * If it's a no-op, we'll only verify the existance of the file.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Log(("RTPathSetTimes('%s',,,,): failed with %Rrc and errno=%d\n", pszPath, rc, errno));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the input to timeval, getting the missing one if necessary,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * and call the API which does the change.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = RTPathQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n",
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n",
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszPath, pAccessTime, pModificationTime, rc, errno));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathSetTimes(%p:{%s}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}): return %Rrc\n",
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszPath, pszPath, pAccessTime, pAccessTime, pModificationTime, pModificationTime,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pChangeTime, pChangeTime, pBirthTime, pBirthTime));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Checks if two files are the one and same file.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic bool rtPathSame(const char *pszNativeSrc, const char *pszNativeDst)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return true;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Worker for RTPathRename, RTDirRename, RTFileRename.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns IPRT status code.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pszSrc The source path.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pszDst The destintation path.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param fRename The rename flags.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param fFileType The filetype. We use the RTFMODE filetypes here. If it's 0,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * source is a directory. If Its RTFS_TYPE_FILE we'll check that it's
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * not a directory (we are NOT checking whether it's a file).
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncint rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the paths.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Check that the source exists and that any types that's specified matches.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * We have to check this first to avoid getting errnous VERR_ALREADY_EXISTS
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * errors from the next step.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * There are race conditions here (perhaps unlikly ones but still), but I'm
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * afraid there is little with can do to fix that.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = S_ISDIR(SrcStat.st_mode) ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = S_ISDIR(SrcStat.st_mode) ? VERR_IS_A_DIRECTORY : VINF_SUCCESS;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync bool fSameFile = false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Check if the target exists, rename is rather destructive.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * We'll have to make sure we don't overwrite the source!
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Another race condition btw.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = errno == ENOENT ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && (SrcStat.st_mode & S_IFMT) == (SrcStat.st_mode & S_IFMT))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * It's likely that we're talking about the same file here.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * We should probably check paths or whatever, but for now this'll have to be enough.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else if (S_ISDIR(DstStat.st_mode) || !(fRename & RTPATHRENAME_FLAGS_REPLACE))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Check that the destination isn't a directory.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Yet another race condition.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): appears to be the same file... (errno=%d)\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = errno != ENOENT ? RTErrConvertFromErrno(errno) : VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): failed to unlink dst rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VERR_ALREADY_EXISTS; /* unless somebody is racing us, this is the right interpretation */
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): source type check failed rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsyncRTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Validate input.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Hand it to the worker.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync int rc = rtPathPosixRename(pszSrc, pszDst, fRename, 0);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Validate input.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Convert the path and check if it exists using stat().
a917e98de4393d1090e536fdbeb04c285f98c92evboxsyncRTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (getcwd(szNativeCurDir, sizeof(szNativeCurDir)) != NULL)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Validate input.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Change the directory.