]> git.saurik.com Git - wxWidgets.git/blob - src/common/file.cpp
no message
[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(__WXMSW__) && !defined(__GNUWIN32__)
31 #include <io.h>
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
54 #elif (defined(__UNIX__) || defined(__GNUWIN32__))
55 #include <unistd.h>
56 #elif (defined(__WXSTUBS__))
57 // Have to ifdef this for different environments
58 #include <io.h>
59 #elif (defined(__WXMAC__))
60 int access( const char *path, int mode ) { return 0 ; }
61 char* mktemp( char * path ) { return path ;}
62 #include <unistd.h>
63 #include <unix.h>
64 #define W_OK 2
65 #define R_OK 4
66 #else
67 #error "Please specify the header with file functions declarations."
68 #endif //Win/UNIX
69
70 #include <stdio.h> // SEEK_xxx constants
71 #include <fcntl.h> // O_RDONLY &c
72 #ifndef __MWERKS__
73 #include <sys/types.h> // needed for stat
74 #include <sys/stat.h> // stat
75 #endif
76
77 // Microsoft compiler loves underscores, feed them to it
78 #ifdef _MSC_VER
79
80 #ifndef __MWERKS__
81
82 // functions
83 #define open _open
84 #define close _close
85 #define read _read
86 #define write _write
87 #define lseek _lseek
88 #define fsync _commit
89 #define access _access
90 #define eof _eof
91
92 // types
93 #define stat _stat
94
95 // constants
96
97 #define O_RDONLY _O_RDONLY
98 #define O_WRONLY _O_WRONLY
99 #define O_RDWR _O_RDWR
100 #define O_EXCL _O_EXCL
101 #define O_CREAT _O_CREAT
102 #define O_BINARY _O_BINARY
103
104 #define S_IFDIR _S_IFDIR
105 #define S_IFREG _S_IFREG
106
107 #endif
108
109 #define W_OK 2
110 #define R_OK 4
111 #else
112 #define tell(fd) lseek(fd, 0, SEEK_CUR)
113 #endif //_MSC_VER
114
115 #ifdef __BORLANDC__
116 #define W_OK 2
117 #define R_OK 4
118 #endif
119
120 // there is no distinction between text and binary files under Unix
121 #ifdef __UNIX__
122 #define O_BINARY (0)
123 #endif //__UNIX__
124
125 // wxWindows
126 #include <wx/string.h>
127 #include <wx/intl.h>
128 #include <wx/file.h>
129 #include <wx/log.h>
130
131 #ifndef MAX_PATH
132 #define MAX_PATH 512
133 #endif
134
135 // ============================================================================
136 // implementation of wxFile
137 // ============================================================================
138
139 // ----------------------------------------------------------------------------
140 // static functions
141 // ----------------------------------------------------------------------------
142 bool wxFile::Exists(const char *name)
143 {
144 struct stat st;
145 return !access(name, 0) && !stat(name, &st) && (st.st_mode & S_IFREG);
146 }
147
148 bool wxFile::Access(const char *name, OpenMode mode)
149 {
150 int how = 0;
151
152 switch ( mode ) {
153 case read:
154 how = R_OK;
155 break;
156
157 case write:
158 how = W_OK;
159 break;
160
161 default:
162 wxFAIL_MSG("bad wxFile::Access mode parameter.");
163 }
164
165 return access(name, how) == 0;
166 }
167
168 // ----------------------------------------------------------------------------
169 // opening/closing
170 // ----------------------------------------------------------------------------
171
172 // ctors
173 wxFile::wxFile(const char *szFileName, OpenMode mode)
174 {
175 m_fd = fd_invalid;
176 m_error = FALSE;
177
178 Open(szFileName, mode);
179 }
180
181 // dtor
182 wxFile::~wxFile()
183 {
184 Close();
185 }
186
187 // create the file, fail if it already exists and bOverwrite
188 bool wxFile::Create(const char *szFileName, bool bOverwrite, int access)
189 {
190 // if bOverwrite we create a new file or truncate the existing one,
191 // otherwise we only create the new file and fail if it already exists
192 int fd = open(szFileName, O_WRONLY | O_CREAT |
193 (bOverwrite ? O_TRUNC : O_EXCL), access);
194
195 if ( fd == -1 ) {
196 wxLogSysError(_("can't create file '%s'"), szFileName);
197 return FALSE;
198 }
199 else {
200 Attach(fd);
201 return TRUE;
202 }
203 }
204
205 // open the file
206 bool wxFile::Open(const char *szFileName, OpenMode mode, int access)
207 {
208 int flags = O_BINARY;
209
210 switch ( mode ) {
211 case read:
212 flags |= O_RDONLY;
213 break;
214
215 case write:
216 flags |= O_WRONLY | O_CREAT | O_TRUNC;
217 break;
218
219 case write_append:
220 flags |= O_WRONLY | O_APPEND;
221 break;
222
223 case read_write:
224 flags |= O_RDWR;
225 break;
226 }
227
228 int fd = open(szFileName, flags, access);
229
230 if ( fd == -1 ) {
231 wxLogSysError(_("can't open file '%s'"), szFileName);
232 return FALSE;
233 }
234 else {
235 Attach(fd);
236 return TRUE;
237 }
238 }
239
240 // close
241 bool wxFile::Close()
242 {
243 if ( IsOpened() ) {
244 if ( close(m_fd) == -1 ) {
245 wxLogSysError(_("can't close file descriptor %d"), m_fd);
246 m_fd = fd_invalid;
247 return FALSE;
248 }
249 else
250 m_fd = fd_invalid;
251 }
252
253 return TRUE;
254 }
255
256 // ----------------------------------------------------------------------------
257 // read/write
258 // ----------------------------------------------------------------------------
259
260 // read
261 off_t wxFile::Read(void *pBuf, off_t nCount)
262 {
263 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
264
265 #ifdef __MWERKS__
266 int iRc = ::read(m_fd, (char*) pBuf, nCount);
267 #else
268 int iRc = ::read(m_fd, pBuf, nCount);
269 #endif
270 if ( iRc == -1 ) {
271 wxLogSysError(_("can't read from file descriptor %d"), m_fd);
272 return wxInvalidOffset;
273 }
274 else
275 return (size_t)iRc;
276 }
277
278 // write
279 size_t wxFile::Write(const void *pBuf, size_t nCount)
280 {
281 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
282
283 #ifdef __MWERKS__
284 int iRc = ::write(m_fd, (const char*) pBuf, nCount);
285 #else
286 int iRc = ::write(m_fd, pBuf, nCount);
287 #endif
288 if ( iRc == -1 ) {
289 wxLogSysError(_("can't write to file descriptor %d"), m_fd);
290 m_error = TRUE;
291 return 0;
292 }
293 else
294 return iRc;
295 }
296
297 // flush
298 bool wxFile::Flush()
299 {
300 if ( IsOpened() ) {
301 // @@@ fsync() is not ANSI (BSDish)
302 // if ( fsync(m_fd) == -1 ) { // TODO
303 if (wxTrue) {
304 wxLogSysError(_("can't flush file descriptor %d"), m_fd);
305 return FALSE;
306 }
307 }
308
309 return TRUE;
310 }
311
312 // ----------------------------------------------------------------------------
313 // seek
314 // ----------------------------------------------------------------------------
315
316 // seek
317 off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
318 {
319 wxASSERT( IsOpened() );
320
321 int flag = -1;
322 switch ( mode ) {
323 case wxFromStart:
324 flag = SEEK_SET;
325 break;
326
327 case wxFromCurrent:
328 flag = SEEK_CUR;
329 break;
330
331 case wxFromEnd:
332 flag = SEEK_END;
333 break;
334
335 default:
336 wxFAIL_MSG(_("unknown seek origin"));
337 }
338
339 int iRc = lseek(m_fd, ofs, flag);
340 if ( iRc == -1 ) {
341 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
342 return wxInvalidOffset;
343 }
344 else
345 return (off_t)iRc;
346 }
347
348 // get current off_t
349 off_t wxFile::Tell() const
350 {
351 wxASSERT( IsOpened() );
352
353 int iRc = tell(m_fd);
354 if ( iRc == -1 ) {
355 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
356 return wxInvalidOffset;
357 }
358 else
359 return (off_t)iRc;
360 }
361
362 // get current file length
363 off_t wxFile::Length() const
364 {
365 wxASSERT( IsOpened() );
366
367 #if defined( _MSC_VER ) && !defined( __MWERKS__ )
368 int iRc = _filelength(m_fd);
369 #else
370 int iRc = tell(m_fd);
371 if ( iRc != -1 ) {
372 // @ have to use const_cast :-(
373 int iLen = ((wxFile *)this)->SeekEnd();
374 if ( iLen != -1 ) {
375 // restore old position
376 if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
377 // error
378 iLen = -1;
379 }
380 }
381
382 iRc = iLen;
383 }
384
385 #endif //_MSC_VER
386
387 if ( iRc == -1 ) {
388 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
389 return wxInvalidOffset;
390 }
391 else
392 return (off_t)iRc;
393 }
394
395 // is end of file reached?
396 bool wxFile::Eof() const
397 {
398 wxASSERT( IsOpened() );
399
400 int iRc;
401
402 #if defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ )
403 // @@ this doesn't work, of course, on unseekable file descriptors
404 off_t ofsCur = Tell(),
405 ofsMax = Length();
406 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
407 iRc = -1;
408 else
409 iRc = ofsCur == ofsMax;
410 #else // Windows and "native" compiler
411 iRc = eof(m_fd);
412 #endif // Windows/Unix
413
414 switch ( iRc ) {
415 case 1:
416 break;
417
418 case 0:
419 return FALSE;
420
421 case -1:
422 wxLogSysError(_("can't determine if the end of file is reached on \
423 descriptor %d"), m_fd);
424 break;
425
426 default:
427 wxFAIL_MSG(_("invalid eof() return value."));
428 }
429
430 return TRUE;
431 }
432
433 // ============================================================================
434 // implementation of wxTempFile
435 // ============================================================================
436
437 // ----------------------------------------------------------------------------
438 // construction
439 // ----------------------------------------------------------------------------
440 wxTempFile::wxTempFile(const wxString& strName)
441 {
442 Open(strName);
443 }
444
445 bool wxTempFile::Open(const wxString& strName)
446 {
447 m_strName = strName;
448
449 // we want to create the file in the same directory as strName because
450 // otherwise rename() in Commit() might not work (if the files are on
451 // different partitions for example). Unfortunately, the only standard
452 // (POSIX) temp file creation function tmpnam() can't do it.
453 #if defined(__UNIX__) || defined(__WXSTUBS__)|| defined( __WXMAC__ )
454 static const char *szMktempSuffix = "XXXXXX";
455 m_strTemp << strName << szMktempSuffix;
456 mktemp((char *)m_strTemp.c_str()); // will do because length doesn't change
457 #else // Windows
458 wxString strPath;
459 wxSplitPath(strName, &strPath, NULL, NULL);
460 if ( strPath.IsEmpty() )
461 strPath = '.'; // GetTempFileName will fail if we give it empty string
462 #ifdef __WIN32__
463 if ( !GetTempFileName(strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
464 #else
465 // Not sure why MSVC++ 1.5 header defines first param as BYTE - bug?
466 if ( !GetTempFileName((BYTE) (const char*) strPath, "wx_",0, m_strTemp.GetWriteBuf(MAX_PATH)) )
467 #endif
468 wxLogLastError("GetTempFileName");
469 m_strTemp.UngetWriteBuf();
470 #endif // Windows/Unix
471
472 return m_file.Open(m_strTemp, wxFile::write);
473 }
474
475 // ----------------------------------------------------------------------------
476 // destruction
477 // ----------------------------------------------------------------------------
478
479 wxTempFile::~wxTempFile()
480 {
481 if ( IsOpened() )
482 Discard();
483 }
484
485 bool wxTempFile::Commit()
486 {
487 m_file.Close();
488
489 if ( wxFile::Exists(m_strName) && remove(m_strName) != 0 ) {
490 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
491 return FALSE;
492 }
493
494 if ( rename(m_strTemp, m_strName) != 0 ) {
495 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
496 return FALSE;
497 }
498
499 return TRUE;
500 }
501
502 void wxTempFile::Discard()
503 {
504 m_file.Close();
505 if ( remove(m_strTemp) != 0 )
506 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
507 }