diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2002-11-03 12:53:25 +0000 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2002-11-03 12:53:25 +0000 |
commit | 30c0872d8409df211bc8a567c8b4f23bbdc8f9af (patch) | |
tree | 7dd8031f3ac0d0316cb79a103f1b02a73b4365d8 | |
parent | 21370dbf8bf74a3b02cdb50bf8c2dfef60642244 (diff) | |
download | mailutils-30c0872d8409df211bc8a567c8b4f23bbdc8f9af.tar.gz mailutils-30c0872d8409df211bc8a567c8b4f23bbdc8f9af.tar.bz2 |
Some applications (e.g. mail.remote)
implicitly rely on the possibility to seek on stdin streams.
To provide this functionality:
(struct _file_stram): Added cache member.
It is a memory stream used to provide seeking capability for
stdio streams.
(_file_destroy): Destroy cache if necessary.
(_stdin_file_read,_stdin_file_readline,_stdout_file_write): New
functions. Provide IO operations for stdio streams.
(stdio_stream_create): Register new IO functions.
-rw-r--r-- | mailbox/file_stream.c | 111 |
1 files changed, 108 insertions, 3 deletions
diff --git a/mailbox/file_stream.c b/mailbox/file_stream.c index 8fc9014a9..3a09bf6d8 100644 --- a/mailbox/file_stream.c +++ b/mailbox/file_stream.c @@ -39,6 +39,7 @@ struct _file_stream int offset; char *filename; + stream_t cache; }; static void @@ -51,6 +52,8 @@ _file_destroy (stream_t stream) if (fs->filename) free (fs->filename); + if (fs->cache) + stream_destroy (&fs->cache, stream_get_owner (fs->cache)); free (fs); } @@ -173,6 +176,100 @@ _file_write (stream_t stream, const char *iptr, size_t isize, } static int +_stdin_file_read (stream_t stream, char *optr, size_t osize, + off_t offset, size_t *pnbytes) +{ + int status; + size_t nbytes; + struct _file_stream *fs = stream_get_owner (stream); + int fs_offset = fs->offset; + + if (offset < fs_offset) + return stream_read (fs->cache, optr, osize, offset, pnbytes); + else if (offset > fs_offset) + { + int status; + size_t n, left = offset - fs_offset + 1; + char *buf = malloc (left); + if (!buf) + return ENOMEM; + while (left > 0 + && (status = stream_read (stream, buf, left, fs_offset, &n)) == 0 + && n > 0) + { + size_t k; + status = stream_write (fs->cache, buf, n, fs_offset, &k); + if (status) + break; + if (k != n) + { + status = EIO; + break; + } + + fs_offset += n; + left -= n; + } + free (buf); + if (status) + return status; + } + status = _file_read (stream, optr, osize, fs_offset, &nbytes); + if (status == 0 && nbytes) + { + size_t k; + + status = stream_write (fs->cache, optr, nbytes, fs_offset, &k); + if (status) + return status; + if (k != nbytes) + return EIO; + } + if (pnbytes) + *pnbytes = nbytes; + return status; +} + +static int +_stdin_file_readline (stream_t stream, char *optr, size_t osize, + off_t offset, size_t *pnbytes) +{ + int status; + size_t nbytes; + struct _file_stream *fs = stream_get_owner (stream); + int fs_offset = fs->offset; + + if (offset < fs->offset) + return stream_readline (fs->cache, optr, osize, offset, pnbytes); + else if (offset > fs->offset) + return ESPIPE; + + fs_offset = fs->offset; + status = _file_readline (stream, optr, osize, fs_offset, &nbytes); + if (status == 0) + { + size_t k; + + status = stream_write (fs->cache, optr, nbytes, fs_offset, &k); + if (status) + return status; + if (k != nbytes) + return EIO; + } + if (pnbytes) + *pnbytes = nbytes; + return status; +} + +static int +_stdout_file_write (stream_t stream, const char *iptr, size_t isize, + off_t offset, size_t *nbytes) +{ + struct _file_stream *fs = stream_get_owner (stream); + return _file_write (stream, iptr, isize, fs->offset, nbytes); +} + +static int _file_truncate (stream_t stream, off_t len) { struct _file_stream *fs = stream_get_owner (stream); @@ -426,14 +523,22 @@ stdio_stream_create (stream_t *stream, FILE* file, int flags) return ret; } + if ((ret = memory_stream_create (&fs->cache, 0, MU_STREAM_RDWR)) + || (ret = stream_open (fs->cache))) + { + stream_destroy (stream, fs); + free (fs); + return ret; + } + /* We don't need to open the FILE, just return success. */ stream_set_open (*stream, NULL, fs); stream_set_close (*stream, _file_close, fs); stream_set_fd (*stream, _file_get_fd, fs); - stream_set_read (*stream, _file_read, fs); - stream_set_readline (*stream, _file_readline, fs); - stream_set_write (*stream, _file_write, fs); + stream_set_read (*stream, _stdin_file_read, fs); + stream_set_readline (*stream, _stdin_file_readline, fs); + stream_set_write (*stream, _stdout_file_write, fs); stream_set_flush (*stream, _file_flush, fs); stream_set_destroy (*stream, _file_destroy, fs); |