FTP可以上传文件

This commit is contained in:
2026-07-22 01:46:29 +08:00
parent 038a2542af
commit c646df5c2a
76 changed files with 851 additions and 172 deletions

View File

@@ -182,11 +182,14 @@ static int receive_file(int socket, const char *path)
return -1;
}
unsigned char buffer[1024];
static unsigned char s_recv_buf[4096];
int bufsize = 4096;
int err;
int total = 0;
while ((err = lftpd_inet_read(socket, buffer, sizeof(buffer))) > 0) {
if (lftpd_io_write(fh, buffer, err) != err) {
while ((err = lftpd_inet_read(socket, s_recv_buf, bufsize)) > 0) {
total += err;
if (lftpd_io_write(fh, s_recv_buf, err) != err) {
err = -1;
break;
}
@@ -197,6 +200,11 @@ static int receive_file(int socket, const char *path)
if (err < 0) {
return err;
}
if (total == 0) {
lftpd_log_error("received 0 bytes");
lftpd_io_unlink(path);
return -1;
}
return 0;
}
@@ -209,18 +217,15 @@ static int cmd_cwd(lftpd_client_t *client, const char *arg)
char *path = lftpd_io_canonicalize_path(client->directory, arg);
uint32_t size;
int is_dir;
if (lftpd_io_stat(path, &size, &is_dir) != 0) {
send_simple_response(client->socket, 550, STATUS_550);
free(path);
return -1;
}
if (!is_dir) {
send_simple_response(client->socket, 550, STATUS_550);
free(path);
return -1;
/* 根目录始终有效,跳过 stat 检查FatFS FF_FS_RPATH=0 下 stat 根目录可能失败) */
if (strcmp(path, "/") != 0) {
uint32_t size;
int is_dir;
if (lftpd_io_stat(path, &size, &is_dir) != 0 || !is_dir) {
send_simple_response(client->socket, 550, STATUS_550);
free(path);
return -1;
}
}
strncpy(client->directory, path, sizeof(client->directory) - 1);
@@ -262,6 +267,11 @@ static int cmd_dele(lftpd_client_t *client, const char *arg)
static int cmd_epsv(lftpd_client_t *client, const char *arg)
{
if (client->data_socket >= 0) {
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
}
int listener_socket = lftpd_inet_listen(0);
if (listener_socket < 0) {
send_simple_response(client->socket, 425, STATUS_425);
@@ -272,16 +282,9 @@ static int cmd_epsv(lftpd_client_t *client, const char *arg)
send_simple_response(client->socket, 229, STATUS_229, port);
lftpd_log_debug("waiting for data port connection on port %d...", port);
int data_sock = lftpd_inet_accept(listener_socket);
if (data_sock < 0) {
lftpd_log_error("error accepting client socket");
lftpd_inet_close(listener_socket);
return -1;
}
lftpd_log_debug("data port connection received...");
lftpd_log_debug("EPSV listener on port %d", port);
client->data_socket = data_sock;
client->data_socket = listener_socket;
return 0;
}
@@ -304,8 +307,17 @@ static int cmd_list(lftpd_client_t *client, const char *arg)
}
send_simple_response(client->socket, 150, STATUS_150);
int err = send_list(client->data_socket, client->directory);
lftpd_inet_close(client->data_socket);
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
if (data_sock < 0) {
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
send_simple_response(client->socket, 425, STATUS_425);
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
return -1;
}
int err = send_list(data_sock, client->directory);
lftpd_inet_close(data_sock);
client->data_socket = -1;
if (err == 0) {
@@ -324,8 +336,17 @@ static int cmd_nlst(lftpd_client_t *client, const char *arg)
}
send_simple_response(client->socket, 150, STATUS_150);
int err = send_nlst(client->data_socket, client->directory);
lftpd_inet_close(client->data_socket);
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
if (data_sock < 0) {
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
send_simple_response(client->socket, 425, STATUS_425);
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
return -1;
}
int err = send_nlst(data_sock, client->directory);
lftpd_inet_close(data_sock);
client->data_socket = -1;
if (err == 0) {
@@ -353,6 +374,11 @@ static int cmd_pasv(lftpd_client_t *client, const char *arg)
int listener_socket = -1;
int retry;
if (client->data_socket >= 0) {
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
}
for (retry = 0; retry < 3; retry++) {
listener_socket = lftpd_inet_listen(0);
if (listener_socket >= 0) break;
@@ -386,16 +412,9 @@ static int cmd_pasv(lftpd_client_t *client, const char *arg)
(port >> 8) & 0xff, (port >> 0) & 0xff);
}
lftpd_log_debug("waiting for data port connection on port %d...", port);
int data_sock = lftpd_inet_accept(listener_socket);
if (data_sock < 0) {
lftpd_log_error("error accepting client socket");
lftpd_inet_close(listener_socket);
return -1;
}
lftpd_log_debug("data port connection received...");
lftpd_log_debug("PASV listener on port %d", port);
client->data_socket = data_sock;
client->data_socket = listener_socket;
return 0;
}
@@ -419,18 +438,29 @@ static int cmd_retr(lftpd_client_t *client, const char *arg)
}
send_simple_response(client->socket, 150, STATUS_150);
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
if (data_sock < 0) {
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
send_simple_response(client->socket, 425, STATUS_425);
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
return -1;
}
char *path = lftpd_io_canonicalize_path(client->directory, arg);
lftpd_log_debug("send '%s'", path);
int err = send_file(client->data_socket, path);
free(path);
lftpd_inet_close(client->data_socket);
int err = send_file(data_sock, path);
lftpd_inet_close(data_sock);
client->data_socket = -1;
if (err == 0) {
lftpd_log_info("DOWNLOAD '%s' OK", path);
send_simple_response(client->socket, 226, STATUS_226);
} else {
lftpd_log_error("DOWNLOAD '%s' FAILED", path);
send_simple_response(client->socket, 450, STATUS_450);
}
free(path);
return 0;
}
@@ -464,18 +494,32 @@ static int cmd_stor(lftpd_client_t *client, const char *arg)
}
send_simple_response(client->socket, 150, STATUS_150);
int data_sock = lftpd_inet_accept_timeout(client->data_socket, 5000);
if (data_sock < 0) {
lftpd_log_error("%s accept failed, sk=%d", __func__, client->data_socket);
send_simple_response(client->socket, 425, STATUS_425);
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
return -1;
}
char *path = lftpd_io_canonicalize_path(client->directory, arg);
lftpd_log_debug("receive '%s'", path);
int err = receive_file(client->data_socket, path);
free(path);
lftpd_inet_close(client->data_socket);
int err = receive_file(data_sock, path);
lftpd_inet_close(data_sock);
client->data_socket = -1;
if (err == 0) {
uint32_t size = 0;
int is_dir = 0;
lftpd_io_stat(path, &size, &is_dir);
lftpd_log_info("UPLOAD '%s' %lu bytes OK", path, (unsigned long)size);
send_simple_response(client->socket, 226, STATUS_226);
} else {
lftpd_log_error("UPLOAD '%s' FAILED", path);
send_simple_response(client->socket, 450, STATUS_450);
}
free(path);
return 0;
}
@@ -548,6 +592,7 @@ static int handle_control_channel(lftpd_client_t *client)
arg = lftpd_string_trim(arg_buf);
}
lftpd_log_info("CMD %s %s", command_tmp, arg ? arg : "");
err = commands[i].handler(client, arg);
matched = true;
break;
@@ -585,7 +630,7 @@ int lftpd_start(const char *directory, int port, lftpd_t *lftpd)
if (client_socket < 0) {
lftpd_log_error("error accepting client socket");
lftpd_inet_close(lftpd->server_socket);
break;
continue;
}
{
@@ -614,14 +659,9 @@ int lftpd_start(const char *directory, int port, lftpd_t *lftpd)
handle_control_channel(&client);
lftpd->client = NULL;
/* 等待 CH395F 稳定Trap 09 */
vTaskDelay(pdMS_TO_TICKS(200));
/* standalone mode: socket was closed in handle_control_channel,
* loop back to create a new listener */
}
return 0;
}
int lftpd_stop(lftpd_t *lftpd)

