Placing exclusive lock on read-only files in Linux

Viewed 190

Assume that:

  • 1) I have a folder on Linux that I only have "read" and "execute" permissions.
  • 2) Somebody with higher privilege (with a "write" permission) will put some files into that folder.
  • 3) Multiple processes of a program running in parallel will read and perform some data processing on the files.

Requirement: A file is read by only one process. When done, the file is either removed or moved to a different place. All the files will not be written/edited. For example, I have 5 files and 2 processes running in parallel. I need to ensure that process 1 will read and perform some works on files 1, 3, and 5. Process 2 will read and perform some works on files 2 and 4. It means computational distributions are done at the file-level. We are not going to distribute computations inside files.

On Linux, there are two functions that can place an exclusive lock: flock and fcntl. They work interchangeably and respect the locks placed by the others. The problem is both the functions require the "write" permission.

Boost library also has the boost::interprocess::file_lock::try_lock() function. It does the same job as the above two functions. It also requires the "write" permission.

Are there any other methods that I can place an exclusive lock on files that I don't have "write" permission?

1 Answers

Any access (read or write) will suffice for a Linux flock syscall to place a lock on file, unlike fcntl lock which requires read access for a read lock and write for a write lock.

You might be using libc that emulates flock on top of fcntl. To get what you need, invoke system call directly through syscall:

#include <sys/syscall.h>
#include <unistd.h>

// from include/uapi/asm-generic/fcntl.h
#define SYS_LOCK_SH 1
#define SYS_LOCK_EX 2
#define SYS_LOCK_UN 8

static int sys_flock(int fd, int op)
{
    return (int) syscall(SYS_flock, fd, op);
}

As the result, the following program must succeed:

#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <unistd.h>

#define SYS_LOCK_EX 2

static long sys_flock(int fd, int flags)
{
    return (int) syscall(SYS_flock, fd, flags);
}

int main(void)
{
    int fd = open("/etc/hosts", O_RDONLY);
    int ret = sys_flock(fd, SYS_LOCK_EX);

    if (ret) {
        errno = -ret;
        perror("flock");
        return 1;
    }
}
Related