file.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2004, 2005, 2007, 2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
00003  * Copyright (C) 2000-2002  Internet Software Consortium.
00004  *
00005  * Permission to use, copy, modify, and/or distribute this software for any
00006  * purpose with or without fee is hereby granted, provided that the above
00007  * copyright notice and this permission notice appear in all copies.
00008  *
00009  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
00010  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
00011  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
00012  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
00013  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
00014  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
00015  * PERFORMANCE OF THIS SOFTWARE.
00016  */
00017 
00018 /*
00019  * Portions Copyright (c) 1987, 1993
00020  *      The Regents of the University of California.  All rights reserved.
00021  *
00022  * Redistribution and use in source and binary forms, with or without
00023  * modification, are permitted provided that the following conditions
00024  * are met:
00025  * 1. Redistributions of source code must retain the above copyright
00026  *    notice, this list of conditions and the following disclaimer.
00027  * 2. Redistributions in binary form must reproduce the above copyright
00028  *    notice, this list of conditions and the following disclaimer in the
00029  *    documentation and/or other materials provided with the distribution.
00030  * 3. Neither the name of the University nor the names of its contributors
00031  *    may be used to endorse or promote products derived from this software
00032  *    without specific prior written permission.
00033  *
00034  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00035  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00036  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00037  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00038  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00039  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00040  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00041  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00042  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00043  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00044  * SUCH DAMAGE.
00045  */
00046 
00047 /* $Id$ */
00048 
00049 /*! \file */
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>               /* Required for utimes on some platforms. */
00058 #include <unistd.h>             /* Required for mkstemp on NetBSD. */
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  * XXXDCL As the API for accessing file statistics undoubtedly gets expanded,
00083  * it might be good to provide a mechanism that allows for the results
00084  * of a previous stat() to be used again without having to do another stat,
00085  * such as perl's mechanism of using "_" in place of a file name to indicate
00086  * that the results of the last stat should be used.  But then you get into
00087  * annoying MP issues.   BTW, Win32 has stat().
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                  * XXXDCL some operating systems provide nanoseconds, too,
00156                  * such as BSD/OS via st_mtimespec.
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          * tv_sec is at least a 32 bit quantity on all platforms we're
00187          * dealing with, but it is signed on most (all?) of them,
00188          * so we need to make sure the high bit isn't set.  This unfortunately
00189          * loses when either:
00190          *   * tv_sec becomes a signed 64 bit integer but long is 32 bits
00191          *      and isc_time_seconds > LONG_MAX, or
00192          *   * isc_time_seconds is changed to be > 32 bits but long is 32 bits
00193          *      and isc_time_seconds has at least 33 significant bits.
00194          */
00195         times[0].tv_sec = times[1].tv_sec = (long)isc_time_seconds(when);
00196 
00197         /*
00198          * Here is the real check for the high bit being set.
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          * isc_time_nanoseconds guarantees a value that divided by 1000 will
00206          * fit into the minimum possible size tv_usec field.  Unfortunately,
00207          * we don't know what that type is so can't cast directly ... but
00208          * we can at least cast to signed so the IRIX compiler shuts up.
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" /*%< 14 characters. */
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          * This function returns success if filename is a plain file.
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          * This function returns success if filename is a plain file.
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          * This function returns success if filename exists and is a
00467          * directory.
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  * Put the absolute name of the current directory into 'dirname', which is
00537  * a buffer of at least 'length' characters.  End the string with the
00538  * appropriate path separator, such that the final product could be
00539  * concatenated with a relative pathname to make a valid pathname string.
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          * allow room for a full sha256 hash (64 chars
00722          * plus null terminator)
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         /* Check whether the full-length SHA256 hash filename exists */
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         /* Check for a truncated SHA256 hash filename */
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          * If neither hash filename already exists, then we'll use
00757          * the original base name if it has no disallowed characters,
00758          * or the truncated hash name if it does.
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 }

Generated on Tue Apr 28 17:41:05 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha