⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fhandler.cc

📁 cygwin, 著名的在win32下模拟unix操作系统的东东
💻 CC
📖 第 1 页 / 共 2 页
字号:
/* fhandler.cc.  See console.cc for fhandler_console functions.   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. */#include "winsup.h"#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <sys/cygwin.h>#include <sys/uio.h>#include <signal.h>#include "cygerrno.h"#include "perprocess.h"#include "security.h"#include "cygwin/version.h"#include "fhandler.h"#include "path.h"#include "dtable.h"#include "cygheap.h"#include "shared_info.h"#include "pinfo.h"#include <assert.h>#include <limits.h>static NO_COPY const int CHUNK_SIZE = 1024; /* Used for crlf conversions */struct __cygwin_perfile *perfile_table;DWORD binmode;inline fhandler_base&fhandler_base::operator =(fhandler_base &x){  memcpy (this, &x, sizeof *this);  unix_path_name = x.unix_path_name ? cstrdup (x.unix_path_name) : NULL;  win32_path_name = x.win32_path_name ? cstrdup (x.win32_path_name) : NULL;  rabuf = NULL;  ralen = 0;  raixget = 0;  raixput = 0;  rabuflen = 0;  return *this;}intfhandler_base::puts_readahead (const char *s, size_t len){  int success = 1;  while ((*s || (len != (size_t) -1 && len--))	 && (success = put_readahead (*s++) > 0))    continue;  return success;}intfhandler_base::put_readahead (char value){  char *newrabuf;  if (raixput < rabuflen)    /* Nothing to do */;  else if ((newrabuf = (char *) realloc (rabuf, rabuflen += 32)))    rabuf = newrabuf;  else    return 0;  rabuf[raixput++] = value;  ralen++;  return 1;}intfhandler_base::get_readahead (){  int chret = -1;  if (raixget < ralen)    chret = ((unsigned char) rabuf[raixget++]) & 0xff;  /* FIXME - not thread safe */  if (raixget >= ralen)    raixget = raixput = ralen = 0;  return chret;}intfhandler_base::peek_readahead (int queryput){  int chret = -1;  if (!queryput && raixget < ralen)    chret = ((unsigned char) rabuf[raixget]) & 0xff;  else if (queryput && raixput > 0)    chret = ((unsigned char) rabuf[raixput - 1]) & 0xff;  return chret;}voidfhandler_base::set_readahead_valid (int val, int ch){  if (!val)    ralen = raixget = raixput = 0;  if (ch != -1)    put_readahead (ch);}intfhandler_base::eat_readahead (int n){  int oralen = ralen;  if (n < 0)    n = ralen;  if (n > 0 && ralen)    {      if ((int) (ralen -= n) < 0)	ralen = 0;      if (raixget >= ralen)	raixget = raixput = ralen = 0;      else if (raixput > ralen)	raixput = ralen;    }  return oralen;}intfhandler_base::get_readahead_into_buffer (char *buf, size_t buflen){  int ch;  int copied_chars = 0;  while (buflen)    if ((ch = get_readahead ()) < 0)      break;    else      {	buf[copied_chars++] = (unsigned char)(ch & 0xff);	buflen--;      }  return copied_chars;}/* Record the file name.   Filenames are used mostly for debugging messages, and it's hoped that   in cases where the name is really required, the filename wouldn't ever   be too long (e.g. devices or some such).   The unix_path_name is also used by virtual fhandlers.  */voidfhandler_base::set_name (const char *unix_path, const char *win32_path, int unit){  if (unix_path == NULL || !*unix_path)    return;  if (win32_path)    win32_path_name = cstrdup (win32_path);  else    {      const char *fmt = get_native_name ();      char *w =  (char *) cmalloc (HEAP_STR, strlen (fmt) + 16);      __small_sprintf (w, fmt, unit);      win32_path_name = w;    }  if (win32_path_name == NULL)    {      system_printf ("fatal error. strdup failed");      exit (ENOMEM);    }  assert (unix_path_name == NULL);  /* FIXME: This isn't really right.  It ignores the first argument if we're     building names for a device and just converts the device name from the     win32 name since it has theoretically been previously detected by     path_conv. Ideally, we should pass in a format string and build the     unix_path, too. */  if (!is_device () || *win32_path_name != '\\')    unix_path_name = unix_path;  else    {      char *p = cstrdup (win32_path_name);      unix_path_name = p;      while ((p = strchr (p, '\\')) != NULL)	*p++ = '/';      if (unix_path)	cfree ((void *) unix_path);    }  if (unix_path_name == NULL)    {      system_printf ("fatal error. strdup failed");      exit (ENOMEM);    }  namehash = hash_path_name (0, win32_path_name);}/* Detect if we are sitting at EOF for conditions where Windows   returns an error but UNIX doesn't.  */static int __stdcallis_at_eof (HANDLE h, DWORD err){  DWORD size, upper1, curr;  size = GetFileSize (h, &upper1);  if (upper1 != 0xffffffff || GetLastError () == NO_ERROR)    {      LONG upper2 = 0;      curr = SetFilePointer (h, 0, &upper2, FILE_CURRENT);      if (curr == size && upper1 == (DWORD) upper2)	return 1;    }  SetLastError (err);  return 0;}voidfhandler_base::set_flags (int flags, int supplied_bin){  int bin;  int fmode;  debug_printf ("flags %p, supplied_bin %p", flags, supplied_bin);  if ((bin = flags & (O_BINARY | O_TEXT)))    debug_printf ("O_TEXT/O_BINARY set in flags %p", bin);  else if (get_r_binset () && get_w_binset ())    bin = get_r_binary () ? O_BINARY : O_TEXT;	// FIXME: Not quite right  else if ((fmode = get_default_fmode (flags)) & O_BINARY)    bin = O_BINARY;  else if (fmode & O_TEXT)    bin = O_TEXT;  else if (supplied_bin)    bin = supplied_bin;  else    bin = get_w_binary () || get_r_binary () || (binmode != O_TEXT)	  ? O_BINARY : O_TEXT;  openflags = flags | bin;  bin &= O_BINARY;  set_r_binary (bin);  set_w_binary (bin);  syscall_printf ("filemode set to %s", bin ? "binary" : "text");}/* Normal file i/o handlers.  *//* Cover function to ReadFile to achieve (as much as possible) Posix style   semantics and use of errno.  */intfhandler_base::raw_read (void *ptr, size_t ulen){  DWORD bytes_read;  if (!ReadFile (get_handle (), ptr, ulen, &bytes_read, 0))    {      int errcode;      /* Some errors are not really errors.  Detect such cases here.  */      errcode = GetLastError ();      switch (errcode)	{	case ERROR_BROKEN_PIPE:	  /* This is really EOF.  */	  bytes_read = 0;	  break;	case ERROR_MORE_DATA:	  /* `bytes_read' is supposedly valid.  */	  break;	case ERROR_NOACCESS:	  if (is_at_eof (get_handle (), errcode))	    return 0;	case ERROR_INVALID_FUNCTION:	case ERROR_INVALID_PARAMETER:	case ERROR_INVALID_HANDLE:	  if (openflags & O_DIROPEN)	    {	      set_errno (EISDIR);	      return -1;	    }	default:	  syscall_printf ("ReadFile %s failed, %E", unix_path_name);	  __seterrno_from_win_error (errcode);	  return -1;	  break;	}    }  return bytes_read;}/* Cover function to WriteFile to provide Posix interface and semantics   (as much as possible).  */intfhandler_base::raw_write (const void *ptr, size_t len){  DWORD bytes_written;  if (!WriteFile (get_handle (), ptr, len, &bytes_written, 0))    {      if (GetLastError () == ERROR_DISK_FULL && bytes_written > 0)	return bytes_written;      __seterrno ();      if (get_errno () == EPIPE)	raise (SIGPIPE);      return -1;    }  return bytes_written;}#define ACCFLAGS(x) (x & (O_RDONLY | O_WRONLY | O_RDWR))intfhandler_base::get_default_fmode (int flags){  int fmode = __fmode;  if (perfile_table)    {      size_t nlen = strlen (get_name ());      unsigned accflags = ACCFLAGS (flags);      for (__cygwin_perfile *pf = perfile_table; pf->name; pf++)	if (!*pf->name && ACCFLAGS (pf->flags) == accflags)	  {	    fmode = pf->flags & ~(O_RDONLY | O_WRONLY | O_RDWR);	    break;	  }	else	  {	    size_t pflen = strlen (pf->name);	    const char *stem = get_name () + nlen - pflen;	    if (pflen > nlen || (stem != get_name () && !isdirsep (stem[-1])))	      continue;	    else if (ACCFLAGS (pf->flags) == accflags && strcasematch (stem, pf->name))	      {		fmode = pf->flags & ~(O_RDONLY | O_WRONLY | O_RDWR);		break;	      }	  }    }  return fmode;}/* Open system call handler function. */intfhandler_base::open (path_conv *pc, int flags, mode_t mode){  int res = 0;  HANDLE x;  int file_attributes;  int shared;  int creation_distribution;  SECURITY_ATTRIBUTES sa = sec_none;  syscall_printf ("(%s, %p) query_open %d", get_win32_name (), flags, get_query_open ());  if (get_win32_name () == NULL)    {      set_errno (ENOENT);      goto done;    }  if (get_query_open ())    access = 0;  else if (get_device () == FH_TAPE)    access = GENERIC_READ | GENERIC_WRITE;  else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_RDONLY)    access = GENERIC_READ;  else if ((flags & (O_RDONLY | O_WRONLY | O_RDWR)) == O_WRONLY)    access = GENERIC_WRITE;  else    access = GENERIC_READ | GENERIC_WRITE;  /* Allow reliable lseek on disk devices. */  if (get_device () == FH_FLOPPY)    access |= GENERIC_READ;  /* FIXME: O_EXCL handling?  */  if ((flags & O_TRUNC) && ((flags & O_ACCMODE) != O_RDONLY))    {      if (flags & O_CREAT)	creation_distribution = CREATE_ALWAYS;      else	creation_distribution = TRUNCATE_EXISTING;    }  else if (flags & O_CREAT)    creation_distribution = OPEN_ALWAYS;  else    creation_distribution = OPEN_EXISTING;  if ((flags & O_EXCL) && (flags & O_CREAT))    creation_distribution = CREATE_NEW;  if (flags & O_APPEND)    set_append_p ();  /* These flags are host dependent. */  shared = wincap.shared ();  file_attributes = FILE_ATTRIBUTE_NORMAL;  if (flags & O_DIROPEN)    file_attributes |= FILE_FLAG_BACKUP_SEMANTICS;  if (get_device () == FH_SERIAL)    file_attributes |= FILE_FLAG_OVERLAPPED;#ifdef HIDDEN_DOT_FILES  if (flags & O_CREAT && get_device () == FH_DISK)    {      char *c = strrchr (get_win32_name (), '\\');      if ((c && c[1] == '.') || *get_win32_name () == '.')	file_attributes |= FILE_ATTRIBUTE_HIDDEN;    }#endif  /* CreateFile() with dwDesiredAccess == 0 when called on remote     share returns some handle, even if file doesn't exist. This code     works around this bug. */  if (get_query_open () && isremote () &&      creation_distribution == OPEN_EXISTING && pc && !pc->exists ())    {      set_errno (ENOENT);      goto done;    }  /* If mode has no write bits set, we set the R/O attribute. */  if (!(mode & (S_IWUSR | S_IWGRP | S_IWOTH)))    file_attributes |= FILE_ATTRIBUTE_READONLY;  /* If the file should actually be created and ntsec is on,     set files attributes. */  if (flags & O_CREAT && get_device () == FH_DISK && allow_ntsec && has_acls ())    set_security_attribute (mode, &sa, alloca (4096), 4096);  x = CreateFile (get_win32_name (), access, shared, &sa, creation_distribution,		  file_attributes, 0);  syscall_printf ("%p = CreateFile (%s, %p, %p, %p, %p, %p, 0)",		  x, get_win32_name (), access, shared, &sa,		  creation_distribution, file_attributes);  if (x == INVALID_HANDLE_VALUE)    {      if (!wincap.can_open_directories () && pc && pc->isdir ())	{	  if (mode & (O_CREAT | O_EXCL) == (O_CREAT | O_EXCL))	    set_errno (EEXIST);	  else if (mode & (O_WRONLY | O_RDWR))	    set_errno (EISDIR);	  else	    set_nohandle (true);	}      else if (GetLastError () == ERROR_INVALID_HANDLE)	set_errno (ENOENT);      else	__seterrno ();      if (!get_nohandle ())	goto done;    }  /* 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 && get_device () == FH_DISK      && GetLastError () != ERROR_ALREADY_EXISTS      && !allow_ntsec && allow_ntea)    set_file_attribute (has_acls (), get_win32_name (), mode);  set_io_handle (x);  set_flags (flags, pc ? pc->binmode () : 0);  res = 1;  set_open_status ();done:  syscall_printf ("%d = fhandler_base::open (%s, %p)", res, get_win32_name (),		  flags);  return res;}/* states:   open buffer in binary mode?  Just do the read.   open buffer in text mode?  Scan buffer for control zs and handle   the first one found.  Then scan buffer, converting every \r\n into   an \n.  If last char is an \r, look ahead one more char, if \n then   modify \r, if not, remember char.*/intfhandler_base::read (void *in_ptr, size_t in_len){  int len = (int) in_len;  char *ptr = (char *) in_ptr;  int c;  int copied_chars = 0;  while (len)    if ((c = get_readahead ()) < 0)      break;    else      {	ptr[copied_chars++] = (unsigned char) (c & 0xff);	len--;      }  if (copied_chars && is_slow ())    return copied_chars;  if (len)    {      int readlen = raw_read (ptr + copied_chars, len);      if (copied_chars == 0)	copied_chars = readlen;		/* Propagate error or EOF */      else if (readlen > 0)		/* FIXME: should flag EOF for next read */	copied_chars += readlen;    }  if (copied_chars <= 0)    return copied_chars;  if (get_r_binary ())    {      debug_printf ("returning %d chars, binary mode", copied_chars);      return copied_chars;    }#if 0  char *ctrlzpos;  /* Scan buffer for a control-z and shorten the buffer to that length */  ctrlzpos = (char *) memchr ((char *) ptr, 0x1a, copied_chars);  if (ctrlzpos)    {      lseek ((ctrlzpos - ((char *) ptr + copied_chars)), SEEK_CUR);      copied_chars = ctrlzpos - (char *) ptr;    }  if (copied_chars == 0)    {      debug_printf ("returning 0 chars, text mode, CTRL-Z found");      return 0;    }#endif  /* Scan buffer and turn \r\n into \n */  register char *src = (char *) ptr;  register char *dst = (char *) ptr;  register char *end = src + copied_chars - 1;  /* Read up to the last but one char - the last char needs special handling */  while (src < end)    {      *dst = *src++;      if (*dst != '\r' || *src != '\n')	dst++;    }  c = *src;  /* if last char is a '\r' then read one more to see if we should     translate this one too */  if (c == '\r')    {      char c1 = 0;      len = raw_read (&c1, 1);      if (len <= 0)	/* nothing */;      else if (c1 == '\n')	c = '\n';      else	set_readahead_valid (1, c1);    }  *dst++ = c;  copied_chars = dst - (char *) ptr;#ifndef NOSTRACE  if (strace.active)    {      char buf[16 * 6 + 1];      char *p = buf;      for (int i = 0; i < copied_chars && i < 16; ++i)	{	  unsigned char c = ((unsigned char *) ptr)[i];	  /* >= 33 so space prints in hex */	  __small_sprintf (p, c >= 33 && c <= 127 ? " %c" : " %p", c);	  p += strlen (p);	}      debug_printf ("read %d bytes (%s%s)", copied_chars, buf,		    copied_chars > 16 ? " ..." : "");    }#endif  debug_printf ("returning %d chars, text mode", copied_chars);  return copied_chars;}intfhandler_base::write (const void *ptr, size_t len){  int res;  if (get_append_p ())    SetFilePointer (get_handle (), 0, 0, FILE_END);  else if (wincap.has_lseek_bug () && get_check_win95_lseek_bug ())    {      /* Note: this bug doesn't happen on NT4, even though the documentation	 for WriteFile() says that it *may* happen on any OS. */      int actual_length, current_position;      set_check_win95_lseek_bug (0); /* don't do it again */      actual_length = GetFileSize (get_handle (), NULL);      current_position = SetFilePointer (get_handle (), 0, 0, FILE_CURRENT);      if (current_position > actual_length)	{	  /* Oops, this is the bug case - Win95 uses whatever is on the disk	     instead of some known (safe) value, so we must seek back and	     fill in the gap with zeros. - DJ */	  char zeros[512];	  int number_of_zeros_to_write = current_position - actual_length;	  memset (zeros, 0, 512);	  SetFilePointer (get_handle (), 0, 0, FILE_END);	  while (number_of_zeros_to_write > 0)	    {	      DWORD zeros_this_time = (number_of_zeros_to_write > 512				     ? 512 : number_of_zeros_to_write);	      DWORD written;	      if (!WriteFile (get_handle (), zeros, zeros_this_time, &written,			      NULL))		{		  __seterrno ();		  if (get_errno () == EPIPE)		    raise (SIGPIPE);		  /* This might fail, but it's the best we can hope for */		  SetFilePointer (get_handle (), current_position, 0, FILE_BEGIN);		  return -1;		}	      if (written < zeros_this_time) /* just in case */		{		  set_errno (ENOSPC);		  /* This might fail, but it's the best we can hope for */		  SetFilePointer (get_handle (), current_position, 0, FILE_BEGIN);		  return -1;		}	      number_of_zeros_to_write -= written;	    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -