API Reference

SmbClient

SmbClient is the entry point for all SMB operations. You obtain an instance by calling the connect() factory function, which negotiates the protocol, authenticates, and returns a connected client. SmbClient implements Closeable and should be closed when you are finished to release the underlying TCP connection.

connect()

Suspend function that establishes an authenticated SMB session with the remote host.

suspend fun SmbClient.Companion.connect(
    host: String,
    credentials: SmbCredentials,
    port: Int = 445,
    config: SmbConfig = SmbConfig()
): SmbClient
Parameter Type Default Description
host String Hostname or IP address of the SMB server
credentials SmbCredentials Authentication credentials (e.g. NtlmCredentials)
port Int 445 TCP port for the SMB service
config SmbConfig SmbConfig() Optional configuration for encryption, chunking, licensing, etc.

Throws:

  • SmbLicenseException — license is missing, expired, or invalid
  • SmbConnectionException — TCP connection or protocol negotiation failed
  • SmbAuthenticationException — credentials were rejected by the server

connectShare()

Connects to a named share on the server and returns an SmbShare for performing file operations.

suspend fun connectShare(shareName: String): SmbShare
Parameter Type Description
shareName String Name of the share to connect to (e.g. "Documents")

close()

Closes the SMB session and releases the underlying TCP connection. Safe to call multiple times.

fun close()

Example

import com.ctreesoft.smb.SmbClient
import com.ctreesoft.smb.SmbConfig
import com.ctreesoft.smb.auth.NtlmCredentials
import com.ctreesoft.smb.license.SmbLicense

val license = SmbLicense.fromFile("/path/to/smb.lic")
val config = SmbConfig(license = license)
val credentials = NtlmCredentials("user", "password", "DOMAIN")

val client = SmbClient.connect("192.168.1.100", credentials, config = config)
try {
    val share = client.connectShare("Documents")
    // ... perform file operations ...
    share.close()
} finally {
    client.close()
}

NtlmCredentials

A data class implementing SmbCredentials that provides NTLM authentication parameters. This is the standard authentication method for SMB connections to Windows servers and Samba.

data class NtlmCredentials(
    val username: String,
    val password: String,
    val domain: String = ""
) : SmbCredentials
Parameter Type Default Description
username String The user account name
password String The user password
domain String "" Windows domain or workgroup name. Empty string for standalone servers.

Example

// Domain-joined user
val corporate = NtlmCredentials("jsmith", "s3cret", "ACME")

// Standalone server — domain can be omitted
val local = NtlmCredentials("admin", "password123")

SmbConfig

A data class that controls session-level behavior including transfer chunk sizing, SMB3 encryption, custom socket factories, address resolution, and licensing. All fields have sensible defaults — you only need to provide a license for production use.

data class SmbConfig(
    val transferChunkSize: TransferChunkSize = TransferChunkSize.Default,
    val forceEncryption: Boolean = false,
    val socketFactory: SmbSocketFactory? = null,
    val resolveAddresses: Boolean = false,
    val license: SmbLicense? = null
)
Parameter Type Default Description
transferChunkSize TransferChunkSize Default Controls the maximum read/write chunk size per SMB request
forceEncryption Boolean false When true, requires SMB3 encryption. Connection fails if the server does not support it.
socketFactory SmbSocketFactory? null Custom socket factory for managed environments (e.g. BlackBerry Dynamics)
resolveAddresses Boolean false When true, resolves hostnames to IP addresses before connecting. Useful when DNS returns names that the transport layer cannot resolve.
license SmbLicense? null License for production use. See Licensing.

TransferChunkSize

Controls the maximum number of bytes read or written in a single SMB request. Larger chunks reduce round trips but use more memory.

Mode Description
TransferChunkSize.Default 64 KB per request. Safe for all servers and networks.
TransferChunkSize.ServerMax Negotiates up to the server maximum (typically 8 MB). Best throughput on fast networks.
TransferChunkSize.Custom(bytes: Int) Explicit chunk size in bytes. Clamped to the server maximum at runtime.

Example

import com.ctreesoft.smb.SmbConfig
import com.ctreesoft.smb.TransferChunkSize
import com.ctreesoft.smb.license.SmbLicense

