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