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 
82 int 			/* 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 
91 int			/* Misc globals				*/
92 	nmagic = 0;	/* number of valid magic[]s 		*/
93 
94 struct  magic *magic;	/* array of magic entries		*/
95 
96 char *magicfile;	/* where magic be found 		*/
97 
98 char *progname;		/* used throughout 			*/
99 int lineno;		/* line number in the magic file	*/
100 
101 #if 0
102 static int	byteconv4	__P((int, int, int));
103 static 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  */
114 static int
115 byteconv4(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  */
145 static short
146 byteconv2(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  */
175 char *
176 get_magic_match(inname)
177 const 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  */
236 void
237 clean_magic()
238 {
239 	if (magic)
240 		free(magic);
241 }
242 
243 
244 #ifdef MAIN
245 main(argc, argv)
246 int	argc;
247 char	**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