RTR3DECL(int)  RTFileChangeLock(RTFILE hFile, unsigned fLock, int64_t offLock, uint64_t cbLock)
{
    Assert(offLock >= 0);

    /* Check arguments. */
    if (fLock & ~RTFILE_LOCK_MASK)
    {
        AssertMsgFailed(("Invalid fLock=%08X\n", fLock));
        return VERR_INVALID_PARAMETER;
    }

    /* Remove old lock. */
    int rc = RTFileUnlock(hFile, offLock, cbLock);
    if (RT_FAILURE(rc))
        return rc;

    /* Set new lock. */
    rc = RTFileLock(hFile, fLock, offLock, cbLock);
    if (RT_SUCCESS(rc))
        return rc;

    /* Try to restore old lock. */
    unsigned fLockOld = (fLock & RTFILE_LOCK_WRITE) ? fLock & ~RTFILE_LOCK_WRITE : fLock | RTFILE_LOCK_WRITE;
    rc = RTFileLock(hFile, fLockOld, offLock, cbLock);
    if (RT_SUCCESS(rc))
        return VERR_FILE_LOCK_VIOLATION;
    else
        return VERR_FILE_LOCK_LOST;
}
/**
 * Creates a PID File and returns the open file descriptor.
 *
 * On DOS based system, file sharing (deny write) is used for locking the PID
 * file.
 *
 * On Unix-y systems, an exclusive advisory lock is used for locking the PID
 * file since the file sharing support is usually missing there.
 *
 * This API will overwrite any existing PID Files without a lock on them, on the
 * assumption that they are stale files which an old process did not properly
 * clean up.
 *
 * @returns IPRT status code.
 * @param   pszPath  The path and filename to create the PID File under
 * @param   phFile   Where to store the file descriptor of the open (and locked
 *                   on Unix-y systems) PID File. On failure, or if another
 *                   process owns the PID File, this will be set to NIL_RTFILE.
 */
VBGLR3DECL(int) VbglR3PidFile(const char *pszPath, PRTFILE phFile)
{
    AssertPtrReturn(pszPath, VERR_INVALID_PARAMETER);
    AssertPtrReturn(phFile, VERR_INVALID_PARAMETER);
    *phFile = NIL_RTFILE;

    RTFILE hPidFile;
    int rc = RTFileOpen(&hPidFile, pszPath,
                        RTFILE_O_READWRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_DENY_WRITE
                        | (0644 << RTFILE_O_CREATE_MODE_SHIFT));
    if (RT_SUCCESS(rc))
    {
#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
        /** @todo using size 0 for locking means lock all on Posix.
         * We should adopt this as our convention too, or something
         * similar. */
        rc = RTFileLock(hPidFile, RTFILE_LOCK_WRITE, 0, 0);
        if (RT_FAILURE(rc))
            RTFileClose(hPidFile);
        else
#endif
        {
            char szBuf[256];
            size_t cbPid = RTStrPrintf(szBuf, sizeof(szBuf), "%d\n",
                                       RTProcSelf());
            RTFileWrite(hPidFile, szBuf, cbPid, NULL);
            *phFile = hPidFile;
        }
    }
    return rc;
}
Esempio n. 3
0
int main()
{
    RTR3InitExeNoArguments(0);
    RTPrintf("tstFileLock: TESTING\n");

    RTFILE File;
    int rc = RTFileOpen(&File, "tstLock.tst", RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
    RTPrintf("File open: rc=%Rrc\n", rc);
    if (RT_FAILURE(rc))
    {
        if (rc != VERR_FILE_NOT_FOUND && rc != VERR_OPEN_FAILED)
        {
            RTPrintf("FATAL\n");
            return 1;
        }

        rc = RTFileOpen(&File, "tstLock.tst", RTFILE_O_READWRITE | RTFILE_O_CREATE | RTFILE_O_DENY_NONE);
        RTPrintf("File create: rc=%Rrc\n", rc);
        if (RT_FAILURE(rc))
        {
            RTPrintf("FATAL\n");
            return 2;
        }
        fRun = true;
    }

    /* grow file a little */
    rc = RTFileSetSize(File, fRun ? 2048 : 20480);
    RTPrintf("File size: rc=%Rrc\n", rc);

    int buf;
    /* read test. */
    rc = RTFileRead(File, &buf, sizeof(buf), NULL);
    RTPrintf("Read: rc=%Rrc\n", rc);

    /* write test. */
    rc = RTFileWrite(File, achTest1, strlen(achTest1), NULL);
    RTPrintf("Write: rc=%Rrc\n", rc);

    /* lock: read, non-blocking. */
    rc = RTFileLock(File, RTFILE_LOCK_READ | RTFILE_LOCK_IMMEDIATELY, 0, _4G);
    RTPrintf("Lock: read, non-blocking, rc=%Rrc\n", rc);
    bool fl = RT_SUCCESS(rc);

    /* read test. */
    rc = RTFileRead(File, &buf, sizeof(buf), NULL);
    RTPrintf("Read: rc=%Rrc\n", rc);

    /* write test. */
    rc = RTFileWrite(File, achTest2, strlen(achTest2), NULL);
    RTPrintf("Write: rc=%Rrc\n", rc);
    RTPrintf("Lock test will change in three seconds\n");
    for (int i = 0; i < 3; i++)
    {
        RTThreadSleep(1000);
        RTPrintf(".");
    }
    RTPrintf("\n");

    /* change lock: write, non-blocking. */
    rc = RTFileLock(File, RTFILE_LOCK_WRITE | RTFILE_LOCK_IMMEDIATELY, 0, _4G);
    RTPrintf("Change lock: write, non-blocking, rc=%Rrc\n", rc);
    RTPrintf("Test will unlock in three seconds\n");
    for (int i = 0; i < 3; i++)
    {
        RTThreadSleep(1000);
        RTPrintf(".");
    }
    RTPrintf("\n");

    /* remove lock. */
    if (fl)
    {
        fl = false;
        rc = RTFileUnlock(File, 0, _4G);
        RTPrintf("Unlock: rc=%Rrc\n", rc);
        RTPrintf("Write test will lock in three seconds\n");
        for (int i = 0; i < 3; i++)
        {
            RTThreadSleep(1000);
            RTPrintf(".");
        }
        RTPrintf("\n");
    }

    /* lock: write, non-blocking. */
    rc = RTFileLock(File, RTFILE_LOCK_WRITE | RTFILE_LOCK_IMMEDIATELY, 0, _4G);
    RTPrintf("Lock: write, non-blocking, rc=%Rrc\n", rc);
    fl = RT_SUCCESS(rc);

    /* grow file test */
    rc = RTFileSetSize(File, fRun ? 2048 : 20480);
    RTPrintf("File size: rc=%Rrc\n", rc);

    /* read test. */
    rc = RTFileRead(File, &buf, sizeof(buf), NULL);
    RTPrintf("Read: rc=%Rrc\n", rc);

    /* write test. */
    rc = RTFileWrite(File, achTest3, strlen(achTest3), NULL);
    RTPrintf("Write: rc=%Rrc\n", rc);
    RTPrintf("Continuing to next test in three seconds\n");
    for (int i = 0; i < 3; i++)
    {
        RTThreadSleep(1000);
        RTPrintf(".");
    }
    RTPrintf("\n");

    RTFileClose(File);
    RTFileDelete("tstLock.tst");


    RTPrintf("tstFileLock: I've no recollection of this testcase succeeding or not, sorry.\n");
    return 0;
}