ยปCore Development>Code coverage>PC/bdist_wininst/extract.c

Python code coverage for PC/bdist_wininst/extract.c

#countcontent
1n/a/*
2n/a IMPORTANT NOTE: IF THIS FILE IS CHANGED, PCBUILD\BDIST_WININST.VCXPROJ MUST
3n/a BE REBUILT AS WELL.
4n/a
5n/a IF CHANGES TO THIS FILE ARE CHECKED IN, THE RECOMPILED BINARIES MUST BE
6n/a CHECKED IN AS WELL!
7n/a*/
8n/a
9n/a#include <windows.h>
10n/a
11n/a#include "zlib.h"
12n/a
13n/a#include <stdio.h>
14n/a#include <stdarg.h>
15n/a
16n/a#include "archive.h"
17n/a
18n/a/* Convert unix-path to dos-path */
19n/astatic void normpath(char *path)
20n/a{
21n/a while (path && *path) {
22n/a if (*path == '/')
23n/a *path = '\\';
24n/a ++path;
25n/a }
26n/a}
27n/a
28n/aBOOL ensure_directory(char *pathname, char *new_part, NOTIFYPROC notify)
29n/a{
30n/a while (new_part && *new_part && (new_part = strchr(new_part, '\\'))) {
31n/a DWORD attr;
32n/a *new_part = '\0';
33n/a attr = GetFileAttributes(pathname);
34n/a if (attr == -1) {
35n/a /* nothing found */
36n/a if (!CreateDirectory(pathname, NULL) && notify)
37n/a notify(SYSTEM_ERROR,
38n/a "CreateDirectory (%s)", pathname);
39n/a else
40n/a notify(DIR_CREATED, pathname);
41n/a }
42n/a if (attr & FILE_ATTRIBUTE_DIRECTORY) {
43n/a ;
44n/a } else {
45n/a SetLastError(183);
46n/a if (notify)
47n/a notify(SYSTEM_ERROR,
48n/a "CreateDirectory (%s)", pathname);
49n/a }
50n/a *new_part = '\\';
51n/a ++new_part;
52n/a }
53n/a return TRUE;
54n/a}
55n/a
56n/a/* XXX Should better explicitly specify
57n/a * uncomp_size and file_times instead of pfhdr!
58n/a */
59n/achar *map_new_file(DWORD flags, char *filename,
60n/a char *pathname_part, int size,
61n/a WORD wFatDate, WORD wFatTime,
62n/a NOTIFYPROC notify)
63n/a{
64n/a HANDLE hFile, hFileMapping;
65n/a char *dst;
66n/a FILETIME ft;
67n/a
68n/a try_again:
69n/a if (!flags)
70n/a flags = CREATE_NEW;
71n/a hFile = CreateFile(filename,
72n/a GENERIC_WRITE | GENERIC_READ,
73n/a 0, NULL,
74n/a flags,
75n/a FILE_ATTRIBUTE_NORMAL, NULL);
76n/a if (hFile == INVALID_HANDLE_VALUE) {
77n/a DWORD x = GetLastError();
78n/a switch (x) {
79n/a case ERROR_FILE_EXISTS:
80n/a if (notify && notify(CAN_OVERWRITE, filename))
81n/a hFile = CreateFile(filename,
82n/a GENERIC_WRITE|GENERIC_READ,
83n/a 0, NULL,
84n/a CREATE_ALWAYS,
85n/a FILE_ATTRIBUTE_NORMAL,
86n/a NULL);
87n/a else {
88n/a if (notify)
89n/a notify(FILE_OVERWRITTEN, filename);
90n/a return NULL;
91n/a }
92n/a break;
93n/a case ERROR_PATH_NOT_FOUND:
94n/a if (ensure_directory(filename, pathname_part, notify))
95n/a goto try_again;
96n/a else
97n/a return FALSE;
98n/a break;
99n/a default:
100n/a SetLastError(x);
101n/a break;
102n/a }
103n/a }
104n/a if (hFile == INVALID_HANDLE_VALUE) {
105n/a if (notify)
106n/a notify (SYSTEM_ERROR, "CreateFile (%s)", filename);
107n/a return NULL;
108n/a }
109n/a
110n/a if (notify)
111n/a notify(FILE_CREATED, filename);
112n/a
113n/a DosDateTimeToFileTime(wFatDate, wFatTime, &ft);
114n/a SetFileTime(hFile, &ft, &ft, &ft);
115n/a
116n/a
117n/a if (size == 0) {
118n/a /* We cannot map a zero-length file (Also it makes
119n/a no sense */
120n/a CloseHandle(hFile);
121n/a return NULL;
122n/a }
123n/a
124n/a hFileMapping = CreateFileMapping(hFile,
125n/a NULL, PAGE_READWRITE, 0, size, NULL);
126n/a
127n/a CloseHandle(hFile);
128n/a
129n/a if (hFileMapping == NULL) {
130n/a if (notify)
131n/a notify(SYSTEM_ERROR,
132n/a "CreateFileMapping (%s)", filename);
133n/a return NULL;
134n/a }
135n/a
136n/a dst = MapViewOfFile(hFileMapping,
137n/a FILE_MAP_WRITE, 0, 0, 0);
138n/a
139n/a CloseHandle(hFileMapping);
140n/a
141n/a if (!dst) {
142n/a if (notify)
143n/a notify(SYSTEM_ERROR, "MapViewOfFile (%s)", filename);
144n/a return NULL;
145n/a }
146n/a return dst;
147n/a}
148n/a
149n/a
150n/aBOOL
151n/aextract_file(char *dst, char *src, int method, int comp_size,
152n/a int uncomp_size, NOTIFYPROC notify)
153n/a{
154n/a z_stream zstream;
155n/a int result;
156n/a
157n/a if (method == Z_DEFLATED) {
158n/a int x;
159n/a memset(&zstream, 0, sizeof(zstream));
160n/a zstream.next_in = src;
161n/a zstream.avail_in = comp_size+1;
162n/a zstream.next_out = dst;
163n/a zstream.avail_out = uncomp_size;
164n/a
165n/a/* Apparently an undocumented feature of zlib: Set windowsize
166n/a to negative values to suppress the gzip header and be compatible with
167n/a zip! */
168n/a result = TRUE;
169n/a if (Z_OK != (x = inflateInit2(&zstream, -15))) {
170n/a if (notify)
171n/a notify(ZLIB_ERROR,
172n/a "inflateInit2 returns %d", x);
173n/a result = FALSE;
174n/a goto cleanup;
175n/a }
176n/a if (Z_STREAM_END != (x = inflate(&zstream, Z_FINISH))) {
177n/a if (notify)
178n/a notify(ZLIB_ERROR,
179n/a "inflate returns %d", x);
180n/a result = FALSE;
181n/a }
182n/a cleanup:
183n/a if (Z_OK != (x = inflateEnd(&zstream))) {
184n/a if (notify)
185n/a notify (ZLIB_ERROR,
186n/a "inflateEnd returns %d", x);
187n/a result = FALSE;
188n/a }
189n/a } else if (method == 0) {
190n/a memcpy(dst, src, uncomp_size);
191n/a result = TRUE;
192n/a } else
193n/a result = FALSE;
194n/a UnmapViewOfFile(dst);
195n/a return result;
196n/a}
197n/a
198n/a/* Open a zip-compatible archive and extract all files
199n/a * into the specified directory (which is assumed to exist)
200n/a */
201n/aBOOL
202n/aunzip_archive(SCHEME *scheme, char *dirname, char *data, DWORD size,
203n/a NOTIFYPROC notify)
204n/a{
205n/a int n;
206n/a char pathname[MAX_PATH];
207n/a char *new_part;
208n/a
209n/a /* read the end of central directory record */
210n/a struct eof_cdir *pe = (struct eof_cdir *)&data[size - sizeof
211n/a (struct eof_cdir)];
212n/a
213n/a int arc_start = size - sizeof (struct eof_cdir) - pe->nBytesCDir -
214n/a pe->ofsCDir;
215n/a
216n/a /* set position to start of central directory */
217n/a int pos = arc_start + pe->ofsCDir;
218n/a
219n/a /* make sure this is a zip file */
220n/a if (pe->tag != 0x06054b50)
221n/a return FALSE;
222n/a
223n/a /* Loop through the central directory, reading all entries */
224n/a for (n = 0; n < pe->nTotalCDir; ++n) {
225n/a int i;
226n/a char *fname;
227n/a char *pcomp;
228n/a char *dst;
229n/a struct cdir *pcdir;
230n/a struct fhdr *pfhdr;
231n/a
232n/a pcdir = (struct cdir *)&data[pos];
233n/a pfhdr = (struct fhdr *)&data[pcdir->ofs_local_header +
234n/a arc_start];
235n/a
236n/a if (pcdir->tag != 0x02014b50)
237n/a return FALSE;
238n/a if (pfhdr->tag != 0x04034b50)
239n/a return FALSE;
240n/a pos += sizeof(struct cdir);
241n/a fname = (char *)&data[pos]; /* This is not null terminated! */
242n/a pos += pcdir->fname_length + pcdir->extra_length +
243n/a pcdir->comment_length;
244n/a
245n/a pcomp = &data[pcdir->ofs_local_header
246n/a + sizeof(struct fhdr)
247n/a + arc_start
248n/a + pfhdr->fname_length
249n/a + pfhdr->extra_length];
250n/a
251n/a /* dirname is the Python home directory (prefix) */
252n/a strcpy(pathname, dirname);
253n/a if (pathname[strlen(pathname)-1] != '\\')
254n/a strcat(pathname, "\\");
255n/a new_part = &pathname[lstrlen(pathname)];
256n/a /* we must now match the first part of the pathname
257n/a * in the archive to a component in the installation
258n/a * scheme (PURELIB, PLATLIB, HEADERS, SCRIPTS, or DATA)
259n/a * and replace this part by the one in the scheme to use
260n/a */
261n/a for (i = 0; scheme[i].name; ++i) {
262n/a if (0 == strnicmp(scheme[i].name, fname,
263n/a strlen(scheme[i].name))) {
264n/a char *rest;
265n/a int len;
266n/a
267n/a /* length of the replaced part */
268n/a int namelen = strlen(scheme[i].name);
269n/a
270n/a strcat(pathname, scheme[i].prefix);
271n/a
272n/a rest = fname + namelen;
273n/a len = pfhdr->fname_length - namelen;
274n/a
275n/a if ((pathname[strlen(pathname)-1] != '\\')
276n/a && (pathname[strlen(pathname)-1] != '/'))
277n/a strcat(pathname, "\\");
278n/a /* Now that pathname ends with a separator,
279n/a * we must make sure rest does not start with
280n/a * an additional one.
281n/a */
282n/a if ((rest[0] == '\\') || (rest[0] == '/')) {
283n/a ++rest;
284n/a --len;
285n/a }
286n/a
287n/a strncat(pathname, rest, len);
288n/a goto Done;
289n/a }
290n/a }
291n/a /* no prefix to replace found, go unchanged */
292n/a strncat(pathname, fname, pfhdr->fname_length);
293n/a Done:
294n/a normpath(pathname);
295n/a if (pathname[strlen(pathname)-1] != '\\') {
296n/a /*
297n/a * The local file header (pfhdr) does not always
298n/a * contain the compressed and uncompressed sizes of
299n/a * the data depending on bit 3 of the flags field. So
300n/a * it seems better to use the data from the central
301n/a * directory (pcdir).
302n/a */
303n/a dst = map_new_file(0, pathname, new_part,
304n/a pcdir->uncomp_size,
305n/a pcdir->last_mod_file_date,
306n/a pcdir->last_mod_file_time, notify);
307n/a if (dst) {
308n/a if (!extract_file(dst, pcomp, pfhdr->method,
309n/a pcdir->comp_size,
310n/a pcdir->uncomp_size,
311n/a notify))
312n/a return FALSE;
313n/a } /* else ??? */
314n/a }
315n/a if (notify)
316n/a notify(NUM_FILES, new_part, (int)pe->nTotalCDir,
317n/a (int)n+1);
318n/a }
319n/a return TRUE;
320n/a}