comparison src/filelock.c @ 442:abe6d1db359e r21-2-36

Import from CVS: tag r21-2-36
author cvs
date Mon, 13 Aug 2007 11:35:02 +0200
parents 9d177e8d4150
children 576fb035e263
comparison
equal deleted inserted replaced
441:72a7cfa4a488 442:abe6d1db359e
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 /* Does not GC. */
124 char *user_name; 127 int err;
128 char *lock_info_str;
125 char *host_name; 129 char *host_name;
126 char *lock_info_str; 130 char *user_name = user_login_name (NULL);
127 131
128 if (STRINGP (Fuser_login_name (Qnil))) 132 if (user_name == NULL)
129 user_name = (char *) XSTRING_DATA (Fuser_login_name (Qnil));
130 else
131 user_name = ""; 133 user_name = "";
132 if (STRINGP (Fsystem_name ())) 134
133 host_name = (char *) XSTRING_DATA (Fsystem_name ()); 135 if (STRINGP (Vsystem_name))
136 host_name = (char *) XSTRING_DATA (Vsystem_name);
134 else 137 else
135 host_name = ""; 138 host_name = "";
139
136 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name) 140 lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
137 + LOCK_PID_MAX + 5); 141 + LOCK_PID_MAX + 5);
138 142
139 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name, 143 sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
140 (unsigned long) getpid ()); 144 (unsigned long) getpid ());
141 145
142 err = symlink (lock_info_str, lfname); 146 err = symlink (lock_info_str, lfname);
143 if (errno == EEXIST && force) 147 if (err != 0 && errno == EEXIST && force)
144 { 148 {
145 unlink (lfname); 149 unlink (lfname);
146 err = symlink (lock_info_str, lfname); 150 err = symlink (lock_info_str, lfname);
147 } 151 }
148 152
155 or -1 if something is wrong with the locking mechanism. */ 159 or -1 if something is wrong with the locking mechanism. */
156 160
157 static int 161 static int
158 current_lock_owner (lock_info_type *owner, char *lfname) 162 current_lock_owner (lock_info_type *owner, char *lfname)
159 { 163 {
160 int o, p, len, ret; 164 /* Does not GC. */
165 int len, ret;
161 int local_owner = 0; 166 int local_owner = 0;
162 char *at, *dot; 167 char *at, *dot;
163 char *lfinfo = 0; 168 char *lfinfo = 0;
164 int bufsize = 50; 169 int bufsize = 50;
165 /* Read arbitrarily-long contents of symlink. Similar code in 170 /* Read arbitrarily-long contents of symlink. Similar code in
169 bufsize *= 2; 174 bufsize *= 2;
170 lfinfo = (char *) xrealloc (lfinfo, bufsize); 175 lfinfo = (char *) xrealloc (lfinfo, bufsize);
171 len = readlink (lfname, lfinfo, bufsize); 176 len = readlink (lfname, lfinfo, bufsize);
172 } 177 }
173 while (len >= bufsize); 178 while (len >= bufsize);
174 179
175 /* If nonexistent lock file, all is well; otherwise, got strange error. */ 180 /* If nonexistent lock file, all is well; otherwise, got strange error. */
176 if (len == -1) 181 if (len == -1)
177 { 182 {
178 xfree (lfinfo); 183 xfree (lfinfo);
179 return errno == ENOENT ? 0 : -1; 184 return errno == ENOENT ? 0 : -1;
180 } 185 }
181 186
182 /* Link info exists, so `len' is its length. Null terminate. */ 187 /* Link info exists, so `len' is its length. Null terminate. */
183 lfinfo[len] = 0; 188 lfinfo[len] = 0;
184 189
185 /* Even if the caller doesn't want the owner info, we still have to 190 /* Even if the caller doesn't want the owner info, we still have to
186 read it to determine return value, so allocate it. */ 191 read it to determine return value, so allocate it. */
187 if (!owner) 192 if (!owner)
188 { 193 {
189 owner = (lock_info_type *) alloca (sizeof (lock_info_type)); 194 owner = (lock_info_type *) alloca (sizeof (lock_info_type));
190 local_owner = 1; 195 local_owner = 1;
191 } 196 }
192 197
193 /* Parse USER@HOST.PID. If can't parse, return -1. */ 198 /* Parse USER@HOST.PID. If can't parse, return -1. */
194 /* The USER is everything before the first @. */ 199 /* The USER is everything before the first @. */
195 at = strchr (lfinfo, '@'); 200 at = strchr (lfinfo, '@');
196 dot = strrchr (lfinfo, '.'); 201 dot = strrchr (lfinfo, '.');
197 if (!at || !dot) { 202 if (!at || !dot) {
200 } 205 }
201 len = at - lfinfo; 206 len = at - lfinfo;
202 owner->user = (char *) xmalloc (len + 1); 207 owner->user = (char *) xmalloc (len + 1);
203 strncpy (owner->user, lfinfo, len); 208 strncpy (owner->user, lfinfo, len);
204 owner->user[len] = 0; 209 owner->user[len] = 0;
205 210
206 /* The PID is everything after the last `.'. */ 211 /* The PID is everything after the last `.'. */
207 owner->pid = atoi (dot + 1); 212 owner->pid = atoi (dot + 1);
208 213
209 /* The host is everything in between. */ 214 /* The host is everything in between. */
210 len = dot - at - 1; 215 len = dot - at - 1;
212 strncpy (owner->host, at + 1, len); 217 strncpy (owner->host, at + 1, len);
213 owner->host[len] = 0; 218 owner->host[len] = 0;
214 219
215 /* We're done looking at the link info. */ 220 /* We're done looking at the link info. */
216 xfree (lfinfo); 221 xfree (lfinfo);
217 222
218 /* On current host? */ 223 /* On current host? */
219 if (STRINGP (Fsystem_name ()) 224 if (STRINGP (Fsystem_name ())
220 && strcmp (owner->host, XSTRING_DATA(Fsystem_name ())) == 0) 225 && strcmp (owner->host, (char *) XSTRING_DATA (Fsystem_name ())) == 0)
221 { 226 {
222 if (owner->pid == getpid ()) 227 if (owner->pid == getpid ())
223 ret = 2; /* We own it. */ 228 ret = 2; /* We own it. */
224 else if (owner->pid > 0 229 else if (owner->pid > 0
225 && (kill (owner->pid, 0) >= 0 || errno == EPERM)) 230 && (kill (owner->pid, 0) >= 0 || errno == EPERM))
234 else 239 else
235 { /* If we wanted to support the check for stale locks on remote machines, 240 { /* If we wanted to support the check for stale locks on remote machines,
236 here's where we'd do it. */ 241 here's where we'd do it. */
237 ret = 1; 242 ret = 1;
238 } 243 }
239 244
240 /* Avoid garbage. */ 245 /* Avoid garbage. */
241 if (local_owner || ret <= 0) 246 if (local_owner || ret <= 0)
242 { 247 {
243 FREE_LOCK_INFO (*owner); 248 FREE_LOCK_INFO (*owner);
244 } 249 }
252 Return -1 if cannot lock for any other reason. */ 257 Return -1 if cannot lock for any other reason. */
253 258
254 static int 259 static int
255 lock_if_free (lock_info_type *clasher, char *lfname) 260 lock_if_free (lock_info_type *clasher, char *lfname)
256 { 261 {
262 /* Does not GC. */
257 if (lock_file_1 (lfname, 0) == 0) 263 if (lock_file_1 (lfname, 0) == 0)
258 { 264 {
259 int locker; 265 int locker;
260 266
261 if (errno != EEXIST) 267 if (errno != EEXIST)
262 return -1; 268 return -1;
263 269
264 locker = current_lock_owner (clasher, lfname); 270 locker = current_lock_owner (clasher, lfname);
265 if (locker == 2) 271 if (locker == 2)
266 { 272 {
267 FREE_LOCK_INFO (*clasher); 273 FREE_LOCK_INFO (*clasher);
268 return 0; /* We ourselves locked it. */ 274 return 0; /* We ourselves locked it. */
293 take away the lock, or return nil meaning ignore the lock. */ 299 take away the lock, or return nil meaning ignore the lock. */
294 300
295 void 301 void
296 lock_file (Lisp_Object fn) 302 lock_file (Lisp_Object fn)
297 { 303 {
298 /* This function can GC. */ 304 /* This function can GC. GC checked 7-11-00 ben */
299 /* dmoore - and can destroy current_buffer and all sorts of other 305 /* dmoore - and can destroy current_buffer and all sorts of other
300 mean nasty things with pointy teeth. If you call this make sure 306 mean nasty things with pointy teeth. If you call this make sure
301 you protect things right. */ 307 you protect things right. */
302 /* Somebody updated the code in this function and removed the previous 308 /* Somebody updated the code in this function and removed the previous
303 comment. -slb */ 309 comment. -slb */
304 310
305 register Lisp_Object attack, orig_fn; 311 register Lisp_Object attack, orig_fn;
306 register char *lfname, *locker; 312 register char *lfname, *locker;
307 lock_info_type lock_info; 313 lock_info_type lock_info;
320 { 326 {
321 subject_buf = get_truename_buffer (orig_fn); 327 subject_buf = get_truename_buffer (orig_fn);
322 if (!NILP (subject_buf) 328 if (!NILP (subject_buf)
323 && NILP (Fverify_visited_file_modtime (subject_buf)) 329 && NILP (Fverify_visited_file_modtime (subject_buf))
324 && !NILP (Ffile_exists_p (fn))) 330 && !NILP (Ffile_exists_p (fn)))
325 call1_in_buffer (XBUFFER(subject_buf), 331 call1_in_buffer (XBUFFER (subject_buf),
326 Qask_user_about_supersession_threat, fn); 332 Qask_user_about_supersession_threat, fn);
327 } 333 }
328 334
329 /* Try to lock the lock. */ 335 /* Try to lock the lock. */
330 if (lock_if_free (&lock_info, lfname) <= 0) 336 if (lock_if_free (&lock_info, lfname) <= 0)
331 /* Return now if we have locked it, or if lock creation failed */ 337 /* Return now if we have locked it, or if lock creation failed */
335 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host) 341 locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
336 + LOCK_PID_MAX + 9); 342 + LOCK_PID_MAX + 9);
337 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host, 343 sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
338 lock_info.pid); 344 lock_info.pid);
339 FREE_LOCK_INFO (lock_info); 345 FREE_LOCK_INFO (lock_info);
340 346
341 attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) : 347 attack = call2_in_buffer (BUFFERP (subject_buf) ? XBUFFER (subject_buf) :
342 current_buffer, Qask_user_about_lock , fn, 348 current_buffer, Qask_user_about_lock , fn,
343 build_string (locker)); 349 build_string (locker));
344 if (!NILP (attack)) 350 if (!NILP (attack))
345 /* User says take the lock */ 351 /* User says take the lock */
353 } 359 }
354 360
355 void 361 void
356 unlock_file (Lisp_Object fn) 362 unlock_file (Lisp_Object fn)
357 { 363 {
364 /* This can GC */
358 register char *lfname; 365 register char *lfname;
366 struct gcpro gcpro1;
367
368 GCPRO1 (fn);
359 369
360 fn = Fexpand_file_name (fn, Qnil); 370 fn = Fexpand_file_name (fn, Qnil);
361 371
362 MAKE_LOCK_NAME (lfname, fn); 372 MAKE_LOCK_NAME (lfname, fn);
363 373
364 if (current_lock_owner (0, lfname) == 2) 374 if (current_lock_owner (0, lfname) == 2)
365 unlink (lfname); 375 unlink (lfname);
376
377 UNGCPRO;
366 } 378 }
367 379
368 void 380 void
369 unlock_all_files () 381 unlock_all_files (void)
370 { 382 {
371 register Lisp_Object tail; 383 register Lisp_Object tail;
372 register struct buffer *b;
373 384
374 for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail)) 385 for (tail = Vbuffer_alist; CONSP (tail); tail = XCDR (tail))
375 { 386 {
376 b = XBUFFER (XCDR (XCAR (tail))); 387 struct buffer *b = XBUFFER (XCDR (XCAR (tail)));
377 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b)) 388 if (STRINGP (b->file_truename) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
378 unlock_file (b->file_truename); 389 unlock_file (b->file_truename);
379 } 390 }
380 } 391 }
381 392
382 DEFUN ("lock-buffer", Flock_buffer, 0, 1, 0, /* 393 DEFUN ("lock-buffer", Flock_buffer, 0, 1, 0, /*
383 Lock FILE, if current buffer is modified.\n\ 394 Lock FILE, if current buffer is modified.
384 FILE defaults to current buffer's visited file,\n\ 395 FILE defaults to current buffer's visited file,
385 or else nothing is done if current buffer isn't visiting a file. 396 or else nothing is done if current buffer isn't visiting a file.
386 */ 397 */
387 (file)) 398 (file))
388 { 399 {
389 if (NILP (file)) 400 if (NILP (file))
390 file = current_buffer->file_truename; 401 file = current_buffer->file_truename;
391 CHECK_STRING (file); 402 CHECK_STRING (file);
392 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer) 403 if (BUF_SAVE_MODIFF (current_buffer) < BUF_MODIFF (current_buffer)
426 && STRINGP (buffer->file_truename)) 437 && STRINGP (buffer->file_truename))
427 unlock_file (buffer->file_truename); 438 unlock_file (buffer->file_truename);
428 } 439 }
429 440
430 DEFUN ("file-locked-p", Ffile_locked_p, 0, 1, 0, /* 441 DEFUN ("file-locked-p", Ffile_locked_p, 0, 1, 0, /*
431 Return nil if the FILENAME is not locked,\n\ 442 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. 443 t if it is locked by you, else a string of the name of the locker.
433 */ 444 */
434 (filename)) 445 (filename))
435 { 446 {
436 Lisp_Object ret; 447 Lisp_Object ret;
437 register char *lfname; 448 register char *lfname;
438 int owner; 449 int owner;
439 lock_info_type locker; 450 lock_info_type locker;
451 struct gcpro gcpro1;
452
453 GCPRO1 (filename);
440 454
441 filename = Fexpand_file_name (filename, Qnil); 455 filename = Fexpand_file_name (filename, Qnil);
442 456
443 MAKE_LOCK_NAME (lfname, filename); 457 MAKE_LOCK_NAME (lfname, filename);
444 458
451 ret = build_string (locker.user); 465 ret = build_string (locker.user);
452 466
453 if (owner > 0) 467 if (owner > 0)
454 FREE_LOCK_INFO (locker); 468 FREE_LOCK_INFO (locker);
455 469
470 UNGCPRO;
471
456 return ret; 472 return ret;
457 } 473 }
458 474
459 475
460 /* Initialization functions. */ 476 /* Initialization functions. */