C++ Code Snippet – File Locking

I program applications that run on IBM AIX servers at work. Multiple people will be running different instances of my programs, and if any of my programs are writing to a file at any time, it could become problematic. For example:

  1. Person 1 runs MyProg, which opens MyFile.txt, which contains the text “Hello, World.”
  2. Person 2 runs MyProg, and also opens MyFile.txt, which contains the text “Hello, World.”
  3. Person 1 now makes edits to MyFile.txt and saves it, so now it reads “Hello, World. Beautiful day today!” He exits the program.
  4. Person 2 then makes his edits to MyFile.txt, which reads “Hello, World. Person 1 is a jerk!” and saves.
  5. Person 1 gets fired.

Because there’s no locking, data can get overwritten without anyone noticing.

 

6. Person 1 goes outside and finds (what's left of) his bike

Get The Lock.

File locking is different across platforms, even on different flavors of Unix. On page 57 in the Secure Programming Cookbook for C and C++ By John Viega and Matt Messier, the author(s) mention how different file locking is across different Unix platforms. For me, I know my first method works on IBM AIX servers, so that’s what I’m putting up. I’ll also show the Windows method of locking as well.

The lock we’re setting here is an exclusive lock, meaning only this instance of this application will be able to write to it. However, another instance of the program may be able to read it as long as it doesn’t try to set the lock or write to the file. This is handy for implementing a “Read Only” mode.

File Locking in AIX

File locking in AIX is a bit odd. IBM has made C functions for opening and closing files that differ from the regular fopen() and fclose(). These functions are simply open() and close(), and as opposed to returning a FILE*, they return a File Descriptor in the form of an int. Details of these functions can be found here.

Hey! What if I opened the file already using fopen()!? That’s fine, because you can easily just use fileno() to get the file descriptor of a FILE*. Handy.

The function I’m using to lock the file is fcntl(). There is another function called lockf(), which pretty much does the same thing, but if you only want to lock a few bytes in the file, you need to seek to the correct offset before you call lockf(). If you want to try, be my guest. Me? I prefer the gritty way. fcntl() provides more control over the file than lockf().

Also, since we’re using fcntl(), we’ll have to use the flock structure (that’s “eff Lock”). simply put, this structure will contain the “parameters” of the lock we want to set – what size, what process ID, what kind of lock, etc.

So, without further TODO, the C++ snippet (with step-by-step comments)

#include
#include 

int FileLock(int nFileDesc, bool bLock)
{
    // Define the file lock structure.
    struct flock fl;
    memset(&fl, 0, sizeof(fl));

    // Set the mode depending on the bool passed in.
    int mode = 0;
    if(bLock == true)
    {
        // This is our exclusive lock mode (Read/Write).
        // A shared lock (Read only) is defined by F_RDLCK
        mode = F_WRLCK;
    }
    else
    {
        // Simply for unlocking.
        mode = F_UNLCK;
    }

    // Now we set the fields in our lock structure.
    // There are additional fields, but they aren't too important right now.
    // Set the type of lock
    fl.l_type   = mode;
    // The starting offset. This one starts at the beginning of the file.
    // Others are SEEK_CUR and SEEK_END
    fl.l_whence = SEEK_SET;
    // The relative offset from l_whence
    fl.l_start  = 0;
    // The length to read up to. Specifying 0 means to EOF
    fl.l_len    = 0;
    // The application's process ID. It's nice to set it explicitly.
    fl.l_pid    = getpid();

    // If we're locking the file, the first thing
    // we want to do is test if it's already locked!
    if(mode != F_UNLCK)
    {
        // Test the lock. What F_GETLK will do is change the l_type field
        // in our flock structure.
        if(fcntl(nFileDesc, F_GETLK, &fl) < 0)
        {
            // We'll only come in here if fcntl had a fatal error. This is a bad sign.
            return -2;
        }

        // If l_type is not set to F_UNLCK from our fcntl call, the file is locked.
        if(fl.l_type != F_UNLCK)
        {
            return -1; // File is locked
        }

        fl.l_type = mode;   // Set it back to what we want to do.
    }    // Now we actually lock/unlock the file with F_SETLK
    if(fcntl(nFileDesc, F_SETLK, &fl) == 0)
    {
        return 0;    // Success!
    }
    else
    {
        return -2; // fcntl error. Again, not good.
    }
}

Windows File Locking

Now, I haven’t done any file locking for Windows (only stuff I did in Windows is mainly game development, and if you have multiple instances of a game playing, you either pwn or your computer is going to catch fire). However, if you read the excerpt from the book I posted, you’ll have read that windows has simple functions LockFile() and LockFileEx(), both using HANDLEs as opposed to FILE*. Not too different, but a lot less code. For anyone looking to do this, you can find a list of file management functions here.

So that’s pretty much it for file locking here. Till next time!

Advertisements

Published by

KeithM

Computer Scientist for Engility, and Indie Game Dev from New Jersey. Loves playing games, and loves making them, too.

One thought on “C++ Code Snippet – File Locking”

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s