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