diff options
author | Janne Blomqvist <jb@gcc.gnu.org> | 2006-02-12 21:59:32 +0200 |
---|---|---|
committer | Janne Blomqvist <jb@gcc.gnu.org> | 2006-02-12 21:59:32 +0200 |
commit | 82b8244c51cbf71e28f53a0e7e998aff924c36e7 (patch) | |
tree | ca366a0096c08065ac811e843aec247485318297 /libgfortran/io/unix.c | |
parent | 5b0b72518b76d75ad93ac95e6e05e772124085df (diff) | |
download | gcc-82b8244c51cbf71e28f53a0e7e998aff924c36e7.zip gcc-82b8244c51cbf71e28f53a0e7e998aff924c36e7.tar.gz gcc-82b8244c51cbf71e28f53a0e7e998aff924c36e7.tar.bz2 |
re PR libfortran/25949 (Unbounded I/O buffer memory usage for formatted IO)
2006-02-12 Janne Blomqvist <jb@gcc.gnu.org>
PR libgfortran/25949
* io/io.h: Add set function pointer to struct stream.
* io/unix.c (fd_seek): Only update offset, don't seek.
(fd_sset): New function.
(fd_read): Call lseek directly if necessary.
(fd_write): Likewise.
(fd_open): Set pointer to fd_sset.
(mem_set): New function.
(open_internal): Set pointer to mem_set.
* io/transfer.c (write_block_direct): Rename to write_buf, add
error return, non-pointer length argument.
(unformatted_write): Update to use write_buf.
(us_write): Simplify by using swrite instead of salloc_w.
(write_us_marker): New function.
(new_record_w): Use sset instead of memset, use write_us_marker,
simplify by using swrite instead of salloc_w.
From-SVN: r110895
Diffstat (limited to 'libgfortran/io/unix.c')
-rw-r--r-- | libgfortran/io/unix.c | 65 |
1 files changed, 55 insertions, 10 deletions
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index 237f09e..40ad2d8 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -562,15 +562,9 @@ fd_sfree (unix_stream * s) static try fd_seek (unix_stream * s, gfc_offset offset) { - if (s->physical_offset == offset) /* Are we lucky and avoid syscall? */ - { - s->logical_offset = offset; - return SUCCESS; - } - - s->physical_offset = s->logical_offset = offset; + s->logical_offset = offset; - return (lseek (s->fd, offset, SEEK_SET) < 0) ? FAILURE : SUCCESS; + return SUCCESS; } @@ -606,6 +600,34 @@ fd_truncate (unix_stream * s) } +/* Similar to memset(), but operating on a stream instead of a string. + Takes care of not using too much memory. */ + +static try +fd_sset (unix_stream * s, int c, size_t n) +{ + size_t bytes_left; + int trans; + void *p; + + bytes_left = n; + + while (bytes_left > 0) + { + /* memset() in chunks of BUFFER_SIZE. */ + trans = (bytes_left < BUFFER_SIZE) ? bytes_left : BUFFER_SIZE; + + p = fd_alloc_w_at (s, &trans, -1); + if (p) + memset (p, c, trans); + else + return FAILURE; + + bytes_left -= trans; + } + + return SUCCESS; +} /* Stream read function. Avoids using a buffer for big reads. The @@ -644,7 +666,8 @@ fd_read (unix_stream * s, void * buf, size_t * nbytes) return errno; } - if (is_seekable ((stream *) s) && fd_seek (s, s->logical_offset) == FAILURE) + if (is_seekable ((stream *) s) && s->physical_offset != s->logical_offset + && lseek (s->fd, s->logical_offset, SEEK_SET) < 0) { *nbytes = 0; return errno; @@ -692,7 +715,8 @@ fd_write (unix_stream * s, const void * buf, size_t * nbytes) return errno; } - if (is_seekable ((stream *) s) && fd_seek (s, s->logical_offset) == FAILURE) + if (is_seekable ((stream *) s) && s->physical_offset != s->logical_offset + && lseek (s->fd, s->logical_offset, SEEK_SET) < 0) { *nbytes = 0; return errno; @@ -739,6 +763,7 @@ fd_open (unix_stream * s) s->st.truncate = (void *) fd_truncate; s->st.read = (void *) fd_read; s->st.write = (void *) fd_write; + s->st.set = (void *) fd_sset; s->buffer = NULL; } @@ -870,6 +895,25 @@ mem_seek (unix_stream * s, gfc_offset offset) } +static try +mem_set (unix_stream * s, int c, size_t n) +{ + void *p; + int len; + + len = n; + + p = mem_alloc_w_at (s, &len, -1); + if (p) + { + memset (p, c, len); + return SUCCESS; + } + else + return FAILURE; +} + + static int mem_truncate (unix_stream * s __attribute__ ((unused))) { @@ -932,6 +976,7 @@ open_internal (char *base, int length) s->st.truncate = (void *) mem_truncate; s->st.read = (void *) mem_read; s->st.write = (void *) mem_write; + s->st.set = (void *) mem_set; return (stream *) s; } |