Hi Folks,
In this post we will briefly cover how to access files in shared directories on operating systems that support SMB protocol.
First, what’s SMB? SMB means Server Message Block. It is a communication protocol used to share files, printers, serial ports and miscellaneous cmomunications between nodes on a network. SMB was originally developed at IBM and is widely supported in Windows mac OS and Linux.
In this post we will assume you’re programming in C#. Also, we will assume the
A good library for accessing shared drive is SMBLibrary https://github.com/TalAloni/SMBLibrary.
Checking a file exists
The procedure involves creating an instance of SMB2Client, connecting to the share server, logging in, creating a file store using TreeConnect method, and using it to look through the files on the shared directory to see if your desired file exists.
Here’s some sample code you can use for checking if a file exists in a given directory, using SMBLibrary.
string Fullpath = @"\\server\sharename\inner-path\inner-path2\"; var parts = Fullpath.Split('\\'); ShareName = parts[1] PathPrefixInShare = $@"\\{parts[0]}\{ShareName}\"; Boolean exists(string directory, string file) { var result = false; var client = SMB2Client(); string error = null; bool isConnected = client.Connect(IPAddress.Parse("sharehostname", SMBTransportType.DirectTCPTransport); if (isConnected) { NTStatus status = client.Login(String.Empty, "someusername", "somepassword") if (status == NTStatus.STATUS_SUCCESS) { ISMBFileStore fileStore = client.TreeConnect(ShareName, out status); object fileHandle; object directoryHandle; FileStatus fileStatus; if (fileStore is SMB2FileStore) { directory = directory.Replace(PathPrefixInShare, ""); status = fileStore.CreateFile(out directoryHandle, out fileStatus, directory, AccessMask.GENERIC_READ, SMBLibrary.Fileattributes.Directory, ShareAccess.Read | ShareAccess.Write, CreateDisposition.FILE_OPEN, CreateOptions.FILE_DIRECTORY_FILE, null); if (status == NTStatus.STATUS_SUCCESS) { List fileList; status = fileStore.QueryDirectory(out fileList, directoryHandle, "*", FileInformationClass.FileDirectoryInformation); status = fileStore.CloseFile(directoryHandle); foreach(FileDirectoryInformation aFile in fileList) { if (aFile.FileName == file) { result = true; break; } } } status = fileStore.Disconnect(); } else { error = "There was an error accessing data"; } client.Logoff(); } client.Disconnect(); } if (error != null) { throw new Exception(error); } return results; }
Reading a file
The procedure involves creating an instance of SMB2Client, connecting to the share server, logging in, creating a file store using TreeConnect method, then get the inner filepath by stripping parent directories, create a file handle, by calling CreateFile method on the file store, then reading the data (bytes) from the file by calling ReadFile method on the file store.
And here is some sample code for fetching the data in a given file path within a shared drive using SMBLibrary
MemoryStream getTheFileStream(string filePath) { MemoryStream stream = new MemoryStream(); var client = SMB2Client(); string error = null; bool isConnected = client.Connect(IPAddress.Parse("someurl", SMBTransportType.DirectTCPTransport); if (isConnected) { NTStatus status = client.Login(String.Empty, "someuser", "somepassword") if (status == NTStatus.STATUS_SUCCESS) { ISMBFileStore fileStore = client.TreeConnect(ShareName, out status); object fileHandle; FileStatus fileStatus; if (fileStore is SMB2FileStore) { filePath = filePath.Replace(PathPrefixInShare, ""); status = fileStore.CreateFile(out fileHandle, out fileStatus, filePath, AccessMask.GENERIC_READ | AccessMask.SYNCHRONIZE, SMBLibrary.Fileattributes.Normal, ShareAccess.Read, CreateDisposition.FILE_OPEN, CreateOptions.FILE_NON_DIRECTORY_FILE | CreateOptions.FILE_SYNCHRONOUS_IO_ALERT, null); if (status == NTStatus.STATUS_SUCCESS) { byte[] data; long bytesRead = 0; while (true) { status = fileStore.ReadFile(out data, fileHandle, bytesRead, (int)client.MaxReadSize); if (status != NTStatus.STATUS_SUCCESS && status != NTStatus.STATUS_END_OF_FILE) { throw new Exception("failed to read from file"); } if (status == NTStatus.STATUS_END_OF_FILE || data.Length == 0) { break; } bytesRead += data.Length; stream.Write(data, 0, data.Length); } } status = fileStore.CloseFile(fileHandle); status = fileStore.Disconnect(); } else { error = "There was an error accessing data"; } client.Logoff(); } client.Disconnect(); } if (error != null) { throw new Exception(error); } stream.Seek(0, SeekOrigin.Begin); return stream; }
That’s all for now. Till next time, happy software development.