Warning fix to unused variable.
[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 TODO: remove all the WinCE ugliness from here, implement the wxOpen(),
15 wxSeek(), ... functions in a separate file for WinCE instead!!!
16 */
17
18 // ----------------------------------------------------------------------------
19 // headers
20 // ----------------------------------------------------------------------------
21
22 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
23 #pragma implementation "file.h"
24 #endif
25
26 // For compilers that support precompilation, includes "wx.h".
27 #include "wx/wxprec.h"
28
29 #ifdef __BORLANDC__
30 #pragma hdrstop
31 #endif
32
33 #if wxUSE_FILE
34
35 // standard
36 #if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
37 #include <io.h>
38
39 #ifndef __SALFORDC__
40 #define WIN32_LEAN_AND_MEAN
41 #define NOSERVICE
42 #define NOIME
43 #define NOATOM
44 #define NOGDI
45 #define NOGDICAPMASKS
46 #define NOMETAFILE
47 #define NOMINMAX
48 #define NOMSG
49 #define NOOPENFILE
50 #define NORASTEROPS
51 #define NOSCROLL
52 #define NOSOUND
53 #define NOSYSMETRICS
54 #define NOTEXTMETRIC
55 #define NOWH
56 #define NOCOMM
57 #define NOKANJI
58 #define NOCRYPT
59 #define NOMCX
60 #endif
61
62 #elif defined(__WXMSW__) && defined(__WXWINCE__)
63 // TODO: what to include?
64 #elif (defined(__OS2__))
65 #include <io.h>
66 #elif (defined(__UNIX__) || defined(__GNUWIN32__))
67 #include <unistd.h>
68 #include <time.h>
69 #include <sys/stat.h>
70 #ifdef __GNUWIN32__
71 #include "wx/msw/wrapwin.h"
72 #endif
73 #elif defined(__DOS__)
74 #if defined(__WATCOMC__)
75 #include <io.h>
76 #elif defined(__DJGPP__)
77 #include <io.h>
78 #include <unistd.h>
79 #include <stdio.h>
80 #else
81 #error "Please specify the header with file functions declarations."
82 #endif
83 #elif (defined(__WXSTUBS__))
84 // Have to ifdef this for different environments
85 #include <io.h>
86 #elif (defined(__WXMAC__))
87 #if __MSL__ < 0x6000
88 int access( const char *path, int mode ) { return 0 ; }
89 #else
90 int _access( const char *path, int mode ) { return 0 ; }
91 #endif
92 char* mktemp( char * path ) { return path ;}
93 #include <stat.h>
94 #include <unistd.h>
95 #else
96 #error "Please specify the header with file functions declarations."
97 #endif //Win/UNIX
98
99 #include <stdio.h> // SEEK_xxx constants
100
101 #ifndef __WXWINCE__
102 #include <fcntl.h> // O_RDONLY &c
103 #endif
104
105 #ifdef __WXWINCE__
106 // Nothing
107 #elif !defined(__MWERKS__)
108 #include <sys/types.h> // needed for stat
109 #include <sys/stat.h> // stat
110 #elif defined(__MWERKS__) && ( defined(__WXMSW__) || defined(__MACH__) )
111 #include <sys/types.h> // needed for stat
112 #include <sys/stat.h> // stat
113 #endif
114
115 // Windows compilers don't have these constants
116 #ifndef W_OK
117 enum
118 {
119 F_OK = 0, // test for existence
120 X_OK = 1, // execute permission
121 W_OK = 2, // write
122 R_OK = 4 // read
123 };
124 #endif // W_OK
125
126 // there is no distinction between text and binary files under Unix, so define
127 // O_BINARY as 0 if the system headers don't do it already
128 #if defined(__UNIX__) && !defined(O_BINARY)
129 #define O_BINARY (0)
130 #endif //__UNIX__
131
132 #ifdef __SALFORDC__
133 #include <unix.h>
134 #endif
135
136 #ifndef MAX_PATH
137 #define MAX_PATH 512
138 #endif
139
140 // some broken compilers don't have 3rd argument in open() and creat()
141 #ifdef __SALFORDC__
142 #define ACCESS(access)
143 #define stat _stat
144 #else // normal compiler
145 #define ACCESS(access) , (access)
146 #endif // Salford C
147
148 // wxWidgets
149 #ifndef WX_PRECOMP
150 #include "wx/string.h"
151 #include "wx/intl.h"
152 #include "wx/log.h"
153 #endif // !WX_PRECOMP
154
155 #include "wx/filename.h"
156 #include "wx/file.h"
157 #include "wx/filefn.h"
158
159 #ifdef __WXMSW__
160 #include "wx/msw/mslu.h"
161 #endif
162
163 #ifdef __WXWINCE__
164 #include "wx/msw/private.h"
165 #endif
166
167 // ============================================================================
168 // implementation of wxFile
169 // ============================================================================
170
171 // ----------------------------------------------------------------------------
172 // static functions
173 // ----------------------------------------------------------------------------
174
175 bool wxFile::Exists(const wxChar *name)
176 {
177 return wxFileExists(name);
178 }
179
180 bool wxFile::Access(const wxChar *name, OpenMode mode)
181 {
182 int how;
183
184 switch ( mode )
185 {
186 default:
187 wxFAIL_MSG(wxT("bad wxFile::Access mode parameter."));
188 // fall through
189
190 case read:
191 how = R_OK;
192 break;
193
194 case write:
195 how = W_OK;
196 break;
197
198 case read_write:
199 how = R_OK | W_OK;
200 break;
201 }
202
203 #ifdef __WXWINCE__
204 // FIXME: use CreateFile with 0 access to query the file
205 return true;
206 #else
207 return wxAccess(name, how) == 0;
208 #endif
209 }
210
211 // ----------------------------------------------------------------------------
212 // opening/closing
213 // ----------------------------------------------------------------------------
214
215 // ctors
216 wxFile::wxFile(const wxChar *szFileName, OpenMode mode)
217 {
218 m_fd = fd_invalid;
219 m_error = false;
220
221 Open(szFileName, mode);
222 }
223
224 // create the file, fail if it already exists and bOverwrite
225 bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode)
226 {
227 // if bOverwrite we create a new file or truncate the existing one,
228 // otherwise we only create the new file and fail if it already exists
229 #if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE
230 // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace
231 // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access);
232 int fd = creat( szFileName , accessMode);
233 #else
234 #ifdef __WXWINCE__
235 HANDLE fileHandle = ::CreateFile(szFileName, GENERIC_WRITE, 0, NULL,
236 bOverwrite ? CREATE_ALWAYS : CREATE_NEW, FILE_ATTRIBUTE_NORMAL,
237 0);
238 int fd = 0;
239 if (fileHandle == INVALID_HANDLE_VALUE)
240 fd = (int) fileHandle;
241 else
242 fd = -1;
243 #else
244 int fd = wxOpen( szFileName,
245 O_BINARY | O_WRONLY | O_CREAT |
246 (bOverwrite ? O_TRUNC : O_EXCL)
247 ACCESS(accessMode) );
248 #endif
249 #endif
250 if ( fd == -1 )
251 {
252 wxLogSysError(_("can't create file '%s'"), szFileName);
253 return false;
254 }
255 else
256 {
257 Attach(fd);
258 return true;
259 }
260 }
261
262 // open the file
263 bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode)
264 {
265 #ifdef __WXWINCE__
266 DWORD access = 0;
267 DWORD shareMode = 0;
268 DWORD disposition = 0;
269
270 switch ( mode )
271 {
272 case read:
273 access = GENERIC_READ;
274 shareMode = FILE_SHARE_READ|FILE_SHARE_WRITE;
275 disposition = OPEN_EXISTING;
276 break;
277
278 case write_append:
279 if ( wxFile::Exists(szFileName) )
280 {
281 access = GENERIC_READ|GENERIC_WRITE;
282 shareMode = FILE_SHARE_READ;
283 disposition = 0;
284 break;
285 }
286 //else: fall through as write_append is the same as write if the
287 // file doesn't exist
288
289 case write:
290 access = GENERIC_WRITE;
291 shareMode = 0;
292 disposition = TRUNCATE_EXISTING;
293 break;
294
295 case write_excl:
296 access = GENERIC_WRITE;
297 shareMode = 0;
298 disposition = TRUNCATE_EXISTING;
299 break;
300
301 case read_write:
302 access = GENERIC_READ|GENERIC_WRITE;
303 shareMode = 0;
304 disposition = 0;
305 break;
306 }
307
308 int fd = 0;
309 HANDLE fileHandle = ::CreateFile(szFileName, access, shareMode, NULL,
310 disposition, FILE_ATTRIBUTE_NORMAL, 0);
311 if (fileHandle == INVALID_HANDLE_VALUE)
312 fd = -1;
313 else
314 fd = (int) fileHandle;
315 #else
316 int flags = O_BINARY;
317
318 switch ( mode )
319 {
320 case read:
321 flags |= O_RDONLY;
322 break;
323
324 case write_append:
325 if ( wxFile::Exists(szFileName) )
326 {
327 flags |= O_WRONLY | O_APPEND;
328 break;
329 }
330 //else: fall through as write_append is the same as write if the
331 // file doesn't exist
332
333 case write:
334 flags |= O_WRONLY | O_CREAT | O_TRUNC;
335 break;
336
337 case write_excl:
338 flags |= O_WRONLY | O_CREAT | O_EXCL;
339 break;
340
341 case read_write:
342 flags |= O_RDWR;
343 break;
344 }
345
346 #ifdef __WINDOWS__
347 // only read/write bits for "all" are supported by this function under
348 // Windows, and VC++ 8 returns EINVAL if any other bits are used in
349 // accessMode, so clear them as they have at best no effect anyhow
350 accessMode &= wxS_IRUSR | wxS_IWUSR;
351 #endif // __WINDOWS__
352
353 int fd = wxOpen( szFileName, flags ACCESS(accessMode));
354 #endif
355 if ( fd == -1 )
356 {
357 wxLogSysError(_("can't open file '%s'"), szFileName);
358 return false;
359 }
360 else {
361 Attach(fd);
362 return true;
363 }
364 }
365
366 // close
367 bool wxFile::Close()
368 {
369 if ( IsOpened() ) {
370 #ifdef __WXWINCE__
371 if (!CloseHandle((HANDLE) m_fd))
372 #else
373 if ( close(m_fd) == -1 )
374 #endif
375 {
376 wxLogSysError(_("can't close file descriptor %d"), m_fd);
377 m_fd = fd_invalid;
378 return false;
379 }
380 else
381 m_fd = fd_invalid;
382 }
383
384 return true;
385 }
386
387 // ----------------------------------------------------------------------------
388 // read/write
389 // ----------------------------------------------------------------------------
390
391 // read
392 off_t wxFile::Read(void *pBuf, off_t nCount)
393 {
394 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
395
396 #ifdef __WXWINCE__
397 DWORD bytesRead = 0;
398 int iRc = 0;
399 if (ReadFile((HANDLE) m_fd, pBuf, (DWORD) nCount, & bytesRead, NULL))
400 iRc = bytesRead;
401 else
402 iRc = -1;
403 #elif defined(__MWERKS__)
404 int iRc = ::read(m_fd, (char*) pBuf, nCount);
405 #else
406 int iRc = ::read(m_fd, pBuf, nCount);
407 #endif
408 if ( iRc == -1 ) {
409 wxLogSysError(_("can't read from file descriptor %d"), m_fd);
410 return wxInvalidOffset;
411 }
412 else
413 return (size_t)iRc;
414 }
415
416 // write
417 size_t wxFile::Write(const void *pBuf, size_t nCount)
418 {
419 wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
420
421 #ifdef __WXWINCE__
422 DWORD bytesWritten = 0;
423 int iRc = 0;
424 if (WriteFile((HANDLE) m_fd, pBuf, (DWORD) nCount, & bytesWritten, NULL))
425 iRc = bytesWritten;
426 else
427 iRc = -1;
428 #elif defined(__MWERKS__)
429 #if __MSL__ >= 0x6000
430 int iRc = ::write(m_fd, (void*) pBuf, nCount);
431 #else
432 int iRc = ::write(m_fd, (const char*) pBuf, nCount);
433 #endif
434 #else
435 int iRc = ::write(m_fd, pBuf, nCount);
436 #endif
437 if ( iRc == -1 ) {
438 wxLogSysError(_("can't write to file descriptor %d"), m_fd);
439 m_error = true;
440 return 0;
441 }
442 else
443 return iRc;
444 }
445
446 // flush
447 bool wxFile::Flush()
448 {
449 if ( IsOpened() ) {
450 #ifdef __WXWINCE__
451 // Do nothing
452 #elif defined(__VISUALC__) || wxHAVE_FSYNC
453 if ( wxFsync(m_fd) == -1 )
454 {
455 wxLogSysError(_("can't flush file descriptor %d"), m_fd);
456 return false;
457 }
458 #else // no fsync
459 // just do nothing
460 #endif // fsync
461 }
462
463 return true;
464 }
465
466 // ----------------------------------------------------------------------------
467 // seek
468 // ----------------------------------------------------------------------------
469
470 // seek
471 off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
472 {
473 wxASSERT( IsOpened() );
474
475 #ifdef __WXWINCE__
476 int origin;
477 switch ( mode ) {
478 default:
479 wxFAIL_MSG(_("unknown seek origin"));
480
481 case wxFromStart:
482 origin = FILE_BEGIN;
483 break;
484
485 case wxFromCurrent:
486 origin = FILE_CURRENT;
487 break;
488
489 case wxFromEnd:
490 origin = FILE_END;
491 break;
492 }
493
494 DWORD res = SetFilePointer((HANDLE) m_fd, ofs, 0, origin) ;
495 if (res == 0xFFFFFFFF && GetLastError() != NO_ERROR)
496 {
497 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
498 return wxInvalidOffset;
499 }
500 else
501 return (off_t)res;
502 #else
503 int origin;
504 switch ( mode ) {
505 default:
506 wxFAIL_MSG(_("unknown seek origin"));
507
508 case wxFromStart:
509 origin = SEEK_SET;
510 break;
511
512 case wxFromCurrent:
513 origin = SEEK_CUR;
514 break;
515
516 case wxFromEnd:
517 origin = SEEK_END;
518 break;
519 }
520
521 int iRc = lseek(m_fd, ofs, origin);
522 if ( iRc == -1 ) {
523 wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
524 return wxInvalidOffset;
525 }
526 else
527 return (off_t)iRc;
528 #endif
529 }
530
531 // get current off_t
532 off_t wxFile::Tell() const
533 {
534 wxASSERT( IsOpened() );
535
536 #ifdef __WXWINCE__
537 DWORD res = SetFilePointer((HANDLE) m_fd, 0, 0, FILE_CURRENT) ;
538 if (res == 0xFFFFFFFF && GetLastError() != NO_ERROR)
539 {
540 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
541 return wxInvalidOffset;
542 }
543 else
544 return (off_t)res;
545 #else
546 int iRc = wxTell(m_fd);
547 if ( iRc == -1 ) {
548 wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
549 return wxInvalidOffset;
550 }
551 else
552 return (off_t)iRc;
553 #endif
554 }
555
556 // get current file length
557 off_t wxFile::Length() const
558 {
559 wxASSERT( IsOpened() );
560
561 #ifdef __WXWINCE__
562 DWORD off0 = SetFilePointer((HANDLE) m_fd, 0, 0, FILE_CURRENT);
563 DWORD off1 = SetFilePointer((HANDLE) m_fd, 0, 0, FILE_END);
564 off_t len = off1;
565
566 // Restore position
567 SetFilePointer((HANDLE) m_fd, off0, 0, FILE_BEGIN);
568 return len;
569 #else
570 #ifdef __VISUALC__
571 int iRc = _filelength(m_fd);
572 #else // !VC++
573 int iRc = wxTell(m_fd);
574 if ( iRc != -1 ) {
575 // @ have to use const_cast :-(
576 int iLen = ((wxFile *)this)->SeekEnd();
577 if ( iLen != -1 ) {
578 // restore old position
579 if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
580 // error
581 iLen = -1;
582 }
583 }
584
585 iRc = iLen;
586 }
587 #endif // VC++
588
589 if ( iRc == -1 ) {
590 wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
591 return wxInvalidOffset;
592 }
593 else
594 return (off_t)iRc;
595 #endif
596 }
597
598 // is end of file reached?
599 bool wxFile::Eof() const
600 {
601 wxASSERT( IsOpened() );
602
603 #ifdef __WXWINCE__
604 DWORD off0 = SetFilePointer((HANDLE) m_fd, 0, 0, FILE_CURRENT);
605 DWORD off1 = SetFilePointer((HANDLE) m_fd, 0, 0, FILE_END);
606 if (off0 == off1)
607 return true;
608 else
609 {
610 SetFilePointer((HANDLE) m_fd, off0, 0, FILE_BEGIN);
611 return false;
612 }
613 #else
614 int iRc;
615
616 #if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__)
617 // @@ this doesn't work, of course, on unseekable file descriptors
618 off_t ofsCur = Tell(),
619 ofsMax = Length();
620 if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
621 iRc = -1;
622 else
623 iRc = ofsCur == ofsMax;
624 #else // Windows and "native" compiler
625 iRc = eof(m_fd);
626 #endif // Windows/Unix
627
628 switch ( iRc ) {
629 case 1:
630 break;
631
632 case 0:
633 return false;
634
635 case -1:
636 wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd);
637 break;
638
639 default:
640 wxFAIL_MSG(_("invalid eof() return value."));
641 }
642
643 return true;
644 #endif
645 }
646
647 // ============================================================================
648 // implementation of wxTempFile
649 // ============================================================================
650
651 // ----------------------------------------------------------------------------
652 // construction
653 // ----------------------------------------------------------------------------
654
655 wxTempFile::wxTempFile(const wxString& strName)
656 {
657 Open(strName);
658 }
659
660 bool wxTempFile::Open(const wxString& strName)
661 {
662 // we must have an absolute filename because otherwise CreateTempFileName()
663 // would create the temp file in $TMP (i.e. the system standard location
664 // for the temp files) which might be on another volume/drive/mount and
665 // wxRename()ing it later to m_strName from Commit() would then fail
666 //
667 // with the absolute filename, the temp file is created in the same
668 // directory as this one which ensures that wxRename() may work later
669 wxFileName fn(strName);
670 if ( !fn.IsAbsolute() )
671 {
672 fn.Normalize(wxPATH_NORM_ABSOLUTE);
673 }
674
675 m_strName = fn.GetFullPath();
676
677 m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file);
678
679 if ( m_strTemp.empty() )
680 {
681 // CreateTempFileName() failed
682 return false;
683 }
684
685 #ifdef __UNIX__
686 // the temp file should have the same permissions as the original one
687 mode_t mode;
688
689 wxStructStat st;
690 if ( stat( (const char*) m_strName.fn_str(), &st) == 0 )
691 {
692 mode = st.st_mode;
693 }
694 else
695 {
696 // file probably didn't exist, just give it the default mode _using_
697 // user's umask (new files creation should respect umask)
698 mode_t mask = umask(0777);
699 mode = 0666 & ~mask;
700 umask(mask);
701 }
702
703 if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 )
704 {
705 #ifndef __OS2__
706 wxLogSysError(_("Failed to set temporary file permissions"));
707 #endif
708 }
709 #endif // Unix
710
711 return true;
712 }
713
714 // ----------------------------------------------------------------------------
715 // destruction
716 // ----------------------------------------------------------------------------
717
718 wxTempFile::~wxTempFile()
719 {
720 if ( IsOpened() )
721 Discard();
722 }
723
724 bool wxTempFile::Commit()
725 {
726 m_file.Close();
727
728 if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
729 wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
730 return false;
731 }
732
733 if ( !wxRenameFile(m_strTemp, m_strName) ) {
734 wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
735 return false;
736 }
737
738 return true;
739 }
740
741 void wxTempFile::Discard()
742 {
743 m_file.Close();
744 if ( wxRemove(m_strTemp) != 0 )
745 wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
746 }
747
748 #endif // wxUSE_FILE
749