📄 dtable.cc
字号:
/* dtable.cc: file descriptor support. Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.This file is part of Cygwin.This software is a copyrighted work licensed under the terms of theCygwin license. Please consult the file "CYGWIN_LICENSE" fordetails. */#define __INSIDE_CYGWIN_NET__#include "winsup.h"#include <errno.h>#include <sys/socket.h>#include <stdlib.h>#include <stdio.h>#include <unistd.h>#include <sys/cygwin.h>#include <assert.h>#include <ntdef.h>#include <winnls.h>#define USE_SYS_TYPES_FD_SET#include <winsock.h>#include "pinfo.h"#include "cygerrno.h"#include "perprocess.h"#include "security.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygheap.h"#include "ntdll.h"static const NO_COPY DWORD std_consts[] = {STD_INPUT_HANDLE, STD_OUTPUT_HANDLE, STD_ERROR_HANDLE};static const char *handle_to_fn (HANDLE, char *);static const char NO_COPY unknown_file[] = "some disk file";/* Set aside space for the table of fds */voiddtable_init (void){ if (!cygheap->fdtab.size) cygheap->fdtab.extend (NOFILE_INCR);}void __stdcallset_std_handle (int fd){ if (fd == 0) SetStdHandle (std_consts[fd], cygheap->fdtab[fd]->get_handle ()); else if (fd <= 2) SetStdHandle (std_consts[fd], cygheap->fdtab[fd]->get_output_handle ());}voiddtable::dec_console_fds (){ if (console_fds > 0 && !--console_fds && myself->ctty != TTY_CONSOLE && !check_pty_fds()) FreeConsole ();}intdtable::extend (int howmuch){ int new_size = size + howmuch; fhandler_base **newfds; if (howmuch <= 0) return 0; /* Try to allocate more space for fd table. We can't call realloc () here to preserve old table if memory allocation fails */ if (!(newfds = (fhandler_base **) ccalloc (HEAP_ARGV, new_size, sizeof newfds[0]))) { debug_printf ("calloc failed"); return 0; } if (fds) { memcpy (newfds, fds, size * sizeof (fds[0])); cfree (fds); } size = new_size; fds = newfds; debug_printf ("size %d, fds %p", size, fds); return 1;}voiddtable::get_debugger_info (){ if (being_debugged ()) { char std[3][sizeof ("/dev/ttyNNNN")]; std[0][0] = std[1][0] = std [2][0] = '\0'; char buf[sizeof ("cYgstd %x") + 32]; sprintf (buf, "cYgstd %x %x %x", (unsigned) &std, sizeof (std[0]), 3); OutputDebugString (buf); for (int i = 0; i < 3; i++) if (std[i][0]) { path_conv pc; HANDLE h = GetStdHandle (std_consts[i]); fhandler_base *fh = build_fhandler_from_name (i, std[i], NULL, pc); if (!fh) continue; if (!fh->open (&pc, (i ? O_WRONLY : O_RDONLY) | O_BINARY, 0777)) release (i); else CloseHandle (h); } }}/* Initialize the file descriptor/handle mapping table. This function should only be called when a cygwin function is invoked by a non-cygwin function, i.e., it should only happen very rarely. */voiddtable::stdio_init (){ extern void set_console_ctty (); /* Set these before trying to output anything from strace. Also, always set them even if we're to pick up our parent's fds in case they're missed. */ if (myself->ppid_handle || ISSTATE (myself, PID_CYGPARENT)) return; HANDLE in = GetStdHandle (STD_INPUT_HANDLE); HANDLE out = GetStdHandle (STD_OUTPUT_HANDLE); HANDLE err = GetStdHandle (STD_ERROR_HANDLE); init_std_file_from_handle (0, in); /* STD_ERROR_HANDLE has been observed to be the same as STD_OUTPUT_HANDLE. We need separate handles (e.g. using pipes to pass data from child to parent). */ if (out == err) { /* Since this code is not invoked for forked tasks, we don't have to worry about the close-on-exec flag here. */ if (!DuplicateHandle (hMainProc, out, hMainProc, &err, 0, 1, DUPLICATE_SAME_ACCESS)) { /* If that fails, do this as a fall back. */ err = out; system_printf ("couldn't make stderr distinct from stdout"); } } init_std_file_from_handle (1, out); init_std_file_from_handle (2, err); /* Assign the console as the controlling tty for this process if we actually have a console and no other controlling tty has been assigned. */ if (myself->ctty < 0 && GetConsoleCP () > 0) set_console_ctty ();}intdtable::find_unused_handle (int start){ AssertResourceOwner (LOCK_FD_LIST, READ_LOCK); do { for (size_t i = start; i < size; i++) /* See if open -- no need for overhead of not_open */ if (fds[i] == NULL) return i; } while (extend (NOFILE_INCR)); return -1;}voiddtable::release (int fd){ if (!not_open (fd)) { switch (fds[fd]->get_device ()) { case FH_SOCKET: dec_need_fixup_before (); break; case FH_CONSOLE: dec_console_fds (); break; } delete fds[fd]; fds[fd] = NULL; }}extern "C" intcygwin_attach_handle_to_fd (char *name, int fd, HANDLE handle, mode_t bin, DWORD myaccess){ if (fd == -1) fd = cygheap->fdtab.find_unused_handle (); path_conv pc; fhandler_base *res = cygheap->fdtab.build_fhandler_from_name (fd, name, handle, pc); res->init (handle, myaccess, bin ?: pc.binmode ()); return fd;}voiddtable::init_std_file_from_handle (int fd, HANDLE handle){ const char *name; CONSOLE_SCREEN_BUFFER_INFO buf; struct sockaddr sa; int sal = sizeof (sa); DCB dcb; unsigned bin = O_BINARY; first_fd_for_open = 0; if (!not_open (fd)) return; SetLastError (0); DWORD ft = GetFileType (handle); if (ft == FILE_TYPE_UNKNOWN && GetLastError () == ERROR_INVALID_HANDLE) name = NULL; else { /* See if we can consoleify it */ if (GetConsoleScreenBufferInfo (handle, &buf)) { if (ISSTATE (myself, PID_USETTY)) name = "/dev/tty"; else name = "/dev/conout"; } else if (GetNumberOfConsoleInputEvents (handle, (DWORD *) &buf)) { if (ISSTATE (myself, PID_USETTY)) name = "/dev/tty"; else name = "/dev/conin"; } else if (ft == FILE_TYPE_PIPE) { if (fd == 0) name = "/dev/piper"; else name = "/dev/pipew"; } else if (wsock_started && getpeername ((SOCKET) handle, &sa, &sal) == 0) name = "/dev/socket"; else if (GetCommState (handle, &dcb)) name = "/dev/ttyS0"; // FIXME - determine correct device else { name = handle_to_fn (handle, (char *) alloca (MAX_PATH + 100)); bin = 0; } } if (!name) fds[fd] = NULL; else { path_conv pc; fhandler_base *fh = build_fhandler_from_name (fd, name, handle, pc); if (!bin) { bin = fh->get_default_fmode (O_RDWR); if (!bin && name != unknown_file) bin = pc.binmode (); } fh->init (handle, GENERIC_READ | GENERIC_WRITE, bin); set_std_handle (fd); paranoid_printf ("fd %d, handle %p", fd, handle); }}fhandler_base *dtable::build_fhandler_from_name (int fd, const char *name, HANDLE handle, path_conv& pc, unsigned opt, suffix_info *si){ pc.check (name, opt | PC_NULLEMPTY | PC_FULL | PC_POSIX, si); if (pc.error) { set_errno (pc.error); return NULL; } if (!pc.exists () && handle) pc.fillin (handle); fhandler_base *fh = build_fhandler (fd, pc.get_devn (), pc.return_and_clear_normalized_path (), pc, pc.get_unitn ()); return fh;}fhandler_base *dtable::build_fhandler (int fd, DWORD dev, const char *unix_name, const char *win32_name, int unit){ return build_fhandler (fd, dev, cstrdup (unix_name), win32_name, unit);}#define cnew(name) new ((void *) ccalloc (HEAP_FHANDLER, 1, sizeof (name))) namefhandler_base *dtable::build_fhandler (int fd, DWORD dev, char *unix_name, const char *win32_name, int unit){ fhandler_base *fh; dev &= FH_DEVMASK; switch (dev) { case FH_TTYM: fh = cnew (fhandler_tty_master) (unit); break; case FH_CONSOLE: case FH_CONIN: case FH_CONOUT: if ((fh = cnew (fhandler_console) ())) inc_console_fds (); break; case FH_PTYM: fh = cnew (fhandler_pty_master) (); break; case FH_TTYS: if (unit < 0) fh = cnew (fhandler_tty_slave) (); else fh = cnew (fhandler_tty_slave) (unit); break; case FH_WINDOWS: fh = cnew (fhandler_windows) (); break; case FH_SERIAL: fh = cnew (fhandler_serial) (unit); break; case FH_PIPE: case FH_PIPER: case FH_PIPEW: fh = cnew (fhandler_pipe) (dev); break; case FH_SOCKET: if ((fh = cnew (fhandler_socket) ())) inc_need_fixup_before (); break; case FH_DISK: fh = cnew (fhandler_disk_file) (); break; case FH_CYGDRIVE: fh = cnew (fhandler_cygdrive) (unit); break; case FH_FLOPPY: fh = cnew (fhandler_dev_floppy) (unit); break; case FH_TAPE: fh = cnew (fhandler_dev_tape) (unit); break; case FH_NULL: fh = cnew (fhandler_dev_null) (); break; case FH_ZERO: fh = cnew (fhandler_dev_zero) (); break; case FH_RANDOM: fh = cnew (fhandler_dev_random) (unit); break; case FH_MEM: fh = cnew (fhandler_dev_mem) (unit); break; case FH_CLIPBOARD: fh = cnew (fhandler_dev_clipboard) (); break; case FH_OSS_DSP: fh = cnew (fhandler_dev_dsp) (); break; case FH_PROC: fh = cnew (fhandler_proc) (); break; case FH_REGISTRY: fh = cnew (fhandler_registry) (); break; case FH_PROCESS: fh = cnew (fhandler_process) (); break; default: system_printf ("internal error -- unknown device - %p", dev); fh = NULL; } if (unix_name) { char new_win32_name[strlen (unix_name) + 1]; if (!win32_name) { char *p; /* FIXME: ? Should we call win32_device_name here?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -