Upstream tarball 20080606
[amule.git] / src / PlatformSpecific.cpp
blob670d87ce04043415da3e15b48954412af264f2e5
1 //
2 // This file is part of the aMule Project.
3 //
4 // Copyright (c) 2008 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 // MP: This define needs to be kept here, before the .h include because wxWidgets will include the WinIoCtl.h
26 // file with a different value, and we'll never get the FSCTL_SET_SPARSE
27 #define _WIN32_WINNT 0x0500
29 #include "PlatformSpecific.h"
31 #ifdef HAVE_CONFIG_H
32 # include "config.h"
33 #endif
35 // NTFS Sparse Files (only for MSW)
36 #ifdef __WXMSW__
37 #include "common/Format.h"
38 #include "Logger.h"
39 #include <winbase.h>
40 #ifdef __MINGW32__
41 # include <ddk/ntifs.h>
42 #else
43 # include <winioctl.h>
44 #endif
46 // Create a message from a Windows error code
47 static wxString SystemError()
49 WCHAR * lpMsgBuf = NULL;
51 FormatMessageW(
52 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
53 NULL,
54 GetLastError(),
55 0, // Default language
56 (LPWSTR) &lpMsgBuf,
58 NULL
61 wxString ret(lpMsgBuf);
62 LocalFree(lpMsgBuf);
63 return ret;
66 // Create a file in sparse mode
67 bool PlatformSpecific::CreateSparseFile(const CPath& name, uint64_t size)
69 DWORD dwReturnedBytes=0;
71 HANDLE hd = CreateFileW(name.GetRaw().c_str(),
72 GENERIC_READ | GENERIC_WRITE,
73 0, // share - not shareable
74 NULL, // security - not inheritable
75 CREATE_ALWAYS,
76 FILE_ATTRIBUTE_ARCHIVE,
77 NULL);
78 if (hd == INVALID_HANDLE_VALUE) {
79 AddDebugLogLineM(true, logPartFile, CFormat(wxT("converting %s to sparse failed (OPEN): %s ")) % name % SystemError());
80 return false;
83 if (!DeviceIoControl(hd, FSCTL_SET_SPARSE, NULL, 0, NULL, 0, &dwReturnedBytes, NULL)) {
84 AddDebugLogLineM(true, logPartFile, CFormat(wxT("converting %s to sparse failed (SET_SPARSE): %s ")) % name % SystemError());
85 } else {
86 // FILE_ZERO_DATA_INFORMATION is not defined here
87 struct {
88 uint64 FileOffset;
89 uint64 BeyondFinalZero;
90 } fzdi;
91 fzdi.FileOffset = 0;
92 fzdi.BeyondFinalZero = size;
93 LARGE_INTEGER largo;
94 largo.QuadPart = size;
96 // zero the data
97 if (!DeviceIoControl(hd, FSCTL_SET_ZERO_DATA, (LPVOID) &fzdi, sizeof(fzdi), NULL, 0, &dwReturnedBytes, NULL)) {
98 AddDebugLogLineM(true, logPartFile, CFormat(wxT("converting %s to sparse failed (ZERO): %s")) % name % SystemError());
99 } else if (!SetFilePointerEx(hd, largo, NULL, FILE_BEGIN) || !SetEndOfFile(hd)) {
100 AddDebugLogLineM(true, logPartFile, CFormat(wxT("converting %s to sparse failed (SEEK): %s")) % name % SystemError());
103 CloseHandle(hd);
104 return true;
107 #else // non Windows systems don't need all this
108 #include "CFile.h"
110 bool PlatformSpecific::CreateSparseFile(const CPath& name, uint64_t WXUNUSED(size))
112 CFile f;
113 return f.Create(name.GetRaw(), true) && f.Close();
116 #endif
118 #ifdef __WXMSW__
119 #include <wx/msw/registry.h>
120 #include <wx/utils.h>
122 // Get the max number of connections that the OS supports, or -1 for default
123 int PlatformSpecific::GetMaxConnections()
125 int maxconn = -1;
126 // Try to get the max connection value in the registry
127 wxRegKey key( wxT("HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services\\VxD\\MSTCP\\MaxConnections") );
128 wxString value;
129 if ( key.Exists() ) {
130 value = key.QueryDefaultValue();
132 if ( !value.IsEmpty() && value.IsNumber() ) {
133 long mc;
134 value.ToLong(&mc);
135 maxconn = (int)mc;
136 } else {
137 switch (wxGetOsVersion()) {
138 case wxOS_WINDOWS_9X:
139 // This includes all Win9x versions
140 maxconn = 50;
141 break;
142 case wxOS_WINDOWS_NT:
143 // This includes NT based windows
144 maxconn = 500;
145 break;
146 default:
147 // Anything else. Let aMule decide...
148 break;
152 return maxconn;
154 #endif
157 #ifdef __WXMSW__
158 #include <winbase.h>
159 #include <shlwapi.h>
161 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
163 LPWSTR volume = path.GetRaw().wchar_str();
164 bool result = PathStripToRootW(volume);
165 if (!result) {
166 return PlatformSpecific::fsOther;
168 PathAddBackslashW(volume);
170 DWORD maximumComponentLength = 0;
171 DWORD filesystemFlags = 0;
172 WCHAR filesystemNameBuffer[128];
173 if (!GetVolumeInformationW(volume, NULL, 0, NULL, &maximumComponentLength, &filesystemFlags, filesystemNameBuffer, 128)) {
174 return PlatformSpecific::fsOther;
176 if (wxStrnicmp(filesystemNameBuffer, wxT("FAT"), 3) == 0) {
177 return PlatformSpecific::fsFAT;
178 } else if (wxStrcmp(filesystemNameBuffer, wxT("NTFS")) == 0) {
179 return PlatformSpecific::fsNTFS;
181 return PlatformSpecific::fsOther;
184 #elif defined(HAVE_GETMNTENT)
185 #include <stdio.h>
186 #include <string.h>
187 #include <mntent.h>
188 #ifndef _PATH_MOUNTED
189 # define _PATH_MOUNTED "/etc/mtab"
190 #endif
191 #include <common/StringFunctions.h>
193 static PlatformSpecific::EFSType doGetFilesystemType(const CPath& path)
195 struct mntent *entry = NULL;
196 PlatformSpecific::EFSType retval = PlatformSpecific::fsOther;
197 FILE *mnttab = fopen(_PATH_MOUNTED, "r");
198 unsigned bestPrefixLen = 0;
200 if (mnttab == NULL) {
201 return PlatformSpecific::fsOther;
204 while ((entry = getmntent(mnttab)) != NULL) {
205 if (entry->mnt_dir) {
206 wxString dir = char2unicode(entry->mnt_dir);
207 if (dir == path.GetRaw().Mid(0, dir.Length())) {
208 if (dir.Length() >= bestPrefixLen) {
209 if (entry->mnt_type == NULL) {
210 break;
211 } else if (!strcmp(entry->mnt_type, "ntfs")) {
212 retval = PlatformSpecific::fsNTFS;
213 } else if (!strcmp(entry->mnt_type, "msdos") ||
214 !strcmp(entry->mnt_type, "umsdos") ||
215 !strcmp(entry->mnt_type, "vfat") ||
216 !strncmp(entry->mnt_type, "fat", 3)) {
217 retval = PlatformSpecific::fsFAT;
218 } else if (!strcmp(entry->mnt_type, "hfs")) {
219 retval = PlatformSpecific::fsHFS;
220 } else if (!strcmp(entry->mnt_type, "hpfs")) {
221 retval = PlatformSpecific::fsHPFS;
222 } else if (!strcmp(entry->mnt_type, "minix")) {
223 retval = PlatformSpecific::fsMINIX;
224 } /* Add more filesystem types here */
225 else if (dir.Length() > bestPrefixLen) {
226 retval = PlatformSpecific::fsOther;
228 bestPrefixLen = dir.Length();
233 fclose(mnttab);
234 return retval;
237 #else
239 // No way to determine filesystem type, all restrictions apply.
240 static inline PlatformSpecific::EFSType doGetFilesystemType(const CPath& WXUNUSED(path))
242 return PlatformSpecific::fsOther;
245 #endif
247 #include <map>
248 #include <wx/thread.h>
250 PlatformSpecific::EFSType PlatformSpecific::GetFilesystemType(const CPath& path)
252 typedef std::map<wxString, EFSType> FSMap;
253 // Caching previous results, to speed up further checks.
254 static FSMap s_fscache;
255 // Lock used to ensure the integrity of the cache.
256 static wxMutex s_lock;
258 wxCHECK_MSG(path.IsOk(), fsOther, wxT("Invalid path in GetFilesystemType()"));
260 wxMutexLocker locker(s_lock);
262 FSMap::iterator it = s_fscache.find(path.GetRaw());
263 if (it != s_fscache.end()) {
264 return it->second;
267 return s_fscache[path.GetRaw()] = doGetFilesystemType(path);