Remove do-nothing command and add warning about it
[amule.git] / src / PlatformSpecific.cpp
blob450d5769dbd6f8f5dbfd460a80d6c9e3c5167733
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2008-2011 aMule Team ( admin@amule.org / http://www.amule.org )
5 //
6 // Any parts of this program derived from the xMule, lMule or eMule project,
7 // or contributed by third-party developers are copyrighted by their
8 // respective authors.
9 //
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
15 // This program is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "PlatformSpecific.h"
26 #include "config.h"
28 // NTFS Sparse Files (only for MSW)
29 #ifdef __WINDOWS__
30 #include "common/Format.h"
31 #include "Logger.h"
32 #include <winbase.h>
33 #include <winioctl.h>
34 #ifndef FSCTL_SET_SPARSE
35 # define FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
36 #endif
37 #ifndef FSCTL_SET_ZERO_DATA
38 # define FSCTL_SET_ZERO_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_DATA)
39 #endif
41 // Create a message from a Windows error code
42 static wxString SystemError()
44 WCHAR * lpMsgBuf = NULL;
46 FormatMessageW(
47 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
48 NULL,
49 GetLastError(),
50 0, // Default language
51 (LPWSTR) &lpMsgBuf,
53 NULL
56 wxString ret(lpMsgBuf);
57 LocalFree(lpMsgBuf);
58 return ret;
61 // Create a file in sparse mode
62 bool PlatformSpecific::CreateSparseFile(const CPath& name, uint64_t size)
64 DWORD dwReturnedBytes=0;
66 HANDLE hd = CreateFileW(name.GetRaw().c_str(),
67 GENERIC_READ | GENERIC_WRITE,
68 0, // share - not shareable
69 NULL, // security - not inheritable
70 CREATE_ALWAYS,
71 FILE_ATTRIBUTE_ARCHIVE,
72 NULL);
73 if (hd == INVALID_HANDLE_VALUE) {
74 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (OPEN): %s ")) % name % SystemError());
75 return false;
78 if (!DeviceIoControl(hd, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwReturnedBytes, NULL)) {
79 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (SET_SPARSE): %s ")) % name % SystemError());
80 } else {
81 // FILE_ZERO_DATA_INFORMATION is not defined here
82 struct {
83 uint64 FileOffset;
84 uint64 BeyondFinalZero;
85 } fzdi;
86 fzdi.FileOffset = 0;
87 fzdi.BeyondFinalZero = size;
88 LARGE_INTEGER largo;
89 largo.QuadPart = size;
91 // zero the data
92 if (!DeviceIoControl(hd, FSCTL_SET_ZERO_DATA, (LPVOID) &fzdi, sizeof(fzdi), NULL, 0, &dwReturnedBytes, NULL)) {
93 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (ZERO): %s")) % name % SystemError());
94 } else if (!SetFilePointerEx(hd, largo, NULL, FILE_BEGIN) || !SetEndOfFile(hd)) {
95 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (SEEK): %s")) % name % SystemError());
98 CloseHandle(hd);
99 return true;
102 #else // non Windows systems don't need all this
103 #include "CFile.h"
105 bool PlatformSpecific::CreateSparseFile(const CPath& name, uint64_t WXUNUSED(size))
107 CFile f;
108 return f.Create(name.GetRaw(), true) && f.Close();
111 #endif
113 #ifdef __WINDOWS__
114 #include <wx/msw/registry.h>
115 #include <wx/utils.h>
117 // Get the max number of connections that the OS supports, or -1 for default
118 int PlatformSpecific::GetMaxConnections()
120 int maxconn = -1;
121 // Try to get the max connection value in the registry
122 wxRegKey key( wxT("HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services\\VxD\\MSTCP\\MaxConnections") );
123 wxString value;
124 if ( key.Exists() ) {
125 value = key.QueryDefaultValue();
127 if ( !value.IsEmpty() && value.IsNumber() ) {
128 long mc;
129 value.ToLong(&mc);
130 maxconn = (int)mc;
131 } else {
132 switch (wxGetOsVersion()) {
133 case wxOS_WINDOWS_9X:
134 // This includes all Win9x versions
135 maxconn = 50;
136 break;
137 case wxOS_WINDOWS_NT:
138 // This includes NT based windows
139 maxconn = 500;
140 break;
141 default:
142 // Anything else. Let aMule decide...
143 break;
147 return maxconn;
149 #endif
152 #ifdef __WINDOWS__
153 #include <winbase.h>
154 #include <shlwapi.h>
156 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
158 wxWritableWCharBuffer pathRaw(path.GetRaw().wchar_str());
159 LPWSTR volume = pathRaw;
160 if (!PathStripToRootW(volume)) {
161 return PlatformSpecific::fsOther;
163 PathAddBackslashW(volume);
165 DWORD maximumComponentLength = 0;
166 DWORD filesystemFlags = 0;
167 WCHAR filesystemNameBuffer[128];
168 if (!GetVolumeInformationW(volume, NULL, 0, NULL, &maximumComponentLength, &filesystemFlags, filesystemNameBuffer, 128)) {
169 return PlatformSpecific::fsOther;
171 if (wxStrnicmp(filesystemNameBuffer, wxT("FAT"), 3) == 0) {
172 return PlatformSpecific::fsFAT;
173 } else if (wxStrcmp(filesystemNameBuffer, wxT("NTFS")) == 0) {
174 return PlatformSpecific::fsNTFS;
176 return PlatformSpecific::fsOther;
179 #elif defined(HAVE_GETMNTENT) && defined(HAVE_MNTENT_H)
180 #include <stdio.h>
181 #include <string.h>
182 #include <mntent.h>
183 #ifndef _PATH_MOUNTED
184 # define _PATH_MOUNTED "/etc/mtab"
185 #endif
186 #include <common/StringFunctions.h>
188 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
190 struct mntent *entry = NULL;
191 PlatformSpecific::EFSType retval = PlatformSpecific::fsOther;
192 FILE *mnttab = fopen(_PATH_MOUNTED, "r");
193 unsigned bestPrefixLen = 0;
195 if (mnttab == NULL) {
196 return PlatformSpecific::fsOther;
199 while ((entry = getmntent(mnttab)) != NULL) {
200 if (entry->mnt_dir) {
201 wxString dir = char2unicode(entry->mnt_dir);
202 if (dir == path.GetRaw().Mid(0, dir.Length())) {
203 if (dir.Length() >= bestPrefixLen) {
204 if (entry->mnt_type == NULL) {
205 break;
206 } else if (!strcmp(entry->mnt_type, "ntfs")) {
207 retval = PlatformSpecific::fsNTFS;
208 } else if (!strcmp(entry->mnt_type, "msdos") ||
209 !strcmp(entry->mnt_type, "umsdos") ||
210 !strcmp(entry->mnt_type, "vfat") ||
211 !strncmp(entry->mnt_type, "fat", 3)) {
212 retval = PlatformSpecific::fsFAT;
213 } else if (!strcmp(entry->mnt_type, "hfs")) {
214 retval = PlatformSpecific::fsHFS;
215 } else if (!strcmp(entry->mnt_type, "hpfs")) {
216 retval = PlatformSpecific::fsHPFS;
217 } else if (!strcmp(entry->mnt_type, "minix")) {
218 retval = PlatformSpecific::fsMINIX;
219 } /* Add more filesystem types here */
220 else if (dir.Length() > bestPrefixLen) {
221 retval = PlatformSpecific::fsOther;
223 bestPrefixLen = dir.Length();
228 fclose(mnttab);
229 return retval;
232 #elif defined(HAVE_GETMNTENT) && defined(HAVE_SYS_MNTENT_H) && defined(HAVE_SYS_MNTTAB_H)
233 #include <stdio.h>
234 #include <string.h>
235 #include <sys/mntent.h>
236 #include <sys/mnttab.h>
237 #ifndef MNTTAB
238 # define MNTTAB "/etc/mnttab"
239 #endif
240 #include <common/StringFunctions.h>
242 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
244 struct mnttab entryStatic;
245 struct mnttab *entry = &entryStatic;
246 PlatformSpecific::EFSType retval = PlatformSpecific::fsOther;
247 FILE *fmnttab = fopen(MNTTAB, "r");
248 unsigned bestPrefixLen = 0;
250 if (fmnttab == NULL) {
251 return PlatformSpecific::fsOther;
254 while (getmntent(fmnttab, entry) == 0) {
255 if (entry->mnt_mountp) {
256 wxString dir = char2unicode(entry->mnt_mountp);
257 if (dir == path.GetRaw().Mid(0, dir.Length())) {
258 if (dir.Length() >= bestPrefixLen) {
259 if (entry->mnt_fstype == NULL) {
260 break;
261 } else if (!strcmp(entry->mnt_fstype, MNTTYPE_PCFS)) {
262 retval = PlatformSpecific::fsFAT;
263 } else if (hasmntopt(entry, MNTOPT_NOLARGEFILES)) {
264 // MINIX is a file system that can handle special chars but has no large files.
265 retval = PlatformSpecific::fsMINIX;
266 } else if (dir.Length() > bestPrefixLen) {
267 retval = PlatformSpecific::fsOther;
269 bestPrefixLen = dir.Length();
274 fclose(fmnttab);
275 return retval;
278 #else
280 // No way to determine filesystem type, no restrictions apply.
281 static inline PlatformSpecific::EFSType doGetFilesystemType(const CPath& WXUNUSED(path))
283 return PlatformSpecific::fsOther;
286 #endif
288 #include <map>
289 #include <wx/thread.h>
291 PlatformSpecific::EFSType PlatformSpecific::GetFilesystemType(const CPath& path)
293 typedef std::map<wxString, EFSType> FSMap;
294 // Caching previous results, to speed up further checks.
295 static FSMap s_fscache;
296 // Lock used to ensure the integrity of the cache.
297 static wxMutex s_lock;
299 wxCHECK_MSG(path.IsOk(), fsOther, wxT("Invalid path in GetFilesystemType()"));
301 wxMutexLocker locker(s_lock);
303 FSMap::iterator it = s_fscache.find(path.GetRaw());
304 if (it != s_fscache.end()) {
305 return it->second;
308 return s_fscache[path.GetRaw()] = doGetFilesystemType(path);
312 // Power event vetoing
314 static bool m_preventingSleepMode = false;
316 #if defined(__WXMAC__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // 10.5 only
317 #include <IOKit/pwr_mgt/IOPMLib.h>
318 static IOPMAssertionID assertionID;
319 #endif
321 void PlatformSpecific::PreventSleepMode()
323 if (!m_preventingSleepMode) {
324 #ifdef _MSC_VER
325 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
326 m_preventingSleepMode = true;
328 // IOPMAssertionCreate has been introduced in Leopard (10.5) but deprecated starting from Snow Leopard(10.6)
329 // For more details see:
330 // - http://developer.apple.com/library/mac/#qa/qa1340/_index.html
331 // - http://www.cimgf.com/2009/10/14/the-journey-to-disabling-sleep-with-iokit/
332 #elif defined(__WXMAC__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 // 10.6 only
333 CFStringRef reasonForActivity= CFSTR("Prevent Display Sleep");
334 IOReturn success = IOPMAssertionCreateWithName(kIOPMAssertionTypeNoDisplaySleep,
335 kIOPMAssertionLevelOn, reasonForActivity, &assertionID);
336 if (success == kIOReturnSuccess) {
337 // Correctly vetoed, flag so we don't do it again.
338 m_preventingSleepMode = true;
339 } else {
340 // May be should be better to trace in log?
343 #elif defined(__WXMAC__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // 10.5 only
344 IOReturn success = IOPMAssertionCreate(kIOPMAssertionTypeNoDisplaySleep,
345 kIOPMAssertionLevelOn, &assertionID);
346 if (success == kIOReturnSuccess) {
347 // Correctly vetoed, flag so we don't do it again.
348 m_preventingSleepMode = true;
349 } else {
350 // ??
352 #else
353 //#warning Power event vetoing not implemented.
354 // Not implemented
355 #endif
359 void PlatformSpecific::AllowSleepMode()
361 if (m_preventingSleepMode) {
362 #ifdef _MSC_VER
363 SetThreadExecutionState(ES_CONTINUOUS); // Clear the system request flag.
364 m_preventingSleepMode = false;
365 #elif defined(__WXMAC__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // 10.5 only
366 IOReturn success = IOPMAssertionRelease(assertionID);
367 if (success == kIOReturnSuccess) {
368 // Correctly restored, flag so we don't do it again.
369 m_preventingSleepMode = false;
370 } else {
371 // ??
373 #else
374 // Not implemented
375 #endif