1/*
2 * Copyright (c) 1999-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#ifdef BUILTIN_MACHO
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sys/types.h>
29#include <sys/param.h>
30#include <sys/file.h>
31#include <unistd.h>
32
33#include <mach-o/fat.h>
34#include <mach-o/arch.h>
35#include <mach-o/swap.h>
36
37#include "file.h"
38
39/* Silence a compiler warning. */
40FILE_RCSID("")
41
42static void
43print_arch_name_for_file(struct magic_set *ms, cpu_type_t cputype,
44	cpu_subtype_t cpusubtype)
45{
46	const NXArchInfo *ArchInfoTable, *ai;
47
48	ArchInfoTable = NXGetAllArchInfos();
49
50	for (ai = ArchInfoTable; ai->name != NULL; ai++) {
51		if(ai->cputype == cputype && ai->cpusubtype == (cpu_subtype_t)(cpusubtype & ~CPU_SUBTYPE_MASK)) {
52			file_printf(ms, " (for architecture %s)", ai->name);
53			return;
54		}
55	}
56
57	file_printf(ms, " (for architecture cputype (%d) cpusubtype (%d))",
58		cputype, cpusubtype);
59}
60
61protected int
62file_trymacho(struct magic_set *ms, int fd, const unsigned char *buf,
63	size_t nbytes, const char *inname)
64{
65	struct stat stat_buf;
66	unsigned long size;
67	struct fat_header fat_header;
68	struct fat_arch *fat_archs;
69	uint32_t arch_size, i;
70	ssize_t tbytes;
71	unsigned char *tmpbuf;
72
73	if (fstat(fd, &stat_buf) == -1) {
74		return -1;
75	}
76
77	size = stat_buf.st_size;
78
79	if (nbytes < sizeof(struct fat_header)) {
80		return -1;
81	}
82
83	memcpy(&fat_header, buf, sizeof(struct fat_header));
84#ifdef __LITTLE_ENDIAN__
85	swap_fat_header(&fat_header, NX_LittleEndian);
86#endif /* __LITTLE_ENDIAN__ */
87
88	/* Check magic number, plus little hack for Mach-O vs. Java. */
89	if(!(fat_header.magic == FAT_MAGIC && fat_header.nfat_arch < 20)) {
90		return -1;
91	}
92
93	arch_size = fat_header.nfat_arch * sizeof(struct fat_arch);
94
95	if (nbytes < sizeof(struct fat_header) + arch_size) {
96		return -1;
97	}
98
99	if ((fat_archs = (struct fat_arch *)malloc(arch_size)) == NULL) {
100		return -1;
101	}
102
103	memcpy((void *)fat_archs, buf + sizeof(struct fat_header), arch_size);
104#ifdef __LITTLE_ENDIAN__
105	swap_fat_arch(fat_archs, fat_header.nfat_arch, NX_LittleEndian);
106#endif /* __LITTLE_ENDIAN__ */
107
108	for(i = 0; i < fat_header.nfat_arch; i++) {
109		file_printf(ms, "\n%s", inname);
110		print_arch_name_for_file(ms,
111			fat_archs[i].cputype, fat_archs[i].cpusubtype);
112		file_printf(ms, ":\t");
113
114		if (fat_archs[i].offset + fat_archs[i].size > size) {
115			free(fat_archs);
116			return -1;
117		}
118
119		if (lseek(fd, fat_archs[i].offset, SEEK_SET) == -1) {
120			free(fat_archs);
121			return -1;
122		}
123
124		tmpbuf = malloc(HOWMANY + 1);
125		memset(tmpbuf, 0, sizeof(tmpbuf));
126		if ((tbytes = read(fd, tmpbuf, HOWMANY)) == -1) {
127			free(fat_archs);
128			free(tmpbuf);
129			return -1;
130		}
131
132		file_buffer(ms, -1, inname, tmpbuf, (size_t)tbytes);
133		free(tmpbuf);
134	}
135
136	free(fat_archs);
137	return 0;
138}
139#endif /* BUILTIN_MACHO */
140