From 36ab0587c0fe388694e7904b40901e34fe7d65ba Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Fri, 1 Apr 2016 17:38:29 +0000 Subject: [PATCH] [stream] fstat() after open() to obtain file size Common case is on non-empty files, and doing fstat() after open() eliminates ToC-ToU between stat() and then open(). While file size of the target file might still change, the fstat() is on the opened file, and can not be on different file (which was possible with stat()) From: Glenn Strauss git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@3137 152afb58-edef-0310-8abb-c4023f1b3aa9 --- NEWS | 1 + src/stream.c | 60 ++++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/NEWS b/NEWS index 37034312..8b394859 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,7 @@ NEWS * [mod_status] use snprintf() instead of sprintf() * pass buf size to li_tohex() * use li_[iu]tostrn() instead of li_[iu]tostr() + * [stream] fstat() after open() to obtain file size - 1.4.39 - 2016-01-02 * [core] fix memset_s call (fixes #2698) diff --git a/src/stream.c b/src/stream.c index 51a27676..a17079c0 100644 --- a/src/stream.c +++ b/src/stream.c @@ -14,32 +14,38 @@ # define O_BINARY 0 #endif +/* don't want to block when open()ing a fifo */ +#if defined(O_NONBLOCK) +# define FIFO_NONBLOCK O_NONBLOCK +#else +# define FIFO_NONBLOCK 0 +#endif + int stream_open(stream *f, buffer *fn) { - struct stat st; + #ifdef HAVE_MMAP + + struct stat st; int fd; -#elif defined __WIN32 - HANDLE *fh, *mh; - void *p; -#endif f->start = NULL; f->size = 0; - if (-1 == stat(fn->ptr, &st)) { + if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY | FIFO_NONBLOCK))) { + return -1; + } + + if (-1 == fstat(fd, &st)) { + close(fd); return -1; } if (0 == st.st_size) { /* empty file doesn't need a mapping */ + close(fd); return 0; } -#ifdef HAVE_MMAP - if (-1 == (fd = open(fn->ptr, O_RDONLY | O_BINARY))) { - return -1; - } - f->start = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); close(fd); @@ -49,7 +55,18 @@ int stream_open(stream *f, buffer *fn) { return -1; } + f->size = st.st_size; + return 0; + #elif defined __WIN32 + + HANDLE *fh, *mh; + void *p; + LARGE_INTEGER fsize; + + f->start = NULL; + f->size = 0; + fh = CreateFile(fn->ptr, GENERIC_READ, FILE_SHARE_READ, @@ -60,11 +77,21 @@ int stream_open(stream *f, buffer *fn) { if (!fh) return -1; + if (0 != GetFileSizeEx(fh, &fsize)) { + CloseHandle(fh); + return -1; + } + + if (0 == fsize) { + CloseHandle(fh); + return 0; + } + mh = CreateFileMapping( fh, NULL, PAGE_READONLY, - (sizeof(off_t) > 4) ? st.st_size >> 32 : 0, - st.st_size & 0xffffffff, + (sizeof(off_t) > 4) ? fsize >> 32 : 0, + fsize & 0xffffffff, NULL); if (!mh) { @@ -79,6 +106,7 @@ int stream_open(stream *f, buffer *fn) { (LPTSTR) &lpMsgBuf, 0, NULL ); */ + CloseHandle(fh); return -1; } @@ -91,13 +119,13 @@ int stream_open(stream *f, buffer *fn) { CloseHandle(fh); f->start = p; + f->size = (off_t)fsize; + return 0; + #else # error no mmap found #endif - f->size = st.st_size; - - return 0; } int stream_close(stream *f) {