ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
scp.h
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file scp.h
6 * @brief SCP (RCP) protocol wire codec - the pure, host-testable half of the SCP-over-SSH server
7 * (PC_ENABLE_SSH_SCP).
8 *
9 * SCP transfers a file over an SSH `exec "scp …"` channel using the old rcp line protocol: the source side
10 * sends a control line `C<mode> <size> <name>\n`, the peer acks with a 0 byte, then the file bytes flow,
11 * ended by a 0 byte and another ack. This file parses/builds the command line and the control line and knows
12 * the ack bytes - no filesystem, no SSH, no Arduino, zero heap. The fs::FS sink/source state machine + the
13 * channel glue live in server/ssh_scp.
14 *
15 * @author Douglas Quigg (dstroy0)
16 * @date 2026
17 */
18
19#ifndef PROTOCORE_SCP_H
20#define PROTOCORE_SCP_H
21
22#include "protocore_config.h"
23
24#if PC_ENABLE_SSH_SCP
25
26#include <stddef.h>
27#include <stdint.h>
28
29// rcp acknowledgement bytes (sent between records).
30#define PC_SCP_ACK_OK 0 ///< proceed
31#define PC_SCP_ACK_WARN 1 ///< warning: followed by a message + '\n'
32#define PC_SCP_ACK_ERROR 2 ///< fatal error: followed by a message + '\n'
33
34/** @brief The role of an `scp` invocation, parsed from the exec command. */
35enum class ScpMode : uint8_t
36{
37 INVALID = 0,
38 SINK, ///< `scp -t <path>`: the client sends a file TO the device (device receives)
39 SOURCE ///< `scp -f <path>`: the client fetches a file FROM the device (device sends)
40};
41
42/**
43 * @brief Parse an exec command `scp [-v] [-r] [-p] [-d] -t|-f <path>` into its role + target path.
44 * @param cmd not NUL-terminated (@p cmd_len bytes). @return the mode; @p path_out gets the (NUL-terminated)
45 * target, ScpMode::INVALID on a command we do not support.
46 */
47ScpMode pc_scp_parse_cmd(const char *cmd, size_t cmd_len, char *path_out, size_t path_cap);
48
49/**
50 * @brief Parse a control line `C<mode> <size> <name>` (a trailing '\n' optional) into its fields.
51 * @return true on a well-formed `C` line; @p mode_out is the octal permission bits, @p size_out the byte
52 * count, @p name_out the (NUL-terminated) filename. Only file records (`C`) are handled (not `D`/`E`).
53 */
54bool pc_scp_parse_cline(const char *line, size_t len, uint32_t *mode_out, uint64_t *size_out, char *name_out,
55 size_t name_cap);
56
57/**
58 * @brief Build a control line `C<mode> <size> <name>\n` for a source transfer. @return the length written, or
59 * 0 if it would not fit @p cap.
60 */
61size_t pc_scp_build_cline(uint32_t mode, uint64_t size, const char *name, char *out, size_t cap);
62
63#endif // PC_ENABLE_SSH_SCP
64
65#endif // PROTOCORE_SCP_H
User-facing configuration for ProtoCore.