Sendfile64 копирует только 2GB

Мне нужно использовать sendfile64 для копирования около 16 ГБ файлов. До сих пор я достиг

#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/sendfile.h>
#include <sys/stat.h>

int main (int argc, char** argv)
{
  long long src;
  long long dest;
  struct stat64 stat_buf;
  off64_t offset = 0LL;
  long long rc;

  if (argc != 3) {
    fprintf(stderr, "usage: %s <source> <destination>\n", argv[0]);
    exit(1);
  }

  src = open64(argv[1], O_RDONLY);
  if (src == -1) {
    fprintf(stderr, "unable to open '%s': %s\n", argv[1], strerror(errno));
    exit(1);
  }

  fstat64(src, &stat_buf);

  dest = open64(argv[2], O_WRONLY|O_CREAT, stat_buf.st_mode);
  if (dest == -1) {
    fprintf(stderr, "unable to open '%s': %s\n", argv[2], strerror(errno));
    exit(1);
  }

 /* copy file using sendfile */
 rc = sendfile64 (dest, src, &offset, stat_buf.st_size);
 if (rc == -1) {
    fprintf(stderr, "error from sendfile: %s\n", strerror(errno));
    exit(1);
 }
 if (rc != stat_buf.st_size) {
   fprintf(stderr, "incomplete transfer from sendfile: %lld of %lld bytes\n",
           rc,
           (long long)stat_buf.st_size);
   exit(1);
 }

 /* clean up and exit */
 close(dest);
 close(src);

 return 0;
}

Я скомпилировал с помощью

g++ BigCopy2.cpp -o BigCopy2 -D_FILE_OFFSET_BITS=64 -DLARGEFILE64_SOURCE

Проблема в том, что я все еще не могу скопировать более 2 ГБ файла.

Может кто-нибудь указать мне, где моя ошибка?

Ответ 1

Вы должны использовать цикл для его копирования, sendfile() может по различным причинам не копировать все данные с одним вызовом. Как указывает janneb, возвращаемое значение sendfile64 является ssize_t, поэтому мы не должны передавать более SSIZE_MAX для sendfile, причем последним аргументом sendfile является size_t, который будет 32-битным на 32-битных платформах.

 /* copy file using sendfile */
while (offset < stat_buf.st_size) {
  size_t count;
  off64_t remaining = stat_buf.st_size- offset;
  if (remaining > SSIZE_MAX)
      count = SSIZE_MAX;
   else 
      count = remaining;
  rc = sendfile64 (dest, src, &offset, count);
  if (rc == 0) {
     break;
  }
  if (rc == -1) {
     fprintf(stderr, "error from sendfile: %s\n", strerror(errno));
     exit(1);
  }
}

 if (offset != stat_buf.st_size) {
   fprintf(stderr, "incomplete transfer from sendfile: %lld of %lld bytes\n",
           rc,
           (long long)stat_buf.st_size);
   exit(1);
 }

Обратите внимание, что вы можете заменить все ваши 64-битные варианты, off64_t, stat64, sendfile64, с off_t, stat, sendfile. Пока у вас есть флаг -D_FILE_OFFSET_BITS=64, этот определитель выполнит правильную работу и преобразует off_t в off64_t, sendfile в sendfile64 и т.д., Если эти типы и функции еще не 64 бит (например, на 32-битных архитектурах).