├── .gitattributes ├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .gitmodules ├── README.md ├── Sshfs ├── FSTester │ ├── App.config │ ├── FSTester.csproj │ ├── Lowlevel.cs │ ├── Program.cs │ ├── Properties │ │ └── AssemblyInfo.cs │ ├── Test.cs │ └── Tests │ │ ├── IO │ │ └── TestWriteLines.cs │ │ └── Others │ │ └── BackupAndShared.cs ├── Sshfs.sln ├── Sshfs │ ├── AboutForm.Designer.cs │ ├── AboutForm.cs │ ├── AboutForm.resx │ ├── ConnectionType.cs │ ├── ContextMenuStripThemedRenderer.cs │ ├── DriveStatus.cs │ ├── MainForm.Designer.cs │ ├── MainForm.cs │ ├── MainForm.resx │ ├── Program.cs │ ├── Properties │ │ ├── AssemblyInfo.cs │ │ ├── Resources.Designer.cs │ │ ├── Resources.resx │ │ ├── Settings.Designer.cs │ │ └── Settings.settings │ ├── Resources │ │ ├── accessories-text-editor.png │ │ ├── add.png │ │ ├── go-jump.png │ │ ├── remove.png │ │ └── undo.png │ ├── SftpContext.cs │ ├── SftpContextStream.cs │ ├── SftpDrive.cs │ ├── SftpFilesystem.cs │ ├── SftpManagerApplication.cs │ ├── Sshfs.csproj │ ├── Utilities.cs │ ├── VirtualDrive.cs │ ├── VirtualFilesystem.cs │ ├── WinSSH4e1-public.snk │ ├── app.config │ ├── app.ico │ ├── app.manifest │ ├── packages.config │ └── ssh.ico ├── WinSSHFS-setup │ ├── Product.wxs │ └── WinSshFs Installer.wixproj ├── appveyor.yml └── showPublicKeyFile.bat ├── TODO ├── license ├── license2 ├── post-commit ├── runversionhook.bat └── version.hook.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | #* text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | For issues and bugs please complete maximum information you now in template below. 2 | 3 | Fot other types of requests you can remove any section. 4 | 5 | If you have tested more versions, fill them all. 6 | 7 | Fill instructions: move 'x' in checkboxes and fill parts marked <...>. 8 | 9 | NOW REMOVE THIS LINE OF TEXT AND THE PREVIOUS CONTENT. 10 | ### Technical data 11 | 12 | #### WinSshFS 13 | - [x] stable 14 | - [ ] prerelease 15 | - [ ] custom build 16 | - Version: <1.b.c.d> 17 | 18 | #### Dokan driver 19 | - [x] stable 20 | - [ ] prerelease 21 | - [ ] custom build 22 | - Version: Dokany <1.b.c.d> 23 | 24 | #### Enviroment 25 | - Windows version: <10> 26 | - Architecture: 27 | - Related software: 28 | 29 | #### Support 30 | - Usage: - 31 | - Your personal priority to solve this issue: 32 | - Support ability: 33 | 34 | ------------------------------------------------ 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | bin 3 | obj 4 | *.suo 5 | *.user 6 | _ReSharper* 7 | # mstest test results 8 | TestResults 9 | /sharpshell 10 | 11 | /Sshfs/Sshfs/publish 12 | /FreeTDS-0.91.98-x86.zip 13 | /README.zip 14 | /Dokan 15 | /bluescreenview 16 | /Sshfs/Sshfs/Properties/AssemblyInfo.cs.bak 17 | /Sshfs/.nuget 18 | /Sshfs/Packages.dgml 19 | /Sshfs/packages 20 | *.prev -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "SSH.NET"] 2 | path = SSH.NET 3 | url = https://github.com/Foreveryone-cz/SSH.NET-for-winsshfs.git 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build status](https://ci.appveyor.com/api/projects/status/bhqp9ib4bkv951w4?svg=true)](https://ci.appveyor.com/project/dimov-cz/win-sshfs) 2 | | 3 | [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=winsshfs%40gmail%2ecom&lc=GB&item_name=WinSSHFS%20support%20donation&item_number=WinSSHFS¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donate_SM%2egif%3aNonHosted) 4 | [![Donate](https://img.shields.io/badge/donate-bitcoin-green.svg)](https://foreveryone-cz.github.io/WinSshFS/donate-bitcoin/) 5 | | 6 | [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/Foreveryone-cz/win-sshfs.svg)](http://isitmaintained.com/project/Foreveryone-cz/win-sshfs "Average time to resolve an issue") 7 | [![Percentage of issues still open](http://isitmaintained.com/badge/open/Foreveryone-cz/win-sshfs.svg)](http://isitmaintained.com/project/Foreveryone-cz/win-sshfs "Percentage of issues still open") 8 | WinSshFS Foreveryone 9 | ======================== 10 | 11 | Download [latest release here](https://github.com/Foreveryone-cz/win-sshfs/releases). 12 | 13 | Main features: 14 | * Windows 10 Support 15 | * Puttyant (Pageant) support 16 | * Support for Android hosts (tested with CyanogenMod 11 [Android 4.4], requires busybox to be installed) 17 | * Spooldrive - remote hosts can by mounted as directories on same virtual drive 18 | * archive flag of file in windows represents and controls permission for group: 19 | * ON => group have same rights as owner 20 | * OFF => same rights as others) 21 | * Ability to use Proxy for connections 22 | * Send Keepalive packets. (Not configurable, each 60sec hardcoded) 23 | 24 | ![img](https://cloud.githubusercontent.com/assets/1085397/10747956/3f684d3a-7c18-11e5-8ca6-0f37a60426e4.jpg "UI") 25 | 26 | Development version: 27 | [![Build status](https://ci.appveyor.com/api/projects/status/bhqp9ib4bkv951w4/branch/devel?svg=true)](https://ci.appveyor.com/project/dimov-cz/win-sshfs/branch/devel) 28 | -------------------------------------------------------------------------------- /Sshfs/FSTester/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Sshfs/FSTester/FSTester.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B} 8 | Exe 9 | Properties 10 | FSTester 11 | FSTester 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | AnyCPU 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 65 | -------------------------------------------------------------------------------- /Sshfs/FSTester/Lowlevel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace FSTester 10 | { 11 | class Lowlevel 12 | { 13 | 14 | public enum FileAttributesEx 15 | { 16 | FILE_FLAG_BACKUP_SEMANTICS = 0x02000000 17 | } 18 | 19 | [StructLayout(LayoutKind.Sequential)] 20 | public struct FILETIME 21 | { 22 | public uint dwLowDateTime; 23 | public uint dwHighDateTime; 24 | } 25 | 26 | [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] 27 | public static extern IntPtr CreateFile( 28 | [MarshalAs(UnmanagedType.LPTStr)] string filename, 29 | [MarshalAs(UnmanagedType.U4)] FileAccess access, 30 | [MarshalAs(UnmanagedType.U4)] FileShare share, 31 | IntPtr securityAttributes, // optional SECURITY_ATTRIBUTES struct or IntPtr.Zero 32 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 33 | [MarshalAs(UnmanagedType.U4)] FileAttributesEx flagsAndAttributes, 34 | IntPtr templateFile); 35 | 36 | [DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)] 37 | public static extern IntPtr CreateFileA( 38 | [MarshalAs(UnmanagedType.LPStr)] string filename, 39 | [MarshalAs(UnmanagedType.U4)] FileAccess access, 40 | [MarshalAs(UnmanagedType.U4)] FileShare share, 41 | IntPtr securityAttributes, 42 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 43 | [MarshalAs(UnmanagedType.U4)] FileAttributesEx flagsAndAttributes, 44 | IntPtr templateFile); 45 | 46 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 47 | public static extern IntPtr CreateFileW( 48 | [MarshalAs(UnmanagedType.LPWStr)] string filename, 49 | [MarshalAs(UnmanagedType.U4)] FileAccess access, 50 | [MarshalAs(UnmanagedType.U4)] FileShare share, 51 | IntPtr securityAttributes, 52 | [MarshalAs(UnmanagedType.U4)] FileMode creationDisposition, 53 | [MarshalAs(UnmanagedType.U4)] FileAttributesEx flagsAndAttributes, 54 | IntPtr templateFile); 55 | 56 | 57 | [DllImport("kernel32.dll")] 58 | public static extern bool GetFileTime(IntPtr hFile, ref FILETIME lpCreationTime, 59 | ref FILETIME lpLastAccessTime, ref FILETIME lpLastWriteTime); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Sshfs/FSTester/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Collections.ObjectModel; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FSTester 9 | { 10 | class Program 11 | { 12 | 13 | static void Main(string[] args) 14 | { 15 | if (args.Length == 0) 16 | { 17 | Console.WriteLine("You need help. right?"); 18 | return; 19 | } 20 | else 21 | { 22 | string workingPath = args[0]; 23 | 24 | Collection tests = new Collection(); 25 | tests.Add(new Tests.IO.TestWriteLines(workingPath)); 26 | tests.Add(new Tests.Others.BackupAndShared(workingPath)); 27 | 28 | foreach (Test test in tests) 29 | { 30 | Console.Write("Test " + test.ToString() + ": "); 31 | if (test.Go()) 32 | { 33 | Console.WriteLine("Success"); 34 | } 35 | else 36 | { 37 | Console.Write("Fail"); 38 | Console.WriteLine(" >>> " + test.getLastError()); 39 | } 40 | 41 | } 42 | } 43 | 44 | Console.ReadKey(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sshfs/FSTester/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FSTester")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("FSTester")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("1b5533b8-dfcd-4f19-9eab-438633e7c00b")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Sshfs/FSTester/Test.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace FSTester 9 | { 10 | public class Test 11 | { 12 | protected string workingPath; 13 | protected string lastError; 14 | 15 | public Test(string workPath) 16 | { 17 | this.workingPath = workPath; 18 | } 19 | 20 | virtual public bool Go() 21 | { 22 | if (!Directory.Exists(this.workingPath)) 23 | { 24 | this.lastError = "Working dir not found('" + this.workingPath + "')"; 25 | return false; 26 | } 27 | return true; 28 | } 29 | 30 | public string getLastError() 31 | { 32 | return this.lastError; 33 | } 34 | 35 | protected void Log(string s) 36 | { 37 | Console.Write(s); 38 | } 39 | protected void LogLine(string line) 40 | { 41 | Console.WriteLine( line ); 42 | } 43 | 44 | protected string getUniqueTempBasename( string suffix = "tmp" ) 45 | { 46 | return Guid.NewGuid().ToString() + "." + suffix; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sshfs/FSTester/Tests/IO/TestWriteLines.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | 8 | namespace FSTester.Tests.IO 9 | { 10 | public class TestWriteLines : Test 11 | { 12 | public TestWriteLines(string workPath) : base(workPath) {} 13 | 14 | override public bool Go() 15 | { 16 | if (!base.Go()) 17 | { 18 | return false; 19 | } 20 | 21 | string tmp = this.getUniqueTempBasename(); 22 | 23 | FileStream f = File.Open(this.workingPath + " \\ " + tmp, FileMode.OpenOrCreate); 24 | string s = "ABCD" + "\n"; 25 | byte[] sb = ASCIIEncoding.UTF8.GetBytes(s); 26 | f.Write(sb, 0, sb.Length); 27 | f.Seek(1, SeekOrigin.Begin); 28 | f.Write(sb, 0, sb.Length); 29 | 30 | f.Flush(); 31 | f.Seek(0, SeekOrigin.Begin); 32 | byte[] data = new byte[4096]; 33 | int received = f.Read(data, 0, data.Length); 34 | string ret = ASCIIEncoding.UTF8.GetString(data, 0, received); 35 | 36 | if (ret == "A" + s) 37 | { 38 | return true; 39 | } 40 | 41 | this.lastError = "Got "+ret+", waited for "+ "A"+s; 42 | return false; 43 | } 44 | 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Sshfs/FSTester/Tests/Others/BackupAndShared.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using System.IO; 7 | using FSTester; 8 | 9 | namespace FSTester.Tests.Others 10 | { 11 | public class BackupAndShared : Test 12 | { 13 | 14 | public BackupAndShared(string workPath) : base(workPath) { } 15 | 16 | override public bool Go() 17 | { 18 | if (!base.Go()) 19 | { 20 | return false; 21 | } 22 | try { 23 | string path = this.workingPath + "\\" + this.getUniqueTempBasename(); 24 | 25 | Directory.CreateDirectory(path); 26 | 27 | IntPtr tmp1 = Lowlevel.CreateFile(path, FileAccess.Read, FileShare.None, IntPtr.Zero, FileMode.Open, Lowlevel.FileAttributesEx.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero); 28 | if ( (int)tmp1 <= 0) 29 | { 30 | throw new Exception("Cannot get tmp1?"); 31 | } 32 | Lowlevel.FILETIME t1 = new Lowlevel.FILETIME(); 33 | Lowlevel.FILETIME t2 = new Lowlevel.FILETIME(); 34 | Lowlevel.FILETIME t3 = new Lowlevel.FILETIME(); 35 | bool r1 = Lowlevel.GetFileTime(tmp1, ref t1, ref t2, ref t3); 36 | 37 | IntPtr tmp2 = Lowlevel.CreateFile(path, FileAccess.Read, FileShare.None, IntPtr.Zero, FileMode.Open, Lowlevel.FileAttributesEx.FILE_FLAG_BACKUP_SEMANTICS, IntPtr.Zero); 38 | if ( (int)tmp2 == -1 ) 39 | { 40 | return true; 41 | } 42 | 43 | bool r2 = Lowlevel.GetFileTime(tmp1, ref t1, ref t2, ref t3); 44 | bool r3 = Lowlevel.GetFileTime(tmp2, ref t1, ref t2, ref t3); 45 | 46 | throw new Exception("Failed, I can open second time with shared.none (related to Dokany #98 and Dokan <=1.0.0rc2)"); 47 | 48 | /*HANDLE tmp1 = CreateFile(L"M:\\test", GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 49 | std::cout << GetLastError() << std::endl; 50 | HANDLE tmp2 = CreateFile(L"M:\\test", GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); 51 | std::cout << GetLastError() << std::endl; 52 | CloseHandle(tmp1); 53 | CloseHandle(tmp2);*/ 54 | } 55 | catch(Exception ex) 56 | { 57 | this.lastError = ex.Message; 58 | } 59 | 60 | return false; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Sshfs/Sshfs.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sshfs", "Sshfs\Sshfs.csproj", "{FF4FC8BB-91A3-45FF-8449-650647610394}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FSTester", "FSTester\FSTester.csproj", "{1B5533B8-DFCD-4F19-9EAB-438633E7C00B}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Renci.SshNet", "..\SSH.NET\src\Renci.SshNet\Renci.SshNet.csproj", "{2F5F8C90-0BD1-424F-997C-7BC6280919D1}" 11 | EndProject 12 | Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "WinSshFs Installer", "WinSSHFS-setup\WinSshFs Installer.wixproj", "{9552311D-F6B4-43F6-8859-7C3B41A4311D}" 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Debug|Mixed Platforms = Debug|Mixed Platforms 18 | Debug|x64 = Debug|x64 19 | Debug|x86 = Debug|x86 20 | DebugNoTimeout|Any CPU = DebugNoTimeout|Any CPU 21 | DebugNoTimeout|Mixed Platforms = DebugNoTimeout|Mixed Platforms 22 | DebugNoTimeout|x64 = DebugNoTimeout|x64 23 | DebugNoTimeout|x86 = DebugNoTimeout|x86 24 | Release|Any CPU = Release|Any CPU 25 | Release|Mixed Platforms = Release|Mixed Platforms 26 | Release|x64 = Release|x64 27 | Release|x86 = Release|x86 28 | ReleaseFW2|Any CPU = ReleaseFW2|Any CPU 29 | ReleaseFW2|Mixed Platforms = ReleaseFW2|Mixed Platforms 30 | ReleaseFW2|x64 = ReleaseFW2|x64 31 | ReleaseFW2|x86 = ReleaseFW2|x86 32 | EndGlobalSection 33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 34 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|Any CPU.ActiveCfg = Debug|x86 35 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|Any CPU.Build.0 = Debug|x86 36 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 37 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|Mixed Platforms.Build.0 = Debug|x86 38 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|x64.ActiveCfg = Debug|x64 39 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|x64.Build.0 = Debug|x64 40 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|x86.ActiveCfg = Debug|x86 41 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Debug|x86.Build.0 = Debug|x86 42 | {FF4FC8BB-91A3-45FF-8449-650647610394}.DebugNoTimeout|Any CPU.ActiveCfg = Debug|x86 43 | {FF4FC8BB-91A3-45FF-8449-650647610394}.DebugNoTimeout|Mixed Platforms.ActiveCfg = Debug|x86 44 | {FF4FC8BB-91A3-45FF-8449-650647610394}.DebugNoTimeout|Mixed Platforms.Build.0 = Debug|x86 45 | {FF4FC8BB-91A3-45FF-8449-650647610394}.DebugNoTimeout|x64.ActiveCfg = Debug|x64 46 | {FF4FC8BB-91A3-45FF-8449-650647610394}.DebugNoTimeout|x64.Build.0 = Debug|x64 47 | {FF4FC8BB-91A3-45FF-8449-650647610394}.DebugNoTimeout|x86.ActiveCfg = Debug|x86 48 | {FF4FC8BB-91A3-45FF-8449-650647610394}.DebugNoTimeout|x86.Build.0 = Debug|x86 49 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Release|Any CPU.ActiveCfg = Release|x86 50 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Release|Mixed Platforms.ActiveCfg = Release|x86 51 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Release|Mixed Platforms.Build.0 = Release|x86 52 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Release|x64.ActiveCfg = Release|x64 53 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Release|x64.Build.0 = Release|x64 54 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Release|x86.ActiveCfg = Release|x86 55 | {FF4FC8BB-91A3-45FF-8449-650647610394}.Release|x86.Build.0 = Release|x86 56 | {FF4FC8BB-91A3-45FF-8449-650647610394}.ReleaseFW2|Any CPU.ActiveCfg = Release|x86 57 | {FF4FC8BB-91A3-45FF-8449-650647610394}.ReleaseFW2|Mixed Platforms.ActiveCfg = Release|x86 58 | {FF4FC8BB-91A3-45FF-8449-650647610394}.ReleaseFW2|Mixed Platforms.Build.0 = Release|x86 59 | {FF4FC8BB-91A3-45FF-8449-650647610394}.ReleaseFW2|x64.ActiveCfg = Release|x64 60 | {FF4FC8BB-91A3-45FF-8449-650647610394}.ReleaseFW2|x64.Build.0 = Release|x64 61 | {FF4FC8BB-91A3-45FF-8449-650647610394}.ReleaseFW2|x86.ActiveCfg = Release|x86 62 | {FF4FC8BB-91A3-45FF-8449-650647610394}.ReleaseFW2|x86.Build.0 = Release|x86 63 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 64 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|Any CPU.Build.0 = Debug|Any CPU 65 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 66 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 67 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|x64.ActiveCfg = Debug|Any CPU 68 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|x64.Build.0 = Debug|Any CPU 69 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|x86.ActiveCfg = Debug|Any CPU 70 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Debug|x86.Build.0 = Debug|Any CPU 71 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|Any CPU.ActiveCfg = Debug|Any CPU 72 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|Any CPU.Build.0 = Debug|Any CPU 73 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|Mixed Platforms.ActiveCfg = Debug|Any CPU 74 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|Mixed Platforms.Build.0 = Debug|Any CPU 75 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|x64.ActiveCfg = Debug|Any CPU 76 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|x64.Build.0 = Debug|Any CPU 77 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|x86.ActiveCfg = Debug|Any CPU 78 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.DebugNoTimeout|x86.Build.0 = Debug|Any CPU 79 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|Any CPU.ActiveCfg = Release|Any CPU 80 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|Any CPU.Build.0 = Release|Any CPU 81 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 82 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|Mixed Platforms.Build.0 = Release|Any CPU 83 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|x64.ActiveCfg = Release|Any CPU 84 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|x64.Build.0 = Release|Any CPU 85 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|x86.ActiveCfg = Release|Any CPU 86 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.Release|x86.Build.0 = Release|Any CPU 87 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|Any CPU.ActiveCfg = Release|Any CPU 88 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|Any CPU.Build.0 = Release|Any CPU 89 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|Mixed Platforms.ActiveCfg = Release|Any CPU 90 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|Mixed Platforms.Build.0 = Release|Any CPU 91 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|x64.ActiveCfg = Release|Any CPU 92 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|x64.Build.0 = Release|Any CPU 93 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|x86.ActiveCfg = Release|Any CPU 94 | {1B5533B8-DFCD-4F19-9EAB-438633E7C00B}.ReleaseFW2|x86.Build.0 = Release|Any CPU 95 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 96 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Any CPU.Build.0 = Debug|Any CPU 97 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 98 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 99 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.ActiveCfg = Debug|Any CPU 100 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x64.Build.0 = Debug|Any CPU 101 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.ActiveCfg = Debug|Any CPU 102 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Debug|x86.Build.0 = Debug|Any CPU 103 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|Any CPU.ActiveCfg = Debug|Any CPU 104 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|Any CPU.Build.0 = Debug|Any CPU 105 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|Mixed Platforms.ActiveCfg = Debug|Any CPU 106 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|Mixed Platforms.Build.0 = Debug|Any CPU 107 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|x64.ActiveCfg = Debug|Any CPU 108 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|x64.Build.0 = Debug|Any CPU 109 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|x86.ActiveCfg = Debug|Any CPU 110 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.DebugNoTimeout|x86.Build.0 = Debug|Any CPU 111 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.ActiveCfg = Release|Any CPU 112 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Any CPU.Build.0 = Release|Any CPU 113 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 114 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU 115 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.ActiveCfg = Release|Any CPU 116 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x64.Build.0 = Release|Any CPU 117 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.ActiveCfg = Release|Any CPU 118 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.Release|x86.Build.0 = Release|Any CPU 119 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|Any CPU.ActiveCfg = Release|Any CPU 120 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|Any CPU.Build.0 = Release|Any CPU 121 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|Mixed Platforms.ActiveCfg = Release|Any CPU 122 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|Mixed Platforms.Build.0 = Release|Any CPU 123 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|x64.ActiveCfg = Release|Any CPU 124 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|x64.Build.0 = Release|Any CPU 125 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|x86.ActiveCfg = Release|Any CPU 126 | {2F5F8C90-0BD1-424F-997C-7BC6280919D1}.ReleaseFW2|x86.Build.0 = Release|Any CPU 127 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Debug|Any CPU.ActiveCfg = Debug|x86 128 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 129 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Debug|Mixed Platforms.Build.0 = Debug|x86 130 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Debug|x64.ActiveCfg = Debug|x86 131 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Debug|x86.ActiveCfg = Debug|x86 132 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Debug|x86.Build.0 = Debug|x86 133 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|Any CPU.ActiveCfg = Release|x86 134 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|Any CPU.Build.0 = Release|x86 135 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|Mixed Platforms.ActiveCfg = Debug|x86 136 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|Mixed Platforms.Build.0 = Debug|x86 137 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|x64.ActiveCfg = Release|x86 138 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|x64.Build.0 = Release|x86 139 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|x86.ActiveCfg = Debug|x86 140 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.DebugNoTimeout|x86.Build.0 = Debug|x86 141 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Release|Any CPU.ActiveCfg = Release|x86 142 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Release|Mixed Platforms.ActiveCfg = Release|x86 143 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Release|Mixed Platforms.Build.0 = Release|x86 144 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Release|x64.ActiveCfg = Release|x86 145 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Release|x86.ActiveCfg = Release|x86 146 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.Release|x86.Build.0 = Release|x86 147 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|Any CPU.ActiveCfg = Release|x86 148 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|Any CPU.Build.0 = Release|x86 149 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|Mixed Platforms.ActiveCfg = Release|x86 150 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|Mixed Platforms.Build.0 = Release|x86 151 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|x64.ActiveCfg = Release|x86 152 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|x64.Build.0 = Release|x86 153 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|x86.ActiveCfg = Release|x86 154 | {9552311D-F6B4-43F6-8859-7C3B41A4311D}.ReleaseFW2|x86.Build.0 = Release|x86 155 | EndGlobalSection 156 | GlobalSection(SolutionProperties) = preSolution 157 | HideSolutionNode = FALSE 158 | EndGlobalSection 159 | EndGlobal 160 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/AboutForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Sshfs 2 | { 3 | partial class AboutForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AboutForm)); 32 | this.pictureBox1 = new System.Windows.Forms.PictureBox(); 33 | this.groupBox1 = new System.Windows.Forms.GroupBox(); 34 | this.linkLabel4 = new System.Windows.Forms.LinkLabel(); 35 | this.label4 = new System.Windows.Forms.Label(); 36 | this.linkLabel3 = new System.Windows.Forms.LinkLabel(); 37 | this.linkLabel2 = new System.Windows.Forms.LinkLabel(); 38 | this.linkLabel1 = new System.Windows.Forms.LinkLabel(); 39 | this.label3 = new System.Windows.Forms.Label(); 40 | this.label2 = new System.Windows.Forms.Label(); 41 | this.label1 = new System.Windows.Forms.Label(); 42 | this.okButton = new System.Windows.Forms.Button(); 43 | this.panel1 = new System.Windows.Forms.Panel(); 44 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); 45 | this.groupBox1.SuspendLayout(); 46 | this.panel1.SuspendLayout(); 47 | this.SuspendLayout(); 48 | // 49 | // pictureBox1 50 | // 51 | this.pictureBox1.BackColor = System.Drawing.SystemColors.ActiveCaptionText; 52 | this.pictureBox1.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox1.Image"))); 53 | this.pictureBox1.Location = new System.Drawing.Point(9, 3); 54 | this.pictureBox1.Name = "pictureBox1"; 55 | this.pictureBox1.Size = new System.Drawing.Size(264, 141); 56 | this.pictureBox1.SizeMode = System.Windows.Forms.PictureBoxSizeMode.AutoSize; 57 | this.pictureBox1.TabIndex = 1; 58 | this.pictureBox1.TabStop = false; 59 | // 60 | // groupBox1 61 | // 62 | this.groupBox1.Controls.Add(this.linkLabel4); 63 | this.groupBox1.Controls.Add(this.label4); 64 | this.groupBox1.Controls.Add(this.linkLabel3); 65 | this.groupBox1.Controls.Add(this.linkLabel2); 66 | this.groupBox1.Controls.Add(this.linkLabel1); 67 | this.groupBox1.Controls.Add(this.label3); 68 | this.groupBox1.Controls.Add(this.label2); 69 | this.groupBox1.Controls.Add(this.label1); 70 | this.groupBox1.Location = new System.Drawing.Point(12, 163); 71 | this.groupBox1.Name = "groupBox1"; 72 | this.groupBox1.Size = new System.Drawing.Size(261, 102); 73 | this.groupBox1.TabIndex = 2; 74 | this.groupBox1.TabStop = false; 75 | // 76 | // linkLabel4 77 | // 78 | this.linkLabel4.AutoSize = true; 79 | this.linkLabel4.Location = new System.Drawing.Point(97, 70); 80 | this.linkLabel4.Name = "linkLabel4"; 81 | this.linkLabel4.Size = new System.Drawing.Size(111, 13); 82 | this.linkLabel4.TabIndex = 7; 83 | this.linkLabel4.TabStop = true; 84 | this.linkLabel4.Text = "tango.freedesktop.org"; 85 | this.linkLabel4.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel_LinkClicked); 86 | // 87 | // label4 88 | // 89 | this.label4.AutoSize = true; 90 | this.label4.Location = new System.Drawing.Point(7, 70); 91 | this.label4.Name = "label4"; 92 | this.label4.Size = new System.Drawing.Size(33, 13); 93 | this.label4.TabIndex = 6; 94 | this.label4.Text = "Icons"; 95 | // 96 | // linkLabel3 97 | // 98 | this.linkLabel3.AutoSize = true; 99 | this.linkLabel3.Location = new System.Drawing.Point(97, 54); 100 | this.linkLabel3.Name = "linkLabel3"; 101 | this.linkLabel3.Size = new System.Drawing.Size(107, 13); 102 | this.linkLabel3.TabIndex = 5; 103 | this.linkLabel3.TabStop = true; 104 | this.linkLabel3.Text = "sshnet.codeplex.com"; 105 | this.linkLabel3.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel_LinkClicked); 106 | // 107 | // linkLabel2 108 | // 109 | this.linkLabel2.AutoSize = true; 110 | this.linkLabel2.Location = new System.Drawing.Point(97, 36); 111 | this.linkLabel2.Name = "linkLabel2"; 112 | this.linkLabel2.Size = new System.Drawing.Size(119, 13); 113 | this.linkLabel2.TabIndex = 4; 114 | this.linkLabel2.TabStop = true; 115 | this.linkLabel2.Text = "dokan.googlecode.com"; 116 | this.linkLabel2.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel_LinkClicked); 117 | // 118 | // linkLabel1 119 | // 120 | this.linkLabel1.AutoSize = true; 121 | this.linkLabel1.Location = new System.Drawing.Point(97, 20); 122 | this.linkLabel1.Name = "linkLabel1"; 123 | this.linkLabel1.Size = new System.Drawing.Size(132, 13); 124 | this.linkLabel1.TabIndex = 3; 125 | this.linkLabel1.TabStop = true; 126 | this.linkLabel1.Text = "win-sshfs.googlecode.com"; 127 | this.linkLabel1.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel_LinkClicked); 128 | // 129 | // label3 130 | // 131 | this.label3.AutoSize = true; 132 | this.label3.Location = new System.Drawing.Point(7, 54); 133 | this.label3.Name = "label3"; 134 | this.label3.Size = new System.Drawing.Size(35, 13); 135 | this.label3.TabIndex = 2; 136 | this.label3.Text = "label3"; 137 | // 138 | // label2 139 | // 140 | this.label2.AutoSize = true; 141 | this.label2.Location = new System.Drawing.Point(7, 37); 142 | this.label2.Name = "label2"; 143 | this.label2.Size = new System.Drawing.Size(35, 13); 144 | this.label2.TabIndex = 1; 145 | this.label2.Text = "label2"; 146 | // 147 | // label1 148 | // 149 | this.label1.AutoSize = true; 150 | this.label1.Location = new System.Drawing.Point(7, 20); 151 | this.label1.Name = "label1"; 152 | this.label1.Size = new System.Drawing.Size(35, 13); 153 | this.label1.TabIndex = 0; 154 | this.label1.Text = "label1"; 155 | // 156 | // okButton 157 | // 158 | this.okButton.Location = new System.Drawing.Point(95, 278); 159 | this.okButton.Name = "okButton"; 160 | this.okButton.Size = new System.Drawing.Size(100, 26); 161 | this.okButton.TabIndex = 3; 162 | this.okButton.Text = "OK"; 163 | this.okButton.UseVisualStyleBackColor = true; 164 | this.okButton.Click += new System.EventHandler(this.ok_Click); 165 | // 166 | // panel1 167 | // 168 | this.panel1.BackColor = System.Drawing.SystemColors.ControlLightLight; 169 | this.panel1.Controls.Add(this.pictureBox1); 170 | this.panel1.Dock = System.Windows.Forms.DockStyle.Top; 171 | this.panel1.Location = new System.Drawing.Point(0, 0); 172 | this.panel1.Name = "panel1"; 173 | this.panel1.Size = new System.Drawing.Size(284, 157); 174 | this.panel1.TabIndex = 5; 175 | this.panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint); 176 | // 177 | // AboutForm 178 | // 179 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 180 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 181 | this.ClientSize = new System.Drawing.Size(284, 316); 182 | this.ControlBox = false; 183 | this.Controls.Add(this.panel1); 184 | this.Controls.Add(this.okButton); 185 | this.Controls.Add(this.groupBox1); 186 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; 187 | this.Name = "AboutForm"; 188 | this.ShowInTaskbar = false; 189 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 190 | this.Text = "About"; 191 | ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); 192 | this.groupBox1.ResumeLayout(false); 193 | this.groupBox1.PerformLayout(); 194 | this.panel1.ResumeLayout(false); 195 | this.panel1.PerformLayout(); 196 | this.ResumeLayout(false); 197 | 198 | } 199 | 200 | #endregion 201 | 202 | private System.Windows.Forms.PictureBox pictureBox1; 203 | private System.Windows.Forms.GroupBox groupBox1; 204 | private System.Windows.Forms.LinkLabel linkLabel3; 205 | private System.Windows.Forms.LinkLabel linkLabel2; 206 | private System.Windows.Forms.LinkLabel linkLabel1; 207 | private System.Windows.Forms.Label label3; 208 | private System.Windows.Forms.Label label2; 209 | private System.Windows.Forms.Label label1; 210 | private System.Windows.Forms.Button okButton; 211 | private System.Windows.Forms.LinkLabel linkLabel4; 212 | private System.Windows.Forms.Label label4; 213 | private System.Windows.Forms.Panel panel1; 214 | 215 | } 216 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/AboutForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Drawing; 4 | using System.Reflection; 5 | using System.Windows.Forms; 6 | using Renci.SshNet; 7 | 8 | namespace Sshfs 9 | { 10 | public partial class AboutForm : Form 11 | { 12 | private static readonly string _sshfsText = String.Format("Sshfs {0}", Assembly.GetEntryAssembly().GetName().Version); 13 | private static readonly string _dokanText = 14 | (DokanNet.Dokan.Version < 600) 15 | ? String.Format("Dokan {0}.{1}.{2}", DokanNet.Dokan.Version / 100, (DokanNet.Dokan.Version % 100) / 10, DokanNet.Dokan.Version % 10) 16 | : String.Format("Dokan {0}.{1}.{2}.{3}", DokanNet.Dokan.Version / 1000, (DokanNet.Dokan.Version % 1000) / 100, (DokanNet.Dokan.Version % 100) / 10, DokanNet.Dokan.Version % 10); 17 | private static readonly string _sshnetText = String.Format("SSH.NET {0}", Assembly.GetAssembly(typeof (SshClient)).GetName().Version); 18 | 19 | public AboutForm() 20 | { 21 | InitializeComponent(); 22 | label1.Text = _sshfsText; 23 | label2.Text = _dokanText; 24 | label3.Text = _sshnetText; 25 | } 26 | 27 | private void ok_Click(object sender, EventArgs e) 28 | { 29 | this.Close(); 30 | } 31 | 32 | private void linkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 33 | { 34 | Process.Start(String.Format("http:\\{0}", (sender as LinkLabel).Text)); 35 | } 36 | 37 | private void panel1_Paint(object sender, PaintEventArgs e) 38 | { 39 | // ControlPaint.DrawBorder3D(e.Graphics,0,0,panel1.Width,panel1.Height,Border3DStyle.); 40 | e.Graphics.DrawLine(new Pen(SystemColors.ActiveBorder,3), 0, panel1.Height, panel1.Width, panel1.Height); 41 | 42 | // ControlPaint.DrawBorder(e.Graphics, new Rectangle(0, panel1.Height-1, panel1.Width, panel1.Height-1), SystemColors.ActiveBorder, ButtonBorderStyle.Dashed); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/AboutForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | 123 | 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 347 | 348 | 349 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/ConnectionType.cs: -------------------------------------------------------------------------------- 1 | namespace Sshfs 2 | { 3 | public enum ConnectionType:byte 4 | { 5 | Password = 0x0, 6 | PrivateKey = 0x1, 7 | Pageant = 0x2, 8 | } 9 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/ContextMenuStripThemedRenderer.cs: -------------------------------------------------------------------------------- 1 | using System.Drawing; 2 | using System.Windows.Forms; 3 | using System.Windows.Forms.VisualStyles; 4 | 5 | namespace Sshfs 6 | { 7 | internal sealed class ContextMenuStripThemedRenderer : ToolStripProfessionalRenderer 8 | { 9 | 10 | private static bool IsSupported 11 | { 12 | get 13 | { 14 | return VisualStyleRenderer.IsSupported && VisualStyleRenderer.IsElementDefined(VisualStyleElement.CreateElement("menu", 7, 1)); 15 | } 16 | } 17 | 18 | 19 | 20 | private static int GetItemState(ToolStripItem item) 21 | { 22 | 23 | return item.Enabled ? (item.Selected ? 2 : 1) : (item.Selected ? 4 : 3); 24 | } 25 | 26 | 27 | 28 | protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e) 29 | { 30 | if (e.Item.IsOnDropDown && IsSupported) 31 | { 32 | 33 | var renderer = new VisualStyleRenderer("menu", 14, GetItemState(e.Item)); 34 | 35 | e.TextColor = renderer.GetColor(ColorProperty.TextColor); 36 | 37 | } 38 | 39 | base.OnRenderItemText(e); 40 | 41 | } 42 | 43 | protected override void OnRenderToolStripBorder(ToolStripRenderEventArgs e) 44 | { 45 | if (e.ToolStrip.IsDropDown && IsSupported) 46 | { 47 | 48 | var renderer = new VisualStyleRenderer("menu", 10, 0); 49 | var clip = e.Graphics.Clip; 50 | var clientRectangle = e.ToolStrip.ClientRectangle; 51 | clientRectangle.Inflate(-1, -1); 52 | e.Graphics.ExcludeClip(clientRectangle); 53 | renderer.DrawBackground(e.Graphics, e.ToolStrip.ClientRectangle, e.AffectedBounds); 54 | e.Graphics.Clip = clip; 55 | 56 | 57 | } 58 | else 59 | { 60 | base.OnRenderToolStripBorder(e); 61 | } 62 | 63 | } 64 | 65 | protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e) 66 | { 67 | if (e.Item.IsOnDropDown && IsSupported) 68 | { 69 | 70 | var renderer = new VisualStyleRenderer("menu", 14, GetItemState(e.Item)); 71 | 72 | var backgroundRectangle = new Rectangle(e.Item.ContentRectangle.X + 1, 0, e.Item.ContentRectangle.Width - 1, e.Item.Bounds.Height); 73 | renderer.DrawBackground(e.Graphics, backgroundRectangle, backgroundRectangle); 74 | 75 | } 76 | else 77 | { 78 | base.OnRenderMenuItemBackground(e); 79 | } 80 | } 81 | 82 | protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e) 83 | { 84 | if (e.ToolStrip.IsDropDown && IsSupported) 85 | { 86 | 87 | var renderer = new VisualStyleRenderer("menu", 9, 0); 88 | 89 | if (renderer.IsBackgroundPartiallyTransparent()) 90 | { 91 | renderer.DrawParentBackground(e.Graphics, e.ToolStrip.ClientRectangle, e.ToolStrip); 92 | } 93 | 94 | renderer.DrawBackground(e.Graphics, e.ToolStrip.ClientRectangle, e.AffectedBounds); 95 | 96 | 97 | } 98 | else 99 | { 100 | base.OnRenderToolStripBackground(e); 101 | } 102 | } 103 | 104 | protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e) 105 | { 106 | if (e.ToolStrip.IsDropDown && IsSupported) 107 | { 108 | var renderer = new VisualStyleRenderer("menu", 15, 0); 109 | var backgroundRectangle = new Rectangle(e.ToolStrip.DisplayRectangle.Left, 0, e.ToolStrip.DisplayRectangle.Width, e.Item.Height); 110 | renderer.DrawBackground(e.Graphics, backgroundRectangle, backgroundRectangle); 111 | } 112 | else 113 | { 114 | base.OnRenderSeparator(e); 115 | } 116 | 117 | } 118 | 119 | protected override void OnRenderItemCheck(ToolStripItemImageRenderEventArgs e) 120 | { 121 | if (e.Item.IsOnDropDown && IsSupported) 122 | { 123 | 124 | var renderer = new VisualStyleRenderer("menu", 12, e.Item.Enabled ? 2 : 1); 125 | 126 | var bounds = new Rectangle(e.Item.ContentRectangle.X + 1, 0, e.Item.Bounds.Height, e.Item.Bounds.Height); 127 | 128 | if (e.Item.RightToLeft == RightToLeft.Yes) 129 | bounds = new Rectangle(e.ToolStrip.ClientSize.Width - bounds.X - bounds.Width, bounds.Y, bounds.Width, bounds.Height); 130 | 131 | renderer.DrawBackground(e.Graphics, bounds); 132 | 133 | var imageRectangle = e.ImageRectangle; 134 | 135 | imageRectangle.X = bounds.X + bounds.Width / 2 - imageRectangle.Width / 2; 136 | imageRectangle.Y = bounds.Y + bounds.Height / 2 - imageRectangle.Height / 2; 137 | 138 | renderer.SetParameters("menu", 11, e.Item.Enabled ? 1 : 2); 139 | 140 | renderer.DrawBackground(e.Graphics, imageRectangle); 141 | 142 | } 143 | else 144 | { 145 | base.OnRenderItemCheck(e); 146 | } 147 | } 148 | 149 | /* protected override void OnRenderImageMargin(ToolStripRenderEventArgs e) 150 | { 151 | if (e.ToolStrip.IsDropDown && IsSupported) 152 | { 153 | var renderer = new VisualStyleRenderer("menu", 13, 0); 154 | 155 | 156 | var themeMargins = renderer.GetMargins(e.Graphics, MarginProperty.CaptionMargins); 157 | 158 | themeMargins.Right+=2; 159 | 160 | int num = e.ToolStrip.Width - e.ToolStrip.DisplayRectangle.Width - themeMargins.Left - themeMargins.Right - 1 - e.AffectedBounds.Width; 161 | var bounds = e.AffectedBounds; 162 | bounds.Y += 2; 163 | bounds.Height -= 4; 164 | int width = renderer.GetPartSize(e.Graphics, ThemeSizeType.True).Width; 165 | if (e.ToolStrip.RightToLeft == RightToLeft.Yes) 166 | { 167 | bounds = new Rectangle(bounds.X - num, bounds.Y, width, bounds.Height); 168 | bounds.X += width; 169 | } 170 | else 171 | { 172 | bounds = new Rectangle(bounds.Width + num - width, bounds.Y, width, bounds.Height); 173 | } 174 | renderer.DrawBackground(e.Graphics, bounds); 175 | } 176 | else 177 | { 178 | base.OnRenderImageMargin(e); 179 | } 180 | }*/ 181 | 182 | 183 | } 184 | } 185 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/DriveStatus.cs: -------------------------------------------------------------------------------- 1 | namespace Sshfs 2 | { 3 | public enum DriveStatus:short 4 | { 5 | Unmounted=0x0, 6 | Mounting=0x1, 7 | Mounted=0x2, 8 | Unmounting=0x3, 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/Program.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System; 4 | using System.Diagnostics; 5 | using System.IO; 6 | 7 | #endregion 8 | 9 | namespace Sshfs 10 | { 11 | internal static class Program 12 | { 13 | //static SftpManagerApplication app; 14 | 15 | /// 16 | /// The main entry point for the application. 17 | /// 18 | [STAThread] 19 | private static void Main(params string[] args ) 20 | { 21 | 22 | #if DEBUG 23 | Debug.AutoFlush = true; 24 | //Debug.Listeners.Clear(); 25 | //Debug.Listeners.Add(new DelimitedListTraceListener(String.Format("{0}\\log{1:yyyy-MM-dd-HH-mm-ss}.txt",Environment.CurrentDirectory,DateTime.Now), "debug")); 26 | Debug.Listeners.Add(new DelimitedListTraceListener(Environment.CurrentDirectory+"\\last.log", "debug")); 27 | //Debug.Listeners.Add(Console.Out); 28 | #endif 29 | #if DEBUG && DEBUGSHADOWCOPY 30 | string shadowCopyDir = Environment.CurrentDirectory + "\\debug-shadow"; 31 | if (Directory.Exists(shadowCopyDir)) 32 | { 33 | Directory.Delete(shadowCopyDir, true); 34 | } 35 | #endif 36 | SftpManagerApplication app = new SftpManagerApplication(); 37 | app.Run(args); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("WinSshFS Foreveryone")] 9 | [assembly: AssemblyDescription("SFTP Filesystem for Windows")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Foreveryone")] 12 | [assembly: AssemblyProduct("WinSshFS Foreveryone 1.6.1.18-devel")] 13 | [assembly: AssemblyCopyright("")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(true)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("f68729eb-03dd-4988-b492-726b9c9f8c44")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.6.1.18")] 35 | [assembly: AssemblyVersion("1.6.1.18")] 36 | [assembly: AssemblyFileVersion("1.6.1.18")] 37 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Sshfs.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sshfs.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap add { 67 | get { 68 | object obj = ResourceManager.GetObject("add", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | 73 | /// 74 | /// Looks up a localized resource of type System.Drawing.Bitmap. 75 | /// 76 | internal static System.Drawing.Bitmap mount { 77 | get { 78 | object obj = ResourceManager.GetObject("mount", resourceCulture); 79 | return ((System.Drawing.Bitmap)(obj)); 80 | } 81 | } 82 | 83 | /// 84 | /// Looks up a localized resource of type System.Drawing.Bitmap. 85 | /// 86 | internal static System.Drawing.Bitmap remove { 87 | get { 88 | object obj = ResourceManager.GetObject("remove", resourceCulture); 89 | return ((System.Drawing.Bitmap)(obj)); 90 | } 91 | } 92 | 93 | /// 94 | /// Looks up a localized resource of type System.Drawing.Bitmap. 95 | /// 96 | internal static System.Drawing.Bitmap save { 97 | get { 98 | object obj = ResourceManager.GetObject("save", resourceCulture); 99 | return ((System.Drawing.Bitmap)(obj)); 100 | } 101 | } 102 | 103 | /// 104 | /// Looks up a localized resource of type System.Drawing.Bitmap. 105 | /// 106 | internal static System.Drawing.Bitmap unmount { 107 | get { 108 | object obj = ResourceManager.GetObject("unmount", resourceCulture); 109 | return ((System.Drawing.Bitmap)(obj)); 110 | } 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 122 | ..\Resources\add.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | 125 | ..\Resources\go-jump.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 126 | 127 | 128 | ..\Resources\remove.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 129 | 130 | 131 | ..\Resources\accessories-text-editor.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 132 | 133 | 134 | ..\Resources\undo.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 135 | 136 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.42000 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Sshfs.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "14.0.0.0")] 16 | public sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.DefaultSettingValueAttribute("300")] 29 | public uint AttributeCacheTimeout { 30 | get { 31 | return ((uint)(this["AttributeCacheTimeout"])); 32 | } 33 | } 34 | 35 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 36 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 37 | [global::System.Configuration.DefaultSettingValueAttribute("60")] 38 | public uint DirContentCacheTimeout { 39 | get { 40 | return ((uint)(this["DirContentCacheTimeout"])); 41 | } 42 | } 43 | 44 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 45 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 46 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 47 | public bool UseOfflineAttribute { 48 | get { 49 | return ((bool)(this["UseOfflineAttribute"])); 50 | } 51 | } 52 | 53 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 54 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 55 | [global::System.Configuration.DefaultSettingValueAttribute("False")] 56 | public bool UseNetworkDrive { 57 | get { 58 | return ((bool)(this["UseNetworkDrive"])); 59 | } 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 300 7 | 8 | 9 | 60 10 | 11 | 12 | False 13 | 14 | 15 | False 16 | 17 | 18 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/Resources/accessories-text-editor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/Resources/accessories-text-editor.png -------------------------------------------------------------------------------- /Sshfs/Sshfs/Resources/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/Resources/add.png -------------------------------------------------------------------------------- /Sshfs/Sshfs/Resources/go-jump.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/Resources/go-jump.png -------------------------------------------------------------------------------- /Sshfs/Sshfs/Resources/remove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/Resources/remove.png -------------------------------------------------------------------------------- /Sshfs/Sshfs/Resources/undo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/Resources/undo.png -------------------------------------------------------------------------------- /Sshfs/Sshfs/SftpContext.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 Dragan Mladjenovic 2 | // Permission is hereby granted, free of charge, to any person obtaining a copy 3 | // of this software and associated documentation files (the "Software"), to deal 4 | // in the Software without restriction, including without limitation the rights 5 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | // copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // The above copyright notice and this permission notice shall be included in 9 | // all copies or substantial portions of the Software. 10 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | // THE SOFTWARE. 17 | using System; 18 | using System.IO; 19 | using Renci.SshNet; 20 | using Renci.SshNet.Sftp; 21 | 22 | namespace Sshfs 23 | { 24 | internal sealed class SftpContext : IDisposable 25 | { 26 | private SftpFileAttributes _attributes; 27 | private SftpContextStream _stream; 28 | 29 | public bool deleteOnCloseWorkaround = false; 30 | 31 | public SftpContext(SftpFileAttributes attributes) 32 | { 33 | _attributes = attributes; 34 | } 35 | 36 | public SftpContext(SftpFileAttributes attributes, bool aDeleteOnCloseWorkaround) 37 | { 38 | _attributes = attributes; 39 | this.deleteOnCloseWorkaround = aDeleteOnCloseWorkaround; 40 | } 41 | 42 | public SftpContext(SftpClient client, string path, FileMode mode, FileAccess access, 43 | SftpFileAttributes attributes) 44 | { 45 | //_stream = client.Open(path, mode, access); 46 | _stream = new SftpContextStream(client.getSftpSession(), path, mode, access, attributes); 47 | _attributes = attributes; 48 | } 49 | 50 | public SftpFileAttributes Attributes 51 | { 52 | get { return _attributes; } 53 | } 54 | 55 | public SftpContextStream Stream 56 | { 57 | get { return _stream; } 58 | } 59 | 60 | #region IDisposable Members 61 | 62 | public void Dispose() 63 | { 64 | _attributes = null; 65 | 66 | if (_stream != null) 67 | { 68 | _stream.Close(); 69 | _stream = null; 70 | } 71 | 72 | 73 | GC.SuppressFinalize(this); 74 | } 75 | 76 | #endregion 77 | 78 | public void Release() 79 | { 80 | _attributes = null; 81 | 82 | if (_stream != null) 83 | { 84 | _stream.Close(); 85 | _stream = null; 86 | } 87 | GC.SuppressFinalize(this); 88 | } 89 | 90 | public override string ToString() 91 | { 92 | return String.Format("[{0:x}]", this.GetHashCode()); 93 | } 94 | } 95 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/SftpContextStream.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 Dragan Mladjenovic 2 | // Permission is hereby granted, free of charge, to any person obtaining a copy 3 | // of this software and associated documentation files (the "Software"), to deal 4 | // in the Software without restriction, including without limitation the rights 5 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | // copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // The above copyright notice and this permission notice shall be included in 9 | // all copies or substantial portions of the Software. 10 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | // THE SOFTWARE. 17 | 18 | using System; 19 | using System.IO; 20 | using System.Threading; 21 | using Renci.SshNet.Sftp; 22 | using Renci.SshNet.Common; 23 | using System.Collections.Generic; 24 | using System.Diagnostics; 25 | 26 | namespace Sshfs 27 | { 28 | internal sealed class SftpContextStream : Stream 29 | { 30 | /// 31 | /// Effective size of readRequest. 32 | /// 33 | private int optimalReadRequestSize; 34 | private byte[] readBuffer; 35 | /// 36 | /// Position of readBuffer data in source stream 37 | /// 38 | private long readBufferPosition; 39 | /// 40 | /// Valid count of data in read buffer 41 | /// 42 | private int readBufferCount; 43 | private bool readBufferIsAtEOF; 44 | 45 | private int WRITE_BUFFER_SIZE; 46 | 47 | 48 | private readonly byte[] _writeBuffer; 49 | 50 | private readonly ISftpSession _session; 51 | private SftpFileAttributes _attributes; 52 | private byte[] _handle; 53 | 54 | private bool _writeMode; 55 | private int _writeBufferPosition; 56 | private long _position; 57 | 58 | internal SftpContextStream(ISftpSession session, string path, FileMode mode, FileAccess access, 59 | SftpFileAttributes attributes) 60 | { 61 | Flags flags = Flags.None; 62 | 63 | switch (access) 64 | { 65 | case FileAccess.Read: 66 | flags = Flags.Read; 67 | break; 68 | case FileAccess.Write: 69 | flags = Flags.Write; 70 | break; 71 | case FileAccess.ReadWrite: 72 | flags = Flags.Read | Flags.Write; 73 | break; 74 | } 75 | 76 | switch (mode) 77 | { 78 | case FileMode.Append: 79 | flags |= Flags.Append; 80 | break; 81 | case FileMode.Create: 82 | if (attributes == null) 83 | { 84 | flags |= Flags.CreateNew; 85 | } 86 | else 87 | { 88 | flags |= Flags.Truncate; 89 | } 90 | break; 91 | case FileMode.CreateNew: 92 | flags |= Flags.CreateNew; 93 | break; 94 | case FileMode.Open: 95 | break; 96 | case FileMode.OpenOrCreate: 97 | flags |= Flags.CreateNewOrOpen; 98 | break; 99 | case FileMode.Truncate: 100 | flags |= Flags.Truncate; 101 | break; 102 | } 103 | 104 | _session = session; 105 | 106 | _handle = _session.RequestOpen(path, flags); 107 | 108 | _attributes = attributes ?? _session.RequestFStat(_handle); 109 | 110 | this.optimalReadRequestSize = checked((int)this._session.CalculateOptimalReadLength(uint.MaxValue)); 111 | this.readBuffer = new byte[this.optimalReadRequestSize]; 112 | this.readBufferCount = 0; 113 | 114 | WRITE_BUFFER_SIZE = (int)_session.CalculateOptimalWriteLength(65536, _handle); 115 | 116 | if (access.HasFlag(FileAccess.Write)) 117 | { 118 | _writeBuffer = new byte[WRITE_BUFFER_SIZE]; 119 | _writeMode = true; 120 | } 121 | 122 | _position = mode != FileMode.Append ? 0 : _attributes.Size; 123 | } 124 | 125 | 126 | public SftpFileAttributes Attributes 127 | { 128 | get 129 | { 130 | lock (this) 131 | { 132 | if (_writeMode) 133 | { 134 | //FlushWriteBuffer(); 135 | SetupRead(); 136 | _attributes = _session.RequestFStat(_handle); 137 | 138 | } 139 | } 140 | return _attributes; 141 | } 142 | } 143 | 144 | 145 | public override bool CanRead 146 | { 147 | get { throw new NotImplementedException(); } 148 | } 149 | 150 | public override bool CanSeek 151 | { 152 | get { throw new NotImplementedException(); } 153 | } 154 | 155 | public override bool CanWrite 156 | { 157 | get { throw new NotImplementedException(); } 158 | } 159 | 160 | public override long Length 161 | { 162 | get { throw new NotImplementedException(); } 163 | } 164 | 165 | 166 | public override long Position 167 | { 168 | get { return _position; } 169 | set 170 | { 171 | if (!_writeMode) 172 | { 173 | 174 | } 175 | else 176 | { 177 | // Console.WriteLine("Position:{0}=?{1}",value,_position); 178 | if (_position != value) 179 | { 180 | FlushWriteBuffer(); 181 | } 182 | } 183 | _position = value; 184 | } 185 | } 186 | 187 | 188 | public override void Close() 189 | { 190 | Dispose(true); 191 | GC.SuppressFinalize(this); 192 | } 193 | 194 | 195 | public override void Flush() 196 | { 197 | lock (this) 198 | { 199 | if (_writeMode) 200 | { 201 | FlushWriteBuffer(); 202 | } 203 | else 204 | { 205 | } 206 | } 207 | } 208 | 209 | /// 210 | /// Asynchronous read, will copy data to buffer and call Received. 211 | /// 212 | /// 213 | /// 214 | /// 215 | /// 216 | /// 217 | private void ReadAsync(long position, int count, byte[] buffer, int bufferOffset, Action Received) 218 | { 219 | #if DEBUG 220 | Debug.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "\t" + " Sending Async read for offset " + bufferOffset); 221 | #endif 222 | this._session.RequestReadAsync(_handle, (ulong)(position), (uint)count, 223 | response => { 224 | #if DEBUG 225 | Debug.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "\t" + " Got data for offset " + bufferOffset); 226 | #endif 227 | if (response.Data != null) 228 | { 229 | lock (buffer) 230 | { 231 | Buffer.BlockCopy(response.Data, 0, buffer, bufferOffset, response.Data.Length); 232 | Received(response.Data.Length); 233 | } 234 | } 235 | else 236 | { 237 | Received(0); 238 | } 239 | } 240 | ); 241 | } 242 | 243 | /// 244 | /// Normal read 245 | /// 246 | /// 247 | /// 248 | /// 249 | /// 250 | /// Length of received data 251 | private int ReadSync(long position, int count, byte[] buffer, int bufferOffset) 252 | { 253 | byte[] data = this._session.RequestRead(this._handle, (ulong)position, (uint)count); 254 | Buffer.BlockCopy(data, 0, buffer, bufferOffset, data.Length); 255 | return data.Length; 256 | } 257 | 258 | /// 259 | /// Update read buffer state with data at position 260 | /// 261 | /// 262 | private void ReadDataToBufferSync(long position) 263 | { 264 | this.readBufferCount = this.ReadSync(position, this.optimalReadRequestSize, this.readBuffer, 0); 265 | this.readBufferPosition = position; 266 | this.readBufferIsAtEOF = this.readBufferCount != this.optimalReadRequestSize || this.readBufferCount == 0; 267 | } 268 | 269 | private void ReadDataToBufferASync(long position) 270 | { 271 | this.ReadAsync(position, this.readBuffer.Length, this.readBuffer, 0, 272 | received => { 273 | this.readBufferPosition = position; 274 | this.readBufferCount = received; 275 | }); 276 | } 277 | 278 | /// 279 | /// Tryes to satisfy request from readBuffer. Returns count of bytes that hits the buffer. 280 | /// 281 | /// 282 | /// 283 | /// 284 | /// 285 | /// true if buffer war read to the end and its also EOF 286 | /// 287 | private int getDataFromBuffer(long position, int count, byte[] dst, int dstOffset, ref bool isEOF) 288 | { 289 | if ((position >= this.readBufferPosition) && 290 | (position < this.readBufferPosition + this.readBufferCount)) //atleast partial hit 291 | { 292 | int hitPosition = (int)(position - this.readBufferPosition); 293 | int hitLength = Math.Min(count, this.readBufferCount - hitPosition); 294 | Buffer.BlockCopy(this.readBuffer, hitPosition, dst, dstOffset, hitLength); 295 | 296 | isEOF = (this.readBufferIsAtEOF) && (hitPosition + hitLength == this.readBufferCount); 297 | return hitLength; 298 | } 299 | return 0; 300 | } 301 | 302 | /// 303 | /// 304 | /// 305 | /// Position to read from 306 | /// Count of bytes, unlimited 307 | /// Destination buffer 308 | /// Offset in destination buffer to write from 309 | /// Count of bytes readed to dst 310 | public int getDataAt(long position, int count, byte[] dst, int dstOffset = 0) 311 | { 312 | int received = 0; 313 | 314 | bool isEOF = false; 315 | int hitLength = this.getDataFromBuffer(position, count, dst, dstOffset, ref isEOF); 316 | if (hitLength > 0) 317 | { 318 | #if DEBUG 319 | Console.WriteLine("Readbuffer hit " + hitLength); 320 | #endif 321 | received += hitLength; 322 | count -= hitLength; 323 | position += hitLength; 324 | dstOffset += hitLength; 325 | if (isEOF || count == 0) //nothing remains 326 | { 327 | _position += received; 328 | return received; 329 | } 330 | } 331 | 332 | //small request, we want to load more data than requested and store them in buffer: 333 | if (count < this.optimalReadRequestSize) 334 | { 335 | this.ReadDataToBufferSync(position); 336 | hitLength = this.getDataFromBuffer(position, count, dst, dstOffset, ref isEOF); 337 | 338 | _position = position + received + hitLength; 339 | return received + hitLength; 340 | } 341 | 342 | 343 | //request with big buffers remains: 344 | 345 | List waits = new List(); 346 | 347 | int readCount = count; 348 | int winOffset = 0; 349 | int receivedTotal = 0; 350 | #if DEBUG 351 | DateTime startTime = DateTime.Now; 352 | #endif 353 | while (readCount > 0) 354 | { 355 | int winSize = readCount > this.optimalReadRequestSize ? this.optimalReadRequestSize : readCount; 356 | 357 | EventWaitHandle wait = new AutoResetEvent(false); 358 | wait.Reset(); 359 | waits.Add(wait); 360 | 361 | this.ReadAsync( 362 | position + winOffset, winSize, 363 | dst, dstOffset + winOffset, 364 | receivedStatus => { 365 | Interlocked.Add(ref receivedTotal, receivedStatus); 366 | wait.Set(); 367 | } 368 | ); 369 | 370 | winOffset += winSize; 371 | readCount -= winSize; 372 | } 373 | 374 | if (!WaitHandle.WaitAll(waits.ToArray(), 20000)) 375 | { 376 | throw new SshOperationTimeoutException("Timeout on wait"); 377 | } 378 | #if DEBUG 379 | int rrTime = (DateTime.Now - startTime).Milliseconds; 380 | Console.WriteLine(rrTime+" with "+waits.Count.ToString()); 381 | #endif 382 | _position = _position + received + receivedTotal; 383 | return received + receivedTotal; 384 | } 385 | 386 | 387 | public override int Read(byte[] buffer, int bufferOffset, int bufferCount) 388 | { 389 | // Set up for the read operation. 390 | SetupRead(); 391 | return this.getDataAt(this._position, bufferCount, buffer, bufferOffset); 392 | } 393 | 394 | 395 | public override long Seek(long offset, SeekOrigin origin) 396 | { 397 | throw new NotImplementedException(); 398 | } 399 | 400 | public override void SetLength(long value) 401 | { 402 | lock (this) 403 | { 404 | // Lock down the file stream while we do this. 405 | 406 | // Setup this object for writing. 407 | SetupWrite(); 408 | 409 | _attributes.Size = value; 410 | 411 | _session.RequestFSetStat(_handle, _attributes); 412 | } 413 | } 414 | 415 | 416 | public override void Write(byte[] buffer, int offset, int count) 417 | { 418 | // Lock down the file stream while we do this. 419 | 420 | // Setup this object for writing. 421 | SetupWrite(); 422 | 423 | // Write data to the file stream. 424 | // while (count > 0) 425 | // { 426 | // Determine how many bytes we can write to the buffer. 427 | int tempLen = WRITE_BUFFER_SIZE - _writeBufferPosition; 428 | 429 | /* if (tempLen <= 0) 430 | { 431 | 432 | _session.RequestWrite(_handle, (ulong) (_position - WRITE_BUFFER_SIZE), _writeBuffer); 433 | 434 | _writeBufferPosition = 0; 435 | tempLen = WRITE_BUFFER_SIZE; 436 | }*/ 437 | 438 | 439 | if (tempLen >= count) //enought remaining space in writeBuffer 440 | { 441 | // No: copy the data to the write buffer first. 442 | Buffer.BlockCopy(buffer, offset, _writeBuffer, _writeBufferPosition, count); 443 | _writeBufferPosition += count; 444 | } 445 | else //writeBuffer space insufficient 446 | { 447 | FlushWriteBuffer(); 448 | 449 | 450 | if (count > WRITE_BUFFER_SIZE) //writeBuffer size is still lower 451 | { 452 | //solves problem: max writtable count is WRITE_BUFFER_SIZE 453 | int remainingcount = count; 454 | int suboffset = 0; 455 | while (remainingcount >= WRITE_BUFFER_SIZE)//fire whole blocks 456 | { 457 | int chunkcount = remainingcount <= WRITE_BUFFER_SIZE ? remainingcount : WRITE_BUFFER_SIZE; 458 | Buffer.BlockCopy(buffer, offset+suboffset, _writeBuffer, _writeBufferPosition/*always zero*/, chunkcount); 459 | _session.RequestWrite( 460 | _handle, 461 | (ulong)(_position+suboffset), 462 | _writeBuffer, 463 | 0, 464 | chunkcount, 465 | null, 466 | null 467 | ); 468 | remainingcount -= chunkcount; 469 | suboffset += chunkcount; 470 | } 471 | if (remainingcount > 0)//if something remains, do it standard way: 472 | { 473 | Buffer.BlockCopy(buffer, offset+suboffset, _writeBuffer, _writeBufferPosition/*shoud be 0*/, remainingcount); 474 | _writeBufferPosition += remainingcount; 475 | } 476 | } 477 | else 478 | { 479 | Buffer.BlockCopy(buffer, offset, _writeBuffer, _writeBufferPosition, count); 480 | _writeBufferPosition += count; 481 | } 482 | } 483 | // Advance the buffer and stream positions. 484 | _position += count; 485 | // offset += tempLen; 486 | // count -= tempLen; 487 | // } 488 | 489 | // If the buffer is full, then do a speculative flush now, 490 | // rather than waiting for the next call to this method. 491 | if (_writeBufferPosition == WRITE_BUFFER_SIZE) 492 | { 493 | 494 | _session.RequestWrite( 495 | _handle, 496 | (ulong) (_position - WRITE_BUFFER_SIZE), 497 | _writeBuffer, 498 | 0, 499 | _writeBufferPosition, 500 | null, 501 | null 502 | ); 503 | 504 | 505 | _writeBufferPosition = 0; 506 | } 507 | } 508 | 509 | 510 | protected override void Dispose(bool disposing) 511 | { 512 | base.Dispose(disposing); 513 | 514 | 515 | if (_handle != null) 516 | { 517 | if (_writeMode) 518 | { 519 | FlushWriteBuffer(); 520 | } 521 | 522 | _session.RequestClose(_handle); 523 | 524 | _handle = null; 525 | } 526 | } 527 | 528 | 529 | private void FlushWriteBuffer() 530 | { 531 | // Console.WriteLine("FLUSHHHH the water"); 532 | if (_writeBufferPosition > 0) 533 | { 534 | // Console.WriteLine("Written:{0}",_writeBufferPosition); 535 | var data = new byte[_writeBufferPosition]; 536 | Buffer.BlockCopy(_writeBuffer, 0, data, 0, _writeBufferPosition); 537 | 538 | 539 | 540 | _session.RequestWrite( 541 | _handle, 542 | (ulong) (_position - _writeBufferPosition), 543 | data, 544 | 0, 545 | _writeBufferPosition, 546 | null, 547 | null 548 | ); 549 | 550 | 551 | _writeBufferPosition = 0; 552 | } 553 | } 554 | 555 | private void SetupRead() 556 | { 557 | if (_writeMode) 558 | { 559 | FlushWriteBuffer(); 560 | _writeMode = false; 561 | } 562 | } 563 | 564 | 565 | private void SetupWrite() 566 | { 567 | if (_writeMode) return; 568 | 569 | _writeBufferPosition = 0; 570 | _writeMode = true; 571 | } 572 | } 573 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/SftpDrive.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 Dragan Mladjenovic 2 | // Permission is hereby granted, free of charge, to any person obtaining a copy 3 | // of this software and associated documentation files (the "Software"), to deal 4 | // in the Software without restriction, including without limitation the rights 5 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 6 | // copies of the Software, and to permit persons to whom the Software is 7 | // furnished to do so, subject to the following conditions: 8 | // The above copyright notice and this permission notice shall be included in 9 | // all copies or substantial portions of the Software. 10 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 11 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 12 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 13 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 14 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 15 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 16 | // THE SOFTWARE. 17 | 18 | 19 | #region 20 | 21 | using System; 22 | using System.Diagnostics; 23 | using System.IO; 24 | using System.Linq; 25 | using System.Runtime.CompilerServices; 26 | using System.Runtime.Serialization; 27 | using System.Threading; 28 | using System.Threading.Tasks; 29 | using DokanNet; 30 | using Renci.SshNet; 31 | using Sshfs.Properties; 32 | using Renci.SshNet.Pageant; 33 | #endregion 34 | 35 | namespace Sshfs 36 | { 37 | [Serializable] 38 | public class SftpDrive : IDisposable, ISerializable 39 | { 40 | 41 | private CancellationTokenSource _mountCancel = new CancellationTokenSource(); 42 | private AutoResetEvent _pauseEvent = new AutoResetEvent(false); 43 | private CancellationTokenSource _threadCancel = new CancellationTokenSource(); 44 | private bool _exeptionThrown; 45 | internal SftpFilesystem _filesystem; 46 | 47 | private Exception _lastExeption; 48 | private Thread _mountThread; 49 | 50 | private string _connection; 51 | 52 | public string Name { get; set; } 53 | 54 | public char Letter { get; set; } 55 | 56 | public ConnectionType ConnectionType { get; set; } 57 | 58 | public string PrivateKey { get; set; } 59 | 60 | public string Password { get; set; } 61 | 62 | public string Passphrase { get; set; } 63 | 64 | public string Username { get; set; } 65 | 66 | public string Host { get; set; } 67 | 68 | 69 | public int Port { get; set; } 70 | 71 | 72 | public bool Automount { get; set; } 73 | 74 | 75 | public string Root { get; set; } 76 | 77 | public object Tag { get; set; } 78 | 79 | public DriveStatus Status { get; private set; } 80 | 81 | public string MountPoint { get; set; } 82 | 83 | public int ProxyType { get; set; } 84 | public string ProxyHost { get; set; } 85 | public string ProxyUser { get; set; } 86 | public string ProxyPass { get; set; } 87 | 88 | public int KeepAliveInterval { get; set; } 89 | 90 | public SftpDrive(){} 91 | 92 | private void OnStatusChanged(EventArgs args) 93 | { 94 | if (StatusChanged != null) 95 | { 96 | StatusChanged(this, args); 97 | } 98 | } 99 | 100 | public event EventHandler StatusChanged; 101 | 102 | 103 | 104 | private void SetupFilesystem() 105 | { 106 | Debug.WriteLine("SetupFilesystem {0},{1},{2},{3}",Host,Port,Username,ConnectionType.ToString()); 107 | 108 | ProxyTypes pt = ProxyTypes.None; 109 | switch (ProxyType) { 110 | case 1: pt = ProxyTypes.Http; break; 111 | case 2: pt = ProxyTypes.Socks4; break; 112 | case 3: pt = ProxyTypes.Socks5; break; 113 | } 114 | int ProxyPort = 8080; 115 | var Proxy = ProxyHost; 116 | if (ProxyHost != null) 117 | { 118 | var s = ProxyHost.Split(':'); 119 | if (s.Length > 1) 120 | { 121 | Int32.TryParse(s[1], out ProxyPort); 122 | Proxy = s[0]; 123 | } 124 | } 125 | 126 | if(KeepAliveInterval <= 0) 127 | { 128 | KeepAliveInterval = 1; 129 | } 130 | 131 | ConnectionInfo info = null; 132 | switch (ConnectionType) 133 | { 134 | case ConnectionType.Pageant: 135 | var agent = new PageantProtocol(); 136 | if (pt == ProxyTypes.None) 137 | { 138 | info = new AgentConnectionInfo(Host, Port, Username, agent); 139 | } 140 | else if (ProxyUser.Length > 0) 141 | { 142 | info = new AgentConnectionInfo(Host, Port, Username, pt, Proxy, ProxyPort, ProxyUser, ProxyPass, agent); 143 | } 144 | else 145 | { 146 | info = new AgentConnectionInfo(Host, Port, Username, pt, Proxy, ProxyPort, agent); 147 | } 148 | break; 149 | case ConnectionType.PrivateKey: 150 | if (pt == ProxyTypes.None) { 151 | info = new PrivateKeyConnectionInfo(Host, Port, Username, new PrivateKeyFile(PrivateKey, Passphrase)); 152 | } 153 | else if (ProxyUser.Length > 0) { 154 | info = new PrivateKeyConnectionInfo(Host, Port, Username, pt, Proxy, ProxyPort, ProxyUser, ProxyPass, new PrivateKeyFile(PrivateKey, Passphrase)); 155 | } 156 | else { 157 | info = new PrivateKeyConnectionInfo(Host, Port, Username, pt, Proxy, ProxyPort, new PrivateKeyFile(PrivateKey, Passphrase)); 158 | } 159 | break; 160 | default: 161 | if (pt == ProxyTypes.None) { 162 | info = new PasswordConnectionInfo(Host, Port, Username, Password); 163 | } 164 | else if (ProxyUser.Length > 0) { 165 | info = new PasswordConnectionInfo(Host, Username, Password, pt, Proxy, ProxyPort, ProxyUser, ProxyPass); 166 | } 167 | else { 168 | info = new PasswordConnectionInfo(Host, Port, Username, Password, pt, Proxy, ProxyPort); 169 | } 170 | break; 171 | } 172 | 173 | _connection = Settings.Default.UseNetworkDrive ? String.Format("\\\\{0}\\{1}\\{2}", info.Host, Root, info.Username) : Name; 174 | info.Timeout = new TimeSpan(0,0,5); 175 | 176 | _filesystem = new SftpFilesystem(info, Root,_connection,Settings.Default.UseOfflineAttribute,false, (int) Settings.Default.AttributeCacheTimeout, (int) Settings.Default.DirContentCacheTimeout); 177 | Debug.WriteLine("Connecting..."); 178 | _filesystem.KeepAliveInterval = new TimeSpan(0, 0, KeepAliveInterval); 179 | _filesystem.Connect(); 180 | _filesystem.Disconnected += OnDisconnectedFSEvent; 181 | _filesystem.ErrorOccurred += OnDisconnectedFSEvent; 182 | } 183 | 184 | Thread reconnectThread; 185 | 186 | private void OnDisconnectedFSEvent(object sender, EventArgs ea) 187 | { 188 | this.startReconnect(); 189 | } 190 | 191 | private void startReconnect() 192 | { 193 | this.stopReconnect(); 194 | 195 | this.reconnectThread = new Thread(new ThreadStart(reconnectJob)); 196 | this.reconnectThread.Start(); 197 | } 198 | private void stopReconnect() 199 | { 200 | this._threadCancel.Cancel(); 201 | if (this.reconnectThread != null && this.reconnectThread.IsAlive) 202 | { 203 | this.reconnectThread.Abort(); 204 | } 205 | this.reconnectThread = null; 206 | } 207 | 208 | private void reconnectJob() 209 | { 210 | this.Unmount(); 211 | 212 | while (this.Status != DriveStatus.Mounted) 213 | { 214 | try 215 | { 216 | if (_threadCancel.IsCancellationRequested) 217 | { 218 | Debug.WriteLine("Reconnect thread:Cancel"); 219 | break; 220 | } 221 | this.Mount(); 222 | } 223 | catch 224 | {} 225 | if (this.Status != DriveStatus.Mounted){ 226 | Thread.Sleep(1000); 227 | } 228 | } 229 | } 230 | 231 | 232 | 233 | private void SetupMountThread() 234 | { 235 | _threadCancel = new CancellationTokenSource(); 236 | _pauseEvent = new AutoResetEvent(false); 237 | _mountCancel = new CancellationTokenSource(); 238 | 239 | Debug.WriteLine("Thread:Created"); 240 | _mountThread = new Thread(MountLoop) {IsBackground = true}; 241 | 242 | _mountThread.Start(); 243 | } 244 | 245 | private void MountLoop() 246 | { 247 | while (true) 248 | { 249 | Debug.WriteLine("Thread:Pause"); 250 | 251 | _pauseEvent.WaitOne(-1); 252 | if (_threadCancel.IsCancellationRequested) 253 | { 254 | Debug.WriteLine("Thread:Cancel"); 255 | break; 256 | } 257 | 258 | Debug.WriteLine("Thread:Mount"); 259 | 260 | 261 | try 262 | { 263 | int threadCount = 8; 264 | #if DEBUG 265 | threadCount=1; 266 | #endif 267 | _filesystem.Mount(String.Format("{0}:\\", Letter), 268 | Settings.Default.UseNetworkDrive?DokanOptions.NetworkDrive: DokanOptions.RemovableDrive, threadCount); 269 | } 270 | catch (Exception e) 271 | { 272 | 273 | _lastExeption = e; 274 | _exeptionThrown = true; 275 | _mountCancel.Cancel(); 276 | } 277 | Status = DriveStatus.Unmounted; 278 | if (!_exeptionThrown) 279 | { 280 | 281 | OnStatusChanged(EventArgs.Empty); 282 | } 283 | 284 | } 285 | } 286 | 287 | [MethodImpl(MethodImplOptions.Synchronized)] 288 | public void Mount() 289 | { 290 | Debug.WriteLine("Mount"); 291 | 292 | 293 | if (Directory.GetLogicalDrives().Any(drive=>drive[0]==Letter)) 294 | { 295 | throw new Exception("Drive with the same letter exists"); 296 | } 297 | 298 | 299 | Status = DriveStatus.Mounting; 300 | 301 | try 302 | { 303 | SetupFilesystem(); 304 | } 305 | catch 306 | { 307 | 308 | Status = DriveStatus.Unmounted; 309 | throw; 310 | } 311 | 312 | if (Letter != ' ') 313 | { 314 | SetupMountThread(); 315 | 316 | var mountEvent = Task.Factory.StartNew(() => 317 | { 318 | while (!_mountCancel.IsCancellationRequested && 319 | Directory.GetLogicalDrives().All( 320 | drive => drive[0] != Letter)) 321 | { 322 | Thread.Sleep(200); 323 | } 324 | }, _mountCancel.Token); 325 | 326 | _pauseEvent.Set(); 327 | 328 | mountEvent.Wait(); 329 | 330 | if (_exeptionThrown) 331 | { 332 | 333 | _exeptionThrown = false; 334 | 335 | throw _lastExeption; 336 | } 337 | if (Settings.Default.UseNetworkDrive) 338 | Utilities.SetNetworkDriveName(_connection, Name); 339 | } 340 | Status= DriveStatus.Mounted; 341 | OnStatusChanged(EventArgs.Empty); 342 | 343 | 344 | 345 | } 346 | 347 | [MethodImpl(MethodImplOptions.Synchronized)] 348 | public void Unmount() 349 | { 350 | if (this.reconnectThread != Thread.CurrentThread) 351 | { 352 | this.stopReconnect(); 353 | } 354 | 355 | if (_threadCancel != null) _threadCancel.Cancel(); 356 | if (_pauseEvent != null) _pauseEvent.Set(); 357 | 358 | Debug.WriteLine("Unmount"); 359 | Status = DriveStatus.Unmounting; 360 | try 361 | { 362 | Dokan.RemoveMountPoint(String.Format("{0}:\\", Letter)); 363 | if (_filesystem != null) 364 | { 365 | _filesystem.Dispose(); 366 | } 367 | } 368 | catch 369 | { 370 | //Status = DriveStatus.Unmounted; 371 | // OnStatusChanged(EventArgs.Empty); 372 | } 373 | finally 374 | { 375 | _filesystem = null; 376 | Status = DriveStatus.Unmounted; 377 | OnStatusChanged(EventArgs.Empty); 378 | } 379 | 380 | } 381 | 382 | public override string ToString() 383 | { 384 | return String.Format("{0}[{1}:]", Name, Letter); 385 | } 386 | #region Implementation of IDisposable 387 | 388 | public void Dispose() 389 | { 390 | Debug.WriteLine("Dispose"); 391 | 392 | 393 | if (_threadCancel != null) _threadCancel.Cancel(); 394 | if (_pauseEvent != null) _pauseEvent.Set(); 395 | 396 | try 397 | { 398 | Dokan.RemoveMountPoint(String.Format("{0}:\\", Letter)); 399 | if (_filesystem != null) 400 | { 401 | _filesystem.Dispose(); 402 | 403 | 404 | _filesystem = null; 405 | } 406 | } 407 | catch 408 | { 409 | if(Status != DriveStatus.Unmounted) 410 | Status = DriveStatus.Unmounted; 411 | } 412 | finally 413 | { 414 | _filesystem = null; 415 | } 416 | 417 | 418 | if (_mountCancel != null) {_mountCancel.Dispose();} 419 | if (_threadCancel != null) {_threadCancel.Dispose();} 420 | if (_pauseEvent != null) {_pauseEvent.Dispose();} 421 | } 422 | 423 | #endregion 424 | 425 | #region Implementation of ISerializable 426 | 427 | public SftpDrive(SerializationInfo info, 428 | StreamingContext context) 429 | { 430 | Name = info.GetString("name"); 431 | Host = info.GetString("host"); 432 | Port = info.GetInt32("port"); 433 | Letter = info.GetChar("drive"); 434 | Root = info.GetString("path"); 435 | Automount = info.GetBoolean("mount"); 436 | Username = info.GetString("user"); 437 | try { 438 | ProxyType = info.GetInt32("proxyType"); 439 | ProxyHost = info.GetString("proxyHost"); 440 | ProxyUser = info.GetString("proxyUser"); 441 | ProxyPass = info.GetString("proxyPass"); 442 | } 443 | catch { } 444 | try 445 | { 446 | KeepAliveInterval = info.GetInt16("keepAliveInterval"); 447 | } 448 | catch 449 | { 450 | KeepAliveInterval = 1; 451 | } 452 | ConnectionType = (ConnectionType) info.GetByte("c"); 453 | if (ConnectionType == ConnectionType.Password) 454 | { 455 | Password = Utilities.UnprotectString(info.GetString("p")); 456 | } 457 | else 458 | { 459 | Passphrase = Utilities.UnprotectString(info.GetString("p")); 460 | PrivateKey = info.GetString("k"); 461 | } 462 | try 463 | { 464 | MountPoint = info.GetString("mountpoint"); 465 | } 466 | catch 467 | { 468 | MountPoint = Name;//default is name after version update 469 | } 470 | } 471 | 472 | 473 | 474 | public void GetObjectData(SerializationInfo info, StreamingContext context) 475 | { 476 | info.AddValue("name", Name); 477 | info.AddValue("host", Host); 478 | info.AddValue("port", Port); 479 | info.AddValue("drive", Letter); 480 | info.AddValue("path",Root); 481 | info.AddValue("mount", Automount); 482 | info.AddValue("user", Username); 483 | info.AddValue("c", (byte)ConnectionType); 484 | info.AddValue("mountpoint", MountPoint); 485 | info.AddValue("proxyType", ProxyType); 486 | info.AddValue("proxyHost", ProxyHost); 487 | info.AddValue("proxyUser", ProxyUser); 488 | info.AddValue("proxyPass", ProxyPass); 489 | info.AddValue("keepAliveInterval", KeepAliveInterval); 490 | if (ConnectionType == ConnectionType.Password) 491 | { 492 | info.AddValue("p", Utilities.ProtectString(Password)); 493 | } 494 | else 495 | { 496 | info.AddValue("p", Utilities.ProtectString(Passphrase)); 497 | info.AddValue("k", PrivateKey); 498 | } 499 | } 500 | 501 | #endregion 502 | 503 | } 504 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/SftpManagerApplication.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using Microsoft.VisualBasic.ApplicationServices; 4 | 5 | #endregion 6 | 7 | namespace Sshfs 8 | { 9 | internal class SftpManagerApplication : WindowsFormsApplicationBase 10 | { 11 | public SftpManagerApplication() 12 | { 13 | IsSingleInstance = true; 14 | EnableVisualStyles = true; 15 | } 16 | 17 | protected override void OnCreateMainForm() 18 | { 19 | MainForm = new MainForm(); 20 | } 21 | 22 | protected override void OnStartupNextInstance(StartupNextInstanceEventArgs eventArgs) 23 | { 24 | (MainForm as MainForm).ReShow(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/Sshfs.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {FF4FC8BB-91A3-45FF-8449-650647610394} 9 | WinExe 10 | Properties 11 | Sshfs 12 | WinSshFS 13 | v4.6 14 | 15 | 16 | 512 17 | true 18 | w:\dev\default\public\dev\winsshfs\ 19 | true 20 | Web 21 | true 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | http://dev.4e1.cz/winsshfs/ 29 | http://dev.4e1.cz/winsshfs/ 30 | cs 31 | WinSshFS 4every1 edition 32 | 4every1 s.r.o. 33 | WinSshFS 34 | true 35 | index.html 36 | false 37 | 9 38 | 1.5.12.9 39 | true 40 | true 41 | true 42 | true 43 | 44 | 45 | 46 | 47 | x86 48 | true 49 | full 50 | false 51 | bin\Debug\ 52 | TRACE;DEBUG;DEBUGSHADOWCOPYOFF 53 | prompt 54 | 3 55 | true 56 | 57 | 58 | x86 59 | pdbonly 60 | true 61 | bin\Release\ 62 | 63 | 64 | prompt 65 | 4 66 | false 67 | 68 | 69 | app.ico 70 | 71 | 72 | Sshfs.Program 73 | 74 | 75 | 76 | true 77 | 78 | 79 | WinSSH4e1-public.snk 80 | 81 | 82 | LocalIntranet 83 | 84 | 85 | false 86 | 87 | 88 | true 89 | bin\x64\Debug\ 90 | DEBUG;TRACE 91 | full 92 | x64 93 | prompt 94 | MinimumRecommendedRules.ruleset 95 | 96 | 97 | bin\x64\Release\ 98 | true 99 | pdbonly 100 | x64 101 | prompt 102 | MinimumRecommendedRules.ruleset 103 | 104 | 105 | 106 | ..\packages\DokanNet.1.1.0\lib\net46\DokanNet.dll 107 | True 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | Form 122 | 123 | 124 | AboutForm.cs 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | Form 133 | 134 | 135 | MainForm.cs 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | AboutForm.cs 147 | 148 | 149 | MainForm.cs 150 | 151 | 152 | ResXFileCodeGenerator 153 | Resources.Designer.cs 154 | Designer 155 | 156 | 157 | True 158 | Resources.resx 159 | True 160 | 161 | 162 | 163 | 164 | 165 | PublicSettingsSingleFileGenerator 166 | Settings.Designer.cs 167 | 168 | 169 | True 170 | Settings.settings 171 | True 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | PreserveNewest 208 | 209 | 210 | 211 | 212 | 213 | False 214 | Microsoft .NET Framework 4.5 %28x86 and x64%29 215 | true 216 | 217 | 218 | False 219 | .NET Framework 3.5 SP1 Client Profile 220 | false 221 | 222 | 223 | False 224 | .NET Framework 3.5 SP1 225 | false 226 | 227 | 228 | False 229 | Windows Installer 4.5 230 | true 231 | 232 | 233 | 234 | 235 | {2f5f8c90-0bd1-424f-997c-7bc6280919d1} 236 | Renci.SshNet 237 | 238 | 239 | 240 | 245 | 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/Utilities.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.IO; 6 | using System.IO.IsolatedStorage; 7 | using System.Linq; 8 | using System.Runtime.Serialization; 9 | using System.Security.Cryptography; 10 | using System.Text; 11 | using System.Windows.Forms; 12 | using Microsoft.Win32; 13 | using Renci.SshNet; 14 | 15 | #endregion 16 | 17 | namespace Sshfs 18 | { 19 | internal static class Utilities 20 | { 21 | private static readonly DirectoryInfo datadir = Directory.CreateDirectory( 22 | Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\WinSshFS" 23 | ); 24 | 25 | public static void Load(this List list, string file) where T : ISerializable 26 | { 27 | string filepath = datadir.FullName+"\\"+file; 28 | if (!File.Exists(filepath)) return; 29 | 30 | var xmlSerializer = new DataContractSerializer(typeof(IEnumerable)); 31 | using ( 32 | var stream = File.Open(filepath, FileMode.OpenOrCreate, 33 | FileAccess.Read)) 34 | { 35 | list.Clear(); 36 | 37 | list.AddRange(xmlSerializer.ReadObject(stream) as IEnumerable); 38 | } 39 | } 40 | 41 | public static T Load(this T obj, string file) where T : ISerializable 42 | { 43 | string filepath = datadir.FullName + "\\" + file; 44 | if (!File.Exists(filepath)) return default(T); 45 | 46 | var xmlSerializer = new DataContractSerializer(typeof(IEnumerable)); 47 | 48 | using ( 49 | var stream = File.Open(filepath, FileMode.OpenOrCreate, 50 | FileAccess.Read)) 51 | { 52 | return (T)xmlSerializer.ReadObject(stream); 53 | } 54 | } 55 | 56 | private static void doBackups(string filepath) 57 | { 58 | if (File.Exists(filepath)) 59 | { 60 | string bak = filepath + "~bak"; 61 | if (!File.Exists(bak)) 62 | { 63 | File.Move(filepath, bak); 64 | } 65 | else { 66 | File.Replace(filepath, bak, bak + "Prev", true); 67 | } 68 | } 69 | } 70 | 71 | public static void Persist(this List list, string file, bool delete = false) where T : ISerializable 72 | 73 | { 74 | string filepath = datadir.FullName + "\\" + file; 75 | if (delete) 76 | { 77 | File.Delete(filepath); 78 | } 79 | else 80 | { 81 | doBackups(filepath); 82 | 83 | var xmlSerializer = new DataContractSerializer(typeof (List)); 84 | using ( 85 | var stream = File.Open(filepath, FileMode.Create, 86 | FileAccess.Write)) 87 | { 88 | xmlSerializer.WriteObject(stream, list); 89 | } 90 | } 91 | } 92 | 93 | 94 | public static void Persist(this T obj, string file, bool delete = false) where T : ISerializable 95 | { 96 | string filepath = datadir.FullName + "\\" + file; 97 | if (delete) 98 | { 99 | File.Delete(filepath); 100 | } 101 | else 102 | { 103 | doBackups(filepath); 104 | 105 | var xmlSerializer = new DataContractSerializer(typeof(List)); 106 | using ( 107 | var stream = File.Open(filepath, FileMode.Create, 108 | FileAccess.Write)) 109 | { 110 | xmlSerializer.WriteObject(stream, obj); 111 | stream.Close(); 112 | } 113 | } 114 | } 115 | 116 | 117 | public static string ProtectString(string stringToProtect) 118 | { 119 | return stringToProtect != null 120 | ? Convert.ToBase64String(ProtectedData.Protect(Encoding.UTF8.GetBytes(stringToProtect), null, 121 | DataProtectionScope.CurrentUser)) 122 | : null; 123 | } 124 | 125 | public static string UnprotectString(string stringToUnprotect) 126 | { 127 | try 128 | { 129 | return stringToUnprotect != null 130 | ? Encoding.UTF8.GetString(ProtectedData.Unprotect(Convert.FromBase64String(stringToUnprotect), 131 | null, 132 | DataProtectionScope.CurrentUser)) 133 | : null; 134 | } 135 | catch 136 | { 137 | //in case of migration of config.xml between hosts - passwords cannot and shoud not work 138 | return null; 139 | } 140 | } 141 | 142 | public static IEnumerable GetAvailableDrives() 143 | { 144 | return Enumerable.Range('D', 23).Select(value => (char) value).Except( 145 | Directory.GetLogicalDrives().Select(drive => drive[0])); 146 | } 147 | 148 | 149 | public static void RegisterForStartup() 150 | { 151 | Registry.CurrentUser.OpenSubKey 152 | ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true).SetValue(Application.ProductName, 153 | Application.ExecutablePath); 154 | } 155 | 156 | public static void UnregisterForStarup() 157 | { 158 | Registry.CurrentUser.OpenSubKey 159 | ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true).DeleteValue(Application.ProductName); 160 | } 161 | 162 | 163 | public static bool IsAppRegistredForStarup() 164 | { 165 | return (Registry.CurrentUser.OpenSubKey 166 | ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", false).GetValue(Application.ProductName) 167 | as string) == Application.ExecutablePath; 168 | } 169 | 170 | 171 | public static bool IsValidUnixPath(string value) 172 | { 173 | return !string.IsNullOrEmpty(value) && (value[0] == '.' || value[0] == '/') && (value.IndexOf('\\') == -1); 174 | } 175 | 176 | /* public static bool IsValidPrivateKey(string path) 177 | { 178 | try 179 | { 180 | new PrivateKeyFile(path); 181 | return true; 182 | } 183 | catch 184 | { 185 | return false; 186 | } 187 | }*/ 188 | 189 | public static void SetNetworkDriveName(string connection,string name) 190 | { 191 | var drive= Registry.CurrentUser.OpenSubKey 192 | ("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\MountPoints2", false).OpenSubKey(connection.Replace("\\","#"),true); 193 | if(drive!=null) 194 | { 195 | drive.SetValue("_LabelFromReg", name); 196 | } 197 | } 198 | } 199 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/VirtualDrive.cs: -------------------------------------------------------------------------------- 1 |  2 | #region 3 | 4 | using System; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Runtime.CompilerServices; 9 | using System.Runtime.Serialization; 10 | using System.Threading; 11 | using System.Threading.Tasks; 12 | using DokanNet; 13 | using Sshfs.Properties; 14 | using System.Collections.Generic; 15 | #endregion 16 | 17 | namespace Sshfs 18 | { 19 | [Serializable] 20 | public class VirtualDrive : IDisposable, ISerializable 21 | { 22 | private CancellationTokenSource _mountCancel; 23 | private AutoResetEvent _pauseEvent; 24 | private CancellationTokenSource _threadCancel; 25 | private Thread _mountThread; 26 | private Exception _lastExeption; 27 | private bool _exeptionThrown; 28 | 29 | private VirtualFilesystem _filesystem; 30 | private List _drives = new List(); 31 | 32 | public string Name { get; set; } 33 | 34 | public char Letter { get; set; } 35 | private char mountedLetter { get; set; } 36 | 37 | public DriveStatus Status { get; private set; } 38 | 39 | //private readonly Dictionary _subsytems = new Dictionary(); 40 | 41 | 42 | 43 | public VirtualDrive() { } 44 | 45 | 46 | internal void AddSubFS(SftpDrive sftpDrive) 47 | { 48 | _drives.Add(sftpDrive); 49 | if (_filesystem!=null) 50 | _filesystem.AddSubFS(sftpDrive); 51 | } 52 | 53 | internal void RemoveSubFS(SftpDrive sftpDrive) 54 | { 55 | _drives.Remove(sftpDrive); 56 | if (_filesystem!=null) 57 | _filesystem.RemoveSubFS(sftpDrive); 58 | } 59 | 60 | 61 | private void OnStatusChanged(EventArgs args) 62 | { 63 | if (StatusChanged != null) 64 | { 65 | StatusChanged(this, args); 66 | } 67 | } 68 | 69 | public event EventHandler StatusChanged; 70 | 71 | 72 | 73 | private void SetupFilesystem() 74 | { 75 | Debug.WriteLine("SetupVirtualFilesystem"); 76 | 77 | 78 | } 79 | 80 | private void SetupMountThread() 81 | { 82 | if (_mountThread == null) 83 | { 84 | Debug.WriteLine("Thread:Created"); 85 | _threadCancel = new CancellationTokenSource(); 86 | _pauseEvent = new AutoResetEvent(false); 87 | _mountCancel = new CancellationTokenSource(); 88 | _mountThread = new Thread(MountLoop) { IsBackground = true }; 89 | _mountThread.Start(); 90 | 91 | } 92 | } 93 | 94 | private void MountLoop() 95 | { 96 | while (true) 97 | { 98 | Debug.WriteLine("Thread:Pause"); 99 | 100 | _pauseEvent.WaitOne(-1); 101 | if (_threadCancel.IsCancellationRequested) 102 | { 103 | Debug.WriteLine("Thread:Cancel"); 104 | break; 105 | } 106 | 107 | Debug.WriteLine("Thread:Mount"); 108 | 109 | 110 | try 111 | { 112 | _filesystem = new VirtualFilesystem("WinSshFS spool"); 113 | foreach (SftpDrive drive in _drives) 114 | { 115 | if (drive.MountPoint != "") 116 | { 117 | _filesystem.AddSubFS(drive); 118 | } 119 | } 120 | mountedLetter = Letter; 121 | int threadCount = 8; 122 | #if DEBUG 123 | threadCount = 1; 124 | #endif 125 | _filesystem.Mount(String.Format("{0}:\\", mountedLetter), Settings.Default.UseNetworkDrive ? DokanOptions.NetworkDrive : DokanOptions.RemovableDrive, threadCount); 126 | } 127 | catch (Exception e) 128 | { 129 | 130 | _lastExeption = e; 131 | _exeptionThrown = true; 132 | _mountCancel.Cancel(); 133 | } 134 | Status = DriveStatus.Unmounted; 135 | this._mountThread = null; 136 | if (!_exeptionThrown) 137 | { 138 | 139 | OnStatusChanged(EventArgs.Empty); 140 | } 141 | 142 | } 143 | } 144 | 145 | 146 | [MethodImpl(MethodImplOptions.Synchronized)] 147 | public void Mount() 148 | { 149 | Debug.WriteLine("Mount"); 150 | 151 | if (Directory.GetLogicalDrives().Any(drive => drive[0] == Letter)) 152 | { 153 | throw new Exception("Drive with the same letter exists"); 154 | } 155 | 156 | 157 | Status = DriveStatus.Mounting; 158 | 159 | try 160 | { 161 | SetupFilesystem(); 162 | } 163 | catch 164 | { 165 | 166 | Status = DriveStatus.Unmounted; 167 | throw; 168 | } 169 | 170 | SetupMountThread(); 171 | 172 | 173 | 174 | var mountEvent = Task.Factory.StartNew(() => 175 | { 176 | while (!_mountCancel.IsCancellationRequested && 177 | Directory.GetLogicalDrives().All( 178 | drive => drive[0] != Letter)) 179 | { 180 | Thread.Sleep(200); 181 | } 182 | }, _mountCancel.Token); 183 | 184 | 185 | _pauseEvent.Set(); 186 | 187 | mountEvent.Wait(); 188 | 189 | if (_exeptionThrown) 190 | { 191 | 192 | _exeptionThrown = false; 193 | 194 | throw _lastExeption; 195 | } 196 | if (Settings.Default.UseNetworkDrive) 197 | Utilities.SetNetworkDriveName("WinSshFS spool drive" , Name); 198 | Status = DriveStatus.Mounted; 199 | OnStatusChanged(EventArgs.Empty); 200 | } 201 | 202 | [MethodImpl(MethodImplOptions.Synchronized)] 203 | public void Unmount() 204 | { 205 | if(this._threadCancel != null) 206 | this._threadCancel.Cancel(); 207 | if(this._pauseEvent != null) 208 | this._pauseEvent.Set(); 209 | 210 | Debug.WriteLine("Unmount"); 211 | 212 | Status = DriveStatus.Unmounting; 213 | try 214 | { 215 | Dokan.RemoveMountPoint(String.Format("{0}:\\", mountedLetter)); 216 | } 217 | catch 218 | { 219 | //Status = DriveStatus.Unmounted; 220 | // OnStatusChanged(EventArgs.Empty); 221 | } 222 | finally 223 | { 224 | _filesystem = null; 225 | } 226 | 227 | } 228 | 229 | public override string ToString() 230 | { 231 | return String.Format("{0}[{1}:]", Name, Letter); 232 | } 233 | #region Implementation of IDisposable 234 | 235 | public void Dispose() 236 | { 237 | Debug.WriteLine("Dispose"); 238 | 239 | try 240 | { 241 | Dokan.RemoveMountPoint(String.Format("{0}:\\", Letter)); 242 | } 243 | catch 244 | { 245 | Status = DriveStatus.Unmounted; 246 | } 247 | finally 248 | { 249 | _filesystem = null; 250 | } 251 | } 252 | 253 | #endregion 254 | 255 | #region Implementation of ISerializable 256 | 257 | public VirtualDrive(SerializationInfo info, 258 | StreamingContext context) 259 | { 260 | Letter = info.GetChar("letter"); 261 | } 262 | 263 | 264 | 265 | public void GetObjectData(SerializationInfo info, StreamingContext context) 266 | { 267 | info.AddValue("letter", Letter); 268 | } 269 | 270 | #endregion 271 | 272 | } 273 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/VirtualFilesystem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Runtime.Caching; 7 | using System.Security.AccessControl; 8 | using System.Security.Principal; 9 | using System.Text; 10 | using DokanNet; 11 | using System.Text.RegularExpressions; 12 | 13 | using FileAccess = DokanNet.FileAccess; 14 | 15 | 16 | namespace Sshfs 17 | { 18 | internal sealed class VirtualFilesystem : IDokanOperations 19 | { 20 | 21 | #region Fields 22 | 23 | private readonly string _volumeLabel; 24 | private bool _debugMode = false; 25 | 26 | private readonly List _subsytems = new List(); 27 | private SftpDrive lastActiveSubsytem; 28 | 29 | #endregion 30 | 31 | #region Constructors 32 | 33 | public VirtualFilesystem(string label = null) 34 | { 35 | _volumeLabel = label; 36 | } 37 | 38 | #endregion 39 | 40 | #region Methods 41 | 42 | internal void AddSubFS(SftpDrive sftpDrive) 43 | { 44 | _subsytems.Add(sftpDrive); 45 | } 46 | 47 | internal void RemoveSubFS(SftpDrive sftpDrive) 48 | { 49 | _subsytems.Remove(sftpDrive); 50 | } 51 | 52 | #endregion 53 | 54 | 55 | #region Logging 56 | [Conditional("DEBUG")] 57 | private void Log(string format, params object[] arg) 58 | { 59 | if (_debugMode) 60 | { 61 | Console.WriteLine(format, arg); 62 | } 63 | 64 | Debug.AutoFlush = false; 65 | Debug.Write(DateTime.Now.ToLongTimeString() + " "); 66 | Debug.WriteLine(format, arg); 67 | Debug.Flush(); 68 | } 69 | 70 | [Conditional("DEBUG")] 71 | private void LogFSAction(String action, String path, SftpDrive subsystem, string format, params object[] arg) 72 | { 73 | Debug.Write(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + "\t" + "[--VFS--]" + "\t" + action + "\t" + ( subsystem!=null? subsystem.Name : "- ") + "\t" + path + "\t"); 74 | Debug.WriteLine(format, arg); 75 | } 76 | 77 | [Conditional("DEBUG")] 78 | private void LogFSActionInit(String action, String path, SftpDrive subsystem, string format, params object[] arg) 79 | { 80 | LogFSAction(action + "^", path, subsystem, format, arg); 81 | } 82 | [Conditional("DEBUG")] 83 | private void LogFSActionSuccess(String action, String path, SftpDrive subsystem, string format, params object[] arg) 84 | { 85 | LogFSAction(action + "$", path, subsystem, format, arg); 86 | } 87 | [Conditional("DEBUG")] 88 | private void LogFSActionError(String action, String path, SftpDrive subsystem, string format, params object[] arg) 89 | { 90 | LogFSAction(action + "!", path, subsystem, format, arg); 91 | } 92 | [Conditional("DEBUG")] 93 | private void LogFSActionOther(String action, String path, SftpDrive subsystem, string format, params object[] arg) 94 | { 95 | LogFSAction(action + "|", path, subsystem, format, arg); 96 | } 97 | 98 | #endregion 99 | 100 | 101 | #region DokanOperations 102 | 103 | NtStatus IDokanOperations.CreateFile(string fileName, FileAccess access, FileShare share, 104 | FileMode mode, FileOptions options, 105 | FileAttributes attributes, DokanFileInfo info) 106 | { 107 | if (info.IsDirectory) 108 | { 109 | if (mode == FileMode.Open) 110 | return OpenDirectory(fileName, info); 111 | if (mode == FileMode.CreateNew) 112 | return CreateDirectory(fileName, info); 113 | 114 | return NtStatus.NotImplemented; 115 | } 116 | 117 | if (fileName.EndsWith("desktop.ini", StringComparison.OrdinalIgnoreCase) || 118 | fileName.EndsWith("autorun.inf", StringComparison.OrdinalIgnoreCase)) //.... 119 | { 120 | return NtStatus.NoSuchFile; 121 | } 122 | 123 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 124 | LogFSActionInit("OpenFile", fileName, drive, "Mode:{0}", mode); 125 | if (drive != null) 126 | { 127 | LogFSActionSuccess("OpenFile", fileName, drive, "Mode:{0} NonVFS", mode); 128 | IDokanOperations idops = GetSubSystemOperations(drive); 129 | if (idops == null) 130 | { 131 | //this happens if mounting failed 132 | return NtStatus.AccessDenied; 133 | } 134 | return idops.CreateFile(fileName, access, share, mode, options, attributes, info); 135 | } 136 | 137 | //check against mountpoints if virtual dir exists 138 | 139 | string path = fileName.Substring(1); 140 | if (path == "") 141 | { 142 | //info.IsDirectory = true; 143 | info.Context = null; 144 | LogFSActionSuccess("OpenFile", fileName, null, "VFS root"); 145 | return NtStatus.Success; 146 | } 147 | foreach (SftpDrive drive2 in this._subsytems) 148 | { 149 | if (drive2.MountPoint.Length > 0) 150 | { 151 | if (drive2.MountPoint.IndexOf(path) == 0) 152 | { 153 | info.IsDirectory = true; 154 | info.Context = drive2; 155 | LogFSActionSuccess("OpenFile", fileName, drive2, "VFS (sub)mountpoint"); 156 | return NtStatus.Success; 157 | } 158 | } 159 | } 160 | 161 | //pathnotfound detection? 162 | 163 | LogFSActionError("OpenFile", fileName, null, "File not found"); 164 | return NtStatus.NoSuchFile; 165 | } 166 | 167 | private SftpDrive GetDriveByMountPoint(string fileName, out string subfspath) 168 | { 169 | LogFSActionInit("LookupMP", fileName, null, ""); 170 | 171 | if (fileName.Length>1) 172 | { 173 | string path = fileName.Substring(1); 174 | foreach (SftpDrive drive in this._subsytems) 175 | { 176 | if (drive.MountPoint.Length > 0) 177 | { 178 | string mpWithPath = drive.MountPoint + "\\"; 179 | if ( path == drive.MountPoint || path.IndexOf(mpWithPath) == 0 ) 180 | { 181 | subfspath = path.Substring(drive.MountPoint.Length); 182 | if (subfspath == "") 183 | subfspath = "\\"; 184 | LogFSActionSuccess("LookupMP", fileName, drive, "Subsystem path: {0}",subfspath); 185 | return drive; 186 | } 187 | } 188 | } 189 | } 190 | subfspath = fileName; 191 | 192 | LogFSActionSuccess("LookupMP", fileName, null, "VFS path"); 193 | return null; 194 | } 195 | 196 | private IDokanOperations GetSubSystemOperations(SftpDrive drive) 197 | { 198 | if (drive == null) 199 | return null; 200 | 201 | if ((drive.Status != DriveStatus.Mounted)&&(drive.Status != DriveStatus.Mounting)) 202 | { 203 | try 204 | { 205 | LogFSActionInit("MOUNT", "", drive, "Mounting..."); 206 | drive.Mount(); 207 | } 208 | catch (Exception e) 209 | { 210 | if (e.Message == "Pageant not running") 211 | { 212 | 213 | return null; 214 | } 215 | 216 | LogFSActionError("MOUNT", "", drive, "Mounting failed: {0}",e.Message); 217 | //Log("VFS: Mount error: {0}", e.Message); 218 | 219 | //maybe failed because of letter blocked, but we dont need the letter: 220 | if (drive.Letter != ' ') 221 | { 222 | LogFSActionError("MOUNT", "", drive, "Trying without mounting drive {0}", drive.Letter); 223 | char l = drive.Letter; 224 | drive.Letter = ' '; 225 | try 226 | { 227 | drive.Mount(); 228 | drive.Letter = l; 229 | } 230 | catch 231 | { 232 | LogFSActionError("MOUNT", "", drive, "Mounting failed again: {0}", e.Message); 233 | //connection error 234 | drive.Letter = l; 235 | //Log("VFS: Mount error: {0}", e.Message); 236 | return null; 237 | } 238 | } 239 | else 240 | { 241 | 242 | return null; 243 | } 244 | 245 | } 246 | } 247 | 248 | return ((IDokanOperations)drive._filesystem); 249 | } 250 | 251 | private NtStatus OpenDirectory(string fileName, DokanFileInfo info) 252 | { 253 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 254 | LogFSActionInit("OpenDir", fileName, drive, ""); 255 | 256 | if (drive != null) 257 | { 258 | lastActiveSubsytem = drive; 259 | 260 | IDokanOperations ops = GetSubSystemOperations(drive); 261 | if (ops == null) 262 | { 263 | LogFSActionError("OpenDir", fileName, drive, "Cannot open, mount failed?"); 264 | return NtStatus.AccessDenied; 265 | } 266 | LogFSActionSuccess("OpenDir", fileName, drive, "Found, subsytem"); 267 | return ops.CreateFile(fileName, FileAccess.GenericRead, FileShare.None, FileMode.Open, FileOptions.None, FileAttributes.Directory, info); 268 | } 269 | 270 | if (fileName.Length == 1) //root dir 271 | { 272 | LogFSActionSuccess("OpenDir", fileName, drive, "Found, VFS root"); 273 | info.IsDirectory = true; 274 | return NtStatus.Success; 275 | } 276 | 277 | 278 | 279 | //root test shoud keep lastactive if drag and drop(win8) 280 | lastActiveSubsytem = null; 281 | 282 | string path = fileName.Substring(1);//cut leading \ 283 | 284 | foreach (SftpDrive subdrive in _subsytems) 285 | { 286 | string mp = subdrive.MountPoint; // mp1 || mp1\mp2 ... 287 | if (path == mp) 288 | { 289 | info.Context = subdrive; 290 | info.IsDirectory = true; 291 | LogFSActionSuccess("OpenDir", fileName, drive, "Found, final mountpoint"); 292 | return NtStatus.Success; 293 | } 294 | 295 | if (mp.IndexOf(path + '\\') == 0) 296 | { //path is part of mount point 297 | info.Context = subdrive; 298 | info.IsDirectory = true; 299 | LogFSActionSuccess("OpenDir", fileName, drive, "Found, part of mountpoint"); 300 | return NtStatus.Success; 301 | } 302 | } 303 | LogFSActionError("OpenDir", fileName, drive, "Path not found"); 304 | return NtStatus.ObjectPathNotFound; 305 | } 306 | 307 | private NtStatus CreateDirectory(string fileName, DokanFileInfo info) 308 | { 309 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 310 | if (drive != null) 311 | return GetSubSystemOperations(drive).CreateFile(fileName, FileAccess.GenericRead, FileShare.None, FileMode.CreateNew, FileOptions.None, FileAttributes.Directory, info); 312 | 313 | return NtStatus.AccessDenied; 314 | } 315 | 316 | void IDokanOperations.Cleanup(string fileName, DokanFileInfo info) 317 | { 318 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 319 | LogFSActionInit("Cleanup", fileName, drive, ""); 320 | if (drive != null) 321 | { 322 | LogFSActionSuccess("Cleanup", fileName, drive, "nonVFS clean"); 323 | GetSubSystemOperations(drive).Cleanup(fileName, info); 324 | return; 325 | } 326 | 327 | if (info.Context != null) 328 | { 329 | drive = info.Context as SftpDrive; 330 | info.Context = null; 331 | } 332 | 333 | LogFSActionSuccess("Cleanup", fileName, drive, "VFS clean"); 334 | return; 335 | } 336 | 337 | void IDokanOperations.CloseFile(string fileName, DokanFileInfo info) 338 | { 339 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 340 | LogFSActionInit("CloseFile", fileName, drive, ""); 341 | if (drive != null) 342 | { 343 | LogFSActionSuccess("CloseFile", fileName, drive, "NonVFS close"); 344 | GetSubSystemOperations(drive).CloseFile(fileName, info); 345 | return; 346 | } 347 | 348 | if (info.Context != null) 349 | { 350 | drive = info.Context as SftpDrive; 351 | info.Context = null; 352 | } 353 | 354 | LogFSActionSuccess("CloseFile", fileName, drive, "VFS close"); 355 | return; 356 | } 357 | 358 | 359 | NtStatus IDokanOperations.ReadFile(string fileName, byte[] buffer, out int bytesRead, long offset, 360 | DokanFileInfo info) 361 | { 362 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 363 | if (drive != null) 364 | return GetSubSystemOperations(drive).ReadFile(fileName, buffer, out bytesRead, offset, info); 365 | 366 | bytesRead = 0; 367 | return NtStatus.AccessDenied; 368 | } 369 | 370 | NtStatus IDokanOperations.WriteFile(string fileName, byte[] buffer, out int bytesWritten, long offset, 371 | DokanFileInfo info) 372 | { 373 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 374 | if (drive != null) 375 | return GetSubSystemOperations(drive).WriteFile(fileName, buffer, out bytesWritten, offset, info); 376 | 377 | bytesWritten = 0; 378 | return NtStatus.AccessDenied; 379 | } 380 | 381 | 382 | NtStatus IDokanOperations.FlushFileBuffers(string fileName, DokanFileInfo info) 383 | { 384 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 385 | if (drive != null) 386 | return GetSubSystemOperations(drive).FlushFileBuffers(fileName, info); 387 | 388 | return NtStatus.Success; 389 | } 390 | 391 | NtStatus IDokanOperations.GetFileInformation(string fileName, out FileInformation fileInfo, 392 | DokanFileInfo info) 393 | { 394 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 395 | LogFSActionInit("FileInfo", fileName, drive, ""); 396 | if (drive != null) 397 | { 398 | LogFSActionSuccess("FileInfo", fileName, drive, "NonVFS"); 399 | return GetSubSystemOperations(drive).GetFileInformation(fileName, out fileInfo, info); 400 | } 401 | 402 | fileInfo = new FileInformation 403 | { 404 | Attributes = 405 | FileAttributes.NotContentIndexed | FileAttributes.Directory | FileAttributes.ReparsePoint | FileAttributes.Offline, 406 | FileName = Path.GetFileName(fileName), //String.Empty, 407 | // GetInfo info doesn't use it maybe for sorting . 408 | CreationTime = DateTime.Now, 409 | LastAccessTime = DateTime.Now, 410 | LastWriteTime = DateTime.Now, 411 | Length = 4096 412 | }; 413 | 414 | if (fileName.Length == 1) 415 | { //root dir 416 | LogFSActionSuccess("FileInfo", fileName, drive, "root info"); 417 | return NtStatus.Success; 418 | } 419 | 420 | string path = fileName.Substring(1);//cut leading \ 421 | 422 | if (info.Context != null) 423 | { 424 | drive = info.Context as SftpDrive; 425 | LogFSActionSuccess("FileInfo", fileName, drive, "from context"); 426 | return NtStatus.Success; 427 | } 428 | 429 | foreach (SftpDrive subdrive in _subsytems) 430 | { 431 | string mp = subdrive.MountPoint; // mp1 || mp1\mp2 ... 432 | if (path == mp) 433 | { 434 | info.Context = mp; 435 | //fileInfo.FileName = path.Substring(path.LastIndexOf("\\")+1); 436 | LogFSActionSuccess("FileInfo", fileName, drive, "final mountpoint"); 437 | return NtStatus.Success; 438 | } 439 | 440 | if (mp.IndexOf(path + '\\') == 0) 441 | { //path is part of mount point 442 | //fileInfo.FileName = path.Substring(path.LastIndexOf("\\") + 1); 443 | LogFSActionSuccess("FileInfo", fileName, drive, "part of mountpoint"); 444 | return NtStatus.Success; 445 | } 446 | } 447 | 448 | LogFSActionError("FileInfo", fileName, drive, "path not found"); 449 | return NtStatus.ObjectPathNotFound; 450 | 451 | 452 | } 453 | 454 | NtStatus IDokanOperations.FindFilesWithPattern(string fileName, string searchPattern, out IList files, DokanFileInfo info) 455 | { 456 | files = null; 457 | return NtStatus.NotImplemented; 458 | } 459 | 460 | NtStatus IDokanOperations.FindFiles(string fileName, out IList files, DokanFileInfo info) 461 | { 462 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 463 | LogFSActionError("FindFiles", fileName, drive, "!? not using FindFilesWithPattern !?"); 464 | 465 | if (drive != null) 466 | return GetSubSystemOperations(drive).FindFiles(fileName, out files, info); 467 | 468 | //this shoud be never called 469 | 470 | files = new List(); 471 | 472 | string path = fileName.Substring(1);//cut leading \ 473 | foreach(SftpDrive subdrive in _subsytems) 474 | { 475 | string mp = subdrive.MountPoint; // mp1 || mp1\mp2 ... 476 | 477 | if (path.Length > 0) //not root dir 478 | { 479 | if (path == mp) //this shoud not happend, because is managed by drive 480 | { 481 | Log("Error, mountpoint not in drives?"); 482 | break; 483 | } 484 | 485 | if (mp.IndexOf(path + '\\') == 0) //path is part of mount point =>implies=> length of path>mp 486 | { 487 | mp = mp.Substring(path.Length + 1); //cut the path 488 | } 489 | else 490 | { 491 | continue; 492 | } 493 | } 494 | 495 | int cuttmp = mp.IndexOf('\\'); 496 | if (cuttmp>0) // have submountpoint like mp1\mp2 497 | { 498 | mp = mp.Substring(0, cuttmp); 499 | } 500 | 501 | if (!files.Select(file => file.FileName).Contains(mp) && mp != "") 502 | { 503 | FileInformation fi = new FileInformation(); 504 | fi.FileName = mp; 505 | fi.Attributes = FileAttributes.NotContentIndexed | FileAttributes.Directory | FileAttributes.ReparsePoint | FileAttributes.Offline; 506 | fi.CreationTime = DateTime.Now; 507 | fi.LastWriteTime = DateTime.Now; 508 | fi.LastAccessTime = DateTime.Now; 509 | 510 | files.Add(fi); 511 | } 512 | } 513 | 514 | return NtStatus.Success; 515 | } 516 | 517 | NtStatus IDokanOperations.SetFileAttributes(string fileName, FileAttributes attributes, DokanFileInfo info) 518 | { 519 | Log("VFS TrySetAttributes:{0}\n{1};", fileName, attributes); 520 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 521 | if (drive != null) 522 | return GetSubSystemOperations(drive).SetFileAttributes(fileName, attributes, info); 523 | 524 | return NtStatus.AccessDenied; 525 | } 526 | 527 | NtStatus IDokanOperations.SetFileTime(string fileName, DateTime? creationTime, DateTime? lastAccessTime, 528 | DateTime? lastWriteTime, DokanFileInfo info) 529 | { 530 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 531 | if (drive != null) 532 | return GetSubSystemOperations(drive).SetFileTime(fileName, creationTime, lastAccessTime, lastWriteTime, info); 533 | 534 | return NtStatus.AccessDenied; 535 | } 536 | 537 | NtStatus IDokanOperations.DeleteFile(string fileName, DokanFileInfo info) 538 | { 539 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 540 | if (drive != null) 541 | return GetSubSystemOperations(drive).DeleteFile(fileName, info); 542 | 543 | return NtStatus.AccessDenied; 544 | } 545 | 546 | NtStatus IDokanOperations.DeleteDirectory(string fileName, DokanFileInfo info) 547 | { 548 | Log("VFS DeleteDirectory:{0}", fileName); 549 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 550 | if (drive != null) 551 | return GetSubSystemOperations(drive).DeleteDirectory(fileName, info); 552 | 553 | return NtStatus.AccessDenied; 554 | } 555 | 556 | NtStatus IDokanOperations.MoveFile(string oldName, string newName, bool replace, DokanFileInfo info) 557 | { 558 | Log("VFS MoveFile |Name:{0} ,NewName:{3},Reaplace{4},IsDirectory:{1} ,Context:{2}", 559 | oldName, info.IsDirectory, 560 | info.Context, newName, replace); 561 | //todo: check newname? 562 | SftpDrive drive = this.GetDriveByMountPoint(oldName, out oldName); 563 | if (drive != null) 564 | { 565 | SftpDrive drive2 = this.GetDriveByMountPoint(newName, out newName); 566 | if (drive2 != drive) 567 | { 568 | //This is server2server move - Total commander handles this by copy&delete, explorer ends with error 569 | //background direct copy between 2 sftp is nice but not real 570 | return NtStatus.NotImplemented; 571 | } 572 | 573 | return GetSubSystemOperations(drive).MoveFile(oldName, newName, replace, info); 574 | } 575 | 576 | return NtStatus.AccessDenied; 577 | } 578 | 579 | NtStatus IDokanOperations.SetEndOfFile(string fileName, long length, DokanFileInfo info) 580 | { 581 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 582 | if (drive != null) 583 | return GetSubSystemOperations(drive).SetEndOfFile(fileName,length, info); 584 | return NtStatus.AccessDenied; 585 | } 586 | 587 | NtStatus IDokanOperations.SetAllocationSize(string fileName, long length, DokanFileInfo info) 588 | { 589 | Log("VFS SetSize"); 590 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 591 | if (drive != null) 592 | return GetSubSystemOperations(drive).SetAllocationSize(fileName, length, info); 593 | 594 | return NtStatus.AccessDenied; 595 | } 596 | 597 | NtStatus IDokanOperations.LockFile(string fileName, long offset, long length, DokanFileInfo info) 598 | { 599 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 600 | if (drive != null) 601 | return GetSubSystemOperations(drive).LockFile(fileName, offset, length, info); 602 | 603 | return NtStatus.AccessDenied; 604 | } 605 | 606 | NtStatus IDokanOperations.UnlockFile(string fileName, long offset, long length, DokanFileInfo info) 607 | { 608 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 609 | if (drive != null) 610 | return GetSubSystemOperations(drive).UnlockFile(fileName, offset, length, info); 611 | return NtStatus.AccessDenied; 612 | } 613 | 614 | NtStatus IDokanOperations.GetDiskFreeSpace(out long free, out long total, 615 | out long used, DokanFileInfo info) 616 | { 617 | Log("VFS GetDiskFreeSpace"); 618 | if (lastActiveSubsytem != null) 619 | { 620 | IDokanOperations ops = GetSubSystemOperations(lastActiveSubsytem); 621 | if (ops != null) 622 | { 623 | return ops.GetDiskFreeSpace(out free, out total, out used, info); 624 | } 625 | } 626 | 627 | long terabyte = (long)1024 * 1024 * 1024 * 1024; 628 | 629 | total = 10*terabyte;//1TB for Explorer to see space 630 | used = terabyte; 631 | free = total - used; 632 | 633 | return NtStatus.Success; 634 | } 635 | 636 | NtStatus IDokanOperations.GetVolumeInformation(out string volumeLabel, out FileSystemFeatures features, 637 | out string filesystemName, DokanFileInfo info) 638 | { 639 | LogFSActionSuccess("DiskInfo", _volumeLabel, null, ""); 640 | 641 | volumeLabel = _volumeLabel; 642 | 643 | filesystemName = "SSHVFS"; 644 | 645 | features = FileSystemFeatures.CasePreservedNames | FileSystemFeatures.CaseSensitiveSearch | 646 | FileSystemFeatures.SupportsRemoteStorage | FileSystemFeatures.UnicodeOnDisk | FileSystemFeatures.SupportsObjectIDs; 647 | //FileSystemFeatures.PersistentAcls 648 | 649 | 650 | return NtStatus.Success; 651 | } 652 | 653 | NtStatus IDokanOperations.GetFileSecurity(string fileName, out FileSystemSecurity security, 654 | AccessControlSections sections, DokanFileInfo info) 655 | { 656 | Log("VFS GetSecurrityInfo:{0}:{1}", fileName, sections); 657 | 658 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 659 | if (drive != null) 660 | return GetSubSystemOperations(drive).GetFileSecurity(fileName, out security, sections, info); 661 | 662 | security = null; 663 | return NtStatus.AccessDenied; 664 | } 665 | 666 | NtStatus IDokanOperations.SetFileSecurity(string fileName, FileSystemSecurity security, 667 | AccessControlSections sections, DokanFileInfo info) 668 | { 669 | Log("VFS TrySetSecurity:{0}", fileName); 670 | SftpDrive drive = this.GetDriveByMountPoint(fileName, out fileName); 671 | if (drive != null) 672 | return GetSubSystemOperations(drive).SetFileSecurity(fileName, security, sections, info); 673 | 674 | return NtStatus.AccessDenied; 675 | } 676 | 677 | NtStatus IDokanOperations.Unmounted(DokanFileInfo info) 678 | { 679 | Log("UNMOUNTED"); 680 | // Disconnect(); 681 | return NtStatus.Success; 682 | } 683 | 684 | NtStatus IDokanOperations.Mounted(DokanFileInfo info) 685 | { 686 | Log("MOUNTED"); 687 | return NtStatus.Success; 688 | } 689 | 690 | NtStatus IDokanOperations.FindStreams(string fileName, out IList streams, DokanFileInfo info) 691 | { 692 | streams = new FileInformation[0]; 693 | return NtStatus.NotImplemented; 694 | } 695 | 696 | #endregion 697 | 698 | /* 699 | #region Events 700 | 701 | public event EventHandler Disconnected 702 | { 703 | add { Session.Disconnected += value; } 704 | remove { Session.Disconnected -= value; } 705 | } 706 | 707 | #endregion*/ 708 | } 709 | } -------------------------------------------------------------------------------- /Sshfs/Sshfs/WinSSH4e1-public.snk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/WinSSH4e1-public.snk -------------------------------------------------------------------------------- /Sshfs/Sshfs/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 300 22 | 23 | 24 | 60 25 | 26 | 27 | False 28 | 29 | 30 | False 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/app.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/app.ico -------------------------------------------------------------------------------- /Sshfs/Sshfs/app.manifest: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 53 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /Sshfs/Sshfs/ssh.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/Sshfs/Sshfs/ssh.ico -------------------------------------------------------------------------------- /Sshfs/WinSSHFS-setup/Product.wxs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 34 | 35 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /Sshfs/WinSSHFS-setup/WinSshFs Installer.wixproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 3.10 7 | 9552311d-f6b4-43f6-8859-7c3b41a4311d 8 | 2.0 9 | WinSSHFS-setup 10 | Package 11 | $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets 12 | $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets 13 | WinSshFs Installer 14 | 15 | 16 | bin\$(Configuration)\ 17 | obj\$(Configuration)\ 18 | Debug 19 | 20 | 21 | bin\$(Configuration)\ 22 | obj\$(Configuration)\ 23 | 24 | 25 | 26 | 27 | 28 | 29 | Sshfs 30 | {ff4fc8bb-91a3-45ff-8449-650647610394} 31 | True 32 | True 33 | Binaries;Content 34 | INSTALLFOLDER 35 | 36 | 37 | 38 | 46 | -------------------------------------------------------------------------------- /Sshfs/appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.6.0.{build} 2 | 3 | # enable patching of AssemblyInfo.* files 4 | assembly_info: 5 | patch: true 6 | file: AssemblyInfo.* 7 | assembly_version: "1.6.0.{build}" 8 | assembly_file_version: "{version}" 9 | assembly_informational_version: "{version}" -------------------------------------------------------------------------------- /Sshfs/showPublicKeyFile.bat: -------------------------------------------------------------------------------- 1 | "c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64\sn.exe" -p sshfs\WinSSH4e1-public.snk WinSSH4e1.pub 2 | "c:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64\sn.exe" -tp WinSSH4e1.pub 3 | pause 4 | del WinSSH4e1.pub -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/feo-cz/win-sshfs/dcb33f3ff1c01533144f44f0a39d1315d03b3668/TODO -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 4 | 5 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 6 | 7 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 8 | 9 | * Neither the name of RENCI nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 10 | 11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /license2: -------------------------------------------------------------------------------- 1 | Copyright (c) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /post-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ ! -f .gitcommit.amend.user ]; then 4 | echo `date` > .gitcommit.amend.user 5 | 6 | ./version.hook.sh 7 | git add Sshfs/Sshfs/Properties/AssemblyInfo.cs 8 | git commit --amend -C HEAD --no-verify 9 | 10 | rm .gitcommit.amend.user 11 | fi -------------------------------------------------------------------------------- /runversionhook.bat: -------------------------------------------------------------------------------- 1 | "%SYSTEMDRIVE%\Program Files\Git\bin\bash.exe" --login version.hook.sh 2 | pause -------------------------------------------------------------------------------- /version.hook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Git Post Merge Hook 3 | #--------------------- 4 | #Gets the latest tag info from the git repo and updates the AssemblyInfo.cs file with it. 5 | #This file needs to be place in the .git/hooks/ folder and only works when a git pull is 6 | #made which contains changes in the remote repo. 7 | 8 | PRODUCT="WinSshFS Foreveryone" 9 | 10 | #get the latest tag info. The 'always' flag will give you a shortened SHA1 if no tag exists. 11 | tag=$(git describe --tags --long) 12 | BRANCH=$(git rev-parse --abbrev-ref HEAD) 13 | 14 | #tag="A.B.C.D-X-hash" 15 | echo $tag 16 | 17 | AI="Sshfs/Sshfs/Properties/AssemblyInfo.cs" 18 | 19 | #If no tag has been added only the sha1 will be returned 20 | if [[ $tag=="*.*" ]] 21 | then 22 | IFS='-' read -ra PARTS <<< "$tag" 23 | 24 | IFS='.' read -ra TAG <<< "${PARTS[0]}" 25 | #echo "${TAG[2]}" 26 | #echo "${TAG[3]}" 27 | 28 | IFS='-' read -ra COMMITS <<< "${PARTS[1]}" 29 | #echo "${COMMITS[0]}" 30 | 31 | #This will be the version in the format .. (. remove revision, amend of version inside will be ok with this) 32 | version="${TAG[0]}"."${TAG[1]}"."${TAG[2]}"."${COMMITS[0]}" 33 | echo $version 34 | 35 | #Update the AssemblyVersion and AssemblyFileVersion attribute with the 'version' 36 | sed -i.bak "s/\AssemblyVersion(\".*\")/AssemblyVersion(\"$version\")/g" $AI 2>/dev/null 37 | sed -i.bak "s/\AssemblyFileVersion(\".*\")/AssemblyFileVersion(\"$version\")/g" $AI 2>/dev/null 38 | sed -i.bak "s/AssemblyProduct(\".*\")/AssemblyProduct(\"$PRODUCT $version-${BRANCH}\")/g" $AI 2>/dev/null 39 | #cat $AI 40 | fi 41 | --------------------------------------------------------------------------------