OpenDNSSEC-signer  1.4.1
file.c
Go to the documentation of this file.
1 /*
2  * $Id: file.c 7084 2013-04-04 15:13:29Z matthijs $
3  *
4  * Copyright (c) 2009 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "config.h"
35 #include "shared/file.h"
36 #include "shared/log.h"
37 
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <unistd.h>
47 
48 #define BUFFER_SIZE (16 * 1024) /* use 16K buffers */
49 
50 static const char* file_str = "file";
51 
52 
57 const char*
58 ods_file_mode2str(const char* mode)
59 {
60  if (!mode) {
61  return "no mode";
62  }
63 
64  if (ods_strcmp(mode, "a") == 0) {
65  return "appending";
66  } else if (ods_strcmp(mode, "r") == 0) {
67  return "reading";
68  } else if (ods_strcmp(mode, "w") == 0) {
69  return "writing";
70  }
71  return "unknown mode";
72 }
73 
74 
79 int
80 ods_fgetc(FILE* fd, unsigned int* line_nr)
81 {
82  int c;
83 
84  ods_log_assert(fd);
85  ods_log_assert(line_nr);
86 
87  c = fgetc(fd);
88  if (c == '\n') {
89  (*line_nr)++;
90  }
91  if (c == EOF && errno != 0) {
92  ods_log_crit("[%s] fgetc() failed, enough memory? (%s)",
93  file_str, strerror(errno));
94  }
95  return c;
96 }
97 
98 
103 int
104 ods_skip_whitespace(FILE* fd, unsigned int* line_nr)
105 {
106  int c;
107 
108  ods_log_assert(fd);
109  ods_log_assert(line_nr);
110 
111  while ((c=ods_fgetc(fd, line_nr)) != EOF) {
112  if (c == ' ' || c == '\t' || c == '\r') {
113  continue;
114  }
115  return c;
116  }
117  return EOF;
118 }
119 
120 
125 char*
126 ods_build_path(const char* file, const char* suffix, int dir, int no_slash)
127 {
128  size_t len_file = 0;
129  size_t len_suffix = 0;
130  size_t len_total = 0;
131  char* openf = NULL;
132 
133  if (file) {
134  len_file = strlen(file);
135  if (suffix) {
136  len_suffix = strlen(suffix);
137  }
138  len_total = len_suffix + len_file;
139  if (dir) {
140  len_total++;
141  }
142 
143  if (len_total > 0) {
144  openf = (char*) malloc(sizeof(char)*(len_total + 1));
145  if (!openf) {
146  ods_log_crit("[%s] build path failed: malloc failed", file_str);
147  return NULL;
148  }
149 
150  strncpy(openf, file, len_file);
151  openf[len_file] = '\0';
152  if (no_slash) {
153  size_t i = 0;
154  for (i=0; i<len_file; i++) {
155  switch (openf[i]) {
156  case '/':
157  case ' ':
158  /* more? */
159  openf[i] = '-';
160  break;
161  default:
162  break;
163  }
164  }
165  }
166 
167  if (suffix) {
168  strncat(openf, suffix, len_suffix);
169  }
170  if (dir) {
171  strncat(openf, "/", 1);
172  }
173  openf[len_total] = '\0';
174  }
175  }
176 
177  return openf;
178 }
179 
180 
185 FILE*
186 ods_fopen(const char* file, const char* dir, const char* mode)
187 {
188  FILE* fd = NULL;
189  size_t len_file = 0;
190  size_t len_dir = 0;
191  size_t len_total = 0;
192  char* openf = NULL;
193 
194  ods_log_assert(mode);
195  ods_log_deeebug("[%s] open file %s%s file=%s mode=%s", file_str,
196  (dir?"dir=":""), (dir?dir:""), (file?file:"(null)"),
197  ods_file_mode2str(mode));
198 
199  if (dir) {
200  len_dir= strlen(dir);
201  }
202  if (file) {
203  len_file= strlen(file);
204  }
205  len_total = len_dir + len_file;
206  if (len_total > 0) {
207  openf = (char*) malloc(sizeof(char)*(len_total + 1));
208  if (!openf) {
209  ods_log_error("[%s] unable to open file %s%s%s for %s: malloc() "
210  "failed", file_str, (dir?dir:""), (dir?"/":""),
211  (file?file:"(null)"), ods_file_mode2str(mode));
212  return NULL;
213  }
214  if (dir) {
215  strncpy(openf, dir, len_dir);
216  openf[len_dir] = '\0';
217  if (file) {
218  strncat(openf, file, len_file);
219  }
220  } else if (file) {
221  strncpy(openf, file, len_file);
222  }
223  openf[len_total] = '\0';
224 
225  if (len_file) {
226  fd = fopen(openf, mode);
227  if (!fd) {
228  ods_log_debug("[%s] unable to open file %s for %s: %s",
229  file_str, openf?openf:"(null)",
230  ods_file_mode2str(mode), strerror(errno));
231  }
232  }
233  free((void*) openf);
234  }
235  return fd;
236 }
237 
242 void
243 ods_fclose(FILE* fd)
244 {
245  if (fd) {
246  fclose(fd);
247  }
248  return;
249 }
250 
251 
256 ssize_t
257 ods_writen(int fd, const void* vptr, size_t n)
258 {
259  size_t nleft;
260  ssize_t nwritten;
261  const char* ptr;
262 
263  ptr = vptr;
264  nleft = n;
265  while (nleft > 0) {
266  if ((nwritten = write(fd, ptr, nleft)) <= 0) {
267  if (nwritten < 0 && errno == EINTR) {
268  nwritten = 0; /* and call write again */
269  } else {
270  return -1; /* error */
271  }
272  }
273  nleft -= nwritten;
274  ptr += nwritten;
275  }
276  return n;
277 }
278 
279 
284 time_t
285 ods_file_lastmodified(const char* file)
286 {
287  int ret;
288  struct stat buf;
289  FILE* fd;
290  ods_log_assert(file);
291  if ((fd = ods_fopen(file, NULL, "r")) != NULL) {
292  ret = stat(file, &buf);
293  if (ret == -1) {
294  ods_log_error("[%s] unable to stat file %s: %s", file_str,
295  file, strerror(errno));
296  }
297  ods_fclose(fd);
298  return buf.st_mtime;
299  } else {
300  ods_log_error("[%s] unable to stat file %s: ods_fopen() failed",
301  file_str, file);
302  }
303  return 0;
304 }
305 
306 
311 int
312 ods_strcmp(const char* s1, const char* s2)
313 {
314  if (!s1 && !s2) {
315  return 0;
316  } else if (!s1) {
317  return -1;
318  } else if (!s2) {
319  return -1;
320  } else if (strlen(s1) != strlen(s2)) {
321  if (strncmp(s1, s2, strlen(s1)) == 0) {
322  return strlen(s1) - strlen(s2);
323  }
324  }
325  return strncmp(s1, s2, strlen(s1));
326 }
327 
328 
333 int
334 ods_strlowercmp(const char* str1, const char* str2)
335 {
336  while (str1 && str2 && *str1 != '\0' && *str2 != '\0') {
337  if (tolower((int)*str1) != tolower((int)*str2)) {
338  if (tolower((int)*str1) < tolower((int)*str2)) {
339  return -1;
340  }
341  return 1;
342  }
343  str1++;
344  str2++;
345  }
346  if (str1 && str2) {
347  if (*str1 == *str2) {
348  return 0;
349  } else if (*str1 == '\0') {
350  return -1;
351  }
352  } else if (!str1 && !str2) {
353  return 0;
354  } else if (!str1 && str2) {
355  return -1;
356  }
357  return 1;
358 }
359 
360 
365 const char*
366 ods_replace(const char *str, const char *oldstr, const char *newstr)
367 {
368  char* buffer = NULL;
369  char* ch = NULL;
370  size_t part1_len = 0;
371  size_t part2_len = 0;
372  size_t part3_len = 0;
373 
374  if (!str) {
375  return NULL;
376  }
377  if (!oldstr || !newstr) {
378  return str;
379  }
380 
381  if (!(ch = strstr(str, oldstr))) {
382  buffer = strdup(str);
383  return buffer;
384  }
385 
386  part1_len = ch-str;
387  part2_len = strlen(newstr);
388  part3_len = strlen(ch+strlen(oldstr));
389  buffer = calloc(part1_len+part2_len+part3_len+1, sizeof(char));
390  if (!buffer) {
391  return NULL;
392  }
393 
394  if (part1_len) {
395  strncpy(buffer, str, part1_len);
396  buffer[part1_len] = '\0';
397 
398  if (part2_len) {
399  strncat(buffer, str, part2_len);
400  buffer[part1_len+part2_len] = '\0';
401  }
402  } else {
403  strncpy(buffer, newstr, part2_len);
404  buffer[part2_len] = '\0';
405  }
406 
407  if (part3_len) {
408  strncat(buffer, ch+strlen(oldstr), part3_len);
409  buffer[part1_len+part2_len+part3_len] = '\0';
410  }
411 
412  buffer[ch-str] = '\0';
413  snprintf(buffer+(ch-str), SYSTEM_MAXLEN, "%s%s", newstr, ch+strlen(oldstr));
414  return buffer;
415 }
416 
417 
423 ods_file_copy(const char* file1, const char* file2)
424 {
425  char buf[BUFFER_SIZE];
426  int fin = 0;
427  int fout = 0;
428  int read_size = 0;
429  if (!file1 || !file2) {
430  return ODS_STATUS_ASSERT_ERR;
431  }
432  if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) {
433  return ODS_STATUS_FOPEN_ERR;
434  }
435  if ((fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
436  close(fin);
437  return ODS_STATUS_FOPEN_ERR;
438  }
439  while (1) {
440  read_size = read(fin, buf, sizeof(buf));
441  if (read_size == 0) {
442  break;
443  }
444  if (read_size < 0) {
445  close(fin);
446  close(fout);
447  return ODS_STATUS_FREAD_ERR;
448  }
449  if (write(fout, buf, (unsigned int) read_size) < 0) {
450  close(fin);
451  close(fout);
452  return ODS_STATUS_FWRITE_ERR;
453  }
454  }
455  close(fin);
456  close(fout);
457  return ODS_STATUS_OK;
458 }
459 
460 
465 char*
466 ods_dir_name(const char* file) {
467  int l = strlen(file);
468  char* dir = NULL;
469 
470  ods_log_assert(file);
471 
472  /* find seperator */
473  while (l>0 && strncmp(file + (l-1), "/", 1) != 0) {
474  l--;
475  }
476 
477  /* now strip off (multiple seperators) */
478  while (l>0 && strncmp(file + (l-1), "/", 1) == 0) {
479  l--;
480  }
481 
482  if (l) {
483  dir = (char*) calloc(l+1, sizeof(char));
484  if (dir) {
485  dir = strncpy(dir, file, l);
486  }
487  return dir;
488  }
489  return NULL;
490 }
491 
496 void
497 ods_chown(const char* file, uid_t uid, gid_t gid, int getdir)
498 {
499  char* dir = NULL;
500 
501  if (!file) {
502  ods_log_warning("[%s] no filename given for chown()", file_str);
503  return;
504  }
505 
506  if (!getdir) {
507  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
508  file_str, file, (signed long) uid, (signed long) gid);
509  if (chown(file, uid, gid) != 0) {
510  ods_log_error("[%s] chown() %s failed: %s", file_str, file,
511  strerror(errno));
512  }
513  } else if ((dir = ods_dir_name(file)) != NULL) {
514  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
515  file_str, dir, (signed long) uid, (signed long) gid);
516  if (chown(dir, uid, gid) != 0) {
517  ods_log_error("[%s] chown() %s failed: %s", file_str,
518  dir, strerror(errno));
519  }
520  free((void*) dir);
521  } else {
522  ods_log_warning("[%s] use of relative path: %s", file_str, file);
523  }
524  return;
525 }
526 
527 
532 void
533 ods_str_trim(char* str)
534 {
535  int i = strlen(str), nl = 0;
536 
537  /* trailing */
538  while (i>0) {
539  --i;
540  if (str[i] == '\n') {
541  nl = 1;
542  }
543  if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') {
544  str[i] = '\0';
545  } else {
546  break;
547  }
548  }
549  if (nl) {
550  str[++i] = '\n';
551  }
552 
553  /* leading */
554  i = 0;
555  while (str[i] == ' ' || str[i] == '\t') {
556  i++;
557  }
558  while (*(str+i) != '\0') {
559  *str = *(str+i);
560  str++;
561  }
562  *str = '\0';
563  return;
564 }
565 
566 
571 void
572 ods_str_list_add(char*** list, char* str)
573 {
574  char** old = NULL;
575  size_t count = 0;
576 
577  if (*list) {
578  for (count=0; (*list)[count]; ++count) {
579  ;
580  }
581  old = *list;
582 
583  *list = (char**) calloc(sizeof(char*), count+2);
584  if (!*list) {
585  ods_fatal_exit("[%s] fatal ods_str_list_add(): calloc() failed",
586  file_str);
587  }
588  if (old) {
589  memcpy(*list, old, count * sizeof(char*));
590  }
591  free(old);
592  (*list)[count] = str;
593  (*list)[count+1] = NULL;
594  } else {
596  *list = calloc(sizeof(char*), 2);
597  if (!*list) {
598  ods_fatal_exit("[%s] fatal ods_str_list_add(): calloc() failed",
599  file_str);
600  }
601  (*list)[0] = str;
602  }
603  return;
604 }
void ods_log_debug(const char *format,...)
Definition: log.c:272
char * ods_dir_name(const char *file)
Definition: file.c:466
void ods_fatal_exit(const char *format,...)
Definition: log.c:384
int ods_skip_whitespace(FILE *fd, unsigned int *line_nr)
Definition: file.c:104
enum ods_enum_status ods_status
Definition: status.h:89
time_t ods_file_lastmodified(const char *file)
Definition: file.c:285
void ods_log_error(const char *format,...)
Definition: log.c:336
int ods_strcmp(const char *s1, const char *s2)
Definition: file.c:312
void ods_str_list_add(char ***list, char *str)
Definition: file.c:572
int ods_fgetc(FILE *fd, unsigned int *line_nr)
Definition: file.c:80
FILE * ods_fopen(const char *file, const char *dir, const char *mode)
Definition: file.c:186
void ods_log_crit(const char *format,...)
Definition: log.c:352
void ods_str_trim(char *str)
Definition: file.c:533
#define SYSTEM_MAXLEN
Definition: file.h:51
ssize_t ods_writen(int fd, const void *vptr, size_t n)
Definition: file.c:257
char * ods_build_path(const char *file, const char *suffix, int dir, int no_slash)
Definition: file.c:126
void ods_chown(const char *file, uid_t uid, gid_t gid, int getdir)
Definition: file.c:497
#define BUFFER_SIZE
Definition: file.c:48
void ods_fclose(FILE *fd)
Definition: file.c:243
void ods_log_deeebug(const char *format,...)
Definition: log.c:256
int ods_strlowercmp(const char *str1, const char *str2)
Definition: file.c:334
#define ods_log_assert(x)
Definition: log.h:156
const char * ods_replace(const char *str, const char *oldstr, const char *newstr)
Definition: file.c:366
void ods_log_warning(const char *format,...)
Definition: log.c:320
ods_status ods_file_copy(const char *file1, const char *file2)
Definition: file.c:423
const char * ods_file_mode2str(const char *mode)
Definition: file.c:58