|
|
//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 2000
//
// File: cscpin.cpp
//
//--------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include <stdio.h>
#include "cscpin.h"
#include "console.h"
#include "error.h"
#include "exitcode.h"
#include "listfile.h"
#include "print.h"
#include "strings.h"
//-----------------------------------------------------------------------------
// CCscPinItem
//
// This class represents a single item being pinned or unpinned.
// It contains all of the knowledge of how to pin and unpin a file. The
// CCscPin class coordinates the pinning and unpinning of the entire set
// of files.
//-----------------------------------------------------------------------------
class CCscPinItem { public: CCscPinItem(LPCWSTR pszFile, const WIN32_FIND_DATAW *pfd, const CPrint& pr);
DWORD Pin(DWORD *pdwCscResult = NULL); DWORD Unpin(DWORD *pdwCscResult = NULL); DWORD DeleteIfUnused(void);
private: WCHAR m_szFile[MAX_PATH]; SHFILEINFOW m_sfi; WIN32_FIND_DATAW m_fd; BOOL m_bIsValidUnc; // Is m_szFile a valid UNC?
BOOL m_bIsValidFindData; // Is m_fd valid?
const CPrint& m_pr; // For console/log output.
bool _Skip(void) const; DWORD _PinFile(LPCWSTR pszFile, WIN32_FIND_DATAW *pfd, DWORD *pdwCscResult); DWORD _PinOrUnpinLinkTarget(LPCWSTR pszFile, BOOL bPin, DWORD *pdwCscResult); DWORD _PinLinkTarget(LPCWSTR pszFile, DWORD *pdwCscResult) { return _PinOrUnpinLinkTarget(pszFile, TRUE, pdwCscResult); } DWORD _UnpinLinkTarget(LPCWSTR pszFile, DWORD *pdwCscResult) { return _PinOrUnpinLinkTarget(pszFile, FALSE, pdwCscResult); } DWORD _UnpinFile(LPCWSTR pszFile, WIN32_FIND_DATAW *pfd, DWORD *pdwCscResult); DWORD _GetDesiredPinCount(LPCWSTR pszFile); void _DecrementPinCountForFile(LPCWSTR pszFile, DWORD dwCurrentPinCount); BOOL _IsSpecialRedirectedFile(LPCWSTR pszFile); WIN32_FIND_DATAW *_FindDataPtrOrNull(void) { return m_bIsValidFindData ? &m_fd : NULL; }
//
// Prevent copy.
//
CCscPinItem(const CCscPinItem& rhs); // not implemented.
CCscPinItem& operator = (const CCscPinItem& rhs); // not implemented.
};
CCscPinItem::CCscPinItem( LPCWSTR pszFile, const WIN32_FIND_DATAW *pfd, // Optional. May be NULL.
const CPrint& pr ) : m_bIsValidUnc(FALSE), m_bIsValidFindData(FALSE), m_pr(pr) { TraceAssert(NULL != pszFile);
lstrcpynW(m_szFile, pszFile, ARRAYSIZE(m_szFile));
if (NULL != pfd) { m_fd = *pfd; m_bIsValidFindData = TRUE; }
ZeroMemory(&m_sfi, sizeof(m_sfi)); m_sfi.dwAttributes = SFGAO_FILESYSTEM | SFGAO_LINK;
if (PathIsUNCW(m_szFile) && SHGetFileInfoW(m_szFile, 0, &m_sfi, sizeof(m_sfi), SHGFI_ATTRIBUTES | SHGFI_ATTR_SPECIFIED)) { m_bIsValidUnc = true; } }
//
// Pins the item's file. If the item is a link, the link target
// is also pinned.
// Returns one of the CSCPROC_RETURN_XXXXX codes.
// Optionally returns the result of CSCPinFile.
//
DWORD CCscPinItem::Pin( DWORD *pdwCscResult // Optional. Default is NULL.
) { TraceEnter(TRACE_ADMINPIN, "CCscPinItem::Pin");
DWORD dwCscResult = ERROR_SUCCESS; DWORD dwResult = CSCPROC_RETURN_SKIP;
if (!_Skip()) { if (SFGAO_LINK & m_sfi.dwAttributes) { //
// Ignore result from pinning the link target.
//
DWORD dwCscResultIgnored; _PinLinkTarget(m_szFile, &dwCscResultIgnored); } dwResult = _PinFile(m_szFile, _FindDataPtrOrNull(), &dwCscResult); } if (NULL != pdwCscResult) { *pdwCscResult = dwCscResult; } TraceLeaveValue(dwResult); }
//
// Unpins the item's file.
// Returns one of the CSCPROC_RETURN_XXXXX codes.
// Optionally returns the result of CSCUnpinFile.
//
DWORD CCscPinItem::Unpin( DWORD *pdwCscResult // Optional. Default is NULL.
) { TraceEnter(TRACE_ADMINPIN, "CCscPinItem::Unpin");
DWORD dwCscResult = ERROR_SUCCESS; DWORD dwResult = CSCPROC_RETURN_SKIP;
if (!_Skip()) { if (SFGAO_LINK & m_sfi.dwAttributes) { //
// Ignore result from unpinning the link target.
//
DWORD dwCscResultIgnored; _UnpinLinkTarget(m_szFile, &dwCscResultIgnored); } dwResult = _UnpinFile(m_szFile, _FindDataPtrOrNull(), &dwCscResult); } if (NULL != pdwCscResult) { *pdwCscResult = dwCscResult; } TraceLeaveResult(dwResult); }
//
// Delete an item if it is no longer used.
//
DWORD CCscPinItem::DeleteIfUnused( void ) { TraceEnter(TRACE_ADMINPIN, "CCscPin::DeleteIfUnused");
DWORD dwStatus = 0; DWORD dwPinCount = 0; DWORD dwHintFlags = 0; DWORD dwResult = ERROR_SUCCESS;
if (CSCQueryFileStatusW(m_szFile, &dwStatus, &dwPinCount, &dwHintFlags) && 0 == dwPinCount && 0 == dwHintFlags && !(dwStatus & FLAG_CSCUI_COPY_STATUS_LOCALLY_DIRTY)) { dwResult = CscDelete(m_szFile); if (ERROR_SUCCESS == dwResult) { m_pr.PrintVerbose(L"Deleted \"%s\" from cache.\n", m_szFile); ShellChangeNotify(m_szFile, _FindDataPtrOrNull(), FALSE); } else { if (ERROR_DIR_NOT_EMPTY == dwResult) { dwResult = ERROR_SUCCESS; } if (ERROR_SUCCESS != dwResult) { m_pr.PrintAlways(L"Error deleting \"%s\" from cache. %s\n", m_szFile, CWinError(dwResult).Text());
} } } TraceLeaveValue(dwResult); }
//
// Internal function for pinning a file. This is a common
// function called by both Pin() and _PinOrUnpinLinkTarget().
//
DWORD CCscPinItem::_PinFile( LPCWSTR pszFile, // UNC path of file to pin.
WIN32_FIND_DATAW *pfd, // Optional. May be NULL.
DWORD *pdwCscResult // Result of CSCPinFile.
) { TraceEnter(TRACE_ADMINPIN, "CCscPinItem::_PinFile"); TraceAssert(NULL != pszFile); TraceAssert(NULL != pdwCscResult);
*pdwCscResult = ERROR_SUCCESS; //
// Collect cache information for the item.
// This may fail, for example if the file is not in the cache
//
DWORD dwPinCount = 0; DWORD dwHintFlags = 0; CSCQueryFileStatusW(pszFile, NULL, &dwPinCount, &dwHintFlags); //
// Is the admin flag already turned on?
//
const BOOL bNewItem = !(dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN); if (bNewItem) { //
// Turn on the admin flag
//
dwHintFlags |= FLAG_CSC_HINT_PIN_ADMIN;
if (CSCPinFileW(pszFile, dwHintFlags, NULL, &dwPinCount, &dwHintFlags)) { m_pr.PrintVerbose(L"Pin \"%s\"\n", pszFile); ShellChangeNotify(pszFile, pfd, FALSE); } else { const DWORD dwErr = GetLastError(); if (ERROR_INVALID_NAME == dwErr) { //
// This is the error we get from CSC when trying to
// pin a file in the exclusion list. Display a unique
// error message for this particular situation.
//
m_pr.PrintAlways(L"Pinning file \"%s\" is not allowed.\n", pszFile); } else { m_pr.PrintAlways(L"Error pinning \"%s\". %s\n", pszFile, CWinError(dwErr).Text()); } *pdwCscResult = dwErr; } } else { m_pr.PrintVerbose(L"\"%s\" already pinned.\n", pszFile); } TraceLeaveValue(CSCPROC_RETURN_CONTINUE); }
//
//.Get the target of a link and pin it.
//
DWORD CCscPinItem::_PinOrUnpinLinkTarget( LPCWSTR pszFile, // UNC of link file.
BOOL bPin, DWORD *pdwCscResult // Result of CSCPinFile on target.
) { TraceEnter(TRACE_ADMINPIN, "CCscPinItem::_PinOrUnpinLinkTarget"); TraceAssert(NULL != pszFile); TraceAssert(NULL != pdwCscResult);
*pdwCscResult = ERROR_SUCCESS;
DWORD dwResult = CSCPROC_RETURN_CONTINUE; LPWSTR pszTarget = NULL; //
// We only want to pin a link target if it's a file (not a directory).
// GetLinkTarget does this check and only returns files.
//
GetLinkTarget(pszFile, &pszTarget, NULL);
if (NULL != pszTarget) { WIN32_FIND_DATAW fd = {0}; LPCWSTR pszT = PathFindFileName(pszTarget); fd.dwFileAttributes = 0; lstrcpynW(fd.cFileName, pszT ? pszT : pszTarget, ARRAYSIZE(fd.cFileName)); //
// Pin the target
//
if (bPin) { dwResult = _PinFile(pszTarget, &fd, pdwCscResult); } else { dwResult = _UnpinFile(pszTarget, &fd, pdwCscResult); }
LocalFree(pszTarget); } TraceLeaveValue(dwResult); }
DWORD CCscPinItem::_UnpinFile( LPCWSTR pszFile, // UNC of file to unpin.
WIN32_FIND_DATAW *pfd, // Optional. May be NULL.
DWORD *pdwCscResult // Result of CSCUnpinFile
) { TraceEnter(TRACE_ADMINPIN, "CCscPinItem::_UnpinFile"); TraceAssert(NULL != pszFile); TraceAssert(NULL != pdwCscResult);
*pdwCscResult = ERROR_SUCCESS;
//
// Collect cache information for the item.
// This may fail, for example if the file is not in the cache
//
DWORD dwPinCount = 0; DWORD dwHintFlags = 0; DWORD dwStatus = 0; CSCQueryFileStatusW(pszFile, &dwStatus, &dwPinCount, &dwHintFlags);
if (dwHintFlags & FLAG_CSC_HINT_PIN_ADMIN) { DWORD dwStatus = 0; DWORD dwHintFlags = 0; //
// Decrement pin count. Amount decremented depends on the file.
// Win2000 deployment code increments the pin count of some special
// folders as well as for the desktop.ini file in those special
// folders. In those cases, we want to leave the pin count at
// 1. For all other files, the pin count can drop to zero.
//
_DecrementPinCountForFile(pszFile, dwPinCount); //
// Clear system-pin flag (aka admin-pin flag).
//
dwHintFlags |= FLAG_CSC_HINT_PIN_ADMIN;
if (CSCUnpinFileW(pszFile, dwHintFlags, &dwStatus, &dwPinCount, &dwHintFlags)) { m_pr.PrintVerbose(L"Unpin \"%s\"\n", pszFile); if (FLAG_CSC_COPY_STATUS_IS_FILE & dwStatus) { //
// Delete a file here. Directories are deleted
// on the backside of the post-order traversal
// in CscPin::_FolderCallback.
//
DeleteIfUnused(); } ShellChangeNotify(pszFile, pfd, FALSE); } else { *pdwCscResult = GetLastError(); m_pr.PrintAlways(L"Error unpinning \"%s\". %s\n", pszFile, CWinError(*pdwCscResult).Text()); } }
TraceLeaveValue(CSCPROC_RETURN_CONTINUE); }
//
// As part of the unpin operation, we decrement the pin count
// to either 0 or 1. Folder redirection (contact RahulTh) increments
// the pin count of redirected special folders and the desktop.ini file
// within those folders. In those cases, we want to leave the
// pin count at 1 so that we don't upset the behavior of redirected
// folders. For all other files we drop the pin count to 0.
//
void CCscPinItem::_DecrementPinCountForFile( LPCWSTR pszFile, DWORD dwCurrentPinCount ) { DWORD dwStatus = 0; DWORD dwPinCount = 0; DWORD dwHintFlags = 0;
const DWORD dwDesiredPinCount = _GetDesiredPinCount(pszFile);
while(dwCurrentPinCount-- > dwDesiredPinCount) { dwHintFlags = FLAG_CSC_HINT_COMMAND_ALTER_PIN_COUNT; CSCUnpinFileW(pszFile, dwHintFlags, &dwStatus, &dwPinCount, &dwHintFlags); } }
//
// This function returns the desired pin count (0 or 1) for a
// given file. Returns 1 for any redirected special folders
// and the desktop.ini file within those folders. Returns 0
// for all other files.
//
DWORD CCscPinItem::_GetDesiredPinCount( LPCWSTR pszFile ) { TraceAssert(NULL != pszFile);
DWORD dwPinCount = 0; // Default for most files.
if (_IsSpecialRedirectedFile(pszFile)) { dwPinCount = 1; } return dwPinCount; }
//
// Determines if a path is a "special" file pinned by the folder
// redirection code.
//
BOOL CCscPinItem::_IsSpecialRedirectedFile( LPCWSTR pszPath ) { TraceAssert(NULL != pszPath);
//
// This list of special folder IDs provided by RahulTh (08/30/00).
// These are the paths that may be pinned by folder redirection.
//
static struct { int csidl; WCHAR szPath[MAX_PATH]; int cchPath;
} rgFolderPaths[] = { { CSIDL_PERSONAL, 0, 0 }, { CSIDL_MYPICTURES, 0, 0 }, { CSIDL_DESKTOPDIRECTORY, 0, 0 }, { CSIDL_STARTMENU, 0, 0 }, { CSIDL_PROGRAMS, 0, 0 }, { CSIDL_STARTUP, 0, 0 }, { CSIDL_APPDATA, 0, 0 } };
int i; if (L'\0' == rgFolderPaths[0].szPath[0]) { //
// Initialize the special folder path data.
// One-time only initialization.
//
for (i = 0; i < ARRAYSIZE(rgFolderPaths); i++) { if (!SHGetSpecialFolderPath(NULL, rgFolderPaths[i].szPath, rgFolderPaths[i].csidl | CSIDL_FLAG_DONT_VERIFY, FALSE)) { m_pr.PrintAlways(L"Error getting path for shell special folder %d. %s\n", rgFolderPaths[i].csidl, CWinError(GetLastError()).Text()); } else { //
// Calculate and cache the length.
//
rgFolderPaths[i].cchPath = lstrlen(rgFolderPaths[i].szPath); } } }
const int cchPath = lstrlen(pszPath);
for (i = 0; i < ARRAYSIZE(rgFolderPaths); i++) { int cchThis = rgFolderPaths[i].cchPath; LPCWSTR pszThis = rgFolderPaths[i].szPath; if (cchPath >= cchThis) { //
// Path being examined is the same length or longer than
// current path from the table. Possible match.
//
if (0 == StrCmpNIW(pszPath, pszThis, cchThis)) { //
// Path being examined is either the same as,
// or a child of, the current path from the table.
//
if (L'\0' == *(pszPath + cchThis)) { //
// Path is same as this path from the table.
//
return TRUE; } else if (0 == lstrcmpiW(pszPath + cchThis + 1, L"desktop.ini")) { //
// Path is for a desktop.ini file that exists in the
// root of one of our special folders.
//
return TRUE; } } } } return FALSE; }
//
// Determines if the item should be skipped or not.
//
bool CCscPinItem::_Skip( void ) const { return !m_bIsValidUnc || (0 == (SFGAO_FILESYSTEM & m_sfi.dwAttributes)); }
//-----------------------------------------------------------------------------
// CCscPin
//-----------------------------------------------------------------------------
CCscPin::CCscPin( const CSCPIN_INFO& info ) : m_bUseListFile(info.bUseListFile), m_bPin(info.bPin), m_bPinDefaultSet(info.bPinDefaultSet), m_bBreakDetected(FALSE), m_cFilesPinned(0), m_cCscErrors(0), m_pr(info.bVerbose, info.pszLogFile) { TraceAssert(NULL != info.pszFile);
lstrcpynW(m_szFile, info.pszFile, ARRAYSIZE(m_szFile)); }
CCscPin::~CCscPin( void ) {
}
//
// The only public method on the CCscPin object.
// Just create an object and tell it to Run.
//
HRESULT CCscPin::Run( void ) { HRESULT hr = E_FAIL;
m_cCscErrors = 0; m_cFilesPinned = 0;
if (!IsCSCEnabled()) { m_pr.PrintAlways(L"Offline Files is not enabled.\n"); SetExitCode(CSCPIN_EXIT_CSC_NOT_ENABLED); } else if (_IsAdminPinPolicyActive()) { m_pr.PrintAlways(L"The Offline Files 'admin-pin' policy is active.\n"); SetExitCode(CSCPIN_EXIT_POLICY_ACTIVE); } else { if (m_bUseListFile) { //
// Process files listed in m_szFile.
//
hr = _ProcessPathsInFile(m_szFile); } else { //
// Process the one file provided on the cmd line.
// Do a quick existence check first.
//
if (DWORD(-1) != GetFileAttributesW(m_szFile)) { hr = _ProcessThisPath(m_szFile, m_bPin); } else { m_pr.PrintAlways(L"File \"%s\" not found.\n", m_szFile); hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); SetExitCode(CSCPIN_EXIT_FILE_NOT_FOUND); } } //
// Flush all change notifications.
//
ShellChangeNotify(NULL, TRUE);
if (0 < m_cFilesPinned && !_DetectConsoleBreak()) { //
// If we pinned some files, fill all sparse
// files in the cache.
//
_FillSparseFiles(); }
if (0 < m_cCscErrors) { SetExitCode(CSCPIN_EXIT_CSC_ERRORS); } } return hr; }
//
// Callback parameter block passed to _FolderCallback.
//
struct CSCPIN_FOLDER_CBK_PARAMS { CCscPin *pCscPin; // Reference to the CCscPin object.
BOOL bPin; // TRUE == Pin files, FALSE == Unpin.
};
//
// Callback used for enumerating the filesystem. This function
// is called for each file processed.
//
DWORD WINAPI CCscPin::_FolderCallback( LPCWSTR pszItem, ENUM_REASON eReason, WIN32_FIND_DATAW *pFind32, LPARAM pContext // Ptr to CSCPIN_FOLDER_CBK_PARAMS.
) { TraceEnter(TRACE_ADMINPIN, "CCscPin::_PinFolderCallback"); TraceAssert(NULL != pszItem); TraceAssert(NULL != pContext);
CSCPIN_FOLDER_CBK_PARAMS *pfcp = (CSCPIN_FOLDER_CBK_PARAMS *)pContext; CCscPin *pThis = pfcp->pCscPin; DWORD dwResult = CSCPROC_RETURN_CONTINUE;
if (pThis->_DetectConsoleBreak()) { TraceLeaveValue(CSCPROC_RETURN_ABORT); }
if (!pszItem || !*pszItem) { TraceLeaveValue(CSCPROC_RETURN_SKIP); }
if (ENUM_REASON_FILE == eReason || ENUM_REASON_FOLDER_BEGIN == eReason) { TraceAssert(NULL != pFind32);
CCscPinItem item(pszItem, pFind32, pThis->m_pr); DWORD dwCscResult = ERROR_SUCCESS; if (pfcp->bPin) { dwResult = item.Pin(&dwCscResult); if (ERROR_SUCCESS == dwCscResult) { pThis->m_cFilesPinned++; } } else { dwResult = item.Unpin(&dwCscResult); } if (ERROR_SUCCESS != dwCscResult) { pThis->m_cCscErrors++; } } else if (ENUM_REASON_FOLDER_END == eReason && !pfcp->bPin) { //
// This code is executed for each folder item after all children
// have been visited in the post-order traversal of the
// CSC filesystem. We use it to remove any empty folder entries
// from the cache.
//
CCscPinItem item(pszItem, pFind32, pThis->m_pr); item.DeleteIfUnused(); } TraceLeaveValue(dwResult); }
//
// Pin or unpin one path string. If it's a folder, all it's children
// are also pinned or unpinned according to the bPin argument.
//
HRESULT CCscPin::_ProcessThisPath( LPCWSTR pszFile, BOOL bPin ) { TraceEnter(TRACE_ADMINPIN, "CCscPin::_ProcessThisPath"); TraceAssert(NULL != pszFile);
LPCWSTR pszPath = pszFile; LPWSTR pszUncPath = NULL;
if (!PathIsUNC(pszPath)) { GetRemotePath(pszPath, &pszUncPath); pszPath = (LPCWSTR)pszUncPath; }
if (NULL != pszPath) { CSCPIN_FOLDER_CBK_PARAMS CbkParams = { this, bPin }; //
// Process this item
//
DWORD dwResult = _FolderCallback(pszPath, ENUM_REASON_FILE, NULL, (LPARAM)&CbkParams); //
// Process everything under this folder (if it's a folder)
//
//
// ISSUE-2000/08/28-BrianAu Should we provide the capability to
// limit recursive pinning and unpinning? Maybe in the future
// but not now.
//
if (CSCPROC_RETURN_CONTINUE == dwResult && PathIsUNC(pszPath)) { _Win32EnumFolder(pszPath, TRUE, _FolderCallback, (LPARAM)&CbkParams); } //
// Finally, once we're all done, delete the top level item if it's
// unused.
//
CCscPinItem item(pszPath, NULL, m_pr); item.DeleteIfUnused(); } LocalFreeString(&pszUncPath); TraceLeaveResult(S_OK); }
//
// Reads paths in the [Pin], [Unpin] and [Default] sections of an INI file.
// For each, call the _ProcessThisPath function.
//
HRESULT CCscPin::_ProcessPathsInFile( LPCWSTR pszFile ) { TraceEnter(TRACE_ADMINPIN, "CCscPin::_ProcessPathsInFile"); TraceAssert(NULL != pszFile);
HRESULT hr = S_OK;
//
// Need a full path name. Otherwise, the PrivateProfile APIs
// used by the CListFile object will assume the file is in
// one of the "system" directories.
//
WCHAR szFile[MAX_PATH]; LPWSTR pszNamePart; if (0 == GetFullPathNameW(pszFile, ARRAYSIZE(szFile), szFile, &pszNamePart)) { const DWORD dwErr = GetLastError(); hr = HRESULT_FROM_WIN32(dwErr); SetExitCode(CSCPIN_EXIT_LISTFILE_NO_OPEN); m_pr.PrintAlways(L"Error expanding path \"%s\". %s\n", pszFile, CWinError(hr).Text()); } else { //
// Before we go any further, verify the file really exists.
//
if (DWORD(-1) == GetFileAttributesW(szFile)) { hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); SetExitCode(CSCPIN_EXIT_LISTFILE_NO_OPEN); m_pr.PrintAlways(L"Error opening input file \"%s\". %s\n", szFile, CWinError(hr).Text()); } else { //
// Read and process the information in the file.
// Note that the listfile object MUST remain alive while the
// iterator is being used.
//
CListFile listfile(szFile); CDblNulStrIter iter;
typedef HRESULT (CListFile::*PFN)(CDblNulStrIter *);
//
// This table describes the sections read from the listfile,
// the order they are read in and if the files read should
// be 'pinned' or 'unpinned'.
//
static const struct { PFN pfn; // Function called to read file contents.
BOOL bQuery; // Query input file for these items?
BOOL bPin; // Action to perform on contents read.
} rgReadFuncs[] = { { &CListFile::GetFilesToUnpin, TRUE, FALSE }, // Reads [Unpin] section.
{ &CListFile::GetFilesToPin, TRUE, TRUE }, // Reads [Pin] section.
{ &CListFile::GetFilesDefault, m_bPinDefaultSet, m_bPin }, // Reads [Default] section.
};
for (int i = 0; i < ARRAYSIZE(rgReadFuncs) && !_DetectConsoleBreak(); i++) { if (rgReadFuncs[i].bQuery) { PFN pfn = rgReadFuncs[i].pfn; BOOL bPin = rgReadFuncs[i].bPin; //
// Read the info from the listfile using the appropriate
// function. The returned iterator will iterate over all
// of the files read.
//
hr = (listfile.*pfn)(&iter); if (SUCCEEDED(hr)) { //
// Process the entries.
//
LPCWSTR pszPath; while(iter.Next(&pszPath)) { //
// Paths in the listfile can contain embedded environment
// strings.
//
TCHAR szPathExpanded[MAX_PATH]; if (0 == ExpandEnvironmentStrings(pszPath, szPathExpanded, ARRAYSIZE(szPathExpanded))) { m_pr.PrintAlways(L"Error expanding \"%s\". %s\n", pszPath, CWinError(GetLastError()));
lstrcpynW(szPathExpanded, pszPath, ARRAYSIZE(szPathExpanded)); } hr = _ProcessThisPath(szPathExpanded, bPin); } } } } } } return hr; }
//
// Enumerates each share in the cache and attempts to fill all sparse
// files in that share.
//
HRESULT CCscPin::_FillSparseFiles( void ) { HRESULT hr = S_OK;
m_pr.PrintAlways(L"Copying pinned files into cache...\n");
DWORD dwStatus; DWORD dwPinCount; DWORD dwHintFlags; WIN32_FIND_DATA fd; FILETIME ft; CCscFindHandle hFind;
hFind = CacheFindFirst(NULL, &fd, &dwStatus, &dwPinCount, &dwHintFlags, &ft); if (hFind.IsValid()) { do { const BOOL bFullSync = FALSE; CSCFillSparseFilesW(fd.cFileName, bFullSync, _FillSparseFilesCallback, (DWORD_PTR)this); } while(CacheFindNext(hFind, &fd, &dwStatus, &dwPinCount, &dwHintFlags, &ft)); } return hr; }
//
// Called by CSC for each file processed by CSCFillSparseFiles.
//
DWORD WINAPI CCscPin::_FillSparseFilesCallback( LPCWSTR pszName, DWORD dwStatus, DWORD dwHintFlags, DWORD dwPinCount, WIN32_FIND_DATAW *pfd, DWORD dwReason, DWORD dwParam1, DWORD dwParam2, DWORD_PTR dwContext ) { TraceAssert(NULL != dwContext);
CCscPin *pThis = (CCscPin *)dwContext;
DWORD dwResult = CSCPROC_RETURN_CONTINUE; if (pThis->_DetectConsoleBreak()) { dwResult = CSCPROC_RETURN_ABORT; } else { switch(dwReason) { case CSCPROC_REASON_BEGIN: pThis->m_pr.PrintVerbose(L"Filling file \"%s\"\n", pszName); break;
case CSCPROC_REASON_END: dwParam2 = pThis->_TranslateFillResult(dwParam2, dwStatus, &dwResult); if (ERROR_SUCCESS != dwParam2) { pThis->m_cCscErrors++; pThis->m_pr.PrintAlways(L"Error filling \"%s\" %s\n", pszName, CWinError(dwParam2).Text()); } break;
default: break; } } TraceLeaveValue(dwResult); }
//
// Translates the error code and status provided by CSC from CSCFillSparseFiles
// into the correct error code and CSCPROC_RETURN_XXXXXX value. Some errors
// require translation before presentation to the user.
//
DWORD CCscPin::_TranslateFillResult( DWORD dwError, DWORD dwStatus, DWORD *pdwCscAction ) { DWORD dwResult = dwError; DWORD dwAction = CSCPROC_RETURN_CONTINUE;
if (ERROR_SUCCESS != dwError) { if (3000 <= dwError && dwError <= 3200) { //
// Special internal CSC error codes.
//
dwResult = ERROR_SUCCESS; } else { switch(dwError) { case ERROR_OPERATION_ABORTED: dwResult = ERROR_SUCCESS; dwAction = CSCPROC_RETURN_ABORT; break;
case ERROR_GEN_FAILURE: if (FLAG_CSC_COPY_STATUS_FILE_IN_USE & dwStatus) { dwResult = ERROR_OPEN_FILES; } break;
case ERROR_DISK_FULL: dwAction = CSCPROC_RETURN_ABORT; break;
default: break; } } } if (NULL != pdwCscAction) { *pdwCscAction = dwAction; } return dwResult; }
//
// Determine if the admin-pin policy is active on the current
// computer.
//
BOOL CCscPin::_IsAdminPinPolicyActive( void ) { const HKEY rghkeyRoots[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
BOOL bIsActive = FALSE; for (int i = 0; !bIsActive && i < ARRAYSIZE(rghkeyRoots); i++) { HKEY hkey; if (ERROR_SUCCESS == RegOpenKeyEx(rghkeyRoots[i], c_szRegKeyAPF, 0, KEY_READ, &hkey)) { WCHAR szName[MAX_PATH]; DWORD cchName = ARRAYSIZE(szName);
if (ERROR_SUCCESS == RegEnumValue(hkey, 0, szName, &cchName, NULL, NULL, NULL, NULL)) { bIsActive = TRUE; } RegCloseKey(hkey); } } return bIsActive; }
//
// Determine if one of the following system events has occured.
//
// 1. User pressed Ctrl-C.
// 2. User pressed Ctrl-Break.
// 3. Console window was closed.
// 4. User logged off.
//
// If one of these events has occured, an output message is generated
// and TRUE is returned.
// Otherwise, FALSE is returned.
// Note that the output message is generated only once.
//
BOOL CCscPin::_DetectConsoleBreak( void ) { if (!m_bBreakDetected) { DWORD dwCtrlEvent; m_bBreakDetected = ConsoleHasCtrlEventOccured(&dwCtrlEvent); if (m_bBreakDetected) { m_pr.PrintAlways(L"Program aborted. "); switch(dwCtrlEvent) { case CTRL_C_EVENT: m_pr.PrintAlways(L"User pressed Ctrl-C\n"); break;
case CTRL_BREAK_EVENT: m_pr.PrintAlways(L"User pressed Ctrl-Break\n"); break;
case CTRL_CLOSE_EVENT: m_pr.PrintAlways(L"Application forceably closed.\n"); break;
case CTRL_LOGOFF_EVENT: m_pr.PrintAlways(L"User logged off.\n"); break;
default: m_pr.PrintAlways(L"Unknown console break event %d\n", dwCtrlEvent); break; } } } return m_bBreakDetected; }
|