1. fixed file descriptors leak in wxFileName::CreateTempFileName()

2. really made it race-safe (provided we have mkstemp())


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13076 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2001-12-18 17:47:27 +00:00
parent 32334453e7
commit df22f86063
5 changed files with 59 additions and 32 deletions

View File

@@ -66,6 +66,8 @@ Unix ports:
All: All:
- fixes to the command line parsing error and usage messages - fixes to the command line parsing error and usage messages
- modified wxFileName::CreateTempFileName() to open the file atomically
(if possible) and, especially, not to leak the file descriptors under Unix
wxMSW: wxMSW:

View File

@@ -226,7 +226,7 @@ Set this file name object to the home directory.
\membersection{wxFileName::AssignTempFileName}\label{wxfilenameassigntempfilename} \membersection{wxFileName::AssignTempFileName}\label{wxfilenameassigntempfilename}
\func{void}{AssignTempFileName}{\param{const wxString\& }{prefix}} \func{void}{AssignTempFileName}{\param{const wxString\& }{prefix}, \param{wxFile *}{fileTemp = {\tt NULL}}}
The function calls \helpref{CreateTempFileName}{wxfilenamecreatetempfilename} to The function calls \helpref{CreateTempFileName}{wxfilenamecreatetempfilename} to
create a temporary file and sets this object to the name of the file. If a create a temporary file and sets this object to the name of the file. If a
@@ -241,16 +241,28 @@ Reset all components to default, uninitialized state.
\membersection{wxFileName::CreateTempFileName}\label{wxfilenamecreatetempfilename} \membersection{wxFileName::CreateTempFileName}\label{wxfilenamecreatetempfilename}
\func{static wxString}{CreateTempFileName}{\param{const wxString\& }{prefix}} \func{static wxString}{CreateTempFileName}{\param{const wxString\& }{prefix}, \param{wxFile *}{fileTemp = {\tt NULL}}}
Returns a temporary file name starting with the given {\it prefix}. If Returns a temporary file name starting with the given {\it prefix}. If
the {\it prefix} is an absolute path, the temporary file is created in this the {\it prefix} is an absolute path, the temporary file is created in this
directory, otherwise it is created in the default system directory for the directory, otherwise it is created in the default system directory for the
temporary files or in the current directory. temporary files or in the current directory.
If the function succeeds, the temporary file is actually created (but not If the function succeeds, the temporary file is actually created. If\rtfsp
opened) as well. Under Unix, it will have read and write permissions for the {\it fileTemp} is not {\tt NULL}, this file will be opened using the name of
owner only. the temporary file. When possible, this is done in an atomic way ensuring that
no race condition occurs between the temporary file name generation and opening
it which could often lead to security compromise on the multiuser systems.
If {\it fileTemp} is {\tt NULL}, the file is only created, but not opened.
Under Unix, the temporary file will have read and write permissions for the
owner only to minimize the security problems.
\wxheading{Parameters}
\docparam{prefix}{Prefix to use for the temporary file name construction}
\docparam{fileTemp}{The file to open or {\tt NULL} to just get the name}
\wxheading{Return value} \wxheading{Return value}

View File

@@ -38,6 +38,8 @@
#include "wx/filefn.h" #include "wx/filefn.h"
#include "wx/datetime.h" #include "wx/datetime.h"
class WXDLLEXPORT wxFile;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// constants // constants
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -208,9 +210,12 @@ public:
void AssignHomeDir(); void AssignHomeDir();
static wxString GetHomeDir(); static wxString GetHomeDir();
// get a temp file name starting with the specified prefix // get a temp file name starting with the specified prefix and open the
void AssignTempFileName(const wxString& prefix); // file passed to us using this name for writing (atomically if
static wxString CreateTempFileName(const wxString& prefix); // possible)
void AssignTempFileName(const wxString& prefix, wxFile *fileTemp = NULL);
static wxString CreateTempFileName(const wxString& prefix,
wxFile *fileTemp = NULL);
// directory creation and removal. // directory creation and removal.
// if full is TRUE, will try to make each directory in the path. // if full is TRUE, will try to make each directory in the path.

