Установка монопольной блокировки на файлы, доступные только для чтения, в Linux - PullRequest
3 голосов
/ 18 июня 2020

Предположим, что:

  • 1) У меня есть папка на Linux, в которой у меня есть только права на чтение и выполнение.
  • 2) Кто-то с более высокими привилегиями (с разрешением на «запись») поместит некоторые файлы в эту папку.
  • 3) Несколько процессов программы, выполняющейся параллельно, будут читать и выполнять некоторую обработку данных в файлах.

Требование: Файл читается только одним процессом. По завершении файл либо удаляется, либо перемещается в другое место. Все файлы не будут записываться / редактироваться. Например, у меня параллельно работают 5 файлов и 2 процесса. Мне нужно убедиться, что процесс 1 будет читать и выполнять некоторые работы с файлами 1, 3 и 5. Процесс 2 будет читать и выполнять некоторые работы с файлами 2 и 4. Это означает, что вычислительные распределения выполняются на уровне файлов. Мы не собираемся распределять вычисления внутри файлов.

На Linux есть две функции, которые могут устанавливать эксклюзивную блокировку: flock и fcntl . Они работают взаимозаменяемо и уважают замки, установленные другими. Проблема в том, что обе функции требуют разрешения на «запись».

Библиотека Boost также имеет функцию boost::interprocess::file_lock::try_lock(). Он выполняет ту же работу, что и две вышеупомянутые функции. Для этого также требуется разрешение на «запись».

Существуют ли какие-либо другие методы, с помощью которых я могу установить исключительную блокировку для файлов, у которых нет разрешения на «запись»?

1 Ответ

1 голос
/ 18 июня 2020

Любого доступа (чтение или запись) будет достаточно для системного вызова Linux flock, чтобы установить блокировку файла, в отличие от fcntl блокировки, для которой требуется доступ на чтение для блокировка чтения и запись для блокировки записи.

Возможно, вы используете lib c, которая имитирует flock поверх fcntl. Чтобы получить то, что вам нужно, вызовите системный вызов напрямую через 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);
}

В результате должна завершиться следующая программа:

#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;
    }
}
...