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 appends the files in the file list to the backup section of
39 * the specified INI, or deletes the entries from the INI file.
42 * lpcszFileList [I] NULL-separated list of filenames.
43 * lpcszBackupDir [I] Path of the backup directory.
44 * lpcszBaseName [I] Basename of the INI file.
45 * dwFlags [I] AADBE_ADD_ENTRY adds the entries in the file list
46 * to the INI file, while AADBE_DEL_ENTRY removes
47 * the entries from the INI file.
54 * If the INI file does not exist before adding entries to it, the file
57 * If lpcszBackupDir is NULL, the INI file is assumed to exist in
58 * c:\windows or created there if it does not exist.
63 HRESULT WINAPI AddDelBackupEntry(LPCSTR lpcszFileList, LPCSTR lpcszBackupDir,
64 LPCSTR lpcszBaseName, DWORD dwFlags)
66 FIXME("(%p, %p, %p, %ld) stub\n", lpcszFileList, lpcszBackupDir,
67 lpcszBaseName, dwFlags);
72 /* FIXME: this is only for the local case, X:\ */
75 UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification,
76 UINT_PTR Param1, UINT_PTR Param2)
81 UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification,
82 UINT_PTR Param1, UINT_PTR Param2)
84 /* only be verbose for error notifications */
86 Notification == SPFILENOTIFY_RENAMEERROR ||
87 Notification == SPFILENOTIFY_DELETEERROR ||
88 Notification == SPFILENOTIFY_COPYERROR)
90 return SetupDefaultQueueCallbackA(Context, Notification,
97 /***********************************************************************
98 * AdvInstallFile (ADVPACK.@)
100 * Copies a file from the source to a destination.
103 * hwnd [I] Handle to the window used for messages.
104 * lpszSourceDir [I] Source directory.
105 * lpszSourceFile [I] Source filename.
106 * lpszDestDir [I] Destination directory.
107 * lpszDestFile [I] Optional destination filename.
108 * dwFlags [I] See advpub.h.
109 * dwReserved [I] Reserved. Must be 0.
116 * If lpszDestFile is NULL, the destination filename is the same as
119 HRESULT WINAPI AdvInstallFile(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile,
120 LPCSTR lpszDestDir, LPCSTR lpszDestFile,
121 DWORD dwFlags, DWORD dwReserved)
123 PSP_FILE_CALLBACK_A pFileCallback;
124 LPSTR szPath, szDestFilename;
125 char szRootPath[ROOT_LENGTH];
126 DWORD dwLen, dwLastError;
130 TRACE("(%p,%p,%p,%p,%p,%ld,%ld)\n", hwnd, debugstr_a(lpszSourceDir),
131 debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir),
132 debugstr_a(lpszDestFile), dwFlags, dwReserved);
134 if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
137 fileQueue = SetupOpenFileQueue();
138 if (fileQueue == INVALID_HANDLE_VALUE)
139 return HRESULT_FROM_WIN32(GetLastError());
142 dwLastError = ERROR_SUCCESS;
144 lstrcpynA(szRootPath, lpszSourceDir, ROOT_LENGTH);
145 szPath = (LPSTR)lpszSourceDir + ROOT_LENGTH;
147 /* use lpszSourceFile as destination filename if lpszDestFile is NULL */
150 dwLen = lstrlenA(lpszDestFile);
151 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen);
152 lstrcpyA(szDestFilename, lpszDestFile);
156 dwLen = lstrlenA(lpszSourceFile);
157 szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen);
158 lstrcpyA(szDestFilename, lpszSourceFile);
161 /* add the file copy operation to the setup queue */
162 if (!SetupQueueCopyA(fileQueue, szRootPath, szPath, lpszSourceFile, NULL,
163 NULL, lpszDestDir, szDestFilename, dwFlags))
165 dwLastError = GetLastError();
169 pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE,
173 dwLastError = GetLastError();
177 /* don't output anything for AIF_QUIET */
178 if (dwFlags & AIF_QUIET)
179 pFileCallback = pQuietQueueCallback;
181 pFileCallback = pQueueCallback;
183 /* perform the file copy */
184 if (!SetupCommitFileQueueA(hwnd, fileQueue, pFileCallback, pContext))
186 dwLastError = GetLastError();
191 SetupTermDefaultQueueCallback(pContext);
192 SetupCloseFileQueue(fileQueue);
194 HeapFree(GetProcessHeap(), 0, szDestFilename);
196 return HRESULT_FROM_WIN32(dwLastError);
199 static HRESULT DELNODE_recurse_dirtree(LPSTR fname, DWORD flags)
201 DWORD fattrs = GetFileAttributesA(fname);
202 HRESULT ret = E_FAIL;
204 if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
207 WIN32_FIND_DATAA w32fd;
209 int fname_len = lstrlenA(fname);
211 /* Generate a path with wildcard suitable for iterating */
212 if (CharPrevA(fname, fname + fname_len) != "\\")
214 lstrcpyA(fname + fname_len, "\\");
217 lstrcpyA(fname + fname_len, "*");
219 if ((hFindFile = FindFirstFileA(fname, &w32fd)) != INVALID_HANDLE_VALUE)
221 /* Iterate through the files in the directory */
222 for (done = FALSE; !done; done = !FindNextFileA(hFindFile, &w32fd))
224 TRACE("%s\n", w32fd.cFileName);
225 if (lstrcmpA(".", w32fd.cFileName) != 0 &&
226 lstrcmpA("..", w32fd.cFileName) != 0)
228 lstrcpyA(fname + fname_len, w32fd.cFileName);
229 if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
235 FindClose(hFindFile);
238 /* We're done with this directory, so restore the old path without wildcard */
239 *(fname + fname_len) = '\0';
243 TRACE("%s: directory\n", fname);
244 if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryA(fname))
252 TRACE("%s: file\n", fname);
253 if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileA(fname))
262 /***********************************************************************
263 * DelNode (ADVPACK.@)
265 * Deletes a file or directory
268 * pszFileOrDirName [I] Name of file or directory to delete
269 * dwFlags [I] Flags; see include/advpub.h
277 * - Native version apparently does a lot of checking to make sure
278 * we're not trying to delete a system directory etc.
280 HRESULT WINAPI DelNode( LPCSTR pszFileOrDirName, DWORD dwFlags )
282 CHAR fname[MAX_PATH];
283 HRESULT ret = E_FAIL;
285 TRACE("(%s, 0x%08lx)\n", debugstr_a(pszFileOrDirName), dwFlags);
288 FIXME("Flags ignored!\n");
290 if (pszFileOrDirName && *pszFileOrDirName)
292 lstrcpyA(fname, pszFileOrDirName);
294 /* TODO: Should check for system directory deletion etc. here */
296 ret = DELNODE_recurse_dirtree(fname, dwFlags);
302 /* returns the parameter at dwIndex in a list of parameters
303 * separated by the cSeparator character
305 static LPSTR get_parameter(LPSTR szParameters, CHAR cSeparator, DWORD dwIndex)
307 LPSTR szParam = NULL;
310 while (*szParameters && i < dwIndex)
312 if (*szParameters == cSeparator)
321 szParam = HeapAlloc(GetProcessHeap(), 0, lstrlenA(szParameters));
322 lstrcpyA(szParam, szParameters);
327 /***********************************************************************
328 * DelNodeRunDLL32 (ADVPACK.@)
330 * Deletes a file or directory, WinMain style.
333 * hWnd [I] Handle to the window used for the display.
334 * hInst [I] Instance of the process.
335 * cmdline [I] Contains parameters in the order FileOrDirName,Flags.
336 * show [I] How the window should be shown.
342 HRESULT WINAPI DelNodeRunDLL32( HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show )
344 LPSTR szFilename, szFlags;
348 TRACE("(%s)\n", debugstr_a(cmdline));
350 /* get the parameters at indexes 0 and 1 respectively */
351 szFilename = get_parameter(cmdline, ',', 0);
352 szFlags = get_parameter(cmdline, ',', 1);
354 dwFlags = atol(szFlags);
356 res = DelNode(szFilename, dwFlags);
358 HeapFree(GetProcessHeap(), 0, szFilename);
359 HeapFree(GetProcessHeap(), 0, szFlags);
364 /* The following defintions were copied from dlls/cabinet/cabinet.h */
366 /* EXTRACTdest flags */
367 #define EXTRACT_FILLFILELIST 0x00000001
368 #define EXTRACT_EXTRACTFILES 0x00000002
370 struct ExtractFileList {
372 struct ExtractFileList *next;
373 BOOL unknown; /* always 1L */
376 /* the first parameter of the function Extract */
378 long result1; /* 0x000 */
379 long unknown1[3]; /* 0x004 */
380 struct ExtractFileList *filelist; /* 0x010 */
381 long filecount; /* 0x014 */
382 DWORD flags; /* 0x018 */
383 char directory[0x104]; /* 0x01c */
384 char lastfile[0x20c]; /* 0x120 */
387 static HRESULT (WINAPI *pExtract)(EXTRACTdest*, LPCSTR);
389 /* removes legal characters before and after file list, and
390 * converts the file list to a NULL-separated list
392 static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles)
395 char *first = (char *)FileList;
396 char *last = (char *)FileList + strlen(FileList) - 1;
397 LPSTR szConvertedList, temp;
399 /* any number of these chars before the list is OK */
400 while (first < last && (*first == ' ' || *first == '\t' || *first == ':'))
403 /* any number of these chars after the list is OK */
404 while (last > first && (*last == ' ' || *last == '\t' || *last == ':'))
410 dwLen = last - first + 3; /* room for double-null termination */
411 szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen);
412 lstrcpynA(szConvertedList, first, dwLen - 1);
414 szConvertedList[dwLen - 1] = '\0';
415 szConvertedList[dwLen] = '\0';
418 if (!lstrlenA(szConvertedList))
423 /* convert the colons to double-null termination */
424 temp = szConvertedList;
436 return szConvertedList;
439 static void free_file_node(struct ExtractFileList *pNode)
441 HeapFree(GetProcessHeap(), 0, pNode->filename);
442 HeapFree(GetProcessHeap(), 0, pNode);
445 /* determines whether szFile is in the NULL-separated szFileList */
446 static BOOL file_in_list(LPSTR szFile, LPSTR szFileList)
448 DWORD dwLen = lstrlenA(szFile);
453 dwTestLen = lstrlenA(szFileList);
455 if (dwTestLen == dwLen)
457 if (!lstrcmpiA(szFile, szFileList))
461 szFileList += dwTestLen + 1;
467 /* removes nodes from the linked list that aren't specified in szFileList
468 * returns the number of files that are in both the linked list and szFileList
470 static DWORD fill_file_list(EXTRACTdest *extractDest, LPCSTR szCabName, LPSTR szFileList)
472 DWORD dwNumFound = 0;
473 struct ExtractFileList *pNode;
474 struct ExtractFileList *prev = NULL;
476 extractDest->flags |= EXTRACT_FILLFILELIST;
477 if (pExtract(extractDest, szCabName))
479 extractDest->flags &= ~EXTRACT_FILLFILELIST;
483 pNode = extractDest->filelist;
486 if (file_in_list(pNode->filename, szFileList))
494 prev->next = pNode->next;
495 free_file_node(pNode);
500 extractDest->filelist = pNode->next;
501 free_file_node(pNode);
502 pNode = extractDest->filelist;
506 extractDest->flags &= ~EXTRACT_FILLFILELIST;
510 /***********************************************************************
511 * ExtractFiles (ADVPACK.@)
513 * Extracts the specified files from a cab archive into
514 * a destination directory.
517 * CabName [I] Filename of the cab archive.
518 * ExpandDir [I] Destination directory for the extracted files.
519 * Flags [I] Reserved.
520 * FileList [I] Optional list of files to extract. See NOTES.
521 * LReserved [I] Reserved. Must be NULL.
522 * Reserved [I] Reserved. Must be 0.
529 * FileList is a colon-separated list of filenames. If FileList is
530 * non-NULL, only the files in the list will be extracted from the
531 * cab file, otherwise all files will be extracted. Any number of
532 * spaces, tabs, or colons can be before or after the list, but
533 * the list itself must only be separated by colons.
535 HRESULT WINAPI ExtractFiles ( LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags,
536 LPCSTR FileList, LPVOID LReserved, DWORD Reserved)
538 EXTRACTdest extractDest;
541 DWORD dwFileCount = 0;
542 DWORD dwFilesFound = 0;
543 LPSTR szConvertedList = NULL;
545 TRACE("(%p %p %ld %p %p %ld)\n", CabName, ExpandDir, Flags,
546 FileList, LReserved, Reserved);
548 if (!CabName || !ExpandDir)
551 if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES)
552 return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND);
554 hCabinet = LoadLibraryA("cabinet.dll");
558 pExtract = (void *)GetProcAddress(hCabinet, "Extract");
565 ZeroMemory(&extractDest, sizeof(EXTRACTdest));
566 lstrcpyA(extractDest.directory, ExpandDir);
570 szConvertedList = convert_file_list(FileList, &dwFileCount);
571 if (!szConvertedList || dwFileCount == -1)
577 dwFilesFound = fill_file_list(&extractDest, CabName, szConvertedList);
578 if (dwFilesFound != dwFileCount)
585 extractDest.flags |= EXTRACT_FILLFILELIST;
587 extractDest.flags |= EXTRACT_EXTRACTFILES;
588 res = pExtract(&extractDest, CabName);
591 FreeLibrary(hCabinet);
592 HeapFree(GetProcessHeap(), 0, szConvertedList);
597 /***********************************************************************
598 * FileSaveMarkNotExist (ADVPACK.@)
600 * Marks the files in the file list as not existing so they won't be
601 * backed up during a save.
604 * pszFileList [I] NULL-separated list of filenames.
605 * pszDir [I] Path of the backup directory.
606 * pszBaseName [I] Basename of the INI file.
612 HRESULT WINAPI FileSaveMarkNotExist(LPSTR pszFileList, LPSTR pszDir, LPSTR pszBaseName)
614 TRACE("(%p, %p, %p)\n", pszFileList, pszDir, pszBaseName);
616 return AddDelBackupEntry(pszFileList, pszDir, pszBaseName, AADBE_DEL_ENTRY);
619 /***********************************************************************
620 * FileSaveRestore (ADVPACK.@)
622 * Saves or restores the files in the specified file list.
625 * hDlg [I] Handle to the dialog used for the display.
626 * pszFileList [I] NULL-separated list of filenames.
627 * pszDir [I] Path of the backup directory.
628 * pszBaseName [I] Basename of the backup files.
629 * dwFlags [I] See advpub.h.
636 * If pszFileList is NULL on restore, all files will be restored.
641 HRESULT WINAPI FileSaveRestore(HWND hDlg, LPSTR pszFileList, LPSTR pszDir,
642 LPSTR pszBaseName, DWORD dwFlags)
644 FIXME("(%p, %p, %p, %p, %ld) stub\n", hDlg, pszFileList, pszDir,
645 pszBaseName, dwFlags);
650 /***********************************************************************
651 * FileSaveRestoreOnINF (ADVPACK.@)
655 * hWnd [I] Handle to the window used for the display.
656 * pszTitle [I] Title of the window.
657 * pszINF [I] Fully-qualified INF filename.
658 * pszSection [I] GenInstall INF section name.
659 * pszBackupDir [I] Directory to store the backup file.
660 * pszBaseBackupFile [I] Basename of the backup files.
661 * dwFlags [I] See advpub.h
668 * If pszSection is NULL, the default section will be used.
673 HRESULT WINAPI FileSaveRestoreOnINF(HWND hWnd, PCSTR pszTitle, PCSTR pszINF,
674 PCSTR pszSection, PCSTR pszBackupDir,
675 PCSTR pszBaseBackupFile, DWORD dwFlags)
677 FIXME("(%p, %p, %p, %p, %p, %p, %ld) stub\n", hWnd, pszTitle, pszINF,
678 pszSection, pszBackupDir, pszBaseBackupFile, dwFlags);
683 /***********************************************************************
684 * GetVersionFromFile (ADVPACK.@)
686 * See GetVersionFromFileEx.
688 HRESULT WINAPI GetVersionFromFile( LPSTR Filename, LPDWORD MajorVer,
689 LPDWORD MinorVer, BOOL Version )
691 TRACE("(%s, %p, %p, %d)\n", Filename, MajorVer, MinorVer, Version);
692 return GetVersionFromFileEx(Filename, MajorVer, MinorVer, Version);
695 /* data for GetVersionFromFileEx */
696 typedef struct tagLANGANDCODEPAGE
702 /***********************************************************************
703 * GetVersionFromFileEx (ADVPACK.@)
705 * Gets the files version or language information.
708 * lpszFilename [I] The file to get the info from.
709 * pdwMSVer [O] Major version.
710 * pdwLSVer [O] Minor version.
711 * bVersion [I] Whether to retrieve version or language info.
714 * Always returns S_OK.
717 * If bVersion is TRUE, version information is retrieved, else
718 * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID.
720 HRESULT WINAPI GetVersionFromFileEx( LPSTR lpszFilename, LPDWORD pdwMSVer,
721 LPDWORD pdwLSVer, BOOL bVersion )
723 VS_FIXEDFILEINFO *pFixedVersionInfo;
724 LANGANDCODEPAGE *pLangAndCodePage;
725 DWORD dwHandle, dwInfoSize;
726 CHAR szWinDir[MAX_PATH];
727 CHAR szFile[MAX_PATH];
728 LPVOID pVersionInfo = NULL;
729 BOOL bFileCopied = FALSE;
732 TRACE("(%s, %p, %p, %d)\n", lpszFilename, pdwMSVer, pdwLSVer, bVersion);
737 lstrcpynA(szFile, lpszFilename, MAX_PATH);
739 dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle);
742 /* check that the file exists */
743 if (GetFileAttributesA(szFile) == INVALID_FILE_ATTRIBUTES)
746 /* file exists, but won't be found by GetFileVersionInfoSize,
747 * so copy it to the temp dir where it will be found.
749 GetWindowsDirectoryA(szWinDir, MAX_PATH);
750 GetTempFileNameA(szWinDir, NULL, 0, szFile);
751 CopyFileA(lpszFilename, szFile, FALSE);
754 dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle);
759 pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize);
763 if (!GetFileVersionInfoA(szFile, dwHandle, dwInfoSize, pVersionInfo))
768 if (!VerQueryValueA(pVersionInfo, "\\",
769 (LPVOID *)&pFixedVersionInfo, &uValueLen))
775 *pdwMSVer = pFixedVersionInfo->dwFileVersionMS;
776 *pdwLSVer = pFixedVersionInfo->dwFileVersionLS;
780 if (!VerQueryValueA(pVersionInfo, "\\VarFileInfo\\Translation",
781 (LPVOID *)&pLangAndCodePage, &uValueLen))
787 *pdwMSVer = pLangAndCodePage->wLanguage;
788 *pdwLSVer = pLangAndCodePage->wCodePage;
792 HeapFree(GetProcessHeap(), 0, pVersionInfo);