/**
 * Device I/O Control entry point.
 *
 * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
 * @param   Dev         The device number (major+minor).
 * @param   iCmd        The IOCtl command.
 * @param   pData       Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
 * @param   fFlags      Flag saying we're a character device (like we didn't know already).
 * @param   pProcess    The process issuing this request.
 */
static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
{
    uint32_t cbReq = IOCPARM_LEN(iCmd);
    PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
    int rc;

    Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
    switch (IOCBASECMD(iCmd))
    {
        case IOCBASECMD(VBOXNETADP_CTL_ADD):
        {
            if (   (IOC_DIRMASK & iCmd) != IOC_INOUT
                || cbReq < sizeof(VBOXNETADPREQ))
                return EINVAL;

            PVBOXNETADP pNew;
            Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
            rc = vboxNetAdpCreate(&pNew,
                                  pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
                                  pReq->szName : NULL);
            if (RT_FAILURE(rc))
                return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL;

            Assert(strlen(pReq->szName) < sizeof(pReq->szName));
            strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
            pReq->szName[sizeof(pReq->szName) - 1] = '\0';
            Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
            break;
        }

        case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
        {
            if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
                return EINVAL;

            PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
            if (!pAdp)
                return EINVAL;

            rc = vboxNetAdpDestroy(pAdp);
            if (RT_FAILURE(rc))
                return EINVAL;
            Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
            break;
        }

        default:
            printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
            return EINVAL;
    }

    return 0;
}
Esempio n. 2
0
RTDECL(int) RTStrATruncateTag(char **ppsz, size_t cchNew, const char *pszTag)
{
    char *pszNew;
    char *pszOld = *ppsz;
    if (!cchNew)
    {
        if (pszOld && *pszOld)
        {
            *pszOld = '\0';
            pszNew = (char *)RTMemReallocTag(pszOld, 1, pszTag);
            if (pszNew)
                *ppsz = pszNew;
        }
    }
    else
    {
        char *pszZero;
        AssertPtrReturn(pszOld, VERR_OUT_OF_RANGE);
        AssertReturn(cchNew < ~(size_t)64, VERR_OUT_OF_RANGE);
        pszZero = RTStrEnd(pszOld, cchNew + 63);
        AssertReturn(!pszZero || (size_t)(pszZero - pszOld) >= cchNew, VERR_OUT_OF_RANGE);
        pszOld[cchNew] = '\0';
        if (!pszZero)
        {
            pszNew = (char *)RTMemReallocTag(pszOld,  cchNew + 1, pszTag);
            if (pszNew)
                *ppsz = pszNew;
        }
    }
    return VINF_SUCCESS;
}
Esempio n. 3
0
/**
 * Deregisters a guest OS digger previously registered by DBGFR3OSRegister.
 *
 * @returns VBox status code.
 *
 * @param   pVM     Pointer to the shared VM structure.
 * @param   pReg    The registration structure.
 * @thread  Any.
 */
VMMR3DECL(int)  DBGFR3OSDeregister(PVM pVM, PCDBGFOSREG pReg)
{
    /*
     * Validate input.
     */
    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
    AssertPtrReturn(pReg, VERR_INVALID_POINTER);
    AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
    AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
    AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);

    DBGF_OS_READ_LOCK(pVM);
    PDBGFOS pOS;
    for (pOS = pVM->dbgf.s.pOSHead; pOS; pOS = pOS->pNext)
        if (pOS->pReg == pReg)
            break;
    DBGF_OS_READ_LOCK(pVM);

    if (!pOS)
    {
        Log(("DBGFR3OSDeregister: %s -> VERR_NOT_FOUND\n", pReg->szName));
        return VERR_NOT_FOUND;
    }

    /*
     * Pass it on to EMT(0).
     */
    return VMR3ReqPriorityCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSDeregister, 2, pVM, pReg);
}
Esempio n. 4
0
/**
 * Registers a guest OS digger.
 *
 * This will instantiate an instance of the digger and add it
 * to the list for us in the next call to DBGFR3OSDetect().
 *
 * @returns VBox status code.
 * @param   pVM     Pointer to the shared VM structure.
 * @param   pReg    The registration structure.
 * @thread  Any.
 */
