first draft for dav edit command feature/dav-edit

Sat, 28 Mar 2020 15:53:44 +0100

author
Mike Becker <universe@uap-core.de>
date
Sat, 28 Mar 2020 15:53:44 +0100
branch
feature/dav-edit
changeset 709
857330e1e3f4
parent 708
3fc7f813b53d
child 710
7384da29c2b4

first draft for dav edit command

dav/main.c file | annotate | diff | comparison | revisions
dav/main.h file | annotate | diff | comparison | revisions
--- a/dav/main.c	Sun Dec 15 18:43:01 2019 +0100
+++ b/dav/main.c	Sat Mar 28 15:53:44 2020 +0100
@@ -35,6 +35,7 @@
 #include <unistd.h>
 #include <time.h>
 #include <sys/types.h>
+#include <sys/wait.h>
 #include <ucx/string.h>
 #include <ucx/utils.h>
 #include <dirent.h>
@@ -158,6 +159,8 @@
         } else if(!strcasecmp(cmd, "cat")) {
             ucx_map_cstr_put(args->options, "output", "-");
             ret = cmd_get(args, FALSE);
+        } else if(!strcasecmp(cmd, "edit")) {
+            ret = cmd_edit(args);
         } else if(!strcasecmp(cmd, "put")) {
             ret = cmd_put(args, FALSE);
         } else if(
@@ -247,6 +250,7 @@
     "list [-altdepcR] [-u <date>] <url>",
     "get [-pcRK] [-o <file>] [-u <date>] [-V <version>] <url>",
     "put [-pcR] [-k <key>] [-L <lock>] <url> <file...>",
+    "edit [-V <version>] <url>",
     "mkdir [-pc] [-k <key>] [-L <lock>] <url> [file...]",
     "remove [-pc] [-L <lock>] <url> [file...]",
     "copy [-pcO] [-L <lock>] <url> <url>",
@@ -1115,6 +1119,160 @@
     return ret;
 }
 
