1  /* Convert between the kernel's `struct stat' format, and libc's.
       2     Copyright (C) 1991-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <assert.h>
      20  #include <errno.h>
      21  #include <sys/stat.h>
      22  #include <kernel_stat.h>
      23  #include <string.h>
      24  
      25  int
      26  __xstat_conv (int vers, struct kernel_stat *kbuf, void *ubuf)
      27  {
      28    switch (vers)
      29      {
      30      case _STAT_VER_KERNEL:
      31        /* Nothing to do.  The struct is in the form the kernel expects.
      32           We should have short-circuted before we got here, but for
      33           completeness... */
      34        *(struct kernel_stat *) ubuf = *kbuf;
      35        break;
      36  
      37      case _STAT_VER_LINUX:
      38        {
      39  	struct stat *buf = ubuf;
      40  
      41  	/* Convert to current kernel version of `struct stat'.  */
      42  	buf->st_dev = kbuf->st_dev;
      43  	buf->__pad1 = 0;
      44  	buf->st_ino = kbuf->st_ino;
      45  	buf->st_mode = kbuf->st_mode;
      46  	buf->st_nlink = kbuf->st_nlink;
      47  	buf->st_uid = kbuf->st_uid;
      48  	buf->st_gid = kbuf->st_gid;
      49  	buf->st_rdev = kbuf->st_rdev;
      50  	buf->__pad2 = 0;
      51  	buf->st_size = kbuf->st_size;
      52  	buf->st_blksize = kbuf->st_blksize;
      53  	buf->st_blocks = kbuf->st_blocks;
      54  	buf->st_atim.tv_sec = kbuf->st_atime_sec;
      55  	buf->st_atim.tv_nsec = 0;
      56  	buf->st_mtim.tv_sec = kbuf->st_mtime_sec;
      57  	buf->st_mtim.tv_nsec = 0;
      58  	buf->st_ctim.tv_sec = kbuf->st_ctime_sec;
      59  	buf->st_ctim.tv_nsec = 0;
      60  	buf->__glibc_reserved4 = 0;
      61  	buf->__glibc_reserved5 = 0;
      62        }
      63        break;
      64  
      65      default:
      66        __set_errno (EINVAL);
      67        return -1;
      68      }
      69  
      70    return 0;
      71  }
      72  
      73  int
      74  __xstat32_conv (int vers, struct stat64 *sbuf, struct stat *buf)
      75  {
      76    struct kernel_stat64 *kbuf;
      77  
      78    /* *stat64 syscalls on sparc64 really fill in struct kernel_stat64,
      79       rather than struct stat64.  But it is the same size as
      80       struct kernel_stat64, so use this hack so that we can reuse
      81       i386 {,f,l}xstat{,at}.c routines.  */
      82    __asm ("" : "=r" (kbuf) : "0" (sbuf));
      83    assert (sizeof (struct stat) == sizeof (struct stat64));
      84    assert (sizeof (struct stat64) >= sizeof (struct kernel_stat64));
      85  
      86    switch (vers)
      87      {
      88      case _STAT_VER_LINUX:
      89        {
      90  	/* Convert current kernel version of `struct stat64' to
      91             `struct stat'.  */
      92  	buf->st_dev = kbuf->st_dev;
      93  	buf->__pad1 = 0;
      94  	buf->st_ino = kbuf->st_ino;
      95  	buf->st_mode = kbuf->st_mode;
      96  	buf->st_nlink = kbuf->st_nlink;
      97  	buf->st_uid = kbuf->st_uid;
      98  	buf->st_gid = kbuf->st_gid;
      99  	buf->st_rdev = kbuf->st_rdev;
     100  	buf->__pad2 = 0;
     101  	buf->st_size = kbuf->st_size;
     102  	buf->st_blksize = kbuf->st_blksize;
     103  	buf->st_blocks = kbuf->st_blocks;
     104  	buf->st_atim.tv_sec = kbuf->st_atime_sec;
     105  	buf->st_atim.tv_nsec = kbuf->st_atime_nsec;
     106  	buf->st_mtim.tv_sec = kbuf->st_mtime_sec;
     107  	buf->st_mtim.tv_nsec = kbuf->st_mtime_nsec;
     108  	buf->st_ctim.tv_sec = kbuf->st_ctime_sec;
     109  	buf->st_ctim.tv_nsec = kbuf->st_ctime_nsec;
     110  	buf->__glibc_reserved4 = 0;
     111  	buf->__glibc_reserved5 = 0;
     112        }
     113        break;
     114  
     115        /* If struct stat64 is different from struct stat then
     116  	 _STAT_VER_KERNEL does not make sense.  */
     117      case _STAT_VER_KERNEL:
     118      default:
     119        __set_errno (EINVAL);
     120        return -1;
     121      }
     122  
     123    return 0;
     124  }