Change in file-locked-p argument.
[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
15e88d21
RS
123static time_t
124get_boot_time ()
125{
2decc5a9 126#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
9177d978 127 int counter;
2decc5a9 128#endif
15e88d21 129
b97771fc 130 if (boot_time_initialized)
15e88d21 131 return boot_time;
b97771fc 132 boot_time_initialized = 1;
15e88d21 133
f805a125
KH
134#if defined (CTL_KERN) && defined (KERN_BOOTTIME)
135 {
136 int mib[2];
137 size_t size;
138 struct timeval boottime_val;
139
140 mib[0] = CTL_KERN;
141 mib[1] = KERN_BOOTTIME;
142 size = sizeof (boottime_val);
143
144 if (sysctl (mib, 2, &boottime_val, &size, NULL, 0) >= 0)
145 {
146 boot_time = boottime_val.tv_sec;
147 return boot_time;
148 }
149 }
150#endif /* defined (CTL_KERN) && defined (KERN_BOOTTIME) */
9177d978 151
a48de9b2
PE
152 if (BOOT_TIME_FILE)
153 {
154 struct stat st;
155 if (stat (BOOT_TIME_FILE, &st) == 0)
156 {
157 boot_time = st.st_mtime;
158 return boot_time;
159 }
160 }
161
c6fd1dc4 162#if defined (BOOT_TIME) && ! defined (NO_WTMP_FILE)
b97771fc
RS
163#ifndef CANNOT_DUMP
164 /* The utmp routines maintain static state.
165 Don't touch that state unless we are initialized,
166 since it might not survive dumping. */
167 if (! initialized)
168 return boot_time;
169#endif /* not CANNOT_DUMP */
170
171 /* Try to get boot time from utmp before wtmp,
172 since utmp is typically much smaller than wtmp.
173 Passing a null pointer causes get_boot_time_1
174 to inspect the default file, namely utmp. */
175 get_boot_time_1 ((char *) 0, 0);
176 if (boot_time)
177 return boot_time;
178
9177d978 179 /* Try to get boot time from the current wtmp file. */
b97771fc 180 get_boot_time_1 (WTMP_FILE, 1);
9177d978
RS
181
182 /* If we did not find a boot time in wtmp, look at wtmp, and so on. */
b97771fc 183 for (counter = 0; counter < 20 && ! boot_time; counter++)
9177d978
RS
184 {
185 char cmd_string[100];
186 Lisp_Object tempname, filename;
187 int delete_flag = 0;
188
189 filename = Qnil;
190
77e544a4 191 sprintf (cmd_string, "%s.%d", WTMP_FILE, counter);
9177d978 192 tempname = build_string (cmd_string);
29a2adb0 193 if (! NILP (Ffile_exists_p (tempname)))
9177d978
RS
194 filename = tempname;
195 else
196 {
77e544a4 197 sprintf (cmd_string, "%s.%d.gz", WTMP_FILE, counter);
9177d978
RS
198 tempname = build_string (cmd_string);
199 if (! NILP (Ffile_exists_p (tempname)))
200 {
201 Lisp_Object args[6];
5f8d6a10
RS
202 tempname = Fexpand_file_name (build_string ("wtmp"),
203 Vtemporary_file_directory);
204 tempname = Fmake_temp_name (tempname);
9177d978
RS
205 args[0] = Vshell_file_name;
206 args[1] = Qnil;
207 args[2] = Qnil;
208 args[3] = Qnil;
209 args[4] = build_string ("-c");
77e544a4
RS
210 sprintf (cmd_string, "gunzip < %s.%d.gz > %s",
211 WTMP_FILE, counter, XSTRING (tempname)->data);
9177d978
RS
212 args[5] = build_string (cmd_string);
213 Fcall_process (6, args);
214 filename = tempname;
215 delete_flag = 1;
216 }
217 }
218
219 if (! NILP (filename))
220 {
b97771fc 221 get_boot_time_1 (XSTRING (filename)->data, 1);
9177d978
RS
222 if (delete_flag)
223 unlink (XSTRING (filename)->data);
224 }
225 }
226
227 return boot_time;
228#else
229 return 0;
230#endif
231}
232
e9f22ced 233#ifdef BOOT_TIME
9177d978
RS
234/* Try to get the boot time from wtmp file FILENAME.
235 This succeeds if that file contains a reboot record.
9177d978 236
b97771fc
RS
237 If FILENAME is zero, use the same file as before;
238 if no FILENAME has ever been specified, this is the utmp file.
239 Use the newest reboot record if NEWEST is nonzero,
240 the first reboot record otherwise.
241 Ignore all reboot records on or before BOOT_TIME.
242 Success is indicated by setting BOOT_TIME to a larger value. */
243
244get_boot_time_1 (filename, newest)
9177d978 245 char *filename;
b97771fc 246 int newest;
9177d978
RS
247{
248 struct utmp ut, *utp;
77e544a4
RS
249 int desc;
250
b97771fc
RS
251 if (filename)
252 {
253 /* On some versions of IRIX, opening a nonexistent file name
254 is likely to crash in the utmp routines. */
68c45bf0 255 desc = emacs_open (filename, O_RDONLY, 0);
b97771fc
RS
256 if (desc < 0)
257 return;
258
68c45bf0 259 emacs_close (desc);
b97771fc
RS
260
261 utmpname (filename);
262 }
9177d978 263
c321b190 264 setutent ();
b97771fc 265
c321b190
RS
266 while (1)
267 {
268 /* Find the next reboot record. */
269 ut.ut_type = BOOT_TIME;
270 utp = getutid (&ut);
271 if (! utp)
272 break;
273 /* Compare reboot times and use the newest one. */
274 if (utp->ut_time > boot_time)
b97771fc
RS
275 {
276 boot_time = utp->ut_time;
277 if (! newest)
278 break;
279 }
c321b190
RS
280 /* Advance on element in the file
281 so that getutid won't repeat the same one. */
282 utp = getutent ();
283 if (! utp)
284 break;
285 }
15e88d21 286 endutent ();
15e88d21 287}
e9f22ced 288#endif /* BOOT_TIME */
15e88d21 289\f
8dbbc384 290/* Here is the structure that stores information about a lock. */
32676c08 291
8dbbc384
RS
292typedef struct
293{
294 char *user;
295 char *host;
9005cb4f 296 unsigned long pid;
15e88d21 297 time_t boot_time;
8dbbc384 298} lock_info_type;
32676c08 299
49b6d120
RS
300/* When we read the info back, we might need this much more,
301 enough for decimal representation plus null. */
302#define LOCK_PID_MAX (4 * sizeof (unsigned long))
32676c08 303
8dbbc384
RS
304/* Free the two dynamically-allocated pieces in PTR. */
305#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
e31fbc7a 306
e31fbc7a 307
8dbbc384
RS
308/* Write the name of the lock file for FN into LFNAME. Length will be
309 that of FN plus two more for the leading `.#' plus one for the null. */
7b92975f 310#define MAKE_LOCK_NAME(lock, file) \
fc932ac6 311 (lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1), \
8dbbc384 312 fill_in_lock_file_name (lock, (file)))
e31fbc7a 313
8dbbc384
RS
314static void
315fill_in_lock_file_name (lockfile, fn)
e31fbc7a
RS
316 register char *lockfile;
317 register Lisp_Object fn;
318{
8dbbc384
RS
319 register char *p;
320
321 strcpy (lockfile, XSTRING (fn)->data);
322
323 /* Shift the nondirectory part of the file name (including the null)
324 right two characters. Here is one of the places where we'd have to
325 do something to support 14-character-max file names. */
326 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
327 p[2] = *p;
e31fbc7a 328
8dbbc384
RS
329 /* Insert the `.#'. */
330 p[1] = '.';
331 p[2] = '#';
332}
e31fbc7a 333
8dbbc384
RS
334/* Lock the lock file named LFNAME.
335 If FORCE is nonzero, we do so even if it is already locked.
336 Return 1 if successful, 0 if not. */
e31fbc7a 337
8dbbc384
RS
338static int
339lock_file_1 (lfname, force)
340 char *lfname;
341 int force;
342{
343 register int err;
bd26d5a3 344 time_t boot_time;
662c2ef2
RS
345 char *user_name;
346 char *host_name;
347 char *lock_info_str;
348
349 if (STRINGP (Fuser_login_name (Qnil)))
266d7a00 350 user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
662c2ef2
RS
351 else
352 user_name = "";
353 if (STRINGP (Fsystem_name ()))
266d7a00 354 host_name = (char *)XSTRING (Fsystem_name ())->data;
662c2ef2
RS
355 else
356 host_name = "";
266d7a00 357 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
15e88d21 358 + LOCK_PID_MAX + 5);
8dbbc384 359
bd26d5a3
RS
360 boot_time = get_boot_time ();
361 if (boot_time)
362 sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
363 (unsigned long) getpid (), (unsigned long) boot_time);
364 else
365 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
366 (unsigned long) getpid ());
8dbbc384
RS
367
368 err = symlink (lock_info_str, lfname);
369 if (errno == EEXIST && force)
e31fbc7a 370 {
8dbbc384
RS
371 unlink (lfname);
372 err = symlink (lock_info_str, lfname);
e31fbc7a 373 }
e31fbc7a 374
8dbbc384
RS
375 return err == 0;
376}
e31fbc7a 377
9177d978 378/* Return 1 if times A and B are no more than one second apart. */
32676c08 379
9177d978
RS
380int
381within_one_second (a, b)
382 time_t a, b;
383{
384 return (a - b >= -1 && a - b <= 1);
385}
8dbbc384
RS
386\f
387/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
388 1 if another process owns it (and set OWNER (if non-null) to info),
389 2 if the current process owns it,
390 or -1 if something is wrong with the locking mechanism. */
e31fbc7a 391
8dbbc384
RS
392static int
393current_lock_owner (owner, lfname)
394 lock_info_type *owner;
395 char *lfname;
32676c08 396{
8dbbc384
RS
397#ifndef index
398 extern char *rindex (), *index ();
399#endif
5f8d6a10 400 int len, ret;
8dbbc384 401 int local_owner = 0;
15e88d21 402 char *at, *dot, *colon;
8dbbc384
RS
403 char *lfinfo = 0;
404 int bufsize = 50;
405 /* Read arbitrarily-long contents of symlink. Similar code in
406 file-symlink-p in fileio.c. */
407 do
408 {
409 bufsize *= 2;
410 lfinfo = (char *) xrealloc (lfinfo, bufsize);
411 len = readlink (lfname, lfinfo, bufsize);
412 }
413 while (len >= bufsize);
414
415 /* If nonexistent lock file, all is well; otherwise, got strange error. */
416 if (len == -1)
417 {
418 xfree (lfinfo);
419 return errno == ENOENT ? 0 : -1;
420 }
32676c08 421
8dbbc384
RS
422 /* Link info exists, so `len' is its length. Null terminate. */
423 lfinfo[len] = 0;
424
425 /* Even if the caller doesn't want the owner info, we still have to
426 read it to determine return value, so allocate it. */
427 if (!owner)
428 {
3609a53b 429 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
8dbbc384
RS
430 local_owner = 1;
431 }
432
15e88d21 433 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
8dbbc384
RS
434 /* The USER is everything before the first @. */
435 at = index (lfinfo, '@');
436 dot = rindex (lfinfo, '.');
15e88d21
RS
437 if (!at || !dot)
438 {
439 xfree (lfinfo);
440 return -1;
441 }
8dbbc384
RS
442 len = at - lfinfo;
443 owner->user = (char *) xmalloc (len + 1);
444 strncpy (owner->user, lfinfo, len);
445 owner->user[len] = 0;
446
15e88d21 447 /* The PID is everything from the last `.' to the `:'. */
8dbbc384 448 owner->pid = atoi (dot + 1);
15e88d21
RS
449 colon = dot;
450 while (*colon && *colon != ':')
451 colon++;
452 /* After the `:', if there is one, comes the boot time. */
453 if (*colon == ':')
454 owner->boot_time = atoi (colon + 1);
455 else
456 owner->boot_time = 0;
32676c08 457
8dbbc384
RS
458 /* The host is everything in between. */
459 len = dot - at - 1;
460 owner->host = (char *) xmalloc (len + 1);
461 strncpy (owner->host, at + 1, len);
462 owner->host[len] = 0;
32676c08 463
8dbbc384
RS
464 /* We're done looking at the link info. */
465 xfree (lfinfo);
466
467 /* On current host? */
662c2ef2
RS
468 if (STRINGP (Fsystem_name ())
469 && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
32676c08 470 {
8dbbc384
RS
471 if (owner->pid == getpid ())
472 ret = 2; /* We own it. */
72dcef0e 473 else if (owner->pid > 0
15e88d21
RS
474 && (kill (owner->pid, 0) >= 0 || errno == EPERM)
475 && (owner->boot_time == 0
9177d978 476 || within_one_second (owner->boot_time, get_boot_time ())))
8dbbc384 477 ret = 1; /* An existing process on this machine owns it. */
8dbbc384
RS
478 /* The owner process is dead or has a strange pid (<=0), so try to
479 zap the lockfile. */
72dcef0e 480 else if (unlink (lfname) < 0)
8dbbc384 481 ret = -1;
72dcef0e
RS
482 else
483 ret = 0;
32676c08 484 }
8dbbc384
RS
485 else
486 { /* If we wanted to support the check for stale locks on remote machines,
487 here's where we'd do it. */
488 ret = 1;
489 }
490
491 /* Avoid garbage. */
492 if (local_owner || ret <= 0)
493 {
494 FREE_LOCK_INFO (*owner);
495 }
496 return ret;
32676c08
JB
497}
498
8dbbc384
RS
499\f
500/* Lock the lock named LFNAME if possible.
501 Return 0 in that case.
502 Return positive if some other process owns the lock, and info about
503 that process in CLASHER.
504 Return -1 if cannot lock for any other reason. */
8489eb67 505
8dbbc384
RS
506static int
507lock_if_free (clasher, lfname)
508 lock_info_type *clasher;
509 register char *lfname;
510{
cfc01fa7 511 while (lock_file_1 (lfname, 0) == 0)
8dbbc384
RS
512 {
513 int locker;
e0e0205b 514
8dbbc384
RS
515 if (errno != EEXIST)
516 return -1;
517
518 locker = current_lock_owner (clasher, lfname);
519 if (locker == 2)
520 {
521 FREE_LOCK_INFO (*clasher);
522 return 0; /* We ourselves locked it. */
523 }
524 else if (locker == 1)
525 return 1; /* Someone else has it. */
5df0b2fa 526 else if (locker == -1)
ae1ef097 527 return -1; /* current_lock_owner returned strange error. */
8dbbc384 528
cfc01fa7 529 /* We deleted a stale lock; try again to lock the file. */
8dbbc384
RS
530 }
531 return 0;
8489eb67
RS
532}
533
8dbbc384 534/* lock_file locks file FN,
8489eb67
RS
535 meaning it serves notice on the world that you intend to edit that file.
536 This should be done only when about to modify a file-visiting
537 buffer previously unmodified.
8dbbc384 538 Do not (normally) call this for a buffer already modified,
8489eb67
RS
539 as either the file is already locked, or the user has already
540 decided to go ahead without locking.
541
8dbbc384 542 When this returns, either the lock is locked for us,
8489eb67
RS
543 or the user has said to go ahead without locking.
544
8dbbc384 545 If the file is locked by someone else, this calls
8489eb67 546 ask-user-about-lock (a Lisp function) with two arguments,
8dbbc384 547 the file name and info about the user who did the locking.
8489eb67
RS
548 This function can signal an error, or return t meaning
549 take away the lock, or return nil meaning ignore the lock. */
550
8489eb67
RS
551void
552lock_file (fn)
eb4b1c05 553 Lisp_Object fn;
8489eb67 554{
f4a4528d 555 register Lisp_Object attack, orig_fn, encoded_fn;
8dbbc384
RS
556 register char *lfname, *locker;
557 lock_info_type lock_info;
3edc33a4 558 struct gcpro gcpro1;
8489eb67 559
33bae690
RS
560 /* Don't do locking while dumping Emacs.
561 Uncompressing wtmp files uses call-process, which does not work
562 in an uninitialized Emacs. */
563 if (! NILP (Vpurify_flag))
564 return;
565
5383bc6d 566 orig_fn = fn;
8af8a9ca 567 GCPRO1 (fn);
1e89de84 568 fn = Fexpand_file_name (fn, Qnil);
f4a4528d 569 encoded_fn = ENCODE_FILE (fn);
1e89de84 570
8dbbc384 571 /* Create the name of the lock-file for file fn */
f4a4528d 572 MAKE_LOCK_NAME (lfname, encoded_fn);
8489eb67 573
32676c08
JB
574 /* See if this file is visited and has changed on disk since it was
575 visited. */
8489eb67 576 {
a57bc488 577 register Lisp_Object subject_buf;
3036594f 578
5383bc6d 579 subject_buf = get_truename_buffer (orig_fn);
3036594f 580
265a9e55
JB
581 if (!NILP (subject_buf)
582 && NILP (Fverify_visited_file_modtime (subject_buf))
583 && !NILP (Ffile_exists_p (fn)))
8489eb67 584 call1 (intern ("ask-user-about-supersession-threat"), fn);
3036594f 585
8489eb67 586 }
8af8a9ca 587 UNGCPRO;
8489eb67
RS
588
589 /* Try to lock the lock. */
8dbbc384
RS
590 if (lock_if_free (&lock_info, lfname) <= 0)
591 /* Return now if we have locked it, or if lock creation failed */
8489eb67
RS
592 return;
593
594 /* Else consider breaking the lock */
266d7a00
RS
595 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
596 + LOCK_PID_MAX + 9);
79e51eeb 597 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
8dbbc384
RS
598 lock_info.pid);
599 FREE_LOCK_INFO (lock_info);
600
601 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
265a9e55 602 if (!NILP (attack))
8489eb67
RS
603 /* User says take the lock */
604 {
8dbbc384 605 lock_file_1 (lfname, 1);
8489eb67
RS
606 return;
607 }
608 /* User says ignore the lock */
609}
610
8489eb67
RS
611void
612unlock_file (fn)
613 register Lisp_Object fn;
614{
615 register char *lfname;
616
1e89de84 617 fn = Fexpand_file_name (fn, Qnil);
88eace34 618 fn = ENCODE_FILE (fn);
1e89de84 619
7b92975f 620 MAKE_LOCK_NAME (lfname, fn);
8489eb67 621
8dbbc384 622 if (current_lock_owner (0, lfname) == 2)
8489eb67 623 unlink (lfname);
8489eb67
RS
624}
625
626void
627unlock_all_files ()
628{
629 register Lisp_Object tail;
630 register struct buffer *b;
631
03699b14 632 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail))
8489eb67 633 {
03699b14 634 b = XBUFFER (XCDR (XCAR (tail)));
5757b805 635 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
1c343051
KH
636 {
637 register char *lfname;
638
639 MAKE_LOCK_NAME (lfname, b->file_truename);
640
641 if (current_lock_owner (0, lfname) == 2)
642 unlink (lfname);
643 }
8489eb67
RS
644 }
645}
8489eb67
RS
646\f
647DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
648 0, 1, 0,
649 "Lock FILE, if current buffer is modified.\n\
650FILE defaults to current buffer's visited file,\n\
651or else nothing is done if current buffer isn't visiting a file.")
e9319ef2
EN
652 (file)
653 Lisp_Object file;
8489eb67 654{
e9319ef2
EN
655 if (NILP (file))
656 file = current_buffer->file_truename;
8489eb67 657 else
e9319ef2 658 CHECK_STRING (file, 0);
6a140159 659 if (SAVE_MODIFF < MODIFF
e9319ef2
EN
660 && !NILP (file))
661 lock_file (file);
8489eb67
RS
662 return Qnil;
663}
664
665DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
666 0, 0, 0,
667 "Unlock the file visited in the current buffer,\n\
668if it should normally be locked.")
669 ()
670{
6a140159 671 if (SAVE_MODIFF < MODIFF
5757b805
RS
672 && STRINGP (current_buffer->file_truename))
673 unlock_file (current_buffer->file_truename);
8489eb67
RS
674 return Qnil;
675}
676
8489eb67
RS
677/* Unlock the file visited in buffer BUFFER. */
678
d07e0802 679void
8489eb67
RS
680unlock_buffer (buffer)
681 struct buffer *buffer;
682{
6a140159 683 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
5757b805
RS
684 && STRINGP (buffer->file_truename))
685 unlock_file (buffer->file_truename);
8489eb67
RS
686}
687
688DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0,
689 "Return nil if the FILENAME is not locked,\n\
690t if it is locked by you, else a string of the name of the locker.")
e9319ef2
EN
691 (filename)
692 Lisp_Object filename;
8489eb67 693{
8dbbc384 694 Lisp_Object ret;
8489eb67
RS
695 register char *lfname;
696 int owner;
8dbbc384 697 lock_info_type locker;
8489eb67 698
e9319ef2 699 filename = Fexpand_file_name (filename, Qnil);
8489eb67 700
e9319ef2 701 MAKE_LOCK_NAME (lfname, filename);
8489eb67 702
8dbbc384 703 owner = current_lock_owner (&locker, lfname);
8489eb67 704 if (owner <= 0)
8dbbc384
RS
705 ret = Qnil;
706 else if (owner == 2)
707 ret = Qt;
708 else
709 ret = build_string (locker.user);
710
711 if (owner > 0)
712 FREE_LOCK_INFO (locker);
713
714 return ret;
8489eb67 715}
32676c08
JB
716\f
717/* Initialization functions. */
718
a3fd58aa
KH
719void
720init_filelock ()
721{
722 boot_time = 0;
b97771fc 723 boot_time_initialized = 0;
a3fd58aa
KH
724}
725
dfcf069d 726void
8489eb67
RS
727syms_of_filelock ()
728{
5f8d6a10
RS
729 DEFVAR_LISP ("temporary-file-directory", &Vtemporary_file_directory,
730 "The directory for writing temporary files.");
731 Vtemporary_file_directory = Qnil;
732
8489eb67
RS
733 defsubr (&Sunlock_buffer);
734 defsubr (&Slock_buffer);
735 defsubr (&Sfile_locked_p);
736}
737
738#endif /* CLASH_DETECTION */