Mercurial > hg > octave-jordi > gnulib-hg
diff lib/flock.c @ 10598:6c19e205b6b8
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.
author | Richard W.M. Jones <rjones@redhat.com> |
---|---|
date | Fri, 03 Oct 2008 14:58:14 +0100 |
parents | |
children | 81b06acec5ca |
line wrap: on
line diff
new file mode 100644 --- /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 */