summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Faylor <cgf@redhat.com>2004-01-24 03:41:28 +0000
committerChristopher Faylor <cgf@redhat.com>2004-01-24 03:41:28 +0000
commit859ac9453a563f2210b24d82c3bd8039efe0484c (patch)
tree64054e40cc844ddd1d3080f0fc459b54810d48f2
parent78db4ae60f67ce0505e77b0a1c834bd5f616dd7f (diff)
downloadgdb-859ac9453a563f2210b24d82c3bd8039efe0484c.tar.gz
* cygheap.cc (init_cygheap::close_ctty): Protect YA vforkism.
* fhandler.h (fhandler_base::has_acls): Make pass through for path_conv method. (fhandler_base::isremote): Ditto. (fhandler_base::is_fs_special): Ditto. (fhandler_base::has_attribute): Ditto. Define new function. (fhandler_base::fhaccess): Declare new function based on access_worker. (fhandler_base::set_has_acls): Eliminate obsolete function. (fhandler_base::set_isremote): Ditto. * fhandler.cc (fhandler_base::fhaccess): Move from syscalls.cc and into fhandler_base class. Use fhandler methods to access data rather than path_conv stuff. (fhandler_base::device_access_denied): Use fhaccess method. * fhandler_disk_file.cc (fhandler_disk_file::opendir): Ditto. (fhandler_base::open_fs): Remove calls to obsolete functions. * fhandler_virtual.cc (fhandler_virtual::open): Ditto. * winsup.h (access_worker): Remove obsolete access_worker declaration. *syscalls.cc (access_worker): Move function to fhandler.cc. (access): Use fhaccess method. * pinfo.cc (_pinfo::set_ctty): Clarify debugging output. * sigproc.cc (sig_dispatch_pending): Ditto. * syscalls.cc (setsid): Perform minor rearrangement.
-rw-r--r--winsup/cygwin/ChangeLog26
-rw-r--r--winsup/cygwin/cygheap.cc2
-rw-r--r--winsup/cygwin/fhandler.cc87
-rw-r--r--winsup/cygwin/fhandler.h1280
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc878
-rw-r--r--winsup/cygwin/fhandler_virtual.cc233
-rw-r--r--winsup/cygwin/pinfo.cc2
-rw-r--r--winsup/cygwin/sigproc.cc2
-rw-r--r--winsup/cygwin/syscalls.cc102
-rw-r--r--winsup/cygwin/winsup.h358
10 files changed, 2875 insertions, 95 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 5e4f35bae4c..2120cf46b9e 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,29 @@
+2004-01-23 Christopher Faylor <cgf@redhat.com>
+
+ * cygheap.cc (init_cygheap::close_ctty): Protect YA vforkism.
+ * fhandler.h (fhandler_base::has_acls): Make pass through for path_conv
+ method.
+ (fhandler_base::isremote): Ditto.
+ (fhandler_base::is_fs_special): Ditto.
+ (fhandler_base::has_attribute): Ditto. Define new function.
+ (fhandler_base::fhaccess): Declare new function based on access_worker.
+ (fhandler_base::set_has_acls): Eliminate obsolete function.
+ (fhandler_base::set_isremote): Ditto.
+ * fhandler.cc (fhandler_base::fhaccess): Move from syscalls.cc and into
+ fhandler_base class. Use fhandler methods to access data rather than
+ path_conv stuff.
+ (fhandler_base::device_access_denied): Use fhaccess method.
+ * fhandler_disk_file.cc (fhandler_disk_file::opendir): Ditto.
+ (fhandler_base::open_fs): Remove calls to obsolete functions.
+ * fhandler_virtual.cc (fhandler_virtual::open): Ditto.
+ * winsup.h (access_worker): Remove obsolete access_worker declaration.
+ *syscalls.cc (access_worker): Move function to fhandler.cc.
+ (access): Use fhaccess method.
+
+ * pinfo.cc (_pinfo::set_ctty): Clarify debugging output.
+ * sigproc.cc (sig_dispatch_pending): Ditto.
+ * syscalls.cc (setsid): Perform minor rearrangement.
+
2004-01-23 Pierre Humblet <pierre.humblet@ieee.org>
* fhandler_socket.cc (fhandler_socket::create_secret_event): Avoid
diff --git a/winsup/cygwin/cygheap.cc b/winsup/cygwin/cygheap.cc
index e057f2fee8c..83189c306a5 100644
--- a/winsup/cygwin/cygheap.cc
+++ b/winsup/cygwin/cygheap.cc
@@ -176,7 +176,9 @@ void
init_cygheap::close_ctty ()
{
debug_printf ("closing cygheap->ctty %p", cygheap->ctty);
+#ifdef NEWVFORK
int usecount = cygheap->ctty->usecount;
+#endif
cygheap->ctty->close ();
#ifndef NEWVFORK
cygheap->ctty = NULL;
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index d5619bd637f..98b685b8775 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -328,7 +328,92 @@ fhandler_base::device_access_denied (int flags)
if (!mode)
mode |= R_OK;
- return access_worker (pc, mode, this);
+ return fhaccess (mode);
+}
+
+bool
+fhandler_base::fhaccess (int flags)
+{
+ if (error ())
+ {
+ set_errno (error ());
+ return -1;
+ }
+
+ if (!exists ())
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
+
+ if (!(flags & (R_OK | W_OK | X_OK)))
+ return 0;
+
+ if (is_fs_special ())
+ /* short circuit */;
+ else if (has_attribute (FILE_ATTRIBUTE_READONLY) && (flags & W_OK))
+ {
+ set_errno (EACCES);
+ return -1;
+ }
+ else if (has_acls () && allow_ntsec)
+ return check_file_access (get_win32_name (), flags);
+
+ struct __stat64 st;
+ int r = fstat (&st);
+ if (r)
+ return -1;
+ r = -1;
+ if (flags & R_OK)
+ {
+ if (st.st_uid == myself->uid)
+ {
+ if (!(st.st_mode & S_IRUSR))
+ goto done;
+ }
+ else if (st.st_gid == myself->gid)
+ {
+ if (!(st.st_mode & S_IRGRP))
+ goto done;
+ }
+ else if (!(st.st_mode & S_IROTH))
+ goto done;
+ }
+ if (flags & W_OK)
+ {
+ if (st.st_uid == myself->uid)
+ {
+ if (!(st.st_mode & S_IWUSR))
+ goto done;
+ }
+ else if (st.st_gid == myself->gid)
+ {
+ if (!(st.st_mode & S_IWGRP))
+ goto done;
+ }
+ else if (!(st.st_mode & S_IWOTH))
+ goto done;
+ }
+ if (flags & X_OK)
+ {
+ if (st.st_uid == myself->uid)
+ {
+ if (!(st.st_mode & S_IXUSR))
+ goto done;
+ }
+ else if (st.st_gid == myself->gid)
+ {
+ if (!(st.st_mode & S_IXGRP))
+ goto done;
+ }
+ else if (!(st.st_mode & S_IXOTH))
+ goto done;
+ }
+ r = 0;
+done:
+ if (r)
+ set_errno (EACCES);
+ return r;
}
/* Open system call handler function. */
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
new file mode 100644
index 00000000000..514609b4508
--- /dev/null
+++ b/winsup/cygwin/fhandler.h
@@ -0,0 +1,1280 @@
+/* fhandler.h
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef _FHANDLER_H_
+#define _FHANDLER_H_
+
+enum
+{
+ FH_RBINARY = 0x00001000, /* binary read mode */
+ FH_WBINARY = 0x00002000, /* binary write mode */
+ FH_CLOEXEC = 0x00004000, /* close-on-exec */
+ FH_RBINSET = 0x00008000, /* binary read mode has been explicitly set */
+ FH_WBINSET = 0x00010000, /* binary write mode has been explicitly set */
+ FH_APPEND = 0x00020000, /* always append */
+ FH_ASYNC = 0x00040000, /* async I/O */
+ FH_ENC = 0x00080000, /* native path is encoded */
+ FH_SYMLINK = 0x00100000, /* is a symlink */
+ FH_EXECABL = 0x00200000, /* file looked like it would run:
+ * ends in .exe or .bat or begins with #! */
+ FH_LSEEKED = 0x00400000, /* 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. */
+ FH_NOHANDLE = 0x00800000, /* No handle associated with fhandler. */
+ FH_NOEINTR = 0x01000000, /* Set if I/O should be uninterruptible. */
+ FH_FFIXUP = 0x02000000, /* Set if need to fixup after fork. */
+ FH_LOCAL = 0x04000000, /* File is unix domain socket */
+ FH_SHUTRD = 0x08000000, /* Socket saw a SHUT_RD */
+ FH_SHUTWR = 0x10000000, /* Socket saw a SHUT_WR */
+ FH_ISREMOTE = 0x10000000, /* File is on a remote drive */
+ FH_DCEXEC = 0x20000000, /* Don't care if this is executable */
+ FH_HASACLS = 0x40000000, /* True if fs of file has ACLS */
+ FH_QUERYOPEN = 0x80000000, /* open file without requesting either read
+ or write access */
+};
+
+#define FHDEVN(n) (n)
+#define FHISSETF(x) __ISSETF (this, x, FH)
+#define FHSETF(x) __SETF (this, x, FH)
+#define FHCLEARF(x) __CLEARF (this, x, FH)
+#define FHCONDSETF(n, x) __CONDSETF(n, this, x, FH)
+
+#define FHSTATOFF 0
+
+/* fcntl flags used only internaly. */
+#define O_NOSYMLINK 0x080000
+#define O_DIROPEN 0x100000
+
+/* newlib used to define O_NDELAY differently from O_NONBLOCK. Now it
+ properly defines both to be the same. Unfortunately, we have to
+ behave properly the old version, too, to accommodate older executables. */
+#define OLD_O_NDELAY (CYGWIN_VERSION_CHECK_FOR_OLD_O_NONBLOCK ? 4 : 0)
+
+/* Care for the old O_NDELAY flag. If one of the flags is set,
+ both flags are set. */
+#define O_NONBLOCK_MASK (O_NONBLOCK | OLD_O_NDELAY)
+
+#define UNCONNECTED 0
+#define CONNECT_PENDING 1
+#define CONNECTED 2
+
+extern const char *windows_device_names[];
+extern struct __cygwin_perfile *perfile_table;
+#define __fmode (*(user_data->fmode_ptr))
+extern const char proc[];
+extern const int proc_len;
+
+class select_record;
+class fhandler_disk_file;
+typedef struct __DIR DIR;
+struct dirent;
+struct iovec;
+
+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
+};
+
+class fhandler_base
+{
+ friend class dtable;
+ friend void close_all_files ();
+ protected:
+ DWORD status;
+ private:
+ int access;
+ HANDLE io_handle;
+
+ __ino64_t namehash; /* hashed filename, used as inode num */
+
+ protected:
+ /* File open flags from open () and fcntl () calls */
+ int openflags;
+
+ char *rabuf; /* used for crlf conversion in text files */
+ size_t ralen;
+ size_t raixget;
+ size_t raixput;
+ size_t rabuflen;
+
+ DWORD open_status;
+ DWORD fs_flags;
+ HANDLE read_state;
+ path_conv pc;
+
+ public:
+ class fhandler_base *archetype;
+ int usecount;
+
+ void set_name (path_conv &pc);
+ 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;}
+ virtual size_t size () const {return sizeof (*this);}
+
+ virtual fhandler_base& operator =(fhandler_base &x);
+ fhandler_base ();
+ virtual ~fhandler_base ();
+
+ /* Non-virtual simple accessor functions. */
+ void set_io_handle (HANDLE x) { io_handle = x; }
+
+ DWORD& get_device () { return dev ().devn; }
+ DWORD get_major () { return dev ().major; }
+ DWORD get_minor () { return dev ().minor; }
+ virtual int get_unit () { return dev ().minor; }
+
+ int get_access () const { return access; }
+ void set_access (int x) { access = x; }
+
+ bool get_async () { return FHISSETF (ASYNC); }
+ void set_async (int x) { FHCONDSETF (x, ASYNC); }
+
+ int get_flags () { return openflags; }
+ void set_flags (int x, int supplied_bin = 0);
+
+ bool is_nonblocking ();
+ void set_nonblocking (int yes);
+
+ bool get_w_binary () { return FHISSETF (WBINSET) ? FHISSETF (WBINARY) : 1; }
+ bool get_r_binary () { return FHISSETF (RBINSET) ? FHISSETF (RBINARY) : 1; }
+
+ bool get_w_binset () { return FHISSETF (WBINSET); }
+ bool get_r_binset () { return FHISSETF (RBINSET); }
+
+ void set_w_binary (int b) { FHCONDSETF (b, WBINARY); FHSETF (WBINSET); }
+ void set_r_binary (int b) { FHCONDSETF (b, RBINARY); FHSETF (RBINSET); }
+ void clear_w_binary () {FHCLEARF (WBINARY); FHCLEARF (WBINSET); }
+ void clear_r_binary () {FHCLEARF (RBINARY); FHCLEARF (RBINSET); }
+
+ bool get_nohandle () { return FHISSETF (NOHANDLE); }
+ void set_nohandle (int x) { FHCONDSETF (x, NOHANDLE); }
+
+ void set_open_status () {open_status = status;}
+ DWORD get_open_status () {return open_status;}
+ void reset_to_open_binmode ()
+ {
+ set_flags ((get_flags () & ~(O_TEXT | O_BINARY))
+ | ((open_status & (FH_WBINARY | FH_RBINARY)
+ ? O_BINARY : O_TEXT)));
+ }
+
+ int get_default_fmode (int flags);
+
+ bool get_r_no_interrupt () { return FHISSETF (NOEINTR); }
+ void set_r_no_interrupt (bool b) { FHCONDSETF (b, NOEINTR); }
+
+ bool get_close_on_exec () { return FHISSETF (CLOEXEC); }
+ int set_close_on_exec_flag (int b) { return FHCONDSETF (b, CLOEXEC); }
+
+ LPSECURITY_ATTRIBUTES get_inheritance (bool all = 0)
+ {
+ if (all)
+ return get_close_on_exec () ? &sec_all_nih : &sec_all;
+ else
+ return get_close_on_exec () ? &sec_none_nih : &sec_none;
+ }
+
+ void set_did_lseek (int b = 1) { FHCONDSETF (b, LSEEKED); }
+ bool get_did_lseek () { return FHISSETF (LSEEKED); }
+
+ bool get_need_fork_fixup () { return FHISSETF (FFIXUP); }
+ void set_need_fork_fixup () { FHSETF (FFIXUP); }
+
+ bool get_encoded () { return FHISSETF (ENC);}
+ void set_encoded () { FHSETF (ENC);}
+
+ virtual void set_close_on_exec (int val);
+
+ virtual void fixup_before_fork_exec (DWORD) {}
+ virtual void fixup_after_fork (HANDLE);
+ virtual void fixup_after_exec (HANDLE) {}
+
+ bool get_symlink_p () { return FHISSETF (SYMLINK); }
+ void set_symlink_p (int val) { FHCONDSETF (val, SYMLINK); }
+ void set_symlink_p () { FHSETF (SYMLINK); }
+
+ bool get_socket_p () { return FHISSETF (LOCAL); }
+ void set_socket_p (int val) { FHCONDSETF (val, LOCAL); }
+ void set_socket_p () { FHSETF (LOCAL); }
+
+ bool get_execable_p () { return FHISSETF (EXECABL); }
+ void set_execable_p (executable_states val)
+ {
+ FHCONDSETF (val == is_executable, EXECABL);
+ FHCONDSETF (val == dont_care_if_executable, DCEXEC);
+ }
+ void set_execable_p () { FHSETF (EXECABL); }
+ bool dont_care_if_execable () { return FHISSETF (DCEXEC); }
+ bool exec_state_isknown () { return FHISSETF (DCEXEC) || FHISSETF (EXECABL); }
+
+ bool get_append_p () { return FHISSETF (APPEND); }
+ void set_append_p (int val) { FHCONDSETF (val, APPEND); }
+ void set_append_p () { FHSETF (APPEND); }
+
+ void set_fs_flags (DWORD flags) { fs_flags = flags; }
+ bool get_fs_flags (DWORD flagval = UINT32_MAX)
+ { return (fs_flags & (flagval)); }
+
+ bool get_query_open () { return FHISSETF (QUERYOPEN); }
+ void set_query_open (bool val) { FHCONDSETF (val, QUERYOPEN); }
+
+ 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);
+
+ int eat_readahead (int n);
+
+ 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.normalized_path; }
+ const char *get_win32_name () { return pc.get_win32 (); }
+ __ino64_t get_namehash () { return namehash; }
+
+ virtual void hclose (HANDLE h) {CloseHandle (h);}
+ virtual void set_inheritance (HANDLE &h, int not_inheriting);
+
+ /* fixup fd possibly non-inherited handles after fork */
+ void fork_fixup (HANDLE parent, HANDLE &h, const char *name);
+ virtual bool need_fixup_before () const {return false;}
+
+ virtual int open (int flags, mode_t mode = 0);
+ int open_fs (int flags, mode_t mode = 0);
+ virtual int close ();
+ int close_fs ();
+ virtual int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ int __stdcall fstat_fs (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ int __stdcall fstat_helper (struct __stat64 *buf,
+ FILETIME ftCreateionTime,
+ FILETIME ftLastAccessTime,
+ FILETIME ftLastWriteTime,
+ DWORD nFileSizeHigh,
+ DWORD nFileSizeLow,
+ DWORD nFileIndexHigh = 0,
+ DWORD nFileIndexLow = 0,
+ DWORD nNumberOfLinks = 1)
+ __attribute__ ((regparm (3)));
+ int __stdcall fstat_by_handle (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ int __stdcall fstat_by_name (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ virtual int ioctl (unsigned int cmd, void *);
+ virtual int fcntl (int cmd, void *);
+ virtual char const *ttyname () { return get_name (); }
+ virtual void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ virtual int 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 _off64_t lseek (_off64_t offset, int whence);
+ virtual int lock (int, struct __flock64 *);
+ virtual void dump ();
+ virtual int dup (fhandler_base *child);
+
+ virtual HANDLE mmap (caddr_t *addr, size_t len, DWORD access,
+ int flags, _off64_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, DWORD access, DWORD offset,
+ DWORD size, void *address);
+
+ void *operator new (size_t, void *p) {return p;}
+
+ virtual void 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 int is_tty () { return 0; }
+ virtual bool isdevice () { return true; }
+ virtual bool isfifo () { return false; }
+ virtual char *ptsname () { return NULL;}
+ virtual class fhandler_socket *is_socket () { return NULL; }
+ virtual class fhandler_console *is_console () { return 0; }
+ virtual int is_windows () {return 0; }
+
+ virtual void raw_read (void *ptr, size_t& ulen);
+ virtual int 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_io_handle () { return io_handle; }
+ virtual HANDLE& get_output_handle () { return io_handle; }
+ virtual bool hit_eof () {return false;}
+ virtual select_record *select_read (select_record *s);
+ virtual select_record *select_write (select_record *s);
+ virtual select_record *select_except (select_record *s);
+ virtual int ready_for_read (int fd, DWORD howlong);
+ virtual const char *get_native_name ()
+ {
+ return dev ().native;
+ }
+ virtual bg_check_types bg_check (int) {return bg_ok;}
+ void clear_readahead ()
+ {
+ raixput = raixget = ralen = rabuflen = 0;
+ rabuf = NULL;
+ }
+ void operator delete (void *);
+ virtual HANDLE get_guard () const {return NULL;}
+ virtual void set_eof () {}
+ virtual DIR *opendir ();
+ virtual dirent *readdir (DIR *);
+ virtual _off64_t telldir (DIR *);
+ virtual void seekdir (DIR *, _off64_t);
+ virtual void rewinddir (DIR *);
+ virtual int closedir (DIR *);
+ virtual bool is_slow () {return 0;}
+ bool is_auto_device () {return isdevice () && !dev ().isfs ();}
+ bool is_fs_special () {return pc.is_fs_special ();}
+ bool device_access_denied (int) __attribute__ ((regparm (2)));
+ bool fhaccess (int flags) __attribute__ ((regparm (2)));
+};
+
+class fhandler_socket: public fhandler_base
+{
+ private:
+ int addr_family;
+ int type;
+ int connect_secret [4];
+ HANDLE secret_event;
+ struct _WSAPROTOCOL_INFOA *prot_info_ptr;
+ char *sun_path;
+ int had_connect_or_listen;
+
+ public:
+ fhandler_socket ();
+ ~fhandler_socket ();
+ int get_socket () { return (int) get_handle(); }
+ fhandler_socket *is_socket () { return this; }
+
+ bool saw_shutdown_read () const {return FHISSETF (SHUTRD);}
+ bool saw_shutdown_write () const {return FHISSETF (SHUTWR);}
+
+ void set_shutdown_read () {FHSETF (SHUTRD);}
+ void set_shutdown_write () {FHSETF (SHUTWR);}
+
+ bool is_unconnected () const {return had_connect_or_listen == UNCONNECTED;}
+ bool is_connect_pending () const {return had_connect_or_listen == CONNECT_PENDING;}
+ bool is_connected () const {return had_connect_or_listen == CONNECTED;}
+ void set_connect_state (int newstate) { had_connect_or_listen = newstate; }
+ int get_connect_state () const { return had_connect_or_listen; }
+
+ int bind (const struct sockaddr *name, int namelen);
+ int connect (const struct sockaddr *name, int namelen);
+ int listen (int backlog);
+ int accept (struct sockaddr *peer, int *len);
+ int getsockname (struct sockaddr *name, int *namelen);
+ int getpeername (struct sockaddr *name, int *namelen);
+
+ ssize_t readv (const struct iovec *, int iovcnt, ssize_t tot = -1);
+ int recvfrom (void *ptr, size_t len, int flags,
+ struct sockaddr *from, int *fromlen);
+ int recvmsg (struct msghdr *msg, int flags, ssize_t tot = -1);
+
+ ssize_t writev (const struct iovec *, int iovcnt, ssize_t tot = -1);
+ int sendto (const void *ptr, size_t len, int flags,
+ const struct sockaddr *to, int tolen);
+ int sendmsg (const struct msghdr *msg, int flags, ssize_t tot = -1);
+
+ int ioctl (unsigned int cmd, void *);
+ int fcntl (int cmd, void *);
+ _off64_t lseek (_off64_t, int) { return 0; }
+ int shutdown (int how);
+ int close ();
+ void hclose (HANDLE) {close ();}
+ int dup (fhandler_base *child);
+
+ void set_close_on_exec (int val);
+ virtual void fixup_before_fork_exec (DWORD);
+ void fixup_after_fork (HANDLE);
+ void fixup_after_exec (HANDLE);
+ bool need_fixup_before () const {return true;}
+
+ select_record *select_read (select_record *s);
+ select_record *select_write (select_record *s);
+ select_record *select_except (select_record *s);
+ void set_addr_family (int af) {addr_family = af;}
+ int get_addr_family () {return addr_family;}
+ void set_socket_type (int st) { type = st;}
+ int get_socket_type () {return type;}
+ void set_sun_path (const char *path);
+ char *get_sun_path () {return sun_path;}
+ void set_connect_secret ();
+ void get_connect_secret (char*);
+ HANDLE create_secret_event (int *secret = NULL);
+ int check_peer_secret_event (struct sockaddr_in *peer, int *secret = NULL);
+ void signal_secret_event ();
+ void close_secret_event ();
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ bool is_slow () {return 1;}
+};
+
+class fhandler_pipe: public fhandler_base
+{
+protected:
+ HANDLE guard;
+ bool broken_pipe;
+ HANDLE writepipe_exists;
+ DWORD orig_pid;
+ unsigned id;
+public:
+ fhandler_pipe ();
+ _off64_t lseek (_off64_t offset, int whence);
+ select_record *select_read (select_record *s);
+ select_record *select_write (select_record *s);
+ select_record *select_except (select_record *s);
+ void set_close_on_exec (int val);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ int close ();
+ void create_guard (SECURITY_ATTRIBUTES *sa) {guard = CreateMutex (sa, FALSE, NULL);}
+ int dup (fhandler_base *child);
+ int ioctl (unsigned int cmd, void *);
+ void fixup_after_fork (HANDLE);
+ void fixup_after_exec (HANDLE);
+ bool hit_eof ();
+ void set_eof () {broken_pipe = true;}
+ HANDLE get_guard () const {return guard;}
+ int ready_for_read (int fd, DWORD howlong);
+ static int create (fhandler_pipe *[2], unsigned, int, bool = false);
+ bool is_slow () {return 1;}
+ friend class fhandler_fifo;
+};
+
+class fhandler_fifo: public fhandler_pipe
+{
+ HANDLE output_handle;
+ HANDLE owner; // You can't have too many mutexes, now, can you?
+ ATOM upand;
+ long read_use;
+ long write_use;
+public:
+ fhandler_fifo ();
+ int open (int flags, mode_t mode = 0);
+ int open_not_mine (int flags) __attribute__ ((regparm (2)));
+ int close ();
+ void set_use (int flags) __attribute__ ((regparm (2)));
+ bool isfifo () { return true; }
+ HANDLE& get_output_handle () { return output_handle; }
+ void set_output_handle (HANDLE h) { output_handle = h; }
+ void set_use ();
+ int dup (fhandler_base *child);
+ bool is_slow () {return 1;}
+ ATOM& get_atom () {return upand;}
+};
+
+class fhandler_dev_raw: public fhandler_base
+{
+ protected:
+ char *devbuf;
+ size_t devbufsiz;
+ size_t devbufstart;
+ size_t devbufend;
+ int eom_detected : 1;
+ int eof_detected : 1;
+ int lastblk_to_read : 1;
+ int is_writing : 1;
+ int has_written : 1;
+ int varblkop : 1;
+
+ virtual void clear (void);
+ virtual int writebuf (void);
+
+ /* returns not null, if `win_error' determines an end of media condition */
+ virtual int is_eom(int win_error) = 0;
+ /* returns not null, if `win_error' determines an end of file condition */
+ virtual int is_eof(int win_error) = 0;
+
+ fhandler_dev_raw ();
+
+ public:
+ ~fhandler_dev_raw (void);
+
+ int open (int flags, mode_t mode = 0);
+ int close (void);
+
+ void raw_read (void *ptr, size_t& ulen);
+ int raw_write (const void *ptr, size_t ulen);
+
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+
+ int dup (fhandler_base *child);
+
+ int ioctl (unsigned int cmd, void *buf);
+
+ void fixup_after_fork (HANDLE);
+ void fixup_after_exec (HANDLE);
+};
+
+class fhandler_dev_floppy: public fhandler_dev_raw
+{
+ protected:
+ virtual int is_eom (int win_error);
+ virtual int is_eof (int win_error);
+
+ public:
+ fhandler_dev_floppy ();
+
+ virtual int open (int flags, mode_t mode = 0);
+ virtual int close (void);
+
+ virtual _off64_t lseek (_off64_t offset, int whence);
+
+ virtual int ioctl (unsigned int cmd, void *buf);
+};
+
+class fhandler_dev_tape: public fhandler_dev_raw
+{
+ int lasterr;
+
+ bool is_rewind_device () { return get_unit () < 128; }
+
+ protected:
+ virtual void clear (void);
+
+ virtual int is_eom (int win_error);
+ virtual int is_eof (int win_error);
+
+ public:
+ fhandler_dev_tape ();
+
+ virtual int open (int flags, mode_t mode = 0);
+ virtual int close (void);
+
+ virtual _off64_t lseek (_off64_t offset, int whence);
+
+ virtual int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+
+ virtual int dup (fhandler_base *child);
+
+ virtual int ioctl (unsigned int cmd, void *buf);
+
+ private:
+ int tape_write_marks (int marktype, DWORD len);
+ int tape_get_pos (unsigned long *ret);
+ int tape_set_pos (int mode, long count, bool sfm_func = false);
+ int tape_erase (int mode);
+ int tape_prepare (int action);
+ bool tape_get_feature (DWORD parm);
+ int tape_get_blocksize (long *min, long *def, long *max, long *cur);
+ int tape_set_blocksize (long count);
+ int tape_status (struct mtget *get);
+ int tape_compression (long count);
+};
+
+/* Standard disk file */
+
+class fhandler_disk_file: public fhandler_base
+{
+ public:
+ fhandler_disk_file ();
+
+ int open (int flags, mode_t mode);
+ int close ();
+ int lock (int, struct __flock64 *);
+ bool isdevice () { return false; }
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+
+ HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, _off64_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, DWORD access, DWORD offset,
+ DWORD size, void *address);
+ DIR *opendir ();
+ struct dirent *readdir (DIR *);
+ _off64_t telldir (DIR *);
+ void seekdir (DIR *, _off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+};
+
+class fhandler_cygdrive: public fhandler_disk_file
+{
+ int ndrives;
+ const char *pdrive;
+ void set_drives ();
+ public:
+ bool iscygdrive_root () { return !dev ().minor; }
+ fhandler_cygdrive ();
+ DIR *opendir ();
+ struct dirent *readdir (DIR *);
+ _off64_t telldir (DIR *);
+ void seekdir (DIR *, _off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+};
+
+class fhandler_serial: public fhandler_base
+{
+ private:
+ size_t vmin_; /* from termios */
+ unsigned int vtime_; /* from termios */
+ pid_t pgrp_;
+ int rts; /* for Windows 9x purposes only */
+ int dtr; /* for Windows 9x purposes only */
+
+ public:
+ int overlapped_armed;
+ OVERLAPPED io_status;
+ DWORD ev;
+
+ /* Constructor */
+ fhandler_serial ();
+
+ int open (int flags, mode_t mode);
+ int close ();
+ void init (HANDLE h, DWORD a, mode_t flags);
+ void overlapped_setup ();
+ int dup (fhandler_base *child);
+ void raw_read (void *ptr, size_t& ulen);
+ int raw_write (const void *ptr, size_t ulen);
+ int tcsendbreak (int);
+ int tcdrain ();
+ int tcflow (int);
+ int ioctl (unsigned int cmd, void *);
+ int tcsetattr (int a, const struct termios *t);
+ int tcgetattr (struct termios *t);
+ _off64_t lseek (_off64_t, int) { return 0; }
+ int tcflush (int);
+ void dump ();
+ int is_tty () { return 1; }
+ void fixup_after_fork (HANDLE parent);
+ void fixup_after_exec (HANDLE);
+
+ /* We maintain a pgrp so that tcsetpgrp and tcgetpgrp work, but we
+ don't use it for permissions checking. fhandler_tty_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_record *s);
+ select_record *select_write (select_record *s);
+ select_record *select_except (select_record *s);
+ bool is_slow () {return 1;}
+};
+
+#define acquire_output_mutex(ms) \
+ __acquire_output_mutex (__PRETTY_FUNCTION__, __LINE__, ms);
+
+#define release_output_mutex() \
+ __release_output_mutex (__PRETTY_FUNCTION__, __LINE__);
+
+class tty;
+class tty_min;
+class fhandler_termios: public fhandler_base
+{
+ protected:
+ HANDLE output_handle;
+ virtual void doecho (const void *, DWORD) {};
+ virtual int accept_input () {return 1;};
+ public:
+ tty_min *tc;
+ fhandler_termios () :
+ fhandler_base ()
+ {
+ set_need_fork_fixup ();
+ }
+ HANDLE& get_output_handle () { return output_handle; }
+ line_edit_status line_edit (const char *rptr, int nread, termios&);
+ void set_output_handle (HANDLE h) { output_handle = h; }
+ void tcinit (tty_min *this_tc, bool force = false);
+ virtual int is_tty () { return 1; }
+ int tcgetpgrp ();
+ int tcsetpgrp (int pid);
+ bg_check_types bg_check (int sig);
+ 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 fixup_after_fork (HANDLE);
+ void fixup_after_exec (HANDLE parent) { fixup_after_fork (parent); }
+ void echo_erase (int force = 0);
+ virtual _off64_t lseek (_off64_t, int);
+};
+
+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 MAXARGS 10
+
+class dev_console
+{
+ 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 alternate_charset_active;
+
+ 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;
+
+ /* saved screen */
+ COORD savebufsiz;
+ PCHAR_INFO savebuf;
+
+ struct
+ {
+ short Top, Bottom;
+ } scroll_region;
+ struct
+ {
+ SHORT winTop;
+ SHORT winBottom;
+ COORD dwWinSize;
+ COORD dwBufferSize;
+ COORD dwCursorPosition;
+ WORD wAttributes;
+ } info;
+
+ COORD dwLastCursorPosition;
+ DWORD dwLastButtonState;
+ int nModifiers;
+
+ bool insert_mode;
+ bool use_mouse;
+ bool raw_win32_keyboard_mode;
+
+ bool con_to_str (char *d, const char *s, DWORD sz);
+ bool str_to_con (char *d, const char *s, DWORD sz);
+
+ friend class fhandler_console;
+};
+
+/* This is a input and output console handle */
+class fhandler_console: public fhandler_termios
+{
+ private:
+ static dev_console *dev_state;
+
+/* Output calls */
+ void set_default_attr ();
+ WORD get_win32_attr ();
+
+ bool fillin_info ();
+ void clear_screen (int, int, int, int);
+ void scroll_screen (int, int, int, int, int, int);
+ void cursor_set (bool, int, int);
+ void cursor_get (int *, int *);
+ void cursor_rel (int, int);
+ const unsigned char *write_normal (unsigned const char*, unsigned const char *);
+ void char_command (char);
+ bool set_raw_win32_keyboard_mode (bool);
+ int output_tcsetattr (int a, const struct termios *t);
+
+/* Input calls */
+ int igncr_enabled ();
+ int input_tcsetattr (int a, const struct termios *t);
+ void set_cursor_maybe ();
+
+ public:
+ fhandler_console ();
+
+ fhandler_console* is_console () { return this; }
+
+ int open (int flags, mode_t mode = 0);
+
+ int write (const void *ptr, size_t len);
+ void doecho (const void *str, DWORD len) { (void) write (str, len); }
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ int close ();
+
+ int tcflush (int);
+ int tcsetattr (int a, const struct termios *t);
+ int tcgetattr (struct termios *t);
+
+ /* Special dup as we must dup two handles */
+ int dup (fhandler_base *child);
+
+ int ioctl (unsigned int cmd, void *);
+ void init (HANDLE, DWORD, mode_t);
+ bool mouse_aware () {return dev_state->use_mouse;}
+
+ select_record *select_read (select_record *s);
+ select_record *select_write (select_record *s);
+ select_record *select_except (select_record *s);
+ void fixup_after_exec (HANDLE);
+ void set_close_on_exec (int val);
+ void fixup_after_fork (HANDLE parent);
+ void set_input_state ();
+ void send_winch_maybe ();
+ static tty_min *get_tty_stuff (int);
+ bool is_slow () {return 1;}
+};
+
+class fhandler_tty_common: public fhandler_termios
+{
+ public:
+ fhandler_tty_common ()
+ : fhandler_termios (), output_done_event (NULL),
+ ioctl_request_event (NULL), ioctl_done_event (NULL), output_mutex (NULL),
+ input_mutex (NULL), input_available_event (NULL), inuse (NULL)
+ {
+ // nothing to do
+ }
+ HANDLE output_done_event; // Raised by master when tty's output buffer
+ // written. Write status in tty::write_retval.
+ HANDLE ioctl_request_event; // Raised by slave to perform ioctl() request.
+ // Ioctl() request in tty::cmd/arg.
+ HANDLE ioctl_done_event; // Raised by master on ioctl() completion.
+ // Ioctl() status in tty::ioctl_retval.
+ HANDLE output_mutex, input_mutex;
+ HANDLE input_available_event;
+ HANDLE inuse; // used to indicate that a tty is in use
+
+ DWORD __acquire_output_mutex (const char *fn, int ln, DWORD ms);
+ void __release_output_mutex (const char *fn, int ln);
+
+ virtual int dup (fhandler_base *child);
+
+ tty *get_ttyp () { return (tty *) tc; }
+
+ int close ();
+ void set_close_on_exec (int val);
+ void fixup_after_fork (HANDLE parent);
+ select_record *select_read (select_record *s);
+ select_record *select_write (select_record *s);
+ select_record *select_except (select_record *s);
+ bool is_slow () {return 1;}
+};
+
+class fhandler_tty_slave: public fhandler_tty_common
+{
+ public:
+ /* Constructor */
+ fhandler_tty_slave ();
+
+ int open (int flags, mode_t mode = 0);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ void 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 ();
+ int dup (fhandler_base *child);
+ void fixup_after_fork (HANDLE parent);
+
+ _off64_t lseek (_off64_t, int) { return 0; }
+ select_record *select_read (select_record *s);
+ int cygserver_attach_tty (HANDLE*, HANDLE*);
+ int get_unit ();
+ virtual char const *ttyname () { return pc.dev.name; }
+};
+
+class fhandler_pty_master: public fhandler_tty_common
+{
+ int pktmode; // non-zero if pty in a packet mode.
+protected:
+ device slave; // device type of slave
+public:
+ int need_nl; // Next read should start with \n
+
+ /* Constructor */
+ fhandler_pty_master ();
+
+ 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);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ int close ();
+
+ int tcsetattr (int a, const struct termios *t);
+ int tcgetattr (struct termios *t);
+ int tcflush (int);
+ int ioctl (unsigned int cmd, void *);
+
+ _off64_t lseek (_off64_t, int) { return 0; }
+ char *ptsname ();
+
+ void set_close_on_exec (int val);
+ bool hit_eof ();
+ int get_unit () const { return slave.minor; }
+};
+
+class fhandler_tty_master: public fhandler_pty_master
+{
+ public:
+ /* Constructor */
+ fhandler_console *console; // device handler to perform real i/o.
+
+ fhandler_tty_master ();
+ int init ();
+ int init_console ();
+ void set_winsize (bool);
+ bool is_slow () {return 1;}
+};
+
+class fhandler_dev_null: public fhandler_base
+{
+ public:
+ fhandler_dev_null ();
+
+ void dump ();
+ select_record *select_read (select_record *s);
+ select_record *select_write (select_record *s);
+ select_record *select_except (select_record *s);
+};
+
+class fhandler_dev_zero: public fhandler_base
+{
+ public:
+ fhandler_dev_zero ();
+ int open (int flags, mode_t mode = 0);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ _off64_t lseek (_off64_t offset, int whence);
+
+ void dump ();
+};
+
+class fhandler_dev_random: public fhandler_base
+{
+ protected:
+ HCRYPTPROV crypt_prov;
+ long pseudo;
+
+ bool crypt_gen_random (void *ptr, size_t len);
+ int pseudo_write (const void *ptr, size_t len);
+ int pseudo_read (void *ptr, size_t len);
+
+ public:
+ fhandler_dev_random ();
+ int open (int flags, mode_t mode = 0);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ _off64_t lseek (_off64_t offset, int whence);
+ int close (void);
+ int dup (fhandler_base *child);
+
+ void dump ();
+};
+
+class fhandler_dev_mem: public fhandler_base
+{
+ protected:
+ DWORD mem_size;
+ _off64_t pos;
+
+ public:
+ fhandler_dev_mem ();
+ ~fhandler_dev_mem (void);
+
+ int open (int flags, mode_t mode = 0);
+ int write (const void *ptr, size_t ulen);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ _off64_t lseek (_off64_t offset, int whence);
+ int close (void);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ int dup (fhandler_base *child);
+
+ HANDLE mmap (caddr_t *addr, size_t len, DWORD access, int flags, _off64_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, DWORD access, DWORD offset,
+ DWORD size, void *address);
+
+ void dump ();
+} ;
+
+class fhandler_dev_clipboard: public fhandler_base
+{
+ public:
+ fhandler_dev_clipboard ();
+ int is_windows (void) { return 1; }
+ int open (int flags, mode_t mode = 0);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ _off64_t lseek (_off64_t offset, int whence);
+ int close (void);
+
+ int dup (fhandler_base *child);
+
+ void dump ();
+
+ private:
+ _off64_t pos;
+ void *membuffer;
+ size_t msize;
+ bool eof;
+};
+
+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 (void) { return 1; }
+ int open (int flags, mode_t mode = 0);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ int ioctl (unsigned int cmd, void *);
+ _off64_t lseek (_off64_t, int) { return 0; }
+ int close (void) { return 0; }
+
+ void set_close_on_exec (int val);
+ void fixup_after_fork (HANDLE parent);
+ select_record *select_read (select_record *s);
+ select_record *select_write (select_record *s);
+ select_record *select_except (select_record *s);
+ bool is_slow () {return 1;}
+};
+
+class fhandler_dev_dsp : public fhandler_base
+{
+ private:
+ int audioformat_;
+ int audiofreq_;
+ int audiobits_;
+ int audiochannels_;
+ bool setupwav(const char *pData, int nBytes);
+ public:
+ fhandler_dev_dsp ();
+ ~fhandler_dev_dsp();
+
+ int open (int flags, mode_t mode = 0);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ int ioctl (unsigned int cmd, void *);
+ _off64_t lseek (_off64_t, int);
+ int close (void);
+ int dup (fhandler_base *child);
+ void dump (void);
+ void fixup_after_exec (HANDLE);
+};
+
+class fhandler_virtual : public fhandler_base
+{
+ protected:
+ char *filebuf;
+ size_t bufalloc;
+ _off64_t filesize;
+ _off64_t position;
+ int fileid; // unique within each class
+ public:
+
+ fhandler_virtual ();
+ virtual ~fhandler_virtual();
+
+ virtual int exists();
+ DIR *opendir ();
+ _off64_t telldir (DIR *);
+ void seekdir (DIR *, _off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+ int write (const void *ptr, size_t len);
+ void __stdcall read (void *ptr, size_t& len) __attribute__ ((regparm (3)));
+ _off64_t lseek (_off64_t, int);
+ int dup (fhandler_base *child);
+ int open (int flags, mode_t mode = 0);
+ int close (void);
+ int __stdcall fstat (struct stat *buf) __attribute__ ((regparm (2)));
+ virtual bool fill_filebuf ();
+ void fixup_after_exec (HANDLE);
+};
+
+class fhandler_proc: public fhandler_virtual
+{
+ public:
+ fhandler_proc ();
+ int exists();
+ struct dirent *readdir (DIR *);
+ static DWORD get_proc_fhandler(const char *path);
+
+ int open (int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ bool fill_filebuf ();
+};
+
+class fhandler_registry: public fhandler_proc
+{
+ private:
+ char *value_name;
+ public:
+ fhandler_registry ();
+ int exists();
+ struct dirent *readdir (DIR *);
+ _off64_t telldir (DIR *);
+ void seekdir (DIR *, _off64_t);
+ void rewinddir (DIR *);
+ int closedir (DIR *);
+
+ int open (int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ bool fill_filebuf ();
+ int close (void);
+};
+
+class pinfo;
+class fhandler_process: public fhandler_proc
+{
+ pid_t pid;
+ public:
+ fhandler_process ();
+ int exists();
+ struct dirent *readdir (DIR *);
+ int open (int flags, mode_t mode = 0);
+ int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
+ bool fill_filebuf ();
+};
+
+struct fhandler_nodevice: public fhandler_base
+{
+ fhandler_nodevice ();
+ int open (int flags, mode_t mode = 0);
+ // int __stdcall fstat (struct __stat64 *buf, path_conv *);
+};
+
+#define report_tty_counts(fh, call, fhs_op, use_op) \
+ termios_printf ("%s %s, %sopen_fhs %d, %susecount %d",\
+ fh->ttyname (), call,\
+ fhs_op, cygheap->open_fhs,\
+ use_op, ((fhandler_tty_slave *) fh)->archetype->usecount);
+
+typedef union
+{
+ char __base[sizeof (fhandler_base)];
+ char __console[sizeof (fhandler_console)];
+ 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_mem[sizeof (fhandler_dev_mem)];
+ 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 __disk_file[sizeof (fhandler_disk_file)];
+ char __pipe[sizeof (fhandler_pipe)];
+ char __proc[sizeof (fhandler_proc)];
+ char __process[sizeof (fhandler_process)];
+ char __pty_master[sizeof (fhandler_pty_master)];
+ char __registry[sizeof (fhandler_registry)];
+ char __serial[sizeof (fhandler_serial)];
+ char __socket[sizeof (fhandler_socket)];
+ char __termios[sizeof (fhandler_termios)];
+ char __tty_common[sizeof (fhandler_tty_common)];
+ char __tty_master[sizeof (fhandler_tty_master)];
+ char __tty_slave[sizeof (fhandler_tty_slave)];
+ char __virtual[sizeof (fhandler_virtual)];
+ char __windows[sizeof (fhandler_windows)];
+ char __nodevice[sizeof (fhandler_nodevice)];
+} fhandler_union;
+
+struct select_record
+{
+ int fd;
+ HANDLE h;
+ fhandler_base *fh;
+ bool saw_error;
+ bool windows_handle;
+ bool read_ready, write_ready, except_ready;
+ bool read_selected, write_selected, except_selected;
+ bool except_on_write;
+ int (*startup) (select_record *me, class select_stuff *stuff);
+ int (*peek) (select_record *, bool);
+ int (*verify) (select_record *me, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds);
+ void (*cleanup) (select_record *me, class select_stuff *stuff);
+ struct select_record *next;
+
+ select_record (fhandler_base *in_fh = NULL) : fd (0), h (NULL),
+ fh (in_fh), saw_error (false), windows_handle (false),
+ read_ready (false), write_ready (false), except_ready (false),
+ read_selected (false), write_selected (false),
+ except_selected (false), except_on_write (false),
+ startup (NULL), peek (NULL), verify (NULL), cleanup (NULL),
+ next (NULL) {}
+};
+
+class select_stuff
+{
+ public:
+ ~select_stuff ();
+ bool always_ready, windows_used;
+ select_record start;
+ void *device_specific_pipe;
+ void *device_specific_socket;
+ void *device_specific_serial;
+
+ int test_and_set (int i, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds);
+ int poll (fd_set *readfds, fd_set *writefds, fd_set *exceptfds);
+ int wait (fd_set *readfds, fd_set *writefds, fd_set *exceptfds, DWORD ms);
+ void cleanup ();
+ select_stuff (): always_ready (0), windows_used (0), start (0),
+ device_specific_pipe (0),
+ device_specific_socket (0),
+ device_specific_serial (0) {}
+};
+
+int __stdcall set_console_state_for_spawn ();
+
+#endif /* _FHANDLER_H_ */
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
new file mode 100644
index 00000000000..d60d632b23d
--- /dev/null
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -0,0 +1,878 @@
+/* fhandler_disk_file.cc
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include <signal.h>
+#include "cygerrno.h"
+#include "perprocess.h"
+#include "security.h"
+#include "cygwin/version.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "cygheap.h"
+#include "shared_info.h"
+#include "pinfo.h"
+#include <assert.h>
+#include <ctype.h>
+
+#define _COMPILING_NEWLIB
+#include <dirent.h>
+
+unsigned __stdcall
+path_conv::ndisk_links (DWORD nNumberOfLinks)
+{
+ if (!isdir () || isremote ())
+ return nNumberOfLinks;
+
+ int len = strlen (*this);
+ char fn[len + 3];
+ strcpy (fn, *this);
+
+ const char *s;
+ unsigned count;
+ if (nNumberOfLinks <= 1)
+ {
+ s = "/*";
+ count = 0;
+ }
+ else
+ {
+ s = "/..";
+ count = nNumberOfLinks;
+ }
+
+ if (len == 0 || isdirsep (fn[len - 1]))
+ strcpy (fn + len, s + 1);
+ else
+ strcpy (fn + len, s);
+
+ WIN32_FIND_DATA buf;
+ HANDLE h = FindFirstFile (fn, &buf);
+
+ int saw_dot = 2;
+ if (h != INVALID_HANDLE_VALUE)
+ {
+ if (nNumberOfLinks > 1)
+ saw_dot--;
+ else
+ do
+ {
+ if (buf.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ count++;
+ if (buf.cFileName[0] == '.'
+ && (buf.cFileName[1] == '\0'
+ || (buf.cFileName[1] == '.' && buf.cFileName[2] == '\0')))
+ saw_dot--;
+ }
+ while (FindNextFileA (h, &buf));
+ FindClose (h);
+ }
+
+ if (nNumberOfLinks > 1)
+ {
+ fn[len + 2] = '\0';
+ h = FindFirstFile (fn, &buf);
+ if (h)
+ saw_dot--;
+ FindClose (h);
+ }
+
+ return count + saw_dot;
+}
+
+int __stdcall
+fhandler_base::fstat_by_handle (struct __stat64 *buf)
+{
+ int res = 0;
+ BY_HANDLE_FILE_INFORMATION local;
+
+ /* NT 3.51 seems to have a bug when attempting to get vol serial
+ numbers. This loop gets around this. */
+ for (int i = 0; i < 2; i++)
+ {
+ if (!(res = GetFileInformationByHandle (get_handle (), &local)))
+ break;
+ if (local.dwVolumeSerialNumber && (long) local.dwVolumeSerialNumber != -1)
+ break;
+ }
+
+ debug_printf ("%d = GetFileInformationByHandle (%s, %d)",
+ res, get_win32_name (), get_handle ());
+ if (res == 0)
+ /* GetFileInformationByHandle will fail if it's given stdin/out/err
+ or a pipe*/
+ {
+ memset (&local, 0, sizeof (local));
+ local.nFileSizeLow = GetFileSize (get_handle (), &local.nFileSizeHigh);
+ }
+
+ return fstat_helper (buf,
+ local.ftCreationTime,
+ local.ftLastAccessTime,
+ local.ftLastWriteTime,
+ local.nFileSizeHigh,
+ local.nFileSizeLow,
+ local.nFileIndexHigh,
+ local.nFileIndexLow,
+ local.nNumberOfLinks);
+}
+
+int __stdcall
+fhandler_base::fstat_by_name (struct __stat64 *buf)
+{
+ int res;
+ HANDLE handle;
+ WIN32_FIND_DATA local;
+
+ if (!pc.exists ())
+ {
+ debug_printf ("already determined that pc does not exist");
+ set_errno (ENOENT);
+ res = -1;
+ }
+ else if ((handle = FindFirstFile (pc, &local)) != INVALID_HANDLE_VALUE)
+ {
+ FindClose (handle);
+ res = fstat_helper (buf,
+ local.ftCreationTime,
+ local.ftLastAccessTime,
+ local.ftLastWriteTime,
+ local.nFileSizeHigh,
+ local.nFileSizeLow);
+ }
+ else if (pc.isdir ())
+ {
+ FILETIME ft = {};
+ res = fstat_helper (buf, ft, ft, ft, 0, 0);
+ }
+ else
+ {
+ debug_printf ("FindFirstFile failed for '%s', %E", (char *) pc);
+ __seterrno ();
+ res = -1;
+ }
+ return res;
+}
+
+int __stdcall
+fhandler_base::fstat_fs (struct __stat64 *buf)
+{
+ int res = -1;
+ int oret;
+ int open_flags = O_RDONLY | O_BINARY | O_DIROPEN;
+ bool query_open_already;
+
+ if (get_io_handle ())
+ {
+ if (get_nohandle ())
+ return fstat_by_name (buf);
+ else
+ return fstat_by_handle (buf);
+ }
+ /* If we don't care if the file is executable or we already know if it is,
+ then just do a "query open" as it is apparently much faster. */
+ if (pc.exec_state () != dont_know_if_executable)
+ set_query_open (query_open_already = true);
+ else
+ query_open_already = false;
+
+ if (query_open_already && strncasematch (pc.volname (), "FAT", 3)
+ && !strpbrk (get_win32_name (), "?*|<>"))
+ oret = 0;
+ else if (!(oret = open_fs (open_flags, 0))
+ && !query_open_already
+ && get_errno () == EACCES)
+ {
+ /* If we couldn't open the file, try a "query open" with no permissions.
+ This will allow us to determine *some* things about the file, at least. */
+ pc.set_exec (0);
+ set_query_open (true);
+ oret = open_fs (open_flags, 0);
+ }
+
+ if (!oret || get_nohandle ())
+ res = fstat_by_name (buf);
+ else
+ {
+ res = fstat_by_handle (buf);
+ close_fs ();
+ }
+
+ return res;
+}
+
+int __stdcall
+fhandler_base::fstat_helper (struct __stat64 *buf,
+ FILETIME ftCreationTime,
+ FILETIME ftLastAccessTime,
+ FILETIME ftLastWriteTime,
+ DWORD nFileSizeHigh,
+ DWORD nFileSizeLow,
+ DWORD nFileIndexHigh,
+ DWORD nFileIndexLow,
+ DWORD nNumberOfLinks)
+{
+ /* This is for FAT filesystems, which don't support atime/ctime */
+ if (ftLastAccessTime.dwLowDateTime == 0
+ && ftLastAccessTime.dwHighDateTime == 0)
+ ftLastAccessTime = ftLastWriteTime;
+ if (ftCreationTime.dwLowDateTime == 0
+ && ftCreationTime.dwHighDateTime == 0)
+ ftCreationTime = ftLastWriteTime;
+
+ to_timestruc_t (&ftLastAccessTime, &buf->st_atim);
+ to_timestruc_t (&ftLastWriteTime, &buf->st_mtim);
+ to_timestruc_t (&ftCreationTime, &buf->st_ctim);
+ buf->st_dev = pc.volser ();
+ buf->st_size = ((_off64_t) nFileSizeHigh << 32) + nFileSizeLow;
+ /* The number of links to a directory includes the
+ number of subdirectories in the directory, since all
+ those subdirectories point to it.
+ This is too slow on remote drives, so we do without it.
+ Setting the count to 2 confuses `find (1)' command. So
+ let's try it with `1' as link count. */
+ buf->st_nlink = pc.ndisk_links (nNumberOfLinks);
+
+ /* Assume that if a drive has ACL support it MAY have valid "inodes".
+ It definitely does not have valid inodes if it does not have ACL
+ support. */
+ switch (pc.has_acls () && (nFileIndexHigh || nFileIndexLow)
+ ? pc.drive_type () : DRIVE_UNKNOWN)
+ {
+ case DRIVE_FIXED:
+ case DRIVE_REMOVABLE:
+ case DRIVE_CDROM:
+ case DRIVE_RAMDISK:
+ /* Although the documentation indicates otherwise, it seems like
+ "inodes" on these devices are persistent, at least across reboots. */
+ buf->st_ino = (((__ino64_t) nFileIndexHigh) << 32)
+ | (__ino64_t) nFileIndexLow;
+ break;
+ default:
+ /* Either the nFileIndex* fields are unreliable or unavailable. Use the
+ next best alternative. */
+ buf->st_ino = get_namehash ();
+ break;
+ }
+
+ buf->st_blksize = S_BLKSIZE;
+
+ /* GetCompressedFileSize() gets autoloaded. It returns INVALID_FILE_SIZE
+ if it doesn't exist. Since that's also a valid return value on 64bit
+ capable file systems, we must additionally check for the win32 error. */
+ nFileSizeLow = GetCompressedFileSizeA (pc, &nFileSizeHigh);
+ if (nFileSizeLow != INVALID_FILE_SIZE || GetLastError () == NO_ERROR)
+ /* On systems supporting compressed (and sparsed) files,
+ GetCompressedFileSize() returns the actual amount of
+ bytes allocated on disk. */
+ buf->st_blocks = (((_off64_t)nFileSizeHigh << 32)
+ + nFileSizeLow + S_BLKSIZE - 1) / S_BLKSIZE;
+ else
+ /* Just compute no. of blocks from file size. */
+ buf->st_blocks = (buf->st_size + S_BLKSIZE - 1) / S_BLKSIZE;
+
+ buf->st_mode = 0;
+ /* Using a side effect: get_file_attibutes checks for
+ directory. This is used, to set S_ISVTX, if needed. */
+ if (pc.isdir ())
+ buf->st_mode = S_IFDIR;
+ else if (pc.issymlink ())
+ {
+ /* symlinks are everything for everyone! */
+ buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
+ get_file_attribute (pc.has_acls (), get_win32_name (), NULL,
+ &buf->st_uid, &buf->st_gid);
+ goto done;
+ }
+ else if (pc.issocket ())
+ buf->st_mode = S_IFSOCK;
+
+ if (get_file_attribute (pc.has_acls (), get_win32_name (), &buf->st_mode,
+ &buf->st_uid, &buf->st_gid) == 0)
+ {
+ /* If read-only attribute is set, modify ntsec return value */
+ if (pc.has_attribute (FILE_ATTRIBUTE_READONLY) && !get_symlink_p ())
+ buf->st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+
+ if (!(buf->st_mode & S_IFMT))
+ buf->st_mode |= S_IFREG;
+ }
+ else
+ {
+ buf->st_mode |= STD_RBITS;
+
+ if (!pc.has_attribute (FILE_ATTRIBUTE_READONLY))
+ buf->st_mode |= STD_WBITS;
+ /* | S_IWGRP | S_IWOTH; we don't give write to group etc */
+
+ if (S_ISDIR (buf->st_mode))
+ buf->st_mode |= S_IFDIR | STD_XBITS;
+ else if (buf->st_mode & S_IFMT)
+ /* nothing */;
+ else if (is_fs_special ())
+ {
+ buf->st_dev = dev ();
+ buf->st_mode = dev ().mode;
+ }
+ else
+ {
+ buf->st_mode |= S_IFREG;
+ if (pc.exec_state () == dont_know_if_executable)
+ {
+ DWORD cur, done;
+ char magic[3];
+
+ /* First retrieve current position, set to beginning
+ of file if not already there. */
+ cur = SetFilePointer (get_handle (), 0, NULL, FILE_CURRENT);
+ if (cur != INVALID_SET_FILE_POINTER
+ && (!cur || SetFilePointer (get_handle (), 0, NULL, FILE_BEGIN)
+ != INVALID_SET_FILE_POINTER))
+ {
+ /* FIXME should we use /etc/magic ? */
+ magic[0] = magic[1] = magic[2] = '\0';
+ if (ReadFile (get_handle (), magic, 3, &done, NULL)
+ && has_exec_chars (magic, done))
+ {
+ set_execable_p ();
+ pc.set_exec ();
+ buf->st_mode |= STD_XBITS;
+ }
+ (void) SetFilePointer (get_handle (), cur, NULL, FILE_BEGIN);
+ }
+ }
+ }
+
+ if (pc.exec_state () == is_executable)
+ buf->st_mode |= STD_XBITS;
+
+ /* This fakes the permissions of all files to match the current umask. */
+ buf->st_mode &= ~(cygheap->umask);
+ }
+
+ done:
+ syscall_printf ("0 = fstat (, %p) st_atime=%x st_size=%D, st_mode=%p, st_ino=%d, sizeof=%d",
+ buf, buf->st_atime, buf->st_size, buf->st_mode,
+ (int) buf->st_ino, sizeof (*buf));
+ return 0;
+}
+
+int __stdcall
+fhandler_disk_file::fstat (struct __stat64 *buf)
+{
+ return fstat_fs (buf);
+}
+
+fhandler_disk_file::fhandler_disk_file () :
+ fhandler_base ()
+{
+}
+
+int
+fhandler_disk_file::open (int flags, mode_t mode)
+{
+ return open_fs (flags, mode);
+}
+
+int
+fhandler_base::open_fs (int flags, mode_t mode)
+{
+ if (pc.case_clash && flags & O_CREAT)
+ {
+ debug_printf ("case clash detected");
+ set_errno (ECASECLASH);
+ return 0;
+ }
+
+ int res = fhandler_base::open (flags | O_DIROPEN, mode);
+ if (!res)
+ goto out;
+
+ /* This is for file systems known for having a buggy CreateFile call
+ which might return a valid HANDLE without having actually opened
+ the file.
+ The only known file system to date is the SUN NFS Solstice Client 3.1
+ which returns a valid handle when trying to open a file in a nonexistent
+ directory. */
+ if (pc.has_buggy_open () && !pc.exists ())
+ {
+ debug_printf ("Buggy open detected.");
+ close_fs ();
+ set_errno (ENOENT);
+ return 0;
+ }
+
+ /* Attributes may be set only if a file is _really_ created.
+ This code is now only used for ntea here since the files
+ security attributes are set in CreateFile () now. */
+ if (flags & O_CREAT
+ && GetLastError () != ERROR_ALREADY_EXISTS
+ && !allow_ntsec && allow_ntea)
+ set_file_attribute (has_acls (), get_win32_name (), mode);
+
+ set_fs_flags (pc.fs_flags ());
+ set_symlink_p (pc.issymlink ());
+ set_execable_p (pc.exec_state ());
+ set_socket_p (pc.issocket ());
+
+out:
+ syscall_printf ("%d = fhandler_disk_file::open (%s, %p)", res,
+ get_win32_name (), flags);
+ return res;
+}
+
+int
+fhandler_disk_file::close ()
+{
+ return close_fs ();
+}
+
+int
+fhandler_base::close_fs ()
+{
+ int res = fhandler_base::close ();
+ if (!res)
+ user_shared->delqueue.process_queue ();
+ return res;
+}
+
+/* FIXME: The correct way to do this to get POSIX locking semantics is to
+ keep a linked list of posix lock requests and map them into Win32 locks.
+ he problem is that Win32 does not deal correctly with overlapping lock
+ requests. Also another pain is that Win95 doesn't do non-blocking or
+ non-exclusive locks at all. For '95 just convert all lock requests into
+ blocking,exclusive locks. This shouldn't break many apps but denying all
+ locking would. For now just convert to Win32 locks and hope for
+ the best. */
+
+int
+fhandler_disk_file::lock (int cmd, struct __flock64 *fl)
+{
+ _off64_t win32_start;
+ _off64_t win32_len;
+ _off64_t startpos;
+
+ /*
+ * We don't do getlck calls yet.
+ */
+
+ if (cmd == F_GETLK)
+ {
+ set_errno (ENOSYS);
+ return -1;
+ }
+
+ /*
+ * Calculate where in the file to start from,
+ * then adjust this by fl->l_start.
+ */
+
+ switch (fl->l_whence)
+ {
+ case SEEK_SET:
+ startpos = 0;
+ break;
+ case SEEK_CUR:
+ if ((startpos = lseek (0, SEEK_CUR)) == ILLEGAL_SEEK)
+ return -1;
+ break;
+ case SEEK_END:
+ {
+ BY_HANDLE_FILE_INFORMATION finfo;
+ if (GetFileInformationByHandle (get_handle (), &finfo) == 0)
+ {
+ __seterrno ();
+ return -1;
+ }
+ startpos = ((_off64_t)finfo.nFileSizeHigh << 32)
+ + finfo.nFileSizeLow;
+ break;
+ }
+ default:
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ /*
+ * Now the fun starts. Adjust the start and length
+ * fields until they make sense.
+ */
+
+ win32_start = startpos + fl->l_start;
+ if (fl->l_len < 0)
+ {
+ win32_start -= fl->l_len;
+ win32_len = -fl->l_len;
+ }
+ else
+ win32_len = fl->l_len;
+
+ if (win32_start < 0)
+ {
+ /* watch the signs! */
+ win32_len -= -win32_start;
+ if (win32_len <= 0)
+ {
+ /* Failure ! */
+ set_errno (EINVAL);
+ return -1;
+ }
+ win32_start = 0;
+ }
+
+ DWORD off_high, off_low, len_high, len_low;
+
+ off_low = (DWORD)(win32_start & UINT32_MAX);
+ off_high = (DWORD)(win32_start >> 32);
+ if (win32_len == 0)
+ {
+ /* Special case if len == 0 for POSIX means lock to the end of
+ the entire file (and all future extensions). */
+ /* CV, 2003-12-03: And yet another Win 9x bugginess. For some reason
+ offset + length must be <= 0x100000000. I'm using 0xffffffff as
+ upper border here, this should be sufficient. */
+ len_low = UINT32_MAX - (wincap.lock_file_highword () ? 0 : off_low);
+ len_high = wincap.lock_file_highword ();
+ }
+ else
+ {
+ len_low = (DWORD)(win32_len & UINT32_MAX);
+ len_high = (DWORD)(win32_len >> 32);
+ }
+
+ BOOL res;
+
+ if (wincap.has_lock_file_ex ())
+ {
+ DWORD lock_flags = (cmd == F_SETLK) ? LOCKFILE_FAIL_IMMEDIATELY : 0;
+ lock_flags |= (fl->l_type == F_WRLCK) ? LOCKFILE_EXCLUSIVE_LOCK : 0;
+
+ OVERLAPPED ov;
+
+ ov.Internal = 0;
+ ov.InternalHigh = 0;
+ ov.Offset = off_low;
+ ov.OffsetHigh = off_high;
+ ov.hEvent = (HANDLE) 0;
+
+ if (fl->l_type == F_UNLCK)
+ {
+ res = UnlockFileEx (get_handle (), 0, len_low, len_high, &ov);
+ }
+ else
+ {
+ res = LockFileEx (get_handle (), lock_flags, 0,
+ len_low, len_high, &ov);
+ /* Deal with the fail immediately case. */
+ /*
+ * FIXME !! I think this is the right error to check for
+ * but I must admit I haven't checked....
+ */
+ if ((res == 0) && (lock_flags & LOCKFILE_FAIL_IMMEDIATELY) &&
+ (GetLastError () == ERROR_LOCK_FAILED))
+ {
+ set_errno (EAGAIN);
+ return -1;
+ }
+ }
+ }
+ else
+ {
+ /* Windows 95 -- use primitive lock call */
+ if (fl->l_type == F_UNLCK)
+ res = UnlockFile (get_handle (), off_low, off_high, len_low, len_high);
+ else
+ res = LockFile (get_handle (), off_low, off_high, len_low, len_high);
+ }
+
+ if (res == 0)
+ {
+ __seterrno ();
+ return -1;
+ }
+
+ return 0;
+}
+
+DIR *
+fhandler_disk_file::opendir ()
+{
+ DIR *dir;
+ DIR *res = NULL;
+ size_t len;
+
+ if (!pc.isdir ())
+ set_errno (ENOTDIR);
+ else if ((len = strlen (pc)) > CYG_MAX_PATH - 3)
+ set_errno (ENAMETOOLONG);
+ else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
+ set_errno (ENOMEM);
+ else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
+ {
+ set_errno (ENOMEM);
+ goto free_dir;
+ }
+ else if ((dir->__d_dirent =
+ (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
+ {
+ set_errno (ENOMEM);
+ goto free_dirname;
+ }
+ else if (fhaccess (R_OK) != 0)
+ goto free_dirent;
+ else
+ {
+ strcpy (dir->__d_dirname, get_win32_name ());
+ dir->__d_dirent->d_version = __DIRENT_VERSION;
+ cygheap_fdnew fd;
+
+ if (fd < 0)
+ goto free_dirent;
+
+ fd = this;
+ fd->set_nohandle (true);
+ dir->__d_dirent->d_fd = fd;
+ dir->__fh = this;
+ /* FindFirstFile doesn't seem to like duplicate /'s. */
+ len = strlen (dir->__d_dirname);
+ if (len == 0 || isdirsep (dir->__d_dirname[len - 1]))
+ strcat (dir->__d_dirname, "*");
+ else
+ strcat (dir->__d_dirname, "\\*"); /**/
+ dir->__d_cookie = __DIRENT_COOKIE;
+ dir->__handle = INVALID_HANDLE_VALUE;
+ dir->__d_position = 0;
+ dir->__d_dirhash = get_namehash ();
+
+ res = dir;
+
+ if (pc.isencoded ())
+ set_encoded ();
+ }
+
+ syscall_printf ("%p = opendir (%s)", res, get_name ());
+ return res;
+
+free_dirent:
+ free (dir->__d_dirent);
+free_dirname:
+ free (dir->__d_dirname);
+free_dir:
+ free (dir);
+ return res;
+}
+
+struct dirent *
+fhandler_disk_file::readdir (DIR *dir)
+{
+ WIN32_FIND_DATA buf;
+ HANDLE handle;
+ struct dirent *res = NULL;
+
+ if (dir->__handle == INVALID_HANDLE_VALUE
+ && dir->__d_position == 0)
+ {
+ handle = FindFirstFileA (dir->__d_dirname, &buf);
+ DWORD lasterr = GetLastError ();
+ dir->__handle = handle;
+ if (handle == INVALID_HANDLE_VALUE && (lasterr != ERROR_NO_MORE_FILES))
+ {
+ seterrno_from_win_error (__FILE__, __LINE__, lasterr);
+ return res;
+ }
+ }
+ else if (dir->__handle == INVALID_HANDLE_VALUE)
+ return res;
+ else if (!FindNextFileA (dir->__handle, &buf))
+ {
+ DWORD lasterr = GetLastError ();
+ (void) FindClose (dir->__handle);
+ dir->__handle = INVALID_HANDLE_VALUE;
+ /* POSIX says you shouldn't set errno when readdir can't
+ find any more files; so, if another error we leave it set. */
+ if (lasterr != ERROR_NO_MORE_FILES)
+ seterrno_from_win_error (__FILE__, __LINE__, lasterr);
+ syscall_printf ("%p = readdir (%p)", res, dir);
+ return res;
+ }
+
+ /* Check for Windows shortcut. If it's a Cygwin or U/WIN
+ symlink, drop the .lnk suffix. */
+ if (buf.dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ {
+ char *c = buf.cFileName;
+ int len = strlen (c);
+ if (strcasematch (c + len - 4, ".lnk"))
+ {
+ char fbuf[CYG_MAX_PATH + 1];
+ strcpy (fbuf, dir->__d_dirname);
+ strcpy (fbuf + strlen (fbuf) - 1, c);
+ path_conv fpath (fbuf, PC_SYM_NOFOLLOW);
+ if (fpath.issymlink () || fpath.isspecial ())
+ c[len - 4] = '\0';
+ }
+ }
+
+ /* We get here if `buf' contains valid data. */
+ if (get_encoded ())
+ (void) fnunmunge (dir->__d_dirent->d_name, buf.cFileName);
+ else
+ strcpy (dir->__d_dirent->d_name, buf.cFileName);
+
+ dir->__d_position++;
+ res = dir->__d_dirent;
+ syscall_printf ("%p = readdir (%p) (%s)",
+ &dir->__d_dirent, dir, buf.cFileName);
+ return res;
+}
+
+_off64_t
+fhandler_disk_file::telldir (DIR *dir)
+{
+ return dir->__d_position;
+}
+
+void
+fhandler_disk_file::seekdir (DIR *dir, _off64_t loc)
+{
+ rewinddir (dir);
+ while (loc > dir->__d_position)
+ if (!readdir (dir))
+ break;
+}
+
+void
+fhandler_disk_file::rewinddir (DIR *dir)
+{
+ if (dir->__handle != INVALID_HANDLE_VALUE)
+ {
+ (void) FindClose (dir->__handle);
+ dir->__handle = INVALID_HANDLE_VALUE;
+ }
+ dir->__d_position = 0;
+}
+
+int
+fhandler_disk_file::closedir (DIR *dir)
+{
+ int res = 0;
+ if (dir->__handle != INVALID_HANDLE_VALUE &&
+ FindClose (dir->__handle) == 0)
+ {
+ __seterrno ();
+ res = -1;
+ }
+ syscall_printf ("%d = closedir (%p)", res, dir);
+ return 0;
+}
+
+fhandler_cygdrive::fhandler_cygdrive () :
+ fhandler_disk_file (), ndrives (0), pdrive (NULL)
+{
+}
+
+#define DRVSZ sizeof ("x:\\")
+void
+fhandler_cygdrive::set_drives ()
+{
+ const int len = 2 + 26 * DRVSZ;
+ char *p = const_cast<char *> (get_win32_name ());
+ pdrive = p;
+ ndrives = GetLogicalDriveStrings (len, p) / DRVSZ;
+}
+
+int
+fhandler_cygdrive::fstat (struct __stat64 *buf)
+{
+ if (!iscygdrive_root ())
+ return fhandler_disk_file::fstat (buf);
+ buf->st_mode = S_IFDIR | 0555;
+ if (!ndrives)
+ set_drives ();
+ buf->st_nlink = ndrives + 2;
+ return 0;
+}
+
+DIR *
+fhandler_cygdrive::opendir ()
+{
+ DIR *dir;
+
+ dir = fhandler_disk_file::opendir ();
+ if (dir && iscygdrive_root () && !ndrives)
+ set_drives ();
+
+ return dir;
+}
+
+struct dirent *
+fhandler_cygdrive::readdir (DIR *dir)
+{
+ if (!iscygdrive_root ())
+ return fhandler_disk_file::readdir (dir);
+ if (!pdrive || !*pdrive)
+ return NULL;
+ if (GetFileAttributes (pdrive) == INVALID_FILE_ATTRIBUTES)
+ {
+ pdrive = strchr (pdrive, '\0') + 1;
+ return readdir (dir);
+ }
+
+ *dir->__d_dirent->d_name = cyg_tolower (*pdrive);
+ dir->__d_dirent->d_name[1] = '\0';
+ dir->__d_position++;
+ pdrive = strchr (pdrive, '\0') + 1;
+ syscall_printf ("%p = readdir (%p) (%s)", &dir->__d_dirent, dir,
+ dir->__d_dirent->d_name);
+ return dir->__d_dirent;
+}
+
+_off64_t
+fhandler_cygdrive::telldir (DIR *dir)
+{
+ return fhandler_disk_file::telldir (dir);
+}
+
+void
+fhandler_cygdrive::seekdir (DIR *dir, _off64_t loc)
+{
+ if (!iscygdrive_root ())
+ return fhandler_disk_file::seekdir (dir, loc);
+
+ for (pdrive = get_win32_name (), dir->__d_position = -1; *pdrive;
+ pdrive = strchr (pdrive, '\0') + 1)
+ if (++dir->__d_position >= loc)
+ break;
+
+ return;
+}
+
+void
+fhandler_cygdrive::rewinddir (DIR *dir)
+{
+ if (!iscygdrive_root ())
+ return fhandler_disk_file::rewinddir (dir);
+ pdrive = get_win32_name ();
+ dir->__d_position = 0;
+ return;
+}
+
+int
+fhandler_cygdrive::closedir (DIR *dir)
+{
+ if (!iscygdrive_root ())
+ return fhandler_disk_file::closedir (dir);
+ pdrive = get_win32_name ();
+ return -1;
+}
diff --git a/winsup/cygwin/fhandler_virtual.cc b/winsup/cygwin/fhandler_virtual.cc
new file mode 100644
index 00000000000..74d25bd6f43
--- /dev/null
+++ b/winsup/cygwin/fhandler_virtual.cc
@@ -0,0 +1,233 @@
+/* fhandler_virtual.cc: base fhandler class for virtual filesystems
+
+ Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/cygwin.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "shared_info.h"
+#include "cygheap.h"
+#include <assert.h>
+
+#include <dirent.h>
+
+fhandler_virtual::fhandler_virtual ():
+ fhandler_base (), filebuf (NULL), bufalloc ((size_t) -1),
+ fileid (-1)
+{
+}
+
+fhandler_virtual::~fhandler_virtual ()
+{
+ if (filebuf)
+ free (filebuf);
+ filebuf = NULL;
+}
+
+void
+fhandler_virtual::fixup_after_exec (HANDLE)
+{
+ if (filebuf)
+ filebuf = NULL;
+}
+
+DIR *
+fhandler_virtual::opendir ()
+{
+ DIR *dir;
+ DIR *res = NULL;
+ size_t len;
+
+ if (exists () <= 0)
+ set_errno (ENOTDIR);
+ else if ((len = strlen (get_name ())) > CYG_MAX_PATH - 3)
+ set_errno (ENAMETOOLONG);
+ else if ((dir = (DIR *) malloc (sizeof (DIR))) == NULL)
+ set_errno (ENOMEM);
+ else if ((dir->__d_dirname = (char *) malloc (len + 3)) == NULL)
+ {
+ free (dir);
+ set_errno (ENOMEM);
+ }
+ else if ((dir->__d_dirent =
+ (struct dirent *) malloc (sizeof (struct dirent))) == NULL)
+ {
+ free (dir);
+ set_errno (ENOMEM);
+ }
+ else
+ {
+ strcpy (dir->__d_dirname, get_name ());
+ dir->__d_dirent->d_version = __DIRENT_VERSION;
+ cygheap_fdnew fd;
+ if (fd >= 0)
+ {
+ fd = this;
+ fd->set_nohandle (true);
+ dir->__d_dirent->d_fd = fd;
+ dir->__fh = this;
+ dir->__d_cookie = __DIRENT_COOKIE;
+ dir->__handle = INVALID_HANDLE_VALUE;
+ dir->__d_position = 0;
+ dir->__d_dirhash = get_namehash ();
+
+ res = dir;
+ }
+ }
+
+ syscall_printf ("%p = opendir (%s)", res, get_name ());
+ return res;
+}
+
+_off64_t fhandler_virtual::telldir (DIR * dir)
+{
+ return dir->__d_position;
+}
+
+void
+fhandler_virtual::seekdir (DIR * dir, _off64_t loc)
+{
+ dir->__d_position = loc;
+ return;
+}
+
+void
+fhandler_virtual::rewinddir (DIR * dir)
+{
+ dir->__d_position = 0;
+ return;
+}
+
+int
+fhandler_virtual::closedir (DIR * dir)
+{
+ return 0;
+}
+
+_off64_t
+fhandler_virtual::lseek (_off64_t offset, int whence)
+{
+ /*
+ * On Linux, when you lseek within a /proc file,
+ * the contents of the file are updated.
+ */
+ if (!fill_filebuf ())
+ return (_off64_t) -1;
+ switch (whence)
+ {
+ case SEEK_SET:
+ position = offset;
+ break;
+ case SEEK_CUR:
+ position += offset;
+ break;
+ case SEEK_END:
+ position = filesize + offset;
+ break;
+ default:
+ set_errno (EINVAL);
+ return (_off64_t) -1;
+ }
+ return position;
+}
+
+int
+fhandler_virtual::dup (fhandler_base * child)
+{
+ int ret = fhandler_base::dup (child);
+
+ if (!ret)
+ {
+ fhandler_virtual *fhproc_child = (fhandler_virtual *) child;
+ fhproc_child->filebuf = (char *) malloc (filesize);
+ fhproc_child->bufalloc = fhproc_child->filesize = filesize;
+ fhproc_child->position = position;
+ memcpy (fhproc_child->filebuf, filebuf, filesize);
+ fhproc_child->set_flags (get_flags ());
+ }
+ return ret;
+}
+
+int
+fhandler_virtual::close ()
+{
+ if (filebuf)
+ free (filebuf);
+ filebuf = NULL;
+ bufalloc = (size_t) -1;
+ user_shared->delqueue.process_queue ();
+ return 0;
+}
+
+void
+fhandler_virtual::read (void *ptr, size_t& len)
+{
+ if (len == 0)
+ return;
+ if (openflags & O_DIROPEN)
+ {
+ set_errno (EISDIR);
+ len = (size_t) -1;
+ return;
+ }
+ if (!filebuf)
+ {
+ len = (size_t) 0;
+ return;
+ }
+ if ((ssize_t) len > filesize - position)
+ len = (size_t) (filesize - position);
+ if ((ssize_t) len < 0)
+ len = 0;
+ else
+ memcpy (ptr, filebuf + position, len);
+ position += len;
+}
+
+int
+fhandler_virtual::write (const void *ptr, size_t len)
+{
+ set_errno (EACCES);
+ return -1;
+}
+
+/* low-level open for all proc files */
+int
+fhandler_virtual::open (int flags, mode_t mode)
+{
+ set_r_binary (1);
+ set_w_binary (1);
+
+ /* what to do about symlinks? */
+ set_symlink_p (false);
+ set_execable_p (not_executable);
+ set_socket_p (false);
+
+ set_flags ((flags & ~O_TEXT) | O_BINARY);
+
+ return 1;
+}
+
+int
+fhandler_virtual::exists ()
+{
+ return 0;
+}
+
+bool
+fhandler_virtual::fill_filebuf ()
+{
+ return true;
+}
diff --git a/winsup/cygwin/pinfo.cc b/winsup/cygwin/pinfo.cc
index 4a01193ae8b..c53ff9125ba 100644
--- a/winsup/cygwin/pinfo.cc
+++ b/winsup/cygwin/pinfo.cc
@@ -258,7 +258,7 @@ pinfo::set_acl()
void
_pinfo::set_ctty (tty_min *tc, int flags, fhandler_tty_slave *arch)
{
- debug_printf ("checking if /dev/tty%d differs from input", ctty);
+ debug_printf ("checking if /dev/tty%d changed", ctty);
if ((ctty < 0 || ctty == tc->ntty) && !(flags & O_NOCTTY))
{
ctty = tc->ntty;
diff --git a/winsup/cygwin/sigproc.cc b/winsup/cygwin/sigproc.cc
index ad0a242cf2c..a7ace07a524 100644
--- a/winsup/cygwin/sigproc.cc
+++ b/winsup/cygwin/sigproc.cc
@@ -593,7 +593,7 @@ sig_dispatch_pending ()
if (exit_state || GetCurrentThreadId () == sigtid || !sigqueue.start.next)
{
#ifdef DEBUGGING
- sigproc_printf ("exit_state %d, GetCurrentThreadId () %p, sigtid %p, sigqueue.start.next %p",
+ sigproc_printf ("exit_state %d, cur thread id %p, sigtid %p, sigqueue.start.next %p",
exit_state, GetCurrentThreadId (), sigtid, sigqueue.start.next);
#endif
return 0;
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index 9e2d4dd8f41..c8a7129e67a 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -327,10 +327,10 @@ setsid (void)
myself->ctty = -1;
myself->sid = getpid ();
myself->pgid = getpid ();
- syscall_printf ("sid %d, pgid %d, ctty %d, open_fhs %d", myself->sid,
- myself->pgid, myself->ctty, cygheap->open_fhs);
if (cygheap->ctty)
cygheap->close_ctty ();
+ syscall_printf ("sid %d, pgid %d, ctty %d, open_fhs %d", myself->sid,
+ myself->pgid, myself->ctty, cygheap->open_fhs);
return myself->sid;
}
@@ -1239,103 +1239,21 @@ lstat (const char *name, struct __stat32 *buf)
return ret;
}
-int
-access_worker (path_conv& real_path, int flags, fhandler_base *fh)
-{
- if (real_path.error)
- {
- set_errno (real_path.error);
- return -1;
- }
-
- if (!real_path.exists ())
- {
- set_errno (ENOENT);
- return -1;
- }
-
- if (!(flags & (R_OK | W_OK | X_OK)))
- return 0;
-
- if (real_path.is_fs_special ())
- /* short circuit */;
- else if (real_path.has_attribute (FILE_ATTRIBUTE_READONLY) && (flags & W_OK))
- {
- set_errno (EACCES);
- return -1;
- }
- else if (real_path.has_acls () && allow_ntsec)
- return check_file_access (real_path, flags);
-
- struct __stat64 st;
- int r = fh ? fh->fstat (&st) : stat_worker (real_path, &st, 0);
- if (r)
- return -1;
- r = -1;
- if (flags & R_OK)
- {
- if (st.st_uid == myself->uid)
- {
- if (!(st.st_mode & S_IRUSR))
- goto done;
- }
- else if (st.st_gid == myself->gid)
- {
- if (!(st.st_mode & S_IRGRP))
- goto done;
- }
- else if (!(st.st_mode & S_IROTH))
- goto done;
- }
- if (flags & W_OK)
- {
- if (st.st_uid == myself->uid)
- {
- if (!(st.st_mode & S_IWUSR))
- goto done;
- }
- else if (st.st_gid == myself->gid)
- {
- if (!(st.st_mode & S_IWGRP))
- goto done;
- }
- else if (!(st.st_mode & S_IWOTH))
- goto done;
- }
- if (flags & X_OK)
- {
- if (st.st_uid == myself->uid)
- {
- if (!(st.st_mode & S_IXUSR))
- goto done;
- }
- else if (st.st_gid == myself->gid)
- {
- if (!(st.st_mode & S_IXGRP))
- goto done;
- }
- else if (!(st.st_mode & S_IXOTH))
- goto done;
- }
- r = 0;
-done:
- if (r)
- set_errno (EACCES);
- return r;
-}
-
extern "C" int
access (const char *fn, int flags)
{
// flags were incorrectly specified
+ int res = -1;
if (flags & ~(F_OK|R_OK|W_OK|X_OK))
+ set_errno (EINVAL);
+ else
{
- set_errno (EINVAL);
- return -1;
+ fhandler_base *fh = build_fh_name (fn, NULL, PC_SYM_FOLLOW | PC_FULL, stat_suffixes);
+ res = fh->fhaccess (flags);
+ delete fh;
}
-
- path_conv pc (fn, PC_SYM_FOLLOW | PC_FULL, stat_suffixes);
- return access_worker (pc, flags);
+ debug_printf ("returning %d", res);
+ return res;
}
extern "C" int
diff --git a/winsup/cygwin/winsup.h b/winsup/cygwin/winsup.h
new file mode 100644
index 00000000000..c92f12dd0cc
--- /dev/null
+++ b/winsup/cygwin/winsup.h
@@ -0,0 +1,358 @@
+/* winsup.h: main Cygwin header file.
+
+ Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifdef DEBUGIT
+#define spf(a, b, c) small_printf (a, b, c)
+#else
+#define spf(a, b, c) do {} while (0)
+#endif
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define __INSIDE_CYGWIN__
+
+#define strlen __builtin_strlen
+#define strcmp __builtin_strcmp
+#define strcpy __builtin_strcpy
+#define memcpy __builtin_memcpy
+#define memcmp __builtin_memcmp
+#ifdef HAVE_BUILTIN_MEMSET
+# define memset __builtin_memset
+#endif
+
+#define NO_COPY __attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy")))
+#define NO_COPY_INIT __attribute__((section(".data_cygwin_nocopy")))
+
+#if !defined(__STDC_VERSION__) || __STDC_VERSION__ >= 199900L
+#define NEW_MACRO_VARARGS
+#endif
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+
+#include <sys/types.h>
+#include <sys/strace.h>
+
+/* Declarations for functions used in C and C++ code. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern __uid32_t getuid32 (void);
+extern __uid32_t geteuid32 (void);
+extern int seteuid32 (__uid32_t);
+extern __gid32_t getegid32 (void);
+extern struct passwd *getpwuid32 (__uid32_t);
+extern struct passwd *getpwnam (const char *);
+extern struct __sFILE64 *fopen64 (const char *, const char *);
+extern struct hostent *cygwin_gethostbyname (const char *name);
+extern unsigned long cygwin_inet_addr (const char *cp);
+
+#ifdef __cplusplus
+}
+#endif
+
+/* Note that MAX_PATH is defined in the windows headers */
+/* There is also PATH_MAX and MAXPATHLEN.
+ PATH_MAX is from Posix and does *not* include the trailing NUL.
+ MAXPATHLEN is from Unix.
+
+ Thou shalt use CYG_MAX_PATH throughout. It avoids the NUL vs no-NUL
+ issue and is neither of the Unixy ones [so we can punt on which
+ one is the right one to use].
+
+ Windows ANSI calls are limited to MAX_PATH in length. Cygwin calls that
+ thunk through to Windows Wide calls are limited to 32K. We define
+ CYG_MAX_PATH as a convenient, not to short, not too long 'happy medium'.
+
+ */
+
+#define CYG_MAX_PATH (MAX_PATH)
+
+#ifdef __cplusplus
+
+extern const char case_folded_lower[];
+#define cyg_tolower(c) (case_folded_lower[(unsigned char)(c)])
+extern const char case_folded_upper[];
+#define cyg_toupper(c) (case_folded_upper[(unsigned char)(c)])
+
+#ifndef MALLOC_DEBUG
+#define cfree newlib_cfree_dont_use
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#define _WINGDI_H
+#define _WINUSER_H
+#define _WINNLS_H
+#define _WINVER_H
+#define _WINNETWK_H
+#define _WINSVC_H
+#include <windows.h>
+#include <wincrypt.h>
+#include <lmcons.h>
+#undef _WINGDI_H
+#undef _WINUSER_H
+#undef _WINNLS_H
+#undef _WINVER_H
+#undef _WINNETWK_H
+#undef _WINSVC_H
+
+#include "wincap.h"
+
+/* The one function we use from winuser.h most of the time */
+extern "C" DWORD WINAPI GetLastError (void);
+
+enum codepage_type {ansi_cp, oem_cp};
+extern codepage_type current_codepage;
+
+UINT get_cp ();
+
+int __stdcall sys_wcstombs(char *, const WCHAR *, int)
+ __attribute__ ((regparm(3)));
+
+int __stdcall sys_mbstowcs(WCHAR *, const char *, int)
+ __attribute__ ((regparm(3)));
+
+/* Used to check if Cygwin DLL is dynamically loaded. */
+extern int dynamically_loaded;
+
+extern int cygserver_running;
+
+#define _MT_SAFE // DELTEME someday
+
+#define TITLESIZE 1024
+
+/* status bit manipulation */
+#define __ISSETF(what, x, prefix) \
+ ((what)->status & prefix##_##x)
+#define __SETF(what, x, prefix) \
+ ((what)->status |= prefix##_##x)
+#define __CLEARF(what, x, prefix) \
+ ((what)->status &= ~prefix##_##x)
+#define __CONDSETF(n, what, x, prefix) \
+ ((n) ? __SETF (what, x, prefix) : __CLEARF (what, x, prefix))
+
+#include "debug.h"
+
+/* Events/mutexes */
+extern HANDLE title_mutex;
+
+/**************************** Convenience ******************************/
+
+/* Used when treating / and \ as equivalent. */
+#define isdirsep(ch) \
+ ({ \
+ char __c = (ch); \
+ ((__c) == '/' || (__c) == '\\'); \
+ })
+
+/* Convert a signal to a signal mask */
+#define SIGTOMASK(sig) (1 << ((sig) - signal_shift_subtract))
+extern unsigned int signal_shift_subtract;
+
+#ifdef NEW_MACRO_VARARGS
+# define api_fatal(...) __api_fatal (__VA_ARGS__)
+#else
+# define api_fatal(fmt, args...) __api_fatal ("%P: *** " fmt,## args)
+#endif
+
+#undef issep
+#define issep(ch) (strchr (" \t\n\r", (ch)) != NULL)
+
+#define isabspath(p) \
+ (isdirsep (*(p)) || (isalpha (*(p)) && (p)[1] == ':' && (!(p)[2] || isdirsep ((p)[2]))))
+
+/******************** Initialization/Termination **********************/
+
+class per_process;
+/* cygwin .dll initialization */
+void dll_crt0 (per_process *) __asm__ ("_dll_crt0__FP11per_process");
+extern "C" void __stdcall _dll_crt0 ();
+
+/* dynamically loaded dll initialization */
+extern "C" int dll_dllcrt0 (HMODULE, per_process *);
+
+/* dynamically loaded dll initialization for non-cygwin apps */
+extern "C" int dll_noncygwin_dllcrt0 (HMODULE, per_process *);
+
+/* exit the program */
+
+enum exit_states
+ {
+ ES_NOT_EXITING = 0,
+ ES_EVENTS_TERMINATE,
+ ES_THREADTERM,
+ ES_SIGNAL,
+ ES_CLOSEALL,
+ ES_SIGPROCTERMINATE,
+ ES_TITLE,
+ ES_HUP_PGRP,
+ ES_HUP_SID,
+ ES_TTY_TERMINATE
+ };
+
+extern exit_states exit_state;
+void __stdcall do_exit (int) __attribute__ ((regparm (1), noreturn));
+
+/* UID/GID */
+void uinfo_init (void);
+
+#define ILLEGAL_UID16 ((__uid16_t)-1)
+#define ILLEGAL_UID ((__uid32_t)-1)
+#define ILLEGAL_GID16 ((__gid16_t)-1)
+#define ILLEGAL_GID ((__gid32_t)-1)
+#define ILLEGAL_SEEK ((_off64_t)-1)
+
+#define uid16touid32(u16) ((u16)==ILLEGAL_UID16?ILLEGAL_UID:(__uid32_t)(u16))
+#define gid16togid32(g16) ((g16)==ILLEGAL_GID16?ILLEGAL_GID:(__gid32_t)(g16))
+
+/* various events */
+void events_init (void);
+void events_terminate (void);
+
+void __stdcall close_all_files (void);
+
+/* Invisible window initialization/termination. */
+HWND __stdcall gethwnd (void);
+/* Check if running in a visible window station. */
+extern bool has_visible_window_station (void);
+
+/* Globals that handle initialization of winsock in a child process. */
+extern HANDLE wsock32_handle;
+extern HANDLE ws2_32_handle;
+
+/* Globals that handle initialization of netapi in a child process. */
+extern HANDLE netapi32_handle;
+
+/* debug_on_trap support. see exceptions.cc:try_to_debug() */
+extern "C" void error_start_init (const char*);
+extern "C" int try_to_debug (bool waitloop = 1);
+
+void set_file_api_mode (codepage_type);
+
+extern int cygwin_finished_initializing;
+
+/**************************** Miscellaneous ******************************/
+
+void __stdcall set_std_handle (int);
+int __stdcall writable_directory (const char *file);
+int __stdcall stat_dev (DWORD, int, unsigned long, struct __stat64 *);
+
+__ino64_t __stdcall hash_path_name (__ino64_t hash, const char *name) __attribute__ ((regparm(2)));
+void __stdcall nofinalslash (const char *src, char *dst) __attribute__ ((regparm(2)));
+extern "C" char *__stdcall rootdir (char *full_path) __attribute__ ((regparm(1)));
+
+/* String manipulation */
+extern "C" char *__stdcall strccpy (char *s1, const char **s2, char c);
+extern "C" int __stdcall strcasematch (const char *s1, const char *s2) __attribute__ ((regparm(2)));
+extern "C" int __stdcall strncasematch (const char *s1, const char *s2, size_t n) __attribute__ ((regparm(3)));
+extern "C" char *__stdcall strcasestr (const char *searchee, const char *lookfor) __attribute__ ((regparm(2)));
+
+/* Time related */
+void __stdcall totimeval (struct timeval *dst, FILETIME * src, int sub, int flag);
+long __stdcall to_time_t (FILETIME * ptr);
+void __stdcall to_timestruc_t (FILETIME * ptr, timestruc_t * out);
+void __stdcall time_as_timestruc_t (timestruc_t * out);
+
+void __stdcall set_console_title (char *);
+void init_console_handler ();
+void init_global_security ();
+
+int __stdcall check_null_str (const char *name) __attribute__ ((regparm(1)));
+int __stdcall check_null_empty_str (const char *name) __attribute__ ((regparm(1)));
+int __stdcall check_null_empty_str_errno (const char *name) __attribute__ ((regparm(1)));
+int __stdcall check_null_str_errno (const char *name) __attribute__ ((regparm(1)));
+int __stdcall __check_null_invalid_struct (void *s, unsigned sz) __attribute__ ((regparm(2)));
+int __stdcall __check_null_invalid_struct_errno (void *s, unsigned sz) __attribute__ ((regparm(2)));
+int __stdcall __check_invalid_read_ptr (const void *s, unsigned sz) __attribute__ ((regparm(2)));
+int __stdcall __check_invalid_read_ptr_errno (const void *s, unsigned sz) __attribute__ ((regparm(2)));
+
+#define check_null_invalid_struct(s) \
+ __check_null_invalid_struct ((s), sizeof (*(s)))
+#define check_null_invalid_struct_errno(s) \
+ __check_null_invalid_struct_errno ((s), sizeof (*(s)))
+#define check_invalid_read_struct_errno(s) \
+ __check_invalid_read_ptr_errno ((s), sizeof (*(s)))
+
+struct iovec;
+ssize_t check_iovec_for_read (const struct iovec *, int) __attribute__ ((regparm(2)));
+ssize_t check_iovec_for_write (const struct iovec *, int) __attribute__ ((regparm(2)));
+
+#define set_winsock_errno() __set_winsock_errno (__FUNCTION__, __LINE__)
+void __set_winsock_errno (const char *fn, int ln) __attribute__ ((regparm(2)));
+
+extern bool wsock_started;
+
+/* Printf type functions */
+extern "C" void __api_fatal (const char *, ...) __attribute__ ((noreturn));
+extern "C" int __small_sprintf (char *dst, const char *fmt, ...) /*__attribute__ ((regparm (2)))*/;
+extern "C" int __small_vsprintf (char *dst, const char *fmt, va_list ap) /*__attribute__ ((regparm (3)))*/;
+extern void multiple_cygwin_problem (const char *, unsigned, unsigned);
+
+int symlink_worker (const char *, const char *, bool, bool)
+ __attribute__ ((regparm (3)));
+
+class path_conv;
+
+int fcntl_worker (int fd, int cmd, void *arg);
+
+extern "C" int low_priority_sleep (DWORD) __attribute__ ((regparm (1)));
+#define SLEEP_0_STAY_LOW INFINITE
+
+size_t getshmlba (void);
+
+/**************************** Exports ******************************/
+
+extern "C" {
+int cygwin_select (int , fd_set *, fd_set *, fd_set *,
+ struct timeval *to);
+int cygwin_gethostname (char *__name, size_t __len);
+
+int kill_pgrp (pid_t, int);
+int _kill (int, int);
+int _raise (int sig);
+
+extern DWORD binmode;
+extern char _data_start__, _data_end__, _bss_start__, _bss_end__;
+extern void (*__CTOR_LIST__) (void);
+extern void (*__DTOR_LIST__) (void);
+extern SYSTEM_INFO system_info;
+};
+
+/*************************** Unsorted ******************************/
+
+#define WM_ASYNCIO 0x8000 // WM_APP
+
+
+#define STD_RBITS (S_IRUSR | S_IRGRP | S_IROTH)
+#define STD_WBITS (S_IWUSR)
+#define STD_XBITS (S_IXUSR | S_IXGRP | S_IXOTH)
+#define NO_W ~(S_IWUSR | S_IWGRP | S_IWOTH)
+#define NO_R ~(S_IRUSR | S_IRGRP | S_IROTH)
+#define NO_X ~(S_IXUSR | S_IXGRP | S_IXOTH)
+
+/* The title on program start. */
+extern char *old_title;
+extern bool display_title;
+
+extern HANDLE hMainThread;
+extern HANDLE hMainProc;
+
+extern bool cygwin_testing;
+
+extern char almost_null[];
+
+#define winsock2_active (wsadata.wVersion >= 512)
+#define winsock_active (wsadata.wVersion < 512)
+extern struct WSAData wsadata;
+
+#endif /* defined __cplusplus */