Annotation of GNUtools/emacs/src/filelock.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.