Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

sendfile64 only copy about 2GB

I need to use sendfile64 to copy about 16GB of files. What I have achieved so far is

#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;
}

I have compiled using

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

The problem is I still can't copy more than 2GB of file.

Can someone point me where is my mistake?

like image 437
Ste Avatar asked Mar 13 '14 08:03

Ste


Video Answer


1 Answers

You should use a loop to copy it all, sendfile() might, for various reasons, not copy all the data with one call. As janneb points out, the return value of sendfile64 is a ssize_t, so we should not pass in more than SSIZE_MAX to sendfile, moreover the last argument to sendfile is a size_t which would be 32 bit on 32 bit platforms.

 /* 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);
 }

Note that you can replace all your 64 bit variants, off64_t, stat64, sendfile64, with off_t, stat, sendfile. As long as you have the -D_FILE_OFFSET_BITS=64 flag, that define will do the right thing and transform off_t to off64_t, sendfile to sendfile64 and so on if those types and functions are not already 64 bits (such as on 32 bit architectures).

like image 65
nos Avatar answered Sep 17 '22 12:09

nos