X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fwgt.c;h=c2a31f2269241ac72a239054d781fe85f51730dd;hb=7553044c59814c33763bb4b1c34664dceed68735;hp=db590914290436c1d002aa6af73f988c08a0ce2f;hpb=f3d64b7c741677cd28e2a11deed67196cd02b46a;p=src%2Fapp-framework-main.git diff --git a/src/wgt.c b/src/wgt.c index db59091..c2a31f2 100644 --- a/src/wgt.c +++ b/src/wgt.c @@ -1,5 +1,7 @@ /* - Copyright 2015 IoT.bzh + Copyright (C) 2015-2019 IoT.bzh + + author: José Bollo Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -32,15 +34,20 @@ struct wgt { int refcount; int rootfd; - int nrlocales; + unsigned int nrlocales; char **locales; }; +/* a valid subpath is a relative path not looking deeper than root using .. */ static int validsubpath(const char *subpath) { int l = 0, i = 0; + + /* absolute path is not valid */ if (subpath[i] == '/') return 0; + + /* inspect the path */ while(subpath[i]) { switch(subpath[i++]) { case '.': @@ -63,7 +70,8 @@ static int validsubpath(const char *subpath) default: while(subpath[i] && subpath[i] != '/') i++; - l++; + if (l >= 0) + l++; case '/': break; } @@ -71,6 +79,25 @@ static int validsubpath(const char *subpath) return l >= 0; } +/* + * Normalizes and checks the 'subpath'. + * Removes any starting '/' and checks that 'subpath' + * does not contains sequence of '..' going deeper than + * root. + * Returns the normalized subpath or NULL in case of + * invalid subpath. + */ +static const char *normalsubpath(const char *subpath) +{ + while(*subpath == '/') + subpath++; + return validsubpath(subpath) ? subpath : NULL; +} + +/* + * Creates a wgt handler and returns it or return NULL + * in case of memory depletion. + */ struct wgt *wgt_create() { struct wgt *wgt = malloc(sizeof * wgt); @@ -85,27 +112,19 @@ struct wgt *wgt_create() return wgt; } -void wgt_disconnect(struct wgt *wgt) -{ - assert(wgt); - if (wgt->rootfd >= 0) - close(wgt->rootfd); - wgt->rootfd = -1; -} - -void wgt_locales_reset(struct wgt *wgt) -{ - assert(wgt); - while(wgt->nrlocales) - free(wgt->locales[--wgt->nrlocales]); -} - +/* + * Adds a reference to 'wgt' + */ void wgt_addref(struct wgt *wgt) { assert(wgt); wgt->refcount++; } +/* + * Drops a reference to 'wgt' and destroys it + * if not more referenced + */ void wgt_unref(struct wgt *wgt) { assert(wgt); @@ -117,72 +136,151 @@ void wgt_unref(struct wgt *wgt) } } +/* + * Creates a wgt handle and connect it to 'dirfd' and 'pathname'. + * + * Returns the created and connected wgt handle on success + * or returns NULL if allocation failed or connecting had + * error. + */ +struct wgt *wgt_createat(int dirfd, const char *pathname) +{ + struct wgt *wgt = wgt_create(); + if (wgt) { + if (wgt_connectat(wgt, dirfd, pathname)) { + wgt_unref(wgt); + wgt = NULL; + } + } + return wgt; +} + +/* + * Connect 'wgt' to the directory of 'pathname' relative + * to the directory handled by 'dirfd'. + * + * Use AT_FDCWD for connecting relatively to the current directory. + * + * Use 'pathname' == NULL or "" for connecting to 'dirfd'. In + * that case, 'dirfd' is duplicated and can safely be used later + * by the client. + * + * If 'wgt' is already connected, it will be diconnected before. + * + * The languages settings are not changed. + * + * Returns 0 in case of success or -1 in case or error. + */ int wgt_connectat(struct wgt *wgt, int dirfd, const char *pathname) { int rfd; assert(wgt); - rfd = dirfd; - if (pathname) { - rfd = openat(rfd, pathname, O_PATH|O_DIRECTORY); - if (rfd < 0) - return rfd; - } + rfd = (pathname && *pathname) ? openat(dirfd, pathname, O_PATH|O_DIRECTORY) : dup(dirfd); + if (rfd < 0) + return rfd; + if (wgt->rootfd >= 0) close(wgt->rootfd); wgt->rootfd = rfd; return 0; } +/* + * Connect 'wgt' to the directory of 'pathname'. + * + * Acts like wgt_connectat(wgt, AT_FDCWD, pathname) + */ int wgt_connect(struct wgt *wgt, const char *pathname) { return wgt_connectat(wgt, AT_FDCWD, pathname); } +/* + * Disconnetcs 'wgt' if connected. + */ +void wgt_disconnect(struct wgt *wgt) +{ + assert(wgt); + if (wgt->rootfd >= 0) + close(wgt->rootfd); + wgt->rootfd = -1; +} + +/* + * Checks if 'wgt' is connected and returns 1 if connected + * or 0 if not connected. + */ int wgt_is_connected(struct wgt *wgt) { assert(wgt); return wgt->rootfd != -1; } +/* + * Tests wether the connected 'wgt' has the 'filename'. + * + * It is an error (with errno = EINVAL) to test an + * invalid filename. + * + * Returns 0 if it hasn't it, 1 if it has it or + * -1 if an error occured. + */ int wgt_has(struct wgt *wgt, const char *filename) { assert(wgt); assert(wgt_is_connected(wgt)); - if (!validsubpath(filename)) { + + filename = normalsubpath(filename); + if (!filename) { errno = EINVAL; return -1; } return 0 == faccessat(wgt->rootfd, filename, F_OK, 0); } +/* + * Opens 'filename' for read from the connected 'wgt'. + * + * Returns the file descriptor as returned by openat + * system call or -1 in case of error. + */ int wgt_open_read(struct wgt *wgt, const char *filename) { assert(wgt); assert(wgt_is_connected(wgt)); - if (!validsubpath(filename)) { + filename = normalsubpath(filename); + if (!filename) { errno = EINVAL; return -1; } return openat(wgt->rootfd, filename, O_RDONLY); } -static int locadd(struct wgt *wgt, const char *locstr, int length) +/* + * Adds if needed the locale 'locstr' of 'length' + * to the list of locales. + */ +static int locadd(struct wgt *wgt, const char *locstr, size_t length) { - int i; + unsigned int i; char *item, **ptr; item = strndup(locstr, length); if (item != NULL) { + /* normalize in lower case */ for (i = 0 ; item[i] ; i++) - item[i] = tolower(item[i]); + item[i] = (char)tolower(item[i]); + + /* search it (no duplication) */ for (i = 0 ; i < wgt->nrlocales ; i++) if (!strcmp(item, wgt->locales[i])) { free(item); return 0; } + /* append it to the list */ ptr = realloc(wgt->locales, (1 + wgt->nrlocales) * sizeof(wgt->locales[0])); if (ptr) { wgt->locales = ptr; @@ -195,15 +293,37 @@ static int locadd(struct wgt *wgt, const char *locstr, int length) return -1; } +/* + * clears the list of locales of 'wgt' + */ +void wgt_locales_reset(struct wgt *wgt) +{ + assert(wgt); + while(wgt->nrlocales) + free(wgt->locales[--wgt->nrlocales]); +} + +/* + * Adds to 'wgt' the locales defined by 'locstr'. + * + * Example: passing "fr-CH,en-GB" will add "fr-CH", + * "fr", "en-GB" and then "en" to the list of locales. + * + * Returns 0 in case of success or -1 in case of memory + * depletion. + */ int wgt_locales_add(struct wgt *wgt, const char *locstr) { const char *stop, *next; assert(wgt); + + /* iterate the comma separated languages */ while (*locstr) { stop = strchrnul(locstr, ','); next = stop + !!*stop; + /* iterate variant of languages in reverse order */ while (locstr != stop) { - if (locadd(wgt, locstr, stop - locstr)) + if (locadd(wgt, locstr, (size_t)(stop - locstr))) return -1; do { stop--; } while(stop > locstr && *stop != '-'); } @@ -212,9 +332,15 @@ int wgt_locales_add(struct wgt *wgt, const char *locstr) return 0; } -int wgt_locales_score(struct wgt *wgt, const char *lang) +/* + * Get the score of the language 'lang' for 'wgt'. + * + * The lower result means the higher priority of the language. + * The returned value of 0 is the top first priority. + */ +unsigned int wgt_locales_score(struct wgt *wgt, const char *lang) { - int i; + unsigned int i; assert(wgt); if (lang) @@ -222,17 +348,29 @@ int wgt_locales_score(struct wgt *wgt, const char *lang) if (!strcasecmp(lang, wgt->locales[i])) return i; - return INT_MAX; + return UINT_MAX; } +/* + * Applies the localisation algorithm of 'filename' + * within 'wgt'. Use the scratch buffer given by 'path'. + * + * Returns the filepath of the located file or NULL + * if not found. If not NULL, the returned value is either + * 'path' or the normalized version of 'filename'. + */ static const char *localize(struct wgt *wgt, const char *filename, char path[PATH_MAX]) { - int i; + unsigned int i; - if (!validsubpath(filename)) { + /* get the normalized name */ + filename = normalsubpath(filename); + if (!filename) { errno = EINVAL; return NULL; } + + /* search in locales */ for (i = 0 ; i < wgt->nrlocales ; i++) { if (snprintf(path, PATH_MAX, "locales/%s/%s", wgt->locales[i], filename) >= PATH_MAX) { errno = EINVAL; @@ -247,6 +385,13 @@ static const char *localize(struct wgt *wgt, const char *filename, char path[PAT return NULL; } +/* + * Gets the localized file of 'filename' within 'wgt'. + * + * Returns a fresh allocated string for the found 'filename'. + * Returns NULL if file is not found (ENOENT) or memory + * exhausted (ENOMEM). + */ char *wgt_locales_locate(struct wgt *wgt, const char *filename) { char path[PATH_MAX]; @@ -255,6 +400,7 @@ char *wgt_locales_locate(struct wgt *wgt, const char *filename) assert(wgt); assert(wgt_is_connected(wgt)); + loc = localize(wgt, filename, path); if (!loc) result = NULL; @@ -266,7 +412,13 @@ char *wgt_locales_locate(struct wgt *wgt, const char *filename) return result; } - +/* + * Opens for read the localized version of 'filename' + * from the connected 'wgt'. + * + * Returns the file descriptor as returned by openat + * system call or -1 in case of error. + */ int wgt_locales_open_read(struct wgt *wgt, const char *filename) { char path[PATH_MAX]; @@ -274,6 +426,7 @@ int wgt_locales_open_read(struct wgt *wgt, const char *filename) assert(wgt); assert(wgt_is_connected(wgt)); + loc = localize(wgt, filename, path); if (!loc) return -1; @@ -282,3 +435,27 @@ int wgt_locales_open_read(struct wgt *wgt, const char *filename) } +#if defined(TEST_wgt_validsubpath) +#include +void t(const char *subpath, int validity) { + printf("%s -> %d = %d, %s\n", subpath, validity, validsubpath(subpath), validsubpath(subpath)==validity ? "ok" : "NOT OK"); +} +int main() { + t("/",0); + t("..",0); + t(".",1); + t("../a",0); + t("a/..",1); + t("a/../////..",0); + t("a/../b/..",1); + t("a/b/c/..",1); + t("a/b/c/../..",1); + t("a/b/c/../../..",1); + t("a/b/c/../../../.",1); + t("./..a/././..b/..c/./.././.././../.",1); + t("./..a/././..b/..c/./.././.././.././..",0); + t("./..a//.//./..b/..c/./.././/./././///.././.././a/a/a/a/a",1); + return 0; +} +#endif +