#1272 Use in-memory temporary files.

This commit is contained in:
Robin Mills 2017-03-05 17:42:12 +00:00
parent 013771b4c1
commit 2ebacb6b0b
15 changed files with 62 additions and 167 deletions

View File

@ -365,8 +365,9 @@ case "$host_os" in
CPPFLAGS="$CPPFLAGS" # mingw doesn't link pthreads if you specify -std !!
;;
*)
if [ $GCC_VERSION -le 5 ]; then CPPFLAGS="$CPPFLAGS -std=c++98" # // most others use c++98
else CPPFLAGS="$CPPFLAGS -std=gnu++98" # // but not GCC 6
CPPFLAGS="$CPPFLAGS -std=c++98"
if [[ ! -z "$GCC_VERSION" ]]; then
if [[ "$GCC_VERSION" -ge 6 ]]; then CPPFLAGS="$CPPFLAGS -std=gnu++98" ; fi # // not GCC 6
fi
;;
esac

View File

@ -242,20 +242,6 @@ namespace Exiv2 {
*/
virtual std::wstring wpath() const =0;
#endif
/*!
@brief Returns a temporary data storage location. This is often
needed to rewrite an IO source.
For example, data may be read from the original IO source, modified
in some way, and then saved to the temporary instance. After the
operation is complete, the BasicIo::transfer method can be used to
replace the original IO source with the modified version. Subclasses
are free to return any class that derives from BasicIo.
@return An instance of BasicIo on success
@throw Error In case of failure
*/
virtual BasicIo::AutoPtr temporary() const = 0;
/*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -527,16 +513,6 @@ namespace Exiv2 {
*/
virtual std::wstring wpath() const;
#endif
/*!
@brief Returns a temporary data storage location. The actual type
returned depends upon the size of the file represented a FileIo
object. For small files, a MemIo is returned while for large files
a FileIo is returned. Callers should not rely on this behavior,
however, since it may change.
@return An instance of BasicIo on success
@throw Error If opening the temporary file fails
*/
virtual BasicIo::AutoPtr temporary() const;
/*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -548,15 +524,6 @@ namespace Exiv2 {
virtual void populateFakeData();
//@}
/*!
@brief Returns the path to a temporary data storage location.
*/
#ifdef EXV_UNICODE_PATH
static std::wstring temporaryPath();
#else
static std::string temporaryPath();
#endif
private:
// NOT IMPLEMENTED
//! Copy constructor
@ -745,13 +712,6 @@ namespace Exiv2 {
*/
virtual std::wstring wpath() const;
#endif
/*!
@brief Returns a temporary data storage location. Currently returns
an empty MemIo object, but callers should not rely on this
behavior since it may change.
@return An instance of BasicIo
*/
virtual BasicIo::AutoPtr temporary() const;
/*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory
@ -1090,13 +1050,6 @@ namespace Exiv2 {
*/
virtual std::wstring wpath() const;
#endif
/*!
@brief Returns a temporary data storage location. Currently returns
an empty MemIo object, but callers should not rely on this
behavior since it may change.
@return An instance of BasicIo
*/
virtual BasicIo::AutoPtr temporary() const;
/*!
@brief Mark all the bNone blocks to bKnow. This avoids allocating memory

View File

@ -2039,6 +2039,52 @@ namespace {
return os.str();
} // tm2Str
// use static CS/MUTEX to make temporaryPath() thread safe
#if defined(_MSC_VER) || defined(__MINGW__)
static CRITICAL_SECTION cs;
#else
/* Unix/Linux/Cygwin/MacOSX */
#include <pthread.h>
#if defined(__APPLE__)
/* This is the critical section object (statically allocated). */
static pthread_mutex_t cs = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
#else
static pthread_mutex_t cs = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
#endif
#endif
static std::string temporaryPath()
{
static int count = 0 ;
#if defined(_MSC_VER) || defined(__MINGW__)
EnterCriticalSection(&cs);
char lpTempPathBuffer[MAX_PATH];
GetTempPath(MAX_PATH,lpTempPathBuffer);
std::string tmp(lpTempPathBuffer);
tmp += "\\";
HANDLE process=0;
DWORD pid = ::GetProcessId(process);
#else
pid_t pid = ::getpid();
pthread_mutex_lock( &cs );
std::string tmp = "/tmp/";
#endif
char sCount[12];
sprintf(sCount,"_%d",++count);
std::string result = tmp + Exiv2::toString(pid) + sCount ;
if ( Exiv2::fileExists(result) ) std::remove(result.c_str());
#if defined(_MSC_VER) || defined(__MINGW__)
LeaveCriticalSection(&cs);
#else
pthread_mutex_unlock( &cs );
#endif
return result;
}
int metacopy(const std::string& source,
const std::string& tgt,
int targetType,
@ -2072,9 +2118,9 @@ namespace {
// Open or create the target file
#ifdef EXV_UNICODE_PATH
std::string target = bStdout ? Exiv2::ws2s(Exiv2::FileIo::temporaryPath()) : tgt;
std::string target = bStdout ? Exiv2::ws2s(temporaryPath()) : tgt;
#else
std::string target = bStdout ? Exiv2::FileIo::temporaryPath() : tgt;
std::string target = bStdout ? temporaryPath() : tgt;
#endif
Exiv2::Image::AutoPtr targetImage;

View File

@ -566,100 +566,6 @@ namespace Exiv2 {
}
#endif
BasicIo::AutoPtr FileIo::temporary() const
{
BasicIo::AutoPtr basicIo;
Impl::StructStat buf;
int ret = p_->stat(buf);
#if defined WIN32 && !defined __CYGWIN__
DWORD nlink = p_->winNumberOfLinks();
#else
nlink_t nlink = buf.st_nlink;
#endif
#ifdef EXV_UNICODE_PATH
std::wstring tmpname;
#else
std::string tmpname;
#endif
// If file is > 1MB and doesn't have hard links then use a file, otherwise
// use a memory buffer. I.e., files with hard links always use a memory
// buffer, which is a workaround to ensure that the links don't get broken.
if (ret != 0 || (buf.st_size > 1048576 && nlink == 1))
{
pid_t pid = ::getpid();
std::auto_ptr<FileIo> fileIo;
#ifdef EXV_UNICODE_PATH
tmpname = temporaryPath() + s2ws(toString(pid));
fileIo = std::auto_ptr<FileIo>(new FileIo(tmpname));
#else
tmpname = temporaryPath() + toString(pid);
fileIo = std::auto_ptr<FileIo>(new FileIo(tmpname));
#endif
if (fileIo->open("w+b") != 0) {
#ifdef EXV_UNICODE_PATH
#if defined(_MSC_VER)
if( !DeleteFileW( tmpname.c_str()) )
{
perror("Error deleting file");
throw WError(10, ws2s(tmpname).c_str(), "w+b", strError().c_str());
}
#endif
#else
#if defined(_MSC_VER) || defined(__MINGW__)
if( !DeleteFile( tmpname.c_str() ) )
#else
if( remove( tmpname.c_str() ) != 0 )
#endif
#endif
{
perror("Error deleting file");
}
throw Error(10, tmpname.c_str(), "w+b", strError());
}
fileIo->p_->copyXattrFrom(*this);
basicIo = fileIo;
} else {
basicIo.reset(new MemIo);
}
return basicIo;
}
static std::string tempPath()
{
static int count = 0 ;
char sCount[12];
sprintf(sCount,"_%d",count++);
#if defined(_MSC_VER) || defined(__MINGW__)
char lpTempPathBuffer[MAX_PATH];
GetTempPath(MAX_PATH,lpTempPathBuffer);
std::string tmp(lpTempPathBuffer);
tmp += "\\";
#else
std::string tmp = "/tmp/";
#endif
pid_t pid = ::getpid();
std::string result = tmp + toString(pid) + sCount ;
if ( Exiv2::fileExists(result) ) std::remove(result.c_str());
return result;
}
#ifdef EXV_UNICODE_PATH
std::wstring FileIo::temporaryPath()
{
return s2ws(tempPath());
}
#else
std::string FileIo::temporaryPath()
{
return tempPath();
}
#endif
long FileIo::write(const byte* data, long wcount)
{
assert(p_->fp_ != 0);
@ -1218,11 +1124,6 @@ namespace Exiv2 {
delete p_;
}
BasicIo::AutoPtr MemIo::temporary() const
{
return BasicIo::AutoPtr(new MemIo);
}
long MemIo::write(const byte* data, long wcount)
{
p_->reserve(wcount);
@ -1991,11 +1892,6 @@ namespace Exiv2 {
}
#endif
BasicIo::AutoPtr RemoteIo::temporary() const
{
return BasicIo::AutoPtr(new MemIo);
}
void RemoteIo::populateFakeData()
{
assert(p_->isMalloced_);

View File

@ -169,7 +169,7 @@ namespace Exiv2 {
CrwParser::encode(blob, buf.pData_, buf.size_, this);
// Write new buffer to file
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
MemIo::AutoPtr tempIo(new MemIo);
assert(tempIo.get() != 0);
tempIo->write((blob.size() > 0 ? &blob[0] : 0), static_cast<long>(blob.size()));
io_->close();

View File

@ -809,7 +809,7 @@ namespace {
}
// create temporary output file
BasicIo::AutoPtr tempIo(io.temporary());
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
if (!tempIo->isopen()) {
#ifndef SUPPRESS_WARNINGS

View File

@ -589,7 +589,7 @@ namespace Exiv2
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
doWriteMetadata(*tempIo); // may throw

View File

@ -834,7 +834,7 @@ namespace Exiv2 {
// exiv2 -pS E.jpg
// binary copy io_ to a temporary file
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
for ( uint64_t i = 0 ; i < (count/2)+1 ; i++ ) {
@ -866,7 +866,7 @@ namespace Exiv2 {
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
doWriteMetadata(*tempIo); // may throw

View File

@ -163,7 +163,7 @@ namespace Exiv2 {
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
doWriteMetadata(*tempIo); // may throw

View File

@ -494,7 +494,7 @@ namespace Exiv2 {
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
doWriteMetadata(*tempIo); // may throw

View File

@ -348,7 +348,7 @@ namespace Exiv2 {
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
doWriteMetadata(*tempIo); // may throw

View File

@ -1968,7 +1968,7 @@ namespace Exiv2 {
encoder.add(createdTree.get(), parsedTree.get(), root);
// Write binary representation from the composite tree
DataBuf header = pHeader->write();
BasicIo::AutoPtr tempIo(io.temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert(tempIo.get() != 0);
IoWrapper ioWrapper(*tempIo, header.pData_, header.size_, pOffsetWriter);
uint32_t imageIdx(uint32_t(-1));

View File

@ -120,7 +120,7 @@ namespace Exiv2 {
throw Error(9, io_->path(), strError());
}
IoCloser closer(*io_);
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert (tempIo.get() != 0);
doWriteMetadata(*tempIo); // may throw

View File

@ -159,7 +159,7 @@ namespace Exiv2 {
if (xmpPacket_.substr(0, 5) != "<?xml") {
xmpPacket_ = xmlHeader + xmpPacket_ + xmlFooter;
}
BasicIo::AutoPtr tempIo(io_->temporary()); // may throw
BasicIo::AutoPtr tempIo(new MemIo);
assert(tempIo.get() != 0);
// Write XMP packet
if ( tempIo->write(reinterpret_cast<const byte*>(xmpPacket_.data()),

View File

@ -76,7 +76,6 @@ TESTS = addmoddel.sh \
modify-test.sh \
path-test.sh \
preview-test.sh \
stdin-test.sh \
stringto-test.sh \
tiff-test.sh \
webp-test.sh \