return false;
// It is important to use the correct extension here, since some
// converters create a wrong output file otherwise (e.g. html2latex)
- TempFile const tempfile("Buffer_importStringXXXXXX." + fmt->extension());
- FileName const name(tempfile.name());
+ FileName const name = tempFileName("Buffer_importStringXXXXXX." + fmt->extension());
ofdocstream os(name.toFilesystemEncoding().c_str());
// Do not convert os implicitly to bool, since that is forbidden in C++11.
bool const success = !(os << contents).fail();
converted = importFile(format, name, errorList);
}
- if (name.exists())
- name.removeFile();
+ removeTempFile(name);
return converted;
}
if (!theConverters().isReachable(format, "lyx"))
return false;
- TempFile const tempfile("Buffer_importFileXXXXXX.lyx");
- FileName const lyx(tempfile.name());
- if (theConverters().convert(0, name, lyx, name, format, "lyx", errorList))
- return readFile(lyx) == ReadSuccess;
+ FileName const lyx = tempFileName("Buffer_importFileXXXXXX.lyx");
+ if (theConverters().convert(0, name, lyx, name, format, "lyx", errorList)) {
+ bool const success = readFile(lyx) == ReadSuccess;
+ removeTempFile(lyx);
+ return success;
+ }
return false;
}
#include "support/filetools.h"
+#include "support/convert.h"
#include "support/debug.h"
#include "support/environment.h"
#include "support/gettext.h"
#include "support/PathChanger.h"
#include "support/Systemcall.h"
#include "support/qstring_helpers.h"
+#include "support/TempFile.h"
#include <QDir>
#include <QTemporaryFile>
}
+FileName const tempFileName(string const & mask)
+{
+ FileName tempfile = TempFile(mask).name();
+ // Since the QTemporaryFile object is destroyed at function return
+ // (which is what is intended here), the next call to this function
+ // may return the same file name again.
+ // Thus, in order to prevent race conditions, we track returned names
+ // and create our own unique names if QTemporaryFile returns a name again.
+ if (tmp_names_.find(tempfile.absFileName()) == tmp_names_.end()) {
+ tmp_names_.insert(tempfile.absFileName());
+ return tempfile;
+ }
+
+ // OK, we need another name. Simply append digits.
+ FileName tmp = tempfile;
+ tmp.changeExtension("");
+ for (int i = 1; i < INT_MAX ;++i) {
+ // Append digit to filename and re-add extension
+ string const new_fn = tmp.absFileName() + convert<string>(i)
+ + "." + tempfile.extension();
+ if (tmp_names_.find(new_fn) == tmp_names_.end()) {
+ tmp_names_.insert(new_fn);
+ tempfile.set(new_fn);
+ return tempfile;
+ }
+ }
+
+ // This should not happen!
+ LYXERR0("tempFileName(): Could not create unique temp file name!");
+ return tempfile;
+}
+
+
+void removeTempFile(FileName const & fn)
+{
+ if (!fn.exists())
+ return;
+
+ string const abs = fn.absFileName();
+ if (tmp_names_.find(abs) != tmp_names_.end())
+ tmp_names_.erase(abs);
+ fn.removeFile();
+}
+
+
static string createTempFile(QString const & mask)
{
// FIXME: This is not safe. QTemporaryFile creates a file in open(),
// 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
+ // TempFile, but using a currently non-existing
// QTemporaryDirectory object).
QTemporaryFile qt_tmp(mask + ".XXXXXXXXXXXX");
if (qt_tmp.open()) {
#include <utility>
#include <string>
+#include <set>
namespace lyx {
namespace support {
class FileName;
+/// Record used temp file names
+static std::set<std::string> tmp_names_;
+
+/// Get a temporary file name.
+/**
+* The actual temp file (QTemporaryFile object) is immediately
+* destroyed after the name has been generated, so a new file
+* has to be created manually from the name.
+* This is needed if the temp file has to be manually removed
+* (e.g., when temp files are used as conversion target, and the initial
+* file only serves as a placeholder), since QTemporaryFile objects
+* cannot be manually removed at least on Windows (they are always
+* kept open internally even after close()).
+* In order to avoid race conditions due to duplicate names, we record
+* all used temp file names.
+* If you don't have to remove the temp file manually, use TempFile instead!
+*/
+FileName const tempFileName(std::string const &);
+
+/// Remove and unregister a temporary file.
+void removeTempFile(FileName const &);
+
/** Creates the global LyX temp dir.
\p deflt can be an existing directory name. In this case a new directory
inside \p deflt is created. If \p deflt does not exist yet, \p deflt is