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;
46 file_lock *lock = g_new0(file_lock, 1);
47 lock->filename = g_strdup(filename);
57 g_static_mutex_lock(&lock_lock);
58 if (locally_locked_files) {
59 g_hash_table_remove(locally_locked_files,
66 g_free(lock->filename);
71 g_static_mutex_unlock(&lock_lock);
81 struct flock lock_buf;
84 g_assert(!lock->locked);
86 /* protect from overlapping lock operations within a process */
87 g_static_mutex_lock(&lock_lock);
88 if (!locally_locked_files) {
89 locally_locked_files = g_hash_table_new(g_str_hash, g_str_equal);
92 /* if this filename is in the hash table, then some other thread in this
93 * process has locked it */
94 if (g_hash_table_lookup(locally_locked_files, lock->filename)) {
99 /* The locks are advisory, so an error here never means the lock is already
101 lock->fd = fd = open(lock->filename, O_CREAT|O_RDWR, 0666);
107 /* now try locking it */
108 lock_buf.l_type = F_WRLCK;
109 lock_buf.l_start = 0;
110 lock_buf.l_whence = SEEK_SET;
111 lock_buf.l_len = 0; /* to EOF */
112 if (fcntl(fd, F_SETLK, &lock_buf) < 0) {
113 if (errno == EACCES || errno == EAGAIN)
120 /* and read the file in its entirety */
121 if (fstat(fd, &stat_buf) < 0) {
126 if (!(stat_buf.st_mode & S_IFREG)) {
132 if (stat_buf.st_size) {
133 lock->data = g_malloc(stat_buf.st_size);
134 lock->len = stat_buf.st_size;
135 if (full_read(fd, lock->data, lock->len) < lock->len) {
141 fd = -1; /* we'll keep the file now */
144 /* the lock is acquired; record this in the hash table */
145 g_hash_table_insert(locally_locked_files, lock->filename, lock->filename);
151 g_static_mutex_unlock(&lock_lock);
152 if (fd >= 0) /* close and unlock if an error occurred */
166 g_assert(lock->locked);
168 /* seek to position 0, rewrite, and truncate */
169 if (lseek(fd, 0, SEEK_SET) < 0)
172 /* from here on out, any errors have corrupted the datafile.. */
173 if (full_write(fd, data, len) < len)
176 if (lock->len > len) {
177 if (ftruncate(fd, len) < 0)
183 lock->data = g_strdup(data);
193 g_assert(lock->locked);
195 g_static_mutex_lock(&lock_lock);
197 /* relase the filesystem-level lock */
200 /* and the hash table entry */
201 g_hash_table_remove(locally_locked_files, lock->filename);
203 g_static_mutex_unlock(&lock_lock);
210 lock->locked = FALSE;
222 ** - These are "best effort" routines.
223 ** - "configure" has four variables that are used to determine which type of
225 ** USE_POSIX_FCNTL - use fcntl(). The full job.
226 ** USE_FLOCK - use flock(). Does just as well.
227 ** USE_LOCKF - use lockf(). Only handles advisory, exclusive,
228 ** blocking file locks as used by Amanda.
229 ** USE_LNLOCK - Home brew exclusive, blocking file lock.
230 ** <none> - No locking available. User beware!
233 /* Interface to the implementations in common-src/amflock-*.c */
235 #ifdef WANT_AMFLOCK_POSIX
236 extern amflock_impl_t amflock_posix_impl;
238 #ifdef WANT_AMFLOCK_FLOCK
239 extern amflock_impl_t amflock_flock_impl;
241 #ifdef WANT_AMFLOCK_LOCKF
242 extern amflock_impl_t amflock_lockf_impl;
244 #ifdef WANT_AMFLOCK_LNLOCK
245 extern amflock_impl_t amflock_lnlock_impl;
248 amflock_impl_t *amflock_impls[] = {
249 #ifdef WANT_AMFLOCK_POSIX
252 #ifdef WANT_AMFLOCK_FLOCK
255 #ifdef WANT_AMFLOCK_LOCKF
258 #ifdef WANT_AMFLOCK_LNLOCK
259 &amflock_lnlock_impl,
264 /* Interface functions */
265 /* FIXME: for now, these just use the first non-NULL implementation
268 /* Get a file lock (for read/write files).
275 if (!amflock_impls[0]) return 0; /* no locking */
276 return amflock_impls[0]->amflock_impl(fd, resource);
280 * Get a file lock (for read-only files).
287 if (!amflock_impls[0]) return 0; /* no locking */
288 return amflock_impls[0]->amroflock_impl(fd, resource);
292 * Release a file lock.
299 if (!amflock_impls[0]) return 0; /* no locking */
300 return amflock_impls[0]->amfunlock_impl(fd, resource);