dav/main.c

changeset 334
5f80c5d0e87f
parent 333
000cdd124115
child 338
c7f3fe4abdb2
--- a/dav/main.c	Wed Oct 25 17:52:35 2017 +0200
+++ b/dav/main.c	Sat Oct 28 15:25:17 2017 +0200
@@ -157,8 +157,8 @@
 
 static char *cmdusageinfo[] = {
     "list [-altdepcR] [-u <date>] <url>",
-    "get [-pcRK] [-o <file>] [-u <date>] <url>",
-    "put [-pcR] [-k <key>] [-L <lock>] <url> <file>",
+    "get [-pcRKA] [-o <file>] [-u <date>] <url>",
+    "put [-pcRA] [-k <key>] [-L <lock>] <url> <file>",
     "mkdir [-pc] [-k <key>] [-L <lock>] <url>",
     "remove [-pc] [-L <lock>] <url>",
     "copy [-pcO] [-L <lock>] <url> <url>",
@@ -218,6 +218,7 @@
     fprintf(stderr, "        -d         order by last modified date\n");
     fprintf(stderr, "        -e         show extended flags\n");
     fprintf(stderr, "        -O         override resources\n");
+    fprintf(stderr, "        -A         tar import/export\n");
     fprintf(stderr, "        -L <lock>  specificy lock token\n");
     fprintf(stderr, "        -T <sec>   timeout in seconds\n");
     fprintf(stderr, "        -n <uri>   specify namespace uri\n");
@@ -717,12 +718,19 @@
      * use stdout if the output file is -
      */
     char *outfile = cmd_getoption(a, "output");
+    char *basepath = outfile;
+    char *tar = cmd_getoption(a, "tar");
     if(!outfile) {
         if(res->iscollection) {
-            outfile = "";
+            basepath = "";
         } else {
-            outfile = res->name;
+            basepath = res->name;
         }
+        if(tar) {
+            outfile = "-";
+        }
+    } else if(tar) {
+        basepath = "";
     } else if(res->iscollection && !strcmp(outfile, "-")) {
         fprintf(
                 stderr,
@@ -738,7 +746,7 @@
     
     GetResource *getres = malloc(sizeof(GetResource));
     getres->res = res;
-    getres->path = strdup(outfile);
+    getres->path = strdup(basepath);
     
     char *structure = cmd_getoption(a, "structure");
     
@@ -756,7 +764,7 @@
                 GetResource *newres = malloc(sizeof(GetResource));
                 newres->res = child;
                 newres->path = pathlen > 0 ?
-                    util_concat_path(g->path, child->name) : child->name;
+                    util_concat_path(g->path, child->name) : strdup(child->name);
 
                 stack = ucx_list_prepend(stack, newres);
                 
@@ -779,15 +787,36 @@
         }
     }
     
+    // download resources
     int ret;
+    getfunc get;
+    TarOutputStream *tout = NULL;
+    if(tar) {
+        get = (getfunc)resource2tar;
+        FILE *tarfile = strcmp(outfile, "-") ? fopen(outfile, "wb") : stdout;
+        if(!tarfile) {
+            perror("Cannot open tar output file");
+            return -1;
+        }
+        tout = tar_open(tarfile);
+    } else {
+        get = get_resource;
+    }
     UCX_FOREACH(elm, reslist) {
         GetResource *getres = elm->data;
         
-        ret = get_resource(repo, getres->res, a, getres->path);
+        ret = get(repo, getres, a, tout);
         if(ret) {
             break;
         }
     }
+    if(tar) {
+        // close tar stream
+        if(tar_close(tout)) {
+            fprintf(stderr, "tar stream broken\n");
+            ret = -1;
+        }
+    }
     
     ucx_list_free_content(reslist, free_getres);
     ucx_list_free(reslist);
@@ -796,8 +825,9 @@
     return ret;
 }
 
