/src/clib/src/common/clib-cache.c
Line | Count | Source |
1 | | // |
2 | | // clib-cache.c |
3 | | // |
4 | | // Copyright (c) 2016-2020 clib authors |
5 | | // MIT licensed |
6 | | // |
7 | | |
8 | | #include "clib-cache.h" |
9 | | #include "copy/copy.h" |
10 | | #include "fs/fs.h" |
11 | | #include "rimraf/rimraf.h" |
12 | | #include <limits.h> |
13 | | #include <mkdirp/mkdirp.h> |
14 | | #include <stdio.h> |
15 | | #include <stdlib.h> |
16 | | #include <unistd.h> |
17 | | |
18 | | #define GET_PKG_CACHE(a, n, v) \ |
19 | 0 | char pkg_cache[BUFSIZ]; \ |
20 | 0 | package_cache_path(pkg_cache, a, n, v); |
21 | | |
22 | | #define GET_JSON_CACHE(a, n, v) \ |
23 | 0 | char json_cache[BUFSIZ]; \ |
24 | 0 | json_cache_path(json_cache, a, n, v); |
25 | | |
26 | | #ifdef _WIN32 |
27 | | #define BASE_DIR getenv("AppData") |
28 | | #else |
29 | 0 | #define BASE_DIR getenv("HOME") |
30 | | #endif |
31 | | |
32 | 0 | #define BASE_CACHE_PATTERN "%s/.cache/clib" |
33 | 0 | #define PKG_CACHE_PATTERN "%s/%s_%s_%s" |
34 | 0 | #define JSON_CACHE_PATTERN "%s/%s_%s_%s.json" |
35 | | |
36 | | /** Portable PATH_MAX ? */ |
37 | | static char package_cache_dir[BUFSIZ]; |
38 | | static char search_cache[BUFSIZ]; |
39 | | static char json_cache_dir[BUFSIZ]; |
40 | | static char meta_cache_dir[BUFSIZ]; |
41 | | static time_t expiration; |
42 | | |
43 | | static void json_cache_path(char *pkg_cache, char *author, char *name, |
44 | 0 | char *version) { |
45 | 0 | sprintf(pkg_cache, JSON_CACHE_PATTERN, json_cache_dir, author, name, version); |
46 | 0 | } |
47 | | |
48 | | static void package_cache_path(char *json_cache, char *author, char *name, |
49 | 0 | char *version) { |
50 | 0 | sprintf(json_cache, PKG_CACHE_PATTERN, package_cache_dir, author, name, |
51 | 0 | version); |
52 | 0 | } |
53 | | |
54 | 0 | const char *clib_cache_dir(void) { return package_cache_dir; } |
55 | | |
56 | 0 | static int check_dir(char *dir) { |
57 | 0 | if (0 != (fs_exists(dir))) { |
58 | 0 | return mkdirp(dir, 0700); |
59 | 0 | } |
60 | 0 | return 0; |
61 | 0 | } |
62 | | |
63 | 0 | int clib_cache_meta_init(void) { |
64 | 0 | sprintf(meta_cache_dir, BASE_CACHE_PATTERN "/meta", BASE_DIR); |
65 | |
|
66 | 0 | if (0 != check_dir(meta_cache_dir)) { |
67 | 0 | return -1; |
68 | 0 | } |
69 | | |
70 | 0 | return 0; |
71 | 0 | } |
72 | | |
73 | 0 | const char *clib_cache_meta_dir(void) { return meta_cache_dir; } |
74 | | |
75 | 0 | int clib_cache_init(time_t exp) { |
76 | 0 | expiration = exp; |
77 | |
|
78 | 0 | sprintf(package_cache_dir, BASE_CACHE_PATTERN "/packages", BASE_DIR); |
79 | 0 | sprintf(json_cache_dir, BASE_CACHE_PATTERN "/json", BASE_DIR); |
80 | 0 | sprintf(search_cache, BASE_CACHE_PATTERN "/search.html", BASE_DIR); |
81 | |
|
82 | 0 | if (0 != check_dir(package_cache_dir)) { |
83 | 0 | return -1; |
84 | 0 | } |
85 | 0 | if (0 != check_dir(json_cache_dir)) { |
86 | 0 | return -1; |
87 | 0 | } |
88 | | |
89 | 0 | return 0; |
90 | 0 | } |
91 | | |
92 | 0 | static int is_expired(char *cache) { |
93 | 0 | fs_stats *stat = fs_stat(cache); |
94 | |
|
95 | 0 | if (!stat) { |
96 | 0 | return -1; |
97 | 0 | } |
98 | | |
99 | 0 | time_t modified = stat->st_mtime; |
100 | 0 | time_t now = time(NULL); |
101 | 0 | free(stat); |
102 | |
|
103 | 0 | return now - modified >= expiration; |
104 | 0 | } |
105 | | |
106 | 0 | int clib_cache_has_json(char *author, char *name, char *version) { |
107 | 0 | GET_JSON_CACHE(author, name, version); |
108 | |
|
109 | 0 | return 0 == fs_exists(json_cache) && !is_expired(json_cache); |
110 | 0 | } |
111 | | |
112 | 0 | char *clib_cache_read_json(char *author, char *name, char *version) { |
113 | 0 | GET_JSON_CACHE(author, name, version); |
114 | |
|
115 | 0 | if (is_expired(json_cache)) { |
116 | 0 | return NULL; |
117 | 0 | } |
118 | | |
119 | 0 | return fs_read(json_cache); |
120 | 0 | } |
121 | | |
122 | | int clib_cache_save_json(char *author, char *name, char *version, |
123 | 0 | char *content) { |
124 | 0 | GET_JSON_CACHE(author, name, version); |
125 | |
|
126 | 0 | return fs_write(json_cache, content); |
127 | 0 | } |
128 | | |
129 | 0 | int clib_cache_delete_json(char *author, char *name, char *version) { |
130 | 0 | GET_JSON_CACHE(author, name, version); |
131 | |
|
132 | 0 | return unlink(json_cache); |
133 | 0 | } |
134 | | |
135 | 0 | int clib_cache_has_search(void) { |
136 | 0 | return 0 == fs_exists(search_cache) && !is_expired(search_cache); |
137 | 0 | } |
138 | | |
139 | 0 | char *clib_cache_read_search(void) { |
140 | 0 | if (!clib_cache_has_search()) { |
141 | 0 | return NULL; |
142 | 0 | } |
143 | 0 | return fs_read(search_cache); |
144 | 0 | } |
145 | | |
146 | 0 | int clib_cache_save_search(char *content) { |
147 | 0 | return fs_write(search_cache, content); |
148 | 0 | } |
149 | | |
150 | 0 | int clib_cache_delete_search(void) { return unlink(search_cache); } |
151 | | |
152 | 0 | int clib_cache_has_package(char *author, char *name, char *version) { |
153 | 0 | GET_PKG_CACHE(author, name, version); |
154 | |
|
155 | 0 | return 0 == fs_exists(pkg_cache) && !is_expired(pkg_cache); |
156 | 0 | } |
157 | | |
158 | 0 | int clib_cache_is_expired_package(char *author, char *name, char *version) { |
159 | 0 | GET_PKG_CACHE(author, name, version); |
160 | |
|
161 | 0 | return is_expired(pkg_cache); |
162 | 0 | } |
163 | | |
164 | | int clib_cache_save_package(char *author, char *name, char *version, |
165 | 0 | char *pkg_dir) { |
166 | 0 | GET_PKG_CACHE(author, name, version); |
167 | |
|
168 | 0 | if (0 == fs_exists(pkg_cache)) { |
169 | 0 | rimraf(pkg_cache); |
170 | 0 | } |
171 | |
|
172 | 0 | return copy_dir(pkg_dir, pkg_cache); |
173 | 0 | } |
174 | | |
175 | | int clib_cache_load_package(char *author, char *name, char *version, |
176 | 0 | char *target_dir) { |
177 | 0 | GET_PKG_CACHE(author, name, version); |
178 | |
|
179 | 0 | if (-1 == fs_exists(pkg_cache)) { |
180 | 0 | return -1; |
181 | 0 | } |
182 | | |
183 | 0 | if (is_expired(pkg_cache)) { |
184 | 0 | rimraf(pkg_cache); |
185 | |
|
186 | 0 | return -2; |
187 | 0 | } |
188 | | |
189 | 0 | return copy_dir(pkg_cache, target_dir); |
190 | 0 | } |
191 | | |
192 | 0 | int clib_cache_delete_package(char *author, char *name, char *version) { |
193 | 0 | GET_PKG_CACHE(author, name, version); |
194 | |
|
195 | 0 | return rimraf(pkg_cache); |
196 | 0 | } |