]>
Commit | Line | Data |
---|---|---|
14527b30 BP |
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; | |
68440496 | 9 | char szVolumeAccessPath[] = "\\\\.\\XXXX:"; |
14527b30 | 10 | HANDLE hVolWrite; |
68440496 | 11 | int success = 0, dos_drive_prefix; |
14527b30 BP |
12 | |
13 | dwRet = GetCurrentDirectory(MAX_PATH, Buffer); | |
14 | if ((0 == dwRet) || (dwRet > MAX_PATH)) | |
15 | return error("Error getting current directory"); | |
16 | ||
68440496 JS |
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'; | |
14527b30 | 23 | |
14527b30 BP |
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 | } |