I have to go off and do something else this afternoon, but here is a
preliminary patch for flock support for Windows.  It compiles with my
MinGW cross-compiler but I haven't really tested it properly yet.

As you can see, it introduces another header file replacement - for
<sys/file.h>  On Linux this file just contains flock and its associated
definitions.  On MinGW the file is empty except for an include of
<fcntl.h>.

Rich.

-- 
Richard Jones, Emerging Technologies, Red Hat  http://et.redhat.com/~rjones
Read my OCaml programming blog: http://camltastic.blogspot.com/
Fedora now supports 68 OCaml packages (the OPEN alternative to F#)
http://cocan.org/getting_started_with_ocaml_on_red_hat_and_fedora
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 058125d..ccce428 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -396,6 +396,7 @@ fgets
 fgetwc
 fgetws
 fileno
+flock
 flockfile
 floor
 floorf
@@ -2105,6 +2106,7 @@ func_all_modules ()
   func_module errno
   func_module fchdir
   func_module fcntl
+  func_module flock
   func_module fopen
   func_module fprintf-posix
   func_module freopen
diff --git a/doc/glibc-functions/flock.texi b/doc/glibc-functions/flock.texi
index 29a2eb8..23878cf 100644
--- a/doc/glibc-functions/flock.texi
+++ b/doc/glibc-functions/flock.texi
@@ -2,15 +2,18 @@
 @subsection @code{flock}
 @findex flock
 
-Gnulib module: ---
+Gnulib module: flock
 
 Portability problems fixed by Gnulib:
 @itemize
[EMAIL PROTECTED]
+This function is missing on some platforms:
+mingw
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
 This function is missing on some platforms:
-AIX 5.1, HP-UX 11, Solaris 10, mingw, BeOS.
+AIX 5.1, HP-UX 11, Solaris 10, BeOS.
 @end itemize
diff --git a/lib/flock.c b/lib/flock.c
new file mode 100644
index 0000000..142fcc4
--- /dev/null
+++ b/lib/flock.c
@@ -0,0 +1,232 @@
+/* Emulate flock on platforms that lack it, primarily Windows and MinGW.
+
+   This is derived from sqlite3 sources.
+   http://www.sqlite.org/cvstrac/rlog?f=sqlite/src/os_win.c
+   http://www.sqlite.org/copyright.html
+
+   Written by Richard W.M. Jones <rjones.at.redhat.com>
+
+   Copyright (C) 2008 Free Software Foundation, Inc.
+
+   This library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   This library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <sys/file.h>
+
+#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
+
+/* _get_osfhandle */
+#include <io.h>
+
+/* LockFile and LockFileEx */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <errno.h>
+
+/* Is this platform NT?  NT has LockFileEx which can do reader/writer
+ * locks, everything before that only has LockFile which can just lock
+ * files.  This is not implemented for WinCE (which lacks both).
+ *
+ * os_type is:
+ *   0 = not determined yet
+ *   1 = 95/98/ME
+ *   2 = NT
+ */
+static int os_type = 0;
+
+static int
+is_NT ()
+{
+  if (os_type==0)
+    {
+      OSVERSIONINFO sInfo;
+
+      sInfo.dwOSVersionInfoSize = sizeof(sInfo);
+      GetVersionEx(&sInfo);
+      os_type = sInfo.dwPlatformId == VER_PLATFORM_WIN32_NT ? 2 : 1;
+    }
+  return os_type == 2;
+}
+
+/* Determine the current size of a file.  Because the other braindead
+ * APIs we'll call need lower/upper 32 bit pairs, keep the file size
+ * like that too.  Use GetFileSize since it's available on all
+ * versions of Windows (GetFileSizeEx is less braindead but only
+ * available on NT).
+ */
+static int
+file_size (HANDLE h, DWORD *lower, DWORD *upper)
+{
+  *lower = GetFileSize (h, upper);
+  return 1;
+}
+
+/* LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. */
+#ifndef LOCKFILE_FAIL_IMMEDIATELY
+# define LOCKFILE_FAIL_IMMEDIATELY 1
+#endif
+
+/* Acquire a reader lock. */
+static int
+do_lock_read (HANDLE h, int non_blocking)
+{
+  int res;
+  DWORD size_lower, size_upper;
+
+  res = file_size (h, &size_lower, &size_upper);
+  if (!res) return 0;
+
+  if (is_NT())
+    {
+      OVERLAPPED ovlp;
+      int flags = 0;
+
+      /* NT is relatively sane.  Request a non-exclusive lock on
+       * the whole file.
+       */
+      ovlp.Offset = 0;
+      ovlp.OffsetHigh = 0;
+      ovlp.hEvent = 0;
+      if (non_blocking) flags |= LOCKFILE_FAIL_IMMEDIATELY;
+      res = LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
+    }
+  else
+    {
+      int lk;
+
+      /* Pre-NT systems have only LockFile, which only locks
+       * exclusively.  Use the same strategy as sqlite: acquire a lock
+       * on a single byte somewhere in the file.  Two readers will
+       * usually be able to continue in parallel (unless they are
+       * unlucky and request the same byte -- of course the size of
+       * the file matters here).  A writer will try to lock the whole
+       * file, so always get exclusive access.
+       */
+      /* XXX rand() isn't thread-safe. */
+      /* XXX sqlite original code saves 'lk' (the offset of the byte
+       * we are locking).  We have nowhere convenient to stash this,
+       * but it shouldn't matter - we unlock the whole file below.
+       */
+      lk = rand () % size_lower;
+      res = LockFile (h, lk, 0, 1, 0);
+    }
+
+  return res;
+}
+
+/* Get an exclusive lock on a file. */
+static int
+do_lock_exclusive (HANDLE h, int non_blocking)
+{
+  int res;
+  DWORD size_lower, size_upper;
+
+  res = file_size (h, &size_lower, &size_upper);
+  if (!res) return 0;
+
+  if (is_NT())
+    {
+      OVERLAPPED ovlp;
+      int flags = LOCKFILE_EXCLUSIVE_LOCK;
+
+      ovlp.Offset = 0;
+      ovlp.OffsetHigh = 0;
+      ovlp.hEvent = 0;
+      if (non_blocking) flags |= LOCKFILE_FAIL_IMMEDIATELY;
+      res = LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
+    }
+  else
+    {
+      /* See discussion in do_lock_read function above. */
+      res = LockFile (h, 0, 0, size_lower, size_upper);
+    }
+
+  return res;
+}
+
+/* Unlock reader or exclusive lock. */
+static int
+do_unlock (HANDLE h)
+{
+  int res;
+  DWORD size_lower, size_upper;
+
+  res = file_size (h, &size_lower, &size_upper);
+  if (!res) return 0;
+
+  res = UnlockFile(h, 0, 0, size_lower, size_upper);
+  return res;
+}
+
+int
+flock (int fd, int operation)
+{
+  HANDLE h = (HANDLE) _get_osfhandle (fd);
+  DWORD res;
+  int non_blocking = operation & LOCK_NB;
+
+  if (h == INVALID_HANDLE_VALUE)
+    {
+      errno = EBADF;
+      return -1;
+    }
+
+  if (operation & LOCK_SH)
+    res = do_lock_read (h, non_blocking);
+  else if (operation & LOCK_EX)
+    res = do_lock_exclusive (h, non_blocking);
+  else if (operation & LOCK_UN)
+    res = do_unlock (h);
+  else {
+    errno = EINVAL;
+    return -1;
+  }
+
+  /* Map Windows errors into Unix errnos.  As usual MSDN fails to
+   * document the permissible error codes.
+   */
+  if (!res) {
+    DWORD err = GetLastError ();
+    switch (err)
+      {
+       /* This means someone else is holding a lock. */
+      case ERROR_LOCK_VIOLATION:
+       /* EWOULDBLOCK is not available on MinGW. */
+       errno = EAGAIN;
+       break;
+
+       /* Out of memory. */
+      case ERROR_NOT_ENOUGH_MEMORY:
+       errno = ENOMEM;
+       break;
+
+       /* Unlikely to be other errors, but at least don't lose the
+        * error code.
+        */
+      default:
+       errno = err;
+      }
+
+    return -1;
+  }
+
+  return 0;
+}
+
+#else /* !Windows */
+
+#error "This platform lacks flock function, and Gnulib doesn't provide a 
replacement. This is a bug in Gnulib."
+
+#endif /* !Windows */
diff --git a/lib/sys_file.in.h b/lib/sys_file.in.h
new file mode 100644
index 0000000..c1d2315
--- /dev/null
+++ b/lib/sys_file.in.h
@@ -0,0 +1,58 @@
+/* Provide a more complete sys/file.h.
+
+   Copyright (C) 2007-2008 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
+
+/* Written by Richard W.M. Jones.  */
+#ifndef _GL_SYS_FILE_H
+
[EMAIL PROTECTED]@
+
+/* The include_next requires a split double-inclusion guard.  */
+# if @HAVE_SYS_FILE_H@
+#  @INCLUDE_NEXT@ @NEXT_SYS_FILE_H@
+# endif
+
+#ifndef _GL_SYS_FILE_H
+#define _GL_SYS_FILE_H
+
+
+#if @GNULIB_FLOCK@
+/* Apply or remove advisory locks on an open file.
+   Return 0 if successful, otherwise -1 and errno set.  */
+# if [EMAIL PROTECTED]@
+extern int flock (int fd, int operation);
+
+/* Operations for the 'flock' call (same as Linux kernel constants).  */
+#define LOCK_SH 1       /* Shared lock.  */
+#define LOCK_EX 2       /* Exclusive lock.  */
+#define LOCK_UN 8       /* Unlock.  */
+
+/* Can be OR'd in to one of the above.  */
+#define LOCK_NB 4       /* Don't block when locking.  */
+
+# endif
+#elif defined GNULIB_POSIXCHECK
+# undef flock
+# define flock(fd,op)                         \
+    (GL_LINK_WARNING ("flock is unportable - " \
+                      "use gnulib module flock for portability"), \
+     flock ((fd), (op)))
+#endif
+
+
+#endif /* _GL_SYS_FILE_H */
+#endif /* _GL_SYS_FILE_H */
diff --git a/m4/flock.m4 b/m4/flock.m4
new file mode 100644
index 0000000..54ef7cf
--- /dev/null
+++ b/m4/flock.m4
@@ -0,0 +1,19 @@
+# flock.m4 serial 1
+dnl Copyright (C) 2008 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN([gl_FUNC_FLOCK],
+[
+  AC_REQUIRE([gl_HEADER_SYS_FILE_H_DEFAULTS])
+  AC_CHECK_FUNCS_ONCE([flock])
+  if test $ac_cv_func_flock = no; then
+    HAVE_FLOCK=0
+    AC_LIBOBJ([flock])
+    gl_PREREQ_FLOCK
+  fi
+])
+
+# Prerequisites of lib/flock.c.
+AC_DEFUN([gl_PREREQ_FLOCK], [:])
diff --git a/m4/sys_file_h.m4 b/m4/sys_file_h.m4
new file mode 100644
index 0000000..436c6fe
--- /dev/null
+++ b/m4/sys_file_h.m4
@@ -0,0 +1,41 @@
+# Configure a replacement for <sys/file.h>.
+
+# Copyright (C) 2008 Free Software Foundation, Inc.
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Written by Richard W.M. Jones.
+
+AC_DEFUN([gl_HEADER_SYS_FILE_H],
+[
+  AC_REQUIRE([gl_HEADER_SYS_FILE_H_DEFAULTS])
+
+  dnl Only flock is defined in a working <sys/file.h>.  If that
+  dnl function is already there, we don't want to do any substitution.
+  AC_CHECK_FUNCS_ONCE([flock])
+
+  gl_CHECK_NEXT_HEADERS([sys/file.h])
+  SYS_FILE_H='sys/file.h'
+  AC_SUBST([SYS_FILE_H])
+
+  AC_CHECK_HEADERS_ONCE([sys/file.h])
+  if test $ac_cv_header_sys_file_h = yes; then
+    HAVE_SYS_FILE_H=1
+  else
+    HAVE_SYS_FILE_H=0
+  fi
+  AC_SUBST([HAVE_SYS_FILE_H])
+])
+
+AC_DEFUN([gl_HEADER_SYS_FILE_MODULE_INDICATOR],
+[
+  AC_REQUIRE([gl_HEADER_SYS_FILE_H_DEFAULTS])
+  
GNULIB_[]m4_translit([$1],[abcdefghijklmnopqrstuvwxyz./-],[ABCDEFGHIJKLMNOPQRSTUVWXYZ___])=1
+])
+
+AC_DEFUN([gl_HEADER_SYS_FILE_H_DEFAULTS],
+[
+  GNULIB_FLOCK=0;        AC_SUBST([GNULIB_FLOCK])
+  HAVE_FLOCK=1;          AC_SUBST([HAVE_FLOCK])
+])
diff --git a/modules/flock b/modules/flock
new file mode 100644
index 0000000..9134d51
--- /dev/null
+++ b/modules/flock
@@ -0,0 +1,24 @@
+Description:
+flock(2) function: advisory file locks.
+
+Files:
+lib/flock.c
+m4/flock.m4
+
+Depends-on:
+sys_file
+
+configure.ac:
+gl_FUNC_FLOCK
+gl_HEADER_SYS_FILE_MODULE_INDICATOR([flock])
+
+Makefile.am:
+
+Include:
+<sys/file.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+Richard W.M. Jones, Jim Meyering
diff --git a/modules/sys_file b/modules/sys_file
new file mode 100644
index 0000000..2c1f8f8
--- /dev/null
+++ b/modules/sys_file
@@ -0,0 +1,44 @@
+Description:
+<sys/file.h> for systems with an incomplete header.
+
+Files:
+lib/sys_file.in.h
+m4/sys_file_h.m4
+
+Depends-on:
+include_next
+link-warning
+
+configure.ac:
+gl_HEADER_SYS_FILE_H
+AC_PROG_MKDIR_P
+
+Makefile.am:
+BUILT_SOURCES += $(SYS_FILE_H)
+
+# We need the following in order to create <sys/file.h> when the system
+# has one that is incomplete.
+sys/file.h: sys_file.in.h
+       @MKDIR_P@ sys
+       rm -f [EMAIL PROTECTED] $@
+       { echo '/* DO NOT EDIT! GENERATED AUTOMATICALLY! */'; \
+         sed -e 's/@''HAVE_SYS_FILE_H''@/$(HAVE_SYS_FILE_H)/g' \
+             -e 's|@''INCLUDE_NEXT''@|$(INCLUDE_NEXT)|g' \
+             -e 's|@''PRAGMA_SYSTEM_HEADER''@|@PRAGMA_SYSTEM_HEADER@|g' \
+             -e 's|@''NEXT_SYS_FILE_H''@|$(NEXT_SYS_FILE_H)|g' \
+             -e 's/@''HAVE_FLOCK''@/$(HAVE_FLOCK)/g' \
+             -e 's/@''GNULIB_FLOCK''@/$(GNULIB_FLOCK)/g' \
+             < $(srcdir)/sys_file.in.h; \
+       } > [EMAIL PROTECTED]
+       mv [EMAIL PROTECTED] $@
+MOSTLYCLEANFILES += sys/file.h sys/file.h-t
+MOSTLYCLEANDIRS += sys
+
+Include:
+#include <sys/file.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all

Reply via email to