diff --git a/Makefile.posix b/Makefile.posix index 2766c91..34b5014 100644 --- a/Makefile.posix +++ b/Makefile.posix @@ -21,6 +21,7 @@ VERSION_TAG := $(shell git describe --abbrev=6 --dirty --always --tags) CFLAGS := -Wall -Werror -DVERSION_TAG=\"$(VERSION_TAG)\" -I. SOURCE := srv.c cmd.c notify.c io.c self.c sha256.c SOURCE += posix/main.c posix/cmd.c posix/self.c +SOURCE += io-linux.c all: $(ELF) diff --git a/Makefile.ps4 b/Makefile.ps4 index 80f18a9..b067d89 100644 --- a/Makefile.ps4 +++ b/Makefile.ps4 @@ -30,6 +30,7 @@ VERSION_TAG := $(shell git describe --abbrev=6 --dirty --always --tags) CFLAGS := -Wall -Werror -DVERSION_TAG=\"$(VERSION_TAG)\" -I. SOURCE := srv.c cmd.c notify.c io.c self.c sha256.c SOURCE += orbis/main.c orbis/cmd.c orbis/self.c +SOURCE += io-freebsd.c all: $(ELF) diff --git a/Makefile.ps5 b/Makefile.ps5 index 1ebad14..8d54b9b 100644 --- a/Makefile.ps5 +++ b/Makefile.ps5 @@ -30,6 +30,7 @@ VERSION_TAG := $(shell git describe --abbrev=6 --dirty --always --tags) CFLAGS := -Wall -Werror -DVERSION_TAG=\"$(VERSION_TAG)\" -I. SOURCE := srv.c cmd.c notify.c io.c self.c sha256.c SOURCE += prospero/main.c prospero/cmd.c prospero/self.c +SOURCE += io-freebsd.c all: $(ELF) diff --git a/cmd.c b/cmd.c index 0756f8f..d32d1ce 100644 --- a/cmd.c +++ b/cmd.c @@ -19,6 +19,7 @@ along with this program; see the file COPYING. If not, see #include #include #include +#include #include #include #include @@ -518,9 +519,6 @@ ftp_cmd_RETR_fd(ftp_env_t *env, int fd) { if(fstat(fd, &st)) { return ftp_perror(env); } - if(lseek(fd, off, SEEK_SET) < 0) { - return ftp_perror(env); - } if(ftp_active_printf(env, "150 Starting data transfer\r\n")) { return -1; @@ -530,16 +528,18 @@ ftp_cmd_RETR_fd(ftp_env_t *env, int fd) { return ftp_perror(env); } - if(io_ncopy(fd, env->data_fd, st.st_size - off)) { - err = ftp_perror(env); - ftp_data_close(env); - return err; - } + err = io_sendfile(fd, env->data_fd, off, st.st_size - off); if(ftp_data_close(env)) { return ftp_perror(env); } + if(err) { + return ftp_perror(env); + } + + env->data_offset = 0; + return ftp_active_printf(env, "226 Transfer completed\r\n"); } diff --git a/io-freebsd.c b/io-freebsd.c new file mode 100644 index 0000000..1647ef4 --- /dev/null +++ b/io-freebsd.c @@ -0,0 +1,55 @@ +/* Copyright (C) 2026 John Törnblom + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, see +. */ + +#include + +#include +#include + +#include "io.h" + + +int +io_sendfile(int fd, int s, off_t offset, size_t n) { + off_t copied = 0; + off_t sbytes = 0; + size_t nbytes; + + while (copied < n) { + nbytes = n - copied; + if(nbytes > IO_COPY_BUFSIZE) { + nbytes = IO_COPY_BUFSIZE; + } + + if(sendfile(fd, s, offset, nbytes, 0, &sbytes, 0) < 0) { + if(errno == EINTR) { + continue; + } + return -1; + } + + if(sbytes == 0) { + errno = EPIPE; + return -1; + } + + copied += sbytes; + offset += sbytes; + } + + return 0; +} + diff --git a/io-linux.c b/io-linux.c new file mode 100644 index 0000000..c19737a --- /dev/null +++ b/io-linux.c @@ -0,0 +1,53 @@ +/* Copyright (C) 2026 John Törnblom + +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 3, or (at your option) any +later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, see +. */ + +#include + +#include +#include + +#include "io.h" + + +int +io_sendfile(int in_fd, int out_fd, off_t offset, size_t n) { + off_t copied = 0; + size_t count; + ssize_t r; + + while (copied < n) { + count = n - copied; + if(count > IO_COPY_BUFSIZE) { + count = IO_COPY_BUFSIZE; + } + + if((r=sendfile(out_fd, in_fd, &offset, count)) < 0) { + if(errno == EINTR) { + continue; + } + return -1; + } + if(r == 0) { + errno = EPIPE; + return -1; + } + + copied += r; + } + + return 0; +} + diff --git a/io.h b/io.h index 2833e50..4a857e0 100644 --- a/io.h +++ b/io.h @@ -43,6 +43,12 @@ int io_nwrite(int fd, const void* buf, size_t n); int io_ncopy(int fd_in, int fd_out, size_t n); +/** + * Copy exactly N bytes from a file descriptor to a socket. + **/ +int io_sendfile(int fd, int sock, off_t off, size_t n); + + /** * Read exactly N bytes from the given file descriptor without affecting its * position.