示例#1
0
/**
 * Checks quickly if this is an correct root specification.
 * Root specs ends with a slash of some kind.
 *
 * @returns indicator.
 * @param   pszFsPath       Path to check.
 */
static bool rtFsIsRoot(const char *pszFsPath)
{
    /*
     * UNC has exactly two slashes..
     *
     * Anything else starting with slashe(s) requires
     * expansion and will have to take the long road.
     */
    if (RTPATH_IS_SLASH(pszFsPath[0]))
    {
        if (    !RTPATH_IS_SLASH(pszFsPath[1])
            ||  RTPATH_IS_SLASH(pszFsPath[2]))
            return false;

        /* end of machine name */
        const char *pszSlash = strpbrk(pszFsPath + 2, "\\/");
        if (!pszSlash)
            return false;

        /* end of service name. */
        pszSlash = strpbrk(pszSlash + 1, "\\/");
        if (!pszSlash)
            return false;

        return pszSlash[1] == '\0';
    }

    /*
     * Ok the other alternative is driver letter.
     */
    return  pszFsPath[0] >= 'A' && pszFsPath[0] <= 'Z'
        &&  pszFsPath[1] == ':'
        &&  RTPATH_IS_SLASH(pszFsPath[2])
        && !pszFsPath[3];
}
/**
 * Check the given UTF-8 path for root escapes.
 *
 * Verify that the path is within the root directory of the mapping.  Count '..'
 * and other path components and check that we do not go over the root.
 *
 * @returns VBox status code.
 * @retval  VINF_SUCCESS
 * @retval  VERR_INVALID_NAME
 *
 * @param   pszPath         The (UTF-8) path to check.  Slashes has been convert
 *                          to host slashes by this time.
 *
 * @remarks This function assumes that the path will be appended to the root
 *          directory of the shared folder mapping.  Keep that in mind when
 *          checking absolute paths!
 */
static int vbsfPathCheckRootEscape(const char *pszPath)
{
    /*
     * Walk the path, component by component and check for escapes.
     */

    int cComponents = 0; /* How many normal path components. */
    int cParentDirs = 0; /* How many '..' components. */

    for (;;)
    {
        char ch;

        /* Skip leading path delimiters. */
        do
            ch = *pszPath++;
        while (RTPATH_IS_SLASH(ch));
        if (ch == '\0')
            return VINF_SUCCESS;

        /* Check if that is a dot component. */
        int cDots = 0;
        while (ch == '.')
        {
            cDots++;
            ch = *pszPath++;
        }

        if (   cDots >= 1
            && (ch == '\0' || RTPATH_IS_SLASH(ch)) )
        {
            if (cDots >= 2) /* Consider all multidots sequences as a 'parent dir'. */
            {
                cParentDirs++;

                /* Escaping? */
                if (cParentDirs > cComponents)
                    return VERR_INVALID_NAME;
            }
            /* else: Single dot, nothing changes. */
        }
        else
        {
            /* Not a dot component, skip to the end of it. */
            while (ch != '\0' && !RTPATH_IS_SLASH(ch))
                ch = *pszPath++;
            cComponents++;
        }
        Assert(cComponents >= cParentDirs);

        /* The end? */
        Assert(ch == '\0' || RTPATH_IS_SLASH(ch));
        if (ch == '\0')
            return VINF_SUCCESS;
    }
}
示例#3
0
/**
 * Finds the root of the specified volume.
 *
 * @returns iprt status code.
 * @param   pszFsPath       Path within the filesystem. Verified as one byte or more.
 * @param   ppwszFsRoot     Where to store the returned string. Free with rtFsFreeRoot(),
 */
static int rtFsGetRoot(const char *pszFsPath, PRTUTF16 *ppwszFsRoot)
{
    /*
     * Do straight forward stuff first,
     */
    if (rtFsIsRoot(pszFsPath))
        return RTStrToUtf16(pszFsPath, ppwszFsRoot);

    /*
     * Expand and add slash (if required).
     */
    char szFullPath[RTPATH_MAX];
    int rc = RTPathAbs(pszFsPath, szFullPath, sizeof(szFullPath));
    if (RT_FAILURE(rc))
        return rc;
    size_t cb = strlen(szFullPath);
    if (!RTPATH_IS_SLASH(szFullPath[cb - 1]))
    {
        AssertReturn(cb + 1 < RTPATH_MAX, VERR_FILENAME_TOO_LONG);
        szFullPath[cb] = '\\';
        szFullPath[++cb] = '\0';
    }

    /*
     * Convert the path.
     */
    rc = RTStrToUtf16(szFullPath, ppwszFsRoot);
    if (RT_FAILURE(rc))
        return rc == VERR_BUFFER_OVERFLOW ? VERR_FILENAME_TOO_LONG : rc;

    /*
     * Walk the path until our proper API is happy or there is no more path left.
     */
    PRTUTF16 pwszStart = *ppwszFsRoot;
    if (!GetVolumeInformationW(pwszStart, NULL, 0, NULL, NULL, 0, NULL, 0))
    {
        PRTUTF16 pwszEnd = pwszStart + RTUtf16Len(pwszStart);
        PRTUTF16 pwszMin = pwszStart + 2;
        do
        {
            /* Strip off the last path component. */
            while (pwszEnd-- > pwszMin)
                if (RTPATH_IS_SLASH(*pwszEnd))
                    break;
            AssertReturn(pwszEnd >= pwszMin, VERR_INTERNAL_ERROR); /* leaks, but that's irrelevant for an internal error. */
            pwszEnd[1] = '\0';
        } while (!GetVolumeInformationW(pwszStart, NULL, 0, NULL, NULL, 0, NULL, 0));
    }

    return VINF_SUCCESS;
}
示例#4
0
/**
 * Get the absolute path (no symlinks, no . or .. components), assuming the
 * given base path as the current directory. The resulting path doesn't have
 * to exist.
 *
 * @returns iprt status code.
 * @param   pszBase         The base path to act like a current directory.
 *                          When NULL, the actual cwd is used (i.e. the call
 *                          is equivalent to RTPathAbs(pszPath, ...).
 * @param   pszPath         The path to resolve.
 * @param   pszAbsPath      Where to store the absolute path.
 * @param   cchAbsPath      Size of the buffer.
 */
RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
{
    if (    pszBase
        &&  pszPath
        &&  !rtPathVolumeSpecLen(pszPath)
       )
    {
#if defined(RT_OS_WINDOWS)
        /* The format for very long paths is not supported. */
        if (    RTPATH_IS_SLASH(pszBase[0])
            &&  RTPATH_IS_SLASH(pszBase[1])
            &&  pszBase[2] == '?'
            &&  RTPATH_IS_SLASH(pszBase[3])
           )
            return VERR_INVALID_NAME;
#endif

        /** @todo there are a couple of things which isn't 100% correct, although the
         * current code will have to do for now, no time to fix.
         *
         * 1) On Windows & OS/2 we confuse '/' with an abspath spec and will
         *    not necessarily resolve it on the right drive.
         * 2) A trailing slash in the base might cause UNC names to be created.
         */
        size_t const cchPath = strlen(pszPath);
        char         szTmpPath[RTPATH_MAX];
        if (RTPATH_IS_SLASH(pszPath[0]))
        {
            /* join the disk name from base and the path (DOS systems only) */
            size_t const cchVolSpec = rtPathVolumeSpecLen(pszBase);
            if (cchVolSpec + cchPath + 1 > sizeof(szTmpPath))
                return VERR_FILENAME_TOO_LONG;
            memcpy(szTmpPath, pszBase, cchVolSpec);
            memcpy(&szTmpPath[cchVolSpec], pszPath, cchPath + 1);
        }
        else
        {
            /* join the base path and the path */
            size_t const cchBase = strlen(pszBase);
            if (cchBase + 1 + cchPath + 1 > sizeof(szTmpPath))
                return VERR_FILENAME_TOO_LONG;
            memcpy(szTmpPath, pszBase, cchBase);
            szTmpPath[cchBase] = RTPATH_DELIMITER;
            memcpy(&szTmpPath[cchBase + 1], pszPath, cchPath + 1);
        }
        return RTPathAbs(szTmpPath, pszAbsPath, cchAbsPath);
    }

    /* Fallback to the non *Ex version */
    return RTPathAbs(pszPath, pszAbsPath, cchAbsPath);
}
RTDECL(size_t) RTPathCountComponents(const char *pszPath)
{
    size_t off = rtPathRootSpecLen(pszPath);
    size_t c   = off != 0;
    while (pszPath[off])
    {
        c++;
        while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
            off++;
        while (RTPATH_IS_SLASH(pszPath[off]))
            off++;
    }
    return c;
}
/**
 * Get the absolute path (no symlinks, no . or .. components), doesn't have to exit.
 *
 * @returns iprt status code.
 * @param   pszPath         The path to resolve.
 * @param   pszAbsPath      Where to store the absolute path.
 * @param   cchAbsPath      Size of the buffer.
 */
