1/*
2**	find file types by using a modified "magic" file
3**
4**	based on file v3.22 by Ian F. Darwin (see below)
5**
6**	For each entry in the magic file, the message MUST start with
7**	two 4 character strings which are the CREATOR and TYPE for the
8**	Mac file. Any continuation lines are ignored. e.g magic entry
9**	for a GIF file:
10**
11**	0       string          GIF8            8BIM GIFf
12**	>4      string          7a              \b, version 8%s,
13**	>4      string          9a              \b, version 8%s,
14**	>6      leshort         >0              %hd x
15**	>8      leshort         >0              %hd,
16**	#>10    byte            &0x80           color mapped,
17**	#>10    byte&0x07       =0x00           2 colors
18**	#>10    byte&0x07       =0x01           4 colors
19**	#>10    byte&0x07       =0x02           8 colors
20**	#>10    byte&0x07       =0x03           16 colors
21**	#>10    byte&0x07       =0x04           32 colors
22**	#>10    byte&0x07       =0x05           64 colors
23**	#>10    byte&0x07       =0x06           128 colors
24**	#>10    byte&0x07       =0x07           256 colors
25**
26**	Just the "8BIM" "GIFf" will be used whatever the type GIF file
27**	it is.
28**
29**	Modified for mkhybrid James Pearson 19/5/98
30*/
31
32/*
33 * file - find type of a file or files - main program.
34 *
35 * Copyright (c) Ian F. Darwin, 1987.
36 * Written by Ian F. Darwin.
37 *
38 * This software is not subject to any license of the American Telephone
39 * and Telegraph Company or of the Regents of the University of California.
40 *
41 * Permission is granted to anyone to use this software for any purpose on
42 * any computer system, and to alter it and redistribute it freely, subject
43 * to the following restrictions:
44 *
45 * 1. The author is not responsible for the consequences of use of this
46 *    software, no matter how awful, even if they arise from flaws in it.
47 *
48 * 2. The origin of this software must not be misrepresented, either by
49 *    explicit claim or by omission.  Since few users ever read sources,
50 *    credits must appear in the documentation.
51 *
52 * 3. Altered versions must be plainly marked as such, and must not be
53 *    misrepresented as being the original software.  Since few users
54 *    ever read sources, credits must appear in the documentation.
55 *
56 * 4. This notice may not be removed or altered.
57 */
58#include <stdio.h>
59#include <stdlib.h>
60#include <string.h>
61#include <sys/types.h>
62#include <sys/param.h>	/* for MAXPATHLEN */
63#include <sys/stat.h>
64#include <fcntl.h>	/* for open() */
65#if (__COHERENT__ >= 0x420)
66# include <sys/utime.h>
67#else
68# ifdef USE_UTIMES
69#  include <sys/time.h>
70# else
71#  include <utime.h>
72# endif
73#endif
74#include <unistd.h>	/* for read() */
75
76#include <netinet/in.h>		/* for byte swapping */
77
78#include "patchlevel.h"
79#include "file.h"
80#include "proto.h"
81
82int 			/* Global command-line options 		*/
83#ifdef DEBUG
84	debug = 1, 	/* debugging 				*/
85#else
86	debug = 0, 	/* debugging 				*/
87#endif /* DEBUG */
88	lflag = 0,	/* follow Symlinks (BSD only) 		*/
89	zflag = 0;	/* follow (uncompress) compressed files */
90
91int			/* Misc globals				*/
92	nmagic = 0;	/* number of valid magic[]s 		*/
93
94struct  magic *magic;	/* array of magic entries		*/
95
96char *magicfile;	/* where magic be found 		*/
97
98char *progname;		/* used throughout 			*/
99int lineno;		/* line number in the magic file	*/
100
101#if 0
102static int	byteconv4	__P((int, int, int));
103static short	byteconv2	__P((int, int, int));
104#endif
105
106#if 0
107/*
108 * byteconv4
109 * Input:
110 *	from		4 byte quantity to convert
111 *	same		whether to perform byte swapping
112 *	big_endian	whether we are a big endian host
113 */
114static int
115byteconv4(from, same, big_endian)
116    int from;
117    int same;
118    int big_endian;
119{
120  if (same)
121    return from;
122  else if (big_endian)		/* lsb -> msb conversion on msb */
123  {
124    union {
125      int i;
126      char c[4];
127    } retval, tmpval;
128
129    tmpval.i = from;
130    retval.c[0] = tmpval.c[3];
131    retval.c[1] = tmpval.c[2];
132    retval.c[2] = tmpval.c[1];
133    retval.c[3] = tmpval.c[0];
134
135    return retval.i;
136  }
137  else
138    return ntohl(from);		/* msb -> lsb conversion on lsb */
139}
140
141/*
142 * byteconv2
143 * Same as byteconv4, but for shorts
144 */
145static short
146byteconv2(from, same, big_endian)
147	int from;
148	int same;
149	int big_endian;
150{
151  if (same)
152    return from;
153  else if (big_endian)		/* lsb -> msb conversion on msb */
154  {
155    union {
156      short s;
157      char c[2];
158    } retval, tmpval;
159
160    tmpval.s = (short) from;
161    retval.c[0] = tmpval.c[1];
162    retval.c[1] = tmpval.c[0];
163
164    return retval.s;
165  }
166  else
167    return ntohs(from);		/* msb -> lsb conversion on lsb */
168}
169#endif
170
171/*
172 * get_magic_match - get the CREATOR/TYPE string
173 * based on the original process()
174 */
175char *
176get_magic_match(inname)
177const char	*inname;
178{
179	int	fd = 0;
180	unsigned char	buf[HOWMANY+1];	/* one extra for terminating '\0' */
181	struct stat	sb;
182	int nbytes = 0;	/* number of bytes read from a datafile */
183	char *match;
184
185	/* check the file is regular and non-zero length */
186	if (stat(inname, &sb) != 0)
187		return 0;
188
189	if (sb.st_size == 0 || ! S_ISREG(sb.st_mode))
190		return 0;
191
192	if ((fd = open(inname, O_RDONLY)) < 0)
193		    return 0;
194
195	/*
196	 * try looking at the first HOWMANY bytes
197	 */
198	if ((nbytes = read(fd, (char *)buf, HOWMANY)) == -1)
199		return 0;
200
201	if (nbytes == 0)
202		return 0;
203	else {
204		buf[nbytes++] = '\0';	/* null-terminate it */
205		match = softmagic(buf, nbytes);
206	}
207
208#ifdef RESTORE_TIME
209	/* really no point as we going to access the file later anyway */
210	{
211		/*
212		 * Try to restore access, modification times if read it.
213		 */
214# ifdef USE_UTIMES
215		struct timeval  utsbuf[2];
216		utsbuf[0].tv_sec = sb.st_atime;
217		utsbuf[1].tv_sec = sb.st_mtime;
218
219		(void) utimes(inname, utsbuf); /* don't care if loses */
220# else
221		struct utimbuf  utbuf;
222
223		utbuf.actime = sb.st_atime;
224		utbuf.modtime = sb.st_mtime;
225		(void) utime(inname, &utbuf); /* don't care if loses */
226# endif
227#endif
228	(void) close(fd);
229
230	return(match);
231}
232
233/*
234 * clean_magic - deallocate memory used
235 */
236void
237clean_magic()
238{
239	if (magic)
240		free(magic);
241}
242
243
244#ifdef MAIN
245main(argc, argv)
246int	argc;
247char	**argv;
248{
249	char	*ret;
250	char	creator[5];
251	char	type[5];
252
253	if (argc < 3)
254		exit(1);
255
256	init_magic(argv[1]);
257
258	ret = get_magic_match(argv[2]);
259
260	if (!ret)
261		ret = "unixTEXT";
262
263	sscanf(ret, "%4s%4s", creator, type);
264
265	creator[4] = type[4] = '\0';
266
267	printf("%s %s\n", creator, type);
268
269
270	exit(0);
271}
272#endif /* MAIN */
273
274