Commit ebc996f3b13004e7272c462254522ba0102f09fe

Authored by Riku Voipio
Committed by Riku Voipio
1 parent 74d753ac

linux-user: fix utimensat

The glibc function for utimensat glibc returns -EINVAL when the path is null
which is a different behaviour with the syscall.

path can be null because internally the glibc is using utimensat with
path null when implmenting futimens. If path is null, call futimes
instead.

don't try to copy timespec from user if is NULL.

Add configure check for older systems

Signed-off-by: Riku Voipio <riku.voipio@iki.fi>
configure
... ... @@ -1285,6 +1285,25 @@ EOF
1285 1285 fi
1286 1286 fi
1287 1287  
  1288 +# check if utimensat and futimens are supported
  1289 +utimens=no
  1290 +cat > $TMPC << EOF
  1291 +#define _ATFILE_SOURCE
  1292 +#define _GNU_SOURCE
  1293 +#include <stddef.h>
  1294 +#include <fcntl.h>
  1295 +
  1296 +int main(void)
  1297 +{
  1298 + utimensat(AT_FDCWD, "foo", NULL, 0);
  1299 + futimens(0, NULL);
  1300 + return 0;
  1301 +}
  1302 +EOF
  1303 +if $cc $ARCH_CFLAGS -o $TMPE $TMPC 2> /dev/null ; then
  1304 + utimens=yes
  1305 +fi
  1306 +
1288 1307 # Check if tools are available to build documentation.
1289 1308 if test "$build_docs" = "yes" -a \( ! -x "`which texi2html 2>/dev/null`" -o ! -x "`which pod2man 2>/dev/null`" \) ; then
1290 1309 build_docs="no"
... ... @@ -1682,6 +1701,9 @@ fi
1682 1701 if test "$atfile" = "yes" ; then
1683 1702 echo "#define CONFIG_ATFILE 1" >> $config_h
1684 1703 fi
  1704 +if test "$utimens" = "yes" ; then
  1705 + echo "#define CONFIG_UTIMENSAT 1" >> $config_h
  1706 +fi
1685 1707 if test "$inotify" = "yes" ; then
1686 1708 echo "#define CONFIG_INOTIFY 1" >> $config_h
1687 1709 fi
... ...
linux-user/syscall.c
... ... @@ -406,13 +406,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags)
406 406 return (unlinkat(dirfd, pathname, flags));
407 407 }
408 408 #endif
409   -#ifdef TARGET_NR_utimensat
410   -static int sys_utimensat(int dirfd, const char *pathname,
411   - const struct timespec times[2], int flags)
412   -{
413   - return (utimensat(dirfd, pathname, times, flags));
414   -}
415   -#endif
416 409 #else /* !CONFIG_ATFILE */
417 410  
418 411 /*
... ... @@ -471,12 +464,24 @@ _syscall3(int,sys_symlinkat,const char *,oldpath,
471 464 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
472 465 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
473 466 #endif
  467 +
  468 +#endif /* CONFIG_ATFILE */
  469 +
  470 +#ifdef CONFIG_UTIMENSAT
  471 +static int sys_utimensat(int dirfd, const char *pathname,
  472 + const struct timespec times[2], int flags)
  473 +{
  474 + if (pathname == NULL)
  475 + return futimens(dirfd, times);
  476 + else
  477 + return utimensat(dirfd, pathname, times, flags);
  478 +}
  479 +#else
474 480 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
475 481 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
476 482 const struct timespec *,tsp,int,flags)
477 483 #endif
478   -
479   -#endif /* CONFIG_ATFILE */
  484 +#endif /* CONFIG_UTIMENSAT */
480 485  
481 486 #ifdef CONFIG_INOTIFY
482 487 #include <sys/inotify.h>
... ... @@ -6669,17 +6674,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6669 6674 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
6670 6675 case TARGET_NR_utimensat:
6671 6676 {
6672   - struct timespec ts[2];
6673   - target_to_host_timespec(ts, arg3);
6674   - target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
  6677 + struct timespec *tsp, ts[2];
  6678 + if (!arg3) {
  6679 + tsp = NULL;
  6680 + } else {
  6681 + target_to_host_timespec(ts, arg3);
  6682 + target_to_host_timespec(ts+1, arg3+sizeof(struct target_timespec));
  6683 + tsp = ts;
  6684 + }
6675 6685 if (!arg2)
6676   - ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4));
  6686 + ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
6677 6687 else {
6678 6688 if (!(p = lock_user_string(arg2))) {
6679 6689 ret = -TARGET_EFAULT;
6680 6690 goto fail;
6681 6691 }
6682   - ret = get_errno(sys_utimensat(arg1, path(p), ts, arg4));
  6692 + ret = get_errno(sys_utimensat(arg1, path(p), tsp, arg4));
6683 6693 unlock_user(p, arg2, 0);
6684 6694 }
6685 6695 }
... ...