* Refactoring kaoupload.c 2nd pass WIP.
authorUrban Wallasch <urban.wallasch@freenet.de>
Sat, 17 Apr 2021 09:49:44 +0000 (11:49 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Sat, 17 Apr 2021 09:49:44 +0000 (11:49 +0200)
.gitignore [new file with mode: 0644]
Makefile
kaoupload.c

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..0d019ef
--- /dev/null
@@ -0,0 +1 @@
+kaoupload
index d731f4df5a4a77b1902a2c6a714f24f1146f363b..d412d9e32a63008f7a6f774cd736c90c0c2e306f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,8 @@
 .PHONY: all clean
 
-CFLAGS+=`pkg-config --cflags libcurl`
-LDFLAGS+=`pkg-config --libs libcurl`
+CFLAGS += -W -Wall
+CFLAGS += `pkg-config --cflags libcurl`
+LDFLAGS += `pkg-config --libs libcurl`
 
 all: kaoupload
 
index 7e7766811904c59f5b5f286836ce5ef330700037..ab523a02d7c86855f0d68a9710d0ddb829173842 100644 (file)
@@ -24,6 +24,15 @@ static struct kaoconf {
     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;
@@ -32,7 +41,7 @@ static void ie( const char *home ) {
 
     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 ) ) {
@@ -57,16 +66,30 @@ static void ie( const char *home ) {
         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 );
 }
 
@@ -79,8 +102,7 @@ struct MemoryStruct {
     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;
@@ -91,142 +113,154 @@ static size_t WriteMemoryCallback( void *contents, size_t size, size_t nmemb, vo
     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] ) );
@@ -237,28 +271,19 @@ int main( int argc, char *argv[], char *const envp[] ) {
     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;
 }