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;
+}