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 static GStaticMutex lock_lock = G_STATIC_MUTEX_INIT;
40 static GHashTable *locally_locked_files = NULL;
41 static int lock_rw_rd(file_lock *lock, short l_type);
47 file_lock *lock = g_new0(file_lock, 1);
48 lock->filename = g_strdup(filename);
58 g_static_mutex_lock(&lock_lock);
59 if (locally_locked_files) {
60 g_hash_table_remove(locally_locked_files,
67 g_free(lock->filename);
72 g_static_mutex_unlock(&lock_lock);
82 struct flock lock_buf;
85 g_assert(!lock->locked);
87 /* protect from overlapping lock operations within a process */
88 g_static_mutex_lock(&lock_lock);
89 if (!locally_locked_files) {
90 locally_locked_files = g_hash_table_new(g_str_hash, g_str_equal);
93 /* if this filename is in the hash table, then some other thread in this
94 * process has locked it */
95 if (g_hash_table_lookup(locally_locked_files, lock->filename)) {
100 /* The locks are advisory, so an error here never means the lock is already
102 lock->fd = fd = open(lock->filename, O_CREAT|O_RDWR, 0666);
108 /* now try locking it */
109 lock_buf.l_type = F_WRLCK;
110 lock_buf.l_start = 0;
111 lock_buf.l_whence = SEEK_SET;
112 lock_buf.l_len = 0; /* to EOF */
113 if (fcntl(fd, F_SETLK, &lock_buf) < 0) {
114 if (errno == EACCES || errno == EAGAIN)
121 /* and read the file in its entirety */
122 if (fstat(fd, &stat_buf) < 0) {
127 if (!(stat_buf.st_mode & S_IFREG)) {
133 if (stat_buf.st_size) {
134 lock->data = g_malloc(stat_buf.st_size);
135 lock->len = stat_buf.st_size;
136 if (full_read(fd, lock->data, lock->len) < lock->len) {
142 fd = -1; /* we'll keep the file now */
145 /* the lock is acquired; record this in the hash table */
146 g_hash_table_insert(locally_locked_files, lock->filename, lock->filename);
152 g_static_mutex_unlock(&lock_lock);
153 if (fd >= 0) /* close and unlock if an error occurred */
167 struct flock lock_buf;
168 struct stat stat_buf;
170 g_assert(!lock->locked);
172 /* protect from overlapping lock operations within a process */
173 g_static_mutex_lock(&lock_lock);
175 /* The locks are advisory, so an error here never means the lock is already
177 lock->fd = fd = open(lock->filename, O_CREAT|O_RDWR, 0666);
183 /* now try locking it */
184 lock_buf.l_type = l_type;
185 lock_buf.l_start = 0;
186 lock_buf.l_whence = SEEK_SET;
187 lock_buf.l_len = 0; /* to EOF */
188 if (fcntl(fd, F_SETLK, &lock_buf) < 0) {
189 if (errno == EACCES || errno == EAGAIN)
196 /* and read the file in its entirety */
197 if (fstat(fd, &stat_buf) < 0) {
202 if (!(stat_buf.st_mode & S_IFREG)) {
208 fd = -1; /* we'll keep the file now */
215 g_static_mutex_unlock(&lock_lock);
216 if (fd >= 0) /* close and unlock if an error occurred */
226 return lock_rw_rd(lock, F_WRLCK);
233 return lock_rw_rd(lock, F_RDLCK);
251 g_assert(lock->locked);
253 /* seek to position 0, rewrite, and truncate */
254 if (lseek(fd, 0, SEEK_SET) < 0)
257 /* from here on out, any errors have corrupted the datafile.. */
258 if (full_write(fd, data, len) < len)
261 if (lock->len > len) {
262 if (ftruncate(fd, len) < 0)
268 lock->data = g_strdup(data);
278 g_assert(lock->locked);
280 g_static_mutex_lock(&lock_lock);
282 /* relase the filesystem-level lock */
285 /* and the hash table entry */
286 if (locally_locked_files) {
287 g_hash_table_remove(locally_locked_files, lock->filename);
290 g_static_mutex_unlock(&lock_lock);
297 lock->locked = FALSE;
309 ** - These are "best effort" routines.
310 ** - "configure" has four variables that are used to determine which type of
312 ** USE_POSIX_FCNTL - use fcntl(). The full job.
313 ** USE_FLOCK - use flock(). Does just as well.
314 ** USE_LOCKF - use lockf(). Only handles advisory, exclusive,
315 ** blocking file locks as used by Amanda.
316 ** USE_LNLOCK - Home brew exclusive, blocking file lock.
317 ** <none> - No locking available. User beware!
320 /* Interface to the implementations in common-src/amflock-*.c */
322 #ifdef WANT_AMFLOCK_POSIX
323 extern amflock_impl_t amflock_posix_impl;
325 #ifdef WANT_AMFLOCK_FLOCK
326 extern amflock_impl_t amflock_flock_impl;
328 #ifdef WANT_AMFLOCK_LOCKF
329 extern amflock_impl_t amflock_lockf_impl;
331 #ifdef WANT_AMFLOCK_LNLOCK
332 extern amflock_impl_t amflock_lnlock_impl;
335 amflock_impl_t *amflock_impls[] = {
336 #ifdef WANT_AMFLOCK_POSIX
339 #ifdef WANT_AMFLOCK_FLOCK
342 #ifdef WANT_AMFLOCK_LOCKF
345 #ifdef WANT_AMFLOCK_LNLOCK
346 &amflock_lnlock_impl,
351 /* Interface functions */
352 /* FIXME: for now, these just use the first non-NULL implementation
355 /* Get a file lock (for read/write files).
362 if (!amflock_impls[0]) return 0; /* no locking */
363 return amflock_impls[0]->amflock_impl(fd, resource);
367 * Get a file lock (for read-only files).
374 if (!amflock_impls[0]) return 0; /* no locking */
375 return amflock_impls[0]->amroflock_impl(fd, resource);
379 * Release a file lock.
386 if (!amflock_impls[0]) return 0; /* no locking */
387 return amflock_impls[0]->amfunlock_impl(fd, resource);