diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c
index b4ff556..4b0665f 100644
--- a/obexd/plugins/filesystem.c
+++ b/obexd/plugins/filesystem.c
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
+#include <sys/sendfile.h>
#include <fcntl.h>
#include <wait.h>
return ret;
}
+static int filesystem_rename(const char *name, const char *destname)
+{
+ int ret;
+
+ ret = rename(name, destname);
+ if (ret < 0) {
+ error("rename(%s, %s): %s (%d)", name, destname,
+ strerror(errno), errno);
+ return -errno;
+ }
+
+ return ret;
+}
+
+static int sendfile_async(int out_fd, int in_fd, off_t *offset, size_t count)
+{
+ int pid;
+
+ /* Run sendfile on child process */
+ pid = fork();
+ switch (pid) {
+ case 0:
+ break;
+ case -1:
+ error("fork() %s (%d)", strerror(errno), errno);
+ return -errno;
+ default:
+ DBG("child %d forked", pid);
+ return pid;
+ }
+
+ /* At child */
+ if (sendfile(out_fd, in_fd, offset, count) < 0)
+ error("sendfile(): %s (%d)", strerror(errno), errno);
+
+ close(in_fd);
+ close(out_fd);
+
+ exit(errno);
+}
+
+static int filesystem_copy(const char *name, const char *destname)
+{
+ void *in, *out;
+ ssize_t ret;
+ size_t size;
+ struct stat st;
+ int in_fd, out_fd, err;
+
+ in = filesystem_open(name, O_RDONLY, 0, NULL, &size, &err);
+ if (in == NULL) {
+ error("open(%s): %s (%d)", name, strerror(-err), -err);
+ return -err;
+ }
+
+ in_fd = GPOINTER_TO_INT(in);
+ ret = fstat(in_fd, &st);
+ if (ret < 0) {
+ error("stat(%s): %s (%d)", name, strerror(errno), errno);
+ return -errno;
+ }
+
+ out = filesystem_open(destname, O_WRONLY | O_CREAT | O_TRUNC,
+ st.st_mode, NULL, &size, &err);
+ if (out == NULL) {
+ error("open(%s): %s (%d)", destname, strerror(-err), -err);
+ filesystem_close(in);
+ return -errno;
+ }
+
+ out_fd = GPOINTER_TO_INT(out);
+
+ /* Check if sendfile is supported */
+ ret = sendfile(out_fd, in_fd, NULL, 0);
+ if (ret < 0) {
+ ret = -errno;
+ error("sendfile: %s (%zd)", strerror(-ret), -ret);
+ goto done;
+ }
+
+ ret = sendfile_async(out_fd, in_fd, NULL, st.st_size);
+ if (ret < 0)
+ goto done;
+
+ return 0;
+
+done:
+ filesystem_close(in);
+ filesystem_close(out);
+
+ return ret;
+}
+
struct capability_object {
int pid;
int output;
.read = filesystem_read,
.write = filesystem_write,
.remove = remove,
+ .move = filesystem_rename,
+ .copy = filesystem_copy,
};
static struct obex_mime_type_driver capability = {