Atomic lock file creation

Hello,
I need to implement a locking system in C. My problem is how to make the check if the lock file exist and locking it atomic operation.
I want to make something like this:

FILE* lock_fname;
lock_fname = fopen ( "file.lock", "r");
/*check if file exsists*/
if (lock_fname)
{
  fclose (lock_fname);
  lock_fname = fopen ( "file.lock", "w");
  /* file is now locked */
}
else
{
  /* looks like file is locked */
}

But this is not very good solution. How can make the check and the creation of lock file atomic operation?
Also there is a good chance that my code may have to run on Windows so I have to stick to standard C functions.
Have you got any suggestions?
Thank you!

EDIT:
This is a good solution, but it won't compile on windows I think:

#include <fcntl.h> // for open()
#include <cerrno> // for errno 
#include <cstdio> // for perror()
int fd;
fd=open("password.lck", O_WRONLY | O_CREAT | O_EXCL)

sig_atomic_t is a datatype which guarantees atomic operations when basic arithmetic operations, like + -, are involved. This is because the operation takes only one uninterruptible cpu instruction.

That's pretty much all there is for atomic operations defined by the C standard.

fopen fclose, etc, are all part of the C library and are hundreds of cpu instructions long, as well as requiring disk i/o. None of these functions could ever be atomic. They are never guaranteed to be atomic. In UNIX, none of the file I/O system calls like read, write are atomic either. The C library sits on top of these system calls.

How about opening a TCP socket at a specific port on 127.0.0.1? UNIX won't let more than one program bind the same port, and though Windows sometimes will, I think it can be configured not to.

There are lots of file operation system calls with absolute guarantees of atomicity. The link system call is the one most often used in locking techniques. First create a temporary file in a well known directory. Then attempt to link() it to a well known name. If two processes try this at the same time, one will succeed and the other fail. If the link works, you own the lock.

For file updates, you can link the file to a lock file. Programs that update /etc/passwd and /etc/shadow often use this technique. They try to link /etc/passwd to /etc/opasswd and /etc/shadow to /etc/oshadow. Using truss and strace, I see that redhat linux and Solaris 8 are still doing that. This was the original way to lock files between cooperating processes.

Hi,

Maybe this is that you want. I will try to do an example.
By the time, try reading this http://www.gnu.org/software/libtool/manual/libc/File-Locks.html

I think this could work. I extracted the comment from open function man page.

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

int main(void)
{
        int fd;

 /*           O_EXCL:

              If O_CREAT and O_EXCL are set, open() shall fail  if  the  file
              exists.  The  check  for the existence of the file and the cre-
              ation of the file if it does not exist  shall  be  atomic  with
              respect to other threads executing open() naming the same file-
              name in the same directory with  O_EXCL  and  O_CREAT  set.  If
              O_EXCL  and  O_CREAT  are  set, and path names a symbolic link,
              open() shall fail and set errno to [EEXIST], regardless of  the
              contents  of the symbolic link. If O_EXCL is set and O_CREAT is
              not set, the result is undefined.
*/


        if ( (fd = open("./test.txt", O_RDWR|O_CREAT|O_EXCL)) < 0 )
        {
                perror("open");
        }
        else
        {
                /*here you can use fcntl in order to lock the file*/
        }

        return 0;
}

lagigliaivan, this works, but it won't compile on windows I think. Actually I've solved my problem with windows specific functions :frowning:
Many thanks to everyone about the replies!

I know that you have figured out your problem, but just for fun, you could take a look to this POSIX and OS/2 are not supported in Windows XP or in Windows Server 2003.

I'm not sure, but if the code is POSIX compliant , it should work.

ivan.