/* 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 #include #include "cygerrno.h" #include "path.h" #include "fhandler.h" #include "dtable.h" #include "cygheap.h" #include "sync.h" #include "child_info.h" #include 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; }