I have some code which sets and clears lock files that works fine on linux but the Windows equivalent does not seem to handle empty files properly. Is there some way to lock an empty file on Windows? Any suggestions will be greatly appreciated.

Details...

This is what I have now (partially, it is part of something much larger):

#ifdef USE_WINDOWS
typedef HANDLE LOCK_HANDLE;
#else
typedef int LOCK_HANDLE;
#endif

LOCK_HANDLE lock_set(const char *lfname){
   fprintf(stderr,"binorder: status: waiting for lock on %s\n",lfname);
   LOCK_HANDLE lh;
#ifdef USE_WINDOWS
lh = CreateFile(_MT(lfname), GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
   if(lh == INVALID_HANDLE_VALUE){
// try just read, if it already exists then hopefully it has at least one byte in it lh = CreateFile(_MT(lfname), GENERIC_READ, 0, NULL, CREATE_ALWAYS, 0, NULL);
      if(lh == INVALID_HANDLE_VALUE){
insane("binorder: fatal error: could not open or create a lock file\n");
          }
   }
   else {
      // write 1 byte of data to it
      char buf=0x12;  // value does not matter, but set it to something
      DWORD dwNumBytesWritten;
      if(!WriteFile(lh, &buf, 1, &dwNumBytesWritten, NULL)){
insane("binorder: fatal error: could not write one byte to lock file\n");
      }
   }
   if(!LockFile(lh, 0, 0, 1, 0)){ // lock the first byte
      insane("binorder: fatal error: could not lock an open file\n");
   }
#else
   lh = open(lfname, O_RDWR|O_CREAT,S_IRWXU);
if(lh==-1){ /* maybe it already exists and we cannot write it, try RD */
      lh = open(lfname, O_RDONLY);
if(lh==-1)insane("binorder: fatal error: could not open a lock file\n");
   }
/* get an exclusive lock, wait until that happens, potentially forever */
   int result = flock(lh, LOCK_EX);
if(result)insane("binorder: fatal error: could not place a lock on a lock file\n");
   fprintf(stderr,"binorder: status: locked %s with lh %d\n",lfname,lh);
#endif
   return(lh);
}

/* release a lock. If the program exits locks are automatically released, so
there is no need to call this on exits caused by errors. */
void lock_clr(LOCK_HANDLE lh){
#ifdef USE_WINDOWS
LPBY_HANDLE_FILE_INFORMATION lhfi = malloc(sizeof(BY_HANDLE_FILE_INFORMATION)); if(!GetFileInformationByHandle(lh,lhfi))return; // not fatal, but no lock to clear
   fprintf(stderr,"binorder: status: releasing lock on lh %p\n",lh);
   if(!UnlockFile(lh, 0, 0, 1, 0)){
insane("binorder: fatal error: could not release a lock on a lock file\n");
   }
   if(!CloseHandle(lh)){
insane("binorder: fatal error: could close handle on unlocked file\n");
   }
#else
   if(!lh)return;
   fprintf(stderr,"binorder: status: releasing lock on lh %d\n",lh);
   int result = flock(lh, LOCK_UN);
if(result)insane("binorder: fatal error: could not release a lock on a lock file\n");
   (void) close(lh);
#endif
}

----
Some code to test it is:

NOW=`date`; echo "! Testing wlock - the wait for a write lock should last ~5 seconds"
if [ false ]
then
   rm -f /tmp/wlock
fi
(exec 200>$/tmp/wlock; \
NOW=`date`; echo "!   ${NOW} locked wlock" ; \
flock -x 200; \
sleep 5; \
exec 200>&- ; \
NOW=`date`; echo "!   ${NOW} unlocked wlock" ; \
NOW=`date`; echo "!   ${NOW} locker/unlocker exits" \
)&
# give it a second to notice the unlock \
sleep 2 #give the subprocess time to place the lock
program  -wlock /tmp/wlock

The test program just tries to lock, and then unlock that file. It should do so 3 only
after the subprocess releases its lock.

This works fine (always) on Linux and sometimes on Windows. For the latter if wlock already exists and is at least 1 byte everything is fine. However if the "false" is changed to true then the flock program creates an empty /tmp/wlock and Filelock() fails, presumably because the range it has been told to lock does not exist. But I don't see how to tell Filelock() to lock "no bytes"!

Thanks,

David Mathog
[email protected]
Manager, Sequence Analysis Facility, Biology Division, Caltech



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to