This source file includes following definitions.
- get_boot_sec
- rename_lock_file
- create_lock_file
- lock_file_1
- within_one_second
- read_lock_data
- current_lock_owner
- lock_if_free
- make_lock_file_name
- lock_file
- unlock_file
- unlock_file_handle_error
- unlock_all_files
- DEFUN
- DEFUN
- DEFUN
- DEFUN
- unlock_buffer
- DEFUN
- syms_of_filelock
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 #include <config.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <signal.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31
32 #ifdef HAVE_PWD_H
33 #include <pwd.h>
34 #endif
35
36 #include <sys/file.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <errno.h>
40
41 #include <boot-time.h>
42 #include <c-ctype.h>
43
44 #include "lisp.h"
45 #include "buffer.h"
46 #include "coding.h"
47 #ifdef WINDOWSNT
48 #include <share.h>
49 #include <sys/socket.h>
50 #endif
51
52 #ifndef MSDOS
53
54 #ifdef HAVE_ANDROID
55 #include "android.h"
56 #endif
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113 static time_t
114 get_boot_sec (void)
115 {
116
117
118 if (will_dump_p ())
119 return 0;
120
121 struct timespec boot_time;
122 boot_time.tv_sec = 0;
123 get_boot_time (&boot_time);
124 return boot_time.tv_sec;
125 }
126
127
128
129 enum { MAX_LFINFO = 8 * 1024 };
130
131
132
133 typedef struct
134 {
135
136
137 char *at, *dot, *colon;
138
139
140
141
142
143
144 char user[MAX_LFINFO + 1 + sizeof " (pid )" - sizeof "."];
145 } lock_info_type;
146
147
148
149
150
151
152 enum { LINKS_MIGHT_NOT_WORK = EPERM };
153
154
155
156
157 static int
158 rename_lock_file (char const *old, char const *new, bool force)
159 {
160 #ifdef WINDOWSNT
161 return sys_rename_replace (old, new, force);
162 #else
163 if (! force)
164 {
165 struct stat st;
166
167 int r = emacs_renameat_noreplace (AT_FDCWD, old,
168 AT_FDCWD, new);
169 if (! (r < 0 && errno == ENOSYS))
170 return r;
171 if (link (old, new) == 0)
172 return emacs_unlink (old) == 0 || errno == ENOENT ? 0 : -1;
173 if (errno != ENOSYS && errno != LINKS_MIGHT_NOT_WORK)
174 return -1;
175
176
177
178
179
180
181
182 if (emacs_fstatat (AT_FDCWD, new, &st, AT_SYMLINK_NOFOLLOW) == 0
183 || errno == EOVERFLOW)
184 {
185 errno = EEXIST;
186 return -1;
187 }
188 if (errno != ENOENT)
189 return -1;
190 }
191
192 return emacs_rename (old, new);
193 #endif
194 }
195
196
197
198
199
200 static int
201 create_lock_file (char *lfname, char *lock_info_str, bool force)
202 {
203 #ifdef WINDOWSNT
204
205
206
207
208 int err = ENOSYS;
209 #else
210 int err = emacs_symlink (lock_info_str, lfname) == 0 ? 0 : errno;
211 #endif
212
213 if (err == EEXIST && force)
214 {
215 emacs_unlink (lfname);
216 err = emacs_symlink (lock_info_str, lfname) == 0 ? 0 : errno;
217 }
218
219 if (err == ENOSYS || err == LINKS_MIGHT_NOT_WORK || err == ENAMETOOLONG)
220 {
221 static char const nonce_base[] = ".#-emacsXXXXXX";
222 char *last_slash = strrchr (lfname, '/');
223 ptrdiff_t lfdirlen = last_slash + 1 - lfname;
224 USE_SAFE_ALLOCA;
225 char *nonce = SAFE_ALLOCA (lfdirlen + sizeof nonce_base);
226 int fd;
227 memcpy (nonce, lfname, lfdirlen);
228 strcpy (nonce + lfdirlen, nonce_base);
229
230 fd = mkostemp (nonce, O_BINARY | O_CLOEXEC);
231 if (fd < 0)
232 err = errno;
233 else
234 {
235 ptrdiff_t lock_info_len;
236 lock_info_len = strlen (lock_info_str);
237 err = 0;
238
239
240
241
242
243 if (emacs_write (fd, lock_info_str, lock_info_len) != lock_info_len
244 || fchmod (fd, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) != 0)
245 err = errno;
246
247
248
249 if (emacs_close (fd) != 0)
250 err = errno;
251 if (!err && rename_lock_file (nonce, lfname, force) != 0)
252 err = errno;
253 if (err)
254 emacs_unlink (nonce);
255 }
256
257 SAFE_FREE ();
258 }
259
260 return err;
261 }
262
263
264
265
266
267 static int
268 lock_file_1 (Lisp_Object lfname, bool force)
269 {
270 intmax_t boot = get_boot_sec ();
271 Lisp_Object luser_name = Fuser_login_name (Qnil);
272 Lisp_Object lhost_name = Fsystem_name ();
273
274
275
276 if (!NILP (lhost_name) && strchr (SSDATA (lhost_name), '@'))
277 lhost_name = CALLN (Ffuncall, intern ("string-replace"),
278 build_string ("@"), build_string ("-"),
279 lhost_name);
280
281 char const *user_name = STRINGP (luser_name) ? SSDATA (luser_name) : "";
282 char const *host_name = STRINGP (lhost_name) ? SSDATA (lhost_name) : "";
283 char lock_info_str[MAX_LFINFO + 1];
284 intmax_t pid = getpid ();
285
286 char const *lock_info_fmt = (boot
287 ? "%s@%s.%"PRIdMAX":%"PRIdMAX
288 : "%s@%s.%"PRIdMAX);
289 int len = snprintf (lock_info_str, sizeof lock_info_str,
290 lock_info_fmt, user_name, host_name, pid, boot);
291 if (! (0 <= len && len < sizeof lock_info_str))
292 return ENAMETOOLONG;
293
294 return create_lock_file (SSDATA (lfname), lock_info_str, force);
295 }
296
297
298
299 static bool
300 within_one_second (time_t a, time_t b)
301 {
302 return (a - b >= -1 && a - b <= 1);
303 }
304
305
306 #ifndef ELOOP
307 # define ELOOP (-1)
308 #endif
309
310
311
312
313
314 static ptrdiff_t
315 read_lock_data (char *lfname, char lfinfo[MAX_LFINFO + 1])
316 {
317 ptrdiff_t nbytes;
318
319 while ((nbytes = readlinkat (AT_FDCWD, lfname, lfinfo, MAX_LFINFO + 1)) < 0
320 && errno == EINVAL)
321 {
322 int fd = emacs_open (lfname, O_RDONLY | O_NOFOLLOW, 0);
323 if (0 <= fd)
324 {
325 ptrdiff_t read_bytes = emacs_read (fd, lfinfo, MAX_LFINFO + 1);
326 int read_errno = errno;
327 if (emacs_close (fd) != 0)
328 return -1;
329 errno = read_errno;
330 return read_bytes;
331 }
332
333 if (errno != ELOOP)
334 return -1;
335
336
337
338
339 maybe_quit ();
340 }
341
342 return nbytes;
343 }
344
345
346
347 enum { NEGATIVE_ERRNO = EDOM < 0 };
348
349
350 enum
351 {
352
353 ANOTHER_OWNS_IT = NEGATIVE_ERRNO ? 1 : -1,
354
355
356 I_OWN_IT = 2 * ANOTHER_OWNS_IT
357 };
358
359
360
361
362
363
364
365 static int
366 current_lock_owner (lock_info_type *owner, Lisp_Object lfname)
367 {
368 lock_info_type local_owner;
369 ptrdiff_t lfinfolen;
370 intmax_t pid, boot_time;
371 char *at, *dot, *lfinfo_end;
372
373
374
375 if (!owner)
376 owner = &local_owner;
377
378
379 lfinfolen = read_lock_data (SSDATA (lfname), owner->user);
380 if (lfinfolen < 0)
381 return errno == ENOENT || errno == ENOTDIR ? 0 : errno;
382 if (MAX_LFINFO < lfinfolen)
383 return ENAMETOOLONG;
384 owner->user[lfinfolen] = 0;
385
386
387
388 owner->at = at = memrchr (owner->user, '@', lfinfolen);
389 if (!at)
390 return EINVAL;
391 owner->dot = dot = strrchr (at, '.');
392 if (!dot)
393 return EINVAL;
394
395
396 if (! c_isdigit (dot[1]))
397 return EINVAL;
398 errno = 0;
399 pid = strtoimax (dot + 1, &owner->colon, 10);
400 if (errno == ERANGE)
401 pid = -1;
402
403
404 char *boot = owner->colon + 1;
405 switch (owner->colon[0])
406 {
407 case 0:
408 boot_time = 0;
409 lfinfo_end = owner->colon;
410 break;
411
412 case '\357':
413
414
415
416
417 if (! (boot[0] == '\200' && boot[1] == '\242'))
418 return EINVAL;
419 boot += 2;
420 FALLTHROUGH;
421 case ':':
422 if (! c_isdigit (boot[0]))
423 return EINVAL;
424 boot_time = strtoimax (boot, &lfinfo_end, 10);
425 break;
426
427 default:
428 return EINVAL;
429 }
430 if (lfinfo_end != owner->user + lfinfolen)
431 return EINVAL;
432
433 Lisp_Object system_name = Fsystem_name ();
434
435
436
437 if (NILP (system_name))
438 system_name = build_string ("");
439
440
441 else if (strchr (SSDATA (system_name), '@'))
442 system_name = CALLN (Ffuncall, intern ("string-replace"),
443 build_string ("@"), build_string ("-"),
444 system_name);
445
446 if (STRINGP (system_name)
447 && dot - (at + 1) == SBYTES (system_name)
448 && memcmp (at + 1, SSDATA (system_name), SBYTES (system_name)) == 0)
449 {
450 if (pid == getpid ())
451 return I_OWN_IT;
452 else if (0 < pid && pid <= TYPE_MAXIMUM (pid_t)
453 && (kill (pid, 0) >= 0 || errno == EPERM)
454 && (boot_time == 0
455 || (boot_time <= TYPE_MAXIMUM (time_t)
456 && within_one_second (boot_time, get_boot_sec ()))))
457 return ANOTHER_OWNS_IT;
458
459
460 else
461 return emacs_unlink (SSDATA (lfname)) < 0 ? errno : 0;
462 }
463 else
464 {
465
466 return ANOTHER_OWNS_IT;
467 }
468 }
469
470
471
472
473
474
475
476
477 static int
478 lock_if_free (lock_info_type *clasher, Lisp_Object lfname)
479 {
480 int err;
481 while ((err = lock_file_1 (lfname, 0)) == EEXIST)
482 {
483 err = current_lock_owner (clasher, lfname);
484
485
486
487 if (err != 0)
488 return err == I_OWN_IT ? 0 : err;
489
490
491
492 }
493
494 return err;
495 }
496
497
498
499 static Lisp_Object
500 make_lock_file_name (Lisp_Object fn)
501 {
502 Lisp_Object lock_file_name;
503 #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
504 char *name;
505 #endif
506
507 fn = Fexpand_file_name (fn, Qnil);
508
509 #if defined HAVE_ANDROID && !defined ANDROID_STUBIFY
510
511
512
513
514 name = SSDATA (fn);
515
516 if (android_is_special_directory (name, "/assets")
517 || android_is_special_directory (name, "/content"))
518 return Qnil;
519 #endif
520
521 lock_file_name = call1 (Qmake_lock_file_name, fn);
522
523 return !NILP (lock_file_name) ? ENCODE_FILE (lock_file_name) : Qnil;
524 }
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544 static Lisp_Object
545 lock_file (Lisp_Object fn)
546 {
547 lock_info_type lock_info;
548
549
550
551
552 if (will_dump_p ())
553 return Qnil;
554
555 Lisp_Object lfname = Qnil;
556 if (create_lockfiles)
557 {
558
559 lfname = make_lock_file_name (fn);
560 if (NILP (lfname))
561 return Qnil;
562 }
563
564
565
566 Lisp_Object subject_buf = get_truename_buffer (fn);
567 if (!NILP (subject_buf)
568 && NILP (Fverify_visited_file_modtime (subject_buf))
569 && !NILP (Ffile_exists_p (fn))
570 && !(!NILP (lfname) && current_lock_owner (NULL, lfname) == I_OWN_IT))
571 call1 (intern ("userlock--ask-user-about-supersession-threat"), fn);
572
573
574 if (!NILP (lfname))
575 {
576
577
578 if (lock_if_free (&lock_info, lfname) == ANOTHER_OWNS_IT)
579 {
580
581 Lisp_Object attack;
582 char *dot = lock_info.dot;
583 ptrdiff_t pidlen = lock_info.colon - (dot + 1);
584 static char const replacement[] = " (pid ";
585 int replacementlen = sizeof replacement - 1;
586 memmove (dot + replacementlen, dot + 1, pidlen);
587 strcpy (dot + replacementlen + pidlen, ")");
588 memcpy (dot, replacement, replacementlen);
589 attack = call2 (intern ("ask-user-about-lock"), fn,
590 build_string (lock_info.user));
591
592 if (!NILP (attack))
593 lock_file_1 (lfname, 1);
594 }
595 }
596 return Qnil;
597 }
598
599 static Lisp_Object
600 unlock_file (Lisp_Object fn)
601 {
602 Lisp_Object lfname = make_lock_file_name (fn);
603 if (NILP (lfname))
604 return Qnil;
605
606 int err = current_lock_owner (0, lfname);
607 if (! (err == 0 || err == ANOTHER_OWNS_IT
608 || (err == I_OWN_IT
609 && (emacs_unlink (SSDATA (lfname)) == 0
610 || (err = errno) == ENOENT))))
611 report_file_errno ("Unlocking file", fn, err);
612
613 return Qnil;
614 }
615
616 static Lisp_Object
617 unlock_file_handle_error (Lisp_Object err)
618 {
619 call1 (intern ("userlock--handle-unlock-error"), err);
620 return Qnil;
621 }
622
623 #endif
624
625 void
626 unlock_all_files (void)
627 {
628 register Lisp_Object tail, buf;
629 register struct buffer *b;
630
631 FOR_EACH_LIVE_BUFFER (tail, buf)
632 {
633 b = XBUFFER (buf);
634 if (STRINGP (BVAR (b, file_truename))
635 && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
636 Funlock_file (BVAR (b, file_truename));
637 }
638 }
639
640 DEFUN ("lock-file", Flock_file, Slock_file, 1, 1, 0,
641 doc:
642 )
643 (Lisp_Object file)
644 {
645 #ifndef MSDOS
646 CHECK_STRING (file);
647
648
649
650 Lisp_Object handler;
651 handler = Ffind_file_name_handler (file, Qlock_file);
652 if (!NILP (handler))
653 return call2 (handler, Qlock_file, file);
654
655 lock_file (file);
656 #endif
657 return Qnil;
658 }
659
660 DEFUN ("unlock-file", Funlock_file, Sunlock_file, 1, 1, 0,
661 doc: )
662 (Lisp_Object file)
663 {
664 #ifndef MSDOS
665 CHECK_STRING (file);
666
667
668
669 Lisp_Object handler;
670 handler = Ffind_file_name_handler (file, Qunlock_file);
671 if (!NILP (handler))
672 {
673 call2 (handler, Qunlock_file, file);
674 return Qnil;
675 }
676
677 internal_condition_case_1 (unlock_file,
678 file,
679 list1 (Qfile_error),
680 unlock_file_handle_error);
681 #endif
682 return Qnil;
683 }
684
685 DEFUN ("lock-buffer", Flock_buffer, Slock_buffer,
686 0, 1, 0,
687 doc:
688
689
690
691 )
692 (Lisp_Object file)
693 {
694 if (NILP (file))
695 file = BVAR (current_buffer, file_truename);
696 else
697 CHECK_STRING (file);
698 if (SAVE_MODIFF < MODIFF
699 && !NILP (file))
700 Flock_file (file);
701 return Qnil;
702 }
703
704 DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer,
705 0, 0, 0,
706 doc:
707
708
709
710
711 )
712 (void)
713 {
714 if (SAVE_MODIFF < MODIFF
715 && STRINGP (BVAR (current_buffer, file_truename)))
716 Funlock_file (BVAR (current_buffer, file_truename));
717 return Qnil;
718 }
719
720
721
722 void
723 unlock_buffer (struct buffer *buffer)
724 {
725 if (BUF_SAVE_MODIFF (buffer) < BUF_MODIFF (buffer)
726 && STRINGP (BVAR (buffer, file_truename)))
727 Funlock_file (BVAR (buffer, file_truename));
728 }
729
730 DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 1, 1, 0,
731 doc:
732
733 )
734 (Lisp_Object filename)
735 {
736 #ifdef MSDOS
737 return Qnil;
738 #else
739 Lisp_Object ret;
740 int owner;
741 lock_info_type locker;
742
743
744
745 Lisp_Object handler;
746 handler = Ffind_file_name_handler (filename, Qfile_locked_p);
747 if (!NILP (handler))
748 {
749 return call2 (handler, Qfile_locked_p, filename);
750 }
751
752 Lisp_Object lfname = make_lock_file_name (filename);
753 if (NILP (lfname))
754 return Qnil;
755
756 owner = current_lock_owner (&locker, lfname);
757 switch (owner)
758 {
759 case I_OWN_IT: ret = Qt; break;
760 case ANOTHER_OWNS_IT:
761 ret = make_string (locker.user, locker.at - locker.user);
762 break;
763 case 0: ret = Qnil; break;
764 default: report_file_errno ("Testing file lock", filename, owner);
765 }
766
767 return ret;
768 #endif
769 }
770
771 void
772 syms_of_filelock (void)
773 {
774 DEFVAR_LISP ("temporary-file-directory", Vtemporary_file_directory,
775 doc: );
776 Vtemporary_file_directory = Qnil;
777
778 DEFVAR_BOOL ("create-lockfiles", create_lockfiles,
779 doc:
780
781
782 );
783 create_lockfiles = true;
784
785 DEFSYM (Qlock_file, "lock-file");
786 DEFSYM (Qunlock_file, "unlock-file");
787 DEFSYM (Qfile_locked_p, "file-locked-p");
788 DEFSYM (Qmake_lock_file_name, "make-lock-file-name");
789
790 defsubr (&Slock_file);
791 defsubr (&Sunlock_file);
792 defsubr (&Slock_buffer);
793 defsubr (&Sunlock_buffer);
794 defsubr (&Sfile_locked_p);
795 }