VMMR3DECL(int) DBGFR3OSRegister(PVM pVM, PCDBGFOSREG pReg)
{
    /*
     * Validate intput.
     */
    VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);

    AssertPtrReturn(pReg, VERR_INVALID_POINTER);
    AssertReturn(pReg->u32Magic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
    AssertReturn(pReg->u32EndMagic == DBGFOSREG_MAGIC, VERR_INVALID_MAGIC);
    AssertReturn(!pReg->fFlags, VERR_INVALID_PARAMETER);
    AssertReturn(pReg->cbData < _2G, VERR_INVALID_PARAMETER);
    AssertReturn(pReg->szName[0], VERR_INVALID_NAME);
    AssertReturn(RTStrEnd(&pReg->szName[0], sizeof(pReg->szName)), VERR_INVALID_NAME);
    AssertPtrReturn(pReg->pfnConstruct, VERR_INVALID_POINTER);
    AssertPtrNullReturn(pReg->pfnDestruct, VERR_INVALID_POINTER);
    AssertPtrReturn(pReg->pfnProbe, VERR_INVALID_POINTER);
    AssertPtrReturn(pReg->pfnInit, VERR_INVALID_POINTER);
    AssertPtrReturn(pReg->pfnRefresh, VERR_INVALID_POINTER);
    AssertPtrReturn(pReg->pfnTerm, VERR_INVALID_POINTER);
    AssertPtrReturn(pReg->pfnQueryVersion, VERR_INVALID_POINTER);
    AssertPtrReturn(pReg->pfnQueryInterface, VERR_INVALID_POINTER);

    /*
     * Pass it on to EMT(0).
     */
    return VMR3ReqPriorityCallWait(pVM, 0 /*idDstCpu*/, (PFNRT)dbgfR3OSRegister, 2, pVM, pReg);
}
/**
 * Read a zero terminated string from guest memory.
 *
 * @returns VBox status code.
 *
 * @param   pVM             Pointer to the shared VM structure.
 * @param   idCpu           The ID of the source CPU context (for the address).
 * @param   pAddress        Where to start reading.
 * @param   pszBuf          Where to store the string.
 * @param   cchBuf          The size of the buffer.
 */
static DECLCALLBACK(int) dbgfR3MemReadString(PVM pVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cchBuf)
{
    /*
     * Validate the input we use, PGM does the rest.
     */
    if (!DBGFR3AddrIsValid(pVM, pAddress))
        return VERR_INVALID_POINTER;
    if (!VALID_PTR(pszBuf))
        return VERR_INVALID_POINTER;

    /*
     * Let dbgfR3MemRead do the job.
     */
    int rc = dbgfR3MemRead(pVM, idCpu, pAddress, pszBuf, cchBuf);

    /*
     * Make sure the result is terminated and that overflow is signaled.
     * This may look a bit reckless with the rc but, it should be fine.
     */
    if (!RTStrEnd(pszBuf, cchBuf))
    {
        pszBuf[cchBuf - 1] = '\0';
        rc = VINF_BUFFER_OVERFLOW;
    }
    /*
     * Handle partial reads (not perfect).
     */
    else if (RT_FAILURE(rc))
    {
        if (pszBuf[0])
            rc = VINF_SUCCESS;
    }

    return rc;
}
Esempio n. 6
0
/**
 * Checks if it's a text stream.
 *
 * Not 100% proof.
 *
 * @returns true if it probably is a text file, false if not.
 * @param   pStream             The stream. Write or read, doesn't matter.
 */
