"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/file_io/unix/dir.c" (1 Apr 2019, 10733 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


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 and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    1 /* Licensed to the Apache Software Foundation (ASF) under one or more
    2  * contributor license agreements.  See the NOTICE file distributed with
    3  * this work for additional information regarding copyright ownership.
    4  * The ASF licenses this file to You under the Apache License, Version 2.0
    5  * (the "License"); you may not use this file except in compliance with
    6  * the License.  You may obtain a copy of the License at
    7  *
    8  *     http://www.apache.org/licenses/LICENSE-2.0
    9  *
   10  * Unless required by applicable law or agreed to in writing, software
   11  * distributed under the License is distributed on an "AS IS" BASIS,
   12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   13  * See the License for the specific language governing permissions and
   14  * limitations under the License.
   15  */
   16 
   17 #include "apr_arch_file_io.h"
   18 #include "apr_strings.h"
   19 #include "apr_portable.h"
   20 #if APR_HAVE_SYS_SYSLIMITS_H
   21 #include <sys/syslimits.h>
   22 #endif
   23 #if APR_HAVE_LIMITS_H
   24 #include <limits.h>
   25 #endif
   26 
   27 #ifndef NAME_MAX
   28 #define NAME_MAX 255
   29 #endif
   30 
   31 static apr_status_t dir_cleanup(void *thedir)
   32 {
   33     apr_dir_t *dir = thedir;
   34     if (closedir(dir->dirstruct) == 0) {
   35         return APR_SUCCESS;
   36     }
   37     else {
   38         return errno;
   39     }
   40 } 
   41 
   42 #define PATH_SEPARATOR '/'
   43 
   44 /* Remove trailing separators that don't affect the meaning of PATH. */
   45 static const char *path_canonicalize (const char *path, apr_pool_t *pool)
   46 {
   47     /* At some point this could eliminate redundant components.  For
   48      * now, it just makes sure there is no trailing slash. */
   49     apr_size_t len = strlen (path);
   50     apr_size_t orig_len = len;
   51     
   52     while ((len > 0) && (path[len - 1] == PATH_SEPARATOR))
   53         len--;
   54     
   55     if (len != orig_len)
   56         return apr_pstrndup (pool, path, len);
   57     else
   58         return path;
   59 }
   60 
   61 /* Remove one component off the end of PATH. */
   62 static char *path_remove_last_component (const char *path, apr_pool_t *pool)
   63 {
   64     const char *newpath = path_canonicalize (path, pool);
   65     int i;
   66     
   67     for (i = (strlen(newpath) - 1); i >= 0; i--) {
   68         if (path[i] == PATH_SEPARATOR)
   69             break;
   70     }
   71 
   72     return apr_pstrndup (pool, path, (i < 0) ? 0 : i);
   73 }
   74 
   75 apr_status_t apr_dir_open(apr_dir_t **new, const char *dirname, 
   76                           apr_pool_t *pool)
   77 {
   78     DIR *dir = opendir(dirname);
   79 
   80     if (!dir) {
   81         return errno;
   82     }
   83 
   84     (*new) = (apr_dir_t *)apr_palloc(pool, sizeof(apr_dir_t));
   85 
   86     (*new)->pool = pool;
   87     (*new)->dirname = apr_pstrdup(pool, dirname);
   88     (*new)->dirstruct = dir;
   89 
   90 #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \
   91                     && !defined(READDIR_IS_THREAD_SAFE)
   92     /* On some platforms (e.g., Linux+GNU libc), d_name[] in struct 
   93      * dirent is declared with enough storage for the name.  On other
   94      * platforms (e.g., Solaris 8 for Intel), d_name is declared as a
   95      * one-byte array.  Note: gcc evaluates this at compile time.
   96      */
   97     (*new)->entry = apr_pcalloc(pool, sizeof(*(*new)->entry) +
   98                                       (sizeof((*new)->entry->d_name) > 1
   99                                        ? 0 : NAME_MAX));
  100 #else
  101     (*new)->entry = NULL;
  102 #endif
  103 
  104     apr_pool_cleanup_register((*new)->pool, *new, dir_cleanup,
  105                               apr_pool_cleanup_null);
  106     return APR_SUCCESS;
  107 }
  108 
  109 apr_status_t apr_dir_close(apr_dir_t *thedir)
  110 {
  111     return apr_pool_cleanup_run(thedir->pool, thedir, dir_cleanup);
  112 }
  113 
  114 #ifdef DIRENT_TYPE
  115 static apr_filetype_e filetype_from_dirent_type(int type)
  116 {
  117     switch (type) {
  118     case DT_REG:
  119         return APR_REG;
  120     case DT_DIR:
  121         return APR_DIR;
  122     case DT_LNK:
  123         return APR_LNK;
  124     case DT_CHR:
  125         return APR_CHR;
  126     case DT_BLK:
  127         return APR_BLK;
  128 #if defined(DT_FIFO)
  129     case DT_FIFO:
  130         return APR_PIPE;
  131 #endif
  132 #if !defined(BEOS) && defined(DT_SOCK)
  133     case DT_SOCK:
  134         return APR_SOCK;
  135 #endif
  136     default:
  137         return APR_UNKFILE;
  138     }
  139 }
  140 #endif
  141 
  142 apr_status_t apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
  143                           apr_dir_t *thedir)
  144 {
  145     apr_status_t ret = 0;
  146 #ifdef DIRENT_TYPE
  147     apr_filetype_e type;
  148 #endif
  149 #if APR_HAS_THREADS && defined(_POSIX_THREAD_SAFE_FUNCTIONS) \
  150                     && !defined(READDIR_IS_THREAD_SAFE)
  151 #ifdef APR_USE_READDIR64_R
  152     struct dirent64 *retent;
  153 
  154     /* If LFS is enabled and readdir64_r is available, readdir64_r is
  155      * used in preference to readdir_r.  This allows directories to be
  156      * read which contain a (64-bit) inode number which doesn't fit
  157      * into the 32-bit apr_ino_t, iff the caller doesn't actually care
  158      * about the inode number (i.e. wanted & APR_FINFO_INODE == 0).
  159      * (such inodes may be seen in some wonky NFS environments)
  160      *
  161      * Similarly, if the d_off field cannot be reprented in a 32-bit
  162      * offset, the libc readdir_r() would barf; using readdir64_r
  163      * bypasses that case entirely since APR does not care about
  164      * d_off. */
  165 
  166     ret = readdir64_r(thedir->dirstruct, thedir->entry, &retent);
  167 #else
  168 
  169     struct dirent *retent;
  170 
  171     ret = readdir_r(thedir->dirstruct, thedir->entry, &retent);
  172 #endif
  173 
  174     /* POSIX treats "end of directory" as a non-error case, so ret
  175      * will be zero and retent will be set to NULL in that case. */
  176     if (!ret && retent == NULL) {
  177         ret = APR_ENOENT;
  178     }
  179 
  180     /* Solaris is a bit strange, if there are no more entries in the
  181      * directory, it returns EINVAL.  Since this is against POSIX, we
  182      * hack around the problem here.  EINVAL is possible from other
  183      * readdir implementations, but only if the result buffer is too small.
  184      * since we control the size of that buffer, we should never have
  185      * that problem.
  186      */
  187     if (ret == EINVAL) {
  188         ret = APR_ENOENT;
  189     }
  190 #else
  191     /* We're about to call a non-thread-safe readdir() that may
  192        possibly set `errno', and the logic below actually cares about
  193        errno after the call.  Therefore we need to clear errno first. */
  194     errno = 0;
  195     thedir->entry = readdir(thedir->dirstruct);
  196     if (thedir->entry == NULL) {
  197         /* If NULL was returned, this can NEVER be a success. Can it?! */
  198         if (errno == APR_SUCCESS) {
  199             ret = APR_ENOENT;
  200         }
  201         else
  202             ret = errno;
  203     }
  204 #endif
  205 
  206     /* No valid bit flag to test here - do we want one? */
  207     finfo->fname = NULL;
  208 
  209     if (ret) {
  210         finfo->valid = 0;
  211         return ret;
  212     }
  213 
  214 #ifdef DIRENT_TYPE
  215     type = filetype_from_dirent_type(thedir->entry->DIRENT_TYPE);
  216     if (type != APR_UNKFILE) {
  217         wanted &= ~APR_FINFO_TYPE;
  218     }
  219 #endif
  220 #ifdef DIRENT_INODE
  221     if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) {
  222 #ifdef APR_USE_READDIR64_R
  223         /* If readdir64_r is used, check for the overflow case of trying
  224          * to fit a 64-bit integer into a 32-bit integer. */
  225         if (sizeof(apr_ino_t) >= sizeof(retent->DIRENT_INODE)
  226             || (apr_ino_t)retent->DIRENT_INODE == retent->DIRENT_INODE) {
  227             wanted &= ~APR_FINFO_INODE;
  228         } else {
  229             /* Prevent the fallback code below from filling in the
  230              * inode if the stat call fails. */
  231             retent->DIRENT_INODE = 0;
  232         }
  233 #else
  234         wanted &= ~APR_FINFO_INODE;
  235 #endif /* APR_USE_READDIR64_R */
  236     }
  237 #endif /* DIRENT_INODE */
  238 
  239     wanted &= ~APR_FINFO_NAME;
  240 
  241     if (wanted)
  242     {
  243         char fspec[APR_PATH_MAX];
  244         char *end;
  245 
  246         end = apr_cpystrn(fspec, thedir->dirname, sizeof fspec);
  247 
  248         if (end > fspec && end[-1] != '/' && (end < fspec + APR_PATH_MAX))
  249             *end++ = '/';
  250 
  251         apr_cpystrn(end, thedir->entry->d_name, 
  252                     sizeof fspec - (end - fspec));
  253 
  254         ret = apr_stat(finfo, fspec, APR_FINFO_LINK | wanted, thedir->pool);
  255         /* We passed a stack name that will disappear */
  256         finfo->fname = NULL;
  257     }
  258 
  259     if (wanted && (ret == APR_SUCCESS || ret == APR_INCOMPLETE)) {
  260         wanted &= ~finfo->valid;
  261     }
  262     else {
  263         /* We don't bail because we fail to stat, when we are only -required-
  264          * to readdir... but the result will be APR_INCOMPLETE
  265          */
  266         finfo->pool = thedir->pool;
  267         finfo->valid = 0;
  268 #ifdef DIRENT_TYPE
  269         if (type != APR_UNKFILE) {
  270             finfo->filetype = type;
  271             finfo->valid |= APR_FINFO_TYPE;
  272         }
  273 #endif
  274 #ifdef DIRENT_INODE
  275         if (thedir->entry->DIRENT_INODE && thedir->entry->DIRENT_INODE != -1) {
  276             finfo->inode = thedir->entry->DIRENT_INODE;
  277             finfo->valid |= APR_FINFO_INODE;
  278         }
  279 #endif
  280     }
  281 
  282     finfo->name = apr_pstrdup(thedir->pool, thedir->entry->d_name);
  283     finfo->valid |= APR_FINFO_NAME;
  284 
  285     if (wanted)
  286         return APR_INCOMPLETE;
  287 
  288     return APR_SUCCESS;
  289 }
  290 
  291 apr_status_t apr_dir_rewind(apr_dir_t *thedir)
  292 {
  293     rewinddir(thedir->dirstruct);
  294     return APR_SUCCESS;
  295 }
  296 
  297 apr_status_t apr_dir_make(const char *path, apr_fileperms_t perm, 
  298                           apr_pool_t *pool)
  299 {
  300     mode_t mode = apr_unix_perms2mode(perm);
  301 
  302     if (mkdir(path, mode) == 0) {
  303         return APR_SUCCESS;
  304     }
  305     else {
  306         return errno;
  307     }
  308 }
  309 
  310 apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm,
  311                                            apr_pool_t *pool) 
  312 {
  313     apr_status_t apr_err = 0;
  314     
  315     apr_err = apr_dir_make (path, perm, pool); /* Try to make PATH right out */
  316     
  317     if (apr_err == ENOENT) { /* Missing an intermediate dir */
  318         char *dir;
  319         
  320         dir = path_remove_last_component(path, pool);
  321         /* If there is no path left, give up. */
  322         if (dir[0] == '\0') {
  323             return apr_err;
  324         }
  325 
  326         apr_err = apr_dir_make_recursive(dir, perm, pool);
  327         
  328         if (!apr_err) 
  329             apr_err = apr_dir_make (path, perm, pool);
  330     }
  331 
  332     /*
  333      * It's OK if PATH exists. Timing issues can lead to the second
  334      * apr_dir_make being called on existing dir, therefore this check
  335      * has to come last.
  336      */
  337     if (APR_STATUS_IS_EEXIST(apr_err))
  338         return APR_SUCCESS;
  339 
  340     return apr_err;
  341 }
  342 
  343 apr_status_t apr_dir_remove(const char *path, apr_pool_t *pool)
  344 {
  345     if (rmdir(path) == 0) {
  346         return APR_SUCCESS;
  347     }
  348     else {
  349         return errno;
  350     }
  351 }
  352 
  353 apr_status_t apr_os_dir_get(apr_os_dir_t **thedir, apr_dir_t *dir)
  354 {
  355     if (dir == NULL) {
  356         return APR_ENODIR;
  357     }
  358     *thedir = dir->dirstruct;
  359     return APR_SUCCESS;
  360 }
  361 
  362 apr_status_t apr_os_dir_put(apr_dir_t **dir, apr_os_dir_t *thedir,
  363                           apr_pool_t *pool)
  364 {
  365     if ((*dir) == NULL) {
  366         (*dir) = (apr_dir_t *)apr_pcalloc(pool, sizeof(apr_dir_t));
  367         (*dir)->pool = pool;
  368     }
  369     (*dir)->dirstruct = thedir;
  370     return APR_SUCCESS;
  371 }
  372 
  373