softmagic

package module
v0.4.6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 9, 2026 License: BSD-2-Clause, BSD-2-Clause Imports: 18 Imported by: 0

README

softmagic

softmagic is a pure-Go port of file(1): given bytes, it returns the description, MIME type and extension that file returns for the same bytes and the same magic database, with every answer stating what it examined and what it did not, safe to call from any number of goroutines, with a bounded cost per call that a crafted input cannot raise.

It is a port of file(1) by Ian F. Darwin and Christos Zoulas. The magic database in magic/Magdir is copied unmodified from the file 5.48 release, and the files whose header says so are translations of its C sources (apprentice.c, softmagic.c, funcs.c, encoding.c, ascmagic.c, print.c, file.h). Both are redistributed under the two-clause BSD licence in COPYING, whose conditions are: redistributions of source code must retain the copyright notice, this list of conditions and the disclaimer; redistributions in binary form must reproduce them in the documentation or other materials provided with the distribution. The Go code is Copyright (c) 2026 Eitanity Systems VCC under the BSD-2-Clause licence in LICENSE.

This module is a library only. The command-line tool is the separate module code.eitanity.com/softmagic-cli.

Install

go get code.eitanity.com/softmagic

The module was renamed from github.com/eitanity/softmagic to code.eitanity.com/softmagic after v0.4.0. The repository is unchanged: the new path resolves to it. Releases up to v0.4.0 remain available under the old path; later releases are published under the new path only, so an importer moves to them by replacing github.com/eitanity/softmagic with code.eitanity.com/softmagic in its imports and go.mod.

Use

db, err := softmagic.Default() // the embedded database; load once, keep it
if err != nil {
    log.Fatal(err)
}
// or, for your own rules: compile.Compile(os.DirFS(dir), softmagic.CompileOptions{})
r := db.Identify(data)
fmt.Println(r.Description, r.MIME, r.Charset, r.Extensions)
fmt.Println(r.Examined.Bytes, r.Examined.Truncated, r.Examined.DatabaseHash)

