10 /* Convert unix-path to dos-path */
11 static void normpath(char *path
)
13 while (path
&& *path
) {
20 BOOL
ensure_directory(char *pathname
, char *new_part
, NOTIFYPROC notify
)
22 while (new_part
&& *new_part
&& (new_part
= strchr(new_part
, '\\'))) {
25 attr
= GetFileAttributes(pathname
);
28 if (!CreateDirectory(pathname
, NULL
) && notify
)
30 "CreateDirectory (%s)", pathname
);
32 notify(DIR_CREATED
, pathname
);
34 if (attr
& FILE_ATTRIBUTE_DIRECTORY
) {
40 "CreateDirectory (%s)", pathname
);
48 /* XXX Should better explicitely specify
49 * uncomp_size and file_times instead of pfhdr!
51 char *map_new_file(DWORD flags
, char *filename
,
52 char *pathname_part
, int size
,
53 WORD wFatDate
, WORD wFatTime
,
56 HANDLE hFile
, hFileMapping
;
63 hFile
= CreateFile(filename
,
64 GENERIC_WRITE
| GENERIC_READ
,
67 FILE_ATTRIBUTE_NORMAL
, NULL
);
68 if (hFile
== INVALID_HANDLE_VALUE
) {
69 DWORD x
= GetLastError();
71 case ERROR_FILE_EXISTS
:
72 if (notify
&& notify(CAN_OVERWRITE
, filename
))
73 hFile
= CreateFile(filename
,
74 GENERIC_WRITE
|GENERIC_READ
,
77 FILE_ATTRIBUTE_NORMAL
,
81 notify(FILE_OVERWRITTEN
, filename
);
85 case ERROR_PATH_NOT_FOUND
:
86 if (ensure_directory(filename
, pathname_part
, notify
))
96 if (hFile
== INVALID_HANDLE_VALUE
) {
98 notify (SYSTEM_ERROR
, "CreateFile (%s)", filename
);
103 notify(FILE_CREATED
, filename
);
105 DosDateTimeToFileTime(wFatDate
, wFatTime
, &ft
);
106 SetFileTime(hFile
, &ft
, &ft
, &ft
);
110 /* We cannot map a zero-length file (Also it makes
116 hFileMapping
= CreateFileMapping(hFile
,
117 NULL
, PAGE_READWRITE
, 0, size
, NULL
);
121 if (hFileMapping
== INVALID_HANDLE_VALUE
) {
124 "CreateFileMapping (%s)", filename
);
128 dst
= MapViewOfFile(hFileMapping
,
129 FILE_MAP_WRITE
, 0, 0, 0);
131 CloseHandle(hFileMapping
);
135 notify(SYSTEM_ERROR
, "MapViewOfFile (%s)", filename
);
143 extract_file(char *dst
, char *src
, int method
, int comp_size
,
144 int uncomp_size
, NOTIFYPROC notify
)
149 if (method
== Z_DEFLATED
) {
151 memset(&zstream
, 0, sizeof(zstream
));
152 zstream
.next_in
= src
;
153 zstream
.avail_in
= comp_size
+1;
154 zstream
.next_out
= dst
;
155 zstream
.avail_out
= uncomp_size
;
157 /* Apparently an undocumented feature of zlib: Set windowsize
158 to negative values to supress the gzip header and be compatible with
161 if (Z_OK
!= (x
= inflateInit2(&zstream
, -15))) {
164 "inflateInit2 returns %d", x
);
168 if (Z_STREAM_END
!= (x
= inflate(&zstream
, Z_FINISH
))) {
171 "inflate returns %d", x
);
175 if (Z_OK
!= (x
= inflateEnd(&zstream
))) {
178 "inflateEnd returns %d", x
);
181 } else if (method
== 0) {
182 memcpy(dst
, src
, uncomp_size
);
186 UnmapViewOfFile(dst
);
190 /* Open a zip-compatible archive and extract all files
191 * into the specified directory (which is assumed to exist)
194 unzip_archive(SCHEME
*scheme
, char *dirname
, char *data
, DWORD size
,
198 char pathname
[MAX_PATH
];
201 /* read the end of central directory record */
202 struct eof_cdir
*pe
= (struct eof_cdir
*)&data
[size
- sizeof
205 int arc_start
= size
- sizeof (struct eof_cdir
) - pe
->nBytesCDir
-
208 /* set position to start of central directory */
209 int pos
= arc_start
+ pe
->ofsCDir
;
211 /* make sure this is a zip file */
212 if (pe
->tag
!= 0x06054b50)
215 /* Loop through the central directory, reading all entries */
216 for (n
= 0; n
< pe
->nTotalCDir
; ++n
) {
224 pcdir
= (struct cdir
*)&data
[pos
];
225 pfhdr
= (struct fhdr
*)&data
[pcdir
->ofs_local_header
+
228 if (pcdir
->tag
!= 0x02014b50)
230 if (pfhdr
->tag
!= 0x04034b50)
232 pos
+= sizeof(struct cdir
);
233 fname
= (char *)&data
[pos
]; /* This is not null terminated! */
234 pos
+= pcdir
->fname_length
+ pcdir
->extra_length
+
235 pcdir
->comment_length
;
237 pcomp
= &data
[pcdir
->ofs_local_header
238 + sizeof(struct fhdr
)
240 + pfhdr
->fname_length
241 + pfhdr
->extra_length
];
243 /* dirname is the Python home directory (prefix) */
244 strcpy(pathname
, dirname
);
245 if (pathname
[strlen(pathname
)-1] != '\\')
246 strcat(pathname
, "\\");
247 new_part
= &pathname
[lstrlen(pathname
)];
248 /* we must now match the first part of the pathname
249 * in the archive to a component in the installation
250 * scheme (PURELIB, PLATLIB, HEADERS, SCRIPTS, or DATA)
251 * and replace this part by the one in the scheme to use
253 for (i
= 0; scheme
[i
].name
; ++i
) {
254 if (0 == strnicmp(scheme
[i
].name
, fname
,
255 strlen(scheme
[i
].name
))) {
259 /* length of the replaced part */
260 int namelen
= strlen(scheme
[i
].name
);
262 strcat(pathname
, scheme
[i
].prefix
);
264 rest
= fname
+ namelen
;
265 len
= pfhdr
->fname_length
- namelen
;
267 if ((pathname
[strlen(pathname
)-1] != '\\')
268 && (pathname
[strlen(pathname
)-1] != '/'))
269 strcat(pathname
, "\\");
270 /* Now that pathname ends with a separator,
271 * we must make sure rest does not start with
274 if ((rest
[0] == '\\') || (rest
[0] == '/')) {
279 strncat(pathname
, rest
, len
);
283 /* no prefix to replace found, go unchanged */
284 strncat(pathname
, fname
, pfhdr
->fname_length
);
287 if (pathname
[strlen(pathname
)-1] != '\\') {
289 * The local file header (pfhdr) does not always
290 * contain the compressed and uncompressed sizes of
291 * the data depending on bit 3 of the flags field. So
292 * it seems better to use the data from the central
295 dst
= map_new_file(0, pathname
, new_part
,
297 pcdir
->last_mod_file_date
,
298 pcdir
->last_mod_file_time
, notify
);
300 if (!extract_file(dst
, pcomp
, pfhdr
->method
,
308 notify(NUM_FILES
, new_part
, (int)pe
->nTotalCDir
,