libssh2_sftp_write(3)
π libssh2_sftp_write β write SFTP data π
okay bestie, welcome to the libssh2 manual page for libssh2_sftp_write(3) β yes that's the whole name, it's giving very "function so nice they named it twice" energy, but it's literally just how man pages do π
β¨ SYNOPSIS β¨
#include <libssh2.h>
#include <libssh2_sftp.h>
ssize_t
libssh2_sftp_write(LIBSSH2_SFTP_HANDLE *handle,
const char *buffer,
size_t count);
πΈ DESCRIPTION πΈ
so libssh2_sftp_write(3) sends a whole block of data over to the SFTP server. it's modeled after the POSIX write() function and uses the exact same calling semantics β so if you already know write(), you already know her π«Ά
handleβ the SFTP file handle, as returned bylibssh2_sftp_open_ex(3).bufferβ points to the data you're sending off into the void β¨countβ number of bytes frombufferto write. and here's the tea: it may not be possible to write all the bytes you asked for. rude, but true.
libssh2_sftp_handle(3) will use as much as possible of the buffer and shove it into a single SFTP protocol packet. which means: if you want maximum performance when you're sending larger files, you should try to always pass in at least 32K of data to this function. periodt. π₯
π WRITE AHEAD π
starting in libssh2 version 1.2.8, the default behavior of libssh2 is to create several smaller outgoing packets for all the data you pass to this function, and it'll return a positive number as soon as the first packet gets acknowledged from the server. main character behavior honestly.
this has the effect that sometimes more data has been sent off but is not acked yet when this function returns β and when this function is subsequently called again to write more data, libssh2 will immediately figure out that the data is already received remotely. no cap.
in most normal situations this should not cause any problems, BUT (big but, bestie) it should be noted that if you have once called libssh2_sftp_write() with data and it returns short, you MUST still assume that the rest of the data might have been cached. so you need to make sure you do not alter that data and think that the version you have in your next function invoke will be detected or used. π
β οΈ fr fr: short return β "the rest is safe to touch." the rest might already be cached. do not edit that buffer and assume your new version will be used. that's the trap.
the reason for this funny behavior is that SFTP can only send 32K data in each packet, and it gets all packets acked individually. this means we cannot use a simple serial approach if we want to reach high performance even on high latency connections. and we want that. π
π RETURN VALUE π
- actual number of bytes written β or negative on failure.
- if used in non-blocking mode, it returns
LIBSSH2_ERROR_EAGAINwhen it would otherwise block. and whileLIBSSH2_ERROR_EAGAINis a negative number, it is not really a failure per se. it's just... vibing. π - if this function returns
0(zero) it should not be considered an error β it just means there was no error, but yet no payload data got sent to the other end. zero bytes, zero drama. π
π ERRORS π
LIBSSH2_ERROR_ALLOCβ an internal memory allocation call failed. the malloc said "not today." πLIBSSH2_ERROR_SOCKET_SENDβ unable to send data on socket. the socket ghosted us.LIBSSH2_ERROR_SOCKET_TIMEOUTβLIBSSH2_ERROR_SFTP_PROTOCOLβ an invalid SFTP protocol response was received on the socket, or an SFTP operation caused an errorcode to be returned by the server.
π¦ SEE ALSO π¦
okay that's the whole page bestie, you're officially SFTP-write literate, slay π and just so you know who to thank: this gem is from libssh2, version 0.15, dated 1 Jun 2007 β so yeah, she's vintage, she's iconic, she's been running the game longer than you've been alive (probably π) πβ¨
π¦ where this page comes from
- alpine 3.22: libssh2-doc 1.11.1-r3 Β· BSD-3-Clause
- alpine 3.23: libssh2-doc 1.11.1-r4 Β· BSD-3-Clause
- alpine 3.24: libssh2-doc 1.11.1-r4 Β· BSD-3-Clause
- arch rolling: libssh2 1.11.1-7 Β· BSD-3-Clause
- debian trixie: libssh2-1-dev 1.11.1-1+deb13u1 Β· BSD3
- debian trixie: libssh2-1-dev 1.11.1-1+deb13u2 Β· BSD3
- epel 10: libssh2-docs 1.11.1-9.el10_3 Β· BSD-3-Clause
- epel 9: libssh2-docs 1.11.1-9.el9 Β· BSD-3-Clause
- fedora 43: libssh2-docs 1.11.1-4.fc43 Β· BSD-3-Clause
- fedora 43: libssh2-docs 1.11.1-9.fc43 Β· BSD-3-Clause
- fedora 44: libssh2-docs 1.11.1-5.fc44 Β· BSD-3-Clause
- fedora 44: libssh2-docs 1.11.1-9.fc44 Β· BSD-3-Clause
- opensuse-leap 16.0: libssh2-devel 1.11.1-160000.5.1 Β· BSD-3-Clause
- opensuse-leap 16.0: libssh2-devel 1.11.1-160000.5.1 Β· BSD-3-Clause
- opensuse-leap 16.0: libssh2-devel 1.11.1-160000.5.1 Β· BSD-3-Clause
- opensuse-leap 16.0: libssh2-devel 1.11.1-160000.5.1 Β· BSD-3-Clause
- ubuntu questing: libssh2-1-dev 1.11.1-1build1
- ubuntu questing: libssh2-1-dev 1.11.1-1ubuntu0.25.10.2
- ubuntu resolute: libssh2-1-dev 1.11.1-1build2 Β· BSD3
- ubuntu resolute: libssh2-1-dev 1.11.1-1ubuntu0.26.04.4 Β· BSD3
- ubuntu stonking: libssh2-1-dev 1.11.1-6 Β· BSD3
- π the page's license: BSD-3-Clause
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms