Coverage Report

Created: 2025-08-29 06:17

/src/jpegoptim/misc.c
Line
Count
Source (jump to first uncovered line)
1
/* misc.c
2
 *
3
 * Copyright (C) 1996-2025 Timo Kokkonen
4
 * All Rights Reserved.
5
 *
6
 * SPDX-License-Identifier: GPL-3.0-or-later
7
 *
8
 * This file is part of JPEGoptim.
9
 *
10
 * JPEGoptim is free software: you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation, either version 3 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * JPEGoptim is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with JPEGoptim. If not, see <https://www.gnu.org/licenses/>.
22
 */
23
24
#ifdef HAVE_CONFIG_H
25
#include "config.h"
26
#endif
27
#include <stdio.h>
28
#include <fcntl.h>
29
#include <sys/types.h>
30
#include <sys/stat.h>
31
#ifdef HAVE_UNISTD_H
32
#include <unistd.h>
33
#endif
34
#include <string.h>
35
#include <stdarg.h>
36
#include <stdlib.h>
37
#include <time.h>
38
39
40
#include "jpegoptim.h"
41
42
43
FILE* create_file(const char *name)
44
0
{
45
0
  FILE *f;
46
0
  int fd;
47
48
0
  if (!name)
49
0
    return NULL;
50
51
#ifdef WIN32
52
  fd = open(name, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, _S_IREAD | _S_IWRITE);
53
#else
54
0
  fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR | S_IRUSR);
55
0
#endif
56
0
  if (fd < 0)
57
0
    return NULL;
58
0
  if (!(f = fdopen(fd, "wb"))) {
59
0
    close(fd);
60
0
    return NULL;
61
0
  }
62
63
0
  return f;
