1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
|
/**************************************************************************
* Copyright (C) 2008-2011 by Eugene V. Lyubimkin *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License *
* (version 3 or above) as published by the Free Software Foundation. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU GPL *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA *
**************************************************************************/
// this group is for stat()
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
using std::to_string;
#include <cupt/download/method.hpp>
#include <cupt/download/uri.hpp>
#include <cupt/file.hpp>
namespace cupt {
class FileMethod: public download::Method
{
string copyFile(const string& sourcePath, File& sourceFile, const string& targetPath,
const std::function< void (const vector< string >&) >& callback)
{
// preparing target
string openError;
File targetFile(targetPath, "a", openError);
if (!openError.empty())
{
return format2("unable to open the file '%s' for appending: %s", targetPath, openError);
}
auto totalBytes = targetFile.tell();
callback({ "downloading", to_string(totalBytes), to_string(0)});
{ // determing the size
struct stat st;
if (::stat(sourcePath.c_str(), &st) == -1)
{
fatal2e(__("%s() failed: '%s'"), "stat", sourcePath);
}
callback({ "expected-size", to_string(st.st_size) });
}
{ // writing
while (auto rawBuffer = sourceFile.getBlock(4096))
{
targetFile.put(rawBuffer.data, rawBuffer.size);
totalBytes += rawBuffer.size;
callback({ "downloading", to_string(totalBytes), to_string(rawBuffer.size)});
}
}
return string();
}
string perform(const Config&, const download::Uri& uri,
const string& targetPath, const std::function< void (const vector< string >&) >& callback)
{
auto sourcePath = uri.getOpaque();
auto protocol = uri.getProtocol();
// preparing source
string openError;
File sourceFile(sourcePath, "r", openError);
if (!openError.empty())
{
return format2("unable to open the file '%s' for reading: %s", sourcePath, openError);
}
if (protocol == "copy")
{
return copyFile(sourcePath, sourceFile, targetPath, callback); // full copying
}
else if (protocol == "file")
{
// symlinking
unlink(targetPath.c_str()); // yep, no error handling;
if (symlink(sourcePath.c_str(), targetPath.c_str()) == -1)
{
return format2e("unable to create symbolic link '%s' -> '%s'", targetPath, sourcePath);
}
return string();
}
else
{
fatal2i("a wrong scheme '%s' for the 'file' download method", protocol);
return string(); // unreachable
}
}
};
}
extern "C"
{
cupt::download::Method* construct()
{
return new cupt::FileMethod();
}
}
|