Make FILE*s less usable after fclose(3).

BSD doesn't invalidate the fd stored in struct FILE, which can make
it possible (via fileno(3), for example), to perform operations on
an fd you didn't intend to (rather than just failing with EBADF).

Fixing this makes the code slightly simpler anyway, and might help
catch bad code before it ships.

Bug: http://stackoverflow.com/questions/10816837/fclose-works-differently-on-android-and-linux
Change-Id: I9db74584038229499197a2695c70b58ed0372a87
diff --git a/libc/stdio/findfp.c b/libc/stdio/findfp.c
index 6e20562..2a6be15 100644
--- a/libc/stdio/findfp.c
+++ b/libc/stdio/findfp.c
@@ -157,3 +157,37 @@
 	/* (void) _fwalk(fclose); */
 	(void) _fwalk(__sflush);		/* `cheating' */
 }
+
+int fclose(FILE* fp) {
+    if (fp->_flags == 0) {
+        // Already freed!
+        errno = EBADF;
+        return EOF;
+    }
+
+    FLOCKFILE(fp);
+    WCIO_FREE(fp);
+    int r = fp->_flags & __SWR ? __sflush(fp) : 0;
+    if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) {
+        r = EOF;
+    }
+    if (fp->_flags & __SMBF) free(fp->_bf._base);
+    if (HASUB(fp)) FREEUB(fp);
+    if (HASLB(fp)) FREELB(fp);
+
+    // Poison this FILE so accesses after fclose will be obvious.
+    fp->_file = -1;
+    fp->_r = fp->_w = 0;
+
+    // Release this FILE for reuse.
+    fp->_flags = 0;
+    FUNLOCKFILE(fp);
+    return (r);
+}
+
+int fileno(FILE* fp) {
+    FLOCKFILE(fp);
+    int result = fileno_unlocked(fp);
+    FUNLOCKFILE(fp);
+    return result;
+}
diff --git a/libc/stdio/local.h b/libc/stdio/local.h
index 6dcd3ae..a15bddf 100644
--- a/libc/stdio/local.h
+++ b/libc/stdio/local.h
@@ -215,7 +215,6 @@
 #define __sfeof(p)     (((p)->_flags & __SEOF) != 0)
 #define __sferror(p)   (((p)->_flags & __SERR) != 0)
 #define __sclearerr(p) ((void)((p)->_flags &= ~(__SERR|__SEOF)))
-#define __sfileno(p)   ((p)->_file)
 #if !defined(__cplusplus)
 #define __sgetc(p) (--(p)->_r < 0 ? __srget(p) : (int)(*(p)->_p++))
 static __inline int __sputc(int _c, FILE* _p) {
diff --git a/libc/stdio/stdio_ext.cpp b/libc/stdio/stdio_ext.cpp
index f273d45..88e5951 100644
--- a/libc/stdio/stdio_ext.cpp
+++ b/libc/stdio/stdio_ext.cpp
@@ -27,6 +27,8 @@
  */
 
 #include <stdio_ext.h>
+
+#include <errno.h>
 #include <stdlib.h>
 
 #include "local.h"
@@ -101,5 +103,10 @@
 }
 
 int fileno_unlocked(FILE* fp) {
-  return __sfileno(fp);
+  int fd = fp->_file;
+  if (fd == -1) {
+    errno = EBADF;
+    return -1;
+  }
+  return fd;
 }