OpenDNSSEC-signer  1.4.7
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  char* f = "root";
132 
133  if (file) {
134  if (ods_strcmp(file, ".")) {
135  f = file;
136  }
137 
138  len_file = strlen(f);
139  if (suffix) {
140  len_suffix = strlen(suffix);
141  }
142  len_total = len_suffix + len_file;
143  if (dir) {
144  len_total++;
145  }
146 
147  if (len_total > 0) {
148  openf = (char*) malloc(sizeof(char)*(len_total + 1));
149  if (!openf) {
150  ods_log_crit("[%s] build path failed: malloc failed", file_str);
151  return NULL;
152  }
153 
154  strncpy(openf, f, len_file);
155  openf[len_file] = '\0';
156  if (no_slash) {
157  size_t i = 0;
158  for (i=0; i<len_file; i++) {
159  switch (openf[i]) {
160  case '/':
161  case ' ':
162  /* more? */
163  openf[i] = '-';
164  break;
165  default:
166  break;
167  }
168  }
169  }
170 
171  if (suffix) {
172  strncat(openf, suffix, len_suffix);
173  }
174  if (dir) {
175  strncat(openf, "/", 1);
176  }
177  openf[len_total] = '\0';
178  }
179  }
180 
181  return openf;
182 }
183 
184 
189 FILE*
190 ods_fopen(const char* file, const char* dir, const char* mode)
191 {
192  FILE* fd = NULL;
193  size_t len_file = 0;
194  size_t len_dir = 0;
195  size_t len_total = 0;
196  char* openf = NULL;
197 
198  ods_log_assert(mode);
199  ods_log_deeebug("[%s] open file %s%s file=%s mode=%s", file_str,
200  (dir?"dir=":""), (dir?dir:""), (file?file:"(null)"),
201  ods_file_mode2str(mode));
202 
203  if (dir) {
204  len_dir= strlen(dir);
205  }
206  if (file) {
207  len_file= strlen(file);
208  }
209  len_total = len_dir + len_file;
210  if (len_total > 0) {
211  openf = (char*) malloc(sizeof(char)*(len_total + 1));
212  if (!openf) {
213  ods_log_error("[%s] unable to open file %s%s%s for %s: malloc() "
214  "failed", file_str, (dir?dir:""), (dir?"/":""),
215  (file?file:"(null)"), ods_file_mode2str(mode));
216  return NULL;
217  }
218  if (dir) {
219  strncpy(openf, dir, len_dir);
220  openf[len_dir] = '\0';
221  if (file) {
222  strncat(openf, file, len_file);
223  }
224  } else if (file) {
225  strncpy(openf, file, len_file);
226  }
227  openf[len_total] = '\0';
228 
229  if (len_file) {
230  fd = fopen(openf, mode);
231  if (!fd) {
232  ods_log_debug("[%s] unable to open file %s for %s: %s",
233  file_str, openf?openf:"(null)",
234  ods_file_mode2str(mode), strerror(errno));
235  } else {
236  file_count++;
237  ods_log_debug("[%s] openfile %s count %u", file_str, openf?openf:"(null)", file_count);
238  }
239  }
240  free((void*) openf);
241  }
242  return fd;
243 }
244 
249 void
250 ods_fclose(FILE* fd)
251 {
252  if (fd) {
253  file_count--;
254  fclose(fd);
255  }
256  return;
257 }
258 
259 
264 ssize_t
265 ods_writen(int fd, const void* vptr, size_t n)
266 {
267  size_t nleft;
268  ssize_t nwritten;
269  const char* ptr;
270 
271  ptr = vptr;
272  nleft = n;
273  while (nleft > 0) {
274  if ((nwritten = write(fd, ptr, nleft)) <= 0) {
275  if (nwritten < 0 && errno == EINTR) {
276  nwritten = 0; /* and call write again */
277  } else {
278  return -1; /* error */
279  }
280  }
281  nleft -= nwritten;
282  ptr += nwritten;
283  }
284  return n;
285 }
286 
287 
292 time_t
293 ods_file_lastmodified(const char* file)
294 {
295  int ret;
296  struct stat buf;
297  FILE* fd;
298  ods_log_assert(file);
299  if ((fd = ods_fopen(file, NULL, "r")) != NULL) {
300  ret = stat(file, &buf);
301  if (ret == -1) {
302  ods_log_warning("[%s] unable to stat file %s: %s", file_str,
303  file, strerror(errno));
304  }
305  ods_fclose(fd);
306  return buf.st_mtime;
307  } else {
308  ods_log_debug("[%s] unable to stat file %s: ods_fopen() failed",
309  file_str, file);
310  }
311  return 0;
312 }
313 
314 
319 int
320 ods_strcmp(const char* s1, const char* s2)
321 {
322  if (!s1 && !s2) {
323  return 0;
324  } else if (!s1) {
325  return -1;
326  } else if (!s2) {
327  return 1;
328  } else if (strlen(s1) != strlen(s2)) {
329  if (strncmp(s1, s2, strlen(s1)) == 0) {
330  return strlen(s1) - strlen(s2);
331  }
332  }
333  return strncmp(s1, s2, strlen(s1));
334 }
335 
336 
341 int
342 ods_strlowercmp(const char* str1, const char* str2)
343 {
344  while (str1 && str2 && *str1 != '\0' && *str2 != '\0') {
345  if (tolower((int)*str1) != tolower((int)*str2)) {
346  if (tolower((int)*str1) < tolower((int)*str2)) {
347  return -1;
348  }
349  return 1;
350  }
351  str1++;
352  str2++;
353  }
354  if (str1 && str2) {
355  if (*str1 == *str2) {
356  return 0;
357  } else if (*str1 == '\0') {
358  return -1;
359  }
360  } else if (!str1 && !str2) {
361  return 0;
362  } else if (!str1 && str2) {
363  return -1;
364  }
365  return 1;
366 }
367 
368 
373 const char*
374 ods_replace(const char *str, const char *oldstr, const char *newstr)
375 {
376  char* buffer = NULL;
377  char* ch = NULL;
378  size_t part1_len = 0;
379  size_t part2_len = 0;
380  size_t part3_len = 0;
381 
382  if (!str) {
383  return NULL;
384  }
385  if (!oldstr || !newstr) {
386  return str;
387  }
388 
389  if (!(ch = strstr(str, oldstr))) {
390  buffer = strdup(str);
391  return buffer;
392  }
393 
394  part1_len = ch-str;
395  part2_len = strlen(newstr);
396  part3_len = strlen(ch+strlen(oldstr));
397  buffer = calloc(part1_len+part2_len+part3_len+1, sizeof(char));
398  if (!buffer) {
399  return NULL;
400  }
401 
402  if (part1_len) {
403  strncpy(buffer, str, part1_len);
404  buffer[part1_len] = '\0';
405 
406  if (part2_len) {
407  strncat(buffer, str, part2_len);
408  buffer[part1_len+part2_len] = '\0';
409  }
410  } else {
411  strncpy(buffer, newstr, part2_len);
412  buffer[part2_len] = '\0';
413  }
414 
415  if (part3_len) {
416  strncat(buffer, ch+strlen(oldstr), part3_len);
417  buffer[part1_len+part2_len+part3_len] = '\0';
418  }
419 
420  buffer[ch-str] = '\0';
421  snprintf(buffer+(ch-str), SYSTEM_MAXLEN, "%s%s", newstr, ch+strlen(oldstr));
422  return buffer;
423 }
424 
425 
431 ods_file_copy(const char* file1, const char* file2, long startpos, int append)
432 {
433  char buf[BUFFER_SIZE];
434  int fin = 0;
435  int fout = 0;
436  int read_size = 0;
437  if (!file1 || !file2) {
438  return ODS_STATUS_ASSERT_ERR;
439  }
440  if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) {
441  return ODS_STATUS_FOPEN_ERR;
442  }
443  if (append) {
444  fout = open(file2, O_WRONLY|O_APPEND|O_CREAT, 0666);
445  } else {
446  fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666);
447  }
448  if (fout < 0) {
449  close(fin);
450  return ODS_STATUS_FOPEN_ERR;
451  }
452  ods_log_debug("[%s] lseek file %s pos %ld", file_str, file1, startpos);
453  if (lseek(fin, startpos, SEEK_SET) < 0) {
454  return ODS_STATUS_FSEEK_ERR;
455  }
456  while (1) {
457  read_size = read(fin, buf, sizeof(buf));
458  if (read_size == 0) {
459  break;
460  }
461  if (read_size < 0) {
462  ods_log_error("[%s] read file %s error %s", file_str, file1,
463  strerror(errno));
464  close(fin);
465  close(fout);
466  return ODS_STATUS_FREAD_ERR;
467  }
468  if (write(fout, buf, (unsigned int) read_size) < 0) {
469  ods_log_error("[%s] write file %s error %s", file_str, file1,
470  strerror(errno));
471  close(fin);
472  close(fout);
473  return ODS_STATUS_FWRITE_ERR;
474  }
475  }
476  close(fin);
477  close(fout);
478  return ODS_STATUS_OK;
479 }
480 
481 
486 char*
487 ods_dir_name(const char* file) {
488  int l = strlen(file);
489  char* dir = NULL;
490 
491  ods_log_assert(file);
492 
493  /* find seperator */
494  while (l>0 && strncmp(file + (l-1), "/", 1) != 0) {
495  l--;
496  }
497 
498  /* now strip off (multiple seperators) */
499  while (l>0 && strncmp(file + (l-1), "/", 1) == 0) {
500  l--;
501  }
502 
503  if (l) {
504  dir = (char*) calloc(l+1, sizeof(char));
505  if (dir) {
506  dir = strncpy(dir, file, l);
507  }
508  return dir;
509  }
510  return NULL;
511 }
512 
517 void
518 ods_chown(const char* file, uid_t uid, gid_t gid, int getdir)
519 {
520  char* dir = NULL;
521 
522  if (!file) {
523  ods_log_warning("[%s] no filename given for chown()", file_str);
524  return;
525  }
526 
527  if (!getdir) {
528  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
529  file_str, file, (signed long) uid, (signed long) gid);
530  if (chown(file, uid, gid) != 0) {
531  ods_log_error("[%s] chown() %s failed: %s", file_str, file,
532  strerror(errno));
533  }
534  } else if ((dir = ods_dir_name(file)) != NULL) {
535  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
536  file_str, dir, (signed long) uid, (signed long) gid);
537  if (chown(dir, uid, gid) != 0) {
538  ods_log_error("[%s] chown() %s failed: %s", file_str,
539  dir, strerror(errno));
540  }
541  free((void*) dir);
542  } else {
543  ods_log_warning("[%s] use of relative path: %s", file_str, file);
544  }
545  return;
546 }
547 
548 
553 void
554 ods_str_trim(char* str)
555 {
556  int i = strlen(str), nl = 0;
557 
558  /* trailing */
559  while (i>0) {
560  --i;
561  if (str[i] == '\n') {
562  nl = 1;
563  }
564  if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') {
565  str[i] = '\0';
566  } else {
567  break;
568  }
569  }
570  if (nl) {
571  str[++i] = '\n';
572  }
573 
574  /* leading */
575  i = 0;
576  while (str[i] == ' ' || str[i] == '\t') {
577  i++;
578  }
579  while (*(str+i) != '\0') {
580  *str = *(str+i);
581  str++;
582  }
583  *str = '\0';
584  return;
585 }
586 
587 
592 void
593 ods_str_list_add(char*** list, char* str)
594 {
595  char** old = NULL;
596  size_t count = 0;
597 
598  if (*list) {
599  for (count=0; (*list)[count]; ++count) {
600  ;
601  }
602  old = *list;
603 
604  *list = (char**) calloc(sizeof(char*), count+2);
605  if (!*list) {
606  ods_fatal_exit("[%s] fatal ods_str_list_add(): calloc() failed",
607  file_str);
608  }
609  if (old) {
610  memcpy(*list, old, count * sizeof(char*));
611  }
612  free(old);
613  (*list)[count] = str;
614  (*list)[count+1] = NULL;
615  } else {
617  *list = calloc(sizeof(char*), 2);
618  if (!*list) {
619  ods_fatal_exit("[%s] fatal ods_str_list_add(): calloc() failed",
620  file_str);
621  }
622  (*list)[0] = str;
623  }
624  return;
625 }
void ods_log_debug(const char *format,...)
Definition: log.c:270
char * ods_dir_name(const char *file)
Definition: file.c:487
void ods_fatal_exit(const char *format,...)
Definition: log.c:382
int ods_skip_whitespace(FILE *fd, unsigned int *line_nr)
Definition: file.c:103
enum ods_enum_status ods_status
Definition: status.h:90
time_t ods_file_lastmodified(const char *file)
Definition: file.c:293
void ods_log_error(const char *format,...)
Definition: log.c:334
int ods_strcmp(const char *s1, const char *s2)
Definition: file.c:320
void ods_str_list_add(char ***list, char *str)
Definition: file.c:593
int ods_fgetc(FILE *fd, unsigned int *line_nr)
Definition: file.c:79
FILE * ods_fopen(const char *file, const char *dir, const char *mode)
Definition: file.c:190
void ods_log_crit(const char *format,...)
Definition: log.c:350
void ods_str_trim(char *str)
Definition: file.c:554
#define SYSTEM_MAXLEN
Definition: file.h:49
ssize_t ods_writen(int fd, const void *vptr, size_t n)
Definition: file.c:265
char * ods_build_path(const char *file, const char *suffix, int dir, int no_slash)
Definition: file.c:125
void ods_chown(const char *file, uid_t uid, gid_t gid, int getdir)
Definition: file.c:518
#define BUFFER_SIZE
Definition: file.c:46
void ods_fclose(FILE *fd)
Definition: file.c:250
void ods_log_deeebug(const char *format,...)
Definition: log.c:254
int ods_strlowercmp(const char *str1, const char *str2)
Definition: file.c:342
#define ods_log_assert(x)
Definition: log.h:154
const char * ods_replace(const char *str, const char *oldstr, const char *newstr)
Definition: file.c:374
void ods_log_warning(const char *format,...)
Definition: log.c:318
const char * ods_file_mode2str(const char *mode)
Definition: file.c:57
ods_status ods_file_copy(const char *file1, const char *file2, long startpos, int append)
Definition: file.c:431