Commits

Mathias Panzenböck committed 986132e

libvpk: yet another fix for the linux file copy optimization

Comments (0)

Files changed (2)

libvpk/include/vpk/file_io.h

 #include <boost/filesystem/operations.hpp>
 
 namespace Vpk {
-	// a simple binary-only FileIO based on C's FILE* functions
+	// a simple FileIO based on C's FILE* functions
 	// this is used because errno+strerror return much more meaningful
 	// error messages than iostreams
 	//
 		void rewind();
 		off_t tell();
 		size_t size() const;
-		size_t buffered() const;
+		bool seekable() const;
 
 		void flush();
 		void sync();

libvpk/src/file_io.cpp

 	return stbuf.st_size;
 }
 
-size_t Vpk::FileIO::buffered() const {
-#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
+bool Vpk::FileIO::seekable() const {
 	if (!m_stream) throw FileIOClosedError();
-	off_t pos = ftello(m_stream);
-	if (pos < 0) {
-		throw IOError(errno);
+	if (ftello(m_stream) < 0) {
+		int errnum = errno;
+		if (errnum == EBADF) {
+			return false;
+		}
+		throw IOError(errnum);
 	}
-	off_t realpos = lseek(::fileno(m_stream), 0, SEEK_CUR);
-	if (realpos < 0) {
-		throw IOError(errno);
-	}
-	if (pos > realpos) {
-		throw IOError(EIO);
-	}
-	return realpos - pos;
-#else
-	throw IOError(ENOSYS);
-#endif
+	return true;
 }
 
 void Vpk::FileIO::flush() {
 	return count;
 }
 
-#define VPK_READ_SOME \
-	char buf[BUFSIZ]; \
-	while (left > 0) { \
-		size_t chunkSize = std::min(left, (size_t)BUFSIZ); \
-		size_t count = fread(buf, 1, chunkSize, m_stream); \
-		if (count < chunkSize) { \
-			if (ferror(m_stream)) { \
-				throw IOError(errno); \
-			} \
-			else { \
-				break; \
-			} \
-		} \
-		if (fwrite(buf, count, 1, dest.m_stream) < 1) { \
-			throw IOError(errno); \
-		} \
-		left -= count; \
-	}
-
 size_t Vpk::FileIO::readSome(FileIO &dest, size_t size) {
+	if (!m_stream || !dest.m_stream) throw FileIOClosedError();
 #if (_POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE) && defined(__linux__)
-	size_t bufsize = buffered();
-	size_t left = std::min(bufsize, size);
-	VPK_READ_SOME;
-	if (left != 0) throw IOError(EOF);
-	if (bufsize < size) {
+	off_t pos = ftello(m_stream);
+	if (pos >= 0) {
 		dest.flush();
 		ssize_t count = sendfile(
 			::fileno(dest.m_stream),
-			::fileno(m_stream), 0, size - bufsize);
+			::fileno(m_stream), &pos, size);
 		if (count < 0) {
 			throw IOError(errno);
 		}
-		return bufsize + count;
+		if (fseeko(m_stream, pos, SEEK_SET) < 0) {
+			throw IOError(errno);
+		}
+		return count;
 	}
-	return size;
-#else
-	if (!m_stream || !dest.m_stream) throw FileIOClosedError();
-	size_t left = size;
-	VPK_READ_SOME;
-	return size - left;
+	else {
+#endif
+		char buf[BUFSIZ];
+		size_t left = size;
+		while (left > 0) {
+			size_t chunkSize = std::min(left, (size_t)BUFSIZ);
+			size_t count = fread(buf, 1, chunkSize, m_stream);
+			if (count < chunkSize) {
+				if (ferror(m_stream)) {
+					throw IOError(errno);
+				}
+				else {
+					break;
+				}
+			}
+			if (fwrite(buf, count, 1, dest.m_stream) < 1) {
+				throw IOError(errno);
+			}
+			left -= count;
+		}
+		return size - left;
+#if (_POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE) && defined(__linux__)
+	}
 #endif
 }