From: Samuel Thibault <samuel.thibault@ens-lyon.org>
Subject: [PATCH] hurd: Fix O_NOFOLLOW

The error code documented by POSIX for opening a symlink with O_NOFOLLOW
is ELOOP.

Also, if the translator does not expose symlink as a symlink translator but
as a S_IFLNK file, O_NOFOLLOW needs to return ELOOP too.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>

---
 hurd/lookup-retry.c | 36 ++++++++++++++++++++----------------
 1 file changed, 20 insertions(+), 16 deletions(-)

diff --git a/hurd/lookup-retry.c b/hurd/lookup-retry.c
index aee2ba8..b7a6a2b 100644
--- a/hurd/lookup-retry.c
+++ b/hurd/lookup-retry.c
@@ -127,7 +127,7 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 		{
 		  /* In Linux, O_NOFOLLOW means to reject symlinks.  If we
 		     did an O_NOLINK lookup above and io_stat here to check
-		     for S_IFLNK, a translator like firmlink could easily
+		     for S_IFLNK only, a translator like firmlink could easily
 		     spoof this check by not showing S_IFLNK, but in fact
 		     redirecting the lookup to some other name
 		     (i.e. opening the very same holes a symlink would).
@@ -145,23 +145,27 @@ __hurd_file_name_lookup_retry (error_t (*use_init_port)
 		     one exception to our general translator-based rule.  */
 		  struct stat64 st;
 		  err = __io_stat (*result, &st);
-		  if (!err
-		      && (st.st_mode & (S_IPTRANS|S_IATRANS)))
+		  if (!err)
 		    {
-		      if (st.st_uid != 0)
-			err = ENOENT;
-		      else if (st.st_mode & S_IPTRANS)
+		      if (S_ISLNK(st.st_mode))
+			err = ELOOP;
+		      else if (st.st_mode & (S_IPTRANS|S_IATRANS))
 			{
-			  char buf[1024];
-			  char *trans = buf;
-			  size_t translen = sizeof buf;
-			  err = __file_get_translator (*result,
-						       &trans, &translen);
-			  if (!err
-			      && translen > sizeof _HURD_SYMLINK
-			      && !memcmp (trans,
-					  _HURD_SYMLINK, sizeof _HURD_SYMLINK))
-			    err = ENOENT;
+			  if (st.st_uid != 0)
+			    err = ELOOP;
+			  else if (st.st_mode & S_IPTRANS)
+			    {
+			      char buf[1024];
+			      char *trans = buf;
+			      size_t translen = sizeof buf;
+			      err = __file_get_translator (*result,
+							   &trans, &translen);
+			      if (!err
+				  && translen > sizeof _HURD_SYMLINK
+				  && !memcmp (trans,
+					      _HURD_SYMLINK, sizeof _HURD_SYMLINK))
+				err = ELOOP;
+			    }
 			}
 		    }
 		}
-- 
tg: (7bb5f8a..) t/NOFOLLOW (depends on: baseline)
