From 061a01701862b1cfc594771df882a8cd6dfebdd3 Mon Sep 17 00:00:00 2001 From: Eric Smith Date: Thu, 28 Apr 2022 21:37:24 -0600 Subject: [PATCH] Fix issues with C stdio stream and Unix FD getting out of sync when rewind() is used. --- tumble_tiff.c | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/tumble_tiff.c b/tumble_tiff.c index e8f7781..466e5b5 100644 --- a/tumble_tiff.c +++ b/tumble_tiff.c @@ -28,6 +28,10 @@ #include #include /* strcasecmp() is a BSDism */ +// Sadly libtiff doesn't accept C streams as input sources, so we have to +// use Unix file descriptors. +#include + #include /* * On the x86, libtiff defaults to big-endian bit order for no good reason. @@ -80,10 +84,43 @@ static bool open_tiff_input_file (FILE *f, char *name) ((buf [0] == 0x4d) && (buf [1] == 0x4d)))) return (0); - tiff_in = TIFFFdOpen (fileno (f), name, "r"); + // At this point we expect never to use f (C stream) again, + // and rewind() isn't guaranteed to have had any effect on + // the C stream, so we explicity lseek() the Unix FD to the start + // of the file. + // However, if TIFFFdOpen() fails, it's possible that another + // input handler will try using the C stream again, so we'll + // have to restore the file offset to where it left it. + + int fd = fileno(f); + + off_t original_offset = lseek(fd, 0, SEEK_CUR); + if (original_offset < 0) + { + // SHOULD NEVER HAPPEN + fprintf(stderr, "can't get file descriptor position from lseek()."); + exit (2); + } + + off_t new_offset = lseek(fd, 0, SEEK_SET); + if (new_offset != 0) + { + // SHOULD NEVER HAPPEN + fprintf(stderr, "can't lseek() to start of file."); + exit (2); + } + + tiff_in = TIFFFdOpen (fd, name, "r"); if (! tiff_in) { fprintf (stderr, "can't open input file '%s'\n", name); + off_t restore_offset = lseek(fd, original_offset, SEEK_SET); + if (restore_offset != original_offset) + { + // SHOULD NEVER HAPPEN + fprintf(stderr, "can't lseek() back to original file offset."); + exit (2); + } return (0); } return (1);