stefan pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=45cabae42b766a9c5df1f577ca251d04f90bbdff

commit 45cabae42b766a9c5df1f577ca251d04f90bbdff
Author: Vincent Torri <vincent.to...@gmail.com>
Date:   Mon Aug 31 11:55:09 2020 +0000

    ecore-file: fix ecore_file_can_exec() on Windows
    
    on Windows access() has no support of X_OK (see 
https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=vs-2019),
 use SHGetFileInfo() instead
    
    Reviewed-by: João Paulo Taylor Ienczak Zanette 
<joao....@expertisesolutions.com.br>
    Reviewed-by: Stefan Schmidt <ste...@datenfreihafen.org>
    Differential Revision: https://phab.enlightenment.org/D12118
---
 src/lib/ecore_file/ecore_file.c | 88 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 87 insertions(+), 1 deletion(-)

diff --git a/src/lib/ecore_file/ecore_file.c b/src/lib/ecore_file/ecore_file.c
index ab8b07f1ce..528de6a97a 100644
--- a/src/lib/ecore_file/ecore_file.c
+++ b/src/lib/ecore_file/ecore_file.c
@@ -622,8 +622,94 @@ ecore_file_can_write(const char *file)
 EAPI Eina_Bool
 ecore_file_can_exec(const char *file)
 {
-   if (!file) return EINA_FALSE;
+#ifdef _WIN32
+   HANDLE h;
+   HANDLE fm;
+   char *base;
+   char *base_nt;
+   LARGE_INTEGER sz;
+   WORD characteristics;
+#endif
+
+   if (!file || !*file) return EINA_FALSE;
+
+#ifdef _WIN32
+   /*
+    * we parse the file to check if it is a PE file (EXE or DLL)
+    * and we finally check whether it's a DLL or not.
+    * Reference :
+    * https://docs.microsoft.com/en-us/windows/win32/debug/pe-format
+    */
+   h = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL,
+                  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
+   if (h == INVALID_HANDLE_VALUE)
+     return EINA_FALSE;
+
+   if (!GetFileSizeEx(h, &sz))
+     goto close_h;
+
+   /* a PE file must have at least the DOS and NT headers */
+   if (sz.QuadPart < (LONGLONG)(sizeof(IMAGE_DOS_HEADER) + 
sizeof(IMAGE_NT_HEADERS)))
+     goto close_h;
+
+   fm = CreateFileMapping(h, NULL, PAGE_READONLY, 0, 0, NULL);
+   if (fm == NULL)
+     goto close_h;
+
+   base = (char *)MapViewOfFile(fm, FILE_MAP_READ, 0, 0, 0);
+   CloseHandle(fm);
+   if (base == NULL)
+     goto close_h;
+
+   /*
+    * the PE file begins with the DOS header.
+    * First magic number : the DOS header must begin with a DOS magic number,
+    * that is "MZ", that is 0x5a4d, stored in a WORD.
+    */
+   if (*((WORD *)base) != 0x5a4d)
+     goto unmap_view;
+
+   /*
+    * The position of the NT header is located at the offset 0x3c.
+    */
+   base_nt = base + *((DWORD *)(base + 0x3c));
+   /*
+    * The NT header begins with the magic number "PE\0\0", that is
+    * 0x00004550, stored in a DWORD.
+    */
+   if (*((DWORD *)base_nt) != 0x00004550)
+     goto unmap_view;
+
+   /*
+    * to get informations about executable (EXE or DLL), we look at
+    * the 'Characteristics' member of the NT header, located at the offset
+    * 22 (4 for the magic number, 18 for the offset) from base_nt.
+    * 
https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#characteristics
+    */
+   characteristics = *((WORD *)(base_nt + 4 + 18));
+
+   UnmapViewOfFile(base);
+   CloseHandle(h);
+
+   /*
+    * 0x0002 : if set, EXE or DLL
+    * 0x2000 : if set, DLL
+    */
+   if ((characteristics & 0x0002) && !(characteristics & 0x2000))
+     return EINA_TRUE;
+
+   /*
+    * a .bat file, considered as an executable, is only a text file,
+    * so we rely on the extension. Not the best but we cannot do more.
+    */
+   return eina_str_has_extension(file, ".bat");
+ unmap_view:
+   UnmapViewOfFile(base);
+ close_h:
+   CloseHandle(h);
+#else
    if (!access(file, X_OK)) return EINA_TRUE;
+#endif
    return EINA_FALSE;
 }
 

-- 


Reply via email to