delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2003/03/08/19:11:43

Date: Sun, 09 Mar 2003 00:14:33 +0000
From: "Richard Dawe" <rich AT phekda DOT freeserve DOT co DOT uk>
Sender: rich AT phekda DOT freeserve DOT co DOT uk
To: djgpp-workers AT delorie DOT com
X-Mailer: Emacs 21.3.50 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6
Subject: New POSIX: pwrite, revision 2 [PATCH]
Message-Id: <E18roPd-0000Rn-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Here's revision 2 of the patch to add pwrite and a test for lseek
to DJGPP CVS. Thanks for the comments. The only change is that
pwrite does not fail anymore, when stdout & stderr have been redirected,
since pwrite can work OK in that case.

OK to commit?

Bye, Rich =]

Index: include/unistd.h
===================================================================
RCS file: /cvs/djgpp/djgpp/include/unistd.h,v
retrieving revision 1.16
diff -p -c -3 -r1.16 unistd.h
*** include/unistd.h	4 Feb 2003 20:24:30 -0000	1.16
--- include/unistd.h	9 Mar 2003 00:08:37 -0000
*************** off_t		lseek(int _fildes, off_t _offset,
*** 134,139 ****
--- 134,140 ----
  long		pathconf(const char *_path, int _name);
  int		pause(void);
  int		pipe(int _fildes[2]);
+ ssize_t		pwrite(int _fildes, const void *_buf, size_t _nbyte, off_t _offset);
  ssize_t		read(int _fildes, void *_buf, size_t _nbyte);
  int		rmdir(const char *_path);
  int		setgid(gid_t _gid);
Index: src/libc/posix/unistd/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/posix/unistd/makefile,v
retrieving revision 1.5
diff -p -c -3 -r1.5 makefile
*** src/libc/posix/unistd/makefile	14 Jun 2001 02:56:32 -0000	1.5
--- src/libc/posix/unistd/makefile	9 Mar 2003 00:08:37 -0000
***************
*** 1,3 ****
--- 1,4 ----
+ # Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details
  # Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details
*************** SRC += lseek.c
*** 39,44 ****
--- 40,46 ----
  SRC += pathconf.c
  SRC += pause.c
  SRC += pipe.c
+ SRC += pwrite.c
  SRC += read.c
  SRC += rmdir.c
  SRC += setgid.c
Index: tests/libc/posix/unistd/makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/posix/unistd/makefile,v
retrieving revision 1.4
diff -p -c -3 -r1.4 makefile
*** tests/libc/posix/unistd/makefile	1 Mar 2003 13:17:36 -0000	1.4
--- tests/libc/posix/unistd/makefile	9 Mar 2003 00:08:40 -0000
*************** SRC += sleep.c
*** 9,13 ****
--- 9,15 ----
  SRC += tread.c
  SRC += write.c
  SRC += t-isatty.c
+ SRC += t-lseek.c
+ SRC += t-pwrite.c
  
  include $(TOP)/../makefile.inc
*** /dev/null	Sun Mar  9 00:12:02 2003
--- src/libc/posix/unistd/pwrite.c	Sat Mar  8 11:44:36 2003
***************
*** 0 ****
--- 1,65 ----
+ /* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
+ #include <libc/stubs.h>
+ #include <errno.h>
+ #include <unistd.h>
+ #include <libc/fd_props.h>
+ 
+ ssize_t
+ pwrite (int fd, const void *buf, size_t nbyte, off_t offset)
+ {
+   const int flags = __get_fd_flags(fd);
+   offset_t start_pos, curr_pos;
+   int old_errno;
+   ssize_t ret;
+ 
+   /* Is this a pipe? Disallow on pipes. */
+   if (flags & FILE_DESC_PIPE) {
+     errno = ESPIPE;
+     return(-1);
+   }
+ 
+   /* TODO: When we support the Large File Summit, fail here, if the offset
+    * is negative. */
+ #if 0
+   if (offset < 0) {
+     errno = EINVAL;
+     return(-1);
+   }
+ #endif
+ 
+   /* Get the current position. */
+   start_pos = llseek(fd, 0LL, SEEK_CUR);
+   if (start_pos == -1)
+     return(-1); /* Pass through errno. */
+ 
+   /* Seek to the new position. */
+   curr_pos = llseek(fd, offset, SEEK_SET);
+   if (curr_pos == -1) {
+     old_errno = errno;
+ 
+     /* Failed. Try to seek back to the original position. */
+     llseek(fd, start_pos, SEEK_SET);
+ 
+     errno = old_errno;
+     return(-1);
+   }
+ 
+   /* Write the data. */
+   ret = write(fd, buf, nbyte);
+   if (ret < 0) {
+     old_errno = errno;
+ 
+     /* Failed. Try to seek back to the original position. */
+     llseek(fd, start_pos, SEEK_SET);
+ 
+     errno = old_errno;
+     return(-1);
+   }
+ 
+   /* Seek back to the start. */
+   curr_pos = llseek(fd, start_pos, SEEK_SET);
+   if (curr_pos == -1)
+     return(-1); /* Pass through errno. */
+ 
+   return(ret);
+ }
*** /dev/null	Sun Mar  9 00:12:02 2003
--- src/libc/posix/unistd/pwrite.txh	Fri Mar  7 13:03:02 2003
***************
*** 0 ****
--- 1,53 ----
+ @node pwrite, io
+ @findex pwrite
+ @subheading Syntax
+ 
+ @example
+ #include <unistd.h>
+ 
+ int pwrite(int file, const void *buffer, size_t count, off_t offset);
+ @end example
+ 
+ @subheading Description
+ 
+ This function writes @var{count} bytes from @var{buffer} to
+ @var{file} at position @var{offset}.  It returns the number of bytes
+ actually written.  It will return zero or a number less than
+ @var{count} if the disk is full, and may return less than @var{count}
+ even under valid conditions.
+ 
+ Note that if @var{file} is a text file, @code{pwrite} may write more
+ bytes than it reports. 
+ 
+ If @var{count} is zero, the function does nothing and returns zero.
+ Use @code{_write} if you want to actually ask DOS to write zero bytes.
+ 
+ The precise behavior of @code{pwrite} when the target filesystem is full
+ are somewhat troublesome, because DOS doesn't fail the underlying system
+ call.  If your application needs to rely on @code{errno} being set to
+ @code{ENOSPC} in such cases, you need to invoke @code{pwrite} as shown in
+ an example for @code{write} (@pxref{write}).  In a nutshell, the trick is
+ to call @code{pwrite} one more time after it returns a value smaller
+ than the @var{count} parameter; then it will @emph{always} set @code{errno}
+ if the disk is full.
+ 
+ @subheading Return Value
+ 
+ The number of bytes written, zero at EOF, or -1 on error.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, !posix-1003.2-1992, posix-1003.1-2001
+ 
+ @subheading Example
+ 
+ @example
+ const char buf[] = "abc";
+ const size_t bufsize = strlen(buf);
+ 
+ /* Write out buf, then overwrite 'b' with 'd'. NB: We should check
+  * for errors. */
+ lseek(fd, 0L, SEEK_SET);
+ write(fd, buf, bufsize);
+ pwrite(fd, "d", 1, 1);
+ @end example
*** /dev/null	Sun Mar  9 00:12:02 2003
--- tests/libc/posix/unistd/t-lseek.c	Fri Mar  7 14:19:02 2003
***************
*** 0 ****
--- 1,81 ----
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ 
+ #define TEST_FILE "t-lseek.tst"
+ 
+ int
+ main (int argc, char *argv[])
+ {
+   int   fd;
+   off_t o;
+   int   ret;
+ 
+   fd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR);
+   if (fd < 0)
+     {
+       puts("Unable to create test file '" TEST_FILE "'!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = write(fd, "a", 1);
+   if (ret < 0)
+     {
+       puts("write() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   o = lseek(fd, 1024 * 1024, SEEK_SET);
+   if (ret < 0)
+     {
+       puts("lseek() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = write(fd, "b", 1);
+   if (ret < 0)
+     {
+       puts("write() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   o = lseek(fd, 2 * 1024 * 1024, SEEK_SET);
+   if (ret < 0)
+     {
+       puts("lseek() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = write(fd, "c", 1);
+   if (ret < 0)
+     {
+       puts("write() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = close(fd);
+   if (ret < 0)
+     {
+       puts("close() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   puts("PASS");
+   return(EXIT_SUCCESS);
+ }
*** /dev/null	Sun Mar  9 00:12:02 2003
--- tests/libc/posix/unistd/t-pwrite.c	Sat Mar  8 11:44:58 2003
***************
*** 0 ****
--- 1,148 ----
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <unistd.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <io.h>
+ #include <libc/fd_props.h>
+ 
+ #define TEST_FILE     "t-pwrite.tst"
+ #define EXTEND_LENGTH (1024 * 1024)
+ 
+ int
+ main (int argc, char *argv[])
+ {
+   int          fd;
+   int          ret;
+   const char   orig_buf[]   = "abc";
+   const size_t orig_bufsize = strlen(orig_buf);
+   const char   repl_char[]  = "d"; /* Replacement character */
+   const size_t repl_pos     = 1;   /* Replacement position */
+   char         after_buf[]  = "XXX";
+   char         buf[128];
+   const size_t bufsize      = sizeof(buf);
+   const int    fd_stdout    = fileno(stdout);
+   const int    fd_stderr    = fileno(stderr);
+   const char   msg_stdout[] = "Just a test (stdout)\n";
+   const char   msg_stderr[] = "Just a test (stderr)\n";
+ 
+   /* Test overwriting a particular position. */
+   strcpy(after_buf, orig_buf);
+   after_buf[repl_pos] = repl_char[0];
+ 
+   fd = open(TEST_FILE, O_RDWR|O_TRUNC|O_CREAT|O_BINARY, S_IRUSR|S_IWUSR);
+   if (fd < 0)
+     {
+       puts("Unable to create test file '" TEST_FILE "'!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = write(fd, orig_buf, orig_bufsize);
+   if (ret < 0)
+     {
+       puts("write() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = pwrite(fd, repl_char, 1, repl_pos);
+   if (ret < 0)
+     {
+       puts("pwrite() to overwrite failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Check that the file now contains after_buf. */
+   ret = lseek(fd, 0, SEEK_SET);
+   if (ret < 0)
+     {
+       puts("lseek() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = read(fd, buf, bufsize);
+   if (ret < 0)
+     {
+       puts("read() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   buf[sizeof(buf) - 1] = '\0';
+ 
+   if (strncmp(after_buf, buf, strlen(after_buf)) != 0)
+     {
+       puts("Data comparison failed!");
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try extending the file's size. */
+   ret = pwrite(fd, orig_buf, orig_bufsize, EXTEND_LENGTH);
+   if (ret < 0)
+     {
+       puts("pwrite() to extend failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Check the file size. */
+   ret = filelength(fd);
+   if (ret < 0)
+     {
+       puts("filelength() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   if (ret != (EXTEND_LENGTH + orig_bufsize))
+     {
+       puts("Failed to extend file to correct length!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = close(fd);
+   if (ret < 0)
+     {
+       puts("close() failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   /* Try writing to stdout, stderr. */
+   ret = pwrite(fd_stdout, msg_stdout, strlen(msg_stdout), 1024);
+   if (ret < 0)
+     {
+       puts("pwrite() to stdout failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   ret = pwrite(fd_stderr, msg_stderr, strlen(msg_stderr), 1024);
+   if (ret < 0)
+     {
+       puts("pwrite() to stderr failed!");
+       perror(argv[0]);
+       puts("FAIL");
+       return(EXIT_FAILURE);
+     }
+ 
+   puts("PASS");
+   return(EXIT_SUCCESS);
+ }

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019