diff options
-rw-r--r-- | doc/HISTORY | 5 | ||||
-rw-r--r-- | lib/pmfileio.c | 129 | ||||
-rw-r--r-- | pm_config.in.h | 9 |
3 files changed, 135 insertions, 8 deletions
diff --git a/doc/HISTORY b/doc/HISTORY index 3191200b..8835b686 100644 --- a/doc/HISTORY +++ b/doc/HISTORY @@ -8,6 +8,11 @@ not yet BJH Release 10.70.00 Add yuy2topam. Thanks Michael Haardt. + On Windows, don't leave temporary files around (previous code + did so because unlink of an open file fails in Windows; new + code deletes temporary files via atexit). Thanks + Ludolf Holzheid <ludolf.holzheid@gmx.de>. + 14.12.25 BJH Release 10.69.00 pnmnorm: add -bsingle, -wsingle. diff --git a/lib/pmfileio.c b/lib/pmfileio.c index b629fd23..a4533b56 100644 --- a/lib/pmfileio.c +++ b/lib/pmfileio.c @@ -306,17 +306,130 @@ pm_make_tmpfile(FILE ** const filePP, +bool const canUnlinkOpen = +#if CAN_UNLINK_OPEN + 1 +#else + 0 +#endif + ; + + + +typedef struct UnlinkListEntry { +/*---------------------------------------------------------------------------- + This is an entry in the linked list of files to close and unlink as the + program exits. +-----------------------------------------------------------------------------*/ + struct UnlinkListEntry * next; + int fd; + char fileName[1]; /* Actually variable length */ +} UnlinkListEntry; + +static UnlinkListEntry * unlinkListP; + + + +static void +unlinkTempFiles(void) { +/*---------------------------------------------------------------------------- + Close and unlink (so presumably delete) the files in the list + *unlinkListP. + + This is an atexit function. +-----------------------------------------------------------------------------*/ + while (unlinkListP) { + UnlinkListEntry * const firstEntryP = unlinkListP; + + unlinkListP = unlinkListP->next; + + close(firstEntryP->fd); + unlink(firstEntryP->fileName); + + free(firstEntryP); + } +} + + + +static UnlinkListEntry * +newUnlinkListEntry(const char * const fileName, + int const fd) { + + UnlinkListEntry * const unlinkListEntryP = + malloc(sizeof(*unlinkListEntryP) + strlen(fileName) + 1); + + if (unlinkListEntryP) { + strcpy(unlinkListEntryP->fileName, fileName); + unlinkListEntryP->fd = fd; + unlinkListEntryP->next = NULL; + } + return unlinkListEntryP; +} + + + +static void +addUnlinkListEntry(const char * const fileName, + int const fd) { + + UnlinkListEntry * const unlinkListEntryP = + newUnlinkListEntry(fileName, fd); + + if (unlinkListEntryP) { + unlinkListEntryP->next = unlinkListP; + unlinkListP = unlinkListEntryP; + } +} + + + +static void +scheduleUnlinkAtExit(const char * const fileName, + int const fd) { +/*---------------------------------------------------------------------------- + Set things up to have the file unlinked as the program exits. + + This is messy and probably doesn't work in all situations; it is a hack + to get Unix code essentially working on Windows, without messing up the + code too badly for Unix. +-----------------------------------------------------------------------------*/ + static bool unlinkListEstablished = false; + + if (!unlinkListEstablished) { + atexit(unlinkTempFiles); + unlinkListP = NULL; + unlinkListEstablished = true; + } + + addUnlinkListEntry(fileName, fd); +} + + + +static void +arrangeUnlink(const char * const fileName, + int const fd) { + + if (canUnlinkOpen) + unlink(fileName); + else + scheduleUnlinkAtExit(fileName, fd); +} + + + FILE * pm_tmpfile(void) { FILE * fileP; - const char * tmpfile; + const char * tmpfileNm; - pm_make_tmpfile(&fileP, &tmpfile); + pm_make_tmpfile(&fileP, &tmpfileNm); - unlink(tmpfile); + arrangeUnlink(tmpfileNm, fileno(fileP)); - pm_strfree(tmpfile); + pm_strfree(tmpfileNm); return fileP; } @@ -327,13 +440,13 @@ int pm_tmpfile_fd(void) { int fd; - const char * tmpfile; + const char * tmpfileNm; - pm_make_tmpfile_fd(&fd, &tmpfile); + pm_make_tmpfile_fd(&fd, &tmpfileNm); - unlink(tmpfile); + arrangeUnlink(tmpfileNm, fd); - pm_strfree(tmpfile); + pm_strfree(tmpfileNm); return fd; } diff --git a/pm_config.in.h b/pm_config.in.h index 1e54f06e..f88a7652 100644 --- a/pm_config.in.h +++ b/pm_config.in.h @@ -145,6 +145,15 @@ #define HAVE_VASPRINTF 0 #endif +/* On Windows, unlinking a file is deleting it, and you can't delete an open + file, so unlink of an open file fails. The errno is (incorrectly) EACCES. +*/ +#if MSVCRT || defined(__CYGWIN__) || defined(DJGPP) + #define CAN_UNLINK_OPEN 0 +#else + #define CAN_UNLINK_OPEN 1 +#endif + #ifdef __amigaos__ #include <clib/exec_protos.h> #define getpid() ((pid_t)FindTask(NULL)) |