diff options
-rw-r--r-- | winsup/cygwin/ChangeLog | 26 | ||||
-rw-r--r-- | winsup/cygwin/cygheap.cc | 2 | ||||
-rw-r--r-- | winsup/cygwin/fhandler.cc | 87 | ||||
-rw-r--r-- | winsup/cygwin/fhandler.h | 1280 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_disk_file.cc | 878 | ||||
-rw-r--r-- | winsup/cygwin/fhandler_virtual.cc | 233 | ||||
-rw-r--r-- | winsup/cygwin/pinfo.cc | 2 | ||||
-rw-r--r-- | winsup/cygwin/sigproc.cc | 2 | ||||
-rw-r--r-- | winsup/cygwin/syscalls.cc | 102 | ||||
-rw-r--r-- | winsup/cygwin/winsup.h | 358 |
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 */ |