From 6a47bca829a9da4a86dd2e341c8677c0cdcb2a97 Mon Sep 17 00:00:00 2001 From: Gavin Romig-Koch Date: Fri, 14 Aug 2009 16:04:27 -0400 Subject: compress the file if necessary, add some random bits to the upload filename --- fastback.cpp | 176 +++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 166 insertions(+), 10 deletions(-) diff --git a/fastback.cpp b/fastback.cpp index 7eb62d1..efe666e 100644 --- a/fastback.cpp +++ b/fastback.cpp @@ -38,6 +38,11 @@ The program keeps a log of all files uploaded, where they were uploaded to, encr #endif #include +#include +#include +#include + +#include #include #include @@ -46,6 +51,11 @@ The program keeps a log of all files uploaded, where they were uploaded to, encr #include #include +#include + +typedef std::string string; + + static const char fastback_name[] = "fastback"; // These are command line options @@ -64,6 +74,12 @@ static bool fastback_verbose = false; static bool fastback_logging = false; +// if we need to create temporary files +// first create a temporary directory, stick it's name here +// and delete the whole tree when we are done +static string fastback_tmpdir; + + //static const char* fastback_default_URLDIR = "ftp://dropbox.redhat.com/incoming/"; static const char* fastback_default_URLDIR = "ftp://indus.usersys.redhat.com/incoming"; @@ -78,7 +94,7 @@ fastback_read(void *buffer, size_t size, size_t nmemb, void *userp) } static void -show(FILE* file, std::string url) +show(FILE* file, string url) { if (fastback_URLDIR) fprintf(file,"fastback URLDIR: %s\n", fastback_URLDIR); @@ -108,12 +124,12 @@ show(FILE* file, std::string url) } static void -check_curl_error(CURLcode err, std::string url, const char* msg) +check_curl_error(CURLcode err, string url, const char* msg) { if (err) { show(stderr, url); - std::string tmsg = fastback_name; + string tmsg = fastback_name; tmsg += ": error: "; tmsg += msg; tmsg += ": "; @@ -254,7 +270,7 @@ parse_config(const char* filename) file = fopen(filename,"r"); if (!file) { - std::string msg = fastback_name; + string msg = fastback_name; msg += ": error: could not open: "; msg += filename; perror(msg.c_str()); @@ -334,7 +350,127 @@ parse_config(const char* filename) return config_file_error; } +void Error(string func, string msg) +{ + std::cerr << func << msg << std::endl; + exit(4); +} +void RunCommand(string cmd) +{ + int retcode = system(cmd.c_str()); + if (retcode == -1) + { + Error("RunCommand:", "error: could not start subshell: " + cmd); + } + if (retcode) + { + std::ostringstream msg; + msg << "error: subshell failed (rc=" << retcode << "):" << cmd; + Error("RunCommand:", msg.str()); + } +} + +string ReadCommand(string cmd) +{ + FILE* fp = popen(cmd.c_str(),"r"); + if (!fp) + { + Error("ReadCommand:", "error: could not start subshell: " + cmd); + } + + __gnu_cxx::stdio_filebuf command_output_buffer(fp, std::ios_base::in); + std::ostringstream output_stream; + output_stream << &command_output_buffer; + + int retcode = pclose(fp); + if (retcode) + { + std::ostringstream msg; + msg << "error: subshell failed (rc=" << retcode << "):" << cmd; + Error("ReadCommand:", msg.str()); + } + + return output_stream.str(); +} + +static string rand_base64(int i) +{ + // return a string of random base64 characters of 'i' length + // + // This should probably use the openssl library (or some other + // library directly, but it doesn't right now + std::ostringstream cmd; + cmd << "openssl rand -base64 " << i; + string r = ReadCommand(cmd.str()); + return r.substr(0,r.length()-1); +} + + +static string +randomize_filename(string filename) +{ + // create (max_rand_bytes * 8) random bits encoded as base64 + // add those bits to the filename before the first dot if any. + const int max_rand_bytes = 3; // 24 random bits + string::size_type p = filename.find_first_of('.'); + string r = rand_base64(max_rand_bytes); + if (p == string::npos) + return filename + '-' + r; + else + return filename.substr(0,p) + '-' + r + filename.substr(p,string::npos); +} + +static bool +is_compressed(const string& filename) +{ + string cmd = string("file ") + filename; + string output = ReadCommand(cmd); + + return output.find("compressed") != string::npos; +} + + +static void +compress(const string& in_filename, const string& out_filename) +{ + // compress file 'in_filename' into 'out_filename' + // again this should probably use a library, but doesn't yet + string cmd = string("gzip <") + in_filename + " >" + out_filename; + ReadCommand(cmd); +} + +static bool +readable(string filename) +{ + // is 'filename' readable by the running user + FILE* file = fopen(filename.c_str(),"r"); + if (file) + { + fclose(file); + return true; + } + return false; +} + +static string +filename_basename(const string& filename) +{ + return basename(filename.c_str()); +} + +static string +create_temporary_file(string filename) +{ + // create a filename in a temporary directory + // for now you must make sure that the name is unique to this run + if (fastback_tmpdir == "") + { + char TEMPLATE[] = "/tmp/fastbackXXXXXX"; + fastback_tmpdir = mkdtemp(TEMPLATE); + } + return fastback_tmpdir + '/' + filename; +} static void cleanup() @@ -342,6 +478,9 @@ cleanup() free(fastback_filename); free(fastback_ticket); free(fastback_URLDIR); + + if (fastback_tmpdir != "") + RunCommand(string("rm -rf " + fastback_tmpdir)); } @@ -355,7 +494,7 @@ main(int argc, char** argv) { if (errno == err) { - std::string msg = fastback_name; + string msg = fastback_name; msg += ": error: argp_parse"; perror(msg.c_str()); } @@ -382,19 +521,36 @@ main(int argc, char** argv) if (!fastback_URLDIR) fastback_URLDIR = strdup(fastback_default_URLDIR); + if (!readable(fastback_filename)) + { + string msg = fastback_name; + msg += ": error: could not open: "; + msg += fastback_filename; + perror(msg.c_str()); + exit(3); + } + + string final_filename = fastback_filename; + if (!is_compressed(final_filename)) + { + string compressed_filename = + create_temporary_file(filename_basename(final_filename) + ".gz"); + compress(final_filename,compressed_filename); + final_filename = compressed_filename; + } CURL* handle; CURLcode curl_err; FILE* file; - std::string url; + string url; - file = fopen(fastback_filename,"r"); + file = fopen(final_filename.c_str(),"r"); if (!file) { - std::string msg = fastback_name; + string msg = fastback_name; msg += ": error: could not open: "; - msg += fastback_filename; + msg += final_filename; perror(msg.c_str()); exit(3); } @@ -402,7 +558,7 @@ main(int argc, char** argv) url = fastback_URLDIR; if (url[url.length()-1] != '/') url += '/'; - url += basename(fastback_filename); + url += randomize_filename(filename_basename(final_filename.c_str())); if (fastback_verbose) show(stdout,url); -- cgit