file.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <bio.h>
  4. #include <ctype.h>
  5. #include <mach.h>
  6. /*
  7. * file - determine type of file
  8. */
  9. #define LENDIAN(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
  10. uchar buf[6001];
  11. short cfreq[140];
  12. short wfreq[50];
  13. int nbuf;
  14. Dir* mbuf;
  15. int fd;
  16. char *fname;
  17. char *slash;
  18. enum
  19. {
  20. Cword,
  21. Fword,
  22. Aword,
  23. Alword,
  24. Lword,
  25. I1,
  26. I2,
  27. I3,
  28. Clatin = 128,
  29. Cbinary,
  30. Cnull,
  31. Ceascii,
  32. Cutf,
  33. };
  34. struct
  35. {
  36. char* word;
  37. int class;
  38. } dict[] =
  39. {
  40. "PATH", Lword,
  41. "TEXT", Aword,
  42. "adt", Alword,
  43. "aggr", Alword,
  44. "alef", Alword,
  45. "array", Lword,
  46. "block", Fword,
  47. "char", Cword,
  48. "common", Fword,
  49. "con", Lword,
  50. "data", Fword,
  51. "dimension", Fword,
  52. "double", Cword,
  53. "extern", Cword,
  54. "bio", I2,
  55. "float", Cword,
  56. "fn", Lword,
  57. "function", Fword,
  58. "h", I3,
  59. "implement", Lword,
  60. "import", Lword,
  61. "include", I1,
  62. "int", Cword,
  63. "integer", Fword,
  64. "iota", Lword,
  65. "libc", I2,
  66. "long", Cword,
  67. "module", Lword,
  68. "real", Fword,
  69. "ref", Lword,
  70. "register", Cword,
  71. "self", Lword,
  72. "short", Cword,
  73. "static", Cword,
  74. "stdio", I2,
  75. "struct", Cword,
  76. "subroutine", Fword,
  77. "u", I2,
  78. "void", Cword,
  79. };
  80. /* codes for 'mode' field in language structure */
  81. enum {
  82. Normal = 0,
  83. First, /* first entry for language spanning several ranges */
  84. Multi, /* later entries " " " ... */
  85. Shared, /* codes used in several languages */
  86. };
  87. struct
  88. {
  89. int mode; /* see enum above */
  90. int count;
  91. int low;
  92. int high;
  93. char *name;
  94. } language[] =
  95. {
  96. Normal, 0, 0x0100, 0x01FF, "Extended Latin",
  97. Normal, 0, 0x0370, 0x03FF, "Greek",
  98. Normal, 0, 0x0400, 0x04FF, "Cyrillic",
  99. Normal, 0, 0x0530, 0x058F, "Armenian",
  100. Normal, 0, 0x0590, 0x05FF, "Hebrew",
  101. Normal, 0, 0x0600, 0x06FF, "Arabic",
  102. Normal, 0, 0x0900, 0x097F, "Devanagari",
  103. Normal, 0, 0x0980, 0x09FF, "Bengali",
  104. Normal, 0, 0x0A00, 0x0A7F, "Gurmukhi",
  105. Normal, 0, 0x0A80, 0x0AFF, "Gujarati",
  106. Normal, 0, 0x0B00, 0x0B7F, "Oriya",
  107. Normal, 0, 0x0B80, 0x0BFF, "Tamil",
  108. Normal, 0, 0x0C00, 0x0C7F, "Telugu",
  109. Normal, 0, 0x0C80, 0x0CFF, "Kannada",
  110. Normal, 0, 0x0D00, 0x0D7F, "Malayalam",
  111. Normal, 0, 0x0E00, 0x0E7F, "Thai",
  112. Normal, 0, 0x0E80, 0x0EFF, "Lao",
  113. Normal, 0, 0x1000, 0x105F, "Tibetan",
  114. Normal, 0, 0x10A0, 0x10FF, "Georgian",
  115. Normal, 0, 0x3040, 0x30FF, "Japanese",
  116. Normal, 0, 0x3100, 0x312F, "Chinese",
  117. First, 0, 0x3130, 0x318F, "Korean",
  118. Multi, 0, 0x3400, 0x3D2F, "Korean",
  119. Shared, 0, 0x4e00, 0x9fff, "CJK",
  120. Normal, 0, 0, 0, 0, /* terminal entry */
  121. };
  122. enum
  123. {
  124. Fascii, /* printable ascii */
  125. Flatin, /* latin 1*/
  126. Futf, /* UTF character set */
  127. Fbinary, /* binary */
  128. Feascii, /* ASCII with control chars */
  129. Fnull, /* NULL in file */
  130. } guess;
  131. void bump_utf_count(Rune);
  132. int cistrncmp(char*, char*, int);
  133. void filetype(int);
  134. int getfontnum(uchar*, uchar**);
  135. int isas(void);
  136. int isc(void);
  137. int iscint(void);
  138. int isenglish(void);
  139. int ishp(void);
  140. int ishtml(void);
  141. int isrfc822(void);
  142. int ismbox(void);
  143. int islimbo(void);
  144. int ismung(void);
  145. int isp9bit(void);
  146. int isp9font(void);
  147. int isrtf(void);
  148. int ismsdos(void);
  149. int iself(void);
  150. int istring(void);
  151. int isoffstr(void);
  152. int iff(void);
  153. int long0(void);
  154. int longoff(void);
  155. int istar(void);
  156. int isface(void);
  157. int isexec(void);
  158. int p9bitnum(uchar*);
  159. int p9subfont(uchar*);
  160. void print_utf(void);
  161. void type(char*, int);
  162. int utf_count(void);
  163. void wordfreq(void);
  164. int (*call[])(void) =
  165. {
  166. long0, /* recognizable by first 4 bytes */
  167. istring, /* recognizable by first string */
  168. iself, /* ELF (foreign) executable */
  169. isexec, /* native executables */
  170. iff, /* interchange file format (strings) */
  171. longoff, /* recognizable by 4 bytes at some offset */
  172. isoffstr, /* recognizable by string at some offset */
  173. isrfc822, /* email file */
  174. ismbox, /* mail box */
  175. istar, /* recognizable by tar checksum */
  176. ishtml, /* html keywords */
  177. iscint, /* compiler/assembler intermediate */
  178. islimbo, /* limbo source */
  179. isc, /* c & alef compiler key words */
  180. isas, /* assembler key words */
  181. isp9font, /* plan 9 font */
  182. isp9bit, /* plan 9 image (as from /dev/window) */
  183. ismung, /* entropy compressed/encrypted */
  184. isenglish, /* char frequency English */
  185. isrtf, /* rich text format */
  186. ismsdos, /* msdos exe (virus file attachement) */
  187. isface, /* ascii face file */
  188. 0
  189. };
  190. int mime;
  191. #define OCTET "application/octet-stream\n"
  192. #define PLAIN "text/plain\n"
  193. void
  194. main(int argc, char *argv[])
  195. {
  196. int i, j, maxlen;
  197. char *cp;
  198. Rune r;
  199. ARGBEGIN{
  200. case 'm':
  201. mime = 1;
  202. break;
  203. default:
  204. fprint(2, "usage: file [-m] [file...]\n");
  205. exits("usage");
  206. }ARGEND;
  207. maxlen = 0;
  208. if(mime == 0 || argc > 1){
  209. for(i = 0; i < argc; i++) {
  210. for (j = 0, cp = argv[i]; *cp; j++, cp += chartorune(&r, cp))
  211. ;
  212. if(j > maxlen)
  213. maxlen = j;
  214. }
  215. }
  216. if (argc <= 0) {
  217. if(!mime)
  218. print ("stdin: ");
  219. filetype(0);
  220. }
  221. else {
  222. for(i = 0; i < argc; i++)
  223. type(argv[i], maxlen);
  224. }
  225. exits(0);
  226. }
  227. void
  228. type(char *file, int nlen)
  229. {
  230. Rune r;
  231. int i;
  232. char *p;
  233. if(nlen > 0){
  234. slash = 0;
  235. for (i = 0, p = file; *p; i++) {
  236. if (*p == '/') /* find rightmost slash */
  237. slash = p;
  238. p += chartorune(&r, p); /* count runes */
  239. }
  240. print("%s:%*s",file, nlen-i+1, "");
  241. }
  242. fname = file;
  243. if ((fd = open(file, OREAD)) < 0) {
  244. print("cannot open\n");
  245. return;
  246. }
  247. filetype(fd);
  248. close(fd);
  249. }
  250. /*
  251. * Unicode 4.0 4-byte runes.
  252. */
  253. typedef int Rune1;
  254. enum {
  255. UTFmax1 = 4,
  256. };
  257. int
  258. fullrune1(char *p, int n)
  259. {
  260. int c;
  261. if(n >= 1) {
  262. c = *(uchar*)p;
  263. if(c < 0x80)
  264. return 1;
  265. if(n >= 2 && c < 0xE0)
  266. return 1;
  267. if(n >= 3 && c < 0xF0)
  268. return 1;
  269. if(n >= 4)
  270. return 1;
  271. }
  272. return 0;
  273. }
  274. int
  275. chartorune1(Rune1 *rune, char *str)
  276. {
  277. int c, c1, c2, c3, n;
  278. Rune r;
  279. c = *(uchar*)str;
  280. if(c < 0xF0){
  281. r = 0;
  282. n = chartorune(&r, str);
  283. *rune = r;
  284. return n;
  285. }
  286. c &= ~0xF0;
  287. c1 = *(uchar*)(str+1) & ~0x80;
  288. c2 = *(uchar*)(str+2) & ~0x80;
  289. c3 = *(uchar*)(str+3) & ~0x80;
  290. n = (c<<18) | (c1<<12) | (c2<<6) | c3;
  291. if(n < 0x10000 || n > 0x10FFFF){
  292. *rune = Runeerror;
  293. return 1;
  294. }
  295. *rune = n;
  296. return 4;
  297. }
  298. void
  299. filetype(int fd)
  300. {
  301. Rune1 r;
  302. int i, f, n;
  303. char *p, *eob;
  304. free(mbuf);
  305. mbuf = dirfstat(fd);
  306. if(mbuf == nil){
  307. print("cannot stat: %r\n");
  308. return;
  309. }
  310. if(mbuf->mode & DMDIR) {
  311. print(mime ? "text/directory\n" : "directory\n");
  312. return;
  313. }
  314. if(mbuf->type != 'M' && mbuf->type != '|') {
  315. print(mime ? OCTET : "special file #%c/%s\n",
  316. mbuf->type, mbuf->name);
  317. return;
  318. }
  319. nbuf = read(fd, buf, sizeof(buf)-1);
  320. if(nbuf < 0) {
  321. print("cannot read\n");
  322. return;
  323. }
  324. if(nbuf == 0) {
  325. print(mime ? PLAIN : "empty file\n");
  326. return;
  327. }
  328. buf[nbuf] = 0;
  329. /*
  330. * build histogram table
  331. */
  332. memset(cfreq, 0, sizeof(cfreq));
  333. for (i = 0; language[i].name; i++)
  334. language[i].count = 0;
  335. eob = (char *)buf+nbuf;
  336. for(n = 0, p = (char *)buf; p < eob; n++) {
  337. if (!fullrune1(p, eob-p) && eob-p < UTFmax1)
  338. break;
  339. p += chartorune1(&r, p);
  340. if (r == 0)
  341. f = Cnull;
  342. else if (r <= 0x7f) {
  343. if (!isprint(r) && !isspace(r))
  344. f = Ceascii; /* ASCII control char */
  345. else f = r;
  346. } else if (r == 0x80) {
  347. bump_utf_count(r);
  348. f = Cutf;
  349. } else if (r < 0xA0)
  350. f = Cbinary; /* Invalid Runes */
  351. else if (r <= 0xff)
  352. f = Clatin; /* Latin 1 */
  353. else {
  354. bump_utf_count(r);
  355. f = Cutf; /* UTF extension */
  356. }
  357. cfreq[f]++; /* ASCII chars peg directly */
  358. }
  359. /*
  360. * gross classify
  361. */
  362. if (cfreq[Cbinary])
  363. guess = Fbinary;
  364. else if (cfreq[Cutf])
  365. guess = Futf;
  366. else if (cfreq[Clatin])
  367. guess = Flatin;
  368. else if (cfreq[Ceascii])
  369. guess = Feascii;
  370. else if (cfreq[Cnull])
  371. guess = Fbinary;
  372. else
  373. guess = Fascii;
  374. /*
  375. * lookup dictionary words
  376. */
  377. memset(wfreq, 0, sizeof(wfreq));
  378. if(guess == Fascii || guess == Flatin || guess == Futf)
  379. wordfreq();
  380. /*
  381. * call individual classify routines
  382. */
  383. for(i=0; call[i]; i++)
  384. if((*call[i])())
  385. return;
  386. /*
  387. * if all else fails,
  388. * print out gross classification
  389. */
  390. if (nbuf < 100 && !mime)
  391. print(mime ? PLAIN : "short ");
  392. if (guess == Fascii)
  393. print(mime ? PLAIN : "Ascii\n");
  394. else if (guess == Feascii)
  395. print(mime ? PLAIN : "extended ascii\n");
  396. else if (guess == Flatin)
  397. print(mime ? PLAIN : "latin ascii\n");
  398. else if (guess == Futf && utf_count() < 4)
  399. print_utf();
  400. else print(mime ? OCTET : "binary\n");
  401. }
  402. void
  403. bump_utf_count(Rune r)
  404. {
  405. int low, high, mid;
  406. high = sizeof(language)/sizeof(language[0])-1;
  407. for (low = 0; low < high;) {
  408. mid = (low+high)/2;
  409. if (r >= language[mid].low) {
  410. if (r <= language[mid].high) {
  411. language[mid].count++;
  412. break;
  413. } else low = mid+1;
  414. } else high = mid;
  415. }
  416. }
  417. int
  418. utf_count(void)
  419. {
  420. int i, count;
  421. count = 0;
  422. for (i = 0; language[i].name; i++)
  423. if (language[i].count > 0)
  424. switch (language[i].mode) {
  425. case Normal:
  426. case First:
  427. count++;
  428. break;
  429. default:
  430. break;
  431. }
  432. return count;
  433. }
  434. int
  435. chkascii(void)
  436. {
  437. int i;
  438. for (i = 'a'; i < 'z'; i++)
  439. if (cfreq[i])
  440. return 1;
  441. for (i = 'A'; i < 'Z'; i++)
  442. if (cfreq[i])
  443. return 1;
  444. return 0;
  445. }
  446. int
  447. find_first(char *name)
  448. {
  449. int i;
  450. for (i = 0; language[i].name != 0; i++)
  451. if (language[i].mode == First
  452. && strcmp(language[i].name, name) == 0)
  453. return i;
  454. return -1;
  455. }
  456. void
  457. print_utf(void)
  458. {
  459. int i, printed, j;
  460. if(mime){
  461. print(PLAIN);
  462. return;
  463. }
  464. if (chkascii()) {
  465. printed = 1;
  466. print("Ascii");
  467. } else
  468. printed = 0;
  469. for (i = 0; language[i].name; i++)
  470. if (language[i].count) {
  471. switch(language[i].mode) {
  472. case Multi:
  473. j = find_first(language[i].name);
  474. if (j < 0)
  475. break;
  476. if (language[j].count > 0)
  477. break;
  478. /* Fall through */
  479. case Normal:
  480. case First:
  481. if (printed)
  482. print(" & ");
  483. else printed = 1;
  484. print("%s", language[i].name);
  485. break;
  486. case Shared:
  487. default:
  488. break;
  489. }
  490. }
  491. if(!printed)
  492. print("UTF");
  493. print(" text\n");
  494. }
  495. void
  496. wordfreq(void)
  497. {
  498. int low, high, mid, r;
  499. uchar *p, *p2, c;
  500. p = buf;
  501. for(;;) {
  502. while (p < buf+nbuf && !isalpha(*p))
  503. p++;
  504. if (p >= buf+nbuf)
  505. return;
  506. p2 = p;
  507. while(p < buf+nbuf && isalpha(*p))
  508. p++;
  509. c = *p;
  510. *p = 0;
  511. high = sizeof(dict)/sizeof(dict[0]);
  512. for(low = 0;low < high;) {
  513. mid = (low+high)/2;
  514. r = strcmp(dict[mid].word, (char*)p2);
  515. if(r == 0) {
  516. wfreq[dict[mid].class]++;
  517. break;
  518. }
  519. if(r < 0)
  520. low = mid+1;
  521. else
  522. high = mid;
  523. }
  524. *p++ = c;
  525. }
  526. }
  527. typedef struct Filemagic Filemagic;
  528. struct Filemagic {
  529. ulong x;
  530. ulong mask;
  531. char *desc;
  532. char *mime;
  533. };
  534. /*
  535. * integers in this table must be as seen on a little-endian machine
  536. * when read from a file.
  537. */
  538. Filemagic long0tab[] = {
  539. 0xF16DF16D, 0xFFFFFFFF, "pac1 audio file\n", OCTET,
  540. /* "pac1" */
  541. 0x31636170, 0xFFFFFFFF, "pac3 audio file\n", OCTET,
  542. /* "pXc2 */
  543. 0x32630070, 0xFFFF00FF, "pac4 audio file\n", OCTET,
  544. 0xBA010000, 0xFFFFFFFF, "mpeg system stream\n", OCTET,
  545. 0x30800CC0, 0xFFFFFFFF, "inferno .dis executable\n", OCTET,
  546. 0x04034B50, 0xFFFFFFFF, "zip archive\n", "application/zip",
  547. 070707, 0xFFFF, "cpio archive\n", OCTET,
  548. 0x2F7, 0xFFFF, "tex dvi\n", "application/dvi",
  549. 0xfaff, 0xfeff, "mp3 audio\n", "audio/mpeg",
  550. 0xfeff0000, 0xffffffff, "utf-32be\n", "text/plain charset=utf-32be",
  551. 0xfffe, 0xffffffff, "utf-32le\n", "text/plain charset=utf-32le",
  552. 0xfeff, 0xffff, "utf-16be\n", "text/plain charset=utf-16be",
  553. 0xfffe, 0xffff, "utf-16le\n", "text/plain charset=utf-16le",
  554. /*
  555. * venti & fossil magic numbers are stored big-endian on disk,
  556. * thus the numbers appear reversed in this table.
  557. */
  558. 0xad4e5cd1, 0xFFFFFFFF, "venti arena\n", OCTET,
  559. };
  560. int
  561. filemagic(Filemagic *tab, int ntab, ulong x)
  562. {
  563. int i;
  564. for(i=0; i<ntab; i++)
  565. if((x&tab[i].mask) == tab[i].x){
  566. print(mime ? tab[i].mime : tab[i].desc);
  567. return 1;
  568. }
  569. return 0;
  570. }
  571. int
  572. long0(void)
  573. {
  574. return filemagic(long0tab, nelem(long0tab), LENDIAN(buf));
  575. }
  576. typedef struct Fileoffmag Fileoffmag;
  577. struct Fileoffmag {
  578. ulong off;
  579. Filemagic;
  580. };
  581. /*
  582. * integers in this table must be as seen on a little-endian machine
  583. * when read from a file.
  584. */
  585. Fileoffmag longofftab[] = {
  586. /*
  587. * venti & fossil magic numbers are stored big-endian on disk,
  588. * thus the numbers appear reversed in this table.
  589. */
  590. 256*1024, 0xe7a5e4a9, 0xFFFFFFFF, "venti arenas partition\n", OCTET,
  591. 256*1024, 0xc75e5cd1, 0xFFFFFFFF, "venti index section\n", OCTET,
  592. 128*1024, 0x89ae7637, 0xFFFFFFFF, "fossil write buffer\n", OCTET,
  593. };
  594. int
  595. fileoffmagic(Fileoffmag *tab, int ntab)
  596. {
  597. int i;
  598. ulong x;
  599. Fileoffmag *tp;
  600. uchar buf[sizeof(long)];
  601. for(i=0; i<ntab; i++) {
  602. tp = tab + i;
  603. seek(fd, tp->off, 0);
  604. if (read(fd, buf, sizeof buf) != sizeof buf)
  605. continue;
  606. x = LENDIAN(buf);
  607. if((x&tp->mask) == tp->x){
  608. print(mime? tp->mime: tp->desc);
  609. return 1;
  610. }
  611. }
  612. return 0;
  613. }
  614. int
  615. longoff(void)
  616. {
  617. return fileoffmagic(longofftab, nelem(longofftab));
  618. }
  619. int
  620. isexec(void)
  621. {
  622. Fhdr f;
  623. seek(fd, 0, 0); /* reposition to start of file */
  624. if(crackhdr(fd, &f)) {
  625. print(mime ? OCTET : "%s\n", f.name);
  626. return 1;
  627. }
  628. return 0;
  629. }
  630. /* from tar.c */
  631. enum { NAMSIZ = 100, TBLOCK = 512 };
  632. union hblock
  633. {
  634. char dummy[TBLOCK];
  635. struct header
  636. {
  637. char name[NAMSIZ];
  638. char mode[8];
  639. char uid[8];
  640. char gid[8];
  641. char size[12];
  642. char mtime[12];
  643. char chksum[8];
  644. char linkflag;
  645. char linkname[NAMSIZ];
  646. /* rest are defined by POSIX's ustar format; see p1003.2b */
  647. char magic[6]; /* "ustar" */
  648. char version[2];
  649. char uname[32];
  650. char gname[32];
  651. char devmajor[8];
  652. char devminor[8];
  653. char prefix[155]; /* if non-null, path = prefix "/" name */
  654. } dbuf;
  655. };
  656. int
  657. checksum(union hblock *hp)
  658. {
  659. int i;
  660. char *cp;
  661. struct header *hdr = &hp->dbuf;
  662. for (cp = hdr->chksum; cp < &hdr->chksum[sizeof hdr->chksum]; cp++)
  663. *cp = ' ';
  664. i = 0;
  665. for (cp = hp->dummy; cp < &hp->dummy[TBLOCK]; cp++)
  666. i += *cp & 0xff;
  667. return i;
  668. }
  669. int
  670. istar(void)
  671. {
  672. int chksum;
  673. char tblock[TBLOCK];
  674. union hblock *hp = (union hblock *)tblock;
  675. struct header *hdr = &hp->dbuf;
  676. seek(fd, 0, 0); /* reposition to start of file */
  677. if (readn(fd, tblock, sizeof tblock) != sizeof tblock)
  678. return 0;
  679. chksum = strtol(hdr->chksum, 0, 8);
  680. if (hdr->name[0] != '\0' && checksum(hp) == chksum) {
  681. if (strcmp(hdr->magic, "ustar") == 0)
  682. print(mime? "application/x-ustar\n":
  683. "posix tar archive\n");
  684. else
  685. print(mime? "application/x-tar\n": "tar archive\n");
  686. return 1;
  687. }
  688. return 0;
  689. }
  690. /*
  691. * initial words to classify file
  692. */
  693. struct FILE_STRING
  694. {
  695. char *key;
  696. char *filetype;
  697. int length;
  698. char *mime;
  699. } file_string[] =
  700. {
  701. "!<arch>\n__.SYMDEF", "archive random library", 16, "application/octet-stream",
  702. "!<arch>\n", "archive", 8, "application/octet-stream",
  703. "070707", "cpio archive - ascii header", 6, "application/octet-stream",
  704. "#!/bin/rc", "rc executable file", 9, "text/plain",
  705. "#!/bin/sh", "sh executable file", 9, "text/plain",
  706. "%!", "postscript", 2, "application/postscript",
  707. "\004%!", "postscript", 3, "application/postscript",
  708. "x T post", "troff output for post", 8, "application/troff",
  709. "x T Latin1", "troff output for Latin1", 10, "application/troff",
  710. "x T utf", "troff output for UTF", 7, "application/troff",
  711. "x T 202", "troff output for 202", 7, "application/troff",
  712. "x T aps", "troff output for aps", 7, "application/troff",
  713. "GIF", "GIF image", 3, "image/gif",
  714. "\0PC Research, Inc\0", "ghostscript fax file", 18, "application/ghostscript",
  715. "%PDF", "PDF", 4, "application/pdf",
  716. "<html>\n", "HTML file", 7, "text/html",
  717. "<HTML>\n", "HTML file", 7, "text/html",
  718. "\111\111\052\000", "tiff", 4, "image/tiff",
  719. "\115\115\000\052", "tiff", 4, "image/tiff",
  720. "\377\330\377\340", "jpeg", 4, "image/jpeg",
  721. "\377\330\377\341", "jpeg", 4, "image/jpeg",
  722. "\377\330\377\333", "jpeg", 4, "image/jpeg",
  723. "BM", "bmp", 2, "image/bmp",
  724. "\xD0\xCF\x11\xE0\xA1\xB1\x1A\xE1", "microsoft office document", 8, "application/octet-stream",
  725. "<MakerFile ", "FrameMaker file", 11, "application/framemaker",
  726. "\033%-12345X", "HPJCL file", 9, "application/hpjcl",
  727. "ID3", "mp3 audio with id3", 3, "audio/mpeg",
  728. "\211PNG", "PNG image", 4, "image/png",
  729. "P3\n", "ppm", 3, "image/ppm",
  730. "P6\n", "ppm", 3, "image/ppm",
  731. "/* XPM */\n", "xbm", 10, "image/xbm",
  732. ".HTML ", "troff -ms input", 6, "text/troff",
  733. ".LP", "troff -ms input", 3, "text/troff",
  734. ".ND", "troff -ms input", 3, "text/troff",
  735. ".PP", "troff -ms input", 3, "text/troff",
  736. ".TL", "troff -ms input", 3, "text/troff",
  737. ".TR", "troff -ms input", 3, "text/troff",
  738. ".TH", "manual page", 3, "text/troff",
  739. ".\\\"", "troff input", 3, "text/troff",
  740. ".de", "troff input", 3, "text/troff",
  741. ".if", "troff input", 3, "text/troff",
  742. ".nr", "troff input", 3, "text/troff",
  743. ".tr", "troff input", 3, "text/troff",
  744. "vac:", "venti score", 4, "text/plain",
  745. "-----BEGIN CERTIFICATE-----\n",
  746. "pem certificate", -1, "text/plain",
  747. "-----BEGIN TRUSTED CERTIFICATE-----\n",
  748. "pem trusted certificate", -1, "text/plain",
  749. "-----BEGIN X509 CERTIFICATE-----\n",
  750. "pem x.509 certificate", -1, "text/plain",
  751. "subject=/C=", "pem certificate with header", -1, "text/plain",
  752. "process snapshot ", "process snapshot", -1, "application/snapfs",
  753. 0,0,0,0
  754. };
  755. int
  756. istring(void)
  757. {
  758. int i, l;
  759. struct FILE_STRING *p;
  760. for(p = file_string; p->key; p++) {
  761. l = p->length;
  762. if(l == -1)
  763. l = strlen(p->key);
  764. if(nbuf >= l && memcmp(buf, p->key, l) == 0) {
  765. if(mime)
  766. print("%s\n", p->mime);
  767. else
  768. print("%s\n", p->filetype);
  769. return 1;
  770. }
  771. }
  772. if(strncmp((char*)buf, "TYPE=", 5) == 0) { /* td */
  773. for(i = 5; i < nbuf; i++)
  774. if(buf[i] == '\n')
  775. break;
  776. if(mime)
  777. print(OCTET);
  778. else
  779. print("%.*s picture\n", utfnlen((char*)buf+5, i-5), (char*)buf+5);
  780. return 1;
  781. }
  782. return 0;
  783. }
  784. struct offstr
  785. {
  786. ulong off;
  787. struct FILE_STRING;
  788. } offstrs[] = {
  789. 32*1024, "\001CD001\001", "ISO9660 CD image", 7, OCTET,
  790. 0, 0, 0, 0, 0
  791. };
  792. int
  793. isoffstr(void)
  794. {
  795. int n;
  796. char buf[256];
  797. struct offstr *p;
  798. for(p = offstrs; p->key; p++) {
  799. seek(fd, p->off, 0);
  800. n = p->length;
  801. if (n > sizeof buf)
  802. n = sizeof buf;
  803. if (read(fd, buf, n) != n)
  804. continue;
  805. if(memcmp(buf, p->key, n) == 0) {
  806. if(mime)
  807. print("%s\n", p->mime);
  808. else
  809. print("%s\n", p->filetype);
  810. return 1;
  811. }
  812. }
  813. return 0;
  814. }
  815. int
  816. iff(void)
  817. {
  818. if (strncmp((char*)buf, "FORM", 4) == 0 &&
  819. strncmp((char*)buf+8, "AIFF", 4) == 0) {
  820. print("%s\n", mime? "audio/x-aiff": "aiff audio");
  821. return 1;
  822. }
  823. return 0;
  824. }
  825. char* html_string[] =
  826. {
  827. "title",
  828. "body",
  829. "head",
  830. "strong",
  831. "h1",
  832. "h2",
  833. "h3",
  834. "h4",
  835. "h5",
  836. "h6",
  837. "ul",
  838. "li",
  839. "dl",
  840. "br",
  841. "em",
  842. 0,
  843. };
  844. int
  845. ishtml(void)
  846. {
  847. uchar *p, *q;
  848. int i, count;
  849. /* compare strings between '<' and '>' to html table */
  850. count = 0;
  851. p = buf;
  852. for(;;) {
  853. while (p < buf+nbuf && *p != '<')
  854. p++;
  855. p++;
  856. if (p >= buf+nbuf)
  857. break;
  858. if(*p == '/')
  859. p++;
  860. q = p;
  861. while(p < buf+nbuf && *p != '>')
  862. p++;
  863. if (p >= buf+nbuf)
  864. break;
  865. for(i = 0; html_string[i]; i++) {
  866. if(cistrncmp(html_string[i], (char*)q, p-q) == 0) {
  867. if(count++ > 4) {
  868. print(mime ? "text/html\n" : "HTML file\n");
  869. return 1;
  870. }
  871. break;
  872. }
  873. }
  874. p++;
  875. }
  876. return 0;
  877. }
  878. char* rfc822_string[] =
  879. {
  880. "from:",
  881. "date:",
  882. "to:",
  883. "subject:",
  884. "received:",
  885. "reply to:",
  886. "sender:",
  887. 0,
  888. };
  889. int
  890. isrfc822(void)
  891. {
  892. char *p, *q, *r;
  893. int i, count;
  894. count = 0;
  895. p = (char*)buf;
  896. for(;;) {
  897. q = strchr(p, '\n');
  898. if(q == nil)
  899. break;
  900. *q = 0;
  901. if(p == (char*)buf && strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ")){
  902. count++;
  903. *q = '\n';
  904. p = q+1;
  905. continue;
  906. }
  907. *q = '\n';
  908. if(*p != '\t' && *p != ' '){
  909. r = strchr(p, ':');
  910. if(r == 0 || r > q)
  911. break;
  912. for(i = 0; rfc822_string[i]; i++) {
  913. if(cistrncmp(p, rfc822_string[i], strlen(rfc822_string[i])) == 0){
  914. count++;
  915. break;
  916. }
  917. }
  918. }
  919. p = q+1;
  920. }
  921. if(count >= 3){
  922. print(mime ? "message/rfc822\n" : "email file\n");
  923. return 1;
  924. }
  925. return 0;
  926. }
  927. int
  928. ismbox(void)
  929. {
  930. char *p, *q;
  931. p = (char*)buf;
  932. q = strchr(p, '\n');
  933. if(q == nil)
  934. return 0;
  935. *q = 0;
  936. if(strncmp(p, "From ", 5) == 0 && strstr(p, " remote from ") == nil){
  937. print(mime ? "text/plain\n" : "mail box\n");
  938. return 1;
  939. }
  940. *q = '\n';
  941. return 0;
  942. }
  943. int
  944. iscint(void)
  945. {
  946. int type;
  947. char *name;
  948. Biobuf b;
  949. if(Binit(&b, fd, OREAD) == Beof)
  950. return 0;
  951. seek(fd, 0, 0);
  952. type = objtype(&b, &name);
  953. if(type < 0)
  954. return 0;
  955. if(mime)
  956. print(OCTET);
  957. else
  958. print("%s intermediate\n", name);
  959. return 1;
  960. }
  961. int
  962. isc(void)
  963. {
  964. int n;
  965. n = wfreq[I1];
  966. /*
  967. * includes
  968. */
  969. if(n >= 2 && wfreq[I2] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
  970. goto yes;
  971. if(n >= 1 && wfreq[Alword] >= n && wfreq[I3] >= n && cfreq['.'] >= n)
  972. goto yes;
  973. /*
  974. * declarations
  975. */
  976. if(wfreq[Cword] >= 5 && cfreq[';'] >= 5)
  977. goto yes;
  978. /*
  979. * assignments
  980. */
  981. if(cfreq[';'] >= 10 && cfreq['='] >= 10 && wfreq[Cword] >= 1)
  982. goto yes;
  983. return 0;
  984. yes:
  985. if(mime){
  986. print(PLAIN);
  987. return 1;
  988. }
  989. if(wfreq[Alword] > 0)
  990. print("alef program\n");
  991. else
  992. print("c program\n");
  993. return 1;
  994. }
  995. int
  996. islimbo(void)
  997. {
  998. /*
  999. * includes
  1000. */
  1001. if(wfreq[Lword] < 4)
  1002. return 0;
  1003. print(mime ? PLAIN : "limbo program\n");
  1004. return 1;
  1005. }
  1006. int
  1007. isas(void)
  1008. {
  1009. /*
  1010. * includes
  1011. */
  1012. if(wfreq[Aword] < 2)
  1013. return 0;
  1014. print(mime ? PLAIN : "as program\n");
  1015. return 1;
  1016. }
  1017. /*
  1018. * low entropy means encrypted
  1019. */
  1020. int
  1021. ismung(void)
  1022. {
  1023. int i, bucket[8];
  1024. float cs;
  1025. if(nbuf < 64)
  1026. return 0;
  1027. memset(bucket, 0, sizeof(bucket));
  1028. for(i=nbuf-64; i<nbuf; i++)
  1029. bucket[(buf[i]>>5)&07] += 1;
  1030. cs = 0.;
  1031. for(i=0; i<8; i++)
  1032. cs += (bucket[i]-8)*(bucket[i]-8);
  1033. cs /= 8.;
  1034. if(cs <= 24.322) {
  1035. if(buf[0]==0x1f && buf[1]==0x9d)
  1036. print(mime ? OCTET : "compressed\n");
  1037. else
  1038. if(buf[0]==0x1f && buf[1]==0x8b)
  1039. print(mime ? OCTET : "gzip compressed\n");
  1040. else
  1041. if(buf[0]=='B' && buf[1]=='Z' && buf[2]=='h')
  1042. print(mime ? OCTET : "bzip2 compressed\n");
  1043. else
  1044. print(mime ? OCTET : "encrypted\n");
  1045. return 1;
  1046. }
  1047. return 0;
  1048. }
  1049. /*
  1050. * english by punctuation and frequencies
  1051. */
  1052. int
  1053. isenglish(void)
  1054. {
  1055. int vow, comm, rare, badpun, punct;
  1056. char *p;
  1057. if(guess != Fascii && guess != Feascii)
  1058. return 0;
  1059. badpun = 0;
  1060. punct = 0;
  1061. for(p = (char *)buf; p < (char *)buf+nbuf-1; p++)
  1062. switch(*p) {
  1063. case '.':
  1064. case ',':
  1065. case ')':
  1066. case '%':
  1067. case ';':
  1068. case ':':
  1069. case '?':
  1070. punct++;
  1071. if(p[1] != ' ' && p[1] != '\n')
  1072. badpun++;
  1073. }
  1074. if(badpun*5 > punct)
  1075. return 0;
  1076. if(cfreq['>']+cfreq['<']+cfreq['/'] > cfreq['e']) /* shell file test */
  1077. return 0;
  1078. if(2*cfreq[';'] > cfreq['e'])
  1079. return 0;
  1080. vow = 0;
  1081. for(p="AEIOU"; *p; p++) {
  1082. vow += cfreq[*p];
  1083. vow += cfreq[tolower(*p)];
  1084. }
  1085. comm = 0;
  1086. for(p="ETAION"; *p; p++) {
  1087. comm += cfreq[*p];
  1088. comm += cfreq[tolower(*p)];
  1089. }
  1090. rare = 0;
  1091. for(p="VJKQXZ"; *p; p++) {
  1092. rare += cfreq[*p];
  1093. rare += cfreq[tolower(*p)];
  1094. }
  1095. if(vow*5 >= nbuf-cfreq[' '] && comm >= 10*rare) {
  1096. print(mime ? PLAIN : "English text\n");
  1097. return 1;
  1098. }
  1099. return 0;
  1100. }
  1101. /*
  1102. * pick up a number with
  1103. * syntax _*[0-9]+_
  1104. */
  1105. #define P9BITLEN 12
  1106. int
  1107. p9bitnum(uchar *bp)
  1108. {
  1109. int n, c, len;
  1110. len = P9BITLEN;
  1111. while(*bp == ' ') {
  1112. bp++;
  1113. len--;
  1114. if(len <= 0)
  1115. return -1;
  1116. }
  1117. n = 0;
  1118. while(len > 1) {
  1119. c = *bp++;
  1120. if(!isdigit(c))
  1121. return -1;
  1122. n = n*10 + c-'0';
  1123. len--;
  1124. }
  1125. if(*bp != ' ')
  1126. return -1;
  1127. return n;
  1128. }
  1129. int
  1130. depthof(char *s, int *newp)
  1131. {
  1132. char *es;
  1133. int d;
  1134. *newp = 0;
  1135. es = s+12;
  1136. while(s<es && *s==' ')
  1137. s++;
  1138. if(s == es)
  1139. return -1;
  1140. if('0'<=*s && *s<='9')
  1141. return 1<<strtol(s, 0, 0);
  1142. *newp = 1;
  1143. d = 0;
  1144. while(s<es && *s!=' '){
  1145. s++; /* skip letter */
  1146. d += strtoul(s, &s, 10);
  1147. }
  1148. if(d % 8 == 0 || 8 % d == 0)
  1149. return d;
  1150. else
  1151. return -1;
  1152. }
  1153. int
  1154. isp9bit(void)
  1155. {
  1156. int dep, lox, loy, hix, hiy, px, new, cmpr;
  1157. ulong t;
  1158. long len;
  1159. char *newlabel;
  1160. uchar *cp;
  1161. cp = buf;
  1162. cmpr = 0;
  1163. newlabel = "old ";
  1164. if(memcmp(cp, "compressed\n", 11) == 0) {
  1165. cmpr = 1;
  1166. cp = buf + 11;
  1167. }
  1168. dep = depthof((char*)cp + 0*P9BITLEN, &new);
  1169. if(new)
  1170. newlabel = "";
  1171. lox = p9bitnum(cp + 1*P9BITLEN);
  1172. loy = p9bitnum(cp + 2*P9BITLEN);
  1173. hix = p9bitnum(cp + 3*P9BITLEN);
  1174. hiy = p9bitnum(cp + 4*P9BITLEN);
  1175. if(dep < 0 || lox < 0 || loy < 0 || hix < 0 || hiy < 0)
  1176. return 0;
  1177. if(dep < 8){
  1178. px = 8/dep; /* pixels per byte */
  1179. /* set l to number of bytes of data per scan line */
  1180. if(lox >= 0)
  1181. len = (hix+px-1)/px - lox/px;
  1182. else{ /* make positive before divide */
  1183. t = (-lox)+px-1;
  1184. t = (t/px)*px;
  1185. len = (t+hix+px-1)/px;
  1186. }
  1187. }else
  1188. len = (hix-lox)*dep/8;
  1189. len *= hiy - loy; /* col length */
  1190. len += 5 * P9BITLEN; /* size of initial ascii */
  1191. /*
  1192. * for compressed images, don't look any further. otherwise:
  1193. * for image file, length is non-zero and must match calculation above
  1194. * for /dev/window and /dev/screen the length is always zero
  1195. * for subfont, the subfont header should follow immediately.
  1196. */
  1197. if (cmpr) {
  1198. print(mime ? OCTET : "Compressed %splan 9 image or subfont, depth %d\n",
  1199. newlabel, dep);
  1200. return 1;
  1201. }
  1202. if (len != 0 && mbuf->length == 0) {
  1203. print(mime ? OCTET : "%splan 9 image, depth %d\n", newlabel, dep);
  1204. return 1;
  1205. }
  1206. if (mbuf->length == len) {
  1207. print(mime ? OCTET : "%splan 9 image, depth %d\n", newlabel, dep);
  1208. return 1;
  1209. }
  1210. /* Ghostscript sometimes produces a little extra on the end */
  1211. if (mbuf->length < len+P9BITLEN) {
  1212. print(mime ? OCTET : "%splan 9 image, depth %d\n", newlabel, dep);
  1213. return 1;
  1214. }
  1215. if (p9subfont(buf+len)) {
  1216. print(mime ? OCTET : "%ssubfont file, depth %d\n", newlabel, dep);
  1217. return 1;
  1218. }
  1219. return 0;
  1220. }
  1221. int
  1222. p9subfont(uchar *p)
  1223. {
  1224. int n, h, a;
  1225. /* if image too big, assume it's a subfont */
  1226. if (p+3*P9BITLEN > buf+sizeof(buf))
  1227. return 1;
  1228. n = p9bitnum(p + 0*P9BITLEN); /* char count */
  1229. if (n < 0)
  1230. return 0;
  1231. h = p9bitnum(p + 1*P9BITLEN); /* height */
  1232. if (h < 0)
  1233. return 0;
  1234. a = p9bitnum(p + 2*P9BITLEN); /* ascent */
  1235. if (a < 0)
  1236. return 0;
  1237. return 1;
  1238. }
  1239. #define WHITESPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n')
  1240. int
  1241. isp9font(void)
  1242. {
  1243. uchar *cp, *p;
  1244. int i, n;
  1245. char pathname[1024];
  1246. cp = buf;
  1247. if (!getfontnum(cp, &cp)) /* height */
  1248. return 0;
  1249. if (!getfontnum(cp, &cp)) /* ascent */
  1250. return 0;
  1251. for (i = 0; cp=(uchar*)strchr((char*)cp, '\n'); i++) {
  1252. if (!getfontnum(cp, &cp)) /* min */
  1253. break;
  1254. if (!getfontnum(cp, &cp)) /* max */
  1255. return 0;
  1256. getfontnum(cp, &cp); /* optional offset */
  1257. while (WHITESPACE(*cp))
  1258. cp++;
  1259. for (p = cp; *cp && !WHITESPACE(*cp); cp++)
  1260. ;
  1261. /* construct a path name, if needed */
  1262. n = 0;
  1263. if (*p != '/' && slash) {
  1264. n = slash-fname+1;
  1265. if (n < sizeof(pathname))
  1266. memcpy(pathname, fname, n);
  1267. else n = 0;
  1268. }
  1269. if (n+cp-p+4 < sizeof(pathname)) {
  1270. memcpy(pathname+n, p, cp-p);
  1271. n += cp-p;
  1272. pathname[n] = 0;
  1273. if (access(pathname, AEXIST) < 0) {
  1274. strcpy(pathname+n, ".0");
  1275. if (access(pathname, AEXIST) < 0)
  1276. return 0;
  1277. }
  1278. }
  1279. }
  1280. if (i) {
  1281. print(mime ? "text/plain\n" : "font file\n");
  1282. return 1;
  1283. }
  1284. return 0;
  1285. }
  1286. int
  1287. getfontnum(uchar *cp, uchar **rp)
  1288. {
  1289. while (WHITESPACE(*cp)) /* extract ulong delimited by whitespace */
  1290. cp++;
  1291. if (*cp < '0' || *cp > '9')
  1292. return 0;
  1293. strtoul((char *)cp, (char **)rp, 0);
  1294. if (!WHITESPACE(**rp)) {
  1295. *rp = cp;
  1296. return 0;
  1297. }
  1298. return 1;
  1299. }
  1300. int
  1301. isrtf(void)
  1302. {
  1303. if(strstr((char *)buf, "\\rtf1")){
  1304. print(mime ? "application/rtf\n" : "rich text format\n");
  1305. return 1;
  1306. }
  1307. return 0;
  1308. }
  1309. int
  1310. ismsdos(void)
  1311. {
  1312. if (buf[0] == 0x4d && buf[1] == 0x5a){
  1313. print(mime ? "application/x-msdownload\n" : "MSDOS executable\n");
  1314. return 1;
  1315. }
  1316. return 0;
  1317. }
  1318. int
  1319. iself(void)
  1320. {
  1321. static char *cpu[] = { /* NB: incomplete and arbitary list */
  1322. [1] "WE32100",
  1323. [2] "SPARC",
  1324. [3] "i386",
  1325. [4] "M68000",
  1326. [5] "M88000",
  1327. [6] "i486",
  1328. [7] "i860",
  1329. [8] "R3000",
  1330. [9] "S370",
  1331. [10] "R4000",
  1332. [15] "HP-PA",
  1333. [18] "sparc v8+",
  1334. [19] "i960",
  1335. [20] "PPC-32",
  1336. [21] "PPC-64",
  1337. [40] "ARM",
  1338. [41] "Alpha",
  1339. [43] "sparc v9",
  1340. [50] "IA-64",
  1341. [62] "AMD64",
  1342. [75] "VAX",
  1343. };
  1344. static char *type[] = {
  1345. [1] "relocatable object",
  1346. [2] "executable",
  1347. [3] "shared library",
  1348. [4] "core dump",
  1349. };
  1350. if (memcmp(buf, "\x7fELF", 4) == 0){
  1351. if (!mime){
  1352. int isdifend = 0;
  1353. int n = (buf[19] << 8) | buf[18];
  1354. char *p = "unknown";
  1355. char *t = "unknown";
  1356. if (n > 0 && n < nelem(cpu) && cpu[n])
  1357. p = cpu[n];
  1358. else {
  1359. /* try the other byte order */
  1360. isdifend = 1;
  1361. n = (buf[18] << 8) | buf[19];
  1362. if (n > 0 && n < nelem(cpu) && cpu[n])
  1363. p = cpu[n];
  1364. }
  1365. if(isdifend)
  1366. n = (buf[16]<< 8) | buf[17];
  1367. else
  1368. n = (buf[17]<< 8) | buf[16];
  1369. if(n>0 && n < nelem(type) && type[n])
  1370. t = type[n];
  1371. print("%s ELF %s\n", p, t);
  1372. }
  1373. else
  1374. print("application/x-elf-executable");
  1375. return 1;
  1376. }
  1377. return 0;
  1378. }
  1379. int
  1380. isface(void)
  1381. {
  1382. int i, j, ldepth, l;
  1383. char *p;
  1384. ldepth = -1;
  1385. for(j = 0; j < 3; j++){
  1386. for(p = (char*)buf, i=0; i<3; i++){
  1387. if(p[0] != '0' || p[1] != 'x')
  1388. return 0;
  1389. if(buf[2+8] == ',')
  1390. l = 2;
  1391. else if(buf[2+4] == ',')
  1392. l = 1;
  1393. else
  1394. return 0;
  1395. if(ldepth == -1)
  1396. ldepth = l;
  1397. if(l != ldepth)
  1398. return 0;
  1399. strtoul(p, &p, 16);
  1400. if(*p++ != ',')
  1401. return 0;
  1402. while(*p == ' ' || *p == '\t')
  1403. p++;
  1404. }
  1405. if (*p++ != '\n')
  1406. return 0;
  1407. }
  1408. if(mime)
  1409. print("application/x-face\n");
  1410. else
  1411. print("face image depth %d\n", ldepth);
  1412. return 1;
  1413. }