summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rwxr-xr-xMODULES.html.sh2
-rw-r--r--doc/glibc-functions/flock.texi7
-rw-r--r--lib/flock.c219
-rw-r--r--lib/sys_file.in.h58
-rw-r--r--m4/flock.m426
-rw-r--r--m4/sys_file_h.m441
-rw-r--r--modules/flock24
-rw-r--r--modules/flock-tests11
-rw-r--r--modules/sys_file44
-rw-r--r--tests/test-flock.c104
11 files changed, 549 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 51ce3f6605..f1c32e6ed8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2008-10-07 Richard W.M. Jones <rjones@redhat.com>
+
+ flock: new module
+ * MODULES.html.sh: Add to list of modules.
+ * lib/flock.c: flock implementation for Windows and Unix systems
+ which have fcntl.
+ * doc/glibc-functions/flock.texi: Update documentation.
+ * lib/sys_file.in.h: <sys/file.h> header file.
+ * m4/flock.m4: M4 macros.
+ * m4/sys_file_h.m4: M4 macros for replacement sys/file.h.
+ * modules/flock: flock module.
+ * modules/flock-tests: flock tests module.
+ * modules/sys_file: sys/file.h module.
+ * tests/test-flock.c: test suite for flock.
+
2008-10-06 Jim Meyering <meyering@redhat.com>
bootstrap: check for LT_INIT more portably still ;-)
diff --git a/MODULES.html.sh b/MODULES.html.sh
index 229fb53e42..96fe700fd0 100755
--- a/MODULES.html.sh
+++ b/MODULES.html.sh
@@ -396,6 +396,7 @@ fgets
fgetwc
fgetws
fileno
+flock
flockfile
floor
floorf
@@ -2106,6 +2107,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 29a2eb8b85..23878cf61a 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
+@item
+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 0000000000..5aa7690bd8
--- /dev/null
+++ b/lib/flock.c
@@ -0,0 +1,219 @@
+/* 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>
+
+/* LockFileEx */
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#include <errno.h>
+
+/* 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.
+ */
+static BOOL
+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 lock. */
+static BOOL
+do_lock (HANDLE h, int non_blocking, int exclusive)
+{
+ BOOL res;
+ DWORD size_lower, size_upper;
+ OVERLAPPED ovlp;
+ int flags = 0;
+
+ /* We're going to lock the whole file, so get the file size. */
+ res = file_size (h, &size_lower, &size_upper);
+ if (!res)
+ return 0;
+
+ /* Start offset is 0, and also zero the remaining members of this struct. */
+ memset (&ovlp, 0, sizeof ovlp);
+
+ if (non_blocking)
+ flags |= LOCKFILE_FAIL_IMMEDIATELY;
+ if (exclusive)
+ flags |= LOCKFILE_EXCLUSIVE_LOCK;
+
+ return LockFileEx (h, flags, 0, size_lower, size_upper, &ovlp);
+}
+
+/* Unlock reader or exclusive lock. */
+static BOOL
+do_unlock (HANDLE h)
+{
+ int res;
+ DWORD size_lower, size_upper;
+
+ res = file_size (h, &size_lower, &size_upper);
+ if (!res)
+ return 0;
+
+ return UnlockFile (h, 0, 0, size_lower, size_upper);
+}
+
+/* Now our BSD-like flock operation. */
+int
+flock (int fd, int operation)
+{
+ HANDLE h = (HANDLE) _get_osfhandle (fd);
+ DWORD res;
+ int non_blocking;
+
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ non_blocking = operation & LOCK_NB;
+ operation &= ~LOCK_NB;
+
+ switch (operation)
+ {
+ case LOCK_SH:
+ res = do_lock (h, non_blocking, 0);
+ break;
+ case LOCK_EX:
+ res = do_lock (h, non_blocking, 1);
+ break;
+ case LOCK_UN:
+ res = do_unlock (h);
+ break;
+ default:
+ 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:
+ errno = EAGAIN;
+ break;
+
+ /* Out of memory. */
+ case ERROR_NOT_ENOUGH_MEMORY:
+ errno = ENOMEM;
+ break;
+
+ case ERROR_BAD_COMMAND:
+ errno = EINVAL;
+ break;
+
+ /* Unlikely to be other errors, but at least don't lose the
+ * error code.
+ */
+ default:
+ errno = err;
+ }
+
+ return -1;
+ }
+
+ return 0;
+}
+
+#else /* !Windows */
+
+#ifdef HAVE_FLOCK_L_TYPE
+/* We know how to implement flock in terms of fcntl. */
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+int
+flock (int fd, int operation)
+{
+ int cmd, r;
+ struct flock fl;
+
+ if (operation & LOCK_NB)
+ cmd = F_SETLK;
+ else
+ cmd = F_SETLKW;
+ operation &= ~LOCK_NB;
+
+ memset (&fl, 0, sizeof fl);
+ fl.l_whence = SEEK_SET;
+ /* l_start & l_len are 0, which as a special case means "whole file". */
+
+ switch (operation)
+ {
+ case LOCK_SH:
+ fl.l_type = F_RDLCK;
+ break;
+ case LOCK_EX:
+ fl.l_type = F_WRLCK;
+ break;
+ case LOCK_UN:
+ fl.l_type = F_UNLCK;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ r = fcntl (fd, cmd, &fl);
+ if (r == -1 && errno == EACCES)
+ errno = EAGAIN;
+
+ return r;
+}
+
+#else /* !HAVE_FLOCK_L_TYPE */
+
+#error "This platform lacks flock function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib."
+
+#endif /* !HAVE_FLOCK_L_TYPE */
+
+#endif /* !Windows */
diff --git a/lib/sys_file.in.h b/lib/sys_file.in.h
new file mode 100644
index 0000000000..c1d2315c0d
--- /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
+
+@PRAGMA_SYSTEM_HEADER@
+
+/* 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 !@HAVE_FLOCK@
+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 0000000000..96475fc579
--- /dev/null
+++ b/m4/flock.m4
@@ -0,0 +1,26 @@
+# 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
+])
+
+dnl Prerequisites of lib/flock.c.
+AC_DEFUN([gl_PREREQ_FLOCK],
+[
+ AC_CHECK_FUNCS_ONCE([fcntl])
+ AC_CHECK_HEADERS_ONCE([unistd.h fcntl.h])
+
+ dnl Do we have a POSIX fcntl lock implementation?
+ AC_CHECK_MEMBERS([struct flock.l_type],[],[],[[#include <fcntl.h>]])
+])
diff --git a/m4/sys_file_h.m4 b/m4/sys_file_h.m4
new file mode 100644
index 0000000000..436c6fec14
--- /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 0000000000..9134d517ce
--- /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/flock-tests b/modules/flock-tests
new file mode 100644
index 0000000000..b546594bed
--- /dev/null
+++ b/modules/flock-tests
@@ -0,0 +1,11 @@
+Files:
+tests/test-flock.c
+
+Depends-on:
+unistd
+
+configure.ac:
+
+Makefile.am:
+TESTS += test-flock
+check_PROGRAMS += test-flock
diff --git a/modules/sys_file b/modules/sys_file
new file mode 100644
index 0000000000..2c1f8f8e51
--- /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 $@-t $@
+ { 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; \
+ } > $@-t
+ mv $@-t $@
+MOSTLYCLEANFILES += sys/file.h sys/file.h-t
+MOSTLYCLEANDIRS += sys
+
+Include:
+#include <sys/file.h>
+
+License:
+LGPLv2+
+
+Maintainer:
+all
diff --git a/tests/test-flock.c b/tests/test-flock.c
new file mode 100644
index 0000000000..a1872cda72
--- /dev/null
+++ b/tests/test-flock.c
@@ -0,0 +1,104 @@
+/* Test of flock() function.
+ Copyright (C) 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 of the License, 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, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/file.h>
+
+#define ASSERT(expr) \
+ do \
+ { \
+ if (!(expr)) \
+ { \
+ fprintf (stderr, "%s:%d: assertion failed, errno = %d\n", \
+ __FILE__, __LINE__, errno); \
+ fflush (stderr); \
+ abort (); \
+ } \
+ } \
+ while (0)
+
+static void
+test_shared (const char *file, int fd)
+{
+ /* Should be able to acquire several shared locks on a file, through
+ * different file table entries.
+ */
+ int fd2, r;
+
+ ASSERT (flock (fd, LOCK_SH) == 0);
+
+ fd2 = open (file, O_RDWR, 0644);
+ ASSERT (fd2 >= 0);
+
+ r = flock (fd2, LOCK_SH | LOCK_NB);
+ ASSERT (r == 0); /* Was able to acquire a second shared lock. */
+
+ ASSERT (flock (fd, LOCK_UN) == 0);
+ ASSERT (close (fd2) == 0);
+}
+
+static void
+test_exclusive (const char *file, int fd)
+{
+ /* Should not be able to acquire more than one exclusive lock on a file. */
+ int fd2, r;
+
+ ASSERT (flock (fd, LOCK_EX) == 0);
+
+ fd2 = open (file, O_RDWR, 0644);
+ ASSERT (fd2 >= 0);
+
+ r = flock (fd2, LOCK_SH | LOCK_NB);
+ ASSERT (r == -1); /* Was unable to acquire a second exclusive lock. */
+
+ ASSERT (flock (fd, LOCK_UN) == 0);
+ ASSERT (close (fd2) == 0);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int fd;
+ const char *file = "test-flock.txt";
+
+ /* Open a non-empty file for testing. */
+ fd = open (file, O_RDWR | O_CREAT | O_TRUNC, 0644);
+ ASSERT (fd >= 0);
+ ASSERT (write (fd, "hello", 5) == 5);
+
+ /* Some impossible operation codes which should never be accepted. */
+ ASSERT (flock (fd, LOCK_SH | LOCK_EX) == -1);
+ ASSERT (errno == EINVAL);
+ ASSERT (flock (fd, LOCK_SH | LOCK_UN) == -1);
+ ASSERT (errno == EINVAL);
+ ASSERT (flock (fd, LOCK_EX | LOCK_UN) == -1);
+ ASSERT (errno == EINVAL);
+ ASSERT (flock (fd, 0) == -1);
+ ASSERT (errno == EINVAL);
+
+ test_shared (file, fd);
+ test_exclusive (file, fd);
+
+ /* Close and remove the test file. */
+ ASSERT (close (fd) == 0);
+ ASSERT (unlink (file) == 0);
+
+ return 0;
+}