/* $OpenLDAP$ */
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
*
- * Copyright 2005-2006 The OpenLDAP Foundation.
+ * Copyright 2005-2013 The OpenLDAP Foundation.
* Portions Copyright 2004-2005 Symas Corporation.
* All rights reserved.
*
* <http://www.OpenLDAP.org/license.html>.
*/
/* ACKNOWLEDGEMENTS:
- * This work was initially developed by Matthew Backes at Symas
+ * This work was initially developed by Emily Backes at Symas
* Corporation for inclusion in OpenLDAP Software.
*/
#include "portable.h"
-#if SLAPD_BDB || SLAPD_HDB || SLAPD_LDBM
+#if SLAPD_BDB || SLAPD_HDB
+#include <lber.h>
#include "alock.h"
+#include "lutil.h"
#include <ac/stdlib.h>
#include <ac/string.h>
#include <ac/assert.h>
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef HAVE_SYS_FILE_H
#include <sys/file.h>
+#endif
#include <fcntl.h>
#ifdef _WIN32
+#include <windows.h>
#include <stdio.h>
#include <io.h>
-#include <sys/locking.h>
#endif
res = fcntl (fd, F_SETLKW, &lock_info);
#elif defined( _WIN32 )
- if( _lseek( fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET ) < 0 )
- return -1;
- /*
- * _lock will try for the lock once per second, returning EDEADLOCK
- * after ten tries. We just loop until we either get the lock
- * or some other error is returned.
- */
- while((res = _locking( fd, _LK_LOCK, ALOCK_SLOT_SIZE )) < 0 ) {
- if( errno != EDEADLOCK )
- break;
- }
+ OVERLAPPED ov;
+ HANDLE hh = _get_osfhandle ( fd );
+ ov.hEvent = 0;
+ ov.Offset = ALOCK_SLOT_SIZE*slot;
+ ov.OffsetHigh = 0;
+ res = LockFileEx( hh, LOCKFILE_EXCLUSIVE_LOCK, 0,
+ ALOCK_SLOT_SIZE, 0, &ov ) ? 0 : -1;
#else
-# error alock needs lockf, fcntl, or _locking
+# error alock needs lockf, fcntl, or LockFile[Ex]
#endif
if (res == -1) {
assert (errno != EDEADLK);
res = fcntl (fd, F_SETLKW, &lock_info);
if (res == -1) return -1;
#elif defined( _WIN32 )
- res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
- if (res == -1) return -1;
- res = _locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
+ HANDLE hh = _get_osfhandle ( fd );
+ if ( !UnlockFile ( hh, ALOCK_SLOT_SIZE*slot, 0,
+ ALOCK_SLOT_SIZE, 0 ))
+ return -1;
+#else
+# error alock needs lockf, fcntl, or LockFile[Ex]
+#endif
+
+ return 0;
+}
+
+static int
+alock_share_lock ( int fd, int slot )
+{
+ int res;
+
+#if defined( HAVE_LOCKF )
+ res = 0; /* lockf has no shared locks */
+#elif defined ( HAVE_FCNTL )
+ struct flock lock_info;
+ (void) memset ((void *) &lock_info, 0, sizeof (struct flock));
+
+ /* The shared lock replaces the existing lock */
+ lock_info.l_type = F_RDLCK;
+ lock_info.l_whence = SEEK_SET;
+ lock_info.l_start = (off_t) (ALOCK_SLOT_SIZE * slot);
+ lock_info.l_len = (off_t) ALOCK_SLOT_SIZE;
+
+ res = fcntl (fd, F_SETLK, &lock_info);
if (res == -1) return -1;
+#elif defined( _WIN32 )
+ OVERLAPPED ov;
+ HANDLE hh = _get_osfhandle ( fd );
+
+ /* Windows locks are mandatory, not advisory.
+ * We must downgrade the lock to allow future
+ * callers to read the slot data.
+ *
+ * First acquire a shared lock. Unlock will
+ * release the existing exclusive lock.
+ */
+ ov.hEvent = 0;
+ ov.Offset = ALOCK_SLOT_SIZE*slot;
+ ov.OffsetHigh = 0;
+ LockFileEx (hh, 0, 0, ALOCK_SLOT_SIZE, 0, &ov);
+ UnlockFile (hh, ALOCK_SLOT_SIZE*slot, 0, ALOCK_SLOT_SIZE, 0);
#else
-# error alock needs lockf, fcntl, or _locking
+# error alock needs lockf, fcntl, or LockFile[Ex]
#endif
return 0;
if (lock_info.l_type != F_UNLCK) return ALOCK_LOCKED;
#elif defined( _WIN32 )
- res = _lseek (fd, (ALOCK_SLOT_SIZE * slot), SEEK_SET);
- if (res == -1) return -1;
- res = _locking( fd, _LK_NBLCK, ALOCK_SLOT_SIZE );
- _locking( fd, _LK_UNLCK, ALOCK_SLOT_SIZE );
- if (res == -1) {
- if( errno == EACCES ) {
- return ALOCK_LOCKED;
- } else {
- return -1;
- }
+ OVERLAPPED ov;
+ HANDLE hh = _get_osfhandle ( fd );
+ ov.hEvent = 0;
+ ov.Offset = ALOCK_SLOT_SIZE*slot;
+ ov.OffsetHigh = 0;
+ if( !LockFileEx( hh,
+ LOCKFILE_EXCLUSIVE_LOCK|LOCKFILE_FAIL_IMMEDIATELY, 0,
+ ALOCK_SLOT_SIZE, 0, &ov )) {
+ int err = GetLastError();
+ if ( err == ERROR_LOCK_VIOLATION )
+ return ALOCK_LOCKED;
+ else
+ return -1;
}
#else
-# error alock needs lockf, fcntl, or _locking
+# error alock needs lockf, fcntl, or LockFile
#endif
return 0;
assert (bufptr != NULL);
bufptr += sizeof (unsigned long int);
- for (count=0; count <= sizeof (unsigned long int); ++count) {
+ for (count=0; count <= (int) sizeof (unsigned long int); ++count) {
val <<= 8;
val += (unsigned long int) *bufptr--;
}
}
if (alock_read_iattr (slotbuf) != ALOCK_MAGIC) {
- return 1;
+ return -1;
}
slot_data->al_lock = alock_read_iattr (slotbuf+8);
slot_data->al_stamp = alock_read_iattr (slotbuf+16);
slot_data->al_pid = alock_read_iattr (slotbuf+24);
- if (slot_data->al_appname) free (slot_data->al_appname);
- slot_data->al_appname = calloc (1, ALOCK_MAX_APPNAME);
+ if (slot_data->al_appname) ber_memfree (slot_data->al_appname);
+ slot_data->al_appname = ber_memcalloc (1, ALOCK_MAX_APPNAME);
+ if (slot_data->al_appname == NULL) {
+ return -1;
+ }
strncpy (slot_data->al_appname, (char *)slotbuf+32, ALOCK_MAX_APPNAME-1);
(slot_data->al_appname) [ALOCK_MAX_APPNAME-1] = '\0';
alock_write_iattr (slotbuf+16, slot_data->al_stamp);
alock_write_iattr (slotbuf+24, slot_data->al_pid);
- strncpy ((char *)slotbuf+32, slot_data->al_appname, ALOCK_MAX_APPNAME-1);
+ if (slot_data->al_appname)
+ strncpy ((char *)slotbuf+32, slot_data->al_appname, ALOCK_MAX_APPNAME-1);
slotbuf[ALOCK_SLOT_SIZE-1] = '\0';
res = lseek (info->al_fd,
(void) memset ((void *) &slot_data, 0, sizeof (alock_slot_t));
alock_read_slot (info, &slot_data);
- if (slot_data.al_appname != NULL) free (slot_data.al_appname);
+ if (slot_data.al_appname != NULL) ber_memfree (slot_data.al_appname);
slot_data.al_appname = NULL;
nosave = slot_data.al_lock & ALOCK_NOSAVE;
char * filename;
int res, max_slot;
int dirty_count, live_count, nosave;
+ char *ptr;
assert (info != NULL);
assert (appname != NULL);
slot_data.al_lock = locktype;
slot_data.al_stamp = time(NULL);
slot_data.al_pid = getpid();
- slot_data.al_appname = calloc (1, ALOCK_MAX_APPNAME);
+ slot_data.al_appname = ber_memcalloc (1, ALOCK_MAX_APPNAME);
+ if (slot_data.al_appname == NULL) {
+ return ALOCK_UNSTABLE;
+ }
strncpy (slot_data.al_appname, appname, ALOCK_MAX_APPNAME-1);
slot_data.al_appname [ALOCK_MAX_APPNAME-1] = '\0';
- filename = calloc (1, strlen (envdir) + strlen ("/alock") + 1);
- strcpy (filename, envdir);
- strcat (filename, "/alock");
+ filename = ber_memcalloc (1, strlen (envdir) + strlen ("/alock") + 1);
+ if (filename == NULL ) {
+ ber_memfree (slot_data.al_appname);
+ return ALOCK_UNSTABLE;
+ }
+ ptr = lutil_strcopy(filename, envdir);
+ lutil_strcopy(ptr, "/alock");
+#ifdef _WIN32
+ { HANDLE handle = CreateFile (filename, GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ info->al_fd = _open_osfhandle (handle, 0);
+ }
+#else
info->al_fd = open (filename, O_CREAT|O_RDWR, 0666);
- free (filename);
+#endif
+ ber_memfree (filename);
if (info->al_fd < 0) {
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
info->al_slot = 0;
res = alock_grab_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
res = fstat (info->al_fd, &statbuf);
if (res == -1) {
close (info->al_fd);
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
++live_count;
} else if (res == ALOCK_UNIQUE
- && locktype == ALOCK_UNIQUE) {
+ && (( locktype & ALOCK_SMASK ) == ALOCK_UNIQUE
+ || nosave )) {
close (info->al_fd);
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
return ALOCK_BUSY;
} else if (res == ALOCK_DIRTY) {
} else if (res == -1) {
close (info->al_fd);
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
if (dirty_count && live_count) {
close (info->al_fd);
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
info->al_slot);
if (res == -1) {
close (info->al_fd);
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
return ALOCK_UNSTABLE;
}
res = alock_write_slot (info, &slot_data);
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
if (res == -1) {
close (info->al_fd);
return ALOCK_UNSTABLE;
}
+ alock_share_lock (info->al_fd, info->al_slot);
res = alock_release_lock (info->al_fd, 0);
if (res == -1) {
}
int
-alock_close ( alock_info_t * info )
+alock_close ( alock_info_t * info, int nosave )
{
alock_slot_t slot_data;
int res;
res = alock_grab_lock (info->al_fd, 0);
if (res == -1) {
+fail:
+ /* Windows doesn't clean up locks immediately when a process exits.
+ * Make sure we release our locks, to prevent stale locks from
+ * hanging around.
+ */
+ alock_release_lock (info->al_fd, 0);
close (info->al_fd);
return ALOCK_UNSTABLE;
}
/* mark our slot as clean */
res = alock_read_slot (info, &slot_data);
if (res == -1) {
- close (info->al_fd);
if (slot_data.al_appname != NULL)
- free (slot_data.al_appname);
- return ALOCK_UNSTABLE;
+ ber_memfree (slot_data.al_appname);
+ goto fail;
+ }
+ slot_data.al_lock = ALOCK_UNLOCKED;
+ if ( nosave )
+ slot_data.al_lock |= ALOCK_NOSAVE;
+ /* since we have slot 0 locked, we don't need our slot lock */
+ res = alock_release_lock (info->al_fd, info->al_slot);
+ if (res == -1) {
+ goto fail;
}
- slot_data.al_lock = ALOCK_UNLOCKED | (slot_data.al_lock & ALOCK_NOSAVE);
res = alock_write_slot (info, &slot_data);
if (res == -1) {
- close (info->al_fd);
if (slot_data.al_appname != NULL)
- free (slot_data.al_appname);
- return ALOCK_UNSTABLE;
+ ber_memfree (slot_data.al_appname);
+ goto fail;
}
if (slot_data.al_appname != NULL) {
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
slot_data.al_appname = NULL;
}
- res = alock_release_lock (info->al_fd, info->al_slot);
- if (res == -1) {
- close (info->al_fd);
- return ALOCK_UNSTABLE;
- }
res = alock_release_lock (info->al_fd, 0);
if (res == -1) {
close (info->al_fd);
res = alock_grab_lock (info->al_fd, 0);
if (res == -1) {
- close (info->al_fd);
- return ALOCK_UNSTABLE;
+ goto fail;
}
res = fstat (info->al_fd, &statbuf);
if (res == -1) {
- close (info->al_fd);
- return ALOCK_UNSTABLE;
+ goto fail;
}
max_slot = (statbuf.st_size + ALOCK_SLOT_SIZE - 1) / ALOCK_SLOT_SIZE;
if (res == ALOCK_LOCKED
|| res == ALOCK_UNIQUE) {
/* recovery attempt on an active db? */
- close (info->al_fd);
- return ALOCK_UNSTABLE;
+ goto fail;
} else if (res == ALOCK_DIRTY) {
/* mark it clean */
res = alock_read_slot (&scan_info, &slot_data);
if (res == -1) {
- close (info->al_fd);
- return ALOCK_UNSTABLE;
+ goto fail;
}
slot_data.al_lock = ALOCK_UNLOCKED;
res = alock_write_slot (&scan_info, &slot_data);
if (res == -1) {
- close (info->al_fd);
if (slot_data.al_appname != NULL)
- free (slot_data.al_appname);
- return ALOCK_UNSTABLE;
+ ber_memfree (slot_data.al_appname);
+ goto fail;
}
if (slot_data.al_appname != NULL) {
- free (slot_data.al_appname);
+ ber_memfree (slot_data.al_appname);
slot_data.al_appname = NULL;
}
} else if (res == -1) {
- close (info->al_fd);
- return ALOCK_UNSTABLE;
+ goto fail;
}
}
}
return ALOCK_CLEAN;
+
+fail:
+ alock_release_lock (info->al_fd, 0);
+ close (info->al_fd);
+ return ALOCK_UNSTABLE;
}
#endif /* SLAPD_BDB || SLAPD_HDB */