-
Notifications
You must be signed in to change notification settings - Fork 86
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
add support to compile this lib for windows #163
Comments
Why? |
@jbkempf Basically the project I'm working on needs to access backup file servers that use SMB and copy some files to another server via SFTP in order to restore files. My code to solve this problem temporarily. using Renci.SshNet;
using SMBLibrary;
using SMBLibrary.Client;
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
namespace dicom_lib;
public enum ErrorCode : int
{
Success = 0,
Unknown = -1,
ConnectionLost = 400,
ServerLoginFailure = 401,
FailedAccessServer = 402,
FailedAccessShare = 403,
FailedAccessFile = 404,
InvalidInstance = 405,
UninitializedFileStore = 406
}
static class ErrorCodeExtensions
{
public static int AsInt(this ErrorCode v)
{
return (int)v;
}
}
public struct SmbInstanceNative
{
public int smbInstanceId;
public int errorCode;
}
public class SmbInstance
{
public SMB2Client client;
public SMB2FileStore fileStore;
public int id;
}
public class DicomLib
{
private static int countSmbInstance = -1;
private static List<SmbInstance> smbInstances = new();
private static string erroMessage = "";
private static SmbInstance GetSmb(int id)
{
foreach (var item in smbInstances)
{
if (item.id == id)
{
return item;
}
}
return null;
}
[UnmanagedCallersOnly(EntryPoint = "initSmb")]
public static SmbInstanceNative InitSmb()
{
try
{
var client = new SMB2Client();
countSmbInstance++;
var instanceSmb = new SmbInstance()
{
client = client,
id = countSmbInstance,
};
smbInstances.Add(instanceSmb);
return new SmbInstanceNative() { smbInstanceId = countSmbInstance, errorCode = ErrorCode.Success.AsInt() };
}
catch (Exception e)
{
erroMessage = $"Unknown error: {e}";
Console.WriteLine(erroMessage);
return new SmbInstanceNative()
{
smbInstanceId = -1,
errorCode = ErrorCode.Unknown.AsInt()
};
}
}
[UnmanagedCallersOnly(EntryPoint = "connectSmb")]
public static int ConnectSmb(SmbInstanceNative smbInstanceNative, IntPtr pIpSmb,
IntPtr pDomainSmb,
IntPtr pUserSmb,
IntPtr pPassSmb)
{
try
{
string ipSmb = Marshal.PtrToStringAnsi(pIpSmb);
string domainSmb = Marshal.PtrToStringAnsi(pDomainSmb);
string userSmb = Marshal.PtrToStringAnsi(pUserSmb);
string passSmb = Marshal.PtrToStringAnsi(pPassSmb);
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
var client = instance.client;
var isSmbConnected = client.Connect(System.Net.IPAddress.Parse(ipSmb), SMBTransportType.DirectTCPTransport);
if (isSmbConnected)
{
var status = client.Login(domainSmb, userSmb, passSmb);
if (status == NTStatus.STATUS_SUCCESS)
{
return ErrorCode.Success.AsInt();
}
else
{
erroMessage = $"Failed to login {status}";
Console.WriteLine(erroMessage);
return ErrorCode.ServerLoginFailure.AsInt();
}
}
else
{
erroMessage = "Failed to access the server";
Console.WriteLine(erroMessage);
return ErrorCode.FailedAccessServer.AsInt();
}
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "disconnectSmb")]
public static int DisconnectSmb(SmbInstanceNative smbInstanceNative)
{
try
{
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
var client = instance.client;
client.Disconnect();
return ErrorCode.Success.AsInt();
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "freeSmb")]
public static int FreeSmb(SmbInstanceNative smbInstanceNative)
{
try
{
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
smbInstances.Remove(instance);
return ErrorCode.Success.AsInt();
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "openShareSmb")]
public static int OpenShareSmb(SmbInstanceNative smbInstanceNative, IntPtr pShareSmb)
{
try
{
string shareSmb = Marshal.PtrToStringAnsi(pShareSmb);
Console.WriteLine($"OpenShareSmb shareSmb {shareSmb}");
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
var client = instance.client;
var status = NTStatus.STATUS_SUCCESS;
var fileStore = client.TreeConnect(shareSmb, out status) as SMB2FileStore;
if (fileStore != null && status == NTStatus.STATUS_SUCCESS)
{
instance.fileStore = fileStore;
return ErrorCode.Success.AsInt();
}
erroMessage = $"Failed to Access Share {status}";
Console.WriteLine(erroMessage);
return ErrorCode.FailedAccessShare.AsInt();
}
catch (Exception ex)
{
erroMessage = $"Unknown error: {ex}";
Console.WriteLine(erroMessage);
return ErrorCode.Unknown.AsInt();
}
}
[UnmanagedCallersOnly(EntryPoint = "getLastError")]
public static IntPtr GetLastError()
{
// Assign pointer of the concatenated string to sumPointer
IntPtr sumPointer = Marshal.StringToHGlobalAnsi(erroMessage);
// Return pointer
return sumPointer;
}
[UnmanagedCallersOnly(EntryPoint = "downloadFileSmb")]
public static int DownloadFileSmb(SmbInstanceNative smbInstanceNative, IntPtr pRemotePathSmb, IntPtr pDestLocalPath)
{
try
{
var retCode = ErrorCode.Success.AsInt();
string remotePathSmb = Marshal.PtrToStringAnsi(pRemotePathSmb);
string destLocalPath = Marshal.PtrToStringAnsi(pDestLocalPath);
Console.WriteLine($"remotePathSmb: {remotePathSmb}");
Console.WriteLine($"destLocalPath: {destLocalPath}");
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
if (instance.fileStore == null)
{
erroMessage = $"uninitialized fileStore use OpenShareSmb before";
Console.WriteLine(erroMessage);
return ErrorCode.UninitializedFileStore.AsInt();
}
object handle;
FileStatus fileStatus;
// Open existing file for reading
var status = instance.fileStore.CreateFile(out handle, out fileStatus, remotePathSmb,
AccessMask.GENERIC_READ, 0, ShareAccess.Read,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE, null);
if (status == NTStatus.STATUS_SUCCESS)
{
using (var memoryStream = new MemoryStream())
{
byte[] buffer;
int bufferLeng = 4096;
long offset = 0;
while (true)
{
status = instance.fileStore.ReadFile(out buffer, handle, offset, bufferLeng);
if (status == NTStatus.STATUS_END_OF_FILE)
{
break;
}
if (status != NTStatus.STATUS_SUCCESS)
{
retCode = ErrorCode.FailedAccessFile.AsInt();
Console.WriteLine("Failed to access file");
break;
}
//(int)offset
memoryStream.Write(buffer, 0, buffer.Length);
offset += buffer.Length;
}
instance.fileStore.CloseFile(handle);
using (var file = new FileStream(destLocalPath, FileMode.Create, System.IO.FileAccess.Write))
{
memoryStream.Seek(0, SeekOrigin.Begin);
memoryStream.CopyTo(file);
memoryStream.Close();
file.Close();
Console.WriteLine($"end of file copy");
}
}
}
else
{
Console.WriteLine($"Failed to access file, {status}");
return ErrorCode.FailedAccessFile.AsInt();
}
return retCode;
}
catch (Exception e)
{
Console.WriteLine($"Unknown error: {e}");
return ErrorCode.Unknown.AsInt();
}
}
// callbackDownload (bytesCopied, bytesTotal)
[UnmanagedCallersOnly(EntryPoint = "copyFileFromSMBtoSFTP")]
public unsafe static int CopyFileFromSMBtoSFTP(SmbInstanceNative smbInstanceNative,
IntPtr pRemotePathSmb,
IntPtr pDestSftpPath,
IntPtr pIpSftpServer,
int portSftpServer,
IntPtr pUserSftp,
IntPtr pPassSftp,
int pBufferLeng,
delegate* unmanaged<long, long, int> downloadCallback,
delegate* unmanaged<long, long, int> uploadCallback
)
{
try
{
var retCode = ErrorCode.Success.AsInt();
string remotePathSmb = Marshal.PtrToStringAnsi(pRemotePathSmb);
string destSftpPath = Marshal.PtrToStringAnsi(pDestSftpPath);
string ipSftpServer = Marshal.PtrToStringAnsi(pIpSftpServer);
string userSftp = Marshal.PtrToStringAnsi(pUserSftp);
string passSftp = Marshal.PtrToStringAnsi(pPassSftp);
Console.WriteLine($"CopyFileFromSMBtoSFTP remotePathSmb: {remotePathSmb}");
Console.WriteLine($"CopyFileFromSMBtoSFTP destSftpPath {destSftpPath}");
Console.WriteLine($"CopyFileFromSMBtoSFTP ipSftpServer {ipSftpServer}");
var instance = GetSmb(smbInstanceNative.smbInstanceId);
if (instance == null)
{
erroMessage = $"invalid instance id";
Console.WriteLine(erroMessage);
return ErrorCode.InvalidInstance.AsInt();
}
if (instance.fileStore == null)
{
erroMessage = $"uninitialized fileStore use OpenShareSmb";
Console.WriteLine(erroMessage);
return ErrorCode.UninitializedFileStore.AsInt();
}
object handle;
FileStatus fileStatus;
// Open existing file for reading
var status = instance.fileStore.CreateFile(out handle, out fileStatus, remotePathSmb,
AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE,
SMBLibrary.FileAttributes.Normal, ShareAccess.Read,
CreateDisposition.FILE_OPEN,
CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT
, null);
//get File Informations
FileInformation fileInformationClass;
long bytesTotal = 0;
status = instance.fileStore.GetFileInformation(out fileInformationClass, handle, FileInformationClass.FileAllInformation);
if(status == NTStatus.STATUS_SUCCESS && fileInformationClass != null)
{
bytesTotal = fileInformationClass.Length;
if (downloadCallback != null)
{
//bytesCopied, bytesTotal
downloadCallback(0, bytesTotal);
}
}
if (status == NTStatus.STATUS_SUCCESS)
{
using (var memoryStream = new MemoryStream())
{
byte[] buffer;
int bufferLeng = pBufferLeng > 1 ? pBufferLeng : (int)instance.client.MaxReadSize;
long bytesRead = 0;
while (true)
{
status = instance.fileStore.ReadFile(out buffer, handle, bytesRead, bufferLeng);
if (downloadCallback != null)
{
//bytesCopied, bytesTotal
downloadCallback(bytesRead, bytesTotal);
}
if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE)
{
retCode = ErrorCode.FailedAccessFile.AsInt();
Console.WriteLine("Failed to access file");
break;
}
if (status == NTStatus.STATUS_END_OF_FILE || buffer.Length == 0)
{
break;
}
bytesRead += buffer.Length;
memoryStream.Write(buffer, 0, buffer.Length);
}
instance.fileStore.CloseFile(handle);
try
{
using (SftpClient sftp = new SftpClient(ipSftpServer, portSftpServer, userSftp, passSftp))
{
sftp.Connect();
memoryStream.Seek(0, SeekOrigin.Begin);
sftp.UploadFile(memoryStream, destSftpPath, delegate (ulong d)
{
if(uploadCallback != null)
{
uploadCallback((long)d, bytesTotal);
}
});
Console.WriteLine($"end of file copy");
sftp.Disconnect();
}
}catch (Exception ex)
{
Console.WriteLine($"Failed to copy file to SFTP server, {ex}");
return ErrorCode.FailedAccessFile.AsInt();
}
finally
{
memoryStream.Close();
}
}
}
else
{
Console.WriteLine($"Failed to access file, {status}");
return ErrorCode.FailedAccessFile.AsInt();
}
return retCode;
}
catch (Exception e)
{
Console.WriteLine($"Unknown error: {e}");
return ErrorCode.Unknown.AsInt();
}
}
} |
I understand, but Windows has SMB support in, by default. So there should not need a new library for this. |
add support to compile this lib for windows
The text was updated successfully, but these errors were encountered: