Migrate timestamps from time_t to FILETIME and store them in UTC universally

Fixes #4491, #3969, #2535 and #215.
This commit is contained in:
Silent 2018-05-31 15:32:44 +02:00 committed by Don HO
parent 08eb29e3d6
commit 9cb8fce854
7 changed files with 35 additions and 28 deletions

View File

@ -4952,7 +4952,7 @@ void Notepad_plus::getCurrentOpenedFiles(Session & session, bool includUntitledD
generic_string languageName = getLangFromMenu(buf);
const TCHAR *langName = languageName.c_str();
sessionFileInfo sfi(buf->getFullPathName(), langName, buf->getEncoding(), buf->getPosition(editView), buf->getBackupFileName().c_str(), int(buf->getLastModifiedTimestamp()), buf->getMapPosition());
sessionFileInfo sfi(buf->getFullPathName(), langName, buf->getEncoding(), buf->getPosition(editView), buf->getBackupFileName().c_str(), buf->getLastModifiedTimestamp(), buf->getMapPosition());
_invisibleEditView.execute(SCI_SETDOCPOINTER, 0, buf->getDocument());
size_t maxLine = static_cast<size_t>(_invisibleEditView.execute(SCI_GETLINECOUNT));

View File

@ -174,7 +174,7 @@ public:
//! \name File Operations
//@{
//The doXXX functions apply to a single buffer and dont need to worry about views, with the excpetion of doClose, since closing one view doesnt have to mean the document is gone
BufferID doOpen(const generic_string& fileName, bool isRecursive = false, bool isReadOnly = false, int encoding = -1, const TCHAR *backupFileName = NULL, time_t fileNameTimestamp = 0);
BufferID doOpen(const generic_string& fileName, bool isRecursive = false, bool isReadOnly = false, int encoding = -1, const TCHAR *backupFileName = NULL, FILETIME fileNameTimestamp = {});
bool doReload(BufferID id, bool alert = true);
bool doSave(BufferID, const TCHAR * filename, bool isSaveCopy = false);
void doClose(BufferID, int whichOne, bool doDeleteBackup = false);

View File

@ -121,7 +121,7 @@ DWORD WINAPI Notepad_plus::monitorFileOnChange(void * params)
return EXIT_SUCCESS;
}
BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive, bool isReadOnly, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp)
BufferID Notepad_plus::doOpen(const generic_string& fileName, bool isRecursive, bool isReadOnly, int encoding, const TCHAR *backupFileName, FILETIME fileNameTimestamp)
{
const rsize_t longFileNameBufferSize = MAX_PATH; // TODO stop using fixed-size buffer
if (fileName.size() >= longFileNameBufferSize - 1) // issue with all other sub-routines

View File

@ -2050,8 +2050,9 @@ bool NppParameters::getSessionFromXmlTree(TiXmlDocument *pSessionDoc, Session *p
const TCHAR *encStr = (childNode->ToElement())->Attribute(TEXT("encoding"), &encoding);
const TCHAR *backupFilePath = (childNode->ToElement())->Attribute(TEXT("backupFilePath"));
int fileModifiedTimestamp = 0;
(childNode->ToElement())->Attribute(TEXT("originalFileLastModifTimestamp"), &fileModifiedTimestamp);
FILETIME fileModifiedTimestamp;
(childNode->ToElement())->Attribute(TEXT("originalFileLastModifTimestamp"), reinterpret_cast<int32_t*>(&fileModifiedTimestamp.dwLowDateTime));
(childNode->ToElement())->Attribute(TEXT("originalFileLastModifTimestampHigh"), reinterpret_cast<int32_t*>(&fileModifiedTimestamp.dwHighDateTime));
sessionFileInfo sfi(fileName, langName, encStr?encoding:-1, position, backupFilePath, fileModifiedTimestamp, mapPosition);
@ -2985,7 +2986,8 @@ void NppParameters::writeSession(const Session & session, const TCHAR *fileName)
(fileNameNode->ToElement())->SetAttribute(TEXT("encoding"), viewSessionFiles[i]._encoding);
(fileNameNode->ToElement())->SetAttribute(TEXT("filename"), viewSessionFiles[i]._fileName.c_str());
(fileNameNode->ToElement())->SetAttribute(TEXT("backupFilePath"), viewSessionFiles[i]._backupFilePath.c_str());
(fileNameNode->ToElement())->SetAttribute(TEXT("originalFileLastModifTimestamp"), static_cast<int32_t>(viewSessionFiles[i]._originalFileLastModifTimestamp));
(fileNameNode->ToElement())->SetAttribute(TEXT("originalFileLastModifTimestamp"), static_cast<int32_t>(viewSessionFiles[i]._originalFileLastModifTimestamp.dwLowDateTime));
(fileNameNode->ToElement())->SetAttribute(TEXT("originalFileLastModifTimestampHigh"), static_cast<int32_t>(viewSessionFiles[i]._originalFileLastModifTimestamp.dwHighDateTime));
// docMap
(fileNameNode->ToElement())->SetAttribute(TEXT("mapFirstVisibleDisplayLine"), viewSessionFiles[i]._mapPos._firstVisibleDisplayLine);

View File

@ -162,7 +162,7 @@ private:
struct sessionFileInfo : public Position
{
sessionFileInfo(const TCHAR *fn, const TCHAR *ln, int encoding, Position pos, const TCHAR *backupFilePath, int originalFileLastModifTimestamp, const MapPosition & mapPos) :
sessionFileInfo(const TCHAR *fn, const TCHAR *ln, int encoding, Position pos, const TCHAR *backupFilePath, FILETIME originalFileLastModifTimestamp, const MapPosition & mapPos) :
_encoding(encoding), Position(pos), _originalFileLastModifTimestamp(originalFileLastModifTimestamp), _mapPos(mapPos)
{
if (fn) _fileName = fn;
@ -179,7 +179,7 @@ struct sessionFileInfo : public Position
int _encoding = -1;
generic_string _backupFilePath;
time_t _originalFileLastModifTimestamp = 0;
FILETIME _originalFileLastModifTimestamp = {};
MapPosition _mapPos;
};

View File

@ -144,10 +144,14 @@ void Buffer::setLangType(LangType lang, const TCHAR* userLangName)
void Buffer::updateTimeStamp()
{
struct _stat buf;
time_t timeStamp = (generic_stat(_fullPathName.c_str(), &buf)==0)?buf.st_mtime:0;
FILETIME timeStamp = {};
WIN32_FILE_ATTRIBUTE_DATA attributes;
if (GetFileAttributesEx(_fullPathName.c_str(), GetFileExInfoStandard, &attributes) != 0)
{
timeStamp = attributes.ftLastWriteTime;
}
if (timeStamp != _timeStamp)
if (CompareFileTime(&_timeStamp, &timeStamp) != 0)
{
_timeStamp = timeStamp;
doNotify(BufferChangeTimestamp);
@ -222,7 +226,7 @@ bool Buffer::checkFileState() //eturns true if the status has been changed (it c
if (_currentStatus == DOC_UNNAMED) //unsaved document cannot change by environment
return false;
struct _stat buf;
WIN32_FILE_ATTRIBUTE_DATA attributes;
bool isWow64Off = false;
NppParameters *pNppParam = NppParameters::getInstance();
@ -238,18 +242,18 @@ bool Buffer::checkFileState() //eturns true if the status has been changed (it c
_currentStatus = DOC_DELETED;
_isFileReadOnly = false;
_isDirty = true; //dirty sicne no match with filesystem
_timeStamp = 0;
_timeStamp = {};
doNotify(BufferChangeStatus | BufferChangeReadonly | BufferChangeTimestamp);
isOK = true;
}
else if (_currentStatus == DOC_DELETED && PathFileExists(_fullPathName.c_str()))
{ //document has returned from its grave
if (not generic_stat(_fullPathName.c_str(), &buf))
if (GetFileAttributesEx(_fullPathName.c_str(), GetFileExInfoStandard, &attributes) != 0)
{
_isFileReadOnly = (bool)(!(buf.st_mode & _S_IWRITE));
_isFileReadOnly = attributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
_currentStatus = DOC_MODIFIED;
_timeStamp = buf.st_mtime;
_timeStamp = attributes.ftLastWriteTime;
if (_reloadFromDiskRequestGuard.try_lock())
{
@ -259,18 +263,18 @@ bool Buffer::checkFileState() //eturns true if the status has been changed (it c
isOK = true;
}
}
else if (not generic_stat(_fullPathName.c_str(), &buf))
else if (GetFileAttributesEx(_fullPathName.c_str(), GetFileExInfoStandard, &attributes) != 0)
{
int mask = 0; //status always 'changes', even if from modified to modified
bool isFileReadOnly = (bool)(not(buf.st_mode & _S_IWRITE));
bool isFileReadOnly = attributes.dwFileAttributes & FILE_ATTRIBUTE_READONLY;
if (isFileReadOnly != _isFileReadOnly)
{
_isFileReadOnly = isFileReadOnly;
mask |= BufferChangeReadonly;
}
if (_timeStamp != buf.st_mtime)
if (CompareFileTime(&_timeStamp, &attributes.ftLastWriteTime) != 0)
{
_timeStamp = buf.st_mtime;
_timeStamp = attributes.ftLastWriteTime;
mask |= BufferChangeTimestamp;
_currentStatus = DOC_MODIFIED;
mask |= BufferChangeStatus; //status always 'changes', even if from modified to modified
@ -300,10 +304,10 @@ bool Buffer::checkFileState() //eturns true if the status has been changed (it c
void Buffer::reload()
{
struct _stat buf;
if (PathFileExists(_fullPathName.c_str()) && not generic_stat(_fullPathName.c_str(), &buf))
WIN32_FILE_ATTRIBUTE_DATA attributes;
if (GetFileAttributesEx(_fullPathName.c_str(), GetFileExInfoStandard, &attributes) != 0)
{
_timeStamp = buf.st_mtime;
_timeStamp = attributes.ftLastWriteTime;
_currentStatus = DOC_NEEDRELOAD;
doNotify(BufferChangeTimestamp | BufferChangeStatus);
}
@ -552,7 +556,7 @@ void FileManager::closeBuffer(BufferID id, ScintillaEditView * identifier)
// backupFileName is sentinel of backup mode: if it's not NULL, then we use it (load it). Otherwise we use filename
BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encoding, const TCHAR *backupFileName, time_t fileNameTimestamp)
BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encoding, const TCHAR *backupFileName, FILETIME fileNameTimestamp)
{
bool ownDoc = false;
if (doc == NULL)
@ -593,7 +597,8 @@ BufferID FileManager::loadFile(const TCHAR * filename, Document doc, int encodin
newBuf->_currentStatus = DOC_UNNAMED;
}
if (fileNameTimestamp != 0)
const FILETIME zeroTime = {};
if (CompareFileTime(&fileNameTimestamp, &zeroTime) != 0)
newBuf->_timeStamp = fileNameTimestamp;
_buffers.push_back(newBuf);

View File

@ -87,7 +87,7 @@ public:
void addBufferReference(BufferID id, ScintillaEditView * identifer); //called by Scintilla etc indirectly
BufferID loadFile(const TCHAR * filename, Document doc = NULL, int encoding = -1, const TCHAR *backupFileName = NULL, time_t fileNameTimestamp = 0); //ID == BUFFER_INVALID on failure. If Doc == NULL, a new file is created, otherwise data is loaded in given document
BufferID loadFile(const TCHAR * filename, Document doc = NULL, int encoding = -1, const TCHAR *backupFileName = NULL, FILETIME fileNameTimestamp = {}); //ID == BUFFER_INVALID on failure. If Doc == NULL, a new file is created, otherwise data is loaded in given document
BufferID newEmptyDocument();
//create Buffer from existing Scintilla, used from new Scintillas. If dontIncrease = true, then the new document number isnt increased afterwards.
//usefull for temporary but neccesary docs
@ -321,7 +321,7 @@ public:
void setModifiedStatus(bool isModified) { _isModified = isModified; }
generic_string getBackupFileName() const { return _backupFileName; }
void setBackupFileName(generic_string fileName) { _backupFileName = fileName; }
time_t getLastModifiedTimestamp() const { return _timeStamp; }
FILETIME getLastModifiedTimestamp() const { return _timeStamp; }
bool isLoadedDirty() const
{
@ -394,7 +394,7 @@ private:
//Environment properties
DocFileStatus _currentStatus;
time_t _timeStamp = 0; // 0 if it's a new doc
FILETIME _timeStamp = {}; // 0 if it's a new doc
bool _isFileReadOnly = false;
generic_string _fullPathName;