|
|
@@ -437,7 +437,7 @@ const std::regex parseReg4(R"(^-.*$)");
|
|
|
*/
|
|
|
static bool parseFileInfo(const std::string& strSrc, std::vector<CF_FileInfo>& fileInfo)
|
|
|
{
|
|
|
- SPDLOG_DEBUG("SRC FILE INFO:\n{}", strSrc);
|
|
|
+ // SPDLOG_DEBUG("SRC FILE INFO:\n{}", strSrc);
|
|
|
#if defined(_WIN32)
|
|
|
// auto str1 = GBToUTF8(strSrc.c_str());
|
|
|
std::string str2 = strSrc;
|
|
|
@@ -459,35 +459,42 @@ static bool parseFileInfo(const std::string& strSrc, std::vector<CF_FileInfo>& f
|
|
|
// std::regex reg3(R"(^d.*)");
|
|
|
// /* 匹配文件 */
|
|
|
// std::regex reg4(R"(^-.*$)");
|
|
|
-
|
|
|
- /* -1 表示对正则表达式之前的子序列感兴趣
|
|
|
- * 0 表示对正则表达式本身感兴趣,输出的就是换行符 */
|
|
|
- std::sregex_token_iterator it2(str2.begin(), str2.end(), parseReg2, -1);
|
|
|
- /* 这里取出每一行 */
|
|
|
- for(; it2 != std::sregex_token_iterator(); ++it2)
|
|
|
- {
|
|
|
- /* 去掉多余的空格 */
|
|
|
- auto line = std::regex_replace(it2->str(), parseRegSpace, " ");
|
|
|
- // LOG_INFO("{}", line);
|
|
|
- CF_FileInfo fi;
|
|
|
- /* 取出文件类型 */
|
|
|
- std::string strFileType = std::regex_replace(line, parseReg1, "$1");
|
|
|
- if(std::regex_match(strFileType, parseReg3))
|
|
|
- {
|
|
|
- fi.type = CF_FileType::DIR;
|
|
|
- }else if (std::regex_match(strFileType, parseReg4))
|
|
|
+ try
|
|
|
+ {
|
|
|
+ /* -1 表示对正则表达式之前的子序列感兴趣
|
|
|
+ * 0 表示对正则表达式本身感兴趣,输出的就是换行符 */
|
|
|
+ std::sregex_token_iterator it2(str2.begin(), str2.end(), parseReg2, -1);
|
|
|
+ /* 这里取出每一行 */
|
|
|
+ for(; it2 != std::sregex_token_iterator(); ++it2)
|
|
|
{
|
|
|
- fi.type = CF_FileType::FILE;
|
|
|
+ /* 去掉多余的空格 */
|
|
|
+ auto line = std::regex_replace(it2->str(), parseRegSpace, " ");
|
|
|
+ // LOG_INFO("{}", line);
|
|
|
+ CF_FileInfo fi;
|
|
|
+ /* 取出文件类型 */
|
|
|
+ std::string strFileType = std::regex_replace(line, parseReg1, "$1");
|
|
|
+ if(std::regex_match(strFileType, parseReg3))
|
|
|
+ {
|
|
|
+ fi.type = CF_FileType::DIR;
|
|
|
+ }else if (std::regex_match(strFileType, parseReg4))
|
|
|
+ {
|
|
|
+ fi.type = CF_FileType::FILE;
|
|
|
+ }
|
|
|
+ /* 取出文件大小 */
|
|
|
+ std::string strFileSize = std::regex_replace(line, parseReg1, "$5");
|
|
|
+ fi.size = std::stoull(strFileSize);
|
|
|
+ /* 取出文件名 */
|
|
|
+ std::string strFileName = std::regex_replace(line, parseReg1, "$7");
|
|
|
+ fi.name = strFileName;
|
|
|
+ /* 去掉本地目录和上一级目录 */
|
|
|
+ if(strFileName == "." || strFileName == "..")
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ /* 加入队列 */
|
|
|
+ fileInfo.push_back(fi);
|
|
|
}
|
|
|
- /* 取出文件大小 */
|
|
|
- std::string strFileSize = std::regex_replace(line, parseReg1, "$5");
|
|
|
- fi.size = std::stoull(strFileSize);
|
|
|
- /* 取出文件名 */
|
|
|
- std::string strFileName = std::regex_replace(line, parseReg1, "$7");
|
|
|
- fi.name = strFileName;
|
|
|
- /* 加入队列 */
|
|
|
- fileInfo.push_back(fi);
|
|
|
- }
|
|
|
+ }StdCatch
|
|
|
|
|
|
return true;
|
|
|
}
|
|
|
@@ -573,16 +580,14 @@ bool CurlFtp::setSftpIPAndPort(const std::string& IP, const int port)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
-/* 设置是否忽略SSL证书,使用SFTP不建议忽略 */
|
|
|
-void CurlFtp::setIgnoreSSLCert(bool isIgnore)
|
|
|
+/* 设置SFTP密钥,仅对SFTP生效 */
|
|
|
+bool CurlFtp::setSftpPrivateKey(const std::string& privateKeyFile, const std::string& publicKeyFile, const std::string& passphrase)
|
|
|
{
|
|
|
- m_isIgnoreSSLCert = isIgnore;
|
|
|
-}
|
|
|
+ m_sftpPrivateKeyFile = privateKeyFile;
|
|
|
+ m_sftpPublicKeyFile = publicKeyFile;
|
|
|
+ m_sftpPassphrase = passphrase;
|
|
|
|
|
|
-/* 设置CA证书文件 */
|
|
|
-void CurlFtp::setCaCertFile(const std::string& caCertFile)
|
|
|
-{
|
|
|
- m_caCertFile = caCertFile;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
/* 设置是否启用CURL的调试信息 */
|
|
|
@@ -600,11 +605,8 @@ bool CurlFtp::getList(std::string dir, std::vector<CF_FileInfo>& fileInfoList)
|
|
|
LOG_WARN("IP or port is empty");
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
- resetCurl(m_curl);
|
|
|
-
|
|
|
/* 获取文件信息 */
|
|
|
- listByWildcard(m_curl, dir, fileInfoList);
|
|
|
+ listByWildcard(dir, fileInfoList);
|
|
|
|
|
|
// curl_easy_cleanup(curl);
|
|
|
|
|
|
@@ -624,7 +626,7 @@ bool CurlFtp::getFileList(std::string dir, std::vector<std::string>& fileList)
|
|
|
|
|
|
std::vector<CF_FileInfo> listInfo;
|
|
|
/* 获取文件信息 */
|
|
|
- listByWildcard(m_curl, dirTmp, listInfo);
|
|
|
+ listByWildcard(dirTmp, listInfo);
|
|
|
for(const CF_FileInfo& fi : listInfo)
|
|
|
{
|
|
|
// LOG_INFO("type = {}, size = {}, name = {}", (int)fi.type, fi.size, fi.name);
|
|
|
@@ -650,18 +652,9 @@ bool CurlFtp::getDirList(std::string dir, std::vector<std::string>& dirList)
|
|
|
/* 检查dir,添加前缀“/” */
|
|
|
auto dirTmp = checkDirPath(dir);
|
|
|
|
|
|
- // CURL *curl = nullptr;
|
|
|
- // curl = curl_easy_init();
|
|
|
- // if(curl == nullptr)
|
|
|
- // {
|
|
|
- // LOG_ERROR("curl init failed !");
|
|
|
- // return false;
|
|
|
- // }
|
|
|
- resetCurl(m_curl);
|
|
|
-
|
|
|
std::vector<CF_FileInfo> listInfo;
|
|
|
/* 获取文件信息 */
|
|
|
- listByWildcard(m_curl, dirTmp, listInfo);
|
|
|
+ listByWildcard(dirTmp, listInfo);
|
|
|
for(const CF_FileInfo& fi : listInfo)
|
|
|
{
|
|
|
// LOG_INFO("type = {}, size = {}, name = {}", (int)fi.type, fi.size, fi.name);
|
|
|
@@ -764,69 +757,45 @@ bool CurlFtp::deleteFile(const std::string& remoteFile)
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
- /* 切到父目录后再删除基名(兼容更多服务器) */
|
|
|
- std::string parentDir, fileName;
|
|
|
- splitParentAndBasePath(filePath, parentDir, fileName);
|
|
|
- if(fileName.empty())
|
|
|
- {
|
|
|
- LOG_ERROR("Delete file base name is empty: " << filePath);
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- std::string parentUrl = m_ftpUrl + parentDir; // parentDir 以'/'结尾
|
|
|
- if(!setCommonCurlOptions(m_curl, parentUrl, 10))
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
+
|
|
|
struct curl_slist *headerlist = nullptr;
|
|
|
std::string deleteCmd;
|
|
|
- if(m_isSftp)
|
|
|
- {
|
|
|
- deleteCmd = "rm " + fileName; // sftp 使用 rm
|
|
|
- }
|
|
|
- else
|
|
|
+ std::string ftpUrl;
|
|
|
+ if(m_isSftp == false)
|
|
|
{
|
|
|
+ /* 切到父目录后再删除基名(兼容更多服务器) */
|
|
|
+ std::string parentDir, fileName;
|
|
|
+ splitParentAndBasePath(filePath, parentDir, fileName);
|
|
|
+ if(fileName.empty())
|
|
|
+ {
|
|
|
+ LOG_ERROR("Delete file base name is empty: " << filePath);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ ftpUrl = m_ftpUrl + parentDir; // parentDir 以'/'结尾
|
|
|
deleteCmd = "DELE " + fileName; // ftp 使用 DELE
|
|
|
- }
|
|
|
- headerlist = curl_slist_append(headerlist, deleteCmd.c_str());
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_QUOTE, headerlist);
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
- LOG_DEBUG("Delete remote file: " << filePath << ", parent: " << parentDir);
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
- curl_slist_free_all(headerlist);
|
|
|
- if(ret)
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /* 回退:尝试使用绝对路径删除(有些服务器允许) */
|
|
|
- LOG_WARN("Delete by basename failed, try absolute path: " << filePath);
|
|
|
- std::string rootUrl = m_ftpUrl + "/";
|
|
|
- if(!setCommonCurlOptions(m_curl, rootUrl, 10))
|
|
|
- {
|
|
|
- return false;
|
|
|
- }
|
|
|
- headerlist = nullptr;
|
|
|
- if(m_isSftp)
|
|
|
+ }else
|
|
|
{
|
|
|
+ /* SFTP需要使用绝对路径删除 */
|
|
|
+ ftpUrl = m_ftpUrl + "/";
|
|
|
+ headerlist = nullptr;
|
|
|
deleteCmd = "rm " + filePath;
|
|
|
}
|
|
|
- else
|
|
|
+ if(!setCommonCurlOptions(ftpUrl, 10))
|
|
|
{
|
|
|
- deleteCmd = "DELE " + filePath;
|
|
|
+ return false;
|
|
|
}
|
|
|
headerlist = curl_slist_append(headerlist, deleteCmd.c_str());
|
|
|
curl_easy_setopt(m_curl, CURLOPT_QUOTE, headerlist);
|
|
|
curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
- bool ret2 = performCurl(m_curl);
|
|
|
+ LOG_DEBUG("Delete remote file: " << filePath);
|
|
|
+ bool ret = performCurl();
|
|
|
curl_slist_free_all(headerlist);
|
|
|
- if(!ret2)
|
|
|
+ if(ret)
|
|
|
{
|
|
|
- LOG_ERROR("Failed to delete remote file: " << filePath);
|
|
|
+ return true;
|
|
|
}
|
|
|
- return ret2;
|
|
|
+
|
|
|
+
|
|
|
}
|
|
|
|
|
|
/* 删除文件夹,递归删除 */
|
|
|
@@ -849,11 +818,11 @@ bool CurlFtp::deleteDirectory(const std::string& ftpDir)
|
|
|
/* 递归删除:先删除内部所有文件和子目录,再删除自身 */
|
|
|
std::vector<CF_FileInfo> vecChildren;
|
|
|
// 使用通配符列举该目录下的所有条目
|
|
|
- if(!listByWildcard(m_curl, dirWithSlash, vecChildren))
|
|
|
+ if(!listByWildcard(dirWithSlash, vecChildren))
|
|
|
{
|
|
|
LOG_WARN("List children failed before delete: " << dirWithSlash);
|
|
|
}
|
|
|
- // 先删文件, 先切换到该目录,避免某些服务器删除失败
|
|
|
+ /* 删除文件, 先切换到该目录,避免FTP频繁切换目录 */
|
|
|
if(!changeToDir(dirWithSlash))
|
|
|
{
|
|
|
LOG_ERROR("ChangeToDir failed: " << dirWithSlash);
|
|
|
@@ -868,10 +837,15 @@ bool CurlFtp::deleteDirectory(const std::string& ftpDir)
|
|
|
{
|
|
|
continue;
|
|
|
}
|
|
|
- if(!deleteFileRelative(fi.name))
|
|
|
+ if(m_isSftp == false)
|
|
|
{
|
|
|
- LOG_ERROR("Failed to delete file: " << fi.name);
|
|
|
- // 回退:尝试使用绝对路径删除
|
|
|
+ if(!deleteFileRelative(fi.name))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ /* SFTP使用绝对路径删除 */
|
|
|
std::string absFile = dirWithSlash + fi.name;
|
|
|
if(!deleteFile(absFile))
|
|
|
{
|
|
|
@@ -905,52 +879,53 @@ bool CurlFtp::deleteDirectory(const std::string& ftpDir)
|
|
|
}
|
|
|
|
|
|
/* 删除自身目录,走到这一步,这个文件夹内的所有文件都被删除了 */
|
|
|
- std::string parentDir, baseName;
|
|
|
- splitParentAndBasePath(dirNoSlash, parentDir, baseName);
|
|
|
- if(baseName.empty())
|
|
|
- {
|
|
|
- LOG_ERROR("Delete directory base name is empty: " << dirNoSlash);
|
|
|
- return false;
|
|
|
- }
|
|
|
- /* 切换到父文件夹并删除当前文件夹 */
|
|
|
- if(!changeToDir(parentDir))
|
|
|
- {
|
|
|
- LOG_ERROR("ChangeToDir parent failed: " << parentDir);
|
|
|
- return false;
|
|
|
- }
|
|
|
- if(deleteDirectoryRelative(baseName))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- /* 绝对路径删除回退(部分服务器支持) */
|
|
|
+ struct curl_slist *headerlist = nullptr;
|
|
|
+ std::string deleteCmd;
|
|
|
+ if(m_isSftp == false)
|
|
|
{
|
|
|
- std::string rootUrl = m_ftpUrl + "/";
|
|
|
- if(!setCommonCurlOptions(m_curl, rootUrl, 10))
|
|
|
+ std::string parentDir, baseName;
|
|
|
+ splitParentAndBasePath(dirNoSlash, parentDir, baseName);
|
|
|
+ if(baseName.empty())
|
|
|
{
|
|
|
+ LOG_ERROR("Delete directory base name is empty: " << dirNoSlash);
|
|
|
return false;
|
|
|
}
|
|
|
- struct curl_slist *headerlist = nullptr;
|
|
|
- std::string deleteCmd;
|
|
|
- if(m_isSftp)
|
|
|
+ /* 切换到父文件夹并删除当前文件夹 */
|
|
|
+ if(!changeToDir(parentDir))
|
|
|
{
|
|
|
- deleteCmd = std::string("rmdir ") + dirNoSlash;
|
|
|
+ LOG_ERROR("ChangeToDir parent failed: " << parentDir);
|
|
|
+ return false;
|
|
|
}
|
|
|
- else
|
|
|
+ // 相对删除:要求已通过 changeToDir() 进入父目录
|
|
|
+ if(baseName.empty())
|
|
|
{
|
|
|
- deleteCmd = std::string("RMD ") + dirNoSlash;
|
|
|
+ LOG_ERROR("Delete relative dir name is empty");
|
|
|
+ return false;
|
|
|
}
|
|
|
- headerlist = curl_slist_append(headerlist, deleteCmd.c_str());
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_QUOTE, headerlist);
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
- bool ret2 = performCurl(m_curl);
|
|
|
- curl_slist_free_all(headerlist);
|
|
|
- if(!ret2)
|
|
|
+ // 不允许包含路径分隔符
|
|
|
+ if(baseName.find('/') != std::string::npos)
|
|
|
{
|
|
|
- LOG_ERROR("Failed to delete remote directory: " << dirNoSlash);
|
|
|
+ LOG_ERROR("DeleteDirectoryRelative only accepts basename without '/' : " << baseName);
|
|
|
+ return false;
|
|
|
}
|
|
|
- return ret2;
|
|
|
+ deleteCmd = "RMD " + baseName; // ftp 使用 RMD
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ /* SFTP使用绝对路径删除 */
|
|
|
+ std::string rootUrl = m_ftpUrl + "/";
|
|
|
+ if(!setCommonCurlOptions(rootUrl, 10))
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ deleteCmd = std::string("rmdir ") + dirNoSlash;
|
|
|
}
|
|
|
+ headerlist = curl_slist_append(headerlist, deleteCmd.c_str());
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_QUOTE, headerlist);
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
+ LOG_DEBUG("Delete relative directory: " << dirNoSlash);
|
|
|
+ bool ret = performCurl();
|
|
|
+ curl_slist_free_all(headerlist);
|
|
|
+ return ret;
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1008,7 +983,7 @@ bool CurlFtp::downloadFile(const std::string& remoteFile, const std::string& loc
|
|
|
}
|
|
|
|
|
|
/* 设置FTP地址 */
|
|
|
- setCommonCurlOptions(m_curl, ftpUrl, timeout);
|
|
|
+ setCommonCurlOptions(ftpUrl, timeout);
|
|
|
|
|
|
/* 设置回调函数 */
|
|
|
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeFileCallBack_QT);
|
|
|
@@ -1020,7 +995,7 @@ bool CurlFtp::downloadFile(const std::string& remoteFile, const std::string& loc
|
|
|
curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 0L);
|
|
|
|
|
|
/* 发送请求 */
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
+ bool ret = performCurl();
|
|
|
if(!ret)
|
|
|
{
|
|
|
std::stringstream ss;
|
|
|
@@ -1057,7 +1032,7 @@ bool CurlFtp::downloadToArray(const std::string& remoteFile, std::vector<char>&
|
|
|
|
|
|
|
|
|
/* 设置FTP地址 */
|
|
|
- setCommonCurlOptions(m_curl, ftpUrl, timeout);
|
|
|
+ setCommonCurlOptions(ftpUrl, timeout);
|
|
|
|
|
|
/* 设置回调函数 */
|
|
|
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeDataCallBack);
|
|
|
@@ -1069,7 +1044,7 @@ bool CurlFtp::downloadToArray(const std::string& remoteFile, std::vector<char>&
|
|
|
curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 0L);
|
|
|
|
|
|
/* 发送请求 */
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
+ bool ret = performCurl();
|
|
|
if(!ret)
|
|
|
{
|
|
|
LOG_ERROR("Failed to get file list, Url = " << ftpUrl);
|
|
|
@@ -1151,7 +1126,7 @@ bool CurlFtp::uploadFile(const std::string& localFile, const std::string& remote
|
|
|
|
|
|
|
|
|
/* 设置FTP地址 */
|
|
|
- if(!setCommonCurlOptions(m_curl, ftpUrl, timeout))
|
|
|
+ if(!setCommonCurlOptions(ftpUrl, timeout))
|
|
|
{
|
|
|
ifs.close();
|
|
|
return false;
|
|
|
@@ -1171,7 +1146,7 @@ bool CurlFtp::uploadFile(const std::string& localFile, const std::string& remote
|
|
|
|
|
|
// printf("uploadFile: %d\n", __LINE__);
|
|
|
/* 发送请求 */
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
+ bool ret = performCurl();
|
|
|
if(!ret)
|
|
|
{
|
|
|
LOG_ERROR("Upload file failed, Url = " << ftpUrl);
|
|
|
@@ -1237,7 +1212,7 @@ bool CurlFtp::uploadData(char* srcData, size_t size, const std::string& remoteFi
|
|
|
|
|
|
|
|
|
/* 设置FTP地址 */
|
|
|
- if(!setCommonCurlOptions(m_curl, ftpUrl, timeout))
|
|
|
+ if(!setCommonCurlOptions(ftpUrl, timeout))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1263,7 +1238,7 @@ bool CurlFtp::uploadData(char* srcData, size_t size, const std::string& remoteFi
|
|
|
curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 1L);
|
|
|
}
|
|
|
/* 发送请求 */
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
+ bool ret = performCurl();
|
|
|
if(!ret)
|
|
|
{
|
|
|
LOG_ERROR("Upload file failed, Url = " << ftpUrl);
|
|
|
@@ -1340,7 +1315,7 @@ bool CurlFtp::uploadData(char* srcData, size_t size, const std::string& remoteFi
|
|
|
* @return true
|
|
|
* @return false
|
|
|
*/
|
|
|
-bool CurlFtp::listByWildcard(CURL* curl, const std::string& dir, std::vector<CF_FileInfo>& out)
|
|
|
+bool CurlFtp::listByWildcard(const std::string& dir, std::vector<CF_FileInfo>& out)
|
|
|
{
|
|
|
if(m_IP.empty())
|
|
|
{
|
|
|
@@ -1350,38 +1325,63 @@ bool CurlFtp::listByWildcard(CURL* curl, const std::string& dir, std::vector<CF_
|
|
|
|
|
|
/* 规范化目录并追加通配符 */
|
|
|
std::string dirWithSlash = checkDirPath(dir); // 保证以'/'结束
|
|
|
- std::string ftpUrl = m_ftpUrl + dirWithSlash + "*";
|
|
|
+ std::string ftpUrl;
|
|
|
|
|
|
- if(!setCommonCurlOptions(curl, ftpUrl, 10))
|
|
|
+ if(m_isSftp)
|
|
|
+ {
|
|
|
+ ftpUrl = m_ftpUrl + dirWithSlash;
|
|
|
+ }else {
|
|
|
+ ftpUrl = m_ftpUrl + dirWithSlash + "*";
|
|
|
+ }
|
|
|
+
|
|
|
+ if(!setCommonCurlOptions(ftpUrl, 10))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
/* 启用通配符匹配并注册回调,仅收集信息不下载 */
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_WILDCARDMATCH, 1L);
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_CHUNK_BGN_FUNCTION, chunk_bgn_cb);
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_CHUNK_END_FUNCTION, chunk_end_cb);
|
|
|
- curl_easy_setopt(m_curl, CURLOPT_CHUNK_DATA, &out);
|
|
|
-
|
|
|
- // FTP 文本模式对目录兼容性更好(SFTP 忽略该设置)
|
|
|
if(m_isSftp == false)
|
|
|
{
|
|
|
+ /* 设置为文本传输 */
|
|
|
curl_easy_setopt(m_curl, CURLOPT_TRANSFERTEXT, 1L);
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_WILDCARDMATCH, 1L);
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_CHUNK_BGN_FUNCTION, chunk_bgn_cb);
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_CHUNK_END_FUNCTION, chunk_end_cb);
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_CHUNK_DATA, &out);
|
|
|
+ bool ret = performCurl();
|
|
|
+ if(!ret)
|
|
|
+ {
|
|
|
+ LOG_ERROR("Wildcard list failed, Url = " << ftpUrl);
|
|
|
+ }
|
|
|
+ return ret;
|
|
|
+ }else
|
|
|
+ {
|
|
|
+ /* 设置回调函数 */
|
|
|
+ std::string strSrc;
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeStringCallback);
|
|
|
+ /* 设置需要写入的容器,回调函数的第四个参数 */
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &strSrc);
|
|
|
+ /* 发送请求 */
|
|
|
+ bool ret = performCurl();
|
|
|
+ if(!ret)
|
|
|
+ {
|
|
|
+ LOG_ERROR("Failed to get file list, Url = " << ftpUrl);
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ // SPDLOG_DEBUG("SFTP Src string: {}", strSrc);
|
|
|
+ /* 解析字符串 */
|
|
|
+ parseFileInfo(strSrc, out);
|
|
|
+ return true;
|
|
|
}
|
|
|
-
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
- if(!ret)
|
|
|
- {
|
|
|
- LOG_ERROR("Wildcard list failed, Url = " << ftpUrl);
|
|
|
- }
|
|
|
- return ret;
|
|
|
+
|
|
|
}
|
|
|
|
|
|
|
|
|
/* 设置常规通用的curl设置 */
|
|
|
-bool CurlFtp::setCommonCurlOptions(CURL* curl, const std::string& ftpUrl, size_t timeout)
|
|
|
+bool CurlFtp::setCommonCurlOptions(const std::string& ftpUrl, size_t timeout)
|
|
|
{
|
|
|
- if(!resetCurl(m_curl))
|
|
|
+ if(!resetCurl())
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1406,7 +1406,7 @@ bool CurlFtp::setCommonCurlOptions(CURL* curl, const std::string& ftpUrl, size_t
|
|
|
curl_easy_setopt(m_curl, CURLOPT_VERBOSE, 1L);
|
|
|
}
|
|
|
/* 设置SFTP */
|
|
|
- if(!setSftp(m_curl))
|
|
|
+ if(!setSftp())
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
@@ -1534,12 +1534,12 @@ bool CurlFtp::checkLocalFileExist(const std::string& localFile)
|
|
|
|
|
|
|
|
|
/* 执行curl,添加重试机制 */
|
|
|
-bool CurlFtp::performCurl(CURL* curl)
|
|
|
+bool CurlFtp::performCurl()
|
|
|
{
|
|
|
- int retry = 3;
|
|
|
+ int retry = 1;
|
|
|
while(retry > 0)
|
|
|
{
|
|
|
- CURLcode res = curl_easy_perform(curl);
|
|
|
+ CURLcode res = curl_easy_perform(m_curl);
|
|
|
if(res == CURLE_OK)
|
|
|
{
|
|
|
return true;
|
|
|
@@ -1548,8 +1548,8 @@ bool CurlFtp::performCurl(CURL* curl)
|
|
|
{
|
|
|
LOG_ERROR("Login failed, error code: " << (int)res << ", " << curl_easy_strerror(res));
|
|
|
/* 设置用户名和密码 */
|
|
|
- curl_easy_setopt(curl, CURLOPT_USERNAME, m_username.c_str());
|
|
|
- curl_easy_setopt(curl, CURLOPT_PASSWORD, m_password.c_str());
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_USERNAME, m_username.c_str());
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_PASSWORD, m_password.c_str());
|
|
|
}
|
|
|
else if(res == CURLE_REMOTE_FILE_NOT_FOUND)
|
|
|
{
|
|
|
@@ -1566,8 +1566,19 @@ bool CurlFtp::performCurl(CURL* curl)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+bool CurlFtp::performCurlStrict()
|
|
|
+{
|
|
|
+ int retry = 1;
|
|
|
+ while (retry-- > 0) {
|
|
|
+ CURLcode res = curl_easy_perform(m_curl);
|
|
|
+ if (res == CURLE_OK) return true;
|
|
|
+ LOG_ERROR("Strict perform failed, code: " << (int)res << ", " << curl_easy_strerror(res));
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
/* 重置curl设置 */
|
|
|
-bool CurlFtp::resetCurl(CURL* curl)
|
|
|
+bool CurlFtp::resetCurl()
|
|
|
{
|
|
|
if(m_curl == nullptr)
|
|
|
{
|
|
|
@@ -1584,22 +1595,27 @@ bool CurlFtp::resetCurl(CURL* curl)
|
|
|
}
|
|
|
|
|
|
/* 设置sftp,如果是sftp就设置 */
|
|
|
-bool CurlFtp::setSftp(CURL* curl)
|
|
|
+bool CurlFtp::setSftp()
|
|
|
{
|
|
|
/* 判断是否是SFTP */
|
|
|
- if(m_isSftp)
|
|
|
+ if(m_isSftp == false)
|
|
|
{
|
|
|
- /* 判断是否需要设置CA证书 */
|
|
|
- if(m_isIgnoreSSLCert)
|
|
|
- {
|
|
|
- /* 忽略证书验证 */
|
|
|
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
|
- /* 忽略主机名验证 */
|
|
|
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
|
|
- } else
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ /* 设置仅使用密码验证,不优先验证密钥 */
|
|
|
+ if(m_isSftpEnableKey == false)
|
|
|
+ {
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PASSWORD);
|
|
|
+ } else {
|
|
|
+ /* 设置使用密钥验证 */
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_SSH_AUTH_TYPES, CURLSSH_AUTH_PUBLICKEY);
|
|
|
+ /* 设置公钥和私钥路径 */
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_SSH_PUBLIC_KEYFILE, m_sftpPublicKeyFile.c_str());
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_SSH_PRIVATE_KEYFILE, m_sftpPrivateKeyFile.c_str());
|
|
|
+ /* 如果密钥有密码,则设置密码 */
|
|
|
+ if(!m_sftpPassphrase.empty())
|
|
|
{
|
|
|
- /* 设置CA证书 */
|
|
|
- curl_easy_setopt(curl, CURLOPT_CAINFO, m_caCertFile.c_str());
|
|
|
+ curl_easy_setopt(m_curl, CURLOPT_KEYPASSWD, m_sftpPassphrase.c_str());
|
|
|
}
|
|
|
}
|
|
|
return true;
|
|
|
@@ -1617,38 +1633,10 @@ bool CurlFtp::checkFtpDirExist(const std::string& dir)
|
|
|
{
|
|
|
/* 检查传入的文件夹 */
|
|
|
auto dirTmp = checkDirPath(dir);
|
|
|
- // dirTmp = m_ftpUrl + dirTmp;
|
|
|
- // if(!setCommonCurlOptions(m_curl, dirTmp, 10))
|
|
|
- // {
|
|
|
- // return false;
|
|
|
- // }
|
|
|
-// /* 获取文件夹是否存在,不需要接收文件 */
|
|
|
-// curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
-// // curl_easy_setopt(m_curl, CURLOPT_HEADER, 1L);
|
|
|
-
|
|
|
-// /* 启用持久连接 */
|
|
|
-// // curl_easy_setopt(m_curl, CURLOPT_TCP_KEEPALIVE, 1L);
|
|
|
-// /* 这里只需要执行一次 */
|
|
|
-// CURLcode res = curl_easy_perform(m_curl);
|
|
|
-// bool result = true;
|
|
|
-// if(res == CURLE_REMOTE_FILE_NOT_FOUND)
|
|
|
-// {
|
|
|
-// result = false;
|
|
|
-// }
|
|
|
-// else if(res == CURLE_OK)
|
|
|
-// {
|
|
|
-// result = true;
|
|
|
-// } else
|
|
|
-// {
|
|
|
-// LOG_ERROR("Check remote dir error, error code: " << (int)res << ", " << curl_easy_strerror(res));
|
|
|
-// result = false;
|
|
|
-// }
|
|
|
-// // LOG_DEBUG("Check remote dir: {}, res: {}", dir, (int)res);
|
|
|
-
|
|
|
/* 获取文件夹 */
|
|
|
std::string parentDir = QFileInfo(QString::fromStdString(dir)).path().toStdString();
|
|
|
std::vector<CF_FileInfo> vecDir;
|
|
|
- bool ret = listByWildcard(m_curl, parentDir, vecDir);
|
|
|
+ bool ret = listByWildcard(parentDir, vecDir);
|
|
|
if(!ret)
|
|
|
{
|
|
|
LOG_ERROR("Failed to check ftp dir: " << dir);
|
|
|
@@ -1709,7 +1697,7 @@ bool CurlFtp::checkFtpFileExist(const std::string& file)
|
|
|
/* 取出上一层文件夹路径 */
|
|
|
std::string parentDir = QFileInfo(QString::fromStdString(file)).path().toStdString();
|
|
|
std::vector<CF_FileInfo> vecFiles;
|
|
|
- bool ret = listByWildcard(m_curl, parentDir, vecFiles);
|
|
|
+ bool ret = listByWildcard(parentDir, vecFiles);
|
|
|
if(!ret)
|
|
|
{
|
|
|
LOG_ERROR("Failed to check ftp file: " << file);
|
|
|
@@ -1744,13 +1732,13 @@ bool CurlFtp::changeToDir(const std::string& dir)
|
|
|
std::string url = m_ftpUrl + dirWithSlash;
|
|
|
|
|
|
// 设置到该目录并发送一个不传输实体的请求,相当于验证可进入
|
|
|
- if(!setCommonCurlOptions(m_curl, url, 10))
|
|
|
+ if(!setCommonCurlOptions(url, 10))
|
|
|
{
|
|
|
return false;
|
|
|
}
|
|
|
curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
LOG_DEBUG("Change to remote dir: " << dirWithSlash);
|
|
|
- return performCurl(m_curl);
|
|
|
+ return performCurlStrict();
|
|
|
}
|
|
|
|
|
|
/* 删除一个文件,相对路径,调用这个函数,需要先调用上面那个函数进入路径 */
|
|
|
@@ -1786,7 +1774,7 @@ bool CurlFtp::deleteFileRelative(const std::string& remoteFile)
|
|
|
curl_easy_setopt(m_curl, CURLOPT_QUOTE, headerlist);
|
|
|
curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
LOG_DEBUG("Delete relative file: " << remoteFile);
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
+ bool ret = performCurl();
|
|
|
curl_slist_free_all(headerlist);
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -1824,7 +1812,7 @@ bool CurlFtp::deleteDirectoryRelative(const std::string& ftpDir)
|
|
|
curl_easy_setopt(m_curl, CURLOPT_QUOTE, headerlist);
|
|
|
curl_easy_setopt(m_curl, CURLOPT_NOBODY, 1L);
|
|
|
LOG_DEBUG("Delete relative directory: " << ftpDir);
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
+ bool ret = performCurl();
|
|
|
curl_slist_free_all(headerlist);
|
|
|
return ret;
|
|
|
}
|
|
|
@@ -1850,7 +1838,7 @@ bool CurlFtp::createOneDirectory(const std::string& ftpDir)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
- setCommonCurlOptions(m_curl, m_ftpUrl, 30);
|
|
|
+ setCommonCurlOptions(m_ftpUrl, 30);
|
|
|
|
|
|
/* 检查传入的文件夹格式 */
|
|
|
auto dirTmp = checkDirPath(ftpDir);
|
|
|
@@ -1874,7 +1862,7 @@ bool CurlFtp::createOneDirectory(const std::string& ftpDir)
|
|
|
|
|
|
LOG_DEBUG("Create remote dir: " << dirTmp);
|
|
|
// CURLcode res = curl_easy_perform(curl);
|
|
|
- bool ret = performCurl(m_curl);
|
|
|
+ bool ret = performCurl();
|
|
|
if(!ret)
|
|
|
{
|
|
|
LOG_ERROR("Failed to create remote Dir");
|