"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/file_io/win32/dir.c" (20 Mar 2019, 12722 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.h"
   18 #include "apr_arch_file_io.h"
   19 #include "apr_file_io.h"
   20 #include "apr_strings.h"
   21 #include "apr_portable.h"
   22 #include "apr_arch_atime.h"
   23 
   24 #if APR_HAVE_ERRNO_H
   25 #include <errno.h>
   26 #endif
   27 #if APR_HAVE_STRING_H
   28 #include <string.h>
   29 #endif
   30 #if APR_HAVE_DIRENT_H
   31 #include <dirent.h>
   32 #endif
   33 #ifdef HAVE_SYS_STAT_H
   34 #include <sys/stat.h>
   35 #endif
   36 
   37 
   38 static apr_status_t dir_cleanup(void *thedir)
   39 {
   40     apr_dir_t *dir = thedir;
   41     if (dir->dirhand != INVALID_HANDLE_VALUE && !FindClose(dir->dirhand)) {
   42         return apr_get_os_error();
   43     }
   44     dir->dirhand = INVALID_HANDLE_VALUE;
   45     return APR_SUCCESS;
   46 } 
   47 
   48 APR_DECLARE(apr_status_t) apr_dir_open(apr_dir_t **new, const char *dirname,
   49                                        apr_pool_t *pool)
   50 {
   51     apr_status_t rv;
   52 
   53     apr_size_t len = strlen(dirname);
   54     (*new) = apr_pcalloc(pool, sizeof(apr_dir_t));
   55     /* Leave room here to add and pop the '*' wildcard for FindFirstFile 
   56      * and double-null terminate so we have one character to change.
   57      */
   58     (*new)->dirname = apr_palloc(pool, len + 3);
   59     memcpy((*new)->dirname, dirname, len);
   60     if (len && (*new)->dirname[len - 1] != '/') {
   61         (*new)->dirname[len++] = '/';
   62     }
   63     (*new)->dirname[len++] = '\0';
   64     (*new)->dirname[len] = '\0';
   65 
   66 #if APR_HAS_UNICODE_FS
   67     IF_WIN_OS_IS_UNICODE
   68     {
   69         /* Create a buffer for the longest file name we will ever see 
   70          */
   71         (*new)->w.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW));
   72         (*new)->name = apr_pcalloc(pool, APR_FILE_MAX * 3 + 1);        
   73     }
   74 #endif
   75 #if APR_HAS_ANSI_FS
   76     ELSE_WIN_OS_IS_ANSI
   77     {
   78         /* Note that we won't open a directory that is greater than MAX_PATH,
   79          * counting the additional '/' '*' wildcard suffix.  If a * won't fit
   80          * then neither will any other file name within the directory.
   81          * The length not including the trailing '*' is stored as rootlen, to
   82          * skip over all paths which are too long.
   83          */
   84         if (len >= APR_PATH_MAX) {
   85             (*new) = NULL;
   86             return APR_ENAMETOOLONG;
   87         }
   88         (*new)->n.entry = apr_pcalloc(pool, sizeof(WIN32_FIND_DATAW));
   89     }
   90 #endif
   91     (*new)->rootlen = len - 1;
   92     (*new)->pool = pool;
   93     (*new)->dirhand = INVALID_HANDLE_VALUE;
   94     apr_pool_cleanup_register((*new)->pool, (void *)(*new), dir_cleanup,
   95                         apr_pool_cleanup_null);
   96 
   97     rv = apr_dir_read(NULL, 0, *new);
   98     if (rv != APR_SUCCESS) {
   99         dir_cleanup(*new);
  100         *new = NULL;
  101     }
  102 
  103     return rv;
  104 }
  105 
  106 APR_DECLARE(apr_status_t) apr_dir_close(apr_dir_t *dir)
  107 {
  108     apr_pool_cleanup_kill(dir->pool, dir, dir_cleanup);
  109     return dir_cleanup(dir);
  110 }
  111 
  112 APR_DECLARE(apr_status_t) apr_dir_read(apr_finfo_t *finfo, apr_int32_t wanted,
  113                                        apr_dir_t *thedir)
  114 {
  115     apr_status_t rv;
  116     char *fname;
  117     /* The while loops below allow us to skip all invalid file names, so that
  118      * we aren't reporting any files where their absolute paths are too long.
  119      */
  120 #if APR_HAS_UNICODE_FS
  121     apr_wchar_t wdirname[APR_PATH_MAX];
  122     apr_wchar_t *eos = NULL;
  123     IF_WIN_OS_IS_UNICODE
  124     {
  125         /* This code path is always be invoked by apr_dir_open or
  126          * apr_dir_rewind, so return without filling out the finfo.
  127          */
  128         if (thedir->dirhand == INVALID_HANDLE_VALUE) 
  129         {
  130             apr_status_t rv;
  131             if ((rv = utf8_to_unicode_path(wdirname, sizeof(wdirname) 
  132                                                    / sizeof(apr_wchar_t), 
  133                                            thedir->dirname))) {
  134                 return rv;
  135             }
  136             eos = wcschr(wdirname, '\0');
  137             eos[0] = '*';
  138             eos[1] = '\0';
  139             thedir->dirhand = FindFirstFileW(wdirname, thedir->w.entry);
  140             eos[0] = '\0';
  141             if (thedir->dirhand == INVALID_HANDLE_VALUE) {
  142                 return apr_get_os_error();
  143             }
  144             thedir->bof = 1;
  145             return APR_SUCCESS;
  146         }
  147         else if (thedir->bof) {
  148             /* Noop - we already called FindFirstFileW from
  149              * either apr_dir_open or apr_dir_rewind ... use
  150              * that first record.
  151              */
  152             thedir->bof = 0; 
  153         }
  154         else if (!FindNextFileW(thedir->dirhand, thedir->w.entry)) {
  155             return apr_get_os_error();
  156         }
  157 
  158         while (thedir->rootlen &&
  159                thedir->rootlen + wcslen(thedir->w.entry->cFileName) >= APR_PATH_MAX)
  160         {
  161             if (!FindNextFileW(thedir->dirhand, thedir->w.entry)) {
  162                 return apr_get_os_error();
  163             }
  164         }
  165         if ((rv = unicode_to_utf8_path(thedir->name, APR_FILE_MAX * 3 + 1, 
  166                                        thedir->w.entry->cFileName)))
  167             return rv;
  168         fname = thedir->name;
  169     }
  170 #endif
  171 #if APR_HAS_ANSI_FS
  172     ELSE_WIN_OS_IS_ANSI
  173     {
  174         /* This code path is always be invoked by apr_dir_open or 
  175          * apr_dir_rewind, so return without filling out the finfo.
  176          */
  177         if (thedir->dirhand == INVALID_HANDLE_VALUE) {
  178             /* '/' terminated, so add the '*' and pop it when we finish */
  179             char *eop = strchr(thedir->dirname, '\0');
  180             eop[0] = '*';
  181             eop[1] = '\0';
  182             thedir->dirhand = FindFirstFileA(thedir->dirname, 
  183                                              thedir->n.entry);
  184             eop[0] = '\0';
  185             if (thedir->dirhand == INVALID_HANDLE_VALUE) {
  186                 return apr_get_os_error();
  187             }
  188             thedir->bof = 1;
  189             return APR_SUCCESS;
  190         }
  191         else if (thedir->bof) {
  192             /* Noop - we already called FindFirstFileW from
  193              * either apr_dir_open or apr_dir_rewind ... use
  194              * that first record.
  195              */
  196             thedir->bof = 0; 
  197         }
  198         else if (!FindNextFileA(thedir->dirhand, thedir->n.entry)) {
  199             return apr_get_os_error();
  200         }
  201         while (thedir->rootlen &&
  202                thedir->rootlen + strlen(thedir->n.entry->cFileName) >= MAX_PATH)
  203         {
  204             if (!FindNextFileA(thedir->dirhand, thedir->n.entry)) {
  205                 return apr_get_os_error();
  206             }
  207         }
  208         fname = thedir->n.entry->cFileName;
  209     }
  210 #endif
  211 
  212     fillin_fileinfo(finfo, (WIN32_FILE_ATTRIBUTE_DATA *) thedir->w.entry, 
  213                     0, 1, fname, wanted);
  214     finfo->pool = thedir->pool;
  215 
  216     finfo->valid |= APR_FINFO_NAME;
  217     finfo->name = fname;
  218 
  219     if (wanted &= ~finfo->valid) {
  220         /* Go back and get more_info if we can't answer the whole inquiry
  221          */
  222 #if APR_HAS_UNICODE_FS
  223         IF_WIN_OS_IS_UNICODE
  224         {
  225             /* Almost all our work is done.  Tack on the wide file name
  226              * to the end of the wdirname (already / delimited)
  227              */
  228             if (!eos)
  229                 eos = wcschr(wdirname, '\0');
  230             wcscpy(eos, thedir->w.entry->cFileName);
  231             rv = more_finfo(finfo, wdirname, wanted, MORE_OF_WFSPEC);
  232             eos[0] = '\0';
  233             return rv;
  234         }
  235 #endif
  236 #if APR_HAS_ANSI_FS
  237         ELSE_WIN_OS_IS_ANSI
  238         {
  239 #if APR_HAS_UNICODE_FS
  240             /* Don't waste stack space on a second buffer, the one we set
  241              * aside for the wide directory name is twice what we need.
  242              */
  243             char *fspec = (char*)wdirname;
  244 #else
  245             char fspec[APR_PATH_MAX];
  246 #endif
  247             apr_size_t dirlen = strlen(thedir->dirname);
  248             if (dirlen >= sizeof(fspec))
  249                 dirlen = sizeof(fspec) - 1;
  250             apr_cpystrn(fspec, thedir->dirname, sizeof(fspec));
  251             apr_cpystrn(fspec + dirlen, fname, sizeof(fspec) - dirlen);
  252             return more_finfo(finfo, fspec, wanted, MORE_OF_FSPEC);
  253         }
  254 #endif
  255     }
  256 
  257     return APR_SUCCESS;
  258 }
  259 
  260 APR_DECLARE(apr_status_t) apr_dir_rewind(apr_dir_t *dir)
  261 {
  262     apr_status_t rv;
  263 
  264     /* this will mark the handle as invalid and we'll open it
  265      * again if apr_dir_read() is subsequently called
  266      */
  267     rv = dir_cleanup(dir);
  268 
  269     if (rv == APR_SUCCESS)
  270         rv = apr_dir_read(NULL, 0, dir);
  271 
  272     return rv;
  273 }
  274 
  275 APR_DECLARE(apr_status_t) apr_dir_make(const char *path, apr_fileperms_t perm,
  276                                        apr_pool_t *pool)
  277 {
  278 #if APR_HAS_UNICODE_FS
  279     IF_WIN_OS_IS_UNICODE
  280     {
  281         apr_wchar_t wpath[APR_PATH_MAX];
  282         apr_status_t rv;
  283         if ((rv = utf8_to_unicode_path(wpath,
  284                                        sizeof(wpath) / sizeof(apr_wchar_t),
  285                                        path))) {
  286             return rv;
  287         }
  288         if (!CreateDirectoryW(wpath, NULL)) {
  289             return apr_get_os_error();
  290         }
  291     }
  292 #endif
  293 #if APR_HAS_ANSI_FS
  294     ELSE_WIN_OS_IS_ANSI
  295         if (!CreateDirectory(path, NULL)) {
  296             return apr_get_os_error();
  297         }
  298 #endif
  299     return APR_SUCCESS;
  300 }
  301 
  302 
  303 static apr_status_t dir_make_parent(char *path,
  304                                     apr_fileperms_t perm,
  305                                     apr_pool_t *pool)
  306 {
  307     apr_status_t rv;
  308     char *ch = strrchr(path, '\\');
  309     if (!ch) {
  310         return APR_ENOENT;
  311     }
  312 
  313     *ch = '\0';
  314     rv = apr_dir_make (path, perm, pool); /* Try to make straight off */
  315     
  316     if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */
  317         rv = dir_make_parent(path, perm, pool);
  318 
  319         if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) {
  320             rv = apr_dir_make(path, perm, pool); /* And complete the path */
  321         }
  322     }
  323 
  324     *ch = '\\'; /* Always replace the slash before returning */
  325     return rv;
  326 }
  327 
  328 APR_DECLARE(apr_status_t) apr_dir_make_recursive(const char *path,
  329                                                  apr_fileperms_t perm,
  330                                                  apr_pool_t *pool)
  331 {
  332     apr_status_t rv = 0;
  333 
  334     rv = apr_dir_make (path, perm, pool); /* Try to make PATH right out */
  335 
  336     if (APR_STATUS_IS_ENOENT(rv)) { /* Missing an intermediate dir */
  337         char *dir;
  338 
  339         rv = apr_filepath_merge(&dir, "", path, APR_FILEPATH_NATIVE, pool);
  340 
  341         if (rv != APR_SUCCESS)
  342             return rv;
  343 
  344         rv = dir_make_parent(dir, perm, pool); /* Make intermediate dirs */
  345 
  346         if (rv == APR_SUCCESS || APR_STATUS_IS_EEXIST(rv)) {
  347             rv = apr_dir_make (dir, perm, pool);   /* And complete the path */
  348 
  349             if (APR_STATUS_IS_EEXIST(rv)) {
  350                 rv = APR_SUCCESS; /* Timing issue; see comment below */
  351             }
  352         }
  353     }
  354     else if (APR_STATUS_IS_EEXIST(rv)) {
  355         /*
  356          * It's OK if PATH exists. Timing issues can lead to the
  357          * second apr_dir_make being called on existing dir, therefore
  358          * this check has to come last.
  359          */
  360         rv = APR_SUCCESS;
  361     }
  362 
  363     return rv;
  364 }
  365 
  366 
  367 APR_DECLARE(apr_status_t) apr_dir_remove(const char *path, apr_pool_t *pool)
  368 {
  369 #if APR_HAS_UNICODE_FS
  370     IF_WIN_OS_IS_UNICODE
  371     {
  372         apr_wchar_t wpath[APR_PATH_MAX];
  373         apr_status_t rv;
  374         if ((rv = utf8_to_unicode_path(wpath,
  375                                        sizeof(wpath) / sizeof(apr_wchar_t),
  376                                        path))) {
  377             return rv;
  378         }
  379         if (!RemoveDirectoryW(wpath)) {
  380             return apr_get_os_error();
  381         }
  382     }
  383 #endif
  384 #if APR_HAS_ANSI_FS
  385     ELSE_WIN_OS_IS_ANSI
  386         if (!RemoveDirectory(path)) {
  387             return apr_get_os_error();
  388         }
  389 #endif
  390     return APR_SUCCESS;
  391 }
  392 
  393 APR_DECLARE(apr_status_t) apr_os_dir_get(apr_os_dir_t **thedir,
  394                                          apr_dir_t *dir)
  395 {
  396     if (dir == NULL) {
  397         return APR_ENODIR;
  398     }
  399     *thedir = dir->dirhand;
  400     return APR_SUCCESS;
  401 }
  402 
  403 APR_DECLARE(apr_status_t) apr_os_dir_put(apr_dir_t **dir,
  404                                          apr_os_dir_t *thedir,
  405                                          apr_pool_t *pool)
  406 {
  407     return APR_ENOTIMPL;
  408 }