file.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1989-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* file -- determine file type
*
* the sum of the hacks {s5,v10,planix} is _____ than the parts
*/
static const char usage[] =
"[-?\n@(#)$Id: file (AT&T Research) 2011-08-01 $\n]"
"[+NAME?file - determine file type]"
"[+DESCRIPTION?\bfile\b tests and attempts to classify each \afile\a argument."
" Non-regular files are classified by their \bstat\b(2) types. Empty and"
" non-readable regular files are classified as such. Otherwise a data"
" block is read from \afile\a and this is used to match against the"
" \amagic\a file(s) (see \bMAGIC FILE\b below). Files with less than 1024"
" bytes of data are labelled \bsmall\b to note that the sample may"
" be too small for an accurate classification. Failing a content match,"
" the file name extension may be used to classify. As a last resort"
" statistical sampling is done for a small range of languages and"
" applications. Failed matches usually result in the less informative"
" \bascii text\b or \bbinary data\b.]"
"[a:all?List all magic table matches.]"
"[b:brief|no-filename?Suppress the output line file name prefix.]"
"[c:mime?List the \bmime\b(1) classification for each \afile\a. Although the"
" default descriptions are fairly consistent, use \b--mime\b for"
" precise classification matching.]"
"[d:default-magic?Equivalent to \b--magic=-\b.]"
"[f:files|file-list?\afile\a contains list of file names, one per line, that"
" are classified.]:[file]"
"[l:list?The loaded \amagic\a files are listed and then \bfile\b exits.]"
"[M:magic?\afile\a is loaded as a \amagic\a file. More than one \b--magic\b"
" option may be specified; the precedence is from left to right. The"
" first \b--magic\b option causes the default system \amagic\a file to"
" be ignored; the file \b-\b may then be specified to explicitly"
" load the default system \amagic\a file. To ignore all magic files"
"[m:append-magic?\afile\a is loaded as a \amagic\a file. Equivalent to the"
" \b--magic\b option, except that the default system \amagic\a file is"
" still loaded last. If \b--magic\b is also specified then the default"
" system \amagic\a is only loaded if explicity specified.]:[file]"
"[p:pattern|match?Only files with descriptions matching the \bsh\b(1)"
" match \apattern\a are listed. \bfile\b exits with status 0 if any"
" files match, 0 otherwise.]:[pattern]"
"[q:quiet|silent?Do not list matching \b--pattern\b files.]"
"[L:logical|dereference?Follow symbolic links.]"
"[P|h:physical?Don't follow symbolic links.]"
"[w:warn?Enable magic file parse warning messages.]"
"\n"
"\n[ file ... ]\n"
"\n"
"[+MAGIC FILE?A \amagic\a file specifies file content and name match"
" expressions, descriptions, and \bmime\b(1) classifications. Each line"
" in the file consists of five \btab\b separated fields:]{"
" [+[op]]offset?\aoffset\a determines tha data location for the content"
" test. \b(@\b\aexpression\a\b)\b specifies an indirect offset,"
" i.e., the offset is the numeric contents of the data"
" location at \aexpression\a. The default indirect numeric size"
" is 4 bytes; a \bB\b suffix denotes 1 byte, \bH\b denotes 2"
" bytes, and \bQ\b denotes 8 bytes. \aoffset\a may also be one"
" of { \batime\b \bblocks\b \bctime\b \bfstype\b \bgid\b"
" \bmode\b \bmtime\b \bname\b \bnlink\b \bsize\b \buid\b } to"
" access \bstat\b(2) information for the current file. The"
" optional \aop\a specifies relationships with surrounding"
" \amagic\a lines:]{"
" [++?previous fields in block match, current optional]"
" [+&?previous and current fields in block match]"
" [+|?previous fields in block do not match, subsequent skipped]"
" [+{?start nesting block]"
" [+}?end nesting block]"
" [+c{?function declaration and call (1 char names)]"
" [+}?function return]"
" [+c()?function call]"
" }"
" [+type?The content data type:]{"
" [+byte?1 byte integer]"
" [+short?2 byte integer]"
" [+long?4 byte integer]"
" [+quad?8 byte integer]"
" [+date?4 byte time_t]"
" [+version?4 byte unsigned integer of the form \aYYYYMMDD\a"
" for \aYYYY-MM-DD\a, 0x\aYYZZ\a for \aYY.ZZ\a, or"
" 0x\aWWXXYYZZ\a for \aWW.XX.YY.ZZ\a]"
" [+edit?substitute operator for string data:"
" %\aold\a%\anew\a%[glu]], where \b%\b is any delimiter]"
" [+match?case insensitive \bsh\b(1) match pattern operator"
" for string data]"
" }"
" [+[mask]]operator?\amask\a is an optional \b&\b\anumber\a that is"
" masked (bit \band\b) with the content data before"
" comparison. \aoperator\a is one of { \b< <= > >= != ==\b }."
" Numeric values may be decimal, octal or hex.]"
" [+description?The description text. Care was taken to maintain"
" consistency between all descriptions, i.e., character case,"
" grammatical parts placement, and punctuation, making"
" description pattern matches feasible. \adescription\a may"
" contain one \bprintf\b(3) format specification for the"
" current data value at \aoffset\a.]"
" and consistent matching key space.]"
"}"
"[+FILES]{"
"}"
"[+SEE ALSO?\bfind\b(1), \bls\b(1), \bmime\b(1), \btw\b(1)]"
;
#include <ast.h>
#include <magic.h>
#include <ctype.h>
#include <error.h>
#define MAGIC_BRIEF (MAGIC_USER<<0)
static int
{
char* s;
char* e;
if (fp)
if (!pattern)
{
return 1;
}
{
return 1;
}
return 0;
}
int
{
register char* p;
char* pattern = 0;
int hit;
for (;;)
{
{
case 'a':
continue;
case 'b':
continue;
case 'c':
continue;
case 'd':
continue;
case 'f':
if (streq(opt_info.arg, "-") || streq(opt_info.arg, "/dev/stdin") || streq(opt_info.arg, "/dev/fd/0"))
continue;
case 'i':
continue;
case 'l':
continue;
case 'L':
continue;
case 'm':
continue;
case 'M':
continue;
case 'p':
continue;
case 'P':
case 'h':
continue;
case 'q':
continue;
case 'w':
continue;
case '?':
continue;
case ':':
continue;
}
break;
}
if (error_info.errors)
{
hit = 1;
}
else
{
hit = 0;
if (list)
if (*p)
while (p = *argv++)
if (*p)
}
return !hit;
}