Documentation
¶
Overview ¶
Package smb1 implements a pure Go SMB1/CIFS client library.
Security Warning ¶
SMB1/CIFS is an outdated protocol with known security vulnerabilities. It should only be used with legacy systems that do not support SMB2 or SMB3. For modern systems, use the go-smb2 library instead: https://github.com/hirochachacha/go-smb2
This library is provided for compatibility with old NAS devices, embedded systems, and Windows XP/2003 servers that require SMB1.
Usage ¶
Basic usage example:
package main
import (
"context"
"fmt"
"io"
"log"
"net"
"os"
"github.com/macourteau/smb1client"
)
func main() {
// Connect to SMB server
conn, err := net.Dial("tcp", "192.168.1.100:445")
if err != nil {
panic(err)
}
defer conn.Close()
// Setup authentication
d := &smb1.Dialer{
Initiator: &smb1.NTLMInitiator{
User: "username",
Password: "password",
Domain: "WORKGROUP",
},
}
// Establish SMB session
session, err := d.Dial(conn)
if err != nil {
panic(err)
}
defer session.Logoff()
// Mount share
share, err := session.Mount("Share")
if err != nil {
panic(err)
}
defer share.Umount()
// Open file
f, err := share.Open("file.txt")
if err != nil {
panic(err)
}
defer f.Close()
// Read file
data, err := io.ReadAll(f)
if err != nil {
panic(err)
}
fmt.Printf("File contents: %s\n", data)
}
Logging ¶
This library uses context-based logging. To enable logging, attach a logger to the context before calling SMB operations:
// Create a custom logger
type myLogger struct{}
func (l *myLogger) Debug(format string, v ...interface{}) {
log.Printf("[DEBUG] "+format, v...)
}
func (l *myLogger) Info(format string, v ...interface{}) {
log.Printf("[INFO] "+format, v...)
}
func (l *myLogger) Warn(format string, v ...interface{}) {
log.Printf("[WARN] "+format, v...)
}
func (l *myLogger) Error(format string, v ...interface{}) {
log.Printf("[ERROR] "+format, v...)
}
// Attach logger to context
ctx := smb1.WithLogger(context.Background(), &myLogger{})
// Use context with SMB operations
session, err := d.DialContext(ctx, conn)
API Compatibility ¶
This library provides an API compatible with go-smb2 for easy migration. Code written for go-smb2 can be adapted to SMB1 by changing import paths and adjusting for protocol differences.
Protocol Support ¶
Supported features:
- NTLM v2 authentication
- Share mounting/unmounting
- File read/write operations
- Directory operations (create, list, remove)
- File operations (stat, truncate, rename)
Unsupported features:
- SMB signing (security feature)
- Encryption (not available in SMB1)
- DFS (Distributed File System)
- Extended attributes
For more features and better security, migrate to SMB2/SMB3 using go-smb2: https://github.com/hirochachacha/go-smb2
Example (Compatibility) ¶
Example demonstrates compatibility features
// Path conversion
windowsPath := smb1.ToWindowsPath("dir/subdir/file.txt")
fmt.Println("Windows path:", windowsPath)
unixPath := smb1.ToUnixPath("dir\\subdir\\file.txt")
fmt.Println("Unix path:", unixPath)
// Share name normalization
shareName := smb1.NormalizeShareName("MyShare", "192.168.1.100:445")
fmt.Println("Normalized share:", shareName)
// Validate share name
err := smb1.ValidateShareName("ValidShare")
fmt.Println("Valid share name:", err == nil)
Output: Windows path: dir\subdir\file.txt Unix path: dir/subdir/file.txt Normalized share: \\192.168.1.100\MyShare Valid share name: true
Example (ErrorHandling) ¶
Example demonstrates basic error handling with the SMB1 client
// Connect to SMB server
conn, err := net.DialTimeout("tcp", "192.168.1.100:445", 5*time.Second)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
// Setup authentication
d := &smb1.Dialer{
Initiator: &smb1.NTLMInitiator{
User: "username",
Password: "password",
Domain: "WORKGROUP",
},
}
// Establish SMB session with context timeout
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
session, err := d.DialContext(ctx, conn)
if err != nil {
// Check for specific error types
if smb1.IsAuthError(err) {
log.Fatal("Authentication failed - check username/password")
}
if smb1.IsNetworkError(err) {
log.Fatal("Network error - check connectivity")
}
log.Fatal(err)
}
defer session.Logoff()
// Mount share
share, err := session.Mount("Share")
if err != nil {
log.Fatal(err)
}
defer share.Umount()
// Try to open a file with error handling
file, err := share.Open("nonexistent.txt")
if err != nil {
if smb1.IsNotFoundError(err) {
fmt.Println("File not found - this is expected")
return
}
if smb1.IsPermissionError(err) {
log.Fatal("Permission denied")
}
log.Fatal(err)
}
defer file.Close()
Example (Logging) ¶
Example demonstrates logging configuration with context
package main
import (
"fmt"
)
func main() {
// Note: In real code, define a logger type that implements smb1.Logger interface.
// For this example, we just show the concept.
// Logging is now context-based. To enable logging:
// 1. Create a type that implements the smb1.Logger interface
// 2. Attach it to context using smb1.WithLogger()
// 3. Pass the context to SMB operations
fmt.Println("Logging configured via context")
}
Output: Logging configured via context
Example (RetryLogic) ¶
Example demonstrates retry logic for transient errors
// The library does not retry on your behalf and does not reconnect: once a
// connection fails it stays failed, so a caller that needs durability owns
// the backoff and the redial. IsTemporary classifies which errors are worth
// another attempt.
// Simulated operation that might fail transiently
operation := func() error {
// Your SMB operation here
return nil
}
// Retry on temporary errors
err := operation()
if err != nil && smb1.IsTemporary(err) {
// Back off and try again — or dial a fresh session, if the failure was
// the connection itself (errors.Is(err, net.ErrClosed)).
log.Printf("Temporary error, retrying: %v", err)
}
fmt.Println("Operation completed:", err == nil)
Output: Operation completed: true
Index ¶
- Constants
- Variables
- func FileAttributesToUnixMode(attrs uint32) os.FileMode
- func FileTimeToTime(ft uint64) time.Time
- func IsArchiveFile(attrs uint32) bool
- func IsAuthError(err error) bool
- func IsExistError(err error) bool
- func IsHiddenFile(name string, attrs uint32) bool
- func IsNetworkError(err error) bool
- func IsNotFoundError(err error) bool
- func IsPathSeparator(c uint8) bool
- func IsPermissionError(err error) bool
- func IsSystemFile(attrs uint32) bool
- func IsTemporary(err error) bool
- func IsTimeoutError(err error) bool
- func Match(pattern, name string) (matched bool, err error)
- func NormalizeShareName(shareName, serverAddr string) string
- func TimeToFileTime(t time.Time) uint64
- func ToUnixPath(path string) string
- func ToWindowsPath(path string) string
- func UnixModeToFileAttributes(mode os.FileMode) uint32
- func ValidateShareName(name string) error
- func WithLogger(ctx context.Context, logger Logger) context.Context
- type AuthenticationError
- type Client
- type ConnectionError
- type ConnectionPool
- type ContextError
- type Dialer
- type File
- func (f *File) Chmod(mode os.FileMode) error
- func (f *File) Close() error
- func (f *File) Name() string
- func (f *File) Read(b []byte) (n int, err error)
- func (f *File) ReadAt(b []byte, off int64) (n int, err error)
- func (f *File) ReadFrom(r io.Reader) (n int64, err error)
- func (f *File) Readdir(n int) ([]os.FileInfo, error)
- func (f *File) Readdirnames(n int) (names []string, err error)
- func (f *File) Seek(offset int64, whence int) (int64, error)
- func (f *File) Stat() (os.FileInfo, error)
- func (f *File) Statfs() (FileFsInfo, error)
- func (f *File) Sync() error
- func (f *File) Truncate(size int64) error
- func (f *File) Write(b []byte) (n int, err error)
- func (f *File) WriteAt(b []byte, off int64) (n int, err error)
- func (f *File) WriteString(s string) (n int, err error)
- func (f *File) WriteTo(w io.Writer) (n int64, err error)
- type FileFsInfo
- type FileStat
- type Initiator
- type InternalError
- type InvalidResponseError
- type Logger
- type NTLMInitiator
- type Negotiator
- type PoolConfig
- type PoolStats
- type PooledSession
- func (ps *PooledSession) Close() error
- func (ps *PooledSession) ListSharenames() ([]string, error)
- func (ps *PooledSession) Logoff() error
- func (ps *PooledSession) Mount(sharename string) (*Share, error)
- func (ps *PooledSession) ReallyClose() error
- func (ps *PooledSession) Session() *Session
- func (ps *PooledSession) WithContext(ctx context.Context) *Session
- type RemoteFile
- type RemoteFileStat
- type RemoteFileSystem
- type ResponseError
- type SMBError
- type ServerCapabilities
- type ServerTime
- type Session
- type Share
- func (fs *Share) Chmod(name string, mode os.FileMode) error
- func (fs *Share) Chtimes(name string, atime time.Time, mtime time.Time) error
- func (fs *Share) CopyFile(src, dst string) error
- func (fs *Share) CopyFrom(localPath, remotePath string) error
- func (fs *Share) CopyTo(remotePath, localPath string) error
- func (fs *Share) Create(name string) (*File, error)
- func (s *Share) DirFS(dirname string) fs.FS
- func (fs *Share) Exists(name string) (bool, error)
- func (fs *Share) Glob(pattern string) (matches []string, err error)
- func (fs *Share) IsDir(name string) (bool, error)
- func (fs *Share) Lstat(name string) (os.FileInfo, error)
- func (fs *Share) Mkdir(name string, perm os.FileMode) error
- func (fs *Share) MkdirAll(path string, perm os.FileMode) error
- func (fs *Share) Open(name string) (*File, error)
- func (fs *Share) OpenFile(name string, flag int, perm os.FileMode) (*File, error)
- func (fs *Share) ReadDir(dirname string) ([]os.FileInfo, error)
- func (fs *Share) ReadFile(filename string) ([]byte, error)
- func (fs *Share) Readdir(dirname string, n int) ([]os.FileInfo, error)
- func (fs *Share) Readlink(name string) (string, error)
- func (fs *Share) Remove(name string) error
- func (fs *Share) RemoveAll(path string) error
- func (fs *Share) Rename(oldpath, newpath string) error
- func (fs *Share) Stat(name string) (os.FileInfo, error)
- func (fs *Share) Statfs(name string) (FileFsInfo, error)
- func (fs *Share) Symlink(target, linkpath string) error
- func (fs *Share) Truncate(name string, size int64) error
- func (fs *Share) Umount() error
- func (fs *Share) VolumeInfo() (*VolumeInfo, error)
- func (fs *Share) Walk(root string, walkFn filepath.WalkFunc) error
- func (fs *Share) WithContext(ctx context.Context) *Share
- func (fs *Share) WriteFile(filename string, data []byte, perm os.FileMode) error
- type TransportError
- type VolumeInfo
Examples ¶
Constants ¶
const MaxReadSizeLimit = 0x100000 // deprecated constant
const PathSeparator = '\\'
PathSeparator is the path separator used in SMB paths.
Variables ¶
var ( // ErrPoolClosed is returned when attempting to get a connection from a closed pool. ErrPoolClosed = errors.New("connection pool is closed") // ErrPoolExhausted is returned when the pool has reached its maximum active connections // and no connections are available. ErrPoolExhausted = errors.New("connection pool exhausted") )
var ErrBadPattern = errors.New("syntax error in pattern")
ErrBadPattern indicates a pattern was malformed.
var NORMALIZE_PATH = true
NORMALIZE_PATH controls whether '/' in user-supplied paths and patterns is converted to the SMB separator '\' before use. It is enabled by default; when disabled, paths containing '/' are rejected by validation instead of being rewritten. The variable mirrors go-smb2's of the same name for source compatibility.
Functions ¶
func FileAttributesToUnixMode ¶
FileAttributesToUnixMode converts Windows file attributes to Unix file mode. This provides a best-effort mapping from Windows attributes to Unix permissions.
func FileTimeToTime ¶
FileTimeToTime converts Windows FILETIME (100-nanosecond intervals since 1601-01-01) to Go time.Time.
func IsArchiveFile ¶
IsArchiveFile returns true if the file has the archive bit set. This indicates the file has been modified since last backup.
func IsAuthError ¶
IsAuthError returns true if the error is an authentication failure. This includes invalid credentials, access denied, and logon failures.
func IsExistError ¶
IsExistError returns true if the error indicates a file or object already exists.
func IsHiddenFile ¶
IsHiddenFile returns true if the file should be considered hidden. On Windows, this checks the HIDDEN attribute. On Unix systems, files starting with "." are considered hidden.
func IsNetworkError ¶
IsNetworkError returns true if the error is a network-level error. This includes connection failures, timeouts, and I/O errors.
func IsNotFoundError ¶
IsNotFoundError returns true if the error indicates a file or object was not found. This includes file not found, path not found, and object name not found errors.
func IsPathSeparator ¶
IsPathSeparator reports whether c is the SMB path separator.
func IsPermissionError ¶
IsPermissionError returns true if the error indicates a permission/access denied error.
func IsSystemFile ¶
IsSystemFile returns true if the file is a system file. On Windows, this checks the SYSTEM attribute.
func IsTemporary ¶
IsTemporary returns true if the error is temporary and the operation can be retried. This includes network timeouts, temporary network errors, and transient SMB errors.
func IsTimeoutError ¶
IsTimeoutError returns true if the error indicates a timeout.
func Match ¶
Match reports whether name matches the shell file name pattern. The pattern syntax is:
pattern:
{ term }
term:
'*' matches any sequence of non-Separator characters
'?' matches any single non-Separator character
'[' [ '^' ] { character-range } ']'
character class (must be non-empty)
c matches character c (c != '*', '?', '[')
character-range:
c matches character c (c != '-', ']')
lo '-' hi matches character c for lo <= c <= hi
The separator is the SMB path separator '\'. When NORMALIZE_PATH is enabled, '/' in the pattern reads as '\' and leading ".\" elements are dropped; the name is never rewritten.
Match requires pattern to match all of name, not just a substring. The only possible returned error is ErrBadPattern, when pattern is malformed.
func NormalizeShareName ¶
NormalizeShareName normalizes a share name for mounting. It accepts various formats and converts them to the canonical UNC format.
Accepted formats:
- "ShareName" - just the share name
- "\\server\ShareName" - full UNC path
- "//server/ShareName" - Unix-style UNC path
- "server\ShareName" - UNC without leading slashes
- "server/ShareName" - Unix-style without leading slashes
Returns a normalized UNC path in the format: \\server\ShareName
func TimeToFileTime ¶
TimeToFileTime converts Go time.Time to Windows FILETIME format. Returns a 64-bit value representing 100-nanosecond intervals since January 1, 1601 UTC.
func ToUnixPath ¶
ToUnixPath converts a Windows-style path to Unix-style path. It replaces backslashes with forward slashes.
func ToWindowsPath ¶
ToWindowsPath converts a Unix-style path to Windows-style path. It replaces forward slashes with backslashes and normalizes the path.
func UnixModeToFileAttributes ¶
UnixModeToFileAttributes converts Unix file mode to Windows file attributes. This provides a best-effort mapping from Unix permissions to Windows attributes.
func ValidateShareName ¶
ValidateShareName validates that a share name is valid for SMB. Valid share names:
- Must not be empty
- Must not contain invalid characters: / \ : * ? " < > |
- Must not be longer than 80 characters (Windows limit)
Types ¶
type AuthenticationError ¶
type AuthenticationError struct {
User string // Username that failed to authenticate
Domain string // Domain (if applicable)
Reason string // Human-readable reason for failure
}
AuthenticationError represents authentication failures. This provides more context about why authentication failed.
func (*AuthenticationError) Error ¶
func (e *AuthenticationError) Error() string
type ConnectionError ¶
ConnectionError represents connection-level errors. This includes TCP connection failures, disconnects, and I/O errors.
func (*ConnectionError) Error ¶
func (e *ConnectionError) Error() string
func (*ConnectionError) Unwrap ¶
func (e *ConnectionError) Unwrap() error
type ConnectionPool ¶
type ConnectionPool struct {
// contains filtered or unexported fields
}
ConnectionPool manages a pool of SMB connections for reuse. It provides connection pooling to improve performance for workloads with many short-lived operations by avoiding the overhead of repeatedly establishing TCP connections and performing authentication.
The pool is thread-safe and can be used concurrently from multiple goroutines.
Example usage:
pool := smb1.NewConnectionPool("192.168.1.100:445", dialer, nil)
defer pool.Close()
// Get a connection from the pool
conn, err := pool.Get(ctx)
if err != nil {
return err
}
defer conn.Close() // Returns connection to pool
// Use the connection
share, err := conn.Mount("Public")
...
func NewConnectionPool ¶
func NewConnectionPool(serverAddr string, dialer *Dialer, config *PoolConfig) *ConnectionPool
NewConnectionPool creates a new connection pool.
Parameters:
- serverAddr: The server address (e.g., "192.168.1.100:445")
- dialer: The Dialer with authentication credentials
- config: Pool configuration (nil for defaults)
The pool starts a background goroutine to clean up idle connections. Call Close() when done to release resources and close all connections.
func (*ConnectionPool) Close ¶
func (p *ConnectionPool) Close() error
Close closes the pool and all connections in it. After calling Close, the pool cannot be used.
func (*ConnectionPool) Get ¶
func (p *ConnectionPool) Get(ctx context.Context) (*PooledSession, error)
Get retrieves a connection from the pool or creates a new one.
The returned PooledSession should be closed when done, which returns it to the pool for reuse. To actually close the connection, call ReallyClose().
If the pool is exhausted (MaxActive reached), Get will wait up to WaitTimeout for a connection to become available. If the context is canceled or the timeout expires, an error is returned.
func (*ConnectionPool) Stats ¶
func (p *ConnectionPool) Stats() PoolStats
Stats returns statistics about the pool.
type ContextError ¶
type ContextError struct {
Err error
}
ContextError wraps a context cancellation or deadline error surfaced by a public API call, so that os.IsTimeout recognises deadline expiry. The type mirrors go-smb2's ContextError for source compatibility.
func (*ContextError) Error ¶
func (e *ContextError) Error() string
func (*ContextError) Timeout ¶
func (e *ContextError) Timeout() bool
Timeout reports whether the wrapped error is a deadline expiry. It checks the whole chain rather than go-smb2's identity comparison because the wrapped error may itself carry context (e.g. "send failed: context deadline exceeded").
func (*ContextError) Unwrap ¶
func (e *ContextError) Unwrap() error
Unwrap exposes the underlying context error so errors.Is(err, context.Canceled) and IsTimeoutError keep working through the wrapper.
type Dialer ¶
type Dialer struct {
// MaxCreditBalance is unused for SMB1 (kept for API compatibility).
// SMB1 does not use the credit-based flow control that SMB2+ uses.
MaxCreditBalance uint16
// Negotiator is unused for SMB1 (kept for API compatibility).
// SMB1 negotiation is always performed automatically.
Negotiator Negotiator
// Initiator is required for authentication.
// Use NTLMInitiator for NTLM v2 authentication.
Initiator Initiator
}
Dialer contains options for establishing an SMB1 session.
API Compatibility Note: MaxCreditBalance and Negotiator are kept for go-smb2 API compatibility, but are not used in SMB1 (SMB1 doesn't have credit-based flow control).
func (*Dialer) Dial ¶
Dial performs protocol negotiation and authentication on the provided TCP connection.
The tcpConn should already be connected to the SMB server (typically port 445 or 139). This method wraps the connection with NetBIOS framing, negotiates the SMB1 protocol, and performs NTLM authentication.
Important: This implementation doesn't support NetBIOS transport on port 139 yet. Use direct SMB over TCP on port 445 instead.
The returned Session uses context.Background() as its default context (with no logger attached). To attach a logger or custom context, use DialContext instead.
Example:
conn, err := net.Dial("tcp", "192.168.1.100:445")
if err != nil {
return err
}
defer conn.Close()
d := &smb1.Dialer{
Initiator: &smb1.NTLMInitiator{
User: "username",
Password: "password",
Domain: "WORKGROUP",
},
}
session, err := d.Dial(conn)
if err != nil {
return err
}
defer session.Logoff()
func (*Dialer) DialContext ¶
DialContext performs negotiation and authentication using the provided context.
The context is used for the negotiation and authentication phases only. Any logger attached to the context will be extracted and used by the returned Session, but timeouts and cancellations are not inherited.
If you want to change the session's context (e.g., to add timeouts), call Session.WithContext() to create a new session with a different context.
The context can be used to set timeouts or cancel the dial operation:
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() session, err := d.DialContext(ctx, conn)
type File ¶
type File struct {
// contains filtered or unexported fields
}
File represents an open file on an SMB share. It provides methods for reading, writing, and seeking within the file. File implements io.Reader, io.Writer, io.Seeker, io.ReaderAt, and io.WriterAt.
func (*File) Chmod ¶
Chmod changes the mode of the open file, with the same semantics as Share.Chmod. If there is an error, it will be of type *os.PathError.
The attribute set normally goes out as TRANS2_SET_FILE_INFORMATION on the open handle; legacy servers that reject that with STATUS_NOT_SUPPORTED get the core-protocol SMB_COM_SET_INFORMATION command instead, which is path-based — it addresses the file by the path it was opened with rather than by handle — with the same attribute semantics.
func (*File) Close ¶
Close closes the File, rendering it unusable for I/O. It returns an error, if any.
func (*File) Read ¶
Read reads up to len(b) bytes from the File. It returns the number of bytes read and any error encountered. At end of file, Read returns 0, io.EOF. For large reads (>= 128KB), this method uses request pipelining for improved performance.
func (*File) ReadAt ¶
ReadAt reads len(b) bytes from the File starting at byte offset off. It returns the number of bytes read and the error, if any. ReadAt always returns a non-nil error when n < len(b). At end of file, that error is io.EOF.
func (*File) ReadFrom ¶
ReadFrom implements io.ReaderFrom: it reads from r until EOF and writes the data to f through the ordinary Write path in buffered chunks. Unlike go-smb2, no server-side copy is attempted when r is another File; the data always streams through the client.
func (*File) Readdir ¶
Readdir reads the contents of the directory associated with file and returns a slice of up to n FileInfo values, as would be returned by Lstat, in directory order. Subsequent calls on the same file will yield further FileInfos.
If n > 0, Readdir returns at most n FileInfo structures. In this case, if Readdir returns an empty slice, it will return a non-nil error explaining why. At the end of a directory, the error is io.EOF.
If n <= 0, Readdir returns all the FileInfo from the directory in a single slice. In this case, if Readdir succeeds (reads all the way to the end of the directory), it returns the slice and a nil error. If it encounters an error before the end of the directory, Readdir returns the FileInfo read until that point and a non-nil error.
Note: This implementation uses the file's offset to track pagination state. Calling Seek() on the file will reset the directory reading position. Also note that this only works if the file was opened as a directory.
func (*File) Readdirnames ¶
Readdirnames reads the contents of the directory associated with file and returns a slice of up to n names of files in the directory, in directory order. Paging behaves exactly as Readdir: subsequent calls on the same file yield further names, and with n > 0 the error at the end of the directory is io.EOF (possibly alongside the final page of names).
func (*File) Seek ¶
Seek sets the offset for the next Read or Write on file to offset, interpreted according to whence: 0 means relative to the origin of the file, 1 means relative to the current offset, and 2 means relative to the end. It returns the new offset and an error, if any.
func (*File) Stat ¶
Stat returns the FileInfo structure describing file. If there is an error, it will be of type *os.PathError.
func (*File) Statfs ¶
func (f *File) Statfs() (FileFsInfo, error)
Statfs returns the capacity of the filesystem backing the file's share, queried over the tree the file was opened on. If there is an error, it will be of type *os.PathError.
func (*File) Sync ¶
Sync commits the current contents of the file to stable storage. Typically, this means flushing the file system's in-memory copy of recently written data to disk.
func (*File) Truncate ¶
Truncate changes the size of the file. It does not change the I/O offset. If there is an error, it will be of type *os.PathError.
func (*File) Write ¶
Write writes len(b) bytes to the File. It returns the number of bytes written and an error, if any. Write returns a non-nil error when n != len(b).
func (*File) WriteAt ¶
WriteAt writes len(b) bytes to the File starting at byte offset off. It returns the number of bytes written and an error, if any. WriteAt returns a non-nil error when n != len(b).
func (*File) WriteString ¶
WriteString is like Write, but writes the contents of string s rather than a slice of bytes.
type FileFsInfo ¶
type FileFsInfo interface {
BlockSize() uint64
FragmentSize() uint64
TotalBlockCount() uint64
FreeBlockCount() uint64
AvailableBlockCount() uint64
}
FileFsInfo describes the capacity of the filesystem backing a mounted share. The interface and its field mapping match go-smb2's FileFsInfo: BlockSize is the bytes per sector, FragmentSize is the sectors per allocation unit, and the three counts are in allocation units — so the volume's total capacity in bytes is TotalBlockCount() * FragmentSize() * BlockSize().
type FileStat ¶
type FileStat struct {
CreationTime time.Time
LastAccessTime time.Time
LastWriteTime time.Time
ChangeTime time.Time
EndOfFile int64 // File size
AllocationSize int64 // Allocated size on disk
FileAttributes uint32 // SMB file attributes
FileName string // File name
}
FileStat implements os.FileInfo for SMB1 files. It contains file metadata returned by SMB1 file operations.
type Initiator ¶
type Initiator interface {
// contains filtered or unexported methods
}
Initiator is the interface for session authentication. It follows the GSS-API pattern used by go-smb2 for API compatibility.
type InternalError ¶
type InternalError struct {
Message string
}
InternalError indicates a client-side error (not a server error). This usually indicates a programming error or configuration issue.
func (*InternalError) Error ¶
func (e *InternalError) Error() string
type InvalidResponseError ¶
type InvalidResponseError struct {
Message string
}
InvalidResponseError indicates the server sent a malformed response. This usually indicates a protocol error or incompatible server.
func (*InvalidResponseError) Error ¶
func (e *InvalidResponseError) Error() string
type Logger ¶
Logger is the interface for logging. Applications can provide their own logger implementation for custom logging behavior.
func LoggerFromContext ¶
LoggerFromContext retrieves the logger from the context. If no logger is attached to the context, it returns a no-op logger.
type NTLMInitiator ¶
type NTLMInitiator struct {
// User is the username for authentication.
// Required field.
User string
// Password is the plain text password.
// Use either Password or Hash, not both.
Password string
// Hash is the pre-computed NTLM password hash (16 bytes).
// Use either Password or Hash, not both.
// Useful for pass-the-hash attacks or when password is not available.
Hash []byte
// Domain is the Windows domain or workgroup name.
// Defaults to "WORKGROUP" if empty.
Domain string
// Workstation is the client workstation name.
// Defaults to "localhost" if empty.
Workstation string
// TargetSPN is the Service Principal Name for the target server.
// Format: "service/hostname[:port]" (e.g., "cifs/server:445")
// Optional field.
TargetSPN string
// contains filtered or unexported fields
}
NTLMInitiator implements NTLM v2 authentication for SMB1 sessions. It provides a public wrapper around the internal NTLM client.
You can use either Password or Hash for authentication:
- Password: plain text password (will be hashed internally)
- Hash: pre-computed NTLM hash (16 bytes, NTOWFv2)
Example:
initiator := &smb1.NTLMInitiator{
User: "username",
Password: "password",
Domain: "WORKGROUP",
}
type Negotiator ¶
type Negotiator struct {
RequireMessageSigning bool // ignored for SMB1
ClientGuid [16]byte // ignored for SMB1
SpecifiedDialect uint16 // ignored for SMB1
}
Negotiator contains options for protocol negotiation, mirroring go-smb2's type of the same name for source compatibility. SMB1 ignores all fields: negotiation is always performed automatically, this client does not negotiate signing, SMB1 negotiation carries no client GUID, and the dialect is always NT LM 0.12.
type PoolConfig ¶
type PoolConfig struct {
// MaxIdle is the maximum number of idle connections to keep in the pool.
// Zero means no idle connections are kept (every Get creates a new connection).
// Default is 5.
MaxIdle int
// MaxActive is the maximum number of active connections (idle + in-use).
// Zero means no limit on active connections.
// Default is 10.
MaxActive int
// IdleTimeout is the maximum time an idle connection can remain in the pool
// before being closed. Zero means no timeout (idle connections never expire).
// Default is 5 minutes.
IdleTimeout time.Duration
// WaitTimeout is the maximum time to wait for a connection when the pool is exhausted.
// Zero means fail immediately if no connection is available.
// Default is 30 seconds.
WaitTimeout time.Duration
// HealthCheck is an optional callback function to verify connection health before reuse.
// If provided, it will be called before returning a connection from the idle pool.
// If the health check returns false or an error, the connection is closed and a new one is created.
// If nil, connections are assumed to be alive (default behavior for backward compatibility).
//
// Example health check that sends an Echo command:
//
// HealthCheck: func(s *Session) (bool, error) {
// // Try to send an Echo command with a timeout
// ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
// defer cancel()
// err := s.WithContext(ctx).sendEcho()
// return err == nil, err
// }
//
// Performance note: Health checks add latency to connection acquisition from the pool.
// Use with caution for latency-sensitive workloads.
HealthCheck func(*Session) (bool, error)
}
PoolConfig contains configuration options for a ConnectionPool.
func DefaultPoolConfig ¶
func DefaultPoolConfig() *PoolConfig
DefaultPoolConfig returns a PoolConfig with recommended default values.
type PoolStats ¶
type PoolStats struct {
// Idle is the number of idle connections in the pool.
Idle int
// Active is the total number of active connections (idle + in-use).
Active int
// Closed indicates whether the pool has been closed.
Closed bool
}
PoolStats contains statistics about a ConnectionPool.
type PooledSession ¶
type PooledSession struct {
// contains filtered or unexported fields
}
PooledSession wraps a Session obtained from a ConnectionPool. When Close() is called, the session is returned to the pool for reuse. To actually close the connection, use ReallyClose().
func (*PooledSession) Close ¶
func (ps *PooledSession) Close() error
Close returns the connection to the pool instead of closing it. The session can be reused by another caller.
func (*PooledSession) ListSharenames ¶
func (ps *PooledSession) ListSharenames() ([]string, error)
ListSharenames is a convenience method that calls ListSharenames on the underlying Session.
func (*PooledSession) Logoff ¶
func (ps *PooledSession) Logoff() error
Logoff is a convenience method that calls ReallyClose(). It's provided for API compatibility but actually closes the connection rather than returning it to the pool.
func (*PooledSession) Mount ¶
func (ps *PooledSession) Mount(sharename string) (*Share, error)
Mount is a convenience method that calls Mount on the underlying Session.
func (*PooledSession) ReallyClose ¶
func (ps *PooledSession) ReallyClose() error
ReallyClose closes the connection and removes it from the pool. Use this when you want to permanently close a connection (e.g., on error).
func (*PooledSession) Session ¶
func (ps *PooledSession) Session() *Session
Session returns the underlying Session for use. The returned Session should not be closed directly - use PooledSession.Close() instead.
func (*PooledSession) WithContext ¶
func (ps *PooledSession) WithContext(ctx context.Context) *Session
WithContext is a convenience method that calls WithContext on the underlying Session.
type RemoteFile ¶
type RemoteFile = File // deprecated type name
type RemoteFileStat ¶
type RemoteFileStat = FileStat // deprecated type name
type RemoteFileSystem ¶
type RemoteFileSystem = Share // deprecated type name
type ResponseError ¶
type ResponseError struct {
Code uint32 // NT_STATUS code
}
ResponseError wraps an NT_STATUS error code from the server. The Code field contains the raw NT_STATUS value. The underlying error string describes the error condition.
func (*ResponseError) Error ¶
func (e *ResponseError) Error() string
type SMBError ¶
type SMBError struct {
Status uint32 // NT_STATUS code
Command uint8 // SMB command that failed
Message string // Human-readable message
}
SMBError represents an SMB protocol error with detailed context. It provides more information than ResponseError including the command that failed and a human-readable message.
type ServerCapabilities ¶
type ServerCapabilities struct {
// MaxMpxCount is the maximum number of outstanding (pipelined) requests
// the server can handle concurrently. A value of 0 or 1 means the server
// does not support request pipelining.
MaxMpxCount uint16
// MaxBufferSize is the maximum size of an SMB message (in bytes) that the
// server can receive. This limits the size of individual read/write requests.
MaxBufferSize uint32
// ServerName is the NetBIOS name of the server.
ServerName string
// DomainName is the domain or workgroup name the server belongs to.
DomainName string
// SupportsPipelining indicates whether the server supports concurrent
// (pipelined) requests. This is true when MaxMpxCount > 1.
SupportsPipelining bool
// EffectivePipelineDepth is the actual pipeline depth that will be used
// by this client implementation, capped at 50 for safety.
EffectivePipelineDepth int
}
ServerCapabilities contains information about the SMB server's capabilities as negotiated during the protocol handshake.
func (ServerCapabilities) String ¶
func (c ServerCapabilities) String() string
String returns a human-readable representation of the server capabilities.
type ServerTime ¶
type ServerTime struct {
// Time is the server's system time in UTC at the moment the server built
// the negotiate response. It is the zero time if the server did not
// report a valid clock.
Time time.Time
// TimeZoneOffsetMinutes is the server's time zone offset in minutes from
// UTC, taken verbatim from the ServerTimeZone field of the negotiate
// response. Time is already in UTC; this value only describes the
// server's local time zone.
TimeZoneOffsetMinutes int16
// ReceivedAt is the local time at which the negotiate response was
// received. Comparing it against Time gives the offset between the
// server clock and the local clock as of the protocol handshake.
ReceivedAt time.Time
}
ServerTime describes the server's clock as reported in the SMB negotiate response. It allows callers to compare the server clock against the local clock, e.g. to compute a clock offset as Time.Sub(ReceivedAt).
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
Session represents an authenticated SMB1 session. A session is created after successful protocol negotiation and authentication.
The session is used to mount shares (Mount) and can be closed with Logoff. A single session can have multiple shares mounted simultaneously.
func (*Session) Capabilities ¶
func (s *Session) Capabilities() ServerCapabilities
Capabilities returns information about the negotiated server capabilities. This includes details about request pipelining support, buffer sizes, and server identification.
func (*Session) ListSharenames ¶
ListSharenames enumerates available shares on the server.
This method first attempts to use the RAP (Remote Administration Protocol) NetShareEnum command for maximum compatibility with SMB1 servers. If RAP is not supported (STATUS_NOT_SUPPORTED), it falls back to the more modern RPC/SRVSVC NetShareEnumAll method.
The returned list includes share names but not administrative metadata. Hidden shares (ending with $) and administrative shares (IPC$, ADMIN$, etc.) are included in the results.
Example:
shares, err := session.ListSharenames()
if err != nil {
log.Fatal(err)
}
for _, share := range shares {
fmt.Println(share)
}
Limitations:
- Returns only share names, not types or comments
- Requires IPC$ access (typically granted to all authenticated users)
func (*Session) Logoff ¶
Logoff terminates the SMB session and closes the connection.
After calling Logoff, the session and any mounted shares should not be used. All open files are closed automatically by the server when the session ends.
It's recommended to call Logoff in a defer statement:
session, err := dialer.Dial(conn)
if err != nil {
return err
}
defer session.Logoff()
func (*Session) Mount ¶
Mount connects to a share on the server.
The sharename can be specified in multiple formats:
- "ShareName" - just the share name (server name is added automatically)
- "\\server\ShareName" - full UNC path
- "server\ShareName" - UNC path without leading backslashes
The server's NetBIOS name is automatically added if not present in the sharename. Note: SMB1 requires the NetBIOS name, not the IP address, in UNC paths.
Examples:
// These are equivalent (assuming server name is "FILESERVER"):
share, err := session.Mount("Public")
share, err := session.Mount("\\FILESERVER\Public")
share, err := session.Mount("FILESERVER\Public")
The returned Share inherits the Session's context (including any logger). Call Share.WithContext() if you need to use a different context for the share.
func (*Session) ServerTime ¶
func (s *Session) ServerTime() ServerTime
ServerTime returns the server clock information captured during protocol negotiation. The values are recorded once at dial time and do not change for the lifetime of the session.
Example (computing the server/local clock offset right after dialing):
st := session.ServerTime() offset := st.Time.Sub(st.ReceivedAt)
func (*Session) WithContext ¶
WithContext returns a new Session that uses the provided context as its default. If ctx is nil, it returns nil and the original Session remains unmodified.
The original Session is not modified - a new Session struct is returned that shares the same underlying connection and authentication but uses a different default context.
Example:
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
sessionWithTimeout := session.WithContext(ctx)
share, err := sessionWithTimeout.Mount("Share")
type Share ¶
type Share struct {
// contains filtered or unexported fields
}
Share represents a mounted SMB share (tree connection). The share provides file system operations like opening files, creating directories, and listing directory contents.
func (*Share) Chmod ¶
Chmod changes the mode of the named file, mimicking os.Chmod within what SMB attributes can express: when the owner-write bit (0200) is absent the file becomes read-only, otherwise read-only is cleared. All other attributes are preserved via a read-modify-write of the current attribute set, matching go-smb2's behavior. If there is an error, it will be of type *os.PathError.
The attribute set normally goes out as TRANS2_SET_PATH_INFORMATION at the SMB_SET_FILE_BASIC_INFO level; legacy servers that reject that with STATUS_NOT_SUPPORTED get the core-protocol SMB_COM_SET_INFORMATION command instead, with the same attribute semantics.
func (*Share) Chtimes ¶
Chtimes changes the access and modification times of the named file, mimicking os.Chtimes. If there is an error, it will be of type *os.PathError.
It is implemented with TRANS2_SET_PATH_INFORMATION at the SMB_SET_FILE_BASIC_INFO level, so the file is not opened. A zero time value leaves the corresponding timestamp unchanged: SMB1 encodes it as FILETIME 0, which the protocol defines as "do not change".
Servers are free to round the stored times to their filesystem's resolution, and some (Samba among them) do not persist access times at all; the modification time is the one callers can rely on reading back.
func (*Share) CopyFile ¶
CopyFile copies a file within the share from src to dst. If dst already exists, it will be overwritten. The file contents are copied by reading from src and writing to dst. Both paths must be relative paths within the share.
func (*Share) CopyFrom ¶
CopyFrom uploads a file from the local filesystem to the share. The localPath is a path on the local filesystem, and remotePath is a relative path within the share. If remotePath already exists, it will be overwritten.
func (*Share) CopyTo ¶
CopyTo downloads a file from the share to the local filesystem. The remotePath is a relative path within the share, and localPath is a path on the local filesystem. If localPath already exists, it will be overwritten.
func (*Share) Create ¶
Create creates or truncates the named file. If the file already exists, it is truncated. If the file does not exist, it is created with mode 0666. If successful, methods on the returned File can be used for I/O; the associated file descriptor has mode O_RDWR. If there is an error, it will be of type *os.PathError.
func (*Share) DirFS ¶
DirFS returns an fs.FS presenting the share subtree rooted at dirname as a read-only file system. dirname is a share path in the same form the other Share methods accept ('\' or, with NORMALIZE_PATH, '/' separators); "" and "." both denote the share root.
Names passed to the returned file system follow the io/fs rules instead: '/'-separated, rooted at dirname, validated with fs.ValidPath, with "." naming the root. Errors are *fs.PathError values carrying those io/fs names, and errors.Is against fs.ErrNotExist, fs.ErrInvalid, etc. works as io/fs documents.
Matching go-smb2, the result also implements fs.StatFS, fs.ReadFileFS and fs.GlobFS (but not fs.ReadDirFS or fs.SubFS; fs.ReadDir and fs.Sub fall back to Open), and files opened on a directory implement fs.ReadDirFile.
func (*Share) Exists ¶
Exists checks if a file or directory exists at the given path. It returns true if the file/directory exists, false if it does not exist. If there is an error other than "not found", it returns false and the error.
func (*Share) Glob ¶
Glob returns the names of all files matching pattern, or nil if there is no matching file. The pattern syntax is that of Match, and matches are returned in lexical order. Glob ignores file system errors such as directories that cannot be read; the only possible returned error is ErrBadPattern, when pattern is malformed.
Unlike filepath.Glob, results use '\' as the separator, and patterns are relative to the share root (a leading '\' matches nothing, since this library rejects absolute paths).
func (*Share) IsDir ¶
IsDir checks if the given path exists and is a directory. It returns true if the path exists and is a directory. If the path does not exist or is not a directory, it returns false. If there is an error checking the path, it returns false and the error.
func (*Share) Lstat ¶
Lstat returns a FileInfo describing the named file. If the file is a symbolic link, the returned FileInfo describes the symbolic link. Lstat makes no attempt to follow the link. If there is an error, it will be of type *os.PathError.
Note: SMB1 doesn't have separate lstat semantics, so this is the same as Stat.
func (*Share) Mkdir ¶
Mkdir creates a new directory with the specified name and permission bits (before umask). If there is an error, it will be of type *os.PathError.
func (*Share) MkdirAll ¶
MkdirAll creates a directory named path, along with any necessary parents, and returns nil, or else returns an error. The permission bits perm (before umask) are used for all directories that MkdirAll creates. If path is already a directory, MkdirAll does nothing and returns nil.
func (*Share) Open ¶
Open opens the named file for reading. If successful, methods on the returned file can be used for reading; the associated file descriptor has mode O_RDONLY. If there is an error, it will be of type *os.PathError.
func (*Share) OpenFile ¶
OpenFile is the generalized open call; most users will use Open or Create instead. It opens the named file with specified flag (O_RDONLY etc.) and perm (before umask), if applicable. If successful, methods on the returned File can be used for I/O. If there is an error, it will be of type *os.PathError.
func (*Share) ReadDir ¶
ReadDir reads the directory named by dirname and returns a list of directory entries sorted by filename.
func (*Share) ReadFile ¶
ReadFile reads the file named by filename and returns the contents. A successful call returns err == nil, not err == EOF. Because ReadFile reads the whole file, it does not treat an EOF from Read as an error to be reported.
Stat only sizes the initial buffer. Read is an io.Reader and may legally return fewer bytes than requested without an error, so the loop below runs to EOF and grows the buffer rather than trusting either the stat size or a single Read to have delivered the whole file.
Prefer Open plus io.CopyBuffer (or CopyTo) for large files: ReadFile holds the entire contents in memory.
func (*Share) Readdir ¶
Readdir reads the directory named by dirname and returns a list of up to n directory entries.
If n > 0, Readdir returns at most n FileInfo structures. In this case, if Readdir returns an empty slice, it will return a non-nil error explaining why. At the end of a directory, the error is io.EOF.
If n <= 0, Readdir returns all the FileInfo from the directory in a single slice. In this case, if Readdir succeeds (reads all the way to the end of the directory), it returns the slice and a nil error. If it encounters an error before the end of the directory, Readdir returns the FileInfo read until that point and a non-nil error.
Note: This implementation does not maintain state between calls. When n > 0, it reads all entries and returns the first n, then returns io.EOF on subsequent calls. For proper pagination with state tracking, use the standard library's fs.ReadDir or open the directory as a File and call File.Readdir.
func (*Share) Readlink ¶
Readlink mimics os.Readlink's signature for go-smb2 parity, but SMB1 has no symbolic link operation — see Symlink — so it always returns an *os.PathError wrapping errors.ErrUnsupported.
func (*Share) Remove ¶
Remove removes the named file or (empty) directory. If there is an error, it will be of type *os.PathError.
func (*Share) RemoveAll ¶
RemoveAll removes path and any children it contains. It removes everything it can but returns the first error it encounters. If the path does not exist, RemoveAll returns nil (no error).
func (*Share) Rename ¶
Rename renames (moves) oldpath to newpath. Files and directories can be renamed within a directory or moved between directories on the same share.
Unlike os.Rename, Rename does not replace an existing newpath: the underlying SMB_COM_RENAME command fails with STATUS_OBJECT_NAME_COLLISION if newpath already exists (use IsExistError to detect this case). This matches go-smb2, whose Rename also does not overwrite an existing target. If there is an error, it will be of type *os.LinkError.
func (*Share) Stat ¶
Stat returns a FileInfo describing the named file. If there is an error, it will be of type *os.PathError.
func (*Share) Statfs ¶
func (fs *Share) Statfs(name string) (FileFsInfo, error)
Statfs returns the capacity of the filesystem backing the share. If there is an error, it will be of type *os.PathError.
The name argument exists for go-smb2 signature parity and is validated and normalized like every other path argument (the empty string addresses the share root, as go-smb2 allows), but SMB1's TRANS2_QUERY_FS_INFORMATION is share-wide — the query is the same whichever path is named, so the name does not reach the wire.
It prefers SMB_QUERY_FS_SIZE_INFO, whose unit counts are 64-bit, and falls back to the legacy SMB_INFO_ALLOCATION level when the server does not support it — the same accommodation ListSharenames makes for servers that lack RAP. The legacy level's counts are 32-bit and so cannot describe a volume beyond roughly 4 billion allocation units.
func (*Share) Symlink ¶
Symlink mimics os.Symlink's signature for go-smb2 parity, but SMB1 has no symbolic link operation — the reparse-point FSCTLs go-smb2 uses are SMB2 constructs — so it always returns an *os.LinkError wrapping errors.ErrUnsupported.
func (*Share) Truncate ¶
Truncate changes the size of the named file. It opens the file write-only, resizes it, and closes it; the file must already exist. A negative size returns os.ErrInvalid; other errors are of type *os.PathError.
func (*Share) Umount ¶
Umount disconnects from the share (sends TREE_DISCONNECT).
After calling Umount, the share should not be used. All open files on this share are closed automatically by the server.
It's recommended to call Umount in a defer statement:
share, err := session.Mount("Public")
if err != nil {
return err
}
defer share.Umount()
func (*Share) VolumeInfo ¶
func (fs *Share) VolumeInfo() (*VolumeInfo, error)
VolumeInfo returns the identity of the volume backing the share.
The serial number answers "is this the same physical media I saw last time" without writing a marker file to the share — useful where the share is removable and deleting from the wrong one would be destructive.
func (*Share) Walk ¶
Walk walks the file tree rooted at root, calling walkFn for each file or directory in the tree, including root. All errors that arise visiting files and directories are filtered by walkFn.
Walk follows the same semantics as filepath.Walk:
- The files are walked in lexical order
- Walk does not follow symbolic links
- If walkFn returns filepath.SkipDir when invoked on a directory, Walk skips the directory's contents
- If walkFn returns any other non-nil error, Walk stops immediately
Note: Unlike filepath.Walk, paths passed to walkFn use backslashes (\) as the separator, consistent with SMB conventions.
func (*Share) WithContext ¶
WithContext returns a new Share that uses the provided context as its default. If ctx is nil, it returns nil and the original Share remains unmodified.
The original Share is not modified - a new Share struct is returned that uses the same underlying tree connection but with a different default context.
type TransportError ¶
type TransportError struct {
Err error
}
TransportError represents an error coming from the net.Conn layer, such as a dropped TCP connection or a socket read/write failure. The type and its message format mirror go-smb2's TransportError for source compatibility.
func (*TransportError) Error ¶
func (e *TransportError) Error() string
func (*TransportError) Unwrap ¶
func (e *TransportError) Unwrap() error
Unwrap exposes the underlying failure so errors.Is/As and predicates like IsNetworkError keep classifying wrapped errors. (go-smb2's TransportError has no Unwrap; ours does so the existing error chains stay intact.)
type VolumeInfo ¶
type VolumeInfo struct {
// SerialNumber is the volume serial number assigned at format time.
SerialNumber uint32
// Label is the volume label. It is frequently empty, and a server may
// decline to report it while still reporting a serial number.
Label string
// CreationTime is when the volume was created. Servers whose filesystem
// does not record this report a zero time.
CreationTime time.Time
}
VolumeInfo identifies the volume backing a mounted share.
SerialNumber is assigned when the volume is formatted, so it distinguishes one piece of removable media from another without writing anything to it. It is not a strong identifier: it is not unique across the world, and reformatting changes it.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
examples
|
|
|
advanced
command
|
|
|
basic
command
|
|
|
dirops
command
|
|
|
fileops
command
|
|
|
listshares
command
|
|
|
pool
command
|
|
|
uploaddownload
command
|
|
|
internal
|
|
|
netbios
Package netbios implements the NetBIOS session service layer for SMB1 protocol.
|
Package netbios implements the NetBIOS session service layer for SMB1 protocol. |
|
smb1
Package smb1 implements the SMB1/CIFS protocol layer.
|
Package smb1 implements the SMB1/CIFS protocol layer. |