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