From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail From: Paul Eggert Newsgroups: gmane.emacs.bugs Subject: bug#36502: Fwd: bug#36502: 27.0.50; infinite loop in file-name-case-insensitive-p Date: Wed, 24 Jul 2019 14:36:25 -0700 Organization: UCLA Computer Science Department Message-ID: <90f841a9-4ec2-14f2-846c-fbfc31b9ad42@cs.ucla.edu> References: <87muhr47k5.fsf@gmail.com> <837e8v87jf.fsf@gnu.org> <2ffa1b04-e667-f708-1047-d5fc38e72787@cornell.edu> <83v9wd7vwi.fsf@gnu.org> <14115c87-c1e7-6f3d-2694-106a9d4c8706@cornell.edu> <83bly47lxk.fsf@gnu.org> <837e8s7hk4.fsf@gnu.org> <2f71c7a3-423c-4a36-a0c2-5c1833905a28@cornell.edu> <2f15cf80-feba-3e71-4cbf-a7fa25b43797@cornell.edu> <83zhlo5tkm.fsf@gnu.org> <41c1033e-bd1c-d244-7293-00dfba900e8f@cornell.edu> <83v9w73gb5.fsf@gnu.org> <07659a69-b89e-51da-8bb3-adc32e1f39ae@cornell.edu> <09ed9fa5-efd8-93df-e4f1-dbd73cb1b823@cornell.edu> <83lfwtt650.fsf@gnu.org> <0a542a8e-67b8-b355-8fdf-f87d5b0cd1c5@cornell.edu> <715cb1de-9815-4229-993c-ecbf16da662a@cs.ucla.edu> <834l3fsc2c.fsf@gnu.org> <22127ce6-182a-38ac-acc1-dfd09d727f18@cornell.edu> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------AAE76996D4A1A3FA9B037523" Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="147199"; mail-complaints-to="usenet@blaine.gmane.org" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.8.0 Cc: "rms@gnu.org" , "schwab@suse.de" , "36502-done@debbugs.gnu.org" <36502@debbugs.gnu.org>, "npostavs@gmail.com" , "monnier@iro.umontreal.ca" , "dan@dpsutton.com" To: Ken Brown , Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Wed Jul 24 23:37:10 2019 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([209.51.188.17]) by blaine.gmane.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.89) (envelope-from ) id 1hqOwg-000c9l-5z for geb-bug-gnu-emacs@m.gmane.org; Wed, 24 Jul 2019 23:37:10 +0200 Original-Received: from localhost ([::1]:54694 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hqOwe-0005vX-Jz for geb-bug-gnu-emacs@m.gmane.org; Wed, 24 Jul 2019 17:37:08 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:40991) by lists.gnu.org with esmtp (Exim 4.86_2) (envelope-from ) id 1hqOwb-0005vL-DX for bug-gnu-emacs@gnu.org; Wed, 24 Jul 2019 17:37:06 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hqOwZ-0000Wj-KW for bug-gnu-emacs@gnu.org; Wed, 24 Jul 2019 17:37:05 -0400 Original-Received: from debbugs.gnu.org ([209.51.188.43]:57554) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hqOwY-0000Ve-Di for bug-gnu-emacs@gnu.org; Wed, 24 Jul 2019 17:37:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1hqOwY-0007Fd-9d for bug-gnu-emacs@gnu.org; Wed, 24 Jul 2019 17:37:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Paul Eggert Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Wed, 24 Jul 2019 21:37:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 36502 X-GNU-PR-Package: emacs Original-Received: via spool by 36502-submit@debbugs.gnu.org id=B36502.156400419827845 (code B ref 36502); Wed, 24 Jul 2019 21:37:02 +0000 Original-Received: (at 36502) by debbugs.gnu.org; 24 Jul 2019 21:36:38 +0000 Original-Received: from localhost ([127.0.0.1]:38142 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hqOw8-0007F1-3B for submit@debbugs.gnu.org; Wed, 24 Jul 2019 17:36:38 -0400 Original-Received: from zimbra.cs.ucla.edu ([131.179.128.68]:39346) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1hqOw5-0007Ej-51 for 36502@debbugs.gnu.org; Wed, 24 Jul 2019 17:36:34 -0400 Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id 1AD47162621; Wed, 24 Jul 2019 14:36:27 -0700 (PDT) Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10032) with ESMTP id jIQk89xWopsb; Wed, 24 Jul 2019 14:36:25 -0700 (PDT) Original-Received: from localhost (localhost [127.0.0.1]) by zimbra.cs.ucla.edu (Postfix) with ESMTP id B88621626A7; Wed, 24 Jul 2019 14:36:25 -0700 (PDT) X-Virus-Scanned: amavisd-new at zimbra.cs.ucla.edu Original-Received: from zimbra.cs.ucla.edu ([127.0.0.1]) by localhost (zimbra.cs.ucla.edu [127.0.0.1]) (amavisd-new, port 10026) with ESMTP id 8anSzFIbdXKk; Wed, 24 Jul 2019 14:36:25 -0700 (PDT) Original-Received: from [192.168.1.9] (cpe-23-242-74-103.socal.res.rr.com [23.242.74.103]) by zimbra.cs.ucla.edu (Postfix) with ESMTPSA id 65E31162621; Wed, 24 Jul 2019 14:36:25 -0700 (PDT) In-Reply-To: <22127ce6-182a-38ac-acc1-dfd09d727f18@cornell.edu> Content-Language: en-US X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 209.51.188.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:163681 Archived-At: This is a multi-part message in MIME format. --------------AAE76996D4A1A3FA9B037523 Content-Type: text/plain; charset=utf-8; format=flowed Content-Transfer-Encoding: 7bit Thanks for the patch. I improved it, wrote a NEWS entry and a test case for it, and installed the attached. I think this finishes off the issues in Bug#36502 and so am closing the bug report. --------------AAE76996D4A1A3FA9B037523 Content-Type: text/x-patch; name="0001-Do-not-treat-nosuchuser-as-an-absolute-file-name.patch" Content-Disposition: attachment; filename*0="0001-Do-not-treat-nosuchuser-as-an-absolute-file-name.patch" Content-Transfer-Encoding: quoted-printable >From a5063aa8b174db286a0e83b8ffdd4e65c521f733 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Wed, 24 Jul 2019 14:28:13 -0700 Subject: [PATCH] Do not treat ~nosuchuser as an absolute file name MIME-Version: 1.0 Content-Type: text/plain; charset=3DUTF-8 Content-Transfer-Encoding: 8bit Derived from Ken Brown=E2=80=99s patch (Bug#36502#97). * doc/lispref/files.texi (Relative File Names): * etc/NEWS: Document this. * src/fileio.c (user_homedir): New function. (Fexpand_file_name, file_name_absolute_p): Use it. (search_embedded_absfilename): Simplify via file_name_absolute_p. * test/src/fileio-tests.el (fileio-tests--no-such-user): New test. --- doc/lispref/files.texi | 10 +++- etc/NEWS | 3 + src/fileio.c | 121 ++++++++++++++++++--------------------- test/src/fileio-tests.el | 11 ++++ 4 files changed, 78 insertions(+), 67 deletions(-) diff --git a/doc/lispref/files.texi b/doc/lispref/files.texi index 0519f787dc..0ea8a4f0a1 100644 --- a/doc/lispref/files.texi +++ b/doc/lispref/files.texi @@ -2154,7 +2154,11 @@ Relative File Names =20 @defun file-name-absolute-p filename This function returns @code{t} if file @var{filename} is an absolute -file name or begins with @samp{~}, @code{nil} otherwise. +file name, @code{nil} otherwise. A file name is considered to be +absolute if its first component is @samp{~}, or is @samp{~@var{user}} +where @var{user} is a valid login name. In the following examples, +assume that there is a user named @samp{rms} but no user named +@samp{nosuchuser}. =20 @example @group @@ -2162,6 +2166,10 @@ Relative File Names @result{} t @end group @group +(file-name-absolute-p "~nosuchuser/foo") + @result{} nil +@end group +@group (file-name-absolute-p "rms/foo") @result{} nil @end group diff --git a/etc/NEWS b/etc/NEWS index 5313270411..08f0e654f7 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1815,6 +1815,9 @@ relative to the 'default-directory' of the current = buffer. We recommend always setting "$HOME" to an absolute file name, so that its meaning is independent of where Emacs was started. =20 +** file-name-absolute-p no longer considers "~foo" to be an absolute +file name if there is no user named "foo". + ** The FILENAME argument to 'file-name-base' is now mandatory and no longer defaults to 'buffer-file-name'. =20 diff --git a/src/fileio.c b/src/fileio.c index e4269b96a3..d1a7f39ac9 100644 --- a/src/fileio.c +++ b/src/fileio.c @@ -744,6 +744,31 @@ file_name_absolute_no_tilde_p (Lisp_Object name) return IS_ABSOLUTE_FILE_NAME (SSDATA (name)); } =20 +/* Return the home directory of the user NAME, or a null pointer if + NAME is empty or the user does not exist or the user's home + directory is not an absolute file name. NAME is an array of bytes + that continues up to (but not including) the next NUL byte or + directory separator. The returned string lives in storage good + until the next call to this or similar functions. */ +static char * +user_homedir (char const *name) +{ + ptrdiff_t length; + for (length =3D 0; name[length] && !IS_DIRECTORY_SEP (name[length]); l= ength++) + continue; + if (length =3D=3D 0) + return NULL; + USE_SAFE_ALLOCA; + char *p =3D SAFE_ALLOCA (length + 1); + memcpy (p, name, length); + p[length] =3D 0; + struct passwd *pw =3D getpwnam (p); + SAFE_FREE (); + if (!pw || (pw->pw_dir && !IS_ABSOLUTE_FILE_NAME (pw->pw_dir))) + return NULL; + return pw->pw_dir; +} + DEFUN ("expand-file-name", Fexpand_file_name, Sexpand_file_name, 1, 2, 0= , doc: /* Convert filename NAME to absolute, and canonicalize it. Second arg DEFAULT-DIRECTORY is directory to start with if NAME is relat= ive @@ -788,7 +813,6 @@ the root directory. */) char *target; =20 ptrdiff_t tlen; - struct passwd *pw; #ifdef DOS_NT int drive =3D 0; bool collapse_newdir =3D true; @@ -1153,39 +1177,29 @@ the root directory. */) } else /* ~user/filename */ { - char *o, *p; - for (p =3D nm; *p && !IS_DIRECTORY_SEP (*p); p++) - continue; - o =3D SAFE_ALLOCA (p - nm + 1); - memcpy (o, nm, p - nm); - o[p - nm] =3D 0; - - block_input (); - pw =3D getpwnam (o + 1); - unblock_input (); - if (pw) + char *nmhome =3D user_homedir (nm + 1); + if (nmhome) { - Lisp_Object tem; - - newdir =3D pw->pw_dir; - /* `getpwnam' may return a unibyte string, which will - bite us when we expect the directory to be multibyte. */ - tem =3D make_unibyte_string (newdir, strlen (newdir)); - newdirlim =3D newdir + SBYTES (tem); - if (multibyte && !STRING_MULTIBYTE (tem)) + ptrdiff_t nmhomelen =3D strlen (nmhome); + newdir =3D nmhome; + newdirlim =3D newdir + nmhomelen; + if (multibyte) { - hdir =3D DECODE_FILE (tem); + AUTO_STRING_WITH_LEN (lisp_nmhome, nmhome, nmhomelen); + hdir =3D DECODE_FILE (lisp_nmhome); newdir =3D SSDATA (hdir); newdirlim =3D newdir + SBYTES (hdir); } - nm =3D p; + + while (*++nm && !IS_DIRECTORY_SEP (*nm)) + continue; #ifdef DOS_NT collapse_newdir =3D false; #endif } =20 /* If we don't find a user of that name, leave the name - unchanged; don't move nm forward to p. */ + unchanged. */ } } =20 @@ -1667,18 +1681,6 @@ See also the function `substitute-in-file-name'.") } #endif =0C -bool -file_name_absolute_p (const char *filename) -{ - return - (IS_DIRECTORY_SEP (*filename) || *filename =3D=3D '~' -#ifdef DOS_NT - || (IS_DRIVE (*filename) && IS_DEVICE_SEP (filename[1]) - && IS_DIRECTORY_SEP (filename[2])) -#endif - ); -} - /* Put into BUF the concatenation of DIR and FILE, with an intervening directory separator if needed. Return a pointer to the NUL byte at the end of the concatenated string. */ @@ -1774,7 +1776,10 @@ get_homedir (void) return ahome; } =20 -/* If /~ or // appears, discard everything through first slash. */ +/* If a directory separator followed by an absolute file name (e.g., + "//foo", "/~", "/~someuser") appears in NM, return the address of + the absolute file name. Otherwise return NULL. ENDP is the + address of the null byte at the end of NM. */ static char * search_embedded_absfilename (char *nm, char *endp) { @@ -1784,34 +1789,8 @@ search_embedded_absfilename (char *nm, char *endp) && !IS_DIRECTORY_SEP (p[1])); #endif for (; p < endp; p++) - { - if (IS_DIRECTORY_SEP (p[-1]) && file_name_absolute_p (p)) - { - char *s; - for (s =3D p; *s && !IS_DIRECTORY_SEP (*s); s++) - continue; - if (p[0] =3D=3D '~' && s > p + 1) /* We've got "/~something/". */ - { - USE_SAFE_ALLOCA; - char *o =3D SAFE_ALLOCA (s - p + 1); - struct passwd *pw; - memcpy (o, p, s - p); - o [s - p] =3D 0; - - /* If we have ~user and `user' exists, discard - everything up to ~. But if `user' does not exist, leave - ~user alone, it might be a literal file name. */ - block_input (); - pw =3D getpwnam (o + 1); - unblock_input (); - SAFE_FREE (); - if (pw) - return p; - } - else - return p; - } - } + if (IS_DIRECTORY_SEP (p[-1]) && file_name_absolute_p (p)) + return p; return NULL; } =20 @@ -2696,13 +2675,23 @@ This happens for interactive use with M-x. */) =0C DEFUN ("file-name-absolute-p", Ffile_name_absolute_p, Sfile_name_absolut= e_p, 1, 1, 0, - doc: /* Return t if FILENAME is an absolute file name or starts w= ith `~'. -On Unix, absolute file names start with `/'. */) + doc: /* Return t if FILENAME is an absolute file name. +On Unix, absolute file names start with `/'. In Emacs, an absolute +file name can also start with an initial `~' or `~USER' component, +where USER is a valid login name. */) (Lisp_Object filename) { CHECK_STRING (filename); return file_name_absolute_p (SSDATA (filename)) ? Qt : Qnil; } + +bool +file_name_absolute_p (char const *filename) +{ + return (IS_ABSOLUTE_FILE_NAME (filename) + || (filename[0] =3D=3D '~' + && (!filename[1] || user_homedir (&filename[1])))); +} =0C DEFUN ("file-exists-p", Ffile_exists_p, Sfile_exists_p, 1, 1, 0, doc: /* Return t if file FILENAME exists (whether or not you can = read it). diff --git a/test/src/fileio-tests.el b/test/src/fileio-tests.el index 813ee5f798..09a5b147e1 100644 --- a/test/src/fileio-tests.el +++ b/test/src/fileio-tests.el @@ -136,3 +136,14 @@ fileio-tests--symlink-failure (name (expand-file-name "bar"))) (should (and (file-name-absolute-p name) (not (eq (aref name 0) ?~)))))) + +(ert-deftest fileio-tests--no-such-user () + "Test file-name-absolute-p on ~nosuchuser." + (unless (user-full-name "nosuchuser") + (should (not (file-name-absolute-p "~nosuchuser"))) + (should (not (file-name-absolute-p "~nosuchuser/"))) + (should (not (file-name-absolute-p "~nosuchuser//"))) + (should (not (file-name-absolute-p "~nosuchuser/foo"))) + (should (not (file-name-absolute-p "~nosuchuser/foo/"))) + (should (not (file-name-absolute-p "~nosuchuser/foo//"))) + (should (not (file-name-absolute-p "~nosuchuser/foo/bar"))))) --=20 2.17.1 --------------AAE76996D4A1A3FA9B037523--