+#ifdef HAVE_MMAP
+ ssize_t _page_size = sysconf(_SC_PAGESIZE);
+ char *data = MAP_FAILED;
+#endif
+ off_t offset = 0;
+ struct stat statb;
+ rrd_file_t *rrd_file = NULL;
+ rrd_simple_file_t *rrd_simple_file = NULL;
+ size_t newfile_size = 0;
+ size_t header_len, value_cnt, data_len;
+
+ /* Are we creating a new file? */
+ if((rdwr & RRD_CREAT) && (rrd->stat_head != NULL))
+ {
+ header_len = rrd_get_header_size(rrd);
+
+ value_cnt = 0;
+ for (ui = 0; ui < rrd->stat_head->rra_cnt; ui++)
+ value_cnt += rrd->stat_head->ds_cnt * rrd->rra_def[ui].row_cnt;
+
+ data_len = sizeof(rrd_value_t) * value_cnt;
+
+ newfile_size = header_len + data_len;
+ }
+
+ rrd_file = (rrd_file_t*)malloc(sizeof(rrd_file_t));
+ if (rrd_file == NULL) {
+ rrd_set_error("allocating rrd_file descriptor for '%s'", file_name);
+ return NULL;
+ }
+ memset(rrd_file, 0, sizeof(rrd_file_t));
+
+ rrd_file->pvt = malloc(sizeof(rrd_simple_file_t));
+ if(rrd_file->pvt == NULL) {
+ rrd_set_error("allocating rrd_simple_file for '%s'", file_name);
+ return NULL;
+ }
+ memset(rrd_file->pvt, 0, sizeof(rrd_simple_file_t));
+ rrd_simple_file = (rrd_simple_file_t *)rrd_file->pvt;
+
+#ifdef DEBUG
+ if ((rdwr & (RRD_READONLY | RRD_READWRITE)) ==
+ (RRD_READONLY | RRD_READWRITE)) {
+ /* Both READONLY and READWRITE were given, which is invalid. */
+ rrd_set_error("in read/write request mask");
+ exit(-1);
+ }
+#endif
+
+#ifdef HAVE_MMAP
+ rrd_simple_file->mm_prot = PROT_READ;
+ rrd_simple_file->mm_flags = 0;
+#endif
+
+ if (rdwr & RRD_READONLY) {
+ flags |= O_RDONLY;
+#ifdef HAVE_MMAP
+ rrd_simple_file->mm_flags = MAP_PRIVATE;
+# ifdef MAP_NORESERVE
+ rrd_simple_file->mm_flags |= MAP_NORESERVE; /* readonly, so no swap backing needed */
+# endif
+#endif
+ } else {
+ if (rdwr & RRD_READWRITE) {
+ flags |= O_RDWR;
+#ifdef HAVE_MMAP
+ rrd_simple_file->mm_flags = MAP_SHARED;
+ rrd_simple_file->mm_prot |= PROT_WRITE;
+#endif
+ }
+ if (rdwr & RRD_CREAT) {
+ flags |= (O_CREAT | O_TRUNC);
+ }
+ if (rdwr & RRD_EXCL) {
+ flags |= O_EXCL;
+ }
+ }
+ if (rdwr & RRD_READAHEAD) {
+#ifdef MAP_POPULATE
+ rrd_simple_file->mm_flags |= MAP_POPULATE; /* populate ptes and data */
+#endif
+#if defined MAP_NONBLOCK
+ rrd_simple_file->mm_flags |= MAP_NONBLOCK; /* just populate ptes */
+#endif
+ }
+#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+ flags |= O_BINARY;
+#endif
+
+ if ((rrd_simple_file->fd = open(file_name, flags, 0666)) < 0) {
+ rrd_set_error("opening '%s': %s", file_name, rrd_strerror(errno));
+ goto out_free;
+ }
+
+#ifdef HAVE_MMAP
+#ifdef HAVE_BROKEN_MS_ASYNC
+ if (rdwr & RRD_READWRITE) {
+ /* some unices, the files mtime does not get update
+ on msync MS_ASYNC, in order to help them,
+ we update the the timestamp at this point.
+ The thing happens pretty 'close' to the open
+ call so the chances of a race should be minimal.
+
+ Maybe ask your vendor to fix your OS ... */
+ utime(file_name,NULL);
+ }
+#endif
+#endif
+
+ /* Better try to avoid seeks as much as possible. stat may be heavy but
+ * many concurrent seeks are even worse. */
+ if (newfile_size == 0 && ((fstat(rrd_simple_file->fd, &statb)) < 0)) {
+ rrd_set_error("fstat '%s': %s", file_name, rrd_strerror(errno));
+ goto out_close;
+ }
+ if (newfile_size == 0) {
+ rrd_file->file_len = statb.st_size;
+ } else {
+ rrd_file->file_len = newfile_size;
+ lseek(rrd_simple_file->fd, newfile_size - 1, SEEK_SET);
+ if ( write(rrd_simple_file->fd, "\0", 1) == -1){ /* poke */
+ rrd_set_error("write '%s': %s", file_name, rrd_strerror(errno));
+ goto out_close;
+ }
+ lseek(rrd_simple_file->fd, 0, SEEK_SET);
+ }