279 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			279 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			C++
		
	
	
	
| /* fhandler_virtual.cc: base fhandler class for virtual filesystems
 | |
| 
 | |
|    Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012,
 | |
|    2013 Red Hat, Inc.
 | |
| 
 | |
| This file is part of Cygwin.
 | |
| 
 | |
| This software is a copyrighted work licensed under the terms of the
 | |
| Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 | |
| details. */
 | |
| 
 | |
| #include "winsup.h"
 | |
| #include <sys/acl.h>
 | |
| #include <sys/statvfs.h>
 | |
| #include "cygerrno.h"
 | |
| #include "path.h"
 | |
| #include "fhandler.h"
 | |
| #include "dtable.h"
 | |
| #include "cygheap.h"
 | |
| #include "sync.h"
 | |
| #include "child_info.h"
 | |
| 
 | |
| #include <dirent.h>
 | |
| 
 | |
| fhandler_virtual::fhandler_virtual ():
 | |
|   fhandler_base (), filebuf (NULL), fileid (-1)
 | |
| {
 | |
| }
 | |
| 
 | |
| fhandler_virtual::~fhandler_virtual ()
 | |
| {
 | |
|   if (filebuf)
 | |
|     {
 | |
|       cfree (filebuf);
 | |
|       filebuf = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_virtual::fixup_after_exec ()
 | |
| {
 | |
| }
 | |
| 
 | |
| DIR *
 | |
| fhandler_virtual::opendir (int fd)
 | |
| {
 | |
|   DIR *dir;
 | |
|   DIR *res = NULL;
 | |
|   size_t len;
 | |
| 
 | |
|   if (exists () <= 0)
 | |
|     set_errno (ENOTDIR);
 | |
|   else if ((len = strlen (get_name ())) > PATH_MAX - 3)
 | |
|     set_errno (ENAMETOOLONG);
 | |
|   else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
 | |
|     set_errno (ENOMEM);
 | |
|   else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
 | |
|     {
 | |
|       free (dir);
 | |
|       set_errno (ENOMEM);
 | |
|     }
 | |
|   else if ((dir->__d_dirent =
 | |
|       (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
 | |
|     {
 | |
|       free (dir->__d_dirname);
 | |
|       free (dir);
 | |
|       set_errno (ENOMEM);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       strcpy (dir->__d_dirname, get_name ());
 | |
|       dir->__d_dirent->__d_version = __DIRENT_VERSION;
 | |
|       dir->__d_cookie = __DIRENT_COOKIE;
 | |
|       dir->__handle = INVALID_HANDLE_VALUE;
 | |
|       dir->__d_position = 0;
 | |
|       dir->__flags = 0;
 | |
| 
 | |
|       if (fd >= 0)
 | |
| 	{
 | |
| 	  dir->__d_fd = fd;
 | |
| 	  dir->__fh = this;
 | |
| 	  res = dir;
 | |
| 	}
 | |
|       else
 | |
| 	{
 | |
| 	  cygheap_fdnew cfd;
 | |
| 	  if (cfd >= 0 && open (O_RDONLY, 0))
 | |
| 	    {
 | |
| 	      cfd = this;
 | |
| 	      dir->__d_fd = cfd;
 | |
| 	      dir->__fh = this;
 | |
| 	      res = dir;
 | |
| 	    }
 | |
| 	}
 | |
|       close_on_exec (true);
 | |
|     }
 | |
| 
 | |
|   syscall_printf ("%p = opendir (%s)", res, get_name ());
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| long
 | |
| fhandler_virtual::telldir (DIR * dir)
 | |
| {
 | |
|   return dir->__d_position;
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_virtual::seekdir (DIR * dir, long loc)
 | |
| {
 | |
|   dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
 | |
|   dir->__d_position = loc;
 | |
| }
 | |
| 
 | |
| void
 | |
| fhandler_virtual::rewinddir (DIR * dir)
 | |
| {
 | |
|   dir->__d_position = 0;
 | |
|   dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_virtual::closedir (DIR * dir)
 | |
| {
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| off_t
 | |
| fhandler_virtual::lseek (off_t offset, int whence)
 | |
| {
 | |
|   /*
 | |
|    * On Linux, when you lseek within a /proc file,
 | |
|    * the contents of the file are updated.
 | |
|    */
 | |
|   if (!fill_filebuf ())
 | |
|     return (off_t) -1;
 | |
|   switch (whence)
 | |
|     {
 | |
|     case SEEK_SET:
 | |
|       position = offset;
 | |
|       break;
 | |
|     case SEEK_CUR:
 | |
|       position += offset;
 | |
|       break;
 | |
|     case SEEK_END:
 | |
|       position = filesize + offset;
 | |
|       break;
 | |
|     default:
 | |
|       set_errno (EINVAL);
 | |
|       return (off_t) -1;
 | |
|     }
 | |
|   return position;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_virtual::dup (fhandler_base * child, int flags)
 | |
| {
 | |
|   int ret = fhandler_base::dup (child, flags);
 | |
| 
 | |
|   if (!ret)
 | |
|     {
 | |
|       fhandler_virtual *fhproc_child = (fhandler_virtual *) child;
 | |
|       fhproc_child->filebuf = (char *) cmalloc_abort (HEAP_BUF, filesize);
 | |
|       memcpy (fhproc_child->filebuf, filebuf, filesize);
 | |
|     }
 | |
|   return ret;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_virtual::close ()
 | |
| {
 | |
|   if (!have_execed)
 | |
|     {
 | |
|       if (filebuf)
 | |
| 	{
 | |
| 	  cfree (filebuf);
 | |
| 	  filebuf = NULL;
 | |
| 	}
 | |
|     }
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| void __reg3
 | |
| fhandler_virtual::read (void *ptr, size_t& len)
 | |
| {
 | |
|   if (len == 0)
 | |
|     return;
 | |
|   if (openflags & O_DIROPEN)
 | |
|     {
 | |
|       set_errno (EISDIR);
 | |
|       len = (size_t) -1;
 | |
|       return;
 | |
|     }
 | |
|   if (!filebuf)
 | |
|     {
 | |
|       len = (size_t) 0;
 | |
|       return;
 | |
|     }
 | |
|   if ((ssize_t) len > filesize - position)
 | |
|     len = (size_t) (filesize - position);
 | |
|   if ((ssize_t) len < 0)
 | |
|     len = 0;
 | |
|   else
 | |
|     memcpy (ptr, filebuf + position, len);
 | |
|   position += len;
 | |
| }
 | |
| 
 | |
| ssize_t __stdcall
 | |
| fhandler_virtual::write (const void *ptr, size_t len)
 | |
| {
 | |
|   set_errno (EACCES);
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| /* low-level open for all proc files */
 | |
| int
 | |
| fhandler_virtual::open (int flags, mode_t mode)
 | |
| {
 | |
|   rbinary (true);
 | |
|   wbinary (true);
 | |
| 
 | |
|   set_flags ((flags & ~O_TEXT) | O_BINARY);
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| virtual_ftype_t
 | |
| fhandler_virtual::exists ()
 | |
| {
 | |
|   return virt_none;
 | |
| }
 | |
| 
 | |
| bool
 | |
| fhandler_virtual::fill_filebuf ()
 | |
| {
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_virtual::fchmod (mode_t mode)
 | |
| {
 | |
|   /* Same as on Linux. */
 | |
|   set_errno (EPERM);
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_virtual::fchown (uid_t uid, gid_t gid)
 | |
| {
 | |
|   /* Same as on Linux. */
 | |
|   set_errno (EPERM);
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| int
 | |
| fhandler_virtual::facl (int cmd, int nentries, aclent_t *aclbufp)
 | |
| {
 | |
|   int res = fhandler_base::facl (cmd, nentries, aclbufp);
 | |
|   if (res >= 0 && cmd == GETACL)
 | |
|     {
 | |
|       aclbufp[0].a_perm = (S_IRUSR | (pc.isdir () ? S_IXUSR : 0)) >> 6;
 | |
|       aclbufp[1].a_perm = (S_IRGRP | (pc.isdir () ? S_IXGRP : 0)) >> 3;
 | |
|       aclbufp[2].a_perm = S_IROTH | (pc.isdir () ? S_IXOTH : 0);
 | |
|     }
 | |
|   return res;
 | |
| }
 | |
| 
 | |
| int __reg2
 | |
| fhandler_virtual::fstatvfs (struct statvfs *sfs)
 | |
| {
 | |
|   /* Virtual file system.  Just return an empty buffer with a few values
 | |
|      set to something useful.  Just as on Linux. */
 | |
|   memset (sfs, 0, sizeof (*sfs));
 | |
|   sfs->f_bsize = sfs->f_frsize = 4096;
 | |
|   sfs->f_flag = ST_RDONLY;
 | |
|   sfs->f_namemax = NAME_MAX;
 | |
|   return 0;
 | |
| }
 |