Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Problem Using sendfile()

683 views
Skip to first unread message

owolablo

unread,
Oct 4, 2006, 10:30:48 AM10/4/06
to
I'm trying to do a data transfer between two files.I have used the
following program:

#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

David Schwartz

unread,
Oct 4, 2006, 10:47:14 AM10/4/06
to

owolablo wrote:

> 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

owolablo

unread,
Oct 4, 2006, 10:59:34 AM10/4/06
to
Quite unfortunately, the destination file resides on an ext3 file
system.
Does this mean that there is no way of working around this?
What other functions can i use?

David Schwartz

unread,
Oct 4, 2006, 1:57:25 PM10/4/06
to

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

Larry Smith

unread,
Oct 4, 2006, 6:23:23 PM10/4/06
to

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

"Nils O. Selåsdal"

unread,
Oct 5, 2006, 2:08:37 AM10/5/06
to
Typically sendfile was just meant to work when the
destination is a socket. These days some additional
types of destination might implement it too, but it
varies.

Use a read/write loop.

0 new messages