mkdir.c 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. /* On some systems, mkdir ("foo/", 0700) fails because of the trailing
  2. slash. On those systems, this wrapper removes the trailing slash.
  3. Copyright (C) 2001, 2003, 2006, 2008-2023 Free Software Foundation, Inc.
  4. This file is free software: you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License as
  6. published by the Free Software Foundation; either version 2.1 of the
  7. License, or (at your option) any later version.
  8. This file is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public License
  13. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  14. /* written by Jim Meyering */
  15. #include <config.h>
  16. /* Specification. */
  17. #include <sys/stat.h>
  18. #include <errno.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "dirname.h"
  23. /* Disable the definition of mkdir to rpl_mkdir (from the <sys/stat.h>
  24. substitute) in this file. Otherwise, we'd get an endless recursion. */
  25. #undef mkdir
  26. /* mingw's _mkdir() function has 1 argument, but we pass 2 arguments.
  27. Additionally, it declares _mkdir (and depending on compile flags, an
  28. alias mkdir), only in the nonstandard includes <direct.h> and <io.h>,
  29. which are included in the <sys/stat.h> override. */
  30. #if defined _WIN32 && ! defined __CYGWIN__
  31. # define mkdir(name,mode) _mkdir (name)
  32. # define maybe_unused _GL_UNUSED
  33. #else
  34. # define maybe_unused /* empty */
  35. #endif
  36. /* This function is required at least for NetBSD 1.5.2. */
  37. int
  38. rpl_mkdir (char const *dir, maybe_unused mode_t mode)
  39. {
  40. int ret_val;
  41. char *tmp_dir;
  42. size_t len = strlen (dir);
  43. if (len && dir[len - 1] == '/')
  44. {
  45. tmp_dir = strdup (dir);
  46. if (!tmp_dir)
  47. {
  48. /* Rather than rely on strdup-posix, we set errno ourselves. */
  49. errno = ENOMEM;
  50. return -1;
  51. }
  52. strip_trailing_slashes (tmp_dir);
  53. }
  54. else
  55. {
  56. tmp_dir = (char *) dir;
  57. }
  58. #if FUNC_MKDIR_DOT_BUG
  59. /* Additionally, cygwin 1.5 mistakenly creates a directory "d/./". */
  60. {
  61. char *last = last_component (tmp_dir);
  62. if (*last == '.' && (last[1] == '\0'
  63. || (last[1] == '.' && last[2] == '\0')))
  64. {
  65. struct stat st;
  66. if (stat (tmp_dir, &st) == 0 || errno == EOVERFLOW)
  67. errno = EEXIST;
  68. return -1;
  69. }
  70. }
  71. #endif /* FUNC_MKDIR_DOT_BUG */
  72. ret_val = mkdir (tmp_dir, mode);
  73. if (tmp_dir != dir)
  74. free (tmp_dir);
  75. return ret_val;
  76. }