From 05d079a3257a977c7c606183954ca22c60f19950 Mon Sep 17 00:00:00 2001 From: James Hawkins Date: Fri, 13 Jan 2006 14:16:29 +0100 Subject: [PATCH] advpack: Move file related functions to files.c. --- dlls/advpack/advpack.c | 604 ---------------------------------------- dlls/advpack/files.c | 607 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 607 insertions(+), 604 deletions(-) diff --git a/dlls/advpack/advpack.c b/dlls/advpack/advpack.c index 3998b13810e..9c6ac1add1b 100644 --- a/dlls/advpack/advpack.c +++ b/dlls/advpack/advpack.c @@ -36,133 +36,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(advpack); typedef HRESULT (WINAPI *DLLREGISTER) (void); -/* FIXME: this is only for the local case, X:\ */ -#define ROOT_LENGTH 3 - -UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification, - UINT_PTR Param1, UINT_PTR Param2) -{ - return 1; -} - -UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification, - UINT_PTR Param1, UINT_PTR Param2) -{ - /* only be verbose for error notifications */ - if (!Notification || - Notification == SPFILENOTIFY_RENAMEERROR || - Notification == SPFILENOTIFY_DELETEERROR || - Notification == SPFILENOTIFY_COPYERROR) - { - return SetupDefaultQueueCallbackA(Context, Notification, - Param1, Param2); - } - - return 1; -} - -/*********************************************************************** - * AdvInstallFile (ADVPACK.@) - * - * Copies a file from the source to a destination. - * - * PARAMS - * hwnd [I] Handle to the window used for messages. - * lpszSourceDir [I] Source directory. - * lpszSourceFile [I] Source filename. - * lpszDestDir [I] Destination directory. - * lpszDestFile [I] Optional destination filename. - * dwFlags [I] See advpub.h. - * dwReserved [I] Reserved. Must be 0. - * - * RETURNS - * Success: S_OK. - * Failure: E_FAIL. - * - * NOTES - * If lpszDestFile is NULL, the destination filename is the same as - * lpszSourceFIle. - */ -HRESULT WINAPI AdvInstallFile(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile, - LPCSTR lpszDestDir, LPCSTR lpszDestFile, - DWORD dwFlags, DWORD dwReserved) -{ - PSP_FILE_CALLBACK_A pFileCallback; - LPSTR szPath, szDestFilename; - char szRootPath[ROOT_LENGTH]; - DWORD dwLen, dwLastError; - HSPFILEQ fileQueue; - PVOID pContext; - - TRACE("(%p,%p,%p,%p,%p,%ld,%ld) stub\n", hwnd, debugstr_a(lpszSourceDir), - debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir), - debugstr_a(lpszDestFile), dwFlags, dwReserved); - - if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir) - return E_INVALIDARG; - - fileQueue = SetupOpenFileQueue(); - if (fileQueue == INVALID_HANDLE_VALUE) - return HRESULT_FROM_WIN32(GetLastError()); - - pContext = NULL; - dwLastError = ERROR_SUCCESS; - - lstrcpynA(szRootPath, lpszSourceDir, ROOT_LENGTH); - szPath = (LPSTR)lpszSourceDir + ROOT_LENGTH; - - /* use lpszSourceFile as destination filename if lpszDestFile is NULL */ - if (lpszDestFile) - { - dwLen = lstrlenA(lpszDestFile); - szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen); - lstrcpyA(szDestFilename, lpszDestFile); - } - else - { - dwLen = lstrlenA(lpszSourceFile); - szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen); - lstrcpyA(szDestFilename, lpszSourceFile); - } - - /* add the file copy operation to the setup queue */ - if (!SetupQueueCopyA(fileQueue, szRootPath, szPath, lpszSourceFile, NULL, - NULL, lpszDestDir, szDestFilename, dwFlags)) - { - dwLastError = GetLastError(); - goto done; - } - - pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE, - 0, 0, NULL); - if (!pContext) - { - dwLastError = GetLastError(); - goto done; - } - - /* don't output anything for AIF_QUIET */ - if (dwFlags & AIF_QUIET) - pFileCallback = pQuietQueueCallback; - else - pFileCallback = pQueueCallback; - - /* perform the file copy */ - if (!SetupCommitFileQueueA(hwnd, fileQueue, pFileCallback, pContext)) - { - dwLastError = GetLastError(); - goto done; - } - -done: - SetupTermDefaultQueueCallback(pContext); - SetupCloseFileQueue(fileQueue); - - HeapFree(GetProcessHeap(), 0, szDestFilename); - - return HRESULT_FROM_WIN32(dwLastError); -} - /*********************************************************************** * DllMain (ADVPACK.@) */ @@ -371,123 +244,6 @@ BOOL WINAPI NeedReboot(DWORD dwRebootCheck) return FALSE; } -/*********************************************************************** - * GetVersionFromFile (ADVPACK.@) - * - * See GetVersionFromFileEx. - */ -HRESULT WINAPI GetVersionFromFile( LPSTR Filename, LPDWORD MajorVer, - LPDWORD MinorVer, BOOL Version ) -{ - TRACE("(%s, %p, %p, %d)\n", Filename, MajorVer, MinorVer, Version); - return GetVersionFromFileEx(Filename, MajorVer, MinorVer, Version); -} - -/* data for GetVersionFromFileEx */ -typedef struct tagLANGANDCODEPAGE -{ - WORD wLanguage; - WORD wCodePage; -} LANGANDCODEPAGE; - -/*********************************************************************** - * GetVersionFromFileEx (ADVPACK.@) - * - * Gets the files version or language information. - * - * PARAMS - * lpszFilename [I] The file to get the info from. - * pdwMSVer [O] Major version. - * pdwLSVer [O] Minor version. - * bVersion [I] Whether to retrieve version or language info. - * - * RETURNS - * Always returns S_OK. - * - * NOTES - * If bVersion is TRUE, version information is retrieved, else - * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID. - */ -HRESULT WINAPI GetVersionFromFileEx( LPSTR lpszFilename, LPDWORD pdwMSVer, - LPDWORD pdwLSVer, BOOL bVersion ) -{ - VS_FIXEDFILEINFO *pFixedVersionInfo; - LANGANDCODEPAGE *pLangAndCodePage; - DWORD dwHandle, dwInfoSize; - CHAR szWinDir[MAX_PATH]; - CHAR szFile[MAX_PATH]; - LPVOID pVersionInfo = NULL; - BOOL bFileCopied = FALSE; - UINT uValueLen; - - TRACE("(%s, %p, %p, %d)\n", lpszFilename, pdwMSVer, pdwLSVer, bVersion); - - *pdwLSVer = 0; - *pdwMSVer = 0; - - lstrcpynA(szFile, lpszFilename, MAX_PATH); - - dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle); - if (!dwInfoSize) - { - /* check that the file exists */ - if (GetFileAttributesA(szFile) == INVALID_FILE_ATTRIBUTES) - return S_OK; - - /* file exists, but won't be found by GetFileVersionInfoSize, - * so copy it to the temp dir where it will be found. - */ - GetWindowsDirectoryA(szWinDir, MAX_PATH); - GetTempFileNameA(szWinDir, NULL, 0, szFile); - CopyFileA(lpszFilename, szFile, FALSE); - bFileCopied = TRUE; - - dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle); - if (!dwInfoSize) - goto done; - } - - pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize); - if (!pVersionInfo) - goto done; - - if (!GetFileVersionInfoA(szFile, dwHandle, dwInfoSize, pVersionInfo)) - goto done; - - if (bVersion) - { - if (!VerQueryValueA(pVersionInfo, "\\", - (LPVOID *)&pFixedVersionInfo, &uValueLen)) - goto done; - - if (!uValueLen) - goto done; - - *pdwMSVer = pFixedVersionInfo->dwFileVersionMS; - *pdwLSVer = pFixedVersionInfo->dwFileVersionLS; - } - else - { - if (!VerQueryValueA(pVersionInfo, "\\VarFileInfo\\Translation", - (LPVOID *)&pLangAndCodePage, &uValueLen)) - goto done; - - if (!uValueLen) - goto done; - - *pdwMSVer = pLangAndCodePage->wLanguage; - *pdwLSVer = pLangAndCodePage->wCodePage; - } - -done: - HeapFree(GetProcessHeap(), 0, pVersionInfo); - - if (bFileCopied) - DeleteFileA(szFile); - - return S_OK; -} - /*********************************************************************** * RegisterOCX (ADVPACK.@) */ @@ -532,133 +288,6 @@ void WINAPI RegisterOCX( HWND hWnd, HINSTANCE hInst, LPCSTR cmdline, INT show ) FreeLibrary(hm); } -static HRESULT DELNODE_recurse_dirtree(LPSTR fname, DWORD flags) -{ - DWORD fattrs = GetFileAttributesA(fname); - HRESULT ret = E_FAIL; - - if (fattrs & FILE_ATTRIBUTE_DIRECTORY) - { - HANDLE hFindFile; - WIN32_FIND_DATAA w32fd; - BOOL done = TRUE; - int fname_len = lstrlenA(fname); - - /* Generate a path with wildcard suitable for iterating */ - if (CharPrevA(fname, fname + fname_len) != "\\") - { - lstrcpyA(fname + fname_len, "\\"); - ++fname_len; - } - lstrcpyA(fname + fname_len, "*"); - - if ((hFindFile = FindFirstFileA(fname, &w32fd)) != INVALID_HANDLE_VALUE) - { - /* Iterate through the files in the directory */ - for (done = FALSE; !done; done = !FindNextFileA(hFindFile, &w32fd)) - { - TRACE("%s\n", w32fd.cFileName); - if (lstrcmpA(".", w32fd.cFileName) != 0 && - lstrcmpA("..", w32fd.cFileName) != 0) - { - lstrcpyA(fname + fname_len, w32fd.cFileName); - if (DELNODE_recurse_dirtree(fname, flags) != S_OK) - { - break; /* Failure */ - } - } - } - FindClose(hFindFile); - } - - /* We're done with this directory, so restore the old path without wildcard */ - *(fname + fname_len) = '\0'; - - if (done) - { - TRACE("%s: directory\n", fname); - if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryA(fname)) - { - ret = S_OK; - } - } - } - else - { - TRACE("%s: file\n", fname); - if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileA(fname)) - { - ret = S_OK; - } - } - - return ret; -} - -/*********************************************************************** - * DelNode (ADVPACK.@) - * - * Deletes a file or directory - * - * PARAMS - * pszFileOrDirName [I] Name of file or directory to delete - * dwFlags [I] Flags; see include/advpub.h - * - * RETURNS - * Success: S_OK - * Failure: E_FAIL - * - * BUGS - * - Ignores flags - * - Native version apparently does a lot of checking to make sure - * we're not trying to delete a system directory etc. - */ -HRESULT WINAPI DelNode( LPCSTR pszFileOrDirName, DWORD dwFlags ) -{ - CHAR fname[MAX_PATH]; - HRESULT ret = E_FAIL; - - TRACE("(%s, 0x%08lx)\n", debugstr_a(pszFileOrDirName), dwFlags); - - if (dwFlags) - FIXME("Flags ignored!\n"); - - if (pszFileOrDirName && *pszFileOrDirName) - { - lstrcpyA(fname, pszFileOrDirName); - - /* TODO: Should check for system directory deletion etc. here */ - - ret = DELNODE_recurse_dirtree(fname, dwFlags); - } - - return ret; -} - -/*********************************************************************** - * DelNodeRunDLL32 (ADVPACK.@) - * - * Deletes a file or directory, WinMain style. - * - * PARAMS - * hWnd [I] Handle to the window used for the display. - * hInst [I] Instance of the process. - * cmdline [I] Contains parameters in the order FileOrDirName,Flags. - * show [I] How the window should be shown. - * - * RETURNS - * Success: S_OK. - * Failure: E_FAIL. - * - * BUGS - * Unimplemented - */ -HRESULT WINAPI DelNodeRunDLL32( HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show ) -{ - FIXME("(%s): stub\n", debugstr_a(cmdline)); - return E_FAIL; -} - /*********************************************************************** * ExecuteCab (ADVPACK.@) * @@ -682,239 +311,6 @@ HRESULT WINAPI ExecuteCab( HWND hwnd, PCABINFO pCab, LPVOID pReserved ) return E_FAIL; } -/* The following defintions were copied from dlls/cabinet/cabinet.h */ - -/* EXTRACTdest flags */ -#define EXTRACT_FILLFILELIST 0x00000001 -#define EXTRACT_EXTRACTFILES 0x00000002 - -struct ExtractFileList { - LPSTR filename; - struct ExtractFileList *next; - BOOL unknown; /* always 1L */ -} ; - -/* the first parameter of the function Extract */ -typedef struct { - long result1; /* 0x000 */ - long unknown1[3]; /* 0x004 */ - struct ExtractFileList *filelist; /* 0x010 */ - long filecount; /* 0x014 */ - DWORD flags; /* 0x018 */ - char directory[0x104]; /* 0x01c */ - char lastfile[0x20c]; /* 0x120 */ -} EXTRACTdest; - -static HRESULT (WINAPI *pExtract)(EXTRACTdest*, LPCSTR); - -/* removes legal characters before and after file list, and - * converts the file list to a NULL-separated list - */ -static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles) -{ - DWORD dwLen; - char *first = (char *)FileList; - char *last = (char *)FileList + strlen(FileList) - 1; - LPSTR szConvertedList, temp; - - /* any number of these chars before the list is OK */ - while (first < last && (*first == ' ' || *first == '\t' || *first == ':')) - first++; - - /* any number of these chars after the list is OK */ - while (last > first && (*last == ' ' || *last == '\t' || *last == ':')) - last--; - - if (first == last) - return NULL; - - dwLen = last - first + 3; /* room for double-null termination */ - szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen); - lstrcpynA(szConvertedList, first, dwLen - 1); - - szConvertedList[dwLen - 1] = '\0'; - szConvertedList[dwLen] = '\0'; - - /* empty list */ - if (!lstrlenA(szConvertedList)) - return NULL; - - *dwNumFiles = 1; - - /* convert the colons to double-null termination */ - temp = szConvertedList; - while (*temp) - { - if (*temp == ':') - { - *temp = '\0'; - (*dwNumFiles)++; - } - - temp++; - } - - return szConvertedList; -} - -static void free_file_node(struct ExtractFileList *pNode) -{ - HeapFree(GetProcessHeap(), 0, pNode->filename); - HeapFree(GetProcessHeap(), 0, pNode); -} - -/* determines whether szFile is in the NULL-separated szFileList */ -static BOOL file_in_list(LPSTR szFile, LPSTR szFileList) -{ - DWORD dwLen = lstrlenA(szFile); - DWORD dwTestLen; - - while (*szFileList) - { - dwTestLen = lstrlenA(szFileList); - - if (dwTestLen == dwLen) - { - if (!lstrcmpiA(szFile, szFileList)) - return TRUE; - } - - szFileList += dwTestLen + 1; - } - - return FALSE; -} - -/* removes nodes from the linked list that aren't specified in szFileList - * returns the number of files that are in both the linked list and szFileList - */ -static DWORD fill_file_list(EXTRACTdest *extractDest, LPCSTR szCabName, LPSTR szFileList) -{ - DWORD dwNumFound = 0; - struct ExtractFileList *pNode; - struct ExtractFileList *prev = NULL; - - extractDest->flags |= EXTRACT_FILLFILELIST; - if (pExtract(extractDest, szCabName)) - { - extractDest->flags &= ~EXTRACT_FILLFILELIST; - return -1; - } - - pNode = extractDest->filelist; - while (pNode) - { - if (file_in_list(pNode->filename, szFileList)) - { - prev = pNode; - pNode = pNode->next; - dwNumFound++; - } - else if (prev) - { - prev->next = pNode->next; - free_file_node(pNode); - pNode = prev->next; - } - else - { - extractDest->filelist = pNode->next; - free_file_node(pNode); - pNode = extractDest->filelist; - } - } - - extractDest->flags &= ~EXTRACT_FILLFILELIST; - return dwNumFound; -} - -/*********************************************************************** - * ExtractFiles (ADVPACK.@) - * - * Extracts the specified files from a cab archive into - * a destination directory. - * - * PARAMS - * CabName [I] Filename of the cab archive. - * ExpandDir [I] Destination directory for the extracted files. - * Flags [I] Reserved. - * FileList [I] Optional list of files to extract. See NOTES. - * LReserved [I] Reserved. Must be NULL. - * Reserved [I] Reserved. Must be 0. - * - * RETURNS - * Success: S_OK. - * Failure: E_FAIL. - * - * NOTES - * FileList is a colon-separated list of filenames. If FileList is - * non-NULL, only the files in the list will be extracted from the - * cab file, otherwise all files will be extracted. Any number of - * spaces, tabs, or colons can be before or after the list, but - * the list itself must only be separated by colons. - */ -HRESULT WINAPI ExtractFiles ( LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags, - LPCSTR FileList, LPVOID LReserved, DWORD Reserved) -{ - EXTRACTdest extractDest; - HMODULE hCabinet; - HRESULT res = S_OK; - DWORD dwFileCount = 0; - DWORD dwFilesFound = 0; - LPSTR szConvertedList = NULL; - - TRACE("(%p %p %ld %p %p %ld): stub\n", CabName, ExpandDir, Flags, - FileList, LReserved, Reserved); - - if (!CabName || !ExpandDir) - return E_INVALIDARG; - - if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES) - return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); - - hCabinet = LoadLibraryA("cabinet.dll"); - if (!hCabinet) - return E_FAIL; - - pExtract = (void *)GetProcAddress(hCabinet, "Extract"); - if (!pExtract) - { - res = E_FAIL; - goto done; - } - - ZeroMemory(&extractDest, sizeof(EXTRACTdest)); - lstrcpyA(extractDest.directory, ExpandDir); - - if (FileList) - { - szConvertedList = convert_file_list(FileList, &dwFileCount); - if (!szConvertedList || dwFileCount == -1) - { - res = E_FAIL; - goto done; - } - - dwFilesFound = fill_file_list(&extractDest, CabName, szConvertedList); - if (dwFilesFound != dwFileCount) - { - res = E_FAIL; - goto done; - } - } - else - extractDest.flags |= EXTRACT_FILLFILELIST; - - extractDest.flags |= EXTRACT_EXTRACTFILES; - res = pExtract(&extractDest, CabName); - -done: - FreeLibrary(hCabinet); - HeapFree(GetProcessHeap(), 0, szConvertedList); - - return res; -} - /*********************************************************************** * TranslateInfString (ADVPACK.@) * diff --git a/dlls/advpack/files.c b/dlls/advpack/files.c index 46ff983e656..6c2d333a696 100644 --- a/dlls/advpack/files.c +++ b/dlls/advpack/files.c @@ -23,11 +23,501 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "winreg.h" +#include "winver.h" +#include "setupapi.h" #include "advpub.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(advpack); +/* FIXME: this is only for the local case, X:\ */ +#define ROOT_LENGTH 3 + +UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification, + UINT_PTR Param1, UINT_PTR Param2) +{ + return 1; +} + +UINT CALLBACK pQueueCallback(PVOID Context, UINT Notification, + UINT_PTR Param1, UINT_PTR Param2) +{ + /* only be verbose for error notifications */ + if (!Notification || + Notification == SPFILENOTIFY_RENAMEERROR || + Notification == SPFILENOTIFY_DELETEERROR || + Notification == SPFILENOTIFY_COPYERROR) + { + return SetupDefaultQueueCallbackA(Context, Notification, + Param1, Param2); + } + + return 1; +} + +/*********************************************************************** + * AdvInstallFile (ADVPACK.@) + * + * Copies a file from the source to a destination. + * + * PARAMS + * hwnd [I] Handle to the window used for messages. + * lpszSourceDir [I] Source directory. + * lpszSourceFile [I] Source filename. + * lpszDestDir [I] Destination directory. + * lpszDestFile [I] Optional destination filename. + * dwFlags [I] See advpub.h. + * dwReserved [I] Reserved. Must be 0. + * + * RETURNS + * Success: S_OK. + * Failure: E_FAIL. + * + * NOTES + * If lpszDestFile is NULL, the destination filename is the same as + * lpszSourceFIle. + */ +HRESULT WINAPI AdvInstallFile(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile, + LPCSTR lpszDestDir, LPCSTR lpszDestFile, + DWORD dwFlags, DWORD dwReserved) +{ + PSP_FILE_CALLBACK_A pFileCallback; + LPSTR szPath, szDestFilename; + char szRootPath[ROOT_LENGTH]; + DWORD dwLen, dwLastError; + HSPFILEQ fileQueue; + PVOID pContext; + + TRACE("(%p,%p,%p,%p,%p,%ld,%ld) stub\n", hwnd, debugstr_a(lpszSourceDir), + debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir), + debugstr_a(lpszDestFile), dwFlags, dwReserved); + + if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir) + return E_INVALIDARG; + + fileQueue = SetupOpenFileQueue(); + if (fileQueue == INVALID_HANDLE_VALUE) + return HRESULT_FROM_WIN32(GetLastError()); + + pContext = NULL; + dwLastError = ERROR_SUCCESS; + + lstrcpynA(szRootPath, lpszSourceDir, ROOT_LENGTH); + szPath = (LPSTR)lpszSourceDir + ROOT_LENGTH; + + /* use lpszSourceFile as destination filename if lpszDestFile is NULL */ + if (lpszDestFile) + { + dwLen = lstrlenA(lpszDestFile); + szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen); + lstrcpyA(szDestFilename, lpszDestFile); + } + else + { + dwLen = lstrlenA(lpszSourceFile); + szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen); + lstrcpyA(szDestFilename, lpszSourceFile); + } + + /* add the file copy operation to the setup queue */ + if (!SetupQueueCopyA(fileQueue, szRootPath, szPath, lpszSourceFile, NULL, + NULL, lpszDestDir, szDestFilename, dwFlags)) + { + dwLastError = GetLastError(); + goto done; + } + + pContext = SetupInitDefaultQueueCallbackEx(hwnd, INVALID_HANDLE_VALUE, + 0, 0, NULL); + if (!pContext) + { + dwLastError = GetLastError(); + goto done; + } + + /* don't output anything for AIF_QUIET */ + if (dwFlags & AIF_QUIET) + pFileCallback = pQuietQueueCallback; + else + pFileCallback = pQueueCallback; + + /* perform the file copy */ + if (!SetupCommitFileQueueA(hwnd, fileQueue, pFileCallback, pContext)) + { + dwLastError = GetLastError(); + goto done; + } + +done: + SetupTermDefaultQueueCallback(pContext); + SetupCloseFileQueue(fileQueue); + + HeapFree(GetProcessHeap(), 0, szDestFilename); + + return HRESULT_FROM_WIN32(dwLastError); +} + +static HRESULT DELNODE_recurse_dirtree(LPSTR fname, DWORD flags) +{ + DWORD fattrs = GetFileAttributesA(fname); + HRESULT ret = E_FAIL; + + if (fattrs & FILE_ATTRIBUTE_DIRECTORY) + { + HANDLE hFindFile; + WIN32_FIND_DATAA w32fd; + BOOL done = TRUE; + int fname_len = lstrlenA(fname); + + /* Generate a path with wildcard suitable for iterating */ + if (CharPrevA(fname, fname + fname_len) != "\\") + { + lstrcpyA(fname + fname_len, "\\"); + ++fname_len; + } + lstrcpyA(fname + fname_len, "*"); + + if ((hFindFile = FindFirstFileA(fname, &w32fd)) != INVALID_HANDLE_VALUE) + { + /* Iterate through the files in the directory */ + for (done = FALSE; !done; done = !FindNextFileA(hFindFile, &w32fd)) + { + TRACE("%s\n", w32fd.cFileName); + if (lstrcmpA(".", w32fd.cFileName) != 0 && + lstrcmpA("..", w32fd.cFileName) != 0) + { + lstrcpyA(fname + fname_len, w32fd.cFileName); + if (DELNODE_recurse_dirtree(fname, flags) != S_OK) + { + break; /* Failure */ + } + } + } + FindClose(hFindFile); + } + + /* We're done with this directory, so restore the old path without wildcard */ + *(fname + fname_len) = '\0'; + + if (done) + { + TRACE("%s: directory\n", fname); + if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && RemoveDirectoryA(fname)) + { + ret = S_OK; + } + } + } + else + { + TRACE("%s: file\n", fname); + if (SetFileAttributesA(fname, FILE_ATTRIBUTE_NORMAL) && DeleteFileA(fname)) + { + ret = S_OK; + } + } + + return ret; +} + +/*********************************************************************** + * DelNode (ADVPACK.@) + * + * Deletes a file or directory + * + * PARAMS + * pszFileOrDirName [I] Name of file or directory to delete + * dwFlags [I] Flags; see include/advpub.h + * + * RETURNS + * Success: S_OK + * Failure: E_FAIL + * + * BUGS + * - Ignores flags + * - Native version apparently does a lot of checking to make sure + * we're not trying to delete a system directory etc. + */ +HRESULT WINAPI DelNode( LPCSTR pszFileOrDirName, DWORD dwFlags ) +{ + CHAR fname[MAX_PATH]; + HRESULT ret = E_FAIL; + + TRACE("(%s, 0x%08lx)\n", debugstr_a(pszFileOrDirName), dwFlags); + + if (dwFlags) + FIXME("Flags ignored!\n"); + + if (pszFileOrDirName && *pszFileOrDirName) + { + lstrcpyA(fname, pszFileOrDirName); + + /* TODO: Should check for system directory deletion etc. here */ + + ret = DELNODE_recurse_dirtree(fname, dwFlags); + } + + return ret; +} + +/*********************************************************************** + * DelNodeRunDLL32 (ADVPACK.@) + * + * Deletes a file or directory, WinMain style. + * + * PARAMS + * hWnd [I] Handle to the window used for the display. + * hInst [I] Instance of the process. + * cmdline [I] Contains parameters in the order FileOrDirName,Flags. + * show [I] How the window should be shown. + * + * RETURNS + * Success: S_OK. + * Failure: E_FAIL. + * + * BUGS + * Unimplemented + */ +HRESULT WINAPI DelNodeRunDLL32( HWND hWnd, HINSTANCE hInst, LPSTR cmdline, INT show ) +{ + FIXME("(%s): stub\n", debugstr_a(cmdline)); + return E_FAIL; +} + +/* The following defintions were copied from dlls/cabinet/cabinet.h */ + +/* EXTRACTdest flags */ +#define EXTRACT_FILLFILELIST 0x00000001 +#define EXTRACT_EXTRACTFILES 0x00000002 + +struct ExtractFileList { + LPSTR filename; + struct ExtractFileList *next; + BOOL unknown; /* always 1L */ +} ; + +/* the first parameter of the function Extract */ +typedef struct { + long result1; /* 0x000 */ + long unknown1[3]; /* 0x004 */ + struct ExtractFileList *filelist; /* 0x010 */ + long filecount; /* 0x014 */ + DWORD flags; /* 0x018 */ + char directory[0x104]; /* 0x01c */ + char lastfile[0x20c]; /* 0x120 */ +} EXTRACTdest; + +static HRESULT (WINAPI *pExtract)(EXTRACTdest*, LPCSTR); + +/* removes legal characters before and after file list, and + * converts the file list to a NULL-separated list + */ +static LPSTR convert_file_list(LPCSTR FileList, DWORD *dwNumFiles) +{ + DWORD dwLen; + char *first = (char *)FileList; + char *last = (char *)FileList + strlen(FileList) - 1; + LPSTR szConvertedList, temp; + + /* any number of these chars before the list is OK */ + while (first < last && (*first == ' ' || *first == '\t' || *first == ':')) + first++; + + /* any number of these chars after the list is OK */ + while (last > first && (*last == ' ' || *last == '\t' || *last == ':')) + last--; + + if (first == last) + return NULL; + + dwLen = last - first + 3; /* room for double-null termination */ + szConvertedList = HeapAlloc(GetProcessHeap(), 0, dwLen); + lstrcpynA(szConvertedList, first, dwLen - 1); + + szConvertedList[dwLen - 1] = '\0'; + szConvertedList[dwLen] = '\0'; + + /* empty list */ + if (!lstrlenA(szConvertedList)) + return NULL; + + *dwNumFiles = 1; + + /* convert the colons to double-null termination */ + temp = szConvertedList; + while (*temp) + { + if (*temp == ':') + { + *temp = '\0'; + (*dwNumFiles)++; + } + + temp++; + } + + return szConvertedList; +} + +static void free_file_node(struct ExtractFileList *pNode) +{ + HeapFree(GetProcessHeap(), 0, pNode->filename); + HeapFree(GetProcessHeap(), 0, pNode); +} + +/* determines whether szFile is in the NULL-separated szFileList */ +static BOOL file_in_list(LPSTR szFile, LPSTR szFileList) +{ + DWORD dwLen = lstrlenA(szFile); + DWORD dwTestLen; + + while (*szFileList) + { + dwTestLen = lstrlenA(szFileList); + + if (dwTestLen == dwLen) + { + if (!lstrcmpiA(szFile, szFileList)) + return TRUE; + } + + szFileList += dwTestLen + 1; + } + + return FALSE; +} + +/* removes nodes from the linked list that aren't specified in szFileList + * returns the number of files that are in both the linked list and szFileList + */ +static DWORD fill_file_list(EXTRACTdest *extractDest, LPCSTR szCabName, LPSTR szFileList) +{ + DWORD dwNumFound = 0; + struct ExtractFileList *pNode; + struct ExtractFileList *prev = NULL; + + extractDest->flags |= EXTRACT_FILLFILELIST; + if (pExtract(extractDest, szCabName)) + { + extractDest->flags &= ~EXTRACT_FILLFILELIST; + return -1; + } + + pNode = extractDest->filelist; + while (pNode) + { + if (file_in_list(pNode->filename, szFileList)) + { + prev = pNode; + pNode = pNode->next; + dwNumFound++; + } + else if (prev) + { + prev->next = pNode->next; + free_file_node(pNode); + pNode = prev->next; + } + else + { + extractDest->filelist = pNode->next; + free_file_node(pNode); + pNode = extractDest->filelist; + } + } + + extractDest->flags &= ~EXTRACT_FILLFILELIST; + return dwNumFound; +} + +/*********************************************************************** + * ExtractFiles (ADVPACK.@) + * + * Extracts the specified files from a cab archive into + * a destination directory. + * + * PARAMS + * CabName [I] Filename of the cab archive. + * ExpandDir [I] Destination directory for the extracted files. + * Flags [I] Reserved. + * FileList [I] Optional list of files to extract. See NOTES. + * LReserved [I] Reserved. Must be NULL. + * Reserved [I] Reserved. Must be 0. + * + * RETURNS + * Success: S_OK. + * Failure: E_FAIL. + * + * NOTES + * FileList is a colon-separated list of filenames. If FileList is + * non-NULL, only the files in the list will be extracted from the + * cab file, otherwise all files will be extracted. Any number of + * spaces, tabs, or colons can be before or after the list, but + * the list itself must only be separated by colons. + */ +HRESULT WINAPI ExtractFiles ( LPCSTR CabName, LPCSTR ExpandDir, DWORD Flags, + LPCSTR FileList, LPVOID LReserved, DWORD Reserved) +{ + EXTRACTdest extractDest; + HMODULE hCabinet; + HRESULT res = S_OK; + DWORD dwFileCount = 0; + DWORD dwFilesFound = 0; + LPSTR szConvertedList = NULL; + + TRACE("(%p %p %ld %p %p %ld): stub\n", CabName, ExpandDir, Flags, + FileList, LReserved, Reserved); + + if (!CabName || !ExpandDir) + return E_INVALIDARG; + + if (GetFileAttributesA(ExpandDir) == INVALID_FILE_ATTRIBUTES) + return HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND); + + hCabinet = LoadLibraryA("cabinet.dll"); + if (!hCabinet) + return E_FAIL; + + pExtract = (void *)GetProcAddress(hCabinet, "Extract"); + if (!pExtract) + { + res = E_FAIL; + goto done; + } + + ZeroMemory(&extractDest, sizeof(EXTRACTdest)); + lstrcpyA(extractDest.directory, ExpandDir); + + if (FileList) + { + szConvertedList = convert_file_list(FileList, &dwFileCount); + if (!szConvertedList || dwFileCount == -1) + { + res = E_FAIL; + goto done; + } + + dwFilesFound = fill_file_list(&extractDest, CabName, szConvertedList); + if (dwFilesFound != dwFileCount) + { + res = E_FAIL; + goto done; + } + } + else + extractDest.flags |= EXTRACT_FILLFILELIST; + + extractDest.flags |= EXTRACT_EXTRACTFILES; + res = pExtract(&extractDest, CabName); + +done: + FreeLibrary(hCabinet); + HeapFree(GetProcessHeap(), 0, szConvertedList); + + return res; +} + /*********************************************************************** * FileSaveMarkNotExist (ADVPACK.@) * @@ -116,3 +606,120 @@ HRESULT WINAPI FileSaveRestoreOnINF(HWND hWnd, PCSTR pszTitle, PCSTR pszINF, return E_FAIL; } + +/*********************************************************************** + * GetVersionFromFile (ADVPACK.@) + * + * See GetVersionFromFileEx. + */ +HRESULT WINAPI GetVersionFromFile( LPSTR Filename, LPDWORD MajorVer, + LPDWORD MinorVer, BOOL Version ) +{ + TRACE("(%s, %p, %p, %d)\n", Filename, MajorVer, MinorVer, Version); + return GetVersionFromFileEx(Filename, MajorVer, MinorVer, Version); +} + +/* data for GetVersionFromFileEx */ +typedef struct tagLANGANDCODEPAGE +{ + WORD wLanguage; + WORD wCodePage; +} LANGANDCODEPAGE; + +/*********************************************************************** + * GetVersionFromFileEx (ADVPACK.@) + * + * Gets the files version or language information. + * + * PARAMS + * lpszFilename [I] The file to get the info from. + * pdwMSVer [O] Major version. + * pdwLSVer [O] Minor version. + * bVersion [I] Whether to retrieve version or language info. + * + * RETURNS + * Always returns S_OK. + * + * NOTES + * If bVersion is TRUE, version information is retrieved, else + * pdwMSVer gets the language ID and pdwLSVer gets the codepage ID. + */ +HRESULT WINAPI GetVersionFromFileEx( LPSTR lpszFilename, LPDWORD pdwMSVer, + LPDWORD pdwLSVer, BOOL bVersion ) +{ + VS_FIXEDFILEINFO *pFixedVersionInfo; + LANGANDCODEPAGE *pLangAndCodePage; + DWORD dwHandle, dwInfoSize; + CHAR szWinDir[MAX_PATH]; + CHAR szFile[MAX_PATH]; + LPVOID pVersionInfo = NULL; + BOOL bFileCopied = FALSE; + UINT uValueLen; + + TRACE("(%s, %p, %p, %d)\n", lpszFilename, pdwMSVer, pdwLSVer, bVersion); + + *pdwLSVer = 0; + *pdwMSVer = 0; + + lstrcpynA(szFile, lpszFilename, MAX_PATH); + + dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle); + if (!dwInfoSize) + { + /* check that the file exists */ + if (GetFileAttributesA(szFile) == INVALID_FILE_ATTRIBUTES) + return S_OK; + + /* file exists, but won't be found by GetFileVersionInfoSize, + * so copy it to the temp dir where it will be found. + */ + GetWindowsDirectoryA(szWinDir, MAX_PATH); + GetTempFileNameA(szWinDir, NULL, 0, szFile); + CopyFileA(lpszFilename, szFile, FALSE); + bFileCopied = TRUE; + + dwInfoSize = GetFileVersionInfoSizeA(szFile, &dwHandle); + if (!dwInfoSize) + goto done; + } + + pVersionInfo = HeapAlloc(GetProcessHeap(), 0, dwInfoSize); + if (!pVersionInfo) + goto done; + + if (!GetFileVersionInfoA(szFile, dwHandle, dwInfoSize, pVersionInfo)) + goto done; + + if (bVersion) + { + if (!VerQueryValueA(pVersionInfo, "\\", + (LPVOID *)&pFixedVersionInfo, &uValueLen)) + goto done; + + if (!uValueLen) + goto done; + + *pdwMSVer = pFixedVersionInfo->dwFileVersionMS; + *pdwLSVer = pFixedVersionInfo->dwFileVersionLS; + } + else + { + if (!VerQueryValueA(pVersionInfo, "\\VarFileInfo\\Translation", + (LPVOID *)&pLangAndCodePage, &uValueLen)) + goto done; + + if (!uValueLen) + goto done; + + *pdwMSVer = pLangAndCodePage->wLanguage; + *pdwLSVer = pLangAndCodePage->wCodePage; + } + +done: + HeapFree(GetProcessHeap(), 0, pVersionInfo); + + if (bFileCopied) + DeleteFileA(szFile); + + return S_OK; +}