📄 files.c
字号:
/*
* Advpack file functions
*
* Copyright 2006 James Hawkins
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <stdarg.h>
#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "winreg.h"
#include "winver.h"
#include "winternl.h"
#include "setupapi.h"
#include "advpub.h"
#include "wine/debug.h"
#include "wine/unicode.h"
#include "advpack_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(advpack);
/* converts an ansi double null-terminated list to a unicode list */
static LPWSTR ansi_to_unicode_list(LPCSTR ansi_list)
{
DWORD len, wlen = 0;
LPWSTR list;
LPCSTR ptr = ansi_list;
while (*ptr) ptr += lstrlenA(ptr) + 1;
len = ptr + 1 - ansi_list;
wlen = MultiByteToWideChar(CP_ACP, 0, ansi_list, len, NULL, 0);
list = HeapAlloc(GetProcessHeap(), 0, wlen * sizeof(WCHAR));
MultiByteToWideChar(CP_ACP, 0, ansi_list, len, list, wlen);
return list;
}
/***********************************************************************
* AddDelBackupEntryA (ADVPACK.@)
*
* See AddDelBackupEntryW.
*/
HRESULT WINAPI AddDelBackupEntryA(LPCSTR lpcszFileList, LPCSTR lpcszBackupDir,
LPCSTR lpcszBaseName, DWORD dwFlags)
{
UNICODE_STRING backupdir, basename;
LPWSTR filelist;
LPCWSTR backup;
HRESULT res;
TRACE("(%s, %s, %s, %d)\n", debugstr_a(lpcszFileList),
debugstr_a(lpcszBackupDir), debugstr_a(lpcszBaseName), dwFlags);
if (lpcszFileList)
filelist = ansi_to_unicode_list(lpcszFileList);
else
filelist = NULL;
RtlCreateUnicodeStringFromAsciiz(&backupdir, lpcszBackupDir);
RtlCreateUnicodeStringFromAsciiz(&basename, lpcszBaseName);
if (lpcszBackupDir)
backup = backupdir.Buffer;
else
backup = NULL;
res = AddDelBackupEntryW(filelist, backup, basename.Buffer, dwFlags);
HeapFree(GetProcessHeap(), 0, filelist);
RtlFreeUnicodeString(&backupdir);
RtlFreeUnicodeString(&basename);
return res;
}
/***********************************************************************
* AddDelBackupEntryW (ADVPACK.@)
*
* Either appends the files in the file list to the backup section of
* the specified INI, or deletes the entries from the INI file.
*
* PARAMS
* lpcszFileList [I] NULL-separated list of filenames.
* lpcszBackupDir [I] Path of the backup directory.
* lpcszBaseName [I] Basename of the INI file.
* dwFlags [I] AADBE_ADD_ENTRY adds the entries in the file list
* to the INI file, while AADBE_DEL_ENTRY removes
* the entries from the INI file.
*
* RETURNS
* S_OK in all cases.
*
* NOTES
* If the INI file does not exist before adding entries to it, the file
* will be created.
*
* If lpcszBackupDir is NULL, the INI file is assumed to exist in
* c:\windows or created there if it does not exist.
*/
HRESULT WINAPI AddDelBackupEntryW(LPCWSTR lpcszFileList, LPCWSTR lpcszBackupDir,
LPCWSTR lpcszBaseName, DWORD dwFlags)
{
WCHAR szIniPath[MAX_PATH];
LPCWSTR szString = NULL;
static const WCHAR szBackupEntry[] = {
'-','1',',','0',',','0',',','0',',','0',',','0',',','-','1',0
};
static const WCHAR backslash[] = {'\\',0};
static const WCHAR ini[] = {'.','i','n','i',0};
static const WCHAR backup[] = {'b','a','c','k','u','p',0};
TRACE("(%s, %s, %s, %d)\n", debugstr_w(lpcszFileList),
debugstr_w(lpcszBackupDir), debugstr_w(lpcszBaseName), dwFlags);
if (!lpcszFileList || !*lpcszFileList)
return S_OK;
if (lpcszBackupDir)
lstrcpyW(szIniPath, lpcszBackupDir);
else
GetWindowsDirectoryW(szIniPath, MAX_PATH);
lstrcatW(szIniPath, backslash);
lstrcatW(szIniPath, lpcszBaseName);
lstrcatW(szIniPath, ini);
SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_NORMAL);
if (dwFlags & AADBE_ADD_ENTRY)
szString = szBackupEntry;
else if (dwFlags & AADBE_DEL_ENTRY)
szString = NULL;
/* add or delete the INI entries */
while (*lpcszFileList)
{
WritePrivateProfileStringW(backup, lpcszFileList, szString, szIniPath);
lpcszFileList += lstrlenW(lpcszFileList) + 1;
}
/* hide the INI file */
SetFileAttributesW(szIniPath, FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN);
return S_OK;
}
/* FIXME: this is only for the local case, X:\ */
#define ROOT_LENGTH 3
static UINT CALLBACK pQuietQueueCallback(PVOID Context, UINT Notification,
UINT_PTR Param1, UINT_PTR Param2)
{
return 1;
}
static 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 SetupDefaultQueueCallbackW(Context, Notification,
Param1, Param2);
}
return 1;
}
/***********************************************************************
* AdvInstallFileA (ADVPACK.@)
*
* See AdvInstallFileW.
*/
HRESULT WINAPI AdvInstallFileA(HWND hwnd, LPCSTR lpszSourceDir, LPCSTR lpszSourceFile,
LPCSTR lpszDestDir, LPCSTR lpszDestFile,
DWORD dwFlags, DWORD dwReserved)
{
UNICODE_STRING sourcedir, sourcefile;
UNICODE_STRING destdir, destfile;
HRESULT res;
TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_a(lpszSourceDir),
debugstr_a(lpszSourceFile), debugstr_a(lpszDestDir),
debugstr_a(lpszDestFile), dwFlags, dwReserved);
if (!lpszSourceDir || !lpszSourceFile || !lpszDestDir)
return E_INVALIDARG;
RtlCreateUnicodeStringFromAsciiz(&sourcedir, lpszSourceDir);
RtlCreateUnicodeStringFromAsciiz(&sourcefile, lpszSourceFile);
RtlCreateUnicodeStringFromAsciiz(&destdir, lpszDestDir);
RtlCreateUnicodeStringFromAsciiz(&destfile, lpszDestFile);
res = AdvInstallFileW(hwnd, sourcedir.Buffer, sourcefile.Buffer,
destdir.Buffer, destfile.Buffer, dwFlags, dwReserved);
RtlFreeUnicodeString(&sourcedir);
RtlFreeUnicodeString(&sourcefile);
RtlFreeUnicodeString(&destdir);
RtlFreeUnicodeString(&destfile);
return res;
}
/***********************************************************************
* AdvInstallFileW (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 AdvInstallFileW(HWND hwnd, LPCWSTR lpszSourceDir, LPCWSTR lpszSourceFile,
LPCWSTR lpszDestDir, LPCWSTR lpszDestFile,
DWORD dwFlags, DWORD dwReserved)
{
PSP_FILE_CALLBACK_W pFileCallback;
LPWSTR szDestFilename;
LPCWSTR szPath;
WCHAR szRootPath[ROOT_LENGTH];
DWORD dwLen, dwLastError;
HSPFILEQ fileQueue;
PVOID pContext;
TRACE("(%p, %s, %s, %s, %s, %d, %d)\n", hwnd, debugstr_w(lpszSourceDir),
debugstr_w(lpszSourceFile), debugstr_w(lpszDestDir),
debugstr_w(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;
lstrcpynW(szRootPath, lpszSourceDir, ROOT_LENGTH);
szPath = lpszSourceDir + ROOT_LENGTH;
/* use lpszSourceFile as destination filename if lpszDestFile is NULL */
if (lpszDestFile)
{
dwLen = lstrlenW(lpszDestFile);
szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
lstrcpyW(szDestFilename, lpszDestFile);
}
else
{
dwLen = lstrlenW(lpszSourceFile);
szDestFilename = HeapAlloc(GetProcessHeap(), 0, dwLen * sizeof(WCHAR));
lstrcpyW(szDestFilename, lpszSourceFile);
}
/* add the file copy operation to the setup queue */
if (!SetupQueueCopyW(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 (!SetupCommitFileQueueW(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(LPWSTR fname, DWORD flags)
{
DWORD fattrs = GetFileAttributesW(fname);
HRESULT ret = E_FAIL;
static const WCHAR asterisk[] = {'*',0};
static const WCHAR dot[] = {'.',0};
static const WCHAR dotdot[] = {'.','.',0};
if (fattrs & FILE_ATTRIBUTE_DIRECTORY)
{
HANDLE hFindFile;
WIN32_FIND_DATAW w32fd;
BOOL done = TRUE;
int fname_len = lstrlenW(fname);
/* Generate a path with wildcard suitable for iterating */
if (fname_len && fname[fname_len-1] != '\\') fname[fname_len++] = '\\';
lstrcpyW(fname + fname_len, asterisk);
if ((hFindFile = FindFirstFileW(fname, &w32fd)) != INVALID_HANDLE_VALUE)
{
/* Iterate through the files in the directory */
for (done = FALSE; !done; done = !FindNextFileW(hFindFile, &w32fd))
{
TRACE("%s\n", debugstr_w(w32fd.cFileName));
if (lstrcmpW(dot, w32fd.cFileName) != 0 &&
lstrcmpW(dotdot, w32fd.cFileName) != 0)
{
lstrcpyW(fname + fname_len, w32fd.cFileName);
if (DELNODE_recurse_dirtree(fname, flags) != S_OK)
{
break; /* Failure */
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -