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