2 * Implementation of VERSION.DLL - File Installer routines
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
13 #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 * VerFindFile() [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 /* VerFindFile32W [VERSION.6] */
322 DWORD WINAPI
VerFindFileW(
323 UINT flags
,LPCWSTR filename
,LPCWSTR windir
,LPCWSTR appdir
,
324 LPWSTR curdir
,UINT
*pcurdirlen
,LPWSTR destdir
,UINT
*pdestdirlen
)
326 UINT curdirlen
, destdirlen
;
327 LPSTR wfn
,wwd
,wad
,wdd
,wcd
;
330 wfn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
331 wwd
= HEAP_strdupWtoA( GetProcessHeap(), 0, windir
);
332 wad
= HEAP_strdupWtoA( GetProcessHeap(), 0, appdir
);
333 wcd
= HeapAlloc( GetProcessHeap(), 0, *pcurdirlen
);
334 wdd
= HeapAlloc( GetProcessHeap(), 0, *pdestdirlen
);
335 ret
= VerFindFileA(flags
,wfn
,wwd
,wad
,wcd
,&curdirlen
,wdd
,&destdirlen
);
336 lstrcpynAtoW(curdir
,wcd
,*pcurdirlen
);
337 lstrcpynAtoW(destdir
,wdd
,*pdestdirlen
);
338 *pcurdirlen
= strlen(wcd
);
339 *pdestdirlen
= strlen(wdd
);
340 HeapFree( GetProcessHeap(), 0, wfn
);
341 HeapFree( GetProcessHeap(), 0, wwd
);
342 HeapFree( GetProcessHeap(), 0, wad
);
343 HeapFree( GetProcessHeap(), 0, wcd
);
344 HeapFree( GetProcessHeap(), 0, wdd
);
349 _fetch_versioninfo(LPSTR fn
,VS_FIXEDFILEINFO
**vffi
) {
355 buf
= xmalloc(alloclen
);
357 ret
= GetFileVersionInfoA(fn
,0,alloclen
,buf
);
362 if (alloclen
<*(WORD
*)buf
) {
364 alloclen
= *(WORD
*)buf
;
365 buf
= xmalloc(alloclen
);
367 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x14);
368 if ((*vffi
)->dwSignature
== 0x004f0049) /* hack to detect unicode */
369 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x28);
370 if ((*vffi
)->dwSignature
!= VS_FFI_SIGNATURE
)
371 WARN("Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi
)->dwSignature
);
378 _error2vif(DWORD error
) {
380 case ERROR_ACCESS_DENIED
:
381 return VIF_ACCESSVIOLATION
;
382 case ERROR_SHARING_VIOLATION
:
383 return VIF_SHARINGVIOLATION
;
390 /******************************************************************************
391 * VerInstallFile32A [VERSION.7]
393 DWORD WINAPI
VerInstallFileA(
394 UINT flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
395 LPCSTR destdir
,LPCSTR curdir
,LPSTR tmpfile
,UINT
*tmpfilelen
)
398 char destfn
[260],tmpfn
[260],srcfn
[260];
400 DWORD attr
,ret
,xret
,tmplast
;
404 TRACE("(%x,%s,%s,%s,%s,%s,%p,%d)\n",
405 flags
,srcfilename
,destfilename
,srcdir
,destdir
,curdir
,tmpfile
,*tmpfilelen
408 sprintf(srcfn
,"%s\\%s",srcdir
,srcfilename
);
409 if (!destdir
|| !*destdir
) pdest
= srcdir
;
410 else pdest
= destdir
;
411 sprintf(destfn
,"%s\\%s",pdest
,destfilename
);
412 hfsrc
=LZOpenFileA(srcfn
,&ofs
,OF_READ
);
413 if (hfsrc
==HFILE_ERROR
)
414 return VIF_CANNOTREADSRC
;
415 sprintf(tmpfn
,"%s\\%s",pdest
,destfilename
);
416 tmplast
=strlen(pdest
)+1;
417 attr
= GetFileAttributesA(tmpfn
);
419 if (attr
& FILE_ATTRIBUTE_READONLY
) {
421 return VIF_WRITEPROT
;
423 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
426 if (flags
& VIFF_FORCEINSTALL
) {
428 sprintf(tmpfn
,"%s\\%s",pdest
,tmpfile
);
429 tmplast
= strlen(pdest
)+1;
430 attr
= GetFileAttributesA(tmpfn
);
431 /* if it exists, it has been copied by the call before.
432 * we jump over the copy part...
439 GetTempFileNameA(pdest
,"ver",0,tmpfn
); /* should not fail ... */
440 s
=strrchr(tmpfn
,'\\');
445 hfdst
= OpenFile(tmpfn
,&ofs
,OF_CREATE
);
446 if (hfdst
== HFILE_ERROR
) {
448 return VIF_CANNOTCREATE
; /* | translated dos error */
450 ret
= LZCopy(hfsrc
,hfdst
);
452 if (((long) ret
) < 0) {
453 /* translate LZ errors into VIF_xxx */
455 case LZERROR_BADINHANDLE
:
457 case LZERROR_BADVALUE
:
458 case LZERROR_UNKNOWNALG
:
459 ret
= VIF_CANNOTREADSRC
;
461 case LZERROR_BADOUTHANDLE
:
463 ret
= VIF_OUTOFMEMORY
; /* FIXME: correct? */
465 case LZERROR_GLOBALLOC
:
466 case LZERROR_GLOBLOCK
:
467 ret
= VIF_OUTOFSPACE
;
469 default: /* unknown error, should not happen */
480 if (!(flags
& VIFF_FORCEINSTALL
)) {
481 VS_FIXEDFILEINFO
*destvffi
,*tmpvffi
;
482 buf1
= _fetch_versioninfo(destfn
,&destvffi
);
484 buf2
= _fetch_versioninfo(tmpfn
,&tmpvffi
);
491 /* compare file versions */
492 if ((destvffi
->dwFileVersionMS
> tmpvffi
->dwFileVersionMS
)||
493 ((destvffi
->dwFileVersionMS
==tmpvffi
->dwFileVersionMS
)&&
494 (destvffi
->dwFileVersionLS
> tmpvffi
->dwFileVersionLS
)
497 xret
|= VIF_MISMATCH
|VIF_SRCOLD
;
498 /* compare filetypes and filesubtypes */
499 if ((destvffi
->dwFileType
!=tmpvffi
->dwFileType
) ||
500 (destvffi
->dwFileSubtype
!=tmpvffi
->dwFileSubtype
)
502 xret
|= VIF_MISMATCH
|VIF_DIFFTYPE
;
503 if (VerQueryValueA(buf1
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf1
,&len1
) &&
504 VerQueryValueA(buf2
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf2
,&len2
)
506 /* irgendwas mit tbuf1 und tbuf2 machen
507 * generiert DIFFLANG|MISMATCH
512 xret
=VIF_MISMATCH
|VIF_SRCOLD
;
517 if (*tmpfilelen
<strlen(tmpfn
+tmplast
)) {
518 xret
|=VIF_BUFFTOOSMALL
;
521 strcpy(tmpfile
,tmpfn
+tmplast
);
522 *tmpfilelen
= strlen(tmpfn
+tmplast
)+1;
526 if (-1!=GetFileAttributesA(destfn
))
527 if (!DeleteFileA(destfn
)) {
528 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETE
;
533 if ((!(flags
& VIFF_DONTDELETEOLD
)) &&
536 lstrcmpiA(curdir
,pdest
)
540 sprintf(curfn
,"%s\\%s",curdir
,destfilename
);
541 if (-1!=GetFileAttributesA(curfn
)) {
542 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
543 if (!DeleteFileA(curfn
))
544 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR
;
547 if (!MoveFileA(tmpfn
,destfn
)) {
548 xret
|=_error2vif(GetLastError())|VIF_CANNOTRENAME
;
557 /* VerInstallFile32W [VERSION.8] */
558 DWORD WINAPI
VerInstallFileW(
559 UINT flags
,LPCWSTR srcfilename
,LPCWSTR destfilename
,LPCWSTR srcdir
,
560 LPCWSTR destdir
,LPCWSTR curdir
,LPWSTR tmpfile
,UINT
*tmpfilelen
)
562 LPSTR wsrcf
,wsrcd
,wdestf
,wdestd
,wtmpf
,wcurd
;
565 wsrcf
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename
);
566 wsrcd
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir
);
567 wdestf
= HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename
);
568 wdestd
= HEAP_strdupWtoA( GetProcessHeap(), 0, destdir
);
569 wtmpf
= HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile
);
570 wcurd
= HEAP_strdupWtoA( GetProcessHeap(), 0, curdir
);
571 ret
= VerInstallFileA(flags
,wsrcf
,wdestf
,wsrcd
,wdestd
,wcurd
,wtmpf
,tmpfilelen
);
573 lstrcpynAtoW(tmpfile
,wtmpf
,*tmpfilelen
);
574 HeapFree( GetProcessHeap(), 0, wsrcf
);
575 HeapFree( GetProcessHeap(), 0, wsrcd
);
576 HeapFree( GetProcessHeap(), 0, wdestf
);
577 HeapFree( GetProcessHeap(), 0, wdestd
);
578 HeapFree( GetProcessHeap(), 0, wtmpf
);
580 HeapFree( GetProcessHeap(), 0, wcurd
);