git-commit-vandalism/t/helper/test-drop-caches.c
Ben Peart 5a06a20e0c handle lower case drive letters on Windows
On Windows, if a tool calls SetCurrentDirectory with a lower case drive
letter, the subsequent call to GetCurrentDirectory will return the same
lower case drive letter. Powershell, for example, does not normalize the
path. If that happens, test-drop-caches will error out as it does not
correctly to handle lower case drive letters.

Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Ben Peart <Ben.Peart@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-07-12 12:11:05 -07:00

158 lines
3.7 KiB
C

#include "test-tool.h"
#include "git-compat-util.h"
#if defined(GIT_WINDOWS_NATIVE)
#include "lazyload.h"
static int cmd_sync(void)
{
char Buffer[MAX_PATH];
DWORD dwRet;
char szVolumeAccessPath[] = "\\\\.\\X:";
HANDLE hVolWrite;
int success = 0;
dwRet = GetCurrentDirectory(MAX_PATH, Buffer);
if ((0 == dwRet) || (dwRet > MAX_PATH))
return error("Error getting current directory");
if (!has_dos_drive_prefix(Buffer))
return error("'%s': invalid drive letter", Buffer);
szVolumeAccessPath[4] = Buffer[0];
hVolWrite = CreateFile(szVolumeAccessPath, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if (INVALID_HANDLE_VALUE == hVolWrite)
return error("Unable to open volume for writing, need admin access");
success = FlushFileBuffers(hVolWrite);
if (!success)
error("Unable to flush volume");
CloseHandle(hVolWrite);
return !success;
}
#define STATUS_SUCCESS (0x00000000L)
#define STATUS_PRIVILEGE_NOT_HELD (0xC0000061L)
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemMemoryListInformation = 80,
} SYSTEM_INFORMATION_CLASS;
typedef enum _SYSTEM_MEMORY_LIST_COMMAND {
MemoryCaptureAccessedBits,
MemoryCaptureAndResetAccessedBits,
MemoryEmptyWorkingSets,
MemoryFlushModifiedList,
MemoryPurgeStandbyList,
MemoryPurgeLowPriorityStandbyList,
MemoryCommandMax
} SYSTEM_MEMORY_LIST_COMMAND;
static BOOL GetPrivilege(HANDLE TokenHandle, LPCSTR lpName, int flags)
{
BOOL bResult;
DWORD dwBufferLength;
LUID luid;
TOKEN_PRIVILEGES tpPreviousState;
TOKEN_PRIVILEGES tpNewState;
dwBufferLength = 16;
bResult = LookupPrivilegeValueA(0, lpName, &luid);
if (bResult) {
tpNewState.PrivilegeCount = 1;
tpNewState.Privileges[0].Luid = luid;
tpNewState.Privileges[0].Attributes = 0;
bResult = AdjustTokenPrivileges(TokenHandle, 0, &tpNewState,
(DWORD)((LPBYTE)&(tpNewState.Privileges[1]) - (LPBYTE)&tpNewState),
&tpPreviousState, &dwBufferLength);
if (bResult) {
tpPreviousState.PrivilegeCount = 1;
tpPreviousState.Privileges[0].Luid = luid;
tpPreviousState.Privileges[0].Attributes = flags != 0 ? 2 : 0;
bResult = AdjustTokenPrivileges(TokenHandle, 0, &tpPreviousState,
dwBufferLength, 0, 0);
}
}
return bResult;
}
static int cmd_dropcaches(void)
{
HANDLE hProcess = GetCurrentProcess();
HANDLE hToken;
DECLARE_PROC_ADDR(ntdll.dll, DWORD, NtSetSystemInformation, INT, PVOID, ULONG);
SYSTEM_MEMORY_LIST_COMMAND command;
int status;
if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
return error("Can't open current process token");
if (!GetPrivilege(hToken, "SeProfileSingleProcessPrivilege", 1))
return error("Can't get SeProfileSingleProcessPrivilege");
CloseHandle(hToken);
if (!INIT_PROC_ADDR(NtSetSystemInformation))
return error("Could not find NtSetSystemInformation() function");
command = MemoryPurgeStandbyList;
status = NtSetSystemInformation(
SystemMemoryListInformation,
&command,
sizeof(SYSTEM_MEMORY_LIST_COMMAND)
);
if (status == STATUS_PRIVILEGE_NOT_HELD)
error("Insufficient privileges to purge the standby list, need admin access");
else if (status != STATUS_SUCCESS)
error("Unable to execute the memory list command %d", status);
return status;
}
#elif defined(__linux__)
static int cmd_sync(void)
{
return system("sync");
}
static int cmd_dropcaches(void)
{
return system("echo 3 | sudo tee /proc/sys/vm/drop_caches");
}
#elif defined(__APPLE__)
static int cmd_sync(void)
{
return system("sync");
}
static int cmd_dropcaches(void)
{
return system("sudo purge");
}
#else
static int cmd_sync(void)
{
return 0;
}
static int cmd_dropcaches(void)
{
return error("drop caches not implemented on this platform");
}
#endif
int cmd__drop_caches(int argc, const char **argv)
{
cmd_sync();
return cmd_dropcaches();
}