coreutils.git - GNU coreutils

authorPaul Eggert <eggert@cs.ucla.edu>2021-05-01 15:19:16 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2021-05-01 15:47:13 -0700
commitd435cfc0bc554b8baef2e690e138e27ac1b4d5b1 (patch)
tree8716fceec4c63bc17831479f945d7e058986307d
parent62a7ce5f503c4a7f8bb410f0cc10fefab106a4d2 (diff)
downloadcoreutils-master.tar.gz

touch: fix wrong diagnostic (Bug#48106)HEADmaster

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.

-rw-r--r--src/touch.c34

1 files 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;

}