From: Vadim Zeitlin Date: Tue, 18 Dec 2001 17:47:27 +0000 (+0000) Subject: 1. fixed file descriptors leak in wxFileName::CreateTempFileName() X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/df22f86063643de23dd02c2a77217d07b1918be1 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 --- diff --git a/docs/changes.txt b/docs/changes.txt index f17c5346fa..ada0039532 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -66,6 +66,8 @@ Unix ports: 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: diff --git a/docs/latex/wx/filename.tex b/docs/latex/wx/filename.tex index a713b4d068..36936b7d1c 100644 --- a/docs/latex/wx/filename.tex +++ b/docs/latex/wx/filename.tex @@ -226,7 +226,7 @@ Set this file name object to the home directory. \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 @@ -241,16 +241,28 @@ Reset all components to default, uninitialized state. \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} diff --git a/include/wx/filename.h b/include/wx/filename.h index 3ad1a98fa7..4128075623 100644 --- a/include/wx/filename.h +++ b/include/wx/filename.h @@ -38,6 +38,8 @@ #include "wx/filefn.h" #include "wx/datetime.h" +class WXDLLEXPORT wxFile; + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -208,9 +210,12 @@ public: 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. diff --git a/src/common/file.cpp b/src/common/file.cpp index f76cdda441..e7834e082a 100644 --- a/src/common/file.cpp +++ b/src/common/file.cpp @@ -478,7 +478,7 @@ bool wxTempFile::Open(const wxString& strName) { m_strName = strName; - m_strTemp = wxFileName::CreateTempFileName(strName); + m_strTemp = wxFileName::CreateTempFileName(strName, &m_file); if ( m_strTemp.empty() ) { @@ -486,13 +486,6 @@ bool wxTempFile::Open(const wxString& strName) 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; diff --git a/src/common/filename.cpp b/src/common/filename.cpp index 9a63058af1..397171c470 100644 --- a/src/common/filename.cpp +++ b/src/common/filename.cpp @@ -456,9 +456,9 @@ wxString wxFileName::GetHomeDir() 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 @@ -471,7 +471,8 @@ void wxFileName::AssignTempFileName( const wxString& prefix ) } /* static */ -wxString wxFileName::CreateTempFileName(const wxString& prefix) +wxString +wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) { 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 // 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 @@ -601,10 +614,20 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix) 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) @@ -616,14 +639,6 @@ wxString wxFileName::CreateTempFileName(const wxString& prefix) path.clear(); } } -#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP - -#endif // Windows/!Windows - - if ( path.empty() ) - { - wxLogSysError(_("Failed to create a temporary file name")); - } return path; }