Vraag Hoe kan ik bestanden vergrendelen met fopen ()?


Ik vraag me af of er een manier is om een ​​bestand in Linux te vergrendelen en ontgrendelen wanneer ik een bestand gebruik met fopen (niet open)?

Gebaseerd op Stack Overflow-vraag C fopen versus open, fopen heeft de voorkeur boven open.

Hoe kan ik mijn eigen bestandsvergrendeling (indien mogelijk) implementeren door slotbestanden te maken en te verwijderen?


15
2017-09-27 17:31


oorsprong


antwoorden:


Ik ben het absoluut oneens met de bewering dat fopen heeft de voorkeur open. Het is onmogelijk om te gebruiken fopen veilig bij het schrijven van een bestand in een map die beschrijfbaar is voor andere gebruikers vanwege symlinkkwetsbaarheden / raceomstandigheden, aangezien er geen is O_EXCL keuze. Als u stdio op POSIX-systemen wilt gebruiken, is het het beste om te gebruiken open en fdopen in plaats van bellen fopen direct.

Nu hangt het vergrendelen af ​​van wat u wilt doen. POSIX heeft geen verplichte vergrendeling zoals Windows, maar als u er zeker van wilt zijn dat u met een nieuw bestand werkt en geen bestaand bestand of een symlink bedekt, gebruik dan de O_EXCL en O_NOFOLLOW opties, indien van toepassing. Als u coöperatieve vergrendeling wilt doen na de eerste keer openen, gebruikt u fcntl sluizen.


16
2017-09-27 23:30



Als u in Linux een bestandsdescriptor nodig hebt (bijvoorbeeld om door te geven aan een primitieve bestandsverzameling), kunt u deze gebruiken fileno(FILE*) om het op te halen. Na het ophalen van de bestandsdescriptor, kunt u deze gebruiken alsof deze is geretourneerd door open.

Bijvoorbeeld in plaats van

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

je zou net zo goed dit kunnen doen:

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

Let daar op fileno is gedefinieerd in de POSIX-standaard, maar niet in C- of C ++ -standaarden.

Wat betreft je tweede vraag, de Linux open() man pagina heeft dit te zeggen:

De oplossing voor het uitvoeren van atomic file locking met een lockfile is om   maak een uniek bestand op hetzelfde bestandssysteem (bijvoorbeeld opnemen   hostnaam en pid), gebruik verbinding (2) om een ​​link naar het vergrendelingsbestand te maken. Als   link () levert 0 op, het slot is succesvol. Anders gebruiken stat (2) op   het unieke bestand om te controleren of het aantal links is toegenomen tot 2, in   in welk geval het slot ook succesvol is.


13
2017-09-27 17:37



Bestanden kunnen worden vergrendeld door te gebruiken flock(). De syntaxis is

 #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);

Het eerste bestand wordt geopend met fopen() of open(). Vervolgens wordt dit geopende bestand vergrendeld met flock() zoals hieronder gegeven

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 . . .

5
2017-11-26 13:05



Als je eenvoudig je eigen slot wilt implementeren, dan raad ik Rob aan om het antwoord op het gebruik van koppel te gebruiken. Als u het op een complexe manier wilt implementeren, bijvoorbeeld voor hoge beschikbaarheid, kunt u proberen een thread te gebruiken om een ​​bestand regelmatig aan te raken. Alle andere programma's die het bestand willen vergrendelen, moeten ook het bestand controleren om te zien of de update-tijd is bijgewerkt in een ander vast maar groter interval (het grootste gedeelte is belangrijk). Dit is waarschijnlijk overkill voor de meeste toepassingen, maar het behandelt zaken als crashes, vastlopen, etc. veel beter dan kudde.


1
2017-09-27 17:56



Merk op dat in onderstaande code fopen zal mislukken (en NULL retourneren) als het vergrendelingsbestand /var/lock/my.lock bestaat niet

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

Gebruik fopen met w+ als u het vergrendelingsbestand moet maken als het niet bestaat.

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

1
2017-12-28 16:15



Er is een andere manier mee Open() functie, maar ik weet het niet zeker of dit het vergrendelde bestand is. Ik gebruik bestandsrechten om een ​​bestand te openen.

De code is hier:

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

Ik heb een vlag gebruikt voor permissies (derde argument). Deze vlag geeft de gebruiker lees-, schrijf- en uitvoerrechten.

$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

Een kleine tip: als u Ubuntu of Debian gebruikt, kunt u de functiebeschrijving zien man [function_name]  man pages van de functie open ().


0
2017-12-28 18:06