-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathmagicmime.go
211 lines (171 loc) · 6.25 KB
/
magicmime.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build linux darwin freebsd
// Package magicmime detects mimetypes using libmagic.
// This package requires libmagic, install it by the following
// commands below.
// - Debian or Ubuntu: apt-get install libmagic-dev
// - RHEL, CentOS or Fedora: yum install file-devel
// - Mac OS X: brew install libmagic
package magicmime
// #cgo CFLAGS: -I/usr/local/include
// #cgo LDFLAGS: -lmagic -L/usr/local/lib
// #include <stdlib.h>
// #include <magic.h>
import "C"
import (
"errors"
"sync"
"unsafe"
)
// Decoder allows for doing mimetype detection using libmagic.
type Decoder struct {
db C.magic_t
}
// decMu and dec are used for the package level functions.
var (
decMu sync.Mutex
dec *Decoder
)
type Flag int
const (
// No special handling
MAGIC_NONE Flag = C.MAGIC_NONE
// Prints debugging messages to stderr
MAGIC_DEBUG Flag = C.MAGIC_DEBUG
// If the file queried is a symlink, follow it.
MAGIC_SYMLINK Flag = C.MAGIC_SYMLINK
// If the file is compressed, unpack it and look at the contents.
MAGIC_COMPRESS Flag = C.MAGIC_COMPRESS
// If the file is a block or character special device, then open the device
// and try to look in its contents.
MAGIC_DEVICES Flag = C.MAGIC_DEVICES
// Return a MIME type string, instead of a textual description.
MAGIC_MIME_TYPE Flag = C.MAGIC_MIME_TYPE
// Return a MIME encoding, instead of a textual description.
MAGIC_MIME_ENCODING Flag = C.MAGIC_MIME_ENCODING
// A shorthand for MAGIC_MIME_TYPE | MAGIC_MIME_ENCODING.
MAGIC_MIME Flag = C.MAGIC_MIME
// Return all matches, not just the first.
MAGIC_CONTINUE Flag = C.MAGIC_CONTINUE
// Check the magic database for consistency and print warnings to stderr.
MAGIC_CHECK Flag = C.MAGIC_CHECK
// On systems that support utime(2) or utimes(2), attempt to preserve the
// access time of files analyzed.
MAGIC_PRESERVE_ATIME Flag = C.MAGIC_PRESERVE_ATIME
// Don't translate unprintable characters to a \ooo octal representation.
MAGIC_RAW Flag = C.MAGIC_RAW
// Treat operating system errors while trying to open files and follow
// symlinks as real errors, instead of printing them in the magic buffer
MAGIC_ERROR Flag = C.MAGIC_ERROR
// Return the Apple creator and type.
MAGIC_APPLE Flag = C.MAGIC_APPLE
// Don't check for EMX application type (only on EMX).
MAGIC_NO_CHECK_APPTYPE Flag = C.MAGIC_NO_CHECK_APPTYPE
// Don't get extra information on MS Composite Document Files.
MAGIC_NO_CHECK_CDF Flag = C.MAGIC_NO_CHECK_CDF
// Don't look inside compressed files.
MAGIC_NO_CHECK_COMPRESS Flag = C.MAGIC_NO_CHECK_COMPRESS
// Don't print ELF details.
MAGIC_NO_CHECK_ELF Flag = C.MAGIC_NO_CHECK_ELF
// Don't check text encodings.
MAGIC_NO_CHECK_ENCODING Flag = C.MAGIC_NO_CHECK_ENCODING
// Don't consult magic files.
MAGIC_NO_CHECK_SOFT Flag = C.MAGIC_NO_CHECK_SOFT
// Don't examine tar files.
MAGIC_NO_CHECK_TAR Flag = C.MAGIC_NO_CHECK_TAR
// Don't check for various types of text files.
MAGIC_NO_CHECK_TEXT Flag = C.MAGIC_NO_CHECK_TEXT
// Don't look for known tokens inside ascii files.
MAGIC_NO_CHECK_TOKENS Flag = C.MAGIC_NO_CHECK_TOKENS
)
// NewDecoder creates a detector that uses libmagic. It initializes
// the opens the magicmime database with the specified flags. Upon
// success users are expected to call Close on the returned Decoder
// when it is no longer needed.
func NewDecoder(flags Flag) (*Decoder, error) {
db := C.magic_open(C.int(0))
if db == nil {
return nil, errors.New("error opening magic")
}
d := &Decoder{db: db}
if code := C.magic_setflags(db, C.int(flags)); code != 0 {
d.Close()
return nil, errors.New(C.GoString(C.magic_error(d.db)))
}
if code := C.magic_load(db, nil); code != 0 {
d.Close()
return nil, errors.New(C.GoString(C.magic_error(d.db)))
}
return d, nil
}
// TypeByFile looks up for a file's mimetype by its content.
// It uses a magic number database which is described in magic(5).
func (d *Decoder) TypeByFile(filename string) (string, error) {
path := C.CString(filename)
defer C.free(unsafe.Pointer(path))
out := C.magic_file(d.db, path)
if out == nil {
return "", errors.New(C.GoString(C.magic_error(d.db)))
}
return C.GoString(out), nil
}
// TypeByBuffer looks up for a blob's mimetype by its contents.
// It uses a magic number database which is described in magic(5).
func (d *Decoder) TypeByBuffer(blob []byte) (string, error) {
bytes := unsafe.Pointer(&blob[0])
out := C.magic_buffer(d.db, bytes, C.size_t(len(blob)))
if out == nil {
return "", errors.New(C.GoString(C.magic_error(d.db)))
}
return C.GoString(out), nil
}
// Close frees up resources associated with d.
func (d *Decoder) Close() {
C.magic_close(d.db)
d.db = nil
}
// Open initializes a global Decoder and opens the magicmime database
// with the specified flags. Once successfully opened, users must
// call Close when they are finished using the package. This must
// be called before any of the package level functions.
func Open(flags Flag) error {
decMu.Lock()
defer decMu.Unlock()
if dec != nil {
return errors.New("cannot open; magic mime db is already open")
}
var err error
dec, err = NewDecoder(flags)
return err
}
// TypeByFile calls TypeByFile on the global Decoder. This is safe for
// concurrent use with the other package level TypeBy* functions.
func TypeByFile(filename string) (string, error) {
decMu.Lock()
defer decMu.Unlock()
return dec.TypeByFile(filename)
}
// TypeByBuffer calls TypeByBuffer on the global Decoder. This is safe for
// concurrent use with the other package level TypeBy* functions.
func TypeByBuffer(blob []byte) (string, error) {
decMu.Lock()
defer decMu.Unlock()
return dec.TypeByBuffer(blob)
}
// Close cleans up the resources associated with the global detector.
func Close() {
dec.Close()
dec = nil
}