bool ScmStreamIsText(PSCMSTREAM pStream)
{
    if (RTStrEnd(pStream->pch, pStream->cb))
        return false;
    if (!pStream->cb)
        return false;
    return true;
}
Esempio n. 7
0
RTDECL(const char *) RTStrCacheEnterN(RTSTRCACHE hStrCache, const char *pchString, size_t cchString)
{
    AssertPtr(pchString);
    AssertReturn(cchString < _1G, NULL);
    Assert(!RTStrEnd(pchString, cchString));

    return (const char *)RTMemPoolDupEx((RTMEMPOOL)hStrCache, pchString, cchString, 1);
}
Esempio n. 8
0
RTDECL(int) RTStrNLenEx(const char *pszString, size_t cchMax, size_t *pcch)
{
    const char *pchEnd = RTStrEnd(pszString, cchMax);
    if (!pchEnd)
    {
        *pcch = cchMax;
        return VERR_BUFFER_OVERFLOW;
    }
    *pcch = pchEnd - pszString;
    return VINF_SUCCESS;
}
Esempio n. 9
0
RTDECL(char *) RTStrDupNTag(const char *pszString, size_t cchMax, const char *pszTag)
{
#if defined(__cplusplus)
    AssertPtr(pszString);
#endif
    char const *pszEnd = RTStrEnd(pszString, cchMax);
    size_t      cch    = pszEnd ? (uintptr_t)pszEnd - (uintptr_t)pszString : cchMax;
    char       *pszDst = (char *)RTMemAllocTag(cch + 1, pszTag);
    if (pszDst)
    {
        memcpy(pszDst, pszString, cch);
        pszDst[cch] = '\0';
    }
    return pszDst;
}
Esempio n. 10
0
RTDECL(int) RTStrCopyEx(char *pszDst, size_t cbDst, const char *pszSrc, size_t cchMaxSrc)
{
    const char *pszSrcEol = RTStrEnd(pszSrc, cchMaxSrc);
    size_t      cchSrc    = pszSrcEol ? (size_t)(pszSrcEol - pszSrc) : cchMaxSrc;
    if (RT_LIKELY(cchSrc < cbDst))
    {
        memcpy(pszDst, pszSrc, cchSrc);
        pszDst[cchSrc] = '\0';
        return VINF_SUCCESS;
    }

    if (cbDst != 0)
    {
        memcpy(pszDst, pszSrc, cbDst - 1);
        pszDst[cbDst - 1] = '\0';
    }
    return VERR_BUFFER_OVERFLOW;
}
RTDECL(int) RTStrCat(char *pszDst, size_t cbDst, const char *pszSrc)
{
    char *pszDst2 = RTStrEnd(pszDst, cbDst);
    AssertReturn(pszDst2, VERR_INVALID_PARAMETER);
    cbDst -= pszDst2 - pszDst;

    size_t cchSrc = strlen(pszSrc);
    if (RT_LIKELY(cchSrc < cbDst))
    {
        memcpy(pszDst2, pszSrc, cchSrc + 1);
        return VINF_SUCCESS;
    }

    if (cbDst != 0)
    {
        memcpy(pszDst2, pszSrc, cbDst - 1);
        pszDst2[cbDst - 1] = '\0';
    }
    return VERR_BUFFER_OVERFLOW;
}
Esempio n. 12
0
RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen)
{
    AssertReturn((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE, VERR_INVALID_FLAGS);
    AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_FLAGS);

    /*
     * Start by obtaining the path to the temporary directory.
     */
    int rc = RTPathTemp(pszFilename, cbFilename);
    if (RT_SUCCESS(rc))
    {
        /*
         * Add a filename pattern.
         */
        static char const s_szTemplate[] = "IPRT-XXXXXXXXXXXX.tmp";
        rc = RTPathAppend(pszFilename, cbFilename, s_szTemplate);
        if (RT_SUCCESS(rc))
        {
            char * const pszX = RTStrEnd(pszFilename, cbFilename) - (sizeof(s_szTemplate) - 1) + 5;
            unsigned     cXes = sizeof(s_szTemplate) - 1 - 4 - 5;
            Assert(pszX[0] == 'X'); Assert(pszX[-1] == '-'); Assert(pszX[cXes] == '.');

            /*
             * Try 10000 times with random names.
             */
            unsigned cTriesLeft = 10000;
            while (cTriesLeft-- > 0)
            {
                rtCreateTempFillTemplate(pszX, cXes);
                rc = RTFileOpen(phFile, pszFilename, fOpen);
                if (RT_SUCCESS(rc))
                    return rc;
            }
        }
    }

    if (cbFilename)
        *pszFilename = '\0';
    *phFile = NIL_RTFILE;
    return rc;
}
Esempio n. 13
0
/**
 * @copydoc DBGFOSREG::pfnQueryVersion
 */
static DECLCALLBACK(int)  dbgDiggerLinuxQueryVersion(PUVM pUVM, void *pvData, char *pszVersion, size_t cchVersion)
{
    PDBGDIGGERLINUX pThis = (PDBGDIGGERLINUX)pvData;
    Assert(pThis->fValid);

    /*
     * It's all in the linux banner.
     */
    int rc = DBGFR3MemReadString(pUVM, 0, &pThis->AddrLinuxBanner, pszVersion, cchVersion);
    if (RT_SUCCESS(rc))
    {
        char *pszEnd = RTStrEnd(pszVersion, cchVersion);
        AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
        while (     pszEnd > pszVersion
               &&   RT_C_IS_SPACE(pszEnd[-1]))
            pszEnd--;
        *pszEnd = '\0';
    }
    else
        RTStrPrintf(pszVersion, cchVersion, "DBGFR3MemRead -> %Rrc", rc);

    return rc;
}
RTDECL(int) RTStrCopyPEx(char **ppszDst, size_t *pcbDst, const char *pszSrc, size_t cchMaxSrc)
{
    const char  *pszSrcEol = RTStrEnd(pszSrc, cchMaxSrc);
    size_t       cchSrc    = pszSrcEol ? (size_t)(pszSrcEol - pszSrc) : cchMaxSrc;
    size_t const cbDst     = *pcbDst;
    char        *pszDst    = *ppszDst;
    if (RT_LIKELY(cchSrc < cbDst))
    {
        memcpy(pszDst, pszSrc, cchSrc);
        *ppszDst = pszDst += cchSrc;
        *pszDst  = '\0';
        *pcbDst -= cchSrc;
        return VINF_SUCCESS;
    }

    if (cbDst != 0)
    {
        memcpy(*ppszDst, pszSrc, cbDst - 1);
        *ppszDst = pszDst += cbDst - 1;
        *pszDst  = '\0';
        *pcbDst  = 1;
    }
    return VERR_BUFFER_OVERFLOW;
}
/**
 * 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;
}
Esempio n. 16
0
RTDECL(size_t) RTStrNLen(const char *pszString, size_t cchMax)
{
    const char *pchEnd = RTStrEnd(pszString, cchMax);
    return pchEnd ? pchEnd - pszString : cchMax;
}
RTDECL(int) RTDirCreateUniqueNumbered(char *pszPath, size_t cbSize, RTFMODE fMode, signed int cchDigits, char chSep)
{
    /*
     * Validate input.
     */
    AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
    AssertReturn(cbSize, VERR_BUFFER_OVERFLOW);
    AssertReturn(cchDigits > 0, VERR_INVALID_PARAMETER);

    /* Check that there is sufficient space. */
    char *pszEnd = RTStrEnd(pszPath, cbSize);
    AssertReturn(pszEnd, VERR_BUFFER_OVERFLOW);
    AssertReturn(cbSize - 1 - (pszEnd - pszPath) >= (size_t)cchDigits + (chSep ? 1 : 0), VERR_BUFFER_OVERFLOW);
    size_t cbLeft = cbSize - (pszEnd - pszPath);

    /* First try is to create the path without any numbers. */
    int rc = RTDirCreate(pszPath, fMode, 0);
    if (   RT_SUCCESS(rc)
        || rc != VERR_ALREADY_EXISTS)
        return rc;

    /* If the separator value isn't zero, add it. */
    if (chSep != '\0')
    {
        cbLeft--;
        *pszEnd++ = chSep;
        *pszEnd   = '\0';
    }

    /* How many tries? Stay within somewhat sane limits. */
    uint32_t cMaxTries;
    if (cchDigits >= 8)
        cMaxTries = 100 * _1M;
    else
    {
        cMaxTries = 10;
        for (int a = 0; a < cchDigits - 1; ++a)
            cMaxTries *= 10;
    }

    /* Try cMaxTries - 1 times to create a directory with appended numbers. */
    uint32_t i = 1;
    while (i < cMaxTries)
    {
        /* Format the number with leading zero's. */
        ssize_t rc2 = RTStrFormatU32(pszEnd, cbLeft, i, 10, cchDigits, 0, RTSTR_F_WIDTH | RTSTR_F_ZEROPAD);
        if (RT_FAILURE((int) rc2))
        {
            *pszPath = '\0';
            return (int)rc2;
        }
        rc = RTDirCreate(pszPath, fMode, 0);
        if (RT_SUCCESS(rc))
            return rc;
        ++i;
    }

    /* We've given up. */
    *pszPath = '\0';
    return VERR_ALREADY_EXISTS;
}
Esempio n. 18
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;
}
int main()
{
    RTTEST hTest;
    int rc = RTTestInitAndCreate("tstRTSystemQueryOsInfo", &hTest);
    if (rc)
        return rc;
    RTTestBanner(hTest);

    /*
     * Simple stuff.
     */
    char szInfo[_4K];

    rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szInfo, sizeof(szInfo));
    RTTestIPrintf(RTTESTLVL_ALWAYS, "PRODUCT: \"%s\", rc=%Rrc\n", szInfo, rc);

    rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szInfo, sizeof(szInfo));
    RTTestIPrintf(RTTESTLVL_ALWAYS, "RELEASE: \"%s\", rc=%Rrc\n", szInfo, rc);

    rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szInfo, sizeof(szInfo));
    RTTestIPrintf(RTTESTLVL_ALWAYS, "VERSION: \"%s\", rc=%Rrc\n", szInfo, rc);

    rc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szInfo, sizeof(szInfo));
    RTTestIPrintf(RTTESTLVL_ALWAYS, "SERVICE_PACK: \"%s\", rc=%Rrc\n", szInfo, rc);

    uint64_t cbTotal;
    rc = RTSystemQueryTotalRam(&cbTotal);
    RTTestIPrintf(RTTESTLVL_ALWAYS, "Total RAM: %'RU64 Bytes (%RU64 KB, %RU64 MB)\n",
                  cbTotal, cbTotal / _1K, cbTotal / _1M);

    uint64_t cbAvailable;
    rc = RTSystemQueryAvailableRam(&cbAvailable);
    RTTestIPrintf(RTTESTLVL_ALWAYS, "Available RAM: %'RU64 Bytes (%RU64 KB, %RU64 MB)\n",
                  cbAvailable, cbAvailable / _1K, cbAvailable / _1M);

    /*
     * Check that unsupported stuff is terminated correctly.
     */
    for (int i = RTSYSOSINFO_INVALID + 1; i < RTSYSOSINFO_END; i++)
    {
        memset(szInfo, ' ', sizeof(szInfo));
        rc = RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, sizeof(szInfo));
        if (    rc == VERR_NOT_SUPPORTED
            &&  szInfo[0] != '\0')
            RTTestIFailed("level=%d; unterminated buffer on VERR_NOT_SUPPORTED\n", i);
        else if (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW)
            RTTESTI_CHECK(RTStrEnd(szInfo, sizeof(szInfo)) != NULL);
        else if (rc != VERR_NOT_SUPPORTED)
            RTTestIFailed("level=%d unexpected rc=%Rrc\n", i, rc);
    }

    /*
     * Check buffer overflow
     */
    RTAssertSetQuiet(true);
    RTAssertSetMayPanic(false);
    for (int i = RTSYSDMISTR_INVALID + 1; i < RTSYSDMISTR_END; i++)
    {
        RTTESTI_CHECK_RC(RTSystemQueryDmiString((RTSYSDMISTR)i, szInfo, 0), VERR_INVALID_PARAMETER);

        /* Get the length of the info and check that we get overflow errors for
           everything less that it.  */
        rc = RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, sizeof(szInfo));
        if (RT_FAILURE(rc))
            continue;
        size_t const cchInfo = strlen(szInfo);

        for (size_t cch = 1; cch < sizeof(szInfo) && cch < cchInfo; cch++)
        {
            memset(szInfo, 0x7f, sizeof(szInfo));
            RTTESTI_CHECK_RC(RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, cch), VERR_BUFFER_OVERFLOW);

            /* check the padding. */
            for (size_t off = cch; off < sizeof(szInfo); off++)
                if (szInfo[off] != 0x7f)
                {
                    RTTestIFailed("level=%d, rc=%Rrc, cch=%zu, off=%zu: Wrote too much!\n", i, rc, cch, off);
                    break;
                }

            /* check for zero terminator. */
            if (!RTStrEnd(szInfo, cch))
                RTTestIFailed("level=%d, rc=%Rrc, cch=%zu: Buffer not terminated!\n", i, rc, cch);
        }

        /* Check that the exact length works. */
        rc = RTSystemQueryOSInfo((RTSYSOSINFO)i, szInfo, cchInfo + 1);
        if (rc != VINF_SUCCESS)
            RTTestIFailed("level=%d: rc=%Rrc when specifying exactly right buffer length (%zu)\n", i, rc, cchInfo + 1);
    }

    return RTTestSummaryAndDestroy(hTest);
}