Merge changes from emacs-24 branch
[bpt/emacs.git] / src / filelock.c
index 7f8f0e1..2613eec 100644 (file)
@@ -1,5 +1,5 @@
 /* Lock files for editing.
-   Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2011
+   Copyright (C) 1985-1987, 1993-1994, 1996, 1998-2012
                  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -168,7 +168,7 @@ get_boot_time (void)
   /* If we did not find a boot time in wtmp, look at wtmp, and so on.  */
   for (counter = 0; counter < 20 && ! boot_time; counter++)
     {
-      char cmd_string[100];
+      char cmd_string[sizeof WTMP_FILE ".19.gz"];
       Lisp_Object tempname, filename;
       int delete_flag = 0;
 
@@ -191,19 +191,16 @@ get_boot_time (void)
                 character long prefix, and call make_temp_file with
                 second arg non-zero, so that it will add not more
                 than 6 characters to the prefix.  */
-             tempname = Fexpand_file_name (build_string ("wt"),
+             filename = Fexpand_file_name (build_string ("wt"),
                                            Vtemporary_file_directory);
-             tempname = make_temp_name (tempname, 1);
-             args[0] = Vshell_file_name;
+             filename = make_temp_name (filename, 1);
+             args[0] = build_string ("gzip");
              args[1] = Qnil;
-             args[2] = Qnil;
+             args[2] = list2 (QCfile, filename);
              args[3] = Qnil;
-             args[4] = build_string ("-c");
-             sprintf (cmd_string, "gunzip < %s.%d.gz > %s",
-                      WTMP_FILE, counter, SDATA (tempname));
-             args[5] = build_string (cmd_string);
+             args[4] = build_string ("-cd");
+             args[5] = tempname;
              Fcall_process (6, args);
-             filename = tempname;
              delete_flag = 1;
            }
        }
@@ -284,14 +281,10 @@ typedef struct
 {
   char *user;
   char *host;
-  unsigned long pid;
+  pid_t pid;
   time_t boot_time;
 } lock_info_type;
 
-/* When we read the info back, we might need this much more,
-   enough for decimal representation plus null.  */
-#define LOCK_PID_MAX (4 * sizeof (unsigned long))
-
 /* Free the two dynamically-allocated pieces in PTR.  */
 #define FREE_LOCK_INFO(i) do { xfree ((i).user); xfree ((i).host); } while (0)
 
@@ -344,13 +337,16 @@ static int
 lock_file_1 (char *lfname, int force)
 {
   register int err;
-  time_t boot_time;
+  printmax_t boot, pid;
   const char *user_name;
   const char *host_name;
   char *lock_info_str;
+  ptrdiff_t lock_info_size;
+  int symlink_errno;
+  USE_SAFE_ALLOCA;
 
   /* Call this first because it can GC.  */
-  boot_time = get_boot_time ();
+  boot = get_boot_time ();
 
   if (STRINGP (Fuser_login_name (Qnil)))
     user_name = SSDATA (Fuser_login_name (Qnil));
@@ -360,15 +356,14 @@ lock_file_1 (char *lfname, int force)
     host_name = SSDATA (Fsystem_name ());
   else
     host_name = "";
-  lock_info_str = (char *)alloca (strlen (user_name) + strlen (host_name)
-                                 + LOCK_PID_MAX + 30);
+  lock_info_size = (strlen (user_name) + strlen (host_name)
+                   + 2 * INT_STRLEN_BOUND (printmax_t)
+                   + sizeof "@.:");
+  SAFE_ALLOCA (lock_info_str, char *, lock_info_size);
+  pid = getpid ();
 
-  if (boot_time)
-    sprintf (lock_info_str, "%s@%s.%lu:%lu", user_name, host_name,
-            (unsigned long) getpid (), (unsigned long) boot_time);
-  else
-    sprintf (lock_info_str, "%s@%s.%lu", user_name, host_name,
-            (unsigned long) getpid ());
+  esprintf (lock_info_str, boot ? "%s@%s.%"pMd":%"pMd : "%s@%s.%"pMd,
+           user_name, host_name, pid, boot);
 
   err = symlink (lock_info_str, lfname);
   if (errno == EEXIST && force)
@@ -377,12 +372,15 @@ lock_file_1 (char *lfname, int force)
       err = symlink (lock_info_str, lfname);
     }
 
+  symlink_errno = errno;
+  SAFE_FREE ();
+  errno = symlink_errno;
   return err == 0;
 }
 
 /* Return 1 if times A and B are no more than one second apart.  */
 
