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