io.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. This file is part of ethash.
  3. ethash is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. ethash is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with ethash. If not, see <http://www.gnu.org/licenses/>.
  13. */
  14. /** @file io.h
  15. * @author Lefteris Karapetsas <lefteris@ethdev.com>
  16. * @date 2015
  17. */
  18. #pragma once
  19. #include <stdlib.h>
  20. #include <stdint.h>
  21. #include <stdbool.h>
  22. #include <stdio.h>
  23. #ifdef __cplusplus
  24. #define __STDC_FORMAT_MACROS 1
  25. #endif
  26. #include <inttypes.h>
  27. #include "endian.h"
  28. #include "ethash.h"
  29. #ifdef __cplusplus
  30. extern "C" {
  31. #endif
  32. // Maximum size for mutable part of DAG file name
  33. // 6 is for "full-R", the suffix of the filename
  34. // 10 is for maximum number of digits of a uint32_t (for REVISION)
  35. // 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of
  36. // the seedhash and last 1 is for the null terminating character
  37. // Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG
  38. #define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1)
  39. /// Possible return values of @see ethash_io_prepare
  40. enum ethash_io_rc {
  41. ETHASH_IO_FAIL = 0, ///< There has been an IO failure
  42. ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong.
  43. ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch
  44. ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything
  45. };
  46. // small hack for windows. I don't feel I should use va_args and forward just
  47. // to have this one function properly cross-platform abstracted
  48. #if defined(_WIN32) && !defined(__GNUC__)
  49. #define snprintf(...) sprintf_s(__VA_ARGS__)
  50. #endif
  51. /**
  52. * Logs a critical error in important parts of ethash. Should mostly help
  53. * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL
  54. * ethash_full_t
  55. */
  56. #ifdef ETHASH_PRINT_CRITICAL_OUTPUT
  57. #define ETHASH_CRITICAL(...) \
  58. do \
  59. { \
  60. printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \
  61. printf("\n"); \
  62. fflush(stdout); \
  63. } while (0)
  64. #else
  65. #define ETHASH_CRITICAL(...)
  66. #endif
  67. /**
  68. * Prepares io for ethash
  69. *
  70. * Create the DAG directory and the DAG file if they don't exist.
  71. *
  72. * @param[in] dirname A null terminated c-string of the path of the ethash
  73. * data directory. If it does not exist it's created.
  74. * @param[in] seedhash The seedhash of the current block number, used in the
  75. * naming of the file as can be seen from the spec at:
  76. * https://github.com/ethereum/wiki/wiki/Ethash-DAG
  77. * @param[out] output_file If there was no failure then this will point to an open
  78. * file descriptor. User is responsible for closing it.
  79. * In the case of memo match then the file is open on read
  80. * mode, while on the case of mismatch a new file is created
  81. * on write mode
  82. * @param[in] file_size The size that the DAG file should have on disk
  83. * @param[out] force_create If true then there is no check to see if the file
  84. * already exists
  85. * @return For possible return values @see enum ethash_io_rc
  86. */
  87. enum ethash_io_rc ethash_io_prepare(
  88. char const* dirname,
  89. ethash_h256_t const seedhash,
  90. FILE** output_file,
  91. uint64_t file_size,
  92. bool force_create
  93. );
  94. /**
  95. * An fopen wrapper for no-warnings crossplatform fopen.
  96. *
  97. * Msvc compiler considers fopen to be insecure and suggests to use their
  98. * alternative. This is a wrapper for this alternative. Another way is to
  99. * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
  100. * not sound like a good idea.
  101. *
  102. * @param file_name The path to the file to open
  103. * @param mode Opening mode. Check fopen()
  104. * @return The FILE* or NULL in failure
  105. */
  106. FILE* ethash_fopen(char const* file_name, char const* mode);
  107. /**
  108. * An strncat wrapper for no-warnings crossplatform strncat.
  109. *
  110. * Msvc compiler considers strncat to be insecure and suggests to use their
  111. * alternative. This is a wrapper for this alternative. Another way is to
  112. * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does
  113. * not sound like a good idea.
  114. *
  115. * @param des Destination buffer
  116. * @param dest_size Maximum size of the destination buffer. This is the
  117. * extra argument for the MSVC secure strncat
  118. * @param src Souce buffer
  119. * @param count Number of bytes to copy from source
  120. * @return If all is well returns the dest buffer. If there is an
  121. * error returns NULL
  122. */
  123. char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count);
  124. /**
  125. * A cross-platform mkdir wrapper to create a directory or assert it's there
  126. *
  127. * @param dirname The full path of the directory to create
  128. * @return true if the directory was created or if it already
  129. * existed
  130. */
  131. bool ethash_mkdir(char const* dirname);
  132. /**
  133. * Get a file's size
  134. *
  135. * @param[in] f The open file stream whose size to get
  136. * @param[out] size Pass a size_t by reference to contain the file size
  137. * @return true in success and false if there was a failure
  138. */
  139. bool ethash_file_size(FILE* f, size_t* ret_size);
  140. /**
  141. * Get a file descriptor number from a FILE stream
  142. *
  143. * @param f The file stream whose fd to get
  144. * @return Platform specific fd handler
  145. */
  146. int ethash_fileno(FILE* f);
  147. /**
  148. * Create the filename for the DAG.
  149. *
  150. * @param dirname The directory name in which the DAG file should reside
  151. * If it does not end with a directory separator it is appended.
  152. * @param filename The actual name of the file
  153. * @param filename_length The length of the filename in bytes
  154. * @return A char* containing the full name. User must deallocate.
  155. */
  156. char* ethash_io_create_filename(
  157. char const* dirname,
  158. char const* filename,
  159. size_t filename_length
  160. );
  161. /**
  162. * Gets the default directory name for the DAG depending on the system
  163. *
  164. * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG
  165. *
  166. * @param[out] strbuf A string buffer of sufficient size to keep the
  167. * null termninated string of the directory name
  168. * @param[in] buffsize Size of @a strbuf in bytes
  169. * @return true for success and false otherwise
  170. */
  171. bool ethash_get_default_dirname(char* strbuf, size_t buffsize);
  172. static inline bool ethash_io_mutable_name(
  173. uint32_t revision,
  174. ethash_h256_t const* seed_hash,
  175. char* output
  176. )
  177. {
  178. uint64_t hash = *((uint64_t*)seed_hash);
  179. #if LITTLE_ENDIAN == BYTE_ORDER
  180. hash = ethash_swap_u64(hash);
  181. #endif
  182. return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0;
  183. }
  184. #ifdef __cplusplus
  185. }
  186. #endif