make_directory.c 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * parse_mode implementation for busybox
  4. *
  5. * Copyright (C) 2003 Manuel Novoa III <mjn3@codepoet.org>
  6. *
  7. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  8. */
  9. /* Mar 5, 2003 Manuel Novoa III
  10. *
  11. * This is the main work function for the 'mkdir' applet. As such, it
  12. * strives to be SUSv3 compliant in it's behaviour when recursively
  13. * making missing parent dirs, and in it's mode setting of the final
  14. * directory 'path'.
  15. *
  16. * To recursively build all missing intermediate directories, make
  17. * sure that (flags & FILEUTILS_RECUR) is non-zero. Newly created
  18. * intermediate directories will have at least u+wx perms.
  19. *
  20. * To set specific permissions on 'path', pass the appropriate 'mode'
  21. * val. Otherwise, pass -1 to get default permissions.
  22. */
  23. #include "libbb.h"
  24. /* This function is used from NOFORK applets. It must not allocate anything */
  25. int FAST_FUNC bb_make_directory(char *path, long mode, int flags)
  26. {
  27. mode_t cur_mask;
  28. mode_t org_mask;
  29. const char *fail_msg;
  30. char *s;
  31. char c;
  32. struct stat st;
  33. /* "path" can be a result of dirname().
  34. * dirname("no_slashes") returns ".", possibly read-only.
  35. * musl dirname() can return read-only "/" too.
  36. * We need writable string. And for "/", "." (and ".."?)
  37. * nothing needs to be created anyway.
  38. */
  39. if (LONE_CHAR(path, '/'))
  40. return 0;
  41. if (path[0] == '.') {
  42. if (path[1] == '\0')
  43. return 0; /* "." */
  44. // if (path[1] == '.' && path[2] == '\0')
  45. // return 0; /* ".." */
  46. }
  47. org_mask = cur_mask = (mode_t)-1L;
  48. s = path;
  49. while (1) {
  50. c = '\0';
  51. if (flags & FILEUTILS_RECUR) { /* Get the parent */
  52. /* Bypass leading non-'/'s and then subsequent '/'s */
  53. while (*s) {
  54. if (*s == '/') {
  55. do {
  56. ++s;
  57. } while (*s == '/');
  58. c = *s; /* Save the current char */
  59. *s = '\0'; /* and replace it with nul */
  60. break;
  61. }
  62. ++s;
  63. }
  64. }
  65. if (c != '\0') {
  66. /* Intermediate dirs: must have wx for user */
  67. if (cur_mask == (mode_t)-1L) { /* wasn't done yet? */
  68. mode_t new_mask;
  69. org_mask = umask(0);
  70. cur_mask = 0;
  71. /* Clear u=wx in umask - this ensures
  72. * they won't be cleared on mkdir */
  73. new_mask = (org_mask & ~(mode_t)0300);
  74. //bb_error_msg("org_mask:%o cur_mask:%o", org_mask, new_mask);
  75. if (new_mask != cur_mask) {
  76. cur_mask = new_mask;
  77. umask(new_mask);
  78. }
  79. }
  80. } else {
  81. /* Last component: uses original umask */
  82. //bb_error_msg("1 org_mask:%o", org_mask);
  83. if (org_mask != cur_mask) {
  84. cur_mask = org_mask;
  85. umask(org_mask);
  86. }
  87. }
  88. //bb_error_msg("mkdir '%s'", path);
  89. if (mkdir(path, 0777) < 0) {
  90. /* If we failed for any other reason than the directory
  91. * already exists, output a diagnostic and return -1 */
  92. if ((errno != EEXIST && errno != EISDIR)
  93. || !(flags & FILEUTILS_RECUR)
  94. || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode))
  95. ) {
  96. fail_msg = "create";
  97. break;
  98. }
  99. /* Since the directory exists, don't attempt to change
  100. * permissions if it was the full target. Note that
  101. * this is not an error condition. */
  102. if (!c) {
  103. goto ret0;
  104. }
  105. } else {
  106. if (flags & FILEUTILS_VERBOSE) {
  107. printf("created directory: '%s'\n", path);
  108. }
  109. }
  110. if (!c) {
  111. /* Done. If necessary, update perms on the newly
  112. * created directory. Failure to update here _is_
  113. * an error. */
  114. if (mode != -1) {
  115. //bb_error_msg("chmod 0%03lo mkdir '%s'", mode, path);
  116. if (chmod(path, mode) < 0) {
  117. fail_msg = "set permissions of";
  118. if (flags & FILEUTILS_IGNORE_CHMOD_ERR) {
  119. flags = 0;
  120. goto print_err;
  121. }
  122. break;
  123. }
  124. }
  125. goto ret0;
  126. }
  127. /* Remove any inserted nul from the path (recursive mode) */
  128. *s = c;
  129. } /* while (1) */
  130. flags = -1;
  131. print_err:
  132. bb_perror_msg("can't %s directory '%s'", fail_msg, path);
  133. goto ret;
  134. ret0:
  135. flags = 0;
  136. ret:
  137. //bb_error_msg("2 org_mask:%o", org_mask);
  138. if (org_mask != cur_mask)
  139. umask(org_mask);
  140. return flags;
  141. }