1
0
mirror of https://github.com/pgbackrest/pgbackrest.git synced 2024-12-04 09:43:08 +02:00

Improve SFTP error messages.

The numbers by themselves weren't very informative and required looking into the libssh2_sftp.h header file for the definition.
This commit is contained in:
Reid Thompson 2024-10-10 04:17:35 -04:00 committed by GitHub
parent c8ccaaa755
commit 70bda2cfb2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 200 additions and 46 deletions

View File

@ -104,6 +104,17 @@
<p>Remove limitation on reading files in parallel during restore.</p>
</release-item>
<release-item>
<github-pull-request id="2439"/>
<release-item-contributor-list>
<release-item-contributor id="reid.thompson"/>
<release-item-reviewer id="david.steele"/>
</release-item-contributor-list>
<p>Improve <proper>SFTP</proper> error messages.</p>
</release-item>
</release-improvement-list>
<release-development-list>

View File

@ -92,6 +92,113 @@ storageSftpKnownHostKeyType(const int hostKeyType)
FUNCTION_TEST_RETURN(INT, result);
}
/***********************************************************************************************************************************
Return error message based on error code
***********************************************************************************************************************************/
static const char *
libssh2SftpErrorMsg(const uint64_t error)
{
FUNCTION_TEST_BEGIN();
FUNCTION_TEST_PARAM(UINT64, error);
FUNCTION_TEST_END();
const char *result;
// SFTP error status codes (returned by libssh2_sftp_last_error()
switch (error)
{
case LIBSSH2_FX_EOF:
result = "eof";
break;
case LIBSSH2_FX_NO_SUCH_FILE:
result = "no such file";
break;
case LIBSSH2_FX_PERMISSION_DENIED:
result = "permission denied";
break;
case LIBSSH2_FX_FAILURE:
result = "failure";
break;
case LIBSSH2_FX_BAD_MESSAGE:
result = "bad message";
break;
case LIBSSH2_FX_NO_CONNECTION:
result = "no connection";
break;
case LIBSSH2_FX_CONNECTION_LOST:
result = "connection lost";
break;
case LIBSSH2_FX_OP_UNSUPPORTED:
result = "operation unsupported";
break;
case LIBSSH2_FX_INVALID_HANDLE:
result = "invalid handle";
break;
case LIBSSH2_FX_NO_SUCH_PATH:
result = "no such path";
break;
case LIBSSH2_FX_FILE_ALREADY_EXISTS:
result = "file already exists";
break;
case LIBSSH2_FX_WRITE_PROTECT:
result = "write protect";
break;
case LIBSSH2_FX_NO_MEDIA:
result = "no media";
break;
case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
result = "no space on filesystem";
break;
case LIBSSH2_FX_QUOTA_EXCEEDED:
result = "quota exceeded";
break;
case LIBSSH2_FX_UNKNOWN_PRINCIPAL:
result = "unknown principal";
break;
case LIBSSH2_FX_LOCK_CONFLICT:
result = "lock conflict";
break;
case LIBSSH2_FX_DIR_NOT_EMPTY:
result = "directory not empty";
break;
case LIBSSH2_FX_NOT_A_DIRECTORY:
result = "not a directory";
break;
case LIBSSH2_FX_INVALID_FILENAME:
result = "invalid filename";
break;
case LIBSSH2_FX_LINK_LOOP:
result = "link loop";
break;
default:
result = "unknown error";
break;
}
FUNCTION_TEST_RETURN_CONST(STRINGZ, result);
}
/***********************************************************************************************************************************
Return a match failed message based on known host check failure type
***********************************************************************************************************************************/
@ -301,7 +408,8 @@ storageSftpLibSsh2SessionFreeResource(THIS_VOID)
THROW_FMT(
ServiceError, "failed to shutdown sftpSession: libssh2 errno [%d]%s", rc,
rc == LIBSSH2_ERROR_SFTP_PROTOCOL ?
strZ(strNewFmt(": sftp errno [%lu]", libssh2_sftp_last_error(this->sftpSession))) : "");
strZ(strNewFmt(": sftp errno [%lu] %s", libssh2_sftp_last_error(this->sftpSession),
libssh2SftpErrorMsg(libssh2_sftp_last_error(this->sftpSession)))) : "");
else
THROW_FMT(
ServiceError, "timeout shutting down sftpSession: libssh2 errno [%d]", rc);
@ -363,7 +471,8 @@ storageSftpEvalLibSsh2Error(
THROWP_FMT(
errorType, "%s%s%s%s", message != NULL ? zNewFmt("%s%s", strZ(message), ssh2Errno == 0 ? "" : ": ") : "",
ssh2Errno == 0 ? "" : zNewFmt("libssh2 error [%d]", ssh2Errno),
ssh2Errno == LIBSSH2_ERROR_SFTP_PROTOCOL ? zNewFmt(": sftp error [%" PRIu64 "]", sftpErrno) : "",
ssh2Errno == LIBSSH2_ERROR_SFTP_PROTOCOL ?
zNewFmt(": sftp error [%" PRIu64 "] %s", sftpErrno, libssh2SftpErrorMsg(sftpErrno)) : "",
hint != NULL ? zNewFmt("\n%s", strZ(hint)) : "");
FUNCTION_TEST_NO_RETURN();
@ -1011,8 +1120,8 @@ storageSftpPathRemove(THIS_VOID, const String *const path, const bool recurse, c
else
{
THROW_FMT(
PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE " libssh sftp [%" PRIu64 "]", strZ(file),
sftpErrno);
PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE " libssh sftp [%" PRIu64 "] %s", strZ(file),
sftpErrno, libssh2SftpErrorMsg(sftpErrno));
}
}
else
@ -1046,7 +1155,11 @@ storageSftpPathRemove(THIS_VOID, const String *const path, const bool recurse, c
const uint64_t sftpErrno = libssh2_sftp_last_error(this->sftpSession);
if (sftpErrno != LIBSSH2_FX_NO_SUCH_FILE)
THROW_FMT(PathRemoveError, STORAGE_ERROR_PATH_REMOVE " sftp error [%" PRIu64 "]", strZ(path), sftpErrno);
{
THROW_FMT(
PathRemoveError, STORAGE_ERROR_PATH_REMOVE " sftp error [%" PRIu64 "] %s", strZ(path), sftpErrno,
libssh2SftpErrorMsg(sftpErrno));
}
// Path does not exist
result = false;

View File

@ -626,7 +626,7 @@ unit:
# ----------------------------------------------------------------------------------------------------------------------------
- name: sftp
total: 19
total: 20
harness:
name: libSsh2
integration: false

View File

@ -2158,10 +2158,12 @@ testRun(void)
TEST_ERROR_FMT(
storageExistsP(storageTest, fileNoPerm),
FileOpenError, STORAGE_ERROR_INFO ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
FileOpenError,
STORAGE_ERROR_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(fileNoPerm));
TEST_ERROR_FMT(
storagePathExistsP(storageTest, fileNoPerm),
FileOpenError, STORAGE_ERROR_INFO ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
FileOpenError,
STORAGE_ERROR_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(fileNoPerm));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file and path");
@ -2230,7 +2232,8 @@ testRun(void)
TEST_ERROR_FMT(
storageInfoP(storageTest, fileNoPerm),
FileOpenError, STORAGE_ERROR_INFO ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
FileOpenError,
STORAGE_ERROR_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -2566,7 +2569,7 @@ testRun(void)
// libssh2_sftp_symlink_ex fail link destination followLink false
TEST_ERROR_FMT(
storageInfoP(storageTest, linkName, .followLink = false), FileReadError,
"unable to get destination for link '" TEST_PATH "/testlink': libssh2 error [-31]: sftp error [21]");
"unable to get destination for link '" TEST_PATH "/testlink': libssh2 error [-31]: sftp error [21] link loop");
// --------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("info - pipe");
@ -2774,12 +2777,12 @@ testRun(void)
TEST_ERROR_FMT(
storageNewItrP(storageTest, pathNoPerm, .errorOnMissing = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(pathNoPerm));
// Should still error even when ignore missing
TEST_ERROR_FMT(
storageNewItrP(storageTest, pathNoPerm), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(pathNoPerm));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("helper function - storageSftpListEntry()");
@ -3740,12 +3743,12 @@ testRun(void)
TEST_ERROR_FMT(
storageListP(storageTest, pathNoPerm, .errorOnMissing = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(pathNoPerm));
// Should still error even when ignore missing
TEST_ERROR_FMT(
storageListP(storageTest, pathNoPerm), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathNoPerm));
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(pathNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -4125,7 +4128,7 @@ testRun(void)
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("sub3/sub4"), .noParentCreate = true), PathCreateError,
"sftp error unable to create path '" TEST_PATH "/sub3/sub4': libssh2 error [-31]: sftp error [2]");
"sftp error unable to create path '" TEST_PATH "/sub3/sub4': libssh2 error [-31]: sftp error [2] no such file");
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("sub3/sub4")), "create sub3/sub4");
// LIBSSH2_ERROR_EAGAIN timeout fail
@ -4184,7 +4187,7 @@ testRun(void)
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("subfail")), "timeout success");
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("subfail"), .noParentCreate = true), PathCreateError,
"sftp error unable to create path '" TEST_PATH "/subfail': libssh2 error [-31]: sftp error [3]");
"sftp error unable to create path '" TEST_PATH "/subfail': libssh2 error [-31]: sftp error [3] permission denied");
TEST_RESULT_VOID(storagePathCreateP(storageTest, STRDEF("subfail")), "do not throw error on already exists");
TEST_ERROR(
storagePathCreateP(storageTest, STRDEF("subfail"), .errorOnExists = true), PathCreateError,
@ -4391,11 +4394,11 @@ testRun(void)
// Mimic creation of pathRemove2 mode 700
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove2), PathRemoveError, STORAGE_ERROR_PATH_REMOVE " sftp error [3]",
strZ(pathRemove2));
storagePathRemoveP(storageTest, pathRemove2), PathRemoveError,
STORAGE_ERROR_PATH_REMOVE " sftp error [3] permission denied", strZ(pathRemove2));
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove2, .recurse = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathRemove2));
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - subpath permission denied");
@ -4403,7 +4406,7 @@ testRun(void)
// Mimic chmod 777 pathRemove1
TEST_ERROR_FMT(
storagePathRemoveP(storageTest, pathRemove2, .recurse = true), PathOpenError,
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3]", strZ(pathRemove2));
STORAGE_ERROR_LIST_INFO ": libssh2 error [-31]: sftp error [3] permission denied", strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - file in subpath, permission denied");
@ -4412,9 +4415,8 @@ testRun(void)
// Mimic "sudo chmod 755 %s && sudo touch %s && sudo chmod 777 %s", strZ(pathRemove2), strZ(fileRemove), strZ(fileRemove));
TEST_ERROR_FMT(
storagePathRemoveP(
storageTest, pathRemove1, .recurse = true), PathRemoveError, STORAGE_ERROR_PATH_REMOVE " sftp error [3]",
strZ(pathRemove2));
storagePathRemoveP(storageTest, pathRemove1, .recurse = true), PathRemoveError,
STORAGE_ERROR_PATH_REMOVE " sftp error [3] permission denied", strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - path with subpath and file removed");
@ -4426,17 +4428,15 @@ testRun(void)
TEST_TITLE("path remove - path with subpath ssh fail on unlink");
TEST_ERROR_FMT(
storagePathRemoveP(
storageTest, pathRemove1, .recurse = true), PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE " libssh ssh [-7]",
strZ(pathRemove2));
storagePathRemoveP(storageTest, pathRemove1, .recurse = true), PathRemoveError,
STORAGE_ERROR_PATH_REMOVE_FILE " libssh ssh [-7]", strZ(pathRemove2));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("path remove - other than LIBSSH2_FX_FAILURE/LIBSSH2_FX_PERMISSION_DENIED");
TEST_ERROR_FMT(
storagePathRemoveP(
storageTest, pathRemove1, .recurse = true), PathRemoveError, STORAGE_ERROR_PATH_REMOVE_FILE " libssh sftp [7]",
strZ(pathRemove2));
storagePathRemoveP(storageTest, pathRemove1, .recurse = true), PathRemoveError,
STORAGE_ERROR_PATH_REMOVE_FILE " libssh sftp [7] connection lost", strZ(pathRemove2));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -4958,7 +4958,7 @@ testRun(void)
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileNoPerm, .noAtomic = true, .noCreatePath = false), "new write file");
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)), FileOpenError,
STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3] permission denied", strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -5270,7 +5270,8 @@ testRun(void)
TEST_RESULT_INT(ioWriteFd(storageWriteIo(file)), -1, "check write fd");
TEST_ERROR_FMT(
ioWriteClose(storageWriteIo(file)), FileCloseError,
"unable to move '%s' to '%s': libssh2 error [-31]: sftp error [7]", strZ(fileNameTmp), strZ(fileName));
"unable to move '%s' to '%s': libssh2 error [-31]: sftp error [7] connection lost", strZ(fileNameTmp),
strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -5681,7 +5682,7 @@ testRun(void)
{.function = HRNLIBSSH2_SESSION_BLOCK_DIRECTIONS, .resultInt = SSH2_NO_BLOCK_READING_WRITING},
{.function = HRNLIBSSH2_SFTP_UNLINK_EX, .param = "[\"" TEST_PATH "/test.empty\"]",
.resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_OK},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = 99},
HRNLIBSSH2_MACRO_SHUTDOWN()
});
@ -5698,7 +5699,7 @@ testRun(void)
TEST_ERROR(
storagePutP(storageNewWriteP(storageTest, emptyFile), NULL), FileRemoveError,
"unable to remove existing '" TEST_PATH "/test.empty': libssh2 error [-31]: sftp error [0]");
"unable to remove existing '" TEST_PATH "/test.empty': libssh2 error [-31]: sftp error [99] unknown error");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -6360,7 +6361,7 @@ testRun(void)
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(storageRemoveP(storageTest, STRDEF("missing"), .errorOnMissing = true), FileRemoveError,
"unable to remove '/missing': libssh2 error [-31]: sftp error [2]");
"unable to remove '/missing': libssh2 error [-31]: sftp error [2] no such file");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -6390,7 +6391,7 @@ testRun(void)
.knownHosts = strLstNewVarLst(cfgOptionIdxLst(cfgOptRepoSftpKnownHost, repoIdx)), .write = true);
TEST_ERROR(storageRemoveP(storageTest, STRDEF("missing")), FileRemoveError,
"unable to remove '/missing': libssh2 error [-31]: sftp error [7]");
"unable to remove '/missing': libssh2 error [-31]: sftp error [7] connection lost");
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -6559,7 +6560,7 @@ testRun(void)
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileName, .noSyncFile = true), "storageWriteSftpOpen sftp error");
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)), FileOpenError,
STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3]", strZ(fileName));
STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3] permission denied", strZ(fileName));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -6659,7 +6660,7 @@ testRun(void)
TEST_ERROR_FMT(
ioReadOpen(storageReadIo(file)),
FileOpenError,
STORAGE_ERROR_READ_OPEN ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
STORAGE_ERROR_READ_OPEN ": libssh2 error [-31]: sftp error [3] permission denied", strZ(fileNoPerm));
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("file missing");
@ -6902,7 +6903,8 @@ testRun(void)
TEST_ASSIGN(file, storageNewWriteP(storageTest, fileNoPerm, .noAtomic = true), "new write file");
TEST_ERROR_FMT(
ioWriteOpen(storageWriteIo(file)),
FileOpenError, STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3]", strZ(fileNoPerm));
FileOpenError, STORAGE_ERROR_WRITE_OPEN ": libssh2 error [-31]: sftp error [3] permission denied",
strZ(fileNoPerm));
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest)));
@ -7663,6 +7665,7 @@ testRun(void)
HRNLIBSSH2_MACRO_STARTUP(),
{.function = HRNLIBSSH2_SFTP_SHUTDOWN, .resultInt = LIBSSH2_ERROR_SFTP_PROTOCOL},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
{.function = HRNLIBSSH2_SFTP_LAST_ERROR, .resultUInt = LIBSSH2_FX_CONNECTION_LOST},
{.function = NULL},
});
@ -7682,7 +7685,7 @@ testRun(void)
TEST_ASSIGN(storageSftp, storageDriver(storageTest), "assign storage");
TEST_ERROR_FMT(
memContextFree(objMemContext((StorageSftp *)storageDriver(storageTest))), ServiceError,
"failed to shutdown sftpSession: libssh2 errno [-31]: sftp errno [7]");
"failed to shutdown sftpSession: libssh2 errno [-31]: sftp errno [7] connection lost");
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("storageSftpLibSsh2SessionFreeResource() sftp shutdown failure EAGAIN");
@ -7859,19 +7862,46 @@ testRun(void)
LIBSSH2_ERROR_SFTP_PROTOCOL, 16, &FileRemoveError,
strNewFmt("unable to move '%s' to '%s'", "BOGUS", "NOT BOGUS"), STRDEF("HINT")),
FileRemoveError,
"unable to move 'BOGUS' to 'NOT BOGUS': libssh2 error [-31]: sftp error [16]\n"
"unable to move 'BOGUS' to 'NOT BOGUS': libssh2 error [-31]: sftp error [16] unknown principal\n"
"HINT");
TEST_ERROR_FMT(
storageSftpEvalLibSsh2Error(
LIBSSH2_ERROR_SFTP_PROTOCOL, 16, &FileRemoveError,
strNewFmt("unable to move '%s' to '%s'", "BOGUS", "NOT BOGUS"), NULL),
FileRemoveError,
"unable to move 'BOGUS' to 'NOT BOGUS': libssh2 error [-31]: sftp error [16]");
FileRemoveError, "unable to move 'BOGUS' to 'NOT BOGUS': libssh2 error [-31]: sftp error [16] unknown principal");
TEST_ERROR_FMT(
storageSftpEvalLibSsh2Error(
LIBSSH2_ERROR_SFTP_PROTOCOL, 16, &FileRemoveError, NULL, NULL),
FileRemoveError,
"libssh2 error [-31]: sftp error [16]");
storageSftpEvalLibSsh2Error(LIBSSH2_ERROR_SFTP_PROTOCOL, 16, &FileRemoveError, NULL, NULL),
FileRemoveError, "libssh2 error [-31]: sftp error [16] unknown principal");
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2
}
// *****************************************************************************************************************************
if (testBegin("libssh2SftpErrorMsg()"))
{
#ifdef HAVE_LIBSSH2
// -------------------------------------------------------------------------------------------------------------------------
TEST_TITLE("libssh2SftpErrorMsg()");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_EOF), "eof", "LIBSSH2_FX_EOF");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_FAILURE), "failure", "LIBSSH2_FX_FAILURE");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_BAD_MESSAGE), "bad message", "LIBSSH2_FX_BAD_MESSAGE");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_NO_CONNECTION), "no connection", "LIBSSH2_FX_NO_CONNECTION");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_OP_UNSUPPORTED), "operation unsupported", "LIBSSH2_FX_OP_UNSUPPORTED");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_INVALID_HANDLE), "invalid handle", "LIBSSH2_FX_INVALID_HANDLE");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_NO_SUCH_PATH), "no such path", "LIBSSH2_FX_NO_SUCH_PATH");
TEST_RESULT_Z(
libssh2SftpErrorMsg(LIBSSH2_FX_FILE_ALREADY_EXISTS), "file already exists", "LIBSSH2_FX_FILE_ALREADY_EXISTS");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_WRITE_PROTECT), "write protect", "LIBSSH2_FX_WRITE_PROTECT");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_NO_MEDIA), "no media", "LIBSSH2_FX_NO_MEDIA");
TEST_RESULT_Z(
libssh2SftpErrorMsg(LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM), "no space on filesystem", "LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_QUOTA_EXCEEDED), "quota exceeded", "LIBSSH2_FX_QUOTA_EXCEEDED");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_LOCK_CONFLICT), "lock conflict", "LIBSSH2_FX_LOCK_CONFLICT");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_DIR_NOT_EMPTY), "directory not empty", "LIBSSH2_FX_DIR_NOT_EMPTY");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_NOT_A_DIRECTORY), "not a directory", "LIBSSH2_FX_NOT_A_DIRECTORY");
TEST_RESULT_Z(libssh2SftpErrorMsg(LIBSSH2_FX_INVALID_FILENAME), "invalid filename", "LIBSSH2_FX_INVALID_FILENAME");
#else
TEST_LOG(PROJECT_NAME " not built with sftp support");
#endif // HAVE_LIBSSH2