From: Urban Wallasch Date: Fri, 16 Apr 2021 20:05:21 +0000 (+0200) Subject: * Cleaned up and fixed kaoupload.c, first pass. X-Git-Url: https://git.packet-gain.de/?a=commitdiff_plain;h=a6913c992927f1cc5701d2ebeda8a45c776064a1;p=kaotools.git * Cleaned up and fixed kaoupload.c, first pass. --- diff --git a/kaoupload.c b/kaoupload.c index 13f7bbf..7e77668 100644 --- a/kaoupload.c +++ b/kaoupload.c @@ -1,17 +1,21 @@ -#include +#include +#include #include #include #include #include +#include -#include -#include #include +#include #include +#include +#include #include #define URL_BASE "https://kaotan.latice.de/uploadx.php" +#define CFG_BASE ".config/kaoconf" static struct kaoconf { const char *user; @@ -20,34 +24,50 @@ static struct kaoconf { int bwlup; } cfg; + static void ie( const char *home ) { - FILE *f; + FILE *fp; char confpath[256]; char buf[256]; - if ( !home ) + if ( NULL == home ) return; - sprintf( confpath,"%s/.config/kaoconf", home ); - //puts(confpath); - f = fopen( confpath, "r" ); - if ( !f ) + sprintf( confpath, "%s/%s", home, CFG_BASE ); + if ( NULL == ( fp = fopen( confpath, "r" ) ) ) return; - while ( fgets( buf, sizeof buf - 1, f ) ) { - char *key = buf; - char *val = strchr(buf, '='); - char *x; - if ( '#' == *buf || !val ) + while ( fgets( buf, sizeof buf - 1, fp ) ) { + char *key, *val, *x; + key = buf; + while ( isspace( (unsigned char)*key ) ) + ++key; + if ( '#' == *key ) + continue; + if ( NULL == ( val = strchr( key, '=' ) ) ) continue; *val++ = '\0'; - x = strrchr( val, '\n' ); - if (x) - *x = 0; - x = strrchr( val, '\r' ); - if (x) - *x = 0; //custom config file on Linux with CRLF? it could happen, you never know! - setenv( key, val, 0 ); //don't overwrite environment, so "PASS=1234 kaoupload ..." is possible + while ( isspace( (unsigned char)*val ) ) + ++val; + if ( '"' == *val || '\'' == *val ) + ++val; + if ( '\0' == *val ) + continue; + x = val + strlen( val ) - 1; + while ( isspace( (unsigned char)*x ) && x > val ) + *x-- = '\0'; + if ( '"' == *x || '\'' == *x ) + *x = '\0'; + // don't overwrite environment, so "PASS=1234 kaoupload ..." is possible + setenv( key, val, 0 ); } - fclose( f ); + fclose( fp ); +} + +static void die( const char *msg, int eno ) { + fprintf( stderr, "ERROR: %s", msg ); + if ( eno ) + fprintf( stderr, ": %s", strerror( eno ) ); + fprintf( stderr, "\n" ); + exit( EXIT_FAILURE ); } @@ -65,15 +85,10 @@ static size_t WriteMemoryCallback( void *contents, size_t size, size_t nmemb, vo struct MemoryStruct *mem = (struct MemoryStruct *)userp; void *newmem; - newmem = realloc( mem->memory, mem->size + realsize + 1 ); - if ( newmem == NULL ) { - /* out of memory! */ - printf("not enough memory (realloc returned NULL)\n"); - return 0; - } - + if ( NULL == ( newmem = realloc( mem->memory, mem->size + realsize + 1 ) ) ) + die( "realloc", errno ); mem->memory = newmem; - memcpy(&(mem->memory[mem->size]), contents, realsize); + memcpy( &(mem->memory[mem->size]), contents, realsize ); mem->size += realsize; mem->memory[mem->size] = 0; @@ -82,30 +97,26 @@ static size_t WriteMemoryCallback( void *contents, size_t size, size_t nmemb, vo struct file_info_t { int32_t fd; - char name[256]; + 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 ) { - perror( "open failed!" ); - return -1; - } - - if ( fstat(fi->fd, &stbuf ) < 0 ) { - perror( "fstat failed!" ); - return -1; - } - - strncpy( fi->name, fn, sizeof fi->name - 1 ); - + 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"); @@ -113,110 +124,141 @@ static int fill_file_info( const char *fn, struct file_info_t *fi ) { return 0; } -static const char *urlencode( const char *s ) { - return s; -} - static int loadNext( struct file_info_t *fi, uint64_t csize ) { int res = -1; struct MemoryStruct chunk; chunk.memory = NULL; /* will be grown as needed by the realloc above */ - chunk.size = 0; /* no data at this point */ + chunk.size = 0; /* no data at this point */ + + if ( csize > fi->remn ) + csize = fi->remn; + void *buf = malloc( csize ); + if ( NULL == buf ) + die( "malloc", errno ); + lseek( fi->fd, fi->coff, SEEK_SET ); + read( fi->fd, buf, csize ); CURL *curl = curl_easy_init(); - if ( NULL != curl ) { - char url[1024]; - char userpass[256]; - - sprintf( url, "%s?fname=%s&fpos=%lu&fsize=%lu", cfg.url, urlencode(fi->name), fi->coff, fi->size ); - sprintf( userpass, "%s:%s", cfg.user, cfg.pass ); - - if ( csize > fi->remn ) - csize=fi->remn; - void *buf = malloc( csize ); - lseek( fi->fd, fi->coff, SEEK_SET ); - read( fi->fd, buf, csize ); - - CURLcode error = curl_easy_setopt( curl, CURLOPT_URL, url ); - error |= curl_easy_setopt( curl, CURLOPT_POST, 1 ); -// error |= curl_easy_setopt(curl, CURLOPT_HEADER, 1L ); - 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 ); - if ( CURLE_OK == error ) - error = curl_easy_perform( curl ); - - curl_easy_cleanup( curl ); - free( buf ); - - if ( CURLE_OK == error ) { - res = 0; - 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); - if ( 200 == response_code || 100 == response_code ) { //simplest case, just uploaded one chunk - fi->coff += csize; - fi->remn -= csize; - } - else if ( 428 == response_code ) { //remote already has data up to Skip-to-position - char *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; - } - } + if ( NULL == curl ) + die( "curl_easy_init failed", 0 ); + + char url[1024]; + char userpass[256]; + char *ucname; + if ( NULL == ( ucname = curl_easy_escape( curl, fi->name, 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 ); + + 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 ); + 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 ); + 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 ); + break; + } } else { - puts( "Not curly or not easy" ); + fprintf( stderr, "WARNING: curl_easy_perform: %s\n", curl_share_strerror( error ) ); } + + curl_easy_cleanup( curl ); free( chunk.memory ); + free( buf ); return res; } +void usage( char *pname ) { + fprintf( stderr, "Usage: %s \n", pname ); + exit( EXIT_FAILURE ); +} + int main( int argc, char *argv[], char *const envp[] ) { - struct file_info_t fi; + struct file_info_t fi = FILE_INFO_INITIALIZER; int csize = 1024; int res; + if ( argc < 2 ) - goto err_usage; + usage( basename( argv[0] ) ); ie( getenv( "HOME" ) ); cfg.user = getenv( "USER" ); cfg.pass = getenv( "PASS" ); - cfg.bwlup = 0; cfg.url = getenv( "URL" ) ? getenv( "URL" ) : URL_BASE; + cfg.bwlup = 0; if ( 0 != fill_file_info( argv[1], &fi ) ) goto err_file; + if ( CURLE_OK != curl_global_init( CURL_GLOBAL_SSL ) ) - goto err_curl; + 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( "%s: %d%% (%5.2f kB/s)\r", fi.name, (int)(100.0 * fi.coff / fi.size), fi.speed / 1024.0 ); + 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( "" ); curl_global_cleanup(); - return 0; -err_usage: + exit( EXIT_SUCCESS ); + err_file: err_curl: - return -1; + exit( EXIT_FAILURE ); }