Mercurial > hg > xemacs-beta
comparison src/filelock.c @ 373:6240c7796c7a r21-2b2
Import from CVS: tag r21-2b2
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:04:06 +0200 |
parents | 70ad99077275 |
children | 064ab7fed2e0 |
comparison
equal
deleted
inserted
replaced
372:49e1ed2d7ed8 | 373:6240c7796c7a |
---|---|
1 /* Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994 | 1 /* Copyright (C) 1985, 86, 87, 93, 94, 96 Free Software Foundation, Inc. |
2 Free Software Foundation, Inc. | 2 |
3 | 3 This file is part of GNU Emacs. |
4 This file is part of XEmacs. | 4 |
5 | 5 GNU Emacs is free software; you can redistribute it and/or modify |
6 XEmacs is free software; you can redistribute it and/or modify it | 6 it under the terms of the GNU General Public License as published by |
7 under the terms of the GNU General Public License as published by the | 7 the Free Software Foundation; either version 2, or (at your option) |
8 Free Software Foundation; either version 2, or (at your option) any | 8 any later version. |
9 later version. | 9 |
10 | 10 GNU Emacs is distributed in the hope that it will be useful, |
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT | 11 but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | 13 GNU General Public License for more details. |
14 for more details. | |
15 | 14 |
16 You should have received a copy of the GNU General Public License | 15 You should have received a copy of the GNU General Public License |
17 along with XEmacs; see the file COPYING. If not, write to | 16 along with GNU Emacs; see the file COPYING. If not, write to |
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | 17 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
19 Boston, MA 02111-1307, USA. */ | 18 Boston, MA 02111-1307, USA. */ |
20 | 19 |
21 /* Synched up with: FSF 19.30. */ | 20 /* Synced with FSF 20.2 */ |
22 | 21 |
23 #include <config.h> | 22 #include <config.h> |
24 #include "lisp.h" | 23 #include "lisp.h" |
25 | 24 |
26 #include "buffer.h" | 25 #include "buffer.h" |
29 #include "sysfile.h" | 28 #include "sysfile.h" |
30 #include "sysdir.h" | 29 #include "sysdir.h" |
31 #include "syspwd.h" | 30 #include "syspwd.h" |
32 #include "syssignal.h" /* for kill */ | 31 #include "syssignal.h" /* for kill */ |
33 | 32 |
34 #ifndef CLASH_DETECTION | |
35 #error CLASH_DETECTION is not defined?? | |
36 #endif | |
37 | |
38 /* FSFmacs uses char *lock_dir and char *superlock_file instead of | |
39 the Lisp variables we use. */ | |
40 | |
41 /* The name of the directory in which we keep lock files, with a '/' | |
42 appended. */ | |
43 Lisp_Object Vlock_directory; | |
44 | |
45 #if 0 /* FSFmacs */ | |
46 /* Look in startup.el */ | |
47 /* The name of the file in the lock directory which is used to | |
48 arbitrate access to the entire directory. */ | |
49 #define SUPERLOCK_NAME "!!!SuperLock!!!" | |
50 #endif | |
51 | |
52 /* The name of the superlock file. This is SUPERLOCK_NAME appended to | |
53 Vlock_directory. */ | |
54 Lisp_Object Vsuperlock_file, Vconfigure_superlock_file; | |
55 | |
56 Lisp_Object Qask_user_about_supersession_threat; | 33 Lisp_Object Qask_user_about_supersession_threat; |
57 Lisp_Object Qask_user_about_lock; | 34 Lisp_Object Qask_user_about_lock; |
58 | 35 |
59 static void lock_superlock (CONST char *lfname); | 36 #ifdef CLASH_DETECTION |
60 static int lock_file_1 (CONST char *lfname, int mode); | 37 |
61 static int lock_if_free (CONST char *lfname); | 38 /* The strategy: to lock a file FN, create a symlink .#FN in FN's |
62 static int current_lock_owner (CONST char *); | 39 directory, with link data `user@host.pid'. This avoids a single |
63 static int current_lock_owner_1 (CONST char *); | 40 mount (== failure) point for lock files. |
64 | 41 |
65 /* Set LOCK to the name of the lock file for the filename FILE. | 42 When the host in the lock data is the current host, we can check if |
66 char *LOCK; Lisp_Object FILE; | 43 the pid is valid with kill. |
67 | 44 |
68 MAKE_LOCK_NAME assumes you have already verified that Vlock_directory | 45 Otherwise, we could look at a separate file that maps hostnames to |
69 is a string. */ | 46 reboot times to see if the remote pid can possibly be valid, since we |
70 | 47 don't want Emacs to have to communicate via pipes or sockets or |
71 #ifndef HAVE_LONG_FILE_NAMES | 48 whatever to other processes, either locally or remotely; rms says |
72 | 49 that's too unreliable. Hence the separate file, which could |
73 #define MAKE_LOCK_NAME(lock, file) \ | 50 theoretically be updated by daemons running separately -- but this |
74 (lock = (char *) alloca (14 + XSTRING_LENGTH (Vlock_directory) + 1), \ | 51 whole idea is unimplemented; in practice, at least in our |
75 fill_in_lock_short_file_name (lock, (file))) | 52 environment, it seems such stale locks arise fairly infrequently, and |
53 Emacs' standard methods of dealing with clashes suffice. | |
54 | |
55 We use symlinks instead of normal files because (1) they can be | |
56 stored more efficiently on the filesystem, since the kernel knows | |
57 they will be small, and (2) all the info about the lock can be read | |
58 in a single system call (readlink). Although we could use regular | |
59 files to be useful on old systems lacking symlinks, nowadays | |
60 virtually all such systems are probably single-user anyway, so it | |
61 didn't seem worth the complication. | |
62 | |
63 Similarly, we don't worry about a possible 14-character limit on | |
64 file names, because those are all the same systems that don't have | |
65 symlinks. | |
66 | |
67 This is compatible with the locking scheme used by Interleaf (which | |
68 has contributed this implementation for Emacs), and was designed by | |
69 Ethan Jacobson, Kimbo Mundy, and others. | |
70 | |
71 --karl@cs.umb.edu/karl@hq.ileaf.com. */ | |
72 | |
73 | |
74 /* Here is the structure that stores information about a lock. */ | |
75 | |
76 typedef struct | |
77 { | |
78 char *user; | |
79 char *host; | |
80 unsigned long pid; | |
81 } lock_info_type; | |
82 | |
83 /* When we read the info back, we might need this much more, | |
84 enough for decimal representation plus null. */ | |
85 #define LOCK_PID_MAX (4 * sizeof (unsigned long)) | |
86 | |
87 /* Free the two dynamically-allocated pieces in PTR. */ | |
88 #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) | |
89 | |
90 /* Write the name of the lock file for FN into LFNAME. Length will be | |
91 that of FN plus two more for the leading `.#' plus one for the null. */ | |
92 #define MAKE_LOCK_NAME(lock, file) \ | |
93 (lock = (char *) alloca (XSTRING_LENGTH(file) + 2 + 1), \ | |
94 fill_in_lock_file_name (lock, (file))) | |
76 | 95 |
77 static void | 96 static void |
78 fill_in_lock_short_file_name (REGISTER char *lockfile, REGISTER Lisp_Object fn) | 97 fill_in_lock_file_name (lockfile, fn) |
79 { | 98 register char *lockfile; |
80 REGISTER union | 99 register Lisp_Object fn; |
81 { | 100 { |
82 unsigned int word [2]; | 101 register char *p; |
83 unsigned char byte [8]; | 102 |
84 } crc; | 103 strcpy (lockfile, XSTRING_DATA(fn)); |
85 REGISTER unsigned char *p, new; | 104 |
86 | 105 /* Shift the nondirectory part of the file name (including the null) |
87 CHECK_STRING (Vlock_directory); | 106 right two characters. Here is one of the places where we'd have to |
88 | 107 do something to support 14-character-max file names. */ |
89 /* 7-bytes cyclic code for burst correction on byte-by-byte basis. | 108 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--) |
90 the used polynomial is D^7 + D^6 + D^3 +1. pot@cnuce.cnr.it */ | 109 p[2] = *p; |
91 | 110 |
92 crc.word[0] = crc.word[1] = 0; | 111 /* Insert the `.#'. */ |
93 | 112 p[1] = '.'; |
94 for (p = XSTRING_DATA (fn); new = *p++; ) | 113 p[2] = '#'; |
95 { | 114 } |
96 new += crc.byte[6]; | 115 |
97 crc.byte[6] = crc.byte[5] + new; | 116 /* Lock the lock file named LFNAME. |
98 crc.byte[5] = crc.byte[4]; | 117 If FORCE is nonzero, we do so even if it is already locked. |
99 crc.byte[4] = crc.byte[3]; | 118 Return 1 if successful, 0 if not. */ |
100 crc.byte[3] = crc.byte[2] + new; | 119 |
101 crc.byte[2] = crc.byte[1]; | 120 static int |
102 crc.byte[1] = crc.byte[0]; | 121 lock_file_1 (char *lfname,int force) |
103 crc.byte[0] = new; | 122 { |
104 } | 123 register int err; |
105 | 124 char *user_name; |
106 { | 125 char *host_name; |
107 int need_slash = 0; | 126 char *lock_info_str; |
108 | 127 |
109 /* in case lock-directory doesn't end in / */ | 128 if (STRINGP (Fuser_login_name (Qnil))) |
110 if (XSTRING_BYTE (Vlock_directory, | 129 user_name = (char *)XSTRING_DATA((Fuser_login_name (Qnil))); |
111 XSTRING_LENGTH (Vlock_directory) - 1) != '/') | 130 else |
112 need_slash = 1; | 131 user_name = ""; |
113 | 132 if (STRINGP (Fsystem_name ())) |
114 sprintf (lockfile, "%s%s%.2x%.2x%.2x%.2x%.2x%.2x%.2x", | 133 host_name = (char *)XSTRING_DATA((Fsystem_name ())); |
115 (char *) XSTRING_DATA (Vlock_directory), | 134 else |
116 need_slash ? "/" : "", | 135 host_name = ""; |
117 crc.byte[0], crc.byte[1], crc.byte[2], crc.byte[3], | 136 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name) |
118 crc.byte[4], crc.byte[5], crc.byte[6]); | 137 + LOCK_PID_MAX + 5); |
138 | |
139 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name, | |
140 (unsigned long) getpid ()); | |
141 | |
142 err = symlink (lock_info_str, lfname); | |
143 if (errno == EEXIST && force) | |
144 { | |
145 unlink (lfname); | |
146 err = symlink (lock_info_str, lfname); | |
147 } | |
148 | |
149 return err == 0; | |
150 } | |
151 | |
152 /* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete, | |
153 1 if another process owns it (and set OWNER (if non-null) to info), | |
154 2 if the current process owns it, | |
155 or -1 if something is wrong with the locking mechanism. */ | |
156 | |
157 static int | |
158 current_lock_owner (lock_info_type *owner, char *lfname) | |
159 { | |
160 #ifndef index | |
161 extern char *rindex (), *index (); | |
162 #endif | |
163 int o, p, len, ret; | |
164 int local_owner = 0; | |
165 char *at, *dot; | |
166 char *lfinfo = 0; | |
167 int bufsize = 50; | |
168 /* Read arbitrarily-long contents of symlink. Similar code in | |
169 file-symlink-p in fileio.c. */ | |
170 do | |
171 { | |
172 bufsize *= 2; | |
173 lfinfo = (char *) xrealloc (lfinfo, bufsize); | |
174 len = readlink (lfname, lfinfo, bufsize); | |
175 } | |
176 while (len >= bufsize); | |
177 | |
178 /* If nonexistent lock file, all is well; otherwise, got strange error. */ | |
179 if (len == -1) | |
180 { | |
181 xfree (lfinfo); | |
182 return errno == ENOENT ? 0 : -1; | |
183 } | |
184 | |
185 /* Link info exists, so `len' is its length. Null terminate. */ | |
186 lfinfo[len] = 0; | |
187 | |
188 /* Even if the caller doesn't want the owner info, we still have to | |
189 read it to determine return value, so allocate it. */ | |
190 if (!owner) | |
191 { | |
192 owner = (lock_info_type *) alloca (sizeof (lock_info_type)); | |
193 local_owner = 1; | |
194 } | |
195 | |
196 /* Parse USER@HOST.PID. If can't parse, return -1. */ | |
197 /* The USER is everything before the first @. */ | |
198 at = index (lfinfo, '@'); | |
199 dot = rindex (lfinfo, '.'); | |
200 if (!at || !dot) { | |
201 xfree (lfinfo); | |
202 return -1; | |
119 } | 203 } |
120 } | 204 len = at - lfinfo; |
121 | 205 owner->user = (char *) xmalloc (len + 1); |
122 #else /* defined HAVE_LONG_FILE_NAMES */ | 206 strncpy (owner->user, lfinfo, len); |
123 | 207 owner->user[len] = 0; |
124 /* +2 for terminating null and possible extra slash */ | 208 |
125 #define MAKE_LOCK_NAME(lock, file) \ | 209 /* The PID is everything after the last `.'. */ |
126 (lock = (char *) alloca (XSTRING_LENGTH (file) + \ | 210 owner->pid = atoi (dot + 1); |
127 XSTRING_LENGTH (Vlock_directory) + 2), \ | 211 |
128 fill_in_lock_file_name (lock, (file))) | 212 /* The host is everything in between. */ |
129 | 213 len = dot - at - 1; |
130 static void | 214 owner->host = (char *) xmalloc (len + 1); |
131 fill_in_lock_file_name (REGISTER char *lockfile, REGISTER Lisp_Object fn) | 215 strncpy (owner->host, at + 1, len); |
132 /* fn must be a Lisp_String! */ | 216 owner->host[len] = 0; |
133 { | 217 |
134 REGISTER char *p; | 218 /* We're done looking at the link info. */ |
135 | 219 xfree (lfinfo); |
136 CHECK_STRING (Vlock_directory); | 220 |
137 | 221 /* On current host? */ |
138 strcpy (lockfile, (char *) XSTRING_DATA (Vlock_directory)); | 222 if (STRINGP (Fsystem_name ()) |
139 | 223 && strcmp (owner->host, XSTRING_DATA(Fsystem_name ())) == 0) |
140 p = lockfile + strlen (lockfile); | 224 { |
141 | 225 if (owner->pid == getpid ()) |
142 if (p == lockfile /* lock-directory is empty?? */ | 226 ret = 2; /* We own it. */ |
143 || *(p - 1) != '/') /* in case lock-directory doesn't end in / */ | 227 else if (owner->pid > 0 |
144 { | 228 && (kill (owner->pid, 0) >= 0 || errno == EPERM)) |
145 *p = '/'; | 229 ret = 1; /* An existing process on this machine owns it. */ |
146 p++; | 230 /* The owner process is dead or has a strange pid (<=0), so try to |
147 } | 231 zap the lockfile. */ |
148 | 232 else if (unlink (lfname) < 0) |
149 strcpy (p, (char *) XSTRING_DATA (fn)); | 233 ret = -1; |
150 | 234 else |
151 for (; *p; p++) | 235 ret = 0; |
152 { | 236 } |
153 if (*p == '/') | 237 else |
154 *p = '!'; | 238 { /* If we wanted to support the check for stale locks on remote machines, |
155 } | 239 here's where we'd do it. */ |
156 } | 240 ret = 1; |
157 #endif /* !defined HAVE_LONG_FILE_NAMES */ | 241 } |
158 | 242 |
159 static Lisp_Object | 243 /* Avoid garbage. */ |
160 lock_file_owner_name (CONST char *lfname) | 244 if (local_owner || ret <= 0) |
161 { | 245 { |
162 struct stat s; | 246 FREE_LOCK_INFO (*owner); |
163 struct passwd *the_pw = 0; | 247 } |
164 | 248 return ret; |
165 if (lstat (lfname, &s) == 0) | 249 } |
166 the_pw = getpwuid (s.st_uid); | 250 |
167 return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name)); | 251 /* Lock the lock named LFNAME if possible. |
168 } | 252 Return 0 in that case. |
169 | 253 Return positive if some other process owns the lock, and info about |
170 | 254 that process in CLASHER. |
171 /* lock_file locks file fn, | 255 Return -1 if cannot lock for any other reason. */ |
256 | |
257 static int | |
258 lock_if_free (lock_info_type *clasher, char *lfname) | |
259 { | |
260 if (lock_file_1 (lfname, 0) == 0) | |
261 { | |
262 int locker; | |
263 | |
264 if (errno != EEXIST) | |
265 return -1; | |
266 | |
267 locker = current_lock_owner (clasher, lfname); | |
268 if (locker == 2) | |
269 { | |
270 FREE_LOCK_INFO (*clasher); | |
271 return 0; /* We ourselves locked it. */ | |
272 } | |
273 else if (locker == 1) | |
274 return 1; /* Someone else has it. */ | |
275 | |
276 return -1; /* Something's wrong. */ | |
277 } | |
278 return 0; | |
279 } | |
280 | |
281 /* lock_file locks file FN, | |
172 meaning it serves notice on the world that you intend to edit that file. | 282 meaning it serves notice on the world that you intend to edit that file. |
173 This should be done only when about to modify a file-visiting | 283 This should be done only when about to modify a file-visiting |
174 buffer previously unmodified. | 284 buffer previously unmodified. |
175 Do not (normally) call lock_buffer for a buffer already modified, | 285 Do not (normally) call this for a buffer already modified, |
176 as either the file is already locked, or the user has already | 286 as either the file is already locked, or the user has already |
177 decided to go ahead without locking. | 287 decided to go ahead without locking. |
178 | 288 |
179 When lock_buffer returns, either the lock is locked for us, | 289 When this returns, either the lock is locked for us, |
180 or the user has said to go ahead without locking. | 290 or the user has said to go ahead without locking. |
181 | 291 |
182 If the file is locked by someone else, lock_buffer calls | 292 If the file is locked by someone else, this calls |
183 ask-user-about-lock (a Lisp function) with two arguments, | 293 ask-user-about-lock (a Lisp function) with two arguments, |
184 the file name and the name of the user who did the locking. | 294 the file name and info about the user who did the locking. |
185 This function can signal an error, or return t meaning | 295 This function can signal an error, or return t meaning |
186 take away the lock, or return nil meaning ignore the lock. */ | 296 take away the lock, or return nil meaning ignore the lock. */ |
187 | |
188 /* The lock file name is the file name with "/" replaced by "!" | |
189 and put in the Emacs lock directory. */ | |
190 /* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */ | |
191 | |
192 /* If HAVE_LONG_FILE_NAMES is not defined, the lock file name is the hex | |
193 representation of a 14-bytes CRC generated from the file name | |
194 and put in the Emacs lock directory (not very nice, but it works). | |
195 (ie., /ka/king/junk.tex -> /!/12a82c62f1c6da). */ | |
196 | 297 |
197 void | 298 void |
198 lock_file (Lisp_Object fn) | 299 lock_file (Lisp_Object fn) |
199 { | 300 { |
200 /* This function can GC. */ | 301 /* This function can GC. */ |
201 /* dmoore - and can destroy current_buffer and all sorts of other | 302 /* dmoore - and can destroy current_buffer and all sorts of other |
202 mean nasty things with pointy teeth. If you call this make sure | 303 mean nasty things with pointy teeth. If you call this make sure |
203 you protect things right. */ | 304 you protect things right. */ |
204 | 305 /* Somebody updated the code in this function and removed the previous |
205 REGISTER Lisp_Object attack, orig_fn; | 306 comment. -slb */ |
206 REGISTER char *lfname; | 307 |
207 struct gcpro gcpro1, gcpro2; | 308 register Lisp_Object attack, orig_fn; |
208 Lisp_Object subject_buf = Qnil; | 309 register char *lfname, *locker; |
209 | 310 lock_info_type lock_info; |
210 if (NILP (Vlock_directory) || NILP (Vsuperlock_file)) | 311 struct gcpro gcpro1,gcpro2; |
211 return; | 312 Lisp_Object subject_buf; |
212 CHECK_STRING (fn); | |
213 CHECK_STRING (Vlock_directory); | |
214 | 313 |
215 GCPRO2 (fn, subject_buf); | 314 GCPRO2 (fn, subject_buf); |
216 orig_fn = fn; | 315 orig_fn = fn; |
217 fn = Fexpand_file_name (fn, Qnil); | 316 fn = Fexpand_file_name (fn, Qnil); |
218 | 317 |
219 /* Create the name of the lock-file for file fn */ | 318 /* Create the name of the lock-file for file fn */ |
220 MAKE_LOCK_NAME (lfname, fn); | 319 MAKE_LOCK_NAME (lfname, fn); |
221 | 320 |
222 /* See if this file is visited and has changed on disk since it was | 321 /* See if this file is visited and has changed on disk since it was |
223 visited. */ | 322 visited. */ |
224 subject_buf = Fget_file_buffer (fn); | 323 { |
225 if (!NILP (subject_buf) | 324 subject_buf = get_truename_buffer (orig_fn); |
226 && NILP (Fverify_visited_file_modtime (subject_buf)) | 325 if (!NILP (subject_buf) |
227 && !NILP (Ffile_exists_p (fn))) | 326 && NILP (Fverify_visited_file_modtime (subject_buf)) |
228 call1_in_buffer (XBUFFER (subject_buf), | 327 && !NILP (Ffile_exists_p (fn))) |
229 Qask_user_about_supersession_threat, fn); | 328 call1_in_buffer (XBUFFER(subject_buf), |
329 Qask_user_about_supersession_threat, fn); | |
330 } | |
230 | 331 |
231 /* Try to lock the lock. */ | 332 /* Try to lock the lock. */ |
232 if (lock_if_free (lfname) <= 0) | 333 if (lock_if_free (&lock_info, lfname) <= 0) |
233 /* Return now if we have locked it, or if lock dir does not exist */ | 334 /* Return now if we have locked it, or if lock creation failed */ |
234 goto done; | 335 goto done; |
235 | 336 |
236 /* Else consider breaking the lock */ | 337 /* Else consider breaking the lock */ |
338 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host) | |
339 + LOCK_PID_MAX + 9); | |
340 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host, | |
341 lock_info.pid); | |
342 FREE_LOCK_INFO (lock_info); | |
343 | |
237 attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) : | 344 attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) : |
238 current_buffer, Qask_user_about_lock, fn, | 345 current_buffer, Qask_user_about_lock , fn, |
239 lock_file_owner_name (lfname)); | 346 build_string (locker)); |
240 if (!NILP (attack)) | 347 if (!NILP (attack)) |
241 /* User says take the lock */ | 348 /* User says take the lock */ |
242 { | 349 { |
243 CHECK_STRING (Vsuperlock_file); | 350 lock_file_1 (lfname, 1); |
244 lock_superlock (lfname); | |
245 lock_file_1 (lfname, O_WRONLY); | |
246 unlink ((char *) XSTRING_DATA (Vsuperlock_file)); | |
247 goto done; | 351 goto done; |
248 } | 352 } |
249 /* User says ignore the lock */ | 353 /* User says ignore the lock */ |
250 done: | 354 done: |
251 UNGCPRO; | 355 UNGCPRO; |
252 } | 356 } |
253 | 357 |
254 | |
255 /* Lock the lock file named LFNAME. | |
256 If MODE is O_WRONLY, we do so even if it is already locked. | |
257 If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free. | |
258 Return 1 if successful, 0 if not. */ | |
259 | |
260 static int | |
261 lock_file_1 (CONST char *lfname, int mode) | |
262 { | |
263 REGISTER int fd; | |
264 char buf[20]; | |
265 | |
266 if ((fd = open (lfname, mode, 0666)) >= 0) | |
267 { | |
268 #if defined(WINDOWSNT) | |
269 chmod(lfname, _S_IREAD|_S_IWRITE); | |
270 #elif defined(USG) | |
271 chmod (lfname, 0666); | |
272 #else | |
273 fchmod (fd, 0666); | |
274 #endif | |
275 sprintf (buf, "%ld ", (long) getpid ()); | |
276 write (fd, buf, strlen (buf)); | |
277 close (fd); | |
278 return 1; | |
279 } | |
280 else | |
281 return 0; | |
282 } | |
283 | |
284 /* Lock the lock named LFNAME if possible. | |
285 Return 0 in that case. | |
286 Return positive if lock is really locked by someone else. | |
287 Return -1 if cannot lock for any other reason. */ | |
288 | |
289 static int | |
290 lock_if_free (CONST char *lfname) | |
291 { | |
292 REGISTER int clasher; | |
293 | |
294 while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0) | |
295 { | |
296 if (errno != EEXIST) | |
297 return -1; | |
298 clasher = current_lock_owner (lfname); | |
299 if (clasher != 0) | |
300 if (clasher != getpid ()) | |
301 return (clasher); | |
302 else return (0); | |
303 /* Try again to lock it */ | |
304 } | |
305 return 0; | |
306 } | |
307 | |
308 /* Return the pid of the process that claims to own the lock file LFNAME, | |
309 or 0 if nobody does or the lock is obsolete, | |
310 or -1 if something is wrong with the locking mechanism. */ | |
311 | |
312 static int | |
313 current_lock_owner (CONST char *lfname) | |
314 { | |
315 int owner = current_lock_owner_1 (lfname); | |
316 if (owner == 0 && errno == ENOENT) | |
317 return (0); | |
318 /* Is it locked by a process that exists? */ | |
319 if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM)) | |
320 return (owner); | |
321 if (unlink (lfname) < 0) | |
322 return (-1); | |
323 return (0); | |
324 } | |
325 | |
326 static int | |
327 current_lock_owner_1 (CONST char *lfname) | |
328 { | |
329 REGISTER int fd; | |
330 char buf[20]; | |
331 int tem; | |
332 | |
333 fd = open (lfname, O_RDONLY, 0666); | |
334 if (fd < 0) | |
335 return 0; | |
336 tem = read (fd, buf, sizeof buf); | |
337 close (fd); | |
338 return (tem <= 0 ? 0 : atoi (buf)); | |
339 } | |
340 | |
341 | |
342 void | 358 void |
343 unlock_file (Lisp_Object fn) | 359 unlock_file (Lisp_Object fn) |
344 { | 360 { |
345 /* This function can GC. */ | 361 register char *lfname; |
346 /* dmoore - and can destroy current_buffer and all sorts of other | |
347 mean nasty things with pointy teeth. If you call this make sure | |
348 you protect things right. */ | |
349 | |
350 REGISTER char *lfname; | |
351 if (NILP (Vlock_directory) || NILP (Vsuperlock_file)) return; | |
352 CHECK_STRING (fn); | |
353 CHECK_STRING (Vlock_directory); | |
354 CHECK_STRING (Vsuperlock_file); | |
355 | 362 |
356 fn = Fexpand_file_name (fn, Qnil); | 363 fn = Fexpand_file_name (fn, Qnil); |
357 | 364 |
358 MAKE_LOCK_NAME (lfname, fn); | 365 MAKE_LOCK_NAME (lfname, fn); |
359 | 366 |
360 lock_superlock (lfname); | 367 if (current_lock_owner (0, lfname) == 2) |
361 | |
362 if (current_lock_owner_1 (lfname) == getpid ()) | |
363 unlink (lfname); | 368 unlink (lfname); |
364 | |
365 unlink ((char *) XSTRING_DATA (Vsuperlock_file)); | |
366 } | |
367 | |
368 static void | |
369 lock_superlock (CONST char *lfname) | |
370 { | |
371 REGISTER int i, fd; | |
372 DIR *lockdir; | |
373 | |
374 for (i = -20; i < 0 && | |
375 (fd = open ((char *) XSTRING_DATA (Vsuperlock_file), | |
376 O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0; | |
377 i++) | |
378 { | |
379 if (errno != EEXIST) | |
380 return; | |
381 | |
382 /* This seems to be necessary to prevent Emacs from hanging when the | |
383 competing process has already deleted the superlock, but it's still | |
384 in the NFS cache. So we force NFS to synchronize the cache. */ | |
385 lockdir = opendir ((char *) XSTRING_DATA (Vlock_directory)); | |
386 if (lockdir) | |
387 closedir (lockdir); | |
388 | |
389 emacs_sleep (1); | |
390 } | |
391 if (fd >= 0) | |
392 { | |
393 #if defined(WINDOWSNT) | |
394 chmod(lfname, _S_IREAD|_S_IWRITE); | |
395 #elif defined(USG) | |
396 chmod ((char *) XSTRING_DATA (Vsuperlock_file), 0666); | |
397 #else | |
398 fchmod (fd, 0666); | |
399 #endif | |
400 write (fd, lfname, strlen (lfname)); | |
401 close (fd); | |
402 } | |
403 } | 369 } |
404 | 370 |
405 void | 371 void |
406 unlock_all_files (void) | 372 unlock_all_files () |
407 { | 373 { |
408 /* This function can GC. */ | 374 register Lisp_Object tail; |
409 | 375 register struct buffer *b; |
410 Lisp_Object tail; | 376 |
411 REGISTER struct buffer *b; | 377 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail)) |
412 struct gcpro gcpro1; | |
413 | |
414 GCPRO1 (tail); | |
415 for (tail = Vbuffer_alist; GC_CONSP (tail); | |
416 tail = XCDR (tail)) | |
417 { | 378 { |
418 b = XBUFFER (XCDR (XCAR (tail))); | 379 b = XBUFFER (XCDR (XCAR (tail))); |
419 if (STRINGP (b->file_truename) && | 380 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) |
420 BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) | |
421 unlock_file (b->file_truename); | 381 unlock_file (b->file_truename); |
422 } | 382 } |
423 UNGCPRO; | 383 } |
424 } | |
425 | |
426 | 384 |
427 DEFUN ("lock-buffer", Flock_buffer, 0, 1, 0, /* | 385 DEFUN ("lock-buffer", Flock_buffer, 0, 1, 0, /* |
428 Lock FILE, if current buffer is modified. | 386 Lock FILE, if current buffer is modified.\n\ |
429 FILE defaults to current buffer's visited file, | 387 FILE defaults to current buffer's visited file,\n\ |
430 or else nothing is done if current buffer isn't visiting a file. | 388 or else nothing is done if current buffer isn't visiting a file. |
431 */ | 389 */ |
432 (fn)) | 390 (file)) |
433 { | 391 { |
434 /* This function can GC */ | 392 if (NILP (file)) |
435 /* dmoore - and can destroy current_buffer and all sorts of other | 393 file = current_buffer->file_truename; |
436 mean nasty things with pointy teeth. If you call this make sure | 394 CHECK_STRING (file); |
437 you protect things right. */ | |
438 | |
439 if (NILP (fn)) | |
440 fn = current_buffer->file_truename; | |
441 CHECK_STRING (fn); | |
442 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer) | 395 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer) |
443 && !NILP (fn)) | 396 && !NILP (file)) |
444 lock_file (fn); | 397 lock_file (file); |
445 return Qnil; | 398 return Qnil; |
446 } | 399 } |
447 | 400 |
448 DEFUN ("unlock-buffer", Funlock_buffer, 0, 0, 0, /* | 401 DEFUN ("unlock-buffer", Funlock_buffer, 0, 0, 0, /* |
449 Unlock the file visited in the current buffer, | 402 Unlock the file visited in the current buffer, |
460 && STRINGP (current_buffer->file_truename)) | 413 && STRINGP (current_buffer->file_truename)) |
461 unlock_file (current_buffer->file_truename); | 414 unlock_file (current_buffer->file_truename); |
462 return Qnil; | 415 return Qnil; |
463 } | 416 } |
464 | 417 |
465 | |
466 /* Unlock the file visited in buffer BUFFER. */ | 418 /* Unlock the file visited in buffer BUFFER. */ |
419 | |
467 | 420 |
468 void | 421 void |
469 unlock_buffer (struct buffer *buffer) | 422 unlock_buffer (struct buffer *buffer) |
470 { | 423 { |
471 /* This function can GC */ | 424 /* This function can GC */ |
476 && STRINGP (buffer->file_truename)) | 429 && STRINGP (buffer->file_truename)) |
477 unlock_file (buffer->file_truename); | 430 unlock_file (buffer->file_truename); |
478 } | 431 } |
479 | 432 |
480 DEFUN ("file-locked-p", Ffile_locked_p, 0, 1, 0, /* | 433 DEFUN ("file-locked-p", Ffile_locked_p, 0, 1, 0, /* |
481 Return nil if the FILENAME is not locked, | 434 Return nil if the FILENAME is not locked,\n\ |
482 t if it is locked by you, else a string of the name of the locker. | 435 t if it is locked by you, else a string of the name of the locker. |
483 */ | 436 */ |
484 (fn)) | 437 (filename)) |
485 { | 438 { |
486 /* This function can GC */ | 439 Lisp_Object ret; |
487 REGISTER char *lfname; | 440 register char *lfname; |
488 int owner; | 441 int owner; |
489 | 442 lock_info_type locker; |
490 if (NILP (Vlock_directory) || NILP (Vsuperlock_file)) | 443 |
491 return Qnil; | 444 filename = Fexpand_file_name (filename, Qnil); |
492 CHECK_STRING (Vlock_directory); | 445 |
493 | 446 MAKE_LOCK_NAME (lfname, filename); |
494 fn = Fexpand_file_name (fn, Qnil); | 447 |
495 | 448 owner = current_lock_owner (&locker, lfname); |
496 MAKE_LOCK_NAME (lfname, fn); | |
497 | |
498 owner = current_lock_owner (lfname); | |
499 if (owner <= 0) | 449 if (owner <= 0) |
500 return Qnil; | 450 ret = Qnil; |
501 else if (owner == getpid ()) | 451 else if (owner == 2) |
502 return Qt; | 452 ret = Qt; |
503 | 453 else |
504 return lock_file_owner_name (lfname); | 454 ret = build_string (locker.user); |
505 } | 455 |
456 if (owner > 0) | |
457 FREE_LOCK_INFO (locker); | |
458 | |
459 return ret; | |
460 } | |
461 | |
462 | |
463 /* Initialization functions. */ | |
506 | 464 |
507 void | 465 void |
508 syms_of_filelock (void) | 466 syms_of_filelock (void) |
509 { | 467 { |
510 /* This function can GC */ | 468 /* This function can GC */ |
515 defsymbol (&Qask_user_about_supersession_threat, | 473 defsymbol (&Qask_user_about_supersession_threat, |
516 "ask-user-about-supersession-threat"); | 474 "ask-user-about-supersession-threat"); |
517 defsymbol (&Qask_user_about_lock, "ask-user-about-lock"); | 475 defsymbol (&Qask_user_about_lock, "ask-user-about-lock"); |
518 } | 476 } |
519 | 477 |
520 void | 478 |
521 vars_of_filelock (void) | 479 #endif /* CLASH_DETECTION */ |
522 { | |
523 DEFVAR_LISP ("lock-directory", &Vlock_directory /* | |
524 Don't change this | |
525 */ ); | |
526 Vlock_directory = Qnil; | |
527 DEFVAR_LISP ("superlock-file", &Vsuperlock_file /* | |
528 Don't change this | |
529 */ ); | |
530 Vsuperlock_file = Qnil; | |
531 } | |
532 | |
533 void | |
534 complex_vars_of_filelock (void) | |
535 { | |
536 DEFVAR_LISP ("configure-superlock-file", &Vconfigure_superlock_file /* | |
537 For internal use by the build procedure only. | |
538 configure's idea of what SUPERLOCK-FILE will be. | |
539 */ ); | |
540 #ifdef PATH_SUPERLOCK | |
541 Vconfigure_superlock_file = build_string (PATH_SUPERLOCK); | |
542 #else | |
543 Vconfigure_superlock_file = Qnil; | |
544 #endif | |
545 /* All the rest done dynamically by startup.el */ | |
546 } |