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