2 * Implementation of VERSION.DLL - File Installer routines
4 * Copyright 1996,1997 Marcus Meissner
5 * Copyright 1997 David Cuthbert
20 /******************************************************************************
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.
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
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)",
55 /******************************************************************************
57 * int testFileExistence(
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
66 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
67 * Original implementation
69 *****************************************************************************/
71 static int testFileExistence(
80 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
82 strcpy(filename
, path
);
83 filenamelen
= strlen(filename
);
85 /* Add a trailing \ if necessary */
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
)
104 /******************************************************************************
106 * int testFileExclusiveExistence(
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.
116 * 30-May-1997 Dave Cuthbert (dacut@ece.cmu.edu)
117 * Original implementation
119 *****************************************************************************/
121 static int testFileExclusiveExistence(
130 fileinfo
.cBytes
= sizeof(OFSTRUCT
);
132 strcpy(filename
, path
);
133 filenamelen
= strlen(filename
);
135 /* Add a trailing \ if necessary */
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
) ==
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.
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(
175 UINT32
*lpuCurDirLen
,
177 UINT32
*lpuDestDirLen
)
182 unsigned int curDirSizeReq
;
183 unsigned int destDirSizeReq
;
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");
195 ver_dstring("\tlpszFilename = ", lpszFilename
, "");
196 ver_dstring("\tlpszWinDir = ", lpszWinDir
, "");
197 ver_dstring("\tlpszAppDir = ", lpszAppDir
, "");
199 TRACE(ver
, "\tlpszCurDir = %p\n", lpszCurDir
);
201 TRACE(ver
, "\tlpuCurDirLen = %p (%u)\n",
202 lpuCurDirLen
, *lpuCurDirLen
);
204 TRACE(ver
, "\tlpuCurDirLen = (null)\n");
206 TRACE(ver
, "\tlpszDestDir = %p\n", lpszDestDir
);
208 TRACE(ver
, "\tlpuDestDirLen = %p (%u)\n",
209 lpuDestDirLen
, *lpuDestDirLen
);
211 /* Figure out where the file should go; shared files default to the
217 if(flags
& VFFF_ISSHAREDFILE
) {
218 GetSystemDirectory32A(destDir
, 256);
220 /* Were we given a filename? If so, try to find the file. */
222 if(testFileExistence(destDir
, lpszFilename
)) {
223 strcpy(curDir
, destDir
);
225 if(!testFileExclusiveExistence(destDir
, lpszFilename
))
226 retval
|= VFF_FILEINUSE
;
228 else if(lpszAppDir
&& testFileExistence(lpszAppDir
,
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 */
241 GetSystemDirectory32A(systemDir
, 256);
243 strcpy(destDir
, lpszAppDir
);
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';
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';
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
, "");
303 TRACE(ver
, "\t(Exit) lpuCurDirLen = %p (%u)\n",
304 lpuCurDirLen
, *lpuCurDirLen
);
306 TRACE(ver
, "\t(Exit) lpuCurDirLen = (null)\n");
308 ver_dstring("\t(Exit) lpszDestDir = ", lpszDestDir
, "");
310 TRACE(ver
, "\t(Exit) lpuDestDirLen = %p (%u)\n",
311 lpuDestDirLen
, *lpuDestDirLen
);
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
;
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
);
344 _fetch_versioninfo(LPSTR fn
,VS_FIXEDFILEINFO
**vffi
) {
350 buf
= xmalloc(alloclen
);
352 ret
= GetFileVersionInfo32A(fn
,0,alloclen
,buf
);
357 if (alloclen
<*(WORD
*)buf
) {
359 alloclen
= *(WORD
*)buf
;
360 buf
= xmalloc(alloclen
);
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
);
373 _error2vif(DWORD error
) {
375 case ERROR_ACCESS_DENIED
:
376 return VIF_ACCESSVIOLATION
;
377 case ERROR_SHARING_VIOLATION
:
378 return VIF_SHARINGVIOLATION
;
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
)
393 char destfn
[260],tmpfn
[260],srcfn
[260];
395 DWORD attr
,ret
,xret
,tmplast
;
399 TRACE(ver
,"(%x,%s,%s,%s,%s,%s,%p,%d)\n",
400 flags
,srcfilename
,destfilename
,srcdir
,destdir
,curdir
,tmpfile
,*tmpfilelen
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
);
414 if (attr
& FILE_ATTRIBUTE_READONLY
) {
416 return VIF_WRITEPROT
;
418 /* FIXME: check if file currently in use and return VIF_FILEINUSE */
421 if (flags
& VIFF_FORCEINSTALL
) {
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...
434 GetTempFileName32A(pdest
,"ver",0,tmpfn
); /* should not fail ... */
435 s
=strrchr(tmpfn
,'\\');
440 hfdst
= OpenFile32(tmpfn
,&ofs
,OF_CREATE
);
441 if (hfdst
== HFILE_ERROR32
) {
443 return VIF_CANNOTCREATE
; /* | translated dos error */
445 ret
= LZCopy32(hfsrc
,hfdst
);
447 if (((long) ret
) < 0) {
448 /* translate LZ errors into VIF_xxx */
450 case LZERROR_BADINHANDLE
:
452 case LZERROR_BADVALUE
:
453 case LZERROR_UNKNOWNALG
:
454 ret
= VIF_CANNOTREADSRC
;
456 case LZERROR_BADOUTHANDLE
:
458 ret
= VIF_OUTOFMEMORY
; /* FIXME: correct? */
460 case LZERROR_GLOBALLOC
:
461 case LZERROR_GLOBLOCK
:
462 ret
= VIF_OUTOFSPACE
;
464 default: /* unknown error, should not happen */
475 if (!(flags
& VIFF_FORCEINSTALL
)) {
476 VS_FIXEDFILEINFO
*destvffi
,*tmpvffi
;
477 buf1
= _fetch_versioninfo(destfn
,&destvffi
);
479 buf2
= _fetch_versioninfo(tmpfn
,&tmpvffi
);
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
507 xret
=VIF_MISMATCH
|VIF_SRCOLD
;
512 if (*tmpfilelen
<strlen(tmpfn
+tmplast
)) {
513 xret
|=VIF_BUFFTOOSMALL
;
514 DeleteFile32A(tmpfn
);
516 strcpy(tmpfile
,tmpfn
+tmplast
);
517 *tmpfilelen
= strlen(tmpfn
+tmplast
)+1;
521 if (-1!=GetFileAttributes32A(destfn
))
522 if (!DeleteFile32A(destfn
)) {
523 xret
|=_error2vif(GetLastError())|VIF_CANNOTDELETE
;
524 DeleteFile32A(tmpfn
);
528 if ((!(flags
& VIFF_DONTDELETEOLD
)) &&
531 lstrcmpi32A(curdir
,pdest
)
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
);
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
;
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
);
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
);
575 HeapFree( GetProcessHeap(), 0, wcurd
);