OpenDNSSEC-signer  1.3.15
file.c
Go to the documentation of this file.
1 /*
2  * $Id: file.c 6498 2012-08-02 21:56:06Z 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 <errno.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <unistd.h>
46 
47 #define BUFFER_SIZE (16 * 1024) /* use 16K buffers */
48 
49 static const char* file_str = "file";
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 == '\r') { /* carriage return */
88  c = ' ';
89  }
90  if (c == '\n') {
91  (*line_nr)++;
92  }
93  if (c == EOF && errno != 0) {
94  ods_log_error("[%s] fgetc() failed, enough memory? (%s)",
95  file_str, strerror(errno));
96  }
97  return c;
98 }
99 
100 
105 int
106 ods_skip_whitespace(FILE* fd, unsigned int* line_nr)
107 {
108  int c;
109 
110  ods_log_assert(fd);
111  ods_log_assert(line_nr);
112 
113  while ((c=ods_fgetc(fd, line_nr)) != EOF) {
114  if (c == ' ' || c == '\t' || c == '\r') {
115  continue;
116  }
117  return c;
118  }
119  return EOF;
120 }
121 
122 
127 char*
128 ods_build_path(const char* file, const char* suffix, int dir, int no_slash)
129 {
130  size_t len_file = 0;
131  size_t len_suffix = 0;
132  size_t len_total = 0;
133  char* openf = NULL;
134 
135  if (file) {
136  len_file = strlen(file);
137  if (suffix) {
138  len_suffix = strlen(suffix);
139  }
140  len_total = len_suffix + len_file;
141  if (dir) {
142  len_total++;
143  }
144 
145  if (len_total > 0) {
146  openf = (char*) malloc(sizeof(char)*(len_total + 1));
147  if (!openf) {
148  ods_log_crit("[%s] build path failed: malloc failed", file_str);
149  return NULL;
150  }
151 
152  strncpy(openf, file, len_file);
153  openf[len_file] = '\0';
154  if (no_slash) {
155  size_t i = 0;
156  for (i=0; i<len_file; i++) {
157  switch (openf[i]) {
158  case '/':
159  case ' ':
160  /* more? */
161  openf[i] = '-';
162  break;
163  default:
164  break;
165  }
166  }
167  }
168 
169  if (suffix) {
170  strncat(openf, suffix, len_suffix);
171  }
172  if (dir) {
173  strncat(openf, "/", 1);
174  }
175  openf[len_total] = '\0';
176  }
177  }
178 
179  return openf;
180 }
181 
182 
187 FILE*
188 ods_fopen(const char* file, const char* dir, const char* mode)
189 {
190  FILE* fd = NULL;
191  size_t len_file = 0;
192  size_t len_dir = 0;
193  size_t len_total = 0;
194  char* openf = NULL;
195 
196  ods_log_assert(mode);
197  ods_log_debug("[%s] open file %s%s file=%s mode=%s", file_str,
198  (dir?"dir=":""), (dir?dir:""), (file?file:"(null)"),
199  ods_file_mode2str(mode));
200 
201  if (dir) {
202  len_dir= strlen(dir);
203  }
204  if (file) {
205  len_file= strlen(file);
206  }
207  len_total = len_dir + len_file;
208  if (len_total > 0) {
209  openf = (char*) malloc(sizeof(char)*(len_total + 1));
210  if (!openf) {
211  ods_log_error("[%s] unable to open file %s%s%s for %s: malloc() "
212  "failed", file_str, (dir?dir:""), (dir?"/":""),
213  (file?file:"(null)"), ods_file_mode2str(mode));
214  return NULL;
215  }
216  if (dir) {
217  strncpy(openf, dir, len_dir);
218  openf[len_dir] = '\0';
219  if (file) {
220  strncat(openf, file, len_file);
221  }
222  } else if (file) {
223  strncpy(openf, file, len_file);
224  }
225  openf[len_total] = '\0';
226 
227  if (len_file) {
228  fd = fopen(openf, mode);
229  if (!fd) {
230  ods_log_error("[%s] unable to open file %s for %s: %s",
231  file_str, openf?openf:"(null)",
232  ods_file_mode2str(mode), strerror(errno));
233  }
234  }
235  free((void*) openf);
236  }
237  return fd;
238 }
239 
244 void
245 ods_fclose(FILE* fd)
246 {
247  if (fd) {
248  fclose(fd);
249  }
250  return;
251 }
252 
253 
258 ssize_t
259 ods_writen(int fd, const void* vptr, size_t n)
260 {
261  size_t nleft;
262  ssize_t nwritten;
263  const char* ptr;
264 
265  ptr = vptr;
266  nleft = n;
267  while (nleft > 0) {
268  if ((nwritten = write(fd, ptr, nleft)) <= 0) {
269  if (nwritten < 0 && errno == EINTR) {
270  nwritten = 0; /* and call write again */
271  } else {
272  return -1; /* error */
273  }
274  }
275  nleft -= nwritten;
276  ptr += nwritten;
277  }
278  return n;
279 }
280 
281 
286 time_t
287 ods_file_lastmodified(const char* file)
288 {
289  int ret;
290  struct stat buf;
291  FILE* fd;
292 
293  ods_log_assert(file);
294 
295  if ((fd = ods_fopen(file, NULL, "r")) != NULL) {
296  ret = stat(file, &buf);
297  ods_fclose(fd);
298  if (ret == -1) {
299  ods_log_error("[%s] unable to stat file %s: %s",
300  file_str, file, strerror(errno));
301  return 0;
302  }
303  return buf.st_mtime;
304  } else {
305  ods_log_error("[%s] unable to stat file %s: ods_fopen() failed",
306  file_str, file, strerror(errno));
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 const char*
339 ods_replace(const char *str, const char *oldstr, const char *newstr)
340 {
341  char* buffer = NULL;
342  char* ch = NULL;
343  size_t part1_len = 0;
344  size_t part2_len = 0;
345  size_t part3_len = 0;
346 
347  if (!str) {
348  return NULL;
349  }
350  if (!oldstr || !newstr) {
351  return str;
352  }
353 
354  if (!(ch = strstr(str, oldstr))) {
355  buffer = strdup(str);
356  return buffer;
357  }
358 
359  part1_len = ch-str;
360  part2_len = strlen(newstr);
361  part3_len = strlen(ch+strlen(oldstr));
362  buffer = calloc(part1_len+part2_len+part3_len+1, sizeof(char));
363  if (!buffer) {
364  return NULL;
365  }
366 
367  if (part1_len) {
368  strncpy(buffer, str, part1_len);
369  buffer[part1_len] = '\0';
370 
371  if (part2_len) {
372  strncat(buffer, str, part2_len);
373  buffer[part1_len+part2_len] = '\0';
374  }
375  } else {
376  strncpy(buffer, newstr, part2_len);
377  buffer[part2_len] = '\0';
378  }
379 
380  if (part3_len) {
381  strncat(buffer, ch+strlen(oldstr), part3_len);
382  buffer[part1_len+part2_len+part3_len] = '\0';
383  }
384 
385  buffer[ch-str] = '\0';
386  snprintf(buffer+(ch-str), SYSTEM_MAXLEN, "%s%s", newstr, ch+strlen(oldstr));
387  return buffer;
388 }
389 
390 
396 ods_file_copy(const char* file1, const char* file2)
397 {
398  char buf[BUFFER_SIZE];
399  int fin = 0;
400  int fout = 0;
401  int read_size = 0;
402  if (!file1 || !file2) {
403  return ODS_STATUS_ASSERT_ERR;
404  }
405  if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) {
406  return ODS_STATUS_FOPEN_ERR;
407  }
408  if ((fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
409  close(fin);
410  return ODS_STATUS_FOPEN_ERR;
411  }
412  while (1) {
413  read_size = read(fin, buf, sizeof(buf));
414  if (read_size == 0) {
415  break;
416  }
417  if (read_size < 0) {
418  close(fin);
419  close(fout);
420  return ODS_STATUS_FREAD_ERR;
421  }
422  if (write(fout, buf, (unsigned int) read_size) < 0) {
423  close(fin);
424  close(fout);
425  return ODS_STATUS_FWRITE_ERR;
426  }
427  }
428  close(fin);
429  close(fout);
430  return ODS_STATUS_OK;
431 }
432 
433 
438 char*
439 ods_dir_name(const char* file) {
440  int l = strlen(file);
441  char* dir = NULL;
442 
443  ods_log_assert(file);
444 
445  /* find seperator */
446  while (l>0 && strncmp(file + (l-1), "/", 1) != 0) {
447  l--;
448  }
449 
450  /* now strip off (multiple seperators) */
451  while (l>0 && strncmp(file + (l-1), "/", 1) == 0) {
452  l--;
453  }
454 
455  if (l) {
456  dir = (char*) calloc(l+1, sizeof(char));
457  if (dir) {
458  dir = strncpy(dir, file, l);
459  }
460  return dir;
461  }
462  return NULL;
463 }
464 
469 void
470 ods_chown(const char* file, uid_t uid, gid_t gid, int getdir)
471 {
472  char* dir = NULL;
473 
474  if (!file) {
475  ods_log_warning("[%s] no filename given for chown()", file_str);
476  return;
477  }
478 
479  if (!getdir) {
480  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
481  file_str, file, (signed long) uid, (signed long) gid);
482  if (chown(file, uid, gid) != 0) {
483  ods_log_error("[%s] chown() %s failed: %s", file_str, file,
484  strerror(errno));
485  }
486  } else if ((dir = ods_dir_name(file)) != NULL) {
487  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
488  file_str, dir, (signed long) uid, (signed long) gid);
489  if (chown(dir, uid, gid) != 0) {
490  ods_log_error("[%s] chown() %s failed: %s", file_str,
491  dir, strerror(errno));
492  }
493  free((void*) dir);
494  } else {
495  ods_log_warning("[%s] use of relative path: %s", file_str, file);
496  }
497  return;
498 }
499 
500 
505 void
506 ods_str_trim(char* str)
507 {
508  int i = strlen(str), nl = 0;
509 
510  /* trailing */
511  while (i>0) {
512  --i;
513  if (str[i] == '\n') {
514  nl = 1;
515  }
516  if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') {
517  str[i] = '\0';
518  } else {
519  break;
520  }
521  }
522  if (nl) {
523  str[++i] = '\n';
524  }
525 
526  /* leading */
527  i = 0;
528  while (str[i] == ' ' || str[i] == '\t') {
529  i++;
530  }
531  while (*(str+i) != '\0') {
532  *str = *(str+i);
533  str++;
534  }
535  *str = '\0';
536  return;
537 }