Upstream tarball 9574
[amule.git] / src / CFile.cpp
blob7e6d4b06106584291feda8bddda19565fba7baa3
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) 1998-2008 Vadim Zeitlin ( zeitlin@dptmaths.ens-cachan.fr )
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 "CFile.h" // Interface declarations.
28 #include "Logger.h" // Needed for AddDebugLogLineM
29 #include <common/Path.h> // Needed for CPath
32 #ifdef HAVE_CONFIG_H
33 #include "config.h" // Needed for HAVE_SYS_PARAM_H
34 #endif
37 #ifdef HAVE_SYS_PARAM_H
38 #include <sys/param.h>
39 #endif
41 // standard
42 #if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__WXMICROWIN__)
43 # include <io.h>
44 # ifndef __SALFORDC__
45 # define WIN32_LEAN_AND_MEAN
46 # define NOSERVICE
47 # define NOIME
48 # define NOATOM
49 # define NOGDI
50 # define NOGDICAPMASKS
51 # define NOMETAFILE
52 # define NOMINMAX
53 # define NOMSG
54 # define NOOPENFILE
55 # define NORASTEROPS
56 # define NOSCROLL
57 # define NOSOUND
58 # define NOSYSMETRICS
59 # define NOTEXTMETRIC
60 # define NOWH
61 # define NOCOMM
62 # define NOKANJI
63 # define NOCRYPT
64 # define NOMCX
65 # endif
66 #elif (defined(__UNIX__) || defined(__GNUWIN32__))
67 # ifdef __GNUWIN32__
68 # include <windows.h>
69 # endif
70 #elif (defined(__WXPM__))
71 # include <io.h>
72 #elif (defined(__WXSTUBS__))
73 // Have to ifdef this for different environments
74 # include <io.h>
75 #elif (defined(__WXMAC__))
76 #if __MSL__ < 0x6000
77 int access( const char *path, int mode ) { return 0 ; }
78 #else
79 int _access( const char *path, int mode ) { return 0 ; }
80 #endif
81 char* mktemp( char * path ) { return path ;}
82 # include <stat.h>
83 #else
84 # error "Please specify the header with file functions declarations."
85 #endif //Win/UNIX
87 // there is no distinction between text and binary files under Unix, so define
88 // O_BINARY as 0 if the system headers don't do it already
89 #if defined(__UNIX__) && !defined(O_BINARY)
90 # define O_BINARY (0)
91 #endif //__UNIX__
93 #ifdef __WXMSW__
94 #include <wx/msw/mslu.h>
95 #endif
98 // The following defines handle different names across platforms,
99 // and ensures that we use 64b IO on windows (only 32b by default).
100 #ifdef __WXMSW__
101 #define FLUSH_FD(x) _commit(x)
102 #define SEEK_FD(x, y, z) _lseeki64(x, y, z)
103 #define TELL_FD(x) _telli64(x)
105 #if (__MSVCRT_VERSION__ < 0x0601)
106 //#warning MSCVRT-Version smaller than 6.01
107 #define STAT_FD(x, y) _fstati64(x, y)
108 #define STAT_STRUCT struct _stati64
109 #else
110 #define STAT_FD(x, y) _fstat64(x, y)
111 #define STAT_STRUCT struct __stat64
112 #endif
113 #else
115 // We don't need to sync all meta-data, just the contents,
116 // so use fdatasync when possible (see man fdatasync).
117 #if defined(_POSIX_SYNCHRONIZED_IO) && (_POSIX_SYNCHRONIZED_IO > 0)
118 #define FLUSH_FD(x) fdatasync(x)
119 #else
120 #define FLUSH_FD(x) fsync(x)
121 #endif
123 #define SEEK_FD(x, y, z) lseek(x, y, z)
124 #define TELL_FD(x) wxTell(x)
125 #define STAT_FD(x, y) fstat(x, y)
126 #define STAT_STRUCT struct stat
127 #endif
130 // This function is used to check if a syscall failed, in that case
131 // log an appropriate message containing the errno string.
132 inline void syscall_check(
133 bool check,
134 const CPath& filePath,
135 const wxString& what)
137 if (!check) {
138 AddDebugLogLineM(true, logCFile,
139 CFormat(wxT("Error when %s (%s): %s"))
140 % what % filePath % wxSysErrorMsg());
145 CSeekFailureException::CSeekFailureException(const wxString& desc)
146 : CIOFailureException(wxT("SeekFailure"), desc)
150 CFile::CFile()
151 : m_fd(fd_invalid)
155 CFile::CFile(const CPath& fileName, OpenMode mode)
156 : m_fd(fd_invalid)
158 Open(fileName, mode);
162 CFile::CFile(const wxString& fileName, OpenMode mode)
163 : m_fd(fd_invalid)
165 Open(fileName, mode);
169 CFile::~CFile()
171 if (IsOpened()) {
172 Close();
177 int CFile::fd() const
179 return m_fd;
183 bool CFile::IsOpened() const
185 return m_fd != fd_invalid;
189 const CPath& CFile::GetFilePath() const
191 MULE_VALIDATE_STATE(IsOpened(), wxT("CFile: Cannot return path of closed file."));
193 return m_filePath;
197 bool CFile::Create(const CPath& path, bool overwrite, int accessMode)
199 if (!overwrite && path.FileExists()) {
200 return false;
203 return Open(path, write, accessMode);
206 bool CFile::Create(const wxString& path, bool overwrite, int accessMode)
208 return Create(CPath(path), overwrite, accessMode);
212 bool CFile::Open(const wxString& fileName, OpenMode mode, int accessMode)
214 MULE_VALIDATE_PARAMS(fileName.Length(), wxT("CFile: Cannot open, empty path."));
216 return Open(CPath(fileName), mode, accessMode);
220 bool CFile::Open(const CPath& fileName, OpenMode mode, int accessMode)
222 MULE_VALIDATE_PARAMS(fileName.IsOk(), wxT("CFile: Cannot open, empty path."));
224 #ifdef __linux__
225 int flags = O_BINARY | O_LARGEFILE;
226 #else
227 int flags = O_BINARY;
228 #endif
229 switch ( mode ) {
230 case read:
231 flags |= O_RDONLY;
232 break;
234 case write_append:
235 if (fileName.FileExists())
237 flags |= O_WRONLY | O_APPEND;
238 break;
240 //else: fall through as write_append is the same as write if the
241 // file doesn't exist
243 case write:
244 flags |= O_WRONLY | O_CREAT | O_TRUNC;
245 break;
247 case write_excl:
248 flags |= O_WRONLY | O_CREAT | O_EXCL;
249 break;
251 case read_write:
252 flags |= O_RDWR;
253 break;
256 if (IsOpened()) {
257 Close();
262 Unicode2CharBuf tmpFileName = filename2char(fileName.GetRaw());
263 wxASSERT_MSG(tmpFileName, wxT("Convertion failed in CFile::Open"));
265 m_filePath = fileName;
266 m_fd = open(tmpFileName, flags, accessMode);
267 syscall_check(m_fd != fd_invalid, m_filePath, wxT("opening file"));
269 return IsOpened();
273 bool CFile::Close()
275 MULE_VALIDATE_STATE(IsOpened(), wxT("CFile: Cannot close closed file."));
277 bool closed = (close(m_fd) != -1);
278 syscall_check(closed, m_filePath, wxT("closing file"));
280 m_fd = fd_invalid;
282 return closed;
286 bool CFile::Flush()
288 MULE_VALIDATE_STATE(IsOpened(), wxT("CFile: Cannot flush closed file."));
290 bool flushed = (FLUSH_FD(m_fd) != -1);
291 syscall_check(flushed, m_filePath, wxT("flushing file"));
293 return flushed;
297 sint64 CFile::doRead(void* buffer, size_t count) const
299 MULE_VALIDATE_PARAMS(buffer, wxT("CFile: Invalid buffer in read operation."));
300 MULE_VALIDATE_STATE(IsOpened(), wxT("CFile: Cannot read from closed file."));
302 size_t totalRead = 0;
303 while (totalRead < count) {
304 int current = ::read(m_fd, (char*)buffer + totalRead, count - totalRead);
306 if (current == -1) {
307 // Read error, nothing we can do other than abort.
308 throw CIOFailureException(wxString(wxT("Error reading from file: ")) + wxSysErrorMsg());
309 } else if ((totalRead + current < count) && Eof()) {
310 // We may fail to read the specified count in a couple
311 // of situations: EOF and interrupts. The check for EOF
312 // is needed to avoid inf. loops.
313 break;
316 totalRead += current;
319 return totalRead;
323 sint64 CFile::doWrite(const void* buffer, size_t nCount)
325 MULE_VALIDATE_PARAMS(buffer, wxT("CFile: Invalid buffer in write operation."));
326 MULE_VALIDATE_STATE(IsOpened(), wxT("CFile: Cannot write to closed file."));
328 sint64 result = ::write(m_fd, buffer, nCount);
330 if (result != (sint64)nCount) {
331 throw CIOFailureException(wxString(wxT("Error writing to file: ")) + wxSysErrorMsg());
334 return result;
338 sint64 CFile::doSeek(sint64 offset) const
340 MULE_VALIDATE_STATE(IsOpened(), wxT("Cannot seek on closed file."));
341 MULE_VALIDATE_PARAMS(offset >= 0, wxT("Invalid position, must be positive."));
343 sint64 result = SEEK_FD(m_fd, offset, SEEK_SET);
345 if (result == offset) {
346 return result;
347 } else if (result == wxInvalidOffset) {
348 throw CSeekFailureException(wxString(wxT("Seeking failed: ")) + wxSysErrorMsg());
349 } else {
350 throw CSeekFailureException(wxT("Seeking returned incorrect position"));
355 uint64 CFile::GetPosition() const
357 MULE_VALIDATE_STATE(IsOpened(), wxT("Cannot get position in closed file."));
359 sint64 pos = TELL_FD(m_fd);
360 if (pos == wxInvalidOffset) {
361 throw CSeekFailureException(wxString(wxT("Failed to retrieve position in file: ")) + wxSysErrorMsg());
364 return pos;
368 uint64 CFile::GetLength() const
370 MULE_VALIDATE_STATE(IsOpened(), wxT("CFile: Cannot get length of closed file."));
372 STAT_STRUCT buf;
373 if (STAT_FD(m_fd, &buf) == -1) {
374 throw CIOFailureException(wxString(wxT("Failed to retrieve length of file: ")) + wxSysErrorMsg());
377 return buf.st_size;
381 uint64 CFile::GetAvailable() const
383 const uint64 length = GetLength();
384 const uint64 position = GetPosition();
386 // Safely handle seeking past EOF
387 if (position < length) {
388 return length - position;
391 // File is at or after EOF
392 return 0;
396 bool CFile::SetLength(size_t new_len)
398 MULE_VALIDATE_STATE(IsOpened(), wxT("CFile: Cannot set length when no file is open."));
400 #ifdef __WXMSW__
401 int result = chsize(m_fd, new_len);
402 #else
403 int result = ftruncate(m_fd, new_len);
404 #endif
406 syscall_check((result != -1), m_filePath, wxT("truncating file"));
408 return (result != -1);
410 // File_checked_for_headers