From b70a2866d5dfc22a0888f874b4b9cd0b97a1760d Mon Sep 17 00:00:00 2001 From: Michael Wetherell Date: Mon, 23 Oct 2006 13:10:12 +0000 Subject: [PATCH] wxFileName::CreateTempFileName changes. Open the tempfiles read/write. Allow self delting temp files to be created, where the OS supports it. Add support for opening wxFFile temp files. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42277 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/filename.h | 23 ++- include/wx/private/filename.h | 56 +++++++ src/common/filename.cpp | 302 ++++++++++++++++++++++++++++++---- 3 files changed, 346 insertions(+), 35 deletions(-) create mode 100644 include/wx/private/filename.h diff --git a/include/wx/filename.h b/include/wx/filename.h index 801529327d..762237b5ae 100644 --- a/include/wx/filename.h +++ b/include/wx/filename.h @@ -32,6 +32,10 @@ class WXDLLIMPEXP_BASE wxFile; #endif +#if wxUSE_FFILE +class WXDLLIMPEXP_BASE wxFFile; +#endif + // ---------------------------------------------------------------------------- // constants // ---------------------------------------------------------------------------- @@ -266,15 +270,30 @@ public: void AssignHomeDir(); static wxString GetHomeDir(); +#if wxUSE_FILE || wxUSE_FFILE + // get a temp file name starting with the specified prefix + void AssignTempFileName(const wxString& prefix); + static wxString CreateTempFileName(const wxString& prefix); +#endif // wxUSE_FILE + #if wxUSE_FILE // 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); + void AssignTempFileName(const wxString& prefix, wxFile *fileTemp); static wxString CreateTempFileName(const wxString& prefix, - wxFile *fileTemp = NULL); + wxFile *fileTemp); #endif // wxUSE_FILE +#if wxUSE_FFILE + // 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, wxFFile *fileTemp); + static wxString CreateTempFileName(const wxString& prefix, + wxFFile *fileTemp); +#endif // wxUSE_FFILE + // directory creation and removal. bool Mkdir( int perm = 0777, int flags = 0); static bool Mkdir( const wxString &dir, int perm = 0777, int flags = 0 ); diff --git a/include/wx/private/filename.h b/include/wx/private/filename.h new file mode 100644 index 0000000000..ac2bbd3242 --- /dev/null +++ b/include/wx/private/filename.h @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: include/wx/private/filename.h +// Purpose: Internal declarations for src/common/filename.cpp +// Author: Mike Wetherell +// Modified by: +// Created: 2006-10-22 +// RCS-ID: $Id$ +// Copyright: (c) 2006 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_FILENAME_H_ +#define _WX_PRIVATE_FILENAME_H_ + +#include "wx/file.h" +#include "wx/ffile.h" + +// Self deleting temp files aren't supported on all platforms. Therefore +// rather than let these be in the API, they can be used internally to +// implement classes (e.g. wxTempFileStream), that will do the clean up when +// the OS doesn't support it. + +// Same usage as wxFileName::CreateTempFileName() with the extra parameter +// deleteOnClose. *deleteOnClose true on entry requests a file created with a +// delete on close flag, on exit the value of *deleteOnClose indicates whether +// available. + +#if wxUSE_FILE +wxString wxCreateTempFileName(const wxString& prefix, + wxFile *fileTemp, + bool *deleteOnClose = NULL); +#endif + +#if wxUSE_FFILE +wxString wxCreateTempFileName(const wxString& prefix, + wxFFile *fileTemp, + bool *deleteOnClose = NULL); +#endif + +// Returns an open temp file, if possible either an unlinked open file or one +// that will delete on close. Only returns the filename if neither was +// possible, so that the caller can delete the file when done. + +#if wxUSE_FILE +bool wxCreateTempFile(const wxString& prefix, + wxFile *fileTemp, + wxString *name); +#endif + +#if wxUSE_FFILE +bool wxCreateTempFile(const wxString& prefix, + wxFFile *fileTemp, + wxString *name); +#endif + +#endif // _WX_PRIVATE_FILENAME_H_ diff --git a/src/common/filename.cpp b/src/common/filename.cpp index b4ea82e56a..c6e42ca232 100644 --- a/src/common/filename.cpp +++ b/src/common/filename.cpp @@ -74,14 +74,13 @@ #include "wx/dynarray.h" #include "wx/intl.h" #include "wx/log.h" - #include "wx/file.h" #include "wx/utils.h" #endif #include "wx/filename.h" +#include "wx/private/filename.h" #include "wx/tokenzr.h" #include "wx/config.h" // for wxExpandEnvVars -#include "wx/file.h" #include "wx/dynlib.h" #if defined(__WIN32__) && defined(__MINGW32__) @@ -583,30 +582,118 @@ wxString wxFileName::GetHomeDir() return ::wxGetHomeDir(); } -#if wxUSE_FILE -void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp) +// ---------------------------------------------------------------------------- +// CreateTempFileName +// ---------------------------------------------------------------------------- + +#if wxUSE_FILE || wxUSE_FFILE + + +#if !defined wx_fdopen && defined HAVE_FDOPEN + #define wx_fdopen fdopen +#endif + +// NB: GetTempFileName() under Windows creates the file, so using +// O_EXCL there would fail +#ifdef __WINDOWS__ + #define wxOPEN_EXCL 0 +#else + #define wxOPEN_EXCL O_EXCL +#endif + + +#ifdef wxOpenOSFHandle +#define WX_HAVE_DELETE_ON_CLOSE +// On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags. +// +static int wxOpenWithDeleteOnClose(const wxString& filename) { - wxString tempname = CreateTempFileName(prefix, fileTemp); - if ( tempname.empty() ) - { - // error, failed to get temp file name - Clear(); - } - else // ok - { - Assign(tempname); - } + DWORD access = GENERIC_READ | GENERIC_WRITE; + + DWORD disposition = OPEN_ALWAYS; + + DWORD attributes = FILE_ATTRIBUTE_TEMPORARY | + FILE_FLAG_DELETE_ON_CLOSE; + + HANDLE h = ::CreateFile(filename, access, 0, NULL, + disposition, attributes, NULL); + + return wxOpenOSFHandle(h, 0); } +#endif // wxOpenOSFHandle -/* static */ -wxString -wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) + +// Helper to open the file +// +static int wxTempOpen(const wxString& path, bool *deleteOnClose) +{ +#ifdef WX_HAVE_DELETE_ON_CLOSE + if (*deleteOnClose) + return wxOpenWithDeleteOnClose(path); +#endif + + *deleteOnClose = false; + + return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600); +} + + +#if wxUSE_FFILE +// Helper to open the file and attach it to the wxFFile +// +static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose) { +#ifndef wx_fdopen + *deleteOnClose = false; + return file->Open(path, _T("w+b")); +#else // wx_fdopen + int fd = wxTempOpen(path, deleteOnClose); + if (fd != -1) + return false; + file->Attach(wx_fdopen(fd, "w+b")); + return file->IsOpened(); +#endif // wx_fdopen +} +#endif // wxUSE_FFILE + + +#if !wxUSE_FILE + #define WXFILEARGS(x, y) y +#elif !wxUSE_FFILE + #define WXFILEARGS(x, y) x +#else + #define WXFILEARGS(x, y) x, y +#endif + + +// Implementation of wxFileName::CreateTempFileName(). +// +static wxString wxCreateTempImpl( + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), + bool *deleteOnClose = NULL) +{ +#if wxUSE_FILE && wxUSE_FFILE + wxASSERT(fileTemp == NULL || ffileTemp == NULL); +#endif wxString path, dir, name; + bool wantDeleteOnClose = false; + + if (deleteOnClose) + { + // set the result to false initially + wantDeleteOnClose = *deleteOnClose; + *deleteOnClose = false; + } + else + { + // easier if it alwasys points to something + deleteOnClose = &wantDeleteOnClose; + } // use the directory specified by the prefix - SplitPath(prefix, &dir, &name, NULL /* extension */); + wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */); if (dir.empty()) { @@ -625,12 +712,12 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) if (dir.empty()) { // FIXME. Create \temp dir? - if (DirExists(wxT("\\temp"))) + if (wxFileName::DirExists(wxT("\\temp"))) dir = wxT("\\temp"); } path = dir + wxT("\\") + name; int i = 1; - while (FileExists(path)) + while (wxFileName::FileExists(path)) { path = dir + wxT("\\") + name ; path << i; @@ -708,12 +795,28 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) { path = wxConvFile.cMB2WX( (const char*) buf ); + #if wxUSE_FILE // avoid leaking the fd if ( fileTemp ) { fileTemp->Attach(fdTemp); } else + #endif + + #if wxUSE_FFILE + if ( ffileTemp ) + { + #ifdef wx_fdopen + ffileTemp->Attach(wx_fdopen(fdTemp, "r+b")); + #else + ffileTemp->Open(path, _T("r+b")); + close(fdTemp); + #endif + } + else + #endif + { close(fdTemp); } @@ -725,7 +828,7 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) path += _T("XXXXXX"); wxCharBuffer buf = wxConvFile.cWX2MB( path ); - if ( !mktemp( (const char*) buf ) ) + if ( !mktemp( (char*)(const char*) buf ) ) { path.clear(); } @@ -746,7 +849,7 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) { // 3 hex digits is enough for numTries == 1000 < 4096 pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n); - if ( !FileExists(pathTry) ) + if ( !wxFileName::FileExists(pathTry) ) { break; } @@ -765,20 +868,33 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) { wxLogSysError(_("Failed to create a temporary file name")); } - else if ( fileTemp && !fileTemp->IsOpened() ) + else { + bool ok = true; + // open the file - of course, there is a race condition here, this is // why we always prefer using mkstemp()... - // - // NB: GetTempFileName() under Windows creates the file, so using - // write_excl there would fail - if ( !fileTemp->Open(path, -#if defined(__WINDOWS__) && !defined(__WXMICROWIN__) - wxFile::write, -#else - wxFile::write_excl, -#endif - wxS_IRUSR | wxS_IWUSR) ) + #if wxUSE_FILE + if ( fileTemp && !fileTemp->IsOpened() ) + { + *deleteOnClose = wantDeleteOnClose; + int fd = wxTempOpen(path, deleteOnClose); + if (fd != -1) + fileTemp->Attach(fd); + else + ok = false; + } + #endif + + #if wxUSE_FFILE + if ( ffileTemp && !ffileTemp->IsOpened() ) + { + *deleteOnClose = wantDeleteOnClose; + ok = wxTempOpen(ffileTemp, path, deleteOnClose); + } + #endif + + if ( !ok ) { // FIXME: If !ok here should we loop and try again with another // file name? That is the standard recourse if open(O_EXCL) @@ -794,8 +910,128 @@ wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) return path; } + +static bool wxCreateTempImpl( + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), + wxString *name) +{ + bool deleteOnClose = true; + + *name = wxCreateTempImpl(prefix, + WXFILEARGS(fileTemp, ffileTemp), + &deleteOnClose); + + bool ok = !name->empty(); + + if (deleteOnClose) + name->clear(); +#ifdef __UNIX__ + else if (ok && wxRemoveFile(*name)) + name->clear(); +#endif + + return ok; +} + + +static void wxAssignTempImpl( + wxFileName *fn, + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp)) +{ + wxString tempname; + tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp)); + + if ( tempname.empty() ) + { + // error, failed to get temp file name + fn->Clear(); + } + else // ok + { + fn->Assign(tempname); + } +} + + +void wxFileName::AssignTempFileName(const wxString& prefix) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL)); +} + +/* static */ +wxString wxFileName::CreateTempFileName(const wxString& prefix) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL)); +} + +#endif // wxUSE_FILE || wxUSE_FFILE + + +#if wxUSE_FILE + +wxString wxCreateTempFileName(const wxString& prefix, + wxFile *fileTemp, + bool *deleteOnClose) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose); +} + +bool wxCreateTempFile(const wxString& prefix, + wxFile *fileTemp, + wxString *name) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name); +} + +void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL)); +} + +/* static */ +wxString +wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) +{ + return wxCreateTempFileName(prefix, fileTemp); +} + #endif // wxUSE_FILE + +#if wxUSE_FFILE + +wxString wxCreateTempFileName(const wxString& prefix, + wxFFile *fileTemp, + bool *deleteOnClose) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose); +} + +bool wxCreateTempFile(const wxString& prefix, + wxFFile *fileTemp, + wxString *name) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name); + +} + +void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp)); +} + +/* static */ +wxString +wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp) +{ + return wxCreateTempFileName(prefix, fileTemp); +} + +#endif // wxUSE_FFILE + + // ---------------------------------------------------------------------------- // directory operations // ---------------------------------------------------------------------------- -- 2.45.2