diff --git a/Makefile b/Makefile index 9084a34..392838d 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ PRE := $(wildcard prev/*.sh) GEN := gen/prev/scripts.h gen/server.h CFLAGS += -Os -MD -Wall -Wextra -Wno-unused-parameter -LDFLAGS += -lmagic +LDFLAGS += -lmagic -lcrypto all: ctpv diff --git a/ctpv.c b/ctpv.c index 03a977b..7f33a41 100644 --- a/ctpv.c +++ b/ctpv.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "error.h" #include "server.h" @@ -25,9 +26,11 @@ static struct { MODE_END, MODE_LIST, MODE_MIME, - MODE_NEWER, + MODE_CHECK_CACHE, } mode; char *server_id_s; + char *check_file; + char *ctpv_path; } ctpv = { .mode = MODE_PREVIEW }; static void cleanup(void) { @@ -98,6 +101,11 @@ static int check_file(char const *f) static int preview(int argc, char *argv[]) { + if (!ctpv.ctpv_path) { + print_error("argument 0 is null"); + return ERR; + } + char *f, *w, *h, *x, *y; GET_PARG(f, 0); GET_PARG(w, 1); @@ -114,7 +122,10 @@ static int preview(int argc, char *argv[]) const char *mimetype; ERRCHK_RET(!(mimetype = get_mimetype(f))); - PreviewArgs args = { .f = f, .w = w, .h = h, .x = x, .y = y }; + PreviewArgs args = { + .ctpv = ctpv.ctpv_path, + .f = f, .w = w, .h = h, .x = x, .y = y + }; return run_preview(get_ext(f), mimetype, &args); } @@ -190,17 +201,8 @@ static int mime(int argc, char *argv[]) return OK; } -static int newer(int argc, char *argv[]) +static int is_newer(char *f1, char *f2) { - char *f1, *f2; - GET_PARG(f1, 0); - GET_PARG(f2, 1); - - if (!f1 || !f2) { - print_error("2 file should be given"); - return ERR; - } - struct stat stat1, stat2; ERRCHK_RET(stat(f1, &stat1) == -1, FUNCFAILED("stat"), ERRNOS); ERRCHK_RET(stat(f2, &stat2) == -1, FUNCFAILED("stat"), ERRNOS); @@ -214,12 +216,54 @@ static int newer(int argc, char *argv[]) return OK; } +static void md5_string(char *buf, size_t len, char *s) +{ + unsigned char out[MD5_DIGEST_LENGTH]; + char b[16]; + + MD5((const unsigned char *)s, strlen(s), out); + + buf[0] = '\0'; + for(unsigned int i = 0; i < LEN(out); i++) { + snprintf(b, LEN(b)-1, "%02x", out[i]); + strncat(buf, b, len); + } +} + +static int check_cache(void) +{ + ERRCHK_RET_OK(check_file(ctpv.check_file)); + + char cache_file[FILENAME_MAX]; + ERRCHK_RET_OK( + get_cache_dir(cache_file, LEN(cache_file) - 1, "ctpv//")); + + { + char cache_file_cpy[FILENAME_MAX]; + strncpy(cache_file_cpy, cache_file, LEN(cache_file_cpy) - 1); + ERRCHK_RET(mkpath(cache_file_cpy, 0700) == -1, FUNCFAILED("mkpath"), + ERRNOS); + } + + char name[64]; + md5_string(name, LEN(name)-1, ctpv.check_file); + + strncat(cache_file, name, LEN(cache_file)-1); + puts(cache_file); + + if (access(cache_file, F_OK) != 0) + return ERR; + + return is_newer(cache_file, ctpv.check_file); +} + int main(int argc, char *argv[]) { - program = argc > 0 ? argv[0] : "ctpv"; + ctpv.ctpv_path = argc > 0 ? argv[0] : NULL; + program = ctpv.ctpv_path ? ctpv.ctpv_path : "ctpv"; int c; - while ((c = getopt(argc, argv, "s:ce:lmn")) != -1) { + while ((c = getopt(argc, argv, "s:ce:lmC:")) != -1) { switch (c) { case 's': ctpv.mode = MODE_SERVER; @@ -238,8 +282,9 @@ int main(int argc, char *argv[]) case 'm': ctpv.mode = MODE_MIME; break; - case 'n': - ctpv.mode = MODE_NEWER; + case 'C': + ctpv.mode = MODE_CHECK_CACHE; + ctpv.check_file = optarg; break; default: return EXIT_FAILURE; @@ -269,8 +314,8 @@ int main(int argc, char *argv[]) case MODE_MIME: ret = mime(argc, argv); break; - case MODE_NEWER: - ret = newer(argc, argv); + case MODE_CHECK_CACHE: + ret = check_cache(); break; default: PRINTINTERR("unknowm mode: %d", ctpv.mode); diff --git a/helpers.sh b/helpers.sh index 5d6c0ef..c2bd98a 100644 --- a/helpers.sh +++ b/helpers.sh @@ -20,11 +20,7 @@ check_exist() { } cache() { - cache_d="${XDG_CACHE_HOME:-$HOME/.cache}/ctpv" - mkdir -p "$cache_d" - cache_f="$cache_d/$(printf '%s' "$f" | md5sum - | cut -d' ' -f1)" - test -e "$cache_f" || return - ctpv -n "$cache_f" "$f" + cache_f="$("$ctpv" -C "$f")" } show_image() { diff --git a/preview.c b/preview.c index 99d5d90..8723a0f 100644 --- a/preview.c +++ b/preview.c @@ -155,6 +155,7 @@ static int run(Preview *p, int *exitcode) int run_preview(const char *ext, const char *mimetype, PreviewArgs *pa) { + SET_PENV("ctpv", pa->ctpv); SET_PENV("f", pa->f); SET_PENV("w", pa->w); SET_PENV("h", pa->h); diff --git a/preview.h b/preview.h index ef9cf0a..802548b 100644 --- a/preview.h +++ b/preview.h @@ -9,7 +9,7 @@ typedef struct { } Preview; typedef struct { - char *f, *w, *h, *x, *y; + char *ctpv, *f, *w, *h, *x, *y; } PreviewArgs; void init_previews(Preview *ps, size_t len); diff --git a/utils.c b/utils.c index aef7b71..baacca9 100644 --- a/utils.c +++ b/utils.c @@ -1,12 +1,14 @@ -#include +#include #include #include #include +#include +#include #include "error.h" #include "utils.h" -char *program; +char *program = NULL; int spawn_redirect(const void *arg) { @@ -80,6 +82,40 @@ int strcmpnull(char const *s1, char const *s2) return strcmp(s1, s2); } +int get_cache_dir(char *buf, size_t len, char *name) +{ + char *home, *cache_d, cache_d_buf[FILENAME_MAX]; + + if (!(cache_d = getenv("XDG_CACHE_HOME"))) { + home = getenv("HOME"); + ERRCHK_RET(!home, "HOME env var does not exist"); + + snprintf(cache_d_buf, LEN(cache_d_buf)-1, "%s/.cache", home); + cache_d = cache_d_buf; + } + + snprintf(buf, len, "%s/%s", cache_d, name); + return OK; +} + +int mkpath(char* file_path, mode_t mode) +{ + for (char* p = strchr(file_path + 1, '/'); p; p = strchr(p + 1, '/')) { + *p = '\0'; + + if (mkdir(file_path, mode) == -1) { + if (errno != EEXIST) { + *p = '/'; + return -1; + } + } + + *p = '/'; + } + + return 0; +} + CharVec char_v_new(size_t cap) { CharVec v; diff --git a/utils.h b/utils.h index 860e987..a2a0150 100644 --- a/utils.h +++ b/utils.h @@ -34,6 +34,8 @@ int spawn(char *args[], pid_t *cpid, int *exitcode, int (*cfunc)(const void *), const void *carg); int strcmpnull(char const *s1, char const *s2); +int get_cache_dir(char *buf, size_t len, char *name); +int mkpath(char* file_path, mode_t mode); CharVec char_v_new(size_t cap); void char_v_append(CharVec *v, char c);