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)
137 rfd = openat(rfd, pathname, O_PATH|O_DIRECTORY);
141 if (wgt->rootfd >= 0)
147 int wgt_connect(struct wgt *wgt, const char *pathname)
149 return wgt_connectat(wgt, AT_FDCWD, pathname);
152 int wgt_is_connected(struct wgt *wgt)
155 return wgt->rootfd != -1;
158 int wgt_has(struct wgt *wgt, const char *filename)
161 assert(wgt_is_connected(wgt));
163 filename = normalsubpath(filename);
168 return 0 == faccessat(wgt->rootfd, filename, F_OK, 0);
171 int wgt_open_read(struct wgt *wgt, const char *filename)
174 assert(wgt_is_connected(wgt));
175 filename = normalsubpath(filename);
180 return openat(wgt->rootfd, filename, O_RDONLY);
183 static int locadd(struct wgt *wgt, const char *locstr, int length)
188 item = strndup(locstr, length);
190 for (i = 0 ; item[i] ; i++)
191 item[i] = tolower(item[i]);
192 for (i = 0 ; i < wgt->nrlocales ; i++)
193 if (!strcmp(item, wgt->locales[i])) {
198 ptr = realloc(wgt->locales, (1 + wgt->nrlocales) * sizeof(wgt->locales[0]));
201 wgt->locales[wgt->nrlocales++] = item;
210 int wgt_locales_add(struct wgt *wgt, const char *locstr)
212 const char *stop, *next;
215 stop = strchrnul(locstr, ',');
216 next = stop + !!*stop;
217 while (locstr != stop) {
218 if (locadd(wgt, locstr, stop - locstr))
220 do { stop--; } while(stop > locstr && *stop != '-');
227 int wgt_locales_score(struct wgt *wgt, const char *lang)
233 for (i = 0 ; i < wgt->nrlocales ; i++)
234 if (!strcasecmp(lang, wgt->locales[i]))
240 static const char *localize(struct wgt *wgt, const char *filename, char path[PATH_MAX])
244 filename = normalsubpath(filename);
249 for (i = 0 ; i < wgt->nrlocales ; i++) {
250 if (snprintf(path, PATH_MAX, "locales/%s/%s", wgt->locales[i], filename) >= PATH_MAX) {
254 if (0 == faccessat(wgt->rootfd, path, F_OK, 0))
257 if (0 == faccessat(wgt->rootfd, filename, F_OK, 0))
263 char *wgt_locales_locate(struct wgt *wgt, const char *filename)
270 assert(wgt_is_connected(wgt));
271 loc = localize(wgt, filename, path);
275 result = strdup(loc);
283 int wgt_locales_open_read(struct wgt *wgt, const char *filename)
289 assert(wgt_is_connected(wgt));
290 loc = localize(wgt, filename, path);
294 return openat(wgt->rootfd, loc, O_RDONLY);
298 #if defined(TEST_wgt_validsubpath)
300 void t(const char *subpath, int validity) {
301 printf("%s -> %d = %d, %s\n", subpath, validity, validsubpath(subpath), validsubpath(subpath)==validity ? "ok" : "NOT OK");
313 t("a/b/c/../../..",1);
314 t("a/b/c/../../../.",1);
315 t("./..a/././..b/..c/./.././.././../.",1);
316 t("./..a/././..b/..c/./.././.././.././..",0);
317 t("./..a//.//./..b/..c/./.././/./././///.././.././a/a/a/a/a",1);