#include <limits.h>
#include <unistd.h>
+#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
+#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
+#endif
#include <string.h>
#include <errno.h>
#define MAP_FAILED ((void *) -1)
#endif
+#ifndef PROT_READ
+#define PROT_READ 1
+#endif
+
+#ifndef PROT_WRITE
+#define PROT_WRITE 2
+#endif
+
+/* These flags aren't defined on all targets (mingw32), so provide them
+ here. */
+#ifndef S_IRGRP
+#define S_IRGRP 0
+#endif
+
+#ifndef S_IWGRP
+#define S_IWGRP 0
+#endif
+
+#ifndef S_IROTH
+#define S_IROTH 0
+#endif
+
+#ifndef S_IWOTH
+#define S_IWOTH 0
+#endif
+
/* This implementation of stream I/O is based on the paper:
*
* "Exploiting the advantages of mapped files for stream I/O",
stream st;
int fd;
- offset_t buffer_offset; /* File offset of the start of the buffer */
- offset_t physical_offset; /* Current physical file offset */
- offset_t logical_offset; /* Current logical file offset */
- offset_t dirty_offset; /* Start of modified bytes in buffer */
- offset_t file_length; /* Length of the file, -1 if not seekable. */
+ gfc_offset buffer_offset; /* File offset of the start of the buffer */
+ gfc_offset physical_offset; /* Current physical file offset */
+ gfc_offset logical_offset; /* Current logical file offset */
+ gfc_offset dirty_offset; /* Start of modified bytes in buffer */
+ gfc_offset file_length; /* Length of the file, -1 if not seekable. */
char *buffer;
int len; /* Physical length of the current buffer */
return FAILURE;
s->physical_offset = s->dirty_offset + s->ndirty;
- if (s->physical_offset > s->file_length)
+
+ /* don't increment file_length if the file is non-seekable */
+ if (s->file_length != -1 && s->physical_offset > s->file_length)
s->file_length = s->physical_offset;
s->ndirty = 0;
* to come next. */
static void
-fd_alloc (unix_stream * s, offset_t where, int *len)
+fd_alloc (unix_stream * s, gfc_offset where, int *len)
{
char *new_buffer;
int n, read_len;
* NULL on I/O error. */
static char *
-fd_alloc_r_at (unix_stream * s, int *len, offset_t where)
+fd_alloc_r_at (unix_stream * s, int *len, gfc_offset where)
{
- offset_t m;
+ gfc_offset m;
int n;
if (where == -1)
* we've already buffered the data or we need to load it. */
static char *
-fd_alloc_w_at (unix_stream * s, int *len, offset_t where)
+fd_alloc_w_at (unix_stream * s, int *len, gfc_offset where)
{
- offset_t n;
+ gfc_offset n;
if (where == -1)
where = s->logical_offset;
}
/* Return a position within the current buffer */
-
- if (s->ndirty == 0)
- { /* First write into a clean buffer */
- s->dirty_offset = where;
- s->ndirty = *len;
+ if (s->ndirty == 0
+ || where > s->dirty_offset + s->ndirty
+ || s->dirty_offset > where + *len)
+ { /* Discontiguous blocks, start with a clean buffer. */
+ /* Flush the buffer. */
+ if (s->ndirty != 0)
+ fd_flush (s);
+ s->dirty_offset = where;
+ s->ndirty = *len;
}
else
- {
- if (s->dirty_offset + s->ndirty == where)
- s->ndirty += *len;
- else
- fd_flush (s); /* Can't combine two dirty blocks */
+ {
+ gfc_offset start; /* Merge with the existing data. */
+ if (where < s->dirty_offset)
+ start = where;
+ else
+ start = s->dirty_offset;
+ if (where + *len > s->dirty_offset + s->ndirty)
+ s->ndirty = where + *len - start;
+ else
+ s->ndirty = s->dirty_offset + s->ndirty - start;
+ s->dirty_offset = start;
}
s->logical_offset = where + *len;
static int
-fd_seek (unix_stream * s, offset_t offset)
+fd_seek (unix_stream * s, gfc_offset offset)
{
s->physical_offset = s->logical_offset = offset;
fd_truncate (unix_stream * s)
{
- if (ftruncate (s->fd, s->logical_offset))
+ if (lseek (s->fd, s->logical_offset, SEEK_SET) == -1)
return FAILURE;
- s->physical_offset = s->file_length = s->logical_offset;
+ /* non-seekable files, like terminals and fifo's fail the lseek.
+ the fd is a regular file at this point */
- if (lseek (s->fd, s->file_length, SEEK_SET) == -1)
+ if (ftruncate (s->fd, s->logical_offset))
+ {
return FAILURE;
+ }
+
+ s->physical_offset = s->file_length = s->logical_offset;
return SUCCESS;
}
* guaranteed to be mappable. */
static try
-mmap_alloc (unix_stream * s, offset_t where, int *len)
+mmap_alloc (unix_stream * s, gfc_offset where, int *len)
{
- offset_t offset;
+ gfc_offset offset;
int length;
char *p;
static char *
-mmap_alloc_r_at (unix_stream * s, int *len, offset_t where)
+mmap_alloc_r_at (unix_stream * s, int *len, gfc_offset where)
{
- offset_t m;
+ gfc_offset m;
if (where == -1)
where = s->logical_offset;
static char *
-mmap_alloc_w_at (unix_stream * s, int *len, offset_t where)
+mmap_alloc_w_at (unix_stream * s, int *len, gfc_offset where)
{
if (where == -1)
where = s->logical_offset;
static int
-mmap_seek (unix_stream * s, offset_t offset)
+mmap_seek (unix_stream * s, gfc_offset offset)
{
s->logical_offset = offset;
static char *
-mem_alloc_r_at (unix_stream * s, int *len, offset_t where)
+mem_alloc_r_at (unix_stream * s, int *len, gfc_offset where)
{
- offset_t n;
+ gfc_offset n;
if (where == -1)
where = s->logical_offset;
if (where < s->buffer_offset || where > s->buffer_offset + s->active)
return NULL;
- if (is_internal_unit() && where + *len > s->file_length)
- return NULL;
-
s->logical_offset = where + *len;
- n = (where - s->buffer_offset) - s->active;
+ n = s->buffer_offset + s->active - where;
if (*len > n)
*len = n;
static char *
-mem_alloc_w_at (unix_stream * s, int *len, offset_t where)
+mem_alloc_w_at (unix_stream * s, int *len, gfc_offset where)
{
- offset_t m;
+ gfc_offset m;
if (where == -1)
where = s->logical_offset;
static int
-mem_seek (unix_stream * s, offset_t offset)
+mem_seek (unix_stream * s, gfc_offset offset)
{
if (offset > s->file_length)
static try
mem_close (unix_stream * s)
{
+ free_mem (s);
return SUCCESS;
}
/* tempfile()-- Generate a temporary filename for a scratch file and
* open it. mkstemp() opens the file for reading and writing, but the
* library mode prevents anything that is not allowed. The descriptor
- * is returns, which is less than zero on error. The template is
- * pointed to by ioparm.file, which is copied into the unit structure
+ * is returned, which is -1 on error. The template is pointed to by
+ * ioparm.file, which is copied into the unit structure
* and freed later. */
static int
template = get_mem (strlen (tempdir) + 20);
- st_sprintf (template, "%s/gfortantmpXXXXXX", tempdir);
+ st_sprintf (template, "%s/gfortrantmpXXXXXX", tempdir);
+
+#ifdef HAVE_MKSTEMP
fd = mkstemp (template);
+#else /* HAVE_MKSTEMP */
+
+ if (mktemp (template))
+ do
+ fd = open (template, O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
+ while (!(fd == -1 && errno == EEXIST) && mktemp (template));
+ else
+ fd = -1;
+
+#endif /* HAVE_MKSTEMP */
+
if (fd < 0)
free_mem (template);
else
break;
case STATUS_REPLACE:
- mode |= O_TRUNC;
+ mode |= O_CREAT | O_TRUNC;
break;
default:
/* file_length()-- Return the file length in bytes, -1 if unknown */
-offset_t
+gfc_offset
file_length (stream * s)
{
/* file_position()-- Return the current position of the file */
-offset_t
+gfc_offset
file_position (stream * s)
{
int
is_seekable (stream * s)
{
-
- return ((unix_stream *) s)->mmaped;
+ /* by convention, if file_length == -1, the file is not seekable
+ note that a mmapped file is always seekable, an fd_ file may
+ or may not be. */
+ return ((unix_stream *) s)->file_length!=-1;
}
try