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