开发者

How do I lock files using fopen()?

开发者 https://www.devze.com 2023-04-09 07:36 出处:网络
I wonder if there is any way to lock and unlock a file in Linux when I open a file using fopen (not open)?

I wonder if there is any way to lock and unlock a file in Linux when I open a file using fopen (not open)?

Based on Stack Overflow开发者_JS百科 question C fopen vs open, fopen is preferred over open.

How can I implement my own file lock (if possible) by creating and deleting lock files?


I would strongly disagree with the claim that fopen is prefered over open. It's impossible to use fopen safely when writing a file in a directory that's writable by other users due to symlink vulnerabilities/race conditions, since there is no O_EXCL option. If you need to use stdio on POSIX systems, it's best to use open and fdopen rather than calling fopen directly.

Now, as for locking it depends on what you want to do. POSIX does not have mandatory locking like Windows, but if you just want to ensure you're working with a new file and not clobbering an existing file or following a symlink, use the O_EXCL and O_NOFOLLOW options, as appropriate. If you want to do cooperative locking beyond the initial open, use fcntl locks.


In Linux, if you need a file descriptor (e.g., to pass to a file-locking primitive), you can use fileno(FILE*) to retrieve it. After retrieving the file descriptor, you can use it as if it had been returned by open.

For example, instead of

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

you could equally well do this:

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

Note that fileno is defined in the POSIX standard, but not in C or C++ standards.

As for your second question, the Linux open() man page has this to say:

The solution for performing atomic file locking using a lockfile is to create a unique file on the same file system (e.g., incorporating hostname and pid), use link(2) to make a link to the lockfile. If link() returns 0, the lock is successful. Otherwise, use stat(2) on the unique file to check if its link count has increased to 2, in which case the lock is also successful.


Files can be locked by using flock(). Its syntax 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);

First file is opened using fopen() or open(). Then this opened file is locked using flock() as given below

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


Note that in below code fopen will fail (and return NULL) if the lock file /var/lock/my.lock doesn't exist.

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

Use fopen with w+ if you need the lockfile to be created if it doesn't exist.

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


If you wish to implement your own lock simply, I suggest Rob's answer of using flock. If you wish to implement it in a complex manner, such as for high availability, you can try something like using a thread to touch a file at a regular interval. All other programs wanting to lock the file should also check the file to see if its update time has been updated in at another fixed, but larger interval (the larger part is important). This is probably overkill for most applications, but it handles things such as crashes, freezes, etc. much better than flock.


There is another way with open() function, but I'm not sure about this called locked file. I am using file permissions to open a file.

The code is here:

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

I used a flag for permissions (third argument). This flag gives read, write and execute permissions to the user.

$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

A little tip: If you are using Ubuntu or Debian, you can see the description of functions with man [function_name] man pages of open() function.


The below code is not letting me lock the file using lockf, flock works fine though

    #include <iostream>
    #include <unistd.h>
    #include<thread>
    #include <vector>
    #include <sys/file.h>
    #include <fcntl.h>
    #include <string.h>

using namespace std;

void append()
{
    FILE *fp=fopen("a.txt","a");
    if(fp)
    {
        cout<<lockf(fileno(fp),F_LOCK,0)<<endl;

        //flock(fileno(fp), LOCK_EX);

        fprintf(fp,"abcdefghijklmnopqrstuvwxyz\n");fflush(fp);
        sleep(1);
        fprintf(fp,"^$^&%&*&^&*(*)_*)_()_*&***&(\n");fflush(fp);

        fclose(fp);
    }
    else {
        printf("null\n");
    }
}


int main()
{
    fclose(fopen("a.txt","w"));
    //return 0;
    vector<thread*> v;
    //#pragma omp parallel for
    for(int i=0;i<1000;++i)
    {
        v.push_back(new thread(append));

        //append();
    }

    for(auto y:v)
    {
        y->join();
        delete y;
    }

    return 0;
}
0

精彩评论

暂无评论...
验证码 换一张
取 消