diff options
-rw-r--r-- | ChangeLog.mips | 11 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/mips/mips32/fxstatat.c | 1 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c | 113 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/mips/xstatconv.c | 115 |
4 files changed, 214 insertions, 26 deletions
diff --git a/ChangeLog.mips b/ChangeLog.mips index b849ffa2cc..0c9fb72c12 100644 --- a/ChangeLog.mips +++ b/ChangeLog.mips @@ -1,3 +1,14 @@ +2006-09-22 Richard Sandiford <richard@codesourcery.com> + + * sysdeps/unix/sysv/linux/mips/xstatconv.c: Remove STAT_IS_KERNEL_STAT + code. + (__xstat_conv): Use memset to clear padding arrays. Check for + overflow. + (__xstat64_conv): Use memset to clear padding arrays. + (__xstat32_conv): New function. + * sysdeps/unix/sysv/linux/mips/mips32/fxstatat.c: New file. + * sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c: Likewise. + 2006-09-21 Joseph Myers <joseph@codesourcery.com> * sysdeps/mips/fpu_control.h: If soft-float, don't use diff --git a/sysdeps/unix/sysv/linux/mips/mips32/fxstatat.c b/sysdeps/unix/sysv/linux/mips/mips32/fxstatat.c new file mode 100644 index 0000000000..0f8b3135d8 --- /dev/null +++ b/sysdeps/unix/sysv/linux/mips/mips32/fxstatat.c @@ -0,0 +1 @@ +#include <sysdeps/unix/sysv/linux/i386/fxstatat.c> diff --git a/sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c b/sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c new file mode 100644 index 0000000000..21a630963f --- /dev/null +++ b/sysdeps/unix/sysv/linux/mips/mips64/fxstatat64.c @@ -0,0 +1,113 @@ +/* Copyright (C) 2005,2006 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <kernel_stat.h> + +#include <sysdep.h> +#include <sys/syscall.h> +#include <bp-checks.h> + +#include <kernel-features.h> + +#include <xstatconv.h> + +/* Get information about the file NAME in BUF. */ + +int +__fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag) +{ + if (__builtin_expect (vers != _STAT_VER_LINUX, 0)) + { + __set_errno (EINVAL); + return -1; + } + + int result; + INTERNAL_SYSCALL_DECL (err); + struct kernel_stat kst; + +#ifdef __NR_newfstatat +# ifndef __ASSUME_ATFCTS + if (__have_atfcts >= 0) +# endif + { + result = INTERNAL_SYSCALL (newfstatat, err, 4, fd, file, &kst, flag); +# ifndef __ASSUME_ATFCTS + if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1) + && INTERNAL_SYSCALL_ERRNO (result, err) == ENOSYS) + __have_atfcts = -1; + else +# endif + if (!__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 1)) + return __xstat64_conv (vers, &kst, st); + else + { + __set_errno (INTERNAL_SYSCALL_ERRNO (result, err)); + return -1; + } + } +#endif + +#ifndef __ASSUME_ATFCTS + if (flag & ~AT_SYMLINK_NOFOLLOW) + { + __set_errno (EINVAL); + return -1; + } + + char *buf = NULL; + + if (fd != AT_FDCWD && file[0] != '/') + { + size_t filelen = strlen (file); + static const char procfd[] = "/proc/self/fd/%d/%s"; + /* Buffer for the path name we are going to use. It consists of + - the string /proc/self/fd/ + - the file descriptor number + - the file name provided. + The final NUL is included in the sizeof. A bit of overhead + due to the format elements compensates for possible negative + numbers. */ + size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen; + buf = alloca (buflen); + + __snprintf (buf, buflen, procfd, fd, file); + file = buf; + } + + if (flag & AT_SYMLINK_NOFOLLOW) + result = INTERNAL_SYSCALL (lstat, err, 2, CHECK_STRING (file), + __ptrvalue (&kst)); + else + result = INTERNAL_SYSCALL (stat, err, 2, CHECK_STRING (file), + __ptrvalue (&kst)); + + if (__builtin_expect (!INTERNAL_SYSCALL_ERROR_P (result, err), 1)) + return __xstat64_conv (vers, &kst, st); + + __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, buf); + return -1; +#endif +} +libc_hidden_def (__fxstatat64) diff --git a/sysdeps/unix/sysv/linux/mips/xstatconv.c b/sysdeps/unix/sysv/linux/mips/xstatconv.c index ccab6b6a79..068c087b0a 100644 --- a/sysdeps/unix/sysv/linux/mips/xstatconv.c +++ b/sysdeps/unix/sysv/linux/mips/xstatconv.c @@ -21,16 +21,8 @@ #include <sys/stat.h> #include <kernel_stat.h> -#ifdef STAT_IS_KERNEL_STAT - -/* Dummy. */ -struct kernel_stat; - -#else - #include <string.h> - int __xstat_conv (int vers, struct kernel_stat *kbuf, void *ubuf) { @@ -49,30 +41,43 @@ __xstat_conv (int vers, struct kernel_stat *kbuf, void *ubuf) /* Convert to current kernel version of `struct stat'. */ buf->st_dev = kbuf->st_dev; - buf->st_pad1[0] = 0; buf->st_pad1[1] = 0; buf->st_pad1[2] = 0; + memset (&buf->st_pad1, 0, sizeof (buf->st_pad1)); buf->st_ino = kbuf->st_ino; + /* Check for overflow. */ + if (buf->st_ino != kbuf->st_ino) + { + __set_errno (EOVERFLOW); + return -1; + } buf->st_mode = kbuf->st_mode; buf->st_nlink = kbuf->st_nlink; buf->st_uid = kbuf->st_uid; buf->st_gid = kbuf->st_gid; buf->st_rdev = kbuf->st_rdev; - buf->st_pad2[0] = 0; buf->st_pad2[1] = 0; - buf->st_pad3 = 0; + memset (&buf->st_pad2, 0, sizeof (buf->st_pad2)); buf->st_size = kbuf->st_size; - buf->st_blksize = kbuf->st_blksize; - buf->st_blocks = kbuf->st_blocks; - + /* Check for overflow. */ + if (buf->st_size != kbuf->st_size) + { + __set_errno (EOVERFLOW); + return -1; + } + buf->st_pad3 = 0; buf->st_atim.tv_sec = kbuf->st_atime_sec; buf->st_atim.tv_nsec = kbuf->st_atime_nsec; buf->st_mtim.tv_sec = kbuf->st_mtime_sec; buf->st_mtim.tv_nsec = kbuf->st_mtime_nsec; buf->st_ctim.tv_sec = kbuf->st_ctime_sec; buf->st_ctim.tv_nsec = kbuf->st_ctime_nsec; - - buf->st_pad5[0] = 0; buf->st_pad5[1] = 0; - buf->st_pad5[2] = 0; buf->st_pad5[3] = 0; - buf->st_pad5[4] = 0; buf->st_pad5[5] = 0; - buf->st_pad5[6] = 0; buf->st_pad5[7] = 0; + buf->st_blksize = kbuf->st_blksize; + buf->st_blocks = kbuf->st_blocks; + /* Check for overflow. */ + if (buf->st_blocks != kbuf->st_blocks) + { + __set_errno (EOVERFLOW); + return -1; + } + memset (&buf->st_pad5, 0, sizeof (buf->st_pad5)); } break; @@ -97,14 +102,14 @@ __xstat64_conv (int vers, struct kernel_stat *kbuf, void *ubuf) struct stat64 *buf = ubuf; buf->st_dev = kbuf->st_dev; - buf->st_pad1[0] = 0; buf->st_pad1[1] = 0; buf->st_pad1[2] = 0; + memset (&buf->st_pad1, 0, sizeof (buf->st_pad1)); buf->st_ino = kbuf->st_ino; buf->st_mode = kbuf->st_mode; buf->st_nlink = kbuf->st_nlink; buf->st_uid = kbuf->st_uid; buf->st_gid = kbuf->st_gid; buf->st_rdev = kbuf->st_rdev; - buf->st_pad2[0] = 0; buf->st_pad2[1] = 0; buf->st_pad2[2] = 0; + memset (&buf->st_pad2, 0, sizeof (buf->st_pad2)); buf->st_pad3 = 0; buf->st_size = kbuf->st_size; buf->st_blksize = kbuf->st_blksize; @@ -117,10 +122,7 @@ __xstat64_conv (int vers, struct kernel_stat *kbuf, void *ubuf) buf->st_ctim.tv_sec = kbuf->st_ctime_sec; buf->st_ctim.tv_nsec = kbuf->st_ctime_nsec; - buf->st_pad4[0] = 0; buf->st_pad4[1] = 0; - buf->st_pad4[2] = 0; buf->st_pad4[3] = 0; - buf->st_pad4[4] = 0; buf->st_pad4[5] = 0; - buf->st_pad4[6] = 0; buf->st_pad4[7] = 0; + memset (&buf->st_pad4, 0, sizeof (buf->st_pad4)); } break; @@ -136,4 +138,65 @@ __xstat64_conv (int vers, struct kernel_stat *kbuf, void *ubuf) #endif } -#endif /* ! STAT_IS_KERNEL_STAT */ +#if _MIPS_SIM == _ABIO32 +int +__xstat32_conv (int vers, struct stat64 *kbuf, struct stat *buf) +{ + switch (vers) + { + case _STAT_VER_LINUX: + /* Convert current kernel version of `struct stat64' to + `struct stat'. The layout of the fields in the kernel's + stat64 is the same as that in the user stat64; the only + difference is that the latter has more trailing padding. */ + buf->st_dev = kbuf->st_dev; + memset (&buf->st_pad1, 0, sizeof (buf->st_pad1)); + buf->st_ino = kbuf->st_ino; + /* Check for overflow. */ + if (buf->st_ino != kbuf->st_ino) + { + __set_errno (EOVERFLOW); + return -1; + } + buf->st_mode = kbuf->st_mode; + buf->st_nlink = kbuf->st_nlink; + buf->st_uid = kbuf->st_uid; + buf->st_gid = kbuf->st_gid; + buf->st_rdev = kbuf->st_rdev; + memset (&buf->st_pad2, 0, sizeof (buf->st_pad2)); + buf->st_size = kbuf->st_size; + /* Check for overflow. */ + if (buf->st_size != kbuf->st_size) + { + __set_errno (EOVERFLOW); + return -1; + } + buf->st_pad3 = 0; + buf->st_atim.tv_sec = kbuf->st_atim.tv_sec; + buf->st_atim.tv_nsec = kbuf->st_atim.tv_nsec; + buf->st_mtim.tv_sec = kbuf->st_mtim.tv_sec; + buf->st_mtim.tv_nsec = kbuf->st_mtim.tv_nsec; + buf->st_ctim.tv_sec = kbuf->st_ctim.tv_sec; + buf->st_ctim.tv_nsec = kbuf->st_ctim.tv_nsec; + buf->st_blksize = kbuf->st_blksize; + buf->st_blocks = kbuf->st_blocks; + /* Check for overflow. */ + if (buf->st_blocks != kbuf->st_blocks) + { + __set_errno (EOVERFLOW); + return -1; + } + memset (&buf->st_pad5, 0, sizeof (buf->st_pad5)); + break; + + /* If struct stat64 is different from struct stat then + _STAT_VER_KERNEL does not make sense. */ + case _STAT_VER_KERNEL: + default: + __set_errno (EINVAL); + return -1; + } + + return 0; +} +#endif /* _MIPS_SIM == _ABIO32 */ |