sum.c 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. /*
  2. * sum -- checksum and count the blocks in a file
  3. * Like BSD sum or SysV sum -r, except like SysV sum if -s option is given.
  4. *
  5. * Copyright (C) 86, 89, 91, 1995-2002, 2004 Free Software Foundation, Inc.
  6. * Copyright (C) 2005 by Erik Andersen <andersen@codepoet.org>
  7. * Copyright (C) 2005 by Mike Frysinger <vapier@gentoo.org>
  8. *
  9. * Written by Kayvan Aghaiepour and David MacKenzie
  10. * Taken from coreutils and turned into a busybox applet by Mike Frysinger
  11. *
  12. * This program is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version.
  16. *
  17. * This program is distributed in the hope that it will be useful,
  18. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  20. * General Public License for more details.
  21. *
  22. * You should have received a copy of the GNU General Public License
  23. * along with this program; if not, write to the Free Software
  24. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  25. *
  26. */
  27. #include <stdio.h>
  28. #include <sys/types.h>
  29. #include <sys/stat.h>
  30. #include <fcntl.h>
  31. #include <unistd.h>
  32. #include <getopt.h>
  33. #include "libbb.h"
  34. /* 1 if any of the files read were the standard input */
  35. static int have_read_stdin;
  36. /* make a little more readable and avoid using strcmp for just 2 bytes */
  37. #define IS_STDIN(s) (s[0] == '-' && s[1] == '\0')
  38. /* Calculate and print the rotated checksum and the size in 1K blocks
  39. of file FILE, or of the standard input if FILE is "-".
  40. If PRINT_NAME is >1, print FILE next to the checksum and size.
  41. The checksum varies depending on sizeof (int).
  42. Return 1 if successful. */
  43. static int bsd_sum_file(const char *file, int print_name)
  44. {
  45. register FILE *fp;
  46. register int checksum = 0; /* The checksum mod 2^16. */
  47. register uintmax_t total_bytes = 0; /* The number of bytes. */
  48. register int ch; /* Each character read. */
  49. if (IS_STDIN(file)) {
  50. fp = stdin;
  51. have_read_stdin = 1;
  52. } else {
  53. fp = bb_wfopen(file, "r");
  54. if (fp == NULL)
  55. return 0;
  56. }
  57. while ((ch = getc(fp)) != EOF) {
  58. ++total_bytes;
  59. checksum = (checksum >> 1) + ((checksum & 1) << 15);
  60. checksum += ch;
  61. checksum &= 0xffff; /* Keep it within bounds. */
  62. }
  63. if (ferror(fp)) {
  64. bb_perror_msg(file);
  65. bb_fclose_nonstdin(fp);
  66. return 0;
  67. }
  68. if (bb_fclose_nonstdin(fp) == EOF) {
  69. bb_perror_msg(file);
  70. return 0;
  71. }
  72. printf("%05d %5s ", checksum,
  73. make_human_readable_str(total_bytes, 1, 1024));
  74. if (print_name > 1)
  75. puts(file);
  76. else
  77. printf("\n");
  78. return 1;
  79. }
  80. /* Calculate and print the checksum and the size in 512-byte blocks
  81. of file FILE, or of the standard input if FILE is "-".
  82. If PRINT_NAME is >0, print FILE next to the checksum and size.
  83. Return 1 if successful. */
  84. static int sysv_sum_file(const char *file, int print_name)
  85. {
  86. int fd;
  87. unsigned char buf[8192];
  88. uintmax_t total_bytes = 0;
  89. int r;
  90. int checksum;
  91. /* The sum of all the input bytes, modulo (UINT_MAX + 1). */
  92. unsigned int s = 0;
  93. if (IS_STDIN(file)) {
  94. fd = 0;
  95. have_read_stdin = 1;
  96. } else {
  97. fd = open(file, O_RDONLY);
  98. if (fd == -1) {
  99. bb_perror_msg(file);
  100. return 0;
  101. }
  102. }
  103. while (1) {
  104. size_t i;
  105. size_t bytes_read = safe_read(fd, buf, sizeof(buf));
  106. if (bytes_read == 0)
  107. break;
  108. if (bytes_read == -1) {
  109. bb_perror_msg(file);
  110. if (!IS_STDIN(file))
  111. close(fd);
  112. return 0;
  113. }
  114. for (i = 0; i < bytes_read; i++)
  115. s += buf[i];
  116. total_bytes += bytes_read;
  117. }
  118. if (!IS_STDIN(file) && close(fd) == -1) {
  119. bb_perror_msg(file);
  120. return 0;
  121. }
  122. r = (s & 0xffff) + ((s & 0xffffffff) >> 16);
  123. checksum = (r & 0xffff) + (r >> 16);
  124. printf("%d %s ", checksum,
  125. make_human_readable_str(total_bytes, 1, 512));
  126. if (print_name)
  127. puts(file);
  128. else
  129. printf("\n");
  130. return 1;
  131. }
  132. int sum_main(int argc, char **argv)
  133. {
  134. int flags;
  135. int ok;
  136. int files_given;
  137. int (*sum_func)(const char *, int) = bsd_sum_file;
  138. /* give the bsd func priority over sysv func */
  139. flags = bb_getopt_ulflags(argc, argv, "sr");
  140. if (flags & 1)
  141. sum_func = sysv_sum_file;
  142. if (flags & 2)
  143. sum_func = bsd_sum_file;
  144. have_read_stdin = 0;
  145. files_given = argc - optind;
  146. if (files_given <= 0)
  147. ok = sum_func("-", files_given);
  148. else
  149. for (ok = 1; optind < argc; optind++)
  150. ok &= sum_func(argv[optind], files_given);
  151. if (have_read_stdin && fclose(stdin) == EOF)
  152. bb_perror_msg_and_die("-");
  153. exit(ok ? EXIT_SUCCESS : EXIT_FAILURE);
  154. }