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