山本です。

EMFILE と EBADF に対処してみました。

(#undef, #define による関数のすり替えがよくわからないのですが、
  これで正しいでしょうか?)

なお、ENOMEM(mallocの失敗)と EINVAL(mode文字列が不適切)は依然と
してerrno に設定されません。

内部関数を使って、これらを設定するパッチも作ってみます。

Index: win32.h
===================================================================
RCS file: /var/cvs/src/ruby/win32/win32.h,v
retrieving revision 1.51
diff -u -w -b -p -r1.51 win32.h
--- win32.h	19 Feb 2004 09:08:23 -0000	1.51
+++ win32.h	21 Jun 2004 16:44:57 -0000
@@ -115,6 +115,16 @@ extern "C++" {
 #define sopen			_sopen
 #undef fstat
 #define fstat(fd,st)		rb_w32_fstat(fd,st)
+#undef fopen
+#define fopen(p, t)		rb_w32_fopen(p, t)
+#undef fdopen
+#define fdopen(h, t)		rb_w32_fdopen(h, t)
+#undef fsopen
+#define fsopen(p, t, f)		rb_w32_fsopen(p, t, f)
+#endif
+#if defined __BORLANDC__ || defined _WIN32_WCE
+#undef fread
+#define fread(p, m, n, stream)	rb_w32_fread(p, m, n, stream)
 #endif
 #define fsync(h)		_commit(h)
 #undef stat
@@ -178,6 +188,15 @@ extern int rb_w32_spawn(int, const char 
 extern int rb_w32_aspawn(int, const char *, char *const *);
 extern int kill(int, int);
 extern pid_t rb_w32_getpid(void);
+#ifdef __BORLANDC__
+extern int   rb_w32_fstat(int fd, struct stat *st);
+extern FILE *rb_w32_fopen(const char *path, const char *type);
+extern FILE *rb_w32_fdopen(int handle, char *type);
+extern FILE *rb_w32_fsopen(const char *path, const char *type, int shflag);
+#endif
+#if defined __BORLANDC__ || defined _WIN32_WCE
+extern size_t rb_w32_fread(void *ptr, size_t size, size_t n, FILE *stream);
+#endif
 
 #include <float.h>
 #if !defined __MINGW32__ || defined __NO_ISOCEXT


Index: win32.c
===================================================================
RCS file: /var/cvs/src/ruby/win32/win32.c,v
retrieving revision 1.117
diff -u -w -b -p -r1.117 win32.c
--- win32.c	21 Jun 2004 00:27:39 -0000	1.117
+++ win32.c	22 Jun 2004 00:39:36 -0000
@@ -2726,6 +2726,54 @@ isUNCRoot(const char *path)
 }
 
 #ifdef __BORLANDC__
+static int too_many_files(void)
+{
+    register FILE *fp;
+    for (fp = _streams; fp < _streams + _nfile; fp++)
+	if (fp->fd < 0) return 0;
+    return 1;
+}
+#undef fopen
+FILE *
+rb_w32_fopen(const char *path, const char *type)
+{
+    if (too_many_files()) {
+	errno = EMFILE;
+	return NULL;
+    }
+    else {
+	errno = 0;
+	return fopen(path, type);
+    }
+}
+FILE *
+rb_w32_fdopen(int handle, char *type)
+{
+    if (handle < 0) {
+	errno = EBADF;
+	return NULL;
+    }
+    else if (too_many_files()) {
+	errno = EMFILE;
+	return NULL;
+    }
+    else {
+	errno = 0;
+	return _fdopen(handle, type);
+    }
+}
+FILE *
+rb_w32_fsopen(const char *path, const char *type, int shflag)
+{
+    if (too_many_files()) {
+	errno = EMFILE;
+	return NULL;
+    }
+    else {
+	errno = 0;
+	return _fsopen(path, type, shflag);
+    }
+}
 #undef fstat
 int
 rb_w32_fstat(int fd, struct stat *st)
@@ -3034,10 +3082,14 @@ rb_w32_getc(FILE* stream)
     else 
 #endif
     {
+#if defined __BORLANDC__ || defined _WIN32_WCE
+	errno = 0;
+#endif
 	c = _filbuf(stream);
 #if defined __BORLANDC__ || defined _WIN32_WCE
         if ((c == EOF) && (errno == EPIPE)) {
 	    clearerr(stream);
+	    stream->flags |= _F_EOF;
         }
 #endif
 	rb_trap_immediate = trap_immediate;
@@ -3065,6 +3117,22 @@ rb_w32_putc(int c, FILE* stream)
     }
     return c;
 }
+
+#if defined __BORLANDC__ || defined _WIN32_WCE
+#undef fread
+size_t
+rb_w32_fread(void *ptr, size_t size, size_t n, FILE *stream)
+{
+    size_t i;
+    errno = 0;
+    i = fread(ptr, size, n, stream);
+    if ((i < n) && (errno == EPIPE)) {
+	clearerr(stream);
+	stream->flags |= _F_EOF;
+    }
+    return i;
+}
+#endif
 
 struct asynchronous_arg_t {
     /* output field */