Deprecate wstat/stat in favour of WinAPI GetFileAttributesEx - unifies code and behaviour between Windows versions

Fixes #4491, fixes #3969, fixes #2535, fixes #215, close #4541
This commit is contained in:
Silent 2018-05-31 16:13:01 +02:00 committed by Don HO
parent 9cb8fce854
commit a9d203a60a
6 changed files with 54 additions and 96 deletions

View File

@ -1194,64 +1194,3 @@ bool isAssoCommandExisting(LPCTSTR FullPathName)
} }
return isAssoCommandExisting; return isAssoCommandExisting;
} }
#ifndef _WIN64
static bool IsWindows2000orXP()
{
bool isWin2kXP = false;
switch (NppParameters::getInstance()->getWinVersion())
{
case WV_W2K:
case WV_XP:
case WV_S2003:
isWin2kXP = true;
break;
}
return isWin2kXP;
}
static ULONGLONG filetime_to_time_ull(const FILETIME* ft)
{
ULARGE_INTEGER ull;
ull.LowPart = ft->dwLowDateTime;
ull.HighPart = ft->dwHighDateTime;
return (ull.QuadPart / 10000000ULL - 11644473600ULL);
}
int custom_wstat(wchar_t const* _FileName, struct _stat* _Stat)
{
static bool isWin2kXP = IsWindows2000orXP();
if (!isWin2kXP)
return _wstat(_FileName, _Stat);
// In Visual Studio 2015, _wstat always returns -1 in Windows XP.
// So here is a WinAPI-based implementation of _wstat.
int nResult = -1;
HANDLE hFile = ::CreateFile(_FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
LARGE_INTEGER fileSize;
FILETIME creationTime, accessTime, writeTime;
if (::GetFileSizeEx(hFile, &fileSize) &&
::GetFileTime(hFile, &creationTime, &accessTime, &writeTime))
{
DWORD dwAttr = ::GetFileAttributes(_FileName);
::ZeroMemory(_Stat, sizeof(struct _stat));
_Stat->st_atime = static_cast<decltype(_Stat->st_atime)>(filetime_to_time_ull(&accessTime));
_Stat->st_ctime = static_cast<decltype(_Stat->st_ctime)>(filetime_to_time_ull(&creationTime));
_Stat->st_mtime = static_cast<decltype(_Stat->st_mtime)>(filetime_to_time_ull(&writeTime));
_Stat->st_size = static_cast<decltype(_Stat->st_size)>(fileSize.QuadPart);
_Stat->st_mode = _S_IREAD | _S_IEXEC; // S_IEXEC : Execute (for ordinary files) or search (for directories)
if ((dwAttr & FILE_ATTRIBUTE_READONLY) == 0)
_Stat->st_mode |= _S_IWRITE;
if ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0)
_Stat->st_mode |= _S_IFDIR;
else
_Stat->st_mode |= _S_IFREG;
nResult = 0;
}
::CloseHandle(hFile);
}
return nResult;
}
#endif

View File

@ -62,11 +62,6 @@ const bool dirDown = false;
#define generic_sscanf swscanf #define generic_sscanf swscanf
#define generic_fopen _wfopen #define generic_fopen _wfopen
#define generic_fgets fgetws #define generic_fgets fgetws
#ifdef _WIN64
#define generic_stat _wstat
#else
#define generic_stat custom_wstat
#endif
#define COPYDATA_FILENAMES COPYDATA_FILENAMESW #define COPYDATA_FILENAMES COPYDATA_FILENAMESW
typedef std::basic_string<TCHAR> generic_string; typedef std::basic_string<TCHAR> generic_string;
@ -196,7 +191,3 @@ HWND CreateToolTip(int toolID, HWND hDlg, HINSTANCE hInst, const PTSTR pszText);
bool isCertificateValidated(const generic_string & fullFilePath, const generic_string & subjectName2check); bool isCertificateValidated(const generic_string & fullFilePath, const generic_string & subjectName2check);
bool isAssoCommandExisting(LPCTSTR FullPathName); bool isAssoCommandExisting(LPCTSTR FullPathName);
#ifndef _WIN64
int custom_wstat(wchar_t const* _FileName, struct _stat* _Stat);
#endif

View File

@ -1913,7 +1913,7 @@ void Notepad_plus::command(int id)
generic_string characterNumber = TEXT(""); generic_string characterNumber = TEXT("");
Buffer * curBuf = _pEditView->getCurrentBuffer(); Buffer * curBuf = _pEditView->getCurrentBuffer();
int fileLen = curBuf->getFileLength(); int64_t fileLen = curBuf->getFileLength();
if (fileLen != -1) if (fileLen != -1)
{ {
@ -1935,7 +1935,7 @@ void Notepad_plus::command(int id)
characterNumber += TEXT("\r"); characterNumber += TEXT("\r");
characterNumber += fileLenLabel; characterNumber += fileLenLabel;
characterNumber += commafyInt(static_cast<UINT64>(fileLen)).c_str(); characterNumber += commafyInt(static_cast<size_t>(fileLen)).c_str();
characterNumber += TEXT("\r"); characterNumber += TEXT("\r");
characterNumber += TEXT("\r"); characterNumber += TEXT("\r");
} }

