#include #include #include #include #include #include "lmdb.h" #include "volksdata/core.h" bool VOLK_env_is_init = false; /** @brief Warning messages. * * The message corresponding to the rc is found by * warning_msg[rc - VOLK_MIN_WARNING]. #VOLK_strerror() facilitates this. */ char *warning_msg[] = { "VOLK_NOACTION: No action or change of state occurred.", "VOLK_NORESULT: No result.", "VOLK_END: End of the loop reached.", "VOLK_CONFLICT: A conflict prevented a resource from being updated.", }; /** @brief error messages. * * Note that all error values are < 0 so it is possible to set conditions to * be triggered only by error return values. * * The message corresponding to the rc is found by * err_msg[rc - VOLK_MIN_ERROR]. #VOLK_strerror() facilitates this. */ char *err_msg[] = { "VOLK_ERROR: Runtime error.", "VOLK_PARSE_ERR: Error parsing input.", "VOLK_VALUE_ERR: Invalid input.", "VOLK_TXN_ERR: MDB transaction error.", "VOLK_DB_ERR: Database error.", "VOLK_NOT_IMPL_ERR: Feature is not implemented.", "VOLK_IO_ERR: Input/Output error.", "VOLK_MEM_ERR: Memory error.", "VOLK_CONFLICT_ERR: A resource conflict interrupted the operation.", "VOLK_ENV_ERR: Environment not initialized. Did you call VOLK_init()?", }; char *VOLK_root_path = __FILE__; // This is trimmed to root path on init. VOLK_rc mkdir_p (const char *_path, mode_t mode) { char *path = strdup (_path); char *p; // Trim any trailing slash(es). for (p = path + strlen (path) - 1; p > path; p--) if (*p == '/') *p = '\0'; else break; errno = 0; VOLK_rc rc = VOLK_NOACTION; /* Iterate the string */ for (p = path + 1; *p; p++) { if (*p == '/') { /* Temporarily truncate */ *p = '\0'; if (mkdir (path, mode) != 0 && errno != EEXIST) goto finally; *p = '/'; } } if (mkdir (path, mode) != 0) { if (errno != EEXIST) rc = errno; } else { rc = VOLK_OK; } finally: LOG_TRACE("Path: %s", path); LOG_TRACE("errno: %d", errno); LOG_TRACE("rc: %d", rc); free (path); return rc; } char * strndup (const char *src, size_t max) { size_t len = strlen (src); if (len > max) len = max; char *dup; dup = malloc (len + 1); if (dup) { memcpy (dup, src, len); dup[len] = '\0'; } return dup; } char * strdup (const char *src) { char *dup; dup = malloc (strlen (src) + 1); if (dup) strcpy(dup, src); return dup; } /** @brief Remove a directory recursively (POSIX compatible). * * Adapted from * https://stackoverflow.com/questions/5467725/how-to-delete-a-directory-and-its-contents-in-posix-c/42596507#42596507 */ VOLK_rc rm_r (const char *path) { size_t path_len; char *full_path; DIR *dir; struct stat stat_path, stat_entry; struct dirent *entry; // stat for the path stat(path, &stat_path); // if path does not exists or is not dir - exit with status -1 if (S_ISDIR(stat_path.st_mode) == 0) { log_error ("%s: %s\n", "Is not directory", path); return VOLK_IO_ERR; } // if not possible to read the directory for this user if ((dir = opendir(path)) == NULL) { log_error ("%s: %s\n", "Can`t open directory", path); return VOLK_IO_ERR; } // the length of the path path_len = strlen(path); // iteration through entries in the directory while ((entry = readdir(dir)) != NULL) { // skip entries "." and ".." if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue; // determine a full path of an entry full_path = calloc( path_len + 1 + strlen(entry->d_name) + 1, sizeof(char)); strcpy(full_path, path); strcat(full_path, "/"); strcat(full_path, entry->d_name); // stat for the entry stat(full_path, &stat_entry); // recursively remove a nested directory if (S_ISDIR(stat_entry.st_mode) != 0) { rm_r (full_path); free (full_path); continue; } // remove a file object if (unlink(full_path) == 0) LOG_DEBUG ("Removed a file:\t%s\n", full_path); else log_error ("Can't remove a file:\t%s\n", full_path); free(full_path); } // remove the devastated directory and close the object of it if (rmdir(path) == 0) LOG_DEBUG ("Removed a directory:\t%s\n", path); else log_error ("Can't remove a directory:\t%s\n", path); closedir(dir); return VOLK_OK; } const char * VOLK_strerror (VOLK_rc rc) { if (rc >= VOLK_MIN_ERROR && rc <= VOLK_MAX_ERROR) return err_msg[rc - VOLK_MIN_ERROR]; if (rc >= VOLK_MIN_WARNING && rc <= VOLK_MAX_WARNING) return warning_msg[rc - VOLK_MIN_WARNING]; return mdb_strerror (rc); } /* Inline extern functions. */ int utf8_encode (const uint32_t utf, unsigned char *out);