int bwlup;
} cfg;
+struct file_info_t {
+ const char *name;
+ char *esc_name;
+ int fd;
+ off_t size;
+ off_t remn;
+ off_t coff;
+ curl_off_t speed;
+};
static void ie( const char *home ) {
FILE *fp;
if ( NULL == home )
return;
- sprintf( confpath, "%s/%s", home, CFG_BASE );
+ snprintf( confpath, sizeof confpath, "%s/%s", home, CFG_BASE );
if ( NULL == ( fp = fopen( confpath, "r" ) ) )
return;
while ( fgets( buf, sizeof buf - 1, fp ) ) {
if ( '"' == *x || '\'' == *x )
*x = '\0';
// don't overwrite environment, so "PASS=1234 kaoupload ..." is possible
- setenv( key, val, 0 );
+ if ( 0 == strcmp( key, "USER" )
+ || 0 == strcmp( key, "PASS" )
+ || 0 == strcmp( key, "BWLUP" ) )
+ setenv( key, val, 0 );
}
fclose( fp );
}
-static void die( const char *msg, int eno ) {
+static void cerr( const char *msg, int eno ) {
+ fprintf( stderr, "ERROR: %s", msg );
+ if ( eno )
+ fprintf( stderr, ": %s", curl_share_strerror( eno ) );
+ fprintf( stderr, "\n" );
+}
+
+static void err( const char *msg, int eno ) {
fprintf( stderr, "ERROR: %s", msg );
if ( eno )
fprintf( stderr, ": %s", strerror( eno ) );
fprintf( stderr, "\n" );
+}
+
+static void die( const char *msg, int eno ) {
+ err( msg, eno );
exit( EXIT_FAILURE );
}
size_t size;
};
-static size_t WriteMemoryCallback( void *contents, size_t size, size_t nmemb, void *userp )
-{
+static size_t WriteMemoryCallback( void *contents, size_t size, size_t nmemb, void *userp ) {
size_t realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)userp;
void *newmem;
memcpy( &(mem->memory[mem->size]), contents, realsize );
mem->size += realsize;
mem->memory[mem->size] = 0;
-
return realsize;
}
-struct file_info_t {
- int32_t fd;
- char *name;
- size_t size;
- size_t remn;
- size_t coff;
- curl_off_t speed;
-};
-
-#define FILE_INFO_INITIALIZER ((struct file_info_t){-1, NULL, 0, 0, 0, 0})
-
-static int fill_file_info( const char *fn, struct file_info_t *fi ) {
- struct stat stbuf;
-
- if ( NULL == ( fi->name = realloc( fi->name, strlen( fn ) + 1 ) ) )
- die( "malloc", errno );
- fi->fd = open( fn, O_RDONLY );
- if ( fi->fd < 0 )
- die( "open", errno );
- if ( fstat(fi->fd, &stbuf ) < 0 )
- die( "fstat", errno );
- strcpy( fi->name, fn );
- fi->remn = fi->size = stbuf.st_size;
- fi->coff = 0;
-// puts ("all ok");
-// printf ("File: %s\nSize: %lu bytes\n", fi->name, fi->size);
- return 0;
-}
-
-static int loadNext( struct file_info_t *fi, uint64_t csize ) {
+static int loadNext( CURL *curl, struct file_info_t *fi, off_t csize ) {
int res = -1;
- struct MemoryStruct chunk;
+ int response_code;
+ ssize_t br;
+ char url[2048];
+ void *slice;
+ char *s;
+ CURLcode error;
+ struct MemoryStruct reply;
- chunk.memory = NULL; /* will be grown as needed by the realloc above */
- chunk.size = 0; /* no data at this point */
+ reply.memory = NULL; /* will be grown as needed */
+ reply.size = 0; /* no data at this point */
if ( csize > fi->remn )
csize = fi->remn;
- void *buf = malloc( csize );
- if ( NULL == buf )
+ if ( NULL == ( slice = malloc( csize ) ) )
die( "malloc", errno );
lseek( fi->fd, fi->coff, SEEK_SET );
- read( fi->fd, buf, csize );
+ br = read( fi->fd, slice, csize );
+ if ( 0 > br ) {
+ err( "read", errno );
+ goto err_out;
+ }
+ if ( csize > br )
+ csize = br;
- CURL *curl = curl_easy_init();
- if ( NULL == curl )
- die( "curl_easy_init failed", 0 );
+ snprintf( url, sizeof url, "%s?fname=%s&fpos=%lu&fsize=%lu", cfg.url, fi->esc_name, fi->coff, fi->size );
+ error = curl_easy_setopt( curl, CURLOPT_URL, url );
+ error |= curl_easy_setopt( curl, CURLOPT_POSTFIELDSIZE, csize );
+ error |= curl_easy_setopt( curl, CURLOPT_POSTFIELDS, slice );
+ error |= curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)&reply );
+ if ( CURLE_OK != error )
+ die( "curl_easy_setopt failed", 0 );
- char url[1024];
+ error = curl_easy_perform( curl );
+ if ( CURLE_OK != error ) {
+ cerr( "curl_easy_perform", error );
+ goto err_out;
+ }
+
+ curl_easy_getinfo( curl, CURLINFO_SPEED_UPLOAD_T, &fi->speed );
+ curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &response_code );
+
+ puts(reply.memory);
+
+ switch ( response_code ) {
+ case 100:
+ case 200:
+ case 201:
+ // simplest case, uploaded one chunk
+ if ( 0 == strncmp( reply.memory, "Have ", strlen("Have ") )
+ || 0 == strncmp( reply.memory, "Upload complete", strlen("Upload complete") ) ) {
+ fi->coff += csize;
+ fi->remn -= csize;
+ res = 0;
+ }
+ else
+ err( "unexpected response: check credentials?", 0 );
+ break;
+ case 428:
+ // remote already has data up to Skip-to-position
+ if ( NULL != ( s = strstr( reply.memory, "Skip-to-position: " ) ) ) {
+ fi->coff = strtoul( s + strlen( "Skip-to-position: " ), NULL, 10 );
+ fi->remn = fi->size - fi->coff;
+ res = 0;
+ }
+ else
+ err( "response code 428 w/o 'Skip-to-position'", 0 );
+ break;
+ default:
+ fprintf( stderr, "WARNING: unexpected response code: %d\n", response_code );
+ break;
+ }
+
+ err_out:
+ free( reply.memory );
+ free( slice );
+ return res;
+}
+
+static int uploadFile( const char *fn ) {
+ int res;
+ int csize = 1024;
char userpass[256];
- char *ucname;
- if ( NULL == ( ucname = curl_easy_escape( curl, fi->name, 0 ) ) )
+ struct file_info_t fi;
+ struct stat stbuf;
+ CURL *curl;
+ CURLcode error;
+
+ if ( NULL == ( curl = curl_easy_init() ) )
+ die( "curl_easy_init failed", 0 );
+
+ fi.name = fn;
+ if ( NULL == ( fi.esc_name = curl_easy_escape( curl, fn, 0 ) ) )
die( "curl_easy_escape failed", 0 );
- snprintf( url, sizeof url, "%s?fname=%s&fpos=%lu&fsize=%lu", cfg.url, ucname, fi->coff, fi->size );
- curl_free( ucname );
- snprintf( userpass, sizeof userpass, "%s:%s", cfg.user, cfg.pass );
+ fi.fd = open( fn, O_RDONLY );
+ if ( fi.fd < 0 )
+ err( fn, errno );
+ if ( fstat(fi.fd, &stbuf ) < 0 ) {
+ err( fn, errno );
+ return -1;
+ }
+ fi.remn = fi.size = stbuf.st_size;
+ fi.coff = 0;
+ printf( "File: %s\nSize: %lu bytes\n", fi.name, fi.size );
- CURLcode error;
- error = curl_easy_setopt( curl, CURLOPT_URL, url );
- error |= curl_easy_setopt( curl, CURLOPT_POST, 1 );
-// error |= curl_easy_setopt(curl, CURLOPT_HEADER, 1L );
+ snprintf( userpass, sizeof userpass, "%s:%s", cfg.user, cfg.pass );
+ error = curl_easy_setopt( curl, CURLOPT_POST, 1 );
error |= curl_easy_setopt( curl, CURLOPT_TIMEOUT, 60 );
- error |= curl_easy_setopt( curl, CURLOPT_POSTFIELDSIZE, csize );
- error |= curl_easy_setopt( curl, CURLOPT_POSTFIELDS, buf );
error |= curl_easy_setopt( curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC );
error |= curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 0 );
error |= curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 0 );
error |= curl_easy_setopt( curl, CURLOPT_USERPWD, userpass );
error |= curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback );
- error |= curl_easy_setopt( curl, CURLOPT_WRITEDATA, (void *)&chunk );
- error |= curl_easy_setopt( curl, CURLOPT_CONNECTTIMEOUT, 1000L );
+ error |= curl_easy_setopt( curl, CURLOPT_CONNECTTIMEOUT, 60L );
+// error |= curl_easy_setopt(curl, CURLOPT_HEADER, 1L );
if ( CURLE_OK != error )
die( "curl_easy_setopt failed", 0 );
- error = curl_easy_perform( curl );
- if ( CURLE_OK == error ) {
- char *s;
- curl_easy_getinfo( curl, CURLINFO_SPEED_UPLOAD_T, &fi->speed );
- long response_code;
- curl_easy_getinfo( curl, CURLINFO_RESPONSE_CODE, &response_code );
-
-// puts(chunk.memory);
-// res = strtoul(chunk.memory+9, NULL, 10);
-// printf ("Res: %u\n", res);
-
- switch ( response_code ) {
- case 100:
- case 200:
- case 201:
- if ( 0 == strncmp( chunk.memory, "Have ", strlen("Have ") ) ) {
- // simplest case, sucessfully uploaded one chunk
- fi->coff += csize;
- fi->remn -= csize;
- res = 0;
- }
- else
- die( "unexpected response content", 0 );
- break;
- case 428:
- // remote already has data up to Skip-to-position
- if ( NULL != ( s = strstr( chunk.memory, "Skip-to-position: " ) ) ) {
- fi->coff = strtoul( s + strlen( "Skip-to-position: " ), NULL, 10 );
-// printf("New coff: %lu\n", fi->coff);
- fi->remn = fi->size - fi->coff;
- res = 0;
- }
- else
- fprintf( stderr, "WARNING: response code 428 w/o Skip-to-position!\n", response_code );
- break;
- default:
- fprintf( stderr, "WARNING: unhandled response code: %l\n", response_code );
+
+ while ( fi.remn ) {
+ res = loadNext( curl, &fi, csize );
+ if ( res < 0 )
break;
- }
- }
- else {
- fprintf( stderr, "WARNING: curl_easy_perform: %s\n", curl_share_strerror( error ) );
+ if ( 1024 == csize )
+ csize *= 256; //this obviously influences upload speed
+ printf( "\r%s: %d%% (%5.2f kB/s) ", fi.name, (int)(100.0 * fi.coff / fi.size), fi.speed / 1024.0 );
+ fflush( stdout );
}
+ curl_free( fi.esc_name );
curl_easy_cleanup( curl );
- free( chunk.memory );
- free( buf );
+ close( fi.fd );
+ puts( "" );
+ if ( res < 0 )
+ err( "file upload aborted", 0 );
return res;
}
-void usage( char *pname ) {
+static void usage( char *pname ) {
fprintf( stderr, "Usage: %s <file>\n", pname );
exit( EXIT_FAILURE );
}
int main( int argc, char *argv[], char *const envp[] ) {
- struct file_info_t fi = FILE_INFO_INITIALIZER;
- int csize = 1024;
- int res;
+ int res = 0;
if ( argc < 2 )
usage( basename( argv[0] ) );
cfg.url = getenv( "URL" ) ? getenv( "URL" ) : URL_BASE;
cfg.bwlup = 0;
- if ( 0 != fill_file_info( argv[1], &fi ) )
- goto err_file;
+/*
+ TODO
+ * cmd line options
+ * bandwidth limit
+*/
if ( CURLE_OK != curl_global_init( CURL_GLOBAL_SSL ) )
die( "curl_global_init", 0 );
- while ( fi.remn ) {
- res = loadNext( &fi, csize );
- if ( res < 0 )
- break;
- if ( 1024 == csize )
- csize *= 256; //this obviously influences upload speed
- printf( "\r%s: %d%% (%5.2f kB/s) ", fi.name, (int)(100.0 * fi.coff / fi.size), fi.speed / 1024.0 );
- fflush( stdout );
- }
- //if (res < 0) say something clever;
- close( fi.fd );
- puts( "" );
+ res = uploadFile( argv[1] );
+
curl_global_cleanup();
- exit( EXIT_SUCCESS );
+ exit( res ? EXIT_FAILURE : EXIT_SUCCESS );
-err_file:
-err_curl:
- exit( EXIT_FAILURE );
+ (void)envp;
}