+static int file_seek(FILE *f, curl_off_t offset, int origin) {
+    int ret = fseek(f, offset, origin);
+    return ret == 0 ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK;
+}
+
+int cmd_edit(CmdArgs *a) {
+    if(a->argc != 1) {
+        fprintf(stderr, "Too %s arguments\n", a->argc < 1 ? "few":"many");
+        fprintf(stderr, "Usage: dav %s\n", find_usage_str("edit"));
+        return -1;
+    }
+    
+    char *url = a->argv[0];
+    char *path = NULL;
+    Repository *repo = url2repo(url, &path);
+    DavSession *sn = connect_to_repo(repo, path, a);
+    
+    if(set_session_config(sn, a)) {
+        return -1;
+    }
+       
+    char *version = cmd_getoption(a, "version");        
+    DavResource *res;
+    
+    res = dav_resource_new(sn, path);
+    int fresh_resource = !dav_exists(res);
+    if(fresh_resource) {
+        // create the resource to check if the resource can be created
+        // we don't want the user to invest time in editing and fail afterwards
+        if(dav_create(res)) {
+            fprintf(stderr, "Resource does not exist and cannot be created.\n");
+            return -1;
+        }
+    } else {
+        if(!res) {
+            print_resource_error(sn, path);
+            return -1;
+        }
+        if(res->iscollection) {
+            fprintf(stderr, "Resource %s is a collection "
+                    "and cannot be opened in an editor.\n", res->path);
+            return -1;
+        }
+
+        if(version) {
+            DavResource *vres = find_version(res, version);
+            if(!vres) {
+                fprintf(stderr, "Cannot find version '%s' for resource.\n", version);
+                return -1;
+            }
+            dav_resource_free_all(res);
+            res = vres;
+        }
+    }
+    
+    // open temporary file
+    // TODO: look up the location of the temp directory, maybe add sys_* funcs
+    char outfile[24];
+    strncpy(outfile, ".dav-edit-XXXXXX", 24);
+    int tmp_fd = mkstemp(outfile);
+    if(tmp_fd < 0) {
+        perror("Cannot open temporary file");
+        return -1;
+    }
+    
+    // get resource
+    if(!fresh_resource) {
+        FILE* tmp_stream = sys_fopen(outfile, "wb");
+        if(!tmp_stream) {
+            perror("Cannot open temporary file");
+            close(tmp_fd);
+            return -1;
+        }
+        if(dav_get_content(res, tmp_stream, (dav_write_func)fwrite)) {
+            print_resource_error(sn, path);
+            close(tmp_fd);
+            unlink(outfile);
+            return -1;
+        }
+        fclose(tmp_stream);
+    }
+    
+    // remember time s.t. we can later check if the file has changed
+    SYS_STAT tmp_stat;
+    // TODO: maybe add sys_fstat
+    if(sys_stat(outfile, &tmp_stat)) {
+        perror("Cannot stat temporary file");
+        close(tmp_fd);
+        unlink(outfile);
+        return -1;
+    }
+    time_t dl_mtime = tmp_stat.st_mtime;
+    
+    // open in editor
+    char* default_editor = "vi";
+    char* editor = getenv("EDITOR");
+    if(!editor) editor = default_editor;
+    char* viargs[3] = {editor, outfile, NULL};
+
+    int ret = 0;
+    // TODO: solution for windows
+    pid_t pid = fork();
+    if(pid < 0) {
+        perror("Cannot create process for editor");
+        ret = 1;
+    } else if(pid == 0) {
+        if(execvp(viargs[0], viargs)) {
+            perror("Opening the editor failed");
+            return 1;
+        }
+    } else {
+        int status = -1;
+        ret = waitpid(pid, &status, 0);
+        if(ret < 0) {
+            perror("Error waiting for editor");
+        } else if(WEXITSTATUS(status)) {
+            fprintf(stderr,
+                    "Editor closed abnormally - file will not be uploaded.\n");
+            ret = 1;
+        } else {
+            // check if the file has changed
+            if (sys_stat(outfile, &tmp_stat)) {
+                perror("Cannot stat temporary file");
+                ret = 1;
+            } else if (dl_mtime < tmp_stat.st_mtime) {
+                // upload changed file
+                FILE* tmp_stream = sys_fopen(outfile, "rb");
+                if(!tmp_stream) {
+                    perror("Cannot open temporary file");
+                    close(tmp_fd);
+                    return -1;
+                }
+                dav_set_content(res, tmp_stream,
+                        (dav_read_func)fread,
+                        (dav_seek_func)file_seek);
+                dav_set_content_length(res, tmp_stat.st_size);
+                ret = dav_store(res);
+                fclose(tmp_stream);
+                if(ret) {
+                    print_resource_error(sn, path);
+                }
+            } else {
+                printf("No changes by user - file will not be uploaded.\n");
+            }
+        }
+    }
+    
+    close(tmp_fd);
+    unlink(outfile);
+    free(path);
+    
+    return ret;
+}
+
 int get_resource(Repository *repo, GetResource *getres, CmdArgs *a, void *unused) {
     DavResource *res = getres->res;
     char *out = getres->path;
@@ -1503,11 +1661,6 @@
     return ret;
 }
 
-static int file_seek(FILE *f, curl_off_t offset, int origin) {
-    int ret = fseek(f, offset, origin);
-    return ret == 0 ? CURL_SEEKFUNC_OK : CURL_SEEKFUNC_CANTSEEK;
-}
-
 int put_file(
         Repository *repo,
         CmdArgs *a,
--- a/dav/main.h	Sun Dec 15 18:43:01 2019 +0100
+++ b/dav/main.h	Sat Mar 28 15:53:44 2020 +0100
@@ -96,6 +96,8 @@
         FILE *in,
         off_t len);
 
+int cmd_edit(CmdArgs *args);
+
 int cmd_remove(CmdArgs *args);
 int cmd_mkdir(CmdArgs *args);
 

mercurial