>From cd7b12cc394f80b07dc86b5516e2ec5ee934efd8 Mon Sep 17 00:00:00 2001 From: Peter O'Gorman Date: Wed, 5 May 2010 02:55:41 +0000 Subject: [PATCH] New module pwrite * doc/posix-functions/pread.texi: Mention gnulib module. * doc/posix-functions/pwrite.texi: Likewise. * MODULES.html.sh: Add pwrite. * lib/unistd.in.h: Likewise. * m4/unistd_h.m4: Likewise. * modules/unistd: Likewise. * tests/test-unistd-c++.cc: Likewise. * lib/pwrite.c: Likewise. * m4/pwrite.m4: Likewise. * modules/pwrite: Likewise. * modules/pwrite-tests: Likewise. * tests/test-pwrite.c: Likewise. * tests/test-pwrite.core: Likewise. * tests/test-pwrite.sh: Likewise. --- ChangeLog | 18 +++++++++ MODULES.html.sh | 2 + doc/posix-functions/pread.texi | 4 +- doc/posix-functions/pwrite.texi | 4 +- lib/pwrite.c | 64 +++++++++++++++++++++++++++++++ lib/unistd.in.h | 36 +++++++++++++++++- m4/pwrite.m4 | 18 +++++++++ m4/unistd_h.m4 | 8 +++- modules/pwrite | 24 ++++++++++++ modules/pwrite-tests | 14 +++++++ modules/unistd | 3 + tests/test-pwrite.c | 80 +++++++++++++++++++++++++++++++++++++++ tests/test-pwrite.sh | 7 +++ tests/test-unistd-c++.cc | 5 ++ 14 files changed, 280 insertions(+), 7 deletions(-) create mode 100644 lib/pwrite.c create mode 100644 m4/pwrite.m4 create mode 100644 modules/pwrite create mode 100644 modules/pwrite-tests create mode 100644 tests/test-pwrite.c create mode 100755 tests/test-pwrite.sh diff --git a/ChangeLog b/ChangeLog index d737948..c3c6e9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2010-05-05 Peter O'Gorman + + New module pwrite + * doc/posix-functions/pread.texi: Mention gnulib module. + * doc/posix-functions/pwrite.texi: Likewise. + * MODULES.html.sh: Add pwrite. + * lib/unistd.in.h: Likewise. + * m4/unistd_h.m4: Likewise. + * modules/unistd: Likewise. + * tests/test-unistd-c++.cc: Likewise. + * lib/pwrite.c: Likewise. + * m4/pwrite.m4: Likewise. + * modules/pwrite: Likewise. + * modules/pwrite-tests: Likewise. + * tests/test-pwrite.c: Likewise. + * tests/test-pwrite.core: Likewise. + * tests/test-pwrite.sh: Likewise. + 2010-05-04 Eric Blake docs: update cygwin progress diff --git a/MODULES.html.sh b/MODULES.html.sh index b0fbe39..822ac83 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -846,6 +846,7 @@ pow powf powl pread +pwrite printf pselect psiginfo @@ -1346,6 +1347,7 @@ index makecontext mktemp pread +pwrite pthread_attr_getstackaddr pthread_attr_setstackaddr rindex diff --git a/doc/posix-functions/pread.texi b/doc/posix-functions/pread.texi index a11e36e..651256d 100644 --- a/doc/posix-functions/pread.texi +++ b/doc/posix-functions/pread.texi @@ -4,13 +4,13 @@ POSIX specification: @url{http://www.opengroup.org/onlinepubs/9699919799/functions/pread.html} -Gnulib module: --- +Gnulib module: pread Portability problems fixed by Gnulib: @itemize @item This function is missing on some platforms: -mingw, BeOS. +mingw, BeOS, HP-UX 10. @end itemize Portability problems not fixed by Gnulib: diff --git a/doc/posix-functions/pwrite.texi b/doc/posix-functions/pwrite.texi index d164503..735c897 100644 --- a/doc/posix-functions/pwrite.texi +++ b/doc/posix-functions/pwrite.texi @@ -4,7 +4,7 @@ POSIX specification: @url{http://www.opengroup.org/onlinepubs/9699919799/functions/pwrite.html} -Gnulib module: --- +Gnulib module: pwrite Portability problems fixed by Gnulib: @itemize @@ -14,5 +14,5 @@ Portability problems not fixed by Gnulib: @itemize @item This function is missing on some platforms: -mingw, BeOS. +mingw, BeOS, HP-UX 10. @end itemize diff --git a/lib/pwrite.c b/lib/pwrite.c new file mode 100644 index 0000000..f9c1498 --- /dev/null +++ b/lib/pwrite.c @@ -0,0 +1,64 @@ +/* Write block to given position in file without changing file + * pointer. + POSIX version. + Copyright (C) 1997, 1998, 1999, 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper , 1997. + + 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 + +#include +#include + +#define __libc_lseek(f,o,w) lseek (f, o, w) +#define __set_errno(Val) errno = (Val) +#define __libc_write(f,b,n) write (f, b, n) + +/* Note: This implementation of pwrite is not multithread-safe. */ + +ssize_t +pwrite (int fd, const void *buf, size_t nbyte, off_t offset) +{ + /* Since we must not change the file pointer preserve the value so that + we can restore it later. */ + int save_errno; + ssize_t result; + off_t old_offset = __libc_lseek (fd, 0, SEEK_CUR); + if (old_offset == (off_t) -1) + return -1; + + /* Set to wanted position. */ + if (__libc_lseek (fd, offset, SEEK_SET) == (off_t) -1) + return -1; + + /* Write out the data. */ + result = __libc_write (fd, buf, nbyte); + + /* Now we have to restore the position. If this fails we have to + return this as an error. But if the writing also failed we + return this error. */ + save_errno = errno; + if (__libc_lseek (fd, old_offset, SEEK_SET) == (off_t) -1) + { + if (result == -1) + __set_errno (save_errno); + return -1; + } + __set_errno (save_errno); + + return result; +} diff --git a/lib/unistd.in.h b/lib/unistd.in.h index b1f0743..49f6bad 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -86,7 +86,7 @@ #endif #if (@GNULIB_WRITE@ || @GNULIB_READLINK@ || @GNULIB_READLINKAT@ \ - || @GNULIB_PREAD@ || defined GNULIB_POSIXCHECK) + || @GNULIB_PREAD@ || @GNULIB_PWRITE@ || defined GNULIB_POSIXCHECK) /* Get ssize_t. */ # include #endif @@ -1016,6 +1016,40 @@ _GL_WARN_ON_USE (pread, "pread is unportable - " #endif +#if @GNULIB_PWRITE@ +/* Write at most BUFSIZE bytes from BUF into FD, starting at OFFSET. + Return the number of bytes written if successful, otherwise + set errno and return -1. 0 indicates nothing written. See the + POSIX:2001 specification + . */ +# if @REPLACE_PWRITE@ +# if !(defined __cplusplus && defined GNULIB_NAMESPACE) +# define pwrite rpl_pwrite +# endif +_GL_FUNCDECL_RPL (pwrite, ssize_t, + (int fd, const void *buf, size_t bufsize, off_t offset) + _GL_ARG_NONNULL ((2))); +_GL_CXXALIAS_RPL (pwrite, ssize_t, + (int fd, const void *buf, size_t bufsize, off_t offset)); +# else +# if address@hidden@ +_GL_FUNCDECL_SYS (pwrite, ssize_t, + (int fd, const void *buf, size_t bufsize, off_t offset) + _GL_ARG_NONNULL ((2))); +# endif +_GL_CXXALIAS_SYS (pwrite, ssize_t, + (int fd, const void *buf, size_t bufsize, off_t offset)); +# endif +_GL_CXXALIASWARN (pwrite); +#elif defined GNULIB_POSIXCHECK +# undef pwrite +# if HAVE_RAW_DECL_PWRITE +_GL_WARN_ON_USE (pwrite, "pwrite is unportable - " + "use gnulib module pwrite for portability"); +# endif +#endif + + #if @GNULIB_READLINK@ /* Read the contents of the symbolic link FILE and place the first BUFSIZE bytes of it into BUF. Return the number of bytes placed into BUF if diff --git a/m4/pwrite.m4 b/m4/pwrite.m4 new file mode 100644 index 0000000..4315fde --- /dev/null +++ b/m4/pwrite.m4 @@ -0,0 +1,18 @@ +# pwrite.m4 serial 1 +dnl Copyright (C) 2010 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_PWRITE], +[ + AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + dnl Persuade glibc to declare pread(). + AC_REQUIRE([AC_USE_SYSTEM_EXTENSIONS]) + + AC_CHECK_FUNCS_ONCE([pwrite]) + if test $ac_cv_func_pwrite = no; then + HAVE_PWRITE=0 + AC_LIBOBJ([pwrite]) + fi +]) diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4 index b26d0a9..48d06c7 100644 --- a/m4/unistd_h.m4 +++ b/m4/unistd_h.m4 @@ -38,8 +38,9 @@ AC_DEFUN([gl_UNISTD_H], ]], [chown dup2 dup3 environ euidaccess faccessat fchdir fchownat fsync ftruncate getcwd getdomainname getdtablesize getgroups gethostname getlogin getlogin_r getpagesize getusershell setusershell - endusershell lchown link linkat lseek pipe2 pread readlink readlinkat - rmdir sleep symlink symlinkat ttyname_r unlink unlinkat usleep]) + endusershell lchown link linkat lseek pipe2 pread pwrite readlink + readlinkat rmdir sleep symlink symlinkat ttyname_r unlink unlinkat + usleep]) ]) AC_DEFUN([gl_UNISTD_MODULE_INDICATOR], @@ -79,6 +80,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], GNULIB_LSEEK=0; AC_SUBST([GNULIB_LSEEK]) GNULIB_PIPE2=0; AC_SUBST([GNULIB_PIPE2]) GNULIB_PREAD=0; AC_SUBST([GNULIB_PREAD]) + GNULIB_PWRITE=0; AC_SUBST([GNULIB_PWRITE]) GNULIB_READLINK=0; AC_SUBST([GNULIB_READLINK]) GNULIB_READLINKAT=0; AC_SUBST([GNULIB_READLINKAT]) GNULIB_RMDIR=0; AC_SUBST([GNULIB_RMDIR]) @@ -113,6 +115,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], HAVE_LINKAT=1; AC_SUBST([HAVE_LINKAT]) HAVE_PIPE2=1; AC_SUBST([HAVE_PIPE2]) HAVE_PREAD=1; AC_SUBST([HAVE_PREAD]) + HAVE_PWRITE=1; AC_SUBST([HAVE_PWRITE]) HAVE_READLINK=1; AC_SUBST([HAVE_READLINK]) HAVE_READLINKAT=1; AC_SUBST([HAVE_READLINKAT]) HAVE_SLEEP=1; AC_SUBST([HAVE_SLEEP]) @@ -140,6 +143,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], REPLACE_LINKAT=0; AC_SUBST([REPLACE_LINKAT]) REPLACE_LSEEK=0; AC_SUBST([REPLACE_LSEEK]) REPLACE_PREAD=0; AC_SUBST([REPLACE_PREAD]) + REPLACE_PWRITE=0; AC_SUBST([REPLACE_PWRITE]) REPLACE_READLINK=0; AC_SUBST([REPLACE_READLINK]) REPLACE_RMDIR=0; AC_SUBST([REPLACE_RMDIR]) REPLACE_SLEEP=0; AC_SUBST([REPLACE_SLEEP]) diff --git a/modules/pwrite b/modules/pwrite new file mode 100644 index 0000000..b1adb4b --- /dev/null +++ b/modules/pwrite @@ -0,0 +1,24 @@ +Description: +pwrite() function: read without changing file offset + +Files: +lib/pwrite.c +m4/pwrite.m4 + +Depends-on: +lseek +unistd + +configure.ac: +gl_FUNC_PWRITE +gl_UNISTD_MODULE_INDICATOR([pwrite]) + +Makefile.am: + +Include: + + +License: +LGPLv2+ + +Maintainer: diff --git a/modules/pwrite-tests b/modules/pwrite-tests new file mode 100644 index 0000000..567b220 --- /dev/null +++ b/modules/pwrite-tests @@ -0,0 +1,14 @@ +Files: +tests/test-pwrite.c +tests/test-pwrite.sh +tests/init.sh +tests/signature.h +tests/macros.h + +Depends-on: + +configure.ac: + +Makefile.am: +TESTS += test-pwrite.sh +check_PROGRAMS += test-pwrite diff --git a/modules/unistd b/modules/unistd index 9ab6835..b5a9d91 100644 --- a/modules/unistd +++ b/modules/unistd @@ -53,6 +53,7 @@ unistd.h: unistd.in.h $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H) -e 's|@''GNULIB_LSEEK''@|$(GNULIB_LSEEK)|g' \ -e 's|@''GNULIB_PIPE2''@|$(GNULIB_PIPE2)|g' \ -e 's|@''GNULIB_PREAD''@|$(GNULIB_PREAD)|g' \ + -e 's|@''GNULIB_PWRITE''@|$(GNULIB_PWRITE)|g' \ -e 's|@''GNULIB_READLINK''@|$(GNULIB_READLINK)|g' \ -e 's|@''GNULIB_READLINKAT''@|$(GNULIB_READLINKAT)|g' \ -e 's|@''GNULIB_RMDIR''@|$(GNULIB_RMDIR)|g' \ @@ -87,6 +88,7 @@ unistd.h: unistd.in.h $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H) -e 's|@''HAVE_LINKAT''@|$(HAVE_LINKAT)|g' \ -e 's|@''HAVE_PIPE2''@|$(HAVE_PIPE2)|g' \ -e 's|@''HAVE_PREAD''@|$(HAVE_PREAD)|g' \ + -e 's|@''HAVE_PWRITE''@|$(HAVE_PWRITE)|g' \ -e 's|@''HAVE_READLINK''@|$(HAVE_READLINK)|g' \ -e 's|@''HAVE_READLINKAT''@|$(HAVE_READLINKAT)|g' \ -e 's|@''HAVE_SLEEP''@|$(HAVE_SLEEP)|g' \ @@ -114,6 +116,7 @@ unistd.h: unistd.in.h $(CXXDEFS_H) $(ARG_NONNULL_H) $(WARN_ON_USE_H) -e 's|@''REPLACE_LINKAT''@|$(REPLACE_LINKAT)|g' \ -e 's|@''REPLACE_LSEEK''@|$(REPLACE_LSEEK)|g' \ -e 's|@''REPLACE_PREAD''@|$(REPLACE_PREAD)|g' \ + -e 's|@''REPLACE_PWRITE''@|$(REPLACE_PWRITE)|g' \ -e 's|@''REPLACE_READLINK''@|$(REPLACE_READLINK)|g' \ -e 's|@''REPLACE_RMDIR''@|$(REPLACE_RMDIR)|g' \ -e 's|@''REPLACE_SLEEP''@|$(REPLACE_SLEEP)|g' \ diff --git a/tests/test-pwrite.c b/tests/test-pwrite.c new file mode 100644 index 0000000..bc8be0b --- /dev/null +++ b/tests/test-pwrite.c @@ -0,0 +1,80 @@ +/* Test the pwrite function. + Copyright (C) 2009, 2010 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include + +#include + +#include "signature.h" +SIGNATURE_CHECK (pwrite, ssize_t, (int, const void *, size_t, off_t)); + +#include +#include +#include + +#include "macros.h" + +#define N (sizeof buf - 1) + +int +main (void) +{ + char const *file = "out"; + int fd; + char buf[] = "0123456789"; + off_t pos = 2; + size_t i; + off_t init_pos; + + ASSERT (file); + + fd = open (file, O_CREAT | O_WRONLY, 0600); + ASSERT (0 <= fd); + ASSERT (write (fd, buf, N) == N); + ASSERT (close (fd) == 0); + + fd = open (file, O_WRONLY, 0600); + ASSERT (0 <= fd); + + init_pos = lseek (fd, pos, SEEK_SET); + ASSERT (init_pos == pos); + + for (i = 0; i < N; i+=2) + { + const char byte = 'W'; + ASSERT (pwrite (fd, &byte, 1, i) == 1); + ASSERT (lseek (fd, 0, SEEK_CUR) == init_pos); + } + + { + /* Invalid offset must evoke failure with EINVAL. */ + const char byte = 'b'; + ASSERT (pwrite (fd, &byte, 1, (off_t) -1) == -1); + ASSERT (errno == EINVAL); + } + + ASSERT (close (fd) == 0); + + { + char read_buf[N]; + fd = open (file, O_RDONLY); + ASSERT (0 <= fd); + ASSERT (read(fd, buf, N) == N); + ASSERT (close (fd) == 0); + ASSERT (strcmp("W1W3W5W7W9",buf) == 0); + } + return 0; +} diff --git a/tests/test-pwrite.sh b/tests/test-pwrite.sh new file mode 100755 index 0000000..aab99ed --- /dev/null +++ b/tests/test-pwrite.sh @@ -0,0 +1,7 @@ +#!/bin/sh +. "${srcdir=.}/init.sh"; path_prepend_ . + +fail=0 +: | test-pwrite || fail=1 + +Exit $fail diff --git a/tests/test-unistd-c++.cc b/tests/test-unistd-c++.cc index 425731a..2769d04 100644 --- a/tests/test-unistd-c++.cc +++ b/tests/test-unistd-c++.cc @@ -138,6 +138,11 @@ SIGNATURE_CHECK (GNULIB_NAMESPACE::pread, ssize_t, (int, void *, size_t, off_t)); #endif +#if GNULIB_TEST_PWRITE +SIGNATURE_CHECK (GNULIB_NAMESPACE::pwrite, ssize_t, + (int, const void *, size_t, off_t)); +#endif + #if GNULIB_TEST_READLINK SIGNATURE_CHECK (GNULIB_NAMESPACE::readlink, ssize_t, (const char *, char *, size_t)); -- 1.6.3.3