Merge branch 'jk/t5561-missing-curl'
[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 }