PDA

View Full Version : File locking with fcntl() fails on shared volumes!?




idelovski
Nov 10, 2008, 02:09 PM
I'm using fcntl() to perform locking of regions on files. It works well on local volume, but fails on shared volumes.

This line produces error 45, ENOTSUP on shared volumes:
fcntl(fp, F_SETLKW, &lk)

Here is an example I wrote to test it. If I give it ~ as a param all works well. If I use some folder on shared volume (on either Mac or Windows) it fails:
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>

int main (int argc, const char * argv[])
{
int fp, bytesGone, len;
char tmpStr[256], buff[256];
struct flock lk;

if (argc != 2)
exit (1);

if (argv[1][strlen(argv[1])-1] == '/')
sprintf (tmpStr, "%s%s", argv[1], "MyFile");
else
sprintf (tmpStr, "%s/%s", argv[1], "MyFile");

if ((fp = open (tmpStr, O_RDWR)) < 0) {
if ((fp = open (tmpStr, O_RDWR | O_CREAT, 0666)) < 0) {
printf ("Open file error!\n");
exit (1);
}
}

lseek (fp, 0L, SEEK_SET);
if (write(fp, tmpStr, len = strlen(tmpStr)+1) != len)
exit (1);

lseek (fp, 0L, SEEK_SET);
if (read (fp, tmpStr, len) != len)
exit (1);

lseek (fp, 0L, SEEK_SET);

lk.l_start = 0;
lk.l_len = 8;
lk.l_pid = 0; // getpid ();
lk.l_type = F_WRLCK;
lk.l_whence = SEEK_CUR;
if (fcntl(fp, F_SETLKW, &lk)) { // or F_SETLK, both give ENOTSUP
printf ("Lock error: %d\n", errno);
exit (1);
}

printf ("All is well! Len = %d\n", len);
return (0);
}


There's even some Tech note by Apple (http://developer.apple.com/technotes/tn/tn2037.html) that shows how to use Gestalt() to test if a volume supports file locking and all the volumes I checked passed that test.

Any idea how to solve this or find a workaround.



gnasher729
Nov 10, 2008, 04:21 PM
I haven't looked very far, but the fcntl man pages recommend that you use flock instead, with comments like "this interface follows the completely stupid semantics of System V and POSIX.1"

idelovski
Nov 10, 2008, 04:41 PM
Thanks for the reply. I've seen the S Word in man and that made me stop crying and start laughing (at least for a moment).

Anyway, "flock applies or removes an advisory lock on the file associated with the file descriptor fd".

It doesn't help with ranges locking within the file.

ChrisA
Nov 10, 2008, 04:47 PM
I'm using fcntl() to perform locking of regions on files. It works well on local volume, but fails on shared volumes.

This line produces error 45, ENOTSUP on shared volumes:

At least you are getting the correct error returned.

Locking a network share is a hard problem. Not all fie servers support locks. To be completely general you need to Handel locking yourself.

A lot of people just give up and decide to keep the central data in an SQL Database rather then a file. This solves the problem completely

Ti_Poussin
Nov 10, 2008, 07:46 PM
You want to make a daemon server on the remote machine if that's possible, the daemon may act as a proxy for you're file and only passing by him you can see the file. The daemon lock by himself the file. If that's not an option, I second the Database idea.

Else, you may change the permission temporary on the file to lock it completely, work on a duplicate, overwrite and give permission back. This won't assure 100% the work, but if you're not having a lot of request to the same file at high speed, it shouldn't be a problem.

flock can lock a part of a file, but it's base on the good will of other software, it mean that if other don't check for flock nothing prevent them to use the same file at the same time. To use flock, every apps that use the file must check for it, I used it for a software and it work well for what it is.