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