#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>

/* Emulate stdio's "w+" mode. The manual page has this to say:

   w+  Open for reading and writing. The file is created if it does
   not exist, otherwise it is truncated. The stream is positioned at
   the beginning of the file.
*/
FILE *
safe_open_wplus(char *fname) {
  struct stat lstat_info, fstat_info;
  FILE *fp;
  char *mode = "rb+";		/* We perform our own truncation. */
  int fd;

  if (lstat(fname, &lstat_info) == -1) {
    /*
     * If the lstat() failed for reasons other than the file not
     * existing, return 0, specifying error.
     */
    if (errno != ENOENT)
      return 0;

    if ((fd = open(fname, O_CREAT | O_EXCL | O_RDWR, 0600)) == -1)
      return 0;

    mode = "wb";
  } else {

    /* Open an existing file */
    if ((fd = open(fname, O_RDWR)) == -1)
      return 0;

    if (fstat(fd, &fstat_info) == -1
	|| lstat_info.st_mode != fstat_info.st_mode
	|| lstat_info.st_ino != fstat_info.st_ino
	|| lstat_info.st_dev != fstat_info.st_dev) {
      close(fd);

      return 0;
    }

    /* Turn the file into an empty file, to mimic w+ semantics. */
    ftruncate(fd, 0);
  }

  /* Open an stdio file over the low-level one */
  fp = fdopen(fd, mode);
  if (fp == NULL) {
    close(fd);
    /* unlink(fname); -- See exercise */

    return 0;
  }

  return fp;
}

