]> git.saurik.com Git - wxWidgets.git/blame - src/common/file.cpp
Corrected some problems
[wxWidgets.git] / src / common / file.cpp
CommitLineData
c801d85f
KB
1/////////////////////////////////////////////////////////////////////////////
2// Name: file.cpp
3// Purpose: wxFile - encapsulates low-level "file descriptor"
4// wxTempFile
5// Author: Vadim Zeitlin
6// Modified by:
7// Created: 29/01/98
8// RCS-ID: $Id$
9// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
246037e2 10// Licence: wxWindows license
c801d85f
KB
11/////////////////////////////////////////////////////////////////////////////
12
13// ----------------------------------------------------------------------------
14// headers
15// ----------------------------------------------------------------------------
16
17#ifdef __GNUG__
18#pragma implementation "file.h"
19#endif
20
21// For compilers that support precompilation, includes "wx.h".
22#include "wx/wxprec.h"
23#include "wx/defs.h"
24
25#ifdef __BORLANDC__
26#pragma hdrstop
27#endif
28
29// standard
246037e2 30#if defined(__WXMSW__) && !defined(__GNUWIN32__)
c801d85f 31 #include <io.h>
30a5be97
VZ
32
33 #define WIN32_LEAN_AND_MEAN
34 #define NOSERVICE
35 #define NOIME
36 #define NOATOM
37 #define NOGDI
38 #define NOGDICAPMASKS
39 #define NOMETAFILE
40 #define NOMINMAX
41 #define NOMSG
42 #define NOOPENFILE
43 #define NORASTEROPS
44 #define NOSCROLL
45 #define NOSOUND
46 #define NOSYSMETRICS
47 #define NOTEXTMETRIC
48 #define NOWH
49 #define NOCOMM
50 #define NOKANJI
51 #define NOCRYPT
52 #define NOMCX
53 #include <windows.h> // for GetTempFileName
c801d85f
KB
54#elif (defined(__UNIX__) || defined(__GNUWIN32__))
55 #include <unistd.h>
56#else
246037e2 57 #error "Please specify the header with file functions declarations."
c801d85f
KB
58#endif //Win/UNIX
59
60#include <stdio.h> // SEEK_xxx constants
61#include <fcntl.h> // O_RDONLY &c
62#include <sys/types.h> // needed for stat
63#include <sys/stat.h> // stat
64
65// Microsoft compiler loves underscores, feed them to it
66#ifdef _MSC_VER
67 // functions
68 #define open _open
69 #define close _close
70 #define read _read
71 #define write _write
72 #define lseek _lseek
73 #define fsync _commit
74 #define access _access
75 #define eof _eof
76
77 // types
78 #define stat _stat
79
80 // constants
81 #define O_RDONLY _O_RDONLY
82 #define O_WRONLY _O_WRONLY
83 #define O_RDWR _O_RDWR
84 #define O_EXCL _O_EXCL
85 #define O_CREAT _O_CREAT
86 #define O_BINARY _O_BINARY
87
88 #define S_IFDIR _S_IFDIR
89 #define S_IFREG _S_IFREG
c801d85f
KB
90#else
91 #define tell(fd) lseek(fd, 0, SEEK_CUR)
92#endif //_MSC_VER
93
94// there is no distinction between text and binary files under Unix
246037e2
VZ
95#ifdef __UNIX__
96 #define O_BINARY (0)
97#endif //__UNIX__
c801d85f
KB
98
99// wxWindows
100#include <wx/string.h>
101#include <wx/intl.h>
102#include <wx/file.h>
103#include <wx/log.h>
104
105
106// ============================================================================
107// implementation of wxFile
108// ============================================================================
109
110// ----------------------------------------------------------------------------
111// static functions
112// ----------------------------------------------------------------------------
113bool wxFile::Exists(const char *sz)
246037e2
VZ
114{
115 struct stat st;
c801d85f
KB
116 return !access(sz, 0) && !stat(sz, &st) && (st.st_mode & S_IFREG);
117}
118
119// ----------------------------------------------------------------------------
120// opening/closing
121// ----------------------------------------------------------------------------
122
123// ctors
124wxFile::wxFile(const char *szFileName, OpenMode mode)
125{
126 m_fd = fd_invalid;
79c3e0e1 127 m_error = FALSE;
c801d85f
KB
128
129 Open(szFileName, mode);
130}
131
132// dtor
133wxFile::~wxFile()
134{
135 Close();
136}
137
138// create the file, fail if it already exists and bOverwrite
246037e2 139bool wxFile::Create(const char *szFileName, bool bOverwrite, int access)
c801d85f
KB
140{
141 // if bOverwrite we create a new file or truncate the existing one,
142 // otherwise we only create the new file and fail if it already exists
246037e2 143 int fd = open(szFileName, O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access);
c801d85f
KB
144
145 if ( fd == -1 ) {
1678ad78 146 wxLogSysError("can't create file '%s'", szFileName);
c801d85f
KB
147 return FALSE;
148 }
149 else {
150 Attach(fd);
151 return TRUE;
152 }
153}
154
155// open the file
246037e2 156bool wxFile::Open(const char *szFileName, OpenMode mode, int access)
c801d85f
KB
157{
158 int flags = O_BINARY;
159
160 switch ( mode ) {
246037e2
VZ
161 case read:
162 flags |= O_RDONLY;
c801d85f
KB
163 break;
164
246037e2
VZ
165 case write:
166 flags |= O_WRONLY | O_CREAT | O_TRUNC;
61b02744
VZ
167 break;
168
169 case write_append:
170 flags |= O_WRONLY | O_APPEND;
c801d85f
KB
171 break;
172
246037e2 173 case read_write:
c801d85f
KB
174 flags |= O_RDWR;
175 break;
176 }
177
246037e2 178 int fd = open(szFileName, flags, access);
c801d85f
KB
179
180 if ( fd == -1 ) {
1678ad78 181 wxLogSysError("can't open file '%s'", szFileName);
c801d85f
KB
182 return FALSE;
183 }
184 else {
185 Attach(fd);
186 return TRUE;
187 }
188}
189
190// close
61b02744 191bool wxFile::Close()
c801d85f
KB
192{
193 if ( IsOpened() ) {
61b02744 194 if ( close(m_fd) == -1 ) {
1678ad78 195 wxLogSysError("can't close file descriptor %d", m_fd);
61b02744
VZ
196 m_fd = fd_invalid;
197 return FALSE;
198 }
199 else
200 m_fd = fd_invalid;
c801d85f 201 }
61b02744
VZ
202
203 return TRUE;
c801d85f
KB
204}
205
206// ----------------------------------------------------------------------------
207// read/write
208// ----------------------------------------------------------------------------
209
210// read
211off_t wxFile::Read(void *pBuf, off_t nCount)
212{
1311c7a9 213 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f
KB
214
215 int iRc = ::read(m_fd, pBuf, nCount);
216 if ( iRc == -1 ) {
1678ad78
GL
217 wxLogSysError("can't read from file descriptor %d", m_fd);
218 return wxInvalidOffset;
c801d85f
KB
219 }
220 else
221 return (uint)iRc;
222}
223
224// write
79c3e0e1 225uint wxFile::Write(const void *pBuf, uint nCount)
c801d85f 226{
1311c7a9 227 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
c801d85f
KB
228
229 int iRc = ::write(m_fd, pBuf, nCount);
230 if ( iRc == -1 ) {
1678ad78 231 wxLogSysError("can't write to file descriptor %d", m_fd);
79c3e0e1
GL
232 m_error = TRUE;
233 return 0;
c801d85f
KB
234 }
235 else
1678ad78 236 return iRc;
c801d85f
KB
237}
238
239// flush
240bool wxFile::Flush()
241{
242 if ( IsOpened() ) {
1678ad78 243 // @@@ fsync() is not ANSI (BSDish)
c801d85f
KB
244// if ( fsync(m_fd) == -1 ) { // TODO
245 if (TRUE) {
1678ad78 246 wxLogSysError("can't flush file descriptor %d", m_fd);
c801d85f
KB
247 return FALSE;
248 }
249 }
250
251 return TRUE;
252}
253
254// ----------------------------------------------------------------------------
255// seek
256// ----------------------------------------------------------------------------
257
258// seek
79c3e0e1 259off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
c801d85f
KB
260{
261 wxASSERT( IsOpened() );
262
263 int flag = -1;
264 switch ( mode ) {
79c3e0e1 265 case wxFromStart:
c801d85f
KB
266 flag = SEEK_SET;
267 break;
268
79c3e0e1 269 case wxFromCurrent:
c801d85f
KB
270 flag = SEEK_CUR;
271 break;
272
79c3e0e1 273 case wxFromEnd:
c801d85f
KB
274 flag = SEEK_END;
275 break;
276
277 default:
278 wxFAIL_MSG("unknown seek origin");
279 }
280
281 int iRc = lseek(m_fd, ofs, flag);
282 if ( iRc == -1 ) {
1678ad78
GL
283 wxLogSysError("can't seek on file descriptor %d", m_fd);
284 return wxInvalidOffset;
c801d85f
KB
285 }
286 else
287 return (off_t)iRc;
288}
289
290// get current off_t
291off_t wxFile::Tell() const
292{
293 wxASSERT( IsOpened() );
294
295 int iRc = tell(m_fd);
296 if ( iRc == -1 ) {
1678ad78
GL
297 wxLogSysError("can't get seek position on file descriptor %d", m_fd);
298 return wxInvalidOffset;
c801d85f
KB
299 }
300 else
301 return (off_t)iRc;
302}
303
304// get current file length
305off_t wxFile::Length() const
306{
307 wxASSERT( IsOpened() );
308
309 #ifdef _MSC_VER
310 int iRc = _filelength(m_fd);
311 #else
312 int iRc = tell(m_fd);
313 if ( iRc != -1 ) {
246037e2 314 // @ have to use const_cast :-(
c801d85f
KB
315 int iLen = ((wxFile *)this)->SeekEnd();
316 if ( iLen != -1 ) {
317 // restore old position
318 if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
319 // error
320 iLen = -1;
321 }
322 }
323
324 iRc = iLen;
325 }
326
327 #endif //_MSC_VER
328
329 if ( iRc == -1 ) {
1678ad78
GL
330 wxLogSysError("can't find length of file on file descriptor %d", m_fd);
331 return wxInvalidOffset;
c801d85f
KB
332 }
333 else
334 return (off_t)iRc;
335}
336
337// is end of file reached?
338bool wxFile::Eof() const
339{
340 wxASSERT( IsOpened() );
341
61b02744
VZ
342 int iRc;
343
344 #if defined(__UNIX__) || defined(__GNUWIN32__)
345 // @@ this doesn't work, of course, on unseekable file descriptors
346 off_t ofsCur = Tell(),
347 ofsMax = Length();
1678ad78 348 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
61b02744
VZ
349 iRc = -1;
350 else
351 iRc = ofsCur == ofsMax;
352 #else // Windows and "native" compiler
353 iRc = eof(m_fd);
354 #endif // Windows/Unix
c801d85f
KB
355
356 switch ( iRc ) {
357 case 1:
358 break;
359
360 case 0:
361 return FALSE;
362
363 case -1:
1678ad78
GL
364 wxLogSysError("can't determine if the end of file is reached on "
365 "descriptor %d", m_fd);
c801d85f
KB
366 break;
367
368 default:
369 wxFAIL_MSG("invalid eof() return value.");
370 }
371
372 return TRUE;
373}
374
375// ============================================================================
376// implementation of wxTempFile
377// ============================================================================
378
379// ----------------------------------------------------------------------------
380// construction
381// ----------------------------------------------------------------------------
382wxTempFile::wxTempFile(const wxString& strName)
383{
384 Open(strName);
385}
386
387bool wxTempFile::Open(const wxString& strName)
388{
389 m_strName = strName;
246037e2 390
b59650be
VZ
391 // we want to create the file in the same directory as strName because
392 // otherwise rename() in Commit() might not work (if the files are on
393 // different partitions for example). Unfortunately, the only standard
394 // (POSIX) temp file creation function tmpnam() can't do it.
395 #ifdef __UNIX__
396 static const char *szMktempSuffix = "XXXXXX";
397 m_strTemp << strName << szMktempSuffix;
30a5be97 398 mktemp((char *)m_strTemp.c_str()); // will do because length doesn't change
b59650be 399 #else // Windows
30a5be97
VZ
400 wxString strPath;
401 wxSplitPath(strName, &strPath, NULL, NULL);
402 if ( strPath.IsEmpty() )
403 strPath = '.'; // GetTempFileName will fail if we give it empty string
404 if ( !GetTempFileName(strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
405 wxLogLastError("GetTempFileName");
406 m_strTemp.UngetWriteBuf();
b59650be 407 #endif // Windows/Unix
246037e2 408
c801d85f
KB
409 return m_file.Open(m_strTemp, wxFile::write);
410}
411
412// ----------------------------------------------------------------------------
413// destruction
414// ----------------------------------------------------------------------------
415
416wxTempFile::~wxTempFile()
417{
418 if ( IsOpened() )
419 Discard();
420}
421
422bool wxTempFile::Commit()
423{
424 m_file.Close();
425
426 if ( wxFile::Exists(m_strName) && remove(m_strName) != 0 ) {
1678ad78 427 wxLogSysError("can't remove file '%s'", m_strName.c_str());
c801d85f
KB
428 return FALSE;
429 }
430
431 if ( rename(m_strTemp, m_strName) != 0 ) {
1678ad78 432 wxLogSysError("can't commit changes to file '%s'", m_strName.c_str());
c801d85f
KB
433 return FALSE;
434 }
435
436 return TRUE;
437}
438
439void wxTempFile::Discard()
440{
441 m_file.Close();
442 if ( remove(m_strTemp) != 0 )
1678ad78 443 wxLogSysError("can't remove temporary file '%s'", m_strTemp.c_str());
c801d85f 444}