path-posix.cpp revision 6dc7df569c3c08b7304fc0905524d35a603507b7
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * innotek Portable Runtime - Path Manipulation, POSIX.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2006-2007 innotek GmbH
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * available from http://www.virtualbox.org. This file is free software;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License as published by the Free Software Foundation,
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * distribution. VirtualBox OSE is distributed in the hope that it will
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * be useful, but WITHOUT ANY WARRANTY of any kind.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync/*******************************************************************************
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync* Header Files *
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync*******************************************************************************/
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, unsigned cchRealPath)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * On POSIX platforms the API doesn't take a length parameter, which makes it
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * a little bit more work.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync const char *psz = realpath(pszNativePath, szTmpPath);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert result and copy it to the return buffer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = rtPathFromNative(&pszUtf8RealPath, szTmpPath);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath,
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>", cchRealPath));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Cleans up a path specifier a little bit.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * This includes removing duplicate slashes, uncessary single dots, and
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns Number of bytes in the clean path.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pszPath The path to cleanup.
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync * @remark Borrowed from innotek libc.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync * Change to '/' and remove duplicates.
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync { /* Skip first slash in a unc path. */
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync /* Remove '/./' and '/.'. */
05406988cc320ac1b0971de976b6cf0c986044a9vboxsync if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync * Remove trailing slash if the path may be pointing to a directory.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, unsigned cchAbsPath)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * On POSIX platforms the API doesn't take a length parameter, which makes it
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * a little bit more work.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /// @todo realpath() returns EIO for non-existent UNC paths like
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // //server/share/subdir (i.e. when a subdir is specified within
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // a share). We should either fix realpath() in libc or remove
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync // this todo.
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * Iterate the path bit by bit an apply realpath to it.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
61e80138f3c5ea5213990bde94a973c8e64d1dadvboxsync size_t cchElement = pszSlash ? pszSlash - pszCur : strlen(pszCur);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* we've got just "//server" or "//" */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /// @todo (r=dmik) not 100% sure we should fail, but the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // above cases are just invalid (incomplete) paths,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync // no matter that Win32 returns these paths as is.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* get the cwd */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* make sure strrchr() will work correctly */
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync size_t cchElement = pszSlash ? pszSlash - pszCur : strlen(pszCur);
090f6abdd6282f48527b83162b8b441425f05e36vboxsync /* else: We've reached the root and the parent of
090f6abdd6282f48527b83162b8b441425f05e36vboxsync * the root is the root. */
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync /* resolve possible symlinks */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /// @todo see above
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync /* no more need to resolve symlinks */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* skip the slash */
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync /* check if we're at the root */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /* if the length is zero here, then we're at the root */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert result and copy it to the return buffer.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath,
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync /* replace '/' back with native RTPATH_SLASH */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pszPath, pszAbsPath, RT_SUCCESS(rc) ? pszAbsPath : "<failed>",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTDECL(int) RTPathProgram(char *pszPath, unsigned cchPath)
d45f7f7fe0c28b500b45b2dc88d7a04f4c0be6b8vboxsync * First time only.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Linux have no API for obtaining the executable path, but provides a symbolic link
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * in the proc file system. Note that readlink is one of the weirdest Unix apis around.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * OS/2 have an api for getting the program file name.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync/** @todo use RTProcGetExecutableName() */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_SOLARIS)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int cchLink = readlink("/proc/self/exe", &g_szrtProgramPath[0], sizeof(g_szrtProgramPath) - 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync sprintf(szFileBuf, "/proc/%ld/path/a.out", (long)getpid());
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int cchLink = readlink(szFileBuf, &g_szrtProgramPath[0], sizeof(g_szrtProgramPath) - 1);
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync# else /* RT_OS_FREEBSD: */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int cchLink = readlink("/proc/curproc/file", &g_szrtProgramPath[0], sizeof(g_szrtProgramPath) - 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync if (cchLink < 0 || cchLink == sizeof(g_szrtProgramPath) - 1)
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync AssertMsgFailed(("couldn't read /proc/self/exe. errno=%d cchLink=%d\n", errno, cchLink));
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync LogFlow(("RTPathProgram(%p, %u): returns %Rrc\n", pszPath, cchPath, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync _execname(g_szrtProgramPath, sizeof(g_szrtProgramPath));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync const char *pszImageName = _dyld_get_image_name(0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync memcpy(g_szrtProgramPath, pszImageName, cchImageName + 1);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert to UTF-8 and strip of the filename.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = rtPathFromNative(&pszTmp, &g_szrtProgramPath[0]);
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync LogFlow(("RTPathProgram(%p, %u): returns %Rrc\n", pszPath, cchPath, rc));
dd8efff5286a99cf8d9b3a5e8dd62340973f3cc1vboxsync LogFlow(("RTPathProgram(%p, %u): returns %Rrc\n", pszPath, cchPath, VERR_BUFFER_OVERFLOW));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Calc the length and check if there is space before copying.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("RTPathProgram(%p:{%s}, %u): returns %Rrc\n", pszPath, pszPath, cchPath, VINF_SUCCESS));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgFailed(("Buffer too small (%d < %d)\n", cchPath, cch));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("RTPathProgram(%p, %u): returns %Rrc\n", pszPath, cchPath, VERR_BUFFER_OVERFLOW));
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync * Worker for RTPathUserHome that looks up the home directory
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync * using the getpwuid_r api.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns IPRT status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pszPath The path buffer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cchPath The size of the buffer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param uid The User ID to query the home directory of.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int rtPathUserHomeByPasswd(char *pszPath, size_t cchPath, uid_t uid)
d45f7f7fe0c28b500b45b2dc88d7a04f4c0be6b8vboxsync * The getpwuid_r function uses the passed in buffer to "allocate" any
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * extra memory it needs. On some systems we should probably use the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * sysconf function to find the appropriate buffer size, but since it won't
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * work everywhere we'll settle with a 5KB buffer and ASSUME that it'll
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * suffice for even the lengthiest user descriptions...
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = getpwuid_r(uid, &Passwd, &achBuffer[0], sizeof(achBuffer), &pPasswd);
42c1972c22e09797b4b24afbd0ec114ed076c37cvboxsync * Check that it isn't empty and that it exists.
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync * Convert it to UTF-8 and copy it to the return buffer.
7e960d3a0a8a3a84d7aba2cca45d72b1c31cc97bvboxsync rc = rtPathFromNative(&pszUtf8Path, pPasswd->pw_dir);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * Worker for RTPathUserHome that looks up the home directory
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * using the HOME environment variable.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns IPRT status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pszPath The path buffer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param cchPath The size of the buffer.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic int rtPathUserHomeByEnv(char *pszPath, size_t cchPath)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Get HOME env. var it and validate it's existance.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert it to UTF-8 and copy it to the return buffer.
a44cdd0b29504e3de7b8aa87f839ad62b6e66f51vboxsyncRTDECL(int) RTPathUserHome(char *pszPath, unsigned cchPath)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * We make an exception for the root user and use the system call
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * getpwuid_r to determine their initial home path instead of
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * reading it from the $HOME variable. This is because the $HOME
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * variable does not get changed by sudo (and possibly su and others)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * which can cause root-owned files to appear in user's home folders.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * On failure, retry using the alternative method.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * (Should perhaps restrict the retry cases a bit more here...)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#else /* RT_OS_L4 */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync#endif /* RT_OS_L4 */
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync LogFlow(("RTPathUserHome(%p:{%s}, %u): returns %Rrc\n", pszPath,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RT_SUCCESS(rc) ? pszPath : "<failed>", cchPath, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate input.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(VALID_PTR(pObjInfo), ("%p\n", pszPath), VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
13d75a5db336ccb682d7ab28b397a4f0b8982ea3vboxsync ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert the filename.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rtFsConvertStatToObjInfo(pObjInfo, &Stat, pszPath, 0);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync /** @todo Use SGI extended attribute interface to query EA info. */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Assert(pObjInfo->Attr.enmAdditional == RTFSOBJATTRADD_UNIX);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("RTPathQueryInfo(%p:{%s}, pObjInfo=%p, %d): returns %Rrc\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pszPath, pszPath, pObjInfo, enmAdditionalAttribs, rc));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncRTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Validate input.
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(*pszPath, ("%p\n", pszPath), VERR_INVALID_PARAMETER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(!pAccessTime || VALID_PTR(pAccessTime), ("%p\n", pAccessTime), VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(!pModificationTime || VALID_PTR(pModificationTime), ("%p\n", pModificationTime), VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(!pChangeTime || VALID_PTR(pChangeTime), ("%p\n", pChangeTime), VERR_INVALID_POINTER);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync AssertMsgReturn(!pBirthTime || VALID_PTR(pBirthTime), ("%p\n", pBirthTime), VERR_INVALID_POINTER);
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * Convert the paths.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * If it's a no-op, we'll only verify the existance of the file.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("RTPathSetTimes('%s',,,,): failed with %Rrc and errno=%d\n", pszPath, rc, errno));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert the input to timeval, getting the missing one if necessary,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * and call the API which does the change.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync int rc = RTPathQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync pszPath, pAccessTime, pModificationTime, rc, errno));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync LogFlow(("RTPathSetTimes(%p:{%s}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}, %p:{%RDtimespec}): return %Rrc\n",
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync pszPath, pszPath, pAccessTime, pAccessTime, pModificationTime, pModificationTime,
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync pChangeTime, pChangeTime, pBirthTime, pBirthTime));
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Checks if two files are the one and same file.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsyncstatic bool rtPathSame(const char *pszNativeSrc, const char *pszNativeDst)
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync return false;
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync return false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return true;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync return false;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Worker for RTPathRename, RTDirRename, RTFileRename.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @returns IPRT status code.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pszSrc The source path.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param pszDst The destintation path.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * @param fRename The rename flags.
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync * @param fFileType The filetype. We use the RTFMODE filetypes here. If it's 0,
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * anything goes. If it's RTFS_TYPE_DIRECTORY we'll check that the
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * source is a directory. If Its RTFS_TYPE_FILE we'll check that it's
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * not a directory (we are NOT checking whether it's a file).
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsyncint rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Convert the paths.
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * Check that the source exists and that any types that's specified matches.
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * We have to check this first to avoid getting errnous VERR_ALREADY_EXISTS
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * errors from the next step.
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * There are race conditions here (perhaps unlikly ones but still), but I'm
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * afraid there is little with can do to fix that.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = S_ISDIR(SrcStat.st_mode) ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = S_ISDIR(SrcStat.st_mode) ? VERR_IS_A_DIRECTORY : VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync bool fSameFile = false;
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync * Check if the target exists, rename is rather destructive.
8dee1778d3770cdc584752c84acf4899d8bfc9f9vboxsync * We'll have to make sure we don't overwrite the source!
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Another race condition btw.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync rc = errno == ENOENT ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync && (SrcStat.st_mode & S_IFMT) == (SrcStat.st_mode & S_IFMT))
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * It's likely that we're talking about the same file here.
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * We should probably check paths or whatever, but for now this'll have to be enough.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync else if (S_ISDIR(DstStat.st_mode) || !(fRename & RTPATHRENAME_FLAGS_REPLACE))
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Check that the destination isn't a directory.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync * Yet another race condition.
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): appears to be the same file... (errno=%d)\n",
e11fe099decbb0f65cfcc7e2939fa00bacefbb1cvboxsync rc = errno != ENOENT ? RTErrConvertFromErrno(errno) : VINF_SUCCESS;
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): failed to unlink dst rc=%Rrc errno=%d\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n",
be9bc9b4ba510c4b4159c193f783d024633ef8e9vboxsync rc = VERR_ALREADY_EXISTS; /* unless somebody is racing us, this is the right interpretation */
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
d408b82da0773c7e8cd4b3a01cb8a065a2c73a2dvboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n",
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): source type check failed rc=%Rrc errno=%d\n",
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsyncRTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename)
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * Validate input.
323b78bf4831666c95416edf3b6e54657a769e5dvboxsync AssertMsgReturn(VALID_PTR(pszSrc), ("%p\n", pszSrc), VERR_INVALID_POINTER);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync AssertMsgReturn(VALID_PTR(pszDst), ("%p\n", pszDst), VERR_INVALID_POINTER);
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync AssertMsgReturn(*pszSrc, ("%p\n", pszSrc), VERR_INVALID_PARAMETER);
b880eb99e249b300390f5eeedff304ac30ba548evboxsync AssertMsgReturn(*pszDst, ("%p\n", pszDst), VERR_INVALID_PARAMETER);
9f16100a870e25701da9bc9819e15c0f9fb3870evboxsync AssertMsgReturn(!(fRename & ~RTPATHRENAME_FLAGS_REPLACE), ("%#x\n", fRename), VERR_INVALID_PARAMETER);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * Hand it to the worker.
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync int rc = rtPathPosixRename(pszSrc, pszDst, fRename, 0);
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync Log(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * Validate input.
ebf9e36b6e5548e4db69cebbef120e669a459afevboxsync * Convert the path and check if it exists using stat().