Sync with maint
[git] / t / helper / test-drop-caches.c
1 #include "git-compat-util.h"
2
3 #if defined(GIT_WINDOWS_NATIVE)
4
5 static 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
38 typedef enum _SYSTEM_INFORMATION_CLASS {
39         SystemMemoryListInformation = 80,
40 } SYSTEM_INFORMATION_CLASS;
41
42 typedef 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
52 static 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
80 static 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
124 static int cmd_sync(void)
125 {
126         return system("sync");
127 }
128
129 static int cmd_dropcaches(void)
130 {
131         return system("echo 3 | sudo tee /proc/sys/vm/drop_caches");
132 }
133
134 #elif defined(__APPLE__)
135
136 static int cmd_sync(void)
137 {
138         return system("sync");
139 }
140
141 static int cmd_dropcaches(void)
142 {
143         return system("sudo purge");
144 }
145
146 #else
147
148 static int cmd_sync(void)
149 {
150         return 0;
151 }
152
153 static int cmd_dropcaches(void)
154 {
155         return error("drop caches not implemented on this platform");
156 }
157
158 #endif
159
160 int cmd_main(int argc, const char **argv)
161 {
162         cmd_sync();
163         return cmd_dropcaches();
164 }