OpenDNSSEC-signer
1.3.8
|
00001 /* 00002 * $Id: file.c 6244 2012-04-03 13:56:27Z 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, int no_slash) 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 (no_slash) { 00151 size_t i = 0; 00152 for (i=0; i<len_file; i++) { 00153 switch (openf[i]) { 00154 case '/': 00155 case ' ': 00156 /* more? */ 00157 openf[i] = '-'; 00158 break; 00159 default: 00160 break; 00161 } 00162 } 00163 } 00164 00165 if (suffix) { 00166 strncat(openf, suffix, len_suffix); 00167 } 00168 if (dir) { 00169 strncat(openf, "/", 1); 00170 } 00171 openf[len_total] = '\0'; 00172 } 00173 } 00174 00175 return openf; 00176 } 00177 00178 00183 FILE* 00184 ods_fopen(const char* file, const char* dir, const char* mode) 00185 { 00186 FILE* fd = NULL; 00187 size_t len_file = 0; 00188 size_t len_dir = 0; 00189 size_t len_total = 0; 00190 char* openf = NULL; 00191 00192 ods_log_assert(mode); 00193 ods_log_debug("[%s] open file %s%s file=%s mode=%s", file_str, 00194 (dir?"dir=":""), (dir?dir:""), (file?file:"(null)"), 00195 ods_file_mode2str(mode)); 00196 00197 if (dir) { 00198 len_dir= strlen(dir); 00199 } 00200 if (file) { 00201 len_file= strlen(file); 00202 } 00203 len_total = len_dir + len_file; 00204 if (len_total > 0) { 00205 openf = (char*) malloc(sizeof(char)*(len_total + 1)); 00206 if (!openf) { 00207 return NULL; 00208 } 00209 if (dir) { 00210 strncpy(openf, dir, len_dir); 00211 openf[len_dir] = '\0'; 00212 if (file) { 00213 strncat(openf, file, len_file); 00214 } 00215 } else if (file) { 00216 strncpy(openf, file, len_file); 00217 } 00218 openf[len_total] = '\0'; 00219 00220 if (len_file) { 00221 fd = fopen(openf, mode); 00222 if (!fd) { 00223 ods_log_verbose("[%s] unable to open file %s for %s: %s", 00224 file_str, openf?openf:"(null)", 00225 ods_file_mode2str(mode), strerror(errno)); 00226 } 00227 } 00228 free((void*) openf); 00229 } 00230 return fd; 00231 } 00232 00237 void 00238 ods_fclose(FILE* fd) 00239 { 00240 if (fd) { 00241 fclose(fd); 00242 } 00243 return; 00244 } 00245 00246 00251 ssize_t 00252 ods_writen(int fd, const void* vptr, size_t n) 00253 { 00254 size_t nleft; 00255 ssize_t nwritten; 00256 const char* ptr; 00257 00258 ptr = vptr; 00259 nleft = n; 00260 while (nleft > 0) { 00261 if ((nwritten = write(fd, ptr, nleft)) <= 0) { 00262 if (nwritten < 0 && errno == EINTR) { 00263 nwritten = 0; /* and call write again */ 00264 } else { 00265 return -1; /* error */ 00266 } 00267 } 00268 nleft -= nwritten; 00269 ptr += nwritten; 00270 } 00271 return n; 00272 } 00273 00274 00279 time_t 00280 ods_file_lastmodified(const char* file) 00281 { 00282 int ret; 00283 struct stat buf; 00284 FILE* fd; 00285 00286 ods_log_assert(file); 00287 00288 if ((fd = ods_fopen(file, NULL, "r")) != NULL) { 00289 ret = stat(file, &buf); 00290 ods_fclose(fd); 00291 return buf.st_mtime; 00292 } 00293 return 0; 00294 } 00295 00296 00301 int 00302 ods_strcmp(const char* s1, const char* s2) 00303 { 00304 if (!s1 && !s2) { 00305 return 0; 00306 } else if (!s1) { 00307 return -1; 00308 } else if (!s2) { 00309 return -1; 00310 } else if (strlen(s1) != strlen(s2)) { 00311 if (strncmp(s1, s2, strlen(s1)) == 0) { 00312 return strlen(s1) - strlen(s2); 00313 } 00314 } 00315 return strncmp(s1, s2, strlen(s1)); 00316 } 00317 00318 00323 const char* 00324 ods_replace(const char *str, const char *oldstr, const char *newstr) 00325 { 00326 char* buffer = NULL; 00327 char* ch = NULL; 00328 size_t part1_len = 0; 00329 size_t part2_len = 0; 00330 size_t part3_len = 0; 00331 00332 if (!str) { 00333 return NULL; 00334 } 00335 if (!oldstr || !newstr) { 00336 return str; 00337 } 00338 00339 if (!(ch = strstr(str, oldstr))) { 00340 buffer = strdup(str); 00341 return buffer; 00342 } 00343 00344 part1_len = ch-str; 00345 part2_len = strlen(newstr); 00346 part3_len = strlen(ch+strlen(oldstr)); 00347 buffer = calloc(part1_len+part2_len+part3_len+1, sizeof(char)); 00348 if (!buffer) { 00349 return NULL; 00350 } 00351 00352 if (part1_len) { 00353 strncpy(buffer, str, part1_len); 00354 buffer[part1_len] = '\0'; 00355 00356 if (part2_len) { 00357 strncat(buffer, str, part2_len); 00358 buffer[part1_len+part2_len] = '\0'; 00359 } 00360 } else { 00361 strncpy(buffer, newstr, part2_len); 00362 buffer[part2_len] = '\0'; 00363 } 00364 00365 if (part3_len) { 00366 strncat(buffer, ch+strlen(oldstr), part3_len); 00367 buffer[part1_len+part2_len+part3_len] = '\0'; 00368 } 00369 00370 buffer[ch-str] = '\0'; 00371 snprintf(buffer+(ch-str), SYSTEM_MAXLEN, "%s%s", newstr, ch+strlen(oldstr)); 00372 return buffer; 00373 } 00374 00375 00380 ods_status 00381 ods_file_copy(const char* file1, const char* file2) 00382 { 00383 char buf[BUFFER_SIZE]; 00384 int fin = 0; 00385 int fout = 0; 00386 int read_size = 0; 00387 if (!file1 || !file2) { 00388 return ODS_STATUS_ASSERT_ERR; 00389 } 00390 if ((fin = open(file1, O_RDONLY|O_NONBLOCK)) < 0) { 00391 return ODS_STATUS_FOPEN_ERR; 00392 } 00393 if ((fout = open(file2, O_WRONLY|O_TRUNC|O_CREAT, 0666)) < 0) { 00394 close(fin); 00395 return ODS_STATUS_FOPEN_ERR; 00396 } 00397 while (1) { 00398 read_size = read(fin, buf, sizeof(buf)); 00399 if (read_size == 0) { 00400 break; 00401 } 00402 if (read_size < 0) { 00403 close(fin); 00404 close(fout); 00405 return ODS_STATUS_FREAD_ERR; 00406 } 00407 if (write(fout, buf, (unsigned int) read_size) < 0) { 00408 close(fin); 00409 close(fout); 00410 return ODS_STATUS_FWRITE_ERR; 00411 } 00412 } 00413 close(fin); 00414 close(fout); 00415 return ODS_STATUS_OK; 00416 } 00417 00418 00423 char* 00424 ods_dir_name(const char* file) { 00425 int l = strlen(file); 00426 char* dir = NULL; 00427 00428 ods_log_assert(file); 00429 00430 /* find seperator */ 00431 while (l>0 && strncmp(file + (l-1), "/", 1) != 0) { 00432 l--; 00433 } 00434 00435 /* now strip off (multiple seperators) */ 00436 while (l>0 && strncmp(file + (l-1), "/", 1) == 0) { 00437 l--; 00438 } 00439 00440 if (l) { 00441 dir = (char*) calloc(l+1, sizeof(char)); 00442 if (dir) { 00443 dir = strncpy(dir, file, l); 00444 } 00445 return dir; 00446 } 00447 return NULL; 00448 } 00449 00454 void 00455 ods_chown(const char* file, uid_t uid, gid_t gid, int getdir) 00456 { 00457 char* dir = NULL; 00458 00459 if (!file) { 00460 ods_log_warning("[%s] no filename given for chown()", file_str); 00461 return; 00462 } 00463 00464 if (!getdir) { 00465 ods_log_debug("[%s] create and chown %s with user=%ld group=%ld", 00466 file_str, file, (signed long) uid, (signed long) gid); 00467 if (chown(file, uid, gid) != 0) { 00468 ods_log_error("[%s] chown() %s failed: %s", file_str, file, 00469 strerror(errno)); 00470 } 00471 } else if ((dir = ods_dir_name(file)) != NULL) { 00472 ods_log_debug("[%s] create and chown %s with user=%ld group=%ld", 00473 file_str, dir, (signed long) uid, (signed long) gid); 00474 if (chown(dir, uid, gid) != 0) { 00475 ods_log_error("[%s] chown() %s failed: %s", file_str, 00476 dir, strerror(errno)); 00477 } 00478 free((void*) dir); 00479 } else { 00480 ods_log_warning("[%s] use of relative path: %s", file_str, file); 00481 } 00482 return; 00483 } 00484 00485 00490 void 00491 ods_str_trim(char* str) 00492 { 00493 int i = strlen(str), nl = 0; 00494 00495 /* trailing */ 00496 while (i>0) { 00497 --i; 00498 if (str[i] == '\n') { 00499 nl = 1; 00500 } 00501 if (str[i] == ' ' || str[i] == '\t' || str[i] == '\n') { 00502 str[i] = '\0'; 00503 } else { 00504 break; 00505 } 00506 } 00507 if (nl) { 00508 str[++i] = '\n'; 00509 } 00510 00511 /* leading */ 00512 i = 0; 00513 while (str[i] == ' ' || str[i] == '\t') { 00514 i++; 00515 } 00516 while (*(str+i) != '\0') { 00517 *str = *(str+i); 00518 str++; 00519 } 00520 *str = '\0'; 00521 return; 00522 }