1/*-
2 * Copyright (c) 2015 Kai Wang
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/stat.h>
28#include <assert.h>
29#include <errno.h>
30#include <stdlib.h>
31#include <unistd.h>
32
33#include "_libpe.h"
34
35ELFTC_VCSID("$Id: libpe_init.c 3312 2016-01-10 09:23:51Z kaiwang27 $");
36
37int
38libpe_open_object(PE *pe)
39{
40	struct stat sb;
41	mode_t mode;
42	char magic[sizeof(PE_DosHdr)];
43
44	if (fstat(pe->pe_fd, &sb) < 0)
45		return (-1);
46
47	mode = sb.st_mode;
48	pe->pe_fsize = (size_t) sb.st_size;
49
50	/* Reject unsupported file types. */
51	if (!S_ISREG(mode) && !S_ISCHR(mode) && !S_ISFIFO(mode) &&
52	    !S_ISSOCK(mode)) {
53		errno = EINVAL;
54		return (-1);
55	}
56
57	/* Read/Write mode is not supported for non-regular file. */
58	if (pe->pe_cmd == PE_C_RDWR && !S_ISREG(mode)) {
59		errno = EINVAL;
60		return (-1);
61	}
62
63	/* The minimal file should at least contain a COFF header. */
64	if (S_ISREG(mode) && pe->pe_fsize < sizeof(PE_CoffHdr)) {
65		errno = ENOENT;
66		return (-1);
67	}
68
69	/*
70	 * Search for MS-DOS header or COFF header.
71	 */
72
73	if (read(pe->pe_fd, magic, 2) != 2) {
74		errno = EIO;
75		return (-1);
76	}
77
78	if (magic[0] == 'M' && magic[1] == 'Z') {
79		pe->pe_obj = PE_O_PE32;
80		if (read(pe->pe_fd, &magic[2], sizeof(PE_DosHdr) - 2) !=
81		    (ssize_t) sizeof(PE_DosHdr) - 2) {
82			errno = EIO;
83			return (-1);
84		}
85		return (libpe_parse_msdos_header(pe, magic));
86
87	} else if (magic[0] == 'P' && magic[1] == 'E') {
88		if (read(pe->pe_fd, magic, 2) != 2) {
89			errno = EIO;
90			return (-1);
91		}
92		if (magic[0] == '\0' && magic[1] == '\0') {
93			pe->pe_obj = PE_O_PE32;
94			if (read(pe->pe_fd, magic, sizeof(PE_CoffHdr)) !=
95			    (ssize_t) sizeof(PE_CoffHdr)) {
96				errno = EIO;
97				return (-1);
98			}
99			return (libpe_parse_coff_header(pe, magic));
100		}
101		errno = ENOENT;
102		return (-1);
103
104	} else {
105		pe->pe_obj = PE_O_COFF;
106		if (read(pe->pe_fd, &magic[2], sizeof(PE_CoffHdr) - 2) !=
107		    (ssize_t) sizeof(PE_CoffHdr) - 2) {
108			errno = EIO;
109			return (-1);
110		}
111		return (libpe_parse_coff_header(pe, magic));
112	}
113}
114
115void
116libpe_release_object(PE *pe)
117{
118	PE_Scn *ps, *_ps;
119
120	if (pe->pe_dh)
121		free(pe->pe_dh);
122
123	if (pe->pe_rh) {
124		free(pe->pe_rh->rh_compid);
125		free(pe->pe_rh->rh_cnt);
126		free(pe->pe_rh);
127	}
128
129	if (pe->pe_ch)
130		free(pe->pe_ch);
131
132	if (pe->pe_oh)
133		free(pe->pe_oh);
134
135	if (pe->pe_dd)
136		free(pe->pe_dd);
137
138	if (pe->pe_stub)
139		free(pe->pe_stub);
140
141	STAILQ_FOREACH_SAFE(ps, &pe->pe_scn, ps_next, _ps)
142		libpe_release_scn(ps);
143
144	free(pe);
145}
146