Converted to the new COM declaration 'standard' for better
[wine/wine-kai.git] / dlls / version / install.c
blobe921ecfb69ae252e216c4b6966a501de11169ec4
1 /*
2 * Implementation of VERSION.DLL - File Installer routines
3 *
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
6 */
8 #include <stdlib.h>
9 #include <string.h>
11 #include "windows.h"
12 #include "winerror.h"
13 #include "heap.h"
14 #include "ver.h"
15 #include "lzexpand.h"
16 #include "xmalloc.h"
17 #include "debug.h"
20 /******************************************************************************
22 * void ver_dstring(
23 * char const * prologue,
24 * char const * teststring,
25 * char const * epilogue )
27 * This function will print via dprintf[_]ver to stddeb the prologue string,
28 * followed by the address of teststring and the string it contains if
29 * teststring is non-null or "(null)" otherwise, and then the epilogue
30 * string followed by a new line.
32 * Revision history
33 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
34 * Original implementation as dprintf[_]ver_string
35 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
36 * Fixed problem that caused bug with tools/make_debug -- renaming
37 * this function should fix the problem.
38 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
39 * Modified it to make it print the message using only one
40 * dprintf[_]ver call.
42 *****************************************************************************/
44 static void ver_dstring(
45 char const * prologue,
46 char const * teststring,
47 char const * epilogue )
49 TRACE(ver, "%s %p (\"%s\") %s\n", prologue,
50 (void const *) teststring,
51 teststring ? teststring : "(null)",
52 epilogue);
55 /******************************************************************************
57 * int testFileExistence(
58 * char const * path,
59 * char const * file )
61 * Tests whether a given path/file combination exists. If the file does
62 * not exist, the return value is zero. If it does exist, the return
63 * value is non-zero.
65 * Revision history
66 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
67 * Original implementation
69 *****************************************************************************/
71 static int testFileExistence(
72 char const * path,
73 char const * file )
75 char filename[1024];
76 int filenamelen;
77 OFSTRUCT fileinfo;
78 int retval;
80 fileinfo.cBytes = sizeof(OFSTRUCT);
82 strcpy(filename, path);
83 filenamelen = strlen(filename);
85 /* Add a trailing \ if necessary */
86 if(filenamelen) {
87 if(filename[filenamelen - 1] != '\\')
88 strcat(filename, "\\");
90 else /* specify the current directory */
91 strcpy(filename, ".\\");
93 /* Create the full pathname */
94 strcat(filename, file);
96 if(OpenFile32(filename, &fileinfo, OF_EXIST) == HFILE_ERROR32)
97 retval = 0;
98 else
99 retval = 1;
101 return retval;
104 /******************************************************************************
106 * int testFileExclusiveExistence(
107 * char const * path,
108 * char const * file )
110 * Tests whether a given path/file combination exists and ensures that no
111 * other programs have handles to the given file. If the file does not
112 * exist or is open, the return value is zero. If it does exist, the
113 * return value is non-zero.
115 * Revision history
116 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
117 * Original implementation
119 *****************************************************************************/
121 static int testFileExclusiveExistence(
122 char const * path,
123 char const * file )
125 char filename[1024];
126 int filenamelen;
127 OFSTRUCT fileinfo;
128 int retval;
130 fileinfo.cBytes = sizeof(OFSTRUCT);
132 strcpy(filename, path);
133 filenamelen = strlen(filename);
135 /* Add a trailing \ if necessary */
136 if(filenamelen) {
137 if(filename[filenamelen - 1] != '\\')
138 strcat(filename, "\\");
140 else /* specify the current directory */
141 strcpy(filename, ".\\");
143 /* Create the full pathname */
144 strcat(filename, file);
146 if(OpenFile32(filename, &fileinfo, OF_EXIST | OF_SHARE_EXCLUSIVE) ==
147 HFILE_ERROR32)
148 retval = 0;
149 else
150 retval = 1;
152 return retval;
155 /*****************************************************************************
157 * VerFindFile() [VER.8]
158 * Determines where to install a file based on whether it locates another
159 * version of the file in the system. The values VerFindFile returns are
160 * used in a subsequent call to the VerInstallFile function.
162 * Revision history:
163 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
164 * Reimplementation of VerFindFile from original stub.
166 ****************************************************************************/
168 /* VerFindFile32A [VERSION.5] */
169 DWORD WINAPI VerFindFile32A(
170 UINT32 flags,
171 LPCSTR lpszFilename,
172 LPCSTR lpszWinDir,
173 LPCSTR lpszAppDir,
174 LPSTR lpszCurDir,
175 UINT32 *lpuCurDirLen,
176 LPSTR lpszDestDir,
177 UINT32 *lpuDestDirLen )
179 DWORD retval;
180 char curDir[256];
181 char destDir[256];
182 unsigned int curDirSizeReq;
183 unsigned int destDirSizeReq;
185 retval = 0;
187 /* Print out debugging information */
188 TRACE(ver, "called with parameters:\n"
189 "\tflags = %x", flags);
190 if(flags & VFFF_ISSHAREDFILE)
191 TRACE(ver, " (VFFF_ISSHAREDFILE)\n");
192 else
193 TRACE(ver, "\n");
195 ver_dstring("\tlpszFilename = ", lpszFilename, "");
196 ver_dstring("\tlpszWinDir = ", lpszWinDir, "");
197 ver_dstring("\tlpszAppDir = ", lpszAppDir, "");
199 TRACE(ver, "\tlpszCurDir = %p\n", lpszCurDir);
200 if(lpuCurDirLen)
201 TRACE(ver, "\tlpuCurDirLen = %p (%u)\n",
202 lpuCurDirLen, *lpuCurDirLen);
203 else
204 TRACE(ver, "\tlpuCurDirLen = (null)\n");
206 TRACE(ver, "\tlpszDestDir = %p\n", lpszDestDir);
207 if(lpuDestDirLen)
208 TRACE(ver, "\tlpuDestDirLen = %p (%u)\n",
209 lpuDestDirLen, *lpuDestDirLen);
211 /* Figure out where the file should go; shared files default to the
212 system directory */
214 strcpy(curDir, "");
215 strcpy(destDir, "");
217 if(flags & VFFF_ISSHAREDFILE) {
218 GetSystemDirectory32A(destDir, 256);
220 /* Were we given a filename? If so, try to find the file. */
221 if(lpszFilename) {
222 if(testFileExistence(destDir, lpszFilename)) {
223 strcpy(curDir, destDir);
225 if(!testFileExclusiveExistence(destDir, lpszFilename))
226 retval |= VFF_FILEINUSE;
228 else if(lpszAppDir && testFileExistence(lpszAppDir,
229 lpszFilename)) {
230 strcpy(curDir, lpszAppDir);
231 retval |= VFF_CURNEDEST;
233 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
234 retval |= VFF_FILEINUSE;
238 else if(!(flags & VFFF_ISSHAREDFILE)) { /* not a shared file */
239 if(lpszAppDir) {
240 char systemDir[256];
241 GetSystemDirectory32A(systemDir, 256);
243 strcpy(destDir, lpszAppDir);
245 if(lpszFilename) {
246 if(testFileExistence(lpszAppDir, lpszFilename)) {
247 strcpy(curDir, lpszAppDir);
249 if(!testFileExclusiveExistence(lpszAppDir, lpszFilename))
250 retval |= VFF_FILEINUSE;
252 else if(testFileExistence(systemDir, lpszFilename)) {
253 strcpy(curDir, systemDir);
254 retval |= VFF_CURNEDEST;
256 if(!testFileExclusiveExistence(systemDir, lpszFilename))
257 retval |= VFF_FILEINUSE;
263 curDirSizeReq = strlen(curDir) + 1;
264 destDirSizeReq = strlen(destDir) + 1;
268 /* Make sure that the pointers to the size of the buffers are
269 valid; if not, do NOTHING with that buffer. If that pointer
270 is valid, then make sure that the buffer pointer is valid, too! */
272 if(lpuDestDirLen && lpszDestDir) {
273 if(*lpuDestDirLen < destDirSizeReq) {
274 retval |= VFF_BUFFTOOSMALL;
275 strncpy(lpszDestDir, destDir, *lpuDestDirLen - 1);
276 lpszDestDir[*lpuDestDirLen - 1] = '\0';
278 else
279 strcpy(lpszDestDir, destDir);
281 *lpuDestDirLen = destDirSizeReq;
284 if(lpuCurDirLen && lpszCurDir) {
285 if(*lpuCurDirLen < curDirSizeReq) {
286 retval |= VFF_BUFFTOOSMALL;
287 strncpy(lpszCurDir, curDir, *lpuCurDirLen - 1);
288 lpszCurDir[*lpuCurDirLen - 1] = '\0';
290 else
291 strcpy(lpszCurDir, curDir);
293 *lpuCurDirLen = curDirSizeReq;
296 TRACE(ver, "ret = %lu (%s%s%s)\n", retval,
297 (retval & VFF_CURNEDEST) ? "VFF_CURNEDEST " : "",
298 (retval & VFF_FILEINUSE) ? "VFF_FILEINUSE " : "",
299 (retval & VFF_BUFFTOOSMALL) ? "VFF_BUFFTOOSMALL " : "");
301 ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir, "");
302 if(lpuCurDirLen)
303 TRACE(ver, "\t(Exit) lpuCurDirLen = %p (%u)\n",
304 lpuCurDirLen, *lpuCurDirLen);
305 else
306 TRACE(ver, "\t(Exit) lpuCurDirLen = (null)\n");
308 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir, "");
309 if(lpuDestDirLen)
310 TRACE(ver, "\t(Exit) lpuDestDirLen = %p (%u)\n",
311 lpuDestDirLen, *lpuDestDirLen);
313 return retval;
316 /* VerFindFile32W [VERSION.6] */
317 DWORD WINAPI VerFindFile32W(
318 UINT32 flags,LPCWSTR filename,LPCWSTR windir,LPCWSTR appdir,
319 LPWSTR curdir,UINT32 *pcurdirlen,LPWSTR destdir,UINT32 *pdestdirlen )
321 UINT32 curdirlen, destdirlen;
322 LPSTR wfn,wwd,wad,wdd,wcd;
323 DWORD ret;
325 wfn = HEAP_strdupWtoA( GetProcessHeap(), 0, filename );
326 wwd = HEAP_strdupWtoA( GetProcessHeap(), 0, windir );
327 wad = HEAP_strdupWtoA( GetProcessHeap(), 0, appdir );
328 wcd = HeapAlloc( GetProcessHeap(), 0, *pcurdirlen );
329 wdd = HeapAlloc( GetProcessHeap(), 0, *pdestdirlen );
330 ret = VerFindFile32A(flags,wfn,wwd,wad,wcd,&curdirlen,wdd,&destdirlen);
331 lstrcpynAtoW(curdir,wcd,*pcurdirlen);
332 lstrcpynAtoW(destdir,wdd,*pdestdirlen);
333 *pcurdirlen = strlen(wcd);
334 *pdestdirlen = strlen(wdd);
335 HeapFree( GetProcessHeap(), 0, wfn );
336 HeapFree( GetProcessHeap(), 0, wwd );
337 HeapFree( GetProcessHeap(), 0, wad );
338 HeapFree( GetProcessHeap(), 0, wcd );
339 HeapFree( GetProcessHeap(), 0, wdd );
340 return ret;
343 static LPBYTE
344 _fetch_versioninfo(LPSTR fn,VS_FIXEDFILEINFO **vffi) {
345 DWORD alloclen;
346 LPBYTE buf;
347 DWORD ret;
349 alloclen = 1000;
350 buf= xmalloc(alloclen);
351 while (1) {
352 ret = GetFileVersionInfo32A(fn,0,alloclen,buf);
353 if (!ret) {
354 free(buf);
355 return 0;
357 if (alloclen<*(WORD*)buf) {
358 free(buf);
359 alloclen = *(WORD*)buf;
360 buf = xmalloc(alloclen);
361 } else {
362 *vffi = (VS_FIXEDFILEINFO*)(buf+0x14);
363 if ((*vffi)->dwSignature == 0x004f0049) /* hack to detect unicode */
364 *vffi = (VS_FIXEDFILEINFO*)(buf+0x28);
365 if ((*vffi)->dwSignature != VS_FFI_SIGNATURE)
366 WARN(ver,"Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi)->dwSignature);
367 return buf;
372 static DWORD
373 _error2vif(DWORD error) {
374 switch (error) {
375 case ERROR_ACCESS_DENIED:
376 return VIF_ACCESSVIOLATION;
377 case ERROR_SHARING_VIOLATION:
378 return VIF_SHARINGVIOLATION;
379 default:
380 return 0;
385 /******************************************************************************
386 * VerInstallFile32A [VERSION.7]
388 DWORD WINAPI VerInstallFile32A(
389 UINT32 flags,LPCSTR srcfilename,LPCSTR destfilename,LPCSTR srcdir,
390 LPCSTR destdir,LPCSTR curdir,LPSTR tmpfile,UINT32 *tmpfilelen )
392 LPCSTR pdest;
393 char destfn[260],tmpfn[260],srcfn[260];
394 HFILE32 hfsrc,hfdst;
395 DWORD attr,ret,xret,tmplast;
396 LPBYTE buf1,buf2;
397 OFSTRUCT ofs;
399 TRACE(ver,"(%x,%s,%s,%s,%s,%s,%p,%d)\n",
400 flags,srcfilename,destfilename,srcdir,destdir,curdir,tmpfile,*tmpfilelen
402 xret = 0;
403 sprintf(srcfn,"%s\\%s",srcdir,srcfilename);
404 if (!destdir || !*destdir) pdest = srcdir;
405 else pdest = destdir;
406 sprintf(destfn,"%s\\%s",pdest,destfilename);
407 hfsrc=LZOpenFile32A(srcfn,&ofs,OF_READ);
408 if (hfsrc==HFILE_ERROR32)
409 return VIF_CANNOTREADSRC;
410 sprintf(tmpfn,"%s\\%s",pdest,destfilename);
411 tmplast=strlen(pdest)+1;
412 attr = GetFileAttributes32A(tmpfn);
413 if (attr!=-1) {
414 if (attr & FILE_ATTRIBUTE_READONLY) {
415 LZClose32(hfsrc);
416 return VIF_WRITEPROT;
418 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
420 attr = -1;
421 if (flags & VIFF_FORCEINSTALL) {
422 if (tmpfile[0]) {
423 sprintf(tmpfn,"%s\\%s",pdest,tmpfile);
424 tmplast = strlen(pdest)+1;
425 attr = GetFileAttributes32A(tmpfn);
426 /* if it exists, it has been copied by the call before.
427 * we jump over the copy part...
431 if (attr == -1) {
432 char *s;
434 GetTempFileName32A(pdest,"ver",0,tmpfn); /* should not fail ... */
435 s=strrchr(tmpfn,'\\');
436 if (s)
437 tmplast = s-tmpfn;
438 else
439 tmplast = 0;
440 hfdst = OpenFile32(tmpfn,&ofs,OF_CREATE);
441 if (hfdst == HFILE_ERROR32) {
442 LZClose32(hfsrc);
443 return VIF_CANNOTCREATE; /* | translated dos error */
445 ret = LZCopy32(hfsrc,hfdst);
446 _lclose32(hfdst);
447 if (((long) ret) < 0) {
448 /* translate LZ errors into VIF_xxx */
449 switch (ret) {
450 case LZERROR_BADINHANDLE:
451 case LZERROR_READ:
452 case LZERROR_BADVALUE:
453 case LZERROR_UNKNOWNALG:
454 ret = VIF_CANNOTREADSRC;
455 break;
456 case LZERROR_BADOUTHANDLE:
457 case LZERROR_WRITE:
458 ret = VIF_OUTOFMEMORY; /* FIXME: correct? */
459 break;
460 case LZERROR_GLOBALLOC:
461 case LZERROR_GLOBLOCK:
462 ret = VIF_OUTOFSPACE;
463 break;
464 default: /* unknown error, should not happen */
465 ret = 0;
466 break;
468 if (ret) {
469 LZClose32(hfsrc);
470 return ret;
474 xret = 0;
475 if (!(flags & VIFF_FORCEINSTALL)) {
476 VS_FIXEDFILEINFO *destvffi,*tmpvffi;
477 buf1 = _fetch_versioninfo(destfn,&destvffi);
478 if (buf1) {
479 buf2 = _fetch_versioninfo(tmpfn,&tmpvffi);
480 if (buf2) {
481 char *tbuf1,*tbuf2;
482 UINT32 len1,len2;
484 len1=len2=40;
486 /* compare file versions */
487 if ((destvffi->dwFileVersionMS > tmpvffi->dwFileVersionMS)||
488 ((destvffi->dwFileVersionMS==tmpvffi->dwFileVersionMS)&&
489 (destvffi->dwFileVersionLS > tmpvffi->dwFileVersionLS)
492 xret |= VIF_MISMATCH|VIF_SRCOLD;
493 /* compare filetypes and filesubtypes */
494 if ((destvffi->dwFileType!=tmpvffi->dwFileType) ||
495 (destvffi->dwFileSubtype!=tmpvffi->dwFileSubtype)
497 xret |= VIF_MISMATCH|VIF_DIFFTYPE;
498 if (VerQueryValue32A(buf1,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf1,&len1) &&
499 VerQueryValue32A(buf2,"\\VarFileInfo\\Translation",(LPVOID*)&tbuf2,&len2)
501 /* irgendwas mit tbuf1 und tbuf2 machen
502 * generiert DIFFLANG|MISMATCH
505 free(buf2);
506 } else
507 xret=VIF_MISMATCH|VIF_SRCOLD;
508 free(buf1);
511 if (xret) {
512 if (*tmpfilelen<strlen(tmpfn+tmplast)) {
513 xret|=VIF_BUFFTOOSMALL;
514 DeleteFile32A(tmpfn);
515 } else {
516 strcpy(tmpfile,tmpfn+tmplast);
517 *tmpfilelen = strlen(tmpfn+tmplast)+1;
518 xret|=VIF_TEMPFILE;
520 } else {
521 if (-1!=GetFileAttributes32A(destfn))
522 if (!DeleteFile32A(destfn)) {
523 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETE;
524 DeleteFile32A(tmpfn);
525 LZClose32(hfsrc);
526 return xret;
528 if ((!(flags & VIFF_DONTDELETEOLD)) &&
529 curdir &&
530 *curdir &&
531 lstrcmpi32A(curdir,pdest)
533 char curfn[260];
535 sprintf(curfn,"%s\\%s",curdir,destfilename);
536 if (-1!=GetFileAttributes32A(curfn)) {
537 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
538 if (!DeleteFile32A(curfn))
539 xret|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR;
542 if (!MoveFile32A(tmpfn,destfn)) {
543 xret|=_error2vif(GetLastError())|VIF_CANNOTRENAME;
544 DeleteFile32A(tmpfn);
547 LZClose32(hfsrc);
548 return xret;
552 /* VerInstallFile32W [VERSION.8] */
553 DWORD WINAPI VerInstallFile32W(
554 UINT32 flags,LPCWSTR srcfilename,LPCWSTR destfilename,LPCWSTR srcdir,
555 LPCWSTR destdir,LPCWSTR curdir,LPWSTR tmpfile,UINT32 *tmpfilelen )
557 LPSTR wsrcf,wsrcd,wdestf,wdestd,wtmpf,wcurd;
558 DWORD ret;
560 wsrcf = HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename );
561 wsrcd = HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir );
562 wdestf = HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename );
563 wdestd = HEAP_strdupWtoA( GetProcessHeap(), 0, destdir );
564 wtmpf = HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile );
565 wcurd = HEAP_strdupWtoA( GetProcessHeap(), 0, curdir );
566 ret = VerInstallFile32A(flags,wsrcf,wdestf,wsrcd,wdestd,wcurd,wtmpf,tmpfilelen);
567 if (!ret)
568 lstrcpynAtoW(tmpfile,wtmpf,*tmpfilelen);
569 HeapFree( GetProcessHeap(), 0, wsrcf );
570 HeapFree( GetProcessHeap(), 0, wsrcd );
571 HeapFree( GetProcessHeap(), 0, wdestf );
572 HeapFree( GetProcessHeap(), 0, wdestd );
573 HeapFree( GetProcessHeap(), 0, wtmpf );
574 if (wcurd)
575 HeapFree( GetProcessHeap(), 0, wcurd );
576 return ret;