1 /* lock.c - Implement basic file locking for GDBM. */
2
3 /* This file is part of GDBM, the GNU data base manager.
4 Copyright (C) 2008-2021 Free Software Foundation, Inc.
5
6 GDBM is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 GDBM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GDBM. If not, see <http://www.gnu.org/licenses/>. */
18
19 /* Include system configuration before all else. */
20 #include "autoconf.h"
21
22 #include "gdbmdefs.h"
23
24 #include <errno.h>
25
26 #if HAVE_FLOCK
27 # ifndef LOCK_SH
28 # define LOCK_SH 1
29 # endif
30
31 # ifndef LOCK_EX
32 # define LOCK_EX 2
33 # endif
34
35 # ifndef LOCK_NB
36 # define LOCK_NB 4
37 # endif
38
39 # ifndef LOCK_UN
40 # define LOCK_UN 8
41 # endif
42 #endif
43
44 #if defined(F_SETLK) && defined(F_RDLCK) && defined(F_WRLCK)
45 # define HAVE_FCNTL_LOCK 1
46 #else
47 # define HAVE_FCNTL_LOCK 0
48 #endif
49
50 #if 0
51 int
52 gdbm_locked (GDBM_FILE dbf)
53 {
54 return (dbf->lock_type != LOCKING_NONE);
55 }
56 #endif
57
58 void
_gdbm_unlock_file(GDBM_FILE dbf)59 _gdbm_unlock_file (GDBM_FILE dbf)
60 {
61 #if HAVE_FCNTL_LOCK
62 struct flock fl;
63 #endif
64
65 switch (dbf->lock_type)
66 {
67 case LOCKING_FLOCK:
68 #if HAVE_FLOCK
69 flock (dbf->desc, LOCK_UN);
70 #endif
71 break;
72
73 case LOCKING_LOCKF:
74 #if HAVE_LOCKF
75 lockf (dbf->desc, F_ULOCK, (off_t)0L);
76 #endif
77 break;
78
79 case LOCKING_FCNTL:
80 #if HAVE_FCNTL_LOCK
81 fl.l_type = F_UNLCK;
82 fl.l_whence = SEEK_SET;
83 fl.l_start = fl.l_len = (off_t)0L;
84 fcntl (dbf->desc, F_SETLK, &fl);
85 #endif
86 break;
87
88 case LOCKING_NONE:
89 break;
90 }
91
92 dbf->lock_type = LOCKING_NONE;
93 }
94
95 /* Try each supported locking mechanism. */
96 int
_gdbm_lock_file(GDBM_FILE dbf)97 _gdbm_lock_file (GDBM_FILE dbf)
98 {
99 #if HAVE_FCNTL_LOCK
100 struct flock fl;
101 #endif
102 int lock_val = -1;
103
104 #if HAVE_FLOCK
105 if (dbf->read_write == GDBM_READER)
106 lock_val = flock (dbf->desc, LOCK_SH + LOCK_NB);
107 else
108 lock_val = flock (dbf->desc, LOCK_EX + LOCK_NB);
109
110 if ((lock_val == -1) && (errno == EWOULDBLOCK))
111 {
112 dbf->lock_type = LOCKING_NONE;
113 return lock_val;
114 }
115 else if (lock_val != -1)
116 {
117 dbf->lock_type = LOCKING_FLOCK;
118 return lock_val;
119 }
120 #endif
121
122 #if HAVE_LOCKF
123 /* Mask doesn't matter for lockf. */
124 lock_val = lockf (dbf->desc, F_LOCK, (off_t)0L);
125 if ((lock_val == -1) && (errno == EDEADLK))
126 {
127 dbf->lock_type = LOCKING_NONE;
128 return lock_val;
129 }
130 else if (lock_val != -1)
131 {
132 dbf->lock_type = LOCKING_LOCKF;
133 return lock_val;
134 }
135 #endif
136
137 #if HAVE_FCNTL_LOCK
138 /* If we're still here, try fcntl. */
139 if (dbf->read_write == GDBM_READER)
140 fl.l_type = F_RDLCK;
141 else
142 fl.l_type = F_WRLCK;
143 fl.l_whence = SEEK_SET;
144 fl.l_start = fl.l_len = (off_t)0L;
145 lock_val = fcntl (dbf->desc, F_SETLK, &fl);
146
147 if (lock_val != -1)
148 dbf->lock_type = LOCKING_FCNTL;
149 #endif
150
151 if (lock_val == -1)
152 dbf->lock_type = LOCKING_NONE;
153 return lock_val;
154 }
155