2 // This file is part of the aMule Project.
4 // Copyright (c) 2008 aMule Team ( admin@amule.org / http://www.amule.org )
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
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"
31 // NTFS Sparse Files (only for MSW)
33 #include "common/Format.h"
37 #ifndef FSCTL_SET_SPARSE
38 # define FSCTL_SET_SPARSE CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 49, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)
40 #ifndef FSCTL_SET_ZERO_DATA
41 # define FSCTL_SET_ZERO_DATA CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 50, METHOD_BUFFERED, FILE_WRITE_DATA)
44 // Create a message from a Windows error code
45 static wxString
SystemError()
47 WCHAR
* lpMsgBuf
= NULL
;
50 FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
53 0, // Default language
59 wxString
ret(lpMsgBuf
);
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
74 FILE_ATTRIBUTE_ARCHIVE
,
76 if (hd
== INVALID_HANDLE_VALUE
) {
77 AddDebugLogLineM(true, logPartFile
, CFormat(wxT("converting %s to sparse failed (OPEN): %s ")) % name
% SystemError());
81 if (!DeviceIoControl(hd
, FSCTL_SET_SPARSE
, NULL
, 0, NULL
, 0, &dwReturnedBytes
, NULL
)) {
82 AddDebugLogLineM(true, logPartFile
, CFormat(wxT("converting %s to sparse failed (SET_SPARSE): %s ")) % name
% SystemError());
84 // FILE_ZERO_DATA_INFORMATION is not defined here
87 uint64 BeyondFinalZero
;
90 fzdi
.BeyondFinalZero
= size
;
92 largo
.QuadPart
= size
;
95 if (!DeviceIoControl(hd
, FSCTL_SET_ZERO_DATA
, (LPVOID
) &fzdi
, sizeof(fzdi
), NULL
, 0, &dwReturnedBytes
, NULL
)) {
96 AddDebugLogLineM(true, logPartFile
, CFormat(wxT("converting %s to sparse failed (ZERO): %s")) % name
% SystemError());
97 } else if (!SetFilePointerEx(hd
, largo
, NULL
, FILE_BEGIN
) || !SetEndOfFile(hd
)) {
98 AddDebugLogLineM(true, logPartFile
, CFormat(wxT("converting %s to sparse failed (SEEK): %s")) % name
% SystemError());
105 #else // non Windows systems don't need all this
108 bool PlatformSpecific::CreateSparseFile(const CPath
& name
, uint64_t WXUNUSED(size
))
111 return f
.Create(name
.GetRaw(), true) && f
.Close();
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()
124 // Try to get the max connection value in the registry
125 wxRegKey
key( wxT("HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Services\\VxD\\MSTCP\\MaxConnections") );
127 if ( key
.Exists() ) {
128 value
= key
.QueryDefaultValue();
130 if ( !value
.IsEmpty() && value
.IsNumber() ) {
135 switch (wxGetOsVersion()) {
136 case wxOS_WINDOWS_9X
:
137 // This includes all Win9x versions
140 case wxOS_WINDOWS_NT
:
141 // This includes NT based windows
145 // Anything else. Let aMule decide...
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)
186 #ifndef _PATH_MOUNTED
187 # define _PATH_MOUNTED "/etc/mtab"
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
) {
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();
235 #elif defined(HAVE_GETMNTENT) && defined(HAVE_SYS_MNTENT_H) && defined(HAVE_SYS_MNTTAB_H)
238 #include <sys/mntent.h>
239 #include <sys/mnttab.h>
241 # define MNTTAB "/etc/mnttab"
243 #include <common/StringFunctions.h>
245 static PlatformSpecific::EFSType
doGetFilesystemType(const CPath
& path
)
247 struct mnttab
*entry
= NULL
;
248 PlatformSpecific::EFSType retval
= PlatformSpecific::fsOther
;
249 FILE *mnttab
= fopen(MNTTAB
, "r");
250 unsigned bestPrefixLen
= 0;
252 if (mnttab
== NULL
) {
253 return PlatformSpecific::fsOther
;
256 while (getmntent(mnttab
, entry
) == 0) {
257 if (entry
->mnt_mountp
) {
258 wxString dir
= char2unicode(entry
->mnt_mountp
);
259 if (dir
== path
.GetRaw().Mid(0, dir
.Length())) {
260 if (dir
.Length() >= bestPrefixLen
) {
261 if (entry
->mnt_fstype
== NULL
) {
263 } else if (!strcmp(entry
->mnt_fstype
, MNTTYPE_PCFS
)) {
264 retval
= PlatformSpecific::fsFAT
;
265 } else if (hasmntopt(entry
, MNTOPT_NOLARGEFILES
)) {
266 // MINIX is a file system that can handle special chars but has no large files.
267 retval
= PlatformSpecific::fsMINIX
;
268 } else if (dir
.Length() > bestPrefixLen
) {
269 retval
= PlatformSpecific::fsOther
;
271 bestPrefixLen
= dir
.Length();
282 // No way to determine filesystem type, no restrictions apply.
283 static inline PlatformSpecific::EFSType
doGetFilesystemType(const CPath
& WXUNUSED(path
))
285 return PlatformSpecific::fsOther
;
291 #include <wx/thread.h>
293 PlatformSpecific::EFSType
PlatformSpecific::GetFilesystemType(const CPath
& path
)
295 typedef std::map
<wxString
, EFSType
> FSMap
;
296 // Caching previous results, to speed up further checks.
297 static FSMap s_fscache
;
298 // Lock used to ensure the integrity of the cache.
299 static wxMutex s_lock
;
301 wxCHECK_MSG(path
.IsOk(), fsOther
, wxT("Invalid path in GetFilesystemType()"));
303 wxMutexLocker
locker(s_lock
);
305 FSMap::iterator it
= s_fscache
.find(path
.GetRaw());
306 if (it
!= s_fscache
.end()) {
310 return s_fscache
[path
.GetRaw()] = doGetFilesystemType(path
);