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