Migrate timestamps from time_t to FILETIME and store them in UTC universally
Fixes #4491, #3969, #2535 and #215.
This commit is contained in:
parent
08eb29e3d6
commit
9cb8fce854
@ -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));
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user