1#include "test-tool.h"
   2#include "git-compat-util.h"
   3#if defined(GIT_WINDOWS_NATIVE)
   5#include "lazyload.h"
   6static 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        dwRet = GetCurrentDirectory(MAX_PATH, Buffer);
  16        if ((0 == dwRet) || (dwRet > MAX_PATH))
  17                return error("Error getting current directory");
  18        if (!has_dos_drive_prefix(Buffer))
  20                return error("'%s': invalid drive letter", Buffer);
  21        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        success = FlushFileBuffers(hVolWrite);
  29        if (!success)
  30                error("Unable to flush volume");
  31        CloseHandle(hVolWrite);
  33        return !success;
  35}
  36#define STATUS_SUCCESS                  (0x00000000L)
  38#define STATUS_PRIVILEGE_NOT_HELD       (0xC0000061L)
  39typedef enum _SYSTEM_INFORMATION_CLASS {
  41        SystemMemoryListInformation = 80,
  42} SYSTEM_INFORMATION_CLASS;
  43typedef enum _SYSTEM_MEMORY_LIST_COMMAND {
  45        MemoryCaptureAccessedBits,
  46        MemoryCaptureAndResetAccessedBits,
  47        MemoryEmptyWorkingSets,
  48        MemoryFlushModifiedList,
  49        MemoryPurgeStandbyList,
  50        MemoryPurgeLowPriorityStandbyList,
  51        MemoryCommandMax
  52} SYSTEM_MEMORY_LIST_COMMAND;
  53static 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        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}
  81static 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        if (!OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
  91                return error("Can't open current process token");
  92        if (!GetPrivilege(hToken, "SeProfileSingleProcessPrivilege", 1))
  94                return error("Can't get SeProfileSingleProcessPrivilege");
  95        CloseHandle(hToken);
  97        if (!INIT_PROC_ADDR(NtSetSystemInformation))
  99                return error("Could not find NtSetSystemInformation() function");
 100        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        return status;
 113}
 114#elif defined(__linux__)
 116static int cmd_sync(void)
 118{
 119        return system("sync");
 120}
 121static int cmd_dropcaches(void)
 123{
 124        return system("echo 3 | sudo tee /proc/sys/vm/drop_caches");
 125}
 126#elif defined(__APPLE__)
 128static int cmd_sync(void)
 130{
 131        return system("sync");
 132}
 133static int cmd_dropcaches(void)
 135{
 136        return system("sudo purge");
 137}
 138#else
 140static int cmd_sync(void)
 142{
 143        return 0;
 144}
 145static int cmd_dropcaches(void)
 147{
 148        return error("drop caches not implemented on this platform");
 149}
 150#endif
 152int cmd__drop_caches(int argc, const char **argv)
 154{
 155        cmd_sync();
 156        return cmd_dropcaches();
 157}