Index: uspace/lib/c/generic/io/io.c
===================================================================
--- uspace/lib/c/generic/io/io.c	(revision bea710f19a6538b895bdc9a355fa66cc74085d13)
+++ uspace/lib/c/generic/io/io.c	(revision bd5414ee4afeba7c42b1fe5e76e4b76c086fea2d)
@@ -64,5 +64,5 @@
 	.buf_head = NULL,
 	.buf_tail = NULL,
-	.buf_state = _bs_empty
+	.buf_state = _bs_empty,
 };
 
@@ -466,8 +466,18 @@
 		return 0;
 
+	bytes_left = size * nmemb;
+	total_read = 0;
+	dp = (uint8_t *) dest;
+
+	/* Bytes from ungetc() buffer */
+	while (stream->ungetc_chars > 0 && bytes_left > 0) {
+		*dp++ = stream->ungetc_buf[--stream->ungetc_chars];
+		++total_read;
+	}
+
 	/* If not buffered stream, read in directly. */
 	if (stream->btype == _IONBF) {
-		now = _fread(dest, size, nmemb, stream);
-		return now;
+		total_read += _fread(dest, 1, bytes_left, stream);
+		return total_read / size;
 	}
 
@@ -481,8 +491,4 @@
 			return 0; /* Errno set by _fallocbuf(). */
 	}
-
-	bytes_left = size * nmemb;
-	total_read = 0;
-	dp = (uint8_t *) dest;
 
 	while ((!stream->error) && (!stream->eof) && (bytes_left > 0)) {
@@ -674,4 +680,19 @@
 }
 
+int ungetc(int c, FILE *stream)
+{
+	if (c == EOF)
+		return EOF;
+
+	if (stream->ungetc_chars >= UNGETC_MAX)
+		return EOF;
+
+	stream->ungetc_buf[stream->ungetc_chars++] =
+	    (uint8_t)c;
+
+	stream->eof = false;
+	return (uint8_t)c;
+}
+
 int fseek(FILE *stream, off64_t offset, int whence)
 {
@@ -679,4 +700,5 @@
 
 	_fflushbuf(stream);
+	stream->ungetc_chars = 0;
 
 	rc = lseek(stream->fd, offset, whence);
@@ -693,5 +715,5 @@
 {
 	_fflushbuf(stream);
-	return lseek(stream->fd, 0, SEEK_CUR);
+	return lseek(stream->fd, 0, SEEK_CUR) - stream->ungetc_chars;
 }
 
Index: uspace/lib/c/generic/private/stdio.h
===================================================================
--- uspace/lib/c/generic/private/stdio.h	(revision bea710f19a6538b895bdc9a355fa66cc74085d13)
+++ uspace/lib/c/generic/private/stdio.h	(revision bd5414ee4afeba7c42b1fe5e76e4b76c086fea2d)
@@ -39,4 +39,7 @@
 #include <stdio.h>
 #include <async.h>
+
+/** Maximum characters that can be pushed back by ungetc() */
+#define UNGETC_MAX 1
 
 struct _IO_FILE {
@@ -82,4 +85,10 @@
 	/** Points to end of occupied space when in read mode. */
 	uint8_t *buf_tail;
+
+	/** Pushed back characters */
+	uint8_t ungetc_buf[UNGETC_MAX];
+
+	/** Number of pushed back characters */
+	int ungetc_chars;
 };
 
Index: uspace/lib/c/include/stdio.h
===================================================================
--- uspace/lib/c/include/stdio.h	(revision bea710f19a6538b895bdc9a355fa66cc74085d13)
+++ uspace/lib/c/include/stdio.h	(revision bd5414ee4afeba7c42b1fe5e76e4b76c086fea2d)
@@ -109,4 +109,6 @@
 extern int puts(const char *);
 
+extern int ungetc(int, FILE *);
+
 /* Formatted string output functions */
 extern int fprintf(FILE *, const char*, ...)
Index: uspace/lib/posix/source/stdio.c
===================================================================
--- uspace/lib/posix/source/stdio.c	(revision bea710f19a6538b895bdc9a355fa66cc74085d13)
+++ uspace/lib/posix/source/stdio.c	(revision bd5414ee4afeba7c42b1fe5e76e4b76c086fea2d)
@@ -118,33 +118,5 @@
 int posix_ungetc(int c, FILE *stream)
 {
-	uint8_t b = (uint8_t) c;
-
-	bool can_unget =
-	    /* Provided character is legal. */
-	    c != EOF &&
-	    /* Stream is consistent. */
-	    !stream->error &&
-	    /* Stream is buffered. */
-	    stream->btype != _IONBF &&
-	    /* Last operation on the stream was a read operation. */
-	    stream->buf_state == _bs_read &&
-	    /* Stream buffer is already allocated (i.e. there was already carried
-	     * out either write or read operation on the stream). This is probably
-	     * redundant check but let's be safe. */
-	    stream->buf != NULL &&
-	    /* There is still space in the stream to retreat. POSIX demands the
-	     * possibility to unget at least 1 character. It should be always
-	     * possible, assuming the last operation on the stream read at least 1
-	     * character, because the buffer is refilled in the lazily manner. */
-	    stream->buf_tail > stream->buf;
-
-	if (can_unget) {
-		--stream->buf_tail;
-		stream->buf_tail[0] = b;
-		stream->eof = false;
-		return (int) b;
-	} else {
-		return EOF;
-	}
+	return ungetc(c, stream);
 }
 
