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