diff options
author | Igor Pavlov <ipavlov@users.sourceforge.net> | 2021-07-23 01:00:14 +0300 |
---|---|---|
committer | Kornel <kornel@geekhood.net> | 2021-07-23 01:00:14 +0300 |
commit | 585698650f7257d2cefa6a3a2a49d5bbe84fd9b2 (patch) | |
tree | 8900be42e892a440bbd1063804b0557288c2f97f /CPP/Windows | |
parent | 4a960640a340a848a2d2c27f19b339c2c3d3f734 (diff) |
21.0221.02
Diffstat (limited to 'CPP/Windows')
49 files changed, 3331 insertions, 291 deletions
diff --git a/CPP/Windows/CommonDialog.cpp b/CPP/Windows/CommonDialog.cpp index 8f4f56d3..eaaecada 100644 --- a/CPP/Windows/CommonDialog.cpp +++ b/CPP/Windows/CommonDialog.cpp @@ -67,8 +67,11 @@ bool CDoubleZeroStringListW::Add(LPCWSTR s) throw() return true; } + +#ifdef UNDER_CE #define MY__OFN_PROJECT 0x00400000 #define MY__OFN_SHOW_ALL 0x01000000 +#endif /* if (lpstrFilter == NULL && nFilterIndex == 0) MSDN : "the system doesn't show any files", @@ -91,14 +94,34 @@ So we use size of old version of structure. */ #if defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500) // || !defined(WINVER) + #ifndef _UNICODE #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA) + #endif #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW) #else + + // MinGW doesn't support some required macros. So we define them here: + #ifndef CDSIZEOF_STRUCT + #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member)) + #endif + #ifndef _UNICODE + #ifndef OPENFILENAME_SIZE_VERSION_400A + #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName) + #endif + #endif + #ifndef OPENFILENAME_SIZE_VERSION_400W + #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName) + #endif + + #ifndef _UNICODE #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A + #endif #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W #endif +#ifndef _UNICODE #define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; } +#endif bool MyGetOpenFileName(HWND hwnd, LPCWSTR title, LPCWSTR initialDir, diff --git a/CPP/Windows/Control/ComboBox.cpp b/CPP/Windows/Control/ComboBox.cpp index febc61ef..f6ed8d34 100644 --- a/CPP/Windows/Control/ComboBox.cpp +++ b/CPP/Windows/Control/ComboBox.cpp @@ -43,10 +43,10 @@ LRESULT CComboBox::GetLBText(int index, UString &s) s.Empty(); if (g_IsNT) { - LRESULT len = SendMsgW(CB_GETLBTEXTLEN, index, 0); + LRESULT len = SendMsgW(CB_GETLBTEXTLEN, MY__int_TO_WPARAM(index), 0); if (len == CB_ERR) return len; - LRESULT len2 = SendMsgW(CB_GETLBTEXT, index, (LPARAM)s.GetBuf((unsigned)len)); + LRESULT len2 = SendMsgW(CB_GETLBTEXT, MY__int_TO_WPARAM(index), (LPARAM)s.GetBuf((unsigned)len)); if (len2 == CB_ERR) return len; if (len > len2) diff --git a/CPP/Windows/Control/ComboBox.h b/CPP/Windows/Control/ComboBox.h index 1d5a4821..f08b1f7c 100644 --- a/CPP/Windows/Control/ComboBox.h +++ b/CPP/Windows/Control/ComboBox.h @@ -5,13 +5,15 @@ #include "../../Common/MyWindows.h" -#include <commctrl.h> +#include <CommCtrl.h> #include "../Window.h" namespace NWindows { namespace NControl { +#define MY__int_TO_WPARAM(i) ((WPARAM)(INT_PTR)(i)) + class CComboBox: public CWindow { public: @@ -20,19 +22,25 @@ public: #ifndef _UNICODE LRESULT AddString(LPCWSTR s); #endif - LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, index, 0); } + + /* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/ + LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY__int_TO_WPARAM(index), 0); } + + /* If no item is selected, it returns CB_ERR (-1) */ int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); } + + /* If an error occurs, it is CB_ERR (-1) */ int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); } - LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, index, 0); } - LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, index, (LPARAM)s); } + LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, MY__int_TO_WPARAM(index), 0); } + LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, MY__int_TO_WPARAM(index), (LPARAM)s); } LRESULT GetLBText(int index, CSysString &s); #ifndef _UNICODE LRESULT GetLBText(int index, UString &s); #endif - LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, index, lParam); } - LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, index, 0); } + LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, MY__int_TO_WPARAM(index), lParam); } + LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, MY__int_TO_WPARAM(index), 0); } LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); } @@ -46,7 +54,11 @@ class CComboBoxEx: public CComboBox public: bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMsg(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); } - LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, index, 0); } + /* Returns: + an INT value that represents the number of items remaining in the control. + If (index) is invalid, the message returns CB_ERR. */ + LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, MY__int_TO_WPARAM(index), 0); } + LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_INSERTITEM, 0, (LPARAM)item); } #ifndef _UNICODE LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMsg(CBEM_INSERTITEMW, 0, (LPARAM)item); } diff --git a/CPP/Windows/Control/ImageList.h b/CPP/Windows/Control/ImageList.h index 0d9c9313..19feb117 100644 --- a/CPP/Windows/Control/ImageList.h +++ b/CPP/Windows/Control/ImageList.h @@ -3,7 +3,7 @@ #ifndef __WINDOWS_CONTROL_IMAGE_LIST_H #define __WINDOWS_CONTROL_IMAGE_LIST_H -#include <commctrl.h> +#include <CommCtrl.h> #include "../Defs.h" diff --git a/CPP/Windows/Control/ListView.cpp b/CPP/Windows/Control/ListView.cpp index 6d916591..16cfd396 100644 --- a/CPP/Windows/Control/ListView.cpp +++ b/CPP/Windows/Control/ListView.cpp @@ -35,7 +35,7 @@ int CListView::InsertColumn(int columnIndex, LPCTSTR text, int width) { LVCOLUMN ci; ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; - ci.pszText = (LPTSTR)text; + ci.pszText = (LPTSTR)(void *)text; ci.iSubItem = columnIndex; ci.cx = width; return InsertColumn(columnIndex, &ci); @@ -47,7 +47,7 @@ int CListView::InsertItem(int index, LPCTSTR text) item.mask = LVIF_TEXT | LVIF_PARAM; item.iItem = index; item.lParam = index; - item.pszText = (LPTSTR)text; + item.pszText = (LPTSTR)(void *)text; item.iSubItem = 0; return InsertItem(&item); } @@ -57,7 +57,7 @@ int CListView::SetSubItem(int index, int subIndex, LPCTSTR text) LVITEM item; item.mask = LVIF_TEXT; item.iItem = index; - item.pszText = (LPTSTR)text; + item.pszText = (LPTSTR)(void *)text; item.iSubItem = subIndex; return SetItem(&item); } @@ -68,7 +68,7 @@ int CListView::InsertColumn(int columnIndex, LPCWSTR text, int width) { LVCOLUMNW ci; ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM; - ci.pszText = (LPWSTR)text; + ci.pszText = (LPWSTR)(void *)text; ci.iSubItem = columnIndex; ci.cx = width; return InsertColumn(columnIndex, &ci); @@ -80,7 +80,7 @@ int CListView::InsertItem(int index, LPCWSTR text) item.mask = LVIF_TEXT | LVIF_PARAM; item.iItem = index; item.lParam = index; - item.pszText = (LPWSTR)text; + item.pszText = (LPWSTR)(void *)text; item.iSubItem = 0; return InsertItem(&item); } @@ -90,7 +90,7 @@ int CListView::SetSubItem(int index, int subIndex, LPCWSTR text) LVITEMW item; item.mask = LVIF_TEXT; item.iItem = index; - item.pszText = (LPWSTR)text; + item.pszText = (LPWSTR)(void *)text; item.iSubItem = subIndex; return SetItem(&item); } diff --git a/CPP/Windows/Control/ListView.h b/CPP/Windows/Control/ListView.h index 9a3abe70..a13b1041 100644 --- a/CPP/Windows/Control/ListView.h +++ b/CPP/Windows/Control/ListView.h @@ -5,7 +5,7 @@ #include "../../Common/MyWindows.h" -#include <commctrl.h> +#include <CommCtrl.h> #include "../Window.h" @@ -32,7 +32,8 @@ public: int InsertColumn(int columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); } int InsertColumn(int columnIndex, LPCTSTR text, int width); - bool SetColumnOrderArray(int count, const int *columns) { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, columns)); } + bool SetColumnOrderArray(int count, const int *columns) + { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, (int *)(void *)columns)); } /* int GetNumColumns() diff --git a/CPP/Windows/Control/ProgressBar.h b/CPP/Windows/Control/ProgressBar.h index 38ebcb61..03743067 100644 --- a/CPP/Windows/Control/ProgressBar.h +++ b/CPP/Windows/Control/ProgressBar.h @@ -5,7 +5,7 @@ #include "../../Common/MyWindows.h" -#include <commctrl.h> +#include <CommCtrl.h> #include "../Window.h" diff --git a/CPP/Windows/Control/PropertyPage.h b/CPP/Windows/Control/PropertyPage.h index 4c4ddad9..b68fd8fe 100644 --- a/CPP/Windows/Control/PropertyPage.h +++ b/CPP/Windows/Control/PropertyPage.h @@ -5,7 +5,7 @@ #include "../../Common/MyWindows.h" -#include <prsht.h> +#include <PrSht.h> #include "Dialog.h" diff --git a/CPP/Windows/DLL.cpp b/CPP/Windows/DLL.cpp index d7f38375..cf5d01a3 100644 --- a/CPP/Windows/DLL.cpp +++ b/CPP/Windows/DLL.cpp @@ -4,6 +4,8 @@ #include "DLL.h" +#ifdef _WIN32 + #ifndef _UNICODE extern bool g_IsNT; #endif @@ -97,7 +99,7 @@ FString GetModuleDirPrefix() { int pos = s.ReverseFind_PathSepar(); if (pos >= 0) - s.DeleteFrom(pos + 1); + s.DeleteFrom((unsigned)(pos + 1)); } if (s.IsEmpty()) s = "." STRING_PATH_SEPARATOR; @@ -107,3 +109,83 @@ FString GetModuleDirPrefix() #endif }} + +#else + +#include <dlfcn.h> +#include <stdlib.h> + +namespace NWindows { +namespace NDLL { + +bool CLibrary::Free() throw() +{ + if (_module == NULL) + return true; + int ret = dlclose(_module); + if (ret != 0) + return false; + _module = NULL; + return true; +} + +static +// FARPROC +void * +local_GetProcAddress(HMODULE module, LPCSTR procName) +{ + void *ptr = NULL; + if (module) + { + ptr = dlsym(module, procName); + } + return ptr; +} + +bool CLibrary::Load(CFSTR path) throw() +{ + if (!Free()) + return false; + + int options = 0; + + #ifdef RTLD_LOCAL + options |= RTLD_LOCAL; + #endif + + #ifdef RTLD_NOW + options |= RTLD_NOW; + #endif + + #ifdef RTLD_GROUP + #if ! (defined(hpux) || defined(__hpux)) + options |= RTLD_GROUP; // mainly for solaris but not for HPUX + #endif + #endif + + void *handler = dlopen(path, options); + + if (handler) + { + // here we can transfer some settings to DLL + } + else + { + } + + _module = handler; + + return (_module != NULL); +} + +// FARPROC +void * CLibrary::GetProc(LPCSTR procName) const +{ + // return My_GetProcAddress(_module, procName); + return local_GetProcAddress(_module, procName); + // return NULL; +} + +}} + +#endif diff --git a/CPP/Windows/DLL.h b/CPP/Windows/DLL.h index 984a1d33..0c093eed 100644 --- a/CPP/Windows/DLL.h +++ b/CPP/Windows/DLL.h @@ -8,10 +8,12 @@ namespace NWindows { namespace NDLL { +#ifdef _WIN32 + #ifdef UNDER_CE -#define My_GetProcAddress(module, procName) ::GetProcAddressA(module, procName) +#define My_GetProcAddress(module, procName) (void *)::GetProcAddressA(module, procName) #else -#define My_GetProcAddress(module, procName) ::GetProcAddress(module, procName) +#define My_GetProcAddress(module, procName) (void *)::GetProcAddress(module, procName) #endif /* Win32: Don't call CLibrary::Free() and FreeLibrary() from another @@ -46,9 +48,33 @@ public: bool Free() throw(); bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw(); bool Load(CFSTR path) throw(); - FARPROC GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); } + // FARPROC + void *GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); } }; +#else + +typedef void * HMODULE; +// typedef int (*FARPROC)(); +// typedef void *FARPROC; + +class CLibrary +{ + HMODULE _module; + + // CLASS_NO_COPY(CLibrary); +public: + CLibrary(): _module(NULL) {}; + ~CLibrary() { Free(); } + + bool Free() throw(); + bool Load(CFSTR path) throw(); + // FARPROC + void *GetProc(LPCSTR procName) const; // { return My_GetProcAddress(_module, procName); } +}; + +#endif + bool MyGetModuleFileName(FString &path); FString GetModuleDirPrefix(); diff --git a/CPP/Windows/Defs.h b/CPP/Windows/Defs.h index 281c40c3..1d96078d 100644 --- a/CPP/Windows/Defs.h +++ b/CPP/Windows/Defs.h @@ -7,10 +7,11 @@ #ifdef _WIN32 inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); } -inline bool BOOLToBool(BOOL v) { return (v != FALSE); } inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); } #endif +inline bool BOOLToBool(BOOL v) { return (v != FALSE); } + inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); } inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); } diff --git a/CPP/Windows/ErrorMsg.cpp b/CPP/Windows/ErrorMsg.cpp index b86c0b39..bfa21e50 100644 --- a/CPP/Windows/ErrorMsg.cpp +++ b/CPP/Windows/ErrorMsg.cpp @@ -2,21 +2,25 @@ #include "StdAfx.h" -#ifndef _UNICODE +#if !defined(_UNICODE) || !defined(_WIN32) #include "../Common/StringConvert.h" #endif #include "ErrorMsg.h" -#ifndef _UNICODE +#ifdef _WIN32 +#if !defined(_UNICODE) extern bool g_IsNT; #endif +#endif namespace NWindows { namespace NError { static bool MyFormatMessage(DWORD errorCode, UString &message) { + #ifdef _WIN32 + LPVOID msgBuf; #ifndef _UNICODE if (!g_IsNT) @@ -38,8 +42,63 @@ static bool MyFormatMessage(DWORD errorCode, UString &message) } ::LocalFree(msgBuf); return true; + + #else // _WIN32 + + AString m; + + const char *s = NULL; + + switch ((Int32)errorCode) + { + // case ERROR_NO_MORE_FILES : s = "No more files"; break; + // case ERROR_DIRECTORY : s = "Error Directory"; break; + case E_NOTIMPL : s = "E_NOTIMPL : Not implemented"; break; + case E_NOINTERFACE : s = "E_NOINTERFACE : No such interface supported"; break; + case E_ABORT : s = "E_ABORT : Operation aborted"; break; + case E_FAIL : s = "E_FAIL : Unspecified error"; break; + + case STG_E_INVALIDFUNCTION : s = "STG_E_INVALIDFUNCTION"; break; + case CLASS_E_CLASSNOTAVAILABLE : s = "CLASS_E_CLASSNOTAVAILABLE"; break; + + case E_OUTOFMEMORY : s = "E_OUTOFMEMORY : Can't allocate required memory"; break; + case E_INVALIDARG : s = "E_INVALIDARG : One or more arguments are invalid"; break; + + // case MY__E_ERROR_NEGATIVE_SEEK : s = "MY__E_ERROR_NEGATIVE_SEEK"; break; + default: + break; + } + + /* strerror() for unknow errors still shows message "Unknown error -12345678") + So we must trasfer error codes before strerror() */ + if (!s) + { + if ((errorCode & 0xFFFF0000) == (UInt32)((MY__FACILITY__WRes << 16) | 0x80000000)) + errorCode &= 0xFFFF; + else if ((errorCode & ((UInt32)1 << 31))) + return false; // we will show hex error later for that case + + s = strerror((int)errorCode); + + // if (!s) + { + m += "errno="; + m.Add_UInt32(errorCode); + if (s) + m += " : "; + } + } + + if (s) + m += s; + + MultiByteToUnicodeString2(message, m); + return true; + + #endif } + UString MyFormatMessage(DWORD errorCode) { UString m; diff --git a/CPP/Windows/ErrorMsg.h b/CPP/Windows/ErrorMsg.h index 0957c696..01204eb9 100644 --- a/CPP/Windows/ErrorMsg.h +++ b/CPP/Windows/ErrorMsg.h @@ -9,6 +9,7 @@ namespace NWindows { namespace NError { UString MyFormatMessage(DWORD errorCode); +inline UString MyFormatMessage(HRESULT errorCode) { return MyFormatMessage((DWORD)errorCode); } }} diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp index 62b11c10..c06e7f37 100644 --- a/CPP/Windows/FileDir.cpp +++ b/CPP/Windows/FileDir.cpp @@ -2,8 +2,21 @@ #include "StdAfx.h" -#ifndef _UNICODE + +#ifndef _WIN32 +#include <stdio.h> +#include <errno.h> +#include <limits.h> +#include <unistd.h> +#include <time.h> +#include <utime.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h> + #include "../Common/StringConvert.h" +#include "../Common/C_FileIO.h" +#include "TimeUtils.h" #endif #include "FileDir.h" @@ -22,6 +35,8 @@ namespace NWindows { namespace NFile { namespace NDir { +#ifdef _WIN32 + #ifndef UNDER_CE bool GetWindowsDir(FString &path) @@ -67,7 +82,8 @@ bool GetSystemDir(FString &path) } return (needLength > 0 && needLength <= MAX_PATH); } -#endif +#endif // UNDER_CE + bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) { @@ -102,6 +118,8 @@ bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const return res; } + + bool SetFileAttrib(CFSTR path, DWORD attrib) { #ifndef _UNICODE @@ -131,8 +149,10 @@ bool SetFileAttrib(CFSTR path, DWORD attrib) bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) { + #ifdef _WIN32 if ((attrib & 0xF0000000) != 0) attrib &= 0x3FFF; + #endif return SetFileAttrib(path, attrib); } @@ -163,6 +183,7 @@ bool RemoveDir(CFSTR path) return false; } + bool MyMoveFile(CFSTR oldFile, CFSTR newFile) { #ifndef _UNICODE @@ -175,8 +196,10 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) #endif { IF_USE_MAIN_PATH_2(oldFile, newFile) + { if (::MoveFileW(fs2us(oldFile), fs2us(newFile))) return true; + } #ifdef WIN_LONG_PATH if (USE_SUPER_PATH_2) { @@ -190,7 +213,6 @@ bool MyMoveFile(CFSTR oldFile, CFSTR newFile) } #ifndef UNDER_CE - EXTERN_C_BEGIN typedef BOOL (WINAPI *Func_CreateHardLinkW)( LPCWSTR lpFileName, @@ -198,6 +220,7 @@ typedef BOOL (WINAPI *Func_CreateHardLinkW)( LPSECURITY_ATTRIBUTES lpSecurityAttributes ); EXTERN_C_END +#endif // UNDER_CE bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) { @@ -215,12 +238,14 @@ bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) #endif { Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW) - ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"); + (void *)::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW"); if (!my_CreateHardLinkW) return false; IF_USE_MAIN_PATH_2(newFileName, existFileName) + { if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL)) return true; + } #ifdef WIN_LONG_PATH if (USE_SUPER_PATH_2) { @@ -233,7 +258,6 @@ bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) return false; } -#endif /* WinXP-64 CreateDir(): @@ -333,6 +357,10 @@ static bool CreateDir2(CFSTR path) return fi.IsDir(); } +#endif // _WIN32 + +static bool CreateDir2(CFSTR path); + bool CreateComplexDir(CFSTR _path) { #ifdef _WIN32 @@ -348,11 +376,21 @@ bool CreateComplexDir(CFSTR _path) if (IsDriveRootPath_SuperAllowed(_path)) return false; - unsigned prefixSize = GetRootPrefixSize(_path); + const unsigned prefixSize = GetRootPrefixSize(_path); - #endif + #endif // UNDER_CE + + #else // _WIN32 + + // Posix + NFind::CFileInfo fi; + if (fi.Find(_path)) + { + if (fi.IsDir()) + return true; + } - #endif + #endif // _WIN32 FString path (_path); @@ -365,7 +403,7 @@ bool CreateComplexDir(CFSTR _path) } const FString path2 (path); - pos = path.Len(); + pos = (int)path.Len(); for (;;) { @@ -384,17 +422,17 @@ bool CreateComplexDir(CFSTR _path) return false; #endif - path.DeleteFrom(pos); + path.DeleteFrom((unsigned)pos); } while (pos < (int)path2.Len()) { - int pos2 = NName::FindSepar(path2.Ptr(pos + 1)); + int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1)); if (pos2 < 0) - pos = path2.Len(); + pos = (int)path2.Len(); else pos += 1 + pos2; - path.SetFrom(path2, pos); + path.SetFrom(path2, (unsigned)pos); if (!CreateDir(path)) return false; } @@ -402,6 +440,9 @@ bool CreateComplexDir(CFSTR _path) return true; } + +#ifdef _WIN32 + bool DeleteFileAlways(CFSTR path) { /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete. @@ -412,7 +453,7 @@ bool DeleteFileAlways(CFSTR path) && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0 && (attrib & FILE_ATTRIBUTE_READONLY) != 0) { - if (!SetFileAttrib(path, attrib & ~FILE_ATTRIBUTE_READONLY)) + if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY)) return false; } } @@ -443,6 +484,8 @@ bool DeleteFileAlways(CFSTR path) return false; } + + bool RemoveDirWithSubItems(const FString &path) { bool needRemoveSubItems = true; @@ -466,7 +509,9 @@ bool RemoveDirWithSubItems(const FString &path) const unsigned prefixSize = s.Len(); NFind::CEnumerator enumerator; enumerator.SetDirPrefix(s); - NFind::CFileInfo fi; + NFind::CDirEntry fi; + bool isError = false; + DWORD lastError = 0; while (enumerator.Next(fi)) { s.DeleteFrom(prefixSize); @@ -474,18 +519,32 @@ bool RemoveDirWithSubItems(const FString &path) if (fi.IsDir()) { if (!RemoveDirWithSubItems(s)) - return false; + { + lastError = GetLastError(); + isError = true; + } } else if (!DeleteFileAlways(s)) - return false; + { + lastError = GetLastError(); + isError = false; + } + } + if (isError) + { + SetLastError(lastError); + return false; } } + // we clear read-only attrib to remove read-only dir if (!SetFileAttrib(path, 0)) return false; return RemoveDir(path); } +#endif // _WIN32 + #ifdef UNDER_CE bool MyGetFullPathName(CFSTR path, FString &resFullPath) @@ -501,6 +560,8 @@ bool MyGetFullPathName(CFSTR path, FString &resFullPath) return GetFullPath(path, resFullPath); } +#ifdef _WIN32 + bool SetCurrentDir(CFSTR path) { // SetCurrentDirectory doesn't support \\?\ prefix @@ -516,9 +577,11 @@ bool SetCurrentDir(CFSTR path) } } + bool GetCurrentDir(FString &path) { path.Empty(); + DWORD needLength; #ifndef _UNICODE if (!g_IsNT) @@ -539,7 +602,9 @@ bool GetCurrentDir(FString &path) return (needLength > 0 && needLength <= MAX_PATH); } -#endif +#endif // _WIN32 +#endif // UNDER_CE + bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName) { @@ -547,8 +612,9 @@ bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName if (!res) resDirPrefix = path; int pos = resDirPrefix.ReverseFind_PathSepar(); - resFileName = resDirPrefix.Ptr(pos + 1); - resDirPrefix.DeleteFrom(pos + 1); + pos++; + resFileName = resDirPrefix.Ptr((unsigned)pos); + resDirPrefix.DeleteFrom((unsigned)pos); return res; } @@ -560,6 +626,7 @@ bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix) bool MyGetTempPath(FString &path) { + #ifdef _WIN32 path.Empty(); DWORD needLength; #ifndef _UNICODE @@ -579,11 +646,27 @@ bool MyGetTempPath(FString &path) path = us2fs(s); } return (needLength > 0 && needLength <= MAX_PATH); + + #else + + // FIXME: improve that code + path = "/tmp/"; + if (!NFind::DoesDirExist_FollowLink(path)) + path = "./"; + return true; + #endif } + static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile) { - UInt32 d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); + UInt32 d = + #ifdef _WIN32 + (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId(); + #else + (UInt32)(time(NULL) << 12) ^ ((UInt32)getppid() << 14) ^ (UInt32)(getpid()); + #endif + for (unsigned i = 0; i < 100; i++) { path = prefix; @@ -670,7 +753,7 @@ bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) // DWORD attrib = 0; if (deleteDestBefore) { - if (NFind::DoesFileExist(name)) + if (NFind::DoesFileExist_Raw(name)) { // attrib = NFind::GetFileAttrib(name); if (!DeleteFileAlways(name)) @@ -690,6 +773,7 @@ bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore) */ } +#ifdef _WIN32 bool CTempDir::Create(CFSTR prefix) { if (!Remove()) @@ -710,5 +794,285 @@ bool CTempDir::Remove() _mustBeDeleted = !RemoveDirWithSubItems(_path); return !_mustBeDeleted; } +#endif + + + +#ifndef _WIN32 + +bool RemoveDir(CFSTR path) +{ + return (rmdir(path) == 0); +} + + +static BOOL My__CopyFile(CFSTR oldFile, CFSTR newFile) +{ + NWindows::NFile::NIO::COutFile outFile; + if (!outFile.Create(newFile, false)) + return FALSE; + + NWindows::NFile::NIO::CInFile inFile; + if (!inFile.Open(oldFile)) + return FALSE; + + char buf[1 << 14]; + + for (;;) + { + const ssize_t num = inFile.read_part(buf, sizeof(buf)); + if (num == 0) + return TRUE; + if (num < 0) + return FALSE; + size_t processed; + const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed); + if (num2 != num || processed != (size_t)num) + return FALSE; + } +} + + +bool MyMoveFile(CFSTR oldFile, CFSTR newFile) +{ + int res = rename(oldFile, newFile); + if (res == 0) + return true; + if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem) + return false; + + if (My__CopyFile(oldFile, newFile) == FALSE) + return false; + + struct stat info_file; + res = stat(oldFile, &info_file); + if (res != 0) + return false; + + /* + ret = chmod(dst,info_file.st_mode & g_umask.mask); + */ + return (unlink(oldFile) == 0); +} + + +bool CreateDir(CFSTR path) +{ + return (mkdir(path, 0777) == 0); // change it +} + +static bool CreateDir2(CFSTR path) +{ + return (mkdir(path, 0777) == 0); // change it +} + + +bool DeleteFileAlways(CFSTR path) +{ + return (remove(path) == 0); +} + +bool SetCurrentDir(CFSTR path) +{ + return (chdir(path) == 0); +} + + +bool GetCurrentDir(FString &path) +{ + path.Empty(); + + #define MY__PATH_MAX PATH_MAX + // #define MY__PATH_MAX 1024 + + char s[MY__PATH_MAX + 1]; + char *res = getcwd(s, MY__PATH_MAX); + if (!res) + { + // if (errno != ERANGE) + return false; + } + path = fas2fs(s); + return true; +} + + +static void FILETME_To_timespec(const FILETIME *ft, timespec &ts) +{ + if (ft) + { + const Int64 sec = NTime::FileTimeToUnixTime64(*ft); + // time_t is long + const time_t sec2 = (time_t)sec; + if (sec2 == sec) + { + ts.tv_sec = sec2; + const UInt64 winTime = (((UInt64)ft->dwHighDateTime) << 32) + ft->dwLowDateTime; + ts.tv_nsec = (long)((winTime % 10000000) * 100); + return; + } + } + // else + { + ts.tv_sec = 0; + // ts.tv_nsec = UTIME_NOW; // set to the current time + ts.tv_nsec = UTIME_OMIT; // keep old timesptamp + } +} + + + + +bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) +{ + // need testing + /* + struct utimbuf buf; + struct stat st; + UNUSED_VAR(cTime) + + printf("\nstat = %s\n", path); + int ret = stat(path, &st); + + if (ret == 0) + { + buf.actime = st.st_atime; + buf.modtime = st.st_mtime; + } + else + { + time_t cur_time = time(0); + buf.actime = cur_time; + buf.modtime = cur_time; + } + + if (aTime) + { + UInt32 ut; + if (NTime::FileTimeToUnixTime(*aTime, ut)) + buf.actime = ut; + } + + if (mTime) + { + UInt32 ut; + if (NTime::FileTimeToUnixTime(*mTime, ut)) + buf.modtime = ut; + } + + return utime(path, &buf) == 0; + */ + + // if (!aTime && !mTime) return true; + + struct timespec times[2]; + UNUSED_VAR(cTime) + + FILETME_To_timespec(aTime, times[0]); + FILETME_To_timespec(mTime, times[1]); + + const int flags = 0; // follow link + // = AT_SYMLINK_NOFOLLOW; // don't follow link + return utimensat(AT_FDCWD, path, times, flags) == 0; +} + + + +struct C_umask +{ + mode_t mask; + + C_umask() + { + /* by security reasons we restrict attributes according + with process's file mode creation mask (umask) */ + const mode_t um = umask(0); // octal :0022 is expected + mask = 0777 & (~um); // octal: 0755 is expected + umask(um); // restore the umask + // printf("\n umask = 0%03o mask = 0%03o\n", um, mask); + + // mask = 0777; // debug we can disable the restriction: + } +}; + +static C_umask g_umask; + +// #define PRF(x) x; +#define PRF(x) + +#define TRACE_SetFileAttrib(msg) \ + PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg)); + +#define TRACE_chmod(s, mode) \ + PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode))); + + +bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib) +{ + TRACE_SetFileAttrib(""); + + struct stat st; + + bool use_lstat = true; + if (use_lstat) + { + if (lstat(path, &st) != 0) + { + TRACE_SetFileAttrib("bad lstat()"); + return false; + } + } + else + { + if (stat(path, &st) != 0) + { + TRACE_SetFileAttrib("bad stat()"); + return false; + } + } + + if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION) + { + st.st_mode = attrib >> 16; + if (S_ISDIR(st.st_mode)) + { + // user/7z must be able to create files in this directory + st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR); + } + else if (!S_ISREG(st.st_mode)) + return true; + } + else if (S_ISLNK(st.st_mode)) + { + // change it + SetLastError(ENOSYS); + return false; + } + else + { + // Only Windows Attributes + if (S_ISDIR(st.st_mode) + || (attrib & FILE_ATTRIBUTE_READONLY) == 0) + return true; + st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions + } + + TRACE_chmod(path, (st.st_mode) & g_umask.mask); + int res = chmod(path, (st.st_mode) & g_umask.mask); + + // TRACE_SetFileAttrib("OK") + return (res == 0); +} + + +bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName) +{ + PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName)); + return (link(existFileName, newFileName) == 0); +} + +#endif // !_WIN32 + +// #endif }}} diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h index 154ed973..6d6ddeaf 100644 --- a/CPP/Windows/FileDir.h +++ b/CPP/Windows/FileDir.h @@ -17,6 +17,8 @@ bool GetSystemDir(FString &path); bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); +#ifdef _WIN32 + bool SetFileAttrib(CFSTR path, DWORD attrib); /* @@ -26,6 +28,8 @@ bool SetFileAttrib(CFSTR path, DWORD attrib); bits that are related to current system only. */ +#endif + bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib); @@ -61,7 +65,7 @@ bool GetCurrentDir(FString &resultPath); bool MyGetTempPath(FString &resultPath); -class CTempFile +class CTempFile MY_UNCOPYABLE { bool _mustBeDeleted; FString _path; @@ -76,7 +80,9 @@ public: bool MoveTo(CFSTR name, bool deleteDestBefore); }; -class CTempDir + +#ifdef _WIN32 +class CTempDir MY_UNCOPYABLE { bool _mustBeDeleted; FString _path; @@ -88,9 +94,11 @@ public: bool Create(CFSTR namePrefix) ; bool Remove(); }; +#endif + #if !defined(UNDER_CE) -class CCurrentDirRestorer +class CCurrentDirRestorer MY_UNCOPYABLE { FString _path; public: diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp index b9692b81..8ef0f7b6 100644 --- a/CPP/Windows/FileFind.cpp +++ b/CPP/Windows/FileFind.cpp @@ -2,8 +2,11 @@ #include "StdAfx.h" -#ifndef _UNICODE -#include "../Common/StringConvert.h" +// #include <stdio.h> + +#ifndef _WIN32 +#include <fcntl.h> /* Definition of AT_* constants */ +#include "TimeUtils.h" #endif #include "FileFind.h" @@ -34,27 +37,51 @@ typedef struct WCHAR cStreamName[MAX_PATH + 36]; } MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA; -typedef WINBASEAPI HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, +typedef HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel, LPVOID findStreamData, DWORD flags); -typedef WINBASEAPI BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData); +typedef BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData); EXTERN_C_END -#endif +#endif // defined(_WIN32) && !defined(UNDER_CE) + namespace NWindows { namespace NFile { + +#ifdef _WIN32 #ifdef SUPPORT_DEVICE_FILE namespace NSystem { bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); } #endif +#endif namespace NFind { +#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; + +void CFileInfoBase::ClearBase() throw() +{ + Size = 0; + MY_CLEAR_FILETIME(CTime); + MY_CLEAR_FILETIME(ATime); + MY_CLEAR_FILETIME(MTime); + Attrib = 0; + // ReparseTag = 0; + IsAltStream = false; + IsDevice = false; + + #ifndef _WIN32 + ino = 0; + nlink = 0; + mode = 0; + #endif +} + bool CFileInfo::IsDots() const throw() { if (!IsDir() || Name.IsEmpty()) @@ -64,12 +91,17 @@ bool CFileInfo::IsDots() const throw() return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.'); } + +#ifdef _WIN32 + + #define WIN_FD_TO_MY_FI(fi, fd) \ fi.Attrib = fd.dwFileAttributes; \ fi.CTime = fd.ftCreationTime; \ fi.ATime = fd.ftLastAccessTime; \ fi.MTime = fd.ftLastWriteTime; \ fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \ + /* fi.ReparseTag = fd.dwReserved0; */ \ fi.IsAltStream = false; \ fi.IsDevice = false; @@ -91,7 +123,6 @@ static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFil } #ifndef _UNICODE - static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi) { WIN_FD_TO_MY_FI(fi, fd); @@ -143,7 +174,8 @@ WinXP-64 FindFirstFile(): \\Server\Share_RootDrive - ERROR_INVALID_NAME \\Server\Share_RootDrive\ - ERROR_INVALID_NAME - c:\* - ERROR_FILE_NOT_FOUND, if thare are no item in that folder + e:\* - ERROR_FILE_NOT_FOUND, if there are no items in that root folder + w:\* - ERROR_PATH_NOT_FOUND, if there is no such drive w: */ bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi) @@ -210,12 +242,13 @@ bool CFindFile::FindNext(CFileInfo &fi) static FindFirstStreamW_Ptr g_FindFirstStreamW; static FindNextStreamW_Ptr g_FindNextStreamW; -struct CFindStreamLoader +static struct CFindStreamLoader { CFindStreamLoader() { - g_FindFirstStreamW = (FindFirstStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindFirstStreamW"); - g_FindNextStreamW = (FindNextStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindNextStreamW"); + HMODULE hm = ::GetModuleHandleA("kernel32.dll"); + g_FindFirstStreamW = (FindFirstStreamW_Ptr)(void *)::GetProcAddress(hm, "FindFirstStreamW"); + g_FindNextStreamW = (FindNextStreamW_Ptr)(void *)::GetProcAddress(hm, "FindNextStreamW"); } } g_FindStreamLoader; @@ -245,7 +278,7 @@ UString CStreamInfo::GetReducedName2() const static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si) { - si.Size = sd.StreamSize.QuadPart; + si.Size = (UInt64)sd.StreamSize.QuadPart; si.Name = sd.cStreamName; } @@ -336,19 +369,6 @@ bool CStreamEnumerator::Next(CStreamInfo &si, bool &found) #endif -#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0; - -void CFileInfoBase::ClearBase() throw() -{ - Size = 0; - MY_CLEAR_FILETIME(CTime); - MY_CLEAR_FILETIME(ATime); - MY_CLEAR_FILETIME(MTime); - Attrib = 0; - IsAltStream = false; - IsDevice = false; -} - /* WinXP-64 GetFileAttributes(): If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code @@ -416,7 +436,7 @@ also we support paths that are not supported by FindFirstFile: c::stream - Name = c::stream */ -bool CFileInfo::Find(CFSTR path) +bool CFileInfo::Find(CFSTR path, bool followLink) { #ifdef SUPPORT_DEVICE_FILE if (IsDevicePath(path)) @@ -454,7 +474,7 @@ bool CFileInfo::Find(CFSTR path) { UString streamName = fs2us(path + (unsigned)colonPos); FString filePath (path); - filePath.DeleteFrom(colonPos); + filePath.DeleteFrom((unsigned)colonPos); /* we allow both cases: name:stream name:stream:$DATA @@ -467,7 +487,7 @@ bool CFileInfo::Find(CFSTR path) bool isOk = true; if (IsDrivePath2(filePath) && - (colonPos == 2 || colonPos == 3 && filePath[2] == '\\')) + (colonPos == 2 || (colonPos == 3 && filePath[2] == '\\'))) { // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT) ClearBase(); @@ -476,11 +496,11 @@ bool CFileInfo::Find(CFSTR path) Name = filePath; } else - isOk = Find(filePath); + isOk = Find(filePath, followLink); // check it (followLink) if (isOk) { - Attrib &= ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); + Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT); Size = 0; CStreamEnumerator enumerator(filePath); for (;;) @@ -536,11 +556,15 @@ bool CFileInfo::Find(CFSTR path) ClearBase(); Attrib = attrib; Name = path + rootSize; - Name.DeleteFrom(2); // we don't need backslash (C:) + Name.DeleteFrom(2); + if (!Fill_From_ByHandleFileInfo(path)) + { + } return true; } } else if (IS_PATH_SEPAR(path[0])) + { if (path[1] == 0) { DWORD attrib = GetFileAttrib(path); @@ -559,10 +583,15 @@ bool CFileInfo::Find(CFSTR path) { if (NName::FindSepar(path + prefixSize) < 0) { + if (Fill_From_ByHandleFileInfo(path)) + { + Name = path + prefixSize; + return true; + } + FString s (path); s.Add_PathSepar(); s += '*'; // CHAR_ANY_MASK - bool isOK = false; if (finder.FindFirst(s, *this)) { @@ -577,7 +606,7 @@ bool CFileInfo::Find(CFSTR path) } { DWORD attrib = GetFileAttrib(path); - if (isOK || attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0) + if (isOK || (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)) { ClearBase(); if (attrib != INVALID_FILE_ATTRIBUTES) @@ -592,23 +621,105 @@ bool CFileInfo::Find(CFSTR path) } } } + } } #endif - return finder.FindFirst(path, *this); + bool res = finder.FindFirst(path, *this); + if (!followLink + || !res + || !HasReparsePoint()) + return res; + + // return FollowReparse(path, IsDir()); + return Fill_From_ByHandleFileInfo(path); +} + +bool CFileInfo::Fill_From_ByHandleFileInfo(CFSTR path) +{ + BY_HANDLE_FILE_INFORMATION info; + if (!NIO::CFileBase::GetFileInformation(path, &info)) + return false; + { + Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + CTime = info.ftCreationTime; + ATime = info.ftLastAccessTime; + MTime = info.ftLastWriteTime; + Attrib = info.dwFileAttributes; + return true; + } } +/* +bool CFileInfo::FollowReparse(CFSTR path, bool isDir) +{ + if (isDir) + { + FString prefix = path; + prefix.Add_PathSepar(); + + // "folder/." refers to folder itself. So we can't use that path + // we must use enumerator and search "." item + CEnumerator enumerator; + enumerator.SetDirPrefix(prefix); + for (;;) + { + CFileInfo fi; + if (!enumerator.NextAny(fi)) + break; + if (fi.Name.IsEqualTo_Ascii_NoCase(".")) + { + // we can copy preperies; + CTime = fi.CTime; + ATime = fi.ATime; + MTime = fi.MTime; + Attrib = fi.Attrib; + Size = fi.Size; + return true; + } + break; + } + // LastError(lastError); + return false; + } + + { + NIO::CInFile inFile; + if (inFile.Open(path)) + { + BY_HANDLE_FILE_INFORMATION info; + if (inFile.GetFileInformation(&info)) + { + ClearBase(); + Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow; + CTime = info.ftCreationTime; + ATime = info.ftLastAccessTime; + MTime = info.ftLastWriteTime; + Attrib = info.dwFileAttributes; + return true; + } + } + return false; + } +} +*/ -bool DoesFileExist(CFSTR name) +bool DoesFileExist_Raw(CFSTR name) { CFileInfo fi; return fi.Find(name) && !fi.IsDir(); } -bool DoesDirExist(CFSTR name) +bool DoesFileExist_FollowLink(CFSTR name) +{ + CFileInfo fi; + return fi.Find_FollowLink(name) && !fi.IsDir(); +} + +bool DoesDirExist(CFSTR name, bool followLink) { CFileInfo fi; - return fi.Find(name) && fi.IsDir(); + return fi.Find(name, followLink) && fi.IsDir(); } bool DoesFileOrDirExist(CFSTR name) @@ -645,15 +756,46 @@ bool CEnumerator::Next(CFileInfo &fi) bool CEnumerator::Next(CFileInfo &fi, bool &found) { + /* + for (;;) + { + if (!NextAny(fi)) + break; + if (!fi.IsDots()) + { + found = true; + return true; + } + } + */ + if (Next(fi)) { found = true; return true; } + found = false; - return (::GetLastError() == ERROR_NO_MORE_FILES); + DWORD lastError = ::GetLastError(); + if (_findFile.IsHandleAllocated()) + return (lastError == ERROR_NO_MORE_FILES); + // we support the case for empty root folder: FindFirstFile("c:\\*") returns ERROR_FILE_NOT_FOUND + if (lastError == ERROR_FILE_NOT_FOUND) + return true; + if (lastError == ERROR_ACCESS_DENIED) + { + // here we show inaccessible root system folder as empty folder to eliminate redundant user warnings + const char *s = "System Volume Information" STRING_PATH_SEPARATOR "*"; + const int len = (int)strlen(s); + const int delta = (int)_wildcard.Len() - len; + if (delta == 0 || (delta > 0 && IS_PATH_SEPAR(_wildcard[(unsigned)delta - 1]))) + if (StringsAreEqual_Ascii(_wildcard.Ptr((unsigned)delta), s)) + return true; + } + return false; } + //////////////////////////////// // CFindChangeNotification // FindFirstChangeNotification can return 0. MSDN doesn't tell about it. @@ -744,6 +886,331 @@ bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings) } } -#endif +#endif // UNDER_CE + + + +#else // _WIN32 + +// ---------- POSIX ---------- + +static int MY__lstat(CFSTR path, struct stat *st, bool followLink) +{ + memset(st, 0, sizeof(*st)); + int res; + // #ifdef ENV_HAVE_LSTAT + if (/* global_use_lstat && */ !followLink) + { + // printf("\nlstat\n"); + res = lstat(path, st); + } + else + // #endif + { + // printf("\nstat\n"); + res = stat(path, st); + } + /* + printf("\nres = %d\n", res); + printf("\n st_dev = %lld \n", (long long)(st->st_dev)); + printf("\n st_ino = %lld \n", (long long)(st->st_ino)); + printf("\n st_mode = %lld \n", (long long)(st->st_mode)); + printf("\n st_nlink = %lld \n", (long long)(st->st_nlink)); + printf("\n st_uid = %lld \n", (long long)(st->st_uid)); + printf("\n st_gid = %lld \n", (long long)(st->st_gid)); + printf("\n st_size = %lld \n", (long long)(st->st_size)); + printf("\n st_blksize = %lld \n", (long long)(st->st_blksize)); + printf("\n st_blocks = %lld \n", (long long)(st->st_blocks)); + */ + + return res; +} + + +static const char *Get_Name_from_Path(CFSTR path) throw() +{ + size_t len = strlen(path); + if (len == 0) + return path; + const char *p = path + len - 1; + { + if (p == path) + return path; + p--; + } + for (;;) + { + char c = *p; + if (IS_PATH_SEPAR(c)) + return p + 1; + if (p == path) + return path; + p--; + } +} + + +void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft) +{ + UInt64 v = NTime::UnixTime64ToFileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100); + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); +} + +UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode) +{ + UInt32 attrib = S_ISDIR(mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + if ((mode & 0222) == 0) // S_IWUSR in p7zip + attrib |= FILE_ATTRIBUTE_READONLY; + return attrib | FILE_ATTRIBUTE_UNIX_EXTENSION | ((mode & 0xFFFF) << 16); +} + +/* +UInt32 Get_WinAttrib_From_stat(const struct stat &st) +{ + UInt32 attrib = S_ISDIR(st.st_mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + + if ((st.st_mode & 0222) == 0) // check it !!! + attrib |= FILE_ATTRIBUTE_READONLY; + + attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((st.st_mode & 0xFFFF) << 16); + return attrib; +} +*/ + +void CFileInfo::SetFrom_stat(const struct stat &st) +{ + IsDevice = false; + + if (S_ISDIR(st.st_mode)) + { + Size = 0; + } + else + { + Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename + } + + Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode); + + // NTime::UnixTimeToFileTime(st.st_ctime, CTime); + // NTime::UnixTimeToFileTime(st.st_mtime, MTime); + // NTime::UnixTimeToFileTime(st.st_atime, ATime); + #ifdef __APPLE__ + timespec_To_FILETIME(st.st_ctimespec, CTime); + timespec_To_FILETIME(st.st_mtimespec, MTime); + timespec_To_FILETIME(st.st_atimespec, ATime); + #else + timespec_To_FILETIME(st.st_ctim, CTime); + timespec_To_FILETIME(st.st_mtim, MTime); + timespec_To_FILETIME(st.st_atim, ATime); + #endif + + dev = st.st_dev; + ino = st.st_ino; + nlink = st.st_nlink; + mode = st.st_mode; +} + +bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink) +{ + struct stat st; + if (MY__lstat(path, &st, followLink) != 0) + return false; + SetFrom_stat(st); + return true; +} + + +bool CFileInfo::Find(CFSTR path, bool followLink) +{ + // printf("\nCEnumerator::Find() name = %s\n", path); + if (!Find_DontFill_Name(path, followLink)) + return false; + + // printf("\nOK\n"); + + Name = Get_Name_from_Path(path); + if (!Name.IsEmpty()) + { + char c = Name.Back(); + if (IS_PATH_SEPAR(c)) + Name.DeleteBack(); + } + return true; +} + + +bool DoesFileExist_Raw(CFSTR name) +{ + // FIXME for symbolic links. + struct stat st; + if (MY__lstat(name, &st, false) != 0) + return false; + return !S_ISDIR(st.st_mode); +} + +bool DoesFileExist_FollowLink(CFSTR name) +{ + // FIXME for symbolic links. + struct stat st; + if (MY__lstat(name, &st, true) != 0) + return false; + return !S_ISDIR(st.st_mode); +} + +bool DoesDirExist(CFSTR name, bool followLink) +{ + struct stat st; + if (MY__lstat(name, &st, followLink) != 0) + return false; + return S_ISDIR(st.st_mode); +} + +bool DoesFileOrDirExist(CFSTR name) +{ + struct stat st; + if (MY__lstat(name, &st, false) != 0) + return false; + return true; +} + + +CEnumerator::~CEnumerator() +{ + if (_dir) + closedir(_dir); +} + +void CEnumerator::SetDirPrefix(const FString &dirPrefix) +{ + _wildcard = dirPrefix; +} + +bool CDirEntry::IsDots() const throw() +{ + if ( + #if !defined(_AIX) + !IsDir() || + #endif + Name.IsEmpty()) + return false; + if (Name[0] != '.') + return false; + return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.'); +} + + +bool CEnumerator::NextAny(CDirEntry &fi, bool &found) +{ + found = false; + + if (!_dir) + { + const char *w = "./"; + if (!_wildcard.IsEmpty()) + w = _wildcard.Ptr(); + _dir = ::opendir((const char *)w); + if (_dir == NULL) + return false; + } + + // To distinguish end of stream from an error, we must set errno to zero before readdir() + errno = 0; + + struct dirent *de = readdir(_dir); + if (!de) + { + if (errno == 0) + return true; // it's end of stream, and we report it with (found = false) + // it's real error + return false; + } + + fi.iNode = de->d_ino; + + #if !defined(_AIX) + fi.Type = de->d_type; + #endif + + /* + if (de->d_type == DT_DIR) + fi.Attrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(S_IFDIR) << 16); + else if (de->d_type < 16) + fi.Attrib = FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(de->d_type) << (16 + 12)); + */ + fi.Name = de->d_name; + + /* + printf("\nCEnumerator::NextAny; len = %d %s \n", (int)fi.Name.Len(), fi.Name.Ptr()); + for (unsigned i = 0; i < fi.Name.Len(); i++) + printf (" %02x", (unsigned)(Byte)de->d_name[i]); + printf("\n"); + */ + + found = true; + return true; +} + + +bool CEnumerator::Next(CDirEntry &fi, bool &found) +{ + // printf("\nCEnumerator::Next()\n"); + // PrintName("Next", ""); + for (;;) + { + if (!NextAny(fi, found)) + return false; + if (!found) + return true; + if (!fi.IsDots()) + { + /* + if (!NeedFullStat) + return true; + // we silently skip error file here - it can be wrong link item + if (fi.Find_DontFill_Name(path)) + return true; + */ + return true; + } + } +} + +/* +bool CEnumerator::Next(CDirEntry &fileInfo, bool &found) +{ + bool found; + if (!Next(fi, found)) + return false; + return found; +} +*/ + +bool CEnumerator::Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) +{ + // printf("\nCEnumerator::Fill_FileInfo()\n"); + struct stat st; + // probably it's OK to use fstatat() even if it changes file position dirfd(_dir) + int res = fstatat(dirfd(_dir), de.Name, &st, followLink ? 0 : AT_SYMLINK_NOFOLLOW); + // if fstatat() is not supported, we can use stat() / lstat() + + /* + const FString path = _wildcard + s; + int res = MY__lstat(path, &st, followLink); + */ + + if (res != 0) + return false; + fileInfo.SetFrom_stat(st); + fileInfo.Name = de.Name; + return true; +} + +#endif // _WIN32 }}} diff --git a/CPP/Windows/FileFind.h b/CPP/Windows/FileFind.h index bfb29206..009e84e7 100644 --- a/CPP/Windows/FileFind.h +++ b/CPP/Windows/FileFind.h @@ -3,13 +3,36 @@ #ifndef __WINDOWS_FILE_FIND_H #define __WINDOWS_FILE_FIND_H +#ifndef _WIN32 +#include <sys/stat.h> +#include <sys/types.h> +#include <dirent.h> +#endif + #include "../Common/MyString.h" +#include "../Common/MyWindows.h" #include "Defs.h" namespace NWindows { namespace NFile { namespace NFind { +// bool DoesFileExist(CFSTR name, bool followLink); +bool DoesFileExist_Raw(CFSTR name); +bool DoesFileExist_FollowLink(CFSTR name); +bool DoesDirExist(CFSTR name, bool followLink); + +inline bool DoesDirExist(CFSTR name) + { return DoesDirExist(name, false); } +inline bool DoesDirExist_FollowLink(CFSTR name) + { return DoesDirExist(name, true); } + +// it's always _Raw +bool DoesFileOrDirExist(CFSTR name); + +DWORD GetFileAttrib(CFSTR path); + + namespace NAttributes { inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; } @@ -33,6 +56,7 @@ public: bool IsAltStream; bool IsDevice; + #ifdef _WIN32 /* #ifdef UNDER_CE DWORD ObjectID; @@ -40,11 +64,24 @@ public: UINT32 ReparseTag; #endif */ + #else + dev_t dev; + ino_t ino; + nlink_t nlink; + mode_t mode; + // bool Use_lstat; + #endif CFileInfoBase() { ClearBase(); } void ClearBase() throw(); - - void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } + + void SetAsDir() + { + Attrib = FILE_ATTRIBUTE_DIRECTORY; + #ifndef _WIN32 + Attrib |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16)); + #endif + } bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } @@ -58,6 +95,14 @@ public: bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } + + #ifndef _WIN32 + bool IsPosixLink() const + { + const UInt32 mod = Attrib >> 16; + return S_ISLNK(mod); + } + #endif }; struct CFileInfo: public CFileInfoBase @@ -68,10 +113,22 @@ struct CFileInfo: public CFileInfoBase #endif bool IsDots() const throw(); - bool Find(CFSTR path); + bool Find(CFSTR path, bool followLink = false); + bool Find_FollowLink(CFSTR path) { return Find(path, true); } + + #ifdef _WIN32 + bool Fill_From_ByHandleFileInfo(CFSTR path); + // bool FollowReparse(CFSTR path, bool isDir); + #else + bool Find_DontFill_Name(CFSTR path, bool followLink = false); + void SetFrom_stat(const struct stat &st); + #endif }; -class CFindFileBase + +#ifdef _WIN32 + +class CFindFileBase MY_UNCOPYABLE { protected: HANDLE _handle; @@ -108,26 +165,21 @@ public: bool FindNext(CStreamInfo &streamInfo); }; -class CStreamEnumerator +class CStreamEnumerator MY_UNCOPYABLE { CFindStream _find; FString _filePath; - bool NextAny(CFileInfo &fileInfo); + bool NextAny(CFileInfo &fileInfo, bool &found); public: CStreamEnumerator(const FString &filePath): _filePath(filePath) {} bool Next(CStreamInfo &streamInfo, bool &found); }; -#endif +#endif // defined(_WIN32) && !defined(UNDER_CE) -bool DoesFileExist(CFSTR name); -bool DoesDirExist(CFSTR name); -bool DoesFileOrDirExist(CFSTR name); - -DWORD GetFileAttrib(CFSTR path); -class CEnumerator +class CEnumerator MY_UNCOPYABLE { CFindFile _findFile; FString _wildcard; @@ -139,7 +191,8 @@ public: bool Next(CFileInfo &fileInfo, bool &found); }; -class CFindChangeNotification + +class CFindChangeNotification MY_UNCOPYABLE { HANDLE _handle; public: @@ -156,6 +209,71 @@ public: bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings); #endif +typedef CFileInfo CDirEntry; + + +#else // WIN32 + + +struct CDirEntry +{ + ino_t iNode; + #if !defined(_AIX) + Byte Type; + #endif + FString Name; + + #if !defined(_AIX) + bool IsDir() const + { + // DT_DIR is + return Type == DT_DIR; + } + #endif + + bool IsDots() const throw(); +}; + +class CEnumerator MY_UNCOPYABLE +{ + DIR *_dir; + FString _wildcard; + + bool NextAny(CDirEntry &fileInfo, bool &found); +public: + CEnumerator(): _dir(NULL) {} + ~CEnumerator(); + void SetDirPrefix(const FString &dirPrefix); + + bool Next(CDirEntry &fileInfo, bool &found); + bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink); +}; + +/* +inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode) +{ + UInt32 attrib = S_ISDIR(mode) ? + FILE_ATTRIBUTE_DIRECTORY : + FILE_ATTRIBUTE_ARCHIVE; + if ((st.st_mode & 0222) == 0) // check it !!! + attrib |= FILE_ATTRIBUTE_READONLY; + return attrib; +} +*/ + +UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode); + +// UInt32 Get_WinAttrib_From_stat(const struct stat &st); +#if defined(_AIX) + #define MY_ST_TIMESPEC st_timespec +#else + #define MY_ST_TIMESPEC timespec +#endif + +void timespec_To_FILETIME(const MY_ST_TIMESPEC &ts, FILETIME &ft); + +#endif // WIN32 + }}} #endif diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp index 56e6ca45..b6f2f26e 100644 --- a/CPP/Windows/FileIO.cpp +++ b/CPP/Windows/FileIO.cpp @@ -6,9 +6,21 @@ #include "../../C/Alloc.h" #endif +// #include <stdio.h> + #include "FileIO.h" #include "FileName.h" +HRESULT GetLastError_noZero_HRESULT() +{ + DWORD res = ::GetLastError(); + if (res == 0) + return E_FAIL; + return HRESULT_FROM_WIN32(res); +} + +#ifdef _WIN32 + #ifndef _UNICODE extern bool g_IsNT; #endif @@ -78,6 +90,42 @@ bool CFileBase::Create(CFSTR path, DWORD desiredAccess, } #endif } + + /* + #ifndef UNDER_CE + #ifndef _SFX + if (_handle == INVALID_HANDLE_VALUE) + { + // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10 + DWORD lastError = GetLastError(); + if (lastError == ERROR_CANT_ACCESS_FILE) + { + CByteBuffer buf; + if (NIO::GetReparseData(path, buf, NULL)) + { + CReparseAttr attr; + if (attr.Parse(buf, buf.Size())) + { + FString dirPrefix, fileName; + if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName)) + { + FString fullPath; + if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath)) + { + // FIX IT: recursion levels must be restricted + return Create(fullPath, desiredAccess, + shareMode, creationDisposition, flagsAndAttributes); + } + } + } + } + SetLastError(lastError); + } + } + #endif + #endif + */ + return (_handle != INVALID_HANDLE_VALUE); } @@ -136,7 +184,7 @@ bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw() { - return Seek(position, FILE_BEGIN, newPosition); + return Seek((Int64)position, FILE_BEGIN, newPosition); } bool CFileBase::SeekToBegin() const throw() @@ -258,7 +306,7 @@ void CInFile::CalcDeviceSize(CFSTR s) if (GetPartitionInfo(&partInfo)) { - Size = partInfo.PartitionLength.QuadPart; + Size = (UInt64)partInfo.PartitionLength.QuadPart; SizeDefined = true; needCorrectSize = false; if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0) @@ -277,7 +325,7 @@ void CInFile::CalcDeviceSize(CFSTR s) my_DISK_GEOMETRY_EX geomEx; SizeDefined = GetGeometryEx(&geomEx); if (SizeDefined) - Size = geomEx.DiskSize.QuadPart; + Size = (UInt64)geomEx.DiskSize.QuadPart; else { DISK_GEOMETRY geom; @@ -285,7 +333,7 @@ void CInFile::CalcDeviceSize(CFSTR s) if (!SizeDefined) SizeDefined = GetCdRomGeometry(&geom); if (SizeDefined) - Size = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; + Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector; } } @@ -310,7 +358,24 @@ void CInFile::CalcDeviceSize(CFSTR s) bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) { - bool res = Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); + DWORD desiredAccess = GENERIC_READ; + + #ifdef _WIN32 + if (PreserveATime) + desiredAccess |= FILE_WRITE_ATTRIBUTES; + #endif + + bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes); + + #ifdef _WIN32 + if (res && PreserveATime) + { + FILETIME ft; + ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF; + ::SetFileTime(_handle, NULL, &ft, NULL); + } + #endif + MY_DEVICE_EXTRA_CODE return res; } @@ -330,7 +395,7 @@ bool CInFile::Open(CFSTR fileName) // for 32 MB (maybe also for 16 MB). // And message can be "Network connection was lost" -static UInt32 kChunkSizeMax = (1 << 22); +static const UInt32 kChunkSizeMax = (1 << 22); bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw() { @@ -366,6 +431,26 @@ bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw() return true; } +bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw() +{ + processedSize = 0; + do + { + UInt32 processedLoc = 0; + const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size); + const bool res = Read1(data, sizeLoc, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (void *)((unsigned char *)data + processedLoc); + size -= processedLoc; + } + while (size > 0); + return true; +} + // ---------- COutFile --------- static inline DWORD GetCreationDisposition(bool createAlways) @@ -430,3 +515,216 @@ bool COutFile::SetLength(UInt64 length) throw() } }}} + +#else // _WIN32 + + +// POSIX + +#include <fcntl.h> +#include <unistd.h> + +namespace NWindows { +namespace NFile { + +namespace NDir { +bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime); +} + +namespace NIO { + +bool CFileBase::OpenBinary(const char *name, int flags) +{ + #ifdef O_BINARY + flags |= O_BINARY; + #endif + + Close(); + _handle = ::open(name, flags, 0666); + return _handle != -1; +} + +bool CFileBase::Close() +{ + if (_handle == -1) + return true; + if (close(_handle) != 0) + return false; + _handle = -1; + return true; +} + +bool CFileBase::GetLength(UInt64 &length) const +{ + const off_t curPos = seek(0, SEEK_CUR); + if (curPos == -1) + return false; + const off_t lengthTemp = seek(0, SEEK_END); + seek(curPos, SEEK_SET); + length = (UInt64)lengthTemp; + return (lengthTemp != -1); +} + +off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const +{ + // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove); + // off_t res = ::lseek(_handle, distanceToMove, moveMethod); + return ::lseek(_handle, distanceToMove, moveMethod); + // printf(" res = %lld", (long long)res); + // return res; +} + +off_t CFileBase::seekToBegin() const throw() +{ + return seek(0, SEEK_SET); +} + +/* +bool CFileBase::SeekToBegin() const throw() +{ + return (::seek(0, SEEK_SET) != -1); +} +*/ + + +///////////////////////// +// CInFile + +bool CInFile::Open(const char *name) +{ + return CFileBase::OpenBinary(name, O_RDONLY); +} + +bool CInFile::OpenShared(const char *name, bool) +{ + return Open(name); +} + +/* +On Linux (32-bit and 64-bit): +read(), write() (and similar system calls) will transfer at most +0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred. +*/ + +static const size_t kChunkSizeMax = ((size_t)1 << 22); + +ssize_t CInFile::read_part(void *data, size_t size) throw() +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + return ::read(_handle, data, size); +} + +bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw() +{ + processed = 0; + do + { + const ssize_t res = read_part(data, size); + if (res < 0) + return false; + if (res == 0) + break; + data = (void *)((unsigned char *)data + (size_t)res); + size -= (size_t)res; + processed += (size_t)res; + } + while (size > 0); + return true; +} + + +///////////////////////// +// COutFile + +bool COutFile::Create(const char *name, bool createAlways) +{ + Path = name; // change it : set it only if open is success. + if (createAlways) + { + Close(); + _handle = ::creat(name, 0666); + return _handle != -1; + } + return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY); +} + +bool COutFile::Open(const char *name, DWORD creationDisposition) +{ + UNUSED_VAR(creationDisposition) // FIXME + return Create(name, false); +} + +ssize_t COutFile::write_part(const void *data, size_t size) throw() +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + return ::write(_handle, data, size); +} + +ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw() +{ + processed = 0; + do + { + const ssize_t res = write_part(data, size); + if (res < 0) + return res; + if (res == 0) + break; + data = (const void *)((const unsigned char *)data + (size_t)res); + size -= (size_t)res; + processed += (size_t)res; + } + while (size > 0); + return (ssize_t)processed; +} + +bool COutFile::SetLength(UInt64 length) throw() +{ + const off_t len2 = (off_t)length; + if ((Int64)length != len2) + { + SetLastError(EFBIG); + return false; + } + int iret = ftruncate(_handle, len2); + return (iret == 0); +} + +bool COutFile::Close() +{ + bool res = CFileBase::Close(); + if (!res) + return res; + if (CTime_defined || ATime_defined || MTime_defined) + { + /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path, + CTime_defined ? &CTime : NULL, + ATime_defined ? &ATime : NULL, + MTime_defined ? &MTime : NULL); + } + return res; +} + +bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw() +{ + // On some OS (cygwin, MacOSX ...), you must close the file before updating times + // return true; + + if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false; + if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false; + if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; + return true; +} + +bool COutFile::SetMTime(const FILETIME *mTime) throw() +{ + if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false; + return true; +} + +}}} + + +#endif diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h index 5ca5448b..276e595e 100644 --- a/CPP/Windows/FileIO.h +++ b/CPP/Windows/FileIO.h @@ -5,8 +5,26 @@ #include "../Common/MyWindows.h" +#define _my_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) +#define _my_IO_REPARSE_TAG_SYMLINK (0xA000000CL) +#define _my_IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL) + +#define _my_SYMLINK_FLAG_RELATIVE 1 + +// what the meaning of that FLAG or field (2)? +#define _my_LX_SYMLINK_FLAG 2 + +#ifdef _WIN32 + #if defined(_WIN32) && !defined(UNDER_CE) -#include <winioctl.h> +#include <WinIoCtl.h> +#endif + +#else + +#include <sys/types.h> +#include <sys/stat.h> + #endif #include "../Common/MyString.h" @@ -14,19 +32,17 @@ #include "Defs.h" -#define _my_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) -#define _my_IO_REPARSE_TAG_SYMLINK (0xA000000CL) - -#define _my_SYMLINK_FLAG_RELATIVE 1 +HRESULT GetLastError_noZero_HRESULT(); -#define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER -#define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER +#define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER +#define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER +#define my_FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER namespace NWindows { namespace NFile { #if defined(_WIN32) && !defined(UNDER_CE) -bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink); +bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL); #endif struct CReparseShortInfo @@ -44,28 +60,50 @@ struct CReparseAttr UString SubsName; UString PrintName; + AString WslName; + + bool HeaderError; + bool TagIsUnknown; + bool MinorError; + DWORD ErrorCode; + CReparseAttr(): Tag(0), Flags(0) {} // Parse() - // returns true and (errorCode = 0), if (correct MOUNT_POINT or SYMLINK) - // returns false and (errorCode = ERROR_REPARSE_TAG_MISMATCH), if not (MOUNT_POINT or SYMLINK) - bool Parse(const Byte *p, size_t size, DWORD &errorCode); + // returns (true) and (ErrorCode = 0), if (it'a correct known link) + // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag + bool Parse(const Byte *p, size_t size); + + bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction + bool IsSymLink_Win() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; } + bool IsSymLink_WSL() const { return Tag == _my_IO_REPARSE_TAG_LX_SYMLINK; } + + bool IsRelative_Win() const { return Flags == _my_SYMLINK_FLAG_RELATIVE; } + + bool IsRelative_WSL() const + { + if (WslName.IsEmpty()) + return true; + char c = WslName[0]; + return !IS_PATH_SEPAR(c); + } - bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction - bool IsSymLink() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; } - bool IsRelative() const { return Flags == _my_SYMLINK_FLAG_RELATIVE; } // bool IsVolume() const; bool IsOkNamePair() const; UString GetPath() const; }; + +#ifdef _WIN32 + namespace NIO { bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL); bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); +bool DeleteReparseData(CFSTR path); -class CFileBase +class CFileBase MY_UNCOPYABLE { protected: HANDLE _handle; @@ -94,13 +132,14 @@ public: } public: + bool PreserveATime; #ifdef SUPPORT_DEVICE_FILE bool IsDeviceFile; bool SizeDefined; UInt64 Size; // it can be larger than real available size #endif - CFileBase(): _handle(INVALID_HANDLE_VALUE) {}; + CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {}; ~CFileBase() { Close(); } bool Close() throw(); @@ -118,6 +157,7 @@ public: static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info) { + // probably it can work for complex paths: unsupported by another things NIO::CFileBase file; if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS)) return false; @@ -189,6 +229,7 @@ public: bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw(); bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw(); bool Read(void *data, UInt32 size, UInt32 &processedSize) throw(); + bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); }; class COutFile: public CFileBase @@ -207,6 +248,83 @@ public: bool SetLength(UInt64 length) throw(); }; -}}} +} + + +#else // _WIN32 + +namespace NIO { + +bool GetReparseData(CFSTR path, CByteBuffer &reparseData); +// bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size); + +// parameters are in reverse order of symlink() function !!! +bool SetSymLink(CFSTR from, CFSTR to); +bool SetSymLink_UString(CFSTR from, const UString &to); + + +class CFileBase +{ +protected: + int _handle; + + bool OpenBinary(const char *name, int flags); +public: + bool PreserveATime; + + CFileBase(): _handle(-1), PreserveATime(false) {}; + ~CFileBase() { Close(); } + bool Close(); + bool GetLength(UInt64 &length) const; + off_t seek(off_t distanceToMove, int moveMethod) const; + off_t seekToBegin() const throw(); + // bool SeekToBegin() throw(); + int my_fstat(struct stat *st) const { return fstat(_handle, st); } +}; + +class CInFile: public CFileBase +{ +public: + bool Open(const char *name); + bool OpenShared(const char *name, bool shareForWrite); + ssize_t read_part(void *data, size_t size) throw(); + // ssize_t read_full(void *data, size_t size, size_t &processed); + bool ReadFull(void *data, size_t size, size_t &processedSize) throw(); +}; + +class COutFile: public CFileBase +{ + bool CTime_defined; + bool ATime_defined; + bool MTime_defined; + + FILETIME CTime; + FILETIME ATime; + FILETIME MTime; + + AString Path; + ssize_t write_part(const void *data, size_t size) throw(); +public: + COutFile(): + CTime_defined(false), + ATime_defined(false), + MTime_defined(false) + {} + + bool Close(); + bool Create(const char *name, bool createAlways); + bool Open(const char *name, DWORD creationDisposition); + ssize_t write_full(const void *data, size_t size, size_t &processed) throw(); + bool SetLength(UInt64 length) throw(); + bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw(); + bool SetMTime(const FILETIME *mTime) throw(); +}; + +} + +#endif // _WIN32 + +}} + #endif diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp index 3e2f6431..8ce634fd 100644 --- a/CPP/Windows/FileLink.cpp +++ b/CPP/Windows/FileLink.cpp @@ -4,10 +4,17 @@ #include "../../C/CpuArch.h" +#ifndef _WIN32 +#include <unistd.h> +#endif + #ifdef SUPPORT_DEVICE_FILE #include "../../C/Alloc.h" #endif +#include "../Common/UTFConvert.h" +#include "../Common/StringConvert.h" + #include "FileDir.h" #include "FileFind.h" #include "FileIO.h" @@ -55,6 +62,12 @@ using namespace NName; */ /* +Win10 WSL2: +admin rights + sudo: it creates normal windows symbolic link. +in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point. +*/ + +/* static const UInt32 kReparseFlags_Alias = (1 << 29); static const UInt32 kReparseFlags_HighLatency = (1 << 30); static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); @@ -71,13 +84,10 @@ static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31); #define Get16(p) GetUi16(p) #define Get32(p) GetUi32(p) -#define Set16(p, v) SetUi16(p, v) -#define Set32(p, v) SetUi32(p, v) - static const wchar_t * const k_LinkPrefix = L"\\??\\"; static const unsigned k_LinkPrefix_Size = 4; -static const bool IsLinkPrefix(const wchar_t *s) +static bool IsLinkPrefix(const wchar_t *s) { return IsString1PrefixedByString2(s, k_LinkPrefix); } @@ -90,7 +100,12 @@ static const bool IsVolumeName(const wchar_t *s) } */ -void WriteString(Byte *dest, const wchar_t *path) +#if defined(_WIN32) && !defined(UNDER_CE) + +#define Set16(p, v) SetUi16(p, v) +#define Set32(p, v) SetUi32(p, v) + +static void WriteString(Byte *dest, const wchar_t *path) { for (;;) { @@ -102,14 +117,32 @@ void WriteString(Byte *dest, const wchar_t *path) } } -#if defined(_WIN32) && !defined(UNDER_CE) - -bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink) +bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL) { bool isAbs = IsAbsolutePath(path); if (!isAbs && !isSymLink) return false; + if (isWSL) + { + // unsupported characters probably use Replacement Character UTF-16 0xFFFD + AString utf; + ConvertUnicodeToUTF8(path, utf); + const size_t size = 4 + utf.Len(); + if (size != (UInt16)size) + return false; + dest.Alloc(8 + size); + Byte *p = dest; + Set32(p, _my_IO_REPARSE_TAG_LX_SYMLINK); + Set16(p + 4, (UInt16)(size)); + Set16(p + 6, 0); + Set32(p + 8, _my_LX_SYMLINK_FLAG); + memcpy(p + 12, utf.Ptr(), utf.Len()); + return true; + } + + // usual symbolic LINK (NOT WSL) + bool needPrintName = true; if (IsSuperPath(path)) @@ -121,12 +154,12 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink) const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0; - unsigned len2 = MyStringLen(path) * 2; - const unsigned len1 = len2 + add_Prefix_Len * 2; + size_t len2 = (size_t)MyStringLen(path) * 2; + const size_t len1 = len2 + add_Prefix_Len * 2; if (!needPrintName) len2 = 0; - unsigned totalNamesSize = (len1 + len2); + size_t totalNamesSize = (len1 + len2); /* some WIM imagex software uses old scheme for symbolic links. so we can old scheme for byte to byte compatibility */ @@ -138,6 +171,8 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink) totalNamesSize += 2 * 2; const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize; + if (size != (UInt16)size) + return false; dest.Alloc(size); memset(dest, 0, size); const UInt32 tag = isSymLink ? @@ -152,9 +187,9 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink) unsigned subOffs = 0; unsigned printOffs = 0; if (newOrderScheme) - subOffs = len2; + subOffs = (unsigned)len2; else - printOffs = len1 + 2; + printOffs = (unsigned)len1 + 2; Set16(p + 0, (UInt16)subOffs); Set16(p + 2, (UInt16)len1); @@ -177,7 +212,8 @@ bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink) return true; } -#endif +#endif // defined(_WIN32) && !defined(UNDER_CE) + static void GetString(const Byte *p, unsigned len, UString &res) { @@ -194,35 +230,69 @@ static void GetString(const Byte *p, unsigned len, UString &res) res.ReleaseBuf_SetLen(i); } -bool CReparseAttr::Parse(const Byte *p, size_t size, DWORD &errorCode) +bool CReparseAttr::Parse(const Byte *p, size_t size) { - errorCode = ERROR_INVALID_REPARSE_DATA; + ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA; + HeaderError = true; + TagIsUnknown = true; + MinorError = false; + if (size < 8) return false; Tag = Get32(p); UInt32 len = Get16(p + 4); - if (len + 8 > size) + if (len + 8 != size) + // if (len + 8 > size) return false; /* if ((type & kReparseFlags_Alias) == 0 || (type & kReparseFlags_Microsoft) == 0 || (type & 0xFFFF) != 3) */ - if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT && - Tag != _my_IO_REPARSE_TAG_SYMLINK) + + if (Get16(p + 6) != 0) // padding + return false; + + HeaderError = false; + + if ( Tag != _my_IO_REPARSE_TAG_MOUNT_POINT + && Tag != _my_IO_REPARSE_TAG_SYMLINK + && Tag != _my_IO_REPARSE_TAG_LX_SYMLINK) { - errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID + // for unsupported reparse points + ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH + // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID return false; } - if (Get16(p + 6) != 0) // padding - return false; - + TagIsUnknown = false; + p += 8; size -= 8; - if (len != size) // do we need that check? - return false; + if (Tag == _my_IO_REPARSE_TAG_LX_SYMLINK) + { + if (len < 4) + return false; + Flags = Get32(p); // maybe it's not Flags + if (Flags != _my_LX_SYMLINK_FLAG) + return false; + len -= 4; + p += 4; + char *s = WslName.GetBuf(len); + unsigned i; + for (i = 0; i < len; i++) + { + char c = (char)p[i]; + s[i] = c; + if (c == 0) + break; + } + WslName.ReleaseBuf_SetEnd(i); + MinorError = (i != len); + ErrorCode = 0; + return true; + } if (len < 8) return false; @@ -250,10 +320,11 @@ bool CReparseAttr::Parse(const Byte *p, size_t size, DWORD &errorCode) GetString(p + subOffs, subLen >> 1, SubsName); GetString(p + printOffs, printLen >> 1, PrintName); - errorCode = 0; + ErrorCode = 0; return true; } + bool CReparseShortInfo::Parse(const Byte *p, size_t size) { const Byte *start = p; @@ -336,26 +407,34 @@ bool CReparseAttr::IsVolume() const UString CReparseAttr::GetPath() const { + if (IsSymLink_WSL()) + { + UString u; + // if (CheckUTF8(attr.WslName) + if (!ConvertUTF8ToUnicode(WslName, u)) + MultiByteToUnicodeString2(u, WslName); + return u; + } + UString s (SubsName); if (IsLinkPrefix(s)) { - s.ReplaceOneCharAtPos(1, '\\'); + s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\" if (IsDrivePath(s.Ptr(k_LinkPrefix_Size))) s.DeleteFrontal(k_LinkPrefix_Size); } return s; } - #ifdef SUPPORT_DEVICE_FILE namespace NSystem { bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); } -#endif +#endif // SUPPORT_DEVICE_FILE -#ifndef UNDER_CE +#if defined(_WIN32) && !defined(UNDER_CE) namespace NIO { @@ -388,11 +467,26 @@ static bool CreatePrefixDirOfFile(CFSTR path) if (pos == 2 && path2[1] == L':') return true; // we don't create Disk folder; #endif - path2.DeleteFrom(pos); + path2.DeleteFrom((unsigned)pos); return NDir::CreateComplexDir(path2); } -// If there is Reprase data already, it still writes new Reparse data + +static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size) +{ + COutFile file; + if (!file.Open(path, + FILE_SHARE_WRITE, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) + return false; + + DWORD returnedSize; + return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize); +} + + +// If there is Reparse data already, it still writes new Reparse data bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) { NFile::NFind::CFileInfo fi; @@ -420,21 +514,100 @@ bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) } } - COutFile file; - if (!file.Open(path, - FILE_SHARE_WRITE, - OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS)) + return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size); +} + + +bool DeleteReparseData(CFSTR path) +{ + CByteBuffer reparseData; + if (!GetReparseData(path, reparseData, NULL)) return false; + /* MSDN: The tag specified in the ReparseTag member of this structure + must match the tag of the reparse point to be deleted, + and the ReparseDataLength member must be zero */ + #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8 + if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE) + { + SetLastError(ERROR_INVALID_REPARSE_DATA); + return false; + } + BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE]; + memset(buf, 0, sizeof(buf)); + memcpy(buf, reparseData, 4); // tag + return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf)); +} - DWORD returnedSize; - if (!file.DeviceIoControl(my_FSCTL_SET_REPARSE_POINT, (void *)data, size, NULL, 0, &returnedSize)) +} + +#endif // defined(_WIN32) && !defined(UNDER_CE) + + +#ifndef _WIN32 + +namespace NIO { + +bool GetReparseData(CFSTR path, CByteBuffer &reparseData) +{ + reparseData.Free(); + + #define MAX_PATHNAME_LEN 1024 + char buf[MAX_PATHNAME_LEN + 2]; + const size_t request = sizeof(buf) - 1; + + // printf("\nreadlink() path = %s \n", path); + const ssize_t size = readlink(path, buf, request); + // there is no tail zero + + if (size < 0) return false; + if ((size_t)size >= request) + { + SetLastError(EINVAL); // check it: ENAMETOOLONG + return false; + } + + // printf("\nreadlink() res = %s size = %d \n", buf, (int)size); + reparseData.CopyFrom((const Byte *)buf, (size_t)size); return true; } + +/* +// If there is Reparse data already, it still writes new Reparse data +bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size) +{ + // AString s; + // s.SetFrom_CalcLen(data, size); + // return (symlink(s, path) == 0); + UNUSED_VAR(path) + UNUSED_VAR(isDir) + UNUSED_VAR(data) + UNUSED_VAR(size) + SetLastError(ENOSYS); + return false; } +*/ -#endif +bool SetSymLink(CFSTR from, CFSTR to) +{ + // printf("\nsymlink() %s -> %s\n", from, to); + int ir; + // ir = unlink(path); + // if (ir == 0) + ir = symlink(to, from); + return (ir == 0); +} + +bool SetSymLink_UString(CFSTR from, const UString &to) +{ + AString utf; + ConvertUnicodeToUTF8(to, utf); + return SetSymLink(from, utf); +} + +} + +#endif // !_WIN32 }} diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp index 2d0b50d5..4ee94575 100644 --- a/CPP/Windows/FileName.cpp +++ b/CPP/Windows/FileName.cpp @@ -2,6 +2,12 @@ #include "StdAfx.h" +#ifndef _WIN32 +#include <limits.h> +#include <unistd.h> +#include "../Common/StringConvert.h" +#endif + #include "FileName.h" #ifndef _UNICODE @@ -58,7 +64,18 @@ void NormalizeDirPathPrefix(UString &dirPath) dirPath.Add_PathSepar(); } -#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z') +#ifdef _WIN32 +void NormalizeDirSeparators(FString &s) +{ + const unsigned len = s.Len(); + for (unsigned i = 0; i < len; i++) + if (s[i] == '/') + s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR); +} +#endif + + +#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z')) bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); } @@ -88,7 +105,9 @@ bool IsAltPathPrefix(CFSTR s) throw() #if defined(_WIN32) && !defined(UNDER_CE) const char * const kSuperPathPrefix = "\\\\?\\"; +#ifdef WIN_LONG_PATH static const char * const kSuperUncPrefix = "\\\\?\\UNC\\"; +#endif #define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3])) #define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3])) @@ -160,7 +179,7 @@ unsigned GetNetworkServerPrefixSize(CFSTR s) throw() int pos = FindSepar(s + prefixSize); if (pos < 0) return 0; - return prefixSize + pos + 1; + return prefixSize + (unsigned)(pos + 1); } bool IsNetworkShareRootPath(CFSTR s) throw() @@ -224,7 +243,7 @@ int FindAltStreamColon(CFSTR path) throw() if (c == ':') { if (colonPos < 0) - colonPos = i; + colonPos = (int)i; continue; } if (IS_SEPAR(c)) @@ -292,7 +311,7 @@ static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw() int pos2 = FindSepar(s + (unsigned)pos + 1); if (pos2 < 0) return 0; - return pos + pos2 + 2; + return (unsigned)(pos + pos2 + 2); } static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw() @@ -318,7 +337,7 @@ static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw() int pos = FindSepar(s + kSuperPathPrefixSize); if (pos < 0) return 0; - return kSuperPathPrefixSize + pos + 1; + return kSuperPathPrefixSize + (unsigned)(pos + 1); } unsigned GetRootPrefixSize(const wchar_t *s) throw() @@ -332,12 +351,13 @@ unsigned GetRootPrefixSize(const wchar_t *s) throw() #else // _WIN32 -bool IsAbsolutePath(const wchar_t *s) { return IS_SEPAR(s[0]); } +bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); } #ifndef USE_UNICODE_FSTRING -unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; } +unsigned GetRootPrefixSize(CFSTR s) throw(); +unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } #endif -unsigned GetRootPrefixSize(const wchar_t *s) { return IS_SEPAR(s[0]) ? 1 : 0; } +unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; } #endif // _WIN32 @@ -347,6 +367,9 @@ unsigned GetRootPrefixSize(const wchar_t *s) { return IS_SEPAR(s[0]) ? 1 : 0; } static bool GetCurDir(UString &path) { path.Empty(); + + #ifdef _WIN32 + DWORD needLength; #ifndef _UNICODE if (!g_IsNT) @@ -365,6 +388,23 @@ static bool GetCurDir(UString &path) path = s; } return (needLength > 0 && needLength <= MAX_PATH); + + #else + + #define MY__PATH_MAX PATH_MAX + // #define MY__PATH_MAX 1024 + + char s[MY__PATH_MAX + 1]; + char *res = getcwd(s, MY__PATH_MAX); + if (!res) + { + // if (errno != ERANGE) + return false; + } + path = GetUnicodeString(s); + return true; + + #endif } static bool ResolveDotsFolders(UString &s) @@ -388,7 +428,7 @@ static bool ResolveDotsFolders(UString &s) { if (i == 0) return false; - int k = i - 2; + int k = (int)i - 2; i += 2; for (;; k--) @@ -407,8 +447,8 @@ static bool ResolveDotsFolders(UString &s) if (k >= 0) { - num = i - k; - i = k; + num = i - (unsigned)k; + i = (unsigned)k; } else { @@ -528,6 +568,7 @@ int GetUseSuperPathType(CFSTR s) throw() } + /* returns false in two cases: - if GetCurDir was used, and GetCurDir returned error. @@ -538,7 +579,6 @@ int GetUseSuperPathType(CFSTR s) throw() for absolute paths, returns true, res is Super path. */ - static bool GetSuperPathBase(CFSTR s, UString &res) { res.Empty(); @@ -702,6 +742,8 @@ bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew) return false; superPath = fs2us(path); } + + NormalizeDirSeparators(superPath); return true; } return false; @@ -712,6 +754,10 @@ bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew) if (!GetSuperPathBase(s1, d1) || !GetSuperPathBase(s2, d2)) return false; + + NormalizeDirSeparators(d1); + NormalizeDirSeparators(d2); + if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew) return false; if (d1.IsEmpty()) d1 = fs2us(s1); diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h index 2c9c56db..de8bd134 100644 --- a/CPP/Windows/FileName.h +++ b/CPP/Windows/FileName.h @@ -17,6 +17,10 @@ int FindSepar(const FChar *s) throw(); void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty void NormalizeDirPathPrefix(UString &dirPath); +#ifdef _WIN32 +void NormalizeDirSeparators(FString &s); +#endif + bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars like "a:\\" bool IsAltPathPrefix(CFSTR s) throw(); /* name: */ diff --git a/CPP/Windows/FileSystem.cpp b/CPP/Windows/FileSystem.cpp index 6c1f48a2..62594532 100644 --- a/CPP/Windows/FileSystem.cpp +++ b/CPP/Windows/FileSystem.cpp @@ -19,6 +19,8 @@ namespace NWindows { namespace NFile { namespace NSystem { +#ifdef _WIN32 + bool MyGetVolumeInformation( CFSTR rootPath, UString &volumeName, @@ -90,7 +92,7 @@ bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, #ifndef _UNICODE if (!g_IsNT) { - GetDiskFreeSpaceExA_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExA_Pointer)GetProcAddress( + GetDiskFreeSpaceExA_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExA_Pointer)(void *)GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExA"); if (pGetDiskFreeSpaceEx) { @@ -105,7 +107,7 @@ bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, else #endif { - GetDiskFreeSpaceExW_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExW_Pointer)GetProcAddress( + GetDiskFreeSpaceExW_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExW_Pointer)(void *)GetProcAddress( GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExW"); if (pGetDiskFreeSpaceEx) { @@ -126,6 +128,8 @@ bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, return true; } +#endif + }}} #endif diff --git a/CPP/Windows/FileSystem.h b/CPP/Windows/FileSystem.h index 9076ea13..9b49a025 100644 --- a/CPP/Windows/FileSystem.h +++ b/CPP/Windows/FileSystem.h @@ -10,6 +10,8 @@ namespace NWindows { namespace NFile { namespace NSystem { +#ifdef _WIN32 + bool MyGetVolumeInformation( CFSTR rootPath , UString &volumeName, @@ -22,6 +24,8 @@ UINT MyGetDriveType(CFSTR pathName); bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize); +#endif + }}} #endif diff --git a/CPP/Windows/Handle.h b/CPP/Windows/Handle.h index bb7cb705..5878c830 100644 --- a/CPP/Windows/Handle.h +++ b/CPP/Windows/Handle.h @@ -3,9 +3,11 @@ #ifndef __WINDOWS_HANDLE_H #define __WINDOWS_HANDLE_H +#include "../Common/MyTypes.h" + namespace NWindows { -class CHandle +class CHandle MY_UNCOPYABLE { protected: HANDLE _handle; diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp index f9d08a6e..fdfbeb9d 100644 --- a/CPP/Windows/MemoryLock.cpp +++ b/CPP/Windows/MemoryLock.cpp @@ -75,11 +75,11 @@ typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); /* We suppose that Window 10 works incorrectly with "Large Pages" at: - - Windows 10 1703 (15063) - - Windows 10 1709 (16299) - - - Windows 10 1809 (17763) on some CPUs that have no 1 GB page support. - We need more information about that new BUG in Windows. + - Windows 10 1703 (15063) : incorrect allocating after VirtualFree() + - Windows 10 1709 (16299) : incorrect allocating after VirtualFree() + - Windows 10 1809 (17763) : the failures for blocks of 1 GiB and larger, + if CPU doesn't support 1 GB pages. + Windows 10 1903 (18362) probably works correctly. */ unsigned Get_LargePages_RiskLevel() @@ -88,7 +88,7 @@ unsigned Get_LargePages_RiskLevel() HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); if (!ntdll) return 0; - Func_RtlGetVersion func = (Func_RtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion"); + Func_RtlGetVersion func = (Func_RtlGetVersion)(void *)GetProcAddress(ntdll, "RtlGetVersion"); if (!func) return 0; func(&vi); @@ -100,7 +100,7 @@ unsigned Get_LargePages_RiskLevel() return 1; #ifdef MY_CPU_X86_OR_AMD64 - if (!CPU_IsSupported_PageGB()) + if (vi.dwBuildNumber < 18362 && !CPU_IsSupported_PageGB()) return 1; #endif diff --git a/CPP/Windows/Menu.cpp b/CPP/Windows/Menu.cpp index 3834881a..3ad69530 100644 --- a/CPP/Windows/Menu.cpp +++ b/CPP/Windows/Menu.cpp @@ -26,11 +26,15 @@ will not work at NT 4.0, if cbSize is set as sizeof(MENUITEMINFO*). So we use size of old version of structure. */ #if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500) + #ifndef _UNICODE #define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA) + #endif #define my_compatib_MENUITEMINFOW_size sizeof(MENUITEMINFOW) #else #define MY_STRUCT_SIZE_BEFORE(structname, member) ((UINT)(UINT_PTR)((LPBYTE)(&((structname*)0)->member) - (LPBYTE)(structname*)0)) + #ifndef _UNICODE #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem) + #endif #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem) #endif @@ -145,7 +149,7 @@ bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) if (item.IsString()) { s = GetSystemString(item.StringValue); - si.dwTypeData = (LPTSTR)(LPCTSTR)s; + si.dwTypeData = s.Ptr_non_const(); } return SetItemInfo(itemIndex, byPosition, &si); } @@ -155,7 +159,7 @@ bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item) MENUITEMINFOW si; ConvertItemToSysForm(item, si); if (item.IsString()) - si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue; + si.dwTypeData = item.StringValue.Ptr_non_const(); return SetItemInfo(itemIndex, byPosition, &si); } } @@ -171,7 +175,7 @@ bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) if (item.IsString()) { s = GetSystemString(item.StringValue); - si.dwTypeData = (LPTSTR)(LPCTSTR)s; + si.dwTypeData = s.Ptr_non_const(); } return InsertItem(itemIndex, byPosition, &si); } @@ -181,7 +185,7 @@ bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item) MENUITEMINFOW si; ConvertItemToSysForm(item, si); if (item.IsString()) - si.dwTypeData = (LPWSTR)(LPCWSTR)item.StringValue; + si.dwTypeData = item.StringValue.Ptr_non_const(); #ifdef UNDER_CE UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING; UINT id = item.wID; diff --git a/CPP/Windows/Net.cpp b/CPP/Windows/Net.cpp index 14d06d6e..2a3952a1 100644 --- a/CPP/Windows/Net.cpp +++ b/CPP/Windows/Net.cpp @@ -35,11 +35,11 @@ DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResour } #endif -static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srsString) +static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srcString) { - defined = (srsString != 0); + defined = (srcString != 0); if (defined) - destString = srsString; + destString = srcString; else destString.Empty(); } @@ -59,9 +59,9 @@ static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResou static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString) { if (defined) - *destString = (TCHAR *)(const TCHAR *)srcString; + *destString = srcString.Ptr_non_const(); else - *destString = 0; + *destString = NULL; } static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource) @@ -78,11 +78,11 @@ static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE #ifndef _UNICODE -static void SetComplexString(bool &defined, UString &destString, LPCWSTR srsString) +static void SetComplexString(bool &defined, UString &destString, LPCWSTR src) { - defined = (srsString != 0); + defined = (src != NULL); if (defined) - destString = srsString; + destString = src; else destString.Empty(); } @@ -102,9 +102,9 @@ static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CReso static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString) { if (defined) - *destString = (WCHAR *)(const WCHAR *)srcString; + *destString = srcString.Ptr_non_const(); else - *destString = 0; + *destString = NULL; } static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource) @@ -141,10 +141,8 @@ static void ConvertResourceToResourceW(const CResource &resource, CResourceW &re DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource) { NETRESOURCE netResource; - LPNETRESOURCE pointer; - if (resource == 0) - pointer = 0; - else + LPNETRESOURCE pointer = NULL; + if (resource) { ConvertCResourceToNETRESOURCE(*resource, netResource); pointer = &netResource; @@ -158,21 +156,17 @@ DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resour if (g_IsNT) { NETRESOURCEW netResource; - LPNETRESOURCEW pointer; - if (resource == 0) - pointer = 0; - else + LPNETRESOURCEW pointer = NULL; + if (resource) { ConvertCResourceToNETRESOURCE(*resource, netResource); pointer = &netResource; } return Open(scope, type, usage, pointer); } - CResource *pointer; CResource resourceA; - if (resource == 0) - pointer = 0; - else + CResource *pointer = NULL; + if (resource) { ConvertResourceWToResource(*resource, resourceA); pointer = &resourceA; @@ -206,7 +200,7 @@ DWORD CEnum::Next(CResource &resource) { const DWORD kBufferSize = 16384; CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); ZeroMemory(lpnrLocal, kBufferSize); DWORD bufferSize = kBufferSize; DWORD numEntries = 1; @@ -226,7 +220,7 @@ DWORD CEnum::Next(CResourceW &resource) { const DWORD kBufferSize = 16384; CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); ZeroMemory(lpnrLocal, kBufferSize); DWORD bufferSize = kBufferSize; DWORD numEntries = 1; @@ -250,7 +244,7 @@ DWORD GetResourceParent(const CResource &resource, CResource &parentResource) { const DWORD kBufferSize = 16384; CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); ZeroMemory(lpnrLocal, kBufferSize); DWORD bufferSize = kBufferSize; NETRESOURCE netResource; @@ -269,7 +263,7 @@ DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource) { const DWORD kBufferSize = 16384; CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); ZeroMemory(lpnrLocal, kBufferSize); DWORD bufferSize = kBufferSize; NETRESOURCEW netResource; @@ -293,7 +287,7 @@ DWORD GetResourceInformation(const CResource &resource, { const DWORD kBufferSize = 16384; CByteArr byteBuffer(kBufferSize); - LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (BYTE *)(byteBuffer); + LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer); ZeroMemory(lpnrLocal, kBufferSize); DWORD bufferSize = kBufferSize; NETRESOURCE netResource; @@ -317,7 +311,7 @@ DWORD GetResourceInformation(const CResourceW &resource, { const DWORD kBufferSize = 16384; CByteArr byteBuffer(kBufferSize); - LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (BYTE *)(byteBuffer); + LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer); ZeroMemory(lpnrLocal, kBufferSize); DWORD bufferSize = kBufferSize; NETRESOURCEW netResource; diff --git a/CPP/Windows/NtCheck.h b/CPP/Windows/NtCheck.h index a1b89ef2..0af32911 100644 --- a/CPP/Windows/NtCheck.h +++ b/CPP/Windows/NtCheck.h @@ -17,6 +17,8 @@ static inline bool IsItWindowsNT() #endif #ifndef _UNICODE + extern + bool g_IsNT; #if defined(_WIN64) || defined(UNDER_CE) bool g_IsNT = true; #define SET_IS_NT diff --git a/CPP/Windows/ProcessUtils.cpp b/CPP/Windows/ProcessUtils.cpp index f7878d51..9bf05383 100644 --- a/CPP/Windows/ProcessUtils.cpp +++ b/CPP/Windows/ProcessUtils.cpp @@ -24,6 +24,21 @@ static UString GetQuotedString(const UString &s) WRes CProcess::Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir) { + /* + OutputDebugStringW(L"CProcess::Create"); + OutputDebugStringW(imageName); + if (params) + { + OutputDebugStringW(L"params:"); + OutputDebugStringW(params); + } + if (curDir) + { + OutputDebugStringW(L"cur dir:"); + OutputDebugStringW(curDir); + } + */ + Close(); const UString params2 = #ifndef UNDER_CE @@ -52,7 +67,8 @@ WRes CProcess::Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir) CSysString curDirA; if (curDir != 0) curDirA = GetSystemString(curDir); - result = ::CreateProcessA(NULL, (LPSTR)(LPCSTR)GetSystemString(params2), + const AString s = GetSystemString(params2); + result = ::CreateProcessA(NULL, s.Ptr_non_const(), NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi); } else @@ -67,8 +83,8 @@ WRes CProcess::Create(LPCWSTR imageName, const UString ¶ms, LPCWSTR curDir) si.cbReserved2 = 0; si.lpReserved2 = 0; - result = CreateProcessW(imageName, (LPWSTR)(LPCWSTR)params2, - NULL, NULL, FALSE, 0, NULL, (LPWSTR)curDir, &si, &pi); + result = CreateProcessW(imageName, params2.Ptr_non_const(), + NULL, NULL, FALSE, 0, NULL, curDir, &si, &pi); } if (result == 0) return ::GetLastError(); diff --git a/CPP/Windows/ProcessUtils.h b/CPP/Windows/ProcessUtils.h index a50bb5fc..e46f9ab2 100644 --- a/CPP/Windows/ProcessUtils.h +++ b/CPP/Windows/ProcessUtils.h @@ -3,7 +3,7 @@ #ifndef __WINDOWS_PROCESS_UTILS_H #define __WINDOWS_PROCESS_UTILS_H -#include <psapi.h> +#include <Psapi.h> #include "../Common/MyString.h" diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp index c4ad3acb..8cc89a3a 100644 --- a/CPP/Windows/PropVariant.cpp +++ b/CPP/Windows/PropVariant.cpp @@ -278,7 +278,8 @@ HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw() HRESULT hr = Clear(); if (FAILED(hr)) return hr; - memcpy(this, pSrc, sizeof(PROPVARIANT)); + // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT)); + *(PROPVARIANT *)this = *pSrc; pSrc->vt = VT_EMPTY; return S_OK; } @@ -291,7 +292,8 @@ HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw() if (FAILED(hr)) return hr; } - memcpy(pDest, this, sizeof(PROPVARIANT)); + // memcpy(pDest, this, sizeof(PROPVARIANT)); + *pDest = *(PROPVARIANT *)this; vt = VT_EMPTY; return S_OK; } diff --git a/CPP/Windows/PropVariantConv.cpp b/CPP/Windows/PropVariantConv.cpp index 65aa9f7e..b58d37e6 100644 --- a/CPP/Windows/PropVariantConv.cpp +++ b/CPP/Windows/PropVariantConv.cpp @@ -1,4 +1,4 @@ -// PropVariantConvert.cpp +// PropVariantConv.cpp #include "StdAfx.h" @@ -86,7 +86,7 @@ bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) th bool res = ConvertUtcFileTimeToString(ft, s, level); for (unsigned i = 0;; i++) { - unsigned char c = s[i]; + Byte c = (Byte)s[i]; dest[i] = c; if (c == 0) break; diff --git a/CPP/Windows/PropVariantUtils.cpp b/CPP/Windows/PropVariantUtils.cpp index fab556a5..6daee839 100644 --- a/CPP/Windows/PropVariantUtils.cpp +++ b/CPP/Windows/PropVariantUtils.cpp @@ -128,7 +128,7 @@ void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM } -AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags) +static AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags) { AString s; for (unsigned i = 0; i < num; i++) diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp index a2893131..2c4643bc 100644 --- a/CPP/Windows/Registry.cpp +++ b/CPP/Windows/Registry.cpp @@ -119,7 +119,7 @@ LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw() { MYASSERT(_object != NULL); return RegSetValueEx(_object, name, 0, REG_DWORD, - (BYTE * const)&value, sizeof(UInt32)); + (const BYTE *)&value, sizeof(UInt32)); } LONG CKey::SetValue(LPCTSTR name, bool value) throw() @@ -132,7 +132,7 @@ LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw() MYASSERT(value != NULL); MYASSERT(_object != NULL); return RegSetValueEx(_object, name, 0, REG_SZ, - (const BYTE * )value, (lstrlen(value) + 1) * sizeof(TCHAR)); + (const BYTE *)value, ((DWORD)lstrlen(value) + 1) * sizeof(TCHAR)); } /* @@ -193,7 +193,7 @@ LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw() { DWORD type = 0; DWORD count = sizeof(DWORD); - LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, + LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)&value, &count); MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD)); MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32))); @@ -219,7 +219,7 @@ LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw() LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() { - bool newVal; + bool newVal = false; LONG res = QueryValue(name, newVal); if (res == ERROR_SUCCESS) value = newVal; @@ -229,7 +229,7 @@ LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw() LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw() { DWORD type = 0; - LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count); + LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ)); return res; } @@ -239,7 +239,7 @@ LONG CKey::QueryValue(LPCTSTR name, CSysString &value) value.Empty(); DWORD type = 0; UInt32 curSize = 0; - LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&curSize); + LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&curSize); if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) return res; UInt32 curSize2 = curSize; @@ -296,7 +296,7 @@ LONG CKey::QueryValue(LPCWSTR name, UString &value) LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw() { DWORD type = 0; - LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count); + LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count); MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY)); return res; } @@ -306,7 +306,7 @@ LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize) { DWORD type = 0; dataSize = 0; - LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&dataSize); + LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&dataSize); if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) return res; value.Alloc(dataSize); @@ -369,7 +369,7 @@ LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings) if (dataSize % sizeof(wchar_t) != 0) return E_FAIL; - const wchar_t *data = (const wchar_t *)(const Byte *)buffer; + const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer; size_t numChars = dataSize / sizeof(wchar_t); size_t prev = 0; UString s; diff --git a/CPP/Windows/ResourceString.cpp b/CPP/Windows/ResourceString.cpp index cc8b964a..ae8182ed 100644 --- a/CPP/Windows/ResourceString.cpp +++ b/CPP/Windows/ResourceString.cpp @@ -25,10 +25,10 @@ static CSysString MyLoadStringA(HINSTANCE hInstance, UINT resourceID) do { size <<= 1; - len = ::LoadString(hInstance, resourceID, s.GetBuf(size - 1), size); + len = ::LoadString(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); } while (size - len <= 1); - s.ReleaseBuf_CalcLen(len); + s.ReleaseBuf_CalcLen((unsigned)len); return s; } @@ -43,10 +43,10 @@ static void MyLoadString2(HINSTANCE hInstance, UINT resourceID, UString &s) do { size <<= 1; - len = ::LoadStringW(hInstance, resourceID, s.GetBuf(size - 1), size); + len = ::LoadStringW(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size); } while (size - len <= 1); - s.ReleaseBuf_CalcLen(len); + s.ReleaseBuf_CalcLen((unsigned)len); } // NT4 doesn't support LoadStringW(,,, 0) to get pointer to resource string. So we don't use it. diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp index 67a9d7fd..640c90dc 100644 --- a/CPP/Windows/SecurityUtils.cpp +++ b/CPP/Windows/SecurityUtils.cpp @@ -34,7 +34,7 @@ bool MyLookupAccountSid(LPCTSTR systemName, PSID sid, static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest) { - int len = (int)wcslen(src); + size_t len = (size_t)wcslen(src); dest->Length = (USHORT)(len * sizeof(WCHAR)); dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR)); dest->Buffer = src; diff --git a/CPP/Windows/Shell.cpp b/CPP/Windows/Shell.cpp index b424e67c..d0f9032c 100644 --- a/CPP/Windows/Shell.cpp +++ b/CPP/Windows/Shell.cpp @@ -192,7 +192,7 @@ bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath) } -int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) +static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) { #ifndef UNDER_CE switch (uMsg) @@ -221,7 +221,7 @@ int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM da } -bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, +static bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags, LPCTSTR initialFolder, CSysString &resultPath) { CSysString displayName; @@ -275,7 +275,7 @@ bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path) typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi); -bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) +static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) { NWindows::NCOM::CComInitializer comInitializer; SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP) @@ -290,7 +290,7 @@ bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath) return GetPathFromIDList(itemIDList, resultPath); } - +static int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data) { switch (uMsg) diff --git a/CPP/Windows/Shell.h b/CPP/Windows/Shell.h index 4bff18cf..de91d3f1 100644 --- a/CPP/Windows/Shell.h +++ b/CPP/Windows/Shell.h @@ -3,8 +3,8 @@ #ifndef __WINDOWS_SHELL_H #define __WINDOWS_SHELL_H -#include <windows.h> -#include <shlobj.h> +#include "../Common/MyWindows.h" +#include <ShlObj.h> #include "../Common/MyString.h" diff --git a/CPP/Windows/Synchronization.cpp b/CPP/Windows/Synchronization.cpp index 5f86d1eb..fbf919dc 100644 --- a/CPP/Windows/Synchronization.cpp +++ b/CPP/Windows/Synchronization.cpp @@ -2,9 +2,62 @@ #include "StdAfx.h" +#ifndef _WIN32 + #include "Synchronization.h" namespace NWindows { namespace NSynchronization { +/* +#define INFINITE 0xFFFFFFFF +#define MAXIMUM_WAIT_OBJECTS 64 +#define STATUS_ABANDONED_WAIT_0 ((NTSTATUS)0x00000080L) +#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 ) +#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 ) +// WINAPI +DWORD WaitForMultipleObjects(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout); +*/ + +DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) +{ + if (count < 1) + { + // abort(); + SetLastError(EINVAL); + return WAIT_FAILED; + } + + CSynchro *synchro = handles[0]->_sync; + synchro->Enter(); + + // #ifdef DEBUG_SYNCHRO + for (DWORD i = 1; i < count; i++) + { + if (synchro != handles[i]->_sync) + { + // abort(); + synchro->Leave(); + SetLastError(EINVAL); + return WAIT_FAILED; + } + } + // #endif + + for (;;) + { + for (DWORD i = 0; i < count; i++) + { + if (handles[i]->IsSignaledAndUpdate()) + { + synchro->Leave(); + return WAIT_OBJECT_0 + i; + } + } + synchro->WaitCond(); + } +} + }} + +#endif diff --git a/CPP/Windows/Synchronization.h b/CPP/Windows/Synchronization.h index dc695f6f..98ea0b69 100644 --- a/CPP/Windows/Synchronization.h +++ b/CPP/Windows/Synchronization.h @@ -5,6 +5,8 @@ #include "../../C/Threads.h" +#include "../Common/MyTypes.h" + #include "Defs.h" #ifdef _WIN32 @@ -14,17 +16,19 @@ namespace NWindows { namespace NSynchronization { -class CBaseEvent +class CBaseEvent MY_UNCOPYABLE { protected: ::CEvent _object; public: bool IsCreated() { return Event_IsCreated(&_object) != 0; } - operator HANDLE() { return _object; } + CBaseEvent() { Event_Construct(&_object); } ~CBaseEvent() { Close(); } WRes Close() { return Event_Close(&_object); } + #ifdef _WIN32 + operator HANDLE() { return _object; } WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL) { _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name); @@ -54,10 +58,10 @@ public: { return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0); } - WRes CreateIfNotCreated() + WRes CreateIfNotCreated_Reset() { if (IsCreated()) - return 0; + return Reset(); return ManualResetEvent_CreateNotSignaled(&_object); } #ifdef _WIN32 @@ -75,21 +79,25 @@ public: { return AutoResetEvent_CreateNotSignaled(&_object); } - WRes CreateIfNotCreated() + WRes CreateIfNotCreated_Reset() { if (IsCreated()) - return 0; + return Reset(); return AutoResetEvent_CreateNotSignaled(&_object); } }; + +/* #ifdef _WIN32 + class CObject: public CHandle { public: WRes Lock(DWORD timeoutInterval = INFINITE) { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); } }; + class CMutex: public CObject { public: @@ -114,33 +122,43 @@ public: return ::ReleaseMutex(_handle) ? 0 : ::GetLastError(); } }; -class CMutexLock + +class CMutexLock MY_UNCOPYABLE { CMutex *_object; public: CMutexLock(CMutex &object): _object(&object) { _object->Lock(); } ~CMutexLock() { _object->Release(); } }; -#endif -class CSemaphore +#endif // _WIN32 +*/ + + +class CSemaphore MY_UNCOPYABLE { ::CSemaphore _object; public: CSemaphore() { Semaphore_Construct(&_object); } ~CSemaphore() { Close(); } - WRes Close() { return Semaphore_Close(&_object); } + WRes Close() { return Semaphore_Close(&_object); } + + #ifdef _WIN32 operator HANDLE() { return _object; } - WRes Create(UInt32 initiallyCount, UInt32 maxCount) + #endif + + // bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; } + + WRes Create(UInt32 initCount, UInt32 maxCount) { - return Semaphore_Create(&_object, initiallyCount, maxCount); + return Semaphore_Create(&_object, initCount, maxCount); } WRes Release() { return Semaphore_Release1(&_object); } WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); } WRes Lock() { return Semaphore_Wait(&_object); } }; -class CCriticalSection +class CCriticalSection MY_UNCOPYABLE { ::CCriticalSection _object; public: @@ -150,7 +168,7 @@ public: void Leave() { CriticalSection_Leave(&_object); } }; -class CCriticalSectionLock +class CCriticalSectionLock MY_UNCOPYABLE { CCriticalSection *_object; void Unlock() { _object->Leave(); } @@ -159,6 +177,213 @@ public: ~CCriticalSectionLock() { Unlock(); } }; + +#ifdef _WIN32 + +typedef HANDLE CHandle_WFMO; +typedef CSemaphore CSemaphore_WFMO; +typedef CAutoResetEvent CAutoResetEvent_WFMO; +typedef CManualResetEvent CManualResetEvent_WFMO; + +inline DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles) +{ + return ::WaitForMultipleObjects(count, handles, FALSE, INFINITE); +} + +#define SYNC_OBJ_DECL(obj) +#define SYNC_WFMO(x) +#define SYNC_PARAM(x) +#define SYNC_PARAM_DECL(x) + +#else // _WIN32 + +// POSIX sync objects for WaitForMultipleObjects + +#define SYNC_WFMO(x) x +#define SYNC_PARAM(x) x, +#define SYNC_PARAM_DECL(x) NWindows::NSynchronization::CSynchro *x +#define SYNC_OBJ_DECL(x) NWindows::NSynchronization::CSynchro x; + +class CSynchro MY_UNCOPYABLE +{ + pthread_mutex_t _mutex; + pthread_cond_t _cond; + bool _isValid; + +public: + CSynchro() { _isValid = false; } + ~CSynchro() + { + if (_isValid) + { + ::pthread_mutex_destroy(&_mutex); + ::pthread_cond_destroy(&_cond); + } + _isValid = false; + } + WRes Create() + { + RINOK(::pthread_mutex_init(&_mutex, 0)); + WRes ret = ::pthread_cond_init(&_cond, 0); + _isValid = 1; + return ret; + } + WRes Enter() + { + return ::pthread_mutex_lock(&_mutex); + } + WRes Leave() + { + return ::pthread_mutex_unlock(&_mutex); + } + WRes WaitCond() + { + return ::pthread_cond_wait(&_cond, &_mutex); + } + WRes LeaveAndSignal() + { + WRes res1 = ::pthread_cond_broadcast(&_cond); + WRes res2 = ::pthread_mutex_unlock(&_mutex); + return (res2 ? res2 : res1); + } +}; + + +struct CBaseHandle_WFMO; +typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO; + +// these constants are from Windows +#define WAIT_OBJECT_0 0 +#define WAIT_FAILED ((DWORD)0xFFFFFFFF) + +DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles); + + +struct CBaseHandle_WFMO MY_UNCOPYABLE +{ + CSynchro *_sync; + + CBaseHandle_WFMO(): _sync(NULL) {} + + operator CHandle_WFMO() { return this; } + virtual bool IsSignaledAndUpdate() = 0; +}; + + +class CBaseEvent_WFMO : public CBaseHandle_WFMO +{ + bool _manual_reset; + bool _state; + +public: + + // bool IsCreated() { return (this->_sync != NULL); } + // CBaseEvent_WFMO() { ; } + ~CBaseEvent_WFMO() { Close(); } + + WRes Close() { this->_sync = NULL; return 0; } + + WRes Create( + CSynchro *sync, + bool manualReset, bool initiallyOwn) + { + this->_sync = sync; + this->_manual_reset = manualReset; + this->_state = initiallyOwn; + return 0; + } + + WRes Set() + { + RINOK(this->_sync->Enter()); + this->_state = true; + return this->_sync->LeaveAndSignal(); + } + + WRes Reset() + { + RINOK(this->_sync->Enter()); + this->_state = false; + return this->_sync->Leave(); + } + + virtual bool IsSignaledAndUpdate() + { + if (this->_state == false) + return false; + if (this->_manual_reset == false) + this->_state = false; + return true; + } +}; + + +class CManualResetEvent_WFMO: public CBaseEvent_WFMO +{ +public: + WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); } +}; + + +class CAutoResetEvent_WFMO: public CBaseEvent_WFMO +{ +public: + WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); } + WRes CreateIfNotCreated_Reset(CSynchro *sync) + { + return Create(sync); + } +}; + + +class CSemaphore_WFMO : public CBaseHandle_WFMO +{ + UInt32 _count; + UInt32 _maxCount; + +public: + CSemaphore_WFMO() : _count(0), _maxCount(0) {} + + WRes Close() { this->_sync = NULL; return 0; } + + WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount) + { + if (initCount > maxCount || maxCount < 1) + return EINVAL; + this->_sync = sync; + this->_count = initCount; + this->_maxCount = maxCount; + return 0; + } + + WRes Release(UInt32 releaseCount = 1) + { + if (releaseCount < 1) + return EINVAL; + + RINOK(this->_sync->Enter()); + UInt32 newCount = this->_count + releaseCount; + if (newCount > this->_maxCount) + { + RINOK(this->_sync->Leave()); + return ERROR_TOO_MANY_POSTS; // EINVAL + } + this->_count = newCount; + + return this->_sync->LeaveAndSignal(); + } + + virtual bool IsSignaledAndUpdate() + { + if (this->_count == 0) + return false; + this->_count--; + return true; + } +}; + +#endif // _WIN32 + }} #endif diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp index cc33169a..099407ec 100644 --- a/CPP/Windows/System.cpp +++ b/CPP/Windows/System.cpp @@ -2,15 +2,27 @@ #include "StdAfx.h" -#include "../Common/MyWindows.h" +#ifndef _WIN32 +#include <unistd.h> +#ifdef __APPLE__ +#include <sys/sysctl.h> +#else +#include <sys/sysinfo.h> +#endif +#endif #include "../Common/Defs.h" +// #include "../Common/MyWindows.h" + +// #include "../../C/CpuArch.h" #include "System.h" namespace NWindows { namespace NSystem { +#ifdef _WIN32 + UInt32 CountAffinity(DWORD_PTR mask) { UInt32 num = 0; @@ -19,8 +31,6 @@ UInt32 CountAffinity(DWORD_PTR mask) return num; } -#ifdef _WIN32 - BOOL CProcessAffinity::Get() { #ifndef UNDER_CE @@ -52,9 +62,45 @@ UInt32 GetNumberOfProcessors() #else + +BOOL CProcessAffinity::Get() +{ + numSysThreads = GetNumberOfProcessors(); + + /* + numSysThreads = 8; + for (unsigned i = 0; i < numSysThreads; i++) + CpuSet_Set(&cpu_set, i); + return TRUE; + */ + + #ifdef _7ZIP_AFFINITY_SUPPORTED + + // numSysThreads = sysconf(_SC_NPROCESSORS_ONLN); // The number of processors currently online + if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) != 0) + return FALSE; + return TRUE; + + #else + + // cpu_set = ((CCpuSet)1 << (numSysThreads)) - 1; + return TRUE; + // errno = ENOSYS; + // return FALSE; + + #endif +} + UInt32 GetNumberOfProcessors() { + #ifndef _7ZIP_ST + long n = sysconf(_SC_NPROCESSORS_CONF); // The number of processors configured + if (n < 1) + n = 1; + return (UInt32)n; + #else return 1; + #endif } #endif @@ -87,17 +133,13 @@ typedef struct _MY_MEMORYSTATUSEX { typedef BOOL (WINAPI *GlobalMemoryStatusExP)(MY_LPMEMORYSTATUSEX lpBuffer); -#endif - -#endif - +#endif // !UNDER_CE + bool GetRamSize(UInt64 &size) { size = (UInt64)(sizeof(size_t)) << 29; - #ifdef _WIN32 - #ifndef UNDER_CE MY_MEMORYSTATUSEX stat; stat.dwLength = sizeof(stat); @@ -114,7 +156,7 @@ bool GetRamSize(UInt64 &size) #ifndef UNDER_CE GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP) - ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GlobalMemoryStatusEx"); + (void *)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "GlobalMemoryStatusEx"); if (globalMemoryStatusEx && globalMemoryStatusEx(&stat)) { size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys); @@ -129,14 +171,61 @@ bool GetRamSize(UInt64 &size) size = MyMin(stat2.dwTotalVirtual, stat2.dwTotalPhys); return true; } - #endif +} + +#else + +// POSIX +// #include <stdio.h> + +bool GetRamSize(UInt64 &size) +{ + size = (UInt64)(sizeof(size_t)) << 29; + + #ifdef __APPLE__ + + #ifdef HW_MEMSIZE + uint64_t val = 0; // support 2Gb+ RAM + int mib[2] = { CTL_HW, HW_MEMSIZE }; + #elif defined(HW_PHYSMEM64) + uint64_t val = 0; // support 2Gb+ RAM + int mib[2] = { CTL_HW, HW_PHYSMEM64 }; + #else + unsigned int val = 0; // For old system + int mib[2] = { CTL_HW, HW_PHYSMEM }; + #endif // HW_MEMSIZE + size_t size_sys = sizeof(val); + + sysctl(mib, 2, &val, &size_sys, NULL, 0); + if (val) + size = val; + + #elif defined(_AIX) + + // fixme #else - return false; + struct sysinfo info; + if (::sysinfo(&info) != 0) + return false; + size = (UInt64)info.mem_unit * info.totalram; + const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1); + if (size > kLimit) + size = kLimit; + + /* + printf("\n mem_unit = %lld", (UInt64)info.mem_unit); + printf("\n totalram = %lld", (UInt64)info.totalram); + printf("\n freeram = %lld", (UInt64)info.freeram); + */ #endif + + return true; } +#endif + }} diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h index 519e0444..23cb0dab 100644 --- a/CPP/Windows/System.h +++ b/CPP/Windows/System.h @@ -3,11 +3,19 @@ #ifndef __WINDOWS_SYSTEM_H #define __WINDOWS_SYSTEM_H +#ifndef _WIN32 +// #include <sched.h> +#include "../../C/Threads.h" +#endif + #include "../Common/MyTypes.h" namespace NWindows { namespace NSystem { + +#ifdef _WIN32 + UInt32 CountAffinity(DWORD_PTR mask); struct CProcessAffinity @@ -25,12 +33,93 @@ struct CProcessAffinity systemAffinityMask = 1; } + void CpuZero() + { + processAffinityMask = 0; + } + + void CpuSet(unsigned cpuIndex) + { + processAffinityMask |= ((DWORD_PTR)1 << cpuIndex); + } + UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); } UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); } BOOL Get(); + + BOOL SetProcAffinity() const + { + return SetProcessAffinityMask(GetCurrentProcess(), processAffinityMask); + } +}; + + +#else // WIN32 + +struct CProcessAffinity +{ + UInt32 numSysThreads; + + UInt32 GetNumSystemThreads() const { return (UInt32)numSysThreads; } + BOOL Get(); + + #ifdef _7ZIP_AFFINITY_SUPPORTED + + CCpuSet cpu_set; + + void InitST() + { + numSysThreads = 1; + CpuSet_Zero(&cpu_set); + CpuSet_Set(&cpu_set, 0); + } + + UInt32 GetNumProcessThreads() const { return (UInt32)CPU_COUNT(&cpu_set); } + void CpuZero() { CpuSet_Zero(&cpu_set); } + void CpuSet(unsigned cpuIndex) { CpuSet_Set(&cpu_set, cpuIndex); } + int IsCpuSet(unsigned cpuIndex) const { return CpuSet_IsSet(&cpu_set, cpuIndex); } + // void CpuClr(int cpuIndex) { CPU_CLR(cpuIndex, &cpu_set); } + + BOOL SetProcAffinity() const + { + return sched_setaffinity(0, sizeof(cpu_set), &cpu_set) == 0; + } + + #else + + void InitST() + { + numSysThreads = 1; + } + + UInt32 GetNumProcessThreads() const + { + return numSysThreads; + /* + UInt32 num = 0; + for (unsigned i = 0; i < sizeof(cpu_set) * 8; i++) + num += (UInt32)((cpu_set >> i) & 1); + return num; + */ + } + + void CpuZero() { } + void CpuSet(unsigned cpuIndex) { UNUSED_VAR(cpuIndex); } + int IsCpuSet(unsigned cpuIndex) const { return (cpuIndex < numSysThreads) ? 1 : 0; } + + BOOL SetProcAffinity() const + { + errno = ENOSYS; + return FALSE; + } + + #endif }; +#endif + + UInt32 GetNumberOfProcessors(); bool GetRamSize(UInt64 &size); // returns false, if unknown ram size diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp new file mode 100644 index 00000000..55403efc --- /dev/null +++ b/CPP/Windows/SystemInfo.cpp @@ -0,0 +1,716 @@ +// Windows/SystemInfo.cpp + +#include "StdAfx.h" + +#include "../../C/CpuArch.h" + +#include "../Common/IntToString.h" + +#ifdef _WIN32 + +#include "Registry.h" + +#else + +#include <sys/utsname.h> +#ifdef __APPLE__ +#include <sys/sysctl.h> +#elif !defined(_AIX) + + +#include <sys/auxv.h> + +#ifdef MY_CPU_ARM_OR_ARM64 +#include <asm/hwcap.h> +#endif +#endif + +#endif + +#include "SystemInfo.h" +#include "System.h" + +using namespace NWindows; + +#ifndef __APPLE__ +static void PrintHex(AString &s, UInt64 v) +{ + char temp[32]; + ConvertUInt64ToHex(v, temp); + s += temp; +} +#endif + +#ifdef MY_CPU_X86_OR_AMD64 + +static void PrintCpuChars(AString &s, UInt32 v) +{ + for (int j = 0; j < 4; j++) + { + Byte b = (Byte)(v & 0xFF); + v >>= 8; + if (b == 0) + break; + s += (char)b; + } +} + + +static void x86cpuid_to_String(const Cx86cpuid &c, AString &s) +{ + s.Empty(); + + UInt32 maxFunc2 = 0; + UInt32 t[3]; + + MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]); + + bool fullNameIsAvail = (maxFunc2 >= 0x80000004); + + if (fullNameIsAvail) + { + for (unsigned i = 0; i < 3; i++) + { + UInt32 d[4] = { 0 }; + MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]); + for (unsigned j = 0; j < 4; j++) + PrintCpuChars(s, d[j]); + } + } + + s.Trim(); + + if (s.IsEmpty()) + { + for (int i = 0; i < 3; i++) + PrintCpuChars(s, c.vendor[i]); + s.Trim(); + } + + s.Add_Space_if_NotEmpty(); + { + char temp[32]; + ConvertUInt32ToHex(c.ver, temp); + s += '('; + s += temp; + s += ')'; + } +} + +/* +static void x86cpuid_all_to_String(AString &s) +{ + Cx86cpuid p; + if (!x86cpuid_CheckAndRead(&p)) + return; + s += "x86cpuid maxFunc = "; + s.Add_UInt32(p.maxFunc); + for (unsigned j = 0; j <= p.maxFunc; j++) + { + s.Add_LF(); + // s.Add_UInt32(j); // align + { + char temp[32]; + ConvertUInt32ToString(j, temp); + unsigned len = (unsigned)strlen(temp); + while (len < 8) + { + len++; + s.Add_Space(); + } + s += temp; + } + + s += ":"; + UInt32 d[4] = { 0 }; + MyCPUID(j, &d[0], &d[1], &d[2], &d[3]); + for (unsigned i = 0; i < 4; i++) + { + char temp[32]; + ConvertUInt32ToHex8Digits(d[i], temp); + s += " "; + s += temp; + } + } +} +*/ + +#endif + + + +#ifdef _WIN32 + +static const char * const k_PROCESSOR_ARCHITECTURE[] = +{ + "x86" // "INTEL" + , "MIPS" + , "ALPHA" + , "PPC" + , "SHX" + , "ARM" + , "IA64" + , "ALPHA64" + , "MSIL" + , "x64" // "AMD64" + , "IA32_ON_WIN64" + , "NEUTRAL" + , "ARM64" + , "ARM32_ON_WIN64" +}; + +#define MY__PROCESSOR_ARCHITECTURE_INTEL 0 +#define MY__PROCESSOR_ARCHITECTURE_AMD64 9 + + +#define MY__PROCESSOR_INTEL_PENTIUM 586 +#define MY__PROCESSOR_AMD_X8664 8664 + +/* +static const CUInt32PCharPair k_PROCESSOR[] = +{ + { 2200, "IA64" }, + { 8664, "x64" } +}; + +#define PROCESSOR_INTEL_386 386 +#define PROCESSOR_INTEL_486 486 +#define PROCESSOR_INTEL_PENTIUM 586 +#define PROCESSOR_INTEL_860 860 +#define PROCESSOR_INTEL_IA64 2200 +#define PROCESSOR_AMD_X8664 8664 +#define PROCESSOR_MIPS_R2000 2000 +#define PROCESSOR_MIPS_R3000 3000 +#define PROCESSOR_MIPS_R4000 4000 +#define PROCESSOR_ALPHA_21064 21064 +#define PROCESSOR_PPC_601 601 +#define PROCESSOR_PPC_603 603 +#define PROCESSOR_PPC_604 604 +#define PROCESSOR_PPC_620 620 +#define PROCESSOR_HITACHI_SH3 10003 +#define PROCESSOR_HITACHI_SH3E 10004 +#define PROCESSOR_HITACHI_SH4 10005 +#define PROCESSOR_MOTOROLA_821 821 +#define PROCESSOR_SHx_SH3 103 +#define PROCESSOR_SHx_SH4 104 +#define PROCESSOR_STRONGARM 2577 // 0xA11 +#define PROCESSOR_ARM720 1824 // 0x720 +#define PROCESSOR_ARM820 2080 // 0x820 +#define PROCESSOR_ARM920 2336 // 0x920 +#define PROCESSOR_ARM_7TDMI 70001 +#define PROCESSOR_OPTIL 18767 // 0x494f +*/ + + +/* +static const char * const k_PF[] = +{ + "FP_ERRATA" + , "FP_EMU" + , "CMPXCHG" + , "MMX" + , "PPC_MOVEMEM_64BIT" + , "ALPHA_BYTE" + , "SSE" + , "3DNOW" + , "RDTSC" + , "PAE" + , "SSE2" + , "SSE_DAZ" + , "NX" + , "SSE3" + , "CMPXCHG16B" + , "CMP8XCHG16" + , "CHANNELS" + , "XSAVE" + , "ARM_VFP_32" + , "ARM_NEON" + , "L2AT" + , "VIRT_FIRMWARE" + , "RDWRFSGSBASE" + , "FASTFAIL" + , "ARM_DIVIDE" + , "ARM_64BIT_LOADSTORE_ATOMIC" + , "ARM_EXTERNAL_CACHE" + , "ARM_FMAC" + , "RDRAND" + , "ARM_V8" + , "ARM_V8_CRYPTO" + , "ARM_V8_CRC32" + , "RDTSCP" + , "RDPID" + , "ARM_V81_ATOMIC" + , "MONITORX" +}; +*/ + +#endif + + +#ifdef _WIN32 + +static void PrintPage(AString &s, UInt32 v) +{ + if ((v & 0x3FF) == 0) + { + s.Add_UInt32(v >> 10); + s += "K"; + } + else + s.Add_UInt32(v >> 10); +} + +static AString TypeToString2(const char * const table[], unsigned num, UInt32 value) +{ + char sz[16]; + const char *p = NULL; + if (value < num) + p = table[value]; + if (!p) + { + ConvertUInt32ToString(value, sz); + p = sz; + } + return (AString)p; +} + +// #if defined(_7ZIP_LARGE_PAGES) || defined(_WIN32) +// #ifdef _WIN32 +void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v) +{ + char c = 0; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'M'; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'G'; + if ((v & 0x3FF) == 0) { v >>= 10; c = 'T'; + }}}} + else + { + PrintHex(s, v); + return; + } + char temp[32]; + ConvertUInt64ToString(v, temp); + s += temp; + if (c) + s += c; +} +// #endif +// #endif + +static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si) +{ + s += TypeToString2(k_PROCESSOR_ARCHITECTURE, ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture); + + if (!( (si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == MY__PROCESSOR_INTEL_PENTIUM) + || (si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == MY__PROCESSOR_AMD_X8664))) + { + s += " "; + // s += TypePairToString(k_PROCESSOR, ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType); + s.Add_UInt32(si.dwProcessorType); + } + s += " "; + PrintHex(s, si.wProcessorLevel); + s += "."; + PrintHex(s, si.wProcessorRevision); + if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors)) + if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8) + { + s += " act:"; + PrintHex(s, si.dwActiveProcessorMask); + } + s += " cpus:"; + s.Add_UInt32(si.dwNumberOfProcessors); + if (si.dwPageSize != 1 << 12) + { + s += " page:"; + PrintPage(s, si.dwPageSize); + } + if (si.dwAllocationGranularity != 1 << 16) + { + s += " gran:"; + PrintPage(s, si.dwAllocationGranularity); + } + s += " "; + + DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress; + UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1; + const UInt32 kReserveSize = ((UInt32)1 << 16); + if (minAdd != kReserveSize) + { + PrintSize_KMGT_Or_Hex(s, minAdd); + s += "-"; + } + else + { + if ((maxSize & (kReserveSize - 1)) == 0) + maxSize += kReserveSize; + } + PrintSize_KMGT_Or_Hex(s, maxSize); +} + +#ifndef _WIN64 +EXTERN_C_BEGIN +typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo); +EXTERN_C_END +#endif + +#endif + +#ifdef __APPLE__ +#ifndef MY_CPU_X86_OR_AMD64 +static void Add_sysctlbyname_to_String(const char *name, AString &s) +{ + size_t bufSize = 256; + char buf[256]; + if (My_sysctlbyname_Get(name, &buf, &bufSize) == 0) + s += buf; +} +#endif +#endif + +void GetSysInfo(AString &s1, AString &s2); +void GetSysInfo(AString &s1, AString &s2) +{ + s1.Empty(); + s2.Empty(); + + #ifdef _WIN32 + SYSTEM_INFO si; + GetSystemInfo(&si); + { + SysInfo_To_String(s1, si); + // s += " : "; + } + + #if !defined(_WIN64) && !defined(UNDER_CE) + Func_GetNativeSystemInfo fn_GetNativeSystemInfo = (Func_GetNativeSystemInfo)(void *)GetProcAddress( + GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"); + if (fn_GetNativeSystemInfo) + { + SYSTEM_INFO si2; + fn_GetNativeSystemInfo(&si2); + // if (memcmp(&si, &si2, sizeof(si)) != 0) + { + // s += " - "; + SysInfo_To_String(s2, si2); + } + } + #endif + #endif +} + + +void GetCpuName(AString &s); +void GetCpuName(AString &s) +{ + s.Empty(); + + #ifdef MY_CPU_X86_OR_AMD64 + { + Cx86cpuid cpuid; + if (x86cpuid_CheckAndRead(&cpuid)) + { + AString s2; + x86cpuid_to_String(cpuid, s2); + s += s2; + } + else + { + #ifdef MY_CPU_AMD64 + s += "x64"; + #else + s += "x86"; + #endif + } + } + #elif defined(__APPLE__) + { + Add_sysctlbyname_to_String("machdep.cpu.brand_string", s); + } + #endif + + + if (s.IsEmpty()) + { + #ifdef MY_CPU_LE + s += "LE"; + #elif defined(MY_CPU_BE) + s += "BE"; + #endif + } + + #ifdef __APPLE__ + { + AString s2; + UInt32 v = 0; + if (My_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0) + { + s2.Add_UInt32(v); + s2 += 'C'; + } + if (My_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0) + { + s2.Add_UInt32(v); + s2 += 'T'; + } + if (!s2.IsEmpty()) + { + s.Add_Space_if_NotEmpty(); + s += s2; + } + } + #endif + + + #ifdef _WIN32 + { + NRegistry::CKey key; + if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS) + { + LONG res[2]; + CByteBuffer bufs[2]; + { + for (int i = 0; i < 2; i++) + { + UInt32 size = 0; + res[i] = key.QueryValue(i == 0 ? + TEXT("Previous Update Revision") : + TEXT("Update Revision"), bufs[i], size); + if (res[i] == ERROR_SUCCESS) + if (size != bufs[i].Size()) + res[i] = ERROR_SUCCESS + 1; + } + } + if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS) + { + s.Add_OptSpaced("("); + for (int i = 0; i < 2; i++) + { + if (i == 1) + s += "->"; + if (res[i] != ERROR_SUCCESS) + continue; + const CByteBuffer &buf = bufs[i]; + if (buf.Size() == 8) + { + UInt32 high = GetUi32(buf); + if (high != 0) + { + PrintHex(s, high); + s += "."; + } + PrintHex(s, GetUi32(buf + 4)); + } + } + s += ")"; + } + } + } + #endif + + + #ifdef _7ZIP_LARGE_PAGES + Add_LargePages_String(s); + #endif +} + +void AddCpuFeatures(AString &s); +void AddCpuFeatures(AString &s) +{ + #ifdef _WIN32 + // const unsigned kNumFeatures_Extra = 32; // we check also for unknown features + // const unsigned kNumFeatures = ARRAY_SIZE(k_PF) + kNumFeatures_Extra; + const unsigned kNumFeatures = 64; + UInt64 flags = 0; + for (unsigned i = 0; i < kNumFeatures; i++) + { + if (IsProcessorFeaturePresent(i)) + { + flags += (UInt64)1 << i; + // s.Add_Space_if_NotEmpty(); + // s += TypeToString2(k_PF, ARRAY_SIZE(k_PF), i); + } + } + s.Add_Space_if_NotEmpty(); + s += "f:"; + PrintHex(s, flags); + + #else // _WIN32 + + #ifdef __APPLE__ + { + UInt32 v = 0; + if (My_sysctlbyname_Get_UInt32("hw.pagesize", &v) == 0) + { + s += "PageSize:"; + s.Add_UInt32(v >> 10); + s += "KB"; + } + } + + #elif !defined(_AIX) + + s.Add_Space_if_NotEmpty(); + s += "hwcap:"; + { + unsigned long h = getauxval(AT_HWCAP); + PrintHex(s, h); + #ifdef MY_CPU_ARM64 + if (h & HWCAP_CRC32) s += ":CRC32"; + if (h & HWCAP_SHA1) s += ":SHA1"; + if (h & HWCAP_SHA2) s += ":SHA2"; + if (h & HWCAP_AES) s += ":AES"; + #endif + } + + { + unsigned long h = getauxval(AT_HWCAP2); + #ifndef MY_CPU_ARM + if (h != 0) + #endif + { + s += " hwcap2:"; + PrintHex(s, h); + #ifdef MY_CPU_ARM + if (h & HWCAP2_CRC32) s += ":CRC32"; + if (h & HWCAP2_SHA1) s += ":SHA1"; + if (h & HWCAP2_SHA2) s += ":SHA2"; + if (h & HWCAP2_AES) s += ":AES"; + #endif + } + } + + #endif + #endif // _WIN32 +} + + +#ifdef _WIN32 +#ifndef UNDER_CE + +EXTERN_C_BEGIN +typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *); +EXTERN_C_END + +static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi) +{ + HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll"); + if (!ntdll) + return FALSE; + Func_RtlGetVersion func = (Func_RtlGetVersion)(void *)GetProcAddress(ntdll, "RtlGetVersion"); + if (!func) + return FALSE; + func(vi); + return TRUE; +} + +#endif +#endif + + +void GetSystemInfoText(AString &sRes) +{ + { + { + AString s; + #ifdef _WIN32 + #ifndef UNDER_CE + // OSVERSIONINFO vi; + OSVERSIONINFOEXW vi; + vi.dwOSVersionInfoSize = sizeof(vi); + // if (::GetVersionEx(&vi)) + if (My_RtlGetVersion(&vi)) + { + s += "Windows"; + if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT) + s.Add_UInt32(vi.dwPlatformId); + s += " "; s.Add_UInt32(vi.dwMajorVersion); + s += "."; s.Add_UInt32(vi.dwMinorVersion); + s += " "; s.Add_UInt32(vi.dwBuildNumber); + + if (vi.wServicePackMajor != 0 || vi.wServicePackMinor != 0) + { + s += " SP:"; s.Add_UInt32(vi.wServicePackMajor); + s += "."; s.Add_UInt32(vi.wServicePackMinor); + } + s += " Suite:"; PrintHex(s, vi.wSuiteMask); + s += " Type:"; s.Add_UInt32(vi.wProductType); + // s += " "; s += GetOemString(vi.szCSDVersion); + } + { + s += " OEMCP:"; + s.Add_UInt32(GetOEMCP()); + s += " ACP:"; + s.Add_UInt32(GetACP()); + } + #endif + #else // _WIN32 + + if (!s.IsEmpty()) + s.Add_LF(); + struct utsname un; + if (uname(&un) == 0) + { + s += un.sysname; + // s += " : "; s += un.nodename; // we don't want to show name of computer + s += " : "; s += un.release; + s += " : "; s += un.version; + s += " : "; s += un.machine; + + #ifdef __APPLE__ + // Add_sysctlbyname_to_String("kern.version", s); + // it's same as "utsname.version" + #endif + } + #endif // _WIN32 + + sRes += s; + sRes.Add_LF(); + } + + { + AString s, s1, s2; + GetSysInfo(s1, s2); + if (!s1.IsEmpty() || !s2.IsEmpty()) + { + s = s1; + if (s1 != s2 && !s2.IsEmpty()) + { + s += " - "; + s += s2; + } + } + { + AddCpuFeatures(s); + if (!s.IsEmpty()) + { + sRes += s; + sRes.Add_LF(); + } + } + } + { + AString s; + GetCpuName(s); + if (!s.IsEmpty()) + { + sRes += s; + sRes.Add_LF(); + } + } + /* + #ifdef MY_CPU_X86_OR_AMD64 + { + AString s; + x86cpuid_all_to_String(s); + if (!s.IsEmpty()) + { + printCallback->Print(s); + printCallback->NewLine(); + } + } + #endif + */ + } +} diff --git a/CPP/Windows/SystemInfo.h b/CPP/Windows/SystemInfo.h new file mode 100644 index 00000000..856bb2ba --- /dev/null +++ b/CPP/Windows/SystemInfo.h @@ -0,0 +1,12 @@ +// Windows/SystemInfo.h + +#ifndef __WINDOWS_SYSTEM_INFO_H +#define __WINDOWS_SYSTEM_INFO_H + +#include "../Common/MyString.h" + +void GetSystemInfoText(AString &s); +void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v); +void Add_LargePages_String(AString &s); + +#endif diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h index 16a509d4..c9571469 100644 --- a/CPP/Windows/Thread.h +++ b/CPP/Windows/Thread.h @@ -9,7 +9,7 @@ namespace NWindows { -class CThread +class CThread MY_UNCOPYABLE { ::CThread thread; public: @@ -17,9 +17,15 @@ public: ~CThread() { Close(); } bool IsCreated() { return Thread_WasCreated(&thread) != 0; } WRes Close() { return Thread_Close(&thread); } - WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter) - { return Thread_Create(&thread, startAddress, parameter); } - WRes Wait() { return Thread_Wait(&thread); } + // WRes Wait() { return Thread_Wait(&thread); } + WRes Wait_Close() { return Thread_Wait_Close(&thread); } + + WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID param) + { return Thread_Create(&thread, startAddress, param); } + WRes Create_With_Affinity(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID param, CAffinityMask affinity) + { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); } + WRes Create_With_CpuSet(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID param, const CCpuSet *cpuSet) + { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); } #ifdef _WIN32 operator HANDLE() { return thread; } diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp index d288f121..1f1335f9 100644 --- a/CPP/Windows/TimeUtils.cpp +++ b/CPP/Windows/TimeUtils.cpp @@ -2,6 +2,10 @@ #include "StdAfx.h" +#ifndef _WIN32 +#include <sys/time.h> +#endif + #include "Defs.h" #include "TimeUtils.h" @@ -10,7 +14,9 @@ namespace NTime { static const UInt32 kNumTimeQuantumsInSecond = 10000000; static const UInt32 kFileTimeStartYear = 1601; +#if !defined(_WIN32) || defined(UNDER_CE) static const UInt32 kDosTimeStartYear = 1980; +#endif static const UInt32 kUnixTimeStartYear = 1970; static const UInt64 kUnixTimeOffset = (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear)); @@ -37,10 +43,6 @@ bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw() static const UInt32 kHighDosTime = 0xFF9FBF7D; static const UInt32 kLowDosTime = 0x210000; -#define PERIOD_4 (4 * 365 + 1) -#define PERIOD_100 (PERIOD_4 * 25 - 1) -#define PERIOD_400 (PERIOD_100 * 4 + 1) - bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw() { #if defined(_WIN32) && !defined(UNDER_CE) @@ -55,6 +57,10 @@ bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw() #else +#define PERIOD_4 (4 * 365 + 1) +#define PERIOD_100 (PERIOD_4 * 25 - 1) +#define PERIOD_400 (PERIOD_100 * 4 + 1) + unsigned year, mon, day, hour, min, sec; UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32); Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; @@ -129,7 +135,7 @@ void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw() UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw() { - return (UInt64)(kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; + return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond; } bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw() @@ -200,6 +206,7 @@ void GetCurUtcFileTime(FILETIME &ft) throw() { // Both variants provide same low resolution on WinXP: about 15 ms. // But GetSystemTimeAsFileTime is much faster. + #ifdef _WIN32 #ifdef UNDER_CE SYSTEMTIME st; @@ -208,6 +215,20 @@ void GetCurUtcFileTime(FILETIME &ft) throw() #else GetSystemTimeAsFileTime(&ft); #endif + + #else + + UInt64 v = 0; + struct timeval now; + if (gettimeofday(&now, 0 ) == 0) + { + v = ((UInt64)now.tv_sec + kUnixTimeOffset) * + kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10; + } + ft.dwLowDateTime = (DWORD)v; + ft.dwHighDateTime = (DWORD)(v >> 32); + + #endif } }} diff --git a/CPP/Windows/Window.cpp b/CPP/Windows/Window.cpp index 36585022..32af4aab 100644 --- a/CPP/Windows/Window.cpp +++ b/CPP/Windows/Window.cpp @@ -114,12 +114,12 @@ bool MySetWindowText(HWND wnd, LPCWSTR s) bool CWindow::GetText(CSysString &s) { s.Empty(); - int len = GetTextLength(); + unsigned len = (unsigned)GetTextLength(); if (len == 0) return (::GetLastError() == ERROR_SUCCESS); TCHAR *p = s.GetBuf(len); { - int len2 = GetText(p, len + 1); + unsigned len2 = (unsigned)GetText(p, (int)(len + 1)); if (len > len2) len = len2; } @@ -135,12 +135,12 @@ bool CWindow::GetText(UString &s) if (g_IsNT) { s.Empty(); - int len = GetWindowTextLengthW(_window); + unsigned len = (unsigned)GetWindowTextLengthW(_window); if (len == 0) return (::GetLastError() == ERROR_SUCCESS); wchar_t *p = s.GetBuf(len); { - int len2 = GetWindowTextW(_window, p, len + 1); + unsigned len2 = (unsigned)GetWindowTextW(_window, p, (int)(len + 1)); if (len > len2) len = len2; } diff --git a/CPP/Windows/Window.h b/CPP/Windows/Window.h index 3bda6795..83726c7a 100644 --- a/CPP/Windows/Window.h +++ b/CPP/Windows/Window.h @@ -171,7 +171,7 @@ public: bool Update() { return BOOLToBool(::UpdateWindow(_window)); } bool InvalidateRect(LPCRECT rect, bool backgroundErase = true) { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); } - void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, BoolToBOOL(redraw), 0); } + void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, (WPARAM)BoolToBOOL(redraw), 0); } LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); } LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); } @@ -244,7 +244,7 @@ public: int GetTextLength() const { return GetWindowTextLength(_window); } - UINT GetText(LPTSTR string, int maxCount) const + int GetText(LPTSTR string, int maxCount) const { return GetWindowText(_window, string, maxCount); } bool GetText(CSysString &s); #ifndef _UNICODE |