Upstream tarball 20080405
[amule.git] / src / libs / common / FileFunctions.cpp
blob7591008a316240df86027f13d7f76481972173ff
1 //
2 // This file is part of the aMule Project.
3 //
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 )
6 //
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
9 // respective authors.
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.
20 //
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
35 #include <errno.h>
36 #include <map>
37 #ifdef __WXMAC__
38 #include <zlib.h> // Do_not_auto_remove
39 #endif
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)
53 : wxDir(dir.GetRaw())
58 CDirIterator::~CDirIterator()
63 CPath CDirIterator::GetFirstFile(FileType type, const wxString& mask)
65 if (!IsOpened()) {
66 return CPath();
69 wxString fileName;
70 if (!GetFirst(&fileName, mask, type)) {
71 return CPath();
74 return CPath(fileName);
78 CPath CDirIterator::GetNextFile()
80 wxString fileName;
81 if (!GetNext(&fileName)) {
82 return CPath();
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);
99 char head[10] = {0};
100 int read = archive.Read(head, std::min<off_t>(10, archive.Length()));
102 if (read == wxInvalidOffset) {
103 return EFT_Unknown;
104 } else if ((head[0] == 'P') && (head[1] == 'K')) {
105 // Zip-archives have a header of "PK".
106 return EFT_Zip;
107 } else if (head[0] == '\x1F' && head[1] == '\x8B') {
108 // Gzip-archives have a header of 0x1F8B
109 return EFT_GZip;
110 } else if (head[0] == '\xE0' || head[0] == '\x0E') {
111 // MET files have either of these headers
112 return EFT_Met;
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])) {
119 return EFT_Unknown;
123 return EFT_Text;
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) {
147 // access meta-data
148 wxString name = entry->GetName();
149 // read 'zip' to access the entry's data
150 if (name == filename) {
151 char buffer[10240];
152 wxTempFile target(file);
153 while (!zip.Eof()) {
154 zip.Read(buffer, sizeof(buffer));
155 target.Write(buffer, zip.LastRead());
157 target.Commit();
159 return true;
164 filename = archive.FindNext();
167 return false;
172 * Unpacks a GZip file and replaces the archive.
174 bool UnpackGZipFile(const wxString& file)
176 char buffer[10240];
177 wxTempFile target(file);
179 bool write = false;
181 #ifdef __WXMAC__
182 // AddDebugLogLineM( false, logFileIO, wxT("Reading gzip stream") );
184 gzFile inputFile = gzopen(filename2char(file), "rb");
185 if (inputFile != NULL) {
186 write = true;
188 while (int bytesRead = gzread(inputFile, buffer, sizeof(buffer))) {
189 if (bytesRead > 0) {
190 // AddDebugLogLineM( false, logFileIO, wxString::Format(wxT("Read %u bytes"), bytesRead) );
191 target.Write(buffer, bytesRead);
192 } else if (bytesRead < 0) {
193 wxString errString;
194 int gzerrnum;
195 const char* gzerrstr = gzerror(inputFile, &gzerrnum);
196 if (gzerrnum == Z_ERRNO) {
197 errString = wxSysErrorMsg();
198 } else {
199 errString = wxString::FromAscii(gzerrstr);
202 // AddDebugLogLineM( false, logFileIO, wxT("Error reading gzip stream (") + errString + wxT(")") );
203 write = false;
204 break;
208 // AddDebugLogLineM( false, logFileIO, wxT("End reading gzip stream") );
209 gzclose(inputFile);
210 } else {
211 // AddDebugLogLineM( false, logFileIO, wxT("Error opening gzip file (") + wxString(wxSysErrorMsg()) + wxT(")") );
213 #else
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());
226 } else {
227 break;
231 // AddDebugLogLineM( false, logFileIO, wxT("End reading gzip stream") );
233 write = inputStream.IsOk() || inputStream.Eof();
235 #endif
237 if (write) {
238 target.Commit();
239 // AddDebugLogLineM( false, logFileIO, wxT("Commited gzip stream") );
242 return write;
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);
252 switch (type) {
253 case EFT_Zip:
254 if (UnpackZipFile(file, files)) {
255 // Unpack nested archives if needed.
256 return UnpackResult(true, UnpackArchive(path, files).second);
257 } else {
258 return UnpackResult(false, EFT_Zip);
261 case EFT_GZip:
262 if (UnpackGZipFile(file)) {
263 // Unpack nested archives if needed.
264 return UnpackResult(true, UnpackArchive(path, files).second);
265 } else {
266 return UnpackResult(false, EFT_GZip);
269 default:
270 return UnpackResult(false, type);
275 #ifdef __WXMSW__
277 FSCheckResult CheckFileSystem(const CPath& WXUNUSED(path))
279 return FS_IsFAT32;
282 #else
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);
291 if (fd != -1) {
292 // Success, the file-system cant be FAT32
293 close(fd);
294 unlink(fullName.fn_str());
296 return FS_NotFAT32;
299 switch (errno) {
300 case EINVAL:
301 // File-name was invalid, file-system is FAT32
302 return FS_IsFAT32;
304 case EEXIST:
305 // File already exists, file-system cant be FAT32
306 return FS_NotFAT32;
308 default:
309 // Something else failed, couldn't check
310 return FS_Failed;
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()) {
330 return it->second;
333 return s_cache[path] = DoCheckFileSystem(path);
336 #endif
337 // File_checked_for_headers