@@ -48,8 +48,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
4848
4949#include <err.h>
5050#include <errno.h>
51- #include <stdio .h>
51+ #include <fcntl .h>
5252#include <stdint.h>
53+ #include <stdio.h>
5354#include <stdlib.h>
5455#include <string.h>
5556#include <time.h>
@@ -68,15 +69,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6869
6970static void initXAndImlib (const char * , int );
7071static void uninitXAndImlib (void );
71- static void scrotSaveImage (const char * );
72+ static void scrotSaveImage (int , const char * );
7273static Imlib_Image scrotGrabFocused (void );
7374static Imlib_Image scrotGrabAutoselect (void );
7475static long miliToNanoSec (int );
7576static Imlib_Image scrotGrabShotMulti (void );
7677static Imlib_Image scrotGrabShotMonitor (void );
7778static Imlib_Image scrotGrabStackWindows (void );
7879static Imlib_Image scrotGrabShot (void );
79- static void scrotCheckIfOverwriteFile (char * * );
80+ static int scrotCheckIfOverwriteFile (char * * );
8081static void scrotExecApp (Imlib_Image , struct tm * , char * , char * );
8182static char * imPrintf (const char * , struct tm * , const char * , const char * ,
8283 Imlib_Image );
@@ -102,6 +103,7 @@ int main(int argc, char *argv[])
102103 char * filenameThumb = NULL ;
103104 struct timespec timeStamp ;
104105 struct tm * tm ;
106+ int fd ;
105107
106108 /* Get the time ASAP to reduce the timing error in case --delay is used. */
107109 opt .delayStart = clockNow ();
@@ -155,9 +157,8 @@ int main(int argc, char *argv[])
155157 imlib_image_attach_data_value ("compression" , NULL , opt .compression , NULL );
156158
157159 filenameIM = imPrintf (opt .outputFile , tm , NULL , NULL , image );
158- scrotCheckIfOverwriteFile (& filenameIM );
159-
160- scrotSaveImage (filenameIM );
160+ fd = scrotCheckIfOverwriteFile (& filenameIM );
161+ scrotSaveImage (fd , filenameIM );
161162
162163 if (opt .thumb != THUMB_DISABLED ) {
163164 int cwidth , cheight ;
@@ -195,8 +196,8 @@ int main(int argc, char *argv[])
195196 imlib_image_set_format (opt .format );
196197
197198 filenameThumb = imPrintf (opt .thumbFile , tm , NULL , NULL , thumbnail );
198- scrotCheckIfOverwriteFile (& filenameThumb );
199- scrotSaveImage (filenameThumb );
199+ fd = scrotCheckIfOverwriteFile (& filenameThumb );
200+ scrotSaveImage (fd , filenameThumb );
200201 imlib_free_image_and_decache ();
201202 }
202203 }
@@ -254,9 +255,11 @@ static void uninitXAndImlib(void)
254255 }
255256}
256257
257- static void scrotSaveImage (const char * filename )
258+ // save image to fd, filename only used for logging
259+ // fd will be closed after calling this function
260+ static void scrotSaveImage (int fd , const char * filename )
258261{
259- imlib_save_image ( filename );
262+ imlib_save_image_fd ( fd , filename );
260263 int imErr = imlib_get_error ();
261264 if (imErr ) {
262265 const char * errmsg = imlib_strerror (imErr );
@@ -537,43 +540,55 @@ static void scrotGrabMousePointer(Imlib_Image image, const int xOffset,
537540 XFree (xcim );
538541}
539542
540- static void scrotCheckIfOverwriteFile (char * * filename )
543+ static int scrotCheckIfOverwriteFile (char * * filename )
541544{
542- if (opt .overwrite )
543- return ;
544-
545- if (access (* filename , F_OK ) == -1 )
546- return ;
547-
548- const size_t maxCounter = 999 ;
549- char fmt [5 ]; // _000 + NUL byte
550- const size_t slen = strlen (* filename );
551- const size_t nalloc = slen + sizeof (fmt );
552-
553- char * ext ;
554- size_t extLength = scrotHaveFileExtension (* filename , & ext );
555-
556- char * newName = ecalloc (nalloc , sizeof (* newName ));
557- memcpy (newName , * filename , slen - extLength );
558- char * ptr = newName + (slen - extLength );
559-
560- size_t counter = 0 ;
561- do {
562- snprintf (fmt , sizeof (fmt ), "_%03zu" , counter ++ );
563- memcpy (ptr , fmt , sizeof (fmt ));
564- memcpy (ptr + sizeof (fmt ) - 1 , ext , extLength );
565- } while ((counter < maxCounter ) && !access (newName , F_OK ));
545+ if (strcmp (* filename , "-" ) == 0 ) {
546+ // scrotSaveImage will close the fd, so dup it
547+ int fd = fcntl (1 , F_DUPFD_CLOEXEC , 3 );
548+ if (fd < 0 )
549+ err (EXIT_FAILURE , "dup failed" );
550+ return fd ;
551+ }
566552
567- scrotAssert (newName [nalloc - 1 ] == '\0' );
553+ int flags = O_RDWR | O_CREAT | (opt .overwrite ? O_TRUNC : O_EXCL );
554+ int fd = open (* filename , flags , 0644 );
555+ if (!opt .overwrite && fd < 0 && errno == EEXIST ) {
556+ const size_t maxCounter = 999 ;
557+ char fmt [5 ]; // _000 + NUL byte
558+ const size_t slen = strlen (* filename );
559+ const size_t nalloc = slen + sizeof (fmt );
560+
561+ char * ext ;
562+ size_t extLength = scrotHaveFileExtension (* filename , & ext );
563+
564+ char * newName = ecalloc (nalloc , sizeof (* newName ));
565+ memcpy (newName , * filename , slen - extLength );
566+ char * ptr = newName + (slen - extLength );
567+
568+ size_t counter = 0 ;
569+ do {
570+ snprintf (fmt , sizeof (fmt ), "_%03zu" , counter ++ );
571+ memcpy (ptr , fmt , sizeof (fmt ));
572+ memcpy (ptr + sizeof (fmt ) - 1 , ext , extLength );
573+ fd = open (newName , flags , 0644 );
574+ } while ((counter < maxCounter ) && fd < 0 && errno == EEXIST );
575+ scrotAssert (newName [nalloc - 1 ] == '\0' );
576+
577+ if (counter == maxCounter ) {
578+ errx (EXIT_FAILURE , "scrot can no longer generate new file names.\n"
579+ "The last attempt is %s" , newName );
580+ }
568581
569- if (counter == maxCounter ) {
570- errx (EXIT_FAILURE , "scrot can no longer generate new file names.\n"
571- "The last attempt is %s" , newName );
582+ int saved_errno = errno ; // avoid errno getting potentially clobbered
583+ warnx ("`%s` already exists, attempting `%s` instead" , * filename , newName );
584+ free (* filename );
585+ * filename = newName ;
586+ errno = saved_errno ;
572587 }
573588
574- warnx ( "`%s` already exists, attempting `%s` instead" , * filename , newName );
575- free ( * filename );
576- * filename = newName ;
589+ if ( fd < 0 )
590+ err ( EXIT_FAILURE , "couldn't open file %s" , * filename );
591+ return fd ;
577592}
578593
579594static int scrotMatchWindowClassName (Window target )
0 commit comments