Fixed problem in the CFile write_safe concept
[amule.git] / src / PlatformSpecific.cpp
blob3be514df6af5f619716697987cef17a1486ee456
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.
19 //
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"
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
31 // NTFS Sparse Files (only for MSW)
32 #ifdef __WXMSW__
33 #include "common/Format.h"
34 #include "Logger.h"
35 #include <winbase.h>
36 #include <winioctl.h>
37 #ifndef FSCTL_SET_SPARSE
38 # define FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
39 #endif
40 #ifndef FSCTL_SET_ZERO_DATA
41 # define FSCTL_SET_ZERO_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_DATA)
42 #endif
44 // Create a message from a Windows error code
45 static wxString SystemError()
47 WCHAR * lpMsgBuf = NULL;
49 FormatMessageW(
50 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
51 NULL,
52 GetLastError(),
53 0, // Default language
54 (LPWSTR) &lpMsgBuf,
56 NULL
59 wxString ret(lpMsgBuf);
60 LocalFree(lpMsgBuf);
61 return ret;
64 // Create a file in sparse mode
65 bool PlatformSpecific::CreateSparseFile(const CPath& name, uint64_t size)
67 DWORD dwReturnedBytes=0;
69 HANDLE hd = CreateFileW(name.GetRaw().c_str(),
70 GENERIC_READ | GENERIC_WRITE,
71 0, // share - not shareable
72 NULL, // security - not inheritable
73 CREATE_ALWAYS,
74 FILE_ATTRIBUTE_ARCHIVE,
75 NULL);
76 if (hd == INVALID_HANDLE_VALUE) {
77 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (OPEN): %s ")) % name % SystemError());
78 return false;
81 if (!DeviceIoControl(hd, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwReturnedBytes, NULL)) {
82 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (SET_SPARSE): %s ")) % name % SystemError());
83 } else {
84 // FILE_ZERO_DATA_INFORMATION is not defined here
85 struct {
86 uint64 FileOffset;
87 uint64 BeyondFinalZero;
88 } fzdi;
89 fzdi.FileOffset = 0;
90 fzdi.BeyondFinalZero = size;
91 LARGE_INTEGER largo;
92 largo.QuadPart = size;
94 // zero the data
95 if (!DeviceIoControl(hd, FSCTL_SET_ZERO_DATA, (LPVOID) &fzdi, sizeof(fzdi), NULL, 0, &dwReturnedBytes, NULL)) {
96 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (ZERO): %s")) % name % SystemError());
97 } else if (!SetFilePointerEx(hd, largo, NULL, FILE_BEGIN) || !SetEndOfFile(hd)) {
98 AddDebugLogLineC(logPartFile, CFormat(wxT("converting %s to sparse failed (SEEK): %s")) % name % SystemError());
101 CloseHandle(hd);
102 return true;
105 #else // non Windows systems don't need all this
106 #include "CFile.h"
108 bool PlatformSpecific::CreateSparseFile(const CPath& name, uint64_t WXUNUSED(size))
110 CFile f;
111 return f.Create(name.GetRaw(), true) && f.Close();
114 #endif
116 #ifdef __WXMSW__
117 #include <wx/msw/registry.h>
118 #include <wx/utils.h>
120 // Get the max number of connections that the OS supports, or -1 for default
121 int PlatformSpecific::GetMaxConnections()
123 int maxconn = -1;
124 // Try to get the max connection value in the registry
125 wxRegKey key( wxT("HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services\\VxD\\MSTCP\\MaxConnections") );
126 wxString value;
127 if ( key.Exists() ) {
128 value = key.QueryDefaultValue();
130 if ( !value.IsEmpty() && value.IsNumber() ) {
131 long mc;
132 value.ToLong(&mc);
133 maxconn = (int)mc;
134 } else {
135 switch (wxGetOsVersion()) {
136 case wxOS_WINDOWS_9X:
137 // This includes all Win9x versions
138 maxconn = 50;
139 break;
140 case wxOS_WINDOWS_NT:
141 // This includes NT based windows
142 maxconn = 500;
143 break;
144 default:
145 // Anything else. Let aMule decide...
146 break;
150 return maxconn;
152 #endif
155 #ifdef __WXMSW__
156 #include <winbase.h>
157 #include <shlwapi.h>
159 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
161 wxWritableWCharBuffer pathRaw(path.GetRaw());
162 LPWSTR volume = pathRaw;
163 if (!PathStripToRootW(volume)) {
164 return PlatformSpecific::fsOther;
166 PathAddBackslashW(volume);
168 DWORD maximumComponentLength = 0;
169 DWORD filesystemFlags = 0;
170 WCHAR filesystemNameBuffer[128];
171 if (!GetVolumeInformationW(volume, NULL, 0, NULL, &maximumComponentLength, &filesystemFlags, filesystemNameBuffer, 128)) {
172 return PlatformSpecific::fsOther;
174 if (wxStrnicmp(filesystemNameBuffer, wxT("FAT"), 3) == 0) {
175 return PlatformSpecific::fsFAT;
176 } else if (wxStrcmp(filesystemNameBuffer, wxT("NTFS")) == 0) {
177 return PlatformSpecific::fsNTFS;
179 return PlatformSpecific::fsOther;
182 #elif defined(HAVE_GETMNTENT) && defined(HAVE_MNTENT_H)
183 #include <stdio.h>
184 #include <string.h>
185 #include <mntent.h>
186 #ifndef _PATH_MOUNTED
187 # define _PATH_MOUNTED "/etc/mtab"
188 #endif
189 #include <common/StringFunctions.h>
191 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
193 struct mntent *entry = NULL;
194 PlatformSpecific::EFSType retval = PlatformSpecific::fsOther;
195 FILE *mnttab = fopen(_PATH_MOUNTED, "r");
196 unsigned bestPrefixLen = 0;
198 if (mnttab == NULL) {
199 return PlatformSpecific::fsOther;
202 while ((entry = getmntent(mnttab)) != NULL) {
203 if (entry->mnt_dir) {
204 wxString dir = char2unicode(entry->mnt_dir);
205 if (dir == path.GetRaw().Mid(0, dir.Length())) {
206 if (dir.Length() >= bestPrefixLen) {
207 if (entry->mnt_type == NULL) {
208 break;
209 } else if (!strcmp(entry->mnt_type, "ntfs")) {
210 retval = PlatformSpecific::fsNTFS;
211 } else if (!strcmp(entry->mnt_type, "msdos") ||
212 !strcmp(entry->mnt_type, "umsdos") ||
213 !strcmp(entry->mnt_type, "vfat") ||
214 !strncmp(entry->mnt_type, "fat", 3)) {
215 retval = PlatformSpecific::fsFAT;
216 } else if (!strcmp(entry->mnt_type, "hfs")) {
217 retval = PlatformSpecific::fsHFS;
218 } else if (!strcmp(entry->mnt_type, "hpfs")) {
219 retval = PlatformSpecific::fsHPFS;
220 } else if (!strcmp(entry->mnt_type, "minix")) {
221 retval = PlatformSpecific::fsMINIX;
222 } /* Add more filesystem types here */
223 else if (dir.Length() > bestPrefixLen) {
224 retval = PlatformSpecific::fsOther;
226 bestPrefixLen = dir.Length();
231 fclose(mnttab);
232 return retval;
235 #elif defined(HAVE_GETMNTENT) && defined(HAVE_SYS_MNTENT_H) && defined(HAVE_SYS_MNTTAB_H)
236 #include <stdio.h>
237 #include <string.h>
238 #include <sys/mntent.h>
239 #include <sys/mnttab.h>
240 #ifndef MNTTAB
241 # define MNTTAB "/etc/mnttab"
242 #endif
243 #include <common/StringFunctions.h>
245 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
247 struct mnttab entryStatic;
248 struct mnttab *entry = &entryStatic;
249 PlatformSpecific::EFSType retval = PlatformSpecific::fsOther;
250 FILE *fmnttab = fopen(MNTTAB, "r");
251 unsigned bestPrefixLen = 0;
253 if (fmnttab == NULL) {
254 return PlatformSpecific::fsOther;
257 while (getmntent(fmnttab, entry) == 0) {
258 if (entry->mnt_mountp) {
259 wxString dir = char2unicode(entry->mnt_mountp);
260 if (dir == path.GetRaw().Mid(0, dir.Length())) {
261 if (dir.Length() >= bestPrefixLen) {
262 if (entry->mnt_fstype == NULL) {
263 break;
264 } else if (!strcmp(entry->mnt_fstype, MNTTYPE_PCFS)) {
265 retval = PlatformSpecific::fsFAT;
266 } else if (hasmntopt(entry, MNTOPT_NOLARGEFILES)) {
267 // MINIX is a file system that can handle special chars but has no large files.
268 retval = PlatformSpecific::fsMINIX;
269 } else if (dir.Length() > bestPrefixLen) {
270 retval = PlatformSpecific::fsOther;
272 bestPrefixLen = dir.Length();
277 fclose(fmnttab);
278 return retval;
281 #else
283 // No way to determine filesystem type, no restrictions apply.
284 static inline PlatformSpecific::EFSType doGetFilesystemType(const CPath& WXUNUSED(path))
286 return PlatformSpecific::fsOther;
289 #endif
291 #include <map>
292 #include <wx/thread.h>
294 PlatformSpecific::EFSType PlatformSpecific::GetFilesystemType(const CPath& path)
296 typedef std::map<wxString, EFSType> FSMap;
297 // Caching previous results, to speed up further checks.
298 static FSMap s_fscache;
299 // Lock used to ensure the integrity of the cache.
300 static wxMutex s_lock;
302 wxCHECK_MSG(path.IsOk(), fsOther, wxT("Invalid path in GetFilesystemType()"));
304 wxMutexLocker locker(s_lock);
306 FSMap::iterator it = s_fscache.find(path.GetRaw());
307 if (it != s_fscache.end()) {
308 return it->second;
311 return s_fscache[path.GetRaw()] = doGetFilesystemType(path);
315 // Power event vetoing
317 static bool m_preventingSleepMode = false;
319 #if defined(__WXMAC__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // 10.5 only
320 #include <IOKit/pwr_mgt/IOPMLib.h>
321 static IOPMAssertionID assertionID;
322 #endif
324 void PlatformSpecific::PreventSleepMode()
326 if (!m_preventingSleepMode) {
327 #ifdef _MSC_VER
328 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED);
329 m_preventingSleepMode = true;
330 #elif defined(__WXMAC__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // 10.5 only
331 IOReturn success = IOPMAssertionCreate(kIOPMAssertionTypeNoDisplaySleep,
332 kIOPMAssertionLevelOn, &assertionID);
333 if (success == kIOReturnSuccess) {
334 // Correctly vetoed, flag so we don't do it again.
335 m_preventingSleepMode = true;
336 } else {
337 // ??
339 #else
340 #warning Power event vetoing not implemented.
341 // Not implemented
342 #endif
346 void PlatformSpecific::AllowSleepMode()
348 if (m_preventingSleepMode) {
349 #ifdef _MSC_VER
350 SetThreadExecutionState(ES_CONTINUOUS); // Clear the system request flag.
351 m_preventingSleepMode = false;
352 #elif defined(__WXMAC__) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 // 10.5 only
353 IOReturn success = IOPMAssertionRelease(assertionID);
354 if (success == kIOReturnSuccess) {
355 // Correctly restored, flag so we don't do it again.
356 m_preventingSleepMode = false;
357 } else {
358 // ??
360 #else
361 // Not implemented
362 #endif