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