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