View File

@@ -478,7 +478,7 @@ bool wxTempFile::Open(const wxString& strName)
{ {
m_strName = strName; m_strName = strName;
m_strTemp = wxFileName::CreateTempFileName(strName); m_strTemp = wxFileName::CreateTempFileName(strName, &m_file);
if ( m_strTemp.empty() ) if ( m_strTemp.empty() )
{ {
@@ -486,13 +486,6 @@ bool wxTempFile::Open(const wxString& strName)
return FALSE; return FALSE;
} }
// actually open the file now (it must already exist)
if ( !m_file.Open(m_strTemp, wxFile::write) )
{
// opening existing file failed?
return FALSE;
}
#ifdef __UNIX__ #ifdef __UNIX__
// the temp file should have the same permissions as the original one // the temp file should have the same permissions as the original one
mode_t mode; mode_t mode;

View File

@@ -456,9 +456,9 @@ wxString wxFileName::GetHomeDir()
return ::wxGetHomeDir(); return ::wxGetHomeDir();
} }
void wxFileName::AssignTempFileName( const wxString& prefix ) void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp)
{ {
wxString tempname = CreateTempFileName(prefix); wxString tempname = CreateTempFileName(prefix, fileTemp);
if ( tempname.empty() ) if ( tempname.empty() )
{ {
// error, failed to get temp file name // error, failed to get temp file name
@@ -471,7 +471,8 @@ void wxFileName::AssignTempFileName( const wxString& prefix )
} }
/* static */ /* static */
wxString wxFileName::CreateTempFileName(const wxString& prefix) wxString
wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
{ {
wxString path, dir, name; wxString path, dir, name;
@@ -558,13 +559,25 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
// can use the cast here because the length doesn't change and the string // can use the cast here because the length doesn't change and the string
// is not shared // is not shared
if ( mkstemp((char *)path.mb_str()) == -1 ) int fdTemp = mkstemp((char *)path.mb_str());
if ( fdTemp == -1 )
{ {
// this might be not necessary as mkstemp() on most systems should have // this might be not necessary as mkstemp() on most systems should have
// already done it but it doesn't hurt neither... // already done it but it doesn't hurt neither...
path.clear(); path.clear();
} }
//else: file already created else // mkstemp() succeeded
{
// avoid leaking the fd
if ( fileTemp )
{
fileTemp->Attach(fdTemp);
}
else
{
close(fdTemp);
}
}
#else // !HAVE_MKSTEMP #else // !HAVE_MKSTEMP
#ifdef HAVE_MKTEMP #ifdef HAVE_MKTEMP
@@ -601,10 +614,20 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
if ( !path.empty() ) if ( !path.empty() )
{ {
// create the file - of course, there is a race condition here, this is }
#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
#endif // Windows/!Windows
if ( path.empty() )
{
wxLogSysError(_("Failed to create a temporary file name"));
}
else if ( fileTemp && !fileTemp->IsOpened() )
{
// open the file - of course, there is a race condition here, this is
// why we always prefer using mkstemp()... // why we always prefer using mkstemp()...
wxFile file; if ( !fileTemp->Open(path, wxFile::write_excl, wxS_IRUSR | wxS_IWUSR) )
if ( !file.Open(path, wxFile::write_excl, wxS_IRUSR | wxS_IWUSR) )
{ {
// FIXME: If !ok here should we loop and try again with another // FIXME: If !ok here should we loop and try again with another
// file name? That is the standard recourse if open(O_EXCL) // file name? That is the standard recourse if open(O_EXCL)
@@ -616,14 +639,6 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix)
path.clear(); path.clear();
} }
} }
#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
#endif // Windows/!Windows
if ( path.empty() )
{
wxLogSysError(_("Failed to create a temporary file name"));
}
return path; return path;
} }