mirror of https://github.com/wolfSSL/wolfssh.git
wolfsftp: Improve POSIX and Windows write/append handling
Ensures EOF appending on all POSIX systems and fails short writes on Windows. Consolidates the Windows SFTP flag matrix testing with shared helpers.pull/1225/head
parent
5a1ff71acd
commit
ea530fe05d
|
|
@ -2347,21 +2347,27 @@ static DWORD SFTP_WinCreationDisp(word32 reason)
|
|||
DWORD disp;
|
||||
|
||||
if (reason & WOLFSSH_FXF_CREAT) {
|
||||
if (reason & WOLFSSH_FXF_EXCL)
|
||||
if (reason & WOLFSSH_FXF_EXCL) {
|
||||
disp = CREATE_NEW;
|
||||
else if (reason & WOLFSSH_FXF_TRUNC)
|
||||
}
|
||||
else if (reason & WOLFSSH_FXF_TRUNC) {
|
||||
disp = CREATE_ALWAYS;
|
||||
else
|
||||
}
|
||||
else {
|
||||
disp = OPEN_ALWAYS;
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* TRUNCATE_EXISTING requires GENERIC_WRITE in dwDesiredAccess or
|
||||
* CreateFile() fails with ERROR_INVALID_PARAMETER; without WRITE
|
||||
* there is no way to truncate, so fall back to OPEN_EXISTING. */
|
||||
if ((reason & WOLFSSH_FXF_TRUNC) && (reason & WOLFSSH_FXF_WRITE))
|
||||
* CreateFile() fails with ERROR_INVALID_PARAMETER. TRUNC without
|
||||
* WRITE is deliberately ignored and the open succeeds untruncated,
|
||||
* as O_RDONLY|O_TRUNC does on most POSIX systems. */
|
||||
if ((reason & WOLFSSH_FXF_TRUNC) && (reason & WOLFSSH_FXF_WRITE)) {
|
||||
disp = TRUNCATE_EXISTING;
|
||||
else
|
||||
}
|
||||
else {
|
||||
disp = OPEN_EXISTING;
|
||||
}
|
||||
}
|
||||
|
||||
return disp;
|
||||
|
|
@ -2692,12 +2698,15 @@ cleanup:
|
|||
}
|
||||
#endif
|
||||
|
||||
if (reason & WOLFSSH_FXF_READ)
|
||||
if (reason & WOLFSSH_FXF_READ) {
|
||||
desiredAccess |= GENERIC_READ;
|
||||
if (reason & WOLFSSH_FXF_WRITE)
|
||||
}
|
||||
if (reason & WOLFSSH_FXF_WRITE) {
|
||||
desiredAccess |= GENERIC_WRITE;
|
||||
if (reason & WOLFSSH_FXF_APPEND)
|
||||
}
|
||||
if (reason & WOLFSSH_FXF_APPEND) {
|
||||
desiredAccess |= FILE_APPEND_DATA;
|
||||
}
|
||||
|
||||
creationDisp = SFTP_WinCreationDisp(reason);
|
||||
|
||||
|
|
@ -4265,6 +4274,7 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
|
|||
WFD fd = 0;
|
||||
int ret = WS_SUCCESS;
|
||||
int rc;
|
||||
int isAppend = 0;
|
||||
word32 idx = 0;
|
||||
word32 ofst[2] = {0,0};
|
||||
|
||||
|
|
@ -4279,6 +4289,7 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
|
|||
if (ssh == NULL) {
|
||||
return WS_BAD_ARGUMENT;
|
||||
}
|
||||
WOLFSSH_UNUSED(isAppend); /* only read on ports that define WWRITE */
|
||||
|
||||
WLOG(WS_LOG_SFTP, "Receiving WOLFSSH_FTP_WRITE");
|
||||
|
||||
|
|
@ -4313,6 +4324,7 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
|
|||
}
|
||||
else {
|
||||
fd = fileEntry->fd;
|
||||
isAppend = fileEntry->isAppend;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4335,8 +4347,20 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
|
|||
/* Retry while WPWRITE makes forward progress; bail on error
|
||||
* or zero return to avoid spinning on a stuck backend. */
|
||||
while (written < strSz) {
|
||||
ret = WPWRITE(ssh->fs, fd, (byte*)str + written,
|
||||
strSz - written, ofst);
|
||||
#ifdef WWRITE
|
||||
if (isAppend) {
|
||||
/* FXF_APPEND: the offset is ignored and the O_APPEND
|
||||
* fd puts the write at EOF. pwrite() would honor the
|
||||
* offset on every POSIX system but Linux. */
|
||||
ret = WWRITE(ssh->fs, fd, (byte*)str + written,
|
||||
strSz - written);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
ret = WPWRITE(ssh->fs, fd, (byte*)str + written,
|
||||
strSz - written, ofst);
|
||||
}
|
||||
if (ret <= 0) {
|
||||
break;
|
||||
}
|
||||
|
|
@ -4459,8 +4483,8 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
|
|||
* non-atomic read-modify-write: the file is shared FILE_SHARE_WRITE,
|
||||
* so concurrent appenders would resolve the same offset and overwrite
|
||||
* each other. Setting both OVERLAPPED offset fields to 0xFFFFFFFF
|
||||
* tells WriteFile() to append atomically at end of file, matching the
|
||||
* POSIX O_APPEND path. */
|
||||
* tells WriteFile() to append atomically at end of file, matching
|
||||
* the POSIX O_APPEND path. */
|
||||
if (isAppend) {
|
||||
offset.Offset = 0xFFFFFFFF;
|
||||
offset.OffsetHigh = 0xFFFFFFFF;
|
||||
|
|
@ -4473,7 +4497,9 @@ int wolfSSH_SFTP_RecvWrite(WOLFSSH* ssh, int reqId, byte* data, word32 maxSz)
|
|||
return WS_BUFFER_E;
|
||||
}
|
||||
|
||||
if (WriteFile(fd, str, strSz, &bytesWritten, &offset) == 0) {
|
||||
/* A short write is a failure too, as on the POSIX side. */
|
||||
if (WriteFile(fd, str, strSz, &bytesWritten, &offset) == 0 ||
|
||||
bytesWritten != strSz) {
|
||||
WLOG(WS_LOG_SFTP, "Error writing to file");
|
||||
res = err;
|
||||
type = WOLFSSH_FTP_FAILURE;
|
||||
|
|
|
|||
545
tests/regress.c
545
tests/regress.c
|
|
@ -8128,6 +8128,146 @@ static void AssertSftpStatusReply(WOLFSSH* ssh, int reqId, word32 code)
|
|||
AssertIntEQ((int)SftpGetU32(reply + LENGTH_SZ + MSG_ID_SZ), reqId);
|
||||
AssertIntEQ((int)SftpGetU32(reply + WOLFSSH_SFTP_HEADER), (int)code);
|
||||
}
|
||||
|
||||
/* The FXP_HANDLE reply carries the handle after the header and its length. */
|
||||
#define SFTP_TEST_HANDLE_OFF (WOLFSSH_SFTP_HEADER + UINT32_SZ)
|
||||
|
||||
#ifdef USE_WINDOWS_API
|
||||
#define SFTP_TEST_PID() ((unsigned long)GetCurrentProcessId())
|
||||
#else
|
||||
#define SFTP_TEST_PID() ((unsigned long)getpid())
|
||||
#endif
|
||||
|
||||
/* FXP_OPEN path with flags and empty attributes. On success the handle from
|
||||
* the FXP_HANDLE reply is copied to handle. */
|
||||
static int SftpOpenPath(WOLFSSH* ssh, int reqId, const char* path,
|
||||
word32 flags, byte* handle)
|
||||
{
|
||||
byte pkt[WOLFSSH_MAX_FILENAME + 3 * UINT32_SZ];
|
||||
word32 idx = 0;
|
||||
word32 pathSz = (word32)WSTRLEN(path);
|
||||
int ret;
|
||||
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(flags, pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
|
||||
ret = wolfSSH_SFTP_RecvOpen(ssh, reqId, pkt, idx);
|
||||
if (ret == WS_SUCCESS) {
|
||||
const byte* reply;
|
||||
word32 replySz;
|
||||
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= SFTP_TEST_HANDLE_OFF + WOLFSSH_HANDLE_ID_SZ);
|
||||
/* no request id check: RecvOpen stamps the reply with ssh->reqId,
|
||||
* which the dispatch loop sets and a direct call leaves at 0 */
|
||||
AssertIntEQ(reply[LENGTH_SZ], WOLFSSH_FTP_HANDLE);
|
||||
WMEMCPY(handle, reply + SFTP_TEST_HANDLE_OFF, WOLFSSH_HANDLE_ID_SZ);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* FXP_WRITE dataSz bytes at the split 64-bit offset through handle. */
|
||||
static int SftpWriteHandle(WOLFSSH* ssh, int reqId, const byte* handle,
|
||||
word32 ofstHi, word32 ofstLo, const void* data, word32 dataSz)
|
||||
{
|
||||
byte pkt[64 + WOLFSSH_HANDLE_ID_SZ + 4 * UINT32_SZ];
|
||||
word32 idx = 0;
|
||||
|
||||
AssertTrue(dataSz <= 64);
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(ofstHi, pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(ofstLo, pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(dataSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, data, dataSz); idx += dataSz;
|
||||
|
||||
return wolfSSH_SFTP_RecvWrite(ssh, reqId, pkt, idx);
|
||||
}
|
||||
|
||||
/* FXP_CLOSE handle. */
|
||||
static int SftpCloseHandle(WOLFSSH* ssh, int reqId, const byte* handle)
|
||||
{
|
||||
byte pkt[WOLFSSH_HANDLE_ID_SZ + UINT32_SZ];
|
||||
word32 idx = 0;
|
||||
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
|
||||
return wolfSSH_SFTP_RecvClose(ssh, reqId, pkt, idx);
|
||||
}
|
||||
|
||||
/* Assert the file at path holds exactly expSz bytes matching exp. */
|
||||
static void AssertSftpFileContents(const char* path, const void* exp,
|
||||
word32 expSz)
|
||||
{
|
||||
WFILE* file;
|
||||
char readBuf[64];
|
||||
word32 readSz;
|
||||
|
||||
AssertTrue(expSz < sizeof(readBuf));
|
||||
AssertIntEQ(WFOPEN(NULL, &file, path, "rb"), 0);
|
||||
AssertTrue(file != WBADFILE);
|
||||
readSz = (word32)WFREAD(NULL, readBuf, 1, sizeof(readBuf), file);
|
||||
WFCLOSE(NULL, file);
|
||||
AssertIntEQ((int)readSz, (int)expSz);
|
||||
AssertIntEQ(WMEMCMP(readBuf, exp, expSz), 0);
|
||||
}
|
||||
|
||||
/* FXF_APPEND puts every write at EOF whatever offset the client sends
|
||||
* (draft-ietf-secsh-filexfer-02 6.3). On Windows that is the OVERLAPPED
|
||||
* 0xFFFFFFFF encoding; on POSIX it needs write() rather than pwrite(),
|
||||
* which ignores O_APPEND everywhere but Linux. */
|
||||
static void TestSftpAppendWritesAtEof(void)
|
||||
{
|
||||
WOLFSSH_CTX* ctx;
|
||||
WOLFSSH* ssh;
|
||||
int rid = 600;
|
||||
WSTAT_T st;
|
||||
byte handle[WOLFSSH_HANDLE_ID_SZ];
|
||||
char cwd[WOLFSSH_MAX_FILENAME];
|
||||
char path[64];
|
||||
const char content[] = "0123456789";
|
||||
const char content2[] = "abcde";
|
||||
const char expect[] = "0123456789abcde";
|
||||
|
||||
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
|
||||
AssertNotNull(ctx);
|
||||
ssh = wolfSSH_new(ctx);
|
||||
AssertNotNull(ssh);
|
||||
AssertIntEQ(wolfSSH_SFTP_TestRecvStateInit(ssh), WS_SUCCESS);
|
||||
|
||||
WSNPRINTF(path, sizeof(path), "wolfssh_append_%lu.tmp", SFTP_TEST_PID());
|
||||
WMEMSET(cwd, 0, sizeof(cwd));
|
||||
AssertNotNull(WGETCWD(ssh->fs, cwd, sizeof(cwd) - 1));
|
||||
AssertIntEQ(wolfSSH_SFTP_SetDefaultPath(ssh, cwd), WS_SUCCESS);
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_APPEND | WOLFSSH_FXF_CREAT,
|
||||
handle), WS_SUCCESS);
|
||||
/* first write at offset 0 lands at EOF 0 */
|
||||
AssertIntEQ(SftpWriteHandle(ssh, rid++, handle, 0, 0,
|
||||
content, (word32)(sizeof(content) - 1)), WS_SUCCESS);
|
||||
/* stale offset 0 again: must append, not overwrite the start */
|
||||
AssertIntEQ(SftpWriteHandle(ssh, rid++, handle, 0, 0,
|
||||
content2, (word32)(sizeof(content2) - 1)), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, (int)(sizeof(expect) - 1));
|
||||
AssertSftpFileContents(path, expect, (word32)(sizeof(expect) - 1));
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
wolfSSH_SFTP_TestRecvStateFree(ssh);
|
||||
wolfSSH_free(ssh);
|
||||
wolfSSH_CTX_free(ctx);
|
||||
}
|
||||
#endif /* !NO_WOLFSSH_SERVER && !NO_FILESYSTEM */
|
||||
|
||||
#if !defined(NO_WOLFSSH_SERVER) && !defined(USE_WINDOWS_API) && \
|
||||
|
|
@ -9217,21 +9357,14 @@ static void TestSftpWindowsOpenFlagMatrix(void)
|
|||
WOLFSSH* ssh;
|
||||
int rid = 500;
|
||||
int reqId;
|
||||
word32 idx;
|
||||
word32 replySz;
|
||||
const byte* reply;
|
||||
const word32 hOff = WOLFSSH_SFTP_HEADER + UINT32_SZ; /* handle in reply */
|
||||
WSTAT_T st;
|
||||
byte handle[WOLFSSH_HANDLE_ID_SZ];
|
||||
byte pkt[256];
|
||||
char cwd[WOLFSSH_MAX_FILENAME];
|
||||
char path[64];
|
||||
word32 pathSz;
|
||||
const char content[] = "0123456789";
|
||||
const char content2[] = "abcde";
|
||||
WFILE* file;
|
||||
char readBuf[32];
|
||||
word32 readSz;
|
||||
const word32 contentSz = (word32)(sizeof(content) - 1);
|
||||
const word32 content2Sz = (word32)(sizeof(content2) - 1);
|
||||
|
||||
ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL);
|
||||
AssertNotNull(ctx);
|
||||
|
|
@ -9241,8 +9374,7 @@ static void TestSftpWindowsOpenFlagMatrix(void)
|
|||
|
||||
/* unique per-process fixture name so parallel runs don't collide */
|
||||
WSNPRINTF(path, sizeof(path), "wolfssh_winflags_%lu.tmp",
|
||||
(unsigned long)GetCurrentProcessId());
|
||||
pathSz = (word32)WSTRLEN(path);
|
||||
SFTP_TEST_PID());
|
||||
|
||||
WMEMSET(cwd, 0, sizeof(cwd));
|
||||
AssertNotNull(WGETCWD(ssh->fs, cwd, sizeof(cwd) - 1));
|
||||
|
|
@ -9251,390 +9383,123 @@ static void TestSftpWindowsOpenFlagMatrix(void)
|
|||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
/* WRITE only, no CREAT: must fail against a missing file, untouched. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE, pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
reqId = rid++;
|
||||
AssertTrue(wolfSSH_SFTP_RecvOpen(ssh, reqId, pkt, idx) != WS_SUCCESS);
|
||||
AssertTrue(SftpOpenPath(ssh, reqId, path, WOLFSSH_FXF_WRITE, handle)
|
||||
!= WS_SUCCESS);
|
||||
AssertSftpStatusReply(ssh, reqId, WOLFSSH_FTP_FAILURE);
|
||||
AssertTrue(WSTAT(ssh->fs, path, &st) != 0);
|
||||
|
||||
/* WRITE|CREAT, no TRUNC: must create the missing file (OPEN_ALWAYS). */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
/* seed content through the handle just opened */
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset hi */
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset lo */
|
||||
SftpPutU32((word32)(sizeof(content) - 1), pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, content, sizeof(content) - 1);
|
||||
idx += (word32)(sizeof(content) - 1);
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvWrite(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
/* WRITE|CREAT, no TRUNC: must create the missing file (OPEN_ALWAYS).
|
||||
* Seed content through the handle just opened. */
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, handle), WS_SUCCESS);
|
||||
AssertIntEQ(SftpWriteHandle(ssh, rid++, handle, 0, 0, content,
|
||||
contentSz), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, (int)(sizeof(content) - 1));
|
||||
AssertIntEQ((int)st.st_size, (int)contentSz);
|
||||
|
||||
/* WRITE|CREAT, no TRUNC, on the existing file: must not truncate it. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, (int)(sizeof(content) - 1));
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
AssertIntEQ((int)st.st_size, (int)contentSz);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
|
||||
/* WRITE|CREAT|TRUNC: must truncate the existing file immediately. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT | WOLFSSH_FXF_TRUNC,
|
||||
pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT | WOLFSSH_FXF_TRUNC,
|
||||
handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, 0);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
|
||||
/* WRITE|CREAT|EXCL against the existing file: must fail. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT | WOLFSSH_FXF_EXCL,
|
||||
pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
reqId = rid++;
|
||||
AssertTrue(wolfSSH_SFTP_RecvOpen(ssh, reqId, pkt, idx) != WS_SUCCESS);
|
||||
AssertTrue(SftpOpenPath(ssh, reqId, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT | WOLFSSH_FXF_EXCL,
|
||||
handle) != WS_SUCCESS);
|
||||
AssertSftpStatusReply(ssh, reqId, WOLFSSH_FTP_FAILURE);
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
/* WRITE|CREAT|EXCL against a missing path: must succeed. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT | WOLFSSH_FXF_EXCL,
|
||||
pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT | WOLFSSH_FXF_EXCL,
|
||||
handle), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
/* READ|WRITE|CREAT, no TRUNC, against a missing path: must create it. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_READ | WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT,
|
||||
pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_READ | WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT,
|
||||
handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
/* WRITE|TRUNC, no CREAT, against a missing path: must fail
|
||||
* (TRUNCATE_EXISTING requires the file to already exist). */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_TRUNC, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
reqId = rid++;
|
||||
AssertTrue(wolfSSH_SFTP_RecvOpen(ssh, reqId, pkt, idx) != WS_SUCCESS);
|
||||
AssertTrue(SftpOpenPath(ssh, reqId, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_TRUNC, handle) != WS_SUCCESS);
|
||||
AssertSftpStatusReply(ssh, reqId, WOLFSSH_FTP_FAILURE);
|
||||
|
||||
/* seed an existing file with content, then WRITE|TRUNC, no CREAT: must
|
||||
* truncate it immediately (TRUNCATE_EXISTING). */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset hi */
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset lo */
|
||||
SftpPutU32((word32)(sizeof(content) - 1), pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, content, sizeof(content) - 1);
|
||||
idx += (word32)(sizeof(content) - 1);
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvWrite(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, handle), WS_SUCCESS);
|
||||
AssertIntEQ(SftpWriteHandle(ssh, rid++, handle, 0, 0, content,
|
||||
contentSz), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, (int)(sizeof(content) - 1));
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_TRUNC, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
AssertIntEQ((int)st.st_size, (int)contentSz);
|
||||
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_TRUNC, handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, 0);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
/* seed an existing file with content for the READ|TRUNC case below. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset hi */
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset lo */
|
||||
SftpPutU32((word32)(sizeof(content) - 1), pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, content, sizeof(content) - 1);
|
||||
idx += (word32)(sizeof(content) - 1);
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvWrite(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_WRITE | WOLFSSH_FXF_CREAT, handle), WS_SUCCESS);
|
||||
AssertIntEQ(SftpWriteHandle(ssh, rid++, handle, 0, 0, content,
|
||||
contentSz), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, (int)(sizeof(content) - 1));
|
||||
AssertIntEQ((int)st.st_size, (int)contentSz);
|
||||
|
||||
/* READ|TRUNC, no WRITE, no CREAT: TRUNCATE_EXISTING requires
|
||||
* GENERIC_WRITE in dwDesiredAccess, so this must still open (falling
|
||||
* back to OPEN_EXISTING) rather than fail with ERROR_INVALID_PARAMETER,
|
||||
* and must leave the content untouched since it cannot actually
|
||||
* truncate. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_READ | WOLFSSH_FXF_TRUNC, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
reqId = rid++;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, reqId, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_READ | WOLFSSH_FXF_TRUNC, handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size, (int)(sizeof(content) - 1));
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
/* WRITE|APPEND|CREAT against a missing path: must create it, and every
|
||||
* write must land at EOF regardless of the client-supplied offset. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_WRITE | WOLFSSH_FXF_APPEND | WOLFSSH_FXF_CREAT,
|
||||
pkt + idx); idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
/* first write, offset 0: lands at EOF (0), file becomes "0123456789" */
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset hi */
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset lo */
|
||||
SftpPutU32((word32)(sizeof(content) - 1), pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, content, sizeof(content) - 1);
|
||||
idx += (word32)(sizeof(content) - 1);
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvWrite(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
/* second write, offset stale at 0 again: must still append at EOF (10)
|
||||
* rather than overwrite the start of the file. */
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset hi */
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset lo */
|
||||
SftpPutU32((word32)(sizeof(content2) - 1), pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, content2, sizeof(content2) - 1);
|
||||
idx += (word32)(sizeof(content2) - 1);
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvWrite(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size,
|
||||
(int)(sizeof(content) - 1 + sizeof(content2) - 1));
|
||||
|
||||
/* content, not just length: a build that appended the right byte
|
||||
* count in the wrong order, or left a gap, would still pass the size
|
||||
* check above. */
|
||||
AssertIntEQ(WFOPEN(NULL, &file, path, "rb"), 0);
|
||||
AssertTrue(file != WBADFILE);
|
||||
readSz = (word32)WFREAD(NULL, readBuf, 1,
|
||||
sizeof(content) - 1 + sizeof(content2) - 1, file);
|
||||
WFCLOSE(NULL, file);
|
||||
AssertIntEQ((int)readSz,
|
||||
(int)(sizeof(content) - 1 + sizeof(content2) - 1));
|
||||
AssertIntEQ(WMEMCMP(readBuf, "0123456789abcde", readSz), 0);
|
||||
AssertIntEQ((int)st.st_size, (int)contentSz);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
|
||||
/* APPEND|CREAT, no WRITE: FILE_APPEND_DATA alone is enough to create
|
||||
* the file and append to it, unlike master, which could not open this
|
||||
* combination at all. */
|
||||
idx = 0;
|
||||
SftpPutU32(pathSz, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, path, pathSz); idx += pathSz;
|
||||
SftpPutU32(WOLFSSH_FXF_APPEND | WOLFSSH_FXF_CREAT, pkt + idx);
|
||||
idx += UINT32_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvOpen(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
reply = wolfSSH_SFTP_TestRecvReply(ssh, &replySz);
|
||||
AssertNotNull(reply);
|
||||
AssertTrue(replySz >= hOff + WOLFSSH_HANDLE_ID_SZ);
|
||||
WMEMCPY(handle, reply + hOff, WOLFSSH_HANDLE_ID_SZ);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset hi */
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset lo */
|
||||
SftpPutU32((word32)(sizeof(content) - 1), pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, content, sizeof(content) - 1);
|
||||
idx += (word32)(sizeof(content) - 1);
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvWrite(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset hi */
|
||||
SftpPutU32(0, pkt + idx); idx += UINT32_SZ; /* offset lo */
|
||||
SftpPutU32((word32)(sizeof(content2) - 1), pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, content2, sizeof(content2) - 1);
|
||||
idx += (word32)(sizeof(content2) - 1);
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvWrite(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
idx = 0;
|
||||
SftpPutU32(WOLFSSH_HANDLE_ID_SZ, pkt + idx); idx += UINT32_SZ;
|
||||
WMEMCPY(pkt + idx, handle, WOLFSSH_HANDLE_ID_SZ);
|
||||
idx += WOLFSSH_HANDLE_ID_SZ;
|
||||
AssertIntEQ(wolfSSH_SFTP_RecvClose(ssh, rid++, pkt, idx), WS_SUCCESS);
|
||||
|
||||
* combination at all. (WRITE|APPEND|CREAT is covered on every platform
|
||||
* by TestSftpAppendWritesAtEof.) */
|
||||
AssertIntEQ(SftpOpenPath(ssh, rid++, path,
|
||||
WOLFSSH_FXF_APPEND | WOLFSSH_FXF_CREAT, handle), WS_SUCCESS);
|
||||
AssertIntEQ(SftpWriteHandle(ssh, rid++, handle, 0, 0, content,
|
||||
contentSz), WS_SUCCESS);
|
||||
AssertIntEQ(SftpWriteHandle(ssh, rid++, handle, 0, 0, content2,
|
||||
content2Sz), WS_SUCCESS);
|
||||
AssertIntEQ(SftpCloseHandle(ssh, rid++, handle), WS_SUCCESS);
|
||||
AssertIntEQ(WSTAT(ssh->fs, path, &st), 0);
|
||||
AssertIntEQ((int)st.st_size,
|
||||
(int)(sizeof(content) - 1 + sizeof(content2) - 1));
|
||||
AssertIntEQ((int)st.st_size, (int)(contentSz + content2Sz));
|
||||
|
||||
(void)WREMOVE(ssh->fs, path);
|
||||
wolfSSH_SFTP_TestRecvStateFree(ssh);
|
||||
|
|
@ -12498,6 +12363,10 @@ int main(int argc, char** argv)
|
|||
/* SETSTAT/FSETSTAT apply the attributes they acknowledge */
|
||||
TestSftpSetStatAttributes();
|
||||
#endif
|
||||
#if !defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM)
|
||||
/* FXF_APPEND writes land at EOF regardless of the request offset */
|
||||
TestSftpAppendWritesAtEof();
|
||||
#endif
|
||||
#if !defined(NO_WOLFSSH_SERVER) && defined(USE_WINDOWS_API) && \
|
||||
!defined(NO_FILESYSTEM)
|
||||
/* RecvOpen's Windows open-flag matrix */
|
||||
|
|
|
|||
|
|
@ -1630,6 +1630,10 @@ extern "C" {
|
|||
const unsigned int* shortOffset);
|
||||
#define WPWRITE(fs,fd,b,s,o) wPwrite((fd),(b),(s),(o))
|
||||
#define WPREAD(fs,fd,b,s,o) wPread((fd),(b),(s),(o))
|
||||
/* Positionless write, for O_APPEND handles: pwrite() only honors
|
||||
* O_APPEND on Linux, write() does everywhere. */
|
||||
#define WWRITE(fs,fd,b,s) (int)write((fd),(b),(s))
|
||||
|
||||
|
||||
#define WTRUNCATE(fs,f,sz) truncate((f),(off_t)(sz))
|
||||
#define WFTRUNCATE(fs,fd,sz) ftruncate((fd),(off_t)(sz))
|
||||
|
|
|
|||
Loading…
Reference in New Issue