delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2001/01/06/07:49:07

Date: Sat, 06 Jan 2001 12:43:52 +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.0.93 (via feedmail 8.3.emacs20_6 I) and Blat ver 1.8.6
Subject: /dev/zero & /dev/full FSEXTs
Message-Id: <E14EtVu-0000G9-00@phekda.freeserve.co.uk>
Reply-To: djgpp-workers AT delorie DOT com

Hello.

Please find below a diff to add the /dev/zero and /dev/full FSEXTs
to DJGPP. I've licensed the FSEXT under the GNU LGPL. If this a problem,
I can change the licence for incorporation into DJGPP.

Currently unfinished:

- I wrote the FSEXT using DJGPP 2.03, rather than the latest library
  sources. So, __FSEXT_llseek is not yet supported (but see my other
  mail on the return-value problem).

- The test program currently breaks on the stat() tests, because of
  a bug in lstat() (see my other mail).

I'm going to be away for a week starting Sunday (tomorrow for me), so
don't expect a quick response to mails about this patch. I'll read
djgpp-workers via the web, though.

Bye, Rich =]

*** /dev/nul	Sat Jan  6 12:39:08 2001
--- /develop/djgpp.0/include/sys/xdevices.h	Sat Jan  6 11:51:50 2001
***************
*** 0 ****
--- 1,27 ----
+ /* Copyright (C) 2000, 2001 DJ Delorie, see COPYING.DJ for details */
+ 
+ #ifndef __dj_include_sys_xdevices_h_
+ #define __dj_include_sys_xdevices_h_
+ 
+ #ifdef __cplusplus
+ extern "C" {
+ #endif
+ 
+ #ifndef __dj_ENFORCE_ANSI_FREESTANDING
+ 
+ #ifndef __STRICT_ANSI__
+ 
+ #ifndef _POSIX_SOURCE
+ 
+ int __install_dev_zero (void);
+ int __install_dev_full (void);
+ 
+ #endif /* !_POSIX_SOURCE */
+ #endif /* !__STRICT_ANSI__ */
+ #endif /* !__dj_ENFORCE_ANSI_FREESTANDING */
+ 
+ #ifdef __cplusplus
+ }
+ #endif
+ 
+ #endif /* !__dj_include_sys_xdevices_h_ */
*** /dev/nul	Sat Jan  6 12:39:08 2001
--- /develop/djgpp.0/src/libc/fsext/fse_zero.c	Sat Jan  6 11:52:22 2001
***************
*** 0 ****
--- 1,662 ----
+ /*
+  * fse_zero.c - An implementation of /dev/zero and /dev/full for DJGPP
+  * Copyright (C) 2000, 2001 by Richard Dawe
+  *
+  * This 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 of the License, or (at your option) any later version.
+  *
+  * This 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 this library; if not, write to the Free
+  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+  */
+ 
+ #include <stdlib.h>
+ #include <string.h>
+ #include <errno.h>
+ #include <limits.h>
+ #include <time.h>
+ #include <fcntl.h>
+ #include <io.h>
+ #include <unistd.h>
+ #include <sys/stat.h>
+ #include <sys/fsext.h>
+ #include <sys/xdevices.h>
+ 
+ static const char DEV_ZERO_PATH[] = "/dev/zero";
+ static const char DEV_FULL_PATH[] = "/dev/full";
+ 
+ typedef struct {
+   int flags;
+   int dev_full:1; /* 1 => /dev/full, 0 => /dev/zero */
+   int dup_count;  /* Support for dup() - reference count. */
+ } DEV_DATA;
+ 
+ static int    dev_fsext_installed = 0;
+ static int    dev_zero_installed  = 0;
+ static int    dev_full_installed  = 0;
+ 
+ /* stat(), fstat() support */
+ static time_t dev_zero_atime;
+ static time_t dev_zero_ctime;
+ static ino_t  dev_zero_inode = 0;
+ static time_t dev_zero_mtime;
+ 
+ static time_t dev_full_atime;
+ static time_t dev_full_ctime;
+ static ino_t  dev_full_inode = 0;
+ static time_t dev_full_mtime;
+ 
+ /* TODO: Get this declaration in a better way. */
+ extern ino_t _invent_inode (const char *name,
+ 			    unsigned time_stamp,
+ 			    unsigned long fsize);
+ 
+ static int dev_fsext (__FSEXT_Fnumber n, int *rv, va_list args);
+ 
+ /* ----------------
+  * - internal_dup -
+  * ---------------- */
+ 
+ static int
+ internal_dup (const int fd)
+ {
+   DEV_DATA *data   = NULL;  
+   int       new_fd = 0;
+ 
+   /* Allocate a new file descriptor. */
+   new_fd = __FSEXT_alloc_fd(dev_fsext);
+   if (new_fd < 0)
+     return(-1);
+ 
+   /* Get context */
+   data = (DEV_DATA *) __FSEXT_get_data(fd);
+   if (data == NULL) {
+     errno = EBADF;
+     _close(new_fd);
+     return(-1);
+   }
+ 
+   /* Associate the context with the new fd too. */
+   if (__FSEXT_set_data(new_fd, (void *) data) == NULL) {
+     errno = ENOMEM;
+     _close(new_fd);
+     return(-1);
+   }
+ 
+   data->dup_count++;
+   return(new_fd);
+ }
+ 
+ /* ------------------------
+  * - internal_stat_simple -
+  * ------------------------ */
+ 
+ /* This sets up the "obvious" fields of 'struct stat'. */
+ 
+ static int inline
+ internal_stat_simple (struct stat *sbuf)
+ {
+   sbuf->st_dev     = -1;
+   sbuf->st_gid     = getgid();
+   /* Everyone can read & write the zero device; it's a character device. */
+   sbuf->st_mode    = S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR|S_IWGRP|S_IWOTH|S_IFCHR;
+   sbuf->st_nlink   = 1;
+   sbuf->st_size    = 0;
+   sbuf->st_blksize = 0;
+   sbuf->st_uid     = getuid();
+ 
+ #ifdef HAVE_ST_RDEV
+   sbuf->st_rdev    = -1;
+ #endif
+ 
+   return(1);
+ }
+ 
+ /* --------------------------
+  * - dev_zero_internal_stat -
+  * -------------------------- */
+ 
+ static int
+ dev_zero_internal_stat (struct stat *sbuf)
+ {
+   internal_stat_simple(sbuf);
+ 
+   sbuf->st_atime = dev_zero_atime;
+   sbuf->st_ctime = dev_zero_ctime;
+   sbuf->st_ino   = dev_zero_inode;
+   sbuf->st_mtime = dev_zero_mtime;
+ 
+   return(1);
+ }
+ 
+ /* --------------------------
+  * - dev_full_internal_stat -
+  * -------------------------- */
+ 
+ /* This sets up the "obvious" fields of 'struct stat' for full device. */
+ 
+ static int
+ dev_full_internal_stat (struct stat *sbuf)
+ {
+   internal_stat_simple(sbuf);
+ 
+   sbuf->st_atime = dev_full_atime;
+   sbuf->st_ctime = dev_full_ctime;
+   sbuf->st_ino   = dev_full_inode;
+   sbuf->st_mtime = dev_full_mtime;
+ 
+   return(1);
+ }
+ 
+ /* ------------------
+  * - match_dev_path -
+  * ------------------ */
+ 
+ static int inline
+ match_dev_path (const char *filename, const char *dev_path)
+ {
+   int ret = 1; /* Successful match by default */
+ 
+   if (filename[0] && (filename[1] == ':')) {
+     /* Drive-extended */
+     if (stricmp(filename + 2, dev_path) != 0) {
+       ret = 0;
+     }
+   } else {
+     /* Normal */
+     if (stricmp(filename, dev_path) != 0) {
+       ret =0;
+     }
+   }
+ 
+   return(ret);
+ }
+ 
+ /* -------------
+  * - dev_fsext -
+  * ------------- */
+ 
+ static int
+ dev_fsext (__FSEXT_Fnumber n, int *rv, va_list args)
+ {
+   int          emul       = 0; /* Emulated call? 1 => yes, 0 = no. */
+   int          fd         = 0;
+   DEV_DATA    *data       = NULL;
+   char        *filename   = NULL;
+   int          open_mode  = 0;
+   int          perm       = 0;
+   mode_t       creat_mode = 0;  
+   void        *buf        = NULL;
+   size_t       buflen     = 0;
+   off_t        offset     = 0;
+   int          whence     = 0;
+   struct stat *sbuf       = NULL;
+   int          cmd        = 0;
+   int          iparam     = 0;
+ #ifdef DJGPP_SUPPORTS_FIONBIO_NOW
+   int         *piparam    = NULL;
+ #endif /* DJGPP_SUPPORTS_FIONBIO_NOW */
+ 
+   switch(n) {
+   default:
+   case __FSEXT_nop:
+     break;
+ 
+   case __FSEXT_open:
+     filename  = va_arg(args, char *);
+     open_mode = va_arg(args, int);
+ 
+     if (open_mode & O_CREAT)
+       perm = va_arg(args, int);
+ 
+     /* Check the filename */
+     if (   !match_dev_path(filename, DEV_ZERO_PATH)
+ 	&& !match_dev_path(filename, DEV_FULL_PATH))
+       break;
+     
+     /* It's for us. */
+     emul = 1;
+ 
+     /* Check whether the zero/full device has been installed. */
+     if (match_dev_path(filename, DEV_ZERO_PATH) && !dev_zero_installed)
+       break;
+ 
+     if (match_dev_path(filename, DEV_FULL_PATH) && !dev_full_installed)
+       break;
+ 
+     /* zero device _always_ exists. */
+     if (open_mode & O_CREAT) {
+       errno = EEXIST;
+       *rv   = -1;	
+       break;
+     }
+ 
+     /* Allocate a file descriptor for the device. */
+     fd = __FSEXT_alloc_fd(dev_fsext);
+     if (fd < 0) {
+       *rv = fd;
+       break;
+     }
+ 
+     /* Allocate some fd context. */
+     data = (DEV_DATA *) malloc(sizeof(*data));
+     if (data == NULL) {
+       errno = ENOMEM;
+       *rv   = -1;
+       break;
+     }
+     
+     /* Set up the context. */
+     memset(data, 0, sizeof(*data));
+ 
+     data->flags     = open_mode; /* Save open mode for read(), write() */
+     data->dup_count = 1;
+ 
+     /* Is this zero or full device? */
+     if (match_dev_path(filename, DEV_FULL_PATH))
+       data->dev_full = 1;
+     else
+       data->dev_full = 0;
+ 
+     /* zero device always has O_NOINHERIT. */
+     data->flags |= O_NOINHERIT;
+ 
+     /* Ensure that we only have relevant flags. */
+     data->flags &= (O_ACCMODE | O_BINARY | O_TEXT | O_NOINHERIT | O_NONBLOCK);
+ 
+     /* Associate the context with the fd. */
+     if (__FSEXT_set_data(fd, (void *) data) == NULL) {
+       errno = ENOMEM;
+       *rv   = -1;
+       break;
+     }
+ 
+     /* Done */
+     *rv = fd;
+     break;
+ 
+   case __FSEXT_creat:
+     filename   = va_arg(args, char *);
+     creat_mode = va_arg(args, mode_t);
+ 
+     /* Check the filename */
+     if (   !match_dev_path(filename, DEV_ZERO_PATH)
+ 	&& !match_dev_path(filename, DEV_FULL_PATH))
+       break;
+ 
+     /* Check whether the zero/full device has been installed. */
+     if (match_dev_path(filename, DEV_ZERO_PATH) && !dev_zero_installed)
+       break;
+ 
+     if (match_dev_path(filename, DEV_FULL_PATH) && !dev_full_installed)
+       break;
+ 
+     /* zero device _always_ exists. */
+     emul  = 1;
+     errno = EEXIST;
+     *rv   = -1;
+     break;
+ 
+   case __FSEXT_read:
+     fd     = va_arg(args, int);
+     buf    = va_arg(args, void *);
+     buflen = va_arg(args, size_t);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Get context */
+     data = (DEV_DATA *) __FSEXT_get_data(fd);
+     if (data == NULL) {
+       errno = EBADF;
+       *rv   = -1;
+       break;
+     }
+ 
+     /* Can we actually read from the zero device? */
+     if (   ((data->flags & O_ACCMODE) != O_RDONLY)
+ 	&& ((data->flags & O_ACCMODE) != O_RDWR) ) {
+       errno = EACCES;
+       *rv   = -1;
+       break;
+     }
+ 
+     /* Now read - just zero the buffer. */
+     memset(buf, '\0', buflen);
+ 
+     /* Update access time */
+     if (data->dev_full)
+       time(&dev_full_atime);
+     else
+       time(&dev_zero_atime);
+ 
+     *rv = (int) buflen;
+     break;
+ 
+   case __FSEXT_write:
+     fd     = va_arg(args, int);
+     buf    = va_arg(args, void *);
+     buflen = va_arg(args, size_t);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Get context */
+     data = (DEV_DATA *) __FSEXT_get_data(fd);
+     if (data == NULL) {
+       errno = EBADF;
+       *rv   = -1;
+       break;
+     }
+ 
+     /* Can we actually write to the zero device? */
+     if (   ((data->flags & O_ACCMODE) != O_WRONLY)
+ 	&& ((data->flags & O_ACCMODE) != O_RDWR) ) {
+       errno = EACCES;
+       *rv   = -1;
+       break;
+     }
+ 
+     if (data->dev_full) {
+       /* Nope, it's full */
+       errno = ENOSPC;
+       *rv   = -1;
+       break;
+     }
+ 
+     /* Now write - just ignore the buffer. */
+ 
+     /* Update access & modification times - it must be zero device here. */
+     time(&dev_zero_atime);
+     time(&dev_zero_mtime);
+     
+     *rv = (int) buflen;    
+     break;
+ 
+   case __FSEXT_ready:
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     *rv  = __FSEXT_ready_read | __FSEXT_ready_write;    
+     break;
+ 
+   case __FSEXT_close:
+     fd = va_arg(args, int);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Get context */
+     data = (DEV_DATA *) __FSEXT_get_data(fd);
+     if (data == NULL) {
+       errno = EBADF;
+       *rv   = -1;
+       break;
+     }
+ 
+     __FSEXT_set_data(fd, NULL);    
+     __FSEXT_set_function(fd, NULL);
+ 
+     /* Cope with dup()'d zero devices. */
+     data->dup_count--;
+ 
+     if (data->dup_count <= 0) {
+       /* No longer referenced */
+       free(data);
+       _close(fd);
+     }
+     break;
+ 
+   case __FSEXT_fcntl:
+     fd  = va_arg(args, int);
+     cmd = va_arg(args, int);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Get context */
+     data = (DEV_DATA *) __FSEXT_get_data(fd);
+     if (data == NULL) {
+       errno = EBADF;
+       *rv   = -1;
+       break;
+     }
+ 
+     switch(cmd) {
+     case F_DUPFD:
+       *rv = internal_dup(fd);
+       break;
+ 
+     case F_GETFD:
+       if (data->flags & O_NOINHERIT)
+ 	*rv = 1;
+       else
+ 	*rv = 0;
+       break;
+ 
+     case F_SETFD:
+       iparam = va_arg(args, int);
+ 
+       /* Unsupported - this can't be changed on DOS/Windows. */
+       errno = ENOSYS;
+       *rv   = -1;
+       break;
+ 
+     case F_GETFL:
+       *rv = data->flags;
+       break;
+ 
+     case F_SETFL:
+       iparam = va_arg(args, int);
+ 
+       /* Trying to change immutable fields? */
+       if ((iparam & ~O_NONBLOCK) != (data->flags & ~O_NONBLOCK)) {
+ 	errno = ENOSYS;
+ 	*rv   = -1;
+ 	break;
+       }
+       
+       /* Handle mutable fields */
+       if (iparam & O_NONBLOCK)
+ 	data->flags |= O_NONBLOCK;
+       else
+ 	data->flags &= ~O_NONBLOCK;
+ 
+       *rv = 0;
+       break;
+ 
+     default:
+       /* Unknown/unhandled fcntl */
+       errno = ENOSYS;
+       *rv   = -1;
+       break;
+     }
+     break;
+ 
+   case __FSEXT_ioctl:
+     fd  = va_arg(args, int);
+     cmd = va_arg(args, int);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;    
+ 
+     switch(cmd) {
+       /* */
+ #ifdef DJGPP_SUPPORTS_FIONBIO_NOW
+     case FIONBIO:
+       piparam = va_arg(args, int *);
+       if (*piparam)
+ 	data->flags |= O_NONBLOCK;
+       else
+ 	data->flags &= ~O_NONBLOCK;
+ 
+       *rv = 0;
+       break;
+ #endif /* DJGPP_SUPPORTS_FIONBIO_NOW */
+       
+     default:
+       errno = ENOTTY;
+       *rv = 1;
+       break;
+     }    
+     break;
+ 
+   case __FSEXT_lseek:
+     fd     = va_arg(args, int);
+     offset = va_arg(args, off_t);
+     whence = va_arg(args, int);    
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     *rv = offset;
+     break;
+ 
+   case __FSEXT_link:
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Fail request */
+     errno = EPERM;
+     *rv   = -1;
+     break;
+ 
+   case __FSEXT_unlink:    
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* The zero device cannot be removed. */
+     errno = EPERM;
+     *rv   = -1;
+     break;
+ 
+   case __FSEXT_dup:
+ #ifdef DJGPP_SUPPORTS_FSEXT_DUP_NOW
+     fd = va_arg(args, int);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Done */
+     *rv = internal_dup(fd);
+ #endif /* DJGPP_SUPPORTS_FSEXT_DUP_NOW */
+     break;
+ 
+   case __FSEXT_dup2:
+ #ifdef DJGPP_SUPPORTS_FSEXT_DUP2_NOW
+     /* TODO: When __FSEXT_dup2 is supported, add support. */
+ #endif /* DJGPP_SUPPORTS_FSEXT_DUP2_NOW */
+     break;
+ 
+   case __FSEXT_stat:
+     filename = va_arg(args, char *);
+     sbuf     = va_arg(args, struct stat *);
+ 
+     /* Check the filename */
+     if (   !match_dev_path(filename, DEV_ZERO_PATH)
+ 	&& !match_dev_path(filename, DEV_FULL_PATH))
+       break;
+ 
+     /* Check whether the zero/full device has been installed. */
+     if (match_dev_path(filename, DEV_ZERO_PATH) && !dev_zero_installed)
+       break;
+ 
+     if (match_dev_path(filename, DEV_FULL_PATH) && !dev_full_installed)
+       break;
+     
+     /* It's for us. */
+     emul = 1;
+ 
+     /* Set up the stat buf */
+     memset(sbuf, 0, sizeof(*sbuf));
+ 
+     if (match_dev_path(filename, DEV_FULL_PATH))
+       dev_full_internal_stat(sbuf);
+     else
+       dev_zero_internal_stat(sbuf);
+ 
+     *rv  = 0;
+     break;
+ 
+   case __FSEXT_fstat:
+     fd   = va_arg(args, int);
+     sbuf = va_arg(args, struct stat *);
+ 
+     /* This must be emulated, since the FSEXT has been called. */
+     emul = 1;
+ 
+     /* Get context */
+     data = (DEV_DATA *) __FSEXT_get_data(fd);
+     if (data == NULL) {
+       errno = EBADF;
+       *rv   = -1;
+       break;
+     }
+ 
+     /* Set up the stat buf */
+     memset(sbuf, 0, sizeof(*sbuf));
+ 
+     if (data->dev_full)
+       dev_full_internal_stat(sbuf);
+     else
+       dev_zero_internal_stat(sbuf);
+ 
+     *rv = 0;
+     break;
+   }  
+ 
+   return(emul);
+ }
+ 
+ /* ----------------------
+  * - __install_dev_zero -
+  * ---------------------- */
+ 
+ int
+ __install_dev_zero (void)
+ {
+   if (dev_zero_installed)
+     return(dev_zero_installed);
+ 
+   if (!dev_fsext_installed) {
+     __FSEXT_add_open_handler(dev_fsext);
+     dev_fsext_installed = 1;
+   }
+ 
+   time(&dev_zero_ctime);
+   dev_zero_atime     = dev_zero_mtime = dev_zero_ctime;
+   dev_zero_inode     = _invent_inode(DEV_ZERO_PATH, 0, 0);
+   dev_zero_installed = 1;
+ 
+   return(1);
+ }
+ 
+ /* ----------------------
+  * - __install_dev_full -
+  * ---------------------- */
+ 
+ int
+ __install_dev_full (void)
+ {
+   if (dev_full_installed)
+     return(dev_full_installed);
+ 
+   if (!dev_fsext_installed) {
+     __FSEXT_add_open_handler(dev_fsext);
+     dev_fsext_installed = 1;
+   }
+ 
+   time(&dev_full_ctime);
+   dev_full_atime     = dev_full_mtime = dev_full_ctime;
+   dev_full_inode     = _invent_inode(DEV_FULL_PATH, 0, 0);
+   dev_full_installed = 1;
+ 
+   return(1);
+ }
*** /dev/nul	Sat Jan  6 12:39:08 2001
--- /develop/djgpp.0/src/libc/fsext/fse_zero.txh	Sat Jan  6 12:38:34 2001
***************
*** 0 ****
--- 1,55 ----
+ @node __install_dev_zero, file system
+ 
+ @subheading Syntax
+ 
+ @example
+ #include <sys/xdevices.h>
+ 
+ int __install_dev_zero (void);
+ @end example
+ 
+ @subheading Description
+ 
+ This function activates support for the special file @file{/dev/zero}.
+ When read, @file{dev/zero} always returns @samp{\0} characters.  When
+ written, @file{/dev/zero} discards the data.  Seeks on @file{/dev/zero}
+ will always succeed.
+ 
+ The DJGPP debug support functions will interfere with @file{/dev/zero}
+ (@pxref{File System Extensions}).
+ 
+ @subheading Return Value
+ 
+ On success, a non-zero value is returned; on failure, zero is returned.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, !posix
+ 
+ @node __install_dev_full, file system
+ 
+ @subheading Syntax
+ 
+ @example
+ #include <sys/xdevices.h>
+ 
+ int __install_dev_full (void);
+ @end example
+ 
+ @subheading Description
+ 
+ This function activates support for the special file @file{/dev/full}.
+ When read, @file{dev/full} always returns @samp{\0} characters.  Writes
+ to @file{/dev/full} will fail with @var{errno} set to @code{ENOSPC}.
+ Seeks on @file{/dev/full} always succeed.
+ 
+ The DJGPP debug support functions will interfere with @file{/dev/full}
+ (@pxref{File System Extensions}).
+ 
+ @subheading Return Value
+ 
+ On success, a non-zero value is returned; on failure, zero is returned.
+ 
+ @subheading Portability
+ 
+ @portability !ansi, !posix
*** /develop/djgpp/src/libc/fsext/makefile	Sat Nov 25 20:38:58 1995
--- /develop/djgpp.0/src/libc/fsext/makefile	Sat Jan  6 11:49:06 2001
*************** TOP=..
*** 3,7 ****
--- 3,8 ----
  
  SRC += fse_open.c
  SRC += fsext.c
+ SRC += fse_zero.c
  
  include $(TOP)/../makefile.inc
*** /dev/nul	Sat Jan  6 12:39:08 2001
--- /develop/djgpp.0/tests/libc/fsext/tzero.c	Sat Jan  6 12:36:36 2001
***************
*** 0 ****
--- 1,533 ----
+ /* Test written by Richard Dawe <richdawe AT bigfoot DOT com> */
+ 
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <errno.h>
+ #include <limits.h>
+ #include <unistd.h>
+ #include <fcntl.h>
+ #include <sys/stat.h>
+ #include <time.h>
+ #include <assert.h>
+ 
+ #include <sys/xdevices.h>
+ 
+ static const char DEV_ZERO_PATH[] = "/dev/zero";
+ static const char DEV_FULL_PATH[] = "/dev/full";
+ 
+ static int
+ jumble_buffer (char *buf, size_t buflen)
+ {
+   size_t i;
+ 
+   for (i = 0; i < buflen; i++) {
+     buf[i] = random() % 0xff;
+   }
+ 
+   return(1);
+ }
+ 
+ static int
+ dump_stat (struct stat *sbuf)
+ {
+   printf("st_atime   = %d\n"
+ 	 "st_ctime   = %d\n"
+ 	 "st_dev     = %d\n"
+ 	 "st_gid     = %d\n"
+ 	 "st_ino     = %d\n"
+ 	 "st_mode    = %d\n"
+ 	 "st_mtime   = %d\n"
+ 	 "st_nlink   = %d\n"
+ 	 "st_size    = %d\n"
+ 	 "st_blksize = %d\n"
+ 	 "st_uid     = %d\n",
+ 	 sbuf->st_atime, sbuf->st_ctime, sbuf->st_dev,
+ 	 sbuf->st_gid, sbuf->st_ino, sbuf->st_mode,
+ 	 sbuf->st_mtime, sbuf->st_nlink, sbuf->st_size,
+ 	 sbuf->st_blksize, sbuf->st_uid);
+ 
+   return(1);
+ }
+ 
+ static int
+ test_fstat (const char *filename)
+ {
+   struct stat sbuf;
+   char        buf[32768];
+   int         fd = 0;
+   int         n  = 0;
+ 
+   fd = open(filename, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", filename, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   sleep(1);
+ 
+   n = read(fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to read %lu bytes from %s: %s\n",
+ 	    sizeof(buf), filename, strerror(errno));
+   }
+ 
+   sleep(1);
+ 
+   n = write(fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to write %lu bytes to %s: %s\n",
+ 	    sizeof(buf), filename, strerror(errno));
+   }
+ 
+   if (fstat(fd, &sbuf) < 0) {
+     fprintf(stderr,
+ 	    "Unable to fstat() %s: %s\n", filename, strerror(errno));
+     close(fd);
+     return(0);
+   }
+ 
+   printf("fstat() result for %s:\n", filename);
+   dump_stat(&sbuf);
+   printf("\n");
+ 
+   close(fd);
+ 
+   return(1);
+ }
+ 
+ int
+ main (int argc, char *argv[])
+ {
+   char           buf[32768];
+   char           filename[PATH_MAX];
+   int            fd         = 0;
+   int            new_fd     = 0;
+   fd_set         readfds, writefds;
+   struct timeval tv;
+   struct stat    sbuf;
+   off_t          offset     = 0;
+   off_t          ret_offset = 0;
+   int            n          = 0;
+   size_t         i          = 0;
+ 
+   if (!__install_dev_zero()) {
+     fprintf(stderr, "__install_dev_zero() failed\n");
+     return(EXIT_FAILURE);
+   }
+ 
+   if (!__install_dev_full()) {
+     fprintf(stderr, "__install_dev_full() failed\n");
+     return(EXIT_FAILURE);
+   }
+ 
+   /* - Test open() - */
+ 
+   /* Normal path */
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
+   fd = open(DEV_FULL_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_FULL_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
+   /* Drive-extended path */
+   sprintf(filename, "c:%s", DEV_ZERO_PATH);
+ 
+   fd = open(filename, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", filename, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
+   /* Upper case */
+   strcpy(filename, DEV_ZERO_PATH);
+   strupr(filename);
+ 
+   fd = open(filename, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", filename, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
+   /* - Generic tests of /dev/zero. - */
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   /* Write buffer into /dev/zero. */
+   jumble_buffer(buf, sizeof(buf));
+ 
+   n = write(fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to write %lu bytes to %s: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(((size_t) n) == sizeof(buf));
+ 
+   /* Zero buffer by reading from /dev/zero. */
+   n = read(fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to read %lu bytes from %s: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(((size_t) n) == sizeof(buf));
+ 
+   for (i = 0; i < sizeof(buf); i++) {
+     if (buf[i] != '\0') {
+       fprintf(stderr, "Byte %lu in read data is non-zero\n", i);
+       return(EXIT_FAILURE);
+     }
+   }
+ 
+   close(fd);
+ 
+   /* - Generic tests for /dev/full - */
+ 
+   /* Writing to /dev/full is tested by test_fstat() later on. */
+ 
+   /* - Test /dev/zero opened read-only. - */
+   fd = open(DEV_ZERO_PATH, O_RDONLY);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s read-only: %s\n",
+ 	    DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   /* Check that writing fails. */
+   jumble_buffer(buf, sizeof(buf));
+ 
+   n = write(fd, buf, sizeof(buf));
+   if (n >= 0) {
+     fprintf(stderr,
+ 	    "Able to write %lu bytes to %s when read-only: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   /* Zero buffer by reading from /dev/zero. */
+   n = read(fd, buf, sizeof(buf));
+ 
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to read %lu bytes from %s when read-only: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(((size_t) n) == sizeof(buf));
+ 
+   close(fd);
+ 
+   /* - Test /dev/zero opened write-only. - */
+   fd = open(DEV_ZERO_PATH, O_WRONLY);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s write-only: %s\n",
+ 	    DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   /* Write buffer into /dev/zero. */
+   jumble_buffer(buf, sizeof(buf));
+ 
+   n = write(fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to write %lu bytes to %s when write-only: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(((size_t) n) == sizeof(buf));
+ 
+   /* Check that reading fails. */  
+   n = read(fd, buf, sizeof(buf));
+   if (n >= 0) {
+     fprintf(stderr,
+ 	    "Able to read %lu bytes from %s when write-only: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
+   /* - Check that creat() fails. - */
+   fd = creat(DEV_ZERO_PATH, S_IRUSR|S_IWUSR);
+   if (fd >= 0) {
+     fprintf(stderr,
+ 	    "creat() succeeded in creating %s - it should fail\n",
+ 	    DEV_ZERO_PATH);
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(errno == EEXIST);
+ 
+   /* - Check that open() fails, when using O_CREAT. - */
+   fd = open(DEV_ZERO_PATH, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR);
+   if (fd >= 0) {
+     fprintf(stderr,
+ 	    "open() succeeded in creating %s - it should fail\n",
+ 	    DEV_ZERO_PATH);
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(errno == EEXIST);
+ 
+   /* - Check select() support. - */
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   FD_ZERO(&readfds);
+   FD_ZERO(&writefds);
+   memset(&tv, 0, sizeof(tv));
+ 
+   FD_SET(fd, &readfds);
+   FD_SET(fd, &writefds);
+ 
+   n = select(fd + 1, &readfds, &writefds, NULL, &tv);
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "select() on %sfailed: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   if (!FD_ISSET(fd, &readfds)) {
+     fprintf(stderr, "Expected %s to be ready for reading\n", DEV_ZERO_PATH);
+     return(EXIT_FAILURE);
+   }
+ 
+   if (!FD_ISSET(fd, &writefds)) {
+     fprintf(stderr, "Expected %s to be ready for writing\n", DEV_ZERO_PATH);
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
+   /* - Check link() fails - */
+ #define LINK_TEST_PATH "/temp/wibble"
+ 
+   n = link(DEV_ZERO_PATH, LINK_TEST_PATH);
+   if (n == 0) {
+     fprintf(stderr,
+ 	    "link(\"%s\", \"%s\") succeeded - it should fail\n",
+ 	    DEV_ZERO_PATH, LINK_TEST_PATH);
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(errno == EPERM);
+ 
+ #undef LINK_TEST_PATH
+ 
+   /* - Check unlink() fails - */
+   n = unlink(DEV_ZERO_PATH);
+   if (n >= 0) {
+     fprintf(stderr,
+ 	    "unlink() succeeded in removing %s - it should fail\n",
+ 	    DEV_ZERO_PATH);
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(errno == EPERM);
+ 
+   /* - Check lseek() - */
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   for (i = 0; i < 1000; i++) {
+     offset     = (off_t) random();
+     ret_offset = lseek(fd, offset, SEEK_SET);
+ 
+     if (ret_offset != offset)
+       fprintf(stderr, "lseek() to position %d failed\n", offset);
+   }
+ 
+   close(fd);
+ 
+   /* - Check dup works - */
+ #ifdef DJGPP_SUPPORTS_FSEXT_DUP_NOW
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   new_fd = dup(fd);
+   if (new_fd < 0) {
+     fprintf(stderr,
+ 	    "Unable do dup file descriptor for %s: %s\n",
+ 	    DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   close(fd);
+ 
+   /* Zero buffer by reading from /dev/zero. */
+   n = read(new_fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to read %lu bytes from %s: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(((size_t) n) == sizeof(buf));
+ 
+   close(new_fd);
+ #endif /* DJGPP_SUPPORTS_FSEXT_DUP_NOW */
+ 
+   /* - Check fcntl() - */
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   new_fd = fcntl(fd, F_DUPFD);
+   if (new_fd < 0) {
+     fprintf(stderr, "F_DUPFD fcntl failed: %s\n", strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   /* Zero buffer by reading from /dev/zero. */
+   n = read(new_fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to read %lu bytes from %s: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(((size_t) n) == sizeof(buf));
+ 
+   /* Close old fd and check we can still read using new_fd. */
+   close(fd);
+ 
+   n = read(new_fd, buf, sizeof(buf));
+   if (n < 0) {
+     fprintf(stderr,
+ 	    "Unable to read %lu bytes from %s: %s\n",
+ 	    sizeof(buf), DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(((size_t) n) == sizeof(buf));
+ 
+   close(new_fd);
+ 
+   /* Now try other fcntls */
+   fd = open(DEV_ZERO_PATH, O_RDWR);
+   if (fd == -1) {
+     fprintf(stderr,
+ 	    "Unable to open %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   n = fcntl(fd, F_GETFD);
+   if (n < 0) {
+     fprintf(stderr, "F_GETFD fcntl failed: %s\n", strerror(errno));
+     return(EXIT_FAILURE);
+   }
+   printf("close-on-exec is %s\n", n ? "enabled" : "disabled");
+ 
+   n = fcntl(fd, F_SETFD, 1);
+   if (n != -1) {
+     fprintf(stderr, "F_SETFD succeeded - it should fail\n");
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(errno == ENOSYS);
+ 
+   n = fcntl(fd, F_GETFL);
+   printf("F_GETFL returns: 0x%x\n", n);
+ 
+   if (n & O_NONBLOCK) {
+     n = fcntl(fd, F_SETFL, n & ~O_NONBLOCK);
+   } else {
+     n = fcntl(fd, F_SETFL, n | O_NONBLOCK);
+   }
+  
+   if (n < 0) {
+     fprintf(stderr, "Failed to flip O_NONBLOCK using F_SETFL fcntl: %s\n",
+ 	    strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   /* Try a bogus fcntl */
+   n = fcntl(fd, 0xff);
+   if (n != -1) {
+     fprintf(stderr, "Bogus fcntl succeeded - it should fail\n");
+     return(EXIT_FAILURE);
+   }
+ 
+   assert(errno == ENOSYS);
+ 
+   close(fd);
+ 
+   /* - Check stat() works - */
+   if (stat(DEV_ZERO_PATH, &sbuf) < 0) {
+     fprintf(stderr,
+ 	    "Unable to stat() %s: %s\n", DEV_ZERO_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   printf("stat() result for %s:\n", DEV_ZERO_PATH);
+   dump_stat(&sbuf);
+   printf("\n");
+ 
+   if (stat(DEV_FULL_PATH, &sbuf) < 0) {
+     fprintf(stderr,
+ 	    "Unable to stat() %s: %s\n", DEV_FULL_PATH, strerror(errno));
+     return(EXIT_FAILURE);
+   }
+ 
+   printf("stat() result for %s:\n", DEV_FULL_PATH);
+   dump_stat(&sbuf);
+   printf("\n");
+ 
+   /* - Check fstat() works - */
+   test_fstat(DEV_ZERO_PATH);
+   test_fstat(DEV_FULL_PATH);
+ 
+   return(EXIT_SUCCESS);
+ }

- Raw text -


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