00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 #include <config.h>
00052
00053 #include <errno.h>
00054 #include <fcntl.h>
00055 #include <limits.h>
00056 #include <stdlib.h>
00057 #include <time.h>
00058 #include <unistd.h>
00059
00060
00061 #include <sys/stat.h>
00062 #include <sys/time.h>
00063
00064 #ifdef HAVE_SYS_MMAN_H
00065 #include <sys/mman.h>
00066 #endif
00067
00068 #include <isc/dir.h>
00069 #include <isc/file.h>
00070 #include <isc/log.h>
00071 #include <isc/mem.h>
00072 #include <isc/print.h>
00073 #include <isc/random.h>
00074 #include <isc/sha2.h>
00075 #include <isc/string.h>
00076 #include <isc/time.h>
00077 #include <isc/util.h>
00078
00079 #include "errno2result.h"
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 static isc_result_t
00090 file_stats(const char *file, struct stat *stats) {
00091 isc_result_t result = ISC_R_SUCCESS;
00092
00093 REQUIRE(file != NULL);
00094 REQUIRE(stats != NULL);
00095
00096 if (stat(file, stats) != 0)
00097 result = isc__errno2result(errno);
00098
00099 return (result);
00100 }
00101
00102 static isc_result_t
00103 fd_stats(int fd, struct stat *stats) {
00104 isc_result_t result = ISC_R_SUCCESS;
00105
00106 REQUIRE(stats != NULL);
00107
00108 if (fstat(fd, stats) != 0)
00109 result = isc__errno2result(errno);
00110
00111 return (result);
00112 }
00113
00114 isc_result_t
00115 isc_file_getsizefd(int fd, off_t *size) {
00116 isc_result_t result;
00117 struct stat stats;
00118
00119 REQUIRE(size != NULL);
00120
00121 result = fd_stats(fd, &stats);
00122
00123 if (result == ISC_R_SUCCESS)
00124 *size = stats.st_size;
00125
00126 return (result);
00127 }
00128
00129 isc_result_t
00130 isc_file_mode(const char *file, mode_t *modep) {
00131 isc_result_t result;
00132 struct stat stats;
00133
00134 REQUIRE(modep != NULL);
00135
00136 result = file_stats(file, &stats);
00137 if (result == ISC_R_SUCCESS)
00138 *modep = (stats.st_mode & 07777);
00139
00140 return (result);
00141 }
00142
00143 isc_result_t
00144 isc_file_getmodtime(const char *file, isc_time_t *modtime) {
00145 isc_result_t result;
00146 struct stat stats;
00147
00148 REQUIRE(file != NULL);
00149 REQUIRE(modtime != NULL);
00150
00151 result = file_stats(file, &stats);
00152
00153 if (result == ISC_R_SUCCESS)
00154
00155
00156
00157
00158 isc_time_set(modtime, stats.st_mtime, 0);
00159
00160 return (result);
00161 }
00162
00163 isc_result_t
00164 isc_file_getsize(const char *file, off_t *size) {
00165 isc_result_t result;
00166 struct stat stats;
00167
00168 REQUIRE(file != NULL);
00169 REQUIRE(size != NULL);
00170
00171 result = file_stats(file, &stats);
00172
00173 if (result == ISC_R_SUCCESS)
00174 *size = stats.st_size;
00175
00176 return (result);
00177 }
00178
00179 isc_result_t
00180 isc_file_settime(const char *file, isc_time_t *when) {
00181 struct timeval times[2];
00182
00183 REQUIRE(file != NULL && when != NULL);
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195 times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(when);
00196
00197
00198
00199
00200 if ((times[0].tv_sec &
00201 (1ULL << (sizeof(times[0].tv_sec) * CHAR_BIT - 1))) != 0)
00202 return (ISC_R_RANGE);
00203
00204
00205
00206
00207
00208
00209
00210 times[0].tv_usec = times[1].tv_usec =
00211 (isc_int32_t)(isc_time_nanoseconds(when) / 1000);
00212
00213 if (utimes(file, times) < 0)
00214 return (isc__errno2result(errno));
00215
00216 return (ISC_R_SUCCESS);
00217 }
00218
00219 #undef TEMPLATE
00220 #define TEMPLATE "tmp-XXXXXXXXXX"
00221
00222 isc_result_t
00223 isc_file_mktemplate(const char *path, char *buf, size_t buflen) {
00224 return (isc_file_template(path, TEMPLATE, buf, buflen));
00225 }
00226
00227 isc_result_t
00228 isc_file_template(const char *path, const char *templet, char *buf,
00229 size_t buflen) {
00230 char *s;
00231
00232 REQUIRE(path != NULL);
00233 REQUIRE(templet != NULL);
00234 REQUIRE(buf != NULL);
00235
00236 s = strrchr(templet, '/');
00237 if (s != NULL)
00238 templet = s + 1;
00239
00240 s = strrchr(path, '/');
00241
00242 if (s != NULL) {
00243 if ((s - path + 1 + strlen(templet) + 1) > buflen)
00244 return (ISC_R_NOSPACE);
00245
00246 strncpy(buf, path, s - path + 1);
00247 buf[s - path + 1] = '\0';
00248 strcat(buf, templet);
00249 } else {
00250 if ((strlen(templet) + 1) > buflen)
00251 return (ISC_R_NOSPACE);
00252
00253 strcpy(buf, templet);
00254 }
00255
00256 return (ISC_R_SUCCESS);
00257 }
00258
00259 static const char alphnum[] =
00260 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
00261
00262 isc_result_t
00263 isc_file_renameunique(const char *file, char *templet) {
00264 char *x;
00265 char *cp;
00266
00267 REQUIRE(file != NULL);
00268 REQUIRE(templet != NULL);
00269
00270 cp = templet;
00271 while (*cp != '\0')
00272 cp++;
00273 if (cp == templet)
00274 return (ISC_R_FAILURE);
00275
00276 x = cp--;
00277 while (cp >= templet && *cp == 'X') {
00278 isc_uint32_t which;
00279
00280 isc_random_get(&which);
00281 *cp = alphnum[which % (sizeof(alphnum) - 1)];
00282 x = cp--;
00283 }
00284 while (link(file, templet) == -1) {
00285 if (errno != EEXIST)
00286 return (isc__errno2result(errno));
00287 for (cp = x;;) {
00288 char *t;
00289 if (*cp == '\0')
00290 return (ISC_R_FAILURE);
00291 t = strchr(alphnum, *cp);
00292 if (t == NULL || *++t == '\0')
00293 *cp++ = alphnum[0];
00294 else {
00295 *cp = *t;
00296 break;
00297 }
00298 }
00299 }
00300 if (unlink(file) < 0)
00301 if (errno != ENOENT)
00302 return (isc__errno2result(errno));
00303 return (ISC_R_SUCCESS);
00304 }
00305
00306 isc_result_t
00307 isc_file_openunique(char *templet, FILE **fp) {
00308 int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
00309 return (isc_file_openuniquemode(templet, mode, fp));
00310 }
00311
00312 isc_result_t
00313 isc_file_openuniqueprivate(char *templet, FILE **fp) {
00314 int mode = S_IWUSR|S_IRUSR;
00315 return (isc_file_openuniquemode(templet, mode, fp));
00316 }
00317
00318 isc_result_t
00319 isc_file_openuniquemode(char *templet, int mode, FILE **fp) {
00320 int fd;
00321 FILE *f;
00322 isc_result_t result = ISC_R_SUCCESS;
00323 char *x;
00324 char *cp;
00325
00326 REQUIRE(templet != NULL);
00327 REQUIRE(fp != NULL && *fp == NULL);
00328
00329 cp = templet;
00330 while (*cp != '\0')
00331 cp++;
00332 if (cp == templet)
00333 return (ISC_R_FAILURE);
00334
00335 x = cp--;
00336 while (cp >= templet && *cp == 'X') {
00337 isc_uint32_t which;
00338
00339 isc_random_get(&which);
00340 *cp = alphnum[which % (sizeof(alphnum) - 1)];
00341 x = cp--;
00342 }
00343
00344
00345 while ((fd = open(templet, O_RDWR|O_CREAT|O_EXCL, mode)) == -1) {
00346 if (errno != EEXIST)
00347 return (isc__errno2result(errno));
00348 for (cp = x;;) {
00349 char *t;
00350 if (*cp == '\0')
00351 return (ISC_R_FAILURE);
00352 t = strchr(alphnum, *cp);
00353 if (t == NULL || *++t == '\0')
00354 *cp++ = alphnum[0];
00355 else {
00356 *cp = *t;
00357 break;
00358 }
00359 }
00360 }
00361 f = fdopen(fd, "w+");
00362 if (f == NULL) {
00363 result = isc__errno2result(errno);
00364 if (remove(templet) < 0) {
00365 isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
00366 ISC_LOGMODULE_FILE, ISC_LOG_ERROR,
00367 "remove '%s': failed", templet);
00368 }
00369 (void)close(fd);
00370 } else
00371 *fp = f;
00372
00373 return (result);
00374 }
00375
00376 isc_result_t
00377 isc_file_bopenunique(char *templet, FILE **fp) {
00378 int mode = S_IWUSR|S_IRUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
00379 return (isc_file_openuniquemode(templet, mode, fp));
00380 }
00381
00382 isc_result_t
00383 isc_file_bopenuniqueprivate(char *templet, FILE **fp) {
00384 int mode = S_IWUSR|S_IRUSR;
00385 return (isc_file_openuniquemode(templet, mode, fp));
00386 }
00387
00388 isc_result_t
00389 isc_file_bopenuniquemode(char *templet, int mode, FILE **fp) {
00390 return (isc_file_openuniquemode(templet, mode, fp));
00391 }
00392
00393 isc_result_t
00394 isc_file_remove(const char *filename) {
00395 int r;
00396
00397 REQUIRE(filename != NULL);
00398
00399 r = unlink(filename);
00400 if (r == 0)
00401 return (ISC_R_SUCCESS);
00402 else
00403 return (isc__errno2result(errno));
00404 }
00405
00406 isc_result_t
00407 isc_file_rename(const char *oldname, const char *newname) {
00408 int r;
00409
00410 REQUIRE(oldname != NULL);
00411 REQUIRE(newname != NULL);
00412
00413 r = rename(oldname, newname);
00414 if (r == 0)
00415 return (ISC_R_SUCCESS);
00416 else
00417 return (isc__errno2result(errno));
00418 }
00419
00420 isc_boolean_t
00421 isc_file_exists(const char *pathname) {
00422 struct stat stats;
00423
00424 REQUIRE(pathname != NULL);
00425
00426 return (ISC_TF(file_stats(pathname, &stats) == ISC_R_SUCCESS));
00427 }
00428
00429 isc_result_t
00430 isc_file_isplainfile(const char *filename) {
00431
00432
00433
00434 struct stat filestat;
00435 memset(&filestat,0,sizeof(struct stat));
00436
00437 if ((stat(filename, &filestat)) == -1)
00438 return(isc__errno2result(errno));
00439
00440 if(! S_ISREG(filestat.st_mode))
00441 return(ISC_R_INVALIDFILE);
00442
00443 return(ISC_R_SUCCESS);
00444 }
00445
00446 isc_result_t
00447 isc_file_isplainfilefd(int fd) {
00448
00449
00450
00451 struct stat filestat;
00452 memset(&filestat,0,sizeof(struct stat));
00453
00454 if ((fstat(fd, &filestat)) == -1)
00455 return(isc__errno2result(errno));
00456
00457 if(! S_ISREG(filestat.st_mode))
00458 return(ISC_R_INVALIDFILE);
00459
00460 return(ISC_R_SUCCESS);
00461 }
00462
00463 isc_result_t
00464 isc_file_isdirectory(const char *filename) {
00465
00466
00467
00468
00469 struct stat filestat;
00470 memset(&filestat,0,sizeof(struct stat));
00471
00472 if ((stat(filename, &filestat)) == -1)
00473 return(isc__errno2result(errno));
00474
00475 if(! S_ISDIR(filestat.st_mode))
00476 return(ISC_R_INVALIDFILE);
00477
00478 return(ISC_R_SUCCESS);
00479 }
00480
00481
00482 isc_boolean_t
00483 isc_file_isabsolute(const char *filename) {
00484 REQUIRE(filename != NULL);
00485 return (ISC_TF(filename[0] == '/'));
00486 }
00487
00488 isc_boolean_t
00489 isc_file_iscurrentdir(const char *filename) {
00490 REQUIRE(filename != NULL);
00491 return (ISC_TF(filename[0] == '.' && filename[1] == '\0'));
00492 }
00493
00494 isc_boolean_t
00495 isc_file_ischdiridempotent(const char *filename) {
00496 REQUIRE(filename != NULL);
00497 if (isc_file_isabsolute(filename))
00498 return (ISC_TRUE);
00499 if (isc_file_iscurrentdir(filename))
00500 return (ISC_TRUE);
00501 return (ISC_FALSE);
00502 }
00503
00504 const char *
00505 isc_file_basename(const char *filename) {
00506 char *s;
00507
00508 REQUIRE(filename != NULL);
00509
00510 s = strrchr(filename, '/');
00511 if (s == NULL)
00512 return (filename);
00513
00514 return (s + 1);
00515 }
00516
00517 isc_result_t
00518 isc_file_progname(const char *filename, char *buf, size_t buflen) {
00519 const char *base;
00520 size_t len;
00521
00522 REQUIRE(filename != NULL);
00523 REQUIRE(buf != NULL);
00524
00525 base = isc_file_basename(filename);
00526 len = strlen(base) + 1;
00527
00528 if (len > buflen)
00529 return (ISC_R_NOSPACE);
00530 memmove(buf, base, len);
00531
00532 return (ISC_R_SUCCESS);
00533 }
00534
00535
00536
00537
00538
00539
00540
00541 static isc_result_t
00542 dir_current(char *dirname, size_t length) {
00543 char *cwd;
00544 isc_result_t result = ISC_R_SUCCESS;
00545
00546 REQUIRE(dirname != NULL);
00547 REQUIRE(length > 0U);
00548
00549 cwd = getcwd(dirname, length);
00550
00551 if (cwd == NULL) {
00552 if (errno == ERANGE)
00553 result = ISC_R_NOSPACE;
00554 else
00555 result = isc__errno2result(errno);
00556 } else {
00557 if (strlen(dirname) + 1 == length)
00558 result = ISC_R_NOSPACE;
00559 else if (dirname[1] != '\0')
00560 strcat(dirname, "/");
00561 }
00562
00563 return (result);
00564 }
00565
00566 isc_result_t
00567 isc_file_absolutepath(const char *filename, char *path, size_t pathlen) {
00568 isc_result_t result;
00569 result = dir_current(path, pathlen);
00570 if (result != ISC_R_SUCCESS)
00571 return (result);
00572 if (strlen(path) + strlen(filename) + 1 > pathlen)
00573 return (ISC_R_NOSPACE);
00574 strcat(path, filename);
00575 return (ISC_R_SUCCESS);
00576 }
00577
00578 isc_result_t
00579 isc_file_truncate(const char *filename, isc_offset_t size) {
00580 isc_result_t result = ISC_R_SUCCESS;
00581
00582 if (truncate(filename, size) < 0)
00583 result = isc__errno2result(errno);
00584 return (result);
00585 }
00586
00587 isc_result_t
00588 isc_file_safecreate(const char *filename, FILE **fp) {
00589 isc_result_t result;
00590 int flags;
00591 struct stat sb;
00592 FILE *f;
00593 int fd;
00594
00595 REQUIRE(filename != NULL);
00596 REQUIRE(fp != NULL && *fp == NULL);
00597
00598 result = file_stats(filename, &sb);
00599 if (result == ISC_R_SUCCESS) {
00600 if ((sb.st_mode & S_IFREG) == 0)
00601 return (ISC_R_INVALIDFILE);
00602 flags = O_WRONLY | O_TRUNC;
00603 } else if (result == ISC_R_FILENOTFOUND) {
00604 flags = O_WRONLY | O_CREAT | O_EXCL;
00605 } else
00606 return (result);
00607
00608 fd = open(filename, flags, S_IRUSR | S_IWUSR);
00609 if (fd == -1)
00610 return (isc__errno2result(errno));
00611
00612 f = fdopen(fd, "w");
00613 if (f == NULL) {
00614 result = isc__errno2result(errno);
00615 close(fd);
00616 return (result);
00617 }
00618
00619 *fp = f;
00620 return (ISC_R_SUCCESS);
00621 }
00622
00623 isc_result_t
00624 isc_file_splitpath(isc_mem_t *mctx, char *path, char **dirname, char **basename)
00625 {
00626 char *dir, *file, *slash;
00627
00628 if (path == NULL)
00629 return (ISC_R_INVALIDFILE);
00630
00631 slash = strrchr(path, '/');
00632
00633 if (slash == path) {
00634 file = ++slash;
00635 dir = isc_mem_strdup(mctx, "/");
00636 } else if (slash != NULL) {
00637 file = ++slash;
00638 dir = isc_mem_allocate(mctx, slash - path);
00639 if (dir != NULL)
00640 strlcpy(dir, path, slash - path);
00641 } else {
00642 file = path;
00643 dir = isc_mem_strdup(mctx, ".");
00644 }
00645
00646 if (dir == NULL)
00647 return (ISC_R_NOMEMORY);
00648
00649 if (*file == '\0') {
00650 isc_mem_free(mctx, dir);
00651 return (ISC_R_INVALIDFILE);
00652 }
00653
00654 *dirname = dir;
00655 *basename = file;
00656
00657 return (ISC_R_SUCCESS);
00658 }
00659
00660 void *
00661 isc_file_mmap(void *addr, size_t len, int prot,
00662 int flags, int fd, off_t offset)
00663 {
00664 #ifdef HAVE_MMAP
00665 return (mmap(addr, len, prot, flags, fd, offset));
00666 #else
00667 void *buf;
00668 ssize_t ret;
00669 off_t end;
00670
00671 UNUSED(addr);
00672 UNUSED(prot);
00673 UNUSED(flags);
00674
00675 end = lseek(fd, 0, SEEK_END);
00676 lseek(fd, offset, SEEK_SET);
00677 if (end - offset < (off_t) len)
00678 len = end - offset;
00679
00680 buf = malloc(len);
00681 ret = read(fd, buf, len);
00682 if (ret != (ssize_t) len) {
00683 free(buf);
00684 buf = NULL;
00685 }
00686
00687 return (buf);
00688 #endif
00689 }
00690
00691 int
00692 isc_file_munmap(void *addr, size_t len) {
00693 #ifdef HAVE_MMAP
00694 return (munmap(addr, len));
00695 #else
00696 UNUSED(len);
00697
00698 free(addr);
00699 return (0);
00700 #endif
00701 }
00702
00703 #define DISALLOW "\\/ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00704 #ifndef PATH_MAX
00705 #define PATH_MAX 1024
00706 #endif
00707
00708 isc_result_t
00709 isc_file_sanitize(const char *dir, const char *base, const char *ext,
00710 char *path, size_t length)
00711 {
00712 char buf[PATH_MAX], hash[PATH_MAX];
00713 size_t l = 0;
00714
00715 REQUIRE(base != NULL);
00716 REQUIRE(path != NULL);
00717
00718 l = strlen(base) + 1;
00719
00720
00721
00722
00723
00724 if (l < 65U)
00725 l = 65;
00726
00727 if (dir != NULL)
00728 l += strlen(dir) + 1;
00729 if (ext != NULL)
00730 l += strlen(ext) + 1;
00731
00732 if (l > length || l > (unsigned)PATH_MAX)
00733 return (ISC_R_NOSPACE);
00734
00735
00736 isc_sha256_data((const void *) base, strlen(base), hash);
00737 snprintf(buf, sizeof(buf), "%s%s%s%s%s",
00738 dir != NULL ? dir : "", dir != NULL ? "/" : "",
00739 hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
00740 if (isc_file_exists(buf)) {
00741 strlcpy(path, buf, length);
00742 return (ISC_R_SUCCESS);
00743 }
00744
00745
00746 hash[16] = '\0';
00747 snprintf(buf, sizeof(buf), "%s%s%s%s%s",
00748 dir != NULL ? dir : "", dir != NULL ? "/" : "",
00749 hash, ext != NULL ? "." : "", ext != NULL ? ext : "");
00750 if (isc_file_exists(buf)) {
00751 strlcpy(path, buf, length);
00752 return (ISC_R_SUCCESS);
00753 }
00754
00755
00756
00757
00758
00759
00760 if (strpbrk(base, DISALLOW) != NULL) {
00761 strlcpy(path, buf, length);
00762 return (ISC_R_SUCCESS);
00763 }
00764
00765 snprintf(buf, sizeof(buf), "%s%s%s%s%s",
00766 dir != NULL ? dir : "", dir != NULL ? "/" : "",
00767 base, ext != NULL ? "." : "", ext != NULL ? ext : "");
00768 strlcpy(path, buf, length);
00769 return (ISC_R_SUCCESS);
00770 }