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