|
|
1.1 ! root 1: /* Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc. ! 2: ! 3: This file is part of GNU Emacs. ! 4: ! 5: GNU Emacs is free software; you can redistribute it and/or modify ! 6: it under the terms of the GNU General Public License as published by ! 7: the Free Software Foundation; either version 1, or (at your option) ! 8: any later version. ! 9: ! 10: GNU Emacs is distributed in the hope that it will be useful, ! 11: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 13: GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with GNU Emacs; see the file COPYING. If not, write to ! 17: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ ! 18: ! 19: ! 20: #include <sys/types.h> ! 21: #include <sys/stat.h> ! 22: #include "config.h" ! 23: #ifdef hpux ! 24: /* needed by <pwd.h> */ ! 25: #include <stdio.h> ! 26: #undef NULL ! 27: #endif ! 28: #include "lisp.h" ! 29: #include "paths.h" ! 30: #include "buffer.h" ! 31: ! 32: #ifdef VMS ! 33: #include "vms-pwd.h" ! 34: #else ! 35: #include <pwd.h> ! 36: #endif ! 37: ! 38: #include <errno.h> ! 39: #include <sys/file.h> ! 40: #ifdef USG ! 41: #include <fcntl.h> ! 42: #endif /* USG */ ! 43: ! 44: #include "filetypes.h" ! 45: ! 46: extern int errno; ! 47: ! 48: #ifdef VMS ! 49: /* Prevent the file from being totally empty. */ ! 50: static dummy () {} ! 51: #endif ! 52: ! 53: #ifdef CLASH_DETECTION ! 54: ! 55: /* If system does not have symbolic links, it does not have lstat. ! 56: In that case, use ordinary stat instead. */ ! 57: ! 58: #ifndef S_IFLNK ! 59: #define lstat stat ! 60: #endif ! 61: ! 62: static Lisp_Object ! 63: lock_file_owner_name (lfname) ! 64: char *lfname; ! 65: { ! 66: struct stat s; ! 67: struct passwd *the_pw; ! 68: extern struct passwd *getpwuid (); ! 69: ! 70: if (lstat (lfname, &s) == 0) ! 71: the_pw = getpwuid (s.st_uid); ! 72: return (the_pw == 0 ? Qnil : build_string (the_pw->pw_name)); ! 73: } ! 74: ! 75: ! 76: /* lock_file locks file fn, ! 77: meaning it serves notice on the world that you intend to edit that file. ! 78: This should be done only when about to modify a file-visiting ! 79: buffer previously unmodified. ! 80: Do not (normally) call lock_buffer for a buffer already modified, ! 81: as either the file is already locked, or the user has already ! 82: decided to go ahead without locking. ! 83: ! 84: When lock_buffer returns, either the lock is locked for us, ! 85: or the user has said to go ahead without locking. ! 86: ! 87: If the file is locked by someone else, lock_buffer calls ! 88: ask-user-about-lock (a Lisp function) with two arguments, ! 89: the file name and the name of the user who did the locking. ! 90: This function can signal an error, or return t meaning ! 91: take away the lock, or return nil meaning ignore the lock. */ ! 92: ! 93: /* The lock file name is the file name with "/" replaced by "!" ! 94: and put in the Emacs lock directory. */ ! 95: /* (ie., /ka/king/junk.tex -> /!/!ka!king!junk.tex). */ ! 96: ! 97: /* If SHORT_FILE_NAMES is defined, the lock file name is the hex ! 98: representation of a 14-bytes CRC generated from the file name ! 99: and put in the Emacs lock directory (not very nice, but it works). ! 100: (ie., /ka/king/junk.tex -> /!/ec92d3ed24a8f0). */ ! 101: ! 102: #ifdef SHORT_FILE_NAMES ! 103: ! 104: # define CREATE_LOCK_FILE_NAME(lfname, fn) \ ! 105: { lfname = (char *) alloca (14 + strlen (PATH_LOCK) + 1); \ ! 106: fill_in_lock_short_file_name (lfname, fn); } ! 107: ! 108: #else ! 109: ! 110: # define CREATE_LOCK_FILE_NAME(lfname, fn) \ ! 111: { lfname = (char *) alloca (XSTRING (fn)->size + strlen (PATH_LOCK) + 1); \ ! 112: fill_in_lock_file_name (lfname, fn); } ! 113: ! 114: #endif ! 115: ! 116: ! 117: ! 118: void ! 119: lock_file (fn) ! 120: register Lisp_Object fn; ! 121: { ! 122: register Lisp_Object attack; ! 123: register char *lfname; ! 124: ! 125: /* Create the name of the lock-file for file fn */ ! 126: CREATE_LOCK_FILE_NAME (lfname, fn); ! 127: ! 128: /* See if this file is visited and has changed on disk since it was visited. */ ! 129: { ! 130: register Lisp_Object subject_buf = Fget_file_buffer (fn); ! 131: if (!NULL (subject_buf) ! 132: && NULL (Fverify_visited_file_modtime (subject_buf)) ! 133: && !NULL (Ffile_exists_p (fn))) ! 134: call1 (intern ("ask-user-about-supersession-threat"), fn); ! 135: } ! 136: ! 137: /* Try to lock the lock. */ ! 138: if (lock_if_free (lfname) <= 0) ! 139: /* Return now if we have locked it, or if lock dir does not exist */ ! 140: return; ! 141: ! 142: /* Else consider breaking the lock */ ! 143: attack = call2 (intern ("ask-user-about-lock"), fn, ! 144: lock_file_owner_name (lfname)); ! 145: if (!NULL (attack)) ! 146: /* User says take the lock */ ! 147: { ! 148: lock_superlock (lfname); ! 149: lock_file_1 (lfname, O_WRONLY) ; ! 150: unlink (PATH_SUPERLOCK); ! 151: return; ! 152: } ! 153: /* User says ignore the lock */ ! 154: } ! 155: ! 156: fill_in_lock_file_name (lockfile, fn) ! 157: register char *lockfile; ! 158: register Lisp_Object fn; ! 159: { ! 160: register char *p; ! 161: ! 162: strcpy (lockfile, PATH_LOCK); ! 163: ! 164: p = lockfile + strlen (lockfile); ! 165: ! 166: strcpy (p, XSTRING (fn)->data); ! 167: ! 168: for (; *p; p++) ! 169: { ! 170: if (*p == '/') ! 171: *p = '!'; ! 172: } ! 173: } ! 174: ! 175: #ifdef SHORT_FILE_NAMES ! 176: fill_in_lock_short_file_name (lockfile, fn) ! 177: register char *lockfile; ! 178: register Lisp_Object fn; ! 179: { ! 180: register union ! 181: { ! 182: unsigned int word [2]; ! 183: unsigned char byte [8]; ! 184: } crc; ! 185: register unsigned char *p, new; ! 186: ! 187: /* 7-bytes cyclic code for burst correction on byte-by-byte basis. ! 188: the used polynomial is D^7 + D^6 + D^3 +1. [email protected] */ ! 189: ! 190: crc.word[0] = crc.word[1] = 0; ! 191: ! 192: for (p = XSTRING (fn)->data; new = *p++; ) ! 193: { ! 194: new += crc.byte[7]; ! 195: crc.byte[7] = crc.byte[6]; ! 196: crc.byte[6] = crc.byte[5] + new; ! 197: crc.byte[5] = crc.byte[4]; ! 198: crc.byte[4] = crc.byte[3]; ! 199: crc.byte[3] = crc.byte[2] + new; ! 200: crc.byte[2] = crc.byte[1]; ! 201: crc.byte[1] = crc.byte[0]; ! 202: crc.byte[0] = new; ! 203: } ! 204: sprintf (lockfile, "%s%.2x%.2x%.2x%.2x%.2x%.2x%.2x", PATH_LOCK, ! 205: crc.byte[0], crc.byte[1], crc.byte[2], crc.byte[3], ! 206: crc.byte[4], crc.byte[5], crc.byte[6]); ! 207: } ! 208: #endif /* SHORT_FILE_NAMES */ ! 209: ! 210: /* Lock the lock file named LFNAME. ! 211: If MODE is O_WRONLY, we do so even if it is already locked. ! 212: If MODE is O_WRONLY | O_EXCL | O_CREAT, we do so only if it is free. ! 213: Return 1 if successful, 0 if not. */ ! 214: ! 215: int ! 216: lock_file_1 (lfname, mode) ! 217: int mode; char *lfname; ! 218: { ! 219: register int fd; ! 220: char buf[20]; ! 221: ! 222: if ((fd = open (lfname, mode, 0666)) >= 0) ! 223: { ! 224: #ifdef NO_FCHMOD ! 225: chmod (lfname, 0666); ! 226: #else ! 227: fchmod (fd, 0666); ! 228: #endif ! 229: sprintf (buf, "%d ", getpid ()); ! 230: write (fd, buf, strlen (buf)); ! 231: close (fd); ! 232: return 1; ! 233: } ! 234: else ! 235: return 0; ! 236: } ! 237: ! 238: /* Lock the lock named LFNAME if possible. ! 239: Return 0 in that case. ! 240: Return positive if lock is really locked by someone else. ! 241: Return -1 if cannot lock for any other reason. */ ! 242: ! 243: int ! 244: lock_if_free (lfname) ! 245: register char *lfname; ! 246: { ! 247: register int clasher; ! 248: ! 249: while (lock_file_1 (lfname, O_WRONLY | O_EXCL | O_CREAT) == 0) ! 250: { ! 251: if (errno != EEXIST) ! 252: return -1; ! 253: clasher = current_lock_owner (lfname); ! 254: if (clasher != 0) ! 255: if (clasher != getpid ()) ! 256: return (clasher); ! 257: else return (0); ! 258: /* Try again to lock it */ ! 259: } ! 260: return 0; ! 261: } ! 262: ! 263: /* Return the pid of the process that claims to own the lock file LFNAME, ! 264: or 0 if nobody does or the lock is obsolete, ! 265: or -1 if something is wrong with the locking mechanism. */ ! 266: ! 267: int ! 268: current_lock_owner (lfname) ! 269: char *lfname; ! 270: { ! 271: int owner = current_lock_owner_1 (lfname); ! 272: if (owner == 0 && errno == ENOENT) ! 273: return (0); ! 274: /* Is it locked by a process that exists? */ ! 275: if (owner != 0 && (kill (owner, 0) >= 0 || errno == EPERM)) ! 276: return (owner); ! 277: if (unlink (lfname) < 0) ! 278: return (-1); ! 279: return (0); ! 280: } ! 281: ! 282: int ! 283: current_lock_owner_1 (lfname) ! 284: char *lfname; ! 285: { ! 286: register int fd; ! 287: char buf[20]; ! 288: int tem; ! 289: ! 290: fd = open (lfname, O_RDONLY, 0666); ! 291: if (fd < 0) ! 292: return 0; ! 293: tem = read (fd, buf, sizeof buf); ! 294: close (fd); ! 295: return (tem <= 0 ? 0 : atoi (buf)); ! 296: } ! 297: ! 298: ! 299: void ! 300: unlock_file (fn) ! 301: register Lisp_Object fn; ! 302: { ! 303: register char *lfname; ! 304: ! 305: CREATE_LOCK_FILE_NAME (lfname, fn); ! 306: ! 307: lock_superlock (lfname); ! 308: ! 309: if (current_lock_owner_1 (lfname) == getpid ()) ! 310: unlink (lfname); ! 311: ! 312: unlink (PATH_SUPERLOCK); ! 313: } ! 314: ! 315: lock_superlock (lfname) ! 316: char *lfname; ! 317: { ! 318: register int i, fd; ! 319: ! 320: for (i = -20; i < 0 && (fd = open (PATH_SUPERLOCK, ! 321: O_WRONLY | O_EXCL | O_CREAT, 0666)) < 0; ! 322: i++) ! 323: { ! 324: if (errno != EEXIST) ! 325: return; ! 326: sleep (1); ! 327: } ! 328: if (fd >= 0) ! 329: { ! 330: #ifdef NO_FCHMOD ! 331: chmod (PATH_SUPERLOCK, 0666); ! 332: #else ! 333: fchmod (fd, 0666); ! 334: #endif ! 335: write (fd, lfname, strlen (lfname)); ! 336: close (fd); ! 337: } ! 338: } ! 339: ! 340: void ! 341: unlock_all_files () ! 342: { ! 343: register Lisp_Object tail; ! 344: register struct buffer *b; ! 345: ! 346: for (tail = Vbuffer_alist; XGCTYPE (tail) == Lisp_Cons; ! 347: tail = XCONS (tail)->cdr) ! 348: { ! 349: b = XBUFFER (XCONS (XCONS (tail)->car)->cdr); ! 350: if (XTYPE (b->filename) == Lisp_String && ! 351: b->save_modified < BUF_MODIFF (b)) ! 352: unlock_file (b->filename); ! 353: } ! 354: } ! 355: ! 356: ! 357: DEFUN ("lock-buffer", Flock_buffer, Slock_buffer, ! 358: 0, 1, 0, ! 359: "Locks FILE, if current buffer is modified.\n\ ! 360: FILE defaults to current buffer's visited file,\n\ ! 361: or else nothing is done if current buffer isn't visiting a file.") ! 362: (fn) ! 363: Lisp_Object fn; ! 364: { ! 365: if (NULL (fn)) ! 366: fn = current_buffer->filename; ! 367: else ! 368: CHECK_STRING (fn, 0); ! 369: if (current_buffer->save_modified < MODIFF ! 370: && !NULL (fn)) ! 371: lock_file (fn); ! 372: return Qnil; ! 373: } ! 374: ! 375: DEFUN ("unlock-buffer", Funlock_buffer, Sunlock_buffer, ! 376: 0, 0, 0, ! 377: "Unlocks the file visited in the current buffer,\n\ ! 378: if it should normally be locked.") ! 379: () ! 380: { ! 381: if (current_buffer->save_modified < MODIFF && ! 382: XTYPE (current_buffer->filename) == Lisp_String) ! 383: unlock_file (current_buffer->filename); ! 384: return Qnil; ! 385: } ! 386: ! 387: ! 388: /* Unlock the file visited in buffer BUFFER. */ ! 389: ! 390: unlock_buffer (buffer) ! 391: struct buffer *buffer; ! 392: { ! 393: if (buffer->save_modified < BUF_MODIFF (buffer) ! 394: && XTYPE (buffer->filename) == Lisp_String) ! 395: unlock_file (buffer->filename); ! 396: } ! 397: ! 398: DEFUN ("file-locked-p", Ffile_locked_p, Sfile_locked_p, 0, 1, 0, ! 399: "Returns nil if the FILENAME is not locked,\n\ ! 400: t if it is locked by you, else a string of the name of the locker.") ! 401: (fn) ! 402: Lisp_Object fn; ! 403: { ! 404: register char *lfname; ! 405: int owner; ! 406: ! 407: fn = Fexpand_file_name (fn, Qnil); ! 408: ! 409: /* Create the name of the lock-file for file filename */ ! 410: CREATE_LOCK_FILE_NAME (lfname, fn); ! 411: ! 412: owner = current_lock_owner (lfname); ! 413: if (owner <= 0) ! 414: return (Qnil); ! 415: else if (owner == getpid ()) ! 416: return (Qt); ! 417: ! 418: return (lock_file_owner_name (lfname)); ! 419: } ! 420: ! 421: syms_of_filelock () ! 422: { ! 423: defsubr (&Sunlock_buffer); ! 424: defsubr (&Slock_buffer); ! 425: defsubr (&Sfile_locked_p); ! 426: } ! 427: ! 428: #endif /* CLASH_DETECTION */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.