aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog48
-rw-r--r--src/filelock.c141
-rw-r--r--src/intervals.h2
-rw-r--r--src/lisp.h2
-rw-r--r--src/textprop.c51
5 files changed, 158 insertions, 86 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 1b8b3c56004..adff00f7189 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,51 @@
12013-03-02 Paul Eggert <eggert@cs.ucla.edu>
2
3 The lock for FILE is now .#FILE or .#-FILE (Bug#13807).
4 The old approach, which fell back on DIR/.#FILE.0 through
5 DIR/.#FILE.9, had race conditions that could not be easily fixed.
6 If DIR/.#FILE is a non-symlink file, Emacs now does not create a
7 lock file for DIR/FILE; that is, DIR/FILE is no longer partly
8 protected by a lock if DIR/.#FILE is a non-symlink file ("partly"
9 because the locking mechanism was never reliable in that case).
10 This patch fixes this and other bugs discovered by a code
11 inspection that was prompted by
12 <http://lists.gnu.org/archive/html/emacs-devel/2013-02/msg00531.html>.
13 Also, this patch switches to .#-FILE (not .#FILE) on MS-Windows,
14 to avoid interoperability problems between the MS-Windows and
15 non-MS-Windows implementations. MS-Windows and non-MS-Windows
16 instances of Emacs now ignore each others' locks.
17 * filelock.c (defined_WINDOWSNT): New constant.
18 (MAKE_LOCK_NAME, fill_in_lock_file_name):
19 Don't create DIR/.#FILE.0 through DIR/.#FILE.9. Instead, create
20 DIR/.#FILE symlinks on non-MS-Windows hosts, and DIR/.#-FILE
21 regular files on MS-Windows hosts.
22 (MAKE_LOCK_NAME, unlock_file, Ffile_locked_p):
23 Use SAFE_ALLOCA to avoid problems with long file names.
24 (MAX_LFINFO): Now a local constant, not a global macro.
25 (IS_LOCK_FILE): Remove.
26 (lock_file_1): Don't inspect errno if symlink call succeeds;
27 that's not portable.
28 (lock_file): Document that this function can return if lock
29 creation fails.
30 (lock_file): Don't access freed storage.
31
322013-03-02 Andreas Schwab <schwab@linux-m68k.org>
33
34 * lisp.h (XPNTR) [!USE_LSB_TAG]: Remove extra paren. (Bug#13734)
35
362013-03-02 Paul Eggert <eggert@cs.ucla.edu>
37
38 * textprop.c: Use bool for booleans.
39 (validate_interval_range, Fadd_text_properties)
40 (Fremove_text_properties): Prefer bool to int when either works.
41
422013-03-02 Eli Zaretskii <eliz@gnu.org>
43
44 * textprop.c (Fadd_text_properties, Fremove_text_properties): If
45 the interval tree changes as a side effect of calling
46 modify_region, re-do processing starting from the call to
47 validate_interval_range. (Bug#13743)
48
12013-02-28 Eli Zaretskii <eliz@gnu.org> 492013-02-28 Eli Zaretskii <eliz@gnu.org>
2 50
3 * w32.c (sys_open): Don't reset the flags for FD in fd_info[]. 51 * w32.c (sys_open): Don't reset the flags for FD in fd_info[].
diff --git a/src/filelock.c b/src/filelock.c
index 78cd60a12e1..14b9d4aaca5 100644
--- a/src/filelock.c
+++ b/src/filelock.c
@@ -64,7 +64,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
64#define WTMP_FILE "/var/log/wtmp" 64#define WTMP_FILE "/var/log/wtmp"
65#endif 65#endif
66 66
67/* The strategy: to lock a file FN, create a symlink .#FN in FN's 67/* On non-MS-Windows systems, use a symbolic link to represent a lock.
68 The strategy: to lock a file FN, create a symlink .#FN in FN's
68 directory, with link data `user@host.pid'. This avoids a single 69 directory, with link data `user@host.pid'. This avoids a single
69 mount (== failure) point for lock files. 70 mount (== failure) point for lock files.
70 71
@@ -97,7 +98,12 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
97 has contributed this implementation for Emacs), and was designed by 98 has contributed this implementation for Emacs), and was designed by
98 Ethan Jacobson, Kimbo Mundy, and others. 99 Ethan Jacobson, Kimbo Mundy, and others.
99 100
100 --karl@cs.umb.edu/karl@hq.ileaf.com. */ 101 --karl@cs.umb.edu/karl@hq.ileaf.com.
102
103 On MS-Windows, symbolic links do not work well, so instead of a
104 symlink .#FN -> 'user@host.pid', the lock is a regular file .#-FN
105 with contents 'user@host.pid'. MS-Windows and non-MS-Windows
106 versions of Emacs ignore each other's locks. */
101 107
102 108
103/* Return the time of the last system boot. */ 109/* Return the time of the last system boot. */
@@ -291,55 +297,31 @@ typedef struct
291/* Free the two dynamically-allocated pieces in PTR. */ 297/* Free the two dynamically-allocated pieces in PTR. */
292#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) 298#define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
293 299
294
295/* Write the name of the lock file for FNAME into LOCKNAME. Length
296 will be that of FN plus two more for the leading `.#' plus 1 for
297 the trailing period plus one for the digit after it plus one for
298 the null. */
299#define MAKE_LOCK_NAME(LOCKNAME, FNAME) \
300 (LOCKNAME = alloca (SBYTES (FNAME) + 2 + 1 + 1 + 1), \
301 fill_in_lock_file_name (LOCKNAME, (FNAME)))
302
303#ifdef WINDOWSNT 300#ifdef WINDOWSNT
304/* 256 chars for user, 1024 chars for host, 10 digits for each of 2 int's. */ 301enum { defined_WINDOWSNT = 1 };
305#define MAX_LFINFO (256 + 1024 + 10 + 10 + 2)
306 /* min size: .@PID */
307#define IS_LOCK_FILE(ST) (MAX_LFINFO >= (ST).st_size && (ST).st_size >= 3)
308#else 302#else
309#define IS_LOCK_FILE(ST) S_ISLNK ((ST).st_mode) 303enum { defined_WINDOWSNT = 0 };
310#endif 304#endif
311 305
306/* Write the name of the lock file for FNAME into LOCKNAME. Length
307 will be that of FNAME plus two more for the leading ".#",
308 plus one for "-" if MS-Windows, plus one for the null. */
309#define MAKE_LOCK_NAME(lockname, fname) \
310 (lockname = SAFE_ALLOCA (SBYTES (fname) + 2 + defined_WINDOWSNT + 1), \
311 fill_in_lock_file_name (lockname, fname))
312
312static void 313static void
313fill_in_lock_file_name (register char *lockfile, register Lisp_Object fn) 314fill_in_lock_file_name (char *lockfile, Lisp_Object fn)
314{ 315{
315 ptrdiff_t length = SBYTES (fn); 316 char *last_slash = memrchr (SSDATA (fn), '/', SBYTES (fn));
316 register char *p; 317 char *base = last_slash + 1;
317 struct stat st; 318 ptrdiff_t dirlen = base - SSDATA (fn);
318 int count = 0; 319 memcpy (lockfile, SSDATA (fn), dirlen);
319 320 lockfile[dirlen] = '.';
320 strcpy (lockfile, SSDATA (fn)); 321 lockfile[dirlen + 1] = '#';
321 322 if (defined_WINDOWSNT)
322 /* Shift the nondirectory part of the file name (including the null) 323 lockfile[dirlen + 2] = '-';
323 right two characters. Here is one of the places where we'd have to 324 strcpy (lockfile + dirlen + 2 + defined_WINDOWSNT, base);
324 do something to support 14-character-max file names. */
325 for (p = lockfile + length; p != lockfile && *p != '/'; p--)
326 p[2] = *p;
327
328 /* Insert the `.#'. */
329 p[1] = '.';
330 p[2] = '#';
331
332 p = lockfile + length + 2;
333
334 while (lstat (lockfile, &st) == 0 && !IS_LOCK_FILE (st))
335 {
336 if (count > 9)
337 {
338 *p = '\0';
339 return;
340 }
341 sprintf (p, ".%d", count++);
342 }
343} 325}
344 326
345static int 327static int
@@ -356,8 +338,8 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
356 { 338 {
357 /* Deny everybody else any kind of access to the file until we are 339 /* Deny everybody else any kind of access to the file until we are
358 done writing it and close the handle. This makes the entire 340 done writing it and close the handle. This makes the entire
359 open/write/close operation atomic, as far as other processes 341 open/write/close operation atomic, as far as other WINDOWSNT
360 are concerned. */ 342 processes are concerned. */
361 int fd = _sopen (lfname, 343 int fd = _sopen (lfname,
362 _O_WRONLY | _O_BINARY | _O_CREAT | _O_EXCL | _O_NOINHERIT, 344 _O_WRONLY | _O_BINARY | _O_CREAT | _O_EXCL | _O_NOINHERIT,
363 _SH_DENYRW, S_IREAD | S_IWRITE); 345 _SH_DENYRW, S_IREAD | S_IWRITE);
@@ -380,7 +362,7 @@ create_lock_file (char *lfname, char *lock_info_str, bool force)
380 } 362 }
381#else 363#else
382 err = symlink (lock_info_str, lfname); 364 err = symlink (lock_info_str, lfname);
383 if (errno == EEXIST && force) 365 if (err != 0 && errno == EEXIST && force)
384 { 366 {
385 unlink (lfname); 367 unlink (lfname);
386 err = symlink (lock_info_str, lfname); 368 err = symlink (lock_info_str, lfname);
@@ -440,6 +422,8 @@ read_lock_data (char *lfname)
440#else 422#else
441 int fd = emacs_open (lfname, O_RDONLY | O_BINARY, S_IREAD); 423 int fd = emacs_open (lfname, O_RDONLY | O_BINARY, S_IREAD);
442 ssize_t nbytes; 424 ssize_t nbytes;
425 /* 256 chars for user, 1024 chars for host, 10 digits for each of 2 int's. */
426 enum { MAX_LFINFO = 256 + 1024 + 10 + 10 + 2 };
443 char lfinfo[MAX_LFINFO + 1]; 427 char lfinfo[MAX_LFINFO + 1];
444 428
445 if (fd < 0) 429 if (fd < 0)
@@ -601,6 +585,7 @@ lock_if_free (lock_info_type *clasher, register char *lfname)
601 decided to go ahead without locking. 585 decided to go ahead without locking.
602 586
603 When this returns, either the lock is locked for us, 587 When this returns, either the lock is locked for us,
588 or lock creation failed,
604 or the user has said to go ahead without locking. 589 or the user has said to go ahead without locking.
605 590
606 If the file is locked by someone else, this calls 591 If the file is locked by someone else, this calls
@@ -612,11 +597,9 @@ lock_if_free (lock_info_type *clasher, register char *lfname)
612void 597void
613lock_file (Lisp_Object fn) 598lock_file (Lisp_Object fn)
614{ 599{
615 register Lisp_Object attack, orig_fn, encoded_fn; 600 Lisp_Object orig_fn, encoded_fn;
616 register char *lfname, *locker; 601 char *lfname;
617 ptrdiff_t locker_size;
618 lock_info_type lock_info; 602 lock_info_type lock_info;
619 printmax_t pid;
620 struct gcpro gcpro1; 603 struct gcpro gcpro1;
621 USE_SAFE_ALLOCA; 604 USE_SAFE_ALLOCA;
622 605
@@ -657,38 +640,36 @@ lock_file (Lisp_Object fn)
657 call1 (intern ("ask-user-about-supersession-threat"), fn); 640 call1 (intern ("ask-user-about-supersession-threat"), fn);
658 641
659 } 642 }
660 UNGCPRO;
661
662 /* Try to lock the lock. */
663 if (lock_if_free (&lock_info, lfname) <= 0)
664 /* Return now if we have locked it, or if lock creation failed */
665 return;
666 643
667 /* Else consider breaking the lock */ 644 /* Try to lock the lock. */
668 locker_size = (strlen (lock_info.user) + strlen (lock_info.host) 645 if (0 < lock_if_free (&lock_info, lfname))
669 + INT_STRLEN_BOUND (printmax_t)
670 + sizeof "@ (pid )");
671 locker = SAFE_ALLOCA (locker_size);
672 pid = lock_info.pid;
673 esprintf (locker, "%s@%s (pid %"pMd")",
674 lock_info.user, lock_info.host, pid);
675 FREE_LOCK_INFO (lock_info);
676
677 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
678 SAFE_FREE ();
679 if (!NILP (attack))
680 /* User says take the lock */
681 { 646 {
682 lock_file_1 (lfname, 1); 647 /* Someone else has the lock. Consider breaking it. */
683 return; 648 ptrdiff_t locker_size = (strlen (lock_info.user) + strlen (lock_info.host)
649 + INT_STRLEN_BOUND (printmax_t)
650 + sizeof "@ (pid )");
651 char *locker = SAFE_ALLOCA (locker_size);
652 printmax_t pid = lock_info.pid;
653 Lisp_Object attack;
654 esprintf (locker, "%s@%s (pid %"pMd")",
655 lock_info.user, lock_info.host, pid);
656 FREE_LOCK_INFO (lock_info);
657
658 attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
659 /* Take the lock if the user said so. */
660 if (!NILP (attack))
661 lock_file_1 (lfname, 1);
684 } 662 }
685 /* User says ignore the lock */ 663
664 UNGCPRO;
665 SAFE_FREE ();
686} 666}
687 667
688void 668void
689unlock_file (register Lisp_Object fn) 669unlock_file (Lisp_Object fn)
690{ 670{
691 register char *lfname; 671 char *lfname;
672 USE_SAFE_ALLOCA;
692 673
693 fn = Fexpand_file_name (fn, Qnil); 674 fn = Fexpand_file_name (fn, Qnil);
694 fn = ENCODE_FILE (fn); 675 fn = ENCODE_FILE (fn);
@@ -697,6 +678,8 @@ unlock_file (register Lisp_Object fn)
697 678
698 if (current_lock_owner (0, lfname) == 2) 679 if (current_lock_owner (0, lfname) == 2)
699 unlink (lfname); 680 unlink (lfname);
681
682 SAFE_FREE ();
700} 683}
701 684
702void 685void
@@ -762,9 +745,10 @@ t if it is locked by you, else a string saying which user has locked it. */)
762 (Lisp_Object filename) 745 (Lisp_Object filename)
763{ 746{
764 Lisp_Object ret; 747 Lisp_Object ret;
765 register char *lfname; 748 char *lfname;
766 int owner; 749 int owner;
767 lock_info_type locker; 750 lock_info_type locker;
751 USE_SAFE_ALLOCA;
768 752
769 filename = Fexpand_file_name (filename, Qnil); 753 filename = Fexpand_file_name (filename, Qnil);
770 754
@@ -781,6 +765,7 @@ t if it is locked by you, else a string saying which user has locked it. */)
781 if (owner > 0) 765 if (owner > 0)
782 FREE_LOCK_INFO (locker); 766 FREE_LOCK_INFO (locker);
783 767
768 SAFE_FREE ();
784 return ret; 769 return ret;
785} 770}
786 771
diff --git a/src/intervals.h b/src/intervals.h
index d6191225b1f..a38e83cf10e 100644
--- a/src/intervals.h
+++ b/src/intervals.h
@@ -259,7 +259,7 @@ extern Lisp_Object get_local_map (ptrdiff_t, struct buffer *, Lisp_Object);
259extern INTERVAL update_interval (INTERVAL, ptrdiff_t); 259extern INTERVAL update_interval (INTERVAL, ptrdiff_t);
260extern void set_intervals_multibyte (bool); 260extern void set_intervals_multibyte (bool);
261extern INTERVAL validate_interval_range (Lisp_Object, Lisp_Object *, 261extern INTERVAL validate_interval_range (Lisp_Object, Lisp_Object *,
262 Lisp_Object *, int); 262 Lisp_Object *, bool);
263extern INTERVAL interval_of (ptrdiff_t, Lisp_Object); 263extern INTERVAL interval_of (ptrdiff_t, Lisp_Object);
264 264
265/* Defined in xdisp.c. */ 265/* Defined in xdisp.c. */
diff --git a/src/lisp.h b/src/lisp.h
index 3d018b2b45e..f978a3b2fe0 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -512,7 +512,7 @@ static EMACS_INT const VALMASK
512 512
513/* DATA_SEG_BITS forces extra bits to be or'd in with any pointers 513/* DATA_SEG_BITS forces extra bits to be or'd in with any pointers
514 which were stored in a Lisp_Object. */ 514 which were stored in a Lisp_Object. */
515#define XPNTR(a) ((uintptr_t) ((XLI (a) & VALMASK)) | DATA_SEG_BITS)) 515#define XPNTR(a) ((uintptr_t) ((XLI (a) & VALMASK) | DATA_SEG_BITS))
516 516
517#endif /* not USE_LSB_TAG */ 517#endif /* not USE_LSB_TAG */
518 518
diff --git a/src/textprop.c b/src/textprop.c
index 9499b53301f..18e893b3ef2 100644
--- a/src/textprop.c
+++ b/src/textprop.c
@@ -125,9 +125,10 @@ modify_region (Lisp_Object buffer, Lisp_Object start, Lisp_Object end)
125#define hard 1 125#define hard 1
126 126
127INTERVAL 127INTERVAL
128validate_interval_range (Lisp_Object object, Lisp_Object *begin, Lisp_Object *end, int force) 128validate_interval_range (Lisp_Object object, Lisp_Object *begin,
129 Lisp_Object *end, bool force)
129{ 130{
130 register INTERVAL i; 131 INTERVAL i;
131 ptrdiff_t searchpos; 132 ptrdiff_t searchpos;
132 133
133 CHECK_STRING_OR_BUFFER (object); 134 CHECK_STRING_OR_BUFFER (object);
@@ -1131,6 +1132,7 @@ Return t if any property value actually changed, nil otherwise. */)
1131 ptrdiff_t s, len; 1132 ptrdiff_t s, len;
1132 bool modified = 0; 1133 bool modified = 0;
1133 struct gcpro gcpro1; 1134 struct gcpro gcpro1;
1135 bool first_time = 1;
1134 1136
1135 properties = validate_plist (properties); 1137 properties = validate_plist (properties);
1136 if (NILP (properties)) 1138 if (NILP (properties))
@@ -1139,6 +1141,7 @@ Return t if any property value actually changed, nil otherwise. */)
1139 if (NILP (object)) 1141 if (NILP (object))
1140 XSETBUFFER (object, current_buffer); 1142 XSETBUFFER (object, current_buffer);
1141 1143
1144 retry:
1142 i = validate_interval_range (object, &start, &end, hard); 1145 i = validate_interval_range (object, &start, &end, hard);
1143 if (!i) 1146 if (!i)
1144 return Qnil; 1147 return Qnil;
@@ -1174,8 +1177,25 @@ Return t if any property value actually changed, nil otherwise. */)
1174 copy_properties (unchanged, i); 1177 copy_properties (unchanged, i);
1175 } 1178 }
1176 1179
1177 if (BUFFERP (object)) 1180 if (BUFFERP (object) && first_time)
1178 modify_region (object, start, end); 1181 {
1182 ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
1183 ptrdiff_t prev_pos = i->position;
1184
1185 modify_region (object, start, end);
1186 /* If someone called us recursively as a side effect of
1187 modify_region, and changed the intervals behind our back
1188 (could happen if lock_file, called by prepare_to_modify_buffer,
1189 triggers redisplay, and that calls add-text-properties again
1190 in the same buffer), we cannot continue with I, because its
1191 data changed. So we restart the interval analysis anew. */
1192 if (TOTAL_LENGTH (i) != prev_total_length
1193 || i->position != prev_pos)
1194 {
1195 first_time = 0;
1196 goto retry;
1197 }
1198 }
1179 1199
1180 /* We are at the beginning of interval I, with LEN chars to scan. */ 1200 /* We are at the beginning of interval I, with LEN chars to scan. */
1181 for (;;) 1201 for (;;)
@@ -1427,10 +1447,12 @@ Use `set-text-properties' if you want to remove all text properties. */)
1427 INTERVAL i, unchanged; 1447 INTERVAL i, unchanged;
1428 ptrdiff_t s, len; 1448 ptrdiff_t s, len;
1429 bool modified = 0; 1449 bool modified = 0;
1450 bool first_time = 1;
1430 1451
1431 if (NILP (object)) 1452 if (NILP (object))
1432 XSETBUFFER (object, current_buffer); 1453 XSETBUFFER (object, current_buffer);
1433 1454
1455 retry:
1434 i = validate_interval_range (object, &start, &end, soft); 1456 i = validate_interval_range (object, &start, &end, soft);
1435 if (!i) 1457 if (!i)
1436 return Qnil; 1458 return Qnil;
@@ -1462,8 +1484,25 @@ Use `set-text-properties' if you want to remove all text properties. */)
1462 copy_properties (unchanged, i); 1484 copy_properties (unchanged, i);
1463 } 1485 }
1464 1486
1465 if (BUFFERP (object)) 1487 if (BUFFERP (object) && first_time)
1466 modify_region (object, start, end); 1488 {
1489 ptrdiff_t prev_total_length = TOTAL_LENGTH (i);
1490 ptrdiff_t prev_pos = i->position;
1491
1492 modify_region (object, start, end);
1493 /* If someone called us recursively as a side effect of
1494 modify_region, and changed the intervals behind our back
1495 (could happen if lock_file, called by prepare_to_modify_buffer,
1496 triggers redisplay, and that calls add-text-properties again
1497 in the same buffer), we cannot continue with I, because its
1498 data changed. So we restart the interval analysis anew. */
1499 if (TOTAL_LENGTH (i) != prev_total_length
1500 || i->position != prev_pos)
1501 {
1502 first_time = 0;
1503 goto retry;
1504 }
1505 }
1467 1506
1468 /* We are at the beginning of an interval, with len to scan */ 1507 /* We are at the beginning of an interval, with len to scan */
1469 for (;;) 1508 for (;;)