using std::stack;
using std::vector;
using std::string;
+using std::time_t;
namespace lyx {
using support::subst;
using support::tempName;
using support::trim;
+using support::sum;
namespace Alert = frontend::Alert;
namespace os = support::os;
/// Container for all sort of Buffer dependant errors.
map<string, ErrorList> errorLists;
+
+ /// timestamp and checksum used to test if the file has been externally
+ /// modified. (Used to properly enable 'File->Revert to saved', bug 4114).
+ time_t timestamp_;
+ unsigned long checksum_;
};
Buffer::Impl::Impl(Buffer & parent, FileName const & file, bool readonly_)
: lyx_clean(true), bak_clean(true), unnamed(false), read_only(readonly_),
filename(file), file_fully_loaded(false), inset(params),
- toc_backend(&parent)
+ timestamp_(0), checksum_(0), toc_backend(&parent)
{
inset.setAutoBreakRows(true);
lyxvc.buffer(&parent);
//MacroTable::localMacros().clear();
pimpl_->file_fully_loaded = true;
+ // save the timestamp and checksum of disk file
+ pimpl_->timestamp_ = fs::last_write_time(filename.toFilesystemEncoding());
+ pimpl_->checksum_ = sum(filename);
return success;
}
}
}
+ // ask if the disk file has been externally modified (use checksum method)
+ if (fs::exists(encodedFilename) && isExternallyModified(checksum_method)) {
+ docstring const file = makeDisplayPath(fileName(), 20);
+ docstring text = bformat(_("Document %1$s has been externally modified. Are you sure "
+ "you want to overwrite this file?"), file);
+ int const ret = Alert::prompt(_("Overwrite modified file?"),
+ text, 1, 1, _("&Overwrite"), _("&Cancel"));
+ if (ret == 1)
+ return false;
+ }
+
if (writeFile(pimpl_->filename)) {
markClean();
removeAutosaveFile(fileName());
+ pimpl_->timestamp_ = fs::last_write_time(pimpl_->filename.toFilesystemEncoding());
+ pimpl_->checksum_ = sum(pimpl_->filename);
return true;
} else {
// Saving failed, so backup is not backup
}
+bool Buffer::isExternallyModified(CheckMethod method) const
+{
+ BOOST_ASSERT(fs::exists(pimpl_->filename.toFilesystemEncoding()));
+ // if method == timestamp, check timestamp before checksum
+ return (method == checksum_method
+ || pimpl_->timestamp_ != fs::last_write_time(pimpl_->filename.toFilesystemEncoding()))
+ && pimpl_->checksum_ != sum(pimpl_->filename);
+}
+
+
void Buffer::markClean() const
{
if (!pimpl_->lyx_clean) {
wrongversion ///< The version of the file does not match ours
};
+ /// Method to check if a file is externally modified, used by
+ /// isExternallyModified()
+ /**
+ * timestamp is fast but inaccurate. For example, the granularity
+ * of timestamp on a FAT filesystem is 2 second. Also, various operations
+ * may touch the timestamp of a file even when its content is unchanged.
+ *
+ * checksum is accurate but slow, which can be a problem when it is
+ * frequently used, or used for a large file on a slow (network) file
+ * system.
+ */
+ enum CheckMethod {
+ checksum_method, ///< Use file check sum
+ timestamp_method, ///< Use timestamp, and checksum if timestamp has changed
+ };
+
/** Constructor
\param file
\param b optional \c false by default
///
bool isDepClean(std::string const & name) const;
+ /// whether or not disk file has been externally modified
+ bool isExternallyModified(CheckMethod method) const;
+
/// mark the main lyx file as not needing saving
void markClean() const;