All:
- 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:
\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
create a temporary file and sets this object to the name of the file. If a
\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
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
temporary files or in the current directory.
-If the function succeeds, the temporary file is actually created (but not
-opened) as well. Under Unix, it will have read and write permissions for the
-owner only.
+If the function succeeds, the temporary file is actually created. If\rtfsp
+{\it fileTemp} is not {\tt NULL}, this file will be opened using the name of
+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}
#include "wx/filefn.h"
#include "wx/datetime.h"
+class WXDLLEXPORT wxFile;
+
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
void AssignHomeDir();
static wxString GetHomeDir();
- // get a temp file name starting with the specified prefix
- void AssignTempFileName(const wxString& prefix);
- static wxString CreateTempFileName(const wxString& prefix);
+ // get a temp file name starting with the specified prefix and open the
+ // file passed to us using this name for writing (atomically if
+ // possible)
+ void AssignTempFileName(const wxString& prefix, wxFile *fileTemp = NULL);
+ static wxString CreateTempFileName(const wxString& prefix,
+ wxFile *fileTemp = NULL);
// directory creation and removal.
// if full is TRUE, will try to make each directory in the path.
{
m_strName = strName;
- m_strTemp = wxFileName::CreateTempFileName(strName);
+ m_strTemp = wxFileName::CreateTempFileName(strName, &m_file);
if ( m_strTemp.empty() )
{
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__
// the temp file should have the same permissions as the original one
mode_t mode;
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() )
{
// error, failed to get temp file name
}
/* static */
-wxString wxFileName::CreateTempFileName(const wxString& prefix)
+wxString
+wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp)
{
wxString path, dir, name;
// can use the cast here because the length doesn't change and the string
// 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
// already done it but it doesn't hurt neither...
path.clear();
}
- //else: file already created
+ else // mkstemp() succeeded
+ {
+ // avoid leaking the fd
+ if ( fileTemp )
+ {
+ fileTemp->Attach(fdTemp);
+ }
+ else
+ {
+ close(fdTemp);
+ }
+ }
#else // !HAVE_MKSTEMP
#ifdef HAVE_MKTEMP
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()...
- wxFile file;
- if ( !file.Open(path, wxFile::write_excl, wxS_IRUSR | wxS_IWUSR) )
+ if ( !fileTemp->Open(path, wxFile::write_excl, wxS_IRUSR | wxS_IWUSR) )
{
// FIXME: If !ok here should we loop and try again with another
// file name? That is the standard recourse if open(O_EXCL)
path.clear();
}
}
-#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
-
-#endif // Windows/!Windows
-
- if ( path.empty() )
- {
- wxLogSysError(_("Failed to create a temporary file name"));
- }
return path;
}