#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>
#include <iostream>
using namespace std;
int main (int argc, char** argv)
{
int src; /* file descriptor for source file */
int dest; /* file descriptor for destination file */
struct stat stat_buf; /* hold information about input file */
off_t offset = 0; /* byte offset used by sendfile */
int rc; /* return code from sendfile */
/* check for two command line arguments */
if (argc != 3) {
fprintf(stderr, "usage: %s <source> <destination>\n", argv[0]);
exit(1);
}
/* check that source file exists and can be opened */
src = open(argv[1], O_RDONLY);
if (src == -1) {
fprintf(stderr, "unable to open '%s': %s\n", argv[1],
strerror(errno));
exit(1);
}
/* get size and permissions of the source file */
fstat(src, &stat_buf);
/* open destination file */
dest = open(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);
}
cout << "Stat_buf.st_size is " << stat_buf.st_size << endl;
/* copy file using sendfile */
rc = sendfile (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: %d of %d
bytes\n",
rc,
(int)stat_buf.st_size);
exit(1);
}
/* clean up and exit */
close(dest);
close(src);
return 0;
}
It keeps giving the following error:
Stat_buf.st_size is 1500
error from sendfile: Invalid argument
Which of the arguments to sendfile is wrong.I don't seem to be able to
place a finger on it!
Somebody please help.
Thanks
> It keeps giving the following error:
>
> Stat_buf.st_size is 1500
> error from sendfile: Invalid argument
>
> Which of the arguments to sendfile is wrong.I don't seem to be able to
> place a finger on it!
> Somebody please help.
Sadly, I think the problem is that the destination file is not on a
filesystem that implements 'sendpage', which is needed to be on the
receiving end of a 'sendfile'. AFAICT, ext2 and ext3 do not support
this.
It's this check in do_sendfile:
retval = -EINVAL;
if (!out_file->f_op || !out_file->f_op->sendpage)
goto fput_out;
Notice that the output file must have a 'sendpage' method.
DS
Why are you using 'sendfile' in the first place? It's an odd system
call. Just do things the normal way, using 'read' and 'write'. If you
want, you can leave the call to 'sendfile' as an optimization for when
it works, and fall back to other operations if it doesn't.
DS
The destination 'fd' must be a socket.
Here's a snip from the 'man' page:
<snip>
ssize_t
sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
...
Presently (Linux 2.6.9): in_fd, must correspond to a file which
supports mmap()-like operations (i.e., it cannot be a socket); and
out_fd must refer to a socket.
Applications may wish to fall back to read(2)/write(2) in the
case where sendfile() fails with EINVAL or ENOSYS.
...
In Linux 2.4 and earlier, out_fd could refer to a regular file,
and sendfile() changed the current offset of that file.
</snip>
Larry
Use a read/write loop.