#include #include #include #include #include #include #include /* 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; }