2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: amflock.c 7161 2007-07-03 16:27:26Z dustin $
30 * file locking routines, put here to hide the system dependant stuff
31 * from the rest of the code
40 #if (GLIB_MAJOR_VERSION > 2 || (GLIB_MAJOR_VERSION == 2 && GLIB_MINOR_VERSION >= 31))
41 # pragma GCC diagnostic push
42 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
43 static GStaticMutex lock_lock = G_STATIC_MUTEX_INIT;
44 # pragma GCC diagnostic pop
46 static GStaticMutex lock_lock = G_STATIC_MUTEX_INIT;
48 static GHashTable *locally_locked_files = NULL;
49 static int lock_rw_rd(file_lock *lock, short l_type);
55 file_lock *lock = g_new0(file_lock, 1);
56 lock->filename = g_strdup(filename);
66 g_static_mutex_lock(&lock_lock);
67 if (locally_locked_files) {
68 g_hash_table_remove(locally_locked_files,
75 g_free(lock->filename);
80 g_static_mutex_unlock(&lock_lock);
90 struct flock lock_buf;
93 g_assert(!lock->locked);
95 /* protect from overlapping lock operations within a process */
96 g_static_mutex_lock(&lock_lock);
97 if (!locally_locked_files) {
98 locally_locked_files = g_hash_table_new(g_str_hash, g_str_equal);
101 /* if this filename is in the hash table, then some other thread in this
102 * process has locked it */
103 if (g_hash_table_lookup(locally_locked_files, lock->filename)) {
108 /* The locks are advisory, so an error here never means the lock is already
110 lock->fd = fd = open(lock->filename, O_CREAT|O_RDWR, 0666);
116 /* now try locking it */
117 lock_buf.l_type = F_WRLCK;
118 lock_buf.l_start = 0;
119 lock_buf.l_whence = SEEK_SET;
120 lock_buf.l_len = 0; /* to EOF */
121 if (fcntl(fd, F_SETLK, &lock_buf) < 0) {
122 if (errno == EACCES || errno == EAGAIN)
129 /* and read the file in its entirety */
130 if (fstat(fd, &stat_buf) < 0) {
135 if (!(stat_buf.st_mode & S_IFREG)) {
141 if (stat_buf.st_size) {
142 lock->data = g_malloc(stat_buf.st_size);
143 lock->len = stat_buf.st_size;
144 if (full_read(fd, lock->data, lock->len) < lock->len) {
150 fd = -1; /* we'll keep the file now */
153 /* the lock is acquired; record this in the hash table */
154 g_hash_table_insert(locally_locked_files, lock->filename, lock->filename);
160 g_static_mutex_unlock(&lock_lock);
161 if (fd >= 0) /* close and unlock if an error occurred */
175 struct flock lock_buf;
176 struct stat stat_buf;
178 g_assert(!lock->locked);
180 /* protect from overlapping lock operations within a process */
181 g_static_mutex_lock(&lock_lock);
183 /* The locks are advisory, so an error here never means the lock is already
185 lock->fd = fd = open(lock->filename, O_CREAT|O_RDWR, 0666);
191 /* now try locking it */
192 lock_buf.l_type = l_type;
193 lock_buf.l_start = 0;
194 lock_buf.l_whence = SEEK_SET;
195 lock_buf.l_len = 0; /* to EOF */
196 if (fcntl(fd, F_SETLK, &lock_buf) < 0) {
197 if (errno == EACCES || errno == EAGAIN)
204 /* and read the file in its entirety */
205 if (fstat(fd, &stat_buf) < 0) {
210 if (!(stat_buf.st_mode & S_IFREG)) {
216 fd = -1; /* we'll keep the file now */
223 g_static_mutex_unlock(&lock_lock);
224 if (fd >= 0) /* close and unlock if an error occurred */
234 return lock_rw_rd(lock, F_WRLCK);
241 return lock_rw_rd(lock, F_RDLCK);
259 g_assert(lock->locked);
261 /* seek to position 0, rewrite, and truncate */
262 if (lseek(fd, 0, SEEK_SET) < 0)
265 /* from here on out, any errors have corrupted the datafile.. */
266 if (full_write(fd, data, len) < len)
269 if (lock->len > len) {
270 if (ftruncate(fd, len) < 0)
276 lock->data = g_strdup(data);
286 g_assert(lock->locked);
288 g_static_mutex_lock(&lock_lock);
290 /* relase the filesystem-level lock */
293 /* and the hash table entry */
294 if (locally_locked_files) {
295 g_hash_table_remove(locally_locked_files, lock->filename);
298 g_static_mutex_unlock(&lock_lock);
305 lock->locked = FALSE;
317 ** - These are "best effort" routines.
318 ** - "configure" has four variables that are used to determine which type of
320 ** USE_POSIX_FCNTL - use fcntl(). The full job.
321 ** USE_FLOCK - use flock(). Does just as well.
322 ** USE_LOCKF - use lockf(). Only handles advisory, exclusive,
323 ** blocking file locks as used by Amanda.
324 ** USE_LNLOCK - Home brew exclusive, blocking file lock.
325 ** <none> - No locking available. User beware!
328 /* Interface to the implementations in common-src/amflock-*.c */
330 #ifdef WANT_AMFLOCK_POSIX
331 extern amflock_impl_t amflock_posix_impl;
333 #ifdef WANT_AMFLOCK_FLOCK
334 extern amflock_impl_t amflock_flock_impl;
336 #ifdef WANT_AMFLOCK_LOCKF
337 extern amflock_impl_t amflock_lockf_impl;
339 #ifdef WANT_AMFLOCK_LNLOCK
340 extern amflock_impl_t amflock_lnlock_impl;
343 amflock_impl_t *amflock_impls[] = {
344 #ifdef WANT_AMFLOCK_POSIX
347 #ifdef WANT_AMFLOCK_FLOCK
350 #ifdef WANT_AMFLOCK_LOCKF
353 #ifdef WANT_AMFLOCK_LNLOCK
354 &amflock_lnlock_impl,
359 /* Interface functions */
360 /* FIXME: for now, these just use the first non-NULL implementation
363 /* Get a file lock (for read/write files).
370 if (!amflock_impls[0]) return 0; /* no locking */
371 return amflock_impls[0]->amflock_impl(fd, resource);
375 * Get a file lock (for read-only files).
382 if (!amflock_impls[0]) return 0; /* no locking */
383 return amflock_impls[0]->amroflock_impl(fd, resource);
387 * Release a file lock.
394 if (!amflock_impls[0]) return 0; /* no locking */
395 return amflock_impls[0]->amfunlock_impl(fd, resource);