*** 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 313/* Write the name of the lock file for FN into LFNAME. Length will be
c1355e1f
GM
314 that of FN plus two more for the leading `.#' plus 1 for the
315 trailing period plus one for the digit after it plus one for the
316 null. */
7b92975f 317#define MAKE_LOCK_NAME(lock, file) \
c1355e1f 318 (lock = (char *) alloca (STRING_BYTES (XSTRING (file)) + 2 + 1 + 1 + 1), \
8dbbc384 319 fill_in_lock_file_name (lock, (file)))
e31fbc7a 320
8dbbc384
RS
321static void
322fill_in_lock_file_name (lockfile, fn)
e31fbc7a
RS
323 register char *lockfile;
324 register Lisp_Object fn;
325{
8dbbc384 326 register char *p;
c1355e1f
GM
327 struct stat st;
328 int count = 0;
8dbbc384
RS
329
330 strcpy (lockfile, XSTRING (fn)->data);
331
332 /* Shift the nondirectory part of the file name (including the null)
333 right two characters. Here is one of the places where we'd have to
334 do something to support 14-character-max file names. */
335 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--)
336 p[2] = *p;
e31fbc7a 337
8dbbc384
RS
338 /* Insert the `.#'. */
339 p[1] = '.';
340 p[2] = '#';
c1355e1f
GM
341
342 p = p + strlen (p);
343
344 while (lstat (lockfile, &st) == 0 && !S_ISLNK (st.st_mode))
345 {
346 if (count > 9)
347 {
348 *p = '\0';
349 return;
350 }
351 sprintf (p, ".%d", count++);
352 }
8dbbc384 353}
e31fbc7a 354
8dbbc384
RS
355/* Lock the lock file named LFNAME.
356 If FORCE is nonzero, we do so even if it is already locked.
357 Return 1 if successful, 0 if not. */
e31fbc7a 358
8dbbc384
RS
359static int
360lock_file_1 (lfname, force)
361 char *lfname;
362 int force;
363{
364 register int err;
bd26d5a3 365 time_t boot_time;
662c2ef2
RS
366 char *user_name;
367 char *host_name;
368 char *lock_info_str;
369
370 if (STRINGP (Fuser_login_name (Qnil)))
266d7a00 371 user_name = (char *)XSTRING (Fuser_login_name (Qnil))->data;
662c2ef2
RS
372 else
373 user_name = "";
374 if (STRINGP (Fsystem_name ()))
266d7a00 375 host_name = (char *)XSTRING (Fsystem_name ())->data;
662c2ef2
RS
376 else
377 host_name = "";
266d7a00 378 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
15e88d21 379 + LOCK_PID_MAX + 5);
8dbbc384 380
bd26d5a3
RS
381 boot_time = get_boot_time ();
382 if (boot_time)
383 sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
384 (unsigned long) getpid (), (unsigned long) boot_time);
385 else
386 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
387 (unsigned long) getpid ());
8dbbc384
RS
388
389 err = symlink (lock_info_str, lfname);
390 if (errno == EEXIST && force)
e31fbc7a 391 {
8dbbc384
RS
392 unlink (lfname);
393 err = symlink (lock_info_str, lfname);
e31fbc7a 394 }
e31fbc7a 395
8dbbc384
RS
396 return err == 0;
397}
e31fbc7a 398
9177d978 399/* Return 1 if times A and B are no more than one second apart. */
32676c08 400
9177d978
RS
401int
402within_one_second (a, b)
403 time_t a, b;
404{
405 return (a - b >= -1 && a - b <= 1);
406}
8dbbc384
RS
407\f
408/* Return 0 if nobody owns the lock file LFNAME or the lock is obsolete,
409 1 if another process owns it (and set OWNER (if non-null) to info),
410 2 if the current process owns it,
411 or -1 if something is wrong with the locking mechanism. */
e31fbc7a 412
8dbbc384
RS
413static int
414current_lock_owner (owner, lfname)
415 lock_info_type *owner;
416 char *lfname;
32676c08 417{
8dbbc384
RS
418#ifndef index
419 extern char *rindex (), *index ();
420#endif
5f8d6a10 421 int len, ret;
8dbbc384 422 int local_owner = 0;
15e88d21 423 char *at, *dot, *colon;
8dbbc384
RS
424 char *lfinfo = 0;
425 int bufsize = 50;
426 /* Read arbitrarily-long contents of symlink. Similar code in
427 file-symlink-p in fileio.c. */
428 do
429 {
430 bufsize *= 2;
431 lfinfo = (char *) xrealloc (lfinfo, bufsize);
432 len = readlink (lfname, lfinfo, bufsize);
433 }
434 while (len >= bufsize);
435
436 /* If nonexistent lock file, all is well; otherwise, got strange error. */
437 if (len == -1)
438 {
439 xfree (lfinfo);
440 return errno == ENOENT ? 0 : -1;
441 }
32676c08 442
8dbbc384
RS
443 /* Link info exists, so `len' is its length. Null terminate. */
444 lfinfo[len] = 0;
445
446 /* Even if the caller doesn't want the owner info, we still have to
447 read it to determine return value, so allocate it. */
448 if (!owner)
449 {
3609a53b 450 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
8dbbc384
RS
451 local_owner = 1;
452 }
453
15e88d21 454 /* Parse USER@HOST.PID:BOOT_TIME. If can't parse, return -1. */
8dbbc384
RS
455 /* The USER is everything before the first @. */
456 at = index (lfinfo, '@');
457 dot = rindex (lfinfo, '.');
15e88d21
RS
458 if (!at || !dot)
459 {
460 xfree (lfinfo);
461 return -1;
462 }
8dbbc384
RS
463 len = at - lfinfo;
464 owner->user = (char *) xmalloc (len + 1);
465 strncpy (owner->user, lfinfo, len);
466 owner->user[len] = 0;
467
15e88d21 468 /* The PID is everything from the last `.' to the `:'. */
8dbbc384 469 owner->pid = atoi (dot + 1);
15e88d21
RS
470 colon = dot;
471 while (*colon && *colon != ':')
472 colon++;
473 /* After the `:', if there is one, comes the boot time. */
474 if (*colon == ':')
475 owner->boot_time = atoi (colon + 1);
476 else
477 owner->boot_time = 0;
32676c08 478
8dbbc384
RS
479 /* The host is everything in between. */
480 len = dot - at - 1;
481 owner->host = (char *) xmalloc (len + 1);
482 strncpy (owner->host, at + 1, len);
483 owner->host[len] = 0;
32676c08 484
8dbbc384
RS
485 /* We're done looking at the link info. */
486 xfree (lfinfo);
487
488 /* On current host? */
662c2ef2
RS
489 if (STRINGP (Fsystem_name ())
490 && strcmp (owner->host, XSTRING (Fsystem_name ())->data) == 0)
32676c08 491 {
8dbbc384
RS
492 if (owner->pid == getpid ())
493 ret = 2; /* We own it. */
72dcef0e 494 else if (owner->pid > 0
15e88d21
RS
495 && (kill (owner->pid, 0) >= 0 || errno == EPERM)
496 && (owner->boot_time == 0
9177d978 497 || within_one_second (owner->boot_time, get_boot_time ())))
8dbbc384 498 ret = 1; /* An existing process on this machine owns it. */
8dbbc384
RS
499 /* The owner process is dead or has a strange pid (<=0), so try to
500 zap the lockfile. */
72dcef0e 501 else if (unlink (lfname) < 0)
8dbbc384 502 ret = -1;
72dcef0e
RS
503 else
504 ret = 0;
32676c08 505 }
8dbbc384
RS
506 else
507 { /* If we wanted to support the check for stale locks on remote machines,
508 here's where we'd do it. */
509 ret = 1;
510 }
511
512 /* Avoid garbage. */
513 if (local_owner || ret <= 0)
514 {
515 FREE_LOCK_INFO (*owner);
516 }
517 return ret;
32676c08
JB
518}
519
8dbbc384
RS
520\f
521/* Lock the lock named LFNAME if possible.
522 Return 0 in that case.
523 Return positive if some other process owns the lock, and info about
524 that process in CLASHER.
525 Return -1 if cannot lock for any other reason. */
8489eb67 526
8dbbc384
RS
527static int
528lock_if_free (clasher, lfname)
529 lock_info_type *clasher;
530 register char *lfname;
531{
cfc01fa7 532 while (lock_file_1 (lfname, 0) == 0)
8dbbc384
RS
533 {
534 int locker;
e0e0205b 535
8dbbc384
RS
536 if (errno != EEXIST)
537 return -1;
538
539 locker = current_lock_owner (clasher, lfname);
540 if (locker == 2)
541 {
542 FREE_LOCK_INFO (*clasher);
543 return 0; /* We ourselves locked it. */
544 }
545 else if (locker == 1)
546 return 1; /* Someone else has it. */
5df0b2fa 547 else if (locker == -1)
ae1ef097 548 return -1; /* current_lock_owner returned strange error. */
8dbbc384 549
cfc01fa7 550 /* We deleted a stale lock; try again to lock the file. */
8dbbc384
RS
551 }
552 return 0;
8489eb67
RS
553}
554
8dbbc384 555/* lock_file locks file FN,
8489eb67
RS
556 meaning it serves notice on the world that you intend to edit that file.
557 This should be done only when about to modify a file-visiting
558 buffer previously unmodified.
8dbbc384 559 Do not (normally) call this for a buffer already modified,
8489eb67
RS
560 as either the file is already locked, or the user has already
561 decided to go ahead without locking.
562
8dbbc384 563 When this returns, either the lock is locked for us,
8489eb67
RS
564 or the user has said to go ahead without locking.
565
8dbbc384 566 If the file is locked by someone else, this calls
8489eb67 567 ask-user-about-lock (a Lisp function) with two arguments,
8dbbc384 568 the file name and info about the user who did the locking.
8489eb67
RS
569 This function can signal an error, or return t meaning
570 take away the lock, or return nil meaning ignore the lock. */
571
8489eb67
RS
572void
573lock_file (fn)
eb4b1c05 574 Lisp_Object fn;
8489eb67 575{
f4a4528d 576 register Lisp_Object attack, orig_fn, encoded_fn;
8dbbc384
RS
577 register char *lfname, *locker;
578 lock_info_type lock_info;
3edc33a4 579 struct gcpro gcpro1;
8489eb67 580
33bae690
RS
581 /* Don't do locking while dumping Emacs.
582 Uncompressing wtmp files uses call-process, which does not work
583 in an uninitialized Emacs. */
584 if (! NILP (Vpurify_flag))
585 return;
586
5383bc6d 587 orig_fn = fn;
8af8a9ca 588 GCPRO1 (fn);
1e89de84 589 fn = Fexpand_file_name (fn, Qnil);
f4a4528d 590 encoded_fn = ENCODE_FILE (fn);
1e89de84 591
8dbbc384 592 /* Create the name of the lock-file for file fn */
f4a4528d 593 MAKE_LOCK_NAME (lfname, encoded_fn);
8489eb67 594
32676c08
JB
595 /* See if this file is visited and has changed on disk since it was
596 visited. */
8489eb67 597 {
a57bc488 598 register Lisp_Object subject_buf;
3036594f 599
5383bc6d 600 subject_buf = get_truename_buffer (orig_fn);
3036594f 601
265a9e55
JB
602 if (!NILP (subject_buf)
603 && NILP (Fverify_visited_file_modtime (subject_buf))
604 && !NILP (Ffile_exists_p (fn)))
8489eb67 605 call1 (intern ("ask-user-about-supersession-threat"), fn);
3036594f 606
8489eb67 607 }
8af8a9ca 608 UNGCPRO;
8489eb67
RS
609
610 /* Try to lock the lock. */
8dbbc384
RS
611 if (lock_if_free (&lock_info, lfname) <= 0)
612 /* Return now if we have locked it, or if lock creation failed */
8489eb67
RS
613 return;
614
615 /* Else consider breaking the lock */
266d7a00
RS
616 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
617 + LOCK_PID_MAX + 9);
79e51eeb 618 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
8dbbc384
RS
619 lock_info.pid);
620 FREE_LOCK_INFO (lock_info);
621
622 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
265a9e55 623 if (!NILP (attack))
8489eb67
RS
624 /* User says take the lock */
625 {
8dbbc384 626 lock_file_1 (lfname, 1);
8489eb67
RS
627 return;
628 }
629 /* User says ignore the lock */
630}
631
8489eb67
RS
632void
633unlock_file (fn)
634 register Lisp_Object fn;
635{
636 register char *lfname;
637
1e89de84 638 fn = Fexpand_file_name (fn, Qnil);
88eace34 639 fn = ENCODE_FILE (fn);
1e89de84 640
7b92975f 641 MAKE_LOCK_NAME (lfname, fn);
8489eb67 642
8dbbc384 643 if (current_lock_owner (0, lfname) == 2)
8489eb67 644 unlink (lfname);
8489eb67
RS
645}
646
647void
648unlock_all_files ()
649{
650 register Lisp_Object tail;
651 register struct buffer *b;
652
03699b14 653 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail))
8489eb67 654 {
03699b14 655 b = XBUFFER (XCDR (XCAR (tail)));
5757b805 656 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
1c343051
KH
657 {
658 register char *lfname;
659
660 MAKE_LOCK_NAME (lfname, b->file_truename);
661
662 if (current_lock_owner (0, lfname) == 2)
663 unlink (lfname);
664 }
8489eb67
RS
665 }
666}
8489eb67
RS
667\f
668DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
669 0, 1, 0,
670 "Lock FILE, if current buffer is modified.\n\
671FILE defaults to current buffer's visited file,\n\
672or else nothing is done if current buffer isn't visiting a file.")
e9319ef2
EN
673 (file)
674 Lisp_Object file;
8489eb67 675{
e9319ef2
EN
676 if (NILP (file))
677 file = current_buffer->file_truename;
8489eb67 678 else
e9319ef2 679 CHECK_STRING (file, 0);
6a140159 680 if (SAVE_MODIFF < MODIFF
e9319ef2
EN
681 && !NILP (file))
682 lock_file (file);
8489eb67
RS
683 return Qnil;
684}
685
686DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
687 0, 0, 0,
688 "Unlock the file visited in the current buffer,\n\
689if it should normally be locked.")
690 ()
691{
6a140159 692 if (SAVE_MODIFF < MODIFF
5757b805
RS
693 && STRINGP (current_buffer->file_truename))
694 unlock_file (current_buffer->file_truename);
8489eb67
RS
695 return Qnil;
696}
697
8489eb67
RS
698/* Unlock the file visited in buffer BUFFER. */
699
d07e0802 700void
8489eb67
RS
701unlock_buffer (buffer)
702 struct buffer *buffer;
703{
6a140159 704 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
5757b805
RS
705 && STRINGP (buffer->file_truename))
706 unlock_file (buffer->file_truename);
8489eb67
RS
707}
708
8105cbf7 709DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 1, 1, 0,
8489eb67
RS
710 "Return nil if the FILENAME is not locked,\n\
711t if it is locked by you, else a string of the name of the locker.")
e9319ef2
EN
712 (filename)
713 Lisp_Object filename;
8489eb67 714{
8dbbc384 715 Lisp_Object ret;
8489eb67
RS
716 register char *lfname;
717 int owner;
8dbbc384 718 lock_info_type locker;
8489eb67 719
e9319ef2 720 filename = Fexpand_file_name (filename, Qnil);
8489eb67 721
e9319ef2 722 MAKE_LOCK_NAME (lfname, filename);
8489eb67 723
8dbbc384 724 owner = current_lock_owner (&locker, lfname);
8489eb67 725 if (owner <= 0)
8dbbc384
RS
726 ret = Qnil;
727 else if (owner == 2)
728 ret = Qt;
729 else
730 ret = build_string (locker.user);
731
732 if (owner > 0)
733 FREE_LOCK_INFO (locker);
734
735 return ret;
8489eb67 736}
32676c08
JB
737\f
738/* Initialization functions. */
739
a3fd58aa
KH
740void
741init_filelock ()
742{
743 boot_time = 0;
b97771fc 744 boot_time_initialized = 0;
a3fd58aa
KH
745}
746
dfcf069d 747void
8489eb67
RS
748syms_of_filelock ()
749{
5f8d6a10
RS
750 DEFVAR_LISP ("temporary-file-directory", &Vtemporary_file_directory,
751 "The directory for writing temporary files.");
752 Vtemporary_file_directory = Qnil;
753
8489eb67
RS
754 defsubr (&Sunlock_buffer);
755 defsubr (&Slock_buffer);
756 defsubr (&Sfile_locked_p);
757}
758
759#endif /* CLASH_DETECTION */