64
0
}
65
66
67
FILE *create_temp_file(const char *tmpdir, const char *name, char *filename, size_t filename_len)
68
62
{
69
62
  FILE *f;
70
62
  int newlen;
71
72
62
#ifdef HAVE_MKSTEMPS
73
  /* Rely on mkstemps() to create us temporary file safely... */
74
62
  newlen = snprintf(filename, filename_len, "%s%s-%u-%u.XXXXXX.tmp",
75
62
      tmpdir, name, getuid(), getpid());
76
#else
77
  /* If platform is missing mkstemps(), try to create at least somewhat "safe" temp file... */
78
  newlen = snprintf(filename, filename_len, "%s%s-%u-%u.%lu.tmp",
79
      tmpdir, name, getuid(), getpid(), (unsigned long)time(NULL));
80
#endif
81
62
  if (newlen >= filename_len) {
82
0
    warn("temp filename too long: %s", filename);
83
0
    return NULL;
84
0
  }
85
86
62
#ifdef HAVE_MKSTEMPS
87
62
  int tmpfd = mkstemps(filename, 4);
88
62
  if (tmpfd < 0) {
89
0
    warn("error creating temp file: mkstemps('%s', 4) failed", filename);
90
0
    return NULL;
91
0
  }
92
62
  f = fdopen(tmpfd, "wb");
93
#else
94
  f = create_file(filename);
95
#endif
96
97
62
  return f;
98
62
}
99
100
101
int delete_file(const char *name)
102
0
{
103
0
  int retval;
104
105
0
  if (!name)
106
0
    return -1;
107
108
0
  if (verbose_mode > 1 && !quiet_mode)
109
0
    fprintf(stderr,"deleting: %s\n",name);
110
0
  if ((retval=unlink(name)) && !quiet_mode)
111
0
    warn("error removing file: %s",name);
112
113
0
  return retval;
114
0
}
115
116
117
long file_size(FILE *fp)
118
730
{
119
730
  struct stat buf;
120
121
730
  if (!fp)
122
0
    return -1;
123
730
  if (fstat(fileno(fp),&buf) != 0)
124
0
    return -2;
125
126
730
  return (long)buf.st_size;
127
730
}
128
129
130
int is_directory(const char *pathname)
131
0
{
132
0
  struct stat buf;
133
134
0
  if (!pathname)
135
0
    return 0;
136
137
0
  if (stat(pathname,&buf) != 0)
138
0
    return 0;
139
140
0
  return (S_ISDIR(buf.st_mode) ? 1 : 0);
141
0
}
142
143
144
int is_file(const char *filename, struct stat *st)
145
0
{
146
0
  struct stat buf;
147
148
0
  if (!filename)
149
0
    return 0;
150
151
0
  if (lstat(filename,&buf) != 0)
152
0
    return 0;
153
0
  if (st)
154
0
    *st=buf;
155
156
0
  return (S_ISREG(buf.st_mode) ? 1 : 0);
157
0
}
158
159
160
int file_exists(const char *pathname)
161
0
{
162
0
  struct stat buf;
163
164
0
  if (!pathname)
165
0
    return 0;
166
167
0
  return (stat(pathname,&buf) == 0 ? 1 : 0);
168
0
}
169
170
171
int rename_file(const char *old_path, const char *new_path)
172
62
{
173
62
  if (!old_path || !new_path)
174
0
    return -1;
175
#ifdef WIN32
176
  if (file_exists(new_path))
177
    delete_file(new_path);
178
#endif
179
62
  return rename(old_path,new_path);
180
62
}
181
182
183
0
#define COPY_BUF_SIZE  (256 * 1024)
184
185
int copy_file(const char *srcfile, const char *dstfile)
186
0
{
187
0
  FILE *in,*out;
188
0
  unsigned char *buf;
189
0
  int r,w;
190
0
  int err=0;
191
192
0
  if (!srcfile || !dstfile)
193
0
    return -1;
194
195
0
  if (!(in = fopen(srcfile, "rb"))) {
196
0
    warn("failed to open file for reading: %s", srcfile);
197
0
    return -2;
198
0
  }
199
0
  if (!(out = create_file(dstfile))) {
200
0
    fclose(in);
201
0
    warn("failed to open file for writing: %s", dstfile);
202
0
    return -3;
203
0
  }
204
205
0
  if (!(buf = calloc(COPY_BUF_SIZE, 1)))
206
0
    fatal("out of memory");
207
208
209
0
  do {
210
0
    r = fread(buf, 1, COPY_BUF_SIZE, in);
211
0
    if (r > 0) {
212
0
      w = fwrite(buf, 1, r, out);
213
0
      if (w != r) {
214
0
        err=1;
215
0
        warn("error writing to file: %s", dstfile);
216
0
        break;
217
0
      }
218
0
    } else {
219
0
      if (ferror(in)) {
220
0
        err=2;
221
0
        warn("error reading from file: %s", srcfile);
222
0
        break;
223
0
      }
224
0
    }
225
0
  } while (!feof(in));
226
227
0
  fclose(out);
228
0
  fclose(in);
229
0
  free(buf);
230
231
0
  return err;
232
0
}
233
234
235
char *fgetstr(char *s, size_t size, FILE *stream)
236
0
{
237
0
  char *p;
238
239
0
  if (!s || size < 1 || !stream)
240
0
    return NULL;
241
242
0
  if (!fgets(s, size, stream))
243
0
    return NULL;
244
245
0
  p = s + strnlen(s, size) - 1;
246
0
  while ((p >= s) && ((*p == 10) || (*p == 13)))
247
0
    *p--=0;
248
249
0
  return s;
250
0
}
251
252
253
char *splitdir(const char *pathname, char *buf, size_t size)
254
0
{
255
0
  char *s;
256
0
  int len = 0;
257
258
0
  if (!pathname || !buf || size < 1)
259
0
    return NULL;
260
261
0
  if ((s = strrchr(pathname, DIR_SEPARATOR_C)))
262
0
    len = (s - pathname) + 1;
263
0
  if (len >= size)
264
0
    return NULL;
265
0
  if (len > 0)
266
0
    memcpy(buf, pathname, len);
267
0
  buf[len] = 0;
268
269
0
  return buf;
270
0
}
271
272
273
char *splitname(const char *pathname, char *buf, size_t size)
274
0
{
275
0
  const char *s = NULL;
276
0
  int len;
277
278
0
  if (!pathname || !buf || size < 1)
279
0
    return NULL;
280
281
0
  if ((s = strrchr(pathname, DIR_SEPARATOR_C)))
282
0
    s++;
283
0
  else
284
0
    s=pathname;
285
286
0
  if ((len = strlen(s)) >= size)
287
0
    return NULL;
288
0
  if (len > 0)
289
0
    memcpy(buf, s, len);
290
0
  buf[len] = 0;
291
292
0
  return buf;
293
0
}
294
295
296
char *strncopy(char *dst, const char *src, size_t size)
297
830
{
298
830
  if (!dst || !src || size < 1)
299
0
    return dst;
300
301
830
  if (size > 1)
302
830
    strncpy(dst, src, size - 1);
303
830
  dst[size - 1] = 0;
304
305
830
  return dst;
306
830
}
307
308
309
char *strncatenate(char *dst, const char *src, size_t size)
310
2.98k
{
311
2.98k
  int used, free;
312
313
2.98k
  if (!dst || !src || size < 1)
314
0
    return dst;
315
316
  /* Check if dst string is already "full" ... */
317
2.98k
  used = strnlen(dst, size);
318
2.98k
  if ((free = size - used) <= 1)
319
153
    return dst;
320
321
2.82k
  return strncat(dst + used, src, free - 1);
322
2.98k
}
323
324
325
char *str_add_list(char *dst, size_t size, const char *src, const char *delim)
326
1.65k
{
327
1.65k
  if (!dst || !src || !delim || size < 1)
328
0
    return dst;
329
330
1.65k
  if (strnlen(dst, size) > 0)
331
1.32k
    strncatenate(dst, delim, size);
332
333
1.65k
  return strncatenate(dst, src, size);
334
1.65k
}
335
336
337
void fatal(const char *format, ...)
338
0
{
339
0
  va_list args;
340
341
0
  fprintf(stderr, PROGRAMNAME ": ");
342
0
  va_start(args,format);
343
0
  vfprintf(stderr, format, args);
344
0
  va_end(args);
345
0
  fprintf(stderr,"\n");
346
0
  fflush(stderr);
347
348
0
  exit(3);
349
0
}
350
351
352
void warn(const char *format, ...)
353
0
{
354
0
  va_list args;
355
356
0
  if (quiet_mode) return;
357
358
0
  fprintf(stderr, PROGRAMNAME ": ");
359
0
  va_start(args,format);
360
0
  vfprintf(stderr, format, args);
361
0
  va_end(args);
362
0
  fprintf(stderr,"\n");
363
0
  fflush(stderr);
364
0
}
365
366
367
/* eof :-) */