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