#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>

#include <sys/user.h>

void create_file(const char* filename, const char* content) {
  int fd = open(filename, O_RDWR|O_CREAT, S_IRUSR|S_IWUSR); // create an empty file
  assert(fd >= 0);
  write(fd, content, strlen(content));
  close(fd);
}

int main() {
  struct stat st;

  create_file("empty_file", "");
  create_file("nonempty_file", "some content");

  int fd = open("empty_file", O_RDONLY);
  int fd2 = open("nonempty_file", O_RDONLY);

  // "fd" should be an empty file, "fd2" non-empty.
  assert(fstat(fd, &st) != -1);
  int filesize = st.st_size;
  assert(filesize == 0);

  assert(fstat(fd2, &st) != -1);
  filesize = st.st_size;
  assert(filesize != 0);

  // mapping a length of zero bytes should always fail
  char *mapped = (char*) mmap(NULL, 0, PROT_READ, MAP_PRIVATE, fd, 0);
  printf("mmap -> %p\n", mapped);
  assert(mapped == MAP_FAILED);
  printf("mmap failed with: %s\n", strerror(errno));
  assert(errno == EINVAL);

  mapped = (char*) mmap(NULL, 0, PROT_READ, MAP_PRIVATE, fd2, 0);
  printf("mmap -> %p\n", mapped);
  assert(mapped == MAP_FAILED);
  printf("mmap failed with: %s\n", strerror(errno));
  assert(errno == EINVAL);

  // mapping a non-zero number of pages should succeed, even for empty files.
  // On native systems this results in pages beyond the length of the file
  // being inaccessible, but we don't have any real memory protection on
  // emscripten so we cannot test that.
  mapped = (char*) mmap(NULL, 2*PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0);
  assert(mapped != MAP_FAILED);
  munmap(mapped, 2*PAGE_SIZE);

  close(fd);
  close(fd2);

  // Now check that mapping zero bytes fails
  printf("done\n");
  return 0;
}
