@@ -48,8 +48,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
48
48
49
49
#include <err.h>
50
50
#include <errno.h>
51
- #include <stdio .h>
51
+ #include <fcntl .h>
52
52
#include <stdint.h>
53
+ #include <stdio.h>
53
54
#include <stdlib.h>
54
55
#include <string.h>
55
56
#include <time.h>
@@ -68,15 +69,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
68
69
69
70
static void initXAndImlib (const char * , int );
70
71
static void uninitXAndImlib (void );
71
- static void scrotSaveImage (const char * );
72
+ static void scrotSaveImage (int , const char * );
72
73
static Imlib_Image scrotGrabFocused (void );
73
74
static Imlib_Image scrotGrabAutoselect (void );
74
75
static long miliToNanoSec (int );
75
76
static Imlib_Image scrotGrabShotMulti (void );
76
77
static Imlib_Image scrotGrabShotMonitor (void );
77
78
static Imlib_Image scrotGrabStackWindows (void );
78
79
static Imlib_Image scrotGrabShot (void );
79
- static void scrotCheckIfOverwriteFile (char * * );
80
+ static int scrotCheckIfOverwriteFile (char * * );
80
81
static void scrotExecApp (Imlib_Image , struct tm * , char * , char * );
81
82
static char * imPrintf (const char * , struct tm * , const char * , const char * ,
82
83
Imlib_Image );
@@ -102,6 +103,7 @@ int main(int argc, char *argv[])
102
103
char * filenameThumb = NULL ;
103
104
struct timespec timeStamp ;
104
105
struct tm * tm ;
106
+ int fd ;
105
107
106
108
/* Get the time ASAP to reduce the timing error in case --delay is used. */
107
109
opt .delayStart = clockNow ();
@@ -155,9 +157,8 @@ int main(int argc, char *argv[])
155
157
imlib_image_attach_data_value ("compression" , NULL , opt .compression , NULL );
156
158
157
159
filenameIM = imPrintf (opt .outputFile , tm , NULL , NULL , image );
158
- scrotCheckIfOverwriteFile (& filenameIM );
159
-
160
- scrotSaveImage (filenameIM );
160
+ fd = scrotCheckIfOverwriteFile (& filenameIM );
161
+ scrotSaveImage (fd , filenameIM );
161
162
162
163
if (opt .thumb != THUMB_DISABLED ) {
163
164
int cwidth , cheight ;
@@ -195,8 +196,8 @@ int main(int argc, char *argv[])
195
196
imlib_image_set_format (opt .format );
196
197
197
198
filenameThumb = imPrintf (opt .thumbFile , tm , NULL , NULL , thumbnail );
198
- scrotCheckIfOverwriteFile (& filenameThumb );
199
- scrotSaveImage (filenameThumb );
199
+ fd = scrotCheckIfOverwriteFile (& filenameThumb );
200
+ scrotSaveImage (fd , filenameThumb );
200
201
imlib_free_image_and_decache ();
201
202
}
202
203
}
@@ -254,9 +255,11 @@ static void uninitXAndImlib(void)
254
255
}
255
256
}
256
257
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 )
258
261
{
259
- imlib_save_image ( filename );
262
+ imlib_save_image_fd ( fd , filename );
260
263
int imErr = imlib_get_error ();
261
264
if (imErr ) {
262
265
const char * errmsg = imlib_strerror (imErr );
@@ -537,43 +540,55 @@ static void scrotGrabMousePointer(Imlib_Image image, const int xOffset,
537
540
XFree (xcim );
538
541
}
539
542
540
- static void scrotCheckIfOverwriteFile (char * * filename )
543
+ static int scrotCheckIfOverwriteFile (char * * filename )
541
544
{
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
+ }
566
552
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
+ }
568
581
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 ;
572
587
}
573
588
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 ;
577
592
}
578
593
579
594
static int scrotMatchWindowClassName (Window target )
0 commit comments