Mercurial > hg > xemacs-beta
comparison src/filelock.c @ 412:697ef44129c6 r21-2-14
Import from CVS: tag r21-2-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:20:41 +0200 |
parents | b8cc9ab3f761 |
children | 11054d720c21 |
comparison
equal
deleted
inserted
replaced
411:12e008d41344 | 412:697ef44129c6 |
---|---|
32 | 32 |
33 Lisp_Object Qask_user_about_supersession_threat; | 33 Lisp_Object Qask_user_about_supersession_threat; |
34 Lisp_Object Qask_user_about_lock; | 34 Lisp_Object Qask_user_about_lock; |
35 | 35 |
36 #ifdef CLASH_DETECTION | 36 #ifdef CLASH_DETECTION |
37 | 37 |
38 /* The strategy: to lock a file FN, create a symlink .#FN in FN's | 38 /* The strategy: to lock a file FN, create a symlink .#FN in FN's |
39 directory, with link data `user@host.pid'. This avoids a single | 39 directory, with link data `user@host.pid'. This avoids a single |
40 mount (== failure) point for lock files. | 40 mount (== failure) point for lock files. |
41 | 41 |
42 When the host in the lock data is the current host, we can check if | 42 When the host in the lock data is the current host, we can check if |
43 the pid is valid with kill. | 43 the pid is valid with kill. |
44 | 44 |
45 Otherwise, we could look at a separate file that maps hostnames to | 45 Otherwise, we could look at a separate file that maps hostnames to |
46 reboot times to see if the remote pid can possibly be valid, since we | 46 reboot times to see if the remote pid can possibly be valid, since we |
47 don't want Emacs to have to communicate via pipes or sockets or | 47 don't want Emacs to have to communicate via pipes or sockets or |
48 whatever to other processes, either locally or remotely; rms says | 48 whatever to other processes, either locally or remotely; rms says |
49 that's too unreliable. Hence the separate file, which could | 49 that's too unreliable. Hence the separate file, which could |
61 didn't seem worth the complication. | 61 didn't seem worth the complication. |
62 | 62 |
63 Similarly, we don't worry about a possible 14-character limit on | 63 Similarly, we don't worry about a possible 14-character limit on |
64 file names, because those are all the same systems that don't have | 64 file names, because those are all the same systems that don't have |
65 symlinks. | 65 symlinks. |
66 | 66 |
67 This is compatible with the locking scheme used by Interleaf (which | 67 This is compatible with the locking scheme used by Interleaf (which |
68 has contributed this implementation for Emacs), and was designed by | 68 has contributed this implementation for Emacs), and was designed by |
69 Ethan Jacobson, Kimbo Mundy, and others. | 69 Ethan Jacobson, Kimbo Mundy, and others. |
70 | 70 |
71 --karl@cs.umb.edu/karl@hq.ileaf.com. */ | 71 --karl@cs.umb.edu/karl@hq.ileaf.com. */ |
72 | |
73 /* Note that muleization is provided by using mule-encapsulated | |
74 versions of the system calls we use like symlink(), unlink(), etc... */ | |
75 | 72 |
76 | 73 |
77 /* Here is the structure that stores information about a lock. */ | 74 /* Here is the structure that stores information about a lock. */ |
78 | 75 |
79 typedef struct | 76 typedef struct |
91 #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) | 88 #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0) |
92 | 89 |
93 /* Write the name of the lock file for FN into LFNAME. Length will be | 90 /* Write the name of the lock file for FN into LFNAME. Length will be |
94 that of FN plus two more for the leading `.#' plus one for the null. */ | 91 that of FN plus two more for the leading `.#' plus one for the null. */ |
95 #define MAKE_LOCK_NAME(lock, file) \ | 92 #define MAKE_LOCK_NAME(lock, file) \ |
96 (lock = (char *) alloca (XSTRING_LENGTH (file) + 2 + 1), \ | 93 (lock = (char *) alloca (XSTRING_LENGTH(file) + 2 + 1), \ |
97 fill_in_lock_file_name ((Bufbyte *) (lock), (file))) | 94 fill_in_lock_file_name (lock, (file))) |
98 | 95 |
99 static void | 96 static void |
100 fill_in_lock_file_name (Bufbyte *lockfile, Lisp_Object fn) | 97 fill_in_lock_file_name (lockfile, fn) |
101 { | 98 register char *lockfile; |
102 Bufbyte *file_name = XSTRING_DATA (fn); | 99 register Lisp_Object fn; |
103 Bufbyte *p; | 100 { |
104 size_t dirlen; | 101 register char *p; |
105 | 102 |
106 for (p = file_name + XSTRING_LENGTH (fn) - 1; | 103 strcpy (lockfile, XSTRING_DATA(fn)); |
107 p > file_name && !IS_ANY_SEP (p[-1]); | 104 |
108 p--) | 105 /* Shift the nondirectory part of the file name (including the null) |
109 ; | 106 right two characters. Here is one of the places where we'd have to |
110 dirlen = p - file_name; | 107 do something to support 14-character-max file names. */ |
111 | 108 for (p = lockfile + strlen (lockfile); p != lockfile && *p != '/'; p--) |
112 memcpy (lockfile, file_name, dirlen); | 109 p[2] = *p; |
113 p = lockfile + dirlen; | 110 |
114 *(p++) = '.'; | 111 /* Insert the `.#'. */ |
115 *(p++) = '#'; | 112 p[1] = '.'; |
116 memcpy (p, file_name + dirlen, XSTRING_LENGTH (fn) - dirlen + 1); | 113 p[2] = '#'; |
117 } | 114 } |
118 | 115 |
119 /* Lock the lock file named LFNAME. | 116 /* Lock the lock file named LFNAME. |
120 If FORCE is nonzero, we do so even if it is already locked. | 117 If FORCE is nonzero, we do so even if it is already locked. |
121 Return 1 if successful, 0 if not. */ | 118 Return 1 if successful, 0 if not. */ |
122 | 119 |
123 static int | 120 static int |
124 lock_file_1 (char *lfname, int force) | 121 lock_file_1 (char *lfname,int force) |
125 { | 122 { |
126 int err; | 123 register int err; |
124 char *user_name; | |
125 char *host_name; | |
127 char *lock_info_str; | 126 char *lock_info_str; |
128 char *host_name; | 127 |
129 char *user_name = user_login_name (NULL); | 128 if (STRINGP (Fuser_login_name (Qnil))) |
130 | 129 user_name = (char *)XSTRING_DATA((Fuser_login_name (Qnil))); |
131 if (user_name == NULL) | 130 else |
132 user_name = ""; | 131 user_name = ""; |
133 | 132 if (STRINGP (Fsystem_name ())) |
134 if (STRINGP (Vsystem_name)) | 133 host_name = (char *)XSTRING_DATA((Fsystem_name ())); |
135 host_name = (char *) XSTRING_DATA (Vsystem_name); | |
136 else | 134 else |
137 host_name = ""; | 135 host_name = ""; |
138 | |
139 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name) | 136 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name) |
140 + LOCK_PID_MAX + 5); | 137 + LOCK_PID_MAX + 5); |
141 | 138 |
142 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name, | 139 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name, |
143 (unsigned long) getpid ()); | 140 (unsigned long) getpid ()); |
144 | 141 |
145 err = symlink (lock_info_str, lfname); | 142 err = symlink (lock_info_str, lfname); |
146 if (err != 0 && errno == EEXIST && force) | 143 if (errno == EEXIST && force) |
147 { | 144 { |
148 unlink (lfname); | 145 unlink (lfname); |
149 err = symlink (lock_info_str, lfname); | 146 err = symlink (lock_info_str, lfname); |
150 } | 147 } |
151 | 148 |
158 or -1 if something is wrong with the locking mechanism. */ | 155 or -1 if something is wrong with the locking mechanism. */ |
159 | 156 |
160 static int | 157 static int |
161 current_lock_owner (lock_info_type *owner, char *lfname) | 158 current_lock_owner (lock_info_type *owner, char *lfname) |
162 { | 159 { |
163 int len, ret; | 160 int o, p, len, ret; |
164 int local_owner = 0; | 161 int local_owner = 0; |
165 char *at, *dot; | 162 char *at, *dot; |
166 char *lfinfo = 0; | 163 char *lfinfo = 0; |
167 int bufsize = 50; | 164 int bufsize = 50; |
168 /* Read arbitrarily-long contents of symlink. Similar code in | 165 /* Read arbitrarily-long contents of symlink. Similar code in |
172 bufsize *= 2; | 169 bufsize *= 2; |
173 lfinfo = (char *) xrealloc (lfinfo, bufsize); | 170 lfinfo = (char *) xrealloc (lfinfo, bufsize); |
174 len = readlink (lfname, lfinfo, bufsize); | 171 len = readlink (lfname, lfinfo, bufsize); |
175 } | 172 } |
176 while (len >= bufsize); | 173 while (len >= bufsize); |
177 | 174 |
178 /* If nonexistent lock file, all is well; otherwise, got strange error. */ | 175 /* If nonexistent lock file, all is well; otherwise, got strange error. */ |
179 if (len == -1) | 176 if (len == -1) |
180 { | 177 { |
181 xfree (lfinfo); | 178 xfree (lfinfo); |
182 return errno == ENOENT ? 0 : -1; | 179 return errno == ENOENT ? 0 : -1; |
183 } | 180 } |
184 | 181 |
185 /* Link info exists, so `len' is its length. Null terminate. */ | 182 /* Link info exists, so `len' is its length. Null terminate. */ |
186 lfinfo[len] = 0; | 183 lfinfo[len] = 0; |
187 | 184 |
188 /* Even if the caller doesn't want the owner info, we still have to | 185 /* Even if the caller doesn't want the owner info, we still have to |
189 read it to determine return value, so allocate it. */ | 186 read it to determine return value, so allocate it. */ |
190 if (!owner) | 187 if (!owner) |
191 { | 188 { |
192 owner = (lock_info_type *) alloca (sizeof (lock_info_type)); | 189 owner = (lock_info_type *) alloca (sizeof (lock_info_type)); |
193 local_owner = 1; | 190 local_owner = 1; |
194 } | 191 } |
195 | 192 |
196 /* Parse USER@HOST.PID. If can't parse, return -1. */ | 193 /* Parse USER@HOST.PID. If can't parse, return -1. */ |
197 /* The USER is everything before the first @. */ | 194 /* The USER is everything before the first @. */ |
198 at = strchr (lfinfo, '@'); | 195 at = strchr (lfinfo, '@'); |
199 dot = strrchr (lfinfo, '.'); | 196 dot = strrchr (lfinfo, '.'); |
200 if (!at || !dot) { | 197 if (!at || !dot) { |
203 } | 200 } |
204 len = at - lfinfo; | 201 len = at - lfinfo; |
205 owner->user = (char *) xmalloc (len + 1); | 202 owner->user = (char *) xmalloc (len + 1); |
206 strncpy (owner->user, lfinfo, len); | 203 strncpy (owner->user, lfinfo, len); |
207 owner->user[len] = 0; | 204 owner->user[len] = 0; |
208 | 205 |
209 /* The PID is everything after the last `.'. */ | 206 /* The PID is everything after the last `.'. */ |
210 owner->pid = atoi (dot + 1); | 207 owner->pid = atoi (dot + 1); |
211 | 208 |
212 /* The host is everything in between. */ | 209 /* The host is everything in between. */ |
213 len = dot - at - 1; | 210 len = dot - at - 1; |
215 strncpy (owner->host, at + 1, len); | 212 strncpy (owner->host, at + 1, len); |
216 owner->host[len] = 0; | 213 owner->host[len] = 0; |
217 | 214 |
218 /* We're done looking at the link info. */ | 215 /* We're done looking at the link info. */ |
219 xfree (lfinfo); | 216 xfree (lfinfo); |
220 | 217 |
221 /* On current host? */ | 218 /* On current host? */ |
222 if (STRINGP (Fsystem_name ()) | 219 if (STRINGP (Fsystem_name ()) |
223 && strcmp (owner->host, (char *) XSTRING_DATA (Fsystem_name ())) == 0) | 220 && strcmp (owner->host, XSTRING_DATA(Fsystem_name ())) == 0) |
224 { | 221 { |
225 if (owner->pid == getpid ()) | 222 if (owner->pid == getpid ()) |
226 ret = 2; /* We own it. */ | 223 ret = 2; /* We own it. */ |
227 else if (owner->pid > 0 | 224 else if (owner->pid > 0 |
228 && (kill (owner->pid, 0) >= 0 || errno == EPERM)) | 225 && (kill (owner->pid, 0) >= 0 || errno == EPERM)) |
237 else | 234 else |
238 { /* If we wanted to support the check for stale locks on remote machines, | 235 { /* If we wanted to support the check for stale locks on remote machines, |
239 here's where we'd do it. */ | 236 here's where we'd do it. */ |
240 ret = 1; | 237 ret = 1; |
241 } | 238 } |
242 | 239 |
243 /* Avoid garbage. */ | 240 /* Avoid garbage. */ |
244 if (local_owner || ret <= 0) | 241 if (local_owner || ret <= 0) |
245 { | 242 { |
246 FREE_LOCK_INFO (*owner); | 243 FREE_LOCK_INFO (*owner); |
247 } | 244 } |
261 { | 258 { |
262 int locker; | 259 int locker; |
263 | 260 |
264 if (errno != EEXIST) | 261 if (errno != EEXIST) |
265 return -1; | 262 return -1; |
266 | 263 |
267 locker = current_lock_owner (clasher, lfname); | 264 locker = current_lock_owner (clasher, lfname); |
268 if (locker == 2) | 265 if (locker == 2) |
269 { | 266 { |
270 FREE_LOCK_INFO (*clasher); | 267 FREE_LOCK_INFO (*clasher); |
271 return 0; /* We ourselves locked it. */ | 268 return 0; /* We ourselves locked it. */ |
300 { | 297 { |
301 /* This function can GC. */ | 298 /* This function can GC. */ |
302 /* dmoore - and can destroy current_buffer and all sorts of other | 299 /* dmoore - and can destroy current_buffer and all sorts of other |
303 mean nasty things with pointy teeth. If you call this make sure | 300 mean nasty things with pointy teeth. If you call this make sure |
304 you protect things right. */ | 301 you protect things right. */ |
305 /* Somebody updated the code in this function and removed the previous | 302 /* Somebody updated the code in this function and removed the previous |
306 comment. -slb */ | 303 comment. -slb */ |
307 | 304 |
308 register Lisp_Object attack, orig_fn; | 305 register Lisp_Object attack, orig_fn; |
309 register char *lfname, *locker; | 306 register char *lfname, *locker; |
310 lock_info_type lock_info; | 307 lock_info_type lock_info; |
324 subject_buf = get_truename_buffer (orig_fn); | 321 subject_buf = get_truename_buffer (orig_fn); |
325 if (!NILP (subject_buf) | 322 if (!NILP (subject_buf) |
326 && NILP (Fverify_visited_file_modtime (subject_buf)) | 323 && NILP (Fverify_visited_file_modtime (subject_buf)) |
327 && !NILP (Ffile_exists_p (fn))) | 324 && !NILP (Ffile_exists_p (fn))) |
328 call1_in_buffer (XBUFFER(subject_buf), | 325 call1_in_buffer (XBUFFER(subject_buf), |
329 Qask_user_about_supersession_threat, fn); | 326 Qask_user_about_supersession_threat, fn); |
330 } | 327 } |
331 | 328 |
332 /* Try to lock the lock. */ | 329 /* Try to lock the lock. */ |
333 if (lock_if_free (&lock_info, lfname) <= 0) | 330 if (lock_if_free (&lock_info, lfname) <= 0) |
334 /* Return now if we have locked it, or if lock creation failed */ | 331 /* Return now if we have locked it, or if lock creation failed */ |
338 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host) | 335 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host) |
339 + LOCK_PID_MAX + 9); | 336 + LOCK_PID_MAX + 9); |
340 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host, | 337 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host, |
341 lock_info.pid); | 338 lock_info.pid); |
342 FREE_LOCK_INFO (lock_info); | 339 FREE_LOCK_INFO (lock_info); |
343 | 340 |
344 attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) : | 341 attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) : |
345 current_buffer, Qask_user_about_lock , fn, | 342 current_buffer, Qask_user_about_lock , fn, |
346 build_string (locker)); | 343 build_string (locker)); |
347 if (!NILP (attack)) | 344 if (!NILP (attack)) |
348 /* User says take the lock */ | 345 /* User says take the lock */ |
357 | 354 |
358 void | 355 void |
359 unlock_file (Lisp_Object fn) | 356 unlock_file (Lisp_Object fn) |
360 { | 357 { |
361 register char *lfname; | 358 register char *lfname; |
362 struct gcpro gcpro1; | |
363 | |
364 GCPRO1 (fn); | |
365 | 359 |
366 fn = Fexpand_file_name (fn, Qnil); | 360 fn = Fexpand_file_name (fn, Qnil); |
367 | 361 |
368 MAKE_LOCK_NAME (lfname, fn); | 362 MAKE_LOCK_NAME (lfname, fn); |
369 | 363 |
370 if (current_lock_owner (0, lfname) == 2) | 364 if (current_lock_owner (0, lfname) == 2) |
371 unlink (lfname); | 365 unlink (lfname); |
372 | |
373 UNGCPRO; | |
374 } | 366 } |
375 | 367 |
376 void | 368 void |
377 unlock_all_files (void) | 369 unlock_all_files () |
378 { | 370 { |
379 register Lisp_Object tail; | 371 register Lisp_Object tail; |
380 | 372 register struct buffer *b; |
381 for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail)) | 373 |
382 { | 374 for (tail = Vbuffer_alist; GC_CONSP (tail); tail = XCDR (tail)) |
383 struct buffer *b = XBUFFER (XCDR (XCAR (tail))); | 375 { |
376 b = XBUFFER (XCDR (XCAR (tail))); | |
384 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) | 377 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) |
385 unlock_file (b->file_truename); | 378 unlock_file (b->file_truename); |
386 } | 379 } |
387 } | 380 } |
388 | 381 |
389 DEFUN ("lock-buffer", Flock_buffer, 0, 1, 0, /* | 382 DEFUN ("lock-buffer", Flock_buffer, 0, 1, 0, /* |
390 Lock FILE, if current buffer is modified. | 383 Lock FILE, if current buffer is modified.\n\ |
391 FILE defaults to current buffer's visited file, | 384 FILE defaults to current buffer's visited file,\n\ |
392 or else nothing is done if current buffer isn't visiting a file. | 385 or else nothing is done if current buffer isn't visiting a file. |
393 */ | 386 */ |
394 (file)) | 387 (file)) |
395 { | 388 { |
396 if (NILP (file)) | 389 if (NILP (file)) |
397 file = current_buffer->file_truename; | 390 file = current_buffer->file_truename; |
398 CHECK_STRING (file); | 391 CHECK_STRING (file); |
399 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer) | 392 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer) |
433 && STRINGP (buffer->file_truename)) | 426 && STRINGP (buffer->file_truename)) |
434 unlock_file (buffer->file_truename); | 427 unlock_file (buffer->file_truename); |
435 } | 428 } |
436 | 429 |
437 DEFUN ("file-locked-p", Ffile_locked_p, 0, 1, 0, /* | 430 DEFUN ("file-locked-p", Ffile_locked_p, 0, 1, 0, /* |
438 Return nil if the FILENAME is not locked, | 431 Return nil if the FILENAME is not locked,\n\ |
439 t if it is locked by you, else a string of the name of the locker. | 432 t if it is locked by you, else a string of the name of the locker. |
440 */ | 433 */ |
441 (filename)) | 434 (filename)) |
442 { | 435 { |
443 Lisp_Object ret; | 436 Lisp_Object ret; |
444 register char *lfname; | 437 register char *lfname; |
445 int owner; | 438 int owner; |
446 lock_info_type locker; | 439 lock_info_type locker; |
447 struct gcpro gcpro1; | |
448 | |
449 GCPRO1 (filename); | |
450 | 440 |
451 filename = Fexpand_file_name (filename, Qnil); | 441 filename = Fexpand_file_name (filename, Qnil); |
452 | 442 |
453 MAKE_LOCK_NAME (lfname, filename); | 443 MAKE_LOCK_NAME (lfname, filename); |
454 | 444 |
461 ret = build_string (locker.user); | 451 ret = build_string (locker.user); |
462 | 452 |
463 if (owner > 0) | 453 if (owner > 0) |
464 FREE_LOCK_INFO (locker); | 454 FREE_LOCK_INFO (locker); |
465 | 455 |
466 UNGCPRO; | |
467 | |
468 return ret; | 456 return ret; |
469 } | 457 } |
470 | 458 |
471 | 459 |
472 /* Initialization functions. */ | 460 /* Initialization functions. */ |