]> git.saurik.com Git - wxWidgets.git/blob - src/common/file.cpp
Applied patch [ 1113624 ] MSW DLL requires global new/delete ops inline
[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 licence
11 /////////////////////////////////////////////////////////////////////////////
12
13 // ----------------------------------------------------------------------------
14 // headers
15 // ----------------------------------------------------------------------------
16
17 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
18     #pragma implementation "file.h"
19 #endif
20
21 // For compilers that support precompilation, includes "wx.h".
22 #include "wx/wxprec.h"
23
24 #ifdef __BORLANDC__
25   #pragma hdrstop
26 #endif
27
28 #if wxUSE_FILE
29
30 // standard
31 #if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
32
33 #ifndef __SALFORDC__
34     #define   WIN32_LEAN_AND_MEAN
35     #define   NOSERVICE
36     #define   NOIME
37     #define   NOATOM
38     #define   NOGDI
39     #define   NOGDICAPMASKS
40     #define   NOMETAFILE
41     #define   NOMINMAX
42     #define   NOMSG
43     #define   NOOPENFILE
44     #define   NORASTEROPS
45     #define   NOSCROLL
46     #define   NOSOUND
47     #define   NOSYSMETRICS
48     #define   NOTEXTMETRIC
49     #define   NOWH
50     #define   NOCOMM
51     #define   NOKANJI
52     #define   NOCRYPT
53     #define   NOMCX
54 #endif
55
56 #elif defined(__WXMSW__) && defined(__WXWINCE__)
57     #include  "wx/msw/missing.h"
58 #elif (defined(__OS2__))
59     #include <io.h>
60 #elif (defined(__UNIX__) || defined(__GNUWIN32__))
61     #include  <unistd.h>
62     #include  <time.h>
63     #include  <sys/stat.h>
64     #ifdef __GNUWIN32__
65         #include "wx/msw/wrapwin.h"
66     #endif
67 #elif defined(__DOS__)
68     #if defined(__WATCOMC__)
69        #include <io.h>
70     #elif defined(__DJGPP__)
71        #include <io.h>
72        #include <unistd.h>
73        #include <stdio.h>
74     #else
75         #error  "Please specify the header with file functions declarations."
76     #endif
77 #elif (defined(__WXSTUBS__))
78     // Have to ifdef this for different environments
79     #include <io.h>
80 #elif (defined(__WXMAC__))
81 #if __MSL__ < 0x6000
82     int access( const char *path, int mode ) { return 0 ; }
83 #else
84     int _access( const char *path, int mode ) { return 0 ; }
85 #endif
86     char* mktemp( char * path ) { return path ;}
87     #include <stat.h>
88     #include <unistd.h>
89 #else
90     #error  "Please specify the header with file functions declarations."
91 #endif  //Win/UNIX
92
93 #include  <stdio.h>       // SEEK_xxx constants
94
95 // Windows compilers don't have these constants
96 #ifndef W_OK
97     enum
98     {
99         F_OK = 0,   // test for existence
100         X_OK = 1,   //          execute permission
101         W_OK = 2,   //          write
102         R_OK = 4    //          read
103     };
104 #endif // W_OK
105
106 // there is no distinction between text and binary files under Unix, so define
107 // O_BINARY as 0 if the system headers don't do it already
108 #if defined(__UNIX__) && !defined(O_BINARY)
109     #define   O_BINARY    (0)
110 #endif  //__UNIX__
111
112 #ifdef __SALFORDC__
113     #include <unix.h>
114 #endif
115
116 #ifndef MAX_PATH
117     #define MAX_PATH 512
118 #endif
119
120 // some broken compilers don't have 3rd argument in open() and creat()
121 #ifdef __SALFORDC__
122     #define ACCESS(access)
123     #define stat    _stat
124 #else // normal compiler
125     #define ACCESS(access)  , (access)
126 #endif // Salford C
127
128 // wxWidgets
129 #ifndef WX_PRECOMP
130     #include  "wx/string.h"
131     #include  "wx/intl.h"
132     #include  "wx/log.h"
133 #endif // !WX_PRECOMP
134
135 #include  "wx/filename.h"
136 #include  "wx/file.h"
137 #include  "wx/filefn.h"
138
139 #ifdef __WXMSW__
140     #include "wx/msw/mslu.h"
141 #endif
142
143 #ifdef __WXWINCE__
144     #include "wx/msw/private.h"
145 #endif
146
147
148 // ============================================================================
149 // implementation of wxFile
150 // ============================================================================
151
152 // ----------------------------------------------------------------------------
153 // static functions
154 // ----------------------------------------------------------------------------
155
156 bool wxFile::Exists(const wxChar *name)
157 {
158     return wxFileExists(name);
159 }
160
161 bool wxFile::Access(const wxChar *name, OpenMode mode)
162 {
163     int how;
164
165     switch ( mode )
166     {
167         default:
168             wxFAIL_MSG(wxT("bad wxFile::Access mode parameter."));
169             // fall through
170
171         case read:
172             how = R_OK;
173             break;
174
175         case write:
176             how = W_OK;
177             break;
178
179         case read_write:
180             how = R_OK | W_OK;
181             break;
182     }
183
184     return wxAccess(name, how) == 0;
185 }
186
187 // ----------------------------------------------------------------------------
188 // opening/closing
189 // ----------------------------------------------------------------------------
190
191 // ctors
192 wxFile::wxFile(const wxChar *szFileName, OpenMode mode)
193 {
194     m_fd = fd_invalid;
195     m_error = false;
196
197     Open(szFileName, mode);
198 }
199
200 // create the file, fail if it already exists and bOverwrite
201 bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode)
202 {
203     // if bOverwrite we create a new file or truncate the existing one,
204     // otherwise we only create the new file and fail if it already exists
205 #if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE
206     // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace
207     // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access);
208     int fd = creat( szFileName , accessMode);
209 #else
210     int fd = wxOpen( szFileName,
211                      O_BINARY | O_WRONLY | O_CREAT |
212                      (bOverwrite ? O_TRUNC : O_EXCL)
213                      ACCESS(accessMode) );
214 #endif
215     if ( fd == -1 )
216     {
217         wxLogSysError(_("can't create file '%s'"), szFileName);
218         return false;
219     }
220     else
221     {
222         Attach(fd);
223         return true;
224     }
225 }
226
227 // open the file
228 bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode)
229 {
230     int flags = O_BINARY;
231
232     switch ( mode )
233     {
234         case read:
235             flags |= O_RDONLY;
236             break;
237
238         case write_append:
239             if ( wxFile::Exists(szFileName) )
240             {
241                 flags |= O_WRONLY | O_APPEND;
242                 break;
243             }
244             //else: fall through as write_append is the same as write if the
245             //      file doesn't exist
246
247         case write:
248             flags |= O_WRONLY | O_CREAT | O_TRUNC;
249             break;
250
251         case write_excl:
252             flags |= O_WRONLY | O_CREAT | O_EXCL;
253             break;
254
255         case read_write:
256             flags |= O_RDWR;
257             break;
258     }
259
260 #ifdef __WINDOWS__
261     // only read/write bits for "all" are supported by this function under
262     // Windows, and VC++ 8 returns EINVAL if any other bits are used in
263     // accessMode, so clear them as they have at best no effect anyhow
264     accessMode &= wxS_IRUSR | wxS_IWUSR;
265 #endif // __WINDOWS__
266
267     int fd = wxOpen( szFileName, flags ACCESS(accessMode));
268
269     if ( fd == -1 )
270     {
271         wxLogSysError(_("can't open file '%s'"), szFileName);
272         return false;
273     }
274     else {
275         Attach(fd);
276         return true;
277     }
278 }
279
280 // close
281 bool wxFile::Close()
282 {
283     if ( IsOpened() ) {
284         if (wxClose(m_fd) == -1)
285         {
286             wxLogSysError(_("can't close file descriptor %d"), m_fd);
287             m_fd = fd_invalid;
288             return false;
289         }
290         else
291             m_fd = fd_invalid;
292     }
293
294     return true;
295 }
296
297 // ----------------------------------------------------------------------------
298 // read/write
299 // ----------------------------------------------------------------------------
300
301 // read
302 ssize_t wxFile::Read(void *pBuf, size_t nCount)
303 {
304     wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
305
306     ssize_t iRc = wxRead(m_fd, pBuf, nCount);
307
308     if ( iRc == -1 )
309     {
310         wxLogSysError(_("can't read from file descriptor %d"), m_fd);
311         return wxInvalidOffset;
312     }
313
314     return iRc;
315 }
316
317 // write
318 size_t wxFile::Write(const void *pBuf, size_t nCount)
319 {
320     wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
321
322     ssize_t iRc = wxWrite(m_fd, pBuf, nCount);
323
324     if ( iRc == -1 )
325     {
326         wxLogSysError(_("can't write to file descriptor %d"), m_fd);
327         m_error = true;
328         iRc = 0;
329     }
330
331     return iRc;
332 }
333
334 // flush
335 bool wxFile::Flush()
336 {
337     if ( IsOpened() ) {
338 #if defined(__VISUALC__) || wxHAVE_FSYNC
339         if ( wxFsync(m_fd) == -1 )
340         {
341             wxLogSysError(_("can't flush file descriptor %d"), m_fd);
342             return false;
343         }
344 #else // no fsync
345         // just do nothing
346 #endif // fsync
347     }
348
349     return true;
350 }
351
352 // ----------------------------------------------------------------------------
353 // seek
354 // ----------------------------------------------------------------------------
355
356 // seek
357 wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode)
358 {
359     wxASSERT( IsOpened() );
360
361     int origin;
362     switch ( mode ) {
363         default:
364             wxFAIL_MSG(_("unknown seek origin"));
365
366         case wxFromStart:
367             origin = SEEK_SET;
368             break;
369
370         case wxFromCurrent:
371             origin = SEEK_CUR;
372             break;
373
374         case wxFromEnd:
375             origin = SEEK_END;
376             break;
377     }
378
379     if (ofs == wxInvalidOffset)
380     {
381         wxLogSysError(_("can't seek on file descriptor %d, large files support is not enabled."), m_fd);
382         return wxInvalidOffset;
383     }
384     wxFileOffset iRc = wxSeek(m_fd, ofs, origin);
385     if ( iRc == wxInvalidOffset )
386     {
387         wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
388     }
389
390     return iRc;
391 }
392
393 // get current file offset
394 wxFileOffset wxFile::Tell() const
395 {
396     wxASSERT( IsOpened() );
397
398     wxFileOffset iRc = wxTell(m_fd);
399     if ( iRc == wxInvalidOffset )
400     {
401         wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
402     }
403
404     return iRc;
405 }
406
407 // get current file length
408 wxFileOffset wxFile::Length() const
409 {
410     wxASSERT( IsOpened() );
411
412     wxFileOffset iRc = Tell();
413     if ( iRc != wxInvalidOffset ) {
414         // have to use const_cast :-(
415         wxFileOffset iLen = ((wxFile *)this)->SeekEnd();
416         if ( iLen != wxInvalidOffset ) {
417             // restore old position
418             if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) {
419                 // error
420                 iLen = wxInvalidOffset;
421             }
422         }
423
424         iRc = iLen;
425     }
426
427     if ( iRc == wxInvalidOffset )
428     {
429         wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
430     }
431
432     return iRc;
433 }
434
435 // is end of file reached?
436 bool wxFile::Eof() const
437 {
438     wxASSERT( IsOpened() );
439
440     wxFileOffset iRc;
441
442 #if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__)
443     // @@ this doesn't work, of course, on unseekable file descriptors
444     wxFileOffset ofsCur = Tell(),
445     ofsMax = Length();
446     if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
447         iRc = wxInvalidOffset;
448     else
449         iRc = ofsCur == ofsMax;
450 #else  // Windows and "native" compiler
451     iRc = wxEof(m_fd);
452 #endif // Windows/Unix
453
454     if ( iRc == 1)
455         {}
456     else if ( iRc == 0 )
457         return false;
458     else if ( iRc == wxInvalidOffset )
459         wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd);
460     else
461         wxFAIL_MSG(_("invalid eof() return value."));
462
463     return true;
464 }
465
466 // ============================================================================
467 // implementation of wxTempFile
468 // ============================================================================
469
470 // ----------------------------------------------------------------------------
471 // construction
472 // ----------------------------------------------------------------------------
473
474 wxTempFile::wxTempFile(const wxString& strName)
475 {
476     Open(strName);
477 }
478
479 bool wxTempFile::Open(const wxString& strName)
480 {
481     // we must have an absolute filename because otherwise CreateTempFileName()
482     // would create the temp file in $TMP (i.e. the system standard location
483     // for the temp files) which might be on another volume/drive/mount and
484     // wxRename()ing it later to m_strName from Commit() would then fail
485     //
486     // with the absolute filename, the temp file is created in the same
487     // directory as this one which ensures that wxRename() may work later
488     wxFileName fn(strName);
489     if ( !fn.IsAbsolute() )
490     {
491         fn.Normalize(wxPATH_NORM_ABSOLUTE);
492     }
493
494     m_strName = fn.GetFullPath();
495
496     m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file);
497
498     if ( m_strTemp.empty() )
499     {
500         // CreateTempFileName() failed
501         return false;
502     }
503
504 #ifdef __UNIX__
505     // the temp file should have the same permissions as the original one
506     mode_t mode;
507
508     wxStructStat st;
509     if ( stat( (const char*) m_strName.fn_str(), &st) == 0 )
510     {
511         mode = st.st_mode;
512     }
513     else
514     {
515         // file probably didn't exist, just give it the default mode _using_
516         // user's umask (new files creation should respect umask)
517         mode_t mask = umask(0777);
518         mode = 0666 & ~mask;
519         umask(mask);
520     }
521
522     if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 )
523     {
524 #ifndef __OS2__
525         wxLogSysError(_("Failed to set temporary file permissions"));
526 #endif
527     }
528 #endif // Unix
529
530     return true;
531 }
532
533 // ----------------------------------------------------------------------------
534 // destruction
535 // ----------------------------------------------------------------------------
536
537 wxTempFile::~wxTempFile()
538 {
539     if ( IsOpened() )
540         Discard();
541 }
542
543 bool wxTempFile::Commit()
544 {
545     m_file.Close();
546
547     if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
548         wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
549         return false;
550     }
551
552     if ( !wxRenameFile(m_strTemp, m_strName)  ) {
553         wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
554         return false;
555     }
556
557     return true;
558 }
559
560 void wxTempFile::Discard()
561 {
562     m_file.Close();
563     if ( wxRemove(m_strTemp) != 0 )
564         wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
565 }
566
567 #endif // wxUSE_FILE
568