4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
41 /* a valid subpath is a relative path not looking deeper than root using .. */
42 static int validsubpath(const char *subpath)
45 if (subpath[i] == '/')
48 switch(subpath[i++]) {
52 if (subpath[i] == '/') {
56 if (subpath[i++] == '.') {
61 if (subpath[i++] == '/') {
67 while(subpath[i] && subpath[i] != '/')
78 static const char *normalsubpath(const char *subpath)
80 while(*subpath == '/')
82 return validsubpath(subpath) ? subpath : NULL;
85 struct wgt *wgt_create()
87 struct wgt *wgt = malloc(sizeof * wgt);
99 void wgt_disconnect(struct wgt *wgt)
102 if (wgt->rootfd >= 0)
107 void wgt_locales_reset(struct wgt *wgt)
110 while(wgt->nrlocales)
111 free(wgt->locales[--wgt->nrlocales]);
114 void wgt_addref(struct wgt *wgt)
120 void wgt_unref(struct wgt *wgt)
123 if (!--wgt->refcount) {
125 wgt_locales_reset(wgt);
131 int wgt_connectat(struct wgt *wgt, int dirfd, const char *pathname)
137 rfd = (pathname && *pathname) ? openat(dirfd, pathname, O_PATH|O_DIRECTORY) : dup(dirfd);
141 if (wgt->rootfd >= 0)
147 int wgt_connect(struct wgt *wgt, const char *pathname)
149 return wgt_connectat(wgt, AT_FDCWD, pathname);
152 struct wgt *wgt_createat(int dirfd, const char *pathname)
154 struct wgt *wgt = wgt_create();
156 if (wgt_connectat(wgt, dirfd, pathname)) {
164 int wgt_is_connected(struct wgt *wgt)
167 return wgt->rootfd != -1;
170 int wgt_has(struct wgt *wgt, const char *filename)
173 assert(wgt_is_connected(wgt));
175 filename = normalsubpath(filename);
180 return 0 == faccessat(wgt->rootfd, filename, F_OK, 0);
183 int wgt_open_read(struct wgt *wgt, const char *filename)
186 assert(wgt_is_connected(wgt));
187 filename = normalsubpath(filename);
192 return openat(wgt->rootfd, filename, O_RDONLY);
195 static int locadd(struct wgt *wgt, const char *locstr, int length)
200 item = strndup(locstr, length);
202 for (i = 0 ; item[i] ; i++)
203 item[i] = tolower(item[i]);
204 for (i = 0 ; i < wgt->nrlocales ; i++)
205 if (!strcmp(item, wgt->locales[i])) {
210 ptr = realloc(wgt->locales, (1 + wgt->nrlocales) * sizeof(wgt->locales[0]));
213 wgt->locales[wgt->nrlocales++] = item;
222 int wgt_locales_add(struct wgt *wgt, const char *locstr)
224 const char *stop, *next;
227 stop = strchrnul(locstr, ',');
228 next = stop + !!*stop;
229 while (locstr != stop) {
230 if (locadd(wgt, locstr, stop - locstr))
232 do { stop--; } while(stop > locstr && *stop != '-');
239 int wgt_locales_score(struct wgt *wgt, const char *lang)
245 for (i = 0 ; i < wgt->nrlocales ; i++)
246 if (!strcasecmp(lang, wgt->locales[i]))
252 static const char *localize(struct wgt *wgt, const char *filename, char path[PATH_MAX])
256 filename = normalsubpath(filename);
261 for (i = 0 ; i < wgt->nrlocales ; i++) {
262 if (snprintf(path, PATH_MAX, "locales/%s/%s", wgt->locales[i], filename) >= PATH_MAX) {
266 if (0 == faccessat(wgt->rootfd, path, F_OK, 0))
269 if (0 == faccessat(wgt->rootfd, filename, F_OK, 0))
275 char *wgt_locales_locate(struct wgt *wgt, const char *filename)
282 assert(wgt_is_connected(wgt));
283 loc = localize(wgt, filename, path);
287 result = strdup(loc);
295 int wgt_locales_open_read(struct wgt *wgt, const char *filename)
301 assert(wgt_is_connected(wgt));
302 loc = localize(wgt, filename, path);
306 return openat(wgt->rootfd, loc, O_RDONLY);
310 #if defined(TEST_wgt_validsubpath)
312 void t(const char *subpath, int validity) {
313 printf("%s -> %d = %d, %s\n", subpath, validity, validsubpath(subpath), validsubpath(subpath)==validity ? "ok" : "NOT OK");
325 t("a/b/c/../../..",1);
326 t("a/b/c/../../../.",1);
327 t("./..a/././..b/..c/./.././.././../.",1);
328 t("./..a/././..b/..c/./.././.././.././..",0);
329 t("./..a//.//./..b/..c/./.././/./././///.././.././a/a/a/a/a",1);