diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2022-08-04 17:58:50 +0300 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2022-08-05 13:02:11 +0300 |
commit | 007e23d6390af11582e55453269b7a51c723d2dd (patch) | |
tree | 8e8cff3ca23f5e56d9766a5ee6c6abb366611b07 /winsup/cygwin/local_includes/fhandler.h | |
parent | 1e428bee1c5ef7c76ba4e46e6693b913edc9bbf3 (diff) |
Cygwin: Reorganize cygwin source dir
Create subdirs and move files accordingly:
- DevDocs: doc files
- fhandler: fhandler sources, split fhandler.cc into base.cc and null.cc
- local_includes: local include files
- scripts: scripts called during build
- sec: security sources
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
Diffstat (limited to 'winsup/cygwin/local_includes/fhandler.h')
-rw-r--r-- | winsup/cygwin/local_includes/fhandler.h | 3335 |
1 files changed, 3335 insertions, 0 deletions
diff --git a/winsup/cygwin/local_includes/fhandler.h b/winsup/cygwin/local_includes/fhandler.h new file mode 100644 index 000000000..aad7f4c37 --- /dev/null +++ b/winsup/cygwin/local_includes/fhandler.h @@ -0,0 +1,3335 @@ +/* fhandler.h + +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. */ + +#pragma once +#include "pinfo.h" + +#include "tty.h" +#include "mqueue_types.h" +#include <cygwin/_socketflags.h> +#include <cygwin/_ucred.h> +#include <sys/un.h> + +/* It appears that 64K is the block size used for buffered I/O on NT. + Using this blocksize in read/write calls in the application results + in a much better performance than using smaller values. */ +#define PREFERRED_IO_BLKSIZE ((blksize_t) 65536) + +/* It also appears that this may be the only acceptable block size for + atomic writes to a pipe. It is a shame that we have to make this + so small. http://cygwin.com/ml/cygwin/2011-03/msg00541.html */ +#define DEFAULT_PIPEBUFSIZE PREFERRED_IO_BLKSIZE + +/* Used for fhandler_pipe::create. Use an available flag which will + never be used in Cygwin for this function. */ +#define PIPE_ADD_PID FILE_FLAG_FIRST_PIPE_INSTANCE + +#define O_TMPFILE_FILE_ATTRS (FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_HIDDEN) + +/* Buffer size for ReadConsoleInput() and PeekConsoleInput(). */ +/* Per MSDN, max size of buffer required is below 64K. */ +/* (65536 / sizeof (INPUT_RECORD)) is 3276, however, + ERROR_NOT_ENOUGH_MEMORY occurs in win7 if this value is used. */ +#define INREC_SIZE 2048 + +extern const char *windows_device_names[]; +extern struct __cygwin_perfile *perfile_table; +#define __fmode (*(user_data->fmode_ptr)) +extern const char proc[]; +extern const size_t proc_len; +extern const char procsys[]; +extern const size_t procsys_len; + +class select_record; +class select_stuff; +class fhandler_disk_file; +class inode_t; +typedef struct __DIR DIR; +struct dirent; +struct iovec; +struct acl; +struct __acl_t; + +enum dirent_states +{ + dirent_ok = 0x0000, + dirent_saw_dot = 0x0001, + dirent_saw_dot_dot = 0x0002, + dirent_saw_eof = 0x0004, + dirent_isroot = 0x0008, + dirent_set_d_ino = 0x0010, + dirent_get_d_ino = 0x0020, + dirent_nfs_d_ino = 0x0040, + + /* Global flags which must not be deleted on rewinddir or seekdir. */ + dirent_info_mask = 0x0078 +}; + +enum bind_state +{ + unbound = 0, + bind_pending = 1, + bound = 2 +}; + +enum conn_state +{ + unconnected = 0, + connect_pending = 1, + connected = 2, + listener = 3, + connect_failed = 4 /* FIXME: Do we really need this? It's basically + the same thing as unconnected. */ +}; + +enum line_edit_status +{ + line_edit_ok = 0, + line_edit_input_done = 1, + line_edit_signalled = 2, + line_edit_error = 3, + line_edit_pipe_full = 4 +}; + +enum bg_check_types +{ + bg_error = -1, + bg_eof = 0, + bg_ok = 1, + bg_signalled = 2 +}; + +enum query_state { + no_query = 0, + query_read_control = 1, + query_read_attributes = 2, + query_write_control = 3, + query_write_dac = 4, + query_write_attributes = 5 +}; + +enum del_lock_called_from { + on_close, + after_fork, + after_exec +}; + +enum virtual_ftype_t { + virt_none = 0x0000, /* Invalid, Error */ + virt_file = 0x0001, /* Regular file */ + virt_symlink = 0x0002, /* Symlink */ + virt_pipe = 0x0003, /* Pipe */ + virt_socket = 0x0004, /* Socket */ + virt_chr = 0x0005, /* Character special */ + virt_blk = 0x0006, /* Block special */ + virt_fdsymlink = 0x0007, /* Fd symlink (e.g. /proc/<PID>/fd/0) */ + virt_fsfile = 0x0008, /* FS-based file via /proc/sys */ + virt_dir_type = 0x1000, + virt_directory = 0x1001, /* Directory */ + virt_rootdir = 0x1002, /* Root directory of virtual FS */ + virt_fsdir = 0x1003, /* FS-based directory via /proc/sys */ +}; + +static inline bool +virt_ftype_isfile (virtual_ftype_t _f) +{ + return _f != virt_none && !(_f & virt_dir_type); +} + +static inline bool +virt_ftype_isdir (virtual_ftype_t _f) +{ + return _f & virt_dir_type; +} + +class fhandler_base +{ + friend class dtable; + friend void close_all_files (bool); + + struct status_flags + { + unsigned rbinary : 1; /* binary read mode */ + unsigned rbinset : 1; /* binary read mode explicitly set */ + unsigned wbinary : 1; /* binary write mode */ + unsigned wbinset : 1; /* binary write mode explicitly set */ + unsigned nohandle : 1; /* No handle associated with fhandler. */ + unsigned did_lseek : 1; /* set when lseek is called as a flag that + _write should check if we've moved + beyond EOF, zero filling or making + file sparse if so. */ + unsigned query_open : 3; /* open file without requesting either + read or write access */ + unsigned close_on_exec : 1; /* close-on-exec */ + unsigned need_fork_fixup : 1; /* Set if need to fixup after fork. */ + unsigned isclosed : 1; /* Set when fhandler is closed. */ + unsigned mandatory_locking : 1; /* Windows mandatory locking */ + + public: + status_flags () : + rbinary (0), rbinset (0), wbinary (0), wbinset (0), nohandle (0), + did_lseek (0), query_open (no_query), close_on_exec (0), + need_fork_fixup (0), isclosed (0), mandatory_locking (0) + {} + } status, open_status; + + private: + ACCESS_MASK access; + ULONG options; + + HANDLE io_handle; + + ino_t ino; /* file ID or hashed filename, depends on FS. */ + LONG _refcnt; + public: + struct rabuf_t + { + char *rabuf; /* used for crlf conversion in text files */ + size_t ralen; + size_t raixget; + size_t raixput; + size_t rabuflen; + }; + + protected: + /* File open flags from open () and fcntl () calls */ + int openflags; + + struct rabuf_t ra; + + /* Used for advisory file locking. See flock.cc. */ + int64_t unique_id; + void del_my_locks (del_lock_called_from); + void set_ino (ino_t i) { ino = i; } + + HANDLE read_state; + HANDLE select_sem; + + public: + LONG inc_refcnt () {return InterlockedIncrement (&_refcnt);} + LONG dec_refcnt () {return InterlockedDecrement (&_refcnt);} + class fhandler_base *archetype; + int usecount; + + path_conv pc; + + virtual bool use_archetype () const {return false;} + virtual void set_name (path_conv &pc); + virtual void set_name (const char *s) + { + pc.set_posix (s); + pc.set_path (s); + } + int error () const {return pc.error;} + void set_error (int error) {pc.error = error;} + bool exists () const {return pc.exists ();} + int pc_binmode () const {return pc.binmode ();} + device& dev () {return pc.dev;} + operator DWORD& () {return (DWORD&) pc;} + fhandler_base (); + virtual ~fhandler_base (); + + /* Non-virtual simple accessor functions. */ + void set_handle (HANDLE x) { io_handle = x; } + + dev_t& get_device () { return dev (); } + _major_t get_major () { return dev ().get_major (); } + _minor_t get_minor () { return dev ().get_minor (); } + + ACCESS_MASK get_access () const { return access; } + void set_access (ACCESS_MASK x) { access = x; } + + ULONG get_options () const { return options; } + void set_options (ULONG x) { options = x; } + + int get_flags () { return openflags; } + void set_flags (int x, int supplied_bin = 0); + + bool is_nonblocking (); + void set_nonblocking (int); + + bool wbinary () const { return status.wbinset ? status.wbinary : 1; } + bool rbinary () const { return status.rbinset ? status.rbinary : 1; } + + void wbinary (bool b) {status.wbinary = b; status.wbinset = 1;} + void rbinary (bool b) {status.rbinary = b; status.rbinset = 1;} + + void set_open_status () {open_status = status;} + void reset_to_open_binmode () + { + set_flags ((get_flags () & ~(O_TEXT | O_BINARY)) + | (((open_status.wbinset ? open_status.wbinary : 1) + || (open_status.rbinset ? open_status.rbinary : 1)) + ? O_BINARY : O_TEXT)); + } + + IMPLEMENT_STATUS_FLAG (bool, wbinset) + IMPLEMENT_STATUS_FLAG (bool, rbinset) + IMPLEMENT_STATUS_FLAG (bool, nohandle) + IMPLEMENT_STATUS_FLAG (bool, did_lseek) + IMPLEMENT_STATUS_FLAG (query_state, query_open) + IMPLEMENT_STATUS_FLAG (bool, close_on_exec) + IMPLEMENT_STATUS_FLAG (bool, need_fork_fixup) + IMPLEMENT_STATUS_FLAG (bool, isclosed) + IMPLEMENT_STATUS_FLAG (bool, mandatory_locking) + + int get_default_fmode (int flags); + + virtual void set_close_on_exec (bool val); + + LPSECURITY_ATTRIBUTES get_inheritance (bool all = 0) + { + if (all) + return close_on_exec () ? &sec_all_nih : &sec_all; + else + return close_on_exec () ? &sec_none_nih : &sec_none; + } + + virtual int fixup_before_fork_exec (DWORD) { return 0; } + virtual void fixup_after_fork (HANDLE); + virtual void fixup_after_exec (); + void create_read_state (LONG n) + { + read_state = CreateSemaphore (&sec_none_nih, 0, n, NULL); + ProtectHandle (read_state); + } + + void signal_read_state (LONG n) + { + ReleaseSemaphore (read_state, n, NULL); + } + + virtual char *&rabuf () { return ra.rabuf; }; + virtual size_t &ralen () { return ra.ralen; }; + virtual size_t &raixget () { return ra.raixget; }; + virtual size_t &raixput () { return ra.raixput; }; + virtual size_t &rabuflen () { return ra.rabuflen; }; + + bool get_readahead_valid () { return raixget () < ralen (); } + int puts_readahead (const char *s, size_t len = (size_t) -1); + int put_readahead (char value); + + int get_readahead (); + int peek_readahead (int queryput = 0); + + void set_readahead_valid (int val, int ch = -1); + + int get_readahead_into_buffer (char *buf, size_t buflen); + + bool has_acls () const { return pc.has_acls (); } + + bool isremote () { return pc.isremote (); } + + bool has_attribute (DWORD x) const {return pc.has_attribute (x);} + const char *get_name () const { return pc.get_posix (); } + const char *get_win32_name () { return pc.get_win32 (); } + virtual dev_t get_dev () { return get_device (); } + /* Use get_plain_ino if the caller needs to avoid hashing if ino is 0. */ + ino_t get_plain_ino () { return ino; } + ino_t get_ino () { return ino ?: ino = hash_path_name (0, pc.get_nt_native_path ()); } + int64_t get_unique_id () const { return unique_id; } + /* Returns name used for /proc/<pid>/fd in buf. */ + virtual char *get_proc_fd_name (char *buf); + + virtual void set_no_inheritance (HANDLE &, bool); + + /* fixup fd possibly non-inherited handles after fork */ + bool fork_fixup (HANDLE, HANDLE &, const char *); + virtual bool need_fixup_before () const {return false;} + + int open_with_arch (int, mode_t = 0); + int open_null (int flags); + virtual int open (int, mode_t); + virtual fhandler_base *fd_reopen (int, mode_t); + virtual bool open_setup (int flags); + virtual void post_open_setup (int fd) {} + void set_unique_id (int64_t u) { unique_id = u; } + void set_unique_id () { NtAllocateLocallyUniqueId ((PLUID) &unique_id); } + + int close_with_arch (); + virtual int close (); + virtual void cleanup (); + int _archetype_usecount (const char *fn, int ln, int n) + { + if (!archetype) + return 0; + archetype->usecount += n; + if (strace.active ()) + strace.prntf (_STRACE_ALL, fn, "line %d: %s<%p> usecount + %d = %d", ln, get_name (), archetype, n, archetype->usecount); + return archetype->usecount; + } + + int open_fs (int, mode_t = 0); +# define archetype_usecount(n) _archetype_usecount (__PRETTY_FUNCTION__, __LINE__, (n)) + int close_fs () { return fhandler_base::close (); } + virtual int fstat (struct stat *buf); + void stat_fixup (struct stat *buf); + int fstat_fs (struct stat *buf); +private: + int fstat_helper (struct stat *buf); + int fstat_by_nfs_ea (struct stat *buf); + int fstat_by_handle (struct stat *buf); + int fstat_by_name (struct stat *buf); +public: + virtual int fstatvfs (struct statvfs *buf); + int fstatvfs_by_handle (HANDLE h, struct statvfs *buf); + int utimens_fs (const struct timespec *); + virtual int fchmod (mode_t mode); + virtual int fchown (uid_t uid, gid_t gid); + virtual int facl (int, int, struct acl *); + virtual struct __acl_t *acl_get (uint32_t); + virtual int acl_set (struct __acl_t *, uint32_t); + virtual ssize_t fgetxattr (const char *, void *, size_t); + virtual int fsetxattr (const char *, const void *, size_t, int); + virtual int fadvise (off_t, off_t, int); + virtual int ftruncate (off_t, bool); + virtual int link (const char *); + virtual int utimens (const struct timespec *); + virtual int fsync (); + virtual int ioctl (unsigned int cmd, void *); + virtual int fcntl (int cmd, intptr_t); + virtual char const *ttyname () { return get_name (); } + virtual void read (void *ptr, size_t& len); + virtual ssize_t write (const void *ptr, size_t len); + virtual ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1); + virtual ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1); + virtual ssize_t pread (void *, size_t, off_t, void *aio = NULL); + virtual ssize_t pwrite (void *, size_t, off_t, void *aio = NULL); + virtual off_t lseek (off_t offset, int whence); + virtual int lock (int, struct flock *); + virtual int mand_lock (int, struct flock *); + virtual int dup (fhandler_base *child, int flags); + virtual int fpathconf (int); + + /* Get a handle to the named pipe file system directory. Used by + fhandler_pipe, fhandler_fifo, and fhandler_socket_unix. */ + static NTSTATUS npfs_handle (HANDLE &); + + virtual HANDLE mmap (caddr_t *addr, size_t len, int prot, + int flags, off_t off); + virtual int munmap (HANDLE h, caddr_t addr, size_t len); + virtual int msync (HANDLE h, caddr_t addr, size_t len, int flags); + virtual bool fixup_mmap_after_fork (HANDLE h, int prot, int flags, + off_t offset, SIZE_T size, + void *address); + + void *operator new (size_t, void *p) __attribute__ ((nothrow)) {return p;} + + virtual int init (HANDLE, DWORD, mode_t); + + virtual int tcflush (int); + virtual int tcsendbreak (int); + virtual int tcdrain (); + virtual int tcflow (int); + virtual int tcsetattr (int a, const struct termios *t); + virtual int tcgetattr (struct termios *t); + virtual int tcsetpgrp (const pid_t pid); + virtual int tcgetpgrp (); + virtual pid_t tcgetsid (); + virtual bool is_tty () const { return false; } + virtual bool ispipe () const { return false; } + virtual pid_t get_popen_pid () const {return 0;} + virtual bool isfifo () const { return false; } + virtual int ptsname_r (char *, size_t); + virtual class fhandler_socket *is_socket () { return NULL; } + virtual class fhandler_socket_wsock *is_wsock_socket () { return NULL; } + virtual class fhandler_console *is_console () { return 0; } + virtual class fhandler_signalfd *is_signalfd () { return NULL; } + virtual class fhandler_timerfd *is_timerfd () { return NULL; } + virtual class fhandler_mqueue *is_mqueue () { return NULL; } + virtual int is_windows () {return 0; } + + virtual void raw_read (void *ptr, size_t& ulen); + virtual ssize_t raw_write (const void *ptr, size_t ulen); + + /* Virtual accessor functions to hide the fact + that some fd's have two handles. */ + virtual HANDLE& get_handle () { return io_handle; } + virtual HANDLE& get_handle_nat () { return io_handle; } + virtual HANDLE& get_output_handle () { return io_handle; } + virtual HANDLE& get_output_handle_nat () { return io_handle; } + virtual HANDLE get_stat_handle () { return pc.handle () ?: io_handle; } + virtual HANDLE get_echo_handle () const { return NULL; } + virtual bool hit_eof () {return false;} + virtual select_record *select_read (select_stuff *); + virtual select_record *select_write (select_stuff *); + virtual select_record *select_except (select_stuff *); + virtual const char *get_native_name () + { + return dev ().native (); + } + virtual bg_check_types bg_check (int, bool = false) {return bg_ok;} + virtual void clear_readahead () + { + raixput () = raixget () = ralen () = rabuflen () = 0; + rabuf () = NULL; + } + void operator delete (void *p) {cfree (p);} + virtual void set_eof () {} + virtual int mkdir (mode_t mode); + virtual int rmdir (); + virtual DIR *opendir (int fd); + virtual int readdir (DIR *, dirent *); + virtual long telldir (DIR *); + virtual void seekdir (DIR *, long); + virtual void rewinddir (DIR *); + virtual int closedir (DIR *); + bool is_fs_special () {return pc.is_fs_special ();} + bool issymlink () {return pc.issymlink ();} + bool device_access_denied (int); + int fhaccess (int flags, bool); + + fhandler_base (void *) {} + + protected: + void _copy_from_reset_helper () + { + ra.rabuf = NULL; + ra.ralen = 0; + ra.raixget = 0; + ra.raixput = 0; + ra.rabuflen = 0; + _refcnt = 0; + } + + public: + virtual void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_base *> (x); + _copy_from_reset_helper (); + } + + virtual fhandler_base *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_base)); + fhandler_base *fh = new (ptr) fhandler_base (ptr); + fh->copy_from (this); + return fh; + } + + HANDLE get_select_sem () { return select_sem; } +}; + +struct wsa_event +{ + LONG serial_number; + long events; + int connect_errorcode; + pid_t owner; +}; + +class fhandler_socket: public fhandler_base +{ + private: + /* permission fake following Linux rules */ + uid_t uid; + uid_t gid; + mode_t mode; + + protected: + int addr_family; + int type; + inline int get_socket_flags () + { + int ret = 0; + if (is_nonblocking ()) + ret |= SOCK_NONBLOCK; + if (close_on_exec ()) + ret |= SOCK_CLOEXEC; + return ret; + } + + protected: + int _rmem; + int _wmem; + public: + int &rmem () { return _rmem; } + int &wmem () { return _wmem; } + void rmem (int nrmem) { _rmem = nrmem; } + void wmem (int nwmem) { _wmem = nwmem; } + + protected: + DWORD _rcvtimeo; /* msecs */ + DWORD _sndtimeo; /* msecs */ + public: + DWORD &rcvtimeo () { return _rcvtimeo; } + DWORD &sndtimeo () { return _sndtimeo; } + + public: + fhandler_socket (); + ~fhandler_socket (); + fhandler_socket *is_socket () { return this; } + + char *get_proc_fd_name (char *buf); + + virtual int socket (int af, int type, int protocol, int flags) = 0; + virtual int socketpair (int af, int type, int protocol, int flags, + fhandler_socket *fh_out) = 0; + virtual int bind (const struct sockaddr *name, int namelen) = 0; + virtual int listen (int backlog) = 0; + virtual int accept4 (struct sockaddr *peer, int *len, int flags) = 0; + virtual int connect (const struct sockaddr *name, int namelen) = 0; + virtual int getsockname (struct sockaddr *name, int *namelen) = 0; + virtual int getpeername (struct sockaddr *name, int *namelen) = 0; + virtual int shutdown (int how) = 0; + virtual int close () = 0; + virtual int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid); + virtual ssize_t recvfrom (void *ptr, size_t len, int flags, + struct sockaddr *from, int *fromlen) = 0; + virtual ssize_t recvmsg (struct msghdr *msg, int flags) = 0; + virtual void read (void *ptr, size_t& len) = 0; + virtual ssize_t readv (const struct iovec *, int iovcnt, + ssize_t tot = -1) = 0; + + virtual ssize_t sendto (const void *ptr, size_t len, int flags, + const struct sockaddr *to, int tolen) = 0; + virtual ssize_t sendmsg (const struct msghdr *msg, int flags) = 0; + virtual ssize_t write (const void *ptr, size_t len) = 0; + virtual ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1) = 0; + virtual int setsockopt (int level, int optname, const void *optval, + __socklen_t optlen) = 0; + virtual int getsockopt (int level, int optname, const void *optval, + __socklen_t *optlen) = 0; + + virtual int ioctl (unsigned int cmd, void *); + virtual int fcntl (int cmd, intptr_t); + + int open (int flags, mode_t mode = 0); + int fstat (struct stat *buf); + int fstatvfs (struct statvfs *buf); + int fchmod (mode_t newmode); + int fchown (uid_t newuid, gid_t newgid); + int facl (int, int, struct acl *); + int link (const char *); + off_t lseek (off_t, int) + { + set_errno (ESPIPE); + return -1; + } + + void set_addr_family (int af) {addr_family = af;} + int get_addr_family () {return addr_family;} + virtual void set_socket_type (int st) { type = st;} + virtual int get_socket_type () {return type;} + + /* select.cc */ + virtual select_record *select_read (select_stuff *) = 0; + virtual select_record *select_write (select_stuff *) = 0; + virtual select_record *select_except (select_stuff *) = 0; +}; + +/* Encapsulate wsock-based socket classes fhandler_socket_inet and + fhandler_socket_local during development of fhandler_socket_unix. + TODO: Perhaps we should keep it that way, under the assumption that + the Windows 10 AF_UNIX class will eventually get useful at one point. */ +class fhandler_socket_wsock: public fhandler_socket +{ + protected: + virtual int af_local_connect () = 0; + + protected: + wsa_event *wsock_events; + HANDLE wsock_mtx; + HANDLE wsock_evt; + bool init_events (); + int wait_for_events (const long event_mask, const DWORD flags); + void release_events (); + public: + const HANDLE wsock_event () const { return wsock_evt; } + int evaluate_events (const long event_mask, long &events, const bool erase); + const LONG serial_number () const { return wsock_events->serial_number; } + + protected: + struct status_flags + { + unsigned async_io : 1; /* async I/O */ + unsigned saw_shutdown_read : 1; /* Socket saw a SHUT_RD */ + unsigned saw_shutdown_write : 1; /* Socket saw a SHUT_WR */ + unsigned saw_reuseaddr : 1; /* Socket saw SO_REUSEADDR call */ + unsigned connect_state : 3; + public: + status_flags () : + async_io (0), saw_shutdown_read (0), saw_shutdown_write (0), + saw_reuseaddr (0), connect_state (unconnected) + {} + } status; + public: + IMPLEMENT_STATUS_FLAG (bool, async_io) + IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_read) + IMPLEMENT_STATUS_FLAG (bool, saw_shutdown_write) + IMPLEMENT_STATUS_FLAG (bool, saw_reuseaddr) + IMPLEMENT_STATUS_FLAG (conn_state, connect_state) + + protected: + struct _WSAPROTOCOL_INFOW *prot_info_ptr; + public: + bool need_fixup_before () const {return prot_info_ptr != NULL;} + void set_close_on_exec (bool val); + void init_fixup_before (); + int fixup_before_fork_exec (DWORD); + void fixup_after_fork (HANDLE); + void fixup_after_exec (); + int dup (fhandler_base *child, int); + +#ifdef __INSIDE_CYGWIN_NET__ + protected: + int set_socket_handle (SOCKET sock, int af, int type, int flags); + public: + /* Originally get_socket returned an int, which is not a good idea + to cast a handle to on 64 bit. The right type here is very certainly + SOCKET instead. On the other hand, we don't want to have to include + winsock.h just to build fhandler.h. Therefore we define get_socket + now only when building network related code. */ + SOCKET get_socket () { return (SOCKET) get_handle(); } +#endif + + protected: + virtual ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg) = 0; + ssize_t send_internal (struct _WSAMSG *wsamsg, int flags); + + public: + fhandler_socket_wsock (); + ~fhandler_socket_wsock (); + + fhandler_socket_wsock *is_wsock_socket () { return this; } + + ssize_t recvfrom (void *ptr, size_t len, int flags, + struct sockaddr *from, int *fromlen); + ssize_t recvmsg (struct msghdr *msg, int flags); + void read (void *ptr, size_t& len); + ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1); + ssize_t write (const void *ptr, size_t len); + ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1); + int shutdown (int how); + int close (); + + int ioctl (unsigned int cmd, void *); + int fcntl (int cmd, intptr_t); + + /* select.cc */ + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); +}; + +class fhandler_socket_inet: public fhandler_socket_wsock +{ + private: + bool oobinline; /* True if option SO_OOBINLINE is set */ + bool tcp_quickack; /* True if quickack is enabled */ + bool tcp_fastopen; /* True if TCP_FASTOPEN is set on older systems */ + int tcp_keepidle; /* TCP_KEEPIDLE value in secs on older systems */ + int tcp_keepcnt; /* TCP_KEEPCNT value on older systems */ + int tcp_keepintvl; /* TCP_KEEPINTVL value in secs on older systems */ + + int set_keepalive (int keepidle, int keepcnt, int keepintvl); + protected: + int af_local_connect () { return 0; } + + protected: + ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg); + + public: + fhandler_socket_inet (); + ~fhandler_socket_inet (); + + int socket (int af, int type, int protocol, int flags); + int socketpair (int af, int type, int protocol, int flags, + fhandler_socket *fh_out); + int bind (const struct sockaddr *name, int namelen); + int listen (int backlog); + int accept4 (struct sockaddr *peer, int *len, int flags); + int connect (const struct sockaddr *name, int namelen); + int getsockname (struct sockaddr *name, int *namelen); + int getpeername (struct sockaddr *name, int *namelen); + ssize_t sendto (const void *ptr, size_t len, int flags, + const struct sockaddr *to, int tolen); + ssize_t sendmsg (const struct msghdr *msg, int flags); + int setsockopt (int level, int optname, const void *optval, + __socklen_t optlen); + int getsockopt (int level, int optname, const void *optval, + __socklen_t *optlen); + + /* from here on: CLONING */ + fhandler_socket_inet (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_socket_inet *> (x); + _copy_from_reset_helper (); + } + + fhandler_socket_inet *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_socket_inet)); + fhandler_socket_inet *fh = new (ptr) fhandler_socket_inet (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_socket_local: public fhandler_socket_wsock +{ + protected: + char *sun_path; + char *peer_sun_path; + void set_sun_path (const char *path); + char *get_sun_path () {return sun_path;} + void set_peer_sun_path (const char *path); + char *get_peer_sun_path () {return peer_sun_path;} + + protected: + int connect_secret[4]; + pid_t sec_pid; + uid_t sec_uid; + gid_t sec_gid; + pid_t sec_peer_pid; + uid_t sec_peer_uid; + gid_t sec_peer_gid; + void af_local_set_secret (char *); + void af_local_setblocking (bool &, bool &); + void af_local_unsetblocking (bool, bool); + void af_local_set_cred (); + void af_local_copy (fhandler_socket_local *); + bool af_local_recv_secret (); + bool af_local_send_secret (); + bool af_local_recv_cred (); + bool af_local_send_cred (); + int af_local_accept (); + int af_local_connect (); + int af_local_set_no_getpeereid (); + void af_local_set_sockpair_cred (); + + protected: + ssize_t recv_internal (struct _WSAMSG *wsamsg, bool use_recvmsg); + + protected: + struct status_flags + { + unsigned no_getpeereid : 1; + public: + status_flags () : no_getpeereid (0) {} + } status; + public: + IMPLEMENT_STATUS_FLAG (bool, no_getpeereid) + + public: + fhandler_socket_local (); + ~fhandler_socket_local (); + + int dup (fhandler_base *child, int); + + int socket (int af, int type, int protocol, int flags); + int socketpair (int af, int type, int protocol, int flags, + fhandler_socket *fh_out); + int bind (const struct sockaddr *name, int namelen); + int listen (int backlog); + int accept4 (struct sockaddr *peer, int *len, int flags); + int connect (const struct sockaddr *name, int namelen); + int getsockname (struct sockaddr *name, int *namelen); + int getpeername (struct sockaddr *name, int *namelen); + int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid); + ssize_t sendto (const void *ptr, size_t len, int flags, + const struct sockaddr *to, int tolen); + ssize_t sendmsg (const struct msghdr *msg, int flags); + int setsockopt (int level, int optname, const void *optval, + __socklen_t optlen); + int getsockopt (int level, int optname, const void *optval, + __socklen_t *optlen); + + int open (int flags, mode_t mode = 0); + int close (); + int fcntl (int cmd, intptr_t); + int fstat (struct stat *buf); + int fstatvfs (struct statvfs *buf); + int fchmod (mode_t newmode); + int fchown (uid_t newuid, gid_t newgid); + int facl (int, int, struct acl *); + struct __acl_t *acl_get (uint32_t); + int acl_set (struct __acl_t *, uint32_t); + int link (const char *); + + /* from here on: CLONING */ + fhandler_socket_local (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_socket_local *> (x); + _copy_from_reset_helper (); + } + + fhandler_socket_local *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_socket_local)); + fhandler_socket_local *fh = new (ptr) fhandler_socket_local (ptr); + fh->copy_from (this); + return fh; + } +}; + +/* Sharable spinlock with low CPU profile. These locks are NOT recursive! */ +class af_unix_spinlock_t +{ + LONG locked; /* 0 or 1 */ + +public: + af_unix_spinlock_t () : locked (0) {} + void lock () + { + LONG ret = InterlockedExchange (&locked, 1); + if (ret) + { + /* This loop counts the ms Sleep up from 0 to 45 in loop, 15ms steps, + with 256 iterations each, . */ + for (uint16_t i = 0; ret; i += 64) + { + Sleep (15 * (i >> 14)); + ret = InterlockedExchange (&locked, 1); + } + } + } + void unlock () + { + InterlockedExchange (&locked, 0); + } +}; + +/* Internal representation of shutdown states */ +enum shut_state { + _SHUT_NONE = 0, + _SHUT_RECV = 1, + _SHUT_SEND = 2, + _SHUT_MASK = 3 +}; + +class sun_name_t +{ + public: + __socklen_t un_len; + union + { + struct sockaddr_un un; + /* Allows 108 bytes sun_path plus trailing NUL */ + char _nul[sizeof (struct sockaddr_un) + 1]; + }; + sun_name_t () { set (NULL, 0); } + sun_name_t (const struct sockaddr *name, __socklen_t namelen) + { set ((const struct sockaddr_un *) name, namelen); } + void set (const struct sockaddr_un *name, __socklen_t namelen); +}; + +/* For each AF_UNIX socket, we need to maintain socket-wide data, + regardless of the number of descriptors. The shmem region gets created + in socket, socketpair or accept4 and reopened by dup, fork or exec. */ +class af_unix_shmem_t +{ + /* Don't use SRWLOCKs here. They are not sharable. If you must lock + multiple locks at the same time, always lock in the order bind -> + conn -> state -> io and unlock io -> state -> conn -> bind to avoid + deadlocks. */ + af_unix_spinlock_t _bind_lock; + af_unix_spinlock_t _conn_lock; + af_unix_spinlock_t _state_lock; + af_unix_spinlock_t _io_lock; + LONG _connection_state; /* conn_state */ + LONG _binding_state; /* bind_state */ + LONG _shutdown; /* shut_state */ + LONG _so_error; /* SO_ERROR */ + LONG _so_passcred; /* SO_PASSCRED */ + LONG _reuseaddr; /* dummy */ + int _type; /* socket type */ + sun_name_t _sun_path; + sun_name_t _peer_sun_path; + struct ucred _sock_cred; /* filled at listen time */ + struct ucred _peer_cred; /* filled at connect time */ + + public: + void bind_lock () { _bind_lock.lock (); } + void bind_unlock () { _bind_lock.unlock (); } + void conn_lock () { _conn_lock.lock (); } + void conn_unlock () { _conn_lock.unlock (); } + void state_lock () { _state_lock.lock (); } + void state_unlock () { _state_lock.unlock (); } + void io_lock () { _io_lock.lock (); } + void io_unlock () { _io_lock.unlock (); } + + conn_state connect_state (conn_state val) + { return (conn_state) InterlockedExchange (&_connection_state, val); } + conn_state connect_state () const { return (conn_state) _connection_state; } + + bind_state binding_state (bind_state val) + { return (bind_state) InterlockedExchange (&_binding_state, val); } + bind_state binding_state () const { return (bind_state) _binding_state; } + + int shutdown (int shut) + { return (int) InterlockedExchange (&_shutdown, shut); } + int shutdown () const { return (int) _shutdown; } + + int so_error (int err) { return (int) InterlockedExchange (&_so_error, err); } + int so_error () const { return _so_error; } + + bool so_passcred (bool pc) + { return (bool) InterlockedExchange (&_so_passcred, pc); } + bool so_passcred () const { return _so_passcred; } + + int reuseaddr (int val) + { return (int) InterlockedExchange (&_reuseaddr, val); } + int reuseaddr () const { return _reuseaddr; } + + void set_socket_type (int val) { _type = val; } + int get_socket_type () const { return _type; } + + void sun_path (struct sockaddr_un *un, __socklen_t unlen) + { _sun_path.set (un, unlen); } + void peer_sun_path (struct sockaddr_un *un, __socklen_t unlen) + { _peer_sun_path.set (un, unlen); } + sun_name_t *sun_path () {return &_sun_path;} + sun_name_t *peer_sun_path () {return &_peer_sun_path;} + + void sock_cred (struct ucred *uc) { _sock_cred = *uc; } + struct ucred *sock_cred () { return &_sock_cred; } + void peer_cred (struct ucred *uc) { _peer_cred = *uc; } + struct ucred *peer_cred () { return &_peer_cred; } +}; + +#ifdef __WITH_AF_UNIX + +class fhandler_socket_unix : public fhandler_socket +{ + protected: + HANDLE shmem_handle; /* Shared memory region used to share + socket-wide state. */ + af_unix_shmem_t *shmem; + HANDLE backing_file_handle; /* Either NT symlink or INVALID_HANDLE_VALUE, + if the socket is backed by a file in the + file system (actually a reparse point) */ + HANDLE connect_wait_thr; + HANDLE cwt_termination_evt; + PVOID cwt_param; + + void bind_lock () { shmem->bind_lock (); } + void bind_unlock () { shmem->bind_unlock (); } + void conn_lock () { shmem->conn_lock (); } + void conn_unlock () { shmem->conn_unlock (); } + void state_lock () { shmem->state_lock (); } + void state_unlock () { shmem->state_unlock (); } + void io_lock () { shmem->io_lock (); } + void io_unlock () { shmem->io_unlock (); } + conn_state connect_state (conn_state val) + { return shmem->connect_state (val); } + conn_state connect_state () const { return shmem->connect_state (); } + bind_state binding_state (bind_state val) + { return shmem->binding_state (val); } + bind_state binding_state () const { return shmem->binding_state (); } + int saw_shutdown (int shut) { return shmem->shutdown (shut); } + int saw_shutdown () const { return shmem->shutdown (); } + int so_error (int err) { return shmem->so_error (err); } + int so_error () const { return shmem->so_error (); } + bool so_passcred (bool pc) { return shmem->so_passcred (pc); } + bool so_passcred () const { return shmem->so_passcred (); } + int reuseaddr (int err) { return shmem->reuseaddr (err); } + int reuseaddr () const { return shmem->reuseaddr (); } + void set_socket_type (int val) { shmem->set_socket_type (val); } + int get_socket_type () const { return shmem->get_socket_type (); } + + int create_shmem (); + int reopen_shmem (); + void gen_pipe_name (); + static HANDLE create_abstract_link (const sun_name_t *sun, + PUNICODE_STRING pipe_name); + static HANDLE create_reparse_point (const sun_name_t *sun, + PUNICODE_STRING pipe_name); + HANDLE create_file (const sun_name_t *sun); + static int open_abstract_link (sun_name_t *sun, PUNICODE_STRING pipe_name); + static int open_reparse_point (sun_name_t *sun, PUNICODE_STRING pipe_name); + static int open_file (sun_name_t *sun, int &type, PUNICODE_STRING pipe_name); + HANDLE autobind (sun_name_t *sun); + wchar_t get_type_char (); + void set_pipe_non_blocking (bool nonblocking); + int send_sock_info (bool from_bind); + int grab_admin_pkg (); + int recv_peer_info (); + HANDLE create_pipe (bool single_instance); + HANDLE create_pipe_instance (); + NTSTATUS open_pipe (PUNICODE_STRING pipe_name, bool xchg_sock_info); + int wait_pipe (PUNICODE_STRING pipe_name); + int connect_pipe (PUNICODE_STRING pipe_name); + int listen_pipe (); + ULONG peek_pipe (PFILE_PIPE_PEEK_BUFFER pbuf, ULONG psize, HANDLE evt); + int disconnect_pipe (HANDLE ph); + /* The NULL pointer check is required for FS methods like fstat. When + called via stat or lstat, there's no shared memory, just a path in pc. */ + sun_name_t *sun_path () {return shmem ? shmem->sun_path () : NULL;} + sun_name_t *peer_sun_path () {return shmem->peer_sun_path ();} + void sun_path (struct sockaddr_un *un, __socklen_t unlen) + { shmem->sun_path (un, unlen); } + void sun_path (sun_name_t *snt) + { snt ? sun_path (&snt->un, snt->un_len) : sun_path (NULL, 0); } + void peer_sun_path (struct sockaddr_un *un, __socklen_t unlen) + { shmem->peer_sun_path (un, unlen); } + void peer_sun_path (sun_name_t *snt) + { snt ? peer_sun_path (&snt->un, snt->un_len) + : peer_sun_path (NULL, 0); } + void init_cred (); + void set_cred (); + void sock_cred (struct ucred *uc) { shmem->sock_cred (uc); } + struct ucred *sock_cred () { return shmem->sock_cred (); } + void peer_cred (struct ucred *uc) { shmem->peer_cred (uc); } + struct ucred *peer_cred () { return shmem->peer_cred (); } + void fixup_after_fork (HANDLE parent); + void fixup_after_exec (); + void set_close_on_exec (bool val); + void fixup_helper (); + + public: + fhandler_socket_unix (); + ~fhandler_socket_unix (); + + int dup (fhandler_base *child, int); + + DWORD wait_pipe_thread (PUNICODE_STRING pipe_name); + + int socket (int af, int type, int protocol, int flags); + int socketpair (int af, int type, int protocol, int flags, + fhandler_socket *fh_out); + int bind (const struct sockaddr *name, int namelen); + int listen (int backlog); + int accept4 (struct sockaddr *peer, int *len, int flags); + int connect (const struct sockaddr *name, int namelen); + int getsockname (struct sockaddr *name, int *namelen); + int getpeername (struct sockaddr *name, int *namelen); + int shutdown (int how); + int open (int flags, mode_t mode = 0); + int close (); + int getpeereid (pid_t *pid, uid_t *euid, gid_t *egid); + ssize_t recvmsg (struct msghdr *msg, int flags); + ssize_t recvfrom (void *ptr, size_t len, int flags, + struct sockaddr *from, int *fromlen); + void read (void *ptr, size_t& len); + ssize_t readv (const struct iovec *const iov, int iovcnt, + ssize_t tot = -1); + + ssize_t sendmsg (const struct msghdr *msg, int flags); + ssize_t sendto (const void *ptr, size_t len, int flags, + const struct sockaddr *to, int tolen); + ssize_t write (const void *ptr, size_t len); + ssize_t writev (const struct iovec *const iov, int iovcnt, + ssize_t tot = -1); + int setsockopt (int level, int optname, const void *optval, + __socklen_t optlen); + int getsockopt (int level, int optname, const void *optval, + __socklen_t *optlen); + + virtual int ioctl (unsigned int cmd, void *); + virtual int fcntl (int cmd, intptr_t); + + int fstat (struct stat *buf); + int fstatvfs (struct statvfs *buf); + int fchmod (mode_t newmode); + int fchown (uid_t newuid, gid_t newgid); + int facl (int, int, struct acl *); + struct __acl_t *acl_get (uint32_t); + int acl_set (struct __acl_t *, uint32_t); + int link (const char *); + + /* select.cc */ + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + /* from here on: CLONING */ + fhandler_socket_unix (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_socket_unix *> (x); + _copy_from_reset_helper (); + } + + fhandler_socket_unix *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_socket_unix)); + fhandler_socket_unix *fh = new (ptr) fhandler_socket_unix (ptr); + fh->copy_from (this); + return fh; + } +}; + +#endif /* __WITH_AF_UNIX */ + +/* A parent of fhandler_pipe and fhandler_fifo. */ +class fhandler_pipe_fifo: public fhandler_base +{ + protected: + size_t pipe_buf_size; + virtual void release_select_sem (const char *) {}; + + public: + fhandler_pipe_fifo (); + + virtual bool reader_closed () { return false; }; + ssize_t raw_write (const void *ptr, size_t len); +}; + +class fhandler_pipe: public fhandler_pipe_fifo +{ +private: + HANDLE read_mtx; + pid_t popen_pid; + HANDLE query_hdl; + HANDLE hdl_cnt_mtx; + HANDLE query_hdl_proc; + HANDLE query_hdl_value; + HANDLE query_hdl_close_req_evt; + uint64_t pipename_key; + DWORD pipename_pid; + LONG pipename_id; + void release_select_sem (const char *); + HANDLE get_query_hdl_per_process (WCHAR *, OBJECT_NAME_INFORMATION *); + HANDLE get_query_hdl_per_system (WCHAR *, OBJECT_NAME_INFORMATION *); +public: + fhandler_pipe (); + + bool ispipe() const { return true; } + void set_pipe_buf_size (); + + void set_popen_pid (pid_t pid) {popen_pid = pid;} + pid_t get_popen_pid () const {return popen_pid;} + off_t lseek (off_t offset, int whence); + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + char *get_proc_fd_name (char *buf); + int open (int flags, mode_t mode = 0); + bool open_setup (int flags); + void fixup_after_fork (HANDLE); + int dup (fhandler_base *child, int); + void set_close_on_exec (bool val); + int close (); + void raw_read (void *ptr, size_t& len); + int ioctl (unsigned int cmd, void *); + int fcntl (int cmd, intptr_t); + int fstat (struct stat *buf); + int fstatvfs (struct statvfs *buf); + int fadvise (off_t, off_t, int); + int ftruncate (off_t, bool); + int init (HANDLE, DWORD, mode_t, int64_t); + static int create (fhandler_pipe *[2], unsigned, int); + static DWORD create (LPSECURITY_ATTRIBUTES, HANDLE *, HANDLE *, DWORD, + const char *, DWORD, int64_t *unique_id = NULL); + fhandler_pipe (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_pipe *> (x); + _copy_from_reset_helper (); + } + + fhandler_pipe *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pipe)); + fhandler_pipe *fh = new (ptr) fhandler_pipe (ptr); + fh->copy_from (this); + return fh; + } + void set_pipe_non_blocking (bool nonblocking); + HANDLE get_query_handle () const { return query_hdl; } + void close_query_handle () + { + if (query_hdl) + { + CloseHandle (query_hdl); + query_hdl = NULL; + } + if (query_hdl_close_req_evt) + { + CloseHandle (query_hdl_close_req_evt); + query_hdl_close_req_evt = NULL; + } + } + bool reader_closed (); + HANDLE temporary_query_hdl (); + bool need_close_query_hdl () + { + return query_hdl_close_req_evt ? + IsEventSignalled (query_hdl_close_req_evt) : false; + } + bool request_close_query_hdl () + { + if (query_hdl_close_req_evt) + { + SetEvent (query_hdl_close_req_evt); + return true; + } + return false; + } +}; + +#define CYGWIN_FIFO_PIPE_NAME_LEN 47 + +enum fifo_client_connect_state +{ + fc_unknown, + fc_error, + fc_disconnected, + fc_closing, + fc_listening, + fc_connected, + fc_input_avail, +}; + +struct fifo_client_handler +{ + HANDLE h; + fifo_client_connect_state _state; + bool last_read; /* true if our last successful read was from this client. */ + fifo_client_handler () : h (NULL), _state (fc_unknown), last_read (false) {} + void close () { NtClose (h); } + fifo_client_connect_state get_state () const { return _state; } + void set_state (fifo_client_connect_state s) { _state = s; } + /* Query O/S. Return previous state. */ + fifo_client_connect_state query_and_set_state (); +}; + +class fhandler_fifo; + +struct fifo_reader_id_t +{ + DWORD winpid; + fhandler_fifo *fh; + + operator bool () const { return winpid != 0 || fh != NULL; } + + friend bool operator == (const fifo_reader_id_t &l, const fifo_reader_id_t &r) + { + return l.winpid == r.winpid && l.fh == r.fh; + } + + friend bool operator != (const fifo_reader_id_t &l, const fifo_reader_id_t &r) + { + return l.winpid != r.winpid || l.fh != r.fh; + } +}; + +/* Info needed by all fhandlers for a given FIFO, stored in named + shared memory. This is mostly for readers, but writers need access + in order to update the count of open writers. */ +class fifo_shmem_t +{ + LONG _nreaders, _nwriters; + fifo_reader_id_t _owner, _prev_owner, _pending_owner; + af_unix_spinlock_t _owner_lock, _reading_lock, _nreaders_lock, _nwriters_lock; + + /* Info about shared memory block used for temporary storage of the + owner's fc_handler list. */ + LONG _sh_nhandlers, _sh_shandlers, _sh_fc_handler_committed, + _sh_fc_handler_updated; + +public: + int nreaders () const { return (int) _nreaders; } + int inc_nreaders () { return (int) InterlockedIncrement (&_nreaders); } + int dec_nreaders () { return (int) InterlockedDecrement (&_nreaders); } + int nwriters () const { return (int) _nwriters; } + int inc_nwriters () { return (int) InterlockedIncrement (&_nwriters); } + int dec_nwriters () { return (int) InterlockedDecrement (&_nwriters); } + + fifo_reader_id_t get_owner () const { return _owner; } + void set_owner (fifo_reader_id_t fr_id) { _owner = fr_id; } + fifo_reader_id_t get_prev_owner () const { return _prev_owner; } + void set_prev_owner (fifo_reader_id_t fr_id) { _prev_owner = fr_id; } + fifo_reader_id_t get_pending_owner () const { return _pending_owner; } + void set_pending_owner (fifo_reader_id_t fr_id) { _pending_owner = fr_id; } + + void owner_lock () { _owner_lock.lock (); } + void owner_unlock () { _owner_lock.unlock (); } + void reading_lock () { _reading_lock.lock (); } + void reading_unlock () { _reading_lock.unlock (); } + void nreaders_lock () { _nreaders_lock.lock (); } + void nreaders_unlock () { _nreaders_lock.unlock (); } + void nwriters_lock () { _nwriters_lock.lock (); } + void nwriters_unlock () { _nwriters_lock.unlock (); } + + int get_shared_nhandlers () const { return (int) _sh_nhandlers; } + void set_shared_nhandlers (int n) { InterlockedExchange (&_sh_nhandlers, n); } + int get_shared_shandlers () const { return (int) _sh_shandlers; } + void set_shared_shandlers (int n) { InterlockedExchange (&_sh_shandlers, n); } + size_t get_shared_fc_handler_committed () const + { return (size_t) _sh_fc_handler_committed; } + void set_shared_fc_handler_committed (size_t n) + { InterlockedExchange (&_sh_fc_handler_committed, (LONG) n); } + bool shared_fc_handler_updated () const { return _sh_fc_handler_updated; } + void shared_fc_handler_updated (bool val) + { InterlockedExchange (&_sh_fc_handler_updated, val); } +}; + +class fhandler_fifo: public fhandler_pipe_fifo +{ + /* Handles to named events shared by all fhandlers for a given FIFO. */ + HANDLE read_ready; /* A reader is open; OK for a writer to open. */ + HANDLE write_ready; /* A writer is open; OK for a reader to open. */ + HANDLE writer_opening; /* A writer is opening; no EOF. */ + + /* Handles to named events needed by all readers of a given FIFO. */ + HANDLE owner_needed_evt; /* The owner is closing. */ + HANDLE owner_found_evt; /* A new owner has taken over. */ + HANDLE update_needed_evt; /* shared_fc_handler needs updating. */ + + /* Handles to non-shared events needed for fifo_reader_threads. */ + HANDLE cancel_evt; /* Signal thread to terminate. */ + HANDLE thr_sync_evt; /* The thread has terminated. */ + + UNICODE_STRING pipe_name; + PWCHAR pipe_name_buf; + fifo_client_handler *fc_handler; /* Dynamically growing array. */ + int shandlers; /* Size (capacity) of the array. */ + int nhandlers; /* Number of elements in the array. */ + af_unix_spinlock_t _fifo_client_lock; + bool reader, writer, duplexer; + fifo_reader_id_t me; + + HANDLE shmem_handle; + fifo_shmem_t *shmem; + HANDLE shared_fc_hdl; + /* Dynamically growing array in shared memory. */ + fifo_client_handler *shared_fc_handler; + + bool wait (HANDLE); + HANDLE create_pipe_instance (); + NTSTATUS open_pipe (HANDLE&); + NTSTATUS wait_open_pipe (HANDLE&); + int add_client_handler (bool new_pipe_instance = true); + void delete_client_handler (int); + void cleanup_handlers (); + void close_all_handlers (); + void cancel_reader_thread (); + + int create_shmem (bool only_open = false); + int reopen_shmem (); + int create_shared_fc_handler (); + int reopen_shared_fc_handler (); + int remap_shared_fc_handler (size_t); + + int nreaders () const { return shmem->nreaders (); } + int inc_nreaders () { return shmem->inc_nreaders (); } + int dec_nreaders () { return shmem->dec_nreaders (); } + int nwriters () const { return shmem->nwriters (); } + int inc_nwriters () { return shmem->inc_nwriters (); } + int dec_nwriters () { return shmem->dec_nwriters (); } + void nreaders_lock () { shmem->nreaders_lock (); } + void nreaders_unlock () { shmem->nreaders_unlock (); } + void nwriters_lock () { shmem->nwriters_lock (); } + void nwriters_unlock () { shmem->nwriters_unlock (); } + + fifo_reader_id_t get_owner () const { return shmem->get_owner (); } + void set_owner (fifo_reader_id_t fr_id) { shmem->set_owner (fr_id); } + fifo_reader_id_t get_prev_owner () const { return shmem->get_prev_owner (); } + void set_prev_owner (fifo_reader_id_t fr_id) + { shmem->set_prev_owner (fr_id); } + fifo_reader_id_t get_pending_owner () const + { return shmem->get_pending_owner (); } + void set_pending_owner (fifo_reader_id_t fr_id) + { shmem->set_pending_owner (fr_id); } + void owner_lock () { shmem->owner_lock (); } + void owner_unlock () { shmem->owner_unlock (); } + + void owner_needed () + { + ResetEvent (owner_found_evt); + SetEvent (owner_needed_evt); + } + void owner_found () + { + ResetEvent (owner_needed_evt); + SetEvent (owner_found_evt); + } + + int get_shared_nhandlers () { return shmem->get_shared_nhandlers (); } + void set_shared_nhandlers (int n) { shmem->set_shared_nhandlers (n); } + int get_shared_shandlers () { return shmem->get_shared_shandlers (); } + void set_shared_shandlers (int n) { shmem->set_shared_shandlers (n); } + size_t get_shared_fc_handler_committed () const + { return shmem->get_shared_fc_handler_committed (); } + void set_shared_fc_handler_committed (size_t n) + { shmem->set_shared_fc_handler_committed (n); } + int update_my_handlers (); + int update_shared_handlers (); + bool shared_fc_handler_updated () const + { return shmem->shared_fc_handler_updated (); } + void shared_fc_handler_updated (bool val) + { shmem->shared_fc_handler_updated (val); } + + void release_select_sem (const char *); + +public: + fhandler_fifo (); + ~fhandler_fifo () + { + if (pipe_name_buf) + cfree (pipe_name_buf); + } + /* Called if we appear to be at EOF after polling fc_handlers. */ + bool hit_eof () const + { return !nwriters () && !IsEventSignalled (writer_opening); } + int get_nhandlers () const { return nhandlers; } + fifo_client_handler &get_fc_handler (int i) { return fc_handler[i]; } + PUNICODE_STRING get_pipe_name (); + DWORD fifo_reader_thread_func (); + void fifo_client_lock () { _fifo_client_lock.lock (); } + void fifo_client_unlock () { _fifo_client_lock.unlock (); } + void record_connection (fifo_client_handler&, bool = true, + fifo_client_connect_state = fc_connected); + + int take_ownership (DWORD timeout = INFINITE); + void reading_lock () { shmem->reading_lock (); } + void reading_unlock () { shmem->reading_unlock (); } + + int open (int, mode_t); + off_t lseek (off_t offset, int whence); + int close (); + int fcntl (int cmd, intptr_t); + int dup (fhandler_base *child, int); + bool isfifo () const { return true; } + void set_close_on_exec (bool val); + void raw_read (void *ptr, size_t& ulen); + void fixup_after_fork (HANDLE); + void fixup_after_exec (); + int fstat (struct stat *buf); + int fstatvfs (struct statvfs *buf); + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + fhandler_fifo (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_fifo *> (x); + _copy_from_reset_helper (); + } + + fhandler_fifo *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_fifo)); + fhandler_fifo *fhf = new (ptr) fhandler_fifo (ptr); + fhf->copy_from (this); + fhf->pipe_name_buf = NULL; + return fhf; + } +}; + +class fhandler_dev_raw: public fhandler_base +{ + protected: + char *devbufalloc; + char *devbuf; + DWORD devbufalign; + DWORD devbufsiz; + DWORD devbufstart; + DWORD devbufend; + struct status_flags + { + unsigned lastblk_to_read : 1; + public: + status_flags () : lastblk_to_read (0) {} + } status; + + IMPLEMENT_STATUS_FLAG (bool, lastblk_to_read) + + fhandler_dev_raw (); + + public: + ~fhandler_dev_raw (); + + int open (int flags, mode_t mode = 0); + + int fstat (struct stat *buf); + + int dup (fhandler_base *child, int); + int ioctl (unsigned int cmd, void *buf); + + void fixup_after_fork (HANDLE); + void fixup_after_exec (); + + fhandler_dev_raw (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_raw *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_raw *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_raw)); + fhandler_dev_raw *fh = new (ptr) fhandler_dev_raw (ptr); + fh->copy_from (this); + return fh; + } +}; + +#define MAX_PARTITIONS 15 + +struct part_t +{ + LONG refcnt; + HANDLE hdl[MAX_PARTITIONS]; +}; + +class fhandler_dev_floppy: public fhandler_dev_raw +{ + private: + off_t drive_size; + part_t *partitions; + struct status_flags + { + unsigned eom_detected : 1; + public: + status_flags () : eom_detected (0) {} + } status; + + IMPLEMENT_STATUS_FLAG (bool, eom_detected) + + inline off_t get_current_position (); + int get_drive_info (struct hd_geometry *geo); + + int lock_partition (DWORD to_write); + + BOOL write_file (const void *buf, DWORD to_write, DWORD *written, int *err); + BOOL read_file (void *buf, DWORD to_read, DWORD *read, int *err); + + public: + fhandler_dev_floppy (); + + int open (int flags, mode_t mode = 0); + int close (); + int dup (fhandler_base *child, int); + void raw_read (void *ptr, size_t& ulen); + ssize_t raw_write (const void *ptr, size_t ulen); + off_t lseek (off_t offset, int whence); + int ioctl (unsigned int cmd, void *buf); + + fhandler_dev_floppy (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_floppy *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_floppy *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_floppy)); + fhandler_dev_floppy *fh = new (ptr) fhandler_dev_floppy (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_dev_tape: public fhandler_dev_raw +{ + HANDLE mt_mtx; + OVERLAPPED ov; + + bool is_rewind_device () { return get_minor () < 128; } + unsigned int driveno () { return (unsigned int) get_minor () & 0x7f; } + void drive_init (); + + inline bool _lock (bool); + inline int unlock (int ret = 0); + + public: + fhandler_dev_tape (); + + int open (int flags, mode_t mode = 0); + virtual int close (); + + void raw_read (void *ptr, size_t& ulen); + ssize_t raw_write (const void *ptr, size_t ulen); + + virtual off_t lseek (off_t offset, int whence); + + virtual int fstat (struct stat *buf); + + virtual int dup (fhandler_base *child, int); + virtual void fixup_after_fork (HANDLE parent); + virtual void set_close_on_exec (bool val); + virtual int ioctl (unsigned int cmd, void *buf); + + fhandler_dev_tape (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_tape *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_tape *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_tape)); + fhandler_dev_tape *fh = new (ptr) fhandler_dev_tape (ptr); + fh->copy_from (this); + return fh; + } +}; + +/* Standard disk file */ + +class fhandler_disk_file: public fhandler_base +{ + HANDLE prw_handle; + bool prw_handle_isasync; + int readdir_helper (DIR *, dirent *, DWORD, DWORD, PUNICODE_STRING fname); + + int prw_open (bool, void *); + uint64_t fs_ioc_getflags (); + int fs_ioc_setflags (uint64_t); + + public: + fhandler_disk_file (); + fhandler_disk_file (path_conv &pc); + + int open (int flags, mode_t mode); + int close (); + int fcntl (int cmd, intptr_t); + int dup (fhandler_base *child, int); + void fixup_after_fork (HANDLE parent); + int mand_lock (int, struct flock *); + int fstat (struct stat *buf); + int fchmod (mode_t mode); + int fchown (uid_t uid, gid_t gid); + int facl (int, int, struct acl *); + struct __acl_t *acl_get (uint32_t); + int acl_set (struct __acl_t *, uint32_t); + ssize_t fgetxattr (const char *, void *, size_t); + int fsetxattr (const char *, const void *, size_t, int); + int fadvise (off_t, off_t, int); + int ftruncate (off_t, bool); + int link (const char *); + int utimens (const struct timespec *); + int fstatvfs (struct statvfs *buf); + int ioctl (unsigned int cmd, void *buf); + + HANDLE mmap (caddr_t *addr, size_t len, int prot, int flags, off_t off); + int munmap (HANDLE h, caddr_t addr, size_t len); + int msync (HANDLE h, caddr_t addr, size_t len, int flags); + bool fixup_mmap_after_fork (HANDLE h, int prot, int flags, + off_t offset, SIZE_T size, void *address); + int mkdir (mode_t mode); + int rmdir (); + DIR *opendir (int fd); + int readdir (DIR *, dirent *); + long telldir (DIR *); + void seekdir (DIR *, long); + void rewinddir (DIR *); + int closedir (DIR *); + + ssize_t pread (void *, size_t, off_t, void *aio = NULL); + ssize_t pwrite (void *, size_t, off_t, void *aio = NULL); + + fhandler_disk_file (void *) {} + dev_t get_dev () { return pc.fs_serial_number (); } + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_disk_file *> (x); + _copy_from_reset_helper (); + } + + fhandler_disk_file *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_disk_file)); + fhandler_disk_file *fh = new (ptr) fhandler_disk_file (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_dev: public fhandler_disk_file +{ + const struct _device *devidx; + bool dir_exists; + int drive, part; +public: + fhandler_dev (); + int open (int flags, mode_t mode); + int close (); + int fstat (struct stat *buf); + int fstatvfs (struct statvfs *buf); + int rmdir (); + DIR *opendir (int fd); + int readdir (DIR *, dirent *); + void rewinddir (DIR *); + + fhandler_dev (void *) {} + dev_t get_dev () { return dir_exists ? pc.fs_serial_number () + : get_device (); } + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev)); + fhandler_dev *fh = new (ptr) fhandler_dev (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_cygdrive: public fhandler_disk_file +{ + public: + fhandler_cygdrive (); + int open (int flags, mode_t mode); + DIR *opendir (int fd); + int readdir (DIR *, dirent *); + void rewinddir (DIR *); + int closedir (DIR *); + int fstat (struct stat *buf); + int fstatvfs (struct statvfs *buf); + + fhandler_cygdrive (void *) {} + dev_t get_dev () { return get_device (); } + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_cygdrive *> (x); + _copy_from_reset_helper (); + } + + fhandler_cygdrive *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_cygdrive)); + fhandler_cygdrive *fh = new (ptr) fhandler_cygdrive (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_serial: public fhandler_base +{ + private: + cc_t vmin_; /* from termios */ + cc_t vtime_; /* from termios */ + pid_t pgrp_; + int rts; /* for Windows 9x purposes only */ + int dtr; /* for Windows 9x purposes only */ + + public: + /* Constructor */ + fhandler_serial (); + + int open (int flags, mode_t mode); + int init (HANDLE h, DWORD a, mode_t flags); + void raw_read (void *ptr, size_t& ulen); + ssize_t raw_write (const void *ptr, size_t ulen); + int tcsendbreak (int); + int tcdrain (); + int tcflow (int); + int ioctl (unsigned int cmd, void *); + int switch_modem_lines (int set, int clr); + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + off_t lseek (off_t, int) + { + set_errno (ESPIPE); + return -1; + } + int tcflush (int); + bool is_tty () const { return true; } + + /* We maintain a pgrp so that tcsetpgrp and tcgetpgrp work, but we + don't use it for permissions checking. fhandler_pty_slave does + permission checking on pgrps. */ + virtual int tcgetpgrp () { return pgrp_; } + virtual int tcsetpgrp (const pid_t pid) { pgrp_ = pid; return 0; } + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + fhandler_serial (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_serial *> (x); + _copy_from_reset_helper (); + } + + fhandler_serial *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_serial)); + fhandler_serial *fh = new (ptr) fhandler_serial (ptr); + fh->copy_from (this); + return fh; + } +}; + +#define acquire_input_mutex(ms) \ + __acquire_input_mutex (__PRETTY_FUNCTION__, __LINE__, ms) + +#define release_input_mutex() \ + __release_input_mutex (__PRETTY_FUNCTION__, __LINE__) + +#define acquire_output_mutex(ms) \ + __acquire_output_mutex (__PRETTY_FUNCTION__, __LINE__, ms) + +#define release_output_mutex() \ + __release_output_mutex (__PRETTY_FUNCTION__, __LINE__) + +extern DWORD mutex_timeout; +DWORD acquire_attach_mutex (DWORD t); +void release_attach_mutex (void); + +class tty; +class tty_min; +class fhandler_termios: public fhandler_base +{ + private: + HANDLE output_handle; + protected: + virtual void doecho (const void *, DWORD) {}; + virtual int accept_input () {return 1;}; + int ioctl (int, void *); + tty_min *_tc; + tty *get_ttyp () {return (tty *) tc ();} + int eat_readahead (int n); + virtual void acquire_input_mutex_if_necessary (DWORD ms) {}; + virtual void release_input_mutex_if_necessary (void) {}; + virtual void discard_input () {}; + + /* Result status of processing keys in process_sigs(). */ + enum process_sig_state { + signalled, /* Signalled normally */ + not_signalled, /* Not signalled at all */ + not_signalled_but_done, /* Not signalled, but CTRL_C_EVENT was sent. */ + not_signalled_with_nat_reader, /* Not signalled, but detected non-cygwin + process may be reading the tty. */ + done_with_debugger /* The key was processed (CTRL_C_EVENT was sent) + for inferior of GDB. */ + }; + + public: + virtual pid_t tc_getpgid () { return 0; }; + tty_min*& tc () {return _tc;} + fhandler_termios () : + fhandler_base () + { + need_fork_fixup (true); + } + HANDLE& get_output_handle () { return output_handle; } + HANDLE& get_output_handle_nat () { return output_handle; } + static process_sig_state process_sigs (char c, tty *ttyp, + fhandler_termios *fh); + static bool process_stop_start (char c, tty *ttyp); + line_edit_status line_edit (const char *rptr, size_t nread, termios&, + ssize_t *bytes_read = NULL); + void set_output_handle (HANDLE h) { output_handle = h; } + void tcinit (bool force); + bool is_tty () const { return true; } + void sigflush (); + int tcgetpgrp (); + int tcsetpgrp (int pid); + bg_check_types bg_check (int sig, bool dontsignal = false); + virtual DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms) {return 1;} + virtual void __release_output_mutex (const char *fn, int ln) {} + void echo_erase (int force = 0); + virtual off_t lseek (off_t, int); + pid_t tcgetsid (); + + fhandler_termios (void *) {} + + virtual void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_termios *> (x); + _copy_from_reset_helper (); + } + + virtual fhandler_termios *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_termios)); + fhandler_termios *fh = new (ptr) fhandler_termios (ptr); + fh->copy_from (this); + return fh; + } + static bool path_iscygexec_a (LPCSTR n, LPSTR c); + static bool path_iscygexec_w (LPCWSTR n, LPWSTR c); + virtual void cleanup_before_exit () {} + virtual void setpgid_aux (pid_t pid) {} + virtual bool need_console_handler () { return false; } + virtual bool need_send_ctrl_c_event () { return true; } + virtual DWORD get_helper_pid () { return 0; } +}; + +enum ansi_intensity +{ + INTENSITY_INVISIBLE, + INTENSITY_DIM, + INTENSITY_NORMAL, + INTENSITY_BOLD +}; + +#define normal 0 +#define gotesc 1 +#define gotsquare 2 +#define gotarg1 3 +#define gotrsquare 4 +#define gotcommand 5 +#define gettitle 6 +#define eattitle 7 +#define gotparen 8 +#define gotrparen 9 +#define eatpalette 10 +#define endpalette 11 +#define MAXARGS 16 + +enum cltype +{ + cl_curr_pos = 1, + cl_disp_beg, + cl_disp_end, + cl_buf_beg, + cl_buf_end +}; + +class dev_console +{ + pid_t owner; + bool is_legacy; + bool orig_virtual_terminal_processing_mode; + + WORD default_color, underline_color, dim_color; + + /* Used to determine if an input keystroke should be modified with META. */ + int meta_mask; + +/* Output state */ + int state; + int args[MAXARGS]; + int nargs; + unsigned rarg; + bool saw_question_mark; + bool saw_greater_than_sign; + bool saw_space; + bool saw_exclamation_mark; + bool vt100_graphics_mode_G0; + bool vt100_graphics_mode_G1; + bool iso_2022_G1; + bool alternate_charset_active; + bool metabit; + char backspace_keycode; + bool screen_alternated; /* For xterm compatible mode only */ + + char my_title_buf [TITLESIZE + 1]; + + WORD current_win32_attr; + ansi_intensity intensity; + bool underline, blink, reverse; + WORD fg, bg; + + /* saved cursor coordinates */ + int savex, savey; + + + struct + { + short Top; + short Bottom; + } scroll_region; + + CONSOLE_SCREEN_BUFFER_INFO b; + COORD dwWinSize; + COORD dwEnd; + + /* saved screen */ + COORD save_bufsize; + PCHAR_INFO save_buf; + COORD save_cursor; + SHORT save_top; + + COORD dwLastCursorPosition; + COORD dwMousePosition; /* scroll-adjusted coord of mouse event */ + COORD dwLastMousePosition; /* scroll-adjusted coord of previous mouse event */ + DWORD dwLastButtonState; /* (not noting mouse wheel events) */ + int last_button_code; /* transformed mouse report button code */ + int nModifiers; + + bool insert_mode; + int use_mouse; + bool ext_mouse_mode5; + bool ext_mouse_mode6; + bool ext_mouse_mode15; + bool use_focus; + bool raw_win32_keyboard_mode; + char cons_rabuf[40]; // cannot get longer than char buf[40] in char_command + char *cons_rapoi; + bool cursor_key_app_mode; + bool disable_master_thread; + bool master_thread_suspended; + int num_processed; /* Number of input events in the current input buffer + already processed by cons_master_thread(). */ + + inline UINT get_console_cp (); + DWORD con_to_str (char *d, int dlen, WCHAR w); + DWORD str_to_con (mbtowc_p, PWCHAR d, const char *s, DWORD sz); + void set_color (HANDLE); + void set_default_attr (); + int set_cl_x (cltype); + int set_cl_y (cltype); + bool fillin (HANDLE); + bool scroll_window (HANDLE, int, int, int, int); + void scroll_buffer (HANDLE, int, int, int, int, int, int); + void clear_screen (HANDLE, int, int, int, int); + void save_restore (HANDLE, char); + + friend class fhandler_console; +}; + +/* This is a input and output console handle */ +class fhandler_console: public fhandler_termios +{ +public: + struct console_state + { + tty_min tty_min_state; + dev_console con; + }; + bool input_ready; + enum input_states + { + input_error = -1, + input_processing = 0, + input_ok = 1, + input_signalled = 2, + input_winch = 3 + }; + struct handle_set_t + { + HANDLE input_handle; + HANDLE output_handle; + HANDLE input_mutex; + HANDLE output_mutex; + }; + HANDLE thread_sync_event; +private: + static const unsigned MAX_WRITE_CHARS; + static console_state *shared_console_info; + static bool invisible_console; + HANDLE input_mutex, output_mutex; + handle_set_t handle_set; + + /* Used when we encounter a truncated multi-byte sequence. The + lead bytes are stored here and revisited in the next write call. */ + struct { + int len; + unsigned char buf[4]; /* Max len of valid UTF-8 sequence. */ + } trunc_buf; + PWCHAR write_buf; + +/* Output calls */ + void set_default_attr (); + + void scroll_buffer (int, int, int, int, int, int); + void scroll_buffer_screen (int, int, int, int, int, int); + void clear_screen (cltype, cltype, cltype, cltype); + void cursor_set (bool, int, int); + void cursor_get (int *, int *); + void cursor_rel (int, int); + inline void write_replacement_char (); + inline bool write_console (PWCHAR, DWORD, DWORD&); + const unsigned char *write_normal (unsigned const char*, unsigned const char *); + void char_command (char); + bool set_raw_win32_keyboard_mode (bool); + +/* Input calls */ + int igncr_enabled (); + void set_cursor_maybe (); + static bool create_invisible_console_workaround (bool force); + static console_state *open_shared_console (HWND, HANDLE&, bool&); + static void fix_tab_position (HANDLE h); + +/* console mode calls */ + const handle_set_t *get_handle_set (void) {return &handle_set;} + static void set_input_mode (tty::cons_mode m, const termios *t, + const handle_set_t *p); + static void set_output_mode (tty::cons_mode m, const termios *t, + const handle_set_t *p); + + public: + pid_t tc_getpgid () + { + return shared_console_info ? + shared_console_info->tty_min_state.getpgid () : 0; + } + fhandler_console (fh_devices); + static console_state *open_shared_console (HWND hw, HANDLE& h) + { + bool createit = false; + return open_shared_console (hw, h, createit); + } + + fhandler_console* is_console () { return this; } + + bool use_archetype () const {return true;} + + int open (int flags, mode_t mode); + bool open_setup (int flags); + void post_open_setup (int fd); + int dup (fhandler_base *, int); + + void read (void *ptr, size_t& len); + ssize_t write (const void *ptr, size_t len); + void doecho (const void *str, DWORD len); + int close (); + static bool exists () + { + acquire_attach_mutex (mutex_timeout); + UINT cp = GetConsoleCP (); + release_attach_mutex (); + return !!cp; + } + + int tcflush (int); + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + + int ioctl (unsigned int cmd, void *); + int init (HANDLE, DWORD, mode_t); + bool mouse_aware (MOUSE_EVENT_RECORD& mouse_event); + bool focus_aware () {return shared_console_info->con.use_focus;} + bool get_cons_readahead_valid () + { + acquire_input_mutex (INFINITE); + bool ret = shared_console_info->con.cons_rapoi != NULL && + *shared_console_info->con.cons_rapoi; + release_input_mutex (); + return ret; + } + + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + void fixup_after_fork_exec (bool); + void fixup_after_exec () {fixup_after_fork_exec (true);} + void fixup_after_fork (HANDLE) {fixup_after_fork_exec (false);} + void set_close_on_exec (bool val); + bool send_winch_maybe (); + void setup (); + bool set_unit (); + static bool need_invisible (bool force = false); + static void free_console (); + static const char *get_nonascii_key (INPUT_RECORD& input_rec, char *); + + fhandler_console (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_console *> (x); + _copy_from_reset_helper (); + } + + fhandler_console *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_console)); + fhandler_console *fh = new (ptr) fhandler_console (ptr); + fh->copy_from (this); + return fh; + } + input_states process_input_message (); + bg_check_types bg_check (int sig, bool dontsignal = false); + void setup_io_mutex (void); + DWORD __acquire_input_mutex (const char *fn, int ln, DWORD ms); + void __release_input_mutex (const char *fn, int ln); + DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms); + void __release_output_mutex (const char *fn, int ln); + void acquire_input_mutex_if_necessary (DWORD ms) + { + acquire_input_mutex (ms); + acquire_attach_mutex (ms); + } + void release_input_mutex_if_necessary (void) + { + release_attach_mutex (); + release_input_mutex (); + } + + char *&rabuf (); + size_t &ralen (); + size_t &raixget (); + size_t &raixput (); + size_t &rabuflen (); + + void get_duplicated_handle_set (handle_set_t *p); + static void close_handle_set (handle_set_t *p); + + static void cons_master_thread (handle_set_t *p, tty *ttyp); + void setup_for_non_cygwin_app (); + static void cleanup_for_non_cygwin_app (handle_set_t *p); + static void set_console_mode_to_native (); + bool need_console_handler (); + static void set_disable_master_thread (bool x, fhandler_console *cons = NULL); + + friend tty_min * tty_list::get_cttyp (); +}; + +class fhandler_pty_common: public fhandler_termios +{ + public: + fhandler_pty_common () + : fhandler_termios (), + output_mutex (NULL), input_mutex (NULL), pipe_sw_mutex (NULL), + input_available_event (NULL) + { + pc.file_attributes (FILE_ATTRIBUTE_NORMAL); + } + static const unsigned pipesize = 128 * 1024; + HANDLE output_mutex, input_mutex, pipe_sw_mutex; + HANDLE input_available_event; + + bool use_archetype () const {return true;} + DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms); + void __release_output_mutex (const char *fn, int ln); + + int close (); + off_t lseek (off_t, int); + bool bytes_available (DWORD& n); + void set_close_on_exec (bool val); + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + fhandler_pty_common (void *) {} + + virtual void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_pty_common *> (x); + _copy_from_reset_helper (); + } + + virtual fhandler_pty_common *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pty_common)); + fhandler_pty_common *fh = new (ptr) fhandler_pty_common (ptr); + fh->copy_from (this); + return fh; + } + + void resize_pseudo_console (struct winsize *); + static DWORD get_console_process_id (DWORD pid, bool match, + bool cygwin = false, + bool stub_only = false); + bool to_be_read_from_nat_pipe (void); + static DWORD attach_console_temporarily (DWORD target_pid, DWORD helper_pid); + static void resume_from_temporarily_attach (DWORD resume_pid); + + protected: + static BOOL process_opost_output (HANDLE h, const void *ptr, ssize_t& len, + bool is_echo, tty *ttyp, + bool is_nonblocking); +}; + +class fhandler_pty_slave: public fhandler_pty_common +{ + HANDLE inuse; // used to indicate that a tty is in use + HANDLE output_handle_nat, io_handle_nat; + HANDLE slave_reading; + LONG num_reader; + + /* Helper functions for fchmod and fchown. */ + bool fch_open_handles (bool chown); + int fch_set_sd (security_descriptor &sd, bool chown); + void fch_close_handles (); + + public: + pid_t tc_getpgid () { return _tc ? _tc->pgid : 0; } + + struct handle_set_t + { + HANDLE from_master_nat; + HANDLE input_available_event; + HANDLE input_mutex; + HANDLE pipe_sw_mutex; + }; + + /* Constructor */ + fhandler_pty_slave (int); + + void set_output_handle_nat (HANDLE h) { output_handle_nat = h; } + HANDLE& get_output_handle_nat () { return output_handle_nat; } + void set_handle_nat (HANDLE h) { io_handle_nat = h; } + HANDLE& get_handle_nat () { return io_handle_nat; } + + int open (int flags, mode_t mode = 0); + bool open_setup (int flags); + ssize_t write (const void *ptr, size_t len); + void read (void *ptr, size_t& len); + int init (HANDLE, DWORD, mode_t); + + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + int tcflush (int); + int ioctl (unsigned int cmd, void *); + int close (); + void cleanup (); + int dup (fhandler_base *child, int); + void fixup_after_fork (HANDLE parent); + void fixup_after_exec (); + + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + bg_check_types bg_check (int sig, bool dontsignal = false); + virtual char const *ttyname () { return pc.dev.name (); } + int fstat (struct stat *buf); + int facl (int, int, struct acl *); + int fchmod (mode_t mode); + int fchown (uid_t uid, gid_t gid); + + fhandler_pty_slave (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_pty_slave *> (x); + _copy_from_reset_helper (); + } + + fhandler_pty_slave *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pty_slave)); + fhandler_pty_slave *fh = new (ptr) fhandler_pty_slave (ptr); + fh->copy_from (this); + return fh; + } + bool setup_pseudoconsole (); + static DWORD get_winpid_to_hand_over (tty *ttyp, DWORD force_switch_to); + static void close_pseudoconsole (tty *ttyp, DWORD force_switch_to = 0); + static void hand_over_only (tty *ttyp, DWORD force_switch_to = 0); + bool term_has_pcon_cap (const WCHAR *env); + void set_switch_to_nat_pipe (void); + void reset_switch_to_nat_pipe (void); + void mask_switch_to_nat_pipe (bool mask, bool xfer); + void setup_locale (void); + void create_invisible_console (void); + static void transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp, + HANDLE input_available_event); + HANDLE get_input_available_event (void) { return input_available_event; } + bool pcon_activated (void) { return get_ttyp ()->pcon_activated; } + void cleanup_before_exit (); + void get_duplicated_handle_set (handle_set_t *p); + static void close_handle_set (handle_set_t *p); + void setup_for_non_cygwin_app (bool nopcon, PWCHAR envblock, + bool stdin_is_ptys); + static void cleanup_for_non_cygwin_app (handle_set_t *p, tty *ttyp, + bool stdin_is_ptys, + DWORD force_switch_to = 0); + void setpgid_aux (pid_t pid); + static void release_ownership_of_nat_pipe (tty *ttyp, fhandler_termios *fh); +}; + +#define __ptsname(buf, unit) __small_sprintf ((buf), "/dev/pty%d", (unit)) +class fhandler_pty_master: public fhandler_pty_common +{ +public: + /* Parameter set for the static function pty_master_thread() */ + struct master_thread_param_t { + HANDLE from_master_nat; + HANDLE from_master; + HANDLE to_master_nat; + HANDLE to_master; + HANDLE to_slave_nat; + HANDLE to_slave; + HANDLE master_ctl; + HANDLE input_available_event; + }; + /* Parameter set for the static function pty_master_fwd_thread() */ + struct master_fwd_thread_param_t { + HANDLE to_master; + HANDLE from_slave_nat; + HANDLE output_mutex; + tty *ttyp; + DWORD helper_pid; + }; +private: + int pktmode; // non-zero if pty in a packet mode. + HANDLE master_ctl; // Control socket for handle duplication + cygthread *master_thread; // Master control thread + HANDLE from_master_nat, to_master_nat, from_slave_nat, to_slave_nat; + HANDLE echo_r, echo_w; + DWORD dwProcessId; // Owner of master handles + HANDLE to_master, from_master; + cygthread *master_fwd_thread; // Master forwarding thread + HANDLE thread_param_copied_event; + HANDLE helper_goodbye; + HANDLE helper_h_process; + DWORD helper_pid; + +public: + HANDLE get_echo_handle () const { return echo_r; } + /* Constructor */ + fhandler_pty_master (int); + + static DWORD pty_master_thread (const master_thread_param_t *p); + static DWORD pty_master_fwd_thread (const master_fwd_thread_param_t *p); + int process_slave_output (char *buf, size_t len, int pktmode_on); + void doecho (const void *str, DWORD len); + int accept_input (); + int open (int flags, mode_t mode = 0); + bool open_setup (int flags); + ssize_t write (const void *ptr, size_t len); + void read (void *ptr, size_t& len); + int close (); + void cleanup (); + + int tcsetattr (int a, const struct termios *t); + int tcgetattr (struct termios *t); + int tcflush (int); + int ioctl (unsigned int cmd, void *); + + int ptsname_r (char *, size_t); + + bool hit_eof (); + bool setup (); + int dup (fhandler_base *, int); + void fixup_after_fork (HANDLE parent); + void fixup_after_exec (); + int tcgetpgrp (); + void flush_to_slave (); + void discard_input (); + + fhandler_pty_master (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_pty_master *> (x); + _copy_from_reset_helper (); + } + + fhandler_pty_master *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_pty_master)); + fhandler_pty_master *fh = new (ptr) fhandler_pty_master (ptr); + fh->copy_from (this); + return fh; + } + void get_master_thread_param (master_thread_param_t *p); + void get_master_fwd_thread_param (master_fwd_thread_param_t *p); + void set_mask_flusho (bool m) { get_ttyp ()->mask_flusho = m; } + bool need_send_ctrl_c_event (); + DWORD get_helper_pid () { return helper_pid; } +}; + +class fhandler_dev_null: public fhandler_base +{ + public: + fhandler_dev_null (); + + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + fhandler_dev_null (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_null *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_null *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_null)); + fhandler_dev_null *fh = new (ptr) fhandler_dev_null (ptr); + fh->copy_from (this); + return fh; + } + + ssize_t write (const void *ptr, size_t len); +}; + +class fhandler_dev_zero: public fhandler_base +{ + public: + fhandler_dev_zero (); + ssize_t write (const void *ptr, size_t len); + void read (void *ptr, size_t& len); + off_t lseek (off_t, int) { return 0; } + + virtual HANDLE mmap (caddr_t *addr, size_t len, int prot, + int flags, off_t off); + virtual int munmap (HANDLE h, caddr_t addr, size_t len); + virtual int msync (HANDLE h, caddr_t addr, size_t len, int flags); + virtual bool fixup_mmap_after_fork (HANDLE h, int prot, int flags, + off_t offset, SIZE_T size, + void *address); + + fhandler_dev_zero (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_zero *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_zero *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_zero)); + fhandler_dev_zero *fh = new (ptr) fhandler_dev_zero (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_dev_random: public fhandler_base +{ + protected: + uint32_t pseudo; + + int pseudo_write (const void *ptr, size_t len); + int pseudo_read (void *ptr, size_t len); + + public: + ssize_t write (const void *ptr, size_t len); + void read (void *ptr, size_t& len); + off_t lseek (off_t, int) { return 0; } + + fhandler_dev_random () : fhandler_base () {} + fhandler_dev_random (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_random *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_random *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_random)); + fhandler_dev_random *fh = new (ptr) fhandler_dev_random (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_dev_clipboard: public fhandler_base +{ + UINT cygnativeformat; + off_t pos; + void *membuffer; + size_t msize; + int set_clipboard (const void *buf, size_t len); + + public: + fhandler_dev_clipboard (); + int is_windows () { return 1; } + int fstat (struct stat *buf); + ssize_t write (const void *ptr, size_t len); + void read (void *ptr, size_t& len); + off_t lseek (off_t offset, int whence); + int close (); + + int dup (fhandler_base *child, int); + void fixup_after_exec (); + + fhandler_dev_clipboard (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_clipboard *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_clipboard *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_clipboard)); + fhandler_dev_clipboard *fh = new (ptr) fhandler_dev_clipboard (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_windows: public fhandler_base +{ + private: + HWND hWnd_; // the window whose messages are to be retrieved by read() call + int method_; // write method (Post or Send) + public: + fhandler_windows (); + int is_windows () { return 1; } + HWND get_hwnd () { return hWnd_; } + int open (int flags, mode_t mode = 0); + ssize_t write (const void *ptr, size_t len); + void read (void *ptr, size_t& len); + int ioctl (unsigned int cmd, void *); + off_t lseek (off_t, int) { return 0; } + int close () { return 0; } + + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + fhandler_windows (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_windows *> (x); + _copy_from_reset_helper (); + } + + fhandler_windows *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_windows)); + fhandler_windows *fh = new (ptr) fhandler_windows (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_dev_dsp: public fhandler_base +{ + public: + class Audio; + class Audio_out; + class Audio_in; + private: + int audioformat_; + int audiofreq_; + int audiobits_; + int audiochannels_; + Audio_out *audio_out_; + Audio_in *audio_in_; + public: + fhandler_dev_dsp (); + fhandler_dev_dsp *base () const {return (fhandler_dev_dsp *)archetype;} + + int open (int, mode_t mode = 0); + ssize_t write (const void *, size_t); + void read (void *, size_t&); + int ioctl (unsigned int, void *); + int close (); + void fixup_after_fork (HANDLE); + void fixup_after_exec (); + + private: + ssize_t _write (const void *, size_t); + void _read (void *, size_t&); + int _ioctl (unsigned int, void *); + void _fixup_after_fork (HANDLE); + void _fixup_after_exec (); + + void close_audio_in (); + void close_audio_out (bool = false); + bool use_archetype () const {return true;} + + fhandler_dev_dsp (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_dsp *> (x); + _copy_from_reset_helper (); + } + + fhandler_dev_dsp *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_dsp)); + fhandler_dev_dsp *fh = new (ptr) fhandler_dev_dsp (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_virtual : public fhandler_base +{ + protected: + char *filebuf; + off_t filesize; + off_t position; + int fileid; // unique within each class + bool diropen; + public: + + fhandler_virtual (); + virtual ~fhandler_virtual(); + + virtual virtual_ftype_t exists(); + DIR *opendir (int fd); + long telldir (DIR *); + void seekdir (DIR *, long); + void rewinddir (DIR *); + int closedir (DIR *); + ssize_t write (const void *ptr, size_t len); + void read (void *ptr, size_t& len); + off_t lseek (off_t, int); + int dup (fhandler_base *child, int); + int open (int flags, mode_t mode = 0); + int close (); + int fstatvfs (struct statvfs *buf); + int fchmod (mode_t mode); + int fchown (uid_t uid, gid_t gid); + int facl (int, int, struct acl *); + virtual bool fill_filebuf (); + char *get_filebuf () { return filebuf; } + void fixup_after_exec (); + + fhandler_virtual (void *) {} + + virtual void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_virtual *> (x); + _copy_from_reset_helper (); + } + + virtual fhandler_virtual *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_virtual)); + fhandler_virtual *fh = new (ptr) fhandler_virtual (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_proc: public fhandler_virtual +{ + public: + fhandler_proc (); + virtual_ftype_t exists(); + DIR *opendir (int fd); + int closedir (DIR *); + int readdir (DIR *, dirent *); + static fh_devices get_proc_fhandler (const char *path); + + int open (int flags, mode_t mode = 0); + int fstat (struct stat *buf); + bool fill_filebuf (); + + fhandler_proc (void *) {} + + virtual void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_proc *> (x); + _copy_from_reset_helper (); + } + + virtual fhandler_proc *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_proc)); + fhandler_proc *fh = new (ptr) fhandler_proc (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_procsys: public fhandler_virtual +{ + public: + fhandler_procsys (); + virtual_ftype_t exists(struct stat *buf); + virtual_ftype_t exists(); + DIR *opendir (int fd); + int readdir (DIR *, dirent *); + long telldir (DIR *); + void seekdir (DIR *, long); + int closedir (DIR *); + int open (int flags, mode_t mode = 0); + int close (); + void read (void *ptr, size_t& len); + ssize_t write (const void *ptr, size_t len); + int fstat (struct stat *buf); + bool fill_filebuf (); + + fhandler_procsys (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_procsys *> (x); + _copy_from_reset_helper (); + } + + fhandler_procsys *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_procsys)); + fhandler_procsys *fh = new (ptr) fhandler_procsys (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_procsysvipc: public fhandler_proc +{ + pid_t pid; + public: + fhandler_procsysvipc (); + virtual_ftype_t exists(); + int readdir (DIR *, dirent *); + int open (int flags, mode_t mode = 0); + int fstat (struct stat *buf); + bool fill_filebuf (); + + fhandler_procsysvipc (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_procsysvipc *> (x); + _copy_from_reset_helper (); + } + + fhandler_procsysvipc *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_procsysvipc)); + fhandler_procsysvipc *fh = new (ptr) fhandler_procsysvipc (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_netdrive: public fhandler_virtual +{ + public: + fhandler_netdrive (); + virtual_ftype_t exists(); + int readdir (DIR *, dirent *); + void seekdir (DIR *, long); + void rewinddir (DIR *); + int closedir (DIR *); + int open (int flags, mode_t mode = 0); + int close (); + int fstat (struct stat *buf); + + fhandler_netdrive (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_netdrive *> (x); + _copy_from_reset_helper (); + } + + fhandler_netdrive *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_netdrive)); + fhandler_netdrive *fh = new (ptr) fhandler_netdrive (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_registry: public fhandler_proc +{ + private: + wchar_t *value_name; + DWORD wow64; + int prefix_len; + public: + fhandler_registry (); + void set_name (path_conv &pc); + virtual_ftype_t exists(); + DIR *opendir (int fd); + int readdir (DIR *, dirent *); + long telldir (DIR *); + void seekdir (DIR *, long); + void rewinddir (DIR *); + int closedir (DIR *); + + int open (int flags, mode_t mode = 0); + int fstat (struct stat *buf); + bool fill_filebuf (); + int close (); + int dup (fhandler_base *child, int); + + fhandler_registry (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_registry *> (x); + _copy_from_reset_helper (); + } + + fhandler_registry *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_registry)); + fhandler_registry *fh = new (ptr) fhandler_registry (ptr); + fh->copy_from (this); + return fh; + } +}; + +class pinfo; +class fhandler_process: public fhandler_proc +{ + protected: + pid_t pid; + virtual_ftype_t fd_type; + public: + fhandler_process (); + virtual_ftype_t exists(); + DIR *opendir (int fd); + int closedir (DIR *); + int readdir (DIR *, dirent *); + int open (int flags, mode_t mode = 0); + int fstat (struct stat *buf); + bool fill_filebuf (); + + fhandler_process (void *) {} + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_process *> (x); + _copy_from_reset_helper (); + } + + fhandler_process *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_process)); + fhandler_process *fh = new (ptr) fhandler_process (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_process_fd : public fhandler_process +{ + fhandler_base *fetch_fh (HANDLE &, uint32_t); + + public: + fhandler_process_fd () : fhandler_process () {} + fhandler_process_fd (void *) {} + + virtual fhandler_base *fd_reopen (int, mode_t); + int fstat (struct stat *buf); + virtual int link (const char *); + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_process_fd *> (x); + _copy_from_reset_helper (); + } + + fhandler_process_fd *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_process_fd)); + fhandler_process_fd *fh = new (ptr) fhandler_process_fd (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_procnet: public fhandler_proc +{ + pid_t pid; + public: + fhandler_procnet (); + fhandler_procnet (void *) {} + virtual_ftype_t exists(); + int readdir (DIR *, dirent *); + int open (int flags, mode_t mode = 0); + int fstat (struct stat *buf); + bool fill_filebuf (); + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_procnet *> (x); + _copy_from_reset_helper (); + } + + fhandler_procnet *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_procnet)); + fhandler_procnet *fh = new (ptr) fhandler_procnet (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_dev_fd: public fhandler_virtual +{ + public: + fhandler_dev_fd (); + virtual_ftype_t exists(); + + int fstat (struct stat *buf); + bool fill_filebuf (); + + fhandler_dev_fd (void *) {} + + virtual void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_dev_fd *> (x); + _copy_from_reset_helper (); + } + + virtual fhandler_dev_fd *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_dev_fd)); + fhandler_dev_fd *fh = new (ptr) fhandler_dev_fd (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_signalfd : public fhandler_base +{ + sigset_t sigset; + + public: + fhandler_signalfd (); + fhandler_signalfd (void *) {} + + fhandler_signalfd *is_signalfd () { return this; } + + char *get_proc_fd_name (char *buf); + + int signalfd (const sigset_t *mask, int flags); + int fstat (struct stat *buf); + void read (void *ptr, size_t& len); + ssize_t write (const void *, size_t); + + int poll (); + inline sigset_t get_sigset () const { return sigset; } + + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_signalfd *> (x); + _copy_from_reset_helper (); + } + + fhandler_signalfd *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_signalfd)); + fhandler_signalfd *fh = new (ptr) fhandler_signalfd (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_timerfd : public fhandler_base +{ + timer_t timerid; + + public: + fhandler_timerfd (); + fhandler_timerfd (void *) {} + ~fhandler_timerfd () {} + + fhandler_timerfd *is_timerfd () { return this; } + + char *get_proc_fd_name (char *buf); + + int timerfd (clockid_t clock_id, int flags); + int settime (int flags, const struct itimerspec *value, + struct itimerspec *ovalue); + int gettime (struct itimerspec *ovalue); + + int fstat (struct stat *buf); + void read (void *ptr, size_t& len); + ssize_t write (const void *, size_t); + int dup (fhandler_base *child, int); + int ioctl (unsigned int, void *); + int close (); + + HANDLE get_timerfd_handle (); + + void fixup_after_fork (HANDLE); + void fixup_after_exec (); + + select_record *select_read (select_stuff *); + select_record *select_write (select_stuff *); + select_record *select_except (select_stuff *); + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_timerfd *> (x); + _copy_from_reset_helper (); + } + + fhandler_timerfd *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_timerfd)); + fhandler_timerfd *fh = new (ptr) fhandler_timerfd (ptr); + fh->copy_from (this); + return fh; + } +}; + +class fhandler_mqueue: public fhandler_disk_file +{ + struct mq_info mqi; + /* Duplicate filebuf usage of fhandler_virtual */ + char *filebuf; + off_t filesize; + off_t position; + + bool valid_path (); + + struct mq_info *_mqinfo (SIZE_T, mode_t, int, bool); + + struct mq_info *mqinfo_create (struct mq_attr *, mode_t, int); + struct mq_info *mqinfo_open (int); + void mq_open_finish (bool, bool); + + int _dup (HANDLE, fhandler_mqueue *); + + bool fill_filebuf (); + + int mutex_lock (HANDLE, bool); + int mutex_unlock (HANDLE); + int cond_timedwait (HANDLE, HANDLE, const struct timespec *); + void cond_signal (HANDLE); + +public: + fhandler_mqueue (); + fhandler_mqueue (void *) {} + ~fhandler_mqueue (); + + fhandler_mqueue *is_mqueue () { return this; } + + char *get_proc_fd_name (char *); + + int open (int, mode_t); + int mq_open (int, mode_t, struct mq_attr *); + int mq_getattr (struct mq_attr *); + int mq_setattr (const struct mq_attr *, struct mq_attr *); + int mq_notify (const struct sigevent *); + int mq_timedsend (const char *, size_t, unsigned int, + const struct timespec *); + ssize_t mq_timedrecv (char *, size_t, unsigned int *, + const struct timespec *); + + struct mq_info *mqinfo () { return &mqi; } + + void fixup_after_fork (HANDLE); + +#define NO_IMPL { set_errno (EPERM); return -1; } + + ssize_t fgetxattr (const char *, void *, size_t) NO_IMPL; + int fsetxattr (const char *, const void *, size_t, int) NO_IMPL; + int fadvise (off_t, off_t, int) NO_IMPL; + int ftruncate (off_t, bool) NO_IMPL; + int link (const char *) NO_IMPL; + int mkdir (mode_t) NO_IMPL; + ssize_t pread (void *, size_t, off_t, void *aio = NULL) NO_IMPL; + ssize_t pwrite (void *, size_t, off_t, void *aio = NULL) NO_IMPL; + int lock (int, struct flock *) NO_IMPL; + int mand_lock (int, struct flock *) NO_IMPL; + void read (void *, size_t&); + off_t lseek (off_t, int); + int fstat (struct stat *); + int dup (fhandler_base *, int); + int fcntl (int cmd, intptr_t); + int ioctl (unsigned int, void *); + int close (); + + void copy_from (fhandler_base *x) + { + pc.free_strings (); + *this = *reinterpret_cast<fhandler_mqueue *> (x); + _copy_from_reset_helper (); + } + + fhandler_mqueue *clone (cygheap_types malloc_type = HEAP_FHANDLER) + { + void *ptr = (void *) ccalloc (malloc_type, 1, sizeof (fhandler_mqueue)); + fhandler_mqueue *fh = new (ptr) fhandler_mqueue (ptr); + fh->copy_from (this); + return fh; + } +}; + +struct fhandler_nodevice: public fhandler_base +{ + fhandler_nodevice (); + int open (int flags, mode_t mode = 0); +}; + +#define report_tty_counts(fh, call, use_op) \ + termios_printf ("%s %s, %susecount %d",\ + fh->ttyname (), call,\ + use_op, ((fhandler_pty_slave *) (fh->archetype ?: fh))->usecount); + +typedef union +{ + char __base[sizeof (fhandler_base)]; + char __console[sizeof (fhandler_console)]; + char __dev[sizeof (fhandler_dev)]; + char __cygdrive[sizeof (fhandler_cygdrive)]; + char __dev_clipboard[sizeof (fhandler_dev_clipboard)]; + char __dev_dsp[sizeof (fhandler_dev_dsp)]; + char __dev_floppy[sizeof (fhandler_dev_floppy)]; + char __dev_null[sizeof (fhandler_dev_null)]; + char __dev_random[sizeof (fhandler_dev_random)]; + char __dev_raw[sizeof (fhandler_dev_raw)]; + char __dev_tape[sizeof (fhandler_dev_tape)]; + char __dev_zero[sizeof (fhandler_dev_zero)]; + char __dev_fd[sizeof (fhandler_dev_fd)]; + char __disk_file[sizeof (fhandler_disk_file)]; + char __fifo[sizeof (fhandler_fifo)]; + char __netdrive[sizeof (fhandler_netdrive)]; + char __nodevice[sizeof (fhandler_nodevice)]; + char __pipe[sizeof (fhandler_pipe)]; + char __proc[sizeof (fhandler_proc)]; + char __process[sizeof (fhandler_process)]; + char __process_fd[sizeof (fhandler_process_fd)]; + char __procnet[sizeof (fhandler_procnet)]; + char __procsys[sizeof (fhandler_procsys)]; + char __procsysvipc[sizeof (fhandler_procsysvipc)]; + char __pty_master[sizeof (fhandler_pty_master)]; + char __registry[sizeof (fhandler_registry)]; + char __serial[sizeof (fhandler_serial)]; + char __signalfd[sizeof (fhandler_signalfd)]; + char __timerfd[sizeof (fhandler_timerfd)]; + char __mqueue[sizeof (fhandler_mqueue)]; + char __socket_inet[sizeof (fhandler_socket_inet)]; + char __socket_local[sizeof (fhandler_socket_local)]; +#ifdef __WITH_AF_UNIX + char __socket_unix[sizeof (fhandler_socket_unix)]; +#endif /* __WITH_AF_UNIX */ + char __termios[sizeof (fhandler_termios)]; + char __pty_common[sizeof (fhandler_pty_common)]; + char __pty_slave[sizeof (fhandler_pty_slave)]; + char __virtual[sizeof (fhandler_virtual)]; + char __windows[sizeof (fhandler_windows)]; +} fhandler_union; |