path-posix.cpp revision b430cc494061cfa35447abc8d2230a5312f437c1
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/* $Id$ */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/** @file
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * IPRT - Path Manipulation, POSIX.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Copyright (C) 2006-2007 Sun Microsystems, Inc.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *
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 *
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 *
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 *
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
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/*******************************************************************************
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync* Header Files *
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync*******************************************************************************/
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#define LOG_GROUP RTLOGGROUP_PATH
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync#include <stdlib.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <limits.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <errno.h>
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync#include <unistd.h>
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync#include <sys/stat.h>
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync#include <sys/time.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <stdio.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <sys/types.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <pwd.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <iprt/path.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <iprt/env.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <iprt/assert.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <iprt/string.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <iprt/err.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include <iprt/log.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include "internal/path.h"
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include "internal/process.h"
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#include "internal/fs.h"
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#ifdef RT_OS_L4
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync# include <l4/vboxserver/vboxserver.h>
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTDECL(int) RTPathReal(const char *pszPath, char *pszRealPath, size_t cchRealPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszNativePath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = rtPathToNative(&pszNativePath, pszPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * On POSIX platforms the API doesn't take a length parameter, which makes it
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * a little bit more work.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char szTmpPath[PATH_MAX + 1];
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync const char *psz = realpath(pszNativePath, szTmpPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (psz)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert result and copy it to the return buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszUtf8RealPath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathFromNative(&pszUtf8RealPath, szTmpPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync size_t cch = strlen(pszUtf8RealPath) + 1;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (cch <= cchRealPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync memcpy(pszRealPath, pszUtf8RealPath, cch);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = VERR_BUFFER_OVERFLOW;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTStrFree(pszUtf8RealPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = RTErrConvertFromErrno(errno);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTStrFree(pszNativePath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathReal(%p:{%s}, %p:{%s}, %u): returns %Rrc\n", pszPath, pszPath,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszRealPath, RT_SUCCESS(rc) ? pszRealPath : "<failed>", cchRealPath));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/**
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 *
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns Number of bytes in the clean path.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pszPath The path to cleanup.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic int fsCleanPath(char *pszPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Change to '/' and remove duplicates.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszSrc = pszPath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszTrg = pszPath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#ifdef HAVE_UNC
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int fUnc = 0;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( RTPATH_IS_SLASH(pszPath[0])
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && RTPATH_IS_SLASH(pszPath[1]))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync { /* Skip first slash in a unc path. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszSrc++;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *pszTrg++ = '/';
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync fUnc = 1;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync for (;;)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char ch = *pszSrc++;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RTPATH_IS_SLASH(ch))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *pszTrg++ = '/';
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync for (;;)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync do ch = *pszSrc++;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync while (RTPATH_IS_SLASH(ch));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* Remove '/./' and '/.'. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync break;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *pszTrg = ch;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!ch)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync break;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszTrg++;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Remove trailing slash if the path may be pointing to a directory.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int cch = pszTrg - pszPath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( cch > 1
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && RTPATH_IS_SLASH(pszTrg[-1])
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#ifdef HAVE_DRIVE
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && !RTPATH_IS_VOLSEP(pszTrg[-2])
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && !RTPATH_IS_SLASH(pszTrg[-2]))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszPath[--cch] = '\0';
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return cch;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Validation.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertPtr(pszAbsPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertPtr(pszPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_UNLIKELY(!*pszPath))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return VERR_INVALID_PARAMETER;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Make a clean working copy of the input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync size_t cchPath = strlen(pszPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (cchPath > PATH_MAX)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return VERR_FILENAME_TOO_LONG;
666edc71e2906904545617ad6fae769f7d0bbf08vboxsync }
666edc71e2906904545617ad6fae769f7d0bbf08vboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char szTmpPath[PATH_MAX + 1];
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync memcpy(szTmpPath, pszPath, cchPath + 1);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync size_t cchTmpPath = fsCleanPath(szTmpPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Handle "." specially (fsCleanPath does).
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (szTmpPath[0] == '.' && !szTmpPath[1])
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return RTPathGetCurrent(pszAbsPath, cchAbsPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Do we have a root slash?
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszCur = szTmpPath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#ifdef HAVE_DRIVE
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszCur += 3;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync# ifdef HAVE_UNC
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else if (pszCur[0] == '/' && pszCur[1] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszCur += 2;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync# endif
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#else /* !HAVE_DRIVE */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszCur[0] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszCur += 1;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif /* !HAVE_DRIVE */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * No, prepend the current directory to the relative path.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char szCurDir[RTPATH_MAX];
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = RTPathGetCurrent(szCurDir, sizeof(szCurDir));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertRCReturn(rc, rc);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync size_t cchCurDir = fsCleanPath(szCurDir); /* paranoia */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (cchCurDir + cchTmpPath + 1 > PATH_MAX)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync LogFlow(("RTPathAbs(%p:{%s}, %p, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath, cchAbsPath, VERR_FILENAME_TOO_LONG));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return VERR_FILENAME_TOO_LONG;
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync }
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync memmove(szTmpPath + cchCurDir + 1, szTmpPath, cchTmpPath + 1);
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync memcpy(szTmpPath, szCurDir, cchCurDir);
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync szTmpPath[cchCurDir] = '/';
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#ifdef HAVE_DRIVE
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszCur[0] && RTPATH_IS_VOLSEP(pszCur[1]) && pszCur[2] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszCur += 3;
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync# ifdef HAVE_UNC
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync else if (pszCur[0] == '/' && pszCur[1] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszCur += 2;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync# endif
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#else
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync if (pszCur[0] == '/')
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync pszCur += 1;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgFailedReturn(("pszCur=%s\n", pszCur), VERR_INTERNAL_ERROR);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszTop = pszCur;
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync * Get rid of double dot path components by evaluating them.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync for (;;)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( pszCur[0] == '.'
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && pszCur[1] == '.'
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && (!pszCur[2] || pszCur[2] == '/'))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* rewind to the previous component if any */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszPrev = pszCur - 1;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszPrev > pszTop)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync while (*--pszPrev != '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync ;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsg(*pszPrev == '/', ("szTmpPath={%s}, pszPrev=+%u\n", szTmpPath, pszPrev - szTmpPath));
db22a92f701bfcc17823963d6c8b745f68d44e30vboxsync memmove(pszPrev, pszCur + 2, strlen(pszCur + 2) + 1);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszCur = pszPrev;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* advance to end of component. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync while (*pszCur && *pszCur != '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszCur++;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!*pszCur)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync break;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /* skip the slash */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync ++pszCur;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszCur < pszTop)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * We overwrote the root slash with '\0', restore it.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *pszCur++ = '/';
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *pszCur = '\0';
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else if (pszCur > pszTop && pszCur[-1] == '/')
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Extra trailing slash in a non-root path, remove it.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * (A bit questionable...)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *--pszCur = '\0';
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Copy the result to the user buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync cchTmpPath = pszCur - szTmpPath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (cchTmpPath < cchAbsPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync memcpy(pszAbsPath, szTmpPath, cchTmpPath + 1);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = VINF_SUCCESS;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = VERR_BUFFER_OVERFLOW;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathAbs(%p:{%s}, %p:{%s}, %d): returns %Rrc\n", pszPath, pszPath, pszAbsPath,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RT_SUCCESS(rc) ? pszAbsPath : "<failed>", cchAbsPath, rc));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#ifndef RT_OS_L4
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/**
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Worker for RTPathUserHome that looks up the home directory
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * using the getpwuid_r api.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *
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.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic int rtPathUserHomeByPasswd(char *pszPath, size_t cchPath, uid_t uid)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
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 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char achBuffer[5120];
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct passwd Passwd;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct passwd *pPasswd;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync memset(&Passwd, 0, sizeof(Passwd));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = getpwuid_r(uid, &Passwd, &achBuffer[0], sizeof(achBuffer), &pPasswd);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (rc != 0)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return RTErrConvertFromErrno(rc);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!pPasswd) /* uid not found in /etc/passwd */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return VERR_PATH_NOT_FOUND;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Check that it isn't empty and that it exists.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat st;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( !pPasswd->pw_dir
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync || !*pPasswd->pw_dir
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync || stat(pPasswd->pw_dir, &st)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync || !S_ISDIR(st.st_mode))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return VERR_PATH_NOT_FOUND;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert it to UTF-8 and copy it to the return buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszUtf8Path;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathFromNative(&pszUtf8Path, pPasswd->pw_dir);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync size_t cchHome = strlen(pszUtf8Path);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (cchHome < cchPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync memcpy(pszPath, pszUtf8Path, cchHome + 1);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = VERR_BUFFER_OVERFLOW;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTStrFree(pszUtf8Path);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/**
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Worker for RTPathUserHome that looks up the home directory
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * using the HOME environment variable.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @returns IPRT status code.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param pszPath The path buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * @param cchPath The size of the buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic int rtPathUserHomeByEnv(char *pszPath, size_t cchPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Get HOME env. var it and validate it's existance.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = VERR_PATH_NOT_FOUND;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync const char *pszHome = RTEnvGet("HOME");
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pszHome)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat st;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( !stat(pszHome, &st)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && S_ISDIR(st.st_mode))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert it to UTF-8 and copy it to the return buffer.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszUtf8Path;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathFromNative(&pszUtf8Path, pszHome);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync size_t cchHome = strlen(pszUtf8Path);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (cchHome < cchPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync memcpy(pszPath, pszUtf8Path, cchHome + 1);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = VERR_BUFFER_OVERFLOW;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTStrFree(pszUtf8Path);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTDECL(int) RTPathUserHome(char *pszPath, size_t cchPath)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#ifndef RT_OS_L4
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
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 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync uid_t uid = geteuid();
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!uid)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathUserHomeByEnv(pszPath, cchPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * On failure, retry using the alternative method.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * (Should perhaps restrict the retry cases a bit more here...)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( RT_FAILURE(rc)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && rc != VERR_BUFFER_OVERFLOW)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!uid)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathUserHomeByEnv(pszPath, cchPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathUserHomeByPasswd(pszPath, cchPath, uid);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#else /* RT_OS_L4 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathUserHomeByEnv(pszPath, cchPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync#endif /* RT_OS_L4 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathUserHome(%p:{%s}, %u): returns %Rrc\n", pszPath,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RT_SUCCESS(rc) ? pszPath : "<failed>", cchPath, rc));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTR3DECL(int) RTPathQueryInfo(const char *pszPath, PRTFSOBJINFO pObjInfo, RTFSOBJATTRADD enmAdditionalAttribs)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Validate input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(VALID_PTR(pszPath), ("%p\n", pszPath), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn(VALID_PTR(pObjInfo), ("%p\n", pszPath), VERR_INVALID_POINTER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgReturn( enmAdditionalAttribs >= RTFSOBJATTRADD_NOTHING
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && enmAdditionalAttribs <= RTFSOBJATTRADD_LAST,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync ("Invalid enmAdditionalAttribs=%p\n", enmAdditionalAttribs),
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync VERR_INVALID_PARAMETER);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the filename.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszNativePath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = rtPathToNative(&pszNativePath, pszPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat Stat;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!stat(pszNativePath, &Stat))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rtFsConvertStatToObjInfo(pObjInfo, &Stat, pszPath, 0);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync switch (enmAdditionalAttribs)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync case RTFSOBJATTRADD_EASIZE:
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /** @todo Use SGI extended attribute interface to query EA info. */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pObjInfo->Attr.enmAdditional = RTFSOBJATTRADD_EASIZE;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pObjInfo->Attr.u.EASize.cb = 0;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync break;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync case RTFSOBJATTRADD_NOTHING:
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync case RTFSOBJATTRADD_UNIX:
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Assert(pObjInfo->Attr.enmAdditional == RTFSOBJATTRADD_UNIX);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync break;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync default:
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync AssertMsgFailed(("Impossible!\n"));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return VERR_INTERNAL_ERROR;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = RTErrConvertFromErrno(errno);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rtPathFreeNative(pszNativePath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync LogFlow(("RTPathQueryInfo(%p:{%s}, pObjInfo=%p, %d): returns %Rrc\n",
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszPath, pszPath, pObjInfo, enmAdditionalAttribs, rc));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncRTR3DECL(int) RTPathSetTimes(const char *pszPath, PCRTTIMESPEC pAccessTime, PCRTTIMESPEC pModificationTime,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync PCRTTIMESPEC pChangeTime, PCRTTIMESPEC pBirthTime)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Validate input.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
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
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the paths.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszNativePath;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = rtPathToNative(&pszNativePath, pszPath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * If it's a no-op, we'll only verify the existance of the file.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!pAccessTime && !pModificationTime)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat Stat;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (!stat(pszNativePath, &Stat))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = VINF_SUCCESS;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = RTErrConvertFromErrno(errno);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Log(("RTPathSetTimes('%s',,,,): failed with %Rrc and errno=%d\n", pszPath, rc, errno));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the input to timeval, getting the missing one if necessary,
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * and call the API which does the change.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct timeval aTimevals[2];
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (pAccessTime && pModificationTime)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTTimeSpecGetTimeval(pAccessTime, &aTimevals[0]);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTTimeSpecGetTimeval(pModificationTime, &aTimevals[1]);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTFSOBJINFO ObjInfo;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = RTPathQueryInfo(pszPath, &ObjInfo, RTFSOBJATTRADD_UNIX);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTTimeSpecGetTimeval(pAccessTime ? pAccessTime : &ObjInfo.AccessTime, &aTimevals[0]);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync RTTimeSpecGetTimeval(pModificationTime ? pModificationTime : &ObjInfo.ModificationTime, &aTimevals[1]);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Log(("RTPathSetTimes('%s',%p,%p,,): RTPathQueryInfo failed with %Rrc\n",
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszPath, pAccessTime, pModificationTime, rc));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (utimes(pszNativePath, aTimevals))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = RTErrConvertFromErrno(errno);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Log(("RTPathSetTimes('%s',%p,%p,,): failed with %Rrc and errno=%d\n",
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync pszPath, pAccessTime, pModificationTime, rc, errno));
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rtPathFreeNative(pszNativePath);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync }
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
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 return rc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/**
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Checks if two files are the one and same file.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncstatic bool rtPathSame(const char *pszNativeSrc, const char *pszNativeDst)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat SrcStat;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (stat(pszNativeSrc, &SrcStat))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat DstStat;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (stat(pszNativeDst, &DstStat))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Assert(SrcStat.st_dev && DstStat.st_dev);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Assert(SrcStat.st_ino && DstStat.st_ino);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( SrcStat.st_dev == DstStat.st_dev
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && SrcStat.st_ino == DstStat.st_ino
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && (SrcStat.st_mode & S_IFMT) == (DstStat.st_mode & S_IFMT))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return true;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync return false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync}
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync/**
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Worker for RTPathRename, RTDirRename, RTFileRename.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync *
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).
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsyncint rtPathPosixRename(const char *pszSrc, const char *pszDst, unsigned fRename, RTFMODE fFileType)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync{
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync * Convert the paths.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszNativeSrc;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync int rc = rtPathToNative(&pszNativeSrc, pszSrc);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync char *pszNativeDst;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = rtPathToNative(&pszNativeDst, pszDst);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
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 *
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 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat SrcStat;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (stat(pszNativeSrc, &SrcStat))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = RTErrConvertFromErrno(errno);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else if (!fFileType)
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = VINF_SUCCESS;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else if (RTFS_IS_DIRECTORY(fFileType))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = S_ISDIR(SrcStat.st_mode) ? VINF_SUCCESS : VERR_NOT_A_DIRECTORY;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = S_ISDIR(SrcStat.st_mode) ? VERR_IS_A_DIRECTORY : VINF_SUCCESS;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (RT_SUCCESS(rc))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync bool fSameFile = false;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
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 */
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync struct stat DstStat;
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if (stat(pszNativeDst, &DstStat))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync rc = errno == ENOENT ? VINF_SUCCESS : RTErrConvertFromErrno(errno);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync else
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Assert(SrcStat.st_dev && DstStat.st_dev);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync Assert(SrcStat.st_ino && DstStat.st_ino);
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync if ( SrcStat.st_dev == DstStat.st_dev
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && SrcStat.st_ino == DstStat.st_ino
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync && (SrcStat.st_mode & S_IFMT) == (SrcStat.st_mode & S_IFMT))
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync {
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync /*
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.
f1f5335f9ec8e56fe0e3e27f253e24b10ff20f2evboxsync */
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync fSameFile = true;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (fSameFile)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else if (S_ISDIR(DstStat.st_mode) || !(fRename & RTPATHRENAME_FLAGS_REPLACE))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VERR_ALREADY_EXISTS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (RT_SUCCESS(rc))
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync {
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync if (!rename(pszNativeSrc, pszNativeDst))
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync rc = VINF_SUCCESS;
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync else if ( (fRename & RTPATHRENAME_FLAGS_REPLACE)
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync && (errno == ENOTDIR || errno == EEXIST))
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync {
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync /*
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Check that the destination isn't a directory.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Yet another race condition.
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync */
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync if (rtPathSame(pszNativeSrc, pszNativeDst))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): appears to be the same file... (errno=%d)\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync pszSrc, pszDst, fRename, fFileType, errno));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (stat(pszNativeDst, &DstStat))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = errno != ENOENT ? RTErrConvertFromErrno(errno) : VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else if (S_ISDIR(DstStat.st_mode))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VERR_ALREADY_EXISTS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (RT_SUCCESS(rc))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (!unlink(pszNativeDst))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (!rename(pszNativeSrc, pszNativeDst))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VINF_SUCCESS;
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = RTErrConvertFromErrno(errno);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): rename failed rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync pszSrc, pszDst, fRename, fFileType, rc, errno));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = RTErrConvertFromErrno(errno);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): failed to unlink dst rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync pszSrc, pszDst, fRename, fFileType, rc, errno));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): dst !dir check failed rc=%Rrc\n",
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync pszSrc, pszDst, fRename, fFileType, rc));
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync }
d012a89a724ba60c4fb5e74ce51f8b404fda4a8cvboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = RTErrConvertFromErrno(errno);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (errno == ENOTDIR)
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 pszSrc, pszDst, fRename, fFileType, rc, errno));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): destination check failed rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync pszSrc, pszDst, fRename, fFileType, rc, errno));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("rtPathRename('%s', '%s', %#x ,%RTfmode): source type check failed rc=%Rrc errno=%d\n",
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync pszSrc, pszDst, fRename, fFileType, rc, errno));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rtPathFreeNative(pszNativeDst);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rtPathFreeNative(pszNativeSrc);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync return rc;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync}
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsyncRTR3DECL(int) RTPathRename(const char *pszSrc, const char *pszDst, unsigned fRename)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync{
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync /*
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Validate input.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync */
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
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync /*
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Hand it to the worker.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync */
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync int rc = rtPathPosixRename(pszSrc, pszDst, fRename, 0);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync Log(("RTPathRename(%p:{%s}, %p:{%s}, %#x): returns %Rrc\n", pszSrc, pszSrc, pszDst, pszDst, fRename, rc));
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync return rc;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync}
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsyncRTDECL(bool) RTPathExists(const char *pszPath)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync{
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync /*
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Validate input.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync */
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertPtrReturn(pszPath, false);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertReturn(*pszPath, false);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync /*
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Convert the path and check if it exists using stat().
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync */
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync char *pszNativePath;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync int rc = rtPathToNative(&pszNativePath, pszPath);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (RT_SUCCESS(rc))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync struct stat Stat;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (!stat(pszNativePath, &Stat))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VERR_GENERAL_FAILURE;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync RTStrFree(pszNativePath);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync return RT_SUCCESS(rc);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync}
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsyncRTDECL(int) RTPathGetCurrent(char *pszPath, size_t cchPath)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync{
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync int rc;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync char szNativeCurDir[RTPATH_MAX];
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (getcwd(szNativeCurDir, sizeof(szNativeCurDir)) != NULL)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync char *pszCurDir;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = rtPathFromNative(&pszCurDir, szNativeCurDir);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (RT_SUCCESS(rc))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync size_t cchCurDir = strlen(pszCurDir);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (cchCurDir < cchPath)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync memcpy(pszPath, pszCurDir, cchCurDir + 1);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync RTStrFree(pszCurDir);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync return VINF_SUCCESS;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = VERR_BUFFER_OVERFLOW;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync RTStrFree(pszCurDir);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync else
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = RTErrConvertFromErrno(errno);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync return rc;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync}
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsyncRTDECL(int) RTPathSetCurrent(const char *pszPath)
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync{
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync /*
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Validate input.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync */
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync AssertReturn(*pszPath, VERR_INVALID_PARAMETER);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync /*
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync * Change the directory.
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync */
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync char *pszNativePath;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync int rc = rtPathToNative(&pszNativePath, pszPath);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (RT_SUCCESS(rc))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync {
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync if (chdir(pszNativePath))
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync rc = RTErrConvertFromErrno(errno);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync RTStrFree(pszNativePath);
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync }
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync return rc;
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync}
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync
a917e98de4393d1090e536fdbeb04c285f98c92evboxsync