Files
wxWidgets/src/common/file.cpp
Robert Roebling 92980e9076 Changed wxStat, wxAccess and wxOpen to no longer
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
2002-08-08 21:44:50 +00:00

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