2 IMPORTANT NOTE: IF THIS FILE IS CHANGED, WININST-6.EXE MUST BE RECOMPILED
3 WITH THE MSVC6 WININST.DSW WORKSPACE FILE MANUALLY, AND WININST-7.1.EXE MUST
4 BE RECOMPILED WITH THE MSVC 2003.NET WININST-7.1.VCPROJ FILE MANUALLY.
6 IF CHANGES TO THIS FILE ARE CHECKED INTO PYTHON CVS, THE RECOMPILED BINARIES
7 MUST BE CHECKED IN AS WELL!
19 /* Convert unix-path to dos-path */
20 static void normpath(char *path
)
22 while (path
&& *path
) {
29 BOOL
ensure_directory(char *pathname
, char *new_part
, NOTIFYPROC notify
)
31 while (new_part
&& *new_part
&& (new_part
= strchr(new_part
, '\\'))) {
34 attr
= GetFileAttributes(pathname
);
37 if (!CreateDirectory(pathname
, NULL
) && notify
)
39 "CreateDirectory (%s)", pathname
);
41 notify(DIR_CREATED
, pathname
);
43 if (attr
& FILE_ATTRIBUTE_DIRECTORY
) {
49 "CreateDirectory (%s)", pathname
);
57 /* XXX Should better explicitely specify
58 * uncomp_size and file_times instead of pfhdr!
60 char *map_new_file(DWORD flags
, char *filename
,
61 char *pathname_part
, int size
,
62 WORD wFatDate
, WORD wFatTime
,
65 HANDLE hFile
, hFileMapping
;
72 hFile
= CreateFile(filename
,
73 GENERIC_WRITE
| GENERIC_READ
,
76 FILE_ATTRIBUTE_NORMAL
, NULL
);
77 if (hFile
== INVALID_HANDLE_VALUE
) {
78 DWORD x
= GetLastError();
80 case ERROR_FILE_EXISTS
:
81 if (notify
&& notify(CAN_OVERWRITE
, filename
))
82 hFile
= CreateFile(filename
,
83 GENERIC_WRITE
|GENERIC_READ
,
86 FILE_ATTRIBUTE_NORMAL
,
90 notify(FILE_OVERWRITTEN
, filename
);
94 case ERROR_PATH_NOT_FOUND
:
95 if (ensure_directory(filename
, pathname_part
, notify
))
105 if (hFile
== INVALID_HANDLE_VALUE
) {
107 notify (SYSTEM_ERROR
, "CreateFile (%s)", filename
);
112 notify(FILE_CREATED
, filename
);
114 DosDateTimeToFileTime(wFatDate
, wFatTime
, &ft
);
115 SetFileTime(hFile
, &ft
, &ft
, &ft
);
119 /* We cannot map a zero-length file (Also it makes
125 hFileMapping
= CreateFileMapping(hFile
,
126 NULL
, PAGE_READWRITE
, 0, size
, NULL
);
130 if (hFileMapping
== INVALID_HANDLE_VALUE
) {
133 "CreateFileMapping (%s)", filename
);
137 dst
= MapViewOfFile(hFileMapping
,
138 FILE_MAP_WRITE
, 0, 0, 0);
140 CloseHandle(hFileMapping
);
144 notify(SYSTEM_ERROR
, "MapViewOfFile (%s)", filename
);
152 extract_file(char *dst
, char *src
, int method
, int comp_size
,
153 int uncomp_size
, NOTIFYPROC notify
)
158 if (method
== Z_DEFLATED
) {
160 memset(&zstream
, 0, sizeof(zstream
));
161 zstream
.next_in
= src
;
162 zstream
.avail_in
= comp_size
+1;
163 zstream
.next_out
= dst
;
164 zstream
.avail_out
= uncomp_size
;
166 /* Apparently an undocumented feature of zlib: Set windowsize
167 to negative values to supress the gzip header and be compatible with
170 if (Z_OK
!= (x
= inflateInit2(&zstream
, -15))) {
173 "inflateInit2 returns %d", x
);
177 if (Z_STREAM_END
!= (x
= inflate(&zstream
, Z_FINISH
))) {
180 "inflate returns %d", x
);
184 if (Z_OK
!= (x
= inflateEnd(&zstream
))) {
187 "inflateEnd returns %d", x
);
190 } else if (method
== 0) {
191 memcpy(dst
, src
, uncomp_size
);
195 UnmapViewOfFile(dst
);
199 /* Open a zip-compatible archive and extract all files
200 * into the specified directory (which is assumed to exist)
203 unzip_archive(SCHEME
*scheme
, char *dirname
, char *data
, DWORD size
,
207 char pathname
[MAX_PATH
];
210 /* read the end of central directory record */
211 struct eof_cdir
*pe
= (struct eof_cdir
*)&data
[size
- sizeof
214 int arc_start
= size
- sizeof (struct eof_cdir
) - pe
->nBytesCDir
-
217 /* set position to start of central directory */
218 int pos
= arc_start
+ pe
->ofsCDir
;
220 /* make sure this is a zip file */
221 if (pe
->tag
!= 0x06054b50)
224 /* Loop through the central directory, reading all entries */
225 for (n
= 0; n
< pe
->nTotalCDir
; ++n
) {
233 pcdir
= (struct cdir
*)&data
[pos
];
234 pfhdr
= (struct fhdr
*)&data
[pcdir
->ofs_local_header
+
237 if (pcdir
->tag
!= 0x02014b50)
239 if (pfhdr
->tag
!= 0x04034b50)
241 pos
+= sizeof(struct cdir
);
242 fname
= (char *)&data
[pos
]; /* This is not null terminated! */
243 pos
+= pcdir
->fname_length
+ pcdir
->extra_length
+
244 pcdir
->comment_length
;
246 pcomp
= &data
[pcdir
->ofs_local_header
247 + sizeof(struct fhdr
)
249 + pfhdr
->fname_length
250 + pfhdr
->extra_length
];
252 /* dirname is the Python home directory (prefix) */
253 strcpy(pathname
, dirname
);
254 if (pathname
[strlen(pathname
)-1] != '\\')
255 strcat(pathname
, "\\");
256 new_part
= &pathname
[lstrlen(pathname
)];
257 /* we must now match the first part of the pathname
258 * in the archive to a component in the installation
259 * scheme (PURELIB, PLATLIB, HEADERS, SCRIPTS, or DATA)
260 * and replace this part by the one in the scheme to use
262 for (i
= 0; scheme
[i
].name
; ++i
) {
263 if (0 == strnicmp(scheme
[i
].name
, fname
,
264 strlen(scheme
[i
].name
))) {
268 /* length of the replaced part */
269 int namelen
= strlen(scheme
[i
].name
);
271 strcat(pathname
, scheme
[i
].prefix
);
273 rest
= fname
+ namelen
;
274 len
= pfhdr
->fname_length
- namelen
;
276 if ((pathname
[strlen(pathname
)-1] != '\\')
277 && (pathname
[strlen(pathname
)-1] != '/'))
278 strcat(pathname
, "\\");
279 /* Now that pathname ends with a separator,
280 * we must make sure rest does not start with
283 if ((rest
[0] == '\\') || (rest
[0] == '/')) {
288 strncat(pathname
, rest
, len
);
292 /* no prefix to replace found, go unchanged */
293 strncat(pathname
, fname
, pfhdr
->fname_length
);
296 if (pathname
[strlen(pathname
)-1] != '\\') {
298 * The local file header (pfhdr) does not always
299 * contain the compressed and uncompressed sizes of
300 * the data depending on bit 3 of the flags field. So
301 * it seems better to use the data from the central
304 dst
= map_new_file(0, pathname
, new_part
,
306 pcdir
->last_mod_file_date
,
307 pcdir
->last_mod_file_time
, notify
);
309 if (!extract_file(dst
, pcomp
, pfhdr
->method
,
317 notify(NUM_FILES
, new_part
, (int)pe
->nTotalCDir
,