OpenDNSSEC-signer  1.4.3
file.c
Go to the documentation of this file.
1 /*
2  * $Id: file.c 7180 2013-07-03 09:24:52Z 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 static unsigned int file_count = 0;
52 
53 
58 const char*
59 ods_file_mode2str(const char* mode)
60 {
61  if (!mode) {
62  return "no mode";
63  }
64 
65  if (ods_strcmp(mode, "a") == 0) {
66  return "appending";
67  } else if (ods_strcmp(mode, "r") == 0) {
68  return "reading";
69  } else if (ods_strcmp(mode, "w") == 0) {
70  return "writing";
71  }
72  return "unknown mode";
73 }
74 
75 
80 int
81 ods_fgetc(FILE* fd, unsigned int* line_nr)
82 {
83  int c;
84 
85  ods_log_assert(fd);
86  ods_log_assert(line_nr);
87 
88  c = fgetc(fd);
89  if (c == '\n') {
90  (*line_nr)++;
91  }
92  if (c == EOF && errno != 0) {
93  ods_log_crit("[%s] fgetc() failed, enough memory? (%s)",
94  file_str, strerror(errno));
95  }
96  return c;
97 }
98 
99 
104 int
105 ods_skip_whitespace(FILE* fd, unsigned int* line_nr)
106 {
107  int c;
108 
109  ods_log_assert(fd);
110  ods_log_assert(line_nr);
111 
112  while ((c=ods_fgetc(fd, line_nr)) != EOF) {
113  if (c == ' ' || c == '\t' || c == '\r') {
114  continue;
115  }
116  return c;
117  }
118  return EOF;
119 }
120 
121 
126 char*
127 ods_build_path(const char* file, const char* suffix, int dir, int no_slash)
128 {
129  size_t len_file = 0;
130  size_t len_suffix = 0;
131  size_t len_total = 0;
132  char* openf = NULL;
133 
134  if (file) {
135  len_file = strlen(file);
136  if (suffix) {
137  len_suffix = strlen(suffix);
138  }
139  len_total = len_suffix + len_file;
140  if (dir) {
141  len_total++;
142  }
143 
144  if (len_total > 0) {
145  openf = (char*) malloc(sizeof(char)*(len_total + 1));
146  if (!openf) {
147  ods_log_crit("[%s] build path failed: malloc failed", file_str);
148  return NULL;
149  }
150 
151  strncpy(openf, file, len_file);
152  openf[len_file] = '\0';
153  if (no_slash) {
154  size_t i = 0;
155  for (i=0; i<len_file; i++) {
156  switch (openf[i]) {
157  case '/':
158  case ' ':
159  /* more? */
160  openf[i] = '-';
161  break;
162  default:
163  break;
164  }
165  }
166  }
167 
168  if (suffix) {
169  strncat(openf, suffix, len_suffix);
170  }
171  if (dir) {
172  strncat(openf, "/", 1);
173  }
174  openf[len_total] = '\0';
175  }
176  }
177 
178  return openf;
179 }
180 
181 
186 FILE*
187 ods_fopen(const char* file, const char* dir, const char* mode)
188 {
189  FILE* fd = NULL;
190  size_t len_file = 0;
191  size_t len_dir = 0;
192  size_t len_total = 0;
193  char* openf = NULL;
194 
195  ods_log_assert(mode);
196  ods_log_deeebug("[%s] open file %s%s file=%s mode=%s", file_str,
197  (dir?"dir=":""), (dir?dir:""), (file?file:"(null)"),
198  ods_file_mode2str(mode));
199 
200  if (dir) {
201  len_dir= strlen(dir);
202  }
203  if (file) {
204  len_file= strlen(file);
205  }
206  len_total = len_dir + len_file;
207  if (len_total > 0) {
208  openf = (char*) malloc(sizeof(char)*(len_total + 1));
209  if (!openf) {
210  ods_log_error("[%s] unable to open file %s%s%s for %s: malloc() "
211  "failed", file_str, (dir?dir:""), (dir?"/":""),
212  (file?file:"(null)"), ods_file_mode2str(mode));
213  return NULL;
214  }
215  if (dir) {
216  strncpy(openf, dir, len_dir);
217  openf[len_dir] = '\0';
218  if (file) {
219  strncat(openf, file, len_file);
220  }
221  } else if (file) {
222  strncpy(openf, file, len_file);
223  }
224  openf[len_total] = '\0';
225 
226  if (len_file) {
227  fd = fopen(openf, mode);
228  if (!fd) {
229  ods_log_debug("[%s] unable to open file %s for %s: %s",
230  file_str, openf?openf:"(null)",
231  ods_file_mode2str(mode), strerror(errno));
232  } else {
233  file_count++;
234  ods_log_debug("[%s] openfile %s count %u", file_str, openf?openf:"(null)", file_count);
235  }
236  }
237  free((void*) openf);
238  }
239  return fd;
240 }
241 
246 void
247 ods_fclose(FILE* fd)
248 {
249  if (fd) {
250  file_count--;
251  fclose(fd);
252  }
253  return;
254 }
255 
256 
261 ssize_t
262 ods_writen(int fd, const void* vptr, size_t n)
263 {
264  size_t nleft;
265  ssize_t nwritten;
266  const char* ptr;
267 
268  ptr = vptr;
269  nleft = n;
270  while (nleft > 0) {
271  if ((nwritten = write(fd, ptr, nleft)) <= 0) {
272  if (nwritten < 0 && errno == EINTR) {
273  nwritten = 0; /* and call write again */
274  } else {
275  return -1; /* error */
276  }
277  }
278  nleft -= nwritten;
279  ptr += nwritten;
280  }
281  return n;
282 }
283 
284 
289 time_t
290 ods_file_lastmodified(const char* file)
291 {
292  int ret;
293  struct stat buf;
294  FILE* fd;
295  ods_log_assert(file);
296  if ((fd = ods_fopen(file, NULL, "r")) != NULL) {
297  ret = stat(file, &buf);
298  if (ret == -1) {
299  ods_log_error("[%s] unable to stat file %s: %s", file_str,
300  file, strerror(errno));
301  }
302  ods_fclose(fd);
303  return buf.st_mtime;
304  } else {
305  ods_log_error("[%s] unable to stat file %s: ods_fopen() failed",
306  file_str, file);
307  }
308  return 0;
309 }
310 
311 
316 int
317 ods_strcmp(const char* s1, const char* s2)
318 {
319  if (!s1 && !s2) {
320  return 0;
321  } else if (!s1) {
322  return -1;
323  } else if (!s2) {
324  return -1;
325  } else if (strlen(s1) != strlen(s2)) {
326  if (strncmp(s1, s2, strlen(s1)) == 0) {
327  return strlen(s1) - strlen(s2);
328  }
329  }
330  return strncmp(s1, s2, strlen(s1));
331 }
332 
333 
338 int
339 ods_strlowercmp(const char* str1, const char* str2)
340 {
341  while (str1 && str2 && *str1 != '\0' && *str2 != '\0') {
342  if (tolower((int)*str1) != tolower((int)*str2)) {
343  if (tolower((int)*str1) < tolower((int)*str2)) {
344  return -1;
345  }
346  return 1;
347  }
348  str1++;
349  str2++;
350  }
351  if (str1 && str2) {
352  if (*str1 == *str2) {
353  return 0;
354  } else if (*str1 == '\0') {
355  return -1;
356  }
357  } else if (!str1 && !str2) {
358  return 0;
359  } else if (!str1 && str2) {
360  return -1;
361  }
362  return 1;
363 }
364 
365 
370 const char*
371 ods_replace(const char *str, const char *oldstr, const char *newstr)
372 {
373  char* buffer = NULL;
374  char* ch = NULL;
375  size_t part1_len = 0;
376  size_t part2_len = 0;
377  size_t part3_len = 0;
378 
379  if (!str) {
380  return NULL;
381  }
382  if (!oldstr || !newstr) {
383  return str;
384  }
385 
386  if (!(ch = strstr(str, oldstr))) {
387  buffer = strdup(str);
388  return buffer;
389  }
390 
391  part1_len = ch-str;
392  part2_len = strlen(newstr);
393  part3_len = strlen(ch+strlen(oldstr));
394  buffer = calloc(part1_len+part2_len+part3_len+1, sizeof(char));
395  if (!buffer) {
396  return NULL;
397  }
398 
399  if (part1_len) {
400  strncpy(buffer, str, part1_len);
401  buffer[part1_len] = '\0';
402 
403  if (part2_len) {
404  strncat(buffer, str, part2_len);
405  buffer[part1_len+part2_len] = '\0';
406  }
407  } else {
408  strncpy(buffer, newstr, part2_len);
409  buffer[part2_len] = '\0';
410  }
411 
412  if (part3_len) {
413  strncat(buffer, ch+strlen(oldstr), part3_len);
414  buffer[part1_len+part2_len+part3_len] = '\0';
415  }
416 
417  buffer[ch-str] = '\0';
418  snprintf(buffer+(ch-str), SYSTEM_MAXLEN, "%s%s", newstr, ch+strlen(oldstr));
419  return buffer;
420 }
421 
422 
428 ods_file_copy(const char* file1, const char* file2)
429 {
430  char buf[BUFFER_SIZE];
431  int fin = 0;
432  int fout = 0;
433  int read_size = 0;
434  if (!file1 || !file2) {
435  return ODS_STATUS_ASSERT_ERR;
436  }
437  if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) {
438  return ODS_STATUS_FOPEN_ERR;
439  }
440  if ((fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
441  close(fin);
442  return ODS_STATUS_FOPEN_ERR;
443  }
444  while (1) {
445  read_size = read(fin, buf, sizeof(buf));
446  if (read_size == 0) {
447  break;
448  }
449  if (read_size < 0) {
450  close(fin);
451  close(fout);
452  return ODS_STATUS_FREAD_ERR;
453  }
454  if (write(fout, buf, (unsigned int) read_size) < 0) {
455  close(fin);
456  close(fout);
457  return ODS_STATUS_FWRITE_ERR;
458  }
459  }
460  close(fin);
461  close(fout);
462  return ODS_STATUS_OK;
463 }
464 
465 
470 char*
471 ods_dir_name(const char* file) {
472  int l = strlen(file);
473  char* dir = NULL;
474 
475  ods_log_assert(file);
476 
477  /* find seperator */
478  while (l>0 && strncmp(file + (l-1), "/", 1) != 0) {
479  l--;
480  }
481 
482  /* now strip off (multiple seperators) */
483  while (l>0 && strncmp(file + (l-1), "/", 1) == 0) {
484  l--;
485  }
486 
487  if (l) {
488  dir = (char*) calloc(l+1, sizeof(char));
489  if (dir) {
490  dir = strncpy(dir, file, l);
491  }
492  return dir;
493  }
494  return NULL;
495 }
496 
501 void
502 ods_chown(const char* file, uid_t uid, gid_t gid, int getdir)
503 {
504  char* dir = NULL;
505 
506  if (!file) {
507  ods_log_warning("[%s] no filename given for chown()", file_str);
508  return;
509  }
510 
511  if (!getdir) {
512  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
513  file_str, file, (signed long) uid, (signed long) gid);
514  if (chown(file, uid, gid) != 0) {
515  ods_log_error("[%s] chown() %s failed: %s", file_str, file,
516  strerror(errno));
517  }
518  } else if ((dir = ods_dir_name(file)) != NULL) {
519  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
520  file_str, dir, (signed long) uid, (signed long) gid);
521  if (chown(dir, uid, gid) != 0) {
522  ods_log_error("[%s] chown() %s failed: %s", file_str,
523  dir, strerror(errno));
524  }
525  free((void*) dir);
526  } else {
527  ods_log_warning("[%s] use of relative path: %s", file_str, file);
528  }
529  return;
530 }
531 
532 
537 void
538 ods_str_trim(char* str)
539 {
540  int i = strlen(str), nl = 0;
541 
542  /* trailing */
543  while (i>0) {
544  --i;
545  if (str[i] == '\n') {
546  nl = 1;
547  }
548  if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') {
549  str[i] = '\0';
550  } else {
551  break;
552  }
553  }
554  if (nl) {
555  str[++i] = '\n';
556  }
557 
558  /* leading */
559  i = 0;
560  while (str[i] == ' ' || str[i] == '\t') {
561  i++;
562  }
563  while (*(str+i) != '\0') {
564  *str = *(str+i);
565  str++;
566  }
567  *str = '\0';
568  return;
569 }
570 
571 
576 void
577 ods_str_list_add(char*** list, char* str)
578 {
579  char** old = NULL;
580  size_t count = 0;
581 
582  if (*list) {
583  for (count=0; (*list)[count]; ++count) {
584  ;
585  }
586  old = *list;
587 
588  *list = (char**) calloc(sizeof(char*), count+2);
589  if (!*list) {
590  ods_fatal_exit("[%s] fatal ods_str_list_add(): calloc() failed",
591  file_str);
592  }
593  if (old) {
594  memcpy(*list, old, count * sizeof(char*));
595  }
596  free(old);
597  (*list)[count] = str;
598  (*list)[count+1] = NULL;
599  } else {
601  *list = calloc(sizeof(char*), 2);
602  if (!*list) {
603  ods_fatal_exit("[%s] fatal ods_str_list_add(): calloc() failed",
604  file_str);
605  }
606  (*list)[0] = str;
607  }
608  return;
609 }
void ods_log_debug(const char *format,...)
Definition: log.c:272
char * ods_dir_name(const char *file)
Definition: file.c:471
void ods_fatal_exit(const char *format,...)
Definition: log.c:384
int ods_skip_whitespace(FILE *fd, unsigned int *line_nr)
Definition: file.c:105
enum ods_enum_status ods_status
Definition: status.h:91
time_t ods_file_lastmodified(const char *file)
Definition: file.c:290
void ods_log_error(const char *format,...)
Definition: log.c:336
int ods_strcmp(const char *s1, const char *s2)
Definition: file.c:317
void ods_str_list_add(char ***list, char *str)
Definition: file.c:577
int ods_fgetc(FILE *fd, unsigned int *line_nr)
Definition: file.c:81
FILE * ods_fopen(const char *file, const char *dir, const char *mode)
Definition: file.c:187
void ods_log_crit(const char *format,...)
Definition: log.c:352
void ods_str_trim(char *str)
Definition: file.c:538
#define SYSTEM_MAXLEN
Definition: file.h:51
ssize_t ods_writen(int fd, const void *vptr, size_t n)
Definition: file.c:262
char * ods_build_path(const char *file, const char *suffix, int dir, int no_slash)
Definition: file.c:127
void ods_chown(const char *file, uid_t uid, gid_t gid, int getdir)
Definition: file.c:502
#define BUFFER_SIZE
Definition: file.c:48
void ods_fclose(FILE *fd)
Definition: file.c:247
void ods_log_deeebug(const char *format,...)
Definition: log.c:256
int ods_strlowercmp(const char *str1, const char *str2)
Definition: file.c:339
#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:371
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:428
const char * ods_file_mode2str(const char *mode)
Definition: file.c:59