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,6 +1285,25 @@ EOF
1285 fi 1285 fi
1286 fi 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 # Check if tools are available to build documentation. 1307 # Check if tools are available to build documentation.
1289 if test "$build_docs" = "yes" -a \( ! -x "`which texi2html 2>/dev/null`" -o ! -x "`which pod2man 2>/dev/null`" \) ; then 1308 if test "$build_docs" = "yes" -a \( ! -x "`which texi2html 2>/dev/null`" -o ! -x "`which pod2man 2>/dev/null`" \) ; then
1290 build_docs="no" 1309 build_docs="no"
@@ -1682,6 +1701,9 @@ fi @@ -1682,6 +1701,9 @@ fi
1682 if test "$atfile" = "yes" ; then 1701 if test "$atfile" = "yes" ; then
1683 echo "#define CONFIG_ATFILE 1" >> $config_h 1702 echo "#define CONFIG_ATFILE 1" >> $config_h
1684 fi 1703 fi
  1704 +if test "$utimens" = "yes" ; then
  1705 + echo "#define CONFIG_UTIMENSAT 1" >> $config_h
  1706 +fi
1685 if test "$inotify" = "yes" ; then 1707 if test "$inotify" = "yes" ; then
1686 echo "#define CONFIG_INOTIFY 1" >> $config_h 1708 echo "#define CONFIG_INOTIFY 1" >> $config_h
1687 fi 1709 fi
linux-user/syscall.c
@@ -406,13 +406,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags) @@ -406,13 +406,6 @@ static int sys_unlinkat(int dirfd, const char *pathname, int flags)
406 return (unlinkat(dirfd, pathname, flags)); 406 return (unlinkat(dirfd, pathname, flags));
407 } 407 }
408 #endif 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 #else /* !CONFIG_ATFILE */ 409 #else /* !CONFIG_ATFILE */
417 410
418 /* 411 /*
@@ -471,12 +464,24 @@ _syscall3(int,sys_symlinkat,const char *,oldpath, @@ -471,12 +464,24 @@ _syscall3(int,sys_symlinkat,const char *,oldpath,
471 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat) 464 #if defined(TARGET_NR_unlinkat) && defined(__NR_unlinkat)
472 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags) 465 _syscall3(int,sys_unlinkat,int,dirfd,const char *,pathname,int,flags)
473 #endif 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 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) 480 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
475 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname, 481 _syscall4(int,sys_utimensat,int,dirfd,const char *,pathname,
476 const struct timespec *,tsp,int,flags) 482 const struct timespec *,tsp,int,flags)
477 #endif 483 #endif
478 -  
479 -#endif /* CONFIG_ATFILE */ 484 +#endif /* CONFIG_UTIMENSAT */
480 485
481 #ifdef CONFIG_INOTIFY 486 #ifdef CONFIG_INOTIFY
482 #include <sys/inotify.h> 487 #include <sys/inotify.h>
@@ -6669,17 +6674,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, @@ -6669,17 +6674,22 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
6669 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat) 6674 #if defined(TARGET_NR_utimensat) && defined(__NR_utimensat)
6670 case TARGET_NR_utimensat: 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 if (!arg2) 6685 if (!arg2)
6676 - ret = get_errno(sys_utimensat(arg1, NULL, ts, arg4)); 6686 + ret = get_errno(sys_utimensat(arg1, NULL, tsp, arg4));
6677 else { 6687 else {
6678 if (!(p = lock_user_string(arg2))) { 6688 if (!(p = lock_user_string(arg2))) {
6679 ret = -TARGET_EFAULT; 6689 ret = -TARGET_EFAULT;
6680 goto fail; 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 unlock_user(p, arg2, 0); 6693 unlock_user(p, arg2, 0);
6684 } 6694 }
6685 } 6695 }