2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: amflock.c 7161 2007-07-03 16:27:26Z dustin $
29 * file locking routines, put here to hide the system dependant stuff
30 * from the rest of the code
39 #if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 31))
40 # pragma GCC diagnostic push
41 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
42 static GStaticMutex lock_lock = G_STATIC_MUTEX_INIT;
43 # pragma GCC diagnostic pop
45 static GStaticMutex lock_lock = G_STATIC_MUTEX_INIT;
47 static GHashTable *locally_locked_files = NULL;
48 static int lock_rw_rd(file_lock *lock, short l_type);
54 file_lock *lock = g_new0(file_lock, 1);
55 lock->filename = g_strdup(filename);
65 g_static_mutex_lock(&lock_lock);
66 if (locally_locked_files) {
67 g_hash_table_remove(locally_locked_files,
74 g_free(lock->filename);
79 g_static_mutex_unlock(&lock_lock);
89 struct flock lock_buf;
92 g_assert(!lock->locked);
94 /* protect from overlapping lock operations within a process */
95 g_static_mutex_lock(&lock_lock);
96 if (!locally_locked_files) {
97 locally_locked_files = g_hash_table_new(g_str_hash, g_str_equal);
100 /* if this filename is in the hash table, then some other thread in this
101 * process has locked it */
102 if (g_hash_table_lookup(locally_locked_files, lock->filename)) {
107 /* The locks are advisory, so an error here never means the lock is already
109 lock->fd = fd = open(lock->filename, O_CREAT|O_RDWR, 0666);
115 /* now try locking it */
116 lock_buf.l_type = F_WRLCK;
117 lock_buf.l_start = 0;
118 lock_buf.l_whence = SEEK_SET;
119 lock_buf.l_len = 0; /* to EOF */
120 if (fcntl(fd, F_SETLK, &lock_buf) < 0) {
121 if (errno == EACCES || errno == EAGAIN)
128 /* and read the file in its entirety */
129 if (fstat(fd, &stat_buf) < 0) {
134 if (!(stat_buf.st_mode & S_IFREG)) {
140 if (stat_buf.st_size) {
141 lock->data = g_malloc(stat_buf.st_size);
142 lock->len = stat_buf.st_size;
143 if (full_read(fd, lock->data, lock->len) < lock->len) {
149 fd = -1; /* we'll keep the file now */
152 /* the lock is acquired; record this in the hash table */
153 g_hash_table_insert(locally_locked_files, lock->filename, lock->filename);
159 g_static_mutex_unlock(&lock_lock);
160 if (fd >= 0) /* close and unlock if an error occurred */
174 struct flock lock_buf;
175 struct stat stat_buf;
177 g_assert(!lock->locked);
179 /* protect from overlapping lock operations within a process */
180 g_static_mutex_lock(&lock_lock);
182 /* The locks are advisory, so an error here never means the lock is already
184 lock->fd = fd = open(lock->filename, O_CREAT|O_RDWR, 0666);
190 /* now try locking it */
191 lock_buf.l_type = l_type;
192 lock_buf.l_start = 0;
193 lock_buf.l_whence = SEEK_SET;
194 lock_buf.l_len = 0; /* to EOF */
195 if (fcntl(fd, F_SETLK, &lock_buf) < 0) {
196 if (errno == EACCES || errno == EAGAIN)
203 /* and read the file in its entirety */
204 if (fstat(fd, &stat_buf) < 0) {
209 if (!(stat_buf.st_mode & S_IFREG)) {
215 fd = -1; /* we'll keep the file now */
222 g_static_mutex_unlock(&lock_lock);
223 if (fd >= 0) /* close and unlock if an error occurred */
233 return lock_rw_rd(lock, F_WRLCK);
240 return lock_rw_rd(lock, F_RDLCK);
258 g_assert(lock->locked);
260 /* seek to position 0, rewrite, and truncate */
261 if (lseek(fd, 0, SEEK_SET) < 0)
264 /* from here on out, any errors have corrupted the datafile.. */
265 if (full_write(fd, data, len) < len)
268 if (lock->len > len) {
269 if (ftruncate(fd, len) < 0)
275 lock->data = g_strdup(data);
285 g_assert(lock->locked);
287 g_static_mutex_lock(&lock_lock);
289 /* relase the filesystem-level lock */
292 /* and the hash table entry */
293 if (locally_locked_files) {
294 g_hash_table_remove(locally_locked_files, lock->filename);
297 g_static_mutex_unlock(&lock_lock);
304 lock->locked = FALSE;
316 ** - These are "best effort" routines.
317 ** - "configure" has four variables that are used to determine which type of
319 ** USE_POSIX_FCNTL - use fcntl(). The full job.
320 ** USE_FLOCK - use flock(). Does just as well.
321 ** USE_LOCKF - use lockf(). Only handles advisory, exclusive,
322 ** blocking file locks as used by Amanda.
323 ** USE_LNLOCK - Home brew exclusive, blocking file lock.
324 ** <none> - No locking available. User beware!
327 /* Interface to the implementations in common-src/amflock-*.c */
329 #ifdef WANT_AMFLOCK_POSIX
330 extern amflock_impl_t amflock_posix_impl;
332 #ifdef WANT_AMFLOCK_FLOCK
333 extern amflock_impl_t amflock_flock_impl;
335 #ifdef WANT_AMFLOCK_LOCKF
336 extern amflock_impl_t amflock_lockf_impl;
338 #ifdef WANT_AMFLOCK_LNLOCK
339 extern amflock_impl_t amflock_lnlock_impl;
342 amflock_impl_t *amflock_impls[] = {
343 #ifdef WANT_AMFLOCK_POSIX
346 #ifdef WANT_AMFLOCK_FLOCK
349 #ifdef WANT_AMFLOCK_LOCKF
352 #ifdef WANT_AMFLOCK_LNLOCK
353 &amflock_lnlock_impl,
358 /* Interface functions */
359 /* FIXME: for now, these just use the first non-NULL implementation
362 /* Get a file lock (for read/write files).
369 if (!amflock_impls[0]) return 0; /* no locking */
370 return amflock_impls[0]->amflock_impl(fd, resource);
374 * Get a file lock (for read-only files).
381 if (!amflock_impls[0]) return 0; /* no locking */
382 return amflock_impls[0]->amroflock_impl(fd, resource);
386 * Release a file lock.
393 if (!amflock_impls[0]) return 0; /* no locking */
394 return amflock_impls[0]->amfunlock_impl(fd, resource);