// Minimal config with just a license
val config = SmbConfig(
    license = SmbLicense.fromFile("/path/to/smb.lic")
)

// High-throughput config with encryption
val fastConfig = SmbConfig(
    transferChunkSize = TransferChunkSize.ServerMax,
    forceEncryption = true,
    license = SmbLicense.fromFile("/path/to/smb.lic")
)

// Custom chunk size
val customConfig = SmbConfig(
    transferChunkSize = TransferChunkSize.Custom(256 * 1024) // 256 KB
)

SmbShare

Represents a connected share on an SMB server. All file and directory operations are performed through this class. Paths are relative to the share root and use backslash (\) or forward slash (/) separators — both are accepted and normalized internally.

listDirectory()

Returns a Flow of SmbFileEntry objects for each item in the specified directory. Results are emitted as they arrive from the server.

fun listDirectory(path: String): Flow<SmbFileEntry>
Parameter Type Description
path String Directory path relative to the share root. Use "" for the root.

readFile()

Opens a file for reading and passes an Okio Source to the provided block. The file handle is closed automatically when the block returns.

suspend fun <T> readFile(
    path: String,
    block: suspend (Source) -> T
): T
Parameter Type Description
path String File path relative to the share root
block suspend (Source) -> T Lambda that reads from the source and returns a result

writeFile()

Opens a file for writing (creating or overwriting) and passes an Okio Sink to the provided block. The file handle is closed and flushed automatically when the block returns.

suspend fun writeFile(
    path: String,
    block: suspend (Sink) -> Unit
)
Parameter Type Description
path String File path relative to the share root
block suspend (Sink) -> Unit Lambda that writes data to the sink

createDirectory()

Creates a directory at the specified path.

suspend fun createDirectory(path: String)

delete()

Deletes a single file or empty directory.

suspend fun delete(path: String)

deleteRecursively()

Deletes a directory and all of its contents recursively.

suspend fun deleteRecursively(path: String)

copyFile()

Copies a file from one path to another within the same share. Uses server-side copy when supported.

suspend fun copyFile(sourcePath: String, destinationPath: String)
Parameter Type Description
sourcePath String Path of the file to copy
destinationPath String Path for the new copy

rename()

Renames or moves a file or directory within the same share.

suspend fun rename(sourcePath: String, destinationPath: String)
Parameter Type Description
sourcePath String Current path of the file or directory
destinationPath String New path for the file or directory

close()

Disconnects from the share. Safe to call multiple times.

fun close()

Example

import com.ctreesoft.smb.SmbClient
import com.ctreesoft.smb.SmbConfig
import com.ctreesoft.smb.auth.NtlmCredentials
import com.ctreesoft.smb.license.SmbLicense
import kotlinx.coroutines.flow.collect
import okio.buffer

val license = SmbLicense.fromFile("/path/to/smb.lic")
val client = SmbClient.connect(
    host = "192.168.1.100",
    credentials = NtlmCredentials("user", "password"),
    config = SmbConfig(license = license)
)

val share = client.connectShare("Projects")

// List files in a directory
share.listDirectory("reports/2026").collect { entry ->
    println("${entry.name} — ${entry.size} bytes")
}

// Read a file into a string
val text = share.readFile("reports/2026/summary.txt") { source ->
    source.buffer().readUtf8()
}

// Write a file
share.writeFile("reports/2026/notes.txt") { sink ->
    sink.buffer().use { buf ->
        buf.writeUtf8("Meeting notes for Q1...")
    }
}

// Create, copy, rename, delete
share.createDirectory("reports/2026/archive")
share.copyFile("reports/2026/summary.txt", "reports/2026/archive/summary-backup.txt")
share.rename("reports/2026/notes.txt", "reports/2026/archive/notes.txt")
share.delete("reports/2026/archive/summary-backup.txt")
share.deleteRecursively("reports/2026/archive")

share.close()
client.close()

SmbFileEntry

A data class representing a file or directory entry returned by listDirectory(). All timestamp fields use java.time.Instant.

