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