2 * Advpack file functions
4 * Copyright 2006 James Hawkins
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(advpack
);
35 /***********************************************************************
36 * AddDelBackupEntry (ADVPACK.@)
38 * Either marks the file in the file list as not existing during file
39 * save, or deletes the file entry from the INI.
42 * lpcszFileList [I] NULL-separated list of filenames.
43 * lpcszBackupDir [I] Path of the backup directory.
44 * lpcszBaseName [I] Basename of the backup files.
45 * dwFlags [I] See advpub.h.
54 HRESULT WINAPI
AddDelBackupEntry(LPCSTR lpcszFileList
, LPCSTR lpcszBackupDir
,
55 LPCSTR lpcszBaseName
, DWORD dwFlags
)
57 FIXME("(%p, %p, %p, %ld) stub\n", lpcszFileList
, lpcszBackupDir
,
58 lpcszBaseName
, dwFlags
);
63 /* FIXME: this is only for the local case, X:\ */
66 UINT CALLBACK
pQuietQueueCallback(PVOID Context
, UINT Notification
,
67 UINT_PTR Param1
, UINT_PTR Param2
)
72 UINT CALLBACK
pQueueCallback(PVOID Context
, UINT Notification
,
73 UINT_PTR Param1
, UINT_PTR Param2
)
75 /* only be verbose for error notifications */
77 Notification
== SPFILENOTIFY_RENAMEERROR
||
78 Notification
== SPFILENOTIFY_DELETEERROR
||
79 Notification
== SPFILENOTIFY_COPYERROR
)
81 return SetupDefaultQueueCallbackA(Context
, Notification
,
88 /***********************************************************************
89 * AdvInstallFile (ADVPACK.@)
91 * Copies a file from the source to a destination.
94 * hwnd [I] Handle to the window used for messages.
95 * lpszSourceDir [I] Source directory.
96 * lpszSourceFile [I] Source filename.
97 * lpszDestDir [I] Destination directory.
98 * lpszDestFile [I] Optional destination filename.
99 * dwFlags [I] See advpub.h.
100 * dwReserved [I] Reserved. Must be 0.
107 * If lpszDestFile is NULL, the destination filename is the same as
110 HRESULT WINAPI
AdvInstallFile(HWND hwnd
, LPCSTR lpszSourceDir
, LPCSTR lpszSourceFile
,
111 LPCSTR lpszDestDir
, LPCSTR lpszDestFile
,
112 DWORD dwFlags
, DWORD dwReserved
)
114 PSP_FILE_CALLBACK_A pFileCallback
;
115 LPSTR szPath
, szDestFilename
;
116 char szRootPath
[ROOT_LENGTH
];
117 DWORD dwLen
, dwLastError
;
121 TRACE("(%p,%p,%p,%p,%p,%ld,%ld)\n", hwnd
, debugstr_a(lpszSourceDir
),
122 debugstr_a(lpszSourceFile
), debugstr_a(lpszDestDir
),
123 debugstr_a(lpszDestFile
), dwFlags
, dwReserved
);
125 if (!lpszSourceDir
|| !lpszSourceFile
|| !lpszDestDir
)
128 fileQueue
= SetupOpenFileQueue();
129 if (fileQueue
== INVALID_HANDLE_VALUE
)
130 return HRESULT_FROM_WIN32(GetLastError());
133 dwLastError
= ERROR_SUCCESS
;
135 lstrcpynA(szRootPath
, lpszSourceDir
, ROOT_LENGTH
);
136 szPath
= (LPSTR
)lpszSourceDir
+ ROOT_LENGTH
;
138 /* use lpszSourceFile as destination filename if lpszDestFile is NULL */
141 dwLen
= lstrlenA(lpszDestFile
);
142 szDestFilename
= HeapAlloc(GetProcessHeap(), 0, dwLen
);
143 lstrcpyA(szDestFilename
, lpszDestFile
);
147 dwLen
= lstrlenA(lpszSourceFile
);
148 szDestFilename
= HeapAlloc(GetProcessHeap(), 0, dwLen
);
149 lstrcpyA(szDestFilename
, lpszSourceFile
);
152 /* add the file copy operation to the setup queue */
153 if (!SetupQueueCopyA(fileQueue
, szRootPath
, szPath
, lpszSourceFile
, NULL
,
154 NULL
, lpszDestDir
, szDestFilename
, dwFlags
))
156 dwLastError
= GetLastError();
160 pContext
= SetupInitDefaultQueueCallbackEx(hwnd
, INVALID_HANDLE_VALUE
,
164 dwLastError
= GetLastError();
168 /* don't output anything for AIF_QUIET */
169 if (dwFlags
& AIF_QUIET
)
170 pFileCallback
= pQuietQueueCallback
;
172 pFileCallback
= pQueueCallback
;
174 /* perform the file copy */
175 if (!SetupCommitFileQueueA(hwnd
, fileQueue
, pFileCallback
, pContext
))
177 dwLastError
= GetLastError();
182 SetupTermDefaultQueueCallback(pContext
);
183 SetupCloseFileQueue(fileQueue
);
185 HeapFree(GetProcessHeap(), 0, szDestFilename
);
187 return HRESULT_FROM_WIN32(dwLastError
);
190 static HRESULT
DELNODE_recurse_dirtree(LPSTR fname
, DWORD flags
)
192 DWORD fattrs
= GetFileAttributesA(fname
);
193 HRESULT ret
= E_FAIL
;
195 if (fattrs
& FILE_ATTRIBUTE_DIRECTORY
)
198 WIN32_FIND_DATAA w32fd
;
200 int fname_len
= lstrlenA(fname
);
202 /* Generate a path with wildcard suitable for iterating */
203 if (CharPrevA(fname
, fname
+ fname_len
) != "\\")
205 lstrcpyA(fname
+ fname_len
, "\\");
208 lstrcpyA(fname
+ fname_len
, "*");
210 if ((hFindFile
= FindFirstFileA(fname
, &w32fd
)) != INVALID_HANDLE_VALUE
)
212 /* Iterate through the files in the directory */
213 for (done
= FALSE
; !done
; done
= !FindNextFileA(hFindFile
, &w32fd
))
215 TRACE("%s\n", w32fd
.cFileName
);
216 if (lstrcmpA(".", w32fd
.cFileName
) != 0 &&
217 lstrcmpA("..", w32fd
.cFileName
) != 0)
219 lstrcpyA(fname
+ fname_len
, w32fd
.cFileName
);
220 if (DELNODE_recurse_dirtree(fname
, flags
) != S_OK
)
226 FindClose(hFindFile
);
229 /* We're done with this directory, so restore the old path without wildcard */
230 *(fname
+ fname_len
) = '\0';
234 TRACE("%s: directory\n", fname
);
235 if (SetFileAttributesA(fname
, FILE_ATTRIBUTE_NORMAL
) && RemoveDirectoryA(fname
))
243 TRACE("%s: file\n", fname
);
244 if (SetFileAttributesA(fname
, FILE_ATTRIBUTE_NORMAL
) && DeleteFileA(fname
))
253 /***********************************************************************
254 * DelNode (ADVPACK.@)
256 * Deletes a file or directory
259 * pszFileOrDirName [I] Name of file or directory to delete
260 * dwFlags [I] Flags; see include/advpub.h
268 * - Native version apparently does a lot of checking to make sure
269 * we're not trying to delete a system directory etc.
271 HRESULT WINAPI
DelNode( LPCSTR pszFileOrDirName
, DWORD dwFlags
)
273 CHAR fname
[MAX_PATH
];
274 HRESULT ret
= E_FAIL
;
276 TRACE("(%s, 0x%08lx)\n", debugstr_a(pszFileOrDirName
), dwFlags
);
279 FIXME("Flags ignored!\n");
281 if (pszFileOrDirName
&& *pszFileOrDirName
)
283 lstrcpyA(fname
, pszFileOrDirName
);
285 /* TODO: Should check for system directory deletion etc. here */
287 ret
= DELNODE_recurse_dirtree(fname
, dwFlags
);
293 /* returns the parameter at dwIndex in a list of parameters
294 * separated by the cSeparator character
296 static LPSTR
get_parameter(LPSTR szParameters
, CHAR cSeparator
, DWORD dwIndex
)
298 LPSTR szParam
= NULL
;
301 while (*szParameters
&& i
< dwIndex
)
303 if (*szParameters
== cSeparator
)
312 szParam
= HeapAlloc(GetProcessHeap(), 0, lstrlenA(szParameters
));
313 lstrcpyA(szParam
, szParameters
);
318 /***********************************************************************
319 * DelNodeRunDLL32 (ADVPACK.@)
321 * Deletes a file or directory, WinMain style.
324 * hWnd [I] Handle to the window used for the display.
325 * hInst [I] Instance of the process.
326 * cmdline [I] Contains parameters in the order FileOrDirName,Flags.
327 * show [I] How the window should be shown.
333 HRESULT WINAPI
DelNodeRunDLL32( HWND hWnd
, HINSTANCE hInst
, LPSTR cmdline
, INT show
)
335 LPSTR szFilename
, szFlags
;
339 TRACE("(%s)\n", debugstr_a(cmdline
));
341 /* get the parameters at indexes 0 and 1 respectively */
342 szFilename
= get_parameter(cmdline
, ',', 0);
343 szFlags
= get_parameter(cmdline
, ',', 1);
345 dwFlags
= atol(szFlags
);
347 res
= DelNode(szFilename
, dwFlags
);
349 HeapFree(GetProcessHeap(), 0, szFilename
);
350 HeapFree(GetProcessHeap(), 0, szFlags
);
355 /* The following defintions were copied from dlls/cabinet/cabinet.h */
357 /* EXTRACTdest flags */
358 #define EXTRACT_FILLFILELIST 0x00000001
359 #define EXTRACT_EXTRACTFILES 0x00000002
361 struct ExtractFileList
{
363 struct ExtractFileList
*next
;
364 BOOL unknown
; /* always 1L */
367 /* the first parameter of the function Extract */
369 long result1
; /* 0x000 */
370 long unknown1
[3]; /* 0x004 */
371 struct ExtractFileList
*filelist
; /* 0x010 */
372 long filecount
; /* 0x014 */
373 DWORD flags
; /* 0x018 */
374 char directory
[0x104]; /* 0x01c */
375 char lastfile
[0x20c]; /* 0x120 */
378 static HRESULT (WINAPI
*pExtract
)(EXTRACTdest
*, LPCSTR
);
380 /* removes legal characters before and after file list, and
381 * converts the file list to a NULL-separated list
383 static LPSTR
convert_file_list(LPCSTR FileList
, DWORD
*dwNumFiles
)
386 char *first
= (char *)FileList
;
387 char *last
= (char *)FileList
+ strlen(FileList
) - 1;
388 LPSTR szConvertedList
, temp
;
390 /* any number of these chars before the list is OK */
391 while (first
< last
&& (*first
== ' ' || *first
== '\t' || *first
== ':'))
394 /* any number of these chars after the list is OK */
395 while (last
> first
&& (*last
== ' ' || *last
== '\t' || *last
== ':'))
401 dwLen
= last
- first
+ 3; /* room for double-null termination */
402 szConvertedList
= HeapAlloc(GetProcessHeap(), 0, dwLen
);
403 lstrcpynA(szConvertedList
, first
, dwLen
- 1);
405 szConvertedList
[dwLen
- 1] = '\0';
406 szConvertedList
[dwLen
] = '\0';
409 if (!lstrlenA(szConvertedList
))
414 /* convert the colons to double-null termination */
415 temp
= szConvertedList
;
427 return szConvertedList
;
430 static void free_file_node(struct ExtractFileList
*pNode
)
432 HeapFree(GetProcessHeap(), 0, pNode
->filename
);
433 HeapFree(GetProcessHeap(), 0, pNode
);
436 /* determines whether szFile is in the NULL-separated szFileList */
437 static BOOL
file_in_list(LPSTR szFile
, LPSTR szFileList
)
439 DWORD dwLen
= lstrlenA(szFile
);
444 dwTestLen
= lstrlenA(szFileList
);
446 if (dwTestLen
== dwLen
)
448 if (!lstrcmpiA(szFile
, szFileList
))
452 szFileList
+= dwTestLen
+ 1;
458 /* removes nodes from the linked list that aren't specified in szFileList
459 * returns the number of files that are in both the linked list and szFileList
461 static DWORD
fill_file_list(EXTRACTdest
*extractDest
, LPCSTR szCabName
, LPSTR szFileList
)
463 DWORD dwNumFound
= 0;
464 struct ExtractFileList
*pNode
;
465 struct ExtractFileList
*prev
= NULL
;
467 extractDest
->flags
|= EXTRACT_FILLFILELIST
;
468 if (pExtract(extractDest
, szCabName
))
470 extractDest
->flags
&= ~EXTRACT_FILLFILELIST
;
474 pNode
= extractDest
->filelist
;
477 if (file_in_list(pNode
->filename
, szFileList
))
485 prev
->next
= pNode
->next
;
486 free_file_node(pNode
);
491 extractDest
->filelist
= pNode
->next
;
492 free_file_node(pNode
);
493 pNode
= extractDest
->filelist
;
497 extractDest
->flags
&= ~EXTRACT_FILLFILELIST
;
501 /***********************************************************************
502 * ExtractFiles (ADVPACK.@)
504 * Extracts the specified files from a cab archive into
505 * a destination directory.
508 * CabName [I] Filename of the cab archive.
509 * ExpandDir [I] Destination directory for the extracted files.
510 * Flags [I] Reserved.
511 * FileList [I] Optional list of files to extract. See NOTES.
512 * LReserved [I] Reserved. Must be NULL.
513 * Reserved [I] Reserved. Must be 0.
520 * FileList is a colon-separated list of filenames. If FileList is
521 * non-NULL, only the files in the list will be extracted from the
522 * cab file, otherwise all files will be extracted. Any number of
523 * spaces, tabs, or colons can be before or after the list, but
524 * the list itself must only be separated by colons.
526 HRESULT WINAPI
ExtractFiles ( LPCSTR CabName
, LPCSTR ExpandDir
, DWORD Flags
,
527 LPCSTR FileList
, LPVOID LReserved
, DWORD Reserved
)
529 EXTRACTdest extractDest
;
532 DWORD dwFileCount
= 0;
533 DWORD dwFilesFound
= 0;
534 LPSTR szConvertedList
= NULL
;
536 TRACE("(%p %p %ld %p %p %ld)\n", CabName
, ExpandDir
, Flags
,
537 FileList
, LReserved
, Reserved
);
539 if (!CabName
|| !ExpandDir
)
542 if (GetFileAttributesA(ExpandDir
) == INVALID_FILE_ATTRIBUTES
)
543 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND
);
545 hCabinet
= LoadLibraryA("cabinet.dll");
549 pExtract
= (void *)GetProcAddress(hCabinet
, "Extract");
556 ZeroMemory(&extractDest
, sizeof(EXTRACTdest
));
557 lstrcpyA(extractDest
.directory
, ExpandDir
);
561 szConvertedList
= convert_file_list(FileList
, &dwFileCount
);
562 if (!szConvertedList
|| dwFileCount
== -1)
568 dwFilesFound
= fill_file_list(&extractDest
, CabName
, szConvertedList
);
569 if (dwFilesFound
!= dwFileCount
)
576 extractDest
.flags
|= EXTRACT_FILLFILELIST
;
578 extractDest
.flags
|= EXTRACT_EXTRACTFILES
;
579 res
= pExtract(&extractDest
, CabName
);
582 FreeLibrary(hCabinet
);
583 HeapFree(GetProcessHeap(), 0, szConvertedList
);
588 /***********************************************************************
589 * FileSaveMarkNotExist (ADVPACK.@)
591 * Marks the files in the file list as not existing so they won't be
592 * backed up during a save.
595 * pszFileList [I] NULL-separated list of filenames.
596 * pszDir [I] Path of the backup directory.
597 * pszBaseName [I] Basename of the backup files.
603 HRESULT WINAPI
FileSaveMarkNotExist(LPSTR pszFileList
, LPSTR pszDir
, LPSTR pszBaseName
)
605 TRACE("(%p, %p, %p)\n", pszFileList
, pszDir
, pszBaseName
);
607 return AddDelBackupEntry(pszFileList
, pszDir
, pszBaseName
, AADBE_DEL_ENTRY
);
610 /***********************************************************************
611 * FileSaveRestore (ADVPACK.@)
613 * Saves or restores the files in the specified file list.
616 * hDlg [I] Handle to the dialog used for the display.
617 * pszFileList [I] NULL-separated list of filenames.
618 * pszDir [I] Path of the backup directory.
619 * pszBaseName [I] Basename of the backup files.
620 * dwFlags [I] See advpub.h.
627 * If pszFileList is NULL on restore, all files will be restored.
632 HRESULT WINAPI
FileSaveRestore(HWND hDlg
, LPSTR pszFileList
, LPSTR pszDir
,
633 LPSTR pszBaseName
, DWORD dwFlags
)
635 FIXME("(%p, %p, %p, %p, %ld) stub\n", hDlg
, pszFileList
, pszDir
,
636 pszBaseName
, dwFlags
);
641 /***********************************************************************
642 * FileSaveRestoreOnINF (ADVPACK.@)
646 * hWnd [I] Handle to the window used for the display.
647 * pszTitle [I] Title of the window.
648 * pszINF [I] Fully-qualified INF filename.
649 * pszSection [I] GenInstall INF section name.
650 * pszBackupDir [I] Directory to store the backup file.
651 * pszBaseBackupFile [I] Basename of the backup files.
652 * dwFlags [I] See advpub.h
659 * If pszSection is NULL, the default section will be used.
664 HRESULT WINAPI
FileSaveRestoreOnINF(HWND hWnd
, PCSTR pszTitle
, PCSTR pszINF
,
665 PCSTR pszSection
, PCSTR pszBackupDir
,
666 PCSTR pszBaseBackupFile
, DWORD dwFlags
)
668 FIXME("(%p, %p, %p, %p, %p, %p, %ld) stub\n", hWnd
, pszTitle
, pszINF
,
669 pszSection
, pszBackupDir
, pszBaseBackupFile
, dwFlags
);
674 /***********************************************************************
675 * GetVersionFromFile (ADVPACK.@)
677 * See GetVersionFromFileEx.
679 HRESULT WINAPI
GetVersionFromFile( LPSTR Filename
, LPDWORD MajorVer
,
680 LPDWORD MinorVer
, BOOL Version
)
682 TRACE("(%s, %p, %p, %d)\n", Filename
, MajorVer
, MinorVer
, Version
);
683 return GetVersionFromFileEx(Filename
, MajorVer
, MinorVer
, Version
);
686 /* data for GetVersionFromFileEx */
687 typedef struct tagLANGANDCODEPAGE
693 /***********************************************************************
694 * GetVersionFromFileEx (ADVPACK.@)
696 * Gets the files version or language information.
699 * lpszFilename [I] The file to get the info from.
700 * pdwMSVer [O] Major version.
701 * pdwLSVer [O] Minor version.
702 * bVersion [I] Whether to retrieve version or language info.
705 * Always returns S_OK.
708 * If bVersion is TRUE, version information is retrieved, else
709 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
711 HRESULT WINAPI
GetVersionFromFileEx( LPSTR lpszFilename
, LPDWORD pdwMSVer
,
712 LPDWORD pdwLSVer
, BOOL bVersion
)
714 VS_FIXEDFILEINFO
*pFixedVersionInfo
;
715 LANGANDCODEPAGE
*pLangAndCodePage
;
716 DWORD dwHandle
, dwInfoSize
;
717 CHAR szWinDir
[MAX_PATH
];
718 CHAR szFile
[MAX_PATH
];
719 LPVOID pVersionInfo
= NULL
;
720 BOOL bFileCopied
= FALSE
;
723 TRACE("(%s, %p, %p, %d)\n", lpszFilename
, pdwMSVer
, pdwLSVer
, bVersion
);
728 lstrcpynA(szFile
, lpszFilename
, MAX_PATH
);
730 dwInfoSize
= GetFileVersionInfoSizeA(szFile
, &dwHandle
);
733 /* check that the file exists */
734 if (GetFileAttributesA(szFile
) == INVALID_FILE_ATTRIBUTES
)
737 /* file exists, but won't be found by GetFileVersionInfoSize,
738 * so copy it to the temp dir where it will be found.
740 GetWindowsDirectoryA(szWinDir
, MAX_PATH
);
741 GetTempFileNameA(szWinDir
, NULL
, 0, szFile
);
742 CopyFileA(lpszFilename
, szFile
, FALSE
);
745 dwInfoSize
= GetFileVersionInfoSizeA(szFile
, &dwHandle
);
750 pVersionInfo
= HeapAlloc(GetProcessHeap(), 0, dwInfoSize
);
754 if (!GetFileVersionInfoA(szFile
, dwHandle
, dwInfoSize
, pVersionInfo
))
759 if (!VerQueryValueA(pVersionInfo
, "\\",
760 (LPVOID
*)&pFixedVersionInfo
, &uValueLen
))
766 *pdwMSVer
= pFixedVersionInfo
->dwFileVersionMS
;
767 *pdwLSVer
= pFixedVersionInfo
->dwFileVersionLS
;
771 if (!VerQueryValueA(pVersionInfo
, "\\VarFileInfo\\Translation",
772 (LPVOID
*)&pLangAndCodePage
, &uValueLen
))
778 *pdwMSVer
= pLangAndCodePage
->wLanguage
;
779 *pdwLSVer
= pLangAndCodePage
->wCodePage
;
783 HeapFree(GetProcessHeap(), 0, pVersionInfo
);