From f09a9fe2e60e4aeaca23b42b2bf30f5d64cfd9b1 Mon Sep 17 00:00:00 2001 From: Georg Baum Date: Mon, 9 Jun 2014 13:05:50 +0200 Subject: [PATCH] Remove unsafe method FileName::tempName() FileName::tempName() created a new temp file name by using qt to create a temporary file with a unique name, and then deleting that file and returning the name. This was unsafe, since other processes or even other threads of the running LyX could create files with the same name between deletion and then using the temp name. This is fixed by using the TempFile class instead. As a side effect, a few cases where the temp files were not deleted after usage were fixed as well. The only place that is still unsafe is createTmpDir(). --- src/Buffer.cpp | 17 +++-- src/CutAndPaste.cpp | 5 +- src/KeyMap.cpp | 5 +- src/LayoutFile.cpp | 6 +- src/LyXRC.cpp | 5 +- src/LyXVC.cpp | 5 +- src/TextClass.cpp | 16 ++-- src/VCBackend.cpp | 106 ++++++++++++++------------- src/frontends/qt4/GuiApplication.cpp | 5 +- src/frontends/qt4/GuiWorkArea.cpp | 6 +- src/graphics/GraphicsCacheItem.cpp | 10 ++- src/graphics/GraphicsConverter.cpp | 9 ++- src/insets/InsetExternal.cpp | 23 ++++-- src/insets/InsetExternal.h | 10 ++- src/mathed/MathExtern.cpp | 5 +- src/support/FileName.cpp | 34 --------- src/support/FileName.h | 9 --- src/support/filetools.cpp | 26 ++++++- 18 files changed, 164 insertions(+), 138 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 866e4dcc36..bf12159db8 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -1050,7 +1050,8 @@ bool Buffer::readString(string const & s) Lexer lex; istringstream is(s); lex.setStream(is); - FileName const fn = FileName::tempName("Buffer_readString"); + TempFile tempfile("Buffer_readStringXXXXXX.lyx"); + FileName const fn = tempfile.name(); int file_format; bool success = parseLyXFormat(lex, fn, file_format) == ReadSuccess; @@ -1067,8 +1068,6 @@ bool Buffer::readString(string const & s) else if (success) if (readDocument(lex)) success = false; - if (fn.exists()) - fn.removeFile(); return success; } @@ -1189,7 +1188,9 @@ Buffer::ReadStatus Buffer::parseLyXFormat(Lexer & lex, Buffer::ReadStatus Buffer::convertLyXFormat(FileName const & fn, FileName & tmpfile, int from_format) { - tmpfile = FileName::tempName("Buffer_convertLyXFormatXXXXXX.lyx"); + TempFile tempfile("Buffer_convertLyXFormatXXXXXX.lyx"); + tempfile.setAutoRemove(false); + tmpfile = tempfile.name(); if(tmpfile.empty()) { Alert::error(_("Conversion failed"), bformat(_("%1$s is from a different" @@ -3730,7 +3731,9 @@ int AutoSaveBuffer::generateChild() // to fork. But we will do the save // anyway. bool failed = false; - FileName const tmp_ret = FileName::tempName("lyxauto"); + TempFile tempfile("lyxautoXXXXXX.lyx"); + tempfile.setAutoRemove(false); + FileName const tmp_ret = tempfile.name(); if (!tmp_ret.empty()) { buffer_.writeFile(tmp_ret); // assume successful write of tmp_ret @@ -3814,7 +3817,9 @@ bool Buffer::autoSave() const // If this buffer is cloned, we assume that // we are running in a separate thread already. - FileName const tmp_ret = FileName::tempName("lyxauto"); + TempFile tempfile("lyxautoXXXXXX.lyx"); + tempfile.setAutoRemove(false); + FileName const tmp_ret = tempfile.name(); if (!tmp_ret.empty()) { writeFile(tmp_ret); // assume successful write of tmp_ret diff --git a/src/CutAndPaste.cpp b/src/CutAndPaste.cpp index c168ca5170..0598e87285 100644 --- a/src/CutAndPaste.cpp +++ b/src/CutAndPaste.cpp @@ -60,6 +60,7 @@ #include "support/lassert.h" #include "support/limited_stack.h" #include "support/lstrings.h" +#include "support/TempFile.h" #include "frontends/alert.h" #include "frontends/Clipboard.h" @@ -484,8 +485,10 @@ void putClipboard(ParagraphList const & paragraphs, // new temporary directory, etc) every time, and then to destroy it. So maybe // it's worth just keeping this one around. // FIXME THREAD + static TempFile tempfile("clipboard.internal"); + tempfile.setAutoRemove(false); static Buffer * staticbuffer = theBufferList().newInternalBuffer( - FileName::tempName("clipboard.internal").absFileName()); + tempfile.name().absFileName()); // These two things only really need doing the first time. staticbuffer->setUnnamed(true); diff --git a/src/KeyMap.cpp b/src/KeyMap.cpp index 23acee0f9f..7628d0dfdb 100644 --- a/src/KeyMap.cpp +++ b/src/KeyMap.cpp @@ -25,6 +25,7 @@ #include "support/filetools.h" #include "support/gettext.h" #include "support/lstrings.h" +#include "support/TempFile.h" #include "frontends/alert.h" @@ -254,7 +255,8 @@ bool KeyMap::read(FileName const & bind_file, KeyMap * unbind_map) return retval == ReadOK; LYXERR(Debug::FILES, "Converting bind file to " << LFUN_FORMAT); - FileName const tempfile = FileName::tempName("convert_bind"); + TempFile tmp("convert_bind"); + FileName const tempfile = tmp.name(); bool const success = prefs2prefs(bind_file, tempfile, true); if (!success) { LYXERR0 ("Unable to convert " << bind_file << @@ -262,7 +264,6 @@ bool KeyMap::read(FileName const & bind_file, KeyMap * unbind_map) return false; } retval = readWithoutConv(tempfile, unbind_map); - tempfile.removeFile(); return retval == ReadOK; } diff --git a/src/LayoutFile.cpp b/src/LayoutFile.cpp index 8ec7474a0a..e428b5d76f 100644 --- a/src/LayoutFile.cpp +++ b/src/LayoutFile.cpp @@ -29,6 +29,7 @@ #include "support/bind.h" #include "support/regex.h" +#include "support/TempFile.h" #include @@ -224,8 +225,9 @@ string layoutpost = LayoutFileIndex LayoutFileList::addEmptyClass(string const & textclass) { // FIXME This could be simplified a bit to call TextClass::read(string, ReadType). - - FileName const tempLayout = FileName::tempName("basic_layout"); + + TempFile tempfile("basicXXXXXX.layout"); + FileName const tempLayout = tempfile.name(); ofstream ofs(tempLayout.toFilesystemEncoding().c_str()); // This writes a very basic class, but it also attempts to include // stdclass.inc. That would give us something moderately usable. diff --git a/src/LyXRC.cpp b/src/LyXRC.cpp index c95cacd606..2cc0369a63 100644 --- a/src/LyXRC.cpp +++ b/src/LyXRC.cpp @@ -40,6 +40,7 @@ #include "support/lstrings.h" #include "support/os.h" #include "support/Package.h" +#include "support/TempFile.h" #include "support/userinfo.h" #include @@ -407,7 +408,8 @@ bool LyXRC::read(FileName const & filename, bool check_format) return retval == ReadOK; LYXERR(Debug::FILES, "Converting LyXRC file to " << LYXRC_FILEFORMAT); - FileName const tempfile = FileName::tempName("convert_lyxrc"); + TempFile tmp("convert_lyxrc"); + FileName const tempfile = tmp.name(); bool const success = prefs2prefs(filename, tempfile, false); if (!success) { LYXERR0 ("Unable to convert " << filename.absFileName() << @@ -422,7 +424,6 @@ bool LyXRC::read(FileName const & filename, bool check_format) LYXERR(Debug::LYXRC, "Reading '" << tempfile << "'..."); retval = read(lexrc2, check_format); } - tempfile.removeFile(); return retval == ReadOK; } diff --git a/src/LyXVC.cpp b/src/LyXVC.cpp index fb6e822426..4dbcfd2675 100644 --- a/src/LyXVC.cpp +++ b/src/LyXVC.cpp @@ -25,6 +25,7 @@ #include "support/filetools.h" #include "support/gettext.h" #include "support/lstrings.h" +#include "support/TempFile.h" using namespace std; using namespace lyx::support; @@ -362,7 +363,9 @@ string const LyXVC::getLogFile() const if (!vcs) return string(); - FileName const tmpf = FileName::tempName("lyxvclog"); + TempFile tempfile("lyxvclog"); + tempfile.setAutoRemove(false); + FileName const tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return string(); diff --git a/src/TextClass.cpp b/src/TextClass.cpp index bd819ab200..23fd1eed9a 100644 --- a/src/TextClass.cpp +++ b/src/TextClass.cpp @@ -36,6 +36,7 @@ #include "support/gettext.h" #include "support/lstrings.h" #include "support/os.h" +#include "support/TempFile.h" #include #include @@ -278,22 +279,24 @@ LexerKeyword textClassTags[] = { bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt) { LYXERR(Debug::TCLASS, "Converting layout file to " << LAYOUT_FORMAT); - FileName const tempfile = FileName::tempName("convert_layout"); + TempFile tmp("convertXXXXXX.layout"); + FileName const tempfile = tmp.name(); bool success = layout2layout(filename, tempfile); if (success) success = readWithoutConv(tempfile, rt) == OK; - tempfile.removeFile(); return success; } std::string TextClass::convert(std::string const & str) { - FileName const fn = FileName::tempName("locallayout"); + TempFile tmp1("localXXXXXX.layout"); + FileName const fn = tmp1.name(); ofstream os(fn.toFilesystemEncoding().c_str()); os << str; os.close(); - FileName const tempfile = FileName::tempName("convert_locallayout"); + TempFile tmp2("convert_localXXXXXX.layout"); + FileName const tempfile = tmp2.name(); bool success = layout2layout(fn, tempfile); if (!success) return ""; @@ -305,7 +308,6 @@ std::string TextClass::convert(std::string const & str) ret += tmp + '\n'; } is.close(); - tempfile.removeFile(); return ret; } @@ -370,7 +372,8 @@ TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt) return retval; // write the layout string to a temporary file - FileName const tempfile = FileName::tempName("TextClass_read"); + TempFile tmp("TextClass_read"); + FileName const tempfile = tmp.name(); ofstream os(tempfile.toFilesystemEncoding().c_str()); if (!os) { LYXERR0("Unable to create temporary file"); @@ -386,7 +389,6 @@ TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt) << LAYOUT_FORMAT); return ERROR; } - tempfile.removeFile(); return OK_OLDFORMAT; } diff --git a/src/VCBackend.cpp b/src/VCBackend.cpp index 96b71d81ea..0e10aaafca 100644 --- a/src/VCBackend.cpp +++ b/src/VCBackend.cpp @@ -27,6 +27,7 @@ #include "support/PathChanger.h" #include "support/Systemcall.h" #include "support/regex.h" +#include "support/TempFile.h" #include @@ -292,7 +293,8 @@ bool RCS::isCheckInWithConfirmation() // if (getDiff(file, diff) && diff.empty()) // return false; - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return true; @@ -303,7 +305,6 @@ bool RCS::isCheckInWithConfirmation() FileName(owner_->filePath())); docstring diff = tmpf.fileContents("UTF-8"); - tmpf.removeFile(); if (diff.empty()) return false; @@ -433,7 +434,8 @@ string RCS::revisionInfo(LyXVC::RevisionInfo const info) bool RCS::getRevisionInfo() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -480,7 +482,9 @@ bool RCS::prepareFileRevision(string const &revis, string & f) if (!VCS::makeRCSRevision(version_, rev)) return false; - FileName tmpf = FileName::tempName("lyxvcrev_" + rev + "_"); + TempFile tempfile("lyxvcrev_" + rev + "_"); + tempfile.setAutoRemove(false); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -657,7 +661,8 @@ int CVS::doVCCommandCallWithOutput(std::string const & cmd, CVS::CvsStatus CVS::getStatus() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return StatusError; @@ -665,7 +670,6 @@ CVS::CvsStatus CVS::getStatus() if (doVCCommandCallWithOutput("cvs status " + getTarget(File), FileName(owner_->filePath()), tmpf)) { - tmpf.removeFile(); return StatusError; } @@ -689,7 +693,6 @@ CVS::CvsStatus CVS::getStatus() status = NeedsCheckout; } } - tmpf.removeFile(); return status; } @@ -698,7 +701,8 @@ void CVS::getRevisionInfo() if (have_rev_info_) return; have_rev_info_ = true; - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return; @@ -708,7 +712,6 @@ void CVS::getRevisionInfo() + " " + getTarget(File), FileName(owner_->filePath()), tmpf); if (rc) { - tmpf.removeFile(); LYXERR(Debug::LYXVC, "cvs log failed with exit code " << rc); return; } @@ -731,7 +734,6 @@ void CVS::getRevisionInfo() break; } } - tmpf.removeFile(); if (rev_author_cache_.empty()) LYXERR(Debug::LYXVC, "Could not retrieve revision info for " << version_ << @@ -902,7 +904,8 @@ string CVS::checkOut() { if (vcstatus != NOLOCKING && edit()) return string(); - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return string(); @@ -920,7 +923,6 @@ string CVS::checkOut() rc = 0; } - tmpf.removeFile(); return rc ? string() : log.empty() ? "CVS: Proceeded" : "CVS: " + log; } @@ -936,7 +938,8 @@ bool CVS::checkOutEnabled() string CVS::repoUpdate() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return string(); @@ -959,10 +962,8 @@ string CVS::repoUpdate() text, 0, 1, _("&Continue"), _("&Abort")); hideDialogs("file", 0); } - if (ret == 1 ) { - tmpf.removeFile(); + if (ret == 1 ) return string(); - } } int rc = update(Directory, tmpf); @@ -980,8 +981,6 @@ string CVS::repoUpdate() file, from_local8bit(sres))); rc = 0; } - - tmpf.removeFile(); return rc ? string() : log.empty() ? "CVS: Proceeded" : "CVS: " + log; } @@ -1108,7 +1107,9 @@ bool CVS::prepareFileRevision(string const & revis, string & f) if (!VCS::makeRCSRevision(version_, rev)) return false; - FileName tmpf = FileName::tempName("lyxvcrev_" + rev + "_"); + TempFile tempfile("lyxvcrev_" + rev + "_"); + tempfile.setAutoRemove(false); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -1156,7 +1157,8 @@ FileName const SVN::findFile(FileName const & file) } // Now we check the status of the file. - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return FileName(); @@ -1167,7 +1169,6 @@ FileName const SVN::findFile(FileName const & file) bool found = 0 == doVCCommandCall("svn info " + quoteName(fname) + " > " + quoteName(tmpf.toFilesystemEncoding()), file.onlyPath()); - tmpf.removeFile(); LYXERR(Debug::LYXVC, "SVN control: " << (found ? "enabled" : "disabled")); return found ? file : FileName(); } @@ -1189,7 +1190,8 @@ void SVN::scanMaster() bool SVN::checkLockMode() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()){ LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -1319,7 +1321,8 @@ LyXVC::CommandResult SVN::checkIn(string const & msg, string & log) LyXVC::CommandResult SVN::checkIn(vector const & f, string const & msg, string & log) { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()){ LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); log = N_("Error: Could not generate logfile."); @@ -1347,7 +1350,6 @@ SVN::checkIn(vector const & f, string const & msg, string & l if (!fileLock(false, tmpf, log)) ret = LyXVC::ErrorCommand; - tmpf.removeFile(); if (!log.empty()) log.insert(0, "SVN: "); if (ret == LyXVC::VCSuccess && log.empty()) @@ -1369,7 +1371,8 @@ bool SVN::isCheckInWithConfirmation() { // FIXME one day common getDiff and perhaps OpMode for all backends - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return true; @@ -1380,7 +1383,6 @@ bool SVN::isCheckInWithConfirmation() FileName(owner_->filePath())); docstring diff = tmpf.fileContents("UTF-8"); - tmpf.removeFile(); if (diff.empty()) return false; @@ -1455,7 +1457,8 @@ bool SVN::fileLock(bool lock, FileName const & tmpf, string &status) string SVN::checkOut() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return N_("Error: Could not generate logfile."); @@ -1476,7 +1479,6 @@ string SVN::checkOut() fileLock(true, tmpf, log); - tmpf.removeFile(); return log.empty() ? string() : "SVN: " + log; } @@ -1492,7 +1494,8 @@ bool SVN::checkOutEnabled() string SVN::repoUpdate() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return N_("Error: Could not generate logfile."); @@ -1518,10 +1521,8 @@ string SVN::repoUpdate() text, 0, 1, _("&Yes"), _("&No")); hideDialogs("file", 0); } - if (ret == 1 ) { - tmpf.removeFile(); + if (ret == 1 ) return string(); - } } // Reverting looks too harsh, see bug #6255. @@ -1535,7 +1536,6 @@ string SVN::repoUpdate() res += "Update log:\n" + tmpf.fileContents("UTF-8"); LYXERR(Debug::LYXVC, res); - tmpf.removeFile(); return to_utf8(res); } @@ -1548,7 +1548,8 @@ bool SVN::repoUpdateEnabled() string SVN::lockingToggle() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return N_("Error: Could not generate logfile."); @@ -1576,7 +1577,6 @@ string SVN::lockingToggle() if (ret) return string(); - tmpf.removeFile(); frontend::Alert::warning(_("SVN File Locking"), (locking ? _("Locking property unset.") : _("Locking property set.")) + "\n" + _("Do not forget to commit the locking property into the repository."), @@ -1667,7 +1667,8 @@ string SVN::revisionInfo(LyXVC::RevisionInfo const info) bool SVN::getFileRevisionInfo() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -1713,14 +1714,14 @@ bool SVN::getFileRevisionInfo() } ifs.close(); - tmpf.removeFile(); return !rev.empty(); } bool SVN::getTreeRevisionInfo() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -1737,7 +1738,6 @@ bool SVN::getTreeRevisionInfo() string line; getline(ifs, line); ifs.close(); - tmpf.removeFile(); rev_tree_cache_ = line; return !line.empty(); @@ -1771,7 +1771,9 @@ bool SVN::prepareFileRevision(string const & revis, string & f) } string revname = convert(rev); - FileName tmpf = FileName::tempName("lyxvcrev_" + revname + "_"); + TempFile tempfile("lyxvcrev_" + revname + "_"); + tempfile.setAutoRemove(false); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -1826,7 +1828,8 @@ FileName const GIT::findFile(FileName const & file) } // Now we check the status of the file. - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return FileName(); @@ -1840,7 +1843,6 @@ FileName const GIT::findFile(FileName const & file) quoteName(tmpf.toFilesystemEncoding()), file.onlyPath()); bool found = !tmpf.isFileEmpty(); - tmpf.removeFile(); LYXERR(Debug::LYXVC, "GIT control: " << (found ? "enabled" : "disabled")); return found ? file : FileName(); } @@ -1934,7 +1936,8 @@ LyXVC::CommandResult GIT::checkIn(string const & msg, string & log) LyXVC::CommandResult GIT::checkIn(vector const & f, string const & msg, string & log) { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()){ LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); log = N_("Error: Could not generate logfile."); @@ -1959,7 +1962,6 @@ GIT::checkIn(vector const & f, string const & msg, string & l ret = LyXVC::ErrorCommand; } - tmpf.removeFile(); if (!log.empty()) log.insert(0, "GIT: "); if (ret == LyXVC::VCSuccess && log.empty()) @@ -1978,7 +1980,8 @@ bool GIT::isCheckInWithConfirmation() { // FIXME one day common getDiff and perhaps OpMode for all backends - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return true; @@ -1989,7 +1992,6 @@ bool GIT::isCheckInWithConfirmation() FileName(owner_->filePath())); docstring diff = tmpf.fileContents("UTF-8"); - tmpf.removeFile(); if (diff.empty()) return false; @@ -2132,7 +2134,8 @@ string GIT::revisionInfo(LyXVC::RevisionInfo const info) bool GIT::getFileRevisionInfo() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -2158,14 +2161,14 @@ bool GIT::getFileRevisionInfo() } ifs.close(); - tmpf.removeFile(); return !rev_file_cache_.empty(); } bool GIT::getTreeRevisionInfo() { - FileName tmpf = FileName::tempName("lyxvcout"); + TempFile tempfile("lyxvcout"); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; @@ -2181,7 +2184,6 @@ bool GIT::getTreeRevisionInfo() ifstream ifs(tmpf.toFilesystemEncoding().c_str()); getline(ifs, rev_tree_cache_); ifs.close(); - tmpf.removeFile(); return !rev_tree_cache_.empty(); } @@ -2218,7 +2220,9 @@ bool GIT::prepareFileRevision(string const & revis, string & f) pointer += ":"; - FileName tmpf = FileName::tempName("lyxvcrev_" + revis + "_"); + TempFile tempfile("lyxvcrev_" + revis + "_"); + tempfile.setAutoRemove(false); + FileName tmpf = tempfile.name(); if (tmpf.empty()) { LYXERR(Debug::LYXVC, "Could not generate logfile " << tmpf); return false; diff --git a/src/frontends/qt4/GuiApplication.cpp b/src/frontends/qt4/GuiApplication.cpp index 22c129b350..f6c8433141 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -70,6 +70,7 @@ #include "support/Package.h" #include "support/PathChanger.h" #include "support/Systemcall.h" +#include "support/TempFile.h" #ifdef Q_WS_MACX #include "support/AppleScript.h" @@ -2827,14 +2828,14 @@ bool GuiApplication::readUIFile(QString const & name, bool include) if (retval == FormatMismatch) { LYXERR(Debug::FILES, "Converting ui file to format " << LFUN_FORMAT); - FileName const tempfile = FileName::tempName("convert_ui"); + TempFile tmp("convertXXXXXX.ui"); + FileName const tempfile = tmp.name(); bool const success = prefs2prefs(ui_path, tempfile, true); if (!success) { LYXERR0("Unable to convert " << ui_path.absFileName() << " to format " << LFUN_FORMAT << "."); } else { retval = readUIFile(tempfile); - tempfile.removeFile(); } } diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index 981420d3b5..514866ac49 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -49,6 +49,7 @@ #include "support/gettext.h" #include "support/FileName.h" #include "support/lassert.h" +#include "support/TempFile.h" #include "frontends/Application.h" #include "frontends/FontMetrics.h" @@ -1426,8 +1427,9 @@ GuiView & GuiWorkArea::view() EmbeddedWorkArea::EmbeddedWorkArea(QWidget * w): GuiWorkArea(w) { - buffer_ = theBufferList().newInternalBuffer( - support::FileName::tempName("embedded.internal").absFileName()); + support::TempFile tempfile("embedded.internal"); + tempfile.setAutoRemove(false); + buffer_ = theBufferList().newInternalBuffer(tempfile.name().absFileName()); buffer_->setUnnamed(true); buffer_->setFullyLoaded(true); setBuffer(*buffer_); diff --git a/src/graphics/GraphicsCacheItem.cpp b/src/graphics/GraphicsCacheItem.cpp index 4939874ab3..4d18ce0778 100644 --- a/src/graphics/GraphicsCacheItem.cpp +++ b/src/graphics/GraphicsCacheItem.cpp @@ -28,6 +28,7 @@ #include "support/lassert.h" #include "support/bind.h" +#include "support/TempFile.h" using namespace std; using namespace lyx::support; @@ -361,8 +362,9 @@ bool CacheItem::Impl::tryDisplayFormat(FileName & filename, string & from) zipped_ = formats.isZippedFile(filename_); if (zipped_) { - unzipped_filename_ = FileName::tempName( - filename_.toFilesystemEncoding()); + TempFile tempfile(filename_.toFilesystemEncoding()); + tempfile.setAutoRemove(false); + unzipped_filename_ = tempfile.name(); if (unzipped_filename_.empty()) { status_ = ErrorConverting; LYXERR(Debug::GRAPHICS, "\tCould not create temporary file."); @@ -422,7 +424,9 @@ void CacheItem::Impl::convertToDisplayFormat() // Add some stuff to create a uniquely named temporary file. // This file is deleted in loadImage after it is loaded into memory. - FileName const to_file_base = FileName::tempName("CacheItem"); + TempFile tempfile("CacheItem"); + tempfile.setAutoRemove(false); + FileName const to_file_base = tempfile.name(); remove_loaded_file_ = true; // Connect a signal to this->imageConverted and pass this signal to diff --git a/src/graphics/GraphicsConverter.cpp b/src/graphics/GraphicsConverter.cpp index 263c91eab9..e833a3570f 100644 --- a/src/graphics/GraphicsConverter.cpp +++ b/src/graphics/GraphicsConverter.cpp @@ -25,6 +25,7 @@ #include "support/os.h" #include "support/bind.h" +#include "support/TempFile.h" #include #include @@ -292,7 +293,9 @@ static void build_script(string const & from_file, // FIXME THREAD static int counter = 0; string const tmp = "gconvert" + convert(counter++); - string const to_base = FileName::tempName(tmp).toFilesystemEncoding(); + TempFile tempfile(tmp); + tempfile.setAutoRemove(false); + string const to_base = tempfile.name().toFilesystemEncoding(); // Create a copy of the file in case the original name contains // problematic characters like ' or ". We can work around that problem @@ -366,7 +369,9 @@ static void build_script(string const & from_file, // If two formats share the same extension we may get identical names if (outfile == infile && conv.result_file.empty()) { - string const new_base = FileName::tempName(tmp).toFilesystemEncoding(); + TempFile tempfile(tmp); + tempfile.setAutoRemove(false); + string const new_base = tempfile.name().toFilesystemEncoding(); outfile = addExtension(new_base, conv.To->extension()); } diff --git a/src/insets/InsetExternal.cpp b/src/insets/InsetExternal.cpp index 50c6e4be87..2e97fc0705 100644 --- a/src/insets/InsetExternal.cpp +++ b/src/insets/InsetExternal.cpp @@ -45,6 +45,7 @@ #include "support/lassert.h" #include "support/lstrings.h" #include "support/lyxlib.h" +#include "support/TempFile.h" #include #include @@ -67,33 +68,39 @@ namespace Alert = frontend::Alert; namespace external { -TempName::TempName() +TempName::TempName() : tempfile_(new support::TempFile("lyxextXXXXXX.tmp")) { - FileName const tempname = FileName::tempName("lyxext"); // must have an extension for the converter code to work correctly. - tempname_ = FileName(tempname.absFileName() + ".tmp"); } -TempName::TempName(TempName const &) +TempName::TempName(TempName const & that) : tempfile_(0) { - tempname_ = TempName()(); + *this = that; } TempName::~TempName() { - tempname_.removeFile(); + delete tempfile_; } TempName & TempName::operator=(TempName const & other) { - if (this != &other) - tempname_ = TempName()(); + if (this != &other) { + delete tempfile_; + tempfile_ = new support::TempFile("lyxextXXXXXX.tmp"); + } return *this; } + +support::FileName TempName::operator()() const +{ + return tempfile_->name(); +} + } // namespace external diff --git a/src/insets/InsetExternal.h b/src/insets/InsetExternal.h index a875d37995..a6167b5dd9 100644 --- a/src/insets/InsetExternal.h +++ b/src/insets/InsetExternal.h @@ -31,6 +31,10 @@ */ namespace lyx { +namespace support { +class TempFile; +} + namespace external { class TempName { @@ -39,9 +43,9 @@ public: TempName(TempName const &); ~TempName(); TempName & operator=(TempName const &); - support::FileName const & operator()() const { return tempname_; } + support::FileName operator()() const; private: - support::FileName tempname_; + support::TempFile * tempfile_; }; } // namespace external @@ -56,7 +60,7 @@ public: bool read(Buffer const &, Lexer &); /// The name of the tempfile used for manipulations. - support::FileName const & tempname() const { return tempname_(); } + support::FileName tempname() const { return tempname_(); } /// The template currently in use. void settemplate(std::string const &); diff --git a/src/mathed/MathExtern.cpp b/src/mathed/MathExtern.cpp index 949061017c..236b24ba85 100644 --- a/src/mathed/MathExtern.cpp +++ b/src/mathed/MathExtern.cpp @@ -40,6 +40,7 @@ #include "support/FileName.h" #include "support/filetools.h" #include "support/lstrings.h" +#include "support/TempFile.h" #include #include @@ -995,7 +996,8 @@ namespace { { // In order to avoid parsing problems with command interpreters // we pass input data through a file - FileName const cas_tmpfile = FileName::tempName("casinput"); + TempFile tempfile("casinput"); + FileName const cas_tmpfile = tempfile.name(); if (cas_tmpfile.empty()) { lyxerr << "Warning: cannot create temporary file." << endl; @@ -1009,7 +1011,6 @@ namespace { lyxerr << "calling: " << cmd << "\ninput: '" << data << "'" << endl; cmd_ret const ret = runCommand(command); - cas_tmpfile.removeFile(); return ret.second; } diff --git a/src/support/FileName.cpp b/src/support/FileName.cpp index 08d726e0c6..84f13d6ae3 100644 --- a/src/support/FileName.cpp +++ b/src/support/FileName.cpp @@ -454,40 +454,6 @@ FileNameList FileName::dirList(string const & ext) const } -static string createTempFile(QString const & mask) -{ - // FIXME: This is not safe. QTemporaryFile creates a file in open(), - // but the file is deleted when qt_tmp goes out of scope. - // Therefore the next call to createTempFile() may create the - // same file again. To make this safe the QTemporaryFile object - // needs to be kept for the whole life time of the temp file name. - // This can be achieved by using the TempFile class. - QTemporaryFile qt_tmp(mask + ".XXXXXXXXXXXX"); - if (qt_tmp.open()) { - string const temp_file = fromqstr(qt_tmp.fileName()); - LYXERR(Debug::FILES, "Temporary file `" << temp_file << "' created."); - return temp_file; - } - LYXERR(Debug::FILES, "Unable to create temporary file with following template: " - << qt_tmp.fileTemplate()); - return string(); -} - - -FileName FileName::tempName(FileName const & temp_dir, string const & mask) -{ - QFileInfo tmp_fi(QDir(temp_dir.d->fi.absoluteFilePath()), toqstr(mask)); - LYXERR(Debug::FILES, "Temporary file in " << tmp_fi.absoluteFilePath()); - return FileName(createTempFile(tmp_fi.absoluteFilePath())); -} - - -FileName FileName::tempName(string const & mask) -{ - return tempName(package().temp_dir(), mask); -} - - FileName FileName::getcwd() { // return makeAbsPath("."); would create an infinite loop diff --git a/src/support/FileName.h b/src/support/FileName.h index 1b37ef2629..f0d1b54748 100644 --- a/src/support/FileName.h +++ b/src/support/FileName.h @@ -175,15 +175,6 @@ public: void changeExtension(std::string const & extension); static FileName fromFilesystemEncoding(std::string const & name); - /// Create a temporary file with the given mask. - /// \p mask must be in filesystem encoding, if it contains a - /// relative path, the template file will be created in the global - /// temporary directory as given by 'package().temp_dir()'. - /// CAUTION: This method may create race conditions. - /// Do not use, use the TempFile class instead. - static FileName tempName(std::string const & mask); - static FileName tempName(FileName const & temp_dir, - std::string const & mask); /// get the current working directory static FileName getcwd(); diff --git a/src/support/filetools.cpp b/src/support/filetools.cpp index 66d4b22701..b9c7e7f01a 100644 --- a/src/support/filetools.cpp +++ b/src/support/filetools.cpp @@ -37,6 +37,7 @@ #include "support/qstring_helpers.h" #include +#include #include "support/lassert.h" #include "support/regex.h" @@ -378,12 +379,35 @@ string const commandPrep(string const & command_in) } +static string createTempFile(QString const & mask) +{ + // FIXME: This is not safe. QTemporaryFile creates a file in open(), + // but the file is deleted when qt_tmp goes out of scope. + // Therefore the next call to createTempFile() may create the + // same file again. To make this safe the QTemporaryFile object + // needs to be kept for the whole life time of the temp file name. + // This could be achieved by creating a class TempDir (like + // TempFile, but using a currentlky non-existing + // QTemporaryDirectory object). + QTemporaryFile qt_tmp(mask + ".XXXXXXXXXXXX"); + if (qt_tmp.open()) { + string const temp_file = fromqstr(qt_tmp.fileName()); + LYXERR(Debug::FILES, "Temporary file `" << temp_file << "' created."); + return temp_file; + } + LYXERR(Debug::FILES, "Unable to create temporary file with following template: " + << qt_tmp.fileTemplate()); + return string(); +} + + static FileName createTmpDir(FileName const & tempdir, string const & mask) { LYXERR(Debug::FILES, "createTmpDir: tempdir=`" << tempdir << "'\n" << "createTmpDir: mask=`" << mask << '\''); - FileName const tmpfl = FileName::tempName(tempdir, mask); + QFileInfo tmp_fi(QDir(toqstr(tempdir.absFileName())), toqstr(mask)); + FileName const tmpfl(createTempFile(tmp_fi.absoluteFilePath())); if (tmpfl.empty() || !tmpfl.createDirectory(0700)) { LYXERR0("LyX could not create temporary directory in " << tempdir -- 2.39.2