]>
Commit | Line | Data |
---|---|---|
1c854745 | 1 | #include "test-tool.h" |
14527b30 BP |
2 | #include "git-compat-util.h" |
3 | ||
4 | #if defined(GIT_WINDOWS_NATIVE) | |
447ed832 | 5 | #include "lazyload.h" |
14527b30 BP |
6 | |
7 | static int cmd_sync(void) | |
8 | { | |
9 | char Buffer[MAX_PATH]; | |
10 | DWORD dwRet; | |
68440496 | 11 | char szVolumeAccessPath[] = "\\\\.\\XXXX:"; |
14527b30 | 12 | HANDLE hVolWrite; |
68440496 | 13 | int success = 0, dos_drive_prefix; |
14527b30 BP |
14 | |
15 | dwRet = GetCurrentDirectory(MAX_PATH, Buffer); | |
16 | if ((0 == dwRet) || (dwRet > MAX_PATH)) | |
17 | return error("Error getting current directory"); | |
18 | ||
68440496 JS |
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'; | |
14527b30 | 25 | |
14527b30 BP |
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; | |
447ed832 | 89 | DECLARE_PROC_ADDR(ntdll.dll, DWORD, NtSetSystemInformation, INT, PVOID, ULONG); |
14527b30 BP |
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 | ||
447ed832 BP |
101 | if (!INIT_PROC_ADDR(NtSetSystemInformation)) |
102 | return error("Could not find NtSetSystemInformation() function"); | |
14527b30 BP |
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 | ||
14527b30 BP |
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 | ||
1c854745 | 156 | int cmd__drop_caches(int argc, const char **argv) |
14527b30 BP |
157 | { |
158 | cmd_sync(); | |
159 | return cmd_dropcaches(); | |
160 | } |