mkdir_complete.cxx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. // Filename: mkdir_complete.cxx
  2. // Created by: drose (29Jun09)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) Carnegie Mellon University. All rights reserved.
  8. //
  9. // All use of this software is subject to the terms of the revised BSD
  10. // license. You should have received a copy of this license along
  11. // with this source code in a file named "LICENSE."
  12. //
  13. ////////////////////////////////////////////////////////////////////
  14. #include "mkdir_complete.h"
  15. #ifdef _WIN32
  16. #include <windows.h>
  17. #else
  18. #include <fcntl.h>
  19. #include <sys/stat.h> // for mkdir()
  20. #include <errno.h>
  21. #endif
  22. ////////////////////////////////////////////////////////////////////
  23. // Function: get_dirname
  24. // Description: Returns the directory component of the indicated
  25. // pathname, or the empty string if there is no
  26. // directory prefix.
  27. ////////////////////////////////////////////////////////////////////
  28. static string
  29. get_dirname(const string &filename) {
  30. size_t p = filename.length();
  31. while (p > 0) {
  32. --p;
  33. if (is_pathsep(filename[p])) {
  34. return filename.substr(0, p);
  35. }
  36. }
  37. return string();
  38. }
  39. ////////////////////////////////////////////////////////////////////
  40. // Function: mkdir_complete
  41. // Description: Creates a new directory, with normal access
  42. // privileges. Returns true on success, false on
  43. // failure. Will create intervening directories if
  44. // necessary.
  45. ////////////////////////////////////////////////////////////////////
  46. bool
  47. mkdir_complete(const string &dirname) {
  48. #ifdef _WIN32
  49. if (CreateDirectory(dirname.c_str(), NULL) != 0) {
  50. // Success!
  51. return true;
  52. }
  53. // Failed.
  54. DWORD last_error = GetLastError();
  55. if (last_error == ERROR_ALREADY_EXISTS) {
  56. // Not really an error: the directory is already there.
  57. return true;
  58. }
  59. if (last_error == ERROR_PATH_NOT_FOUND) {
  60. // We need to make the parent directory first.
  61. string parent = get_dirname(dirname);
  62. if (!parent.empty() && mkdir_complete(parent)) {
  63. // Parent successfully created. Try again to make the child.
  64. if (CreateDirectory(dirname.c_str(), NULL) != 0) {
  65. // Got it!
  66. return true;
  67. }
  68. }
  69. }
  70. return false;
  71. #else //_WIN32
  72. if (mkdir(dirname.c_str(), 0777) == 0) {
  73. // Success!
  74. return true;
  75. }
  76. // Failed.
  77. if (errno == EEXIST) {
  78. // Not really an error: the directory is already there.
  79. return true;
  80. }
  81. if (errno == ENOENT) {
  82. // We need to make the parent directory first.
  83. string parent = get_dirname(dirname);
  84. if (!parent.empty() && mkdir_complete(parent)) {
  85. // Parent successfully created. Try again to make the child.
  86. if (mkdir(dirname.c_str(), 0777) == 0) {
  87. // Got it!
  88. return true;
  89. }
  90. }
  91. }
  92. return false;
  93. #endif // _WIN32
  94. }
  95. ////////////////////////////////////////////////////////////////////
  96. // Function: mkfile_complete
  97. // Description: Creates a new file with normal access
  98. // priviledges. Returns true on success, false on
  99. // failure. This will create intervening directories if
  100. // needed.
  101. ////////////////////////////////////////////////////////////////////
  102. bool
  103. mkfile_complete(const string &filename) {
  104. #ifdef _WIN32
  105. HANDLE file = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
  106. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  107. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  108. if (file == INVALID_HANDLE_VALUE) {
  109. // Try to make the parent directory first.
  110. string parent = get_dirname(filename);
  111. if (!parent.empty() && mkdir_complete(parent)) {
  112. // Parent successfully created. Try again to make the file.
  113. file = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
  114. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  115. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  116. }
  117. if (file == INVALID_HANDLE_VALUE) {
  118. return false;
  119. }
  120. }
  121. CloseHandle(file);
  122. return true;
  123. #else // _WIN32
  124. int fd = creat(filename.c_str(), 0777);
  125. if (fd == -1) {
  126. // Try to make the parent directory first.
  127. string parent = get_dirname(filename);
  128. if (!parent.empty() && mkdir_complete(parent)) {
  129. // Parent successfully created. Try again to make the file.
  130. fd = creat(filename.c_str(), 0777);
  131. }
  132. if (fd == -1) {
  133. return false;
  134. }
  135. }
  136. close(fd);
  137. return true;
  138. #endif // _WIN32
  139. }