2 * Implementation of VERSION.DLL - File Installer routines
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
14 #include "wine/winestring.h"
18 #include "debugtools.h"
20 DEFAULT_DEBUG_CHANNEL(ver
);
23 /******************************************************************************
26 * char const * prologue,
27 * char const * teststring,
28 * char const * epilogue )
30 * This function will print via dprintf[_]ver to stddeb the prologue string,
31 * followed by the address of teststring and the string it contains if
32 * teststring is non-null or "(null)" otherwise, and then the epilogue
33 * string followed by a new line.
36 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
37 * Original implementation as dprintf[_]ver_string
38 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
39 * Fixed problem that caused bug with tools/make_debug -- renaming
40 * this function should fix the problem.
41 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
42 * Modified it to make it print the message using only one
45 *****************************************************************************/
47 static void ver_dstring(
48 char const * prologue
,
49 char const * teststring
,
50 char const * epilogue
)
52 TRACE("%s %p (\"%s\") %s\n", prologue
,
53 (void const *) teststring
,
54 teststring
? teststring
: "(null)",
58 /******************************************************************************
60 * int testFileExistence(
64 * Tests whether a given path/file combination exists. If the file does
65 * not exist, the return value is zero. If it does exist, the return
69 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
70 * Original implementation
72 *****************************************************************************/
74 static int testFileExistence(
83 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
85 strcpy(filename
, path
);
86 filenamelen
= strlen(filename
);
88 /* Add a trailing \ if necessary */
90 if(filename
[filenamelen
- 1] != '\\')
91 strcat(filename
, "\\");
93 else /* specify the current directory */
94 strcpy(filename
, ".\\");
96 /* Create the full pathname */
97 strcat(filename
, file
);
99 if(OpenFile(filename
, &fileinfo
, OF_EXIST
) == HFILE_ERROR
)
107 /******************************************************************************
109 * int testFileExclusiveExistence(
111 * char const * file )
113 * Tests whether a given path/file combination exists and ensures that no
114 * other programs have handles to the given file. If the file does not
115 * exist or is open, the return value is zero. If it does exist, the
116 * return value is non-zero.
119 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
120 * Original implementation
122 *****************************************************************************/
124 static int testFileExclusiveExistence(
133 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
135 strcpy(filename
, path
);
136 filenamelen
= strlen(filename
);
138 /* Add a trailing \ if necessary */
140 if(filename
[filenamelen
- 1] != '\\')
141 strcat(filename
, "\\");
143 else /* specify the current directory */
144 strcpy(filename
, ".\\");
146 /* Create the full pathname */
147 strcat(filename
, file
);
149 if(OpenFile(filename
, &fileinfo
, OF_EXIST
| OF_SHARE_EXCLUSIVE
) ==
158 /*****************************************************************************
160 * VerFindFileA() [VER.8]
161 * Determines where to install a file based on whether it locates another
162 * version of the file in the system. The values VerFindFile returns are
163 * used in a subsequent call to the VerInstallFile function.
166 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
167 * Reimplementation of VerFindFile from original stub.
169 ****************************************************************************/
171 /* VerFindFile32A [VERSION.5] */
172 DWORD WINAPI
VerFindFileA(
180 UINT
*lpuDestDirLen
)
185 unsigned int curDirSizeReq
;
186 unsigned int destDirSizeReq
;
190 /* Print out debugging information */
191 TRACE("called with parameters:\n"
192 "\tflags = %x", flags
);
193 if(flags
& VFFF_ISSHAREDFILE
)
194 TRACE(" (VFFF_ISSHAREDFILE)\n");
198 ver_dstring("\tlpszFilename = ", lpszFilename
, "");
199 ver_dstring("\tlpszWinDir = ", lpszWinDir
, "");
200 ver_dstring("\tlpszAppDir = ", lpszAppDir
, "");
202 TRACE("\tlpszCurDir = %p\n", lpszCurDir
);
204 TRACE("\tlpuCurDirLen = %p (%u)\n",
205 lpuCurDirLen
, *lpuCurDirLen
);
207 TRACE("\tlpuCurDirLen = (null)\n");
209 TRACE("\tlpszDestDir = %p\n", lpszDestDir
);
211 TRACE("\tlpuDestDirLen = %p (%u)\n",
212 lpuDestDirLen
, *lpuDestDirLen
);
214 /* Figure out where the file should go; shared files default to the
220 if(flags
& VFFF_ISSHAREDFILE
) {
221 GetSystemDirectoryA(destDir
, 256);
223 /* Were we given a filename? If so, try to find the file. */
225 if(testFileExistence(destDir
, lpszFilename
)) {
226 strcpy(curDir
, destDir
);
228 if(!testFileExclusiveExistence(destDir
, lpszFilename
))
229 retval
|= VFF_FILEINUSE
;
231 else if(lpszAppDir
&& testFileExistence(lpszAppDir
,
233 strcpy(curDir
, lpszAppDir
);
234 retval
|= VFF_CURNEDEST
;
236 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
237 retval
|= VFF_FILEINUSE
;
241 else if(!(flags
& VFFF_ISSHAREDFILE
)) { /* not a shared file */
244 GetSystemDirectoryA(systemDir
, 256);
246 strcpy(destDir
, lpszAppDir
);
249 if(testFileExistence(lpszAppDir
, lpszFilename
)) {
250 strcpy(curDir
, lpszAppDir
);
252 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
253 retval
|= VFF_FILEINUSE
;
255 else if(testFileExistence(systemDir
, lpszFilename
)) {
256 strcpy(curDir
, systemDir
);
257 retval
|= VFF_CURNEDEST
;
259 if(!testFileExclusiveExistence(systemDir
, lpszFilename
))
260 retval
|= VFF_FILEINUSE
;
266 curDirSizeReq
= strlen(curDir
) + 1;
267 destDirSizeReq
= strlen(destDir
) + 1;
271 /* Make sure that the pointers to the size of the buffers are
272 valid; if not, do NOTHING with that buffer. If that pointer
273 is valid, then make sure that the buffer pointer is valid, too! */
275 if(lpuDestDirLen
&& lpszDestDir
) {
276 if(*lpuDestDirLen
< destDirSizeReq
) {
277 retval
|= VFF_BUFFTOOSMALL
;
278 if (*lpuDestDirLen
) {
279 lstrcpynA(lpszDestDir
, destDir
, *lpuDestDirLen
);
283 strcpy(lpszDestDir
, destDir
);
285 *lpuDestDirLen
= destDirSizeReq
;
288 if(lpuCurDirLen
&& lpszCurDir
) {
289 if(*lpuCurDirLen
< curDirSizeReq
) {
290 retval
|= VFF_BUFFTOOSMALL
;
292 lstrcpynA(lpszCurDir
, curDir
, *lpuCurDirLen
);
296 strcpy(lpszCurDir
, curDir
);
298 *lpuCurDirLen
= curDirSizeReq
;
301 TRACE("ret = %lu (%s%s%s)\n", retval
,
302 (retval
& VFF_CURNEDEST
) ? "VFF_CURNEDEST " : "",
303 (retval
& VFF_FILEINUSE
) ? "VFF_FILEINUSE " : "",
304 (retval
& VFF_BUFFTOOSMALL
) ? "VFF_BUFFTOOSMALL " : "");
306 ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir
, "");
308 TRACE("\t(Exit) lpuCurDirLen = %p (%u)\n",
309 lpuCurDirLen
, *lpuCurDirLen
);
311 TRACE("\t(Exit) lpuCurDirLen = (null)\n");
313 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir
, "");
315 TRACE("\t(Exit) lpuDestDirLen = %p (%u)\n",
316 lpuDestDirLen
, *lpuDestDirLen
);
321 /*****************************************************************************
322 * VerFindFileW [VERSION.6]
324 DWORD WINAPI
VerFindFileW(
325 UINT flags
,LPCWSTR filename
,LPCWSTR windir
,LPCWSTR appdir
,
326 LPWSTR curdir
,UINT
*pcurdirlen
,LPWSTR destdir
,UINT
*pdestdirlen
)
328 UINT curdirlen
, destdirlen
;
329 LPSTR wfn
,wwd
,wad
,wdd
,wcd
;
332 wfn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
333 wwd
= HEAP_strdupWtoA( GetProcessHeap(), 0, windir
);
334 wad
= HEAP_strdupWtoA( GetProcessHeap(), 0, appdir
);
335 wcd
= HeapAlloc( GetProcessHeap(), 0, *pcurdirlen
);
336 wdd
= HeapAlloc( GetProcessHeap(), 0, *pdestdirlen
);
337 ret
= VerFindFileA(flags
,wfn
,wwd
,wad
,wcd
,&curdirlen
,wdd
,&destdirlen
);
338 lstrcpynAtoW(curdir
,wcd
,*pcurdirlen
);
339 lstrcpynAtoW(destdir
,wdd
,*pdestdirlen
);
340 *pcurdirlen
= strlen(wcd
);
341 *pdestdirlen
= strlen(wdd
);
342 HeapFree( GetProcessHeap(), 0, wfn
);
343 HeapFree( GetProcessHeap(), 0, wwd
);
344 HeapFree( GetProcessHeap(), 0, wad
);
345 HeapFree( GetProcessHeap(), 0, wcd
);
346 HeapFree( GetProcessHeap(), 0, wdd
);
351 _fetch_versioninfo(LPSTR fn
,VS_FIXEDFILEINFO
**vffi
) {
357 buf
=HeapAlloc(GetProcessHeap(), 0, alloclen
);
359 WARN("Memory exausted while fetching version info!");
363 ret
= GetFileVersionInfoA(fn
,0,alloclen
,buf
);
365 HeapFree(GetProcessHeap(), 0, buf
);
368 if (alloclen
<*(WORD
*)buf
) {
369 alloclen
= *(WORD
*)buf
;
370 HeapFree(GetProcessHeap(), 0, buf
);
371 buf
= HeapAlloc(GetProcessHeap(), 0, alloclen
);
373 WARN("Memory exausted while fetching version info!");
377 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x14);
378 if ((*vffi
)->dwSignature
== 0x004f0049) /* hack to detect unicode */
379 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x28);
380 if ((*vffi
)->dwSignature
!= VS_FFI_SIGNATURE
)
381 WARN("Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi
)->dwSignature
);
388 _error2vif(DWORD error
) {
390 case ERROR_ACCESS_DENIED
:
391 return VIF_ACCESSVIOLATION
;
392 case ERROR_SHARING_VIOLATION
:
393 return VIF_SHARINGVIOLATION
;
400 /******************************************************************************
401 * VerInstallFileA [VERSION.7]
403 DWORD WINAPI
VerInstallFileA(
404 UINT flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
405 LPCSTR destdir
,LPCSTR curdir
,LPSTR tmpfile
,UINT
*tmpfilelen
)
408 char destfn
[260],tmpfn
[260],srcfn
[260];
410 DWORD attr
,ret
,xret
,tmplast
;
414 TRACE("(%x,%s,%s,%s,%s,%s,%p,%d)\n",
415 flags
,srcfilename
,destfilename
,srcdir
,destdir
,curdir
,tmpfile
,*tmpfilelen
418 sprintf(srcfn
,"%s\\%s",srcdir
,srcfilename
);
419 if (!destdir
|| !*destdir
) pdest
= srcdir
;
420 else pdest
= destdir
;
421 sprintf(destfn
,"%s\\%s",pdest
,destfilename
);
422 hfsrc
=LZOpenFileA(srcfn
,&ofs
,OF_READ
);
423 if (hfsrc
==HFILE_ERROR
)
424 return VIF_CANNOTREADSRC
;
425 sprintf(tmpfn
,"%s\\%s",pdest
,destfilename
);
426 tmplast
=strlen(pdest
)+1;
427 attr
= GetFileAttributesA(tmpfn
);
429 if (attr
& FILE_ATTRIBUTE_READONLY
) {
431 return VIF_WRITEPROT
;
433 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
436 if (flags
& VIFF_FORCEINSTALL
) {
438 sprintf(tmpfn
,"%s\\%s",pdest
,tmpfile
);
439 tmplast
= strlen(pdest
)+1;
440 attr
= GetFileAttributesA(tmpfn
);
441 /* if it exists, it has been copied by the call before.
442 * we jump over the copy part...
449 GetTempFileNameA(pdest
,"ver",0,tmpfn
); /* should not fail ... */
450 s
=strrchr(tmpfn
,'\\');
455 hfdst
= OpenFile(tmpfn
,&ofs
,OF_CREATE
);
456 if (hfdst
== HFILE_ERROR
) {
458 return VIF_CANNOTCREATE
; /* | translated dos error */
460 ret
= LZCopy(hfsrc
,hfdst
);
462 if (((long) ret
) < 0) {
463 /* translate LZ errors into VIF_xxx */
465 case LZERROR_BADINHANDLE
:
467 case LZERROR_BADVALUE
:
468 case LZERROR_UNKNOWNALG
:
469 ret
= VIF_CANNOTREADSRC
;
471 case LZERROR_BADOUTHANDLE
:
473 ret
= VIF_OUTOFMEMORY
; /* FIXME: correct? */
475 case LZERROR_GLOBALLOC
:
476 case LZERROR_GLOBLOCK
:
477 ret
= VIF_OUTOFSPACE
;
479 default: /* unknown error, should not happen */
490 if (!(flags
& VIFF_FORCEINSTALL
)) {
491 VS_FIXEDFILEINFO
*destvffi
,*tmpvffi
;
492 buf1
= _fetch_versioninfo(destfn
,&destvffi
);
494 buf2
= _fetch_versioninfo(tmpfn
,&tmpvffi
);
501 /* compare file versions */
502 if ((destvffi
->dwFileVersionMS
> tmpvffi
->dwFileVersionMS
)||
503 ((destvffi
->dwFileVersionMS
==tmpvffi
->dwFileVersionMS
)&&
504 (destvffi
->dwFileVersionLS
> tmpvffi
->dwFileVersionLS
)
507 xret
|= VIF_MISMATCH
|VIF_SRCOLD
;
508 /* compare filetypes and filesubtypes */
509 if ((destvffi
->dwFileType
!=tmpvffi
->dwFileType
) ||
510 (destvffi
->dwFileSubtype
!=tmpvffi
->dwFileSubtype
)
512 xret
|= VIF_MISMATCH
|VIF_DIFFTYPE
;
513 if (VerQueryValueA(buf1
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf1
,&len1
) &&
514 VerQueryValueA(buf2
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf2
,&len2
)
516 /* irgendwas mit tbuf1 und tbuf2 machen
517 * generiert DIFFLANG|MISMATCH
520 HeapFree(GetProcessHeap(), 0, buf2
);
522 xret
=VIF_MISMATCH
|VIF_SRCOLD
;
523 HeapFree(GetProcessHeap(), 0, buf1
);
527 if (*tmpfilelen
<strlen(tmpfn
+tmplast
)) {
528 xret
|=VIF_BUFFTOOSMALL
;
531 strcpy(tmpfile
,tmpfn
+tmplast
);
532 *tmpfilelen
= strlen(tmpfn
+tmplast
)+1;
536 if (-1!=GetFileAttributesA(destfn
))
537 if (!DeleteFileA(destfn
)) {
538 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETE
;
543 if ((!(flags
& VIFF_DONTDELETEOLD
)) &&
546 lstrcmpiA(curdir
,pdest
)
550 sprintf(curfn
,"%s\\%s",curdir
,destfilename
);
551 if (-1!=GetFileAttributesA(curfn
)) {
552 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
553 if (!DeleteFileA(curfn
))
554 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR
;
557 if (!MoveFileA(tmpfn
,destfn
)) {
558 xret
|=_error2vif(GetLastError())|VIF_CANNOTRENAME
;
567 /******************************************************************************
568 * VerInstallFileW [VERSION.8]
570 DWORD WINAPI
VerInstallFileW(
571 UINT flags
,LPCWSTR srcfilename
,LPCWSTR destfilename
,LPCWSTR srcdir
,
572 LPCWSTR destdir
,LPCWSTR curdir
,LPWSTR tmpfile
,UINT
*tmpfilelen
)
574 LPSTR wsrcf
,wsrcd
,wdestf
,wdestd
,wtmpf
,wcurd
;
577 wsrcf
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename
);
578 wsrcd
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir
);
579 wdestf
= HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename
);
580 wdestd
= HEAP_strdupWtoA( GetProcessHeap(), 0, destdir
);
581 wtmpf
= HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile
);
582 wcurd
= HEAP_strdupWtoA( GetProcessHeap(), 0, curdir
);
583 ret
= VerInstallFileA(flags
,wsrcf
,wdestf
,wsrcd
,wdestd
,wcurd
,wtmpf
,tmpfilelen
);
585 lstrcpynAtoW(tmpfile
,wtmpf
,*tmpfilelen
);
586 HeapFree( GetProcessHeap(), 0, wsrcf
);
587 HeapFree( GetProcessHeap(), 0, wsrcd
);
588 HeapFree( GetProcessHeap(), 0, wdestf
);
589 HeapFree( GetProcessHeap(), 0, wdestd
);
590 HeapFree( GetProcessHeap(), 0, wtmpf
);
592 HeapFree( GetProcessHeap(), 0, wcurd
);