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_file_io.h" 18#include "apr_lib.h" 19#include "apr_strings.h" 20#include <string.h> 21 22#define IS_SEP(c) (c == '/' || c == '\\') 23 24/* Remove trailing separators that don't affect the meaning of PATH. */ 25static const char *path_canonicalize(const char *path, apr_pool_t *pool) 26{ 27 /* At some point this could eliminate redundant components. For 28 * now, it just makes sure there is no trailing slash. */ 29 apr_size_t len = strlen(path); 30 apr_size_t orig_len = len; 31 32 while ((len > 0) && IS_SEP(path[len - 1])) { 33 len--; 34 } 35 36 if (len != orig_len) { 37 return apr_pstrndup(pool, path, len); 38 } 39 else { 40 return path; 41 } 42} 43 44 45 46/* Remove one component off the end of PATH. */ 47static char *path_remove_last_component(const char *path, apr_pool_t *pool) 48{ 49 const char *newpath = path_canonicalize(path, pool); 50 int i; 51 52 for (i = strlen(newpath) - 1; i >= 0; i--) { 53 if (IS_SEP(path[i])) { 54 break; 55 } 56 } 57 58 return apr_pstrndup(pool, path, (i < 0) ? 0 : i); 59} 60 61 62 63apr_status_t apr_dir_make_recursive(const char *path, apr_fileperms_t perm, 64 apr_pool_t *pool) 65{ 66 apr_status_t apr_err = APR_SUCCESS; 67 68 apr_err = apr_dir_make(path, perm, pool); /* Try to make PATH right out */ 69 70 if (APR_STATUS_IS_ENOENT(apr_err)) { /* Missing an intermediate dir */ 71 char *dir; 72 73 dir = path_remove_last_component(path, pool); 74 apr_err = apr_dir_make_recursive(dir, perm, pool); 75 76 if (!apr_err) { 77 apr_err = apr_dir_make(path, perm, pool); 78 } 79 } 80 81 /* 82 * It's OK if PATH exists. Timing issues can lead to the second 83 * apr_dir_make being called on existing dir, therefore this check 84 * has to come last. 85 */ 86 if (APR_STATUS_IS_EEXIST(apr_err)) 87 return APR_SUCCESS; 88 89 return apr_err; 90} 91