copyfd.c 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * Utility routines.
  4. *
  5. * Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
  6. *
  7. * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  8. */
  9. #include "libbb.h"
  10. /* Used by NOFORK applets (e.g. cat) - must not use xmalloc */
  11. static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
  12. {
  13. int status = -1;
  14. off_t total = 0;
  15. #if CONFIG_FEATURE_COPYBUF_KB <= 4
  16. char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024];
  17. enum { buffer_size = sizeof(buffer) };
  18. #else
  19. char *buffer;
  20. int buffer_size;
  21. /* We want page-aligned buffer, just in case kernel is clever
  22. * and can do page-aligned io more efficiently */
  23. buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024,
  24. PROT_READ | PROT_WRITE,
  25. MAP_PRIVATE | MAP_ANON,
  26. /* ignored: */ -1, 0);
  27. buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
  28. if (buffer == MAP_FAILED) {
  29. buffer = alloca(4 * 1024);
  30. buffer_size = 4 * 1024;
  31. }
  32. #endif
  33. if (src_fd < 0)
  34. goto out;
  35. if (!size) {
  36. size = buffer_size;
  37. status = 1; /* copy until eof */
  38. }
  39. while (1) {
  40. ssize_t rd;
  41. rd = safe_read(src_fd, buffer, size > buffer_size ? buffer_size : size);
  42. if (!rd) { /* eof - all done */
  43. status = 0;
  44. break;
  45. }
  46. if (rd < 0) {
  47. bb_perror_msg(bb_msg_read_error);
  48. break;
  49. }
  50. /* dst_fd == -1 is a fake, else... */
  51. if (dst_fd >= 0) {
  52. ssize_t wr = full_write(dst_fd, buffer, rd);
  53. if (wr < rd) {
  54. bb_perror_msg(bb_msg_write_error);
  55. break;
  56. }
  57. }
  58. total += rd;
  59. if (status < 0) { /* if we aren't copying till EOF... */
  60. size -= rd;
  61. if (!size) {
  62. /* 'size' bytes copied - all done */
  63. status = 0;
  64. break;
  65. }
  66. }
  67. }
  68. out:
  69. #if CONFIG_FEATURE_COPYBUF_KB > 4
  70. if (buffer_size != 4 * 1024)
  71. munmap(buffer, buffer_size);
  72. #endif
  73. return status ? -1 : total;
  74. }
  75. #if 0
  76. void FAST_FUNC complain_copyfd_and_die(off_t sz)
  77. {
  78. if (sz != -1)
  79. bb_error_msg_and_die("short read");
  80. /* if sz == -1, bb_copyfd_XX already complained */
  81. xfunc_die();
  82. }
  83. #endif
  84. off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size)
  85. {
  86. if (size) {
  87. return bb_full_fd_action(fd1, fd2, size);
  88. }
  89. return 0;
  90. }
  91. void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size)
  92. {
  93. off_t sz = bb_copyfd_size(fd1, fd2, size);
  94. if (sz == size)
  95. return;
  96. if (sz != -1)
  97. bb_error_msg_and_die("short read");
  98. /* if sz == -1, bb_copyfd_XX already complained */
  99. xfunc_die();
  100. }
  101. off_t FAST_FUNC bb_copyfd_eof(int fd1, int fd2)
  102. {
  103. return bb_full_fd_action(fd1, fd2, 0);
  104. }