dir_make_recurse.c 2.6 KB

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