comparison src/filelock.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children ac2d302a0011
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
1 /* Copyright (C) 1985, 1986, 1987, 1992, 1993, 1994
2 Free Software Foundation, Inc.
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Synched up with: FSF 19.30. */
22
23 #include <config.h>
24 #include "lisp.h"
25
26 #include "buffer.h"
27 #include "paths.h"
28
29 #include "sysfile.h"
30 #include "sysdir.h"
31 #include "syspwd.h"
32 #include "syssignal.h" /* for kill */
33
34
35 #ifdef CLASH_DETECTION
36
37 /* FSFmacs uses char *lock_dir and char *superlock_file instead of
38 the Lisp variables we use. */
39
40 /* The name of the directory in which we keep lock files, with a '/'
41 appended. */
42 Lisp_Object Vlock_directory;
43
44 #if 0 /* FSFmacs */
45 /* Look in startup.el */
46 /* The name of the file in the lock directory which is used to
47 arbitrate access to the entire directory. */
48 #define SUPERLOCK_NAME "!!!SuperLock!!!"
49 #endif
50
51 /* The name of the superlock file. This is SUPERLOCK_NAME appended to
52 Vlock_directory. */
53 Lisp_Object Vsuperlock_file;
54
55 Lisp_Object Qask_user_about_supersession_threat;
56 Lisp_Object Qask_user_about_lock;
57
58 static void lock_superlock (CONST char *lfname);
59 static int lock_file_1 (CONST char *lfname, int mode);
60 static int lock_if_free (CONST char *lfname);
61 static int current_lock_owner (CONST char *);
62 static int current_lock_owner_1 (CONST char *);
63
64 /* Set LOCK to the name of the lock file for the filename FILE.
65 char *LOCK; Lisp_Object FILE;
66
67 MAKE_LOCK_NAME assumes you have already verified that Vlock_directory
68 is a string. */
69
70 #ifndef HAVE_LONG_FILE_NAMES
71
72 #define MAKE_LOCK_NAME(lock, file) \
73 (lock = (char *) alloca (14 + string_length (XSTRING (Vlock_directory)) + \
74 1), \
75 fill_in_lock_short_file_name (lock, (file)))
76
77 static void
78 fill_in_lock_short_file_name (REGISTER char *lockfile, REGISTER Lisp_Object fn)
79 {
80 REGISTER union
81 {
82 unsigned int word [2];
83 unsigned char byte [8];
84 } crc;
85 REGISTER unsigned char *p, new;
86
87 CHECK_STRING (Vlock_directory);
88
89 /* 7-bytes cyclic code for burst correction on byte-by-byte basis.
90 the used polynomial is D^7 + D^6 + D^3 +1. pot@cnuce.cnr.it */
91
92 crc.word[0] = crc.word[1] = 0;
93
94 for (p = string_data (XSTRING (fn)); new = *p++; )
95 {
96 new += crc.byte[6];
97 crc.byte[6] = crc.byte[5] + new;
98 crc.byte[5] = crc.byte[4];
99 crc.byte[4] = crc.byte[3];
100 crc.byte[3] = crc.byte[2] + new;
101 crc.byte[2] = crc.byte[1];
102 crc.byte[1] = crc.byte[0];
103 crc.byte[0] = new;
104 }
105
106 {
107 int need_slash = 0;
108
109 /* in case lock-directory doesn't end in / */
110 if (string_byte (XSTRING (Vlock_directory),
111 string_length (XSTRING (Vlock_directory)) - 1) != '/')
112 need_slash = 1;
113
114 sprintf (lockfile, "%s%s%.2x%.2x%.2x%.2x%.2x%.2x%.2x",
115 (char *) string_data (XSTRING (Vlock_directory)),
116 need_slash ? "/" : "",
117 crc.byte[0], crc.byte[1], crc.byte[2], crc.byte[3],
118 crc.byte[4], crc.byte[5], crc.byte[6]);
119 }
120 }
121
122 #else /* defined HAVE_LONG_FILE_NAMES */
123
124 /* +2 for terminating null and possible extra slash */
125 #define MAKE_LOCK_NAME(lock, file) \
126 (lock = (char *) alloca (string_length (XSTRING (file)) + \
127 string_length (XSTRING (Vlock_directory)) + 2), \
128 fill_in_lock_file_name (lock, (file)))
129
130 static void
131 fill_in_lock_file_name (REGISTER char *lockfile, REGISTER Lisp_Object fn)
132 /* fn must be a Lisp_String! */
133 {
134 REGISTER char *p;
135
136 CHECK_STRING (Vlock_directory);
137
138 strcpy (lockfile, (char *) string_data (XSTRING (Vlock_directory)));
139
140 p = lockfile + strlen (lockfile);
141
142 if (p == lockfile /* lock-directory is empty?? */
143 || *(p - 1) != '/') /* in case lock-directory doesn't end in / */
144 {
145 *p = '/';
146 p++;
147 }
148
149 strcpy (p, (char *) string_data (XSTRING (fn)));
150
151 for (; *p; p++)
152 {
153 if (*p == '/')
154 *p = '!';
155 }
156 }
157 #endif /* !defined HAVE_LONG_FILE_NAMES */
158
159 static Lisp_Object
160 lock_file_owner_name (CONST char *lfname)
161 {
162 struct stat s;
163 struct passwd *the_pw = 0;
164
165 if (lstat (lfname, &s) == 0)
166 the_pw = getpwuid (s.st_uid);
167 return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name));
168 }
169
170
171 /* lock_file locks file fn,
172 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
174 buffer previously unmodified.
175 Do not (normally) call lock_buffer for a buffer already modified,
176 as either the file is already locked, or the user has already
177 decided to go ahead without locking.
178
179 When lock_buffer returns, either the lock is locked for us,
180 or the user has said to go ahead without locking.
181
182 If the file is locked by someone else, lock_buffer calls
183 ask-user-about-lock (a Lisp function) with two arguments,
184 the file name and the name of the user who did the locking.
185 This function can signal an error, or return t meaning
186 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
197 void
198 lock_file (Lisp_Object fn)
199 {
200 /* This function can GC */
201 REGISTER Lisp_Object attack, orig_fn;
202 REGISTER char *lfname;
203 struct gcpro gcpro1, gcpro2;
204 Lisp_Object subject_buf = Qnil;
205
206 if (NILP (Vlock_directory) || NILP (Vsuperlock_file))
207 return;
208 CHECK_STRING (fn);
209 CHECK_STRING (Vlock_directory);
210
211 GCPRO2 (fn, subject_buf);
212 orig_fn = fn;
213 fn = Fexpand_file_name (fn, Qnil);
214
215 /* Create the name of the lock-file for file fn */
216 MAKE_LOCK_NAME (lfname, fn);
217
218 /* See if this file is visited and has changed on disk since it was
219 visited. */
220 subject_buf = Fget_file_buffer (fn);
221 if (!NILP (subject_buf)
222 && NILP (Fverify_visited_file_modtime (subject_buf))
223 && !NILP (Ffile_exists_p (fn)))
224 call1_in_buffer (XBUFFER (subject_buf),
225 Qask_user_about_supersession_threat, fn);
226
227 /* Try to lock the lock. */
228 if (lock_if_free (lfname) <= 0)
229 /* Return now if we have locked it, or if lock dir does not exist */
230 goto done;
231
232 /* Else consider breaking the lock */
233 attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) :
234 current_buffer, Qask_user_about_lock, fn,
235 lock_file_owner_name (lfname));
236 if (!NILP (attack))
237 /* User says take the lock */
238 {
239 CHECK_STRING (Vsuperlock_file);
240 lock_superlock (lfname);
241 lock_file_1 (lfname, O_WRONLY);
242 unlink ((char *) string_data (XSTRING (Vsuperlock_file)));
243 goto done;
244 }
245 /* User says ignore the lock */
246 done:
247 UNGCPRO;
248 }
249
250
251 /* Lock the lock file named LFNAME.
252 If MODE is O_WRONLY, we do so even if it is already locked.
253 If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free.
254 Return 1 if successful, 0 if not. */
255
256 static int
257 lock_file_1 (CONST char *lfname, int mode)
258 {
259 REGISTER int fd;
260 char buf[20];
261
262 if ((fd = open (lfname, mode, 0666)) >= 0)
263 {
264 #ifdef USG
265 chmod (lfname, 0666);
266 #else
267 fchmod (fd, 0666);
268 #endif
269 sprintf (buf, "%ld ", (long) getpid ());
270 write (fd, buf, strlen (buf));
271 close (fd);
272 return 1;
273 }
274 else
275 return 0;
276 }
277
278 /* Lock the lock named LFNAME if possible.
279 Return 0 in that case.
280 Return positive if lock is really locked by someone else.
281 Return -1 if cannot lock for any other reason. */
282
283 static int
284 lock_if_free (CONST char *lfname)
285 {
286 REGISTER int clasher;
287
288 while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0)
289 {
290 if (errno != EEXIST)
291 return -1;
292 clasher = current_lock_owner (lfname);
293 if (clasher != 0)
294 if (clasher != getpid ())
295 return (clasher);
296 else return (0);
297 /* Try again to lock it */
298 }
299 return 0;
300 }
301
302 /* Return the pid of the process that claims to own the lock file LFNAME,
303 or 0 if nobody does or the lock is obsolete,
304 or -1 if something is wrong with the locking mechanism. */
305
306 static int
307 current_lock_owner (CONST char *lfname)
308 {
309 int owner = current_lock_owner_1 (lfname);
310 if (owner == 0 && errno == ENOENT)
311 return (0);
312 /* Is it locked by a process that exists? */
313 if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM))
314 return (owner);
315 if (unlink (lfname) < 0)
316 return (-1);
317 return (0);
318 }
319
320 static int
321 current_lock_owner_1 (CONST char *lfname)
322 {
323 REGISTER int fd;
324 char buf[20];
325 int tem;
326
327 fd = open (lfname, O_RDONLY, 0666);
328 if (fd < 0)
329 return 0;
330 tem = read (fd, buf, sizeof buf);
331 close (fd);
332 return (tem <= 0 ? 0 : atoi (buf));
333 }
334
335
336 void
337 unlock_file (Lisp_Object fn)
338 {
339 REGISTER char *lfname;
340 if (NILP (Vlock_directory) || NILP (Vsuperlock_file)) return;
341 CHECK_STRING (fn);
342 CHECK_STRING (Vlock_directory);
343 CHECK_STRING (Vsuperlock_file);
344
345 fn = Fexpand_file_name (fn, Qnil);
346
347 MAKE_LOCK_NAME (lfname, fn);
348
349 lock_superlock (lfname);
350
351 if (current_lock_owner_1 (lfname) == getpid ())
352 unlink (lfname);
353
354 unlink ((char *) string_data (XSTRING (Vsuperlock_file)));
355 }
356
357 static void
358 lock_superlock (CONST char *lfname)
359 {
360 REGISTER int i, fd;
361 DIR *lockdir;
362
363 for (i = -20; i < 0 &&
364 (fd = open ((char *) string_data (XSTRING (Vsuperlock_file)),
365 O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0;
366 i++)
367 {
368 if (errno != EEXIST)
369 return;
370
371 /* This seems to be necessary to prevent Emacs from hanging when the
372 competing process has already deleted the superlock, but it's still
373 in the NFS cache. So we force NFS to synchronize the cache. */
374 lockdir = opendir ((char *) string_data (XSTRING (Vlock_directory)));
375 if (lockdir)
376 closedir (lockdir);
377
378 emacs_sleep (1);
379 }
380 if (fd >= 0)
381 {
382 #ifdef USG
383 chmod ((char *) string_data (XSTRING (Vsuperlock_file)), 0666);
384 #else
385 fchmod (fd, 0666);
386 #endif
387 write (fd, lfname, strlen (lfname));
388 close (fd);
389 }
390 }
391
392 void
393 unlock_all_files (void)
394 {
395 REGISTER Lisp_Object tail;
396 REGISTER struct buffer *b;
397
398 for (tail = Vbuffer_alist; GC_CONSP (tail);
399 tail = XCDR (tail))
400 {
401 b = XBUFFER (XCDR (XCAR (tail)));
402 if (STRINGP (b->file_truename) &&
403 BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
404 unlock_file (b->file_truename);
405 }
406 }
407
408
409 DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
410 0, 1, 0 /*
411 Lock FILE, if current buffer is modified.
412 FILE defaults to current buffer's visited file,
413 or else nothing is done if current buffer isn't visiting a file.
414 */ )
415 (fn)
416 Lisp_Object fn;
417 {
418 /* This function can GC */
419 if (NILP (fn))
420 fn = current_buffer->file_truename;
421 CHECK_STRING (fn);
422 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer)
423 && !NILP (fn))
424 lock_file (fn);
425 return Qnil;
426 }
427
428 DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
429 0, 0, 0 /*
430 Unlock the file visited in the current buffer,
431 if it should normally be locked.
432 */ )
433 ()
434 {
435 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer)
436 && STRINGP (current_buffer->file_truename))
437 unlock_file (current_buffer->file_truename);
438 return Qnil;
439 }
440
441
442 /* Unlock the file visited in buffer BUFFER. */
443
444 void
445 unlock_buffer (struct buffer *buffer)
446 {
447 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
448 && STRINGP (buffer->file_truename))
449 unlock_file (buffer->file_truename);
450 }
451
452 DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0 /*
453 Return nil if the FILENAME is not locked,
454 t if it is locked by you, else a string of the name of the locker.
455 */ )
456 (fn)
457 Lisp_Object fn;
458 {
459 /* This function can GC */
460 REGISTER char *lfname;
461 int owner;
462
463 if (NILP (Vlock_directory) || NILP (Vsuperlock_file))
464 return Qnil;
465 CHECK_STRING (Vlock_directory);
466
467 fn = Fexpand_file_name (fn, Qnil);
468
469 MAKE_LOCK_NAME (lfname, fn);
470
471 owner = current_lock_owner (lfname);
472 if (owner <= 0)
473 return (Qnil);
474 else if (owner == getpid ())
475 return (Qt);
476
477 return (lock_file_owner_name (lfname));
478 }
479
480 void
481 syms_of_filelock (void)
482 {
483 /* This function can GC */
484 defsubr (&Sunlock_buffer);
485 defsubr (&Slock_buffer);
486 defsubr (&Sfile_locked_p);
487
488 defsymbol (&Qask_user_about_supersession_threat,
489 "ask-user-about-supersession-threat");
490 defsymbol (&Qask_user_about_lock, "ask-user-about-lock");
491 }
492
493 void
494 vars_of_filelock (void)
495 {
496 DEFVAR_LISP ("lock-directory", &Vlock_directory /*
497 Don't change this
498 */ );
499 DEFVAR_LISP ("superlock-file", &Vsuperlock_file /*
500 Don't change this
501 */ );
502 }
503
504 void
505 complex_vars_of_filelock (void)
506 {
507 #ifdef PATH_LOCK
508 Vlock_directory =
509 Ffile_name_as_directory (build_string (PATH_LOCK));
510 #else
511 Vlock_directory = Qnil;
512 #endif
513 #ifdef PATH_SUPERLOCK
514 Vsuperlock_file =
515 Ffile_name_as_directory (build_string (PATH_SUPERLOCK));
516 #else
517 Vsuperlock_file = Qnil;
518 #endif
519 /* All the rest done dynamically by startup.el */
520 }
521
522 #endif /* CLASH_DETECTION */