4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
39 /* a valid subpath is a relative path not looking deeper than root using .. */
40 static int validsubpath(const char *subpath)
43 if (subpath[i] == '/')
46 switch(subpath[i++]) {
50 if (subpath[i] == '/') {
54 if (subpath[i++] == '.') {
59 if (subpath[i++] == '/') {
65 while(subpath[i] && subpath[i] != '/')
76 static const char *normalsubpath(const char *subpath)
78 while(*subpath == '/')
80 return validsubpath(subpath) ? subpath : NULL;
83 struct wgt *wgt_create()
85 struct wgt *wgt = malloc(sizeof * wgt);
97 void wgt_disconnect(struct wgt *wgt)
100 if (wgt->rootfd >= 0)
105 void wgt_locales_reset(struct wgt *wgt)
108 while(wgt->nrlocales)
109 free(wgt->locales[--wgt->nrlocales]);
112 void wgt_addref(struct wgt *wgt)
118 void wgt_unref(struct wgt *wgt)
121 if (!--wgt->refcount) {
123 wgt_locales_reset(wgt);
129 int wgt_connectat(struct wgt *wgt, int dirfd, const char *pathname)
135 rfd = (pathname && *pathname) ? openat(dirfd, pathname, O_PATH|O_DIRECTORY) : dup(dirfd);
139 if (wgt->rootfd >= 0)
145 int wgt_connect(struct wgt *wgt, const char *pathname)
147 return wgt_connectat(wgt, AT_FDCWD, pathname);
150 struct wgt *wgt_createat(int dirfd, const char *pathname)
152 struct wgt *wgt = wgt_create();
154 if (wgt_connectat(wgt, dirfd, pathname)) {
162 int wgt_is_connected(struct wgt *wgt)
165 return wgt->rootfd != -1;
168 int wgt_has(struct wgt *wgt, const char *filename)
171 assert(wgt_is_connected(wgt));
173 filename = normalsubpath(filename);
178 return 0 == faccessat(wgt->rootfd, filename, F_OK, 0);
181 int wgt_open_read(struct wgt *wgt, const char *filename)
184 assert(wgt_is_connected(wgt));
185 filename = normalsubpath(filename);
190 return openat(wgt->rootfd, filename, O_RDONLY);
193 static int locadd(struct wgt *wgt, const char *locstr, int length)
198 item = strndup(locstr, length);
200 for (i = 0 ; item[i] ; i++)
201 item[i] = tolower(item[i]);
202 for (i = 0 ; i < wgt->nrlocales ; i++)
203 if (!strcmp(item, wgt->locales[i])) {
208 ptr = realloc(wgt->locales, (1 + wgt->nrlocales) * sizeof(wgt->locales[0]));
211 wgt->locales[wgt->nrlocales++] = item;
220 int wgt_locales_add(struct wgt *wgt, const char *locstr)
222 const char *stop, *next;
225 stop = strchrnul(locstr, ',');
226 next = stop + !!*stop;
227 while (locstr != stop) {
228 if (locadd(wgt, locstr, stop - locstr))
230 do { stop--; } while(stop > locstr && *stop != '-');
237 int wgt_locales_score(struct wgt *wgt, const char *lang)
243 for (i = 0 ; i < wgt->nrlocales ; i++)
244 if (!strcasecmp(lang, wgt->locales[i]))
250 static const char *localize(struct wgt *wgt, const char *filename, char path[PATH_MAX])
254 filename = normalsubpath(filename);
259 for (i = 0 ; i < wgt->nrlocales ; i++) {
260 if (snprintf(path, PATH_MAX, "locales/%s/%s", wgt->locales[i], filename) >= PATH_MAX) {
264 if (0 == faccessat(wgt->rootfd, path, F_OK, 0))
267 if (0 == faccessat(wgt->rootfd, filename, F_OK, 0))
273 char *wgt_locales_locate(struct wgt *wgt, const char *filename)
280 assert(wgt_is_connected(wgt));
281 loc = localize(wgt, filename, path);
285 result = strdup(loc);
293 int wgt_locales_open_read(struct wgt *wgt, const char *filename)
299 assert(wgt_is_connected(wgt));
300 loc = localize(wgt, filename, path);
304 return openat(wgt->rootfd, loc, O_RDONLY);
308 #if defined(TEST_wgt_validsubpath)
310 void t(const char *subpath, int validity) {
311 printf("%s -> %d = %d, %s\n", subpath, validity, validsubpath(subpath), validsubpath(subpath)==validity ? "ok" : "NOT OK");
323 t("a/b/c/../../..",1);
324 t("a/b/c/../../../.",1);
325 t("./..a/././..b/..c/./.././.././../.",1);
326 t("./..a/././..b/..c/./.././.././.././..",0);
327 t("./..a//.//./..b/..c/./.././/./././///.././.././a/a/a/a/a",1);