diff options
Diffstat (limited to 'winsup/cygwin/fhandler/virtual.cc')
-rw-r--r-- | winsup/cygwin/fhandler/virtual.cc | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/winsup/cygwin/fhandler/virtual.cc b/winsup/cygwin/fhandler/virtual.cc new file mode 100644 index 000000000..21ff4f35e --- /dev/null +++ b/winsup/cygwin/fhandler/virtual.cc @@ -0,0 +1,275 @@ +/* fhandler_virtual.cc: base fhandler class for virtual filesystems + +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 <cygwin/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 (!virt_ftype_isdir (exists ())) + 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 +fhandler_virtual::read (void *ptr, size_t& len) +{ + if (len == 0) + return; + if (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 +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 +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; +} |