core.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #include <errno.h>
  2. #include <dirent.h>
  3. #include <sys/stat.h>
  4. #include <unistd.h>
  5. #include <string.h>
  6. #include "lmdb.h"
  7. #include "volksdata/core.h"
  8. bool VOLK_env_is_init = false;
  9. /** @brief Warning messages.
  10. *
  11. * The message corresponding to the rc is found by
  12. * warning_msg[rc - VOLK_MIN_WARNING]. #VOLK_strerror() facilitates this.
  13. */
  14. char *warning_msg[] = {
  15. "VOLK_NOACTION: No action or change of state occurred.",
  16. "VOLK_NORESULT: No result.",
  17. "VOLK_END: End of the loop reached.",
  18. "VOLK_CONFLICT: A conflict prevented a resource from being updated.",
  19. };
  20. /** @brief error messages.
  21. *
  22. * Note that all error values are < 0 so it is possible to set conditions to
  23. * be triggered only by error return values.
  24. *
  25. * The message corresponding to the rc is found by
  26. * err_msg[rc - VOLK_MIN_ERROR]. #VOLK_strerror() facilitates this.
  27. */
  28. char *err_msg[] = {
  29. "VOLK_ERROR: Runtime error.",
  30. "VOLK_PARSE_ERR: Error parsing input.",
  31. "VOLK_VALUE_ERR: Invalid input.",
  32. "VOLK_TXN_ERR: MDB transaction error.",
  33. "VOLK_DB_ERR: Database error.",
  34. "VOLK_NOT_IMPL_ERR: Feature is not implemented.",
  35. "VOLK_IO_ERR: Input/Output error.",
  36. "VOLK_MEM_ERR: Memory error.",
  37. "VOLK_CONFLICT_ERR: A resource conflict interrupted the operation.",
  38. "VOLK_ENV_ERR: Environment not initialized. Did you call VOLK_init()?",
  39. };
  40. char *VOLK_root_path = __FILE__; // This is trimmed to root path on init.
  41. VOLK_rc
  42. mkdir_p (const char *_path, mode_t mode)
  43. {
  44. char *path = strdup (_path);
  45. char *p;
  46. // Trim any trailing slash(es).
  47. for (p = path + strlen (path) - 1; p > path; p--)
  48. if (*p == '/') *p = '\0';
  49. else break;
  50. errno = 0;
  51. VOLK_rc rc = VOLK_NOACTION;
  52. /* Iterate the string */
  53. for (p = path + 1; *p; p++) {
  54. if (*p == '/') {
  55. /* Temporarily truncate */
  56. *p = '\0';
  57. if (mkdir (path, mode) != 0 && errno != EEXIST) goto finally;
  58. *p = '/';
  59. }
  60. }
  61. if (mkdir (path, mode) != 0) {
  62. if (errno != EEXIST) rc = errno;
  63. } else {
  64. rc = VOLK_OK;
  65. }
  66. finally:
  67. LOG_TRACE("Path: %s", path);
  68. LOG_TRACE("errno: %d", errno);
  69. LOG_TRACE("rc: %d", rc);
  70. free (path);
  71. return rc;
  72. }
  73. char *
  74. strndup (const char *src, size_t max)
  75. {
  76. size_t len = strlen (src);
  77. if (len > max) len = max;
  78. char *dup;
  79. dup = malloc (len + 1);
  80. if (dup) {
  81. memcpy (dup, src, len);
  82. dup[len] = '\0';
  83. }
  84. return dup;
  85. }
  86. char *
  87. strdup (const char *src)
  88. {
  89. char *dup;
  90. dup = malloc (strlen (src) + 1);
  91. if (dup) strcpy(dup, src);
  92. return dup;
  93. }
  94. /** @brief Remove a directory recursively (POSIX compatible).
  95. *
  96. * Adapted from
  97. * https://stackoverflow.com/questions/5467725/how-to-delete-a-directory-and-its-contents-in-posix-c/42596507#42596507
  98. */
  99. VOLK_rc rm_r (const char *path)
  100. {
  101. size_t path_len;
  102. char *full_path;
  103. DIR *dir;
  104. struct stat stat_path, stat_entry;
  105. struct dirent *entry;
  106. // stat for the path
  107. stat(path, &stat_path);
  108. // if path does not exists or is not dir - exit with status -1
  109. if (S_ISDIR(stat_path.st_mode) == 0) {
  110. log_error ("%s: %s\n", "Is not directory", path);
  111. return VOLK_IO_ERR;
  112. }
  113. // if not possible to read the directory for this user
  114. if ((dir = opendir(path)) == NULL) {
  115. log_error ("%s: %s\n", "Can`t open directory", path);
  116. return VOLK_IO_ERR;
  117. }
  118. // the length of the path
  119. path_len = strlen(path);
  120. // iteration through entries in the directory
  121. while ((entry = readdir(dir)) != NULL) {
  122. // skip entries "." and ".."
  123. if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, ".."))
  124. continue;
  125. // determine a full path of an entry
  126. full_path = calloc(
  127. path_len + 1 + strlen(entry->d_name) + 1, sizeof(char));
  128. strcpy(full_path, path);
  129. strcat(full_path, "/");
  130. strcat(full_path, entry->d_name);
  131. // stat for the entry
  132. stat(full_path, &stat_entry);
  133. // recursively remove a nested directory
  134. if (S_ISDIR(stat_entry.st_mode) != 0) {
  135. rm_r (full_path);
  136. free (full_path);
  137. continue;
  138. }
  139. // remove a file object
  140. if (unlink(full_path) == 0)
  141. LOG_DEBUG ("Removed a file:\t%s\n", full_path);
  142. else
  143. log_error ("Can't remove a file:\t%s\n", full_path);
  144. free(full_path);
  145. }
  146. // remove the devastated directory and close the object of it
  147. if (rmdir(path) == 0)
  148. LOG_DEBUG ("Removed a directory:\t%s\n", path);
  149. else
  150. log_error ("Can't remove a directory:\t%s\n", path);
  151. closedir(dir);
  152. return VOLK_OK;
  153. }
  154. const char *
  155. VOLK_strerror (VOLK_rc rc)
  156. {
  157. if (rc >= VOLK_MIN_ERROR && rc <= VOLK_MAX_ERROR)
  158. return err_msg[rc - VOLK_MIN_ERROR];
  159. if (rc >= VOLK_MIN_WARNING && rc <= VOLK_MAX_WARNING)
  160. return warning_msg[rc - VOLK_MIN_WARNING];
  161. return mdb_strerror (rc);
  162. }
  163. /* Inline extern functions. */
  164. int utf8_encode (const uint32_t utf, unsigned char *out);