2 // This file is part of the aMule Project.
4 // Copyright (c) 2003-2008 aMule Team ( admin@amule.org / http://www.amule.org )
5 // Copyright (c) 2002 Merkur ( devs@emule-project.net / http://www.emule-project.net )
7 // Any parts of this program derived from the xMule, lMule or eMule project,
8 // or contributed by third-party developers are copyrighted by their
11 // This program is free software; you can redistribute it and/or modify
12 // it under the terms of the GNU General Public License as published by
13 // the Free Software Foundation; either version 2 of the License, or
14 // (at your option) any later version.
16 // This program is distributed in the hope that it will be useful,
17 // but WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 // GNU General Public License for more details.
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include <wx/dir.h> // Needed for wxDir
28 #include <wx/fs_zip.h> // Needed for wxZipFSHandler
29 #include <wx/wfstream.h> // wxFileInputStream
30 #include <wx/zipstrm.h> // Needed for wxZipInputStream
31 #include <wx/zstream.h> // Needed for wxZlibInputStream
32 #include <wx/thread.h> // Needed for wxMutex
33 #include <wx/log.h> // Needed for wxSysErrorMsg
38 #include <zlib.h> // Do_not_auto_remove
40 #include <memory> // Needed for std::auto_ptr
42 #include "FileFunctions.h"
43 #include "StringFunctions.h"
46 // This class assumes that the following line has been executed:
48 // wxConvFileName = &aMuleConvBrokenFileNames;
50 // This line is necessary so that wxWidgets handles unix file names correctly.
52 CDirIterator::CDirIterator(const CPath
& dir
)
58 CDirIterator::~CDirIterator()
63 CPath
CDirIterator::GetFirstFile(FileType type
, const wxString
& mask
)
70 if (!GetFirst(&fileName
, mask
, type
)) {
74 return CPath(fileName
);
78 CPath
CDirIterator::GetNextFile()
81 if (!GetNext(&fileName
)) {
85 return CPath(fileName
);
89 bool CDirIterator::HasSubDirs(const wxString
& spec
)
91 // Checking IsOpened() in case we don't have permissions to read that dir.
92 return IsOpened() && wxDir::HasSubDirs(spec
);
96 EFileType
GuessFiletype(const wxString
& file
)
98 wxFile
archive(file
, wxFile::read
);
100 int read
= archive
.Read(head
, std::min
<off_t
>(10, archive
.Length()));
102 if (read
== wxInvalidOffset
) {
104 } else if ((head
[0] == 'P') && (head
[1] == 'K')) {
105 // Zip-archives have a header of "PK".
107 } else if (head
[0] == '\x1F' && head
[1] == '\x8B') {
108 // Gzip-archives have a header of 0x1F8B
110 } else if (head
[0] == '\xE0' || head
[0] == '\x0E') {
111 // MET files have either of these headers
115 // Check at most the first ten chars, if all are printable,
116 // then we can probably assume it is ascii text-file.
117 for (int i
= 0; i
< read
; ++i
) {
118 if (!isprint(head
[i
]) && !isspace(head
[i
])) {
128 * Replaces the zip-archive with "guarding.p2p" or "ipfilter.dat",
129 * if either of those files are found in the archive.
131 bool UnpackZipFile(const wxString
& file
, const wxChar
* files
[])
133 wxZipFSHandler archive
;
134 wxString filename
= archive
.FindFirst(
135 wxT("file:") + file
+ wxT("#zip:/*"), wxFILE
);
136 while (!filename
.IsEmpty()) {
137 // Extract the filename part of the URI
138 filename
= filename
.AfterLast(wxT(':')).Lower();
140 // We only care about the files specified in the array
141 for (size_t i
= 0; files
[i
]; ++i
) {
142 if (files
[i
] == filename
) {
143 std::auto_ptr
<wxZipEntry
> entry
;
144 wxFFileInputStream
fileInputStream(file
);
145 wxZipInputStream
zip(fileInputStream
);
146 while (entry
.reset(zip
.GetNextEntry()), entry
.get() != NULL
) {
148 wxString name
= entry
->GetName();
149 // read 'zip' to access the entry's data
150 if (name
== filename
) {
152 wxTempFile
target(file
);
154 zip
.Read(buffer
, sizeof(buffer
));
155 target
.Write(buffer
, zip
.LastRead());
164 filename
= archive
.FindNext();
172 * Unpacks a GZip file and replaces the archive.
174 bool UnpackGZipFile(const wxString
& file
)
177 wxTempFile
target(file
);
182 // AddDebugLogLineM( false, logFileIO, wxT("Reading gzip stream") );
184 gzFile inputFile
= gzopen(filename2char(file
), "rb");
185 if (inputFile
!= NULL
) {
188 while (int bytesRead
= gzread(inputFile
, buffer
, sizeof(buffer
))) {
190 // AddDebugLogLineM( false, logFileIO, wxString::Format(wxT("Read %u bytes"), bytesRead) );
191 target
.Write(buffer
, bytesRead
);
192 } else if (bytesRead
< 0) {
195 const char* gzerrstr
= gzerror(inputFile
, &gzerrnum
);
196 if (gzerrnum
== Z_ERRNO
) {
197 errString
= wxSysErrorMsg();
199 errString
= wxString::FromAscii(gzerrstr
);
202 // AddDebugLogLineM( false, logFileIO, wxT("Error reading gzip stream (") + errString + wxT(")") );
208 // AddDebugLogLineM( false, logFileIO, wxT("End reading gzip stream") );
211 // AddDebugLogLineM( false, logFileIO, wxT("Error opening gzip file (") + wxString(wxSysErrorMsg()) + wxT(")") );
215 // AddDebugLogLineM( false, logFileIO, wxT("Reading gzip stream") );
217 wxFileInputStream
source(file
);
218 wxZlibInputStream
inputStream(source
);
220 while (!inputStream
.Eof()) {
221 inputStream
.Read(buffer
, sizeof(buffer
));
223 // AddDebugLogLineM( false, logFileIO, wxString::Format(wxT("Read %u bytes"),inputStream.LastRead()) );
224 if (inputStream
.LastRead()) {
225 target
.Write(buffer
, inputStream
.LastRead());
231 // AddDebugLogLineM( false, logFileIO, wxT("End reading gzip stream") );
233 write
= inputStream
.IsOk() || inputStream
.Eof();
239 // AddDebugLogLineM( false, logFileIO, wxT("Commited gzip stream") );
246 UnpackResult
UnpackArchive(const CPath
& path
, const wxChar
* files
[])
248 const wxString file
= path
.GetRaw();
250 // Attempt to discover the filetype and uncompress
251 EFileType type
= GuessFiletype(file
);
254 if (UnpackZipFile(file
, files
)) {
255 // Unpack nested archives if needed.
256 return UnpackResult(true, UnpackArchive(path
, files
).second
);
258 return UnpackResult(false, EFT_Zip
);
262 if (UnpackGZipFile(file
)) {
263 // Unpack nested archives if needed.
264 return UnpackResult(true, UnpackArchive(path
, files
).second
);
266 return UnpackResult(false, EFT_GZip
);
270 return UnpackResult(false, type
);
277 FSCheckResult
CheckFileSystem(const CPath
& WXUNUSED(path
))
284 FSCheckResult
DoCheckFileSystem(const CPath
& path
)
286 // This is an invalid filename on FAT32/NTFS
287 wxString fullName
= JoinPaths(path
.GetRaw(), wxT(":"));
289 // Try to open the file, without overwriting existing files.
290 int fd
= open(fullName
.fn_str(), O_WRONLY
| O_CREAT
| O_EXCL
);
292 // Success, the file-system cant be FAT32
294 unlink(fullName
.fn_str());
301 // File-name was invalid, file-system is FAT32
305 // File already exists, file-system cant be FAT32
309 // Something else failed, couldn't check
315 typedef std::map
<CPath
, FSCheckResult
> CPathCache
;
317 //! Lock used to ensure the integrity of the cache.
318 static wxMutex s_lock
;
319 //! Cache of results from checking various paths.
320 static CPathCache s_cache
;
323 FSCheckResult
CheckFileSystem(const CPath
& path
)
325 wxCHECK_MSG(path
.IsOk(), FS_Failed
, wxT("Invalid path in CheckFileSystem!"));
327 wxMutexLocker
locker(s_lock
);
328 CPathCache::iterator it
= s_cache
.find(path
);
329 if (it
!= s_cache
.end()) {
333 return s_cache
[path
] = DoCheckFileSystem(path
);
337 // File_checked_for_headers