Subject: bug#48106: closed (Re: bug#48106: bug: touch utility does not handle file create error properly)

From: [email-masked] (GNU bug Tracking System)
Date: Sat, 01 May 2021 22:49:02 +0000

Your bug report

#48106: bug: touch utility does not handle file create error properly

which was filed against the coreutils package, has been closed.

The explanation is attached below, along with your original report.
If you require more details, please reply to [email-masked].

-- 
48106: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=48106
GNU Bug Tracking System
Contact [email-masked] with problems

Subject: Re: bug#48106: bug: touch utility does not handle file create error properly
From: Paul Eggert <[email-masked]>
To: Roland <[email-masked]>
Cc: [email-masked]
Date: Sat, 1 May 2021 15:48:43 -0700
List-Id: <debbugs-submit.debbugs.gnu.org>

Thanks for reporting the problem. I installed the attached to fix it.
>From aaa0f003303ab90778b6b426cd9e5a1f1d137ffc Mon Sep 17 00:00:00 2001
From: Paul Eggert <[email-masked]>
Date: Sat, 1 May 2021 15:19:16 -0700
Subject: [PATCH] touch: fix wrong diagnostic (Bug#48106)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem reported by Roland (Bug#48106).
* src/touch.c (touch): Take more care when deciding whether
to use open_errno or utime_errno in the diagnostic.
Stop worrying about SunOS 4 (which as part of the problem),
as it’s long obsolete.  For Solaris 10, verify that EINVAL
really means the file was a directory.
---
 src/touch.c | 34 +++++++++++++++++++---------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/src/touch.c b/src/touch.c
index 653fd313b..46ddd86bb 100644
--- a/src/touch.c
+++ b/src/touch.c
@@ -122,7 +122,6 @@ get_reldate (struct timespec *result,
 static bool
 touch (char const *file)
 {
-  bool ok;
   int fd = -1;
   int open_errno = 0;
   struct timespec const *t = newtime;
@@ -134,12 +133,7 @@ touch (char const *file)
       /* Try to open FILE, creating it if necessary.  */
       fd = fd_reopen (STDIN_FILENO, file,
                       O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY, MODE_RW_UGO);
-
-      /* Don't save a copy of errno if it's EISDIR, since that would lead
-         touch to give a bogus diagnostic for e.g., 'touch /' (assuming
-         we don't own / or have write access to it).  On Solaris 5.6,
-         and probably other systems, it is EINVAL.  On SunOS4, it's EPERM.  */
-      if (fd == -1 && errno != EISDIR && errno != EINVAL && errno != EPERM)
+      if (fd < 0)
         open_errno = errno;
     }
 
@@ -162,9 +156,10 @@ touch (char const *file)
       t = NULL;
     }
 
-  ok = (fdutimensat (fd, AT_FDCWD, (fd == STDOUT_FILENO ? NULL : file), t,
-                     (no_dereference && fd == -1) ? AT_SYMLINK_NOFOLLOW : 0)
-        == 0);
+  char const *file_opt = fd == STDOUT_FILENO ? NULL : file;
+  int atflag = no_dereference ? AT_SYMLINK_NOFOLLOW : 0;
+  int utime_errno = (fdutimensat (fd, AT_FDCWD, file_opt, t, atflag) == 0
+                     ? 0 : errno);
 
   if (fd == STDIN_FILENO)
     {
@@ -177,13 +172,22 @@ touch (char const *file)
   else if (fd == STDOUT_FILENO)
     {
       /* Do not diagnose "touch -c - >&-".  */
-      if (!ok && errno == EBADF && no_create)
+      if (utime_errno == EBADF && no_create)
         return true;
     }
 
-  if (!ok)
+  if (utime_errno != 0)
     {
-      if (open_errno)
+      /* Don't diagnose with open_errno if FILE is a directory, as that
+         would give a bogus diagnostic for e.g., 'touch /' (assuming we
+         don't own / or have write access).  On Solaris 10 and probably
+         other systems, opening a directory like "." fails with EINVAL.
+         (On SunOS 4 it was EPERM but that's obsolete.)  */
+      struct stat st;
+      if (open_errno
+          && ! (open_errno == EISDIR
+                || (open_errno == EINVAL
+                    && stat (file, &st) == 0 && S_ISDIR (st.st_mode))))
         {
           /* The wording of this diagnostic should cover at least two cases:
              - the file does not exist, but the parent directory is unwritable
@@ -193,9 +197,9 @@ touch (char const *file)
         }
       else
         {
-          if (no_create && errno == ENOENT)
+          if (no_create && utime_errno == ENOENT)
             return true;
-          error (0, errno, _("setting times of %s"), quoteaf (file));
+          error (0, utime_errno, _("setting times of %s"), quoteaf (file));
         }
       return false;
     }
-- 
2.27.0

Subject: bug: touch utility does not handle file create error properly
From: Roland <[email-masked]>
To: [email-masked]
Date: Thu, 29 Apr 2021 20:23:47 +0200
List-Id: <debbugs-submit.debbugs.gnu.org>

hello,

touch utility telling weird error on file creation on a immutable/ro dir.

apparently, it does not catch/report the first error (EPERM) but only
the second one (ENOENT), when trying to set the time on the non-existing
file.

regards
roland kletzing
sysadmin

root@s900:/tmp# mkdir /tmp/test
root@s900:/tmp# chown 0400 /tmp/test/
root@s900:/tmp# chattr +i /tmp/test
root@s900:/tmp# touch /tmp/test/testfile
touch: setting times of '/tmp/test/testfile': No such file or directory

root@s900:/tmp# strace touch /tmp/test/testfile 2>&1 |grep -i test
execve("/usr/bin/touch", ["touch", "/tmp/test/testfile"], 0x7ffe690abb88
/* 19 vars */) = 0
openat(AT_FDCWD, "/tmp/test/testfile",
O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK, 0666) = -1 EPERM (Operation not
permitted)
utimensat(AT_FDCWD, "/tmp/test/testfile", NULL, 0) = -1 ENOENT (No such
file or directory)
write(2, "setting times of '/tmp/test/test"..., 37setting times of
'/tmp/test/testfile') = 37

# touch  --version
touch (GNU coreutils) 8.30

(on debian 10.9)