-int get_resource(Repository *repo, DavResource *res, CmdArgs *a, char *out) {
-    size_t outlen = strlen(out);
+int get_resource(Repository *repo, GetResource *getres, CmdArgs *a, void *unused) {
+    DavResource *res = getres->res;
+    char *out = res->path;
     
     if(res->iscollection) {
         printf("get: %s\n", res->path);
@@ -851,6 +881,35 @@
     return 0;
 }
 
+#define DEFAULT_DIR_MODE T_IRUSR | T_IWUSR | T_IXUSR | T_IRGRP | T_IXGRP | T_IROTH | T_IXOTH
+#define DEFAULT_FILE_MODE T_IRUSR | T_IWUSR | T_IRGRP | T_IROTH
+
+int resource2tar(Repository *repo, GetResource *res, CmdArgs *a, TarOutputStream *tar) { 
+    DavResource *d = res->res;
+    
+    if(d->iscollection) {
+        fprintf(stderr, "add d: %s\n", res->path);
+        return tar_add_dir(tar, res->path, DEFAULT_DIR_MODE, d->lastmodified);
+    }
+    
+    fprintf(stderr, "add f: %s\n", res->path);
+    
+    // add tar file header
+    if(tar_begin_file(tar, res->path, DEFAULT_FILE_MODE, d->contentlength, d->lastmodified)) {
+        fprintf(stderr, "TAR Error: %s\n", tar_error2str(tar->error));
+        return -1;
+    }
+    
+    if(dav_get_content(d, tar, (dav_write_func)tar_fwrite)) {
+        print_resource_error(d->session, d->path);
+        return -1;
+    }
+    
+    // download content
+    
+    return tar_end_file(tar);
+}
+
 int cmd_put(CmdArgs *a) {
     if(a->argc != 2) {
         // TODO: change, when put supports multiple files (however it should do)
@@ -883,12 +942,17 @@
         }
     }
     
+    char *tar = cmd_getoption(a, "tar");
     int ret;
-    if(!strcmp(file, "-")) {
-        FILE *in = stdin;
-        ret = put_file(repo, a, sn, path, "stdin", in, 0);
+    if(!tar) {
+        if(!strcmp(file, "-")) {
+            FILE *in = stdin;
+            ret = put_file(repo, a, sn, path, "stdin", in, 0);
+        } else {
+            ret = put_entry(repo, a, sn, path, file, TRUE); 
+        }
     } else {
-        ret = put_entry(repo, a, sn, path, file, TRUE); 
+        ret = put_tar(repo, a, sn, file, path);
     }
     
     free(path);
@@ -977,6 +1041,91 @@
     return ret;
 }
 
+int put_tar(Repository *repo, CmdArgs *a, DavSession *sn, char *tarfile, char *path) {
+    int isstdin = !strcmp(tarfile, "-");
+    FILE *in = isstdin ? stdin : fopen(tarfile, "rb");
+    if(!in) {
+        perror("Cannot open tar file");
+        return -1;
+    }
+    
+    DavResource *col = NULL;
+    for(int i=0;i<2;i++) {
+        col = dav_query(sn, "select - from %s", path);
+        if(!col && sn->error == DAV_UNAUTHORIZED) {
+            if(request_auth(repo, sn, a)) {
+                continue;
+            }
+        }
+        break;
+    }
+    if(!col) {
+        if(sn->error == DAV_NOT_FOUND) {
+            col = dav_resource_new(sn, path);
+            col->iscollection = TRUE;
+            if(dav_create(col)) {
+                print_resource_error(sn, path);
+                return -1;
+            }
+        } else {
+            print_resource_error(sn, path);
+            return -1;
+        }
+    } else if(!col->iscollection) {
+        fprintf(stderr, "%s is not a collection\n", col->href);
+        return -1;
+    }
+    
+    
+    int ret = 0;
+    TarInputStream *tar = tar_inputstream_open(in);
+    TarEntry *e = NULL;
+    while((e = tar_read_entry(tar)) != NULL) {
+        char *newpath = util_concat_path(path, e->path);
+        if(e->type == TAR_TYPE_FILE) {
+            fprintf(stderr, "put: %s\n", e->path);
+            DavResource *res = dav_resource_new(sn, newpath);
+            dav_set_content(res, tar, (dav_read_func)tar_fread);
+            dav_set_content_length(res, (size_t)e->size);
+
+            if(dav_store(res)) {
+                print_resource_error(sn, res->path);
+                fprintf(stderr, "Cannot upload file.\n");
+                if(sn->errorstr) {
+                    fprintf(stderr, "%s\n", sn->errorstr);
+                }
+                return -1;
+            }
+            
+        } else if(e->type == TAR_TYPE_DIRECTORY) {
+            printf("mkcol: %s\n", e->path);
+            DavResource *res = dav_resource_new(sn, newpath);
+            res->iscollection = TRUE;
+            if(!dav_exists(res)) {
+                if(dav_create(res)) {
+                    fprintf(stderr, "Cannot create collection %s\n", newpath);
+                    print_resource_error(sn, res->path);
+                    ret = 1;
+                    free(newpath);
+                    break;
+                }
+            }
+        } else {
+            fprintf(stderr, "skip: %s\n", e->path);
+        }
+        free(newpath);
+    }
+    if(tar->error != TAR_OK) {
+        ret = -1;
+    }
+    
+    if(!isstdin) {
+        fclose(in);
+    }
+    
+    return ret;
+}
+
 int put_file(Repository *repo, CmdArgs *a, DavSession *sn, char *path, char *name, FILE *in, off_t len) {
     DavResource *res = NULL;
     for(int i=0;i<2;i++) {

mercurial