(LOCALTIME_CACHE): Defined.
[bpt/emacs.git] / src / filelock.c
CommitLineData
c6c5df7f 1/* Copyright (C) 1985, 1986, 1987, 1993 Free Software Foundation, Inc.
8489eb67
RS
2
3This file is part of GNU Emacs.
4
5GNU Emacs is free software; you can redistribute it and/or modify
6it under the terms of the GNU General Public License as published by
32676c08 7the Free Software Foundation; either version 2, or (at your option)
8489eb67
RS
8any later version.
9
10GNU Emacs is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with GNU Emacs; see the file COPYING. If not, write to
17the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
18
19
20#include <sys/types.h>
21#include <sys/stat.h>
22#include "config.h"
bfb61299
JB
23
24#ifdef VMS
b350a838 25#include "vms-pwd.h"
bfb61299 26#else
8489eb67 27#include <pwd.h>
bfb61299
JB
28#endif
29
8489eb67
RS
30#include <errno.h>
31#include <sys/file.h>
32#ifdef USG
33#include <fcntl.h>
34#endif /* USG */
35
8489eb67
RS
36#include "lisp.h"
37#include "paths.h"
38#include "buffer.h"
39
40extern int errno;
41
32676c08 42extern char *egetenv ();
d8cafeb5 43extern char *strcpy ();
32676c08 44
8489eb67
RS
45#ifdef CLASH_DETECTION
46
47/* If system does not have symbolic links, it does not have lstat.
48 In that case, use ordinary stat instead. */
49
50#ifndef S_IFLNK
51#define lstat stat
52#endif
53
32676c08
JB
54
55/* The name of the directory in which we keep lock files, with a '/'
56 appended. */
57char *lock_path;
58
59/* The name of the file in the lock directory which is used to
60 arbitrate access to the entire directory. */
61#define SUPERLOCK_NAME "!!!SuperLock!!!"
62
63/* The path to the superlock file. This is SUPERLOCK_NAME appended to
64 lock_path. */
65char *superlock_path;
66
67/* Set LOCK to the name of the lock file for the filename FILE.
68 char *LOCK; Lisp_Object FILE; */
e31fbc7a 69
6c10d0cd 70#ifndef HAVE_LONG_FILE_NAMES
e31fbc7a
RS
71
72#define MAKE_LOCK_PATH(lock, file) \
73 (lock = (char *) alloca (14 + strlen (lock_path) + 1), \
74 fill_in_lock_short_file_name (lock, (file)))
75
76
77fill_in_lock_short_file_name (lockfile, fn)
78 register char *lockfile;
79 register Lisp_Object fn;
80{
81 register union
82 {
83 unsigned int word [2];
84 unsigned char byte [8];
85 } crc;
86 register unsigned char *p, new;
87
88 /* 7-bytes cyclic code for burst correction on byte-by-byte basis.
89 the used polynomial is D^7 + D^6 + D^3 +1. pot@cnuce.cnr.it */
90
91 crc.word[0] = crc.word[1] = 0;
92
93 for (p = XSTRING (fn)->data; new = *p++; )
94 {
95 new += crc.byte[7];
96 crc.byte[7] = 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 sprintf (lockfile, "%s%.2x%.2x%.2x%.2x%.2x%.2x%.2x", lock_path,
106 crc.byte[0], crc.byte[1], crc.byte[2], crc.byte[3],
107 crc.byte[4], crc.byte[5], crc.byte[6]);
108}
109
6c10d0cd 110#else /* defined HAVE_LONG_FILE_NAMES */
e31fbc7a 111
e065a56e 112#define MAKE_LOCK_PATH(lock, file) \
32676c08
JB
113 (lock = (char *) alloca (XSTRING (file)->size + strlen (lock_path) + 1), \
114 fill_in_lock_file_name (lock, (file)))
115
e31fbc7a 116
32676c08
JB
117fill_in_lock_file_name (lockfile, fn)
118 register char *lockfile;
119 register Lisp_Object fn;
120{
121 register char *p;
122
123 strcpy (lockfile, lock_path);
124
125 p = lockfile + strlen (lockfile);
126
127 strcpy (p, XSTRING (fn)->data);
128
129 for (; *p; p++)
130 {
131 if (*p == '/')
132 *p = '!';
133 }
134}
6c10d0cd 135#endif /* !defined HAVE_LONG_FILE_NAMES */
32676c08 136
8489eb67
RS
137static Lisp_Object
138lock_file_owner_name (lfname)
139 char *lfname;
140{
141 struct stat s;
142 struct passwd *the_pw;
143 extern struct passwd *getpwuid ();
144
145 if (lstat (lfname, &s) == 0)
146 the_pw = getpwuid (s.st_uid);
147 return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name));
148}
149
150
151/* lock_file locks file fn,
152 meaning it serves notice on the world that you intend to edit that file.
153 This should be done only when about to modify a file-visiting
154 buffer previously unmodified.
155 Do not (normally) call lock_buffer for a buffer already modified,
156 as either the file is already locked, or the user has already
157 decided to go ahead without locking.
158
159 When lock_buffer returns, either the lock is locked for us,
160 or the user has said to go ahead without locking.
161
162 If the file is locked by someone else, lock_buffer calls
163 ask-user-about-lock (a Lisp function) with two arguments,
164 the file name and the name of the user who did the locking.
165 This function can signal an error, or return t meaning
166 take away the lock, or return nil meaning ignore the lock. */
167
168/* The lock file name is the file name with "/" replaced by "!"
169 and put in the Emacs lock directory. */
170/* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */
171
6c10d0cd 172/* If HAVE_LONG_FILE_NAMES is not defined, the lock file name is the hex
e31fbc7a
RS
173 representation of a 14-bytes CRC generated from the file name
174 and put in the Emacs lock directory (not very nice, but it works).
175 (ie., /ka/king/junk.tex -> /!/ec92d3ed24a8f0). */
176
8489eb67
RS
177void
178lock_file (fn)
179 register Lisp_Object fn;
180{
181 register Lisp_Object attack;
182 register char *lfname;
183
32676c08 184 MAKE_LOCK_PATH (lfname, fn);
8489eb67 185
32676c08
JB
186 /* See if this file is visited and has changed on disk since it was
187 visited. */
8489eb67
RS
188 {
189 register Lisp_Object subject_buf = Fget_file_buffer (fn);
265a9e55
JB
190 if (!NILP (subject_buf)
191 && NILP (Fverify_visited_file_modtime (subject_buf))
192 && !NILP (Ffile_exists_p (fn)))
8489eb67
RS
193 call1 (intern ("ask-user-about-supersession-threat"), fn);
194 }
195
196 /* Try to lock the lock. */
197 if (lock_if_free (lfname) <= 0)
198 /* Return now if we have locked it, or if lock dir does not exist */
199 return;
200
201 /* Else consider breaking the lock */
202 attack = call2 (intern ("ask-user-about-lock"), fn,
203 lock_file_owner_name (lfname));
265a9e55 204 if (!NILP (attack))
8489eb67
RS
205 /* User says take the lock */
206 {
207 lock_superlock (lfname);
208 lock_file_1 (lfname, O_WRONLY) ;
32676c08 209 unlink (superlock_path);
8489eb67
RS
210 return;
211 }
212 /* User says ignore the lock */
213}
214
8489eb67
RS
215/* Lock the lock file named LFNAME.
216 If MODE is O_WRONLY, we do so even if it is already locked.
217 If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free.
218 Return 1 if successful, 0 if not. */
219
220int
221lock_file_1 (lfname, mode)
222 int mode; char *lfname;
223{
224 register int fd;
225 char buf[20];
226
227 if ((fd = open (lfname, mode, 0666)) >= 0)
228 {
229#ifdef USG
230 chmod (lfname, 0666);
231#else
232 fchmod (fd, 0666);
233#endif
234 sprintf (buf, "%d ", getpid ());
235 write (fd, buf, strlen (buf));
236 close (fd);
237 return 1;
238 }
239 else
240 return 0;
241}
242
243/* Lock the lock named LFNAME if possible.
244 Return 0 in that case.
245 Return positive if lock is really locked by someone else.
246 Return -1 if cannot lock for any other reason. */
247
248int
249lock_if_free (lfname)
250 register char *lfname;
251{
252 register int clasher;
253
254 while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0)
255 {
256 if (errno != EEXIST)
257 return -1;
258 clasher = current_lock_owner (lfname);
259 if (clasher != 0)
260 if (clasher != getpid ())
261 return (clasher);
262 else return (0);
263 /* Try again to lock it */
264 }
265 return 0;
266}
267
268/* Return the pid of the process that claims to own the lock file LFNAME,
269 or 0 if nobody does or the lock is obsolete,
270 or -1 if something is wrong with the locking mechanism. */
271
272int
273current_lock_owner (lfname)
274 char *lfname;
275{
276 int owner = current_lock_owner_1 (lfname);
277 if (owner == 0 && errno == ENOENT)
278 return (0);
279 /* Is it locked by a process that exists? */
280 if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM))
281 return (owner);
282 if (unlink (lfname) < 0)
283 return (-1);
284 return (0);
285}
286
287int
288current_lock_owner_1 (lfname)
289 char *lfname;
290{
291 register int fd;
292 char buf[20];
293 int tem;
294
295 fd = open (lfname, O_RDONLY, 0666);
296 if (fd < 0)
297 return 0;
298 tem = read (fd, buf, sizeof buf);
299 close (fd);
300 return (tem <= 0 ? 0 : atoi (buf));
301}
302
303\f
304void
305unlock_file (fn)
306 register Lisp_Object fn;
307{
308 register char *lfname;
309
32676c08 310 MAKE_LOCK_PATH (lfname, fn);
8489eb67
RS
311
312 lock_superlock (lfname);
313
314 if (current_lock_owner_1 (lfname) == getpid ())
315 unlink (lfname);
316
32676c08 317 unlink (superlock_path);
8489eb67
RS
318}
319
320lock_superlock (lfname)
321 char *lfname;
322{
323 register int i, fd;
324
32676c08 325 for (i = -20; i < 0 && (fd = open (superlock_path,
8489eb67
RS
326 O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0;
327 i++)
328 {
329 if (errno != EEXIST)
330 return;
331 sleep (1);
332 }
333 if (fd >= 0)
334 {
335#ifdef USG
32676c08 336 chmod (superlock_path, 0666);
8489eb67
RS
337#else
338 fchmod (fd, 0666);
339#endif
340 write (fd, lfname, strlen (lfname));
341 close (fd);
342 }
343}
344
345void
346unlock_all_files ()
347{
348 register Lisp_Object tail;
349 register struct buffer *b;
350
351 for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons;
352 tail = XCONS (tail)->cdr)
353 {
354 b = XBUFFER (XCONS (XCONS (tail)->car)->cdr);
355 if (XTYPE (b->filename) == Lisp_String &&
356 b->save_modified < BUF_MODIFF (b))
357 unlock_file (b->filename);
358 }
359}
360
361\f
362DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
363 0, 1, 0,
364 "Lock FILE, if current buffer is modified.\n\
365FILE defaults to current buffer's visited file,\n\
366or else nothing is done if current buffer isn't visiting a file.")
367 (fn)
368 Lisp_Object fn;
369{
265a9e55 370 if (NILP (fn))
8489eb67
RS
371 fn = current_buffer->filename;
372 else
373 CHECK_STRING (fn, 0);
374 if (current_buffer->save_modified < MODIFF
265a9e55 375 && !NILP (fn))
8489eb67
RS
376 lock_file (fn);
377 return Qnil;
378}
379
380DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
381 0, 0, 0,
382 "Unlock the file visited in the current buffer,\n\
383if it should normally be locked.")
384 ()
385{
386 if (current_buffer->save_modified < MODIFF &&
387 XTYPE (current_buffer->filename) == Lisp_String)
388 unlock_file (current_buffer->filename);
389 return Qnil;
390}
391
392\f
393/* Unlock the file visited in buffer BUFFER. */
394
395unlock_buffer (buffer)
396 struct buffer *buffer;
397{
398 if (buffer->save_modified < BUF_MODIFF (buffer) &&
399 XTYPE (buffer->filename) == Lisp_String)
400 unlock_file (buffer->filename);
401}
402
403DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
404 "Return nil if the FILENAME is not locked,\n\
405t if it is locked by you, else a string of the name of the locker.")
406 (fn)
407 Lisp_Object fn;
408{
409 register char *lfname;
410 int owner;
411
412 fn = Fexpand_file_name (fn, Qnil);
413
32676c08 414 MAKE_LOCK_PATH (lfname, fn);
8489eb67
RS
415
416 owner = current_lock_owner (lfname);
417 if (owner <= 0)
418 return (Qnil);
419 else if (owner == getpid ())
420 return (Qt);
421
422 return (lock_file_owner_name (lfname));
423}
424
32676c08
JB
425\f
426/* Initialization functions. */
427
428init_filelock ()
429{
430 lock_path = egetenv ("EMACSLOCKDIR");
431 if (! lock_path)
432 lock_path = PATH_LOCK;
433
434 /* Make sure it ends with a slash. */
435 if (lock_path[strlen (lock_path) - 1] != '/')
436 {
437 lock_path = strcpy ((char *) xmalloc (strlen (lock_path) + 2),
438 lock_path);
439 strcat (lock_path, "/");
440 }
441
442 superlock_path = (char *) xmalloc ((strlen (lock_path)
443 + sizeof (SUPERLOCK_NAME)));
444 strcpy (superlock_path, lock_path);
445 strcat (superlock_path, SUPERLOCK_NAME);
446}
447
8489eb67
RS
448syms_of_filelock ()
449{
450 defsubr (&Sunlock_buffer);
451 defsubr (&Slock_buffer);
452 defsubr (&Sfile_locked_p);
453}
454
455#endif /* CLASH_DETECTION */