logo

utils-std

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

sha1sum.c (5691B)


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