X-Git-Url: https://git.hcoop.net/bpt/emacs.git/blobdiff_plain/37b3d30244ad822e049b6b20c2eadf5946cb02cc..a8e7d6d783219972c08fd49a3a2afaf26eb139c2:/src/filelock.c?ds=sidebyside diff --git a/src/filelock.c b/src/filelock.c index 8e18bb7b65..2613eec4ac 100644 --- a/src/filelock.c +++ b/src/filelock.c @@ -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. @@ -51,10 +51,6 @@ along with GNU Emacs. If not, see . */ #include #endif -#if !defined (S_ISLNK) && defined (S_IFLNK) -#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) -#endif - /* A file whose last-modified time is just after the most recent boot. Define this to be NULL to disable checking for this file. */ #ifndef BOOT_TIME_FILE @@ -172,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; @@ -195,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; } } @@ -288,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) @@ -348,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)); @@ -364,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) @@ -381,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); @@ -400,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 @. */ @@ -445,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 ()) @@ -498,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); } @@ -560,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 @@ -598,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 */ { @@ -639,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)); } } }