being just a define so that the signature is
using wxChar under Unicode under Unix just as
it does under Unicode under Mac. This required
some modification in various places, but should
make debugging a little easier, among others.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@16426 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
565 lines
14 KiB
C++
565 lines
14 KiB
C++
/////////////////////////////////////////////////////////////////////////////
|
|
// Name: file.cpp
|
|
// Purpose: wxFile - encapsulates low-level "file descriptor"
|
|
// wxTempFile
|
|
// Author: Vadim Zeitlin
|
|
// Modified by:
|
|
// Created: 29/01/98
|
|
// RCS-ID: $Id$
|
|
// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
|
|
// Licence: wxWindows license
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// headers
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifdef __GNUG__
|
|
#pragma implementation "file.h"
|
|
#endif
|
|
|
|
// For compilers that support precompilation, includes "wx.h".
|
|
#include "wx/wxprec.h"
|
|
|
|
#ifdef __BORLANDC__
|
|
#pragma hdrstop
|
|
#endif
|
|
|
|
#if wxUSE_FILE
|
|
|
|
// standard
|
|
#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXWINE__) && !defined(__WXMICROWIN__)
|
|
#include <io.h>
|
|
|
|
#ifndef __SALFORDC__
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#define NOSERVICE
|
|
#define NOIME
|
|
#define NOATOM
|
|
#define NOGDI
|
|
#define NOGDICAPMASKS
|
|
#define NOMETAFILE
|
|
#define NOMINMAX
|
|
#define NOMSG
|
|
#define NOOPENFILE
|
|
#define NORASTEROPS
|
|
#define NOSCROLL
|
|
#define NOSOUND
|
|
#define NOSYSMETRICS
|
|
#define NOTEXTMETRIC
|
|
#define NOWH
|
|
#define NOCOMM
|
|
#define NOKANJI
|
|
#define NOCRYPT
|
|
#define NOMCX
|
|
#endif
|
|
|
|
#elif (defined(__UNIX__) || defined(__GNUWIN32__))
|
|
#include <unistd.h>
|
|
#ifdef __GNUWIN32__
|
|
#include <windows.h>
|
|
#endif
|
|
#elif defined(__DOS__)
|
|
#if defined(__WATCOMC__)
|
|
#include <io.h>
|
|
#elif defined(__DJGPP__)
|
|
#include <io.h>
|
|
#include <unistd.h>
|
|
#include <stdio.h>
|
|
#else
|
|
#error "Please specify the header with file functions declarations."
|
|
#endif
|
|
#elif (defined(__WXPM__))
|
|
#include <io.h>
|
|
#define W_OK 2
|
|
#define R_OK 4
|
|
#elif (defined(__WXSTUBS__))
|
|
// Have to ifdef this for different environments
|
|
#include <io.h>
|
|
#elif (defined(__WXMAC__))
|
|
#if __MSL__ < 0x6000
|
|
int access( const char *path, int mode ) { return 0 ; }
|
|
#else
|
|
int _access( const char *path, int mode ) { return 0 ; }
|
|
#endif
|
|
char* mktemp( char * path ) { return path ;}
|
|
#include <stat.h>
|
|
#define W_OK 2
|
|
#define R_OK 4
|
|
#include <unistd.h>
|
|
#else
|
|
#error "Please specify the header with file functions declarations."
|
|
#endif //Win/UNIX
|
|
|
|
#include <stdio.h> // SEEK_xxx constants
|
|
#include <fcntl.h> // O_RDONLY &c
|
|
|
|
#ifndef __MWERKS__
|
|
#include <sys/types.h> // needed for stat
|
|
#include <sys/stat.h> // stat
|
|
#elif ( defined(__MWERKS__) && defined(__WXMSW__) )
|
|
#include <sys/types.h> // needed for stat
|
|
#include <sys/stat.h> // stat
|
|
#endif
|
|
|
|
#if defined(__BORLANDC__) || defined(_MSC_VER)
|
|
#define W_OK 2
|
|
#define R_OK 4
|
|
#endif
|
|
|
|
// there is no distinction between text and binary files under Unix, so define
|
|
// O_BINARY as 0 if the system headers don't do it already
|
|
#if defined(__UNIX__) && !defined(O_BINARY)
|
|
#define O_BINARY (0)
|
|
#endif //__UNIX__
|
|
|
|
#ifdef __SALFORDC__
|
|
#include <unix.h>
|
|
#endif
|
|
|
|
#ifndef MAX_PATH
|
|
#define MAX_PATH 512
|
|
#endif
|
|
|
|
// some broken compilers don't have 3rd argument in open() and creat()
|
|
#ifdef __SALFORDC__
|
|
#define ACCESS(access)
|
|
#define stat _stat
|
|
#else // normal compiler
|
|
#define ACCESS(access) , (access)
|
|
#endif // Salford C
|
|
|
|
// wxWindows
|
|
#ifndef WX_PRECOMP
|
|
#include "wx/string.h"
|
|
#include "wx/intl.h"
|
|
#include "wx/log.h"
|
|
#endif // !WX_PRECOMP
|
|
|
|
#include "wx/filename.h"
|
|
#include "wx/file.h"
|
|
|
|
#ifdef __WXMSW__
|
|
#include "wx/msw/mslu.h"
|
|
#endif
|
|
|
|
// ============================================================================
|
|
// implementation of wxFile
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// static functions
|
|
// ----------------------------------------------------------------------------
|
|
bool wxFile::Exists(const wxChar *name)
|
|
{
|
|
wxStructStat st;
|
|
return !wxAccess(name, 0) &&
|
|
!wxStat(name, &st) &&
|
|
(st.st_mode & S_IFREG);
|
|
}
|
|
|
|
bool wxFile::Access(const wxChar *name, OpenMode mode)
|
|
{
|
|
int how = 0;
|
|
|
|
switch ( mode ) {
|
|
case read:
|
|
how = R_OK;
|
|
break;
|
|
|
|
case write:
|
|
how = W_OK;
|
|
break;
|
|
|
|
default:
|
|
wxFAIL_MSG(wxT("bad wxFile::Access mode parameter."));
|
|
}
|
|
|
|
return wxAccess( name, how) == 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// opening/closing
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// ctors
|
|
wxFile::wxFile(const wxChar *szFileName, OpenMode mode)
|
|
{
|
|
m_fd = fd_invalid;
|
|
m_error = FALSE;
|
|
|
|
Open(szFileName, mode);
|
|
}
|
|
|
|
// create the file, fail if it already exists and bOverwrite
|
|
bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode)
|
|
{
|
|
// if bOverwrite we create a new file or truncate the existing one,
|
|
// otherwise we only create the new file and fail if it already exists
|
|
#if defined(__WXMAC__) && !defined(__UNIX__)
|
|
// Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace
|
|
// int fd = open(wxUnix2MacFilename( szFileName ), O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access);
|
|
int fd = creat( szFileName , accessMode);
|
|
#else
|
|
int fd = wxOpen( szFileName,
|
|
O_BINARY | O_WRONLY | O_CREAT |
|
|
(bOverwrite ? O_TRUNC : O_EXCL)
|
|
ACCESS(accessMode) );
|
|
#endif
|
|
if ( fd == -1 )
|
|
{
|
|
wxLogSysError(_("can't create file '%s'"), szFileName);
|
|
return FALSE;
|
|
}
|
|
else
|
|
{
|
|
Attach(fd);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// open the file
|
|
bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode)
|
|
{
|
|
int flags = O_BINARY;
|
|
|
|
switch ( mode )
|
|
{
|
|
case read:
|
|
flags |= O_RDONLY;
|
|
break;
|
|
|
|
case write_append:
|
|
if ( wxFile::Exists(szFileName) )
|
|
{
|
|
flags |= O_WRONLY | O_APPEND;
|
|
break;
|
|
}
|
|
//else: fall through as write_append is the same as write if the
|
|
// file doesn't exist
|
|
|
|
case write:
|
|
flags |= O_WRONLY | O_CREAT | O_TRUNC;
|
|
break;
|
|
|
|
case write_excl:
|
|
flags |= O_WRONLY | O_CREAT | O_EXCL;
|
|
break;
|
|
|
|
case read_write:
|
|
flags |= O_RDWR;
|
|
break;
|
|
}
|
|
|
|
int fd = wxOpen( szFileName, flags ACCESS(accessMode));
|
|
if ( fd == -1 )
|
|
{
|
|
wxLogSysError(_("can't open file '%s'"), szFileName);
|
|
return FALSE;
|
|
}
|
|
else {
|
|
Attach(fd);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
// close
|
|
bool wxFile::Close()
|
|
{
|
|
if ( IsOpened() ) {
|
|
if ( close(m_fd) == -1 ) {
|
|
wxLogSysError(_("can't close file descriptor %d"), m_fd);
|
|
m_fd = fd_invalid;
|
|
return FALSE;
|
|
}
|
|
else
|
|
m_fd = fd_invalid;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// read/write
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// read
|
|
off_t wxFile::Read(void *pBuf, off_t nCount)
|
|
{
|
|
wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
|
|
|
|
#ifdef __MWERKS__
|
|
int iRc = ::read(m_fd, (char*) pBuf, nCount);
|
|
#else
|
|
int iRc = ::read(m_fd, pBuf, nCount);
|
|
#endif
|
|
if ( iRc == -1 ) {
|
|
wxLogSysError(_("can't read from file descriptor %d"), m_fd);
|
|
return wxInvalidOffset;
|
|
}
|
|
else
|
|
return (size_t)iRc;
|
|
}
|
|
|
|
// write
|
|
size_t wxFile::Write(const void *pBuf, size_t nCount)
|
|
{
|
|
wxCHECK( (pBuf != NULL) && IsOpened(), 0 );
|
|
|
|
#ifdef __MWERKS__
|
|
#if __MSL__ >= 0x6000
|
|
int iRc = ::write(m_fd, (void*) pBuf, nCount);
|
|
#else
|
|
int iRc = ::write(m_fd, (const char*) pBuf, nCount);
|
|
#endif
|
|
#else
|
|
int iRc = ::write(m_fd, pBuf, nCount);
|
|
#endif
|
|
if ( iRc == -1 ) {
|
|
wxLogSysError(_("can't write to file descriptor %d"), m_fd);
|
|
m_error = TRUE;
|
|
return 0;
|
|
}
|
|
else
|
|
return iRc;
|
|
}
|
|
|
|
// flush
|
|
bool wxFile::Flush()
|
|
{
|
|
if ( IsOpened() ) {
|
|
#if defined(__VISUALC__) || wxHAVE_FSYNC
|
|
if ( wxFsync(m_fd) == -1 )
|
|
{
|
|
wxLogSysError(_("can't flush file descriptor %d"), m_fd);
|
|
return FALSE;
|
|
}
|
|
#else // no fsync
|
|
// just do nothing
|
|
#endif // fsync
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// seek
|
|
// ----------------------------------------------------------------------------
|
|
|
|
// seek
|
|
off_t wxFile::Seek(off_t ofs, wxSeekMode mode)
|
|
{
|
|
wxASSERT( IsOpened() );
|
|
|
|
int origin;
|
|
switch ( mode ) {
|
|
default:
|
|
wxFAIL_MSG(_("unknown seek origin"));
|
|
|
|
case wxFromStart:
|
|
origin = SEEK_SET;
|
|
break;
|
|
|
|
case wxFromCurrent:
|
|
origin = SEEK_CUR;
|
|
break;
|
|
|
|
case wxFromEnd:
|
|
origin = SEEK_END;
|
|
break;
|
|
}
|
|
|
|
int iRc = lseek(m_fd, ofs, origin);
|
|
if ( iRc == -1 ) {
|
|
wxLogSysError(_("can't seek on file descriptor %d"), m_fd);
|
|
return wxInvalidOffset;
|
|
}
|
|
else
|
|
return (off_t)iRc;
|
|
}
|
|
|
|
// get current off_t
|
|
off_t wxFile::Tell() const
|
|
{
|
|
wxASSERT( IsOpened() );
|
|
|
|
int iRc = wxTell(m_fd);
|
|
if ( iRc == -1 ) {
|
|
wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd);
|
|
return wxInvalidOffset;
|
|
}
|
|
else
|
|
return (off_t)iRc;
|
|
}
|
|
|
|
// get current file length
|
|
off_t wxFile::Length() const
|
|
{
|
|
wxASSERT( IsOpened() );
|
|
|
|
#ifdef __VISUALC__
|
|
int iRc = _filelength(m_fd);
|
|
#else // !VC++
|
|
int iRc = wxTell(m_fd);
|
|
if ( iRc != -1 ) {
|
|
// @ have to use const_cast :-(
|
|
int iLen = ((wxFile *)this)->SeekEnd();
|
|
if ( iLen != -1 ) {
|
|
// restore old position
|
|
if ( ((wxFile *)this)->Seek(iRc) == -1 ) {
|
|
// error
|
|
iLen = -1;
|
|
}
|
|
}
|
|
|
|
iRc = iLen;
|
|
}
|
|
#endif // VC++
|
|
|
|
if ( iRc == -1 ) {
|
|
wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd);
|
|
return wxInvalidOffset;
|
|
}
|
|
else
|
|
return (off_t)iRc;
|
|
}
|
|
|
|
// is end of file reached?
|
|
bool wxFile::Eof() const
|
|
{
|
|
wxASSERT( IsOpened() );
|
|
|
|
int iRc;
|
|
|
|
#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__)
|
|
// @@ this doesn't work, of course, on unseekable file descriptors
|
|
off_t ofsCur = Tell(),
|
|
ofsMax = Length();
|
|
if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset )
|
|
iRc = -1;
|
|
else
|
|
iRc = ofsCur == ofsMax;
|
|
#else // Windows and "native" compiler
|
|
iRc = eof(m_fd);
|
|
#endif // Windows/Unix
|
|
|
|
switch ( iRc ) {
|
|
case 1:
|
|
break;
|
|
|
|
case 0:
|
|
return FALSE;
|
|
|
|
case -1:
|
|
wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd);
|
|
break;
|
|
|
|
default:
|
|
wxFAIL_MSG(_("invalid eof() return value."));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// ============================================================================
|
|
// implementation of wxTempFile
|
|
// ============================================================================
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// construction
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxTempFile::wxTempFile(const wxString& strName)
|
|
{
|
|
Open(strName);
|
|
}
|
|
|
|
bool wxTempFile::Open(const wxString& strName)
|
|
{
|
|
// we must have an absolute filename because otherwise CreateTempFileName()
|
|
// would create the temp file in $TMP (i.e. the system standard location
|
|
// for the temp files) which might be on another volume/drive/mount and
|
|
// wxRename()ing it later to m_strName from Commit() would then fail
|
|
//
|
|
// with the absolute filename, the temp file is created in the same
|
|
// directory as this one which ensures that wxRename() may work later
|
|
wxFileName fn(strName);
|
|
if ( !fn.IsAbsolute() )
|
|
{
|
|
fn.Normalize(wxPATH_NORM_ABSOLUTE);
|
|
}
|
|
|
|
m_strName = fn.GetFullPath();
|
|
|
|
m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file);
|
|
|
|
if ( m_strTemp.empty() )
|
|
{
|
|
// CreateTempFileName() failed
|
|
return FALSE;
|
|
}
|
|
|
|
#ifdef __UNIX__
|
|
// the temp file should have the same permissions as the original one
|
|
mode_t mode;
|
|
|
|
wxStructStat st;
|
|
if ( stat(m_strName.fn_str(), &st) == 0 )
|
|
{
|
|
mode = st.st_mode;
|
|
}
|
|
else
|
|
{
|
|
// file probably didn't exist, just give it the default mode _using_
|
|
// user's umask (new files creation should respect umask)
|
|
mode_t mask = umask(0777);
|
|
mode = 0666 & ~mask;
|
|
umask(mask);
|
|
}
|
|
|
|
if ( chmod(m_strTemp.mb_str(), mode) == -1 )
|
|
{
|
|
wxLogSysError(_("Failed to set temporary file permissions"));
|
|
}
|
|
#endif // Unix
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// destruction
|
|
// ----------------------------------------------------------------------------
|
|
|
|
wxTempFile::~wxTempFile()
|
|
{
|
|
if ( IsOpened() )
|
|
Discard();
|
|
}
|
|
|
|
bool wxTempFile::Commit()
|
|
{
|
|
m_file.Close();
|
|
|
|
if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) {
|
|
wxLogSysError(_("can't remove file '%s'"), m_strName.c_str());
|
|
return FALSE;
|
|
}
|
|
|
|
if ( wxRename(m_strTemp, m_strName) != 0 ) {
|
|
wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str());
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void wxTempFile::Discard()
|
|
{
|
|
m_file.Close();
|
|
if ( wxRemove(m_strTemp) != 0 )
|
|
wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
|
|
}
|
|
|
|
#endif // wxUSE_FILE
|
|
|