View File

@ -1076,10 +1076,10 @@ bool NppParameters::load()
BOOL doRecover = FALSE; BOOL doRecover = FALSE;
if (::PathFileExists(langs_xml_path.c_str())) if (::PathFileExists(langs_xml_path.c_str()))
{ {
struct _stat buf; WIN32_FILE_ATTRIBUTE_DATA attributes;
if (generic_stat(langs_xml_path.c_str(), &buf)==0) if (GetFileAttributesEx(langs_xml_path.c_str(), GetFileExInfoStandard, &attributes) != 0)
if (buf.st_size == 0) if (attributes.nFileSizeLow == 0 && attributes.nFileSizeHigh == 0)
doRecover = _pNativeLangSpeaker->messageBox("LoadLangsFailed", doRecover = _pNativeLangSpeaker->messageBox("LoadLangsFailed",
NULL, NULL,
TEXT("Load langs.xml failed!\rDo you want to recover your langs.xml?"), TEXT("Load langs.xml failed!\rDo you want to recover your langs.xml?"),

View File

@ -313,17 +313,18 @@ void Buffer::reload()
} }
} }
int Buffer::getFileLength() const int64_t Buffer::getFileLength() const
{ {
if (_currentStatus == DOC_UNNAMED) if (_currentStatus == DOC_UNNAMED)
return -1; return -1;
struct _stat buf; WIN32_FILE_ATTRIBUTE_DATA attributes;
if (GetFileAttributesEx(_fullPathName.c_str(), GetFileExInfoStandard, &attributes) != 0)
if (PathFileExists(_fullPathName.c_str()))
{ {
if (!generic_stat(_fullPathName.c_str(), &buf)) LARGE_INTEGER size;
return buf.st_size; size.LowPart = attributes.nFileSizeLow;
size.HighPart = attributes.nFileSizeHigh;
return size.QuadPart;
} }
return -1; return -1;
} }
@ -331,26 +332,53 @@ int Buffer::getFileLength() const
generic_string Buffer::getFileTime(fileTimeType ftt) const generic_string Buffer::getFileTime(fileTimeType ftt) const
{ {
if (_currentStatus == DOC_UNNAMED) generic_string result;
return generic_string();
struct _stat buf; if (_currentStatus != DOC_UNNAMED)
if (PathFileExists(_fullPathName.c_str()))
{ {
if (!generic_stat(_fullPathName.c_str(), &buf)) WIN32_FILE_ATTRIBUTE_DATA attributes;
if (GetFileAttributesEx(_fullPathName.c_str(), GetFileExInfoStandard, &attributes) != 0)
{ {
time_t rawtime = (ftt == ft_created ? buf.st_ctime : (ftt == ft_modified ? buf.st_mtime : buf.st_atime)); FILETIME rawtime;
tm *timeinfo = localtime(&rawtime); switch (ftt)
const int temBufLen = 64; {
TCHAR tmpbuf[temBufLen]; case ft_created:
rawtime = attributes.ftCreationTime;
break;
case ft_modified:
rawtime = attributes.ftLastWriteTime;
break;
default:
rawtime = attributes.ftLastAccessTime;
break;
}
generic_strftime(tmpbuf, temBufLen, TEXT("%Y-%m-%d %H:%M:%S"), timeinfo); SYSTEMTIME utcSystemTime, localSystemTime;
return tmpbuf; FileTimeToSystemTime(&rawtime, &utcSystemTime);
SystemTimeToTzSpecificLocalTime(nullptr, &utcSystemTime, &localSystemTime);
int cbSize = GetDateFormat(LOCALE_USER_DEFAULT, 0, &localSystemTime, nullptr, nullptr, 0);
if (cbSize != 0)
{
TCHAR* buf = new TCHAR[cbSize];
GetDateFormat(LOCALE_USER_DEFAULT, 0, &localSystemTime, nullptr, buf, cbSize);
result += buf;
delete[] buf;
}
result += ' ';
cbSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0, &localSystemTime, nullptr, nullptr, 0);
if (cbSize != 0)
{
TCHAR* buf = new TCHAR[cbSize];
GetTimeFormat(LOCALE_USER_DEFAULT, 0, &localSystemTime, nullptr, buf, cbSize);
result += buf;
delete[] buf;
}
} }
} }
return result;
return generic_string();
} }

View File

@ -310,7 +310,7 @@ public:
return _pManager->docLength(_id); return _pManager->docLength(_id);
} }
int getFileLength() const; // return file length. -1 if file is not existing. int64_t getFileLength() const; // return file length. -1 if file is not existing.
enum fileTimeType { ft_created, ft_modified, ft_accessed }; enum fileTimeType { ft_created, ft_modified, ft_accessed };
generic_string getFileTime(fileTimeType ftt) const; generic_string getFileTime(fileTimeType ftt) const;