From 482a19a11fe0f7ac42145da725d414571b40a41c Mon Sep 17 00:00:00 2001 From: Ali Azam Rana <85216275+alirana01@users.noreply.github.com> Date: Thu, 16 May 2024 08:15:42 +0200 Subject: [PATCH] IEP-1226: added filter for python3 in dialog (#947) * added filter for python3 in dialog * python filter updated for dialog * support for identifying reparse points in windows --- .../META-INF/MANIFEST.MF | 4 +- .../idf/core/SystemExecutableFinder.java | 15 +- .../com/espressif/idf/core/util/IDFUtil.java | 12 ++ .../core/util/WinNativeFileTagOperations.java | 138 ++++++++++++++++++ .../idf/ui/install/IDFDownloadPage.java | 11 +- 5 files changed, 172 insertions(+), 8 deletions(-) create mode 100644 bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/WinNativeFileTagOperations.java diff --git a/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF b/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF index e1b036d40..b9e4f070e 100644 --- a/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF +++ b/bundles/com.espressif.idf.core/META-INF/MANIFEST.MF @@ -26,7 +26,9 @@ Require-Bundle: org.eclipse.core.runtime, org.eclipse.jface, org.apache.commons.logging;bundle-version="1.2.0", org.eclipse.core.variables, - org.eclipse.embedcdt.core;visibility:=reexport + org.eclipse.embedcdt.core;visibility:=reexport, + com.sun.jna, + com.sun.jna.platform Bundle-RequiredExecutionEnvironment: JavaSE-17 Automatic-Module-Name: com.espressif.idf.core Bundle-ActivationPolicy: lazy diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemExecutableFinder.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemExecutableFinder.java index 9d927c859..4222a8277 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemExecutableFinder.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/SystemExecutableFinder.java @@ -12,7 +12,9 @@ import org.eclipse.core.runtime.Platform; import com.espressif.idf.core.logging.Logger; +import com.espressif.idf.core.util.IDFUtil; import com.espressif.idf.core.util.StringUtil; +import com.espressif.idf.core.util.WinNativeFileTagOperations; public class SystemExecutableFinder implements ExecutableFinder { @@ -109,8 +111,17 @@ protected boolean isPlatformWindows() private boolean isExecutable(IPath path) { File file = path.toFile(); - - if (file == null || !file.exists() || file.isDirectory()) + + if (isPlatformWindows() && !file.exists()) + { + if (WinNativeFileTagOperations.fileExists(file)) + { + return IDFUtil.isReparseTag(file); + } + } + + + if (!file.exists() || file.isDirectory()) { return false; } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java index 9db7668eb..da800ff1f 100644 --- a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/IDFUtil.java @@ -735,4 +735,16 @@ public static String getGitExecutablePathFromSystem() } return StringUtil.EMPTY; } + + public static boolean isReparseTag(File file) + { + if (!Platform.getOS().equals(Platform.OS_WIN32)) + return false; + int reparseTag = WinNativeFileTagOperations.getReparseTag(file.getAbsolutePath()); + if (reparseTag != -1) + { + return WinNativeFileTagOperations.isReparseTagMicrosoft(reparseTag); + } + return false; + } } diff --git a/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/WinNativeFileTagOperations.java b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/WinNativeFileTagOperations.java new file mode 100644 index 000000000..ddaf32d85 --- /dev/null +++ b/bundles/com.espressif.idf.core/src/com/espressif/idf/core/util/WinNativeFileTagOperations.java @@ -0,0 +1,138 @@ +/******************************************************************************* + * Copyright 2024 Espressif Systems (Shanghai) PTE LTD. All rights reserved. + * Use is subject to license terms. + *******************************************************************************/ +package com.espressif.idf.core.util; + +import java.io.File; + +import com.espressif.idf.core.logging.Logger; +import com.sun.jna.Native; +import com.sun.jna.Pointer; +import com.sun.jna.Structure; +import com.sun.jna.platform.win32.WinBase; +import com.sun.jna.platform.win32.WinDef; +import com.sun.jna.platform.win32.WinNT; +import com.sun.jna.win32.W32APIOptions; + +/** + * Win32 native api class to use because of reparse tags. This is only meant for windows. + * + * @author Ali Azam Rana + * + */ +public class WinNativeFileTagOperations +{ + private static final int MICROSOFT_REPARSE_TAG_BIT = 0x80000000; + + @Structure.FieldOrder({ "dwFileAttributes", "ftCreationTime", "ftLastAccessTime", "ftLastWriteTime", + "nFileSizeHigh", "nFileSizeLow", "dwReserved0", "dwReserved1", "cFileName", "cAlternateFileName" }) + public static class WIN32_FIND_DATA extends Structure + { + public WinDef.DWORD dwFileAttributes; + public WinBase.FILETIME ftCreationTime; + public WinBase.FILETIME ftLastAccessTime; + public WinBase.FILETIME ftLastWriteTime; + public WinDef.DWORD nFileSizeHigh; + public WinDef.DWORD nFileSizeLow; + public WinDef.DWORD dwReserved0; + public WinDef.DWORD dwReserved1; + public byte[] cFileName = new byte[WinDef.MAX_PATH]; + public byte[] cAlternateFileName = new byte[14]; + + public WIN32_FIND_DATA() + { + super(); + } + + public WIN32_FIND_DATA(Pointer memory) + { + super(memory); + read(); + } + } + + public interface Kernel32 extends com.sun.jna.platform.win32.Kernel32 + { + Kernel32 INSTANCE = Native.load("kernel32", Kernel32.class, W32APIOptions.DEFAULT_OPTIONS); //$NON-NLS-1$ + + WinNT.HANDLE FindFirstFile(String lpFileName, + com.espressif.idf.core.util.WinNativeFileTagOperations.WIN32_FIND_DATA findFileData); + + boolean FindClose(WinNT.HANDLE hFindFile); + } + + public static int getReparseTag(String filePath) + { + WIN32_FIND_DATA findFileData = new WIN32_FIND_DATA(); + WinNT.HANDLE hFind = Kernel32.INSTANCE.FindFirstFile(filePath, findFileData); + + if (WinBase.INVALID_HANDLE_VALUE.equals(hFind)) + { + Logger.log("FindFirstFile failed: " + Native.getLastError()); //$NON-NLS-1$ + } + + try + { + if ((findFileData.dwFileAttributes.intValue() & WinNT.FILE_ATTRIBUTE_REPARSE_POINT) != 0) + { + int reparseTag = findFileData.dwReserved0.intValue(); + Logger.log("The file has a reparse point. Reparse Tag: 0x" + Integer.toHexString(reparseTag)); //$NON-NLS-1$ + return reparseTag; + } + else + { + Logger.log("The file does not have a reparse point."); //$NON-NLS-1$ + } + } finally + { + Kernel32.INSTANCE.FindClose(hFind); + } + return -1; + } + + public static boolean isReparseTagMicrosoft(int tag) + { + return (tag & MICROSOFT_REPARSE_TAG_BIT) != 0; + } + + public static boolean fileExists(File file) + { + String filePath = file.getAbsolutePath(); + WIN32_FIND_DATA findFileData = new WIN32_FIND_DATA(); + WinNT.HANDLE hFind = Kernel32.INSTANCE.FindFirstFile(filePath, findFileData); + + if (WinBase.INVALID_HANDLE_VALUE.equals(hFind)) + { + // File does not exist + return false; + } + else + { + // File exists + Kernel32.INSTANCE.FindClose(hFind); + return true; + } + } + + public static boolean isDirectory(String filePath) + { + WIN32_FIND_DATA findFileData = new WIN32_FIND_DATA(); + WinNT.HANDLE hFind = Kernel32.INSTANCE.FindFirstFile(filePath, findFileData); + + if (WinBase.INVALID_HANDLE_VALUE.equals(hFind)) + { + Logger.log("FindFirstFile failed: " + Native.getLastError()); //$NON-NLS-1$ + return false; + } + + try + { + return (findFileData.dwFileAttributes.intValue() & WinNT.FILE_ATTRIBUTE_DIRECTORY) != 0; + } finally + { + Kernel32.INSTANCE.FindClose(hFind); + } + } + +} diff --git a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFDownloadPage.java b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFDownloadPage.java index 7dcb1b8c3..a6bf8b5f4 100644 --- a/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFDownloadPage.java +++ b/bundles/com.espressif.idf.ui/src/com/espressif/idf/ui/install/IDFDownloadPage.java @@ -349,7 +349,7 @@ private boolean validateGitAndPython() gitExecutablePath = pathGit.toOSString(); File file = new File(gitExecutablePath); - if (!file.exists()) + if (!file.exists() && !IDFUtil.isReparseTag(file)) { setErrorMessage("Git executable not found"); return false; @@ -361,7 +361,7 @@ private boolean validateGitAndPython() pythonExecutablePath = pythonPath.toOSString(); } file = new File(pythonExecutablePath); - if (!file.exists()) + if (!file.exists() && !IDFUtil.isReparseTag(file)) { setErrorMessage("Python executable not found"); return false; @@ -510,7 +510,8 @@ private class BrowseButtonSelectionAdapter extends SelectionAdapter private Text linkedText; private int dialog; private static final String GIT_FILE = "git"; //$NON-NLS-1$ - private static final String PYTHON_FILE = "python"; //$NON-NLS-1$ + private static final String PYTHON_FILE = "python*"; //$NON-NLS-1$ + private static final String PYTHON_FILTERS = "Python Executables"; //$NON-NLS-1$ private static final String WINDOWS_EXTENSION = ".exe"; //$NON-NLS-1$ private BrowseButtonSelectionAdapter(Text text, int dialog) @@ -545,12 +546,12 @@ private FileDialog pythonDialog() FileDialog dialog = new FileDialog(PlatformUI.getWorkbench().getDisplay().getActiveShell()); if (Platform.getOS().equals(Platform.OS_WIN32)) { - dialog.setFilterNames(new String[] { PYTHON_FILE.concat(WINDOWS_EXTENSION) }); + dialog.setFilterNames(new String[] { PYTHON_FILTERS }); dialog.setFilterExtensions(new String[] { PYTHON_FILE.concat(WINDOWS_EXTENSION) }); } else { - dialog.setFilterNames(new String[] { PYTHON_FILE }); + dialog.setFilterNames(new String[] { PYTHON_FILTERS }); dialog.setFilterExtensions(new String[] { PYTHON_FILE }); } return dialog;