RTDECL(int) RTPathAbs(const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
{
    /*
     * Validation.
     */
    AssertPtr(pszAbsPath);
    AssertPtr(pszPath);
    if (RT_UNLIKELY(!*pszPath))
        return VERR_INVALID_PARAMETER;

    /*
     * Convert to UTF-16, call Win32 API, convert back.
     */
    LPWSTR pwszPath;
    int rc = RTStrToUtf16(pszPath, &pwszPath);
    if (!RT_SUCCESS(rc))
        return (rc);

    LPWSTR pwszFile; /* Ignored */
    RTUTF16 wsz[RTPATH_MAX];
    rc = GetFullPathNameW(pwszPath, RT_ELEMENTS(wsz), &wsz[0], &pwszFile);
    if (rc > 0 && rc < RT_ELEMENTS(wsz))
    {
        size_t cch;
        rc = RTUtf16ToUtf8Ex(&wsz[0], RTSTR_MAX, &pszAbsPath, cchAbsPath, &cch);
        if (RT_SUCCESS(rc))
        {
# if 1 /** @todo This code is completely bonkers. */
            /*
             * Remove trailing slash if the path may be pointing to a directory.
             * (See posix variant.)
             */
            if (    cch > 1
                &&  RTPATH_IS_SLASH(pszAbsPath[cch - 1])
                &&  !RTPATH_IS_VOLSEP(pszAbsPath[cch - 2])
                &&  !RTPATH_IS_SLASH(pszAbsPath[cch - 2]))
                pszAbsPath[cch - 1] = '\0';
# endif
        }
    }
    else if (rc <= 0)
        rc = RTErrConvertFromWin32(GetLastError());
    else
        rc = VERR_FILENAME_TOO_LONG;

    RTUtf16Free(pwszPath);
    return rc;
}
示例#7
0
/**
 * Figures the length of the root part of the path.
 *
 * @returns length of the root specifier.
 * @retval  0 if none.
 *
 * @param   pszPath         The path to investigate.
 *
 * @remarks Unnecessary root slashes will not be counted. The caller will have
 *          to deal with it where it matters.  (Unlike rtPathRootSpecLen which
 *          counts them.)
 */
static size_t rtPathRootSpecLen2(const char *pszPath)
{
    /* fend of wildlife. */
    if (!pszPath)
        return 0;

    /* Root slash? */
    if (RTPATH_IS_SLASH(pszPath[0]))
    {
#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
        /* UNC? */
        if (    RTPATH_IS_SLASH(pszPath[1])
            &&  pszPath[2] != '\0'
            &&  !RTPATH_IS_SLASH(pszPath[2]))
        {
            /* Find the end of the server name. */
            const char *pszEnd = pszPath + 2;
            pszEnd += 2;
            while (   *pszEnd != '\0'
                   && !RTPATH_IS_SLASH(*pszEnd))
                pszEnd++;
            if (RTPATH_IS_SLASH(*pszEnd))
            {
                pszEnd++;
                while (RTPATH_IS_SLASH(*pszEnd))
                    pszEnd++;

                /* Find the end of the share name */
                while (   *pszEnd != '\0'
                       && !RTPATH_IS_SLASH(*pszEnd))
                    pszEnd++;
                if (RTPATH_IS_SLASH(*pszEnd))
                    pszEnd++;
                return pszPath - pszEnd;
            }
        }
#endif
        return 1;
    }

#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
    /* Drive specifier? */
    if (   pszPath[0] != '\0'
        && pszPath[1] == ':'
        && RT_C_IS_ALPHA(pszPath[0]))
    {
        if (RTPATH_IS_SLASH(pszPath[2]))
            return 3;
        return 2;
    }
#endif
    return 0;
}
/**
 * Validates the specified file or directory.
 *
 * @returns IPRT status code, errors go via rtPathRmError.
 * @param   pOpts               The RM options.
 * @param   pszPath             The path to the file, directory, whatever.
 */
static int rtPathRmOneValidate(PRTPATHRMCMDOPTS pOpts, const char *pszPath)
{
    /*
     * RTPathFilename doesn't do the trailing slash thing the way we need it to.
     * E.g. both '..' and '../' should be rejected.
     */
    size_t cchPath = strlen(pszPath);
    while (cchPath > 0 && RTPATH_IS_SLASH(pszPath[cchPath - 1]))
        cchPath--;

    if (   (  cchPath == 0
            || 0 /** @todo drive letter + UNC crap */)
        && pOpts->fPreserveRoot)
        return rtPathRmError(pOpts, pszPath, VERR_CANT_DELETE_DIRECTORY, "Cannot remove root directory ('%s').\n", pszPath);

    size_t offLast = cchPath - 1;
    while (offLast > 0 && !RTPATH_IS_SEP(pszPath[offLast - 1]))
        offLast--;

    size_t cchLast = cchPath - offLast;
    if (   pszPath[offLast] == '.'
        && (   cchLast == 1
            || (cchLast == 2 && pszPath[offLast + 1] == '.')))
        return rtPathRmError(pOpts, pszPath, VERR_CANT_DELETE_DIRECTORY, "Cannot remove special directory '%s'.\n", pszPath);

    return VINF_SUCCESS;
}
RTDECL(int) RTPathCopyComponents(char *pszDst, size_t cbDst, const char *pszSrc, size_t cComponents)
{
    /*
     * Quick input validation.
     */
    AssertPtr(pszDst);
    AssertPtr(pszSrc);
    if (cbDst == 0)
        return VERR_BUFFER_OVERFLOW;

    /*
     * Fend of the simple case where nothing is wanted.
     */
    if (cComponents == 0)
    {
        *pszDst = '\0';
        return VINF_SUCCESS;
    }

    /*
     * Parse into the path until we've counted the desired number of objects
     * or hit the end.
     */
    size_t off = rtPathRootSpecLen(pszSrc);
    size_t c   = off != 0;
    while (c < cComponents && pszSrc[off])
    {
        c++;
        while (!RTPATH_IS_SLASH(pszSrc[off]) && pszSrc[off])
            off++;
        while (RTPATH_IS_SLASH(pszSrc[off]))
            off++;
    }

    /*
     * Copy up to but not including 'off'.
     */
    if (off >= cbDst)
        return VERR_BUFFER_OVERFLOW;

    memcpy(pszDst, pszSrc, off);
    pszDst[off] = '\0';
    return VINF_SUCCESS;
}
示例#10
0
/**
 * Figures out the length of the root (or drive) specifier in @a pszPath.
 *
 * For UNC names, we consider the root specifier to include both the server and
 * share names.
 *
 * @returns The length including all slashes.  0 if relative path.
 *
 * @param   pszPath         The path to examine.
 */
DECLHIDDEN(size_t) rtPathRootSpecLen(const char *pszPath)
{
    /*
     * If it's an absolute path, threat the root or volume specification as
     * component 0.  UNC is making this extra fun on OS/2 and Windows as usual.
     */
    size_t off = 0;
    if (RTPATH_IS_SLASH(pszPath[0]))
    {
#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
        if (   RTPATH_IS_SLASH(pszPath[1])
            && !RTPATH_IS_SLASH(pszPath[2])
            && pszPath[2])
        {
            /* UNC server name */
            off = 2;
            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                off++;
            while (RTPATH_IS_SLASH(pszPath[off]))
                off++;

            /* UNC share */
            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                off++;
        }
        else
#endif
        {
            off = 1;
        }
        while (RTPATH_IS_SLASH(pszPath[off]))
            off++;
    }
#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
    else if (RT_C_IS_ALPHA(pszPath[0]) && pszPath[1] == ':')
    {
        off = 2;
        while (RTPATH_IS_SLASH(pszPath[off]))
            off++;
    }
#endif
    Assert(!RTPATH_IS_SLASH(pszPath[off]));

    return off;
}
示例#11
0
/**
 * Cleans up a path specifier a little bit.
 *
 * This includes removing duplicate slashes, unnecessary single dots, and
 * trailing slashes. Also, replaces all slash characters with RTPATH_SLASH.
 *
 * @returns Length of the cleaned path (in chars).
 * @param   pszPath     The path to cleanup.
 */
static int fsCleanPath(char *pszPath)
{
    char *pszSrc = pszPath;
    char *pszTrg = pszPath;

    /*
     * On windows, you either use on or two slashes at the head of a path,
     * seems like it treats additional slashes as part of the UNC server name.
     * Just change slashes to RTPATH_SLASH and skip them.
     */
    /** @todo check how OS/2 treats unnecessary leading slashes */
    int cchIgnoreLeading = 0;
#ifdef HAVE_UNC
    if (   RTPATH_IS_SLASH(pszSrc[0])
        && RTPATH_IS_SLASH(pszSrc[1]))
    {
        pszTrg[0] = RTPATH_SLASH;
        pszTrg[1] = RTPATH_SLASH;
        pszTrg += 2;
        pszSrc += 2;
        cchIgnoreLeading = 1;
        while (RTPATH_IS_SLASH(*pszSrc))
        {
            cchIgnoreLeading++;
            pszSrc++;
            *pszTrg++ = RTPATH_SLASH;
        }
    }
#endif

    /*
     * Change slashes to RTPATH_SLASH and remove duplicates.
     */
    for (;;)
    {
        char ch = *pszSrc++;
        if (RTPATH_IS_SLASH(ch))
        {
            *pszTrg++ = RTPATH_SLASH;
            for (;;)
            {
                do
                    ch = *pszSrc++;
                while (RTPATH_IS_SLASH(ch));

                /* Remove '/./' and '/.'. */
                if (   ch != '.'
                    || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
                    break;
            }
        }
        *pszTrg = ch;
        if (!ch)
            break;
        pszTrg++;
    }

    return pszTrg - pszPath;
}
示例#12
0
/**
 * Cleans up a path specifier a little bit.
 * This includes removing duplicate slashes, unnecessary single dots, and
 * trailing slashes. Also, replaces all RTPATH_SLASH characters with '/'.
 *
 * @returns Number of bytes in the clean path.
 * @param   pszPath     The path to cleanup.
 */
static int fsCleanPath(char *pszPath)
{
    /*
     * Change to '/' and remove duplicates.
     */
    char   *pszSrc = pszPath;
    char   *pszTrg = pszPath;
#ifdef HAVE_UNC
    int     fUnc = 0;
    if (    RTPATH_IS_SLASH(pszPath[0])
        &&  RTPATH_IS_SLASH(pszPath[1]))
    {   /* Skip first slash in a unc path. */
        pszSrc++;
        *pszTrg++ = '/';
        fUnc = 1;
    }
#endif

    for (;;)
    {
        char ch = *pszSrc++;
        if (RTPATH_IS_SLASH(ch))
        {
            *pszTrg++ = '/';
            for (;;)
            {
                do  ch = *pszSrc++;
                while (RTPATH_IS_SLASH(ch));

                /* Remove '/./' and '/.'. */
                if (ch != '.' || (*pszSrc && !RTPATH_IS_SLASH(*pszSrc)))
                    break;
            }
        }
        *pszTrg = ch;
        if (!ch)
            break;
        pszTrg++;
    }

    /*
     * Remove trailing slash if the path may be pointing to a directory.
     */
    int cch = pszTrg - pszPath;
    if (    cch > 1
        &&  RTPATH_IS_SLASH(pszTrg[-1])
#ifdef HAVE_DRIVE
        &&  !RTPATH_IS_VOLSEP(pszTrg[-2])
#endif
        &&  !RTPATH_IS_SLASH(pszTrg[-2]))
        pszPath[--cch] = '\0';

    return cch;
}
示例#13
0
/**
 * Adds a image bundle of some sort.
 *
 * @returns IPRT status code.
 * @param   pszPath             Path to the bundle. This a RTPATH_MAX size
 *                              buffer that we can write to when creating the
 *                              path to the file inside the bundle that we're
 *                              interested in.
 * @param   cchPath             The length of the path up to the bundle name.
 * @param   cchName             The length of the bundle name.
 * @param   pDirEntry           The directory entry buffer, for handling bundle
 *                              within bundle recursion.
 * @param   pCfg                The configuration.
 */
static int rtDbgSymCacheAddImageBundle(char *pszPath, size_t cchPath, size_t cchName,
                                       PRTDIRENTRYEX pDirEntry, PCRTDBGSYMCACHEADDCFG pCfg)
{
    /*
     * Assuming these are kexts or simple applications, we only add the image
     * file itself to the cache.  No Info.plist or other files.
     */
    /** @todo consider looking for Frameworks and handling framework bundles. */
    int rc = rtDbgSymCacheConstructBundlePath(pszPath, cchPath, cchName, "Contents/MacOS/", g_apszBundleSuffixes);
    if (RT_SUCCESS(rc))
        rc = rtDbgSymCacheAddImageFile(pszPath, NULL, RTDBG_CACHE_UUID_MAP_DIR_IMAGES, pCfg);

    /*
     * Look for plugins and other sub-bundles.
     */
    if (pCfg->fRecursive)
    {
        static char const * const s_apszSubBundleDirs[] =
        {
            "Contents/Plugins/",
            /** @todo Frameworks ++ */
        };
        for (uint32_t i = 0; i < RT_ELEMENTS(s_apszSubBundleDirs); i++)
        {
            pszPath[cchPath + cchName] = '\0';
            int rc2 = RTPathAppend(pszPath, RTPATH_MAX - 1, s_apszSubBundleDirs[i]);
            if (RT_SUCCESS(rc2))
            {
                if (RTDirExists(pszPath))
                {
                    size_t cchPath2 = strlen(pszPath);
                    if (!RTPATH_IS_SLASH(pszPath[cchPath2 - 1]))
                    {
                        pszPath[cchPath2++] = RTPATH_SLASH;
                        pszPath[cchPath2]   = '\0';
                    }
                    rc2 = rtDbgSymCacheAddDirWorker(pszPath, cchPath2, pDirEntry, pCfg);
                }
            }
            else
            {
                pszPath[cchPath + cchName] = '\0';
                RTMsgError("Error constructing bundle subdir path for '%s' + '%s': %Rrc", pszPath, s_apszSubBundleDirs[i], rc);
            }
            if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
                rc = rc2;
        }
    }

    return rc;
}
示例#14
0
/**
 * Checks if a path starts with the given parent path.
 *
 * This means that either the path and the parent path matches completely, or
 * that the path is to some file or directory residing in the tree given by the
 * parent directory.
 *
 * The path comparison takes platform-dependent details into account,
 * see RTPathCompare() for details.
 *
 * @returns |true| when \a pszPath starts with \a pszParentPath (or when they
 *          are identical), or |false| otherwise.
 *
 * @param   pszPath         Path to check, must be an absolute path.
 * @param   pszParentPath   Parent path, must be an absolute path.
 *                          No trailing directory slash!
 */
RTDECL(bool) RTPathStartsWith(const char *pszPath, const char *pszParentPath)
{
    if (pszPath == pszParentPath)
        return true;
    if (!pszPath || !pszParentPath)
        return false;

    if (rtPathCompare(pszPath, pszParentPath, true /* limited by path 2 */) != 0)
        return false;

    const size_t cchParentPath = strlen(pszParentPath);
    if (RTPATH_IS_SLASH(pszPath[cchParentPath]))
        return true;
    if (pszPath[cchParentPath] == '\0')
        return true;

    /* Deal with pszParentPath = root (or having a trailing slash). */
    if (   cchParentPath > 0
        && RTPATH_IS_SLASH(pszParentPath[cchParentPath - 1])
        && RTPATH_IS_SLASH(pszPath[cchParentPath - 1]))
        return true;

    return false;
}
示例#15
0
/**
 * Strips the filename from a path. Truncates the given string in-place by overwriting the
 * last path separator character with a null byte in a platform-neutral way.
 *
 * @param   pszPath     Path from which filename should be extracted, will be truncated.
 *                      If the string contains no path separator, it will be changed to a "." string.
 */
RTDECL(void) RTPathStripFilename(char *pszPath)
{
    char *psz = pszPath;
    char *pszLastSep = NULL;


    for (;; psz++)
    {
        switch (*psz)
        {
            /* handle separators. */
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
            case ':':
                pszLastSep = psz + 1;
                if (RTPATH_IS_SLASH(psz[1]))
                    pszPath = psz + 1;
                else
                    pszPath = psz;
                break;

            case '\\':
#endif
            case '/':
                pszLastSep = psz;
                break;

            /* the end */
            case '\0':
                if (!pszLastSep)
                {
                    /* no directory component */
                    pszPath[0] = '.';
                    pszPath[1] = '\0';
                }
                else if (pszLastSep == pszPath)
                {
                    /* only root. */
                    pszLastSep[1] = '\0';
                }
                else
                    pszLastSep[0] = '\0';
                return;
        }
    }
    /* will never get here */
}
RTDECL(int) RTPathGetCurrentDrive(char *pszPath, size_t cbPath)
{
#ifdef HAVE_DRIVE
    /*
     * Query the current directroy and extract the wanted information from it.
     */
    int rc = RTPathGetCurrent(pszPath, cbPath);
    if (RT_SUCCESS(rc))
    {
        /*
         * Drive letter? Chop off at root slash.
         */
        if (pszPath[0] && RTPATH_IS_VOLSEP(pszPath[1]))
        {
            pszPath[2] = '\0';
            return rc;
        }

        /*
         * UNC? Chop off after share.
         */
        if (   RTPATH_IS_SLASH(pszPath[0])
            && RTPATH_IS_SLASH(pszPath[1])
            && !RTPATH_IS_SLASH(pszPath[2])
            && pszPath[2])
        {
            /* Work thru the server name. */
            size_t off = 3;
            while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                off++;
            size_t offServerSlash = off;

            /* Is there a share name? */
            if (RTPATH_IS_SLASH(pszPath[off]))
            {
                while (RTPATH_IS_SLASH(pszPath[off]))
                    off++;
                if (pszPath[off])
                {
                    /* Work thru the share name. */
                    while (!RTPATH_IS_SLASH(pszPath[off]) && pszPath[off])
                        off++;
                }
                /* No share name, chop at server name. */
                else
                    off = offServerSlash;
            }
        }
        return VERR_INTERNAL_ERROR_4;
    }
    return rc;

#else  /* !HAVE_DRIVE */
    /*
     * No drive letters on this system, return empty string.
     */
    if (cbPath > 0)
    {
        *pszPath = '\0';
        return VINF_SUCCESS;
    }
    return VERR_BUFFER_OVERFLOW;
#endif /* !HAVE_DRIVE */
}
/**
 * Create one directory and any missing parent directories.
 *
 * @returns exit code
 * @param   pOpts               The mkdir option.
 * @param   pszDir              The path to the new directory.
 */
static int rtCmdRmDirOneWithParents(RTCMDRMDIROPTS const *pOpts, const char *pszDir)
{
    /* We need a copy we can work with here. */
    char *pszCopy = RTStrDup(pszDir);
    if (!pszCopy)
        return RTMsgErrorExitFailure("Out of string memory!");

    int rc;
    if (!pOpts->fAlwaysUseChainApi && !RTVfsChainIsSpec(pszDir) )
    {
        size_t cchCopy = strlen(pszCopy);
        do
        {
            rc = RTDirRemove(pszCopy);
            if (RT_SUCCESS(rc))
            {
                if (pOpts->fVerbose)
                    RTPrintf("%s\n", pszCopy);
            }
            else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
                rc = VINF_SUCCESS;
            else
            {
                if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
                    rc = VINF_SUCCESS;
                else
                    RTMsgError("Failed to remove directory '%s': %Rrc", pszCopy, rc);
                break;
            }

            /* Strip off a component. */
            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            while (cchCopy > 0 && !RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            while (cchCopy > 0 && RTPATH_IS_SLASH(pszCopy[cchCopy - 1]))
                cchCopy--;
            pszCopy[cchCopy] = '\0';
        } while (cchCopy > 0);
    }
    else
    {
        /*
         * Strip the final path element from the pszDir spec.
         */
        char       *pszFinalPath;
        char       *pszSpec;
        uint32_t    offError;
        rc = RTVfsChainSplitOffFinalPath(pszCopy, &pszSpec, &pszFinalPath, &offError);
        if (RT_SUCCESS(rc))
        {
            /*
             * Open the root director/whatever.
             */
            RTERRINFOSTATIC ErrInfo;
            RTVFSDIR hVfsBaseDir;
            if (pszSpec)
            {
                rc = RTVfsChainOpenDir(pszSpec, 0 /*fOpen*/, &hVfsBaseDir, &offError, RTErrInfoInitStatic(&ErrInfo));
                if (RT_FAILURE(rc))
                    RTVfsChainMsgError("RTVfsChainOpenDir", pszSpec, rc, offError, &ErrInfo.Core);
                else if (!pszFinalPath)
                    pszFinalPath = RTStrEnd(pszSpec, RTSTR_MAX);
            }
            else if (!RTPathStartsWithRoot(pszFinalPath))
            {
                rc = RTVfsDirOpenNormal(".", 0 /*fOpen*/, &hVfsBaseDir);
                if (RT_FAILURE(rc))
                    RTMsgError("Failed to open '.' (for %s): %Rrc", rc, pszFinalPath);
            }
            else
            {
                char *pszRoot = pszFinalPath;
                pszFinalPath = RTPathSkipRootSpec(pszFinalPath);
                char const chSaved = *pszFinalPath;
                *pszFinalPath = '\0';
                rc = RTVfsDirOpenNormal(pszRoot, 0 /*fOpen*/, &hVfsBaseDir);
                *pszFinalPath = chSaved;
                if (RT_FAILURE(rc))
                    RTMsgError("Failed to open root dir for '%s': %Rrc", rc, pszRoot);
            }

            /*
             * Walk the path component by component, starting at the end.
             */
            if (RT_SUCCESS(rc))
            {
                size_t cchFinalPath = strlen(pszFinalPath);
                while (RT_SUCCESS(rc) && cchFinalPath > 0)
                {
                    rc = RTVfsDirRemoveDir(hVfsBaseDir, pszFinalPath, 0 /*fFlags*/);
                    if (RT_SUCCESS(rc))
                    {
                        if (pOpts->fVerbose)
                            RTPrintf("%s\n", pszCopy);
                    }
                    else if ((rc == VERR_PATH_NOT_FOUND || rc == VERR_FILE_NOT_FOUND) && pOpts->fIgnoreNonExisting)
                        rc = VINF_SUCCESS;
                    else
                    {
                        if ((rc == VERR_DIR_NOT_EMPTY || rc == VERR_SHARING_VIOLATION) && pOpts->fIgnoreNotEmpty)
                            rc = VINF_SUCCESS;
                        else if (pszSpec)
                            RTMsgError("Failed to remove directory '%s:%s': %Rrc", pszSpec, pszFinalPath, rc);
                        else
                            RTMsgError("Failed to remove directory '%s': %Rrc", pszFinalPath, rc);
                        break;
                    }

                    /* Strip off a component. */
                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    while (cchFinalPath > 0 && !RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    while (cchFinalPath > 0 && RTPATH_IS_SLASH(pszFinalPath[cchFinalPath - 1]))
                        cchFinalPath--;
                    pszFinalPath[cchFinalPath] = '\0';
                }

                RTVfsDirRelease(hVfsBaseDir);
            }
        }
        else
            RTVfsChainMsgError("RTVfsChainOpenParentDir", pszCopy, rc, offError, NULL);
    }
    RTStrFree(pszCopy);
    return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
}
示例#18
0
文件: dir2.cpp 项目: bayasist/vbox
/**
 * Recursion worker for RTDirRemoveRecursive.
 *
 * @returns IPRT status code.
 * @param   pszBuf              The path buffer.  Contains the abs path to the
 *                              directory to recurse into.  Trailing slash.
 * @param   cchDir              The length of the directory we're cursing into,
 *                              including the trailing slash.
 * @param   pDirEntry           The dir entry buffer.  (Shared to save stack.)
 * @param   pObjInfo            The object info buffer.  (ditto)
 */
static int rtDirRemoveRecursiveSub(char *pszBuf, size_t cchDir, PRTDIRENTRY pDirEntry, PRTFSOBJINFO pObjInfo)
{
    AssertReturn(RTPATH_IS_SLASH(pszBuf[cchDir - 1]), VERR_INTERNAL_ERROR_4);

    /*
     * Enumerate the directory content and dispose of it.
     */
    PRTDIR pDir;
    int rc = RTDirOpen(&pDir, pszBuf);
    if (RT_FAILURE(rc))
        return rc;
    while (RT_SUCCESS(rc = RTDirRead(pDir, pDirEntry, NULL)))
    {
        if (   pDirEntry->szName[0] != '.'
            || pDirEntry->cbName > 2
            || (   pDirEntry->cbName == 2
                && pDirEntry->szName[1] != '.')
           )
        {
            /* Construct the full name of the entry. */
            if (cchDir + pDirEntry->cbName + 1 /* dir slash */ >= RTPATH_MAX)
            {
                rc = VERR_FILENAME_TOO_LONG;
                break;
            }
            memcpy(&pszBuf[cchDir], pDirEntry->szName, pDirEntry->cbName + 1);

            /* Deal with the unknown type. */
            if (pDirEntry->enmType == RTDIRENTRYTYPE_UNKNOWN)
            {
                rc = RTPathQueryInfoEx(pszBuf, pObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
                if (RT_SUCCESS(rc) && RTFS_IS_DIRECTORY(pObjInfo->Attr.fMode))
                    pDirEntry->enmType = RTDIRENTRYTYPE_DIRECTORY;
                else if (RT_SUCCESS(rc) && RTFS_IS_FILE(pObjInfo->Attr.fMode))
                    pDirEntry->enmType = RTDIRENTRYTYPE_FILE;
                else if (RT_SUCCESS(rc) && RTFS_IS_SYMLINK(pObjInfo->Attr.fMode))
                    pDirEntry->enmType = RTDIRENTRYTYPE_SYMLINK;
            }

            /* Try the delete the fs object. */
            switch (pDirEntry->enmType)
            {
                case RTDIRENTRYTYPE_FILE:
                    rc = RTFileDelete(pszBuf);
                    break;

                case RTDIRENTRYTYPE_DIRECTORY:
                {
                    size_t cchSubDir = cchDir + pDirEntry->cbName;
                    pszBuf[cchSubDir++] = '/';
                    pszBuf[cchSubDir]   = '\0';
                    rc = rtDirRemoveRecursiveSub(pszBuf, cchSubDir, pDirEntry, pObjInfo);
                    if (RT_SUCCESS(rc))
                    {
                        pszBuf[cchSubDir] = '\0';
                        rc = RTDirRemove(pszBuf);
                    }
                    break;
                }

                //case RTDIRENTRYTYPE_SYMLINK:
                //    rc = RTSymlinkDelete(pszBuf, 0);
                //    break;

                default:
                    /** @todo not implemented yet. */
                    rc = VINF_SUCCESS;
                    break;
            }
            if (RT_FAILURE(rc))
               break;
        }
    }
    if (rc == VERR_NO_MORE_FILES)
        rc = VINF_SUCCESS;
    RTDirClose(pDir);
    return rc;
}
int vbsfPathGuestToHost(SHFLCLIENTDATA *pClient, SHFLROOT hRoot,
                        PCSHFLSTRING pGuestString, uint32_t cbGuestString,
                        char **ppszHostPath, uint32_t *pcbHostPathRoot,
                        uint32_t fu32Options,
                        uint32_t *pfu32PathFlags)
{
#ifdef VBOX_STRICT
    /*
     * Check that the pGuestPath has correct size and encoding.
     */
    if (ShflStringIsValidIn(pGuestString, cbGuestString, RT_BOOL(pClient->fu32Flags & SHFL_CF_UTF8)) == false)
    {
        LogFunc(("Invalid input string\n"));
        return VERR_INTERNAL_ERROR;
    }
#else
    NOREF(cbGuestString);
#endif

    /*
     * Resolve the root handle into a string.
     */
    uint32_t cbRootLen = 0;
    const char *pszRoot = NULL;
    int rc = vbsfMappingsQueryHostRootEx(hRoot, &pszRoot, &cbRootLen);
    if (RT_FAILURE(rc))
    {
        LogFunc(("invalid root\n"));
        return rc;
    }

    AssertReturn(cbRootLen > 0, VERR_INTERNAL_ERROR_2); /* vbsfMappingsQueryHostRootEx ensures this. */

    /*
     * Get the UTF8 string with the relative path provided by the guest.
     * If guest uses UTF-16 then convert it to UTF-8.
     */
    uint32_t    cbGuestPath = 0;        /* Shut up MSC */
    const char *pchGuestPath = NULL;    /* Ditto. */
    char *pchGuestPathAllocated = NULL; /* Converted from UTF-16. */
    if (BIT_FLAG(pClient->fu32Flags, SHFL_CF_UTF8))
    {
        /* UTF-8 */
        cbGuestPath = pGuestString->u16Length;
        pchGuestPath = pGuestString->String.ach;
    }
    else
    {
        /* UTF-16 */

#ifdef RT_OS_DARWIN /* Misplaced hack! See todo! */
        uint32_t cwcSrc  = 0;
        PRTUTF16 pwszSrc = NULL;
        rc = vbsfNormalizeStringDarwin(&pGuestString->String.ucs2[0],
                                       pGuestString->u16Length / sizeof(RTUTF16),
                                       &pwszSrc, &cwcSrc);
#else
        uint32_t  const cwcSrc  = pGuestString->u16Length / sizeof(RTUTF16);
        PCRTUTF16 const pwszSrc = &pGuestString->String.ucs2[0];
#endif

        if (RT_SUCCESS(rc))
        {
            size_t cbPathAsUtf8 = RTUtf16CalcUtf8Len(pwszSrc);
            if (cbPathAsUtf8 >= cwcSrc)
            {
                /* Allocate buffer that will be able to contain the converted UTF-8 string. */
                pchGuestPathAllocated = (char *)RTMemAlloc(cbPathAsUtf8 + 1);
                if (RT_LIKELY(pchGuestPathAllocated != NULL))
                {
                    if (RT_LIKELY(cbPathAsUtf8))
                    {
                        size_t cchActual;
                        char *pszDst = pchGuestPathAllocated;
                        rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, cbPathAsUtf8 + 1, &cchActual);
                        AssertRC(rc);
                        AssertStmt(RT_FAILURE(rc) || cchActual == cbPathAsUtf8, rc = VERR_INTERNAL_ERROR_4);
                        Assert(strlen(pszDst) == cbPathAsUtf8);
                    }

                    if (RT_SUCCESS(rc))
                    {
                        /* Terminate the string. */
                        pchGuestPathAllocated[cbPathAsUtf8] = '\0';

                        cbGuestPath = (uint32_t)cbPathAsUtf8; Assert(cbGuestPath == cbPathAsUtf8);
                        pchGuestPath = pchGuestPathAllocated;
                    }
                }
                else
                {
                    rc = VERR_NO_MEMORY;
                }
            }
            else
            {
                AssertFailed();
                rc = VERR_INTERNAL_ERROR_3;
            }

#ifdef RT_OS_DARWIN
            RTMemFree(pwszSrc);
#endif
        }
    }

    char *pszFullPath = NULL;

    if (RT_SUCCESS(rc))
    {
        LogFlowFunc(("Root %s path %.*s\n", pszRoot, cbGuestPath, pchGuestPath));

        /*
         * Allocate enough memory to build the host full path from the root and the relative path.
         */
        const uint32_t cbFullPathAlloc = cbRootLen + 1 + cbGuestPath + 1; /* root + possible_slash + relative + 0 */
        pszFullPath = (char *)RTMemAlloc(cbFullPathAlloc);
        if (RT_LIKELY(pszFullPath != NULL))
        {
            /* Buffer for the verified guest path. */
            char *pchVerifiedPath = (char *)RTMemAlloc(cbGuestPath + 1);
            if (RT_LIKELY(pchVerifiedPath != NULL))
            {
                /* Init the pointer for the guest relative path. */
                uint32_t cbSrc = cbGuestPath;
                const char *pchSrc = pchGuestPath;

                /* Strip leading delimiters from the path the guest specified. */
                while (   cbSrc > 0
                       && *pchSrc == pClient->PathDelimiter)
                {
                    ++pchSrc;
                    --cbSrc;
                }

                /*
                 * Iterate the guest path components, verify each of them replacing delimiters with the host slash.
                 */
                char *pchDst = pchVerifiedPath;
                bool fLastComponentHasWildcard = false;
                for (; cbSrc > 0; --cbSrc, ++pchSrc)
                {
                    if (RT_LIKELY(*pchSrc != pClient->PathDelimiter))
                    {
                        if (RT_LIKELY(vbsfPathIsValidNameChar(*pchSrc)))
                        {
                            if (pfu32PathFlags && vbsfPathIsWildcardChar(*pchSrc))
                            {
                                fLastComponentHasWildcard = true;
                            }

                            *pchDst++ = *pchSrc;
                        }
                        else
                        {
                            rc = VERR_INVALID_NAME;
                            break;
                        }
                    }
                    else
                    {
                        /* Replace with the host slash. */
                        *pchDst++ = RTPATH_SLASH;

                        if (pfu32PathFlags && fLastComponentHasWildcard && cbSrc > 1)
                        {
                            /* Processed component has a wildcard and there are more characters in the path. */
                            *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_PREFIX;
                        }
                        fLastComponentHasWildcard = false;
                    }
                }

                if (RT_SUCCESS(rc))
                {
                    *pchDst++ = 0;

                    /* Construct the full host path removing '.' and '..'. */
                    rc = vbsfPathAbs(pszRoot, pchVerifiedPath, pszFullPath, cbFullPathAlloc);
                    if (RT_SUCCESS(rc))
                    {
                        if (pfu32PathFlags && fLastComponentHasWildcard)
                        {
                            *pfu32PathFlags |= VBSF_F_PATH_HAS_WILDCARD_IN_LAST;
                        }

                        /* Check if the full path is still within the shared folder. */
                        if (fu32Options & VBSF_O_PATH_CHECK_ROOT_ESCAPE)
                        {
                            if (!RTPathStartsWith(pszFullPath, pszRoot))
                            {
                                rc = VERR_INVALID_NAME;
                            }
                        }

                        if (RT_SUCCESS(rc))
                        {
                            /*
                             * If the host file system is case sensitive and the guest expects
                             * a case insensitive fs, then correct the path components casing.
                             */
                            if (    vbsfIsHostMappingCaseSensitive(hRoot)
                                && !vbsfIsGuestMappingCaseSensitive(hRoot))
                            {
                                const bool fWildCard = RT_BOOL(fu32Options & VBSF_O_PATH_WILDCARD);
                                const bool fPreserveLastComponent = RT_BOOL(fu32Options & VBSF_O_PATH_PRESERVE_LAST_COMPONENT);
                                rc = vbsfCorrectPathCasing(pClient, pszFullPath, strlen(pszFullPath),
                                                           fWildCard, fPreserveLastComponent);
                            }

                            if (RT_SUCCESS(rc))
                            {
                               LogFlowFunc(("%s\n", pszFullPath));

                               /* Return the full host path. */
                               *ppszHostPath = pszFullPath;

                               if (pcbHostPathRoot)
                               {
                                   /* Return the length of the root path without the trailing slash. */
                                   *pcbHostPathRoot = RTPATH_IS_SLASH(pszFullPath[cbRootLen - 1]) ?
                                                          cbRootLen - 1 : /* pszRoot already had the trailing slash. */
                                                          cbRootLen; /* pszRoot did not have the trailing slash. */
                               }
                            }
                        }
                    }
                    else
                    {
                        LogFunc(("vbsfPathAbs %Rrc\n", rc));
                    }
                }

                RTMemFree(pchVerifiedPath);
            }
            else
            {
                rc = VERR_NO_MEMORY;
            }
        }
        else
        {
            rc = VERR_NO_MEMORY;
        }
    }

    /*
     * Cleanup.
     */
    RTMemFree(pchGuestPathAllocated);

    if (RT_SUCCESS(rc))
    {
        return rc;
    }

    /*
     * Cleanup on failure.
     */
    RTMemFree(pszFullPath);

    LogFunc(("%Rrc\n", rc));
    return rc;
}
示例#20
0
/**
 * Parses a path.
 *
 * It figures the length of the directory component, the offset of
 * the file name and the location of the suffix dot.
 *
 * @returns The path length.
 *
 * @param   pszPath     Path to find filename in.
 * @param   pcchDir     Where to put the length of the directory component. If
 *                      no directory, this will be 0. Optional.
 * @param   poffName    Where to store the filename offset.
 *                      If empty string or if it's ending with a slash this
 *                      will be set to -1. Optional.
 * @param   poffSuff    Where to store the suffix offset (the last dot).
 *                      If empty string or if it's ending with a slash this
 *                      will be set to -1. Optional.
 */
RTDECL(size_t) RTPathParseSimple(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff)
{
    const char *psz = pszPath;
    ssize_t     offRoot = 0;
    const char *pszName = pszPath;
    const char *pszLastDot = NULL;

    for (;; psz++)
    {
        switch (*psz)
        {
            /* handle separators. */
#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
            case ':':
                pszName = psz + 1;
                offRoot = pszName - psz;
                break;

            case '\\':
#endif
            case '/':
                pszName = psz + 1;
                break;

            case '.':
                pszLastDot = psz;
                break;

            /*
             * The end. Complete the results.
             */
            case '\0':
            {
                ssize_t offName = *pszName != '\0' ? pszName - pszPath : -1;
                if (poffName)
                    *poffName = offName;

                if (poffSuff)
                {
                    ssize_t offSuff = -1;
                    if (pszLastDot)
                    {
                        offSuff = pszLastDot - pszPath;
                        if (offSuff <= offName)
                            offSuff = -1;
                    }
                    *poffSuff = offSuff;
                }

                if (pcchDir)
                {
                    ssize_t off = offName - 1;
                    while (off >= offRoot && RTPATH_IS_SLASH(pszPath[off]))
                        off--;
                    *pcchDir = RT_MAX(off, offRoot) + 1;
                }

                return psz - pszPath;
            }
        }
    }

    /* will never get here */
    return 0;
}
示例#21
0
RTDECL(int) RTSymlinkCreate(const char *pszSymlink, const char *pszTarget, RTSYMLINKTYPE enmType, uint32_t fCreate)
{
    /*
     * Validate the input.
     */
    AssertReturn(enmType > RTSYMLINKTYPE_INVALID && enmType < RTSYMLINKTYPE_END, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pszSymlink, VERR_INVALID_POINTER);
    AssertPtrReturn(pszTarget, VERR_INVALID_POINTER);

    /*
     * Resolve the API.
     */
    typedef BOOLEAN (WINAPI *PFNCREATESYMBOLICLINKW)(LPCWSTR, LPCWSTR, DWORD);
    static PFNCREATESYMBOLICLINKW   s_pfnCreateSymbolicLinkW = NULL;
    static bool                     s_fTried = FALSE;
    if (!s_fTried)
    {
        HMODULE hmod = LoadLibrary("KERNEL32.DLL");
        if (hmod)
        {
            PFNCREATESYMBOLICLINKW pfn = (PFNCREATESYMBOLICLINKW)GetProcAddress(hmod, "CreateSymbolicLinkW");
            if (pfn)
                s_pfnCreateSymbolicLinkW = pfn;
        }
        s_fTried = true;
    }
    if (!s_pfnCreateSymbolicLinkW)
    {
        LogFlow(("RTSymlinkCreate(%p={%s}, %p={%s}, %d, %#x): returns VERR_NOT_SUPPORTED - Windows API not found\n",
                 pszSymlink, pszSymlink, pszTarget, pszTarget, enmType, fCreate));
        return VERR_NOT_SUPPORTED;
    }

    /*
     * Convert the paths.
     */
    PRTUTF16 pwszNativeSymlink;
    int rc = RTStrToUtf16(pszSymlink, &pwszNativeSymlink);
    if (RT_SUCCESS(rc))
    {
        PRTUTF16 pwszNativeTarget;
        rc = RTStrToUtf16(pszTarget, &pwszNativeTarget);
        if (RT_SUCCESS(rc))
        {
            /*
             * Massage the target path, determin the link type.
             */
            size_t cchTarget        = strlen(pszTarget);
            size_t cchVolSpecTarget = rtPathVolumeSpecLen(pszTarget);
#if 0 /* looks like this isn't needed after all. That makes everything much simper :-) */
            if (   cchTarget > RT_MIN(cchVolSpecTarget, 1)
                && RTPATH_IS_SLASH(pszTarget[cchTarget - 1]))
            {
                size_t cwcNativeTarget = RTUtf16Len(pwszNativeTarget);
                size_t offFromEnd = 1;
                while (   offFromEnd < cchTarget
                       && cchTarget - offFromEnd >= cchVolSpecTarget
                       && RTPATH_IS_SLASH(pszTarget[cchTarget - offFromEnd]))
                {
                    Assert(offFromEnd < cwcNativeTarget);
                    pwszNativeTarget[cwcNativeTarget - offFromEnd] = 0;
                    offFromEnd++;
                }
            }
#endif

            if (enmType == RTSYMLINKTYPE_UNKNOWN)
            {
                if (   cchTarget > cchVolSpecTarget
                    && RTPATH_IS_SLASH(pszTarget[cchTarget - 1]))
                    enmType = RTSYMLINKTYPE_DIR;
                else if (cchVolSpecTarget)
                {
                    /** @todo this is subject to sharing violations. */
                    DWORD dwAttr = GetFileAttributesW(pwszNativeTarget);
                    if (   dwAttr != INVALID_FILE_ATTRIBUTES
                        && (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
                        enmType = RTSYMLINKTYPE_DIR;
                }
                else
                {
                    /** @todo Join the symlink directory with the target and
                     *        look up the attributes on that. -lazy bird. */
                }
            }

            /*
             * Create the link.
             */
            if (s_pfnCreateSymbolicLinkW(pwszNativeSymlink, pwszNativeTarget, enmType == RTSYMLINKTYPE_DIR))
                rc = VINF_SUCCESS;
            else
                rc = RTErrConvertFromWin32(GetLastError());

            RTUtf16Free(pwszNativeTarget);
        }
        RTUtf16Free(pwszNativeSymlink);
    }

    LogFlow(("RTSymlinkCreate(%p={%s}, %p={%s}, %d, %#x): returns %Rrc\n", pszSymlink, pszSymlink, pszTarget, pszTarget, enmType, fCreate, rc));
    return rc;
}
示例#22
0
/**
 * Recursively delete a directory.
 *
 * @returns IPRT status code, errors go via rtPathRmError.
 * @param   pOpts               The RM options.
 * @param   pszPath             Pointer to a writable buffer holding the path to
 *                              the directory.
 * @param   cchPath             The length of the path (avoid strlen).
 * @param   pDirEntry           Pointer to a directory entry buffer that is
 *                              RTPATHRM_DIR_MAX_ENTRY_SIZE bytes big.
 */
static int rtPathRmRecursive(PRTPATHRMCMDOPTS pOpts, char *pszPath, size_t cchPath, PRTDIRENTRYEX pDirEntry)
{
    /*
     * Make sure the path ends with a slash.
     */
    if (!cchPath || !RTPATH_IS_SLASH(pszPath[cchPath - 1]))
    {
        if (cchPath + 1 >= RTPATH_MAX)
            return rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Buffer overflow fixing up '%s'.\n", pszPath);
        pszPath[cchPath++] = RTPATH_SLASH;
        pszPath[cchPath]   = '\0';
    }

    /*
     * Traverse the directory.
     */
    PRTDIR hDir;
    int rc = RTDirOpen(&hDir, pszPath);
    if (RT_FAILURE(rc))
        return rtPathRmError(pOpts, pszPath, rc, "Error opening directory '%s': %Rrc", pszPath, rc);
    int rcRet = VINF_SUCCESS;
    for (;;)
    {
        /*
         * Read the next entry, constructing an full path for it.
         */
        size_t cbEntry = RTPATHRM_DIR_MAX_ENTRY_SIZE;
        rc = RTDirReadEx(hDir, pDirEntry, &cbEntry, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
        if (rc == VERR_NO_MORE_FILES)
        {
            /*
             * Reached the end of the directory.
             */
            pszPath[cchPath] = '\0';
            rc = RTDirClose(hDir);
            if (RT_FAILURE(rc))
                return rtPathRmError(pOpts, pszPath, rc, "Error closing directory '%s': %Rrc", pszPath, rc);

            /* Delete the directory. */
            int rc2 = rtPathRmOneDir(pOpts, pszPath);
            if (RT_FAILURE(rc2) && RT_SUCCESS(rcRet))
                return rc2;
            return rcRet;
        }

        if (RT_FAILURE(rc))
        {
            rc = rtPathRmError(pOpts, pszPath, rc, "Error reading directory '%s': %Rrc", pszPath, rc);
            break;
        }

        /* Skip '.' and '..'. */
        if (   pDirEntry->szName[0] == '.'
            && (   pDirEntry->cbName == 1
                || (   pDirEntry->cbName == 2
                    && pDirEntry->szName[1] == '.')))
            continue;

        /* Construct full path. */
        if (cchPath + pDirEntry->cbName >= RTPATH_MAX)
        {
            pszPath[cchPath] = '\0';
            rc = rtPathRmError(pOpts, pszPath, VERR_BUFFER_OVERFLOW, "Path buffer overflow in directory '%s'.", pszPath);
            break;
        }
        memcpy(pszPath + cchPath, pDirEntry->szName, pDirEntry->cbName + 1);

        /*
         * Take action according to the type.
         */
        switch (pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK)
        {
            case RTFS_TYPE_FILE:
                rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
                break;

            case RTFS_TYPE_DIRECTORY:
                rc = rtPathRmRecursive(pOpts, pszPath, cchPath + pDirEntry->cbName, pDirEntry);
                break;

            case RTFS_TYPE_SYMLINK:
                rc = rtPathRmOneSymlink(pOpts, pszPath);
                break;

            case RTFS_TYPE_FIFO:
            case RTFS_TYPE_DEV_CHAR:
            case RTFS_TYPE_DEV_BLOCK:
            case RTFS_TYPE_SOCKET:
                rc = rtPathRmOneFile(pOpts, pszPath, &pDirEntry->Info);
                break;

            case RTFS_TYPE_WHITEOUT:
            default:
                rc = rtPathRmError(pOpts, pszPath, VERR_UNEXPECTED_FS_OBJ_TYPE,
                                   "Object '%s' has an unknown file type: %o\n",
                                   pszPath, pDirEntry->Info.Attr.fMode & RTFS_TYPE_MASK);
                break;
        }
        if (RT_FAILURE(rc) && RT_SUCCESS(rcRet))
            rcRet = rc;
    }

    /*
     * Some error occured, close and return.
     */
    RTDirClose(hDir);
    return rc;
}
示例#23
0
RTDECL(int) RTPathAppendEx(char *pszPath, size_t cbPathDst, const char *pszAppend, size_t cchAppendMax)
{
    char *pszPathEnd = RTStrEnd(pszPath, cbPathDst);
    AssertReturn(pszPathEnd, VERR_INVALID_PARAMETER);

    /*
     * Special cases.
     */
    if (!pszAppend)
        return VINF_SUCCESS;
    size_t cchAppend = RTStrNLen(pszAppend, cchAppendMax);
    if (!cchAppend)
        return VINF_SUCCESS;
    if (pszPathEnd == pszPath)
    {
        if (cchAppend >= cbPathDst)
            return VERR_BUFFER_OVERFLOW;
        memcpy(pszPath, pszAppend, cchAppend);
        pszPath[cchAppend] = '\0';
        return VINF_SUCCESS;
    }

    /*
     * Balance slashes and check for buffer overflow.
     */
    if (!RTPATH_IS_SLASH(pszPathEnd[-1]))
    {
        if (!RTPATH_IS_SLASH(pszAppend[0]))
        {
#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
            if (    (size_t)(pszPathEnd - pszPath) == 2
                &&  pszPath[1] == ':'
                &&  RT_C_IS_ALPHA(pszPath[0]))
            {
                if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
                    return VERR_BUFFER_OVERFLOW;
            }
            else
#endif
            {
                if ((size_t)(pszPathEnd - pszPath) + 1 + cchAppend >= cbPathDst)
                    return VERR_BUFFER_OVERFLOW;
                *pszPathEnd++ = RTPATH_SLASH;
            }
        }
        else
        {
            /* One slash is sufficient at this point. */
            while (cchAppend > 1 && RTPATH_IS_SLASH(pszAppend[1]))
                pszAppend++, cchAppend--;

            if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
                return VERR_BUFFER_OVERFLOW;
        }
    }
    else
    {
        /* No slashes needed in the appended bit. */
        while (cchAppend && RTPATH_IS_SLASH(*pszAppend))
            pszAppend++, cchAppend--;

        /* In the leading path we can skip unnecessary trailing slashes, but
           be sure to leave one. */
        size_t const cchRoot = rtPathRootSpecLen2(pszPath);
        while (     (size_t)(pszPathEnd - pszPath) > RT_MAX(1, cchRoot)
               &&   RTPATH_IS_SLASH(pszPathEnd[-2]))
            pszPathEnd--;

        if ((size_t)(pszPathEnd - pszPath) + cchAppend >= cbPathDst)
            return VERR_BUFFER_OVERFLOW;
    }

    /*
     * What remains now is the just the copying.
     */
    memcpy(pszPathEnd, pszAppend, cchAppend);
    pszPathEnd[cchAppend] = '\0';
    return VINF_SUCCESS;
}