解决一个擦除的bug

This commit is contained in:
2026-07-21 20:18:28 +08:00
parent f50b9c9e66
commit 66a1e8fd6a
25 changed files with 2005 additions and 61 deletions

View File

@@ -293,22 +293,24 @@ static int gd5f_set_feature(uint8_t addr, uint8_t data) {
}
/*
* 函数功能:块擦除(擦<EFBFBD>?28KB块
* 入口参数block_addr - 块编<EFBFBD>? uint32_t 0 - 2047
* 返回值0 - 成功,其<EFBFBD>?- 错误<EFBFBD>? * 限定条件gd5f2gq5ue_init() 已调<E5B7B2>? * 函数说明<E8AFB4>?. 写使<E58699>?- D8h + 3字节字节地址 - 等待完成
* 2. 擦除完成后检<E5908E>?E_FAIL <20>? */
* 函数功能:块擦除(擦除128KB块
* 入口参数block_addr - 块编 uint32_t 0 - 2047
* 返回值0 - 成功,其- 错误
* 限定条件gd5f2gq5ue_init() 已调用
* 函数说明1. 写使能 - D8h + 3字节页地址 - 等待完成
* 2. 擦除完成后检查 E_FAIL */
int gd5f_block_erase(uint32_t block_addr) {
int ret = GD5F_OK;
uint8_t cmd[4];
uint8_t status = 0;
uint32_t byte_addr = block_addr * GD5F_BLOCK_SIZE;
uint32_t page_addr = block_addr * GD5F_PAGES_PER_BLOCK;
gd5f_write_enable();
cmd[0] = GD5F_CMD_BLOCK_ERASE;
cmd[1] = (byte_addr >> 16) & 0xFF;
cmd[2] = (byte_addr >> 8) & 0xFF;
cmd[3] = byte_addr & 0xFF;
cmd[1] = (page_addr >> 16) & 0xFF;
cmd[2] = (page_addr >> 8) & 0xFF;
cmd[3] = page_addr & 0xFF;
GD5F_CS_LOW();
HAL_SPI_Transmit(&hspi1, cmd, 4, GD5F_SPI_TIMEOUT);
@@ -358,6 +360,42 @@ static int gd5f_bbt_scan(void) {
return GD5F_OK;
}
void gd5f2gq5ue_bbt_rescan(void) {
uint32_t blk;
uint8_t spare[64];
memset(s_bbt, 0, GD5F_BBT_SIZE);
for (blk = 0; blk < GD5F_TOTAL_BLOCKS; blk++) {
uint32_t page = (blk << 6) | 63;
gd5f_page_read(page);
gd5f_read_from_cache(GD5F_PAGE_SIZE, spare, sizeof(spare));
if (spare[0] != 0xFF) {
s_bbt[blk >> 3] |= (1 << (blk & 7));
}
}
}
void gd5f2gq5ue_bbt_clear(void) {
memset(s_bbt, 0, GD5F_BBT_SIZE);
}
void gd5f2gq5ue_print_bbt(void) {
uint32_t bad_count = 0;
for (uint32_t b = 0; b < GD5F_TOTAL_BLOCKS; b++) {
if ((s_bbt[b >> 3] >> (b & 7)) & 1) bad_count++;
}
DBG_INFO("BBT: %lu/%lu blocks bad", bad_count, GD5F_TOTAL_BLOCKS);
if (bad_count > 0) {
uint32_t shown = 0;
for (uint32_t b = 0; b < GD5F_TOTAL_BLOCKS && shown < 32; b++) {
if ((s_bbt[b >> 3] >> (b & 7)) & 1) {
DBG_INFO(" block %lu (offset 0x%08lX)", b, b * GD5F_BLOCK_SIZE);
shown++;
}
}
if (bad_count > 32) DBG_INFO(" ... and %lu more", bad_count - 32);
}
}
/* ======================== 公共函数定义 ======================== */
/*

View File

@@ -161,6 +161,9 @@ int gd5f2gq5ue_is_block_bad(uint32_t block);
* 函数说明:更新 BBT并尝试物理标记该块最后一页 spare byte 0 为 0x00
*/
void gd5f2gq5ue_mark_block_bad(uint32_t block);
void gd5f2gq5ue_bbt_clear(void);
void gd5f2gq5ue_bbt_rescan(void);
void gd5f2gq5ue_print_bbt(void);
/* ==================== SPI 原语FTL 共享) ==================== */

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Jason von Nieda <jason@vonnieda.org>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,626 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <stdbool.h>
#include <ctype.h>
#include "lftpd.h"
#include "private/lftpd_status.h"
#include "private/lftpd_inet.h"
#include "private/lftpd_log.h"
#include "private/lftpd_string.h"
#include "private/lftpd_io.h"
#include "net_socket.h"
#include "net_config.h"
#include "ff.h"
typedef struct {
const char *command;
int (*handler)(lftpd_client_t *client, const char *arg);
} command_t;
static int cmd_cwd(lftpd_client_t *client, const char *arg);
static int cmd_dele(lftpd_client_t *client, const char *arg);
static int cmd_epsv(lftpd_client_t *client, const char *arg);
static int cmd_feat(lftpd_client_t *client, const char *arg);
static int cmd_list(lftpd_client_t *client, const char *arg);
static int cmd_nlst(lftpd_client_t *client, const char *arg);
static int cmd_noop(lftpd_client_t *client, const char *arg);
static int cmd_pass(lftpd_client_t *client, const char *arg);
static int cmd_pasv(lftpd_client_t *client, const char *arg);
static int cmd_pwd(lftpd_client_t *client, const char *arg);
static int cmd_quit(lftpd_client_t *client, const char *arg);
static int cmd_retr(lftpd_client_t *client, const char *arg);
static int cmd_size(lftpd_client_t *client, const char *arg);
static int cmd_stor(lftpd_client_t *client, const char *arg);
static int cmd_syst(lftpd_client_t *client, const char *arg);
static int cmd_type(lftpd_client_t *client, const char *arg);
static int cmd_user(lftpd_client_t *client, const char *arg);
static command_t commands[] = {
{ "CWD", cmd_cwd },
{ "DELE", cmd_dele },
{ "EPSV", cmd_epsv },
{ "FEAT", cmd_feat },
{ "LIST", cmd_list },
{ "NLST", cmd_nlst },
{ "NOOP", cmd_noop },
{ "PASS", cmd_pass },
{ "PASV", cmd_pasv },
{ "PWD", cmd_pwd },
{ "QUIT", cmd_quit },
{ "RETR", cmd_retr },
{ "SIZE", cmd_size },
{ "STOR", cmd_stor },
{ "SYST", cmd_syst },
{ "TYPE", cmd_type },
{ "USER", cmd_user },
{ NULL, NULL },
};
static int send_response(int socket, int code, bool include_code,
bool multiline_start, const char *format, ...)
{
va_list args;
char message[256];
char response[512];
va_start(args, format);
vsnprintf(message, sizeof(message), format, args);
va_end(args);
if (include_code) {
if (multiline_start) {
snprintf(response, sizeof(response), "%d-%s%s", code, message, CRLF);
} else {
snprintf(response, sizeof(response), "%d %s%s", code, message, CRLF);
}
} else {
snprintf(response, sizeof(response), "%s%s", message, CRLF);
}
return lftpd_inet_write_string(socket, response);
}
#define send_simple_response(socket, code, format, ...) \
send_response(socket, code, true, false, format, ##__VA_ARGS__)
#define send_multiline_response_begin(socket, code, format, ...) \
send_response(socket, code, true, true, format, ##__VA_ARGS__)
#define send_multiline_response_line(socket, format, ...) \
send_response(socket, 0, false, false, format, ##__VA_ARGS__)
#define send_multiline_response_end(socket, code, format, ...) \
send_response(socket, code, true, false, format, ##__VA_ARGS__)
static int send_list(int socket, const char *path)
{
static const char *directory_format = "drw-rw-rw- 1 owner group %13lu Jan 01 1970 %s";
static const char *file_format = "-rw-rw-rw- 1 owner group %13lu Jan 01 1970 %s";
void *dp = lftpd_io_opendir(path);
if (dp == NULL) {
return -1;
}
char name[256];
uint32_t size;
int is_dir;
while (lftpd_io_readdir(dp, name, sizeof(name), &size, &is_dir) == 0) {
if (is_dir) {
send_multiline_response_line(socket, directory_format,
(unsigned long)size, name);
} else {
send_multiline_response_line(socket, file_format,
(unsigned long)size, name);
}
}
lftpd_io_closedir(dp);
return 0;
}
static int send_nlst(int socket, const char *path)
{
void *dp = lftpd_io_opendir(path);
if (dp == NULL) {
return -1;
}
char name[256];
uint32_t size;
int is_dir;
while (lftpd_io_readdir(dp, name, sizeof(name), &size, &is_dir) == 0) {
if (!is_dir) {
send_multiline_response_line(socket, name);
}
}
lftpd_io_closedir(dp);
return 0;
}
static int send_file(int socket, const char *path)
{
int fh = lftpd_io_open_read(path);
if (fh < 0) {
lftpd_log_error("failed to open file for read");
return -1;
}
unsigned char buffer[1024];
int read_len;
while ((read_len = lftpd_io_read(fh, buffer, sizeof(buffer))) > 0) {
unsigned char *p = buffer;
while (read_len > 0) {
int write_len = lftpd_inet_write(socket, p, read_len);
if (write_len < 0) {
lftpd_log_error("write error");
lftpd_io_close(fh);
return -1;
}
p += write_len;
read_len -= write_len;
}
}
lftpd_io_close(fh);
return 0;
}
static int receive_file(int socket, const char *path)
{
int fh = lftpd_io_open_write(path);
if (fh < 0) {
lftpd_log_error("failed to open file for write");
return -1;
}
unsigned char buffer[1024];
int err;
while ((err = lftpd_inet_read(socket, buffer, sizeof(buffer))) > 0) {
if (lftpd_io_write(fh, buffer, err) != err) {
err = -1;
break;
}
}
lftpd_io_close(fh);
if (err < 0) {
return err;
}
return 0;
}
static int cmd_cwd(lftpd_client_t *client, const char *arg)
{
if (arg == NULL || strlen(arg) == 0) {
send_simple_response(client->socket, 550, STATUS_550);
return -1;
}
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;
}
strncpy(client->directory, path, sizeof(client->directory) - 1);
client->directory[sizeof(client->directory) - 1] = '\0';
free(path);
send_simple_response(client->socket, 250, STATUS_250);
return 0;
}
static int cmd_dele(lftpd_client_t *client, const char *arg)
{
if (arg == NULL || strlen(arg) == 0) {
send_simple_response(client->socket, 550, STATUS_550);
return -1;
}
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;
}
lftpd_io_unlink(path);
free(path);
send_simple_response(client->socket, 250, STATUS_250);
return 0;
}
static int cmd_epsv(lftpd_client_t *client, const char *arg)
{
int listener_socket = lftpd_inet_listen(0);
if (listener_socket < 0) {
send_simple_response(client->socket, 425, STATUS_425);
return -1;
}
int port = lftpd_inet_get_socket_port(listener_socket);
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...");
client->data_socket = data_sock;
return 0;
}
static int cmd_feat(lftpd_client_t *client, const char *arg)
{
send_multiline_response_begin(client->socket, 211, STATUS_211);
send_multiline_response_line(client->socket, "EPSV");
send_multiline_response_line(client->socket, "PASV");
send_multiline_response_line(client->socket, "SIZE");
send_multiline_response_line(client->socket, "NLST");
send_multiline_response_end(client->socket, 211, STATUS_211);
return 0;
}
static int cmd_list(lftpd_client_t *client, const char *arg)
{
if (client->data_socket == -1) {
send_simple_response(client->socket, 425, STATUS_425);
return -1;
}
send_simple_response(client->socket, 150, STATUS_150);
int err = send_list(client->data_socket, client->directory);
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
if (err == 0) {
send_simple_response(client->socket, 226, STATUS_226);
} else {
send_simple_response(client->socket, 550, STATUS_550);
}
return 0;
}
static int cmd_nlst(lftpd_client_t *client, const char *arg)
{
if (client->data_socket == -1) {
send_simple_response(client->socket, 425, STATUS_425);
return -1;
}
send_simple_response(client->socket, 150, STATUS_150);
int err = send_nlst(client->data_socket, client->directory);
lftpd_inet_close(client->data_socket);
client->data_socket = -1;
if (err == 0) {
send_simple_response(client->socket, 226, STATUS_226);
} else {
send_simple_response(client->socket, 550, STATUS_550);
}
return 0;
}
static int cmd_noop(lftpd_client_t *client, const char *arg)
{
send_simple_response(client->socket, 200, STATUS_200);
return 0;
}
static int cmd_pass(lftpd_client_t *client, const char *arg)
{
send_simple_response(client->socket, 230, STATUS_230);
return 0;
}
static int cmd_pasv(lftpd_client_t *client, const char *arg)
{
int listener_socket = lftpd_inet_listen(0);
if (listener_socket < 0) {
send_simple_response(client->socket, 425, STATUS_425);
return -1;
}
int port = lftpd_inet_get_socket_port(listener_socket);
{
struct net_sockaddr_in local_addr;
int addrlen = sizeof(local_addr);
int err = net_getsockname(client->socket,
(struct net_sockaddr *)&local_addr, &addrlen);
if (err != 0) {
lftpd_log_error("error getting client IP info");
send_simple_response(client->socket, 425, STATUS_425);
lftpd_inet_close(listener_socket);
return -1;
}
uint32_t ip = net_htonl(local_addr.sin_addr.s_addr);
send_simple_response(client->socket, 227, STATUS_227,
(ip >> 24) & 0xff,
(ip >> 16) & 0xff,
(ip >> 8) & 0xff,
(ip >> 0) & 0xff,
(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...");
client->data_socket = data_sock;
return 0;
}
static int cmd_pwd(lftpd_client_t *client, const char *arg)
{
send_simple_response(client->socket, 257, "\"%s\"", client->directory);
return 0;
}
static int cmd_quit(lftpd_client_t *client, const char *arg)
{
send_simple_response(client->socket, 221, STATUS_221);
return -1;
}
static int cmd_retr(lftpd_client_t *client, const char *arg)
{
if (client->data_socket == -1) {
send_simple_response(client->socket, 425, STATUS_425);
return -1;
}
send_simple_response(client->socket, 150, STATUS_150);
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);
client->data_socket = -1;
if (err == 0) {
send_simple_response(client->socket, 226, STATUS_226);
} else {
send_simple_response(client->socket, 450, STATUS_450);
}
return 0;
}
static int cmd_size(lftpd_client_t *client, const char *arg)
{
if (arg == NULL) {
send_simple_response(client->socket, 550, STATUS_550);
return 0;
}
char *path = lftpd_io_canonicalize_path(client->directory, arg);
lftpd_log_debug("size %s", path);
uint32_t size;
int is_dir;
if (lftpd_io_stat(path, &size, &is_dir) == 0 && !is_dir) {
send_simple_response(client->socket, 213, "%lu", (unsigned long)size);
} else {
send_simple_response(client->socket, 550, STATUS_550);
}
free(path);
return 0;
}
static int cmd_stor(lftpd_client_t *client, const char *arg)
{
if (client->data_socket == -1) {
send_simple_response(client->socket, 425, STATUS_425);
return -1;
}
send_simple_response(client->socket, 150, STATUS_150);
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);
client->data_socket = -1;
if (err == 0) {
send_simple_response(client->socket, 226, STATUS_226);
} else {
send_simple_response(client->socket, 450, STATUS_450);
}
return 0;
}
static int cmd_syst(lftpd_client_t *client, const char *arg)
{
send_simple_response(client->socket, 215, "UNIX Type: L8");
return 0;
}
static int cmd_type(lftpd_client_t *client, const char *arg)
{
send_simple_response(client->socket, 200, STATUS_200);
return 0;
}
static int cmd_user(lftpd_client_t *client, const char *arg)
{
send_simple_response(client->socket, 230, STATUS_230);
return 0;
}
static int handle_control_channel(lftpd_client_t *client)
{
int err = send_simple_response(client->socket, 220, STATUS_220);
if (err != 0) {
lftpd_log_error("error sending welcome message");
goto cleanup;
}
char read_buffer[512];
while (err == 0) {
int line_len = lftpd_inet_read_line(client->socket, read_buffer,
sizeof(read_buffer));
if (line_len != 0) {
lftpd_log_error("error reading next command");
goto cleanup;
}
int index;
char *p = strchr(read_buffer, ' ');
if (p != NULL) {
index = (int)(p - read_buffer);
} else {
index = (int)strlen(read_buffer);
}
if (index >= 5) {
err = send_simple_response(client->socket, 500, STATUS_500);
continue;
}
char command_tmp[4 + 1];
memset(command_tmp, 0, sizeof(command_tmp));
memcpy(command_tmp, read_buffer, (size_t)index);
for (int i = 0; command_tmp[i]; i++) {
command_tmp[i] = (char)toupper((int)command_tmp[i]);
}
bool matched = false;
for (int i = 0; commands[i].command; i++) {
if (strcmp(commands[i].command, command_tmp) == 0) {
char arg_buf[512];
const char *arg = NULL;
if (index < (int)strlen(read_buffer)) {
strncpy(arg_buf, read_buffer + index + 1, sizeof(arg_buf) - 1);
arg_buf[sizeof(arg_buf) - 1] = '\0';
arg = lftpd_string_trim(arg_buf);
}
err = commands[i].handler(client, arg);
matched = true;
break;
}
}
if (!matched) {
send_simple_response(client->socket, 502, STATUS_502);
}
}
cleanup:
lftpd_inet_close(client->socket);
return 0;
}
int lftpd_start(const char *directory, int port, lftpd_t *lftpd)
{
memset(lftpd, 0, sizeof(lftpd_t));
lftpd->directory = directory;
lftpd->port = port;
while (true) {
lftpd->server_socket = lftpd_inet_listen(port);
if (lftpd->server_socket < 0) {
lftpd_log_error("error creating listener");
vTaskDelay(pdMS_TO_TICKS(3000));
continue;
}
lftpd_log_info("waiting for connection...");
int client_socket = lftpd_inet_accept(lftpd->server_socket);
if (client_socket < 0) {
lftpd_log_error("error accepting client socket");
lftpd_inet_close(lftpd->server_socket);
break;
}
{
char ip_str[16];
struct net_sockaddr_in addr;
int addrlen = sizeof(addr);
if (net_getsockname(client_socket,
(struct net_sockaddr *)&addr, &addrlen) == 0) {
net_inet_ntoa(addr.sin_addr.s_addr, ip_str);
int remote_port = lftpd_inet_get_socket_port(client_socket);
lftpd_log_info("connection received from %s:%d...",
ip_str, remote_port);
} else {
lftpd_log_info("connection received...");
}
}
lftpd_client_t client;
memset(&client, 0, sizeof(client));
strncpy(client.directory, directory, sizeof(client.directory) - 1);
client.directory[sizeof(client.directory) - 1] = '\0';
client.socket = client_socket;
client.data_socket = -1;
lftpd->client = &client;
handle_control_channel(&client);
lftpd->client = NULL;
/* standalone mode: socket was closed in handle_control_channel,
* loop back to create a new listener */
}
return 0;
}
int lftpd_stop(lftpd_t *lftpd)
{
if (lftpd->server_socket >= 0) {
lftpd_inet_close(lftpd->server_socket);
}
if (lftpd->client) {
lftpd_inet_close(lftpd->client->socket);
}
return 0;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <stdint.h>
typedef struct {
char directory[256];
int socket;
int data_socket;
} lftpd_client_t;
typedef struct {
const char *directory;
int port;
int server_socket;
lftpd_client_t *client;
} lftpd_t;
int lftpd_start(const char *directory, int port, lftpd_t *lftpd);
int lftpd_stop(lftpd_t *lftpd);

View File

@@ -0,0 +1,161 @@
#define DBG_TAG "[LFT_INET]"
#include "private/lftpd_inet.h"
#include "dbg_log.h"
#include "net_socket.h"
#include <string.h>
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;
}
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("error binding listener port %d", port);
net_close(s);
return -1;
}
if (net_listen(s, 0) < 0) {
DBG_ERROR("error listening on socket");
net_close(s);
return -1;
}
return s;
}
int lftpd_inet_listen_multi(int port, int backlog)
{
int s = net_socket(NET_AF_INET, NET_SOCK_STREAM, 0);
if (s < 0) {
DBG_ERROR("error creating multi listener socket");
return -1;
}
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("error binding multi listener port %d", port);
net_close(s);
return -1;
}
if (net_listen(s, backlog) < 0) {
DBG_ERROR("error listening on multi socket");
net_close(s);
return -1;
}
return s;
}
int lftpd_inet_get_socket_port(int socket)
{
struct net_sockaddr_in addr;
int addrlen = sizeof(addr);
if (net_getsockname(socket, (struct net_sockaddr *)&addr, &addrlen) < 0) {
DBG_ERROR("error getting socket port number");
return -1;
}
return (int)net_ntohs(addr.sin_port);
}
int lftpd_inet_accept(int socket)
{
while (1) {
int s = net_accept(socket, NULL, NULL);
if (s >= 0) {
return s;
}
vTaskDelay(pdMS_TO_TICKS(10));
}
}
int lftpd_inet_read_line(int socket, char *buffer, size_t buffer_len)
{
memset(buffer, 0, buffer_len);
int total_read_len = 0;
while (total_read_len < (int)buffer_len) {
int read_len = net_recv(socket,
buffer + total_read_len,
buffer_len - total_read_len - 1,
0);
if (read_len == 0) {
return -1;
}
if (read_len < 0) {
return read_len;
}
total_read_len += read_len;
char *p = strstr(buffer, "\r\n");
if (p != NULL) {
*p = '\0';
return 0;
}
}
return -1;
}
int lftpd_inet_write_string(int socket, const char *message)
{
const char *p = message;
int length = (int)strlen(message);
while (length > 0) {
int write_len = net_send(socket, p, length, 0);
if (write_len < 0) {
DBG_ERROR("write error");
return write_len;
}
p += write_len;
length -= write_len;
}
return 0;
}
int lftpd_inet_write(int socket, const void *buf, int len)
{
const char *p = (const char *)buf;
int remaining = len;
while (remaining > 0) {
int n = net_send(socket, p, remaining, 0);
if (n < 0) {
return n;
}
p += n;
remaining -= n;
}
return len;
}
int lftpd_inet_read(int socket, void *buf, int len)
{
int n = net_recv(socket, buf, len, 0);
return n;
}
int lftpd_inet_close(int socket)
{
return net_close(socket);
}

View File

@@ -0,0 +1,204 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "ff.h"
#include "private/lftpd_io.h"
static int s_file_open = 0;
static FIL s_ftp_file;
char *lftpd_io_canonicalize_path(const char *base, const char *name)
{
if (base == NULL) {
base = "";
}
if (name == NULL) {
name = "";
}
char *path;
if (name[0] == '/') {
path = (char *)malloc(strlen(name) + 1);
if (path == NULL) return NULL;
strcpy(path, name);
} else {
size_t len = strlen(base) + 1 + strlen(name) + 1;
path = (char *)malloc(len);
if (path == NULL) return NULL;
snprintf(path, len, "%s/%s", base, name);
}
char *abs_path = (char *)malloc(strlen(path) + 2);
if (abs_path == NULL) {
free(path);
return NULL;
}
abs_path[0] = '\0';
char *p = path;
while (*p != '\0') {
while (*p == '/') p++;
if (*p == '\0') break;
char *seg_start = p;
while (*p != '\0' && *p != '/') p++;
char saved = *p;
*p = '\0';
if (strcmp(seg_start, ".") == 0) {
/* ignore */
} else if (strcmp(seg_start, "..") == 0) {
char *slash = strrchr(abs_path, '/');
if (slash != NULL) {
*slash = '\0';
}
} else {
strcat(abs_path, "/");
strcat(abs_path, seg_start);
}
*p = saved;
}
free(path);
if (strlen(abs_path) == 0) {
strcpy(abs_path, "/");
}
return abs_path;
}
int lftpd_io_open_read(const char *path)
{
if (s_file_open) {
return -1;
}
if (f_open(&s_ftp_file, path, FA_READ) != FR_OK) {
return -1;
}
s_file_open = 1;
return 0;
}
int lftpd_io_open_write(const char *path)
{
if (s_file_open) {
return -1;
}
if (f_open(&s_ftp_file, path, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) {
return -1;
}
s_file_open = 1;
return 0;
}
int lftpd_io_read(int handle, void *buf, int len)
{
(void)handle;
UINT br;
if (f_read(&s_ftp_file, buf, (UINT)len, &br) != FR_OK) {
return -1;
}
return (int)br;
}
int lftpd_io_write(int handle, const void *buf, int len)
{
(void)handle;
UINT bw;
if (f_write(&s_ftp_file, buf, (UINT)len, &bw) != FR_OK) {
return -1;
}
if ((int)bw != len) {
return -1;
}
return (int)bw;
}
void lftpd_io_close(int handle)
{
(void)handle;
if (s_file_open) {
f_close(&s_ftp_file);
s_file_open = 0;
}
}
int lftpd_io_stat(const char *path, uint32_t *p_size, int *p_is_dir)
{
FILINFO fno;
if (f_stat(path, &fno) != FR_OK) {
return -1;
}
if (p_size != NULL) {
*p_size = (uint32_t)fno.fsize;
}
if (p_is_dir != NULL) {
*p_is_dir = (fno.fattrib & AM_DIR) ? 1 : 0;
}
return 0;
}
int lftpd_io_unlink(const char *path)
{
if (f_unlink(path) == FR_OK) {
return 0;
}
return -1;
}
void *lftpd_io_opendir(const char *path)
{
DIR *dp = (DIR *)malloc(sizeof(DIR));
if (dp == NULL) {
return NULL;
}
if (f_opendir(dp, path) != FR_OK) {
free(dp);
return NULL;
}
return (void *)dp;
}
int lftpd_io_readdir(void *dp, char *name, int name_max, uint32_t *p_size, int *p_is_dir)
{
FILINFO fno;
FRESULT fr;
while (1) {
fr = f_readdir((DIR *)dp, &fno);
if (fr != FR_OK || fno.fname[0] == 0) {
return -1;
}
if (fno.fname[0] == '.') {
continue;
}
break;
}
strncpy(name, fno.fname, (size_t)(name_max - 1));
name[name_max - 1] = '\0';
if (p_size != NULL) {
*p_size = (uint32_t)fno.fsize;
}
if (p_is_dir != NULL) {
*p_is_dir = (fno.fattrib & AM_DIR) ? 1 : 0;
}
return 0;
}
void lftpd_io_closedir(void *dp)
{
if (dp != NULL) {
f_closedir((DIR *)dp);
free(dp);
}
}

View File

@@ -0,0 +1,18 @@
#include "private/lftpd_log.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
void lftpd_log_internal(const char* level, const char* format, ...) {
char buffer[256];
va_list args;
va_start(args, format);
int err = vsnprintf(buffer, sizeof(buffer), format, args);
va_end(args);
if (err >= sizeof(buffer)) {
return;
}
printf("%s %s\n", level, buffer);
}

View File

@@ -0,0 +1,16 @@
#include <string.h>
#include <ctype.h>
#include "private/lftpd_string.h"
char *lftpd_string_trim(char *s)
{
char *p = s;
for (int i = 0, len = (int)strlen(s); i < len && isspace((int)s[i]); i++) {
p++;
}
for (int i = (int)strlen(p); i >= 0 && isspace((int)p[i]); i--) {
p[i] = '\0';
}
return p;
}

View File

@@ -0,0 +1,14 @@
#pragma once
#include <stdlib.h>
#include <stdint.h>
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_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);
int lftpd_inet_read(int socket, void *buf, int len);
int lftpd_inet_close(int socket);

View File

@@ -0,0 +1,18 @@
#pragma once
#include <stdint.h>
char *lftpd_io_canonicalize_path(const char *base, const char *name);
int lftpd_io_open_read(const char *path);
int lftpd_io_open_write(const char *path);
int lftpd_io_read(int handle, void *buf, int len);
int lftpd_io_write(int handle, const void *buf, int len);
void lftpd_io_close(int handle);
int lftpd_io_stat(const char *path, uint32_t *p_size, int *p_is_dir);
int lftpd_io_unlink(const char *path);
void *lftpd_io_opendir(const char *path);
int lftpd_io_readdir(void *dp, char *name, int name_max, uint32_t *p_size, int *p_is_dir);
void lftpd_io_closedir(void *dp);

View File

@@ -0,0 +1,7 @@
#pragma once
#include "dbg_log.h"
#define lftpd_log_error(format, ...) DBG_ERROR("[FTP] " format, ##__VA_ARGS__)
#define lftpd_log_info(format, ...) DBG_INFO("[FTP] " format, ##__VA_ARGS__)
#define lftpd_log_debug(format, ...)

View File

@@ -0,0 +1,42 @@
#pragma once
#define STATUS_110 "Restart marker reply."
#define STATUS_120 "Service ready in %d minutes."
#define STATUS_125 "Data connection already open; transfer starting."
#define STATUS_150 "File status okay; about to open data connection."
#define STATUS_200 "Command okay."
#define STATUS_202 "Command not implemented, superfluous at this site."
#define STATUS_211 "System status, or system help reply."
#define STATUS_212 "Directory status."
#define STATUS_213 "File status."
#define STATUS_214 "Help message."
#define STATUS_215 "%s system type."
#define STATUS_220 "Service ready for new user."
#define STATUS_221 "Service closing control connection."
#define STATUS_225 "Data connection open; no transfer in progress."
#define STATUS_226 "Closing data connection."
#define STATUS_227 "Entering Passive Mode (%d,%d,%d,%d,%d,%d)."
#define STATUS_229 "Entering Extended Passive Mode (|||%d|)."
#define STATUS_230 "User logged in, proceed."
#define STATUS_250 "Requested file action okay, completed."
#define STATUS_257 "\"%s\" created."
#define STATUS_331 "User name okay, need password."
#define STATUS_332 "Need account for login."
#define STATUS_350 "Requested file action pending further information."
#define STATUS_421 "Service not available, closing control connection."
#define STATUS_425 "Can't open data connection."
#define STATUS_426 "Connection closed; transfer aborted."
#define STATUS_450 "Requested file action not taken. File unavailable (e.g., file busy)."
#define STATUS_451 "Requested action aborted: local error in processing."
#define STATUS_452 "Requested action not taken. Insufficient storage space in system."
#define STATUS_500 "Syntax error, command unrecognized. This may include errors such as command line too long."
#define STATUS_501 "Syntax error in parameters or arguments."
#define STATUS_502 "Command not implemented."
#define STATUS_503 "Bad sequence of commands."
#define STATUS_504 "Command not implemented for that parameter."
#define STATUS_530 "Not logged in."
#define STATUS_532 "Need account for storing files."
#define STATUS_550 "Requested action not taken. File unavailable (e.g., file not found, no access)."
#define STATUS_551 "Requested action aborted: page type unknown."
#define STATUS_552 "Requested file action aborted. Exceeded storage allocation (for current directory or dataset)."
#define STATUS_553 "Requested action not taken. File name not allowed."

View File

@@ -0,0 +1,5 @@
#pragma once
#define CRLF "\r\n"
char* lftpd_string_trim(char* s);