*** empty log message ***
[bpt/emacs.git] / src / filelock.c
CommitLineData
b97771fc
RS
1/* Lock files for editing.
2 Copyright (C) 1985, 86, 87, 93, 94, 96, 98, 1999 Free Software Foundation, Inc.
8489eb67
RS
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
32676c08 8the Free Software Foundation; either version 2, or (at your option)
8489eb67
RS
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
3b7ad313
EN
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, MA 02111-1307, USA. */
8489eb67
RS
20
21
68c45bf0 22#include <config.h>
8489eb67
RS
23#include <sys/types.h>
24#include <sys/stat.h>
dfcf069d 25#include <signal.h>
2decc5a9 26#include <stdio.h>
bfb61299
JB
27
28#ifdef VMS
b350a838 29#include "vms-pwd.h"
bfb61299 30#else
8489eb67 31#include <pwd.h>
8dbbc384 32#endif /* not VMS */
bfb61299 33
8489eb67
RS
34#include <sys/file.h>
35#ifdef USG
36#include <fcntl.h>
8dbbc384 37#include <string.h>
8489eb67
RS
38#endif /* USG */
39
dfcf069d
AS
40#ifdef HAVE_UNISTD_H
41#include <unistd.h>
42#endif
43
f805a125
KH
44#ifdef __FreeBSD__
45#include <sys/time.h>
46#include <sys/types.h>
47#include <sys/sysctl.h>
48#endif /* __FreeBSD__ */
49
8489eb67 50#include "lisp.h"
8489eb67 51#include "buffer.h"
f4a4528d
RS
52#include "charset.h"
53#include "coding.h"
9177d978 54#include "systime.h"
8489eb67 55
15e88d21 56#include <time.h>
8dbbc384
RS
57#include <errno.h>
58#ifndef errno
8489eb67 59extern int errno;
79941276
RS
60#endif
61
5f8d6a10
RS
62/* The directory for writing temporary files. */
63
64Lisp_Object Vtemporary_file_directory;
65
8489eb67 66#ifdef CLASH_DETECTION
e788eecc
KH
67
68#include <utmp.h>
77e544a4 69
a48de9b2
PE
70/* A file whose last-modified time is just after the most recent boot.
71 Define this to be NULL to disable checking for this file. */
72#ifndef BOOT_TIME_FILE
73#define BOOT_TIME_FILE "/var/run/random-seed"
74#endif
75
77e544a4
RS
76#ifndef WTMP_FILE
77#define WTMP_FILE "/var/log/wtmp"
78#endif
8489eb67 79
8dbbc384
RS
80/* The strategy: to lock a file FN, create a symlink .#FN in FN's
81 directory, with link data `user@host.pid'. This avoids a single
82 mount (== failure) point for lock files.
83
84 When the host in the lock data is the current host, we can check if
85 the pid is valid with kill.
86
87 Otherwise, we could look at a separate file that maps hostnames to
88 reboot times to see if the remote pid can possibly be valid, since we
89 don't want Emacs to have to communicate via pipes or sockets or
90 whatever to other processes, either locally or remotely; rms says
91 that's too unreliable. Hence the separate file, which could
92 theoretically be updated by daemons running separately -- but this
93 whole idea is unimplemented; in practice, at least in our
1c4f857c 94 environment, it seems such stale locks arise fairly infrequently, and
8dbbc384
RS
95 Emacs' standard methods of dealing with clashes suffice.
96
97 We use symlinks instead of normal files because (1) they can be
98 stored more efficiently on the filesystem, since the kernel knows
99 they will be small, and (2) all the info about the lock can be read
100 in a single system call (readlink). Although we could use regular
1c4f857c 101 files to be useful on old systems lacking symlinks, nowadays
8dbbc384
RS
102 virtually all such systems are probably single-user anyway, so it
103 didn't seem worth the complication.
104
105 Similarly, we don't worry about a possible 14-character limit on
106 file names, because those are all the same systems that don't have
107 symlinks.
108
109 This is compatible with the locking scheme used by Interleaf (which
110 has contributed this implementation for Emacs), and was designed by
111 Ethan Jacobson, Kimbo Mundy, and others.
112
113 --karl@cs.umb.edu/karl@hq.ileaf.com. */
8489eb67 114
8dbbc384 115\f
15e88d21
RS
116/* Return the time of the last system boot. */
117
118static time_t boot_time;
b97771fc 119static int boot_time_initialized;
15e88d21 120
9177d978
RS
121extern Lisp_Object Vshell_file_name;
122
2f2500ef
DL
123#ifdef BOOT_TIME
124static void get_boot_time_1 P_ ((char *, int));
125#endif
126
15e88d21
RS
127static time_t
128get_boot_time ()
129{
2decc5a9 130#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
9177d978 131 int counter;
2decc5a9 132#endif
15e88d21 133
b97771fc 134 if (boot_time_initialized)
15e88d21 135 return boot_time;
b97771fc 136 boot_time_initialized = 1;
15e88d21 137
f805a125
KH
138#if defined (CTL_KERN) && defined (KERN_BOOTTIME)
139 {
140 int mib[2];
141 size_t size;
142 struct timeval boottime_val;
143
144 mib[0] = CTL_KERN;
145 mib[1] = KERN_BOOTTIME;
146 size = sizeof (boottime_val);
147
148 if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0)
149 {
150 boot_time = boottime_val.tv_sec;
151 return boot_time;
152 }
153 }
154#endif /* defined (CTL_KERN) && defined (KERN_BOOTTIME) */
9177d978 155
a48de9b2
PE
156 if (BOOT_TIME_FILE)
157 {
158 struct stat st;
159 if (stat (BOOT_TIME_FILE, &st) == 0)
160 {
161 boot_time = st.st_mtime;
162 return boot_time;
163 }
164 }
165
c6fd1dc4 166#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
b97771fc
RS
167#ifndef CANNOT_DUMP
168 /* The utmp routines maintain static state.
169 Don't touch that state unless we are initialized,
170 since it might not survive dumping. */
171 if (! initialized)
172 return boot_time;
173#endif /* not CANNOT_DUMP */
174
175 /* Try to get boot time from utmp before wtmp,
176 since utmp is typically much smaller than wtmp.
177 Passing a null pointer causes get_boot_time_1
178 to inspect the default file, namely utmp. */
179 get_boot_time_1 ((char *) 0, 0);
180 if (boot_time)
181 return boot_time;
182
9177d978 183 /* Try to get boot time from the current wtmp file. */
b97771fc 184 get_boot_time_1 (WTMP_FILE, 1);
9177d978
RS
185
186 /* If we did not find a boot time in wtmp, look at wtmp, and so on. */
b97771fc 187 for (counter = 0; counter < 20 && ! boot_time; counter++)
9177d978
RS
188 {
189 char cmd_string[100];
190 Lisp_Object tempname, filename;
191 int delete_flag = 0;
192
193 filename = Qnil;
194
77e544a4 195 sprintf (cmd_string, "%s.%d", WTMP_FILE, counter);
9177d978 196 tempname = build_string (cmd_string);
29a2adb0 197 if (! NILP (Ffile_exists_p (tempname)))
9177d978
RS
198 filename = tempname;
199 else
200 {
77e544a4 201 sprintf (cmd_string, "%s.%d.gz", WTMP_FILE, counter);
9177d978
RS
202 tempname = build_string (cmd_string);
203 if (! NILP (Ffile_exists_p (tempname)))
204 {
205 Lisp_Object args[6];
5f8d6a10
RS
206 tempname = Fexpand_file_name (build_string ("wtmp"),
207 Vtemporary_file_directory);
208 tempname = Fmake_temp_name (tempname);
9177d978
RS
209 args[0] = Vshell_file_name;
210 args[1] = Qnil;
211 args[2] = Qnil;
212 args[3] = Qnil;
213 args[4] = build_string ("-c");
77e544a4
RS
214 sprintf (cmd_string, "gunzip < %s.%d.gz > %s",
215 WTMP_FILE, counter, XSTRING (tempname)->data);
9177d978
RS
216 args[5] = build_string (cmd_string);
217 Fcall_process (6, args);
218 filename = tempname;
219 delete_flag = 1;
220 }
221 }
222
223 if (! NILP (filename))
224 {
b97771fc 225 get_boot_time_1 (XSTRING (filename)->data, 1);
9177d978
RS
226 if (delete_flag)
227 unlink (XSTRING (filename)->data);
228 }
229 }
230
231 return boot_time;
232#else
233 return 0;
234#endif
235}
236
e9f22ced 237#ifdef BOOT_TIME
9177d978
RS
238/* Try to get the boot time from wtmp file FILENAME.
239 This succeeds if that file contains a reboot record.
9177d978 240
b97771fc
RS
241 If FILENAME is zero, use the same file as before;
242 if no FILENAME has ever been specified, this is the utmp file.
243 Use the newest reboot record if NEWEST is nonzero,
244 the first reboot record otherwise.
245 Ignore all reboot records on or before BOOT_TIME.
246 Success is indicated by setting BOOT_TIME to a larger value. */
247
2f2500ef 248void
b97771fc 249get_boot_time_1 (filename, newest)
9177d978 250 char *filename;
b97771fc 251 int newest;
9177d978
RS
252{
253 struct utmp ut, *utp;
77e544a4
RS
254 int desc;
255
b97771fc
RS
256 if (filename)
257 {
258 /* On some versions of IRIX, opening a nonexistent file name
259 is likely to crash in the utmp routines. */
68c45bf0 260 desc = emacs_open (filename, O_RDONLY, 0);
b97771fc
RS
261 if (desc < 0)
262 return;
263
68c45bf0 264 emacs_close (desc);
b97771fc
RS
265
266 utmpname (filename);
267 }
9177d978 268
c321b190 269 setutent ();
b97771fc 270
c321b190
RS
271 while (1)
272 {
273 /* Find the next reboot record. */
274 ut.ut_type = BOOT_TIME;
275 utp = getutid (&ut);
276 if (! utp)
277 break;
278 /* Compare reboot times and use the newest one. */
279 if (utp->ut_time > boot_time)
b97771fc
RS
280 {
281 boot_time = utp->ut_time;
282 if (! newest)
283 break;
284 }
c321b190
RS
285 /* Advance on element in the file
286 so that getutid won't repeat the same one. */
287 utp = getutent ();
288 if (! utp)
289 break;
290 }
15e88d21 291 endutent ();
15e88d21 292}
e9f22ced 293#endif /* BOOT_TIME */
15e88d21 294\f
8dbbc384 295/* Here is the structure that stores information about a lock. */
32676c08 296
8dbbc384
RS
297typedef struct
298{
299 char *user;
300 char *host;
9005cb4f 301 unsigned long pid;
15e88d21 302 time_t boot_time;
8dbbc384 303} lock_info_type;
32676c08 304
49b6d120
RS
305/* When we read the info back, we might need this much more,
306 enough for decimal representation plus null. */
307#define LOCK_PID_MAX (4 * sizeof (unsigned long))
32676c08 308
8dbbc384
RS
309/* Free the two dynamically-allocated pieces in PTR. */
310#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
e31fbc7a 311
e31fbc7a 312
8dbbc384
RS
313/* Write the name of the lock file for FN into LFNAME. Length will be
314 that of FN plus two more for the leading `.#' plus one for the null. */
7b92975f 315#define MAKE_LOCK_NAME(lock, file) \
fc932ac6 316 (lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1), \
8dbbc384 317 fill_in_lock_file_name (lock, (file)))
e31fbc7a 318
8dbbc384
RS
319static void
320fill_in_lock_file_name (lockfile, fn)
e31fbc7a
RS
321 register char *lockfile;
322 register Lisp_Object fn;
323{
8dbbc384
RS
324 register char *p;
325
326 strcpy (lockfile, XSTRING (fn)->data);
327
328 /* Shift the nondirectory part of the file name (including the null)
329 right two characters. Here is one of the places where we'd have to
330 do something to support 14-character-max file names. */
331 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
332 p[2] = *p;
e31fbc7a 333
8dbbc384
RS
334 /* Insert the `.#'. */
335 p[1] = '.';
336 p[2] = '#';
337}
e31fbc7a 338
8dbbc384
RS
339/* Lock the lock file named LFNAME.
340 If FORCE is nonzero, we do so even if it is already locked.
341 Return 1 if successful, 0 if not. */
e31fbc7a 342
8dbbc384
RS
343static int
344lock_file_1 (lfname, force)
345 char *lfname;
346 int force;
347{
348 register int err;
bd26d5a3 349 time_t boot_time;
662c2ef2
RS
350 char *user_name;
351 char *host_name;
352 char *lock_info_str;
353
354 if (STRINGP (Fuser_login_name (Qnil)))
266d7a00 355 user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
662c2ef2
RS
356 else
357 user_name = "";
358 if (STRINGP (Fsystem_name ()))
266d7a00 359 host_name = (char *)XSTRING (Fsystem_name ())->data;
662c2ef2
RS
360 else
361 host_name = "";
266d7a00 362 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
15e88d21 363 + LOCK_PID_MAX + 5);
8dbbc384 364
bd26d5a3
RS
365 boot_time = get_boot_time ();
366 if (boot_time)
367 sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
368 (unsigned long) getpid (), (unsigned long) boot_time);
369 else
370 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
371 (unsigned long) getpid ());
8dbbc384
RS
372
373 err = symlink (lock_info_str, lfname);
374 if (errno == EEXIST && force)
e31fbc7a 375 {
8dbbc384
RS
376 unlink (lfname);
377 err = symlink (lock_info_str, lfname);
e31fbc7a 378 }
e31fbc7a 379
8dbbc384
RS
380 return err == 0;
381}
e31fbc7a 382
9177d978 383/* Return 1 if times A and B are no more than one second apart. */
32676c08 384
9177d978
RS
385int
386within_one_second (a, b)
387 time_t a, b;
388{
389 return (a - b >= -1 && a - b <= 1);
390}
8dbbc384
RS
391\f
392/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
393 1 if another process owns it (and set OWNER (if non-null) to info),
394 2 if the current process owns it,
395 or -1 if something is wrong with the locking mechanism. */
e31fbc7a 396
8dbbc384
RS
397static int
398current_lock_owner (owner, lfname)
399 lock_info_type *owner;
400 char *lfname;
32676c08 401{
8dbbc384
RS
402#ifndef index
403 extern char *rindex (), *index ();
404#endif
5f8d6a10 405 int len, ret;
8dbbc384 406 int local_owner = 0;
15e88d21 407 char *at, *dot, *colon;
8dbbc384
RS
408 char *lfinfo = 0;
409 int bufsize = 50;
410 /* Read arbitrarily-long contents of symlink. Similar code in
411 file-symlink-p in fileio.c. */
412 do
413 {
414 bufsize *= 2;
415 lfinfo = (char *) xrealloc (lfinfo, bufsize);
416 len = readlink (lfname, lfinfo, bufsize);
417 }
418 while (len >= bufsize);
419
420 /* If nonexistent lock file, all is well; otherwise, got strange error. */
421 if (len == -1)
422 {
423 xfree (lfinfo);
424 return errno == ENOENT ? 0 : -1;
425 }
32676c08 426
8dbbc384
RS
427 /* Link info exists, so `len' is its length. Null terminate. */
428 lfinfo[len] = 0;
429
430 /* Even if the caller doesn't want the owner info, we still have to
431 read it to determine return value, so allocate it. */
432 if (!owner)
433 {
3609a53b 434 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
8dbbc384
RS
435 local_owner = 1;
436 }
437
15e88d21 438 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
8dbbc384
RS
439 /* The USER is everything before the first @. */
440 at = index (lfinfo, '@');
441 dot = rindex (lfinfo, '.');
15e88d21
RS
442 if (!at || !dot)
443 {
444 xfree (lfinfo);
445 return -1;
446 }
8dbbc384
RS
447 len = at - lfinfo;
448 owner->user = (char *) xmalloc (len + 1);
449 strncpy (owner->user, lfinfo, len);
450 owner->user[len] = 0;
451
15e88d21 452 /* The PID is everything from the last `.' to the `:'. */
8dbbc384 453 owner->pid = atoi (dot + 1);
15e88d21
RS
454 colon = dot;
455 while (*colon && *colon != ':')
456 colon++;
457 /* After the `:', if there is one, comes the boot time. */
458 if (*colon == ':')
459 owner->boot_time = atoi (colon + 1);
460 else
461 owner->boot_time = 0;
32676c08 462
8dbbc384
RS
463 /* The host is everything in between. */
464 len = dot - at - 1;
465 owner->host = (char *) xmalloc (len + 1);
466 strncpy (owner->host, at + 1, len);
467 owner->host[len] = 0;
32676c08 468
8dbbc384
RS
469 /* We're done looking at the link info. */
470 xfree (lfinfo);
471
472 /* On current host? */
662c2ef2
RS
473 if (STRINGP (Fsystem_name ())
474 && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
32676c08 475 {
8dbbc384
RS
476 if (owner->pid == getpid ())
477 ret = 2; /* We own it. */
72dcef0e 478 else if (owner->pid > 0
15e88d21
RS
479 && (kill (owner->pid, 0) >= 0 || errno == EPERM)
480 && (owner->boot_time == 0
9177d978 481 || within_one_second (owner->boot_time, get_boot_time ())))
8dbbc384 482 ret = 1; /* An existing process on this machine owns it. */
8dbbc384
RS
483 /* The owner process is dead or has a strange pid (<=0), so try to
484 zap the lockfile. */
72dcef0e 485 else if (unlink (lfname) < 0)
8dbbc384 486 ret = -1;
72dcef0e
RS
487 else
488 ret = 0;
32676c08 489 }
8dbbc384
RS
490 else
491 { /* If we wanted to support the check for stale locks on remote machines,
492 here's where we'd do it. */
493 ret = 1;
494 }
495
496 /* Avoid garbage. */
497 if (local_owner || ret <= 0)
498 {
499 FREE_LOCK_INFO (*owner);
500 }
501 return ret;
32676c08
JB
502}
503
8dbbc384
RS
504\f
505/* Lock the lock named LFNAME if possible.
506 Return 0 in that case.
507 Return positive if some other process owns the lock, and info about
508 that process in CLASHER.
509 Return -1 if cannot lock for any other reason. */
8489eb67 510
8dbbc384
RS
511static int
512lock_if_free (clasher, lfname)
513 lock_info_type *clasher;
514 register char *lfname;
515{
cfc01fa7 516 while (lock_file_1 (lfname, 0) == 0)
8dbbc384
RS
517 {
518 int locker;
e0e0205b 519
8dbbc384
RS
520 if (errno != EEXIST)
521 return -1;
522
523 locker = current_lock_owner (clasher, lfname);
524 if (locker == 2)
525 {
526 FREE_LOCK_INFO (*clasher);
527 return 0; /* We ourselves locked it. */
528 }
529 else if (locker == 1)
530 return 1; /* Someone else has it. */
5df0b2fa 531 else if (locker == -1)
ae1ef097 532 return -1; /* current_lock_owner returned strange error. */
8dbbc384 533
cfc01fa7 534 /* We deleted a stale lock; try again to lock the file. */
8dbbc384
RS
535 }
536 return 0;
8489eb67
RS
537}
538
8dbbc384 539/* lock_file locks file FN,
8489eb67
RS
540 meaning it serves notice on the world that you intend to edit that file.
541 This should be done only when about to modify a file-visiting
542 buffer previously unmodified.
8dbbc384 543 Do not (normally) call this for a buffer already modified,
8489eb67
RS
544 as either the file is already locked, or the user has already
545 decided to go ahead without locking.
546
8dbbc384 547 When this returns, either the lock is locked for us,
8489eb67
RS
548 or the user has said to go ahead without locking.
549
8dbbc384 550 If the file is locked by someone else, this calls
8489eb67 551 ask-user-about-lock (a Lisp function) with two arguments,
8dbbc384 552 the file name and info about the user who did the locking.
8489eb67
RS
553 This function can signal an error, or return t meaning
554 take away the lock, or return nil meaning ignore the lock. */
555
8489eb67
RS
556void
557lock_file (fn)
eb4b1c05 558 Lisp_Object fn;
8489eb67 559{
f4a4528d 560 register Lisp_Object attack, orig_fn, encoded_fn;
8dbbc384
RS
561 register char *lfname, *locker;
562 lock_info_type lock_info;
3edc33a4 563 struct gcpro gcpro1;
8489eb67 564
33bae690
RS
565 /* Don't do locking while dumping Emacs.
566 Uncompressing wtmp files uses call-process, which does not work
567 in an uninitialized Emacs. */
568 if (! NILP (Vpurify_flag))
569 return;
570
5383bc6d 571 orig_fn = fn;
8af8a9ca 572 GCPRO1 (fn);
1e89de84 573 fn = Fexpand_file_name (fn, Qnil);
f4a4528d 574 encoded_fn = ENCODE_FILE (fn);
1e89de84 575
8dbbc384 576 /* Create the name of the lock-file for file fn */
f4a4528d 577 MAKE_LOCK_NAME (lfname, encoded_fn);
8489eb67 578
32676c08
JB
579 /* See if this file is visited and has changed on disk since it was
580 visited. */
8489eb67 581 {
a57bc488 582 register Lisp_Object subject_buf;
3036594f 583
5383bc6d 584 subject_buf = get_truename_buffer (orig_fn);
3036594f 585
265a9e55
JB
586 if (!NILP (subject_buf)
587 && NILP (Fverify_visited_file_modtime (subject_buf))
588 && !NILP (Ffile_exists_p (fn)))
8489eb67 589 call1 (intern ("ask-user-about-supersession-threat"), fn);
3036594f 590
8489eb67 591 }
8af8a9ca 592 UNGCPRO;
8489eb67
RS
593
594 /* Try to lock the lock. */
8dbbc384
RS
595 if (lock_if_free (&lock_info, lfname) <= 0)
596 /* Return now if we have locked it, or if lock creation failed */
8489eb67
RS
597 return;
598
599 /* Else consider breaking the lock */
266d7a00
RS
600 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
601 + LOCK_PID_MAX + 9);
79e51eeb 602 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
8dbbc384
RS
603 lock_info.pid);
604 FREE_LOCK_INFO (lock_info);
605
606 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
265a9e55 607 if (!NILP (attack))
8489eb67
RS
608 /* User says take the lock */
609 {
8dbbc384 610 lock_file_1 (lfname, 1);
8489eb67
RS
611 return;
612 }
613 /* User says ignore the lock */
614}
615
8489eb67
RS
616void
617unlock_file (fn)
618 register Lisp_Object fn;
619{
620 register char *lfname;
621
1e89de84 622 fn = Fexpand_file_name (fn, Qnil);
88eace34 623 fn = ENCODE_FILE (fn);
1e89de84 624
7b92975f 625 MAKE_LOCK_NAME (lfname, fn);
8489eb67 626
8dbbc384 627 if (current_lock_owner (0, lfname) == 2)
8489eb67 628 unlink (lfname);
8489eb67
RS
629}
630
631void
632unlock_all_files ()
633{
634 register Lisp_Object tail;
635 register struct buffer *b;
636
03699b14 637 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail))
8489eb67 638 {
03699b14 639 b = XBUFFER (XCDR (XCAR (tail)));
5757b805 640 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
1c343051
KH
641 {
642 register char *lfname;
643
644 MAKE_LOCK_NAME (lfname, b->file_truename);
645
646 if (current_lock_owner (0, lfname) == 2)
647 unlink (lfname);
648 }
8489eb67
RS
649 }
650}
8489eb67
RS
651\f
652DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
653 0, 1, 0,
654 "Lock FILE, if current buffer is modified.\n\
655FILE defaults to current buffer's visited file,\n\
656or else nothing is done if current buffer isn't visiting a file.")
e9319ef2
EN
657 (file)
658 Lisp_Object file;
8489eb67 659{
e9319ef2
EN
660 if (NILP (file))
661 file = current_buffer->file_truename;
8489eb67 662 else
e9319ef2 663 CHECK_STRING (file, 0);
6a140159 664 if (SAVE_MODIFF < MODIFF
e9319ef2
EN
665 && !NILP (file))
666 lock_file (file);
8489eb67
RS
667 return Qnil;
668}
669
670DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
671 0, 0, 0,
672 "Unlock the file visited in the current buffer,\n\
673if it should normally be locked.")
674 ()
675{
6a140159 676 if (SAVE_MODIFF < MODIFF
5757b805
RS
677 && STRINGP (current_buffer->file_truename))
678 unlock_file (current_buffer->file_truename);
8489eb67
RS
679 return Qnil;
680}
681
8489eb67
RS
682/* Unlock the file visited in buffer BUFFER. */
683
d07e0802 684void
8489eb67
RS
685unlock_buffer (buffer)
686 struct buffer *buffer;
687{
6a140159 688 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
5757b805
RS
689 && STRINGP (buffer->file_truename))
690 unlock_file (buffer->file_truename);
8489eb67
RS
691}
692
8105cbf7 693DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 1, 1, 0,
8489eb67
RS
694 "Return nil if the FILENAME is not locked,\n\
695t if it is locked by you, else a string of the name of the locker.")
e9319ef2
EN
696 (filename)
697 Lisp_Object filename;
8489eb67 698{
8dbbc384 699 Lisp_Object ret;
8489eb67
RS
700 register char *lfname;
701 int owner;
8dbbc384 702 lock_info_type locker;
8489eb67 703
e9319ef2 704 filename = Fexpand_file_name (filename, Qnil);
8489eb67 705
e9319ef2 706 MAKE_LOCK_NAME (lfname, filename);
8489eb67 707
8dbbc384 708 owner = current_lock_owner (&locker, lfname);
8489eb67 709 if (owner <= 0)
8dbbc384
RS
710 ret = Qnil;
711 else if (owner == 2)
712 ret = Qt;
713 else
714 ret = build_string (locker.user);
715
716 if (owner > 0)
717 FREE_LOCK_INFO (locker);
718
719 return ret;
8489eb67 720}
32676c08
JB
721\f
722/* Initialization functions. */
723
a3fd58aa
KH
724void
725init_filelock ()
726{
727 boot_time = 0;
b97771fc 728 boot_time_initialized = 0;
a3fd58aa
KH
729}
730
dfcf069d 731void
8489eb67
RS
732syms_of_filelock ()
733{
5f8d6a10
RS
734 DEFVAR_LISP ("temporary-file-directory", &Vtemporary_file_directory,
735 "The directory for writing temporary files.");
736 Vtemporary_file_directory = Qnil;
737
8489eb67
RS
738 defsubr (&Sunlock_buffer);
739 defsubr (&Slock_buffer);
740 defsubr (&Sfile_locked_p);
741}
742
743#endif /* CLASH_DETECTION */