View File

@@ -7,30 +7,40 @@
int lftpd_inet_listen(int port)
{
int s = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
if (s < 0) {
DBG_ERROR("error creating listener socket");
return -1;
}
int retry;
int s;
struct net_sockaddr_in addr;
addr.sin_family = NET_AF_INET;
addr.sin_port = net_htons((uint16_t)port);
addr.sin_addr.s_addr = 0;
for (retry = 0; retry < 5; retry++) {
s = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
if (s < 0) {
if (retry == 0) DBG_ERROR("create socket");
vTaskDelay(pdMS_TO_TICKS(500));
continue;
}
struct net_sockaddr_in addr;
addr.sin_family = NET_AF_INET;
addr.sin_port = net_htons((uint16_t)port);
addr.sin_addr.s_addr = 0;
if (net_bind(s, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
DBG_ERROR("bind port %d", port);
net_close(s);
return -1;
}
if (net_listen(s, 0) >= 0) {
return s;
}
if (net_bind(s, (struct net_sockaddr *)&addr, sizeof(addr)) < 0) {
DBG_ERROR("error binding listener port %d", port);
net_close(s);
return -1;
if (retry < 4) {
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
if (net_listen(s, 0) < 0) {
DBG_ERROR("error listening on socket");
net_close(s);
return -1;
}
return s;
DBG_ERROR("listen failed after 5 retries (total 10s wait)");
return -1;
}
int lftpd_inet_listen_multi(int port, int backlog)
@@ -81,10 +91,33 @@ int lftpd_inet_accept(int socket)
if (s >= 0) {
return s;
}
vTaskDelay(pdMS_TO_TICKS(10));
vTaskDelay(pdMS_TO_TICKS(100));
}
}
int lftpd_inet_accept_timeout(int socket, int timeout_ms)
{
int elapsed = 0;
while (elapsed < timeout_ms) {
int s = net_accept(socket, NULL, NULL);
if (s >= 0) {
return s;
}
/* 数据连接已被对端关闭时提前退出,不等待超时 */
net_sock_t *p_sock = net_get_sock(socket);
if (p_sock == NULL || p_sock->state != NET_SOCK_STATE_LISTENING) {
DBG_ERROR("data socket closed, accept aborted");
return -1;
}
vTaskDelay(pdMS_TO_TICKS(100));
elapsed += 100;
}
DBG_ERROR("accept timeout (%dms)", timeout_ms);
return -1;
}
int lftpd_inet_read_line(int socket, char *buffer, size_t buffer_len)
{
memset(buffer, 0, buffer_len);

View File

@@ -11,17 +11,17 @@
/*
* FatFS 在 FF_USE_LFN=0 时不接受 "/" 前缀路径。
* 剥离前导 "/" 后用 FatFS 兼容路径,根目录用 "." 替代空字符串
* 剥离前导 "/" 后用 FatFS 兼容路径,根目录用 "0:"(驱动号格式)替代
*/
static const char *to_fatfs_path(const char *path)
{
if (path == NULL || *path == '\0') {
return ".";
return "0:";
}
if (*path == '/') {
path++;
if (*path == '\0') {
return ".";
return "0:";
}
}
return path;

View File

@@ -7,6 +7,7 @@ int lftpd_inet_listen(int port);
int lftpd_inet_listen_multi(int port, int backlog);
int lftpd_inet_get_socket_port(int socket);
int lftpd_inet_accept(int socket);
int lftpd_inet_accept_timeout(int socket, int timeout_ms);
int lftpd_inet_read_line(int socket, char *buffer, size_t buffer_len);
int lftpd_inet_write_string(int socket, const char *message);
int lftpd_inet_write(int socket, const void *buf, int len);