home *** CD-ROM | disk | FTP | other *** search
- /* @(#)lock-file.c 1.2 91/01/24 */
- /* copyright 1991, Mike Howard & Miller/Howard Investments, Inc.
- all rights reserved */
-
- /*
- these are convenience routines which implement file locking in standard
- ways regardless of the method selected within the particular operating
- system.
-
- Note: for record locks, the current file position is changed to the
- beginning of the locked region. for whole file locks, the current file
- position is not changed.
-
- Note: these routines do not work on buffered files.
-
- In all cases, the three parameters are:
- fd - int - file descriptor
- offset - off_t - offset from the beginning of file to begin locking
- region.
- len - off_t - length of locked region.
-
- offset == 0, len == 0 locks entire file.
-
- The functions do what they appear to do:
- int lock_record_shared_wait(fd, offset, len)
- int lock_record_exclusive_wait(fd, offset, len)
- int lock_record_shared_nowait(fd, offset, len)
- int lock_record_exclusive_nowait(fd, offset, len)
- int unlock_record(fd, offset, len)
- int lock_file_shared_wait(fd)
- int lock_file_exclusive_wait(fd)
- int lock_file_shared_nowait(fd)
- int lock_file_exclusive_nowait(fd)
- int unlock_file(fd)
-
- All functions return 0 if successful, -1 if the requested lock would
- block, and-2 on failure. They set the extern int lock_errno as follows:
- return lock_errno explanation
- 0 LCK_OK requested lock implemented
-
- -1 LCK_BLOCK the requested lock was blocked
-
- -2 LCK_BADFD fd is not a valid file descriptor
- -2 LCK_DEADLOCK a deadlock was detected
- -2 LCK_INTR an interrupt occurred which aborted the system call
- -2 LCK_OTHER some other error - errno may give more information
- if you know how to interpret it
-
- The extent of support depends on the system call used to implement
- the actual locks. The int lock_support contains the appropriate bitwise
- OR of the following defines:
- LCK_RECORD 1
- LCK_SHARED 2
- LCK_EXCLUSIVE 4
- LCK_NO_BLOCK 8
-
- The character pointer locking_style contains a user readable message
- specifying the underlying locking mechanism.
-
- Not all functions are available under all UNIX file locking schemes.
- For example, flock style locking only locks entire files. lockf style
- locking does not support shared locks. If a requested feature is not
- supported, the least restrictive feature which does gives at least the
- requested protection is used.
-
- */
- /*
- a convenient template
- int lock_record_shared_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- }
-
- int lock_record_exclusive_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- }
-
- int lock_record_shared_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- }
-
- int lock_record_exclusive_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- }
-
- int unlock_record(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- }
-
- int lock_file_shared_wait(fd)
- int fd;
- {
- }
-
- int lock_file_exclusive_wait(fd)
- int fd;
- {
- }
-
- int lock_file_shared_nowait(fd)
- int fd;
- {
- }
-
- int lock_file_exclusive_nowait(fd)
- int fd;
- {
- }
-
- int unlock_file(fd)
- int fd;
- {
- }
- */
-
-
- #include <sys/types.h>
- #include <errno.h>
- extern int errno;
- int lock_errno;
- #include "lock-file.h"
- #include "patchlevel.h"
-
- static patchlevel = PATCHLEVEL;
-
- /* #define FCNTL_STYLE /* */
- /* #define FLOCK_STYLE /* */
- /* #define LOCKF_STYLE /* */
-
- /* default style is FCNTL_STYLE */
- #ifndef FCNTL_STYLE
- #ifndef FLOCK_STYLE
- #ifndef LOCKF_STYLE
- # define FCNTL_STYLE
- #endif
- #endif
- #endif
-
- #ifdef FCNTL_STYLE
- #include <fcntl.h>
-
- int lock_support = LCK_RECORD | LCK_SHARED | LCK_EXCLUSIVE | LCK_NO_BLOCK;
- static struct flock flock;
- static int do_fcntl_lock();
-
- char *locking_style = "fcntl style file locking";
-
- int lock_record_shared_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_fcntl_lock(fd, offset, len, F_RDLCK, F_SETLKW);
- }
-
- int lock_record_exclusive_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_fcntl_lock(fd, offset, len, F_WRLCK, F_SETLKW);
- }
-
- int lock_record_shared_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_fcntl_lock(fd, offset, len, F_RDLCK, F_SETLK);
- }
-
- int lock_record_exclusive_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_fcntl_lock(fd, offset, len, F_WRLCK, F_SETLK);
- }
-
- int unlock_record(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_fcntl_lock(fd, offset, len, F_UNLCK, F_SETLK);
- }
-
- int lock_file_shared_wait(fd)
- int fd;
- {
- return do_fcntl_lock(fd, 0L, 0L, F_RDLCK, F_SETLKW);
- }
-
- int lock_file_exclusive_wait(fd)
- int fd;
- {
- return do_fcntl_lock(fd, 0L, 0L, F_WRLCK, F_SETLKW);
- }
-
- int lock_file_shared_nowait(fd)
- int fd;
- {
- return do_fcntl_lock(fd, 0L, 0L, F_RDLCK, F_SETLK);
- }
-
- int lock_file_exclusive_nowait(fd)
- int fd;
- {
- return do_fcntl_lock(fd, 0L, 0L, F_WRLCK, F_SETLK);
- }
-
- int unlock_file(fd)
- int fd;
- {
- return do_fcntl_lock(fd, 0L, 0L, F_UNLCK, F_SETLK);
- }
-
- static int do_fcntl_lock(fd, offset, len, lock_cmd, set_cmd)
- int fd;
- off_t offset;
- off_t len;
- int lock_cmd;
- int set_cmd;
- {
- flock.l_type = lock_cmd;
- flock.l_whence = 0;
- flock.l_start = offset;
- flock.l_len = len;
- if (fcntl(fd, set_cmd, &flock)) {
- switch (errno) {
- case EACCES:
- case EAGAIN:
- lock_errno = LCK_BLOCK;
- return -1;
- case EBADF:
- lock_errno = LCK_BADFD;
- return -2;
- case EDEADLK:
- lock_errno = LCK_DEADLOCK;
- return -2;
- case EINTR:
- lock_errno = LCK_INTR;
- return -2;
- default:
- lock_errno = LCK_OTHER;
- return -2;
- }
- }
-
- lock_errno = LCK_OK;
- return 0;
- }
- #endif
-
- #ifdef FLOCK_STYLE
- /* WARNING: this does not correctly handle the case where more than
- one lock is applied to a file (or segments of a file) by a single
- process and then released `a little at a time'. The fix is straight
- forward: build a list of lock count records indexed by fd's and
- decrement when an unlock is requested. But this doesn't work either
- in the case that a file is dup'ed or reopenned. So I have not bothered
- to 'do it right', inasmuch as 'right' isn't.
- */
-
- #include <sys/file.h>
-
- char *locking_style = "flock style file locking";
- int lock_support = LCK_SHARED | LCK_EXCLUSIVE | LCK_NO_BLOCK;
- static int do_flock();
-
- int lock_record_shared_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
-
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_flock(fd, LOCK_SH);
- }
-
- int lock_record_exclusive_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
-
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_flock(fd, LOCK_EX);
- }
-
- int lock_record_shared_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
-
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_flock(fd, LOCK_SH | LOCK_NB);
- }
-
- int lock_record_exclusive_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- if (len < 0) {
- offset += len;
- len = -len;
- }
-
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- return do_flock(fd, LOCK_EX | LOCK_NB);
- }
-
- int unlock_record(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- return do_flock(fd, LOCK_UN);
- }
-
- int lock_file_shared_wait(fd)
- int fd;
- {
- return do_flock(fd, LOCK_SH);
- }
-
- int lock_file_exclusive_wait(fd)
- int fd;
- {
- return do_flock(fd, LOCK_EX);
- }
-
- int lock_file_shared_nowait(fd)
- int fd;
- {
- return do_flock(fd, LOCK_SH | LOCK_NB);
- }
-
- int lock_file_exclusive_nowait(fd)
- int fd;
- {
- return do_flock(fd, LOCK_EX | LOCK_NB);
- }
-
- int unlock_file(fd)
- int fd;
- {
- return do_flock(fd, LOCK_UN);
- }
-
- static int do_flock(fd, operation)
- int fd;
- int operation;
- {
- if (flock(fd, operation)) {
- switch (errno) {
- case EWOULDBLOCK:
- lock_errno = LCK_BLOCK;
- return -1;
- case EBADF:
- lock_errno = LCK_BADFD;
- return -2;
- case EDEADLK:
- lock_errno = LCK_DEADLOCK;
- return -2;
- case EINTR:
- lock_errno = LCK_INTR;
- return -2;
- default:
- lock_errno = LCK_OTHER;
- return -2;
- }
- }
-
- lock_errno = LCK_OK;
- return 0;
- }
- #endif
-
- #ifdef LOCKF_STYLE
- #include <unistd.h>
- #ifndef lseek
- long lseek();
- #endif
-
- char *locking_style = "lockf style file locking";
- int lock_support = LCK_RECORD | LCK_EXCLUSIVE | LCK_NO_BLOCK;
- static int do_lockf();
-
- int lock_record_shared_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- return do_lockf(fd, F_LOCK, offset, len, 0);
- }
-
- int lock_record_exclusive_wait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- return do_lockf(fd, F_LOCK, offset, len, 0);
- }
-
- int lock_record_shared_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- return do_lockf(fd, F_TLOCK, offset, len, 0);
- }
-
- int lock_record_exclusive_nowait(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- return do_lockf(fd, F_TLOCK, offset, len, 0);
- }
-
- int unlock_record(fd, offset, len)
- int fd;
- off_t offset;
- off_t len;
- {
- return do_lockf(fd, F_ULOCK, offset, len, 0);
- }
-
- int lock_file_shared_wait(fd)
- int fd;
- {
- return do_lockf(fd, F_LOCK, 0L, 0L, 1);
- }
-
- int lock_file_exclusive_wait(fd)
- int fd;
- {
- return do_lockf(fd, F_LOCK, 0L, 0L, 1);
- }
-
- int lock_file_shared_nowait(fd)
- int fd;
- {
- return do_lockf(fd, F_TLOCK, 0L, 0L, 1);
- }
-
- int lock_file_exclusive_nowait(fd)
- int fd;
- {
- return do_lockf(fd, F_TLOCK, 0L, 0L, 1);
- }
-
- int unlock_file(fd)
- int fd;
- {
- return do_lockf(fd, F_ULOCK, 0L, 0L, 1);
- }
-
- static int do_lockf(fd, command, offset, len, original_offset_flag)
- int fd;
- int command;
- off_t offset;
- off_t len;
- int original_offset_flag;
- {
- int ret;
- off_t original_offset;
- long lseek();
-
- if (original_offset_flag) {
- if ((original_offset = (off_t)lseek(fd, 0L, 1)) < 0)
- original_offset_flag = 0;
- }
- if (len < 0) {
- offset += len;
- len = -len;
- }
- if (lseek(fd, offset, 0) < 0) {
- lock_errno = errno == EBADF ? LCK_BADFD : LCK_OTHER;
- return -2;
- }
- if (lockf(fd, command, len)) {
- switch (errno) {
- case EACCES:
- lock_errno = LCK_BLOCK;
- ret = -1;
- break;
- case EBADF:
- lock_errno = LCK_BADFD;
- ret = -2;
- break;
- case EDEADLK:
- lock_errno = LCK_DEADLOCK;
- ret = -2;
- break;
- case EINTR:
- lock_errno = LCK_INTR;
- ret = -2;
- break;
- default:
- lock_errno = LCK_OTHER;
- ret = -2;
- break;
- }
- }
- else {
- lock_errno = LCK_OK;
- ret = 0;
- }
- if (original_offset_flag)
- lseek(fd, original_offset, 0);
-
- return ret;
- }
- #endif
-