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