data class SmbFileEntry(
    val name: String,
    val size: Long,
    val isDirectory: Boolean,
    val isReadOnly: Boolean,
    val isHidden: Boolean,
    val creationTime: Instant,
    val lastModifiedTime: Instant,
    val lastAccessTime: Instant
)
Property Type Description
name String File or directory name (not the full path)
size Long File size in bytes. Always 0 for directories.
isDirectory Boolean true if this entry is a directory
isReadOnly Boolean true if the read-only attribute is set
isHidden Boolean true if the hidden attribute is set
creationTime Instant When the file was created
lastModifiedTime Instant When the file was last written to
lastAccessTime Instant When the file was last read

Example

share.listDirectory("documents").collect { entry ->
    if (entry.isDirectory) {
        println("[DIR]  ${entry.name}")
    } else {
        println("[FILE] ${entry.name} (${entry.size} bytes, modified ${entry.lastModifiedTime})")
    }
}

SmbLicense

Factory for loading license files required for production use. License files are Ed25519-signed plain-text documents issued by CTreeSoft. See Licensing for the file format and embedding instructions.

Factory Methods

object SmbLicense {
    fun fromFile(file: File): SmbLicense
    fun fromStream(inputStream: InputStream): SmbLicense
    fun fromString(text: String): SmbLicense
}
Method Parameter Description
fromFile file: File Load a license from a .lic file on disk
fromStream inputStream: InputStream Load a license from any input stream (Android assets, classpath resources, etc.)
fromString text: String Parse a license from its raw text content

Example

// From a file
val license = SmbLicense.fromFile(File("/etc/myapp/smb.lic"))

// From Android assets
val license = SmbLicense.fromStream(context.assets.open("smb.lic"))

// From classpath resources (JVM)
val stream = Thread.currentThread().contextClassLoader
    .getResourceAsStream("smb.lic")
val license = SmbLicense.fromStream(stream!!)

SmbSocketFactory

A functional interface for providing custom Socket instances. This is useful in managed environments such as BlackBerry Dynamics, where all network I/O must go through a vendor-provided socket implementation.

fun interface SmbSocketFactory {
    fun createSocket(): Socket
}

Example

// BlackBerry Dynamics example
import com.good.gd.net.GDSocket

val config = SmbConfig(
    socketFactory = SmbSocketFactory { GDSocket() },
    license = SmbLicense.fromFile("/path/to/smb.lic")
)

val client = SmbClient.connect("server.corp.local", credentials, config = config)

Exception Hierarchy

All exceptions thrown by smb-kotlin extend the abstract SmbException base class. Each subclass represents a specific failure mode so you can catch precisely the errors you want to handle.

SmbException (abstract)
├── SmbConnectionException
│   └── SmbConnectionLostException
├── SmbAuthenticationException
├── SmbAccessDeniedException
├── SmbFileNotFoundException
├── SmbShareNotFoundException
├── SmbFileExistsException
├── SmbDirectoryNotEmptyException
├── SmbDiskFullException
├── SmbProtocolException
└── SmbLicenseException
Exception When Thrown
SmbConnectionException TCP connection failed or protocol negotiation was rejected
SmbConnectionLostException An established connection was dropped mid-operation
SmbAuthenticationException NTLM authentication failed (bad username, password, or domain)
SmbAccessDeniedException The authenticated user lacks permission for the requested operation
SmbFileNotFoundException The target file or directory does not exist
SmbShareNotFoundException The named share does not exist on the server
SmbFileExistsException A create or rename would overwrite an existing entry
SmbDirectoryNotEmptyException delete() was called on a non-empty directory (use deleteRecursively() instead)
SmbDiskFullException The server reported insufficient disk space
SmbProtocolException The server sent a malformed or unexpected SMB response
SmbLicenseException License is missing, expired, or signature verification failed

Example

import com.ctreesoft.smb.*

try {
    val client = SmbClient.connect("server", credentials, config = config)
    val share = client.connectShare("Documents")
    share.readFile("secret/report.docx") { source ->
        source.buffer().readByteArray()
    }
} catch (e: SmbAuthenticationException) {
    println("Login failed: ${e.message}")
} catch (e: SmbAccessDeniedException) {
    println("Permission denied: ${e.message}")
} catch (e: SmbFileNotFoundException) {
    println("File not found: ${e.message}")
} catch (e: SmbConnectionLostException) {
    println("Connection dropped: ${e.message}")
} catch (e: SmbException) {
    println("SMB error: ${e.message}")
}