logo

utils-std

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

sha1sum.c (5334B)


  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. 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. "sha1sum: I/O Error while reading file '%s': %s\n",
  32. fdname ? fdname : "<stdin>",
  33. strerror(errno));
  34. return -1;
  35. }
  36. uint8_t res[SHA1_DIGEST_LENGTH] = "";
  37. sha1_sum(&ctx, res);
  38. bytes2hex(res, SHA1_DIGEST_LENGTH, sum, SHA1SUM_LEN);
  39. return 0;
  40. }
  41. #define STR(s) #s
  42. #define XSTR(s) STR(s)
  43. static int
  44. check(FILE *file, const char *filename)
  45. {
  46. int err = 0;
  47. ssize_t nread = -1;
  48. char *line = NULL;
  49. size_t len = 0;
  50. errno = 0;
  51. while((nread = getline(&line, &len, file)) > 0)
  52. {
  53. assert(errno == 0);
  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. "sha1sum: Error: Invalid character '%c' while reading hash in line: %s\n",
  66. line[i],
  67. line);
  68. if(len > 0) free(line);
  69. return -1;
  70. }
  71. if(line[i++] != '\0')
  72. {
  73. fprintf(stderr, "sha1sum: Error: Invalid line: %s\n", line);
  74. if(len > 0) free(line);
  75. return -1;
  76. }
  77. if(i != SHA1SUM_LEN)
  78. {
  79. fprintf(stderr,
  80. "sha1sum: Error: Got %zd hexadecimal digits while expected %d for a SHA1\n",
  81. i,
  82. SHA1SUM_LEN);
  83. if(len > 0) free(line);
  84. return -1;
  85. }
  86. while(i < nread && line[i] == ' ')
  87. i++;
  88. if(i < nread && line[i] == '*') i++;
  89. char *target = line + i;
  90. int fd = open(target, O_RDONLY | O_NOCTTY);
  91. if(fd < 0)
  92. {
  93. fprintf(stderr, "sha1sum: Error: Failed opening file '%s': %s\n", target, strerror(errno));
  94. if(len > 0) free(line);
  95. return -1;
  96. }
  97. int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  98. if(ret != 0)
  99. fprintf(stderr,
  100. "sha1sum: Warning: posix_fadvise failed on file '%s': %s\n",
  101. target,
  102. strerror(ret));
  103. char got[SHA1SUM_LEN] = "";
  104. if(sha1sum(fd, target, got) < 0) err = 1;
  105. if(memcmp(line, got, SHA1SUM_LEN) == 0)
  106. {
  107. printf("%s: OK\n", target);
  108. }
  109. else
  110. {
  111. err = 1;
  112. printf("%s: FAILED\n", target);
  113. }
  114. if(close(fd) < 0)
  115. {
  116. fprintf(stderr, "sha1sum: Failed closing file '%s': %s\n", filename, strerror(errno));
  117. if(len > 0) free(line);
  118. return -1;
  119. }
  120. }
  121. if(nread < 0 && errno != 0)
  122. {
  123. err = 1;
  124. fprintf(stderr, "sha1sum: Failed reading line from file '%s': %s\n", filename, strerror(errno));
  125. }
  126. if(len > 0) free(line);
  127. return err;
  128. }
  129. int
  130. main(int argc, char *argv[])
  131. {
  132. bool opt_c = false;
  133. int c = -1;
  134. while((c = getopt(argc, argv, "c")) != -1)
  135. {
  136. switch(c)
  137. {
  138. case 'c':
  139. opt_c = true;
  140. break;
  141. default:
  142. fprintf(stderr, "sha1sum: Unhandled option '-%c'\n", c);
  143. return 1;
  144. }
  145. }
  146. argc -= optind;
  147. argv += optind;
  148. if(opt_c)
  149. {
  150. if(argc == 0)
  151. {
  152. if(check(stdin, "<stdin>") != 0) return 1;
  153. return 0;
  154. }
  155. int err = 0;
  156. for(int i = 0; i < argc; i++)
  157. {
  158. FILE *file = NULL;
  159. const char *filename = argv[i];
  160. if(filename[0] == '-' && filename[1] == '\0')
  161. {
  162. filename = "<stdin>";
  163. file = stdin;
  164. }
  165. else
  166. {
  167. file = fopen(filename, "rb");
  168. if(file == NULL)
  169. {
  170. fprintf(
  171. stderr, "sha1sum: Error: Failed opening file '%s': %s\n", filename, strerror(errno));
  172. return 1;
  173. }
  174. }
  175. if(check(file, filename) != 0) err = 1;
  176. if(fclose(file) < 0)
  177. {
  178. fprintf(stderr, "sha1sum: Failed closing file '%s': %s\n", filename, strerror(errno));
  179. return 1;
  180. }
  181. }
  182. return err;
  183. }
  184. if(argc == 0)
  185. {
  186. char sum[SHA1SUM_LEN] = "";
  187. if(sha1sum(STDIN_FILENO, NULL, sum) < 0) return 1;
  188. puts(sum);
  189. return 0;
  190. }
  191. for(int i = 0; i < argc; i++)
  192. {
  193. int fd = -1;
  194. const char *filename = argv[i];
  195. if(filename[0] == '-' && filename[1] == '\0')
  196. {
  197. filename = "<stdin>";
  198. fd = STDIN_FILENO;
  199. }
  200. else
  201. {
  202. fd = open(filename, O_RDONLY | O_NOCTTY);
  203. if(fd < 0)
  204. {
  205. fprintf(
  206. stderr, "sha1sum: Error: Failed opening file '%s': %s\n", filename, strerror(errno));
  207. return 1;
  208. }
  209. int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  210. if(ret != 0)
  211. fprintf(stderr,
  212. "sha1sum: Warning: posix_fadvise failed on file '%s': %s\n",
  213. filename,
  214. strerror(ret));
  215. }
  216. int err = 0;
  217. char sum[SHA1SUM_LEN] = "";
  218. if(sha1sum(fd, filename, sum) < 0) err = 1;
  219. printf("%s %s\n", sum, filename);
  220. if(close(fd) < 0)
  221. {
  222. fprintf(stderr, "sha1sum: Failed closing file '%s': %s\n", filename, strerror(errno));
  223. return 1;
  224. }
  225. if(err == 1) return 1;
  226. }
  227. return 0;
  228. }