HOME BLOG

Archive for the ‘C#’ Category

How to access Shared Directories on Operating Systems that support SMB protocol using SMBLibrary

Posted on: April 27th, 2025 by Olu No Comments

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.

How to create objects with dynamic field names in C#

Posted on: December 18th, 2024 by Olu No Comments

Hi Folks,

In this post I’ll talk briefly about how to create objects with dynamic fields on the fly in a C# application.

First of all, why is this important?

An example is if you’re developing an API that returns some data where the fields are calculated at runtime.

This means you can’t anticipate what it would be before hand and create classes ahead of time.

In C# we use what is called ExpandoObject.

ExpandoObject represents an object whose members can be dynamically added or removed at runtime.

To create an ExpandoObject instance, you do something like

 

dynamic row = new ExpandoObject();

 

To set a field whose name you know at compile time, do something like

 

row.SomeField = somevalue

 

To set a field whose name you don’t know ahead of time, but whose name is stored in the value of another object, say fieldNameHolder, to some value stored in a variable, say fieldValueHolder, do something like

 

(IDictionary<string, object>row).Add(fieldNameHolder, fieldValueHolder);

 

That’s all for now. Till next time, happy software development.

 

References

ExpandoObject Class. Microsoft Learn. https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-9.0M