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. */