OpenDNSSEC-signer
1.3.4
|
00001 /* 00002 * $Id: file.c 5805 2011-10-24 13:22:51Z matthijs $ 00003 * 00004 * Copyright (c) 2009 NLNet Labs. All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions 00008 * are met: 00009 * 1. Redistributions of source code must retain the above copyright 00010 * notice, this list of conditions and the following disclaimer. 00011 * 2. Redistributions in binary form must reproduce the above copyright 00012 * notice, this list of conditions and the following disclaimer in the 00013 * documentation and/or other materials provided with the distribution. 00014 * 00015 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00016 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00017 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00018 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 00019 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00020 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00021 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00022 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 00023 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 00024 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 00025 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00026 * 00027 */ 00028 00034 #include "config.h" 00035 #include "shared/file.h" 00036 #include "shared/log.h" 00037 00038 #include <errno.h> 00039 #include <fcntl.h> 00040 #include <stdio.h> 00041 #include <stdlib.h> 00042 #include <string.h> 00043 #include <sys/stat.h> 00044 #include <sys/types.h> 00045 #include <unistd.h> 00046 00047 #define BUFFER_SIZE (16 * 1024) /* use 16K buffers */ 00048 00049 static const char* file_str = "file"; 00050 00051 00056 const char* 00057 ods_file_mode2str(const char* mode) 00058 { 00059 if (!mode) { 00060 return "no mode"; 00061 } 00062 00063 if (ods_strcmp(mode, "a") == 0) { 00064 return "appending"; 00065 } else if (ods_strcmp(mode, "r") == 0) { 00066 return "reading"; 00067 } else if (ods_strcmp(mode, "w") == 0) { 00068 return "writing"; 00069 } 00070 return "unknown mode"; 00071 } 00072 00073 00078 int 00079 ods_fgetc(FILE* fd, unsigned int* line_nr) 00080 { 00081 int c; 00082 00083 ods_log_assert(fd); 00084 ods_log_assert(line_nr); 00085 00086 c = fgetc(fd); 00087 if (c == '\r') { /* carriage return */ 00088 c = ' '; 00089 } 00090 if (c == '\n') { 00091 (*line_nr)++; 00092 } 00093 return c; 00094 } 00095 00096 00101 int 00102 ods_skip_whitespace(FILE* fd, unsigned int* line_nr) 00103 { 00104 int c; 00105 00106 ods_log_assert(fd); 00107 ods_log_assert(line_nr); 00108 00109 while ((c=ods_fgetc(fd, line_nr)) != EOF) { 00110 if (c == ' ' || c == '\t' || c == '\r') { 00111 continue; 00112 } 00113 return c; 00114 } 00115 return EOF; 00116 } 00117 00118 00123 char* 00124 ods_build_path(const char* file, const char* suffix, int dir) 00125 { 00126 size_t len_file = 0; 00127 size_t len_suffix = 0; 00128 size_t len_total = 0; 00129 char* openf = NULL; 00130 00131 if (file) { 00132 len_file = strlen(file); 00133 if (suffix) { 00134 len_suffix = strlen(suffix); 00135 } 00136 len_total = len_suffix + len_file; 00137 if (dir) { 00138 len_total++; 00139 } 00140 00141 if (len_total > 0) { 00142 openf = (char*) malloc(sizeof(char)*(len_total + 1)); 00143 if (!openf) { 00144 ods_log_crit("[%s] build path failed: malloc failed", file_str); 00145 return NULL; 00146 } 00147 00148 strncpy(openf, file, len_file); 00149 openf[len_file] = '\0'; 00150 if (suffix) { 00151 strncat(openf, suffix, len_suffix); 00152 } 00153 if (dir) { 00154 strncat(openf, "/", 1); 00155 } 00156 openf[len_total] = '\0'; 00157 } 00158 } 00159 00160 return openf; 00161 } 00162 00163 00168 FILE* 00169 ods_fopen(const char* file, const char* dir, const char* mode) 00170 { 00171 FILE* fd = NULL; 00172 size_t len_file = 0; 00173 size_t len_dir = 0; 00174 size_t len_total = 0; 00175 char* openf = NULL; 00176 00177 ods_log_assert(mode); 00178 ods_log_debug("[%s] open file %s%s file=%s mode=%s", file_str, 00179 (dir?"dir=":""), (dir?dir:""), (file?file:"(null)"), 00180 ods_file_mode2str(mode)); 00181 00182 if (dir) { 00183 len_dir= strlen(dir); 00184 } 00185 if (file) { 00186 len_file= strlen(file); 00187 } 00188 len_total = len_dir + len_file; 00189 if (len_total > 0) { 00190 openf = (char*) malloc(sizeof(char)*(len_total + 1)); 00191 if (!openf) { 00192 return NULL; 00193 } 00194 if (dir) { 00195 strncpy(openf, dir, len_dir); 00196 openf[len_dir] = '\0'; 00197 if (file) { 00198 strncat(openf, file, len_file); 00199 } 00200 } else if (file) { 00201 strncpy(openf, file, len_file); 00202 } 00203 openf[len_total] = '\0'; 00204 00205 if (len_file) { 00206 fd = fopen(openf, mode); 00207 if (!fd) { 00208 ods_log_verbose("[%s] unable to open file %s for %s: %s", 00209 file_str, openf?openf:"(null)", 00210 ods_file_mode2str(mode), strerror(errno)); 00211 } 00212 } 00213 free((void*) openf); 00214 } 00215 return fd; 00216 } 00217 00222 void 00223 ods_fclose(FILE* fd) 00224 { 00225 if (fd) { 00226 fclose(fd); 00227 } 00228 return; 00229 } 00230 00231 00236 ssize_t 00237 ods_writen(int fd, const void* vptr, size_t n) 00238 { 00239 size_t nleft; 00240 ssize_t nwritten; 00241 const char* ptr; 00242 00243 ptr = vptr; 00244 nleft = n; 00245 while (nleft > 0) { 00246 if ((nwritten = write(fd, ptr, nleft)) <= 0) { 00247 if (nwritten < 0 && errno == EINTR) { 00248 nwritten = 0; /* and call write again */ 00249 } else { 00250 return -1; /* error */ 00251 } 00252 } 00253 nleft -= nwritten; 00254 ptr += nwritten; 00255 } 00256 return n; 00257 } 00258 00259 00264 time_t 00265 ods_file_lastmodified(const char* file) 00266 { 00267 int ret; 00268 struct stat buf; 00269 FILE* fd; 00270 00271 ods_log_assert(file); 00272 00273 if ((fd = ods_fopen(file, NULL, "r")) != NULL) { 00274 ret = stat(file, &buf); 00275 ods_fclose(fd); 00276 return buf.st_mtime; 00277 } 00278 return 0; 00279 } 00280 00281 00286 int 00287 ods_strcmp(const char* s1, const char* s2) 00288 { 00289 if (!s1 && !s2) { 00290 return 0; 00291 } else if (!s1) { 00292 return -1; 00293 } else if (!s2) { 00294 return -1; 00295 } else if (strlen(s1) != strlen(s2)) { 00296 if (strncmp(s1, s2, strlen(s1)) == 0) { 00297 return strlen(s1) - strlen(s2); 00298 } 00299 } 00300 return strncmp(s1, s2, strlen(s1)); 00301 } 00302 00303 00308 const char* 00309 ods_replace(const char *str, const char *oldstr, const char *newstr) 00310 { 00311 char* buffer = NULL; 00312 char* ch = NULL; 00313 size_t part1_len = 0; 00314 size_t part2_len = 0; 00315 size_t part3_len = 0; 00316 00317 if (!str) { 00318 return NULL; 00319 } 00320 if (!oldstr || !newstr) { 00321 return str; 00322 } 00323 00324 if (!(ch = strstr(str, oldstr))) { 00325 buffer = strdup(str); 00326 return buffer; 00327 } 00328 00329 part1_len = ch-str; 00330 part2_len = strlen(newstr); 00331 part3_len = strlen(ch+strlen(oldstr)); 00332 buffer = calloc(part1_len+part2_len+part3_len+1, sizeof(char)); 00333 if (!buffer) { 00334 return NULL; 00335 } 00336 00337 if (part1_len) { 00338 strncpy(buffer, str, part1_len); 00339 buffer[part1_len] = '\0'; 00340 00341 if (part2_len) { 00342 strncat(buffer, str, part2_len); 00343 buffer[part1_len+part2_len] = '\0'; 00344 } 00345 } else { 00346 strncpy(buffer, newstr, part2_len); 00347 buffer[part2_len] = '\0'; 00348 } 00349 00350 if (part3_len) { 00351 strncat(buffer, ch+strlen(oldstr), part3_len); 00352 buffer[part1_len+part2_len+part3_len] = '\0'; 00353 } 00354 00355 buffer[ch-str] = '\0'; 00356 snprintf(buffer+(ch-str), SYSTEM_MAXLEN, "%s%s", newstr, ch+strlen(oldstr)); 00357 return buffer; 00358 } 00359 00360 00365 ods_status 00366 ods_file_copy(const char* file1, const char* file2) 00367 { 00368 char buf[BUFFER_SIZE]; 00369 int fin = 0; 00370 int fout = 0; 00371 int read_size = 0; 00372 if (!file1 || !file2) { 00373 return ODS_STATUS_ASSERT_ERR; 00374 } 00375 if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) { 00376 return ODS_STATUS_FOPEN_ERR; 00377 } 00378 if ((fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { 00379 close(fin); 00380 return ODS_STATUS_FOPEN_ERR; 00381 } 00382 while (1) { 00383 read_size = read(fin, buf, sizeof(buf)); 00384 if (read_size == 0) { 00385 break; 00386 } 00387 if (read_size < 0) { 00388 close(fin); 00389 close(fout); 00390 return ODS_STATUS_FREAD_ERR; 00391 } 00392 if (write(fout, buf, (unsigned int) read_size) < 0) { 00393 close(fin); 00394 close(fout); 00395 return ODS_STATUS_FWRITE_ERR; 00396 } 00397 } 00398 close(fin); 00399 close(fout); 00400 return ODS_STATUS_OK; 00401 } 00402 00403 00408 char* 00409 ods_dir_name(const char* file) { 00410 int l = strlen(file); 00411 char* dir = NULL; 00412 00413 ods_log_assert(file); 00414 00415 /* find seperator */ 00416 while (l>0 && strncmp(file + (l-1), "/", 1) != 0) { 00417 l--; 00418 } 00419 00420 /* now strip off (multiple seperators) */ 00421 while (l>0 && strncmp(file + (l-1), "/", 1) == 0) { 00422 l--; 00423 } 00424 00425 if (l) { 00426 dir = (char*) calloc(l+1, sizeof(char)); 00427 if (dir) { 00428 dir = strncpy(dir, file, l); 00429 } 00430 return dir; 00431 } 00432 return NULL; 00433 } 00434 00439 void 00440 ods_chown(const char* file, uid_t uid, gid_t gid, int getdir) 00441 { 00442 char* dir = NULL; 00443 00444 if (!file) { 00445 ods_log_warning("[%s] no filename given for chown()", file_str); 00446 return; 00447 } 00448 00449 if (!getdir) { 00450 ods_log_debug("[%s] create and chown %s with user=%ld group=%ld", 00451 file_str, file, (signed long) uid, (signed long) gid); 00452 if (chown(file, uid, gid) != 0) { 00453 ods_log_error("[%s] chown() %s failed: %s", file_str, file, 00454 strerror(errno)); 00455 } 00456 } else if ((dir = ods_dir_name(file)) != NULL) { 00457 ods_log_debug("[%s] create and chown %s with user=%ld group=%ld", 00458 file_str, dir, (signed long) uid, (signed long) gid); 00459 if (chown(dir, uid, gid) != 0) { 00460 ods_log_error("[%s] chown() %s failed: %s", file_str, 00461 dir, strerror(errno)); 00462 } 00463 free((void*) dir); 00464 } else { 00465 ods_log_warning("[%s] use of relative path: %s", file_str, file); 00466 } 00467 return; 00468 } 00469 00470 00475 void 00476 ods_str_trim(char* str) 00477 { 00478 int i = strlen(str), nl = 0; 00479 00480 /* trailing */ 00481 while (i>0) { 00482 --i; 00483 if (str[i] == '\n') { 00484 nl = 1; 00485 } 00486 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') { 00487 str[i] = '\0'; 00488 } else { 00489 break; 00490 } 00491 } 00492 if (nl) { 00493 str[++i] = '\n'; 00494 } 00495 00496 /* leading */ 00497 i = 0; 00498 while (str[i] == ' ' || str[i] == '\t') { 00499 i++; 00500 } 00501 while (*(str+i) != '\0') { 00502 *str = *(str+i); 00503 str++; 00504 } 00505 *str = '\0'; 00506 return; 00507 }