t / helper / test-drop-caches.con commit t/helper: merge test-read-cache into test-tool (5fbe600)
   1#include "test-tool.h"
   2#include "git-compat-util.h"
   3
   4#if defined(GIT_WINDOWS_NATIVE)
   5
   6static int cmd_sync(void)
   7{
   8        char Buffer[MAX_PATH];
   9        DWORD dwRet;
  10        char szVolumeAccessPath[] = "\\\\.\\X:";
  11        HANDLE hVolWrite;
  12        int success = 0;
  13
  14        dwRet = GetCurrentDirectory(MAX_PATH, Buffer);
  15        if ((0 == dwRet) || (dwRet > MAX_PATH))
  16                return error("Error getting current directory");
  17
  18        if ((Buffer[0] < 'A') || (Buffer[0] > 'Z'))
  19                return error("Invalid drive letter '%c'", Buffer[0]);
  20
  21        szVolumeAccessPath[4] = Buffer[0];
  22        hVolWrite = CreateFile(szVolumeAccessPath, GENERIC_READ | GENERIC_WRITE,
  23                FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
  24        if (INVALID_HANDLE_VALUE == hVolWrite)
  25                return error("Unable to open volume for writing, need admin access");
  26
  27        success = FlushFileBuffers(hVolWrite);
  28        if (!success)
  29                error("Unable to flush volume");
  30
  31        CloseHandle(hVolWrite);
  32
  33        return !success;
  34}
  35
  36#define STATUS_SUCCESS                  (0x00000000L)
  37#define STATUS_PRIVILEGE_NOT_HELD       (0xC0000061L)
  38
  39typedef enum _SYSTEM_INFORMATION_CLASS {
  40        SystemMemoryListInformation = 80,
  41} SYSTEM_INFORMATION_CLASS;
  42
  43typedef enum _SYSTEM_MEMORY_LIST_COMMAND {
  44        MemoryCaptureAccessedBits,
  45        MemoryCaptureAndResetAccessedBits,
  46        MemoryEmptyWorkingSets,
  47        MemoryFlushModifiedList,
  48        MemoryPurgeStandbyList,
  49        MemoryPurgeLowPriorityStandbyList,
  50        MemoryCommandMax
  51} SYSTEM_MEMORY_LIST_COMMAND;
  52
  53static BOOL GetPrivilege(HANDLE TokenHandle, LPCSTR lpName, int flags)
  54{
  55        BOOL bResult;
  56        DWORD dwBufferLength;
  57        LUID luid;
  58        TOKEN_PRIVILEGES tpPreviousState;
  59        TOKEN_PRIVILEGES tpNewState;
  60
  61        dwBufferLength = 16;
  62        bResult = LookupPrivilegeValueA(0, lpName, &luid);
  63        if (bResult) {
  64                tpNewState.PrivilegeCount = 1;
  65                tpNewState.Privileges[0].Luid = luid;
  66                tpNewState.Privileges[0].Attributes = 0;
  67                bResult = AdjustTokenPrivileges(TokenHandle, 0, &tpNewState,
  68                        (DWORD)((LPBYTE)&(tpNewState.Privileges[1]) - (LPBYTE)&tpNewState),
  69                        &tpPreviousState, &dwBufferLength);
  70                if (bResult) {
  71                        tpPreviousState.PrivilegeCount = 1;
  72                        tpPreviousState.Privileges[0].Luid = luid;
  73                        tpPreviousState.Privileges[0].Attributes = flags != 0 ? 2 : 0;
  74                        bResult = AdjustTokenPrivileges(TokenHandle, 0, &tpPreviousState,
  75                                dwBufferLength, 0, 0);
  76                }
  77        }
  78        return bResult;
  79}
  80
  81static int cmd_dropcaches(void)
  82{
  83        HANDLE hProcess = GetCurrentProcess();
  84        HANDLE hToken;
  85        HMODULE ntdll;
  86        DWORD(WINAPI *NtSetSystemInformation)(INT, PVOID, ULONG);
  87        SYSTEM_MEMORY_LIST_COMMAND command;
  88        int status;
  89
  90        if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
  91                return error("Can't open current process token");
  92
  93        if (!GetPrivilege(hToken, "SeProfileSingleProcessPrivilege", 1))
  94                return error("Can't get SeProfileSingleProcessPrivilege");
  95
  96        CloseHandle(hToken);
  97
  98        ntdll = LoadLibrary("ntdll.dll");
  99        if (!ntdll)
 100                return error("Can't load ntdll.dll, wrong Windows version?");
 101
 102        NtSetSystemInformation =
 103                (DWORD(WINAPI *)(INT, PVOID, ULONG))GetProcAddress(ntdll, "NtSetSystemInformation");
 104        if (!NtSetSystemInformation)
 105                return error("Can't get function addresses, wrong Windows version?");
 106
 107        command = MemoryPurgeStandbyList;
 108        status = NtSetSystemInformation(
 109                SystemMemoryListInformation,
 110                &command,
 111                sizeof(SYSTEM_MEMORY_LIST_COMMAND)
 112        );
 113        if (status == STATUS_PRIVILEGE_NOT_HELD)
 114                error("Insufficient privileges to purge the standby list, need admin access");
 115        else if (status != STATUS_SUCCESS)
 116                error("Unable to execute the memory list command %d", status);
 117
 118        FreeLibrary(ntdll);
 119
 120        return status;
 121}
 122
 123#elif defined(__linux__)
 124
 125static int cmd_sync(void)
 126{
 127        return system("sync");
 128}
 129
 130static int cmd_dropcaches(void)
 131{
 132        return system("echo 3 | sudo tee /proc/sys/vm/drop_caches");
 133}
 134
 135#elif defined(__APPLE__)
 136
 137static int cmd_sync(void)
 138{
 139        return system("sync");
 140}
 141
 142static int cmd_dropcaches(void)
 143{
 144        return system("sudo purge");
 145}
 146
 147#else
 148
 149static int cmd_sync(void)
 150{
 151        return 0;
 152}
 153
 154static int cmd_dropcaches(void)
 155{
 156        return error("drop caches not implemented on this platform");
 157}
 158
 159#endif
 160
 161int cmd__drop_caches(int argc, const char **argv)
 162{
 163        cmd_sync();
 164        return cmd_dropcaches();
 165}