Impove temp file creation and handling, especially for memory mapped
temp files
This commit is contained in:
parent
976d30c24b
commit
fa2b30fea1
5 changed files with 279 additions and 57 deletions
|
@ -36,8 +36,6 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <pcrecpp.h>
|
||||
#include <algorithm>
|
||||
|
@ -71,7 +69,7 @@ public:
|
|||
typedef std::map<std::string, pcrecpp::StringPiece> Content;
|
||||
typedef std::map<std::string, boost::variant<std::string> > Params;
|
||||
|
||||
void pullAll(Content &dst, std::string &buffer, pcrecpp::StringPiece &memRange);
|
||||
void pullAll(Content &dst, std::string &buffer, TmpFile &tmpFile);
|
||||
|
||||
void shutdown(void);
|
||||
|
||||
|
@ -294,47 +292,14 @@ void PbapSession::initSession(const std::string &address, const std::string &for
|
|||
SE_LOG_DEBUG(NULL, NULL, "PBAP session initialized");
|
||||
}
|
||||
|
||||
void PbapSession::pullAll(Content &dst, std::string &buffer, pcrecpp::StringPiece &memRange)
|
||||
void PbapSession::pullAll(Content &dst, std::string &buffer, TmpFile &tmpFile)
|
||||
{
|
||||
pcrecpp::StringPiece content;
|
||||
if (m_newobex) {
|
||||
char *addr;
|
||||
class TmpFileGuard {
|
||||
int m_fd;
|
||||
PlainGStr m_filename;
|
||||
public:
|
||||
/**
|
||||
* Create temporary file. Will be closed and unlinked when
|
||||
* this instance destructs.
|
||||
*/
|
||||
TmpFileGuard(PbapSyncSource &parent) {
|
||||
gchar *filename;
|
||||
GErrorCXX gerror;
|
||||
m_fd = g_file_open_tmp (NULL, &filename, gerror);
|
||||
m_filename = filename;
|
||||
if (m_fd == -1) {
|
||||
parent.throwError(std::string("opening temporary file for PBAP: ") +
|
||||
(gerror ? gerror->message : "unknown failure"));
|
||||
}
|
||||
}
|
||||
~TmpFileGuard() {
|
||||
// Unlink before closing to avoid race condition
|
||||
// (close, someone else opens file, we remove it).
|
||||
if (remove(m_filename) == -1) {
|
||||
// Continue despite error.
|
||||
SE_LOG_ERROR(NULL, NULL, "Unable to remove temporary file %s: %s",
|
||||
m_filename.get(), strerror(errno));
|
||||
}
|
||||
close (m_fd);
|
||||
}
|
||||
|
||||
const char *getFilename() const { return m_filename; }
|
||||
int getFD() const { return m_fd; }
|
||||
} tmpfile(m_parent);
|
||||
|
||||
SE_LOG_DEBUG(NULL, NULL, "Created temporary file for PullAll %s", tmpfile.getFilename());
|
||||
tmpFile.create();
|
||||
SE_LOG_DEBUG(NULL, NULL, "Created temporary file for PullAll %s", tmpFile.filename().c_str());
|
||||
GDBusCXX::DBusClientCall1<std::pair<GDBusCXX::DBusObject_t, Params> > pullall(*m_session, "PullAll");
|
||||
std::pair<GDBusCXX::DBusObject_t, Params> tuple = pullall(std::string(tmpfile.getFilename()));
|
||||
std::pair<GDBusCXX::DBusObject_t, Params> tuple = pullall(tmpFile.filename());
|
||||
const GDBusCXX::DBusObject_t &transfer = tuple.first;
|
||||
const Params &properties = tuple.second;
|
||||
|
||||
|
@ -349,19 +314,11 @@ void PbapSession::pullAll(Content &dst, std::string &buffer, pcrecpp::StringPiec
|
|||
m_transferErrorMsg.c_str()));
|
||||
}
|
||||
|
||||
struct stat sb;
|
||||
if (fstat(tmpfile.getFD(), &sb) == -1) {
|
||||
m_parent.throwError("stat on PBAP temp file", errno);
|
||||
}
|
||||
SE_LOG_DEBUG(NULL, NULL, "Temporary file size is %ld", (long)sb.st_size);
|
||||
|
||||
addr = (char*)mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, tmpfile.getFD(), 0);
|
||||
if (addr == MAP_FAILED) {
|
||||
m_parent.throwError("mmap temporary file", errno);
|
||||
}
|
||||
memRange.set(addr, sb.st_size);
|
||||
content = memRange;
|
||||
SE_LOG_DEBUG(NULL, NULL, "Temporary file size is %u", static_cast<unsigned> (tmpFile.size()));
|
||||
|
||||
content = tmpFile.stringPiece();
|
||||
// closing tmp file leaves the mapping
|
||||
tmpFile.close();
|
||||
} else {
|
||||
GDBusCXX::DBusClientCall1<std::string> pullall(*m_session, "PullAll");
|
||||
buffer = pullall();
|
||||
|
@ -403,9 +360,6 @@ PbapSyncSource::PbapSyncSource(const SyncSourceParams ¶ms) :
|
|||
|
||||
PbapSyncSource::~PbapSyncSource()
|
||||
{
|
||||
if (m_memRange.data()) {
|
||||
munmap(const_cast<char *>(m_memRange.data()), m_memRange.size());
|
||||
}
|
||||
}
|
||||
|
||||
std::string PbapSyncSource::getMimeType() const
|
||||
|
@ -430,7 +384,7 @@ void PbapSyncSource::open()
|
|||
std::string address = database.substr(prefix.size());
|
||||
|
||||
m_session->initSession(address, getDatabaseFormat());
|
||||
m_session->pullAll(m_content, m_buffer, m_memRange);
|
||||
m_session->pullAll(m_content, m_buffer, m_tmpFile);
|
||||
m_session->shutdown();
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <pcrecpp.h>
|
||||
|
||||
#include <syncevo/declarations.h>
|
||||
#include <syncevo/TmpFile.h>
|
||||
SE_BEGIN_CXX
|
||||
|
||||
class PbapSession;
|
||||
|
@ -68,7 +69,7 @@ class PbapSyncSource : public TrackingSyncSource, private boost::noncopyable
|
|||
Content m_content;
|
||||
|
||||
std::string m_buffer;
|
||||
pcrecpp::StringPiece m_memRange;
|
||||
TmpFile m_tmpFile;
|
||||
};
|
||||
|
||||
SE_END_CXX
|
||||
|
|
135
src/syncevo/TmpFile.cpp
Normal file
135
src/syncevo/TmpFile.cpp
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
|
||||
#include <cstdio>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib/gstdio.h>
|
||||
|
||||
#include "TmpFile.h"
|
||||
|
||||
|
||||
TmpFile::TmpFile() :
|
||||
m_fd(-1),
|
||||
m_mapptr(0),
|
||||
m_mapsize(0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
TmpFile::~TmpFile()
|
||||
{
|
||||
try {
|
||||
unmap();
|
||||
close();
|
||||
} catch (std::exception &x) {
|
||||
fprintf(stderr, "TmpFile::~TmpFile(): %s\n", x.what());
|
||||
} catch (...) {
|
||||
fputs("TmpFile::~TmpFile(): unknown exception\n", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TmpFile::create()
|
||||
{
|
||||
gchar *filename = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (m_fd >= 0 || m_mapptr || m_mapsize) {
|
||||
throw TmpFileException("TmpFile::create(): busy");
|
||||
}
|
||||
m_fd = g_file_open_tmp(NULL, &filename, &error);
|
||||
if (error != NULL) {
|
||||
throw TmpFileException(
|
||||
std::string("TmpFile::create(): g_file_open_tmp(): ") +
|
||||
std::string(error->message));
|
||||
}
|
||||
m_filename = filename;
|
||||
g_free(filename);
|
||||
}
|
||||
|
||||
|
||||
void TmpFile::map(void **mapptr, size_t *mapsize)
|
||||
{
|
||||
struct stat sb;
|
||||
|
||||
if (m_mapptr || m_mapsize) {
|
||||
throw TmpFileException("TmpFile::map(): busy");
|
||||
}
|
||||
if (m_fd < 0) {
|
||||
throw TmpFileException("TmpFile::map(): m_fd < 0");
|
||||
}
|
||||
if (fstat(m_fd, &sb) != 0) {
|
||||
throw TmpFileException("TmpFile::map(): fstat()");
|
||||
}
|
||||
m_mapptr = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
|
||||
m_fd, 0);
|
||||
if (m_mapptr == MAP_FAILED) {
|
||||
m_mapptr = 0;
|
||||
throw TmpFileException("TmpFile::map(): mmap()");
|
||||
}
|
||||
m_mapsize = sb.st_size;
|
||||
|
||||
if (mapptr != NULL) {
|
||||
*mapptr = m_mapptr;
|
||||
}
|
||||
if (mapsize != NULL) {
|
||||
*mapsize = m_mapsize;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TmpFile::unmap()
|
||||
{
|
||||
if (m_mapptr && m_mapsize) {
|
||||
munmap(m_mapptr, m_mapsize);
|
||||
}
|
||||
m_mapsize = 0;
|
||||
m_mapptr = 0;
|
||||
}
|
||||
|
||||
|
||||
void TmpFile::close()
|
||||
{
|
||||
if (!m_filename.empty()) {
|
||||
unlink(m_filename.c_str());
|
||||
m_filename.clear();
|
||||
}
|
||||
if (m_fd >= 0) {
|
||||
::close(m_fd);
|
||||
m_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pcrecpp::StringPiece TmpFile::stringPiece()
|
||||
{
|
||||
pcrecpp::StringPiece sp;
|
||||
|
||||
if (!(m_mapptr && m_mapsize)) {
|
||||
map();
|
||||
}
|
||||
sp.set(m_mapptr, static_cast<int> (m_mapsize));
|
||||
return sp;
|
||||
}
|
||||
|
129
src/syncevo/TmpFile.h
Normal file
129
src/syncevo/TmpFile.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) version 3.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef INCL_SYNCEVOLUTION_TMPFILE
|
||||
#define INCL_SYNCEVOLUTION_TMPFILE
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include <pcrecpp.h>
|
||||
|
||||
|
||||
/**
|
||||
* Exception class for TmpFile.
|
||||
*/
|
||||
class TmpFileException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
TmpFileException(const std::string &what)
|
||||
: std::runtime_error(what)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Class for handling temporary files, either read/write access
|
||||
* or memory mapped.
|
||||
*
|
||||
* Closing and removing a mapped file is supported by calling close()
|
||||
* after map().
|
||||
*/
|
||||
class TmpFile
|
||||
{
|
||||
protected:
|
||||
int m_fd;
|
||||
void *m_mapptr;
|
||||
size_t m_mapsize;
|
||||
std::string m_filename;
|
||||
|
||||
public:
|
||||
TmpFile();
|
||||
virtual ~TmpFile();
|
||||
|
||||
/**
|
||||
* Create a temporary file.
|
||||
*/
|
||||
void create();
|
||||
/**
|
||||
* Map a view of file and optionally return pointer and/or size.
|
||||
*
|
||||
* File should already have a correct size.
|
||||
*
|
||||
* @param mapptr Pointer to variable for mapped pointer. (can be NULL)
|
||||
* @param mapsize Pointer to variable for mapped size. (can be NULL)
|
||||
*/
|
||||
void map(void **mapptr = 0, size_t *mapsize = 0);
|
||||
/**
|
||||
* Unmap a view of file.
|
||||
*/
|
||||
void unmap();
|
||||
/**
|
||||
* Remove and close the file.
|
||||
*
|
||||
* Calling this after map() will make the file disappear from
|
||||
* filesystem but the mapping will be valid until unmapped or
|
||||
* instance of this class is destroyed.
|
||||
*/
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Retrieve file name of the file.
|
||||
*
|
||||
* @return file name
|
||||
*/
|
||||
const std::string & filename() const
|
||||
{ return m_filename; }
|
||||
/**
|
||||
* Retrieve descriptor of the file.
|
||||
*
|
||||
* @return descriptor
|
||||
*/
|
||||
int fd()
|
||||
{ return m_fd; }
|
||||
/**
|
||||
* Size of the mapping.
|
||||
*
|
||||
* @return mapped size
|
||||
*/
|
||||
size_t size() const
|
||||
{ return m_mapsize; }
|
||||
/**
|
||||
* Pointer to the mapping.
|
||||
*
|
||||
* @return pointer to the mapping
|
||||
*/
|
||||
operator void *()
|
||||
{ return m_mapptr; }
|
||||
/**
|
||||
* @overload
|
||||
*/
|
||||
operator const void *() const
|
||||
{ return m_mapptr; }
|
||||
|
||||
/**
|
||||
* Retrieve pcrecpp::StringPiece object for the mapped view.
|
||||
*
|
||||
* @return pcrecpp::StringPiece of the mapped view
|
||||
*/
|
||||
pcrecpp::StringPiece stringPiece();
|
||||
};
|
||||
|
||||
#endif // INCL_SYNCEVOLUTION_TMPFILE
|
||||
|
|
@ -62,6 +62,9 @@ src_syncevo_sources = \
|
|||
src/syncevo/util.h \
|
||||
src/syncevo/BoostHelper.h \
|
||||
\
|
||||
src/syncevo/TmpFile.cpp \
|
||||
src/syncevo/TmpFile.h \
|
||||
\
|
||||
src/syncevo/Timespec.h \
|
||||
\
|
||||
src/syncevo/lcs.h \
|
||||
|
|
Loading…
Reference in a new issue