+
+/* Set position of rrd_file. */
+
+off_t rrd_seek(
+ rrd_file_t *rrd_file,
+ off_t off,
+ int whence)
+{
+ off_t ret = 0;
+
+#ifdef HAVE_MMAP
+ if (whence == SEEK_SET)
+ rrd_file->pos = off;
+ else if (whence == SEEK_CUR)
+ rrd_file->pos += off;
+ else if (whence == SEEK_END)
+ rrd_file->pos = rrd_file->file_len + off;
+#else
+ ret = lseek(rrd_file->fd, off, whence);
+ if (ret < 0)
+ rrd_set_error("lseek: %s", rrd_strerror(errno));
+ rrd_file->pos = ret;
+#endif
+ /* mimic fseek, which returns 0 upon success */
+ return ret < 0; /*XXX: or just ret to mimic lseek */
+}
+
+
+/* Get current position in rrd_file. */
+
+off_t rrd_tell(
+ rrd_file_t *rrd_file)
+{
+ return rrd_file->pos;
+}
+
+
+/* Read count bytes into buffer buf, starting at rrd_file->pos.
+ * Returns the number of bytes read or <0 on error. */
+
+ssize_t rrd_read(
+ rrd_file_t *rrd_file,
+ void *buf,
+ size_t count)
+{
+#ifdef HAVE_MMAP
+ size_t _cnt = count;
+ ssize_t _surplus;
+
+ if (rrd_file->pos > rrd_file->file_len || _cnt == 0) /* EOF */
+ return 0;
+ if (buf == NULL)
+ return -1; /* EINVAL */
+ _surplus = rrd_file->pos + _cnt - rrd_file->file_len;
+ if (_surplus > 0) { /* short read */
+ _cnt -= _surplus;
+ }
+ if (_cnt == 0)
+ return 0; /* EOF */
+ buf = memcpy(buf, rrd_file->file_start + rrd_file->pos, _cnt);
+
+ rrd_file->pos += _cnt; /* mimmic read() semantics */
+ return _cnt;
+#else
+ ssize_t ret;
+
+ ret = read(rrd_file->fd, buf, count);
+ if (ret > 0)
+ rrd_file->pos += ret; /* mimmic read() semantics */
+ return ret;
+#endif
+}
+
+
+/* Write count bytes from buffer buf to the current position
+ * rrd_file->pos of rrd_file->fd.
+ * Returns the number of bytes written or <0 on error. */
+
+ssize_t rrd_write(
+ rrd_file_t *rrd_file,
+ const void *buf,
+ size_t count)
+{
+#ifdef HAVE_MMAP
+ /* These flags are used if creating a new RRD */
+ int mm_prot = PROT_READ | PROT_WRITE, mm_flags = MAP_SHARED;
+ int old_size = rrd_file->file_len;
+ int new_size = rrd_file->file_len;
+ if (count == 0)
+ return 0;
+ if (buf == NULL)
+ return -1; /* EINVAL */
+
+ if((rrd_file->pos + count) > old_size)
+ {
+ new_size = rrd_file->pos + count;
+ rrd_file->file_len = new_size;
+ lseek(rrd_file->fd, new_size - 1, SEEK_SET);
+ write(rrd_file->fd, "\0", 1); /* poke */
+ lseek(rrd_file->fd, 0, SEEK_SET);
+ if(rrd_file->file_start == NULL)
+ {
+ rrd_file->file_start = mmap(0, new_size, mm_prot, mm_flags,
+ rrd_file->fd, 0);
+ }
+ else
+ rrd_file->file_start = mremap(rrd_file->file_start, old_size, new_size, MREMAP_MAYMOVE);
+
+ if (rrd_file->file_start == MAP_FAILED) {
+ rrd_set_error("m(re)maping file : %s",
+ rrd_strerror(errno));
+ return -1;
+ }
+ }
+ memcpy(rrd_file->file_start + rrd_file->pos, buf, count);
+ rrd_file->pos += count;
+ return count; /* mimmic write() semantics */
+#else
+ ssize_t _sz = write(rrd_file->fd, buf, count);
+
+ if (_sz > 0)
+ rrd_file->pos += _sz;
+ return _sz;
+#endif
+}
+
+
+/* flush all data pending to be written to FD. */
+
+void rrd_flush(
+ rrd_file_t *rrd_file)
+{
+ if (fdatasync(rrd_file->fd) != 0) {
+ rrd_set_error("flushing fd %d: %s", rrd_file->fd,
+ rrd_strerror(errno));
+ }
+}
+
+
+/* Initialize RRD header. */
+
+void rrd_init(
+ rrd_t *rrd)