1. added wxFileName::CreateTempFileName() and implemented it properly (using

mkstemp() when available)
2. wxTempFile::Open() and wxGetTempFileName() now use CreateTempFileName()
   avoiding code duplication
3. updated the docs


git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@12805 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2001-12-01 17:18:11 +00:00
parent 1d21855083
commit ade35f11fe
11 changed files with 543 additions and 352 deletions

468
configure vendored

File diff suppressed because it is too large Load Diff

View File

@@ -3055,6 +3055,9 @@ fi
dnl check for vfork() (even if it's the same as fork() in modern Unices)
AC_CHECK_FUNCS(vfork)
dnl check for the function for temp files creation
AC_CHECK_FUNCS(mkstemp mktemp, break)
dnl get the library function to use for wxGetDiskSpace(): it is statfs() under
dnl Linux and *BSD and statvfs() under Solaris
AC_CACHE_CHECK(for statfs, wx_cv_func_statfs,

View File

@@ -234,15 +234,33 @@ get the value of user home (Unix only mainly)
\func{void}{AssignTempFileName}{\param{const wxString\& }{prefix}}
get a temp file name starting with thespecified prefix
The function calls \helpref{CreateTempFileName}{wxfilenamecreatetempfilename} to
create a temporary file and sets this object to the name of the file. If a
temporary file couldn't be created, the object is put into the\rtfsp
\helpref{invalid}{wxfilenameisok} state.
\membersection{wxFileName::Clear}\label{wxfilenameclear}
\func{void}{Clear}{\void}
reset all components to default, uninitialized state
Reset all components to default, uninitialized state.
\membersection{wxFileName::CreateTempFileName}{wxfilenamecreatetempfilename}
\func{static wxString}{CreateTempFileName}{\param{const wxString\& }{prefix}}
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.
\wxheading{Return value}
The full temporary file name or an empty string on error.
\membersection{wxFileName::DirExists}\label{wxfilenamedirexists}
@@ -443,9 +461,10 @@ are the file names of this type cases sensitive?
\constfunc{bool}{IsOk}{\void}
file tests
is the filename valid at all?
Returns {\tt TRUE} if the filename is valid, {\tt FALSE} if it is not
initialized yet. The assignment functions and
\helpref{Clear}{wxfilenameclear} may reset the object to the uninitialized,
invalid state (the former only do it on failure).
\membersection{wxFileName::IsPathSeparator}\label{wxfilenameispathseparator}

View File

@@ -265,15 +265,19 @@ if the buffer is NULL.
\func{bool}{wxGetTempFileName}{\param{const wxString\& }{prefix}, \param{wxString\& }{buf}}
Makes a temporary filename based on {\it prefix}, opens and closes the file,
and places the name in {\it buf}. If {\it buf} is NULL, new store
is allocated for the temporary filename using {\it new}.
%% Makes a temporary filename based on {\it prefix}, opens and closes the file,
%% and places the name in {\it buf}. If {\it buf} is NULL, new store
%% is allocated for the temporary filename using {\it new}.
%%
%% Under Windows, the filename will include the drive and name of the
%% directory allocated for temporary files (usually the contents of the
%% TEMP variable). Under Unix, the {\tt /tmp} directory is used.
%%
%% It is the application's responsibility to create and delete the file.
Under Windows, the filename will include the drive and name of the
directory allocated for temporary files (usually the contents of the
TEMP variable). Under Unix, the {\tt /tmp} directory is used.
It is the application's responsibility to create and delete the file.
These functions are obsolete, please use\rtfsp
\helpref{wxFileName::CreateTempFileName}{wxfilenamecreatetempfilename}\rtfsp
instead.
\membersection{::wxIsWild}\label{wxiswild}

View File

@@ -185,7 +185,7 @@ WXDLLEXPORT wxString wxUnix2MacFilename( const char *s);
WXDLLEXPORT void wxStripExtension(wxChar *buffer);
WXDLLEXPORT void wxStripExtension(wxString& buffer);
// Get a temporary filename, opening and closing the file.
// Get a temporary filename
WXDLLEXPORT wxChar* wxGetTempFileName(const wxString& prefix, wxChar *buf = (wxChar *) NULL);
WXDLLEXPORT bool wxGetTempFileName(const wxString& prefix, wxString& buf);
@@ -197,8 +197,8 @@ WXDLLEXPORT bool wxExpandPath(wxString& dest, const wxChar *path);
// and make (if under the home tree) relative to home
// [caller must copy-- volatile]
WXDLLEXPORT wxChar* wxContractPath(const wxString& filename,
const wxString& envname = wxEmptyString,
const wxString& user = wxEmptyString);
const wxString& envname = wxEmptyString,
const wxString& user = wxEmptyString);
// Destructive removal of /./ and /../ stuff
WXDLLEXPORT wxChar* wxRealPath(wxChar *path);

View File

@@ -200,8 +200,9 @@ public:
void AssignHomeDir();
static wxString GetHomeDir();
// get a temp file name starting with thespecified prefix
void AssignTempFileName( const wxString &prefix );
// get a temp file name starting with the specified prefix
void AssignTempFileName(const wxString& prefix);
static wxString CreateTempFileName(const wxString& prefix);
// directory creation and removal.
// if full is TRUE, will try to make each directory in the path.

View File

@@ -844,6 +844,35 @@ static void TestFileNameSplit()
}
}
static void TestFileNameTemp()
{
puts("*** testing wxFileName temp file creation ***");
static const char *tmpprefixes[] =
{
"foo",
"/tmp/foo",
"..",
"../bar",
"/tmp/foo/bar", // this one must be an error
};
for ( size_t n = 0; n < WXSIZEOF(tmpprefixes); n++ )
{
wxString path = wxFileName::CreateTempFileName(tmpprefixes[n]);
if ( !path.empty() )
{
printf("Prefix '%s'\t-> temp file '%s'\n",
tmpprefixes[n], path.c_str());
if ( !wxRemoveFile(path) )
{
wxLogWarning("Failed to remove temp file '%s'", path.c_str());
}
}
}
}
static void TestFileNameComparison()
{
// TODO!
@@ -5187,10 +5216,11 @@ int main(int argc, char **argv)
#endif // TEST_FILE
#ifdef TEST_FILENAME
TestFileNameConstruction();
TestFileNameSplit();
TestFileNameTemp();
if ( 0 )
{
TestFileNameConstruction();
TestFileNameSplit();
TestFileNameCwd();
TestFileNameComparison();
TestFileNameOperations();

View File

@@ -964,6 +964,12 @@
/* Define if you have the inet_aton function. */
#undef HAVE_INET_ATON
/* Define if you have the mktemp function. */
#undef HAVE_MKTEMP
/* Define if you have the mkstemp function. */
#undef HAVE_MKSTEMP
/* Define if you have the nanosleep function. */
#undef HAVE_NANOSLEEP

View File

@@ -54,7 +54,6 @@
#define NOMCX
#endif
#include <windows.h> // for GetTempFileName
#elif (defined(__UNIX__) || defined(__GNUWIN32__))
#include <unistd.h>
#ifdef __GNUWIN32__
@@ -121,10 +120,14 @@
#endif // Salford C
// wxWindows
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/file.h"
#include "wx/log.h"
#ifndef WX_PRECOMP
#include "wx/string.h"
#include "wx/intl.h"
#include "wx/file.h"
#include "wx/log.h"
#endif // !WX_PRECOMP
#include "wx/filename.h"
// ============================================================================
// implementation of wxFile
@@ -465,87 +468,39 @@ bool wxTempFile::Open(const wxString& strName)
{
m_strName = strName;
// we want to create the file in the same directory as strName because
// otherwise rename() in Commit() might not work (if the files are on
// different partitions for example). Unfortunately, the only standard
// (POSIX) temp file creation function tmpnam() can't do it.
#if defined(__UNIX__) || defined(__WXSTUBS__)|| defined( __WXMAC__ )
static const wxChar *szMktempSuffix = wxT("XXXXXX");
m_strTemp << strName << szMktempSuffix;
// can use the cast because length doesn't change
mktemp(wxMBSTRINGCAST m_strTemp.mb_str());
#elif defined(__WXPM__)
// for now just create a file
// future enhancements can be to set some extended attributes for file systems
// OS/2 supports that have them (HPFS, FAT32) and security (HPFS386)
static const wxChar *szMktempSuffix = wxT("XXX");
m_strTemp << strName << szMktempSuffix;
// Temporarily remove - MN
#ifndef __WATCOMC__
::DosCreateDir(m_strTemp.GetWriteBuf(MAX_PATH), NULL);
#endif
#else // Windows
wxString strPath;
wxSplitPath(strName, &strPath, NULL, NULL);
if ( strPath.IsEmpty() )
strPath = wxT('.'); // GetTempFileName will fail if we give it empty string
#ifdef __WIN32__
if ( !GetTempFileName(strPath, wxT("wx_"),0, m_strTemp.GetWriteBuf(MAX_PATH)) )
#else
// Not sure why MSVC++ 1.5 header defines first param as BYTE - bug?
if ( !GetTempFileName((BYTE) (DWORD)(const wxChar*) strPath, wxT("wx_"),0, m_strTemp.GetWriteBuf(MAX_PATH)) )
#endif
wxLogLastError(wxT("GetTempFileName"));
m_strTemp.UngetWriteBuf();
#endif // Windows/Unix
m_strTemp = wxFileName::CreateTempFileName(strName);
if ( m_strTemp.empty() )
{
// CreateTempFileName() failed
return FALSE;
}
int access = wxS_DEFAULT;
#ifdef __UNIX__
// create the file with the same mode as the original one under Unix
mode_t umaskOld = 0; // just to suppress compiler warning
bool changedUmask;
// the temp file should have the same permissions as the original one
mode_t mode;
wxStructStat st;
if ( stat(strName.fn_str(), &st) == 0 )
{
// this assumes that only lower bits of st_mode contain the access
// rights, but it's true for at least all Unices which have S_IXXXX()
// macros, so should not be less portable than using (not POSIX)
// S_IFREG &c
access = st.st_mode & 0777;
// we want to create the file with exactly the same access rights as
// the original one, so disable the user's umask for the moment
umaskOld = umask(0);
changedUmask = TRUE;
mode = st.st_mode;
}
else
{
// file probably didn't exist, just create with default mode _using_
// file probably didn't exist, just give it the default mode _using_
// user's umask (new files creation should respect umask)
changedUmask = FALSE;
mode_t mask = umask(0777);
mode = 0666 & ~mask;
umask(mask);
}
#endif // Unix
// Open this file securely, since it surely should not exist unless
// nefarious activities (or other random bad things) are at play.
bool ok = m_file.Open(m_strTemp, wxFile::write_excl, access);
// FIXME: If !ok here should we loop and try again with another file
// name? That is the standard recourse if open(O_EXCL) fails,
// though of course it should be protected against possible
// infinite looping too.
#ifdef __UNIX__
if ( changedUmask )
if ( chmod(m_strTemp.mb_str(), mode) == -1 )
{
// restore umask now that the file is created
(void)umask(umaskOld);
wxLogSysError(_("Failed to set temporary file permissions"));
}
#endif // Unix
return ok;
return TRUE;
}
// ----------------------------------------------------------------------------
@@ -582,5 +537,5 @@ void wxTempFile::Discard()
wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str());
}
#endif
#endif // wxUSE_FILE

View File

@@ -1262,59 +1262,23 @@ bool wxPathExists(const wxChar *pszPathName)
// Get a temporary filename, opening and closing the file.
wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf)
{
#if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
wxString filename = wxFileName::CreateTempFileName(prefix);
if ( filename.empty() )
return NULL;
#ifndef __WIN32__
wxChar tmp[144];
::GetTempFileName(0, WXSTRINGCAST prefix, 0, tmp);
#else
wxChar tmp[MAX_PATH];
wxChar tmpPath[MAX_PATH];
::GetTempPath(MAX_PATH, tmpPath);
::GetTempFileName(tmpPath, WXSTRINGCAST prefix, 0, tmp);
#endif
if (buf) wxStrcpy(buf, tmp);
else buf = copystring(tmp);
return buf;
if ( buf )
wxStrcpy(buf, filename);
else
buf = copystring(filename);
#else
static short last_temp = 0; // cache last to speed things a bit
// At most 1000 temp files to a process! We use a ring count.
wxChar tmp[100]; // FIXME static buffer
for (short suffix = last_temp + 1; suffix != last_temp; ++suffix %= 1000)
{
wxSprintf (tmp, wxT("/tmp/%s%d.%03x"), WXSTRINGCAST prefix, (int) getpid (), (int) suffix);
if (!wxFileExists( tmp ))
{
// Touch the file to create it (reserve name)
FILE *fd = fopen (wxFNCONV(tmp), "w");
if (fd)
fclose (fd);
last_temp = suffix;
if (buf)
wxStrcpy( buf, tmp);
else
buf = copystring( tmp );
return buf;
}
}
wxLogError( _("wxWindows: error finding temporary file name.\n") );
if (buf) buf[0] = 0;
return (wxChar *) NULL;
#endif
return buf;
}
bool wxGetTempFileName(const wxString& prefix, wxString& buf)
{
wxChar buf2[512];
if (wxGetTempFileName(prefix, buf2) != (wxChar*) NULL)
{
buf = buf2;
return TRUE;
}
else
return FALSE;
buf = wxFileName::CreateTempFileName(prefix);
return !buf.empty();
}
// Get first file name matching given wild card.

View File

@@ -360,17 +360,170 @@ wxString wxFileName::GetHomeDir()
return ::wxGetHomeDir();
}
void wxFileName::AssignTempFileName( const wxString &prefix )
void wxFileName::AssignTempFileName( const wxString& prefix )
{
wxString fullname;
if ( wxGetTempFileName(prefix, fullname) )
{
Assign(fullname);
}
else // error
wxString tempname = CreateTempFileName(prefix);
if ( tempname.empty() )
{
// error, failed to get temp file name
Clear();
}
else // ok
{
Assign(tempname);
}
}
/* static */
wxString wxFileName::CreateTempFileName(const wxString& prefix)
{
wxString path, dir, name;
// use the directory specified by the prefix
SplitPath(prefix, &dir, &name, NULL /* extension */);
#if defined(__WINDOWS__) && !defined(__WXMICROWIN__)
#ifdef __WIN32__
if ( dir.empty() )
{
if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) )
{
wxLogLastError(_T("GetTempPath"));
}
if ( dir.empty() )
{
// GetTempFileName() fails if we pass it an empty string
dir = _T('.');
}
}
if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) )
{
wxLogLastError(_T("GetTempFileName"));
path.clear();
}
#else // Win16
if ( !::GetTempFileName(NULL, prefix, 0, wxStringBuffer(path, 1025)) )
{
path.clear();
}
#endif // Win32/16
#elif defined(__WXPM__)
// for now just create a file
//
// future enhancements can be to set some extended attributes for file
// systems OS/2 supports that have them (HPFS, FAT32) and security
// (HPFS386)
static const wxChar *szMktempSuffix = wxT("XXX");
path << dir << _T('/') << name << szMktempSuffix;
// Temporarily remove - MN
#ifndef __WATCOMC__
::DosCreateDir(wxStringBuffer(MAX_PATH), NULL);
#endif
#else // !Windows, !OS/2
if ( dir.empty() )
{
dir = wxGetenv(_T("TMP"));
if ( path.empty() )
{
dir = wxGetenv(_T("TEMP"));
}
if ( dir.empty() )
{
// default
dir = _T("/tmp");
}
}
path = dir;
if ( !wxEndsWithPathSeparator(dir) &&
(name.empty() || !wxIsPathSeparator(name[0u])) )
{
path += _T('/');
}
path += name;
#ifdef HAVE_MKSTEMP
// scratch space for mkstemp()
path += _T("XXXXXX");
// can use the cast here because the length doesn't change and the string
// is not shared
if ( mkstemp((char *)path.mb_str()) == -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 // !HAVE_MKSTEMP
#ifdef HAVE_MKTEMP
// same as above
path += _T("XXXXXX");
if ( !mktemp((char *)path.mb_str()) )
{
path.clear();
}
#else // !HAVE_MKTEMP
// generate the unique file name ourselves
path << (unsigned int)getpid();
wxString pathTry;
static const size_t numTries = 1000;
for ( size_t n = 0; n < numTries; n++ )
{
// 3 hex digits is enough for numTries == 1000 < 4096
pathTry = path + wxString::Format(_T("%.03x"), n);
if ( !wxFile::Exists(pathTry) )
{
break;
}
pathTry.clear();
}
path = pathTry;
#endif // HAVE_MKTEMP/!HAVE_MKTEMP
if ( !path.empty() )
{
// create 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) )
{
// FIXME: If !ok here should we loop and try again with another
// file name? That is the standard recourse if open(O_EXCL)
// fails, though of course it should be protected against
// possible infinite looping too.
wxLogError(_("Failed to open temporary file."));
path.clear();
}
}
#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP
#endif // Windows/!Windows
if ( path.empty() )
{
wxLogSysError(_("Failed to create a temporary file name"));
}
return path;
}
// ----------------------------------------------------------------------------