OpenDNSSEC-signer  1.3.9
file.c
Go to the documentation of this file.
1 /*
2  * $Id: file.c 6244 2012-04-03 13:56:27Z 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  return c;
94 }
95 
96 
101 int
102 ods_skip_whitespace(FILE* fd, unsigned int* line_nr)
103 {
104  int c;
105 
106  ods_log_assert(fd);
107  ods_log_assert(line_nr);
108 
109  while ((c=ods_fgetc(fd, line_nr)) != EOF) {
110  if (c == ' ' || c == '\t' || c == '\r') {
111  continue;
112  }
113  return c;
114  }
115  return EOF;
116 }
117 
118 
123 char*
124 ods_build_path(const char* file, const char* suffix, int dir, int no_slash)
125 {
126  size_t len_file = 0;
127  size_t len_suffix = 0;
128  size_t len_total = 0;
129  char* openf = NULL;
130 
131  if (file) {
132  len_file = strlen(file);
133  if (suffix) {
134  len_suffix = strlen(suffix);
135  }
136  len_total = len_suffix + len_file;
137  if (dir) {
138  len_total++;
139  }
140 
141  if (len_total > 0) {
142  openf = (char*) malloc(sizeof(char)*(len_total + 1));
143  if (!openf) {
144  ods_log_crit("[%s] build path failed: malloc failed", file_str);
145  return NULL;
146  }
147 
148  strncpy(openf, file, len_file);
149  openf[len_file] = '\0';
150  if (no_slash) {
151  size_t i = 0;
152  for (i=0; i<len_file; i++) {
153  switch (openf[i]) {
154  case '/':
155  case ' ':
156  /* more? */
157  openf[i] = '-';
158  break;
159  default:
160  break;
161  }
162  }
163  }
164 
165  if (suffix) {
166  strncat(openf, suffix, len_suffix);
167  }
168  if (dir) {
169  strncat(openf, "/", 1);
170  }
171  openf[len_total] = '\0';
172  }
173  }
174 
175  return openf;
176 }
177 
178 
183 FILE*
184 ods_fopen(const char* file, const char* dir, const char* mode)
185 {
186  FILE* fd = NULL;
187  size_t len_file = 0;
188  size_t len_dir = 0;
189  size_t len_total = 0;
190  char* openf = NULL;
191 
192  ods_log_assert(mode);
193  ods_log_debug("[%s] open file %s%s file=%s mode=%s", file_str,
194  (dir?"dir=":""), (dir?dir:""), (file?file:"(null)"),
195  ods_file_mode2str(mode));
196 
197  if (dir) {
198  len_dir= strlen(dir);
199  }
200  if (file) {
201  len_file= strlen(file);
202  }
203  len_total = len_dir + len_file;
204  if (len_total > 0) {
205  openf = (char*) malloc(sizeof(char)*(len_total + 1));
206  if (!openf) {
207  return NULL;
208  }
209  if (dir) {
210  strncpy(openf, dir, len_dir);
211  openf[len_dir] = '\0';
212  if (file) {
213  strncat(openf, file, len_file);
214  }
215  } else if (file) {
216  strncpy(openf, file, len_file);
217  }
218  openf[len_total] = '\0';
219 
220  if (len_file) {
221  fd = fopen(openf, mode);
222  if (!fd) {
223  ods_log_verbose("[%s] unable to open file %s for %s: %s",
224  file_str, openf?openf:"(null)",
225  ods_file_mode2str(mode), strerror(errno));
226  }
227  }
228  free((void*) openf);
229  }
230  return fd;
231 }
232 
237 void
238 ods_fclose(FILE* fd)
239 {
240  if (fd) {
241  fclose(fd);
242  }
243  return;
244 }
245 
246 
251 ssize_t
252 ods_writen(int fd, const void* vptr, size_t n)
253 {
254  size_t nleft;
255  ssize_t nwritten;
256  const char* ptr;
257 
258  ptr = vptr;
259  nleft = n;
260  while (nleft > 0) {
261  if ((nwritten = write(fd, ptr, nleft)) <= 0) {
262  if (nwritten < 0 && errno == EINTR) {
263  nwritten = 0; /* and call write again */
264  } else {
265  return -1; /* error */
266  }
267  }
268  nleft -= nwritten;
269  ptr += nwritten;
270  }
271  return n;
272 }
273 
274 
279 time_t
280 ods_file_lastmodified(const char* file)
281 {
282  int ret;
283  struct stat buf;
284  FILE* fd;
285 
286  ods_log_assert(file);
287 
288  if ((fd = ods_fopen(file, NULL, "r")) != NULL) {
289  ret = stat(file, &buf);
290  ods_fclose(fd);
291  return buf.st_mtime;
292  }
293  return 0;
294 }
295 
296 
301 int
302 ods_strcmp(const char* s1, const char* s2)
303 {
304  if (!s1 && !s2) {
305  return 0;
306  } else if (!s1) {
307  return -1;
308  } else if (!s2) {
309  return -1;
310  } else if (strlen(s1) != strlen(s2)) {
311  if (strncmp(s1, s2, strlen(s1)) == 0) {
312  return strlen(s1) - strlen(s2);
313  }
314  }
315  return strncmp(s1, s2, strlen(s1));
316 }
317 
318 
323 const char*
324 ods_replace(const char *str, const char *oldstr, const char *newstr)
325 {
326  char* buffer = NULL;
327  char* ch = NULL;
328  size_t part1_len = 0;
329  size_t part2_len = 0;
330  size_t part3_len = 0;
331 
332  if (!str) {
333  return NULL;
334  }
335  if (!oldstr || !newstr) {
336  return str;
337  }
338 
339  if (!(ch = strstr(str, oldstr))) {
340  buffer = strdup(str);
341  return buffer;
342  }
343 
344  part1_len = ch-str;
345  part2_len = strlen(newstr);
346  part3_len = strlen(ch+strlen(oldstr));
347  buffer = calloc(part1_len+part2_len+part3_len+1, sizeof(char));
348  if (!buffer) {
349  return NULL;
350  }
351 
352  if (part1_len) {
353  strncpy(buffer, str, part1_len);
354  buffer[part1_len] = '\0';
355 
356  if (part2_len) {
357  strncat(buffer, str, part2_len);
358  buffer[part1_len+part2_len] = '\0';
359  }
360  } else {
361  strncpy(buffer, newstr, part2_len);
362  buffer[part2_len] = '\0';
363  }
364 
365  if (part3_len) {
366  strncat(buffer, ch+strlen(oldstr), part3_len);
367  buffer[part1_len+part2_len+part3_len] = '\0';
368  }
369 
370  buffer[ch-str] = '\0';
371  snprintf(buffer+(ch-str), SYSTEM_MAXLEN, "%s%s", newstr, ch+strlen(oldstr));
372  return buffer;
373 }
374 
375 
381 ods_file_copy(const char* file1, const char* file2)
382 {
383  char buf[BUFFER_SIZE];
384  int fin = 0;
385  int fout = 0;
386  int read_size = 0;
387  if (!file1 || !file2) {
388  return ODS_STATUS_ASSERT_ERR;
389  }
390  if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) {
391  return ODS_STATUS_FOPEN_ERR;
392  }
393  if ((fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) {
394  close(fin);
395  return ODS_STATUS_FOPEN_ERR;
396  }
397  while (1) {
398  read_size = read(fin, buf, sizeof(buf));
399  if (read_size == 0) {
400  break;
401  }
402  if (read_size < 0) {
403  close(fin);
404  close(fout);
405  return ODS_STATUS_FREAD_ERR;
406  }
407  if (write(fout, buf, (unsigned int) read_size) < 0) {
408  close(fin);
409  close(fout);
410  return ODS_STATUS_FWRITE_ERR;
411  }
412  }
413  close(fin);
414  close(fout);
415  return ODS_STATUS_OK;
416 }
417 
418 
423 char*
424 ods_dir_name(const char* file) {
425  int l = strlen(file);
426  char* dir = NULL;
427 
428  ods_log_assert(file);
429 
430  /* find seperator */
431  while (l>0 && strncmp(file + (l-1), "/", 1) != 0) {
432  l--;
433  }
434 
435  /* now strip off (multiple seperators) */
436  while (l>0 && strncmp(file + (l-1), "/", 1) == 0) {
437  l--;
438  }
439 
440  if (l) {
441  dir = (char*) calloc(l+1, sizeof(char));
442  if (dir) {
443  dir = strncpy(dir, file, l);
444  }
445  return dir;
446  }
447  return NULL;
448 }
449 
454 void
455 ods_chown(const char* file, uid_t uid, gid_t gid, int getdir)
456 {
457  char* dir = NULL;
458 
459  if (!file) {
460  ods_log_warning("[%s] no filename given for chown()", file_str);
461  return;
462  }
463 
464  if (!getdir) {
465  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
466  file_str, file, (signed long) uid, (signed long) gid);
467  if (chown(file, uid, gid) != 0) {
468  ods_log_error("[%s] chown() %s failed: %s", file_str, file,
469  strerror(errno));
470  }
471  } else if ((dir = ods_dir_name(file)) != NULL) {
472  ods_log_debug("[%s] create and chown %s with user=%ld group=%ld",
473  file_str, dir, (signed long) uid, (signed long) gid);
474  if (chown(dir, uid, gid) != 0) {
475  ods_log_error("[%s] chown() %s failed: %s", file_str,
476  dir, strerror(errno));
477  }
478  free((void*) dir);
479  } else {
480  ods_log_warning("[%s] use of relative path: %s", file_str, file);
481  }
482  return;
483 }
484 
485 
490 void
491 ods_str_trim(char* str)
492 {
493  int i = strlen(str), nl = 0;
494 
495  /* trailing */
496  while (i>0) {
497  --i;
498  if (str[i] == '\n') {
499  nl = 1;
500  }
501  if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') {
502  str[i] = '\0';
503  } else {
504  break;
505  }
506  }
507  if (nl) {
508  str[++i] = '\n';
509  }
510 
511  /* leading */
512  i = 0;
513  while (str[i] == ' ' || str[i] == '\t') {
514  i++;
515  }
516  while (*(str+i) != '\0') {
517  *str = *(str+i);
518  str++;
519  }
520  *str = '\0';
521  return;
522 }