What’s that? Using magic on your Mac

Most files and packages – folders cunningly disguised as files – have extensions and other telltales which reveal what they are. If it has the extension .txt or .text and QuickLook previews its contents as text, you can be confident that’s what it is.

But every so often, you’ll come across one or more files which are more obscure. QuickLook doesn’t want to know them, and the Finder’s Get Info dialog isn’t much more helpful. This article looks at the definitive way to discover exactly what every file and Finder item is, and the fascinating ‘magic’ system which makes that possible: using the command tool file.

file is very simple to use. Just give it a file to inspect, and it’ll tell you what it knows about it.
file /sbin/autodiskmount
should return something like
/sbin/autodiskmount: Mach-O executable i386
meaning that is a command tool which is 32-bit only.

It’s a bit less helpful with app bundles, though:
file /Applications/iMovie.app
returns
/Applications/iMovie.app: directory
rather than telling you that it’s an app bundle. To find out more, you’ll have to point file at the app code itself:
file /Applications/iMovie.app/Contents/MacOS/iMovie
then reveals
/Applications/iMovie.app/Contents/MacOS/iMovie: Mach-O 64-bit executable x86_64

So, if nothing else, file is a useful way to check Mach-O code files to see if they’re still 32-bit.

The Finder isn’t always good at grokking different types of text file. A LaTeX document named test.tex, for example, will just be shown as a text file. Point file at it, though, and you’ll be informed
test.tex: LaTeX 2e document text, ASCII text

file has plenty of options if you want to do more sophisticated things with it, like retrieve the classic file type and creator code, return MIME type strings rather than normal results, or look inside compressed files. But most of the time, the plain command and file path will be all that you’ll want to use.

So how does file do so much better than the Finder?

Its man page, one of the best you’ll ever find, explains that file uses three unrelated systems to establish what the file is. The first is to ask macOS for the file attributes, which is what the Finder does too.

If that doesn’t identify the file properly, it then turns to magic, or, to be more precise, the file’s magic number. This is the first few bytes of the file. It matches those against the patterns it holds in /usr/share/file/magic.mgc, which it compiles in turn from the definitions kept in files inside /usr/share/file/magic. You can browse those text files if you’re interested: they contain many fascinating tidbits of information, and can be helpful to developers at any level.

If attributes and magic can’t tell what the file is, file has one more trick up its sleeve: it peeks. This works best for telling the different forms of text, like ASCII and UTF-8, apart.

If you write code in Swift 4, it’s not hard to use magic yourself, although it is easier to read the whole of a file than just its first few bytes.

I’m sure there are some magic definitions which you could import, but in my case it was quicker just to add the two that I needed.
let theMagic32: UInt32 = 0xfeedface
let theMagic64: UInt32 = 0xfeedfacf

When you have confirmed that a URL does refer to a file,
let theFHandle = try FileHandle.init(forReadingFrom: theSourceURL)
gets a traditional FileHandle for the URL.

let theMagic = theFHandle.readData(ofLength: 4)
reads just the first 4 bytes of the file, containing that magic number, into Data. Then ensure that you’ve actually got 4 bytes of Data:
if !theMagic.isEmpty {
if theMagic.count > 3 {
let theMagicNumber = theMagic.withUnsafeBytes { (ptr: UnsafePointer<UInt32>) -> UInt32 in return ptr.pointee }

returns the 4 bytes of Data as a UInt32, which you can test to see if it is theMagic32 with
if theMagicNumber == self.theMagic32 {
and so on.

It’s disappointing and puzzling that Apple doesn’t enhance the Finder’s Get Info dialog with the addition of magic checks, but at least they’re readily accessible in Terminal.