|
Packit Service |
21b5d1 |
// ***************************************************************** -*- C++ -*-
|
|
Packit Service |
21b5d1 |
/*
|
|
Packit Service |
21b5d1 |
* Copyright (C) 2004-2018 Exiv2 authors
|
|
Packit Service |
21b5d1 |
* This program is part of the Exiv2 distribution.
|
|
Packit Service |
21b5d1 |
*
|
|
Packit Service |
21b5d1 |
* This program is free software; you can redistribute it and/or
|
|
Packit Service |
21b5d1 |
* modify it under the terms of the GNU General Public License
|
|
Packit Service |
21b5d1 |
* as published by the Free Software Foundation; either version 2
|
|
Packit Service |
21b5d1 |
* of the License, or (at your option) any later version.
|
|
Packit Service |
21b5d1 |
*
|
|
Packit Service |
21b5d1 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
21b5d1 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
21b5d1 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
21b5d1 |
* GNU General Public License for more details.
|
|
Packit Service |
21b5d1 |
*
|
|
Packit Service |
21b5d1 |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
21b5d1 |
* along with this program; if not, write to the Free Software
|
|
Packit Service |
21b5d1 |
* Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
/*
|
|
Packit Service |
21b5d1 |
File: basicio.cpp
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
// *****************************************************************************
|
|
Packit Service |
21b5d1 |
// included header files
|
|
Packit Service |
21b5d1 |
#include "config.h"
|
|
Packit Service |
21b5d1 |
#include "datasets.hpp"
|
|
Packit Service |
21b5d1 |
#include "basicio.hpp"
|
|
Packit Service |
21b5d1 |
#include "futils.hpp"
|
|
Packit Service |
21b5d1 |
#include "types.hpp"
|
|
Packit Service |
21b5d1 |
#include "error.hpp"
|
|
Packit Service |
21b5d1 |
#include "http.hpp"
|
|
Packit Service |
21b5d1 |
#include "properties.hpp"
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// + standard includes
|
|
Packit Service |
21b5d1 |
#include <string>
|
|
Packit Service |
21b5d1 |
#include <memory>
|
|
Packit Service |
21b5d1 |
#include <iostream>
|
|
Packit Service |
21b5d1 |
#include <cstring> // std::memcpy
|
|
Packit Service |
21b5d1 |
#include <cassert>
|
|
Packit Service |
21b5d1 |
#include <fstream> // write the temporary file
|
|
Packit Service |
21b5d1 |
#include <fcntl.h> // _O_BINARY in FileIo::FileIo
|
|
Packit Service |
21b5d1 |
#include <cstdio> // for remove, rename
|
|
Packit Service |
21b5d1 |
#include <cstdlib> // for alloc, realloc, free
|
|
Packit Service |
21b5d1 |
#include <ctime> // timestamp for the name of temporary file
|
|
Packit Service |
21b5d1 |
#include <sys/types.h> // for stat, chmod
|
|
Packit Service |
21b5d1 |
#include <sys/stat.h> // for stat, chmod
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_HAVE_SYS_MMAN_H
|
|
Packit Service |
21b5d1 |
# include <sys/mman.h> // for mmap and munmap
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
#ifdef EXV_HAVE_PROCESS_H
|
|
Packit Service |
21b5d1 |
# include <process.h>
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
#ifdef EXV_HAVE_UNISTD_H
|
|
Packit Service |
21b5d1 |
# include <unistd.h> // for getpid, stat
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_USE_CURL
|
|
Packit Service |
21b5d1 |
# include <curl/curl.h>
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_USE_SSH
|
|
Packit Service |
21b5d1 |
# include "ssh.hpp"
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
# define mode_t unsigned short
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// Platform specific headers for handling extended attributes (xattr)
|
|
Packit Service |
21b5d1 |
#if defined(__APPLE__)
|
|
Packit Service |
21b5d1 |
# include <sys/xattr.h>
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if defined(__MINGW__) || (defined(WIN32) && !defined(__CYGWIN))
|
|
Packit Service |
21b5d1 |
// Windows doesn't provide nlink_t
|
|
Packit Service |
21b5d1 |
typedef short nlink_t;
|
|
Packit Service |
21b5d1 |
# include <windows.h>
|
|
Packit Service |
21b5d1 |
# include <io.h>
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// *****************************************************************************
|
|
Packit Service |
21b5d1 |
// class member definitions
|
|
Packit Service |
21b5d1 |
namespace Exiv2 {
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
BasicIo::~BasicIo()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//! Internal Pimpl structure of class FileIo.
|
|
Packit Service |
21b5d1 |
class FileIo::Impl {
|
|
Packit Service |
21b5d1 |
public:
|
|
Packit Service |
21b5d1 |
//! Constructor
|
|
Packit Service |
21b5d1 |
Impl(const std::string& path);
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
//! Constructor accepting a unicode path in an std::wstring
|
|
Packit Service |
21b5d1 |
Impl(const std::wstring& wpath);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
// Enumerations
|
|
Packit Service |
21b5d1 |
//! Mode of operation
|
|
Packit Service |
21b5d1 |
enum OpMode { opRead, opWrite, opSeek };
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
//! Used to indicate if the path is stored as a standard or unicode string
|
|
Packit Service |
21b5d1 |
enum WpMode { wpStandard, wpUnicode };
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
// DATA
|
|
Packit Service |
21b5d1 |
std::string path_; //!< (Standard) path
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::wstring wpath_; //!< Unicode path
|
|
Packit Service |
21b5d1 |
WpMode wpMode_; //!< Indicates which path is in use
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
std::string openMode_; //!< File open mode
|
|
Packit Service |
21b5d1 |
FILE *fp_; //!< File stream pointer
|
|
Packit Service |
21b5d1 |
OpMode opMode_; //!< File open mode
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
HANDLE hFile_; //!< Duplicated fd
|
|
Packit Service |
21b5d1 |
HANDLE hMap_; //!< Handle from CreateFileMapping
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
byte* pMappedArea_; //!< Pointer to the memory-mapped area
|
|
Packit Service |
21b5d1 |
size_t mappedLength_; //!< Size of the memory-mapped area
|
|
Packit Service |
21b5d1 |
bool isMalloced_; //!< Is the mapped area allocated?
|
|
Packit Service |
21b5d1 |
bool isWriteable_; //!< Can the mapped area be written to?
|
|
Packit Service |
21b5d1 |
// TYPES
|
|
Packit Service |
21b5d1 |
//! Simple struct stat wrapper for internal use
|
|
Packit Service |
21b5d1 |
struct StructStat {
|
|
Packit Service |
21b5d1 |
StructStat() : st_mode(0), st_size(0), st_nlink(0) {}
|
|
Packit Service |
21b5d1 |
mode_t st_mode; //!< Permissions
|
|
Packit Service |
21b5d1 |
off_t st_size; //!< Size
|
|
Packit Service |
21b5d1 |
nlink_t st_nlink; //!< Number of hard links (broken on Windows, see winNumberOfLinks())
|
|
Packit Service |
21b5d1 |
};
|
|
Packit Service |
21b5d1 |
// #endif
|
|
Packit Service |
21b5d1 |
// METHODS
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Switch to a new access mode, reopening the file if needed.
|
|
Packit Service |
21b5d1 |
Optimized to only reopen the file when it is really necessary.
|
|
Packit Service |
21b5d1 |
@param opMode The mode to switch to.
|
|
Packit Service |
21b5d1 |
@return 0 if successful
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
int switchMode(OpMode opMode);
|
|
Packit Service |
21b5d1 |
//! stat wrapper for internal use
|
|
Packit Service |
21b5d1 |
int stat(StructStat& buf) const;
|
|
Packit Service |
21b5d1 |
//! copy extended attributes (xattr) from another file
|
|
Packit Service |
21b5d1 |
void copyXattrFrom(const FileIo& src);
|
|
Packit Service |
21b5d1 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
// Windows function to determine the number of hardlinks (on NTFS)
|
|
Packit Service |
21b5d1 |
DWORD winNumberOfLinks() const;
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
private:
|
|
Packit Service |
21b5d1 |
// NOT IMPLEMENTED
|
|
Packit Service |
21b5d1 |
Impl(const Impl& rhs); //!< Copy constructor
|
|
Packit Service |
21b5d1 |
Impl& operator=(const Impl& rhs); //!< Assignment
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
}; // class FileIo::Impl
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
FileIo::Impl::Impl(const std::string& path)
|
|
Packit Service |
21b5d1 |
: path_(path),
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
wpMode_(wpStandard),
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
fp_(0), opMode_(opSeek),
|
|
Packit Service |
21b5d1 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
hFile_(0), hMap_(0),
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
pMappedArea_(0), mappedLength_(0), isMalloced_(false), isWriteable_(false)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
FileIo::Impl::Impl(const std::wstring& wpath)
|
|
Packit Service |
21b5d1 |
: wpath_(wpath),
|
|
Packit Service |
21b5d1 |
wpMode_(wpUnicode),
|
|
Packit Service |
21b5d1 |
fp_(0), opMode_(opSeek),
|
|
Packit Service |
21b5d1 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
hFile_(0), hMap_(0),
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
pMappedArea_(0), mappedLength_(0), isMalloced_(false), isWriteable_(false)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
int FileIo::Impl::switchMode(OpMode opMode)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(fp_ != 0);
|
|
Packit Service |
21b5d1 |
if (opMode_ == opMode) return 0;
|
|
Packit Service |
21b5d1 |
OpMode oldOpMode = opMode_;
|
|
Packit Service |
21b5d1 |
opMode_ = opMode;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool reopen = true;
|
|
Packit Service |
21b5d1 |
switch(opMode) {
|
|
Packit Service |
21b5d1 |
case opRead:
|
|
Packit Service |
21b5d1 |
// Flush if current mode allows reading, else reopen (in mode "r+b"
|
|
Packit Service |
21b5d1 |
// as in this case we know that we can write to the file)
|
|
Packit Service |
21b5d1 |
if (openMode_[0] == 'r' || openMode_[1] == '+') reopen = false;
|
|
Packit Service |
21b5d1 |
break;
|
|
Packit Service |
21b5d1 |
case opWrite:
|
|
Packit Service |
21b5d1 |
// Flush if current mode allows writing, else reopen
|
|
Packit Service |
21b5d1 |
if (openMode_[0] != 'r' || openMode_[1] == '+') reopen = false;
|
|
Packit Service |
21b5d1 |
break;
|
|
Packit Service |
21b5d1 |
case opSeek:
|
|
Packit Service |
21b5d1 |
reopen = false;
|
|
Packit Service |
21b5d1 |
break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (!reopen) {
|
|
Packit Service |
21b5d1 |
// Don't do anything when switching _from_ opSeek mode; we
|
|
Packit Service |
21b5d1 |
// flush when switching _to_ opSeek.
|
|
Packit Service |
21b5d1 |
if (oldOpMode == opSeek) return 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// Flush. On msvcrt fflush does not do the job
|
|
Packit Service |
21b5d1 |
std::fseek(fp_, 0, SEEK_CUR);
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// Reopen the file
|
|
Packit Service |
21b5d1 |
long offset = std::ftell(fp_);
|
|
Packit Service |
21b5d1 |
if (offset == -1) return -1;
|
|
Packit Service |
21b5d1 |
// 'Manual' open("r+b") to avoid munmap()
|
|
Packit Service |
21b5d1 |
if (fp_ != 0) {
|
|
Packit Service |
21b5d1 |
std::fclose(fp_);
|
|
Packit Service |
21b5d1 |
fp_= 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
openMode_ = "r+b";
|
|
Packit Service |
21b5d1 |
opMode_ = opSeek;
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (wpMode_ == wpUnicode) {
|
|
Packit Service |
21b5d1 |
fp_ = ::_wfopen(wpath_.c_str(), s2ws(openMode_).c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
fp_ = std::fopen(path_.c_str(), openMode_.c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (!fp_) return 1;
|
|
Packit Service |
21b5d1 |
return std::fseek(fp_, offset, SEEK_SET);
|
|
Packit Service |
21b5d1 |
} // FileIo::Impl::switchMode
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::Impl::stat(StructStat& buf) const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
int ret = 0;
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
#ifdef _WIN64
|
|
Packit Service |
21b5d1 |
struct _stat64 st;
|
|
Packit Service |
21b5d1 |
ret = ::_wstati64(wpath_.c_str(), &st);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (0 == ret) {
|
|
Packit Service |
21b5d1 |
buf.st_size = st.st_size;
|
|
Packit Service |
21b5d1 |
buf.st_mode = st.st_mode;
|
|
Packit Service |
21b5d1 |
buf.st_nlink = st.st_nlink;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
struct _stat st;
|
|
Packit Service |
21b5d1 |
ret = ::_wstat(wpath_.c_str(), &st);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (0 == ret) {
|
|
Packit Service |
21b5d1 |
buf.st_size = st.st_size;
|
|
Packit Service |
21b5d1 |
buf.st_mode = st.st_mode;
|
|
Packit Service |
21b5d1 |
buf.st_nlink = st.st_nlink;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
struct stat st;
|
|
Packit Service |
21b5d1 |
ret = ::stat(path_.c_str(), &st);
|
|
Packit Service |
21b5d1 |
if (0 == ret) {
|
|
Packit Service |
21b5d1 |
buf.st_size = st.st_size;
|
|
Packit Service |
21b5d1 |
buf.st_nlink = st.st_nlink;
|
|
Packit Service |
21b5d1 |
buf.st_mode = st.st_mode;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return ret;
|
|
Packit Service |
21b5d1 |
} // FileIo::Impl::stat
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if defined(__APPLE__)
|
|
Packit Service |
21b5d1 |
void FileIo::Impl::copyXattrFrom(const FileIo& src)
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
void FileIo::Impl::copyXattrFrom(const FileIo&)
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
#if defined(__APPLE__)
|
|
Packit Service |
21b5d1 |
# if defined(EXV_UNICODE_PATH)
|
|
Packit Service |
21b5d1 |
# error No xattr API for MacOS X with unicode support
|
|
Packit Service |
21b5d1 |
# endif
|
|
Packit Service |
21b5d1 |
ssize_t namebufSize = ::listxattr(src.p_->path_.c_str(), 0, 0, 0);
|
|
Packit Service |
21b5d1 |
if (namebufSize < 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (namebufSize == 0) {
|
|
Packit Service |
21b5d1 |
// No extended attributes in source file
|
|
Packit Service |
21b5d1 |
return;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
char* namebuf = new char[namebufSize];
|
|
Packit Service |
21b5d1 |
if (::listxattr(src.p_->path_.c_str(), namebuf, namebufSize, 0) != namebufSize) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, src.p_->path_, strError(), "listxattr");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
for (ssize_t namebufPos = 0; namebufPos < namebufSize;) {
|
|
Packit Service |
21b5d1 |
const char *name = namebuf + namebufPos;
|
|
Packit Service |
21b5d1 |
namebufPos += strlen(name) + 1;
|
|
Packit Service |
21b5d1 |
const ssize_t valueSize = ::getxattr(src.p_->path_.c_str(), name, 0, 0, 0, 0);
|
|
Packit Service |
21b5d1 |
if (valueSize < 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, src.p_->path_, strError(), "getxattr");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
char* value = new char[valueSize];
|
|
Packit Service |
21b5d1 |
if (::getxattr(src.p_->path_.c_str(), name, value, valueSize, 0, 0) != valueSize) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, src.p_->path_, strError(), "getxattr");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
// #906. Mountain Lion 'sandbox' terminates the app when we call setxattr
|
|
Packit Service |
21b5d1 |
#ifndef __APPLE__
|
|
Packit Service |
21b5d1 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit Service |
21b5d1 |
EXV_DEBUG << "Copying xattr \"" << name << "\" with value size " << valueSize << "\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
if (::setxattr(path_.c_str(), name, value, valueSize, 0, 0) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path_, strError(), "setxattr");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
delete [] value;
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
delete [] namebuf;
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
// No xattr support for this platform.
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
} // FileIo::Impl::copyXattrFrom
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
DWORD FileIo::Impl::winNumberOfLinks() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
DWORD nlink = 1;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
HANDLE hFd = (HANDLE)_get_osfhandle(fileno(fp_));
|
|
Packit Service |
21b5d1 |
if (hFd != INVALID_HANDLE_VALUE) {
|
|
Packit Service |
21b5d1 |
typedef BOOL (WINAPI * GetFileInformationByHandle_t)(HANDLE, LPBY_HANDLE_FILE_INFORMATION);
|
|
Packit Service |
21b5d1 |
HMODULE hKernel = ::GetModuleHandleA("kernel32.dll");
|
|
Packit Service |
21b5d1 |
if (hKernel) {
|
|
Packit Service |
21b5d1 |
GetFileInformationByHandle_t pfcn_GetFileInformationByHandle = (GetFileInformationByHandle_t)GetProcAddress(hKernel, "GetFileInformationByHandle");
|
|
Packit Service |
21b5d1 |
if (pfcn_GetFileInformationByHandle) {
|
|
Packit Service |
21b5d1 |
BY_HANDLE_FILE_INFORMATION fi = {0,0,0,0,0,0,0,0,0,0,0,0,0};
|
|
Packit Service |
21b5d1 |
if (pfcn_GetFileInformationByHandle(hFd, &fi)) {
|
|
Packit Service |
21b5d1 |
nlink = fi.nNumberOfLinks;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit Service |
21b5d1 |
else EXV_DEBUG << "GetFileInformationByHandle failed\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit Service |
21b5d1 |
else EXV_DEBUG << "GetProcAddress(hKernel, \"GetFileInformationByHandle\") failed\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit Service |
21b5d1 |
else EXV_DEBUG << "GetModuleHandleA(\"kernel32.dll\") failed\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit Service |
21b5d1 |
else EXV_DEBUG << "_get_osfhandle failed: INVALID_HANDLE_VALUE\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
return nlink;
|
|
Packit Service |
21b5d1 |
} // FileIo::Impl::winNumberOfLinks
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif // defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
FileIo::FileIo(const std::string& path)
|
|
Packit Service |
21b5d1 |
: p_(new Impl(path))
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
FileIo::FileIo(const std::wstring& wpath)
|
|
Packit Service |
21b5d1 |
: p_(new Impl(wpath))
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
FileIo::~FileIo()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
close();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::munmap()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
int rc = 0;
|
|
Packit Service |
21b5d1 |
if (p_->pMappedArea_ != 0) {
|
|
Packit Service |
21b5d1 |
#if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
|
|
Packit Service |
21b5d1 |
if (::munmap(p_->pMappedArea_, p_->mappedLength_) != 0) {
|
|
Packit Service |
21b5d1 |
rc = 1;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#elif defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
UnmapViewOfFile(p_->pMappedArea_);
|
|
Packit Service |
21b5d1 |
CloseHandle(p_->hMap_);
|
|
Packit Service |
21b5d1 |
p_->hMap_ = 0;
|
|
Packit Service |
21b5d1 |
CloseHandle(p_->hFile_);
|
|
Packit Service |
21b5d1 |
p_->hFile_ = 0;
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
if (p_->isWriteable_) {
|
|
Packit Service |
21b5d1 |
seek(0, BasicIo::beg);
|
|
Packit Service |
21b5d1 |
write(p_->pMappedArea_, p_->mappedLength_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (p_->isMalloced_) {
|
|
Packit Service |
21b5d1 |
delete[] p_->pMappedArea_;
|
|
Packit Service |
21b5d1 |
p_->isMalloced_ = false;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (p_->isWriteable_) {
|
|
Packit Service |
21b5d1 |
if (p_->fp_ != 0) p_->switchMode(Impl::opRead);
|
|
Packit Service |
21b5d1 |
p_->isWriteable_ = false;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->pMappedArea_ = 0;
|
|
Packit Service |
21b5d1 |
p_->mappedLength_ = 0;
|
|
Packit Service |
21b5d1 |
return rc;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
byte* FileIo::mmap(bool isWriteable)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
if (munmap() != 0) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), strError().c_str(), "munmap");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), strError(), "munmap");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->mappedLength_ = size();
|
|
Packit Service |
21b5d1 |
p_->isWriteable_ = isWriteable;
|
|
Packit Service |
21b5d1 |
if (p_->isWriteable_ && p_->switchMode(Impl::opWrite) != 0) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFailedToMapFileForReadWrite, wpath(), strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerFailedToMapFileForReadWrite, path(), strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#if defined EXV_HAVE_MMAP && defined EXV_HAVE_MUNMAP
|
|
Packit Service |
21b5d1 |
int prot = PROT_READ;
|
|
Packit Service |
21b5d1 |
if (p_->isWriteable_) {
|
|
Packit Service |
21b5d1 |
prot |= PROT_WRITE;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
void* rc = ::mmap(0, p_->mappedLength_, prot, MAP_SHARED, fileno(p_->fp_), 0);
|
|
Packit Service |
21b5d1 |
if (MAP_FAILED == rc) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), strError().c_str(), "mmap");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), strError(), "mmap");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->pMappedArea_ = static_cast<byte*>(rc);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#elif defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
// Windows implementation
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// TODO: An attempt to map a file with a length of 0 (zero) fails with
|
|
Packit Service |
21b5d1 |
// an error code of ERROR_FILE_INVALID.
|
|
Packit Service |
21b5d1 |
// Applications should test for files with a length of 0 (zero) and
|
|
Packit Service |
21b5d1 |
// reject those files.
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
DWORD dwAccess = FILE_MAP_READ;
|
|
Packit Service |
21b5d1 |
DWORD flProtect = PAGE_READONLY;
|
|
Packit Service |
21b5d1 |
if (isWriteable) {
|
|
Packit Service |
21b5d1 |
dwAccess = FILE_MAP_WRITE;
|
|
Packit Service |
21b5d1 |
flProtect = PAGE_READWRITE;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
HANDLE hPh = GetCurrentProcess();
|
|
Packit Service |
21b5d1 |
HANDLE hFd = (HANDLE)_get_osfhandle(fileno(p_->fp_));
|
|
Packit Service |
21b5d1 |
if (hFd == INVALID_HANDLE_VALUE) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), "MSG1", "_get_osfhandle");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), "MSG1", "_get_osfhandle");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (!DuplicateHandle(hPh, hFd, hPh, &p_->hFile_, 0, false, DUPLICATE_SAME_ACCESS)) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), "MSG2", "DuplicateHandle");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), "MSG2", "DuplicateHandle");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->hMap_ = CreateFileMapping(p_->hFile_, 0, flProtect, 0, (DWORD) p_->mappedLength_, 0);
|
|
Packit Service |
21b5d1 |
if (p_->hMap_ == 0 ) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), "MSG3", "CreateFileMapping");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), "MSG3", "CreateFileMapping");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
void* rc = MapViewOfFile(p_->hMap_, dwAccess, 0, 0, 0);
|
|
Packit Service |
21b5d1 |
if (rc == 0) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), "MSG4", "CreateFileMapping");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), "MSG4", "CreateFileMapping");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->pMappedArea_ = static_cast<byte*>(rc);
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
// Workaround for platforms without mmap: Read the file into memory
|
|
Packit Service |
21b5d1 |
DataBuf buf(static_cast<long>(p_->mappedLength_));
|
|
Packit Service |
21b5d1 |
if (read(buf.pData_, buf.size_) != buf.size_) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), strError().c_str(), "FileIo::read");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), strError(), "FileIo::read");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (error()) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath(), strError().c_str(), "FileIo::mmap");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), strError(), "FileIo::mmap");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->pMappedArea_ = buf.release().first;
|
|
Packit Service |
21b5d1 |
p_->isMalloced_ = true;
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
return p_->pMappedArea_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void FileIo::setPath(const std::string& path) {
|
|
Packit Service |
21b5d1 |
close();
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
std::wstring wpath;
|
|
Packit Service |
21b5d1 |
wpath.assign(path.begin(), path.end());
|
|
Packit Service |
21b5d1 |
p_->wpath_ = wpath;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->path_ = path;
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
p_->path_ = path;
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
void FileIo::setPath(const std::wstring& wpath) {
|
|
Packit Service |
21b5d1 |
close();
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpStandard) {
|
|
Packit Service |
21b5d1 |
std::string path;
|
|
Packit Service |
21b5d1 |
path.assign(wpath.begin(), wpath.end());
|
|
Packit Service |
21b5d1 |
p_->path_ = path;
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
p_->wpath_ = wpath;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long FileIo::write(const byte* data, long wcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
if (p_->switchMode(Impl::opWrite) != 0) return 0;
|
|
Packit Service |
21b5d1 |
return (long)std::fwrite(data, 1, wcount, p_->fp_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long FileIo::write(BasicIo& src)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
if (static_cast<BasicIo*>(this) == &src) return 0;
|
|
Packit Service |
21b5d1 |
if (!src.isopen()) return 0;
|
|
Packit Service |
21b5d1 |
if (p_->switchMode(Impl::opWrite) != 0) return 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
byte buf[4096];
|
|
Packit Service |
21b5d1 |
long readCount = 0;
|
|
Packit Service |
21b5d1 |
long writeCount = 0;
|
|
Packit Service |
21b5d1 |
long writeTotal = 0;
|
|
Packit Service |
21b5d1 |
while ((readCount = src.read(buf, sizeof(buf)))) {
|
|
Packit Service |
21b5d1 |
writeTotal += writeCount = (long)std::fwrite(buf, 1, readCount, p_->fp_);
|
|
Packit Service |
21b5d1 |
if (writeCount != readCount) {
|
|
Packit Service |
21b5d1 |
// try to reset back to where write stopped
|
|
Packit Service |
21b5d1 |
src.seek(writeCount-readCount, BasicIo::cur);
|
|
Packit Service |
21b5d1 |
break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
return writeTotal;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void FileIo::transfer(BasicIo& src)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
const bool wasOpen = (p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
const std::string lastMode(p_->openMode_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
FileIo *fileIo = dynamic_cast<FileIo*>(&src;;
|
|
Packit Service |
21b5d1 |
if (fileIo) {
|
|
Packit Service |
21b5d1 |
// Optimization if src is another instance of FileIo
|
|
Packit Service |
21b5d1 |
fileIo->close();
|
|
Packit Service |
21b5d1 |
// Check if the file can be written to, if it already exists
|
|
Packit Service |
21b5d1 |
if (open("a+b") != 0) {
|
|
Packit Service |
21b5d1 |
// Remove the (temporary) file
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (fileIo->p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
::_wremove(fileIo->wpath().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
::remove(fileIo->path().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileOpenFailed, wpath(), "a+b", strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerFileOpenFailed, path(), "a+b", strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
close();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool statOk = true;
|
|
Packit Service |
21b5d1 |
mode_t origStMode = 0;
|
|
Packit Service |
21b5d1 |
std::string spf;
|
|
Packit Service |
21b5d1 |
char* pf = 0;
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::wstring wspf;
|
|
Packit Service |
21b5d1 |
wchar_t* wpf = 0;
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
wspf = wpath();
|
|
Packit Service |
21b5d1 |
wpf = const_cast<wchar_t*>(wspf.c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
spf = path();
|
|
Packit Service |
21b5d1 |
pf = const_cast<char*>(spf.c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// Get the permissions of the file, or linked-to file, on platforms which have lstat
|
|
Packit Service |
21b5d1 |
#ifdef EXV_HAVE_LSTAT
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
# ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
# error EXV_UNICODE_PATH and EXV_HAVE_LSTAT are not compatible. Stop.
|
|
Packit Service |
21b5d1 |
# endif
|
|
Packit Service |
21b5d1 |
struct stat buf1;
|
|
Packit Service |
21b5d1 |
if (::lstat(pf, &buf1) == -1) {
|
|
Packit Service |
21b5d1 |
statOk = false;
|
|
Packit Service |
21b5d1 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit Service |
21b5d1 |
EXV_WARNING << Error(kerCallFailed, pf, strError(), "::lstat") << "\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
origStMode = buf1.st_mode;
|
|
Packit Service |
21b5d1 |
DataBuf lbuf; // So that the allocated memory is freed. Must have same scope as pf
|
|
Packit Service |
21b5d1 |
// In case path() is a symlink, get the path of the linked-to file
|
|
Packit Service |
21b5d1 |
if (statOk && S_ISLNK(buf1.st_mode)) {
|
|
Packit Service |
21b5d1 |
lbuf.alloc(buf1.st_size + 1);
|
|
Packit Service |
21b5d1 |
memset(lbuf.pData_, 0x0, lbuf.size_);
|
|
Packit Service |
21b5d1 |
pf = reinterpret_cast<char*>(lbuf.pData_);
|
|
Packit Service |
21b5d1 |
if (::readlink(path().c_str(), pf, lbuf.size_ - 1) == -1) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path(), strError(), "readlink");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
// We need the permissions of the file, not the symlink
|
|
Packit Service |
21b5d1 |
if (::stat(pf, &buf1) == -1) {
|
|
Packit Service |
21b5d1 |
statOk = false;
|
|
Packit Service |
21b5d1 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit Service |
21b5d1 |
EXV_WARNING << Error(kerCallFailed, pf, strError(), "::stat") << "\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
origStMode = buf1.st_mode;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#else // EXV_HAVE_LSTAT
|
|
Packit Service |
21b5d1 |
Impl::StructStat buf1;
|
|
Packit Service |
21b5d1 |
if (p_->stat(buf1) == -1) {
|
|
Packit Service |
21b5d1 |
statOk = false;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
origStMode = buf1.st_mode;
|
|
Packit Service |
21b5d1 |
#endif // !EXV_HAVE_LSTAT
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// MSVCRT rename that does not overwrite existing files
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
#if defined(WIN32) && defined(REPLACEFILE_IGNORE_MERGE_ERRORS)
|
|
Packit Service |
21b5d1 |
// Windows implementation that deals with the fact that ::rename fails
|
|
Packit Service |
21b5d1 |
// if the target filename still exists, which regularly happens when
|
|
Packit Service |
21b5d1 |
// that file has been opened with FILE_SHARE_DELETE by another process,
|
|
Packit Service |
21b5d1 |
// like a virus scanner or disk indexer
|
|
Packit Service |
21b5d1 |
// (see also http://stackoverflow.com/a/11023068)
|
|
Packit Service |
21b5d1 |
typedef BOOL (WINAPI * ReplaceFileW_t)(LPCWSTR, LPCWSTR, LPCWSTR, DWORD, LPVOID, LPVOID);
|
|
Packit Service |
21b5d1 |
HMODULE hKernel = ::GetModuleHandleA("kernel32.dll");
|
|
Packit Service |
21b5d1 |
if (hKernel) {
|
|
Packit Service |
21b5d1 |
ReplaceFileW_t pfcn_ReplaceFileW = (ReplaceFileW_t)GetProcAddress(hKernel, "ReplaceFileW");
|
|
Packit Service |
21b5d1 |
if (pfcn_ReplaceFileW) {
|
|
Packit Service |
21b5d1 |
BOOL ret = pfcn_ReplaceFileW(wpf, fileIo->wpath().c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL);
|
|
Packit Service |
21b5d1 |
if (ret == 0) {
|
|
Packit Service |
21b5d1 |
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
Packit Service |
21b5d1 |
if (::_wrename(fileIo->wpath().c_str(), wpf) == -1) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
::_wremove(fileIo->wpath().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else {
|
|
Packit Service |
21b5d1 |
if (fileExists(wpf) && ::_wremove(wpf) != 0) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpf, strError().c_str(), "::_wremove");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (::_wrename(fileIo->wpath().c_str(), wpf) == -1) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
::_wremove(fileIo->wpath().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
if (fileExists(wpf) && ::_wremove(wpf) != 0) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpf, strError().c_str(), "::_wremove");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (::_wrename(fileIo->wpath().c_str(), wpf) == -1) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileRenameFailed, fileIo->wpath(), wpf, strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
::_wremove(fileIo->wpath().c_str());
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
// Check permissions of new file
|
|
Packit Service |
21b5d1 |
struct _stat buf2;
|
|
Packit Service |
21b5d1 |
if (statOk && ::_wstat(wpf, &buf2) == -1) {
|
|
Packit Service |
21b5d1 |
statOk = false;
|
|
Packit Service |
21b5d1 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit Service |
21b5d1 |
EXV_WARNING << Error(kerCallFailed, wpf, strError(), "::_wstat") << "\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (statOk && origStMode != buf2.st_mode) {
|
|
Packit Service |
21b5d1 |
// Set original file permissions
|
|
Packit Service |
21b5d1 |
if (::_wchmod(wpf, origStMode) == -1) {
|
|
Packit Service |
21b5d1 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit Service |
21b5d1 |
EXV_WARNING << Error(kerCallFailed, wpf, strError(), "::_wchmod") << "\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
} // if (p_->wpMode_ == Impl::wpUnicode)
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif // EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
#if defined(WIN32) && defined(REPLACEFILE_IGNORE_MERGE_ERRORS)
|
|
Packit Service |
21b5d1 |
// Windows implementation that deals with the fact that ::rename fails
|
|
Packit Service |
21b5d1 |
// if the target filename still exists, which regularly happens when
|
|
Packit Service |
21b5d1 |
// that file has been opened with FILE_SHARE_DELETE by another process,
|
|
Packit Service |
21b5d1 |
// like a virus scanner or disk indexer
|
|
Packit Service |
21b5d1 |
// (see also http://stackoverflow.com/a/11023068)
|
|
Packit Service |
21b5d1 |
typedef BOOL (WINAPI * ReplaceFileA_t)(LPCSTR, LPCSTR, LPCSTR, DWORD, LPVOID, LPVOID);
|
|
Packit Service |
21b5d1 |
HMODULE hKernel = ::GetModuleHandleA("kernel32.dll");
|
|
Packit Service |
21b5d1 |
if (hKernel) {
|
|
Packit Service |
21b5d1 |
ReplaceFileA_t pfcn_ReplaceFileA = (ReplaceFileA_t)GetProcAddress(hKernel, "ReplaceFileA");
|
|
Packit Service |
21b5d1 |
if (pfcn_ReplaceFileA) {
|
|
Packit Service |
21b5d1 |
BOOL ret = pfcn_ReplaceFileA(pf, fileIo->path().c_str(), NULL, REPLACEFILE_IGNORE_MERGE_ERRORS, NULL, NULL);
|
|
Packit Service |
21b5d1 |
if (ret == 0) {
|
|
Packit Service |
21b5d1 |
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
Packit Service |
21b5d1 |
if (::rename(fileIo->path().c_str(), pf) == -1) {
|
|
Packit Service |
21b5d1 |
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
::remove(fileIo->path().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else {
|
|
Packit Service |
21b5d1 |
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else {
|
|
Packit Service |
21b5d1 |
if (fileExists(pf) && ::remove(pf) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, pf, strError(), "::remove");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (::rename(fileIo->path().c_str(), pf) == -1) {
|
|
Packit Service |
21b5d1 |
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
::remove(fileIo->path().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
if (fileExists(pf) && ::remove(pf) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, pf, strError(), "::remove");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (::rename(fileIo->path().c_str(), pf) == -1) {
|
|
Packit Service |
21b5d1 |
throw Error(kerFileRenameFailed, fileIo->path(), pf, strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
::remove(fileIo->path().c_str());
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
// Check permissions of new file
|
|
Packit Service |
21b5d1 |
struct stat buf2;
|
|
Packit Service |
21b5d1 |
if (statOk && ::stat(pf, &buf2) == -1) {
|
|
Packit Service |
21b5d1 |
statOk = false;
|
|
Packit Service |
21b5d1 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit Service |
21b5d1 |
EXV_WARNING << Error(kerCallFailed, pf, strError(), "::stat") << "\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (statOk && origStMode != buf2.st_mode) {
|
|
Packit Service |
21b5d1 |
// Set original file permissions
|
|
Packit Service |
21b5d1 |
if (::chmod(pf, origStMode) == -1) {
|
|
Packit Service |
21b5d1 |
#ifndef SUPPRESS_WARNINGS
|
|
Packit Service |
21b5d1 |
EXV_WARNING << Error(kerCallFailed, pf, strError(), "::chmod") << "\n";
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
} // if (fileIo)
|
|
Packit Service |
21b5d1 |
else {
|
|
Packit Service |
21b5d1 |
// Generic handling, reopen both to reset to start
|
|
Packit Service |
21b5d1 |
if (open("w+b") != 0) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileOpenFailed, wpath(), "w+b", strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerFileOpenFailed, path(), "w+b", strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (src.open() != 0) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerDataSourceOpenFailed, src.wpath(), strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerDataSourceOpenFailed, src.path(), strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
write(src);
|
|
Packit Service |
21b5d1 |
src.close();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (wasOpen) {
|
|
Packit Service |
21b5d1 |
if (open(lastMode) != 0) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileOpenFailed, wpath(), lastMode.c_str(), strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerFileOpenFailed, path(), lastMode, strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else close();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (error() || src.error()) {
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
throw WError(kerTransferFailed, wpath(), strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
throw Error(kerTransferFailed, path(), strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
} // FileIo::transfer
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::putb(byte data)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
if (p_->switchMode(Impl::opWrite) != 0) return EOF;
|
|
Packit Service |
21b5d1 |
return putc(data, p_->fp_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if defined(_MSC_VER)
|
|
Packit Service |
21b5d1 |
int FileIo::seek( int64_t offset, Position pos )
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int fileSeek = 0;
|
|
Packit Service |
21b5d1 |
switch (pos) {
|
|
Packit Service |
21b5d1 |
case BasicIo::cur: fileSeek = SEEK_CUR; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::beg: fileSeek = SEEK_SET; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::end: fileSeek = SEEK_END; break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (p_->switchMode(Impl::opSeek) != 0) return 1;
|
|
Packit Service |
21b5d1 |
#ifdef _WIN64
|
|
Packit Service |
21b5d1 |
return _fseeki64(p_->fp_, offset, fileSeek);
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
return std::fseek(p_->fp_,static_cast<long>(offset), fileSeek);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
int FileIo::seek(long offset, Position pos)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int fileSeek = 0;
|
|
Packit Service |
21b5d1 |
switch (pos) {
|
|
Packit Service |
21b5d1 |
case BasicIo::cur: fileSeek = SEEK_CUR; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::beg: fileSeek = SEEK_SET; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::end: fileSeek = SEEK_END; break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (p_->switchMode(Impl::opSeek) != 0) {
|
|
Packit Service |
21b5d1 |
return 1;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return std::fseek(p_->fp_, offset, fileSeek);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long FileIo::tell() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
return std::ftell(p_->fp_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t FileIo::size() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
// Flush and commit only if the file is open for writing
|
|
Packit Service |
21b5d1 |
if (p_->fp_ != 0 && (p_->openMode_[0] != 'r' || p_->openMode_[1] == '+')) {
|
|
Packit Service |
21b5d1 |
std::fflush(p_->fp_);
|
|
Packit Service |
21b5d1 |
#if defined WIN32 && !defined __CYGWIN__
|
|
Packit Service |
21b5d1 |
// This is required on msvcrt before stat after writing to a file
|
|
Packit Service |
21b5d1 |
_commit(_fileno(p_->fp_));
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
Impl::StructStat buf;
|
|
Packit Service |
21b5d1 |
int ret = p_->stat(buf);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (ret != 0) return -1;
|
|
Packit Service |
21b5d1 |
return buf.st_size;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::open()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
// Default open is in read-only binary mode
|
|
Packit Service |
21b5d1 |
return open("rb");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::open(const std::string& mode)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
close();
|
|
Packit Service |
21b5d1 |
p_->openMode_ = mode;
|
|
Packit Service |
21b5d1 |
p_->opMode_ = Impl::opSeek;
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
p_->fp_ = ::_wfopen(wpath().c_str(), s2ws(mode).c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_->fp_ = ::fopen(path().c_str(), mode.c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (!p_->fp_) return 1;
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool FileIo::isopen() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->fp_ != 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::close()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
int rc = 0;
|
|
Packit Service |
21b5d1 |
if (munmap() != 0) rc = 2;
|
|
Packit Service |
21b5d1 |
if (p_->fp_ != 0) {
|
|
Packit Service |
21b5d1 |
if (std::fclose(p_->fp_) != 0) rc |= 1;
|
|
Packit Service |
21b5d1 |
p_->fp_= 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return rc;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
DataBuf FileIo::read(long rcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
if ( (size_t) rcount > size() ) throw Error(kerInvalidMalloc);
|
|
Packit Service |
21b5d1 |
DataBuf buf(rcount);
|
|
Packit Service |
21b5d1 |
long readCount = read(buf.pData_, buf.size_);
|
|
Packit Service |
21b5d1 |
buf.size_ = readCount;
|
|
Packit Service |
21b5d1 |
return buf;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long FileIo::read(byte* buf, long rcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
if (p_->switchMode(Impl::opRead) != 0) {
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return (long)std::fread(buf, 1, rcount, p_->fp_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::getb()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
if (p_->switchMode(Impl::opRead) != 0) return EOF;
|
|
Packit Service |
21b5d1 |
return getc(p_->fp_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int FileIo::error() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->fp_ != 0 ? ferror(p_->fp_) : 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool FileIo::eof() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->fp_ != 0);
|
|
Packit Service |
21b5d1 |
return feof(p_->fp_) != 0 || tell() >= (long) size() ;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string FileIo::path() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpUnicode) {
|
|
Packit Service |
21b5d1 |
return ws2s(p_->wpath_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
return p_->path_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::wstring FileIo::wpath() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (p_->wpMode_ == Impl::wpStandard) {
|
|
Packit Service |
21b5d1 |
return s2ws(p_->path_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return p_->wpath_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void FileIo::populateFakeData() {
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//! Internal Pimpl structure of class MemIo.
|
|
Packit Service |
21b5d1 |
class MemIo::Impl {
|
|
Packit Service |
21b5d1 |
public:
|
|
Packit Service |
21b5d1 |
Impl(); //!< Default constructor
|
|
Packit Service |
21b5d1 |
Impl(const byte* data, long size); //!< Constructor 2
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// DATA
|
|
Packit Service |
21b5d1 |
byte* data_; //!< Pointer to the start of the memory area
|
|
Packit Service |
21b5d1 |
long idx_; //!< Index into the memory area
|
|
Packit Service |
21b5d1 |
long size_; //!< Size of the memory area
|
|
Packit Service |
21b5d1 |
long sizeAlloced_; //!< Size of the allocated buffer
|
|
Packit Service |
21b5d1 |
bool isMalloced_; //!< Was the buffer allocated?
|
|
Packit Service |
21b5d1 |
bool eof_; //!< EOF indicator
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// METHODS
|
|
Packit Service |
21b5d1 |
void reserve(long wcount); //!< Reserve memory
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
private:
|
|
Packit Service |
21b5d1 |
// NOT IMPLEMENTED
|
|
Packit Service |
21b5d1 |
Impl(const Impl& rhs); //!< Copy constructor
|
|
Packit Service |
21b5d1 |
Impl& operator=(const Impl& rhs); //!< Assignment
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
}; // class MemIo::Impl
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
MemIo::Impl::Impl()
|
|
Packit Service |
21b5d1 |
: data_(0),
|
|
Packit Service |
21b5d1 |
idx_(0),
|
|
Packit Service |
21b5d1 |
size_(0),
|
|
Packit Service |
21b5d1 |
sizeAlloced_(0),
|
|
Packit Service |
21b5d1 |
isMalloced_(false),
|
|
Packit Service |
21b5d1 |
eof_(false)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
MemIo::Impl::Impl(const byte* data, long size)
|
|
Packit Service |
21b5d1 |
: data_(const_cast<byte*>(data)),
|
|
Packit Service |
21b5d1 |
idx_(0),
|
|
Packit Service |
21b5d1 |
size_(size),
|
|
Packit Service |
21b5d1 |
sizeAlloced_(0),
|
|
Packit Service |
21b5d1 |
isMalloced_(false),
|
|
Packit Service |
21b5d1 |
eof_(false)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Utility class provides the block mapping to the part of data. This avoids allocating
|
|
Packit Service |
21b5d1 |
a single contiguous block of memory to the big data.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
class EXIV2API BlockMap {
|
|
Packit Service |
21b5d1 |
public:
|
|
Packit Service |
21b5d1 |
//! the status of the block.
|
|
Packit Service |
21b5d1 |
enum blockType_e {bNone, bKnown, bMemory};
|
|
Packit Service |
21b5d1 |
//! @name Creators
|
|
Packit Service |
21b5d1 |
//@{
|
|
Packit Service |
21b5d1 |
//! Default constructor. the init status of the block is bNone.
|
|
Packit Service |
21b5d1 |
BlockMap() : type_(bNone), data_(NULL), size_(0)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//! Destructor. Releases all managed memory.
|
|
Packit Service |
21b5d1 |
~BlockMap()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (data_) {
|
|
Packit Service |
21b5d1 |
std::free(data_);
|
|
Packit Service |
21b5d1 |
data_ = NULL;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//! @brief Populate the block.
|
|
Packit Service |
21b5d1 |
//! @param source The data populate to the block
|
|
Packit Service |
21b5d1 |
//! @param num The size of data
|
|
Packit Service |
21b5d1 |
void populate (byte* source, size_t num)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
size_ = num;
|
|
Packit Service |
21b5d1 |
data_ = (byte*)std::malloc(size_);
|
|
Packit Service |
21b5d1 |
type_ = bMemory;
|
|
Packit Service |
21b5d1 |
std::memcpy(data_, source, size_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Change the status to bKnow. bKnow blocks do not contain the data,
|
|
Packit Service |
21b5d1 |
but they keep the size of data. This avoids allocating memory for parts
|
|
Packit Service |
21b5d1 |
of the file that contain image-date (non-metadata/pixel data) which never change in exiv2.
|
|
Packit Service |
21b5d1 |
@param num The size of the data
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
void markKnown(size_t num)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
type_ = bKnown;
|
|
Packit Service |
21b5d1 |
size_ = num;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool isNone() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return type_ == bNone;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
bool isInMem () const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return type_ == bMemory;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
bool isKnown () const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return type_ == bKnown;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
byte* getData () const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return data_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
size_t getSize () const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return size_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
private:
|
|
Packit Service |
21b5d1 |
blockType_e type_;
|
|
Packit Service |
21b5d1 |
byte* data_;
|
|
Packit Service |
21b5d1 |
size_t size_;
|
|
Packit Service |
21b5d1 |
}; // class BlockMap
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void MemIo::Impl::reserve(long wcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
const long need = wcount + idx_;
|
|
Packit Service |
21b5d1 |
long blockSize = 32*1024; // 32768 `
|
|
Packit Service |
21b5d1 |
const long maxBlockSize = 4*1024*1024;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (!isMalloced_) {
|
|
Packit Service |
21b5d1 |
// Minimum size for 1st block
|
|
Packit Service |
21b5d1 |
long size = EXV_MAX(blockSize * (1 + need / blockSize), size_);
|
|
Packit Service |
21b5d1 |
byte* data = (byte*)std::malloc(size);
|
|
Packit Service |
21b5d1 |
if ( data == NULL ) {
|
|
Packit Service |
21b5d1 |
throw Error(kerMallocFailed);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (data_ != NULL) {
|
|
Packit Service |
21b5d1 |
std::memcpy(data, data_, size_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
data_ = data;
|
|
Packit Service |
21b5d1 |
sizeAlloced_ = size;
|
|
Packit Service |
21b5d1 |
isMalloced_ = true;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (need > size_) {
|
|
Packit Service |
21b5d1 |
if (need > sizeAlloced_) {
|
|
Packit Service |
21b5d1 |
blockSize = 2*sizeAlloced_ ;
|
|
Packit Service |
21b5d1 |
if ( blockSize > maxBlockSize ) blockSize = maxBlockSize ;
|
|
Packit Service |
21b5d1 |
// Allocate in blocks
|
|
Packit Service |
21b5d1 |
long want = blockSize * (1 + need / blockSize );
|
|
Packit Service |
21b5d1 |
data_ = (byte*)std::realloc(data_, want);
|
|
Packit Service |
21b5d1 |
if ( data_ == NULL ) {
|
|
Packit Service |
21b5d1 |
throw Error(kerMallocFailed);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
sizeAlloced_ = want;
|
|
Packit Service |
21b5d1 |
isMalloced_ = true;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
size_ = need;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
MemIo::MemIo()
|
|
Packit Service |
21b5d1 |
: p_(new Impl())
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
MemIo::MemIo(const byte* data, long size)
|
|
Packit Service |
21b5d1 |
: p_(new Impl(data, size))
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
MemIo::~MemIo()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (p_->isMalloced_) {
|
|
Packit Service |
21b5d1 |
std::free(p_->data_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long MemIo::write(const byte* data, long wcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_->reserve(wcount);
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
if (data != NULL) {
|
|
Packit Service |
21b5d1 |
std::memcpy(&p_->data_[p_->idx_], data, wcount);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->idx_ += wcount;
|
|
Packit Service |
21b5d1 |
return wcount;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void MemIo::transfer(BasicIo& src)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
MemIo *memIo = dynamic_cast<MemIo*>(&src;;
|
|
Packit Service |
21b5d1 |
if (memIo) {
|
|
Packit Service |
21b5d1 |
// Optimization if src is another instance of MemIo
|
|
Packit Service |
21b5d1 |
if (p_->isMalloced_) {
|
|
Packit Service |
21b5d1 |
std::free(p_->data_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->idx_ = 0;
|
|
Packit Service |
21b5d1 |
p_->data_ = memIo->p_->data_;
|
|
Packit Service |
21b5d1 |
p_->size_ = memIo->p_->size_;
|
|
Packit Service |
21b5d1 |
p_->isMalloced_ = memIo->p_->isMalloced_;
|
|
Packit Service |
21b5d1 |
memIo->p_->idx_ = 0;
|
|
Packit Service |
21b5d1 |
memIo->p_->data_ = 0;
|
|
Packit Service |
21b5d1 |
memIo->p_->size_ = 0;
|
|
Packit Service |
21b5d1 |
memIo->p_->isMalloced_ = false;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
else {
|
|
Packit Service |
21b5d1 |
// Generic reopen to reset position to start
|
|
Packit Service |
21b5d1 |
if (src.open() != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerDataSourceOpenFailed, src.path(), strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
p_->idx_ = 0;
|
|
Packit Service |
21b5d1 |
write(src);
|
|
Packit Service |
21b5d1 |
src.close();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
if (error() || src.error()) throw Error(kerMemoryTransferFailed, strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long MemIo::write(BasicIo& src)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (static_cast<BasicIo*>(this) == &src) return 0;
|
|
Packit Service |
21b5d1 |
if (!src.isopen()) return 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
byte buf[4096];
|
|
Packit Service |
21b5d1 |
long readCount = 0;
|
|
Packit Service |
21b5d1 |
long writeTotal = 0;
|
|
Packit Service |
21b5d1 |
while ((readCount = src.read(buf, sizeof(buf)))) {
|
|
Packit Service |
21b5d1 |
write(buf, readCount);
|
|
Packit Service |
21b5d1 |
writeTotal += readCount;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
return writeTotal;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int MemIo::putb(byte data)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_->reserve(1);
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
p_->data_[p_->idx_++] = data;
|
|
Packit Service |
21b5d1 |
return data;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if defined(_MSC_VER)
|
|
Packit Service |
21b5d1 |
int MemIo::seek( int64_t offset, Position pos )
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
int64_t newIdx = 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
switch (pos) {
|
|
Packit Service |
21b5d1 |
case BasicIo::cur: newIdx = p_->idx_ + offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::beg: newIdx = offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::end: newIdx = p_->size_ + offset; break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (newIdx < 0)
|
|
Packit Service |
21b5d1 |
return 1;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (static_cast<size_t>(newIdx) > p_->size_) {
|
|
Packit Service |
21b5d1 |
p_->eof_ = true;
|
|
Packit Service |
21b5d1 |
return 1;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
p_->idx_ = static_cast<long>(newIdx);
|
|
Packit Service |
21b5d1 |
p_->eof_ = false;
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
int MemIo::seek(long offset, Position pos)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
long newIdx = 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
switch (pos) {
|
|
Packit Service |
21b5d1 |
case BasicIo::cur: newIdx = p_->idx_ + offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::beg: newIdx = offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::end: newIdx = p_->size_ + offset; break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (newIdx < 0)
|
|
Packit Service |
21b5d1 |
return 1;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (newIdx > p_->size_) {
|
|
Packit Service |
21b5d1 |
p_->eof_ = true;
|
|
Packit Service |
21b5d1 |
return 1;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
p_->idx_ = newIdx;
|
|
Packit Service |
21b5d1 |
p_->eof_ = false;
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
byte* MemIo::mmap(bool /*isWriteable*/)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->data_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int MemIo::munmap()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long MemIo::tell() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->idx_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t MemIo::size() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->size_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int MemIo::open()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_->idx_ = 0;
|
|
Packit Service |
21b5d1 |
p_->eof_ = false;
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool MemIo::isopen() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return true;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int MemIo::close()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
DataBuf MemIo::read(long rcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
DataBuf buf(rcount);
|
|
Packit Service |
21b5d1 |
long readCount = read(buf.pData_, buf.size_);
|
|
Packit Service |
21b5d1 |
buf.size_ = readCount;
|
|
Packit Service |
21b5d1 |
return buf;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long MemIo::read(byte* buf, long rcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
long avail = EXV_MAX(p_->size_ - p_->idx_, 0);
|
|
Packit Service |
21b5d1 |
long allow = EXV_MIN(rcount, avail);
|
|
Packit Service |
21b5d1 |
std::memcpy(buf, &p_->data_[p_->idx_], allow);
|
|
Packit Service |
21b5d1 |
p_->idx_ += allow;
|
|
Packit Service |
21b5d1 |
if (rcount > avail) p_->eof_ = true;
|
|
Packit Service |
21b5d1 |
return allow;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int MemIo::getb()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (p_->idx_ >= p_->size_) {
|
|
Packit Service |
21b5d1 |
p_->eof_ = true;
|
|
Packit Service |
21b5d1 |
return EOF;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return p_->data_[p_->idx_++];
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int MemIo::error() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool MemIo::eof() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->eof_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string MemIo::path() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return "MemIo";
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::wstring MemIo::wpath() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return EXV_WIDEN("MemIo");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
void MemIo::populateFakeData() {
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if EXV_XPATH_MEMIO
|
|
Packit Service |
21b5d1 |
XPathIo::XPathIo(const std::string& path) {
|
|
Packit Service |
21b5d1 |
Protocol prot = fileProtocol(path);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (prot == pStdin) ReadStdin();
|
|
Packit Service |
21b5d1 |
else if (prot == pDataUri) ReadDataUri(path);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
XPathIo::XPathIo(const std::wstring& wpath) {
|
|
Packit Service |
21b5d1 |
std::string path;
|
|
Packit Service |
21b5d1 |
path.assign(wpath.begin(), wpath.end());
|
|
Packit Service |
21b5d1 |
Protocol prot = fileProtocol(path);
|
|
Packit Service |
21b5d1 |
if (prot == pStdin) ReadStdin();
|
|
Packit Service |
21b5d1 |
else if (prot == pDataUri) ReadDataUri(path);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void XPathIo::ReadStdin() {
|
|
Packit Service |
21b5d1 |
if (isatty(fileno(stdin)))
|
|
Packit Service |
21b5d1 |
throw Error(kerInputDataReadFailed);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef _O_BINARY
|
|
Packit Service |
21b5d1 |
// convert stdin to binary
|
|
Packit Service |
21b5d1 |
if (_setmode(_fileno(stdin), _O_BINARY) == -1)
|
|
Packit Service |
21b5d1 |
throw Error(kerInputDataReadFailed);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
char readBuf[100*1024];
|
|
Packit Service |
21b5d1 |
std::streamsize readBufSize = 0;
|
|
Packit Service |
21b5d1 |
do {
|
|
Packit Service |
21b5d1 |
std::cin.read(readBuf, sizeof(readBuf));
|
|
Packit Service |
21b5d1 |
readBufSize = std::cin.gcount();
|
|
Packit Service |
21b5d1 |
if (readBufSize > 0) {
|
|
Packit Service |
21b5d1 |
write((byte*)readBuf, (long)readBufSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
} while(readBufSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void XPathIo::ReadDataUri(const std::string& path) {
|
|
Packit Service |
21b5d1 |
size_t base64Pos = path.find("base64,");
|
|
Packit Service |
21b5d1 |
if (base64Pos == std::string::npos)
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "No base64 data");
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string data = path.substr(base64Pos+7);
|
|
Packit Service |
21b5d1 |
char* decodeData = new char[data.length()];
|
|
Packit Service |
21b5d1 |
long size = base64decode(data.c_str(), decodeData, data.length());
|
|
Packit Service |
21b5d1 |
if (size > 0)
|
|
Packit Service |
21b5d1 |
write((byte*)decodeData, size);
|
|
Packit Service |
21b5d1 |
else
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Unable to decode base 64.");
|
|
Packit Service |
21b5d1 |
delete[] decodeData;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
const std::string XPathIo::TEMP_FILE_EXT = ".exiv2_temp";
|
|
Packit Service |
21b5d1 |
const std::string XPathIo::GEN_FILE_EXT = ".exiv2";
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
XPathIo::XPathIo(const std::string& orgPath) : FileIo(XPathIo::writeDataToFile(orgPath)) {
|
|
Packit Service |
21b5d1 |
isTemp_ = true;
|
|
Packit Service |
21b5d1 |
tempFilePath_ = path();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
XPathIo::XPathIo(const std::wstring& wOrgPathpath) : FileIo(XPathIo::writeDataToFile(wOrgPathpath)) {
|
|
Packit Service |
21b5d1 |
isTemp_ = true;
|
|
Packit Service |
21b5d1 |
tempFilePath_ = path();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
XPathIo::~XPathIo() {
|
|
Packit Service |
21b5d1 |
if (isTemp_ && remove(tempFilePath_.c_str()) != 0) {
|
|
Packit Service |
21b5d1 |
// error when removing file
|
|
Packit Service |
21b5d1 |
// printf ("Warning: Unable to remove the temp file %s.\n", tempFilePath_.c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void XPathIo::transfer(BasicIo& src) {
|
|
Packit Service |
21b5d1 |
if (isTemp_) {
|
|
Packit Service |
21b5d1 |
// replace temp path to gent path.
|
|
Packit Service |
21b5d1 |
std::string currentPath = path();
|
|
Packit Service |
21b5d1 |
setPath(ReplaceStringInPlace(currentPath, XPathIo::TEMP_FILE_EXT, XPathIo::GEN_FILE_EXT));
|
|
Packit Service |
21b5d1 |
// rename the file
|
|
Packit Service |
21b5d1 |
tempFilePath_ = path();
|
|
Packit Service |
21b5d1 |
if (rename(currentPath.c_str(), tempFilePath_.c_str()) != 0) {
|
|
Packit Service |
21b5d1 |
// printf("Warning: Failed to rename the temp file. \n");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
isTemp_ = false;
|
|
Packit Service |
21b5d1 |
// call super class method
|
|
Packit Service |
21b5d1 |
FileIo::transfer(src);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string XPathIo::writeDataToFile(const std::string& orgPath) {
|
|
Packit Service |
21b5d1 |
Protocol prot = fileProtocol(orgPath);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// generating the name for temp file.
|
|
Packit Service |
21b5d1 |
std::time_t timestamp = std::time(NULL);
|
|
Packit Service |
21b5d1 |
std::stringstream ss;
|
|
Packit Service |
21b5d1 |
ss << timestamp << XPathIo::TEMP_FILE_EXT;
|
|
Packit Service |
21b5d1 |
std::string path = ss.str();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (prot == pStdin) {
|
|
Packit Service |
21b5d1 |
if (isatty(fileno(stdin)))
|
|
Packit Service |
21b5d1 |
throw Error(kerInputDataReadFailed);
|
|
Packit Service |
21b5d1 |
#if defined(_MSC_VER) || defined(__MINGW__)
|
|
Packit Service |
21b5d1 |
// convert stdin to binary
|
|
Packit Service |
21b5d1 |
if (_setmode(_fileno(stdin), _O_BINARY) == -1)
|
|
Packit Service |
21b5d1 |
throw Error(kerInputDataReadFailed);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
std::ofstream fs(path.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
|
|
Packit Service |
21b5d1 |
// read stdin and write to the temp file.
|
|
Packit Service |
21b5d1 |
char readBuf[100*1024];
|
|
Packit Service |
21b5d1 |
std::streamsize readBufSize = 0;
|
|
Packit Service |
21b5d1 |
do {
|
|
Packit Service |
21b5d1 |
std::cin.read(readBuf, sizeof(readBuf));
|
|
Packit Service |
21b5d1 |
readBufSize = std::cin.gcount();
|
|
Packit Service |
21b5d1 |
if (readBufSize > 0) {
|
|
Packit Service |
21b5d1 |
fs.write (readBuf, readBufSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
} while(readBufSize);
|
|
Packit Service |
21b5d1 |
fs.close();
|
|
Packit Service |
21b5d1 |
} else if (prot == pDataUri) {
|
|
Packit Service |
21b5d1 |
std::ofstream fs(path.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
|
|
Packit Service |
21b5d1 |
// read data uri and write to the temp file.
|
|
Packit Service |
21b5d1 |
size_t base64Pos = orgPath.find("base64,");
|
|
Packit Service |
21b5d1 |
if (base64Pos == std::string::npos) {
|
|
Packit Service |
21b5d1 |
fs.close();
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "No base64 data");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string data = orgPath.substr(base64Pos+7);
|
|
Packit Service |
21b5d1 |
char* decodeData = new char[data.length()];
|
|
Packit Service |
21b5d1 |
long size = base64decode(data.c_str(), decodeData, data.length());
|
|
Packit Service |
21b5d1 |
if (size > 0) {
|
|
Packit Service |
21b5d1 |
fs.write(decodeData, size);
|
|
Packit Service |
21b5d1 |
fs.close();
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
fs.close();
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Unable to decode base 64.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
delete[] decodeData;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
return path;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::string XPathIo::writeDataToFile(const std::wstring& wOrgPath) {
|
|
Packit Service |
21b5d1 |
std::string orgPath;
|
|
Packit Service |
21b5d1 |
orgPath.assign(wOrgPath.begin(), wOrgPath.end());
|
|
Packit Service |
21b5d1 |
return XPathIo::writeDataToFile(orgPath);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//! Internal Pimpl abstract structure of class RemoteIo.
|
|
Packit Service |
21b5d1 |
class RemoteIo::Impl {
|
|
Packit Service |
21b5d1 |
public:
|
|
Packit Service |
21b5d1 |
//! Constructor
|
|
Packit Service |
21b5d1 |
Impl(const std::string& path, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
//! Constructor accepting a unicode path in an std::wstring
|
|
Packit Service |
21b5d1 |
Impl(const std::wstring& wpath, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
//! Destructor. Releases all managed memory.
|
|
Packit Service |
21b5d1 |
virtual ~Impl();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// DATA
|
|
Packit Service |
21b5d1 |
std::string path_; //!< (Standard) path
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::wstring wpath_; //!< Unicode path
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
size_t blockSize_; //!< Size of the block memory.
|
|
Packit Service |
21b5d1 |
BlockMap* blocksMap_; //!< An array contains all blocksMap
|
|
Packit Service |
21b5d1 |
size_t size_; //!< The file size
|
|
Packit Service |
21b5d1 |
long idx_; //!< Index into the memory area
|
|
Packit Service |
21b5d1 |
bool isMalloced_; //!< Was the blocksMap_ allocated?
|
|
Packit Service |
21b5d1 |
bool eof_; //!< EOF indicator
|
|
Packit Service |
21b5d1 |
Protocol protocol_; //!< the protocol of url
|
|
Packit Service |
21b5d1 |
uint32_t totalRead_; //!< bytes requested from host
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// METHODS
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the length (in bytes) of the remote file.
|
|
Packit Service |
21b5d1 |
@return Return -1 if the size is unknown. Otherwise it returns the length of remote file (in bytes).
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
virtual long getFileLength() = 0;
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the data by range.
|
|
Packit Service |
21b5d1 |
@param lowBlock The start block index.
|
|
Packit Service |
21b5d1 |
@param highBlock The end block index.
|
|
Packit Service |
21b5d1 |
@param response The data from the server.
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
@note Set lowBlock = -1 and highBlock = -1 to get the whole file content.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
virtual void getDataByRange(long lowBlock, long highBlock, std::string& response) = 0;
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Submit the data to the remote machine. The data replace a part of the remote file.
|
|
Packit Service |
21b5d1 |
The replaced part of remote file is indicated by from and to parameters.
|
|
Packit Service |
21b5d1 |
@param data The data are submitted to the remote machine.
|
|
Packit Service |
21b5d1 |
@param size The size of data.
|
|
Packit Service |
21b5d1 |
@param from The start position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@param to The end position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@note The write access is available on some protocols. HTTP and HTTPS require the script file
|
|
Packit Service |
21b5d1 |
on the remote machine to handle the data. SSH requires the permission to edit the file.
|
|
Packit Service |
21b5d1 |
@throw Error if it fails.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
virtual void writeRemote(const byte* data, size_t size, long from, long to) = 0;
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the data from the remote machine and write them to the memory blocks.
|
|
Packit Service |
21b5d1 |
@param lowBlock The start block index.
|
|
Packit Service |
21b5d1 |
@param highBlock The end block index.
|
|
Packit Service |
21b5d1 |
@return Number of bytes written to the memory block successfully
|
|
Packit Service |
21b5d1 |
@throw Error if it fails.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
virtual size_t populateBlocks(size_t lowBlock, size_t highBlock);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
}; // class RemoteIo::Impl
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
RemoteIo::Impl::Impl(const std::string& url, size_t blockSize)
|
|
Packit Service |
21b5d1 |
: path_(url), blockSize_(blockSize), blocksMap_(0), size_(0),
|
|
Packit Service |
21b5d1 |
idx_(0), isMalloced_(false), eof_(false), protocol_(fileProtocol(url)),totalRead_(0)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
RemoteIo::Impl::Impl(const std::wstring& wurl, size_t blockSize)
|
|
Packit Service |
21b5d1 |
: wpath_(wurl), blockSize_(blockSize), blocksMap_(0), size_(0),
|
|
Packit Service |
21b5d1 |
idx_(0), isMalloced_(false), eof_(false), protocol_(fileProtocol(wurl))
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t RemoteIo::Impl::populateBlocks(size_t lowBlock, size_t highBlock)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(isMalloced_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// optimize: ignore all true blocks on left & right sides.
|
|
Packit Service |
21b5d1 |
while(!blocksMap_[lowBlock].isNone() && lowBlock < highBlock) lowBlock++;
|
|
Packit Service |
21b5d1 |
while(!blocksMap_[highBlock].isNone() && highBlock > lowBlock) highBlock--;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t rcount = 0;
|
|
Packit Service |
21b5d1 |
if (blocksMap_[highBlock].isNone())
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
std::string data;
|
|
Packit Service |
21b5d1 |
getDataByRange( (long) lowBlock, (long) highBlock, data);
|
|
Packit Service |
21b5d1 |
rcount = data.length();
|
|
Packit Service |
21b5d1 |
if (rcount == 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Data By Range is empty. Please check the permission.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
byte* source = (byte*)data.c_str();
|
|
Packit Service |
21b5d1 |
size_t remain = rcount, totalRead = 0;
|
|
Packit Service |
21b5d1 |
size_t iBlock = (rcount == size_) ? 0 : lowBlock;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
while (remain) {
|
|
Packit Service |
21b5d1 |
size_t allow = EXV_MIN(remain, blockSize_);
|
|
Packit Service |
21b5d1 |
blocksMap_[iBlock].populate(&source[totalRead], allow);
|
|
Packit Service |
21b5d1 |
remain -= allow;
|
|
Packit Service |
21b5d1 |
totalRead += allow;
|
|
Packit Service |
21b5d1 |
iBlock++;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
return rcount;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
RemoteIo::Impl::~Impl() {
|
|
Packit Service |
21b5d1 |
if (blocksMap_) delete[] blocksMap_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
RemoteIo::~RemoteIo()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (p_) {
|
|
Packit Service |
21b5d1 |
close();
|
|
Packit Service |
21b5d1 |
delete p_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int RemoteIo::open()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
close(); // reset the IO position
|
|
Packit Service |
21b5d1 |
bigBlock_ = NULL;
|
|
Packit Service |
21b5d1 |
if (p_->isMalloced_ == false) {
|
|
Packit Service |
21b5d1 |
long length = p_->getFileLength();
|
|
Packit Service |
21b5d1 |
if (length < 0) { // unable to get the length of remote file, get the whole file content.
|
|
Packit Service |
21b5d1 |
std::string data;
|
|
Packit Service |
21b5d1 |
p_->getDataByRange(-1, -1, data);
|
|
Packit Service |
21b5d1 |
p_->size_ = data.length();
|
|
Packit Service |
21b5d1 |
size_t nBlocks = (p_->size_ + p_->blockSize_ - 1) / p_->blockSize_;
|
|
Packit Service |
21b5d1 |
p_->blocksMap_ = new BlockMap[nBlocks];
|
|
Packit Service |
21b5d1 |
p_->isMalloced_ = true;
|
|
Packit Service |
21b5d1 |
byte* source = (byte*)data.c_str();
|
|
Packit Service |
21b5d1 |
size_t remain = p_->size_, iBlock = 0, totalRead = 0;
|
|
Packit Service |
21b5d1 |
while (remain) {
|
|
Packit Service |
21b5d1 |
size_t allow = EXV_MIN(remain, p_->blockSize_);
|
|
Packit Service |
21b5d1 |
p_->blocksMap_[iBlock].populate(&source[totalRead], allow);
|
|
Packit Service |
21b5d1 |
remain -= allow;
|
|
Packit Service |
21b5d1 |
totalRead += allow;
|
|
Packit Service |
21b5d1 |
iBlock++;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
} else if (length == 0) { // file is empty
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "the file length is 0");
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
p_->size_ = (size_t) length;
|
|
Packit Service |
21b5d1 |
size_t nBlocks = (p_->size_ + p_->blockSize_ - 1) / p_->blockSize_;
|
|
Packit Service |
21b5d1 |
p_->blocksMap_ = new BlockMap[nBlocks];
|
|
Packit Service |
21b5d1 |
p_->isMalloced_ = true;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return 0; // means OK
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int RemoteIo::close()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (p_->isMalloced_) {
|
|
Packit Service |
21b5d1 |
p_->eof_ = false;
|
|
Packit Service |
21b5d1 |
p_->idx_ = 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit Service |
21b5d1 |
std::cerr << "RemoteIo::close totalRead_ = " << p_->totalRead_ << std::endl;
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
if ( bigBlock_ ) {
|
|
Packit Service |
21b5d1 |
delete [] bigBlock_;
|
|
Packit Service |
21b5d1 |
bigBlock_=NULL;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long RemoteIo::write(const byte* /* unused data*/, long /* unused wcount*/)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return 0; // means failure
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long RemoteIo::write(BasicIo& src)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
if (!src.isopen()) return 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
/*
|
|
Packit Service |
21b5d1 |
* The idea is to compare the file content, find the different bytes and submit them to the remote machine.
|
|
Packit Service |
21b5d1 |
* To simplify it, it:
|
|
Packit Service |
21b5d1 |
* + goes from the left, find the first different position -> $left
|
|
Packit Service |
21b5d1 |
* + goes from the right, find the first different position -> $right
|
|
Packit Service |
21b5d1 |
* The different bytes are [$left-$right] part.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
size_t left = 0;
|
|
Packit Service |
21b5d1 |
size_t right = 0;
|
|
Packit Service |
21b5d1 |
size_t blockIndex = 0;
|
|
Packit Service |
21b5d1 |
size_t i = 0;
|
|
Packit Service |
21b5d1 |
size_t readCount = 0;
|
|
Packit Service |
21b5d1 |
size_t blockSize = 0;
|
|
Packit Service |
21b5d1 |
byte* buf = (byte*) std::malloc(p_->blockSize_);
|
|
Packit Service |
21b5d1 |
size_t nBlocks = (p_->size_ + p_->blockSize_ - 1) / p_->blockSize_;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// find $left
|
|
Packit Service |
21b5d1 |
src.seek(0, BasicIo::beg);
|
|
Packit Service |
21b5d1 |
bool findDiff = false;
|
|
Packit Service |
21b5d1 |
while (blockIndex < nBlocks && !src.eof() && !findDiff) {
|
|
Packit Service |
21b5d1 |
blockSize = p_->blocksMap_[blockIndex].getSize();
|
|
Packit Service |
21b5d1 |
bool isFakeData = p_->blocksMap_[blockIndex].isKnown(); // fake data
|
|
Packit Service |
21b5d1 |
readCount = (size_t) src.read(buf, (long) blockSize);
|
|
Packit Service |
21b5d1 |
byte* blockData = p_->blocksMap_[blockIndex].getData();
|
|
Packit Service |
21b5d1 |
for (i = 0; (i < readCount) && (i < blockSize) && !findDiff; i++) {
|
|
Packit Service |
21b5d1 |
if ((!isFakeData && buf[i] != blockData[i]) || (isFakeData && buf[i] != 0)) {
|
|
Packit Service |
21b5d1 |
findDiff = true;
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
left++;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
blockIndex++;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// find $right
|
|
Packit Service |
21b5d1 |
findDiff = false;
|
|
Packit Service |
21b5d1 |
blockIndex = nBlocks - 1;
|
|
Packit Service |
21b5d1 |
blockSize = p_->blocksMap_[blockIndex].getSize();
|
|
Packit Service |
21b5d1 |
while ((blockIndex + 1 > 0) && right < src.size() && !findDiff) {
|
|
Packit Service |
21b5d1 |
if(src.seek(-1 * (blockSize + right), BasicIo::end)) {
|
|
Packit Service |
21b5d1 |
findDiff = true;
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
bool isFakeData = p_->blocksMap_[blockIndex].isKnown(); // fake data
|
|
Packit Service |
21b5d1 |
readCount = src.read(buf, (long) blockSize);
|
|
Packit Service |
21b5d1 |
byte* blockData = p_->blocksMap_[blockIndex].getData();
|
|
Packit Service |
21b5d1 |
for (i = 0; (i < readCount) && (i < blockSize) && !findDiff; i++) {
|
|
Packit Service |
21b5d1 |
if ((!isFakeData && buf[readCount - i - 1] != blockData[blockSize - i - 1]) || (isFakeData && buf[readCount - i - 1] != 0)) {
|
|
Packit Service |
21b5d1 |
findDiff = true;
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
right++;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
blockIndex--;
|
|
Packit Service |
21b5d1 |
blockSize = (long)p_->blocksMap_[blockIndex].getSize();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// free buf
|
|
Packit Service |
21b5d1 |
if (buf) std::free(buf);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// submit to the remote machine.
|
|
Packit Service |
21b5d1 |
long dataSize = (long) (src.size() - left - right);
|
|
Packit Service |
21b5d1 |
if (dataSize > 0) {
|
|
Packit Service |
21b5d1 |
byte* data = (byte*) std::malloc(dataSize);
|
|
Packit Service |
21b5d1 |
src.seek(left, BasicIo::beg);
|
|
Packit Service |
21b5d1 |
src.read(data, dataSize);
|
|
Packit Service |
21b5d1 |
p_->writeRemote(data, (size_t)dataSize, (long)left, (long) (p_->size_ - right));
|
|
Packit Service |
21b5d1 |
if (data) std::free(data);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return (long) src.size();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int RemoteIo::putb(byte /*unused data*/)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
DataBuf RemoteIo::read(long rcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
DataBuf buf(rcount);
|
|
Packit Service |
21b5d1 |
long readCount = read(buf.pData_, buf.size_);
|
|
Packit Service |
21b5d1 |
buf.size_ = readCount;
|
|
Packit Service |
21b5d1 |
return buf;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long RemoteIo::read(byte* buf, long rcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
if (p_->eof_) return 0;
|
|
Packit Service |
21b5d1 |
p_->totalRead_ += rcount;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t allow = EXV_MIN(rcount, (long)( p_->size_ - p_->idx_));
|
|
Packit Service |
21b5d1 |
size_t lowBlock = p_->idx_ /p_->blockSize_;
|
|
Packit Service |
21b5d1 |
size_t highBlock = (p_->idx_ + allow)/p_->blockSize_;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// connect to the remote machine & populate the blocks just in time.
|
|
Packit Service |
21b5d1 |
p_->populateBlocks(lowBlock, highBlock);
|
|
Packit Service |
21b5d1 |
byte* fakeData = (byte*) std::calloc(p_->blockSize_, sizeof(byte));
|
|
Packit Service |
21b5d1 |
if (!fakeData) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Unable to allocate data");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t iBlock = lowBlock;
|
|
Packit Service |
21b5d1 |
size_t startPos = p_->idx_ - lowBlock*p_->blockSize_;
|
|
Packit Service |
21b5d1 |
size_t totalRead = 0;
|
|
Packit Service |
21b5d1 |
do {
|
|
Packit Service |
21b5d1 |
byte* data = p_->blocksMap_[iBlock++].getData();
|
|
Packit Service |
21b5d1 |
if (data == NULL) data = fakeData;
|
|
Packit Service |
21b5d1 |
size_t blockR = EXV_MIN(allow, p_->blockSize_ - startPos);
|
|
Packit Service |
21b5d1 |
std::memcpy(&buf[totalRead], &data[startPos], blockR);
|
|
Packit Service |
21b5d1 |
totalRead += blockR;
|
|
Packit Service |
21b5d1 |
startPos = 0;
|
|
Packit Service |
21b5d1 |
allow -= blockR;
|
|
Packit Service |
21b5d1 |
} while(allow);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (fakeData) std::free(fakeData);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
p_->idx_ += (long) totalRead;
|
|
Packit Service |
21b5d1 |
p_->eof_ = (p_->idx_ == (long) p_->size_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
return (long) totalRead;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int RemoteIo::getb()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
if (p_->idx_ == (long)p_->size_) {
|
|
Packit Service |
21b5d1 |
p_->eof_ = true;
|
|
Packit Service |
21b5d1 |
return EOF;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t expectedBlock = (p_->idx_ + 1)/p_->blockSize_;
|
|
Packit Service |
21b5d1 |
// connect to the remote machine & populate the blocks just in time.
|
|
Packit Service |
21b5d1 |
p_->populateBlocks(expectedBlock, expectedBlock);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
byte* data = p_->blocksMap_[expectedBlock].getData();
|
|
Packit Service |
21b5d1 |
return data[p_->idx_++ - expectedBlock*p_->blockSize_];
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void RemoteIo::transfer(BasicIo& src)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (src.open() != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "unable to open src when transferring");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
write(src);
|
|
Packit Service |
21b5d1 |
src.close();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#if defined(_MSC_VER)
|
|
Packit Service |
21b5d1 |
int RemoteIo::seek( int64_t offset, Position pos )
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
uint64_t newIdx = 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
switch (pos) {
|
|
Packit Service |
21b5d1 |
case BasicIo::cur: newIdx = p_->idx_ + offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::beg: newIdx = offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::end: newIdx = p_->size_ + offset; break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if ( /*newIdx < 0 || */ newIdx > static_cast<uint64_t>(p_->size_) ) return 1;
|
|
Packit Service |
21b5d1 |
p_->idx_ = static_cast<long>(newIdx); //not very sure about this. need more test!! - note by Shawn fly2xj@gmail.com //TODO
|
|
Packit Service |
21b5d1 |
p_->eof_ = false;
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#else
|
|
Packit Service |
21b5d1 |
int RemoteIo::seek(long offset, Position pos)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
long newIdx = 0;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
switch (pos) {
|
|
Packit Service |
21b5d1 |
case BasicIo::cur: newIdx = p_->idx_ + offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::beg: newIdx = offset; break;
|
|
Packit Service |
21b5d1 |
case BasicIo::end: newIdx = p_->size_ + offset; break;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// #1198. Don't return 1 when asked to seek past EOF. Stay calm and set eof_
|
|
Packit Service |
21b5d1 |
// if (newIdx < 0 || newIdx > (long) p_->size_) return 1;
|
|
Packit Service |
21b5d1 |
p_->idx_ = newIdx;
|
|
Packit Service |
21b5d1 |
p_->eof_ = newIdx > (long) p_->size_;
|
|
Packit Service |
21b5d1 |
if ( p_->idx_ > (long) p_->size_ ) p_->idx_= (long) p_->size_;
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
byte* RemoteIo::mmap(bool /*isWriteable*/)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
size_t nRealData = 0 ;
|
|
Packit Service |
21b5d1 |
if ( !bigBlock_ ) {
|
|
Packit Service |
21b5d1 |
size_t blockSize = p_->blockSize_;
|
|
Packit Service |
21b5d1 |
size_t blocks = (p_->size_ + blockSize -1)/blockSize ;
|
|
Packit Service |
21b5d1 |
bigBlock_ = new byte[blocks*blockSize] ;
|
|
Packit Service |
21b5d1 |
for ( size_t block = 0 ; block < blocks ; block ++ ) {
|
|
Packit Service |
21b5d1 |
void* p = p_->blocksMap_[block].getData();
|
|
Packit Service |
21b5d1 |
if ( p ) {
|
|
Packit Service |
21b5d1 |
nRealData += blockSize ;
|
|
Packit Service |
21b5d1 |
memcpy(bigBlock_+(block*blockSize),p,blockSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXIV2_DEBUG_MESSAGES
|
|
Packit Service |
21b5d1 |
std::cerr << "RemoteIo::mmap nRealData = " << nRealData << std::endl;
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
return bigBlock_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int RemoteIo::munmap()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long RemoteIo::tell() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->idx_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
size_t RemoteIo::size() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return (long) p_->size_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool RemoteIo::isopen() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->isMalloced_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int RemoteIo::error() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return 0;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
bool RemoteIo::eof() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->eof_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string RemoteIo::path() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->path_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::wstring RemoteIo::wpath() const
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
return p_->wpath_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void RemoteIo::populateFakeData()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
assert(p_->isMalloced_);
|
|
Packit Service |
21b5d1 |
size_t nBlocks = (p_->size_ + p_->blockSize_ - 1) / p_->blockSize_;
|
|
Packit Service |
21b5d1 |
for (size_t i = 0; i < nBlocks; i++) {
|
|
Packit Service |
21b5d1 |
if (p_->blocksMap_[i].isNone())
|
|
Packit Service |
21b5d1 |
p_->blocksMap_[i].markKnown(p_->blockSize_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//! Internal Pimpl structure of class HttpIo.
|
|
Packit Service |
21b5d1 |
class HttpIo::HttpImpl : public Impl {
|
|
Packit Service |
21b5d1 |
public:
|
|
Packit Service |
21b5d1 |
//! Constructor
|
|
Packit Service |
21b5d1 |
HttpImpl(const std::string& path, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
//! Constructor accepting a unicode path in an std::wstring
|
|
Packit Service |
21b5d1 |
HttpImpl(const std::wstring& wpath, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
Exiv2::Uri hostInfo_; //!< the host information extracted from the path
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// METHODS
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the length (in bytes) of the remote file.
|
|
Packit Service |
21b5d1 |
@return Return -1 if the size is unknown. Otherwise it returns the length of remote file (in bytes).
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
long getFileLength();
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the data by range.
|
|
Packit Service |
21b5d1 |
@param lowBlock The start block index.
|
|
Packit Service |
21b5d1 |
@param highBlock The end block index.
|
|
Packit Service |
21b5d1 |
@param response The data from the server.
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
@note Set lowBlock = -1 and highBlock = -1 to get the whole file content.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
void getDataByRange(long lowBlock, long highBlock, std::string& response);
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Submit the data to the remote machine. The data replace a part of the remote file.
|
|
Packit Service |
21b5d1 |
The replaced part of remote file is indicated by from and to parameters.
|
|
Packit Service |
21b5d1 |
@param data The data are submitted to the remote machine.
|
|
Packit Service |
21b5d1 |
@param size The size of data.
|
|
Packit Service |
21b5d1 |
@param from The start position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@param to The end position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@note The data are submitted to the remote machine via POST. This requires the script file
|
|
Packit Service |
21b5d1 |
on the remote machine to receive the data and edit the remote file. The server-side
|
|
Packit Service |
21b5d1 |
script may be specified with the environment string EXIV2_HTTP_POST. The default value is
|
|
Packit Service |
21b5d1 |
"/exiv2.php". More info is available at http://dev.exiv2.org/wiki/exiv2
|
|
Packit Service |
21b5d1 |
@throw Error if it fails.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
void writeRemote(const byte* data, size_t size, long from, long to);
|
|
Packit Service |
21b5d1 |
protected:
|
|
Packit Service |
21b5d1 |
// NOT IMPLEMENTED
|
|
Packit Service |
21b5d1 |
HttpImpl(const HttpImpl& rhs); //!< Copy constructor
|
|
Packit Service |
21b5d1 |
HttpImpl& operator=(const HttpImpl& rhs); //!< Assignment
|
|
Packit Service |
21b5d1 |
}; // class HttpIo::HttpImpl
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
HttpIo::HttpImpl::HttpImpl(const std::string& url, size_t blockSize):Impl(url, blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
hostInfo_ = Exiv2::Uri::Parse(url);
|
|
Packit Service |
21b5d1 |
Exiv2::Uri::Decode(hostInfo_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
HttpIo::HttpImpl::HttpImpl(const std::wstring& wurl, size_t blockSize):Impl(wurl, blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
std::string url;
|
|
Packit Service |
21b5d1 |
url.assign(wurl.begin(), wurl.end());
|
|
Packit Service |
21b5d1 |
path_ = url;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
hostInfo_ = Exiv2::Uri::Parse(url);
|
|
Packit Service |
21b5d1 |
Exiv2::Uri::Decode(hostInfo_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long HttpIo::HttpImpl::getFileLength()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
Exiv2::Dictionary response;
|
|
Packit Service |
21b5d1 |
Exiv2::Dictionary request;
|
|
Packit Service |
21b5d1 |
std::string errors;
|
|
Packit Service |
21b5d1 |
request["server"] = hostInfo_.Host;
|
|
Packit Service |
21b5d1 |
request["page" ] = hostInfo_.Path;
|
|
Packit Service |
21b5d1 |
if (hostInfo_.Port != "") request["port"] = hostInfo_.Port;
|
|
Packit Service |
21b5d1 |
request["verb"] = "HEAD";
|
|
Packit Service |
21b5d1 |
long serverCode = (long)http(request, response, errors);
|
|
Packit Service |
21b5d1 |
if (serverCode < 0 || serverCode >= 400 || errors.compare("") != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerTiffDirectoryTooLarge, "Server", serverCode);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
Exiv2::Dictionary_i lengthIter = response.find("Content-Length");
|
|
Packit Service |
21b5d1 |
return (lengthIter == response.end()) ? -1 : atol((lengthIter->second).c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void HttpIo::HttpImpl::getDataByRange(long lowBlock, long highBlock, std::string& response)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
Exiv2::Dictionary responseDic;
|
|
Packit Service |
21b5d1 |
Exiv2::Dictionary request;
|
|
Packit Service |
21b5d1 |
request["server"] = hostInfo_.Host;
|
|
Packit Service |
21b5d1 |
request["page" ] = hostInfo_.Path;
|
|
Packit Service |
21b5d1 |
if (hostInfo_.Port != "") request["port"] = hostInfo_.Port;
|
|
Packit Service |
21b5d1 |
request["verb"] = "GET";
|
|
Packit Service |
21b5d1 |
std::string errors;
|
|
Packit Service |
21b5d1 |
if (lowBlock > -1 && highBlock > -1) {
|
|
Packit Service |
21b5d1 |
std::stringstream ss;
|
|
Packit Service |
21b5d1 |
ss << "Range: bytes=" << lowBlock * blockSize_ << "-" << ((highBlock + 1) * blockSize_ - 1) << "\r\n";
|
|
Packit Service |
21b5d1 |
request["header"] = ss.str();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long serverCode = (long)http(request, responseDic, errors);
|
|
Packit Service |
21b5d1 |
if (serverCode < 0 || serverCode >= 400 || errors.compare("") != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerTiffDirectoryTooLarge, "Server", serverCode);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
response = responseDic["body"];
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void HttpIo::HttpImpl::writeRemote(const byte* data, size_t size, long from, long to)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
std::string scriptPath(getEnv(envHTTPPOST));
|
|
Packit Service |
21b5d1 |
if (scriptPath == "") {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Please set the path of the server script to handle http post data to EXIV2_HTTP_POST environmental variable.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// standadize the path without "/" at the beginning.
|
|
Packit Service |
21b5d1 |
std::size_t protocolIndex = scriptPath.find("://");
|
|
Packit Service |
21b5d1 |
if (protocolIndex == std::string::npos && scriptPath[0] != '/') {
|
|
Packit Service |
21b5d1 |
scriptPath = "/" + scriptPath;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
Exiv2::Dictionary response;
|
|
Packit Service |
21b5d1 |
Exiv2::Dictionary request;
|
|
Packit Service |
21b5d1 |
std::string errors;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
Uri scriptUri = Exiv2::Uri::Parse(scriptPath);
|
|
Packit Service |
21b5d1 |
request["server"] = scriptUri.Host == "" ? hostInfo_.Host : scriptUri.Host;
|
|
Packit Service |
21b5d1 |
if (scriptUri.Port != "") request["port"] = scriptUri.Port;
|
|
Packit Service |
21b5d1 |
request["page"] = scriptUri.Path;
|
|
Packit Service |
21b5d1 |
request["verb"] = "POST";
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// encode base64
|
|
Packit Service |
21b5d1 |
size_t encodeLength = ((size + 2) / 3) * 4 + 1;
|
|
Packit Service |
21b5d1 |
char* encodeData = new char[encodeLength];
|
|
Packit Service |
21b5d1 |
base64encode(data, size, encodeData, encodeLength);
|
|
Packit Service |
21b5d1 |
// url encode
|
|
Packit Service |
21b5d1 |
const std::string urlencodeData = urlencode(encodeData);
|
|
Packit Service |
21b5d1 |
delete[] encodeData;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::stringstream ss;
|
|
Packit Service |
21b5d1 |
ss << "path=" << hostInfo_.Path << "&"
|
|
Packit Service |
21b5d1 |
<< "from=" << from << "&"
|
|
Packit Service |
21b5d1 |
<< "to=" << to << "&"
|
|
Packit Service |
21b5d1 |
<< "data=" << urlencodeData;
|
|
Packit Service |
21b5d1 |
std::string postData = ss.str();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// create the header
|
|
Packit Service |
21b5d1 |
ss.str("");
|
|
Packit Service |
21b5d1 |
ss << "Content-Length: " << postData.length() << "\n"
|
|
Packit Service |
21b5d1 |
<< "Content-Type: application/x-www-form-urlencoded\n"
|
|
Packit Service |
21b5d1 |
<< "\n" << postData << "\r\n";
|
|
Packit Service |
21b5d1 |
request["header"] = ss.str();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
int serverCode = http(request, response, errors);
|
|
Packit Service |
21b5d1 |
if (serverCode < 0 || serverCode >= 400 || errors.compare("") != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerTiffDirectoryTooLarge, "Server", serverCode);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
HttpIo::HttpIo(const std::string& url, size_t blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_ = new HttpImpl(url, blockSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
HttpIo::HttpIo(const std::wstring& wurl, size_t blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_ = new HttpImpl(wurl, blockSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_USE_CURL
|
|
Packit Service |
21b5d1 |
//! Internal Pimpl structure of class RemoteIo.
|
|
Packit Service |
21b5d1 |
class CurlIo::CurlImpl : public Impl {
|
|
Packit Service |
21b5d1 |
public:
|
|
Packit Service |
21b5d1 |
//! Constructor
|
|
Packit Service |
21b5d1 |
CurlImpl(const std::string& path, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
//! Constructor accepting a unicode path in an std::wstring
|
|
Packit Service |
21b5d1 |
CurlImpl(const std::wstring& wpath, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
//! Destructor. Cleans up the curl pointer and releases all managed memory.
|
|
Packit Service |
21b5d1 |
~CurlImpl();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
CURL* curl_; //!< libcurl pointer
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// METHODS
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the length (in bytes) of the remote file.
|
|
Packit Service |
21b5d1 |
@return Return -1 if the size is unknown. Otherwise it returns the length of remote file (in bytes).
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
long getFileLength();
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the data by range.
|
|
Packit Service |
21b5d1 |
@param lowBlock The start block index.
|
|
Packit Service |
21b5d1 |
@param highBlock The end block index.
|
|
Packit Service |
21b5d1 |
@param response The data from the server.
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
@note Set lowBlock = -1 and highBlock = -1 to get the whole file content.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
void getDataByRange(long lowBlock, long highBlock, std::string& response);
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Submit the data to the remote machine. The data replace a part of the remote file.
|
|
Packit Service |
21b5d1 |
The replaced part of remote file is indicated by from and to parameters.
|
|
Packit Service |
21b5d1 |
@param data The data are submitted to the remote machine.
|
|
Packit Service |
21b5d1 |
@param size The size of data.
|
|
Packit Service |
21b5d1 |
@param from The start position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@param to The end position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@throw Error if it fails.
|
|
Packit Service |
21b5d1 |
@note The write access is only available on HTTP & HTTPS protocols. The data are submitted to server
|
|
Packit Service |
21b5d1 |
via POST method. It requires the script file on the remote machine to receive the data
|
|
Packit Service |
21b5d1 |
and edit the remote file. The server-side script may be specified with the environment
|
|
Packit Service |
21b5d1 |
string EXIV2_HTTP_POST. The default value is "/exiv2.php". More info is available at
|
|
Packit Service |
21b5d1 |
http://dev.exiv2.org/wiki/exiv2
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
void writeRemote(const byte* data, size_t size, long from, long to);
|
|
Packit Service |
21b5d1 |
protected:
|
|
Packit Service |
21b5d1 |
// NOT IMPLEMENTED
|
|
Packit Service |
21b5d1 |
CurlImpl(const CurlImpl& rhs); //!< Copy constructor
|
|
Packit Service |
21b5d1 |
CurlImpl& operator=(const CurlImpl& rhs); //!< Assignment
|
|
Packit Service |
21b5d1 |
private:
|
|
Packit Service |
21b5d1 |
long timeout_; //!< The number of seconds to wait while trying to connect.
|
|
Packit Service |
21b5d1 |
}; // class RemoteIo::Impl
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
CurlIo::CurlImpl::CurlImpl(const std::string& url, size_t blockSize):Impl(url, blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
// init curl pointer
|
|
Packit Service |
21b5d1 |
curl_ = curl_easy_init();
|
|
Packit Service |
21b5d1 |
if(!curl_) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Uable to init libcurl.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// The default block size for FTP is much larger than other protocols
|
|
Packit Service |
21b5d1 |
// the reason is that getDataByRange() in FTP always creates the new connection,
|
|
Packit Service |
21b5d1 |
// so we need the large block size to reduce the overhead of creating the connection.
|
|
Packit Service |
21b5d1 |
if (blockSize_ == 0) {
|
|
Packit Service |
21b5d1 |
blockSize_ = protocol_ == pFtp ? 102400 : 1024;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string timeout = getEnv(envTIMEOUT);
|
|
Packit Service |
21b5d1 |
timeout_ = atol(timeout.c_str());
|
|
Packit Service |
21b5d1 |
if (timeout_ == 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Timeout Environmental Variable must be a positive integer.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
CurlIo::CurlImpl::CurlImpl(const std::wstring& wurl, size_t blockSize):Impl(wurl, blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
std::string url;
|
|
Packit Service |
21b5d1 |
url.assign(wurl.begin(), wurl.end());
|
|
Packit Service |
21b5d1 |
path_ = url;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// init curl pointer
|
|
Packit Service |
21b5d1 |
curl_ = curl_easy_init();
|
|
Packit Service |
21b5d1 |
if(!curl_) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Uable to init libcurl.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// The default block size for FTP is much larger than other protocols
|
|
Packit Service |
21b5d1 |
// the reason is that getDataByRange() in FTP always creates the new connection,
|
|
Packit Service |
21b5d1 |
// so we need the large block size to reduce the overhead of creating the connection.
|
|
Packit Service |
21b5d1 |
if (blockSize_ == 0) {
|
|
Packit Service |
21b5d1 |
blockSize_ = protocol_ == pFtp ? 102400 : 1024;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long CurlIo::CurlImpl::getFileLength()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
curl_easy_reset(curl_); // reset all options
|
|
Packit Service |
21b5d1 |
std::string response;
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_URL, path_.c_str());
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_NOBODY, 1); // HEAD
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curlWriter);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, 0L);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_CONNECTTIMEOUT, timeout_);
|
|
Packit Service |
21b5d1 |
//curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1); // debugging mode
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
/* Perform the request, res will get the return code */
|
|
Packit Service |
21b5d1 |
CURLcode res = curl_easy_perform(curl_);
|
|
Packit Service |
21b5d1 |
if(res != CURLE_OK) { // error happends
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, curl_easy_strerror(res));
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
// get return code
|
|
Packit Service |
21b5d1 |
long returnCode;
|
|
Packit Service |
21b5d1 |
curl_easy_getinfo (curl_, CURLINFO_RESPONSE_CODE, &returnCode); // get code
|
|
Packit Service |
21b5d1 |
if (returnCode >= 400 || returnCode < 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerTiffDirectoryTooLarge, "Server", returnCode);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
// get length
|
|
Packit Service |
21b5d1 |
double temp;
|
|
Packit Service |
21b5d1 |
curl_easy_getinfo(curl_, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &temp); // return -1 if unknown
|
|
Packit Service |
21b5d1 |
return (long) temp;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void CurlIo::CurlImpl::getDataByRange(long lowBlock, long highBlock, std::string& response)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
curl_easy_reset(curl_); // reset all options
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_URL, path_.c_str());
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L); // no progress meter please
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_WRITEFUNCTION, curlWriter);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_WRITEDATA, &response);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_CONNECTTIMEOUT, timeout_);
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYHOST, 0L);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1); // debugging mode
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (lowBlock > -1 && highBlock> -1) {
|
|
Packit Service |
21b5d1 |
std::stringstream ss;
|
|
Packit Service |
21b5d1 |
ss << lowBlock * blockSize_ << "-" << ((highBlock + 1) * blockSize_ - 1);
|
|
Packit Service |
21b5d1 |
std::string range = ss.str();
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_RANGE, range.c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
/* Perform the request, res will get the return code */
|
|
Packit Service |
21b5d1 |
CURLcode res = curl_easy_perform(curl_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if(res != CURLE_OK) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, curl_easy_strerror(res));
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
long serverCode;
|
|
Packit Service |
21b5d1 |
curl_easy_getinfo (curl_, CURLINFO_RESPONSE_CODE, &serverCode); // get code
|
|
Packit Service |
21b5d1 |
if (serverCode >= 400 || serverCode < 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerTiffDirectoryTooLarge, "Server", serverCode);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void CurlIo::CurlImpl::writeRemote(const byte* data, size_t size, long from, long to)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
std::string scriptPath(getEnv(envHTTPPOST));
|
|
Packit Service |
21b5d1 |
if (scriptPath == "") {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Please set the path of the server script to handle http post data to EXIV2_HTTP_POST environmental variable.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
Exiv2::Uri hostInfo = Exiv2::Uri::Parse(path_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// add the protocol and host to the path
|
|
Packit Service |
21b5d1 |
std::size_t protocolIndex = scriptPath.find("://");
|
|
Packit Service |
21b5d1 |
if (protocolIndex == std::string::npos) {
|
|
Packit Service |
21b5d1 |
if (scriptPath[0] != '/') scriptPath = "/" + scriptPath;
|
|
Packit Service |
21b5d1 |
scriptPath = hostInfo.Protocol + "://" + hostInfo.Host + scriptPath;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
curl_easy_reset(curl_); // reset all options
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_NOPROGRESS, 1L); // no progress meter please
|
|
Packit Service |
21b5d1 |
//curl_easy_setopt(curl_, CURLOPT_VERBOSE, 1); // debugging mode
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_URL, scriptPath.c_str());
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_SSL_VERIFYPEER, 0L);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// encode base64
|
|
Packit Service |
21b5d1 |
size_t encodeLength = ((size + 2) / 3) * 4 + 1;
|
|
Packit Service |
21b5d1 |
char* encodeData = new char[encodeLength];
|
|
Packit Service |
21b5d1 |
base64encode(data, size, encodeData, encodeLength);
|
|
Packit Service |
21b5d1 |
// url encode
|
|
Packit Service |
21b5d1 |
const std::string urlencodeData = urlencode(encodeData);
|
|
Packit Service |
21b5d1 |
delete[] encodeData;
|
|
Packit Service |
21b5d1 |
std::stringstream ss;
|
|
Packit Service |
21b5d1 |
ss << "path=" << hostInfo.Path << "&"
|
|
Packit Service |
21b5d1 |
<< "from=" << from << "&"
|
|
Packit Service |
21b5d1 |
<< "to=" << to << "&"
|
|
Packit Service |
21b5d1 |
<< "data=" << urlencodeData;
|
|
Packit Service |
21b5d1 |
std::string postData = ss.str();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
curl_easy_setopt(curl_, CURLOPT_POSTFIELDS, postData.c_str());
|
|
Packit Service |
21b5d1 |
// Perform the request, res will get the return code.
|
|
Packit Service |
21b5d1 |
CURLcode res = curl_easy_perform(curl_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if(res != CURLE_OK) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, curl_easy_strerror(res));
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
long serverCode;
|
|
Packit Service |
21b5d1 |
curl_easy_getinfo (curl_, CURLINFO_RESPONSE_CODE, &serverCode);
|
|
Packit Service |
21b5d1 |
if (serverCode >= 400 || serverCode < 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerTiffDirectoryTooLarge, "Server", serverCode);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
CurlIo::CurlImpl::~CurlImpl() {
|
|
Packit Service |
21b5d1 |
curl_easy_cleanup(curl_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long CurlIo::write(const byte* data, long wcount)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (p_->protocol_ == pHttp || p_->protocol_ == pHttps) {
|
|
Packit Service |
21b5d1 |
return RemoteIo::write(data, wcount);
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "doesnt support write for this protocol.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long CurlIo::write(BasicIo& src)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (p_->protocol_ == pHttp || p_->protocol_ == pHttps) {
|
|
Packit Service |
21b5d1 |
return RemoteIo::write(src);
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "doesnt support write for this protocol.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
CurlIo::CurlIo(const std::string& url, size_t blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_ = new CurlImpl(url, blockSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
CurlIo::CurlIo(const std::wstring& wurl, size_t blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_ = new CurlImpl(wurl, blockSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_USE_SSH
|
|
Packit Service |
21b5d1 |
//! Internal Pimpl structure of class RemoteIo.
|
|
Packit Service |
21b5d1 |
class SshIo::SshImpl : public Impl {
|
|
Packit Service |
21b5d1 |
public:
|
|
Packit Service |
21b5d1 |
//! Constructor
|
|
Packit Service |
21b5d1 |
SshImpl(const std::string& path, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
//! Constructor accepting a unicode path in an std::wstring
|
|
Packit Service |
21b5d1 |
SshImpl(const std::wstring& wpath, size_t blockSize);
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
//! Destructor. Closes ssh session and releases all managed memory.
|
|
Packit Service |
21b5d1 |
~SshImpl();
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
Exiv2::Uri hostInfo_; //!< host information extracted from path
|
|
Packit Service |
21b5d1 |
SSH* ssh_; //!< SSH pointer
|
|
Packit Service |
21b5d1 |
sftp_file fileHandler_; //!< sftp file handler
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// METHODS
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the length (in bytes) of the remote file.
|
|
Packit Service |
21b5d1 |
@return Return -1 if the size is unknown. Otherwise it returns the length of remote file (in bytes).
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
long getFileLength();
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Get the data by range.
|
|
Packit Service |
21b5d1 |
@param lowBlock The start block index.
|
|
Packit Service |
21b5d1 |
@param highBlock The end block index.
|
|
Packit Service |
21b5d1 |
@param response The data from the server.
|
|
Packit Service |
21b5d1 |
@throw Error if the server returns the error code.
|
|
Packit Service |
21b5d1 |
@note Set lowBlock = -1 and highBlock = -1 to get the whole file content.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
void getDataByRange(long lowBlock, long highBlock, std::string& response);
|
|
Packit Service |
21b5d1 |
/*!
|
|
Packit Service |
21b5d1 |
@brief Submit the data to the remote machine. The data replace a part of the remote file.
|
|
Packit Service |
21b5d1 |
The replaced part of remote file is indicated by from and to parameters.
|
|
Packit Service |
21b5d1 |
@param data The data are submitted to the remote machine.
|
|
Packit Service |
21b5d1 |
@param size The size of data.
|
|
Packit Service |
21b5d1 |
@param from The start position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@param to The end position in the remote file where the data replace.
|
|
Packit Service |
21b5d1 |
@note The write access is only available on the SSH protocol. It requires the write permission
|
|
Packit Service |
21b5d1 |
to edit the remote file.
|
|
Packit Service |
21b5d1 |
@throw Error if it fails.
|
|
Packit Service |
21b5d1 |
*/
|
|
Packit Service |
21b5d1 |
void writeRemote(const byte* data, size_t size, long from, long to);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
protected:
|
|
Packit Service |
21b5d1 |
// NOT IMPLEMENTED
|
|
Packit Service |
21b5d1 |
SshImpl(const SshImpl& rhs); //!< Copy constructor
|
|
Packit Service |
21b5d1 |
SshImpl& operator=(const SshImpl& rhs); //!< Assignment
|
|
Packit Service |
21b5d1 |
}; // class RemoteIo::Impl
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
SshIo::SshImpl::SshImpl(const std::string& url, size_t blockSize):Impl(url, blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
hostInfo_ = Exiv2::Uri::Parse(url);
|
|
Packit Service |
21b5d1 |
Exiv2::Uri::Decode(hostInfo_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// remove / at the beginning of the path
|
|
Packit Service |
21b5d1 |
if (hostInfo_.Path[0] == '/') {
|
|
Packit Service |
21b5d1 |
hostInfo_.Path = hostInfo_.Path.substr(1);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
ssh_ = new SSH(hostInfo_.Host, hostInfo_.Username, hostInfo_.Password, hostInfo_.Port);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (protocol_ == pSftp) {
|
|
Packit Service |
21b5d1 |
ssh_->getFileSftp(hostInfo_.Path, fileHandler_);
|
|
Packit Service |
21b5d1 |
if (fileHandler_ == NULL) throw Error(kerErrorMessage, "Unable to open the file");
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
fileHandler_ = NULL;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
SshIo::SshImpl::SshImpl(const std::wstring& wurl, size_t blockSize):Impl(wurl, blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
std::string url;
|
|
Packit Service |
21b5d1 |
url.assign(wurl.begin(), wurl.end());
|
|
Packit Service |
21b5d1 |
path_ = url;
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
hostInfo_ = Exiv2::Uri::Parse(url);
|
|
Packit Service |
21b5d1 |
Exiv2::Uri::Decode(hostInfo_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// remove / at the beginning of the path
|
|
Packit Service |
21b5d1 |
if (hostInfo_.Path[0] == '/') {
|
|
Packit Service |
21b5d1 |
hostInfo_.Path = hostInfo_.Path.substr(1);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
ssh_ = new SSH(hostInfo_.Host, hostInfo_.Username, hostInfo_.Password, hostInfo_.Port);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
if (protocol_ == pSftp) {
|
|
Packit Service |
21b5d1 |
ssh_->getFileSftp(hostInfo_.Path, fileHandler_);
|
|
Packit Service |
21b5d1 |
if (fileHandler_ == NULL) throw Error(kerErrorMessage, "Unable to open the file");
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
fileHandler_ = NULL;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
long SshIo::SshImpl::getFileLength()
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
long length = 0;
|
|
Packit Service |
21b5d1 |
if (protocol_ == pSftp) { // sftp
|
|
Packit Service |
21b5d1 |
sftp_attributes attributes = sftp_fstat(fileHandler_);
|
|
Packit Service |
21b5d1 |
length = (long)attributes->size;
|
|
Packit Service |
21b5d1 |
} else { // ssh
|
|
Packit Service |
21b5d1 |
std::string response;
|
|
Packit Service |
21b5d1 |
//std::string cmd = "stat -c %s " + hostInfo_.Path;
|
|
Packit Service |
21b5d1 |
std::string cmd = "declare -a x=($(ls -alt " + hostInfo_.Path + ")); echo ${x[4]}";
|
|
Packit Service |
21b5d1 |
if (ssh_->runCommand(cmd, &response) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Unable to get file length.");
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
length = atol(response.c_str());
|
|
Packit Service |
21b5d1 |
if (length == 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "File is empty or not found.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return length;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void SshIo::SshImpl::getDataByRange(long lowBlock, long highBlock, std::string& response)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (protocol_ == pSftp) {
|
|
Packit Service |
21b5d1 |
if (sftp_seek(fileHandler_, (uint32_t) (lowBlock * blockSize_)) < 0) throw Error(kerErrorMessage, "SFTP: unable to sftp_seek");
|
|
Packit Service |
21b5d1 |
size_t buffSize = (highBlock - lowBlock + 1) * blockSize_;
|
|
Packit Service |
21b5d1 |
std::vector<char> buffer(buffSize);
|
|
Packit Service |
21b5d1 |
long nBytes = static_cast<long>(sftp_read(fileHandler_, &buffer.at(0), buffSize));
|
|
Packit Service |
21b5d1 |
if (nBytes < 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "SFTP: unable to sftp_read");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
response.assign(&buffer.at(0), buffSize);
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
std::stringstream ss;
|
|
Packit Service |
21b5d1 |
if (lowBlock > -1 && highBlock > -1) {
|
|
Packit Service |
21b5d1 |
ss << "dd if=" << hostInfo_.Path
|
|
Packit Service |
21b5d1 |
<< " ibs=" << blockSize_
|
|
Packit Service |
21b5d1 |
<< " skip=" << lowBlock
|
|
Packit Service |
21b5d1 |
<< " count=" << (highBlock - lowBlock) + 1<< " 2>/dev/null";
|
|
Packit Service |
21b5d1 |
} else {
|
|
Packit Service |
21b5d1 |
ss << "dd if=" << hostInfo_.Path
|
|
Packit Service |
21b5d1 |
<< " ibs=" << blockSize_
|
|
Packit Service |
21b5d1 |
<< " 2>/dev/null";
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
std::string cmd = ss.str();
|
|
Packit Service |
21b5d1 |
if (ssh_->runCommand(cmd, &response) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "Unable to get data by range.");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
void SshIo::SshImpl::writeRemote(const byte* data, size_t size, long from, long to)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (protocol_ == pSftp) throw Error(kerErrorMessage, "not support SFTP write access.");
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
//printf("ssh update size=%ld from=%ld to=%ld\n", (long)size, from, to);
|
|
Packit Service |
21b5d1 |
assert(isMalloced_);
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
std::string tempFile = hostInfo_.Path + ".exiv2tmp";
|
|
Packit Service |
21b5d1 |
std::string response;
|
|
Packit Service |
21b5d1 |
std::stringstream ss;
|
|
Packit Service |
21b5d1 |
// copy the head (byte 0 to byte fromByte) of original file to filepath.exiv2tmp
|
|
Packit Service |
21b5d1 |
ss << "head -c " << from
|
|
Packit Service |
21b5d1 |
<< " " << hostInfo_.Path
|
|
Packit Service |
21b5d1 |
<< " > " << tempFile;
|
|
Packit Service |
21b5d1 |
std::string cmd = ss.str();
|
|
Packit Service |
21b5d1 |
if (ssh_->runCommand(cmd, &response) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "SSH: Unable to cope the head of file to temp");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// upload the data (the byte ranges which are different between the original
|
|
Packit Service |
21b5d1 |
// file and the new file) to filepath.exiv2datatemp
|
|
Packit Service |
21b5d1 |
if (ssh_->scp(hostInfo_.Path + ".exiv2datatemp", data, size) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "SSH: Unable to copy file");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// concatenate the filepath.exiv2datatemp to filepath.exiv2tmp
|
|
Packit Service |
21b5d1 |
cmd = "cat " + hostInfo_.Path + ".exiv2datatemp >> " + tempFile;
|
|
Packit Service |
21b5d1 |
if (ssh_->runCommand(cmd, &response) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "SSH: Unable to copy the rest");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// copy the tail (from byte toByte to the end of file) of original file to filepath.exiv2tmp
|
|
Packit Service |
21b5d1 |
ss.str("");
|
|
Packit Service |
21b5d1 |
ss << "tail -c+" << (to + 1)
|
|
Packit Service |
21b5d1 |
<< " " << hostInfo_.Path
|
|
Packit Service |
21b5d1 |
<< " >> " << tempFile;
|
|
Packit Service |
21b5d1 |
cmd = ss.str();
|
|
Packit Service |
21b5d1 |
if (ssh_->runCommand(cmd, &response) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "SSH: Unable to copy the rest");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// replace the original file with filepath.exiv2tmp
|
|
Packit Service |
21b5d1 |
cmd = "mv " + tempFile + " " + hostInfo_.Path;
|
|
Packit Service |
21b5d1 |
if (ssh_->runCommand(cmd, &response) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "SSH: Unable to copy the rest");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// remove filepath.exiv2datatemp
|
|
Packit Service |
21b5d1 |
cmd = "rm " + hostInfo_.Path + ".exiv2datatemp";
|
|
Packit Service |
21b5d1 |
if (ssh_->runCommand(cmd, &response) != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerErrorMessage, "SSH: Unable to copy the rest");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
SshIo::SshImpl::~SshImpl() {
|
|
Packit Service |
21b5d1 |
if (fileHandler_) sftp_close(fileHandler_);
|
|
Packit Service |
21b5d1 |
if (ssh_) delete ssh_;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
SshIo::SshIo(const std::string& url, size_t blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_ = new SshImpl(url, blockSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
SshIo::SshIo(const std::wstring& wurl, size_t blockSize)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
p_ = new SshImpl(wurl, blockSize);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
// *************************************************************************
|
|
Packit Service |
21b5d1 |
// free functions
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
DataBuf readFile(const std::string& path)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
FileIo file(path);
|
|
Packit Service |
21b5d1 |
if (file.open("rb") != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerFileOpenFailed, path, "rb", strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
struct stat st;
|
|
Packit Service |
21b5d1 |
if (0 != ::stat(path.c_str(), &st)) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path, strError(), "::stat");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
DataBuf buf(st.st_size);
|
|
Packit Service |
21b5d1 |
long len = file.read(buf.pData_, buf.size_);
|
|
Packit Service |
21b5d1 |
if (len != buf.size_) {
|
|
Packit Service |
21b5d1 |
throw Error(kerCallFailed, path, strError(), "FileIo::read");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return buf;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
DataBuf readFile(const std::wstring& wpath)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
FileIo file(wpath);
|
|
Packit Service |
21b5d1 |
if (file.open("rb") != 0) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileOpenFailed, wpath, "rb", strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
struct _stat st;
|
|
Packit Service |
21b5d1 |
if (0 != ::_wstat(wpath.c_str(), &st)) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath, strError().c_str(), "::_wstat");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
DataBuf buf(st.st_size);
|
|
Packit Service |
21b5d1 |
long len = file.read(buf.pData_, buf.size_);
|
|
Packit Service |
21b5d1 |
if (len != buf.size_) {
|
|
Packit Service |
21b5d1 |
throw WError(kerCallFailed, wpath, strError().c_str(), "FileIo::read");
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return buf;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
long writeFile(const DataBuf& buf, const std::string& path)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
FileIo file(path);
|
|
Packit Service |
21b5d1 |
if (file.open("wb") != 0) {
|
|
Packit Service |
21b5d1 |
throw Error(kerFileOpenFailed, path, "wb", strError());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return file.write(buf.pData_, buf.size_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
long writeFile(const DataBuf& buf, const std::wstring& wpath)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
FileIo file(wpath);
|
|
Packit Service |
21b5d1 |
if (file.open("wb") != 0) {
|
|
Packit Service |
21b5d1 |
throw WError(kerFileOpenFailed, wpath, "wb", strError().c_str());
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return file.write(buf.pData_, buf.size_);
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
std::string ReplaceStringInPlace(std::string subject, const std::string& search,
|
|
Packit Service |
21b5d1 |
const std::string& replace) {
|
|
Packit Service |
21b5d1 |
size_t pos = 0;
|
|
Packit Service |
21b5d1 |
while((pos = subject.find(search, pos)) != std::string::npos) {
|
|
Packit Service |
21b5d1 |
subject.replace(pos, search.length(), replace);
|
|
Packit Service |
21b5d1 |
pos += replace.length();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return subject;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
|
|
Packit Service |
21b5d1 |
#ifdef EXV_UNICODE_PATH
|
|
Packit Service |
21b5d1 |
std::wstring ReplaceStringInPlace(std::wstring subject, const std::wstring& search,
|
|
Packit Service |
21b5d1 |
const std::wstring& replace) {
|
|
Packit Service |
21b5d1 |
std::wstring::size_type pos = 0;
|
|
Packit Service |
21b5d1 |
while((pos = subject.find(search, pos)) != std::wstring::npos) {
|
|
Packit Service |
21b5d1 |
subject.replace(pos, search.length(), replace);
|
|
Packit Service |
21b5d1 |
pos += replace.length();
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
return subject;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
#ifdef EXV_USE_CURL
|
|
Packit Service |
21b5d1 |
size_t curlWriter(char* data, size_t size, size_t nmemb,
|
|
Packit Service |
21b5d1 |
std::string* writerData)
|
|
Packit Service |
21b5d1 |
{
|
|
Packit Service |
21b5d1 |
if (writerData == NULL) return 0;
|
|
Packit Service |
21b5d1 |
writerData->append(data, size*nmemb);
|
|
Packit Service |
21b5d1 |
return size * nmemb;
|
|
Packit Service |
21b5d1 |
}
|
|
Packit Service |
21b5d1 |
#endif
|
|
Packit Service |
21b5d1 |
} // namespace Exiv2
|