Documentation
¶
Overview ¶
Package archivecli runs operator-provided archive tools behind a small, fixed interface. It never evaluates a shell command: provider arguments are assembled here and the executable path comes only from process config.
Index ¶
- Constants
- Variables
- func CanonicalFormat(v string) string
- func CanonicalFormats(in []string) []string
- func CheckPassword(password, format string) error
- func CleanMemberPath(name string) (string, error)
- func FormatFromPath(name string) string
- func IsCreateFormat(format string) bool
- func Preflight(entries []Entry, policy Policy) error
- func ReadsItself(logicalName string) bool
- func ValidDictionarySizeMiB(size int) bool
- type Config
- type CreateOptions
- type Entry
- type Policy
- type ProviderStatus
- type Service
- func (s *Service) Create(ctx context.Context, sourceDir, destPath string, opts CreateOptions) error
- func (s *Service) Extract(ctx context.Context, archivePath, destDir, password string, members []string) error
- func (s *Service) ExtractAs(ctx context.Context, archivePath, logicalName, destDir, password string, ...) error
- func (s *Service) List(ctx context.Context, archivePath, password string) ([]Entry, error)
- func (s *Service) ListAs(ctx context.Context, archivePath, logicalName, password string) ([]Entry, error)
- func (s *Service) Policy(ctx context.Context) Policy
- func (s *Service) Providers(ctx context.Context) []ProviderStatus
- func (s *Service) SevenZipAvailable(ctx context.Context) bool
- func (s *Service) Test(ctx context.Context, archivePath, password string) error
- func (s *Service) TestAs(ctx context.Context, archivePath, logicalName, password string) error
- func (s *Service) WorkDir() string
- type SettingsStore
Constants ¶
const ( SettingEnabled = "archive.enabled" SettingDefaultFormat = "archive.default_format" SettingAllowedFormats = "archive.allowed_formats" SettingMaxEntries = "archive.max_entries" SettingMaxExpandedBytes = "archive.max_expanded_bytes" SettingTimeoutSeconds = "archive.timeout_seconds" DefaultMaxEntries = 20_000 DefaultMaxExpandedBytes = int64(20 << 30) DefaultTimeout = 30 * time.Minute )
Variables ¶
var ( ErrPasswordRequired = errors.New("archive password required") ErrBadPassword = errors.New("incorrect archive password") ErrUnsupported = errors.New("unsupported archive format") ErrLimits = errors.New("archive exceeds configured limits") // ErrPasswordCharset: a password 7-Zip cannot take. It reads one LINE from // stdin, so a line break cannot be part of one, and it refuses to encrypt // a ZIP with anything but printable ASCII (E_INVALIDARG) — said up front // instead of as "archive provider failed" after the files were staged. ErrPasswordCharset = errors.New("archive password contains characters this format cannot use") )
Functions ¶
func CanonicalFormat ¶
func CanonicalFormats ¶
func CheckPassword ¶
CheckPassword refuses what 7-Zip cannot be given: a line break ends the one line it reads, and ZIP encryption takes printable ASCII only.
func CleanMemberPath ¶
CleanMemberPath turns an archive member name into a safe relative path, or refuses it. One rule for every reader (archive/zip in the handlers, TAR here): backslashes are separators, leading slashes and "./" are dropped, a drive letter or any ".." component is refused.
func FormatFromPath ¶
func IsCreateFormat ¶
func Preflight ¶
Preflight judges a listing before anything is extracted, the same way for every reader: each member must have a clean relative path, be a file or a folder (never a link or a special file) and say how large it is; the declared sizes and the number of entries must fit the policy.
func ReadsItself ¶
ReadsItself reports whether filex reads this archive without 7-Zip (xz layers aside): ZIP through archive/zip, the TAR family and gzip/bzip2 here.
func ValidDictionarySizeMiB ¶
ValidDictionarySizeMiB bounds 7z's memory use to explicit, predictable powers of two. Zero means let 7-Zip choose its format/level default.
Types ¶
type Config ¶
Config contains the operator-owned settings. Binary is never writable over HTTP because changing it is equivalent to allowing arbitrary code execution.
type CreateOptions ¶
type CreateOptions struct {
Format string
Password string
EncryptNames bool
Compression int
Solid *bool
DictionarySizeMiB int
Progress func(percent int)
}
CreateOptions is the fixed, validated set of switches filex may pass to an archive provider. Keeping this typed prevents a browser from smuggling raw command-line arguments into the process invocation.
type Entry ¶
type Entry struct {
Name string `json:"name"`
Size int64 `json:"size"`
Mtime time.Time `json:"mtime"`
IsDir bool `json:"is_dir"`
Encrypted bool `json:"encrypted,omitempty"`
IsLink bool `json:"is_link,omitempty"`
// Special: a FIFO, a device or a socket — neither a file nor a folder.
Special bool `json:"special,omitempty"`
// SizeUnknown: the archive does not say how large this member is (a RAR5
// stream written by `rar -si` sets that flag; 7-Zip lists `Size = ` empty).
// 7-Zip then decodes it to the end of its data, so nothing before the
// extraction can hold it to the limit: Preflight refuses it.
SizeUnknown bool `json:"-"`
}
Entry is one archive member as reported by the provider.
type Policy ¶
type Policy struct {
Enabled bool `json:"enabled"`
DefaultFormat string `json:"default_format"`
AllowedFormats []string `json:"allowed_formats"`
MaxEntries int `json:"max_entries"`
MaxExpandedBytes int64 `json:"max_expanded_bytes"`
TimeoutSeconds int `json:"timeout_seconds"`
}
Policy is the live, admin-writable archive policy.
type ProviderStatus ¶
type ProviderStatus struct {
Name string `json:"name"`
Available bool `json:"available"`
Version string `json:"version,omitempty"`
CreateFormats []string `json:"create_formats"`
ExtractFormats []string `json:"extract_formats"`
Encrypted bool `json:"encrypted"`
Error string `json:"error,omitempty"`
// RequiredVersion: the oldest version filex accepts, so the admin page can
// say what to install in its own language.
RequiredVersion string `json:"required_version,omitempty"`
}
ProviderStatus describes an archive provider without exposing host paths.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service resolves and invokes supported archive providers.
func New ¶
func New(store SettingsStore, cfg Config) *Service
func (*Service) Create ¶
Create builds an archive from the entire contents of sourceDir. Compressed TAR formats stream the TAR producer directly into gzip, bzip2 or xz, avoiding a potentially large intermediate file. sourceDir is an isolated workspace prepared by filex, so no user-controlled path becomes an option and no host path can be archived accidentally.
func (*Service) Extract ¶
func (s *Service) Extract(ctx context.Context, archivePath, destDir, password string, members []string) error
Extract expands archivePath, taking its format from its own name.
func (*Service) ExtractAs ¶
func (s *Service) ExtractAs(ctx context.Context, archivePath, logicalName, destDir, password string, members []string) error
ExtractAs expands an archive the user calls logicalName into destDir, an empty private workspace, while enforcing the live archive policy. The caller still validates paths and file types before copying anything into a storage driver.
The TAR family and bare gzip/bzip2/xz are read by filex (stream.go): exact limits, links refused from the header. 7z, RAR and ZIP go through 7-Zip, whose decoders stop at each member's declared size — the preflight checks those — with the workspace monitor as the backstop for a format that does not declare one.
func (*Service) ListAs ¶
func (s *Service) ListAs(ctx context.Context, archivePath, logicalName, password string) ([]Entry, error)
ListAs lists archivePath as the format logicalName names. The TAR family and bare gzip/bzip2/xz are read here (stream.go); 7z, RAR and ZIP through 7-Zip, which prints stable Path/Size/Modified/Attributes blocks.
func (*Service) SevenZipAvailable ¶
SevenZipAvailable reports whether a supported 7-Zip is usable right now: installed, new enough, and not switched off in the archive policy.
func (*Service) Test ¶
Test validates that every member can be decrypted without materialising it. Listing alone is insufficient for ZIP and non-header-encrypted 7z archives: 7-Zip can reveal their names without ever checking the content password.