Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4033 lines
89 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
api.c
Abstract:
reintegration functions
Contents:
Author:
Shishir Pardikar
Environment:
Win32 (user-mode) DLL
Revision History:
4/24/97 Created shishirp
--*/
#include "pch.h"
#ifdef CSC_ON_NT
#include <winioctl.h>
#define UNICODE
#endif //CSC_ON_NT
#include "shdcom.h"
#include "shdsys.h"
#include "reint.h"
#include "utils.h"
#include "resource.h"
#include "strings.h"
// this sets flags in a couple of headers to not include some defs.
#define REINT
#include "lib3.h"
#include "cscapi.h"
//
// Defines/structures
//
#define SHADOW_FIND_SIGNATURE 0x61626162 // abab
#define FLAG_SHADOW_FIND_TERMINATED 0x00000001
typedef struct tagSHADOW_FIND
{
DWORD dwSignature; // for validation
DWORD dwFlags;
HANDLE hShadowDB;
ULONG ulPrincipalID;
CSC_ENUMCOOKIE uEnumCookie;
}
SHADOW_FIND, *LPSHADOW_FIND;
typedef struct tagMST_LIST
{
struct tagMST_LIST *lpNext;
HSHADOW hDir;
} MST_LIST, *LPMST_LIST;
typedef struct tagMOVE_SUBTREE
{
DWORD dwFlags;
DWORD cntFail;
HSHARE hShareTo;
LPCTSTR lptzSource;
LPCTSTR lptzDestination;
LPMST_LIST lpTos;
MST_LIST sTos;
SHADOWINFO sSI;
WIN32_FIND_DATA sFind32;
} MOVE_SUBTREE, *LPMOVE_SUBTREE;
#define MST_REPLACE_IF_EXISTS 0x00000001
#define MST_SHARE_MARKED_DIRTY 0x00000002
#define MST_MARK_AS_LOCAL 0x00000004
typedef struct tagSET_SUBTREE_STATUS
{
DWORD dwFlags;
ULONG uStatus;
ULONG uOp;
} SET_SUBTREE_STATUS, *LPSET_SUBTREE_STATUS;
#define EDS_FLAG_ERROR_ENCOUNTERED 0x00000001
typedef struct tagENCRYPT_DECRYPT_SUBTREE
{
DWORD dwFlags;
BOOL fEncrypt;
LPCSCPROCW lpfnEnumProgress;
DWORD_PTR dwContext;
DWORD dwEndingNameSpaceVersion;
}ENCRYPT_DECRYPT_SUBTREE, *LPENCRYPT_DECRYPT_SUBTREE;
BOOL
CheckCSCAccessForThread(
HSHADOW hDir,
HSHADOW hShadow,
BOOL fWrite
);
int
MoveSubtree(
HANDLE hShadowDB,
LPSECURITYINFO pShareSecurityInfo,
LPTSTR lptzFullPath,
DWORD dwCallbackReason,
WIN32_FIND_DATA *lpFind32,
SHADOWINFO *lpSI,
LPMOVE_SUBTREE lpMst
);
int
SetSubtreeStatus(
HANDLE hShadowDB,
LPSECURITYINFO pShareSecurityInfo,
LPTSTR lptzFullPath,
DWORD dwCallbackReason,
WIN32_FIND_DATA *lpFind32,
SHADOWINFO *lpSI,
LPSET_SUBTREE_STATUS lpSss
);
int
EncryptDecryptSubtree(
HANDLE hShadowDB,
LPSECURITYINFO pShareSecurityInfo,
LPTSTR lptzFullPath,
DWORD dwCallbackReason,
WIN32_FIND_DATA *lpFind32,
SHADOWINFO *lpSI,
LPENCRYPT_DECRYPT_SUBTREE lpEds
);
BOOL
UncPathToDfsPath(
PWCHAR UncPath,
PWCHAR DfsPath,
ULONG cbLen);
BOOL
IsPersonal(VOID);
//
// local data
//
static TCHAR vszStarDotStar[] = _TEXT("*.*");
static TCHAR vszStar[] = _TEXT("*");
static TCHAR vszPrefix[] = _TEXT("CSC");
AssertData;
AssertError;
//
// functions
//
BOOL
WINAPI
CSCIsCSCEnabled(
VOID
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
unsigned ulSwitch = SHADOW_SWITCH_SHADOWING;
if(ShadowSwitches(INVALID_HANDLE_VALUE, &ulSwitch, SHADOW_SWITCH_GET_STATE))
{
return((ulSwitch & SHADOW_SWITCH_SHADOWING)!=0);
}
return FALSE;
}
BOOL
WINAPI
CSCGetSpaceUsageA(
LPSTR lptzLocation,
DWORD dwSize,
LPDWORD lpdwMaxSpaceHigh,
LPDWORD lpdwMaxSpaceLow,
LPDWORD lpdwCurrentSpaceHigh,
LPDWORD lpdwCurrentSpaceLow,
LPDWORD lpcntTotalFiles,
LPDWORD lpcntTotalDirs
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
SHADOWSTORE sST;
WIN32_FIND_DATA sFind32;
BOOL fRet = FALSE;
DWORD dwLen;
// NTRAID#455247-1/31/2000-shishirp parameter validation
if (GetShadowDatabaseLocation(INVALID_HANDLE_VALUE, &sFind32))
{
memset(lptzLocation, 0, sizeof(dwSize));
WideCharToMultiByte(CP_ACP, 0, sFind32.cFileName, wcslen(sFind32.cFileName), lptzLocation, dwSize, NULL, NULL);
if (GetSpaceStats(INVALID_HANDLE_VALUE, &sST))
{
*lpdwMaxSpaceHigh = 0;
*lpdwMaxSpaceLow = sST.sMax.ulSize;
*lpdwCurrentSpaceHigh = 0;
*lpdwCurrentSpaceLow = sST.sCur.ulSize;
*lpcntTotalFiles = sST.sCur.ucntFiles;
*lpcntTotalFiles = sST.sCur.ucntDirs;
fRet = TRUE;
}
}
return fRet;
#endif
}
BOOL
WINAPI
CSCGetSpaceUsageW(
LPTSTR lptzLocation,
DWORD dwSize,
LPDWORD lpdwMaxSpaceHigh,
LPDWORD lpdwMaxSpaceLow,
LPDWORD lpdwCurrentSpaceHigh,
LPDWORD lpdwCurrentSpaceLow,
LPDWORD lpcntTotalFiles,
LPDWORD lpcntTotalDirs
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
SHADOWSTORE sST;
WIN32_FIND_DATA sFind32;
BOOL fRet = FALSE;
// NTRAID#455247-1/31/2000-shishirp parameter validation
if (GetShadowDatabaseLocation(INVALID_HANDLE_VALUE, &sFind32))
{
memset(lptzLocation, 0, dwSize);
wcsncpy(lptzLocation, sFind32.cFileName, dwSize/sizeof(USHORT)-1);
if (GetSpaceStats(INVALID_HANDLE_VALUE, &sST))
{
*lpdwMaxSpaceHigh = 0;
*lpdwMaxSpaceLow = sST.sMax.ulSize;
*lpdwCurrentSpaceHigh = 0;
*lpdwCurrentSpaceLow = sST.sCur.ulSize;
*lpcntTotalFiles = sST.sCur.ucntFiles;
*lpcntTotalDirs = sST.sCur.ucntDirs;
fRet = TRUE;
}
}
return fRet;
#endif
}
BOOL
WINAPI
CSCSetMaxSpace(
DWORD nFileSizeHigh,
DWORD nFileSizeLow
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
int iRet;
// 2GB is our limit
if ((nFileSizeHigh)||(nFileSizeLow > 0x7fffffff))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
iRet = SetMaxShadowSpace(INVALID_HANDLE_VALUE, (long)nFileSizeHigh, (long)nFileSizeLow);
if (iRet<0)
{
SetLastError(ERROR_INTERNAL_ERROR);
}
return (iRet >= 1);
}
BOOL
CSCPinFileInternal(
LPCTSTR lpszFileName,
DWORD dwHintFlags,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
BOOL fCreated, fRet = FALSE;
DWORD dwError = ERROR_GEN_FAILURE;
// NTRAID#455247-1/31/2000-shishirp parameter validation !!!!
if (BeginInodeTransactionHSHADOW())
{
if(FindCreateShadowFromPath(lpszFileName, TRUE, &sFind32, &sSI, &fCreated))
{
sSI.ulHintFlags = dwHintFlags;
fRet = (AddHintFromInode( INVALID_HANDLE_VALUE,
sSI.hDir,
sSI.hShadow,
&(sSI.ulHintPri),
&(sSI.ulHintFlags)
) != 0);
if (fRet)
{
if (lpdwStatus)
{
*lpdwStatus = sSI.uStatus;
}
if (lpdwPinCount)
{
*lpdwPinCount = sSI.ulHintPri;
}
if (lpdwHintFlags)
{
*lpdwHintFlags = sSI.ulHintFlags;
}
}
else
{
dwError = ERROR_INVALID_FUNCTION;
}
}
else
{
dwError = GetLastError();
}
EndInodeTransactionHSHADOW();
}
if (!fRet)
{
Assert(dwError != ERROR_SUCCESS);
SetLastError(dwError);
}
return fRet;
}
BOOL
CSCUnpinFileInternal(
LPCTSTR lpszFileName,
IN DWORD dwHintFlags,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
BOOL fRet = FALSE;
DWORD dwError = ERROR_GEN_FAILURE;
// NTRAID#455247-1/31/2000-shishirp parameter validation !!!!
if (BeginInodeTransactionHSHADOW())
{
if(FindCreateShadowFromPath(lpszFileName, FALSE, &sFind32, &sSI, NULL))
{
sSI.ulHintFlags = dwHintFlags;
fRet = (DeleteHintFromInode( INVALID_HANDLE_VALUE,
sSI.hDir,
sSI.hShadow,
&(sSI.ulHintPri),
&(sSI.ulHintFlags)
) != 0);
if (fRet)
{
if (lpdwStatus)
{
*lpdwStatus = sSI.uStatus;
}
if (lpdwPinCount)
{
*lpdwPinCount = sSI.ulHintPri;
}
if (lpdwHintFlags)
{
*lpdwHintFlags = sSI.ulHintFlags;
}
}
else
{
dwError = ERROR_INVALID_FUNCTION;
}
}
else
{
dwError = GetLastError();
}
EndInodeTransactionHSHADOW();
}
if (!fRet)
{
SetLastError(dwError);
}
return fRet;
}
BOOL
CSCQueryFileStatusInternal(
LPCTSTR lpszFileName,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
LPDWORD lpdwUserPerms,
LPDWORD lpdwOtherPerms
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
// NTRAID#455247-1/31/2000-shishirp parameter validation !!!!
if (FindCreateShadowFromPath(lpszFileName, FALSE, &sFind32, &sSI, NULL) != TRUE)
return FALSE;
if (lpdwStatus != NULL) {
*lpdwStatus = sSI.uStatus;
// return accessmask for files or the root
if ((sSI.uStatus & SHADOW_IS_FILE)||(!sSI.hDir)) {
if (sSI.hShadow) {
ULONG ulPrincipalID;
if (!GetCSCPrincipalID(&ulPrincipalID))
ulPrincipalID = CSC_GUEST_PRINCIPAL_ID;
GetCSCAccessMaskForPrincipalEx(
ulPrincipalID,
sSI.hDir,
sSI.hShadow,
lpdwStatus,
lpdwUserPerms,
lpdwOtherPerms);
Assert((*lpdwStatus & ~FLAG_CSC_ACCESS_MASK) == sSI.uStatus);
if (lpdwUserPerms != NULL && lpdwOtherPerms != NULL) {
ULONG i;
ULONG GuestIdx = CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS;
ULONG UserIdx = CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS;
SECURITYINFO rgsSecurityInfo[CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS];
_TCHAR tchBuff[MAX_SERVER_SHARE_NAME_FOR_CSC];
ULONG nRet = 0;
DWORD dwDummy;
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI2;
BOOL fDone = FALSE;
// DbgPrint("CSCQueryFileStatusInternal(%ws)\n", lpszFileName);
if (lstrlen(lpszFileName) >= MAX_SERVER_SHARE_NAME_FOR_CSC)
goto AllDone;
lstrcpy(tchBuff, lpszFileName);
if (!LpBreakPath(tchBuff, TRUE, &fDone))
goto AllDone;
// DbgPrint(" tchBuff=%ws\n", tchBuff);
if (!FindCreateShadowFromPath(tchBuff, FALSE, &sFind32, &sSI2, NULL))
goto AllDone;
// DbgPrint("CSCQueryFileStatusInternal: hShare=0x%x,hShadow=0x%x,hDir=0x%x\n",
// sSI2.hShare,
// sSI2.hShadow,
// sSI2.hDir);
dwDummy = sizeof(rgsSecurityInfo);
nRet = GetSecurityInfoForCSC(
INVALID_HANDLE_VALUE,
0,
sSI2.hShadow,
rgsSecurityInfo,
&dwDummy);
// DbgPrint(" GetSecurityInfoForCSC returned %d\n", nRet);
if (nRet == 0)
goto AllDone;
//
// Find the user's and guest's entries
//
for (i = 0; i < CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS; i++) {
if (rgsSecurityInfo[i].ulPrincipalID == ulPrincipalID)
UserIdx = i;
if (rgsSecurityInfo[i].ulPrincipalID == CSC_GUEST_PRINCIPAL_ID)
GuestIdx = i;
}
if (GuestIdx < CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS) {
if (UserIdx >= CSC_MAXIMUM_NUMBER_OF_CACHED_PRINCIPAL_IDS)
UserIdx = GuestIdx;
*lpdwUserPerms &= rgsSecurityInfo[UserIdx].ulPermissions;
*lpdwOtherPerms &= rgsSecurityInfo[GuestIdx].ulPermissions;
// DbgPrint("UserPerms=0x%x,OtherPerms=0x%x\n",
// *lpdwUserPerms,
// *lpdwOtherPerms);
}
}
}
}
}
AllDone:
if (lpdwPinCount) {
*lpdwPinCount = sSI.ulHintPri;
}
if (lpdwHintFlags) {
*lpdwHintFlags = sSI.ulHintFlags;
}
return TRUE;
}
HANDLE
CSCFindFirstFileInternal(
LPCTSTR lpszFileName,
ULONG ulPrincipalID,
WIN32_FIND_DATA *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
SHADOWINFO sSI;
BOOL fRet = FALSE;
LPSHADOW_FIND lpShadowFind = NULL;
// NTRAID#455247-1/31/2000-shishirp parameter validation !!!!
if (lpszFileName && *lpszFileName)
{
fRet = FindCreateShadowFromPath(
lpszFileName, // UNC path
FALSE, // don't create
lpFind32,
&sSI,
NULL);
if (fRet && !sSI.hShadow)
{
// a situation where, the share is connected but it's entry is
// not in the database
fRet = FALSE;
}
}
else
{
memset(&sSI, 0, sizeof(sSI)); // sSI.hShadow is 0 => we are enumerating all shares
lpFind32->dwFileAttributes = FILE_ATTRIBUTE_DIRECTORY;
fRet = TRUE;
}
if (fRet)
{
fRet = FALSE;
// Found the shadow
if (lpShadowFind = AllocMem(sizeof(SHADOW_FIND)))
{
lpShadowFind->dwSignature = SHADOW_FIND_SIGNATURE;
lpShadowFind->hShadowDB = INVALID_HANDLE_VALUE;
if (ulPrincipalID != CSC_INVALID_PRINCIPAL_ID)
{
lpShadowFind->ulPrincipalID = ulPrincipalID;
}
else
{
if (!GetCSCPrincipalID(&lpShadowFind->ulPrincipalID))
{
lpShadowFind->ulPrincipalID = CSC_GUEST_PRINCIPAL_ID;
}
}
if (!(lpFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
lpShadowFind->dwFlags |= FLAG_SHADOW_FIND_TERMINATED;
fRet = TRUE;
}
else
{
// lpShadowFind->hShadowDB = OpenShadowDatabaseIO();
// if (lpShadowFind->hShadowDB != INVALID_HANDLE_VALUE)
{
#ifndef CSC_ON_NT
lstrcpy(lpFind32->cFileName, vszStarDotStar);
#else
lstrcpy(lpFind32->cFileName, vszStar);
#endif
if(FindOpenShadow(
lpShadowFind->hShadowDB,
sSI.hShadow,
FINDOPEN_SHADOWINFO_ALL,
lpFind32,
&sSI
))
{
lpShadowFind->uEnumCookie = sSI.uEnumCookie;
fRet = TRUE;
}
}
}
}
}
if (!fRet)
{
if (lpShadowFind)
{
if (lpShadowFind->hShadowDB != INVALID_HANDLE_VALUE)
{
CloseShadowDatabaseIO(lpShadowFind->hShadowDB);
}
FreeMem(lpShadowFind);
}
EndInodeTransactionHSHADOW();
return (INVALID_HANDLE_VALUE);
}
else
{
if (lpdwStatus)
{
*lpdwStatus = (DWORD)(sSI.uStatus);
// return accessmask for files or the root
if ((sSI.uStatus & SHADOW_IS_FILE)||(!sSI.hDir))
{
GetCSCAccessMaskForPrincipal(lpShadowFind->ulPrincipalID, sSI.hDir, sSI.hShadow, lpdwStatus);
Assert((*lpdwStatus & ~FLAG_CSC_ACCESS_MASK) == sSI.uStatus);
}
}
if (lpdwPinCount)
{
*lpdwPinCount = (DWORD)(sSI.ulHintPri);
}
if (lpdwHintFlags)
{
*lpdwHintFlags = sSI.ulHintFlags;
}
if (lpOrgFileTime)
{
*lpOrgFileTime = lpFind32->ftLastAccessTime;
}
return ((HANDLE)lpShadowFind);
}
}
BOOL
CSCFindNextFileInternal(
HANDLE hFind,
WIN32_FIND_DATA *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
LPSHADOW_FIND lpShadowFind = (LPSHADOW_FIND)hFind;
BOOL fRet = FALSE;
SHADOWINFO sSI;
// validate parameters !!!!
if (lpShadowFind->dwFlags & FLAG_SHADOW_FIND_TERMINATED)
{
SetLastError(ERROR_NO_MORE_FILES);
return FALSE;
}
else
{
if (!FindNextShadow( lpShadowFind->hShadowDB,
lpShadowFind->uEnumCookie,
lpFind32,
&sSI
))
{
lpShadowFind->dwFlags |= FLAG_SHADOW_FIND_TERMINATED;
SetLastError(ERROR_NO_MORE_FILES);
}
else
{
if (lpdwStatus)
{
*lpdwStatus = (DWORD)(sSI.uStatus);
// return accessmask for files or the root
if ((sSI.uStatus & SHADOW_IS_FILE)||(!sSI.hDir))
{
GetCSCAccessMaskForPrincipal(lpShadowFind->ulPrincipalID, sSI.hDir, sSI.hShadow, lpdwStatus);
Assert((*lpdwStatus & ~FLAG_CSC_ACCESS_MASK) == sSI.uStatus);
}
}
if (lpdwPinCount)
{
*lpdwPinCount = (DWORD)(sSI.ulHintPri);
}
if (lpdwHintFlags)
{
*lpdwHintFlags = sSI.ulHintFlags;
}
if (lpOrgFileTime)
{
*lpOrgFileTime = lpFind32->ftLastAccessTime;
}
fRet = TRUE;
}
}
return (fRet);
}
BOOL
WINAPI
CSCFindClose(
HANDLE hFind
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
LPSHADOW_FIND lpShadowFind = (LPSHADOW_FIND)hFind;
if (lpShadowFind->uEnumCookie)
{
// don't check any errors
FindCloseShadow(lpShadowFind->hShadowDB, lpShadowFind->uEnumCookie);
}
if (lpShadowFind->hShadowDB != INVALID_HANDLE_VALUE)
{
CloseShadowDatabaseIO(lpShadowFind->hShadowDB);
}
FreeMem(lpShadowFind);
return (TRUE);
}
BOOL
CSCDeleteInternal(
LPCTSTR lpszName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
BOOL fRet = FALSE;
DWORD dwError = ERROR_GEN_FAILURE;
DWORD dwStatus = 0;
BOOL DoDelete = FALSE;
// NTRAID#455247 -1/31/2000-shishirp parameter validation !!!!
ReintKdPrint(API, ("Delete %ls\r\n", lpszName));
if(CSCQueryFileStatus(lpszName, &dwStatus, NULL, NULL))
{
// Shouls check if the user has the permission to delete this file - Bug 524237
if(!(FLAG_CSC_COPY_STATUS_IS_FILE & dwStatus) || //is directory or
(((dwStatus & FLAG_CSC_GUEST_ACCESS_MASK) & // the guest has write permission
FLAG_CSC_WRITE_ACCESS << FLAG_CSC_GUEST_ACCESS_SHIFT_COUNT) ||
((dwStatus & FLAG_CSC_USER_ACCESS_MASK) & // or the user has write permission
FLAG_CSC_WRITE_ACCESS << FLAG_CSC_USER_ACCESS_SHIFT_COUNT)))
{
if (BeginInodeTransactionHSHADOW())
{
if(FindCreateShadowFromPath(lpszName, FALSE, &sFind32, &sSI, NULL))
{
ReintKdPrint(API, ("Delete Inode %x %x\r\n", sSI.hDir, sSI.hShadow));
if (DeleteShadow(INVALID_HANDLE_VALUE, sSI.hDir, sSI.hShadow))
{
fRet = TRUE;
}
else
{
dwError = ERROR_ACCESS_DENIED;
}
}
else
{
dwError = GetLastError();
}
EndInodeTransactionHSHADOW();
}
}
else
{
dwError = ERROR_ACCESS_DENIED;
}
}
if (!fRet)
{
SetLastError(dwError);
}
return fRet;
}
BOOL
CSCFillSparseFilesInternal(
IN LPCTSTR lpszShareOrFileName,
IN BOOL fFullSync,
IN LPCSCPROC lpfnFillProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
DWORD dwError = ERROR_INVALID_PARAMETER, dwRet;
LPCOPYPARAMS lpCP = NULL;
ULONG ulPrincipalID;
if (!GetCSCPrincipalID(&ulPrincipalID))
{
ulPrincipalID = CSC_GUEST_PRINCIPAL_ID;
}
if(FindCreateShadowFromPath(lpszShareOrFileName, FALSE, &sFind32, &sSI, NULL))
{
if (!sSI.hDir)
{
dwError = NO_ERROR;
// if this is a share
dwRet = (*lpfnFillProgress)(
lpszShareOrFileName,
sSI.uStatus,
sSI.ulHintFlags,
sSI.ulHintPri,
&sFind32,
CSCPROC_REASON_BEGIN,
0,
0,
dwContext
);
if (dwRet == CSCPROC_RETURN_CONTINUE)
{
AttemptCacheFill(sSI.hShare, DO_ALL, fFullSync, ulPrincipalID, lpfnFillProgress, dwContext);
}
else
{
if (dwRet == CSCPROC_RETURN_ABORT)
{
dwError = ERROR_OPERATION_ABORTED;
}
}
(*lpfnFillProgress)(
lpszShareOrFileName,
sSI.uStatus,
sSI.ulHintFlags,
sSI.ulHintPri,
&sFind32,
CSCPROC_REASON_END,
0,
0,
dwContext
);
}
else if (!(sFind32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
BOOL fStalenessCheck;
dwError = NO_ERROR;
fStalenessCheck = (fFullSync || (sSI.uStatus & SHADOW_STALE));
if (fStalenessCheck)
{
if (!(lpCP = LpAllocCopyParams()))
{
dwError = GetLastError();
Assert(dwError != NO_ERROR);
}
else if(!GetUNCPath(INVALID_HANDLE_VALUE, sSI.hShare, sSI.hDir, sSI.hShadow, lpCP))
{
Assert(lpCP);
FreeCopyParams(lpCP);
dwError = GetLastError();
Assert(dwError != NO_ERROR);
}
}
if ((dwError == NO_ERROR) &&
(fStalenessCheck || (sSI.uStatus & SHADOW_SPARSE))) {
dwError = DoSparseFill( INVALID_HANDLE_VALUE,
(LPTSTR)lpszShareOrFileName,
NULL,
&sSI,
&sFind32,
lpCP,
fStalenessCheck,
ulPrincipalID,
lpfnFillProgress,
dwContext);
}
if (lpCP)
{
FreeCopyParams(lpCP);
lpCP = NULL;
}
}
}
else
{
dwError = GetLastError();
}
if (dwError != NO_ERROR)
{
SetLastError(dwError);
return FALSE;
}
return TRUE;
}
BOOL
CSCMergeShareInternal(
IN LPCTSTR lpszShareName,
IN LPCSCPROC lpfnMergeProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
int cntDriveMapped = 0;
BOOL fTransitionedToOnline = FALSE, fDone=FALSE;
_TCHAR tchBuff[MAX_SERVER_SHARE_NAME_FOR_CSC];
DWORD dwError = ERROR_SUCCESS;
ULONG ulPrincipalID;
if (!GetCSCPrincipalID(&ulPrincipalID))
{
ulPrincipalID = CSC_GUEST_PRINCIPAL_ID;
}
if (lstrlen(lpszShareName) >= MAX_SERVER_SHARE_NAME_FOR_CSC)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lstrcpy(tchBuff, lpszShareName);
if (!LpBreakPath(tchBuff, TRUE, &fDone) && !fDone)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if(FindCreateShadowFromPath(tchBuff, FALSE, &sFind32, &sSI, NULL))
{
fDone = ReintOneShare(sSI.hShare, sSI.hShadow, NULL, NULL, NULL, ulPrincipalID, lpfnMergeProgress, dwContext);
if (!fDone)
{
dwError = GetLastError();
}
// TransitionShareToOnline(INVALID_HANDLE_VALUE, sSI.hShare);
if (!fDone)
{
SetLastError(dwError);
}
return fDone;
}
return FALSE;
}
BOOL
CSCCopyReplicaInternal(
IN LPCTSTR lpszFullPath,
OUT LPTSTR *lplpszLocalName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
BOOL fRet = FALSE;
DWORD dwError = ERROR_GEN_FAILURE;
if (BeginInodeTransactionHSHADOW())
{
if(FindCreateShadowFromPath(lpszFullPath, FALSE, &sFind32, &sSI, NULL))
{
if (sFind32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
dwError = ERROR_INVALID_PARAMETER;
goto bailout;
}
if (!CheckCSCAccessForThread(sSI.hDir, sSI.hShadow, FALSE))
{
dwError = GetLastError();
goto bailout;
}
if (!(*lplpszLocalName = GetTempFileForCSC(NULL)))
{
goto bailout;
}
if(!CopyShadow(INVALID_HANDLE_VALUE, sSI.hDir, sSI.hShadow, *lplpszLocalName))
{
LocalFree(*lplpszLocalName);
*lplpszLocalName = NULL;
goto bailout;
}
fRet = TRUE;
}
else
{
dwError = GetLastError();
}
EndInodeTransactionHSHADOW();
}
bailout:
if (!fRet)
{
SetLastError(dwError);
}
return fRet;
}
BOOL
CSCEnumForStatsInternal(
IN LPCTSTR lpszShareName,
IN LPCSCPROC lpfnEnumProgress,
IN BOOL fPeruserInfo,
IN BOOL fUpdateShareReintBit,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
BOOL fRet = TRUE;
PQPARAMS sPQP;
HANDLE hShadowDB = INVALID_HANDLE_VALUE;
DWORD dwRet;
ULONG ulPrincipalID = CSC_INVALID_PRINCIPAL_ID;
if (lpszShareName)
{
if(!FindCreateShadowFromPath(lpszShareName, FALSE, &sFind32, &sSI, NULL))
{
fRet = FALSE;
}
}
else
{
sSI.hShare = 0;
}
if (fRet)
{
fRet = FALSE;
if ((hShadowDB = OpenShadowDatabaseIO())==INVALID_HANDLE_VALUE)
{
goto bailout;
}
if (lpfnEnumProgress)
{
dwRet = (*lpfnEnumProgress)(NULL, 0, 0, 0, NULL, CSCPROC_REASON_BEGIN, 0, 0, dwContext);
if (dwRet != CSCPROC_RETURN_CONTINUE )
{
goto bailout;
}
}
if (fPeruserInfo)
{
if (!GetCSCPrincipalID(&ulPrincipalID))
{
ulPrincipalID = CSC_GUEST_PRINCIPAL_ID;
}
}
memset(&sPQP, 0, sizeof(sPQP));
if(BeginPQEnum(hShadowDB, &sPQP) == 0) {
goto bailout;
}
do {
if(NextPriShadow(hShadowDB, &sPQP) == 0) {
break;
}
if (!sPQP.hShadow) {
break;
}
if (!sSI.hShare || (sSI.hShare == sPQP.hShare))
{
if (fPeruserInfo)
{
// return accessmask for files or the root
if ((sPQP.ulStatus & SHADOW_IS_FILE)||(!sPQP.hDir))
{
GetCSCAccessMaskForPrincipal(ulPrincipalID, sPQP.hDir, sPQP.hShadow, &sPQP.ulStatus);
}
}
if (lpfnEnumProgress)
{
// if we are enumerating for a particular share
// besides status, report whether file or directory and whether a root or a non-root
dwRet = (*lpfnEnumProgress)(NULL, sPQP.ulStatus & ~SHADOW_IS_FILE, sPQP.ulHintFlags, sPQP.ulHintPri, NULL, CSCPROC_REASON_MORE_DATA, (mShadowIsFile(sPQP.ulStatus) != 0), (sPQP.hDir==0), dwContext);
if (dwRet != CSCPROC_RETURN_CONTINUE )
{
break;
}
}
// if we are enumerating for a particular share
// then make sure that the share dirty bit matches with what we got on the
// actual files
if (fUpdateShareReintBit && sSI.hShare && (sSI.hShare == sPQP.hShare))
{
if (mShadowNeedReint(sPQP.ulStatus) && !(sSI.uStatus & SHARE_REINT))
{
if(SetShareStatus(hShadowDB, sSI.hShare, SHARE_REINT, SHADOW_FLAGS_OR))
{
sSI.uStatus |= SHARE_REINT;
}
}
}
}
} while (sPQP.uPos);
// Close the enumeration
EndPQEnum(hShadowDB, &sPQP);
if (lpfnEnumProgress)
{
dwRet = (*lpfnEnumProgress)(NULL, 0, 0, 0, NULL, CSCPROC_REASON_END, 0, 0, dwContext);
}
fRet = TRUE;
}
bailout:
if (hShadowDB != INVALID_HANDLE_VALUE)
{
CloseShadowDatabaseIO(hShadowDB);
}
return fRet;
}
BOOL
WINAPI
CSCPinFileA(
IN LPCSTR lpszFileName,
IN DWORD dwHintFlags,
IN LPDWORD lpdwStatus,
IN LPDWORD lpdwPinCount,
IN LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCPinFileInternal(lpszFileName, dwHintFlags, lpdwStatus, lpdwPinCount, lpdwHintFlags));
#endif
}
BOOL
WINAPI
CSCUnpinFileA(
IN LPCSTR lpszFileName,
IN DWORD dwHintFlags,
IN LPDWORD lpdwStatus,
IN LPDWORD lpdwPinCount,
IN LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCUnpinFileInternal(lpszFileName, dwHintFlags, lpdwStatus, lpdwPinCount, lpdwHintFlags));
#endif
}
BOOL
WINAPI
CSCQueryFileStatusA(
LPCSTR lpszFileName,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCQueryFileStatusInternal(
lpszFileName,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
NULL,
NULL));
#endif
}
BOOL
WINAPI
CSCQueryFileStatusExA(
LPCSTR lpszFileName,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
LPDWORD lpdwUserPerms,
LPDWORD lpdwOtherPerms
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCQueryFileStatusInternal(
lpszFileName,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpdwUserPerms,
llpdwOtherPerms));
#endif
}
BOOL
WINAPI
CSCQueryShareStatusA(
LPCSTR lpszFileName,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
LPDWORD lpdwUserPerms,
LPDWORD lpdwOtherPerms)
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCQueryFileStatusInternal(
lpszFileName,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpdwUserPerms,
llpdwOtherPerms));
#endif
}
HANDLE
WINAPI
CSCFindFirstFileA(
LPCSTR lpszFileName,
WIN32_FIND_DATA *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCFindFirstFileInternal(
lpszFileName,
CSC_INVALID_PRINCIPAL_ID,
lpFind32,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpOrgFileTime
));
#endif
}
HANDLE
WINAPI
CSCFindFirstFileForSidA(
LPCSTR lpszFileName,
PSID pSid,
WIN32_FIND_DATA *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
}
BOOL
WINAPI
CSCFindNextFileA(
HANDLE hFind,
WIN32_FIND_DATA *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCFindNextFileInternal(
hFind,
lpFind32,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpOrgFileTime
));
#endif
}
BOOL
WINAPI
CSCDeleteA(
LPCSTR lpszFileName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCDeleteInternal(lpszFileName));
#endif
}
BOOL
WINAPI
CSCFillSparseFilesA(
IN LPCSTR lpszShareName,
IN BOOL fFullSync,
IN LPCSCPROCA lpfnFillProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCFillSparseFilesInternal(
lpszShareName,
fFullSync,
lpfnFillProgress,
dwContext));
#endif
}
BOOL
WINAPI
CSCMergeShareA(
IN LPCSTR lpszShareName,
IN LPCSCPROCA lpfnMergeProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCMergeShareInternal(
lpszShareName,
lpfnMergeProgress,
dwContext));
#endif
}
BOOL
WINAPI
CSCCopyReplicaA(
IN LPCSTR lpszFullPath,
OUT LPSTR *lplpszLocalName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCCopyReplicaInternal(
lpszFullPath,
lplpszLocalName));
#endif
}
BOOL
WINAPI
CSCEnumForStatsA(
IN LPCSTR lpszShareName,
IN LPCSCPROCA lpfnEnumProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifdef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCEnumForStatsInternal(
lpszShareName,
lpfnEnumProgress,
FALSE,
FALSE,
dwContext));
#endif
}
BOOL
WINAPI
CSCPinFileW(
IN LPCWSTR lpszFileName,
IN DWORD dwHintFlags,
IN LPDWORD lpdwStatus,
IN LPDWORD lpdwPinCount,
IN LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCPinFileInternal(lpszFileName, dwHintFlags, lpdwStatus, lpdwPinCount, lpdwHintFlags));
#endif
}
BOOL
WINAPI
CSCUnpinFileW(
IN LPCWSTR lpszFileName,
IN DWORD dwHintFlags,
IN LPDWORD lpdwStatus,
IN LPDWORD lpdwPinCount,
IN LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCUnpinFileInternal(lpszFileName, dwHintFlags, lpdwStatus, lpdwPinCount, lpdwHintFlags));
#endif
}
BOOL
WINAPI
CSCQueryFileStatusW(
LPCWSTR lpszFileName,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCQueryFileStatusInternal(
lpszFileName,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
NULL,
NULL));
#endif
}
BOOL
WINAPI
CSCQueryFileStatusExW(
LPCWSTR lpszFileName,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
LPDWORD lpdwUserPerms,
LPDWORD lpdwOtherPerms
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCQueryFileStatusInternal(
lpszFileName,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpdwUserPerms,
lpdwOtherPerms));
#endif
}
BOOL
WINAPI
CSCQueryShareStatusW(
LPCWSTR lpszFileName,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
LPDWORD lpdwUserPerms,
LPDWORD lpdwOtherPerms)
{
BOOL fStatus = FALSE;
BOOL fDfsStatus = FALSE;
DWORD dwDfsStatus;
WCHAR lpszOrgPath[MAX_PATH];
WCHAR lpszDfsPath[MAX_PATH];
PWCHAR wCp;
ULONG sCount;
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
// DbgPrint("CSCQueryShareStatusW(%ws)\n", lpszFileName);
//
// Save a copy of the original path passed in
//
wcscpy(lpszOrgPath, lpszFileName);
// Now truncate to just \\server\share
for (sCount = 0, wCp = lpszOrgPath; *wCp !=L'\0'; wCp++) {
if (*wCp == L'\\') {
if (++sCount == 4) {
*wCp = L'\0';
break;
}
}
}
// DbgPrint(" OrgPath=%ws\n", lpszOrgPath);
fStatus = CSCQueryFileStatusInternal(
lpszOrgPath,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpdwUserPerms,
lpdwOtherPerms);
//
// If we found info, check if DFS, and (if so)
// adjust Status
//
if (fStatus == TRUE) {
DWORD Junk;
lpszDfsPath[0] = L'\0';
fDfsStatus = UncPathToDfsPath(
(PWCHAR)lpszFileName,
lpszDfsPath,
sizeof(lpszDfsPath));
if (fDfsStatus != TRUE)
goto AllDone;
// DbgPrint("DfsPath(1)=%ws\n", lpszDfsPath);
// turn into just \\server\share
for (sCount = 0, wCp = lpszDfsPath; *wCp !=L'\0'; wCp++) {
if (*wCp == L'\\') {
if (++sCount == 4) {
*wCp = L'\0';
break;
}
}
}
// DbgPrint("DfsPath(2)=%ws\n", lpszDfsPath);
fDfsStatus = CSCQueryFileStatusInternal(
lpszDfsPath,
&dwDfsStatus,
&Junk,
&Junk,
&Junk,
&Junk);
if (
fDfsStatus == TRUE
&&
(dwDfsStatus & FLAG_CSC_SHARE_STATUS_CACHING_MASK) == FLAG_CSC_SHARE_STATUS_NO_CACHING
) {
*lpdwStatus &= ~FLAG_CSC_SHARE_STATUS_CACHING_MASK;
*lpdwStatus |= FLAG_CSC_SHARE_STATUS_NO_CACHING;
// DbgPrint("New Status=0x%x\n", dwDfsStatus);
}
}
AllDone:
return fStatus;
#endif
}
HANDLE
WINAPI
CSCFindFirstFileW(
LPCWSTR lpszFileName,
WIN32_FIND_DATAW *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (INVALID_HANDLE_VALUE);
#else
return (CSCFindFirstFileInternal(
lpszFileName,
CSC_INVALID_PRINCIPAL_ID,
lpFind32,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpOrgFileTime
));
#endif
}
HANDLE
WINAPI
CSCFindFirstFileForSidW(
LPCWSTR lpszFileName,
PSID pSid,
WIN32_FIND_DATAW *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
ULONG ulPrincipalID;
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (INVALID_HANDLE_VALUE);
#else
if (pSid)
{
if(!FindCreatePrincipalIDFromSID(INVALID_HANDLE_VALUE, pSid, GetLengthSid(pSid), &ulPrincipalID, FALSE))
{
return INVALID_HANDLE_VALUE;
}
}
else
{
ulPrincipalID = CSC_INVALID_PRINCIPAL_ID;
}
return (CSCFindFirstFileInternal(
lpszFileName,
ulPrincipalID,
lpFind32,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpOrgFileTime
));
#endif
}
BOOL
WINAPI
CSCFindNextFileW(
HANDLE hFind,
WIN32_FIND_DATAW *lpFind32,
LPDWORD lpdwStatus,
LPDWORD lpdwPinCount,
LPDWORD lpdwHintFlags,
FILETIME *lpOrgFileTime
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCFindNextFileInternal(
hFind,
lpFind32,
lpdwStatus,
lpdwPinCount,
lpdwHintFlags,
lpOrgFileTime
));
#endif
}
BOOL
WINAPI
CSCDeleteW(
LPCWSTR lpszFileName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCDeleteInternal(lpszFileName));
#endif
}
BOOL
WINAPI
CSCFillSparseFilesW(
IN LPCWSTR lpszShareName,
IN BOOL fFullSync,
IN LPCSCPROCW lpfnFillProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return (CSCFillSparseFilesInternal(
lpszShareName,
fFullSync,
lpfnFillProgress,
dwContext));
#endif
}
BOOL
WINAPI
CSCMergeShareW(
IN LPCWSTR lpszShareName,
IN LPCSCPROCW lpfnMergeProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCMergeShareInternal(
lpszShareName,
lpfnMergeProgress,
dwContext));
#endif
}
BOOL
WINAPI
CSCCopyReplicaW(
IN LPCWSTR lpszFullPath,
OUT LPWSTR *lplpszLocalName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCCopyReplicaInternal(
lpszFullPath,
lplpszLocalName));
#endif
}
BOOL
WINAPI
CSCEnumForStatsW(
IN LPCWSTR lpszShareName,
IN LPCSCPROCW lpfnEnumProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCEnumForStatsInternal(
lpszShareName,
lpfnEnumProgress,
FALSE,
FALSE,
dwContext));
#endif
}
BOOL
WINAPI
CSCEnumForStatsExA(
IN LPCSTR lpszShareName,
IN LPCSCPROCA lpfnEnumProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
}
BOOL
WINAPI
CSCEnumForStatsExW(
IN LPCWSTR lpszShareName,
IN LPCSCPROCW lpfnEnumProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
#ifndef UNICODE
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
#else
return(CSCEnumForStatsInternal(
lpszShareName,
lpfnEnumProgress,
TRUE,
FALSE,
dwContext));
#endif
}
BOOL
WINAPI
CSCFreeSpace(
DWORD nFileSizeHigh,
DWORD nFileSizeLow
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
SHADOWSTORE sSTLast, sST;
BOOL fRet = FALSE;
if(!GetSpaceStats(INVALID_HANDLE_VALUE, &sSTLast))
{
return FALSE;
}
do
{
if (!FreeShadowSpace(INVALID_HANDLE_VALUE, nFileSizeHigh, nFileSizeLow, FALSE))
{
break;
}
if(!GetSpaceStats(INVALID_HANDLE_VALUE, &sST))
{
break;
}
// check if we are making any progress over successive
// free space calls. If the current space used is greater than
// after we last called, just quit.
if (sST.sCur.ulSize >= sSTLast.sCur.ulSize)
{
fRet = TRUE;
break;
}
sSTLast = sST;
}
while (TRUE);
return fRet;
}
BOOL
WINAPI
CSCIsServerOfflineW(
LPCWSTR lptzServerName,
BOOL *lpfOffline
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
return(IsServerOfflineW(INVALID_HANDLE_VALUE, lptzServerName, lpfOffline));
}
BOOL
WINAPI
CSCIsServerOfflineA(
LPCSTR lptzServerName,
BOOL *lpfOffline
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
return(IsServerOfflineA(INVALID_HANDLE_VALUE, lptzServerName, lpfOffline));
}
BOOL
WINAPI
CSCTransitionServerOnlineW(
IN LPCWSTR lpszShareName
)
/*++
Routine Description:
This routine transitions the server for the given share to online.
Arguments:
lpszShareName
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
BOOL fTransitionedToOnline = FALSE, fDone=FALSE;
_TCHAR tchBuff[MAX_SERVER_SHARE_NAME_FOR_CSC], tzDrive[4];
DWORD i;
if (lstrlen(lpszShareName) >= MAX_SERVER_SHARE_NAME_FOR_CSC)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lstrcpy(tchBuff, lpszShareName);
if (!LpBreakPath(tchBuff, TRUE, &fDone) && !fDone)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
tzDrive[0] = 0;
if(FindCreateShadowFromPath(tchBuff, FALSE, &sFind32, &sSI, NULL))
{
LPCONNECTINFO lpHead = NULL;
BOOL fServerIsOffline = FALSE;
fServerIsOffline = ((sSI.uStatus & SHARE_DISCONNECTED_OP) != 0);
if(FGetConnectionListEx(&lpHead, tchBuff, TRUE, fServerIsOffline, NULL))
{
// take an extra reference, just in case there are some credentials on the server entry
// with the redir
// if it fails, don't stop going online
// the worst that could happen is that the user might get an extra popup
// for the explicit credential case
DWORD dwError;
dwError = DWConnectNet(tchBuff, tzDrive, NULL, NULL, NULL, 0, NULL);
if ((dwError != WN_SUCCESS) && (dwError != WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
{
tzDrive[0] = 0;
}
DisconnectList(&lpHead, NULL, 0);
}
fTransitionedToOnline = TransitionShareToOnline(INVALID_HANDLE_VALUE, sSI.hShare);
for (i=2;i<MAX_SERVER_SHARE_NAME_FOR_CSC;++i)
{
if (tchBuff[i] == '\\')
{
break;
}
}
Assert(i< MAX_SERVER_SHARE_NAME_FOR_CSC);
// going online
ReportTransitionToDfs(tchBuff, FALSE, i*sizeof(_TCHAR));
if (lpHead)
{
ReconnectList(&lpHead, NULL);
ClearConnectionList(&lpHead);
}
// if there was an extra reference,
// remove it
if (tzDrive[0])
{
DWDisconnectDriveMappedNet(tzDrive, TRUE);
}
}
return(fTransitionedToOnline);
}
BOOL
WINAPI
CSCTransitionServerOnlineA(
IN LPCSTR lpszShareName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
}
BOOL
WINAPI
CSCCheckShareOnlineExW(
IN LPCWSTR lpszShareName,
LPDWORD lpdwSpeed
)
/*++
Routine Description:
This routine checks whether a given share is available online.
Arguments:
lpszShareName
Returns:
Notes:
--*/
{
_TCHAR tchBuff[MAX_SERVER_SHARE_NAME_FOR_CSC], tzDrive[4];
BOOL fIsOnline = FALSE, fDone;
DWORD dwError;
if (lstrlen(lpszShareName) >= MAX_SERVER_SHARE_NAME_FOR_CSC)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lstrcpy(tchBuff, lpszShareName);
if (!LpBreakPath(tchBuff, TRUE, &fDone) && !fDone)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
dwError = DWConnectNet(tchBuff, tzDrive, NULL, NULL, NULL, 0, NULL);
if ((dwError == WN_SUCCESS) || (dwError == WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
{
fIsOnline = TRUE;
if (lpdwSpeed)
{
GetConnectionInfoForDriveBasedName(tzDrive, lpdwSpeed);
}
DWDisconnectDriveMappedNet(tzDrive, TRUE);
}
else
{
SetLastError(dwError);
}
return(fIsOnline);
}
BOOL
WINAPI
CSCCheckShareOnlineW(
IN LPCWSTR lpszShareName
)
/*++
Routine Description:
This routine checks whether a given share is available online.
Arguments:
lpszShareName
Returns:
Notes:
--*/
{
return (CSCCheckShareOnlineExW(lpszShareName, NULL));
}
BOOL
WINAPI
CSCCheckShareOnlineA(
IN LPCSTR lpszShareName
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
}
BOOL
WINAPI
CSCDoLocalRenameW(
IN LPCWSTR lpszSource,
IN LPCWSTR lpszDestination,
IN BOOL fReplaceFileIfExists
)
{
return CSCDoLocalRenameExW(lpszSource, lpszDestination, NULL, FALSE, fReplaceFileIfExists);
}
BOOL
WINAPI
CSCDoLocalRenameExW(
IN LPCWSTR lpszSource,
IN LPCWSTR lpszDestination,
IN WIN32_FIND_DATAW *lpFind32,
IN BOOL fMarkAsLocal,
IN BOOL fReplaceFileIfExists
)
/*++
Routine Description:
This routine does a rename in the datbase. The rename operation can be across shares
Arguments:
lpszSource Fully qualified source name (must be UNC)
lpszDestination Fully qualified destination directory name (must be UNC)
lpFind32 New name in the destination directory, given the long name
the shortnmae is locally generated. For this reason, when
a new name is given, fMarkAsLocal is forced TRUE.
fMarkAsLocal Mark the newly created entry as locally created (except see lpFind32)
fReplaceFileIfExists replace destination file with the source if it exists
Returns:
TRUE if successfull, FALSE otherwise. If the API fails, GetLastError returns the specific
errorcode.
Notes:
--*/
{
DWORD dwError = NO_ERROR;
WIN32_FIND_DATA sFind32;
BOOL fDone=FALSE, fRet = FALSE, fBeginInodeTransaction = FALSE, fSourceIsFile=FALSE;
SHADOWINFO sSI;
HSHADOW hDirFrom, hShadowFrom, hDirTo, hShadowTo=0;
HSHARE hShareFrom, hShareTo;
HANDLE hShadowDB;
DWORD lenSrc=0, lenDst=0;
ReintKdPrint(API, ("DoLocalRenameEx %ls %ls %x %x %x\r\n", lpszSource, lpszDestination, lpFind32, fMarkAsLocal, fReplaceFileIfExists));
try
{
if ((lenSrc = lstrlen(lpszSource)) >= MAX_PATH)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lstrcpy(sFind32.cFileName, lpszSource);
if (!LpBreakPath(sFind32.cFileName, TRUE, &fDone) && fDone)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
try
{
if ((lenDst = lstrlen(lpszDestination)) >= MAX_PATH)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
except(EXCEPTION_EXECUTE_HANDLER)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
// if source is not greater than the destination
// verify that we are not renaming the parent under it's own child
if (lenSrc <= lenDst)
{
lstrcpy(sFind32.cFileName, lpszDestination);
sFind32.cFileName[lenSrc] = 0;
// make a case insensitive comparison
if(!lstrcmpi(lpszSource, sFind32.cFileName))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
}
if ((hShadowDB = OpenShadowDatabaseIO()) ==INVALID_HANDLE_VALUE)
{
ReintKdPrint(BADERRORS, ("failed to open database\r\n"));
return FALSE;
}
if(BeginInodeTransactionHSHADOW())
{
fBeginInodeTransaction = TRUE;
if(!FindCreateShadowFromPath(lpszSource, FALSE, &sFind32, &sSI, NULL))
{
goto bailout;
}
ReintKdPrint(API, ("Source Share = %x Inode %x %x\r\n", sSI.hShare, sSI.hDir, sSI.hShadow));
hDirFrom = sSI.hDir;
hShadowFrom = sSI.hShadow;
hShareFrom = sSI.hShare;
fSourceIsFile = ((sFind32.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)==0);
if(!FindCreateShadowFromPath(lpszDestination, TRUE, &sFind32, &sSI, NULL))
{
goto bailout;
}
ReintKdPrint(API, ("Destination Share = %x Inode %x %x\r\n", sSI.hShare, sSI.hDir, sSI.hShadow));
hShareTo = sSI.hShare;
hDirTo = sSI.hShadow;
// if we are creating a new entry in the database, we say it was created
// offline
if (lpFind32)
{
fMarkAsLocal = TRUE;
fReplaceFileIfExists = FALSE;
}
if (((hShareFrom == hShareTo) && !fReplaceFileIfExists) ||fSourceIsFile)
{
// do the rename only if the source directory is not the same as the destination directory.
// or the destination name is different, otherwise there is nothing to do
if ((hDirFrom != sSI.hShadow)||(lpFind32))
{
if (RenameShadow(hShadowDB, hDirFrom, hShadowFrom, hDirTo, lpFind32, fReplaceFileIfExists, &hShadowTo))
{
//
fRet = SetShareStatus(hShadowDB, hShareTo, SHARE_REINT, SHADOW_FLAGS_OR);
if (fMarkAsLocal)
{
Assert(hShadowTo);
if (fSourceIsFile)
{
fRet = SetShadowInfo(hShadowDB, hDirTo, hShadowTo, NULL, SHADOW_LOCALLY_CREATED, SHADOW_FLAGS_ASSIGN);
}
else
{
SET_SUBTREE_STATUS sSSS;
memset(&sSSS, 0, sizeof(sSSS));
sSSS.uStatus = SHADOW_LOCALLY_CREATED;
sSSS.uOp = SHADOW_FLAGS_ASSIGN;
fRet = (TraverseOneDirectory(hShadowDB, NULL, hDirTo, hShadowTo, (LPTSTR)lpszSource, SetSubtreeStatus, &sSSS)!=TOD_ABORT);
}
}
if (!fRet)
{
dwError = GetLastError();
}
}
else
{
dwError = GetLastError();
}
}
else
{
fRet = TRUE;
}
}
else
{
MOVE_SUBTREE sMST;
memset(&sMST, 0, sizeof(sMST));
sMST.lptzSource = lpszSource;
sMST.lptzDestination = lpszDestination;
sMST.lpTos = &sMST.sTos;
sMST.sTos.hDir = hDirTo;
sMST.hShareTo = hShareTo;
if (fReplaceFileIfExists)
{
sMST.dwFlags |= MST_REPLACE_IF_EXISTS;
}
TraverseOneDirectory(hShadowDB, NULL, hDirFrom, hShadowFrom, (LPTSTR)lpszSource, MoveSubtree, &sMST);
fRet = (sMST.cntFail == 0);
Assert(sMST.lpTos == &sMST.sTos);
Assert(sMST.sTos.lpNext == NULL);
}
}
bailout:
if (fBeginInodeTransaction)
{
EndInodeTransactionHSHADOW();
}
if (!fRet)
{
SetLastError(dwError);
}
CloseShadowDatabaseIO(hShadowDB);
return fRet;
}
BOOL
CreateDirectoryAndSetHints(
HANDLE hShadowDB,
LPTSTR lptzFullPath,
DWORD dwCallbackReason,
WIN32_FIND_DATA *lpFind32,
SHADOWINFO *lpSI,
LPMOVE_SUBTREE lpMst
)
/*++
Routine Description:
This routine creates a copy of a source directory under a destination directory
Arguments:
hShadowDB Handle to issue ioctls to the redir
lptzFullPath fully qualified path to the item
dwCallbackReason TOD_CALLBACK_REASON_XXX (BEGIN, NEXT_ITEM or END)
lpFind32 local win32info
lpSI other info such as priority, pincount etc.
lpMst MOVE_SUBTREE structure which contains the rlevant info about this move
Returns:
TRUE if successfull, FALSE otherwise. If the API fails, GetLastError returns the specific
errorcode.
Notes:
--*/
{
BOOL fRet = FALSE;
lpMst->sFind32 = *lpFind32;
if(GetShadowEx(hShadowDB, lpMst->lpTos->hDir, &lpMst->sFind32, &lpMst->sSI))
{
// if it doesn't exist, create it and set it's hints to those found on the source
if (!lpMst->sSI.hShadow)
{
if (CreateShadow(hShadowDB, lpMst->lpTos->hDir, &lpMst->sFind32, lpSI->uStatus, &lpMst->sSI.hShadow))
{
lpMst->sSI.ulHintPri = lpSI->ulHintPri;
lpMst->sSI.ulHintFlags = lpSI->ulHintFlags;
if(AddHintFromInode(hShadowDB, lpMst->lpTos->hDir, lpMst->sSI.hShadow, &(lpMst->sSI.ulHintPri), &(lpMst->sSI.ulHintFlags)) != 0)
{
fRet = TRUE;
}
}
}
else
{
fRet = TRUE;
}
}
return fRet;
}
BOOL
WINAPI
CSCDoLocalRenameA(
IN LPCSTR lpszSource,
IN LPCSTR lpszDestination,
IN BOOL fReplcaeFileIfExists
)
/*++
Routine Description:
This routine does a rename in the datbase. The rename operation can be across shares
Arguments:
lpszSource Fully qualified source name (must be UNC)
lpszDestination Fully qualified destination name (must be UNC)
Returns:
TRUE if successfull, FALSE otherwise. If the API fails, GetLastError returns the specific
errorcode.
Notes:
--*/
{
SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
return (FALSE);
}
BOOL
WINAPI
CSCDoEnableDisable(
BOOL fEnable
)
/*++
Routine Description:
This routine enables/disables CSC
Arguments:
fEnable enable CSC if TRUE, else disable CSC
Returns:
TRUE if successfull, FALSE otherwise. If the API fails, GetLastError returns the specific
errorcode.
Notes:
--*/
{
BOOL fRet = FALSE, fReformat = FALSE;
char szDBDir[MAX_PATH+1];
DWORD dwDBCapacity, dwClusterSize;
if (IsPersonal() == TRUE) {
SetLastError(ERROR_INVALID_OPERATION);
return FALSE;
}
if (fEnable)
{
if (InitValues(szDBDir, sizeof(szDBDir), &dwDBCapacity, &dwClusterSize))
{
fReformat = QueryFormatDatabase();
fRet = EnableShadowingForUser(INVALID_HANDLE_VALUE, szDBDir, NULL, 0, dwDBCapacity, dwClusterSize, fReformat);
}
}
else
{
fRet = DisableShadowingForUser(INVALID_HANDLE_VALUE);
}
return fRet;
}
int
MoveSubtree(
HANDLE hShadowDB,
LPSECURITYINFO pShareSecurityInfo,
LPTSTR lptzFullPath,
DWORD dwCallbackReason,
WIN32_FIND_DATA *lpFind32,
SHADOWINFO *lpSI,
LPMOVE_SUBTREE lpMst
)
/*++
Routine Description:
This is a callback routine to TraverseOneDirectory. It moves the subtree from one place
in the hierarchy to another. It would be necessary to call this routine only when
the subtree is being moved from one share to another.
Arguments:
hShadowDB Handle to issue ioctls to the redir
lptzFullPath fully qualified path to the item
dwCallbackReason TOD_CALLBACK_REASON_XXX (BEGIN, NEXT_ITEM or END)
lpFind32 local win32info
lpSI other info such as priority, pincount etc.
lpMst MOVE_SUBTREE structure which contains the rlevant info about this move
Returns:
return code, whether continue, cancel etc.
Notes:
As TravesreOneDirectory descends the source subtree, this routine creates directories in the
corresponding location in the destination subtree. It then moves the files from one subtree
to another. At the end of the enumeration of any directory, it tries to delete the source
directory. The delete succeeds only if there are no more descedents left to the source
directory
--*/
{
BOOL fRet = FALSE;
LPMST_LIST lpT;
ReintKdPrint(API, ("MoveSubTree %ls\r\n", lptzFullPath));
switch (dwCallbackReason)
{
case TOD_CALLBACK_REASON_BEGIN:
{
ReintKdPrint(API, ("MST Begin source Inode %x %x\r\n", lpSI->hDir, lpSI->hShadow));
// Get the source directory info
if (GetShadowInfoEx(hShadowDB, lpSI->hDir, lpSI->hShadow, lpFind32, lpSI))
{
fRet = CreateDirectoryAndSetHints(hShadowDB, lptzFullPath, dwCallbackReason, lpFind32, lpSI, lpMst);
}
// if all is well, then make this directory the parent directory for
// all subsequent creates and renames
if (fRet)
{
lpT = (LPMST_LIST)LocalAlloc(LPTR, sizeof(MST_LIST));
if (!lpT)
{
return TOD_ABORT;
}
lpT->hDir = lpMst->sSI.hShadow;
lpT->lpNext = lpMst->lpTos;
lpMst->lpTos = lpT;
// mark the destination share dirty, if necessary
if (lpSI->uStatus & SHADOW_MODFLAGS)
{
if (!(lpMst->dwFlags & MST_SHARE_MARKED_DIRTY))
{
ReintKdPrint(API, ("Setting Share %x dirty \n", lpMst->hShareTo));
if(SetShareStatus(hShadowDB, lpMst->hShareTo, SHARE_REINT, SHADOW_FLAGS_OR))
{
lpMst->dwFlags |= MST_SHARE_MARKED_DIRTY;
}
}
}
}
else
{
lpMst->cntFail++;
}
}
break;
case TOD_CALLBACK_REASON_NEXT_ITEM:
// if the source is a file, then move it
ReintKdPrint(API, ("MST next source Inode %x %x\r\n", lpSI->hDir, lpSI->hShadow));
if(!(lpFind32->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
{
ReintKdPrint(API, ("MST rename file SrcInode %x %x to destdir %x\r\n", lpSI->hDir, lpSI->hShadow, lpMst->lpTos->hDir));
if (RenameShadow(hShadowDB, lpSI->hDir, lpSI->hShadow, lpMst->lpTos->hDir, NULL,
((lpMst->dwFlags & MST_REPLACE_IF_EXISTS)!=0), NULL))
{
fRet = TRUE;
}
}
else
{
if(CreateDirectoryAndSetHints(hShadowDB, lptzFullPath, dwCallbackReason, lpFind32, lpSI, lpMst))
{
fRet = TRUE;
}
}
if (!fRet)
{
lpMst->cntFail++;
}
// mark the destination share dirty, if necessary
if (lpSI->uStatus & SHADOW_MODFLAGS)
{
if (!(lpMst->dwFlags & MST_SHARE_MARKED_DIRTY))
{
if(SetShareStatus(hShadowDB, lpMst->hShareTo, SHARE_REINT, SHADOW_FLAGS_OR))
{
lpMst->dwFlags |= MST_SHARE_MARKED_DIRTY;
}
}
}
break;
case TOD_CALLBACK_REASON_END:
Assert(lpMst->lpTos);
lpT = lpMst->lpTos;
lpMst->lpTos = lpMst->lpTos->lpNext;
LocalFree(lpT);
fRet = TRUE;
ReintKdPrint(API, ("MST End Delete Inode %x %x \r\n", lpSI->hDir, lpSI->hShadow));
DeleteShadow(hShadowDB, lpSI->hDir, lpSI->hShadow);
break;
}
return (fRet?TOD_CONTINUE:TOD_ABORT);
}
int
SetSubtreeStatus(
HANDLE hShadowDB,
LPSECURITYINFO pShareSecurityInfo,
LPTSTR lptzFullPath,
DWORD dwCallbackReason,
WIN32_FIND_DATA *lpFind32,
SHADOWINFO *lpSI,
LPSET_SUBTREE_STATUS lpSss
)
/*++
Routine Description:
This is a callback routine to TraverseOneDirectory. It moves the subtree from one place
in the hierarchy to another. It would be necessary to call this routine only when
the subtree is being moved from one share to another.
Arguments:
hShadowDB Handle to issue ioctls to the redir
lptzFullPath fully qualified path to the item
dwCallbackReason TOD_CALLBACK_REASON_XXX (BEGIN, NEXT_ITEM or END)
lpFind32 local win32info
lpSI other info such as priority, pincount etc.
lpSss SET_SUBTREE_STATE structure which contains the relevant info about this state setting
Returns:
return code, whether continue, cancel etc.
Notes:
As TravesreOneDirectory descends the source subtree, this routine sets the required bits
--*/
{
ReintKdPrint(API, ("SetSubTreeState %ls\r\n", lptzFullPath));
if(SetShadowInfo(hShadowDB, lpSI->hDir, lpSI->hShadow, NULL, lpSss->uStatus, lpSss->uOp) == TRUE)
{
return TOD_CONTINUE;
}
else
{
return TOD_ABORT;
}
}
BOOL
WINAPI
CSCBeginSynchronizationW(
IN LPCTSTR lpszShareName,
LPDWORD lpdwSpeed,
LPDWORD lpdwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
_TCHAR tchBuff[MAX_SERVER_SHARE_NAME_FOR_CSC], tzDrive[4];
BOOL fIsOnline = FALSE, fDone, fExplicitCredentials=FALSE, fIsDfs;
DWORD dwError;
if (lstrlen(lpszShareName) >= MAX_SERVER_SHARE_NAME_FOR_CSC)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lstrcpy(tchBuff, lpszShareName);
if (!LpBreakPath(tchBuff, TRUE, &fDone) && !fDone)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
ReintKdPrint(API, (" CSCBeginSynchronization %ls\r\n", tchBuff));
dwError = DWConnectNet(tchBuff, tzDrive, NULL, NULL, NULL, CONNECT_INTERACTIVE, NULL);
if ((dwError == WN_SUCCESS)||(dwError==WN_CONNECTED_OTHER_PASSWORD)||(dwError==WN_CONNECTED_OTHER_PASSWORD_DEFAULT))
{
fIsOnline = TRUE;
if (lpdwSpeed)
{
GetConnectionInfoForDriveBasedName(tzDrive, lpdwSpeed);
}
if (dwError==WN_CONNECTED_OTHER_PASSWORD || dwError==WN_CONNECTED_OTHER_PASSWORD_DEFAULT)
{
ReintKdPrint(API, (" CSCBeginSynchronization: Explicit Credentials\r\n"));
fExplicitCredentials = TRUE;
dwError = DoNetUseAddForAgent(tchBuff, NULL, NULL, NULL, NULL, 0, &fIsDfs);
if (dwError != WN_SUCCESS && dwError!=WN_CONNECTED_OTHER_PASSWORD_DEFAULT)
{
fIsOnline = FALSE;
ReintKdPrint(API, (" CSCBeginSynchronization: Failed extra reference %d\r\n", dwError));
}
}
DWDisconnectDriveMappedNet(tzDrive, TRUE);
}
if (!fIsOnline)
{
ReintKdPrint(ALWAYS, (" CSCBeginSynchronization: Failed %d\r\n", dwError));
SetLastError(dwError);
}
else
{
*lpdwContext = fExplicitCredentials;
}
return(fIsOnline);
}
BOOL
WINAPI
CSCEndSynchronizationW(
IN LPCTSTR lpszShareName,
DWORD dwContext
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
_TCHAR tchBuff[MAX_SERVER_SHARE_NAME_FOR_CSC], tzDrive[4];
BOOL fIsOnline = FALSE, fDone, fExplicitCredentials=FALSE;
DWORD dwError;
if (lstrlen(lpszShareName) >= MAX_SERVER_SHARE_NAME_FOR_CSC)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
lstrcpy(tchBuff, lpszShareName);
if (!LpBreakPath(tchBuff, TRUE, &fDone) && !fDone)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (dwContext != 0)
{
WNetCancelConnection2(tchBuff, 0, TRUE);
}
return TRUE;
}
#if 0
BOOL
WINAPI
CSCEncryptDecryptFileW(
IN LPCTSTR lpszFileName,
IN BOOL fEncrypt
)
/*++
Routine Description:
Arguments:
Returns:
Notes:
--*/
{
WIN32_FIND_DATA sFind32;
SHADOWINFO sSI;
BOOL fRet = FALSE;
DWORD dwError = ERROR_GEN_FAILURE;
//
if(FindCreateShadowFromPath(lpszFileName, FALSE, &sFind32, &sSI, NULL))
{
fRet = RecreateShadow(INVALID_HANDLE_VALUE, sSI.hDir, sSI.hShadow, (fEncrypt)?FILE_ATTRIBUTE_ENCRYPTED:0);
}
return fRet;
}
#endif
BOOL
WINAPI
CSCQueryDatabaseStatus(
ULONG *pulStatus,
ULONG *pulErrors
)
/*++
Routine Description:
Allows caller to query the database status.
Arguments:
pulStatus Current status. Encryption status is the most interesting
pulErrors If the database has any errors, one or more bits will be set
Returns:
TRUE if the API succeeded
Notes:
--*/
{
GLOBALSTATUS sGS;
if(!GetGlobalStatus(INVALID_HANDLE_VALUE, &sGS))
{
return FALSE;
}
*pulStatus = sGS.sST.uFlags;
*pulErrors = sGS.uDatabaseErrorFlags;
return TRUE;
}
BOOL
WINAPI
CSCEncryptDecryptDatabase(
IN BOOL fEncrypt,
IN LPCSCPROCW lpfnEnumProgress,
IN DWORD_PTR dwContext
)
/*++
Routine Description:
This routine is used to encrypt/decrypt the entire database in system context. The routine checks that
the CSC database is hosted on a filesystem that allows encryption. Only admins can do the conversion
Arguments:
fEncrypt if TRUE, we encrypt the database else we decrypt.
LPCSCPROCW callback proc. The usual set of CSCPROC_REASON_BEGIN, CSCPROC_REASON_MORE_DATA, CSC_PROC_END
are sent when the conversion actually begins. Conversion can fail if a file is open or for
some other reason, in which case the second to last parameter in the callback with
CSCPROC_REASON_MORE_DATA has the error code. The third to last parameter indicates whether
the conversion was complete or not. Incomplete conversion is not an error condition.
dwContext callback context
Returns:
TRUE if no errors encountered.
Notes:
Theory of operations:
The CSC database encryption code encrypts all the inodes represented by remote files.
Who: Only user in admingroup can do encryption/decryption. This is checked in kernel
Which context: Files are encrypted in system context. This allows files to be shared
while still being encrypted. This solution protects from a stolen laptop case.
The database can have the following status set on it based on the four encryption states:
a) FLAG_DATABASESTATUS_UNENCRYPTED b) FLAG_DATABASESTATUS_PARTIALLY_UNENCRYPTED
c) FLAG_DATABASESTATUS_ENCRYPTED d) FLAG_DATABASESTATUS_PARTIALLY_ENCRYPTED
In states a) and b) new files are created unencrypted. In states c) and d) new files are created encrypted.
At the beginning of the conversion, the database stats is marked to the appropriate XX_PARTIAL_XX
state. At the end, if all goes well, it is transitioned to the final state.
At the time of enabling CSC, if the database state is XX_PARTIAL_XX, the kernel code tries to
complete the conversion to the appropriate final state.
--*/
{
BOOL fRet = FALSE, fComplete = FALSE;
HANDLE hShadowDB = INVALID_HANDLE_VALUE;
SHADOWSTORE sST;
DWORD dwRet, dwError=0, dwStartigNameSpaceVersion;
ULONG uT;
WIN32_FIND_DATA sFind32;
ENCRYPT_DECRYPT_SUBTREE sEDS;
SHADOWINFO sSI;
HANDLE ulEnumCookie;
// we have begun
if (lpfnEnumProgress)
{
dwRet = (*lpfnEnumProgress)(NULL, 0, 0, 0, NULL, CSCPROC_REASON_BEGIN, fEncrypt, 0, dwContext);
if (dwRet != CSCPROC_RETURN_CONTINUE )
{
goto bailout;
}
}
if (GetShadowDatabaseLocation(INVALID_HANDLE_VALUE, &sFind32))
{
// Set NULL after the root backslash so that this API works correctly
sFind32.cFileName[3] = 0;
if(!GetVolumeInformation(sFind32.cFileName, NULL, 0, NULL, &dwRet, &dwError, NULL, 0))
{
ReintKdPrint(BADERRORS, ("failed to get volume info for %ls Error=%d\r\n", sFind32.cFileName, GetLastError()));
goto bailout;
}
if (!(dwError & FILE_SUPPORTS_ENCRYPTION))
{
ReintKdPrint(BADERRORS, ("volume doesn't support replication \r\n"));
SetLastError(ERROR_NOT_SUPPORTED);
goto bailout;
}
}
else
{
ReintKdPrint(BADERRORS, ("failed to get database location Error=%d\r\n", GetLastError()));
goto bailout;
}
if ((hShadowDB = OpenShadowDatabaseIO())==INVALID_HANDLE_VALUE)
{
goto bailout;
}
// let us see whether we need to do anything
if(!GetSpaceStats(hShadowDB, &sST))
{
goto bailout;
}
sST.uFlags &= FLAG_DATABASESTATUS_ENCRYPTION_MASK;
// the database is already in the state desired, succeed and quit
if ((fEncrypt && (sST.uFlags == FLAG_DATABASESTATUS_ENCRYPTED))||
(!fEncrypt && (sST.uFlags == FLAG_DATABASESTATUS_UNENCRYPTED)))
{
fRet = TRUE;
goto bailout;
}
sST.uFlags = (fEncrypt)? FLAG_DATABASESTATUS_PARTIALLY_ENCRYPTED : FLAG_DATABASESTATUS_PARTIALLY_UNENCRYPTED;
// mark the database in appropriate transient state
// once this is marked, any new file that is created is in correct encryption state
if (!SetDatabaseStatus(hShadowDB, sST.uFlags, FLAG_DATABASESTATUS_ENCRYPTION_MASK))
{
goto bailout;
}
memset(&sEDS, 0, sizeof(sEDS));
memset(&sFind32, 0, sizeof(sFind32));
lstrcpy(sFind32.cFileName, _TEXT("*"));
if(!FindOpenShadow( hShadowDB, 0, FINDOPEN_SHADOWINFO_ALL,
&sFind32, &sSI))
{
// The database is empty, so set the state to fully encrypted (or decrypted)
sST.uFlags = (fEncrypt)? FLAG_DATABASESTATUS_ENCRYPTED : FLAG_DATABASESTATUS_UNENCRYPTED;
SetDatabaseStatus(hShadowDB, sST.uFlags, FLAG_DATABASESTATUS_ENCRYPTION_MASK);
goto bailout;
}
dwStartigNameSpaceVersion = sSI.dwNameSpaceVersion;
ulEnumCookie = sSI.uEnumCookie;
sEDS.dwContext = dwContext;
sEDS.lpfnEnumProgress = lpfnEnumProgress;
sEDS.fEncrypt = fEncrypt;
ReintKdPrint(ALWAYS, ("Starting NameSpaceVersion %x \n", dwStartigNameSpaceVersion));
do {
if(TraverseOneDirectory(hShadowDB, NULL, sSI.hDir, sSI.hShadow, sFind32.cFileName, EncryptDecryptSubtree, &sEDS)==TOD_ABORT)
{
break;
}
}while(FindNextShadow(hShadowDB, ulEnumCookie, &sFind32, &sSI));
FindCloseShadow(hShadowDB, ulEnumCookie);
ReintKdPrint(ALWAYS, ("Ending NameSpaceVersion %x \n", sEDS.dwEndingNameSpaceVersion));
if (!(sEDS.dwFlags & EDS_FLAG_ERROR_ENCOUNTERED) &&
(dwStartigNameSpaceVersion == sEDS.dwEndingNameSpaceVersion))
{
sST.uFlags = (fEncrypt)? FLAG_DATABASESTATUS_ENCRYPTED : FLAG_DATABASESTATUS_UNENCRYPTED;
if (!SetDatabaseStatus(hShadowDB, sST.uFlags, FLAG_DATABASESTATUS_ENCRYPTION_MASK))
{
goto bailout;
}
fComplete = TRUE;
}
dwError = NO_ERROR;
fRet = TRUE;
bailout:
if (!fRet)
{
dwError = GetLastError();
}
if (hShadowDB != INVALID_HANDLE_VALUE)
{
CloseShadowDatabaseIO(hShadowDB);
}
if (lpfnEnumProgress)
{
dwRet = (*lpfnEnumProgress)(NULL, 0, 0, 0, NULL, CSCPROC_REASON_END, fComplete, dwError, dwContext);
}
return fRet;
}
int
EncryptDecryptSubtree(
HANDLE hShadowDB,
LPSECURITYINFO pShareSecurityInfo,
LPTSTR lptzFullPath,
DWORD dwCallbackReason,
WIN32_FIND_DATA *lpFind32,
SHADOWINFO *lpSI,
LPENCRYPT_DECRYPT_SUBTREE lpEds
)
/*++
Routine Description:
This is a callback routine to TraverseOneDirectory. It encrypts or decrypts files in the subtree
Arguments:
hShadowDB Handle to issue ioctls to the redir
lptzFullPath fully qualified path to the item
dwCallbackReason TOD_CALLBACK_REASON_XXX (BEGIN, NEXT_ITEM or END)
lpFind32 local win32info
lpSI other info such as priority, pincount etc.
lpEds ENCRYPT_DECRYPT_SUBTREE structure which contains the relevant info such
as encrypt-or-decrypt, callback function, context, error flag
Returns:
return code, whether continue, cancel etc.
Notes:
--*/
{
BOOL fRet;
DWORD dwError, dwRet;
int iRet = TOD_CONTINUE;
//Bug: 581224
// Should return TOD_CONTINUE for TOD_CALLBACK_REASON_BEGIN
if (dwCallbackReason == TOD_CALLBACK_REASON_BEGIN) {
return iRet;
}
// save the last known version number, the calling routine will
// compare it against the first one
if(dwCallbackReason == TOD_CALLBACK_REASON_NEXT_ITEM)
{
lpEds->dwEndingNameSpaceVersion = lpSI->dwNameSpaceVersion;
}
// operate only on files
if (lpSI->uStatus & SHADOW_IS_FILE)
{
ReintKdPrint(ALWAYS, ("Processing file %ls \n", lptzFullPath));
do
{
dwError = 0;
// try conversion. If we fail, not in the EDS structure so
// the caller knows
if(!RecreateShadow(hShadowDB, lpSI->hDir, lpSI->hShadow, (lpEds->fEncrypt)?FILE_ATTRIBUTE_ENCRYPTED:0))
{
dwError = GetLastError();
}
if (lpEds->lpfnEnumProgress)
{
dwRet = (*(lpEds->lpfnEnumProgress))(lptzFullPath, 0, 0, 0, lpFind32, CSCPROC_REASON_MORE_DATA, 0, dwError, lpEds->dwContext);
if (dwRet == CSCPROC_RETURN_RETRY)
{
continue;
}
// abort if the callback wants to
if (dwRet != CSCPROC_RETURN_CONTINUE )
{
iRet = TOD_ABORT;
}
}
break;
}
while (TRUE);
if (dwError != ERROR_SUCCESS)
{
lpEds->dwFlags |= EDS_FLAG_ERROR_ENCOUNTERED;
}
}
return iRet;
}
BOOL
CSCPurgeUnpinnedFiles(
ULONG Timeout,
PULONG pnFiles,
PULONG pnYoungFiles)
{
BOOL iRet;
iRet = PurgeUnpinnedFiles(
INVALID_HANDLE_VALUE,
Timeout,
pnFiles,
pnYoungFiles);
// DbgPrint("CSCPurgeUnpinnedFiles(Timeout=%d nFiles=%d nYoungFiles=%d)\n",
// Timeout,
// *pnFiles,
// *pnYoungFiles);
return iRet;
}
BOOL
WINAPI
CSCShareIdToShareName(
ULONG ShareId,
PBYTE Buffer,
PDWORD pBufSize)
{
BOOL iRet;
iRet = ShareIdToShareName(
INVALID_HANDLE_VALUE,
ShareId,
Buffer,
pBufSize);
return iRet;
}
BOOL
IsPersonal(VOID)
{
OSVERSIONINFOEX Osvi;
DWORD TypeMask;
DWORDLONG ConditionMask;
memset(&Osvi, 0, sizeof(OSVERSIONINFOEX));
Osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
Osvi.wSuiteMask = VER_SUITE_PERSONAL;
TypeMask = VER_SUITENAME;
ConditionMask = 0;
VER_SET_CONDITION(ConditionMask, VER_SUITENAME, VER_OR);
return(VerifyVersionInfo(&Osvi, TypeMask, ConditionMask));
}