Как заблокировать файлы с помощью функции fopen()?

Интересно, есть ли способ заблокировать и разблокировать файл в Linux, когда я открываю файл с помощью fopen (not open)?

В зависимости от вопроса о переполнении стека C fopen vs open, fopen предпочтительнее open.

Как я могу реализовать свою собственную блокировку файла (если это возможно) путем создания и удаления файлов блокировки?

Ответы

Ответ 1

Я бы категорически не согласен с утверждением, что fopen предпочтительнее open. Невозможно использовать fopen безопасно при записи файла в каталог, доступный для записи другими пользователями из-за уязвимостей/условий гонки символов, поскольку нет опции O_EXCL. Если вам нужно использовать stdio в системах POSIX, лучше использовать open и fdopen, а не напрямую обращаться к fopen.

Теперь, что касается блокировки, это зависит от того, что вы хотите сделать. POSIX не имеет обязательной блокировки, такой как Windows, но если вы просто хотите убедиться, что работаете с новым файлом, а не сбиваете существующий файл или следуете символической ссылке, используйте опции O_EXCL и O_NOFOLLOW, если это необходимо. Если вы хотите сделать совместное блокирование за пределами начального открытого, используйте блокировки fcntl.

Ответ 2

В Linux, если вам нужен файловый дескриптор (например, для перехода к примитиву блокировки файлов), вы можете использовать fileno(FILE*) для его получения. После извлечения дескриптора файла вы можете использовать его, как если бы он был возвращен open.

Например, вместо

int fd = open("myfile.txt", flags);
int result = flock(fd, LOCK_SH);

вы могли бы так же хорошо:

FILE* f = fopen("myfile.txt", "r");
int result = flock(fileno(f)), LOCK_SH);

Обратите внимание, что fileno определяется в стандарте POSIX, но не в стандартах C или С++.

Что касается вашего второго вопроса, на странице руководства Linux open() есть следующее:

Решение для выполнения блокировки атомарного файла с использованием файла блокировки создать уникальный файл в той же файловой системе (например, включить hostname и pid), используйте ссылку (2), чтобы сделать ссылку на файл блокировки. Если link() возвращает 0, блокировка выполнена успешно. В противном случае используйте stat (2) в уникальный файл, чтобы проверить, увеличилось ли его количество ссылок до 2, в в этом случае блокировка также успешна.

Ответ 3

Файлы можно заблокировать с помощью flock(). Его синтаксис

 #include <sys/file.h>
 #define   LOCK_SH   1    /* shared lock */
 #define   LOCK_EX   2    /* exclusive lock */
 #define   LOCK_NB   4    /* don't block when locking */
 #define   LOCK_UN   8    /* unlock */

int flock(int fd, int operation);

Первый файл открывается с помощью fopen() или open(). Затем этот открытый файл блокируется с помощью flock(), как указано ниже

int fd = open("test.txt","r");
int lock = flock(fd, LOCK_SH);  // Lock the file . . .
// . . . .
// Locked file in use 
// . . . .
int release = flock(fd, LOCK_UN);  // Unlock the file . . .

Ответ 4

Если вы хотите просто реализовать свой собственный замок, я предлагаю Робу ответить на использование стаи. Если вы хотите реализовать его сложным образом, например, для обеспечения высокой доступности, вы можете попробовать что-то вроде использования потока, чтобы прикоснуться к файлу с регулярным интервалом. Все остальные программы, которые хотят заблокировать файл, также должны проверить файл, чтобы узнать, обновлено ли его время обновления на другом фиксированном, но большем интервале (важна большая часть). Вероятно, это избыток для большинства приложений, но он обрабатывает такие вещи, как сбои, зависания и т.д. Намного лучше, чем стая.

Ответ 5

Обратите внимание, что в приведенном ниже коде fopen произойдет сбой (и возврат NULL), если файл блокировки /var/lock/my.lock не существует.

FILE* f = fopen("/var/lock/my.lock", "r");
int result = flock(fileno(f)), LOCK_SH);

Используйте fopen с w+, если вам нужно создать файл блокировки, если он не существует.

FILE* f = fopen("/var/lock/my.lock", "w+");
int result = flock(fileno(f)), LOCK_SH);

Ответ 6

Существует еще один способ с функцией open(), но я не уверен, что это называется заблокированным файлом. Я использую права доступа к файлам для открытия файла.

Код находится здесь:

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>

#define FILE_NAME "hello.txt"

int main()
{
    int fd;

    fd = open(FILE_NAME, O_CREAT, S_IRWXU);

    // Error checking
    if(fd == -1){
        perror("[error]\n");
    }
    else{
        printf("[file is opened]\n");
    }

    return 0;
}

Я использовал флаг для разрешений (третий аргумент). Этот флаг предоставляет пользователю права на чтение, запись и выполнение.

$ls -alh

total 24K
drwxrwxr-x  2 arien arien 4.0K Dec 28 20:56 .
drwxrwxr-x 18 arien arien 4.0K Dec 27 22:20 ..
-rwxrwxr-x  1 arien arien 8.5K Dec 28 20:56 fopen
-rw-rw-r--  1 arien arien  290 Dec 28 20:56 fopen.c
-rwx------  1 arien arien    0 Dec 28 20:55 hello.txt

Маленький совет: если вы используете Ubuntu или Debian, вы можете увидеть описание функций с помощью man [function_name] справочных страниц функции open().