-int
+static int
 within_one_second (time_t a, time_t b)
 {
   return (a - b >= -1 && a - b <= 1);
@@ -396,44 +394,22 @@ within_one_second (time_t a, time_t b)
 static int
 current_lock_owner (lock_info_type *owner, char *lfname)
 {
-  int len, ret;
-  int local_owner = 0;
+  int ret;
+  ptrdiff_t len;
+  lock_info_type local_owner;
+  intmax_t n;
   char *at, *dot, *colon;
-  char *lfinfo = 0;
-  int bufsize = 50;
-  /* Read arbitrarily-long contents of symlink.  Similar code in
-     file-symlink-p in fileio.c.  */
-  do
-    {
-      bufsize *= 2;
-      lfinfo = (char *) xrealloc (lfinfo, bufsize);
-      errno = 0;
-      len = readlink (lfname, lfinfo, bufsize);
-#ifdef ERANGE
-      /* HP-UX reports ERANGE if the buffer is too small.  */
-      if (len == -1 && errno == ERANGE)
-       len = bufsize;
-#endif
-    }
-  while (len >= bufsize);
+  char readlink_buf[READLINK_BUFSIZE];
+  char *lfinfo = emacs_readlink (lfname, readlink_buf);
 
   /* If nonexistent lock file, all is well; otherwise, got strange error. */
-  if (len == -1)
-    {
-      xfree (lfinfo);
-      return errno == ENOENT ? 0 : -1;
-    }
-
-  /* Link info exists, so `len' is its length.  Null terminate.  */
-  lfinfo[len] = 0;
+  if (!lfinfo)
+    return errno == ENOENT ? 0 : -1;
 
   /* Even if the caller doesn't want the owner info, we still have to
-     read it to determine return value, so allocate it.  */
+     read it to determine return value.  */
   if (!owner)
-    {
-      owner = (lock_info_type *) alloca (sizeof (lock_info_type));
-      local_owner = 1;
-    }
+    owner = &local_owner;
 
   /* Parse USER@HOST.PID:BOOT_TIME.  If can't parse, return -1.  */
   /* The USER is everything before the last @.  */
@@ -441,33 +417,45 @@ current_lock_owner (lock_info_type *owner, char *lfname)
   dot = strrchr (lfinfo, '.');
   if (!at || !dot)
     {
-      xfree (lfinfo);
+      if (lfinfo != readlink_buf)
+       xfree (lfinfo);
       return -1;
     }
   len = at - lfinfo;
   owner->user = (char *) xmalloc (len + 1);
-  strncpy (owner->user, lfinfo, len);
+  memcpy (owner->user, lfinfo, len);
   owner->user[len] = 0;
 
   /* The PID is everything from the last `.' to the `:'.  */
-  owner->pid = atoi (dot + 1);
-  colon = dot;
-  while (*colon && *colon != ':')
-    colon++;
+  errno = 0;
+  n = strtoimax (dot + 1, NULL, 10);
+  owner->pid =
+    ((0 <= n && n <= TYPE_MAXIMUM (pid_t)
+      && (TYPE_MAXIMUM (pid_t) < INTMAX_MAX || errno != ERANGE))
+     ? n : 0);
+
+  colon = strchr (dot + 1, ':');
   /* After the `:', if there is one, comes the boot time.  */
-  if (*colon == ':')
-    owner->boot_time = atoi (colon + 1);
-  else
-    owner->boot_time = 0;
+  n = 0;
+  if (colon)
+    {
+      errno = 0;
+      n = strtoimax (colon + 1, NULL, 10);
+    }
+  owner->boot_time =
+    ((0 <= n && n <= TYPE_MAXIMUM (time_t)
+      && (TYPE_MAXIMUM (time_t) < INTMAX_MAX || errno != ERANGE))
+     ? n : 0);
 
   /* The host is everything in between.  */
   len = dot - at - 1;
   owner->host = (char *) xmalloc (len + 1);
-  strncpy (owner->host, at + 1, len);
+  memcpy (owner->host, at + 1, len);
   owner->host[len] = 0;
 
   /* We're done looking at the link info.  */
-  xfree (lfinfo);
+  if (lfinfo != readlink_buf)
+    xfree (lfinfo);
 
   /* On current host?  */
   if (STRINGP (Fsystem_name ())
@@ -494,7 +482,7 @@ current_lock_owner (lock_info_type *owner, char *lfname)
     }
 
   /* Avoid garbage.  */
-  if (local_owner || ret <= 0)
+  if (owner == &local_owner || ret <= 0)
     {
       FREE_LOCK_INFO (*owner);
     }
@@ -556,8 +544,11 @@ lock_file (Lisp_Object fn)
 {
   register Lisp_Object attack, orig_fn, encoded_fn;
   register char *lfname, *locker;
+  ptrdiff_t locker_size;
   lock_info_type lock_info;
+  printmax_t pid;
   struct gcpro gcpro1;
+  USE_SAFE_ALLOCA;
 
   /* Don't do locking while dumping Emacs.
      Uncompressing wtmp files uses call-process, which does not work
@@ -594,13 +585,17 @@ lock_file (Lisp_Object fn)
     return;
 
   /* Else consider breaking the lock */
-  locker = (char *) alloca (strlen (lock_info.user) + strlen (lock_info.host)
-                           + LOCK_PID_MAX + 9);
-  sprintf (locker, "%s@%s (pid %lu)", lock_info.user, lock_info.host,
-           lock_info.pid);
+  locker_size = (strlen (lock_info.user) + strlen (lock_info.host)
+                + INT_STRLEN_BOUND (printmax_t)
+                + sizeof "@ (pid )");
+  SAFE_ALLOCA (locker, char *, locker_size);
+  pid = lock_info.pid;
+  esprintf (locker, "%s@%s (pid %"pMd")",
+           lock_info.user, lock_info.host, pid);
   FREE_LOCK_INFO (lock_info);
 
   attack = call2 (intern ("ask-user-about-lock"), fn, build_string (locker));
+  SAFE_FREE ();
   if (!NILP (attack))
     /* User says take the lock */
     {
@@ -635,7 +630,7 @@ unlock_all_files (void)
       b = XBUFFER (XCDR (XCAR (tail)));
       if (STRINGP (BVAR (b, file_truename)) && BUF_SAVE_MODIFF (b) < BUF_MODIFF (b))
        {
-         unlock_file(BVAR (b, file_truename));
+         unlock_file (BVAR (b, file_truename));
        }
     }
 }