"Fossies" - the Fresh Open Source Software Archive

Member "bind-9.17.5/lib/isc/unix/dir.c" (4 Sep 2020, 5155 Bytes) of package /linux/misc/dns/bind9/9.17.5/bind-9.17.5.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dir.c" see the Fossies "Dox" file reference documentation.

    1 /*
    2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
    3  *
    4  * This Source Code Form is subject to the terms of the Mozilla Public
    5  * License, v. 2.0. If a copy of the MPL was not distributed with this
    6  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
    7  *
    8  * See the COPYRIGHT file distributed with this work for additional
    9  * information regarding copyright ownership.
   10  */
   11 
   12 /*! \file */
   13 
   14 #include <ctype.h>
   15 #include <errno.h>
   16 #include <sys/stat.h>
   17 #include <sys/types.h>
   18 #include <unistd.h>
   19 
   20 #include <isc/dir.h>
   21 #include <isc/magic.h>
   22 #include <isc/netdb.h>
   23 #include <isc/print.h>
   24 #include <isc/string.h>
   25 #include <isc/util.h>
   26 
   27 #include "errno2result.h"
   28 
   29 #define ISC_DIR_MAGIC  ISC_MAGIC('D', 'I', 'R', '*')
   30 #define VALID_DIR(dir) ISC_MAGIC_VALID(dir, ISC_DIR_MAGIC)
   31 
   32 void
   33 isc_dir_init(isc_dir_t *dir) {
   34     REQUIRE(dir != NULL);
   35 
   36     dir->entry.name[0] = '\0';
   37     dir->entry.length = 0;
   38 
   39     dir->handle = NULL;
   40 
   41     dir->magic = ISC_DIR_MAGIC;
   42 }
   43 
   44 /*!
   45  * \brief Allocate workspace and open directory stream. If either one fails,
   46  * NULL will be returned.
   47  */
   48 isc_result_t
   49 isc_dir_open(isc_dir_t *dir, const char *dirname) {
   50     char *p;
   51     isc_result_t result = ISC_R_SUCCESS;
   52 
   53     REQUIRE(VALID_DIR(dir));
   54     REQUIRE(dirname != NULL);
   55 
   56     /*
   57      * Copy directory name.  Need to have enough space for the name,
   58      * a possible path separator, the wildcard, and the final NUL.
   59      */
   60     if (strlen(dirname) + 3 > sizeof(dir->dirname)) {
   61         /* XXXDCL ? */
   62         return (ISC_R_NOSPACE);
   63     }
   64     strlcpy(dir->dirname, dirname, sizeof(dir->dirname));
   65 
   66     /*
   67      * Append path separator, if needed, and "*".
   68      */
   69     p = dir->dirname + strlen(dir->dirname);
   70     if (dir->dirname < p && *(p - 1) != '/') {
   71         *p++ = '/';
   72     }
   73     *p++ = '*';
   74     *p = '\0';
   75 
   76     /*
   77      * Open stream.
   78      */
   79     dir->handle = opendir(dirname);
   80 
   81     if (dir->handle == NULL) {
   82         return (isc__errno2result(errno));
   83     }
   84 
   85     return (result);
   86 }
   87 
   88 /*!
   89  * \brief Return previously retrieved file or get next one.
   90  *
   91  * Unix's dirent has
   92  * separate open and read functions, but the Win32 and DOS interfaces open
   93  * the dir stream and reads the first file in one operation.
   94  */
   95 isc_result_t
   96 isc_dir_read(isc_dir_t *dir) {
   97     struct dirent *entry;
   98 
   99     REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
  100 
  101     /*
  102      * Fetch next file in directory.
  103      */
  104     entry = readdir(dir->handle);
  105 
  106     if (entry == NULL) {
  107         return (ISC_R_NOMORE);
  108     }
  109 
  110     /*
  111      * Make sure that the space for the name is long enough.
  112      */
  113     if (sizeof(dir->entry.name) <= strlen(entry->d_name)) {
  114         return (ISC_R_UNEXPECTED);
  115     }
  116 
  117     strlcpy(dir->entry.name, entry->d_name, sizeof(dir->entry.name));
  118 
  119     /*
  120      * Some dirents have d_namlen, but it is not portable.
  121      */
  122     dir->entry.length = strlen(entry->d_name);
  123 
  124     return (ISC_R_SUCCESS);
  125 }
  126 
  127 /*!
  128  * \brief Close directory stream.
  129  */
  130 void
  131 isc_dir_close(isc_dir_t *dir) {
  132     REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
  133 
  134     (void)closedir(dir->handle);
  135     dir->handle = NULL;
  136 }
  137 
  138 /*!
  139  * \brief Reposition directory stream at start.
  140  */
  141 isc_result_t
  142 isc_dir_reset(isc_dir_t *dir) {
  143     REQUIRE(VALID_DIR(dir) && dir->handle != NULL);
  144 
  145     rewinddir(dir->handle);
  146 
  147     return (ISC_R_SUCCESS);
  148 }
  149 
  150 isc_result_t
  151 isc_dir_chdir(const char *dirname) {
  152     /*!
  153      * \brief Change the current directory to 'dirname'.
  154      */
  155 
  156     REQUIRE(dirname != NULL);
  157 
  158     if (chdir(dirname) < 0) {
  159         return (isc__errno2result(errno));
  160     }
  161 
  162     return (ISC_R_SUCCESS);
  163 }
  164 
  165 isc_result_t
  166 isc_dir_chroot(const char *dirname) {
  167 #ifdef HAVE_CHROOT
  168     void *tmp;
  169 #endif /* ifdef HAVE_CHROOT */
  170 
  171     REQUIRE(dirname != NULL);
  172 
  173 #ifdef HAVE_CHROOT
  174     /*
  175      * Try to use getservbyname and getprotobyname before chroot.
  176      * If WKS records are used in a zone under chroot, Name Service Switch
  177      * may fail to load library in chroot.
  178      * Do not report errors if it fails, we do not need any result now.
  179      */
  180     tmp = getprotobyname("udp");
  181     if (tmp != NULL) {
  182         (void)getservbyname("domain", "udp");
  183     }
  184 
  185     if (chroot(dirname) < 0 || chdir("/") < 0) {
  186         return (isc__errno2result(errno));
  187     }
  188 
  189     return (ISC_R_SUCCESS);
  190 #else  /* ifdef HAVE_CHROOT */
  191     return (ISC_R_NOTIMPLEMENTED);
  192 #endif /* ifdef HAVE_CHROOT */
  193 }
  194 
  195 isc_result_t
  196 isc_dir_createunique(char *templet) {
  197     isc_result_t result;
  198     char *x;
  199     char *p;
  200     int i;
  201     int pid;
  202 
  203     REQUIRE(templet != NULL);
  204 
  205     /*!
  206      * \brief mkdtemp is not portable, so this emulates it.
  207      */
  208 
  209     pid = getpid();
  210 
  211     /*
  212      * Replace trailing Xs with the process-id, zero-filled.
  213      */
  214     for (x = templet + strlen(templet) - 1; *x == 'X' && x >= templet;
  215          x--, pid /= 10)
  216     {
  217         *x = pid % 10 + '0';
  218     }
  219 
  220     x++; /* Set x to start of ex-Xs. */
  221 
  222     do {
  223         i = mkdir(templet, 0700);
  224         if (i == 0 || errno != EEXIST) {
  225             break;
  226         }
  227 
  228         /*
  229          * The BSD algorithm.
  230          */
  231         p = x;
  232         while (*p != '\0') {
  233             if (isdigit(*p & 0xff)) {
  234                 *p = 'a';
  235             } else if (*p != 'z') {
  236                 ++*p;
  237             } else {
  238                 /*
  239                  * Reset character and move to next.
  240                  */
  241                 *p++ = 'a';
  242                 continue;
  243             }
  244 
  245             break;
  246         }
  247 
  248         if (*p == '\0') {
  249             /*
  250              * Tried all combinations.  errno should already
  251              * be EEXIST, but ensure it is anyway for
  252              * isc__errno2result().
  253              */
  254             errno = EEXIST;
  255             break;
  256         }
  257     } while (1);
  258 
  259     if (i == -1) {
  260         result = isc__errno2result(errno);
  261     } else {
  262         result = ISC_R_SUCCESS;
  263     }
  264 
  265     return (result);
  266 }