2 * Implementation of VERSION.DLL - File Installer routines
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
13 #include "wine/winestring.h"
19 #include "debugtools.h"
21 DEFAULT_DEBUG_CHANNEL(ver
)
24 /******************************************************************************
27 * char const * prologue,
28 * char const * teststring,
29 * char const * epilogue )
31 * This function will print via dprintf[_]ver to stddeb the prologue string,
32 * followed by the address of teststring and the string it contains if
33 * teststring is non-null or "(null)" otherwise, and then the epilogue
34 * string followed by a new line.
37 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
38 * Original implementation as dprintf[_]ver_string
39 * 05-Jul-1997 Dave Cuthbert (dacut@ece.cmu.edu)
40 * Fixed problem that caused bug with tools/make_debug -- renaming
41 * this function should fix the problem.
42 * 15-Feb-1998 Dimitrie Paun (dimi@cs.toronto.edu)
43 * Modified it to make it print the message using only one
46 *****************************************************************************/
48 static void ver_dstring(
49 char const * prologue
,
50 char const * teststring
,
51 char const * epilogue
)
53 TRACE("%s %p (\"%s\") %s\n", prologue
,
54 (void const *) teststring
,
55 teststring
? teststring
: "(null)",
59 /******************************************************************************
61 * int testFileExistence(
65 * Tests whether a given path/file combination exists. If the file does
66 * not exist, the return value is zero. If it does exist, the return
70 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
71 * Original implementation
73 *****************************************************************************/
75 static int testFileExistence(
84 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
86 strcpy(filename
, path
);
87 filenamelen
= strlen(filename
);
89 /* Add a trailing \ if necessary */
91 if(filename
[filenamelen
- 1] != '\\')
92 strcat(filename
, "\\");
94 else /* specify the current directory */
95 strcpy(filename
, ".\\");
97 /* Create the full pathname */
98 strcat(filename
, file
);
100 if(OpenFile(filename
, &fileinfo
, OF_EXIST
) == HFILE_ERROR
)
108 /******************************************************************************
110 * int testFileExclusiveExistence(
112 * char const * file )
114 * Tests whether a given path/file combination exists and ensures that no
115 * other programs have handles to the given file. If the file does not
116 * exist or is open, the return value is zero. If it does exist, the
117 * return value is non-zero.
120 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
121 * Original implementation
123 *****************************************************************************/
125 static int testFileExclusiveExistence(
134 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
136 strcpy(filename
, path
);
137 filenamelen
= strlen(filename
);
139 /* Add a trailing \ if necessary */
141 if(filename
[filenamelen
- 1] != '\\')
142 strcat(filename
, "\\");
144 else /* specify the current directory */
145 strcpy(filename
, ".\\");
147 /* Create the full pathname */
148 strcat(filename
, file
);
150 if(OpenFile(filename
, &fileinfo
, OF_EXIST
| OF_SHARE_EXCLUSIVE
) ==
159 /*****************************************************************************
161 * VerFindFile() [VER.8]
162 * Determines where to install a file based on whether it locates another
163 * version of the file in the system. The values VerFindFile returns are
164 * used in a subsequent call to the VerInstallFile function.
167 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
168 * Reimplementation of VerFindFile from original stub.
170 ****************************************************************************/
172 /* VerFindFile32A [VERSION.5] */
173 DWORD WINAPI
VerFindFileA(
181 UINT
*lpuDestDirLen
)
186 unsigned int curDirSizeReq
;
187 unsigned int destDirSizeReq
;
191 /* Print out debugging information */
192 TRACE("called with parameters:\n"
193 "\tflags = %x", flags
);
194 if(flags
& VFFF_ISSHAREDFILE
)
195 TRACE(" (VFFF_ISSHAREDFILE)\n");
199 ver_dstring("\tlpszFilename = ", lpszFilename
, "");
200 ver_dstring("\tlpszWinDir = ", lpszWinDir
, "");
201 ver_dstring("\tlpszAppDir = ", lpszAppDir
, "");
203 TRACE("\tlpszCurDir = %p\n", lpszCurDir
);
205 TRACE("\tlpuCurDirLen = %p (%u)\n",
206 lpuCurDirLen
, *lpuCurDirLen
);
208 TRACE("\tlpuCurDirLen = (null)\n");
210 TRACE("\tlpszDestDir = %p\n", lpszDestDir
);
212 TRACE("\tlpuDestDirLen = %p (%u)\n",
213 lpuDestDirLen
, *lpuDestDirLen
);
215 /* Figure out where the file should go; shared files default to the
221 if(flags
& VFFF_ISSHAREDFILE
) {
222 GetSystemDirectoryA(destDir
, 256);
224 /* Were we given a filename? If so, try to find the file. */
226 if(testFileExistence(destDir
, lpszFilename
)) {
227 strcpy(curDir
, destDir
);
229 if(!testFileExclusiveExistence(destDir
, lpszFilename
))
230 retval
|= VFF_FILEINUSE
;
232 else if(lpszAppDir
&& testFileExistence(lpszAppDir
,
234 strcpy(curDir
, lpszAppDir
);
235 retval
|= VFF_CURNEDEST
;
237 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
238 retval
|= VFF_FILEINUSE
;
242 else if(!(flags
& VFFF_ISSHAREDFILE
)) { /* not a shared file */
245 GetSystemDirectoryA(systemDir
, 256);
247 strcpy(destDir
, lpszAppDir
);
250 if(testFileExistence(lpszAppDir
, lpszFilename
)) {
251 strcpy(curDir
, lpszAppDir
);
253 if(!testFileExclusiveExistence(lpszAppDir
, lpszFilename
))
254 retval
|= VFF_FILEINUSE
;
256 else if(testFileExistence(systemDir
, lpszFilename
)) {
257 strcpy(curDir
, systemDir
);
258 retval
|= VFF_CURNEDEST
;
260 if(!testFileExclusiveExistence(systemDir
, lpszFilename
))
261 retval
|= VFF_FILEINUSE
;
267 curDirSizeReq
= strlen(curDir
) + 1;
268 destDirSizeReq
= strlen(destDir
) + 1;
272 /* Make sure that the pointers to the size of the buffers are
273 valid; if not, do NOTHING with that buffer. If that pointer
274 is valid, then make sure that the buffer pointer is valid, too! */
276 if(lpuDestDirLen
&& lpszDestDir
) {
277 if(*lpuDestDirLen
< destDirSizeReq
) {
278 retval
|= VFF_BUFFTOOSMALL
;
279 if (*lpuDestDirLen
) {
280 strncpy(lpszDestDir
, destDir
, *lpuDestDirLen
- 1);
281 lpszDestDir
[*lpuDestDirLen
- 1] = '\0';
285 strcpy(lpszDestDir
, destDir
);
287 *lpuDestDirLen
= destDirSizeReq
;
290 if(lpuCurDirLen
&& lpszCurDir
) {
291 if(*lpuCurDirLen
< curDirSizeReq
) {
292 retval
|= VFF_BUFFTOOSMALL
;
294 strncpy(lpszCurDir
, curDir
, *lpuCurDirLen
- 1);
295 lpszCurDir
[*lpuCurDirLen
- 1] = '\0';
299 strcpy(lpszCurDir
, curDir
);
301 *lpuCurDirLen
= curDirSizeReq
;
304 TRACE("ret = %lu (%s%s%s)\n", retval
,
305 (retval
& VFF_CURNEDEST
) ? "VFF_CURNEDEST " : "",
306 (retval
& VFF_FILEINUSE
) ? "VFF_FILEINUSE " : "",
307 (retval
& VFF_BUFFTOOSMALL
) ? "VFF_BUFFTOOSMALL " : "");
309 ver_dstring("\t(Exit) lpszCurDir = ", lpszCurDir
, "");
311 TRACE("\t(Exit) lpuCurDirLen = %p (%u)\n",
312 lpuCurDirLen
, *lpuCurDirLen
);
314 TRACE("\t(Exit) lpuCurDirLen = (null)\n");
316 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir
, "");
318 TRACE("\t(Exit) lpuDestDirLen = %p (%u)\n",
319 lpuDestDirLen
, *lpuDestDirLen
);
324 /* VerFindFile32W [VERSION.6] */
325 DWORD WINAPI
VerFindFileW(
326 UINT flags
,LPCWSTR filename
,LPCWSTR windir
,LPCWSTR appdir
,
327 LPWSTR curdir
,UINT
*pcurdirlen
,LPWSTR destdir
,UINT
*pdestdirlen
)
329 UINT curdirlen
, destdirlen
;
330 LPSTR wfn
,wwd
,wad
,wdd
,wcd
;
333 wfn
= HEAP_strdupWtoA( GetProcessHeap(), 0, filename
);
334 wwd
= HEAP_strdupWtoA( GetProcessHeap(), 0, windir
);
335 wad
= HEAP_strdupWtoA( GetProcessHeap(), 0, appdir
);
336 wcd
= HeapAlloc( GetProcessHeap(), 0, *pcurdirlen
);
337 wdd
= HeapAlloc( GetProcessHeap(), 0, *pdestdirlen
);
338 ret
= VerFindFileA(flags
,wfn
,wwd
,wad
,wcd
,&curdirlen
,wdd
,&destdirlen
);
339 lstrcpynAtoW(curdir
,wcd
,*pcurdirlen
);
340 lstrcpynAtoW(destdir
,wdd
,*pdestdirlen
);
341 *pcurdirlen
= strlen(wcd
);
342 *pdestdirlen
= strlen(wdd
);
343 HeapFree( GetProcessHeap(), 0, wfn
);
344 HeapFree( GetProcessHeap(), 0, wwd
);
345 HeapFree( GetProcessHeap(), 0, wad
);
346 HeapFree( GetProcessHeap(), 0, wcd
);
347 HeapFree( GetProcessHeap(), 0, wdd
);
352 _fetch_versioninfo(LPSTR fn
,VS_FIXEDFILEINFO
**vffi
) {
358 buf
= xmalloc(alloclen
);
360 ret
= GetFileVersionInfoA(fn
,0,alloclen
,buf
);
365 if (alloclen
<*(WORD
*)buf
) {
367 alloclen
= *(WORD
*)buf
;
368 buf
= xmalloc(alloclen
);
370 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x14);
371 if ((*vffi
)->dwSignature
== 0x004f0049) /* hack to detect unicode */
372 *vffi
= (VS_FIXEDFILEINFO
*)(buf
+0x28);
373 if ((*vffi
)->dwSignature
!= VS_FFI_SIGNATURE
)
374 WARN("Bad VS_FIXEDFILEINFO signature 0x%08lx\n",(*vffi
)->dwSignature
);
381 _error2vif(DWORD error
) {
383 case ERROR_ACCESS_DENIED
:
384 return VIF_ACCESSVIOLATION
;
385 case ERROR_SHARING_VIOLATION
:
386 return VIF_SHARINGVIOLATION
;
393 /******************************************************************************
394 * VerInstallFile32A [VERSION.7]
396 DWORD WINAPI
VerInstallFileA(
397 UINT flags
,LPCSTR srcfilename
,LPCSTR destfilename
,LPCSTR srcdir
,
398 LPCSTR destdir
,LPCSTR curdir
,LPSTR tmpfile
,UINT
*tmpfilelen
)
401 char destfn
[260],tmpfn
[260],srcfn
[260];
403 DWORD attr
,ret
,xret
,tmplast
;
407 TRACE("(%x,%s,%s,%s,%s,%s,%p,%d)\n",
408 flags
,srcfilename
,destfilename
,srcdir
,destdir
,curdir
,tmpfile
,*tmpfilelen
411 sprintf(srcfn
,"%s\\%s",srcdir
,srcfilename
);
412 if (!destdir
|| !*destdir
) pdest
= srcdir
;
413 else pdest
= destdir
;
414 sprintf(destfn
,"%s\\%s",pdest
,destfilename
);
415 hfsrc
=LZOpenFileA(srcfn
,&ofs
,OF_READ
);
416 if (hfsrc
==HFILE_ERROR
)
417 return VIF_CANNOTREADSRC
;
418 sprintf(tmpfn
,"%s\\%s",pdest
,destfilename
);
419 tmplast
=strlen(pdest
)+1;
420 attr
= GetFileAttributesA(tmpfn
);
422 if (attr
& FILE_ATTRIBUTE_READONLY
) {
424 return VIF_WRITEPROT
;
426 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
429 if (flags
& VIFF_FORCEINSTALL
) {
431 sprintf(tmpfn
,"%s\\%s",pdest
,tmpfile
);
432 tmplast
= strlen(pdest
)+1;
433 attr
= GetFileAttributesA(tmpfn
);
434 /* if it exists, it has been copied by the call before.
435 * we jump over the copy part...
442 GetTempFileNameA(pdest
,"ver",0,tmpfn
); /* should not fail ... */
443 s
=strrchr(tmpfn
,'\\');
448 hfdst
= OpenFile(tmpfn
,&ofs
,OF_CREATE
);
449 if (hfdst
== HFILE_ERROR
) {
451 return VIF_CANNOTCREATE
; /* | translated dos error */
453 ret
= LZCopy(hfsrc
,hfdst
);
455 if (((long) ret
) < 0) {
456 /* translate LZ errors into VIF_xxx */
458 case LZERROR_BADINHANDLE
:
460 case LZERROR_BADVALUE
:
461 case LZERROR_UNKNOWNALG
:
462 ret
= VIF_CANNOTREADSRC
;
464 case LZERROR_BADOUTHANDLE
:
466 ret
= VIF_OUTOFMEMORY
; /* FIXME: correct? */
468 case LZERROR_GLOBALLOC
:
469 case LZERROR_GLOBLOCK
:
470 ret
= VIF_OUTOFSPACE
;
472 default: /* unknown error, should not happen */
483 if (!(flags
& VIFF_FORCEINSTALL
)) {
484 VS_FIXEDFILEINFO
*destvffi
,*tmpvffi
;
485 buf1
= _fetch_versioninfo(destfn
,&destvffi
);
487 buf2
= _fetch_versioninfo(tmpfn
,&tmpvffi
);
494 /* compare file versions */
495 if ((destvffi
->dwFileVersionMS
> tmpvffi
->dwFileVersionMS
)||
496 ((destvffi
->dwFileVersionMS
==tmpvffi
->dwFileVersionMS
)&&
497 (destvffi
->dwFileVersionLS
> tmpvffi
->dwFileVersionLS
)
500 xret
|= VIF_MISMATCH
|VIF_SRCOLD
;
501 /* compare filetypes and filesubtypes */
502 if ((destvffi
->dwFileType
!=tmpvffi
->dwFileType
) ||
503 (destvffi
->dwFileSubtype
!=tmpvffi
->dwFileSubtype
)
505 xret
|= VIF_MISMATCH
|VIF_DIFFTYPE
;
506 if (VerQueryValueA(buf1
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf1
,&len1
) &&
507 VerQueryValueA(buf2
,"\\VarFileInfo\\Translation",(LPVOID
*)&tbuf2
,&len2
)
509 /* irgendwas mit tbuf1 und tbuf2 machen
510 * generiert DIFFLANG|MISMATCH
515 xret
=VIF_MISMATCH
|VIF_SRCOLD
;
520 if (*tmpfilelen
<strlen(tmpfn
+tmplast
)) {
521 xret
|=VIF_BUFFTOOSMALL
;
524 strcpy(tmpfile
,tmpfn
+tmplast
);
525 *tmpfilelen
= strlen(tmpfn
+tmplast
)+1;
529 if (-1!=GetFileAttributesA(destfn
))
530 if (!DeleteFileA(destfn
)) {
531 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETE
;
536 if ((!(flags
& VIFF_DONTDELETEOLD
)) &&
539 lstrcmpiA(curdir
,pdest
)
543 sprintf(curfn
,"%s\\%s",curdir
,destfilename
);
544 if (-1!=GetFileAttributesA(curfn
)) {
545 /* FIXME: check if in use ... if it is, VIF_CANNOTDELETECUR */
546 if (!DeleteFileA(curfn
))
547 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETECUR
;
550 if (!MoveFileA(tmpfn
,destfn
)) {
551 xret
|=_error2vif(GetLastError())|VIF_CANNOTRENAME
;
560 /* VerInstallFile32W [VERSION.8] */
561 DWORD WINAPI
VerInstallFileW(
562 UINT flags
,LPCWSTR srcfilename
,LPCWSTR destfilename
,LPCWSTR srcdir
,
563 LPCWSTR destdir
,LPCWSTR curdir
,LPWSTR tmpfile
,UINT
*tmpfilelen
)
565 LPSTR wsrcf
,wsrcd
,wdestf
,wdestd
,wtmpf
,wcurd
;
568 wsrcf
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcfilename
);
569 wsrcd
= HEAP_strdupWtoA( GetProcessHeap(), 0, srcdir
);
570 wdestf
= HEAP_strdupWtoA( GetProcessHeap(), 0, destfilename
);
571 wdestd
= HEAP_strdupWtoA( GetProcessHeap(), 0, destdir
);
572 wtmpf
= HEAP_strdupWtoA( GetProcessHeap(), 0, tmpfile
);
573 wcurd
= HEAP_strdupWtoA( GetProcessHeap(), 0, curdir
);
574 ret
= VerInstallFileA(flags
,wsrcf
,wdestf
,wsrcd
,wdestd
,wcurd
,wtmpf
,tmpfilelen
);
576 lstrcpynAtoW(tmpfile
,wtmpf
,*tmpfilelen
);
577 HeapFree( GetProcessHeap(), 0, wsrcf
);
578 HeapFree( GetProcessHeap(), 0, wsrcd
);
579 HeapFree( GetProcessHeap(), 0, wdestf
);
580 HeapFree( GetProcessHeap(), 0, wdestd
);
581 HeapFree( GetProcessHeap(), 0, wtmpf
);
583 HeapFree( GetProcessHeap(), 0, wcurd
);