logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git

sha1sum.c (5733B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include "../lib/sha1.h" // sha1_*
  6. #include "../lib/strconv.h" // bytes2hex
  7. #include <assert.h>
  8. #include <ctype.h> // isxdigit
  9. #include <errno.h>
  10. #include <fcntl.h> // open, O_*
  11. #include <stdbool.h>
  12. #include <stdio.h> // fprintf
  13. #include <stdlib.h> // free
  14. #include <string.h> // strerror
  15. #include <unistd.h> // read, write, close, getopt
  16. #define SHA1SUM_LEN SHA1_DIGEST_LENGTH * 2 + 1
  17. const char *argv0 = "sha1sum";
  18. static int
  19. sha1sum(int fd, const char *fdname, char sum[SHA1SUM_LEN])
  20. {
  21. struct sha1 ctx;
  22. sha1_init(&ctx);
  23. uint8_t buf[BUFSIZ];
  24. ssize_t nread = -1;
  25. while((nread = read(fd, buf, BUFSIZ)) > 0)
  26. {
  27. sha1_update(&ctx, buf, nread);
  28. }
  29. if(nread < 0)
  30. {
  31. fprintf(stderr,
  32. "%s: error: Failed reading file '%s': %s\n",
  33. argv0,
  34. fdname ? fdname : "<stdin>",
  35. strerror(errno));
  36. return -1;
  37. }
  38. uint8_t res[SHA1_DIGEST_LENGTH] = "";
  39. sha1_sum(&ctx, res);
  40. bytes2hex(res, SHA1_DIGEST_LENGTH, sum, SHA1SUM_LEN);
  41. return 0;
  42. }
  43. #define STR(s) #s
  44. #define XSTR(s) STR(s)
  45. static int
  46. check(FILE *file, const char *filename)
  47. {
  48. int err = 0;
  49. ssize_t nread = -1;
  50. char *line = NULL;
  51. size_t len = 0;
  52. errno = 0;
  53. while((nread = getline(&line, &len, file)) > 0)
  54. {
  55. assert(errno == 0);
  56. if(line[nread - 1] == '\n') line[nread - 1] = '\0';
  57. ssize_t i = 0;
  58. for(; i < nread; i++)
  59. {
  60. if(isxdigit(line[i])) continue;
  61. if(line[i] == ' ')
  62. {
  63. line[i] = '\0';
  64. break;
  65. }
  66. fprintf(stderr,
  67. "%s: error: Invalid character '%c' while reading hash in line: %s\n",
  68. argv0,
  69. line[i],
  70. line);
  71. if(len > 0) free(line);
  72. return -1;
  73. }
  74. if(line[i++] != '\0')
  75. {
  76. fprintf(stderr, "%s: error: Invalid line: %s\n", argv0, line);
  77. if(len > 0) free(line);
  78. return -1;
  79. }
  80. if(i != SHA1SUM_LEN)
  81. {
  82. fprintf(stderr,
  83. "%s: error: Got %zd hexadecimal digits while expected %d for a SHA1\n",
  84. argv0,
  85. i,
  86. SHA1SUM_LEN);
  87. if(len > 0) free(line);
  88. return -1;
  89. }
  90. while(i < nread && line[i] == ' ')
  91. i++;
  92. if(i < nread && line[i] == '*') i++;
  93. char *target = line + i;
  94. int fd = open(target, O_RDONLY | O_NOCTTY);
  95. if(fd < 0)
  96. {
  97. fprintf(stderr, "%s: error: Failed opening file '%s': %s\n", argv0, target, strerror(errno));
  98. if(len > 0) free(line);
  99. return -1;
  100. }
  101. int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  102. if(ret != 0)
  103. fprintf(stderr,
  104. "%s: warning: posix_fadvise failed on file '%s': %s\n",
  105. argv0,
  106. target,
  107. strerror(ret));
  108. char got[SHA1SUM_LEN] = "";
  109. if(sha1sum(fd, target, got) < 0) err = 1;
  110. if(memcmp(line, got, SHA1SUM_LEN) == 0)
  111. {
  112. printf("%s: OK\n", target);
  113. }
  114. else
  115. {
  116. err = 1;
  117. printf("%s: FAILED\n", target);
  118. }
  119. if(close(fd) < 0)
  120. {
  121. fprintf(
  122. stderr, "%s: error: Failed closing file '%s': %s\n", argv0, filename, strerror(errno));
  123. if(len > 0) free(line);
  124. return -1;
  125. }
  126. }
  127. if(nread < 0 && errno != 0)
  128. {
  129. err = 1;
  130. fprintf(stderr,
  131. "%s: error: Failed reading line from file '%s': %s\n",
  132. argv0,
  133. filename,
  134. strerror(errno));
  135. }
  136. if(len > 0) free(line);
  137. return err;
  138. }
  139. int
  140. main(int argc, char *argv[])
  141. {
  142. bool opt_c = false;
  143. int c = -1;
  144. while((c = getopt(argc, argv, ":c")) != -1)
  145. {
  146. switch(c)
  147. {
  148. case 'c':
  149. opt_c = true;
  150. break;
  151. case ':':
  152. fprintf(stderr, "%s: error: Missing operand for option: '-%c'\n", argv0, optopt);
  153. return 1;
  154. case '?':
  155. fprintf(stderr, "%s: error: Unrecognised option: '-%c'\n", argv0, optopt);
  156. return 1;
  157. default:
  158. abort();
  159. }
  160. }
  161. argc -= optind;
  162. argv += optind;
  163. if(opt_c)
  164. {
  165. if(argc == 0)
  166. {
  167. if(check(stdin, "<stdin>") != 0) return 1;
  168. return 0;
  169. }
  170. int err = 0;
  171. for(int i = 0; i < argc; i++)
  172. {
  173. FILE *file = NULL;
  174. const char *filename = argv[i];
  175. if(filename[0] == '-' && filename[1] == '\0')
  176. {
  177. filename = "<stdin>";
  178. file = stdin;
  179. }
  180. else
  181. {
  182. file = fopen(filename, "rb");
  183. if(file == NULL)
  184. {
  185. fprintf(stderr,
  186. "%s: error: Failed opening file '%s': %s\n",
  187. argv0,
  188. filename,
  189. strerror(errno));
  190. return 1;
  191. }
  192. }
  193. if(check(file, filename) != 0) err = 1;
  194. if(fclose(file) < 0)
  195. {
  196. fprintf(
  197. stderr, "%s: error: Failed closing file '%s': %s\n", argv0, filename, strerror(errno));
  198. return 1;
  199. }
  200. }
  201. return err;
  202. }
  203. if(argc == 0)
  204. {
  205. char sum[SHA1SUM_LEN] = "";
  206. if(sha1sum(STDIN_FILENO, NULL, sum) < 0) return 1;
  207. puts(sum);
  208. return 0;
  209. }
  210. for(int i = 0; i < argc; i++)
  211. {
  212. int fd = -1;
  213. const char *filename = argv[i];
  214. if(filename[0] == '-' && filename[1] == '\0')
  215. {
  216. filename = "<stdin>";
  217. fd = STDIN_FILENO;
  218. }
  219. else
  220. {
  221. fd = open(filename, O_RDONLY | O_NOCTTY);
  222. if(fd < 0)
  223. {
  224. fprintf(
  225. stderr, "%s: error: Failed opening file '%s': %s\n", argv0, filename, strerror(errno));
  226. return 1;
  227. }
  228. int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  229. if(ret != 0)
  230. fprintf(stderr,
  231. "%s: warning: posix_fadvise failed on file '%s': %s\n",
  232. argv0,
  233. filename,
  234. strerror(ret));
  235. }
  236. int err = 0;
  237. char sum[SHA1SUM_LEN] = "";
  238. if(sha1sum(fd, filename, sum) < 0) err = 1;
  239. printf("%s %s\n", sum, filename);
  240. if(close(fd) < 0)
  241. {
  242. fprintf(
  243. stderr, "%s: error: Failed closing file '%s': %s\n", argv0, filename, strerror(errno));
  244. return 1;
  245. }
  246. if(err == 1) return 1;
  247. }
  248. return 0;
  249. }