diff options
author | Florian Pritz <bluewind@server-speed.net> | 2011-03-07 19:00:06 +0100 |
---|---|---|
committer | Florian Pritz <bluewind@server-speed.net> | 2011-03-20 21:08:32 +0100 |
commit | 913ed7c9d756407212c56205d23cc2a06d25511a (patch) | |
tree | 72fa248b2cec43cc54487027fe55695b1927cb8d | |
parent | 483ddd7630faaa5942907659e658db3fe91c898b (diff) |
use helper script instead of curl for uploading
Signed-off-by: Florian Pritz <bluewind@server-speed.net>
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | Makefile | 19 | ||||
-rw-r--r-- | fb.c.in | 203 | ||||
-rw-r--r-- | fb.in | 21 |
4 files changed, 225 insertions, 20 deletions
@@ -1,3 +1,5 @@ dist fb.1 fb +fb-upload +fb.c @@ -1,33 +1,44 @@ VERSION:=$(shell git describe --dirty | sed 's/^v//') MANDIR=/usr/share/man BINDIR=/usr/bin +LIBDIR=/usr/lib +CC=gcc +CFLAGS=-O2 -std=c99 -Wall -Wextra -pedantic -all: fb.1 fb +all: fb.1 fb fb-upload fb: fb.in @[ -n "$(VERSION)" ] || (echo "Error: version detection failed"; exit 1) - sed 's/@VERSION@/$(VERSION)/' fb.in > fb + sed 's|@VERSION@|$(VERSION)|; s|@LIBDIR@|$(LIBDIR)|' fb.in > fb chmod 755 fb +fb.c: fb.c.in + sed 's/@VERSION@/$(VERSION)/' fb.c.in > fb.c + +fb-upload: fb.c + $(CC) $(CFLAGS) -lcurl -lm -o fb-upload fb.c + fb.1: fb.pod pod2man -c "" fb.pod fb.1 clean: - rm -f fb.1 fb + rm -f fb.1 fb fb.c fb-upload rm -rf dist install: all install -Dm755 fb $(DESTDIR)$(BINDIR)/fb + install -Dm755 fb-upload $(DESTDIR)$(LIBDIR)/fb-upload install -Dm644 fb.1 $(DESTDIR)$(MANDIR)/man1/fb.1 uninstall: rm -f $(DESTDIR)$(BINDIR)/fb + rm -f $(DESTDIR)$(LIBDIR)/fb-upload rm -f $(DESTDIR)$(MANDIR)/man1/fb.1 dist: all @[ -n "$(VERSION)" ] || (echo "Error: version detection failed"; exit 1) mkdir -p dist/fb-$(VERSION) - cp -a fb fb.in fb.pod fb.1 COPYING Makefile dist/fb-$(VERSION) + cp -a fb fb.c fb.in fb.pod fb.1 COPYING Makefile dist/fb-$(VERSION) sed -i 's/^VERSION:=.*$$/VERSION:="'$(VERSION)'"/' dist/fb-$(VERSION)/Makefile cd dist; tar -czf fb-$(VERSION).tar.gz fb-$(VERSION) @@ -0,0 +1,203 @@ +#include <stdio.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <libgen.h> +#include <string.h> +#include <stdlib.h> +#include <math.h> + +#include <curl/curl.h> +#include <curl/types.h> +#include <curl/easy.h> + +/* struct which holds the persistent data for progress_callback */ +struct progressData { + struct timeval starttime; + struct timeval last; + double ullast; + int lastStringLength; +}; + +/* load the contents of file fn into data */ +int load_file(const char *fn, char **data, size_t *data_size) +{ + FILE *fp; + size_t buf_size = 1024*1024; /* use 1MiB chunks */ + int size = 0; + + fp = fopen(fn, "rb"); + if (fp == NULL) { + perror("load_file"); + return 1; + } + + /* read the file in buf_size chunks and appened the data to *data */ + while (!feof(fp)) { + *data = realloc(*data, *data_size + buf_size); + if (*data == NULL) { + perror("load_file"); + return 1; + } + size = fread(*data + *data_size, sizeof(char), buf_size, fp); + *data_size += size; + } + + fclose(fp); + + return 0; +} + +void format_bytes(double bytes, char *buf) +{ + double base = 0; + char suffix[][4] = {"B", "KiB", "MiB", "GiB", "TiB"}; + + base = log(bytes) / log(1024); + + snprintf(buf, 64, "%.2f%s", pow(1024, base - floor(base)), suffix[(int)floor(base)]); +} + +int progress_callback(void *cb_data, + double dltotal, double dlnow, + double ultotal, double ulnow) +{ + struct timeval now; + struct progressData *data = (struct progressData *)cb_data; + double timeSpent = 0; + int printed = 0; + char speed[64]; + char total[64]; + + if (0 == ulnow) + return 0; + + /* upload complete; clean up */ + if (ulnow >= ultotal) { + fprintf(stderr, "\r"); + return 0; + } + + gettimeofday(&now, NULL); + + /* only refresh once a second */ + if (data->last.tv_sec == now.tv_sec) + return 0; + + /* calculate time between this and the last call in seconds */ + timeSpent = + (double)(now.tv_sec - data->last.tv_sec) + + (double)(now.tv_usec - data->last.tv_usec) / 1000000.0; + + format_bytes((ulnow - data->ullast) / timeSpent, (char *)&speed); + format_bytes(ulnow, (char *)&total); + + /* print the progress */ + printed = fprintf(stderr, + "\r%s/s uploaded: %.1f%% = %s", + speed, /* upload speed */ + ulnow * 100.0 / ultotal, /* percent uploaded */ + total); /* total data uploaded */ + + /* pad the string if the last one was longer to remove left over characters */ + if (data->lastStringLength > printed) + fprintf(stderr, "%*s", data->lastStringLength - printed, ""); + + /* save current values for the next run */ + data->ullast = ulnow; + data->last = now; + data->lastStringLength = printed; + + return 0; +} + +int main(int argc, char *argv[]) +{ + CURL *curl; + CURLcode res; + + char *userAgent = "fb-client/@VERSION@"; + + struct progressData cb_data = { + .starttime = {.tv_sec = 0, .tv_usec = 0}, + .last = {.tv_sec = 0, .tv_usec = 0}, + .ullast = 0.0, + .lastStringLength = 0 + }; + struct stat statbuf; + + struct curl_httppost *formpost=NULL; + struct curl_httppost *lastptr=NULL; + struct curl_slist *headerlist=NULL; + static const char buf[] = "Expect:"; + struct curl_forms forms[4]; + + char *data = NULL; + size_t data_size = 0; + + /* simple arg check */ + if(argc != 3) + return 1; + + if (curl_global_init(CURL_GLOBAL_ALL) != 0) { + fprintf(stderr, "Error initializing curl"); + return 10; + } + + if(stat(argv[2], &statbuf) == -1) { + perror("fb-upload"); + return 1; + } + + /* load files with 0 size (/proc files for example) into memory so we can + * determine their real length */ + if (statbuf.st_size == 0) { + if (load_file(argv[2], &data, &data_size) != 0) { + return 1; + } + forms[0].option = CURLFORM_BUFFER; + forms[0].value = basename(argv[2]); + forms[1].option = CURLFORM_BUFFERPTR; + forms[1].value = data; + forms[2].option = CURLFORM_BUFFERLENGTH; + forms[2].value = (char *)data_size; + forms[3].option = CURLFORM_END; + } else { + forms[0].option = CURLFORM_FILE; + forms[0].value = argv[2]; + forms[1].option = CURLFORM_END; + } + + /* Fill in the file upload field */ + curl_formadd(&formpost, + &lastptr, + CURLFORM_COPYNAME, "file", + CURLFORM_ARRAY, forms, + CURLFORM_END); + + curl = curl_easy_init(); + /* initialize custom header list (stating that Expect: 100-continue is not + wanted */ + headerlist = curl_slist_append(headerlist, buf); + if(curl) { + /* what URL that receives this POST */ + curl_easy_setopt(curl, CURLOPT_URL, argv[1]); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); + curl_easy_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &cb_data); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress_callback); + curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent); + curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); + gettimeofday(&cb_data.starttime, NULL); + res = curl_easy_perform(curl); + + /* cleanup */ + curl_easy_cleanup(curl); + curl_formfree(formpost); + curl_slist_free_all (headerlist); + curl_global_cleanup(); + free(data); + } + return 0; +} @@ -25,6 +25,7 @@ WARNSIZE=10485760 USERAGENT="fb-client/$VERSION" CLIPBOARD="" EXITCODE=0 +LIBDIR="@LIBDIR@" do_upload() { local EXTRA="" @@ -53,9 +54,6 @@ do_upload() { file="$TMPDIR/$basefilename.xz" fi - if [ "$EXTENSION" ]; then - EXTRA="-F extension=$EXTENSION" - fi TMPFILE=`mktemp "$TMPDIR/data.XXXXXX"` if [ `stat -c %s -- "$file"` -gt "$WARNSIZE" ]; then WARNSIZE=`curl -s "$PASTEBIN/file/get_max_size"` @@ -65,21 +63,12 @@ do_upload() { return 1 fi fi - CURLOPTS="-# -n -L -A $USERAGENT $EXTRA" - if [ `stat -c %s -- "$file"` -eq "0" ] || echo "$file" | grep -F -q ","; then - basefilename=`echo "$basefilename" | tr -d ,` - if ! curl $CURLOPTS -F "file=@-;filename=$basefilename" "$PASTEBIN/file/do_upload" < "$file" > $TMPFILE; then - EXITCODE=1 - return 1 - fi - else - if ! curl $CURLOPTS -F "file=@$file" "$PASTEBIN/file/do_upload" > $TMPFILE; then - EXITCODE=1 - return 1 - fi + if ! $LIBDIR/fb-upload "$PASTEBIN/file/do_upload" "$file" > $TMPFILE; then + EXITCODE=1 + return 1 fi sed '$d' $TMPFILE >&2 - URL=`tail -1 $TMPFILE` + URL=`tail -1 $TMPFILE`"$EXTENSION" echo $URL CLIPBOARD="$CLIPBOARD $URL" } |