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