IdentifyWith takes a context.Context (its deadline ends the match with Truncated: "time") and Options (MaxBytes, default 7 MiB as in file 5.48; MaxDepth for use/indirect nesting; Executable, the file's permission bit). IdentifyAt takes an io.ReaderAt and the input's size, so the ELF built-in can read headers past the window as file(1) does; it is what a CLI should call for a file. IdentifyPrefix identifies a prefix and says in Examined.NeedMore whether more bytes could change the answer. List() prints the database in matching order in the format of file -l. A Result is never blank: an unmatched input is data / application/octet-stream.

Options.Continue is libmagic's MAGIC_CONTINUE, file -k: Result.Continued then holds every match, as one list per output mode (descriptions, MIME types, encodings, extensions, Apple codes). The reference computes each mode in a run of its own, so the lists are independent: element i of one is not about the same entry as element i of another. Each list joined with "\\012- " is byte-identical to file -b -k in that mode (with Raw, joined with "\n- ", to file -b -k -r), and the rest of the Result is what it is without the option. A continue call does the work of five runs and costs about five times a first-match call: median 0.26 ms against 0.03 ms on the corpus, max 1.1 ms. Options.Raw is MAGIC_RAW, file -r: the answer is returned as it was printed. Without it, every answer goes through the reference's output escaping, as libmagic's magic_buffer returns it: a character glibc's iswprint rejects in a UTF-8 locale (a control byte a %c rule copied from the input, say) is written as the \ooo escapes of its bytes, and an answer that is not valid UTF-8 has every byte outside printable ASCII escaped. The table of printable characters is generated from glibc (make wctype). Failure buffers are not escaped, as file prints its errors.

Options.SafeText is not in the reference: it gives an answer safe to put into HTML, a log line or a quoted value as it is. Every byte copied from the input (a %s string or match, a %c byte, an ELF interpreter or note string, a CDF property or catalog name) is written as \xHH unless it is printable ASCII other than \ < > & " ' and the backquote, so text from the file can neither open markup nor end a quoted value, and each backslash from the file starts an escape, which makes the text decode exactly. Every answer and failure buffer is then printable ASCII. The rules' own text and the classification are unchanged; it overrides Raw.

Options.Exclude is MAGIC_NO_CHECK_*, file -e: CheckSoft, CheckText, CheckEncoding, CheckTar, CheckJSON, CheckCSV, CheckSIMH, CheckCDF, CheckELF switch those checks off (CheckCompress, CheckAppType and CheckTokens are accepted and change nothing, as in the reference). Options.Limits is libmagic's other parameters, file -P: indirect count, use nesting, regex bytes, encoding bytes and the ELF note, program-header, section and note-size limits; zero is file's default and a negative value is its 0 (likewise MaxBytes, so MaxBytes: -1 is bytes=0). Three limits are errors in the reference when reached: indirect, name and ELF note size. The library still returns an answer, with Examined.Truncated naming the limit, and Result.Failures carries for each output mode the error libmagic would report; Failure.Text is what file prints after ERROR: .

softmagic.DumpSources and compile.Dump are file -c: each rule line, in the order read, in libmagic's parsed form (*unknown*, 14: > 0 string,=@abstract:,"A2ML ..."]), byte-identical to what file -c prints for the same directory.

The compiled form (Marshal, Load) carries a format version, the file release it was compiled for and the source hash; Load refuses another version or release by name. After Load or Default, regexes compile on first use behind one sync.Once per rule, which keeps the load near a millisecond. DefaultEager and LoadEager compile all of them before returning (1.5 ms for Magdir): nothing lazy remains, no allocation follows initialisation, and the matcher never touches a sync.Once. A database from compile.Compile is always eager, since compilation validates every pattern anyway, and a Join of two eager databases stays eager.

Two packages. softmagic loads, identifies, lists and marshals; softmagic/compile reads a rule directory, hashes it and builds a database (compile.Compile, compile.Append). The split is for the linker: a program that only loads the embedded database, the common case, imports softmagic alone and carries neither the hashing nor its package initialiser, nor the regex parser beyond what regexp itself needs; measured on a minimal load-and-identify program, 172 KB less in a stripped binary, with no crypto symbol left. Rules already in memory can go straight to softmagic.CompileSources, which takes the sources and the hash to record.

A caller's own rules extend the embedded database as file -m extends the reference's: compile them with CompileOptions{Base: base} so their use lines may name the base's entries, then compile.Append(base, extra) (or base.Join(extra, hash) with a hash of the caller's choosing). Each source keeps its own sort and the base is searched first, as the reference searches -m a:b; the joined database reports a hash over both, and Marshal writes it as one file. Result.Apple is the first !:apple annotation on the winning path, what file --apple prints.

CompileOptions.SourceDir is the directory name the reference was given on its command line (file -m <dir>); the reference writes <dir>/<file> into every empty description and its ordering tie-break compares those bytes, so the port needs the same name to reproduce the same order. The default, magic/Magdir, is what the listing oracle was taken with.

Safety

No unsafe, cgo, os/exec, network or third-party module in the build: every requirement in go.mod is there for a tool directive (the linters and govulncheck), and none is linked into the library or a program that uses it. SECURITY.md describes what the library trusts and how to use it on untrusted input. The compiled database is immutable; all per-call state is a pooled scan struct of fixed-size arrays. Every limit that fires is reported in Examined.Truncated. The module's own code follows Holzmann's Power of Ten: no recursion (the reference's recursive use/indirect evaluation runs on an explicit frame stack), only counted loops, one assertion primitive (internal/invariant) that panics in tests and in release returns the failed condition to its caller, which handles it, functions under a page, no package-level mutable state, checked integer conversions, one build tag, no function values or double indirection, and zero warnings from every tool. internal/rules is the test that checks what the linters cannot.

Verification

make test     # go test -tags softmagic_assert -race ./...
make lint     # vet, staticcheck, govulncheck, gosec, golangci-lint
make fuzz     # every fuzz target for FUZZTIME (default 30s), on amd64 and 386, with and without assertions
make cross    # go vet on every supported OS and architecture
make emulated # the tests on s390x, ppc64, mips, arm and arm64 under qemu-user
make generate # rebuild magic/softmagic.db from magic/Magdir (TestEmbeddedCurrent fails if stale)
make wctype   # regenerate wctype.go, the iswprint table, from this host's glibc (C.UTF-8)
go test -tags softmagic_assert -run NONE -fuzz FuzzIdentify -fuzztime 60s .
go test -run TestLatencyReport -v .

Every test runs under -tags softmagic_assert, which makes a failed invariant panic. The parity corpus and its expected outputs are described in testdata/corpus/SOURCES.md; the reference listing is testdata/file-5.48-list.txt. Both came from file 5.48 built from the signed release tarball (magic/README.md).

Updating the database

A file release is one commit: verify the tarball's signature, diff the grammar in apprentice.c, softmagic.c and file.h against the implemented release, vendor Magdir and COPYING, regenerate the expected listing and corpus outputs with the reference built from the same tarball, and bump ImplementsFile. A database newer than ImplementsFile is refused.

Documentation

Overview

Package softmagic is a pure-Go port of file(1)'s rule-driven matcher.

It compiles libmagic's Magdir source files unchanged and reproduces the reference's entry ordering exactly. The ordering, strength and tie-break code is a translation of apprentice.c from file 5.48, Copyright (c) Ian F. Darwin 1986-1995, maintained by Christos Zoulas; that notice is reproduced in COPYING.

This module is a library only. The command-line tool lives in the separate module code.eitanity.com/softmagic-cli.

Index

Constants

View Source
const (
	// PhaseBuiltin is a built-in detector (tar, JSON, CSV, SIMH, CDF).
	PhaseBuiltin = "builtin"
	// PhaseMagic is a binary rule match, with any ELF text appended.
	PhaseMagic = "magic"
	// PhaseText is the text phase: text rules and the encoding
	// description.
	PhaseText = "text"
	// PhaseDefault is "data", "empty" or "very short file (no magic)".
	PhaseDefault = "default"
)

Phases: which pass of file_buffer produced the description.

View Source
const (
	TruncRecursion = "recursion"
	TruncSearch    = "search"
	TruncRegex     = "regex"
	TruncTime      = "time"
	TruncOutput    = "output"
	TruncInvariant = "invariant"
	// TruncCDF is a Composite Document File sector chain larger than the
	// library reads (only a header with a nonstandard sector size can
	// declare one); the document is described as one whose chain could
	// not be read.
	TruncCDF = "cdf"
	// TruncMemory is Options.MaxMemory: a read past the window that would
	// have held more than the budget failed, and the answer is the one
	// the reference gives when that read fails.
	TruncMemory = "memory"
	// TruncIndirect, TruncName and TruncELF are the hard limits of
	// Options.Limits: the reference stops with an error, and so does the
	// output mode that reached one (see Result.Failures).
	TruncIndirect = "indirect"
	TruncName     = "name"
	TruncELF      = "elf"
	// TruncRead is a window IdentifyAt could not read; see
	// Examined.ReadError.
	TruncRead = "read"
)

Truncation reasons.

View Source
const (
	// DefaultMaxBytes is how much of the input is consulted: the
	// reference's FILE_BYTES_MAX in file 5.48.
	DefaultMaxBytes = 7 * 1024 * 1024

	// DefaultMaxMemory is how many bytes one call's working buffers may
	// hold beyond the input window, the default of Options.MaxMemory.
	DefaultMaxMemory = 64 << 20
)

Limits. The reference's are named beside each. A limit that fires is reported in Examined.Truncated, never hidden.

View Source
const ImplementsFile = "5.48"

ImplementsFile is the file(1) release whose grammar, strength function and sort this package reproduces. A compiled database made for another release is refused at load.

Variables

This section is empty.

Functions

func DumpSources

func DumpSources(srcs []Source, o CompileOptions) (string, error)

DumpSources is file -c over rule sources: each rule line in the order read, in libmagic's parsed form, one per line as file_mdump prints it. The text is what was dumped before an error, if there was one; the reference prints a warning for a refused line and goes on, where this returns the CompileError.

Types

type Checks

type Checks uint16

Checks is a set of libmagic's optional checks, for Options.Exclude.

const (
	CheckSoft     Checks = 1 << iota // the rules: -e soft
	CheckText                        // the text phase: -e text, -e ascii
	CheckEncoding                    // the classification file_buffer passes on: -e encoding
	CheckTar                         // -e tar
	CheckJSON                        // -e json
	CheckCSV                         // -e csv
	CheckSIMH                        // -e simh
	CheckCDF                         // -e cdf
	CheckELF                         // -e elf
	CheckCompress                    // -e compress
	CheckAppType                     // -e apptype
	CheckTokens                      // -e tokens
)

The checks file -e names. CheckCompress, CheckAppType and CheckTokens are accepted and have no effect, as in the reference on this platform: there is no decompression, the application-type check is OS/2's, and tokens is kept upstream only for compatibility.

type CompileError

type CompileError struct {
	File string
	Msg  string
	Line int
}

CompileError is a refused rule file: the file and line are always named so a malformed rule fails here, at compile time; identifying has no error path.

func (*CompileError) Error

func (e *CompileError) Error() string

type CompileOptions

type CompileOptions struct {
	// Base, when set, is the database this one will be appended to: a
	// "use" may name one of its "name" entries (a local rule
	// file extending the embedded database, as file -m a:b does).
	Base *Database
	// SourceDir is the directory name the reference was given on its command
	// line (file -m <dir>). The reference tucks "<dir>/<file>" into every
	// empty description, where it takes part in the ordering tie-break
	// so the port must know the same name to reproduce the same
	// order. Default: "magic/Magdir".
	SourceDir string
}

CompileOptions configures Compile. The zero value is the default.

type Continued

type Continued struct {
	// Descriptions is file -b -k.
	Descriptions []string
	// MIMEs is file -b -k --mime-type. file -b -k -i is MIMEs joined,
	// then "; charset=" and Result.Charset.
	MIMEs []string
	// Encodings is file -b -k --mime-encoding: separators from the matches,
	// which print nothing in that mode, then the charset in the last
	// element.
	Encodings []string
	// Extensions is file -b -k --extension, each element as printed
	// ("jpeg/jpg").
	Extensions []string
	// Apple is file -b -k --apple.
	Apple []string
	// Failures are the continue runs that a hard limit stopped; a mode
	// that failed has no list.
	Failures Failures
}

Continued is a continue-mode answer (libmagic's MAGIC_CONTINUE, file -k). The reference computes each output mode in a run of its own, and an entry can answer in one mode and not another (a match with no MIME annotation is a description and no MIME type), so element i of one list is not about the same entry as element i of another. Each list is that mode's output split where a separator was printed. Without Options.Raw the elements are escaped as the reference escapes the one buffer it prints them in, so joined with "\\012- " (the separator as that escaping prints it) a list is byte-identical to file -b -k in that mode; with Raw, joined with "\n- ", to file -b -k -r. An element can be empty: the reference prints a separator after a match that printed nothing in that mode. All are nil without Options.Continue.

type Database

type Database struct {
	// contains filtered or unexported fields
}

Database is a compiled, immutable rule set. It is safe for concurrent use: nothing writes to it after Compile returns, and all per-call state lives in the pooled scan.

func CompileSources

func CompileSources(hash string, srcs []Source, o CompileOptions) (*Database, error)

CompileSources builds the sorted database from rule sources in the order given (the reference reads a directory in byte order of name) and records hash as the database's identity, which Hash and Examined.DatabaseHash report. The compile package reads a directory and hashes it; call that unless the rules are already in memory.

func Default

func Default() (*Database, error)

Default loads the database compiled into the library from the vendored Magdir of the release named by ImplementsFile. Load it once and keep it; it is safe for concurrent use. Its regexes compile on first use, which keeps the load near a millisecond; DefaultEager compiles them now. Unlike Load it does not compile them to check them: the embedded bytes are what Compile produced, which TestEmbeddedCurrent enforces.

func DefaultEager

func DefaultEager() (*Database, error)

DefaultEager is Default with every regex compiled before it returns: no lazy work and no allocation after this call, at about 1.5 ms more load time. A long-running process wants this; a one-file command does not.

func Load

func Load(data []byte) (*Database, error)

Load reads a compiled database. It refuses a different format version or a database compiled for a different file(1) release, naming both, and any record Compile could not have produced, including a regex RE2 rejects: every regex is compiled before Load returns (about 1 ms for the whole Magdir), since the bytes may come from anywhere.

func LoadEager

func LoadEager(data []byte) (*Database, error)

LoadEager is Load, which already compiles every regex before it returns; it is kept beside DefaultEager for callers that name it.

func (*Database) Entries

func (db *Database) Entries() int

Entries is the number of top-level entries in all sets of all maps.

func (*Database) Hash

func (db *Database) Hash() string

Hash is the SHA-256 of the Magdir source the database was compiled from, as hex: Examined.DatabaseHash in every Result.

func (*Database) Identify

func (db *Database) Identify(data []byte) Result

Identify returns what file(1) would print for data, with the default options and no deadline. It is safe to call from any number of goroutines on one Database.

func (*Database) IdentifyAt

func (db *Database) IdentifyAt(ctx context.Context, r io.ReaderAt, size int64, o Options) Result

IdentifyAt identifies an input of the given size that r reads: the first MaxBytes are consulted as Identify would, and the ELF built-in may read headers beyond them, as file(1) does through its file descriptor. Examined.Bytes counts only the window.

func (*Database) IdentifyPrefix

func (db *Database) IdentifyPrefix(ctx context.Context, prefix []byte, o Options) Result

IdentifyPrefix identifies from a prefix of the input: Examined.Complete is false, and NeedMore reports whether more bytes could change the answer.

func (*Database) IdentifyWith

func (db *Database) IdentifyWith(ctx context.Context, data []byte, o Options) Result

IdentifyWith is Identify with a context, whose deadline or cancellation stops the match with Truncated "time", and explicit options.

func (*Database) Join

func (db *Database) Join(extra *Database, hash string) (*Database, error)

Join returns a new database that searches db first and then extra, as file(1) searches the directories of `-m a:b` in order: each keeps its own sort, a "use" may name an entry of either, and the first map to match answers. hash identifies the combination; the compile package's Append derives one from both inputs' hashes. Neither input is modified.

func (*Database) Lines

func (db *Database) Lines() int

Lines is the number of rule lines.

func (*Database) List

func (db *Database) List() string

List prints every entry in matching order in the format of file -l:

Set 0:
Binary patterns:
Strength = 670@1446: WonderWitch transfer file []
...
Text patterns:
...
Set 1:
...

The output is byte-identical to the reference's `file -m <dir> -l` for the same Magdir; the tests compare the two in full, which is what proves the matching order.

func (*Database) Marshal

func (db *Database) Marshal() ([]byte, error)

Marshal serialises the database in the compiled form.

type Examined

type Examined struct {
	// Truncated is "" or what stopped a match, one of the Trunc constants:
	// "recursion", "search", "regex", "time", "output", "invariant" (an
	// internal consistency check failed and the entry under evaluation was
	// skipped), "cdf", "memory", "indirect", "name", "elf" or "read".
	Truncated string
	// ReadError is the error IdentifyAt's reader returned for the window,
	// when it read fewer bytes than asked and the error is not io.EOF.
	// Nothing was identified: Truncated is TruncRead and the answer is
	// the default, "data". file reports such an input as unreadable.
	ReadError error
	// DatabaseHash is the hash of the Magdir source the database was
	// compiled from.
	DatabaseHash string
	// ImplementsFile is the file(1) release whose grammar and ordering this
	// library reproduces.
	ImplementsFile string
	// Bytes is the number of input bytes actually consulted.
	Bytes int
	// Complete is true when the whole input was available; false for a
	// bounded prefix (IdentifyPrefix).
	Complete bool
	// NeedMore is true when a longer prefix could change Description or
	// MIME; always false when Complete.
	NeedMore bool
}

Examined reports the scope and the limits of one identification.

type Failure

type Failure struct {
	// Message is libmagic's own: "indirect count (50) exceeded".
	Message string
	// Buffer is what the output buffer held: what the mode had printed, or,
	// when Pushed, the output of the indirect match or ELF reader the error
	// came inside, which the reference reads into a buffer of its own.
	Buffer string
	Pushed bool
}

Failure is libmagic's error for one output mode; the zero value is none. libmagic appends Message to its current output buffer, after a blank when that is not empty, and magic_error returns the result: see Text.

func (Failure) Failed

func (f Failure) Failed() bool

Failed reports whether the mode stopped with an error.

func (Failure) Text

func (f Failure) Text(prefix string) string

Text is magic_error's text, which file(1) prints after "ERROR: ". prefix is whatever the caller's buffer held before the identification began (file's stat-layer words, such as "setuid "); it is part of the buffer only when the error was not inside a pushed one.

type Failures

type Failures struct {
	Description Failure
	MIME        Failure // also -i, which is the MIME run with the charset after it
	Encoding    Failure
	Extension   Failure
	Apple       Failure
}

Failures holds, per output mode, the error libmagic reports when a hard limit of Options.Limits stopped that mode's run. Each mode is a run of its own in the reference, and a run that returns at its first annotation can finish before the line that stops another, so one mode can fail while another answers.

type Limits

type Limits struct {
	Indirect  int // -P indir: indirect evaluations per pass over the rules (50)
	Name      int // -P name: nested name/use evaluations (150)
	Regex     int // -P regex: bytes a regex test scans (8192)
	Encoding  int // -P encoding: bytes classified as text or not (65536)
	ELFNotes  int // -P elf_notes: ELF notes read (256)
	ELFPhnum  int // -P elf_phnum: ELF program headers read (2048)
	ELFShnum  int // -P elf_shnum: ELF section headers read (32768)
	ELFShsize int // -P elf_shsize: largest ELF note section read (128 MiB)
}

Limits are libmagic's MAGIC_PARAM_* parameters (file -P) other than the byte count, which is Options.MaxBytes. Zero means file's default; a negative value stands for file's 0; a value above what file -P accepts is clamped to it. Reaching Indirect, Name or ELFShsize stops the identification as the reference's error does: see Result.Failures.

type LoadError

type LoadError struct {
	Msg string
}

LoadError is a refused compiled database.

func (*LoadError) Error

func (e *LoadError) Error() string

type Options

type Options struct {
	// MaxBytes caps the input consulted (file -P bytes); 0 means
	// DefaultMaxBytes, a negative value means none at all, as bytes=0
	// does for the reference, and values above 0x7fffffff, the most file
	// -P accepts, are clamped to it. IdentifyAt allocates the window, up
	// to the smaller of MaxBytes and the input's size, before it reads.
	MaxBytes int
	// MaxDepth caps use/indirect nesting; 0 means maxFrames, and larger
	// values are clamped to it.
	MaxDepth int
	// Executable is the input file's executable permission bit, which the
	// reference consults through ${x?a:b} in rule descriptions (file(1)
	// sets it from stat; an ELF dynamic section overrides it).
	Executable bool
	// Continue is libmagic's MAGIC_CONTINUE (file -k): Result.Continued
	// lists every match in each output mode. The other fields of the
	// Result are what they are without it.
	Continue bool
	// Raw is libmagic's MAGIC_RAW (file -r): the answer is returned as it
	// was printed. Without it, strings copied from the input have their
	// non-printable bytes as \ooo escapes, and the whole answer then goes
	// through the reference's output escaping, which writes as \ooo every
	// character glibc's iswprint rejects in a UTF-8 locale (a control byte
	// a %c rule copied, say) and, when the answer is not valid UTF-8,
	// every byte outside printable ASCII.
	Raw bool
	// SafeText is not in the reference: an answer safe to place in HTML, a
	// log line or a quoted value as it is. Every byte copied from the
	// input is written as \xHH unless it is printable ASCII other than
	// \ < > & " ' and `, so text from the file can neither open markup
	// nor end a quoted value, and each backslash from the file starts an
	// escape, which makes the text decode exactly. The answer as a whole,
	// failure buffers included, is then printable ASCII: any other byte,
	// such as the UTF-8 of a rule's own text, is \xHH too. Rule text is
	// otherwise unchanged and the classification is the same. It
	// overrides Raw. The answer is no longer the reference's.
	SafeText bool
	// Exclude switches checks off, as libmagic's MAGIC_NO_CHECK_* flags
	// (file -e) do.
	Exclude Checks
	// Limits are libmagic's other MAGIC_PARAM_* parameters (file -P).
	Limits Limits
	// MaxMemory caps the bytes one call's working buffers may hold beyond
	// the input window: the tables and streams of a Composite Document
	// File, ELF data read past the window, and the file's tail. 0 means
	// DefaultMaxMemory, values above 1 GiB are clamped to it, and a
	// negative value allows none. A read that would need more fails, with
	// Truncated "memory". The reference has no such limit.
	MaxMemory int
}

Options configures one identification. The zero value means defaults.

type Result

type Result struct {
	// Description is exactly what `file -b` prints.
	Description string
	// MIME is exactly what `file -b -i` prints before "; charset=".
	MIME string
	// Charset is the charset `file -i` reports; "binary" for binary input.
	Charset string
	// Extensions is the !:ext list of the first annotated line on the
	// winning path, split on '/'; nil when there is none.
	Extensions []string
	// Apple is the !:apple creator/type of the first annotated line on the
	// winning path (what `file --apple` prints); "" when there is none.
	Apple string
	// Rules lists every rule line that contributed text, in emission order.
	Rules []RuleID
	// Phase names the pass that produced Description: PhaseBuiltin,
	// PhaseMagic, PhaseText or PhaseDefault. file(1)'s driver needs it:
	// the reference joins its stat-layer prefix to a text-phase
	// description differently from the others.
	Phase string
	// Continued is set with Options.Continue: what `file -b -k` prints in
	// each output mode, as lists.
	Continued Continued
	// Failures is set when a hard limit of Options.Limits stopped an output
	// mode, where the reference reports an error; the fields above are then
	// what was established before it.
	Failures Failures
	// Examined says what the call looked at and what stopped it.
	Examined Examined
	// Strength is the winning entry's computed strength (as file -l prints it), 0 when
	// no entry matched.
	Strength int
}

Result is what Identify returns. A blank is never an answer: an input that matches no rule has Description "data" and MIME "application/octet-stream", as file(1) prints.

type RuleID

type RuleID struct {
	File string
	Line int
}

RuleID names a rule line by its source file and line number.

type Source

type Source struct {
	Name string
	Data []byte
}

Source is one rule file: its name, which error messages and the ordering tie-break use, and its text.

Directories

Path Synopsis
Package compile builds a softmagic database from rule source on a file system, as file(1) reads a magic directory, and identifies the result by a SHA-256 of what it read.
Package compile builds a softmagic database from rule source on a file system, as file(1) reads a magic directory, and identifies the result by a SHA-256 of what it read.
internal
invariant
Package invariant is the module's one assertion primitive (Power of Ten rule 5: assertions stay in production and have a recovery action).
Package invariant is the module's one assertion primitive (Power of Ten rule 5: assertions stay in production and have a recovery action).
rules
Package rules holds the test that checks this module's own code against the parts of Holzmann's Power of Ten ("The Power of 10: Rules for Developing Safety-Critical Code", IEEE Computer 39(6), 2006) that no linter checks: recursion, loop forms, assertion density, conversions to int that a 32-bit host would wrap, pointer and func types, package-level state, build tags and suppression comments.
Package rules holds the test that checks this module's own code against the parts of Holzmann's Power of Ten ("The Power of 10: Rules for Developing Safety-Critical Code", IEEE Computer 39(6), 2006) that no linter checks: recursion, loop forms, assertion density, conversions to int that a 32-bit host would wrap, pointer and func types, package-level state, build tags and suppression comments.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL