C++ Library to handle BagIt structures. BagIt is a standard format to create transfer packages for digital preservation purposes. See https://en.wikipedia.org/wiki/BagIt for details http://andreas-romeyke.de
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

150 lines
4.1 KiB

  1. // Copyright (C) 2018 Andreas Romeyke (art1@andreas-romeyke.de), 2018.
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation, either version 3 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  15. #include <string>
  16. #include <iostream>
  17. #include <memory>
  18. #include <curl/curl.h>
  19. #include "fetchfile.hpp"
  20. #include <boost/filesystem.hpp>
  21. #include <sstream>
  22. //#include <filesystem> // c++17
  23. //namespace fs = std::filesystem;
  24. namespace fs = boost::filesystem;
  25. using namespace std;
  26. Fetchfile::Fetchfile( string basedir ) {
  27. Fetchfile::basedir = basedir;
  28. // test if file exists
  29. string filename = basedir + "fetch.txt";
  30. fs::path p{ filename };
  31. fs::file_status s = fs::status( p );
  32. log << "path "<< p.string() << endl;
  33. log << "is file: "<< fs::is_regular_file( s) << endl;
  34. if (fs::is_regular_file( s)) {
  35. this->exist_fetchfile = true;
  36. // map entries
  37. // from spec: A metadata element MUST consist of a label, a colon, and a value,
  38. // each separated by optional whitespace
  39. // Long values may be continued
  40. // onto the next line by inserting a newline (LF), a carriage return
  41. // (CR), or carriage return plus newline (CRLF) and indenting the next
  42. // line with linear white space (spaces or tabs)
  43. ifstream file;
  44. file.open( filename );
  45. if (file.is_open()) {
  46. string line;
  47. while (getline(file, line)) {
  48. stringstream line_ss ( line );
  49. string url;
  50. string length;
  51. string subfile;
  52. line_ss >> url;
  53. line_ss >> length;
  54. line_ss >> subfile;
  55. fetch_t entry;
  56. entry.url = url;
  57. entry.size = stoi( length );
  58. entry.filename = subfile;
  59. this->entries.push_back( entry );
  60. }
  61. file.close();
  62. }
  63. } else { // no file
  64. this->exist_fetchfile = false;
  65. }
  66. }
  67. bool Fetchfile::fetch( fetch_t fetch ) {
  68. CURL *curl;
  69. CURLcode result;
  70. curl = curl_easy_init();
  71. if (curl != nullptr) {
  72. FILE *fp;
  73. fp = fopen( fetch.filename.c_str(), "wb");
  74. curl_easy_setopt(curl, CURLOPT_URL, fetch.url.c_str());
  75. // FIXME: curl needs a write function if WIN32,
  76. // see https://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html#DESCRIPTION
  77. curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, NULL);
  78. curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
  79. result = curl_easy_perform(curl);
  80. curl_easy_cleanup(curl);
  81. fclose(fp);
  82. } else {
  83. return false;
  84. }
  85. return true;
  86. }
  87. bool Fetchfile::has_fetchfile() {
  88. return this->exist_fetchfile;
  89. }
  90. list<fetch_t> Fetchfile::get_entries() {
  91. return this->entries;
  92. }
  93. bool Fetchfile::fetch_all_entries() {
  94. bool is_successful = true;
  95. for (auto & entrie : this->entries) {
  96. bool result = this->fetch( entrie );
  97. if (!result) {
  98. is_successful = false;
  99. }
  100. }
  101. return is_successful;
  102. }
  103. bool Fetchfile::validate() {
  104. bool is_valid = true;
  105. if (this->has_fetchfile()) {
  106. // TODO(art1):
  107. }
  108. return is_valid;
  109. }
  110. bool Fetchfile::store( string basedir ) {
  111. fs::path p{ basedir };
  112. fs::file_status s = fs::status( p );
  113. if (! fs::is_directory( s)) {
  114. Fetchfile::log << "directory '" << basedir << "' does not exist" << endl;
  115. return false;
  116. }
  117. string filename = basedir + "fetch.txt";
  118. ofstream fetchfile_txt_file;
  119. fetchfile_txt_file.open( filename );
  120. if (fetchfile_txt_file.is_open()) {
  121. for (auto & entrie : this->entries) {
  122. fetchfile_txt_file << entrie.url << " " << entrie.size << " " << entrie.filename << endl;
  123. }
  124. fetchfile_txt_file.close();
  125. }
  126. return true;
  127. }
  128. void Fetchfile::get_logstream( stringstream & log ) {
  129. log << this->log.rdbuf();
  130. }
  131. void Fetchfile::reset_logstream() {
  132. this->log.str(std::string());
  133. }
  134. // vim: set tabstop=4 softtabstop=0 expandtab shiftwidth=4 smarttab