gpt4 book ai didi

linux - popen ("tar xvf tarball.tar") 在调试中工作但在发布版本中不工作

转载 作者:太空宇宙 更新时间:2023-11-04 09:37:00 25 4
gpt4 key购买 nike

我正在为 Ubuntu 开发一个 C++ 程序,该程序使用 curl_easy_perform 下载 tar 存档,在将存档下载到/tmp 后,我使用 popen 执行适当的 tar 命令行。

当我运行程序的调试构建时,popen("tar xvf/tmp/example.tar -C/tmp/existingdir") 工作,但是当我在发布构建中运行此命令时,popen调用总是失败。

这是我的代码,删除了大部分错误检查和不相关的内容:

//tl;dr version:
// first I download a tar archive from url using Curl and save it to filelocation,
// then I untar it using pOpen.
// pOpen always works in debug, never in release builds
////
Status ExpandTarBall(const MyString& FileName)
{
//extract the tar ball into a previously created temporary directory, tempDirPath
MyString args = "tar xvf /tmp/ + FileName + " -C " + tempDirPath;
cout << "running:" << args << endl;
// args example:
// tar xvf /tmp/UserIdXXxCtnAl/examplepackage -C /tmp/UserIdXXxCtnAl
//
Status result = ER_OPEN_FAILED;
FILE* fp = popen(args.c_str(), "re"); //<========== always works in debug builds, fails with 0 returned in release builds! :(
if (fp)
{
result = pclose(fp) == 0 ? ER_OK : ER_INVALID_DATA;
}

return result;
}



//Note: MyString is an std::string class with some local extensions
Status SslDownloader::DownloadFile(MyString url, MyString fileLocation, bool sslVerify) {

CURL* curl = NULL;
CurlInitHelper helper(curl);

cout << "downloading from " << url.c_str() << " to " << fileLocation.c_str() << endl;

if (!curl) {
return ER_SSL_INIT;
}
FILE* fp = fopen(fileLocation.c_str(), "wb");
if(NULL == fp) {
return ER_OPEN_FAILED;
}
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_USERAGENT, AJPM_USER_AGENT);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, true);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);

if (sslVerify) {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L);
curl_easy_setopt(curl, CURLOPT_CAINFO, AJPM_CERT_STORE_LOCATION );
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
} else {
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
}

CURLcode res = curl_easy_perform(curl);

if (0 != fclose(fp)) {
return ER_WRITE_ERROR;
}

if (res != CURLE_OK) {
return res == ER_SSL_CONNECT;
}

cout << "SSL download of " << fileLocation.c_str() << " succeeded\n"; // works every time
return ExpandTarBall(const MyString& FileName);
}

我错过了什么简单的事情?

最佳答案

在您使用 popen 启动子进程后,您立即调用 pclose(),而不是从 popen() 返回的文件中读取。

tar 的 xvf 选项将在其标准输出中转储文件列表,这是一个管道,popen 将管道的读取端返回给您。

pclose() 先关闭管道,然后等待子进程终止。

在父进程和子进程同时运行的情况下,如果父进程赢得比赛并在子进程启动之前关闭了管道,当子进程试图写入其标准输出时,管道的写入端管道,它会得到一个 SIGPIPE 信号,杀死子进程。

您的应用程序的“调试”和“发布”构建之间的运行时配置文件的差异很可能足以使发布构建的规模向该结果倾斜,而额外的开销无论您实际指的是什么“调试构建”将减慢速度,以便子进程有时间在父进程开始关闭管道之前溢出其标准输出。

请记住,一旦您的 tarball 包含足够数量的文件,即使 tar 在这场比赛中领先,它的输出也会填满管道缓冲区和 block ,一旦父进程开始关闭管道,它将 SIGPIPE 子进程,并且 tar 将始终失败。

故事的寓意:当使用 popen 从启动的子进程读取时,始终从管道读取并使用子进程的输出,直到获得 EOF,然后再 pclose() 它。

关于linux - popen ("tar xvf tarball.tar") 在调试中工作但在发布版本中不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25612821/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com