123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- /* Copyright (C) 2014 Stony Brook University
- This file is part of Graphene Library OS.
- Graphene Library OS is free software: you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public License
- as published by the Free Software Foundation, either version 3 of the
- License, or (at your option) any later version.
- Graphene Library OS is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>. */
- /*
- * path.c
- *
- * This file contains functions to read app config (manifest) file and create a tree to
- * lookup / access config values.
- */
- #include <api.h>
- #include <pal_error.h>
- /*
- * Finds next '/' in `path`.
- * Returns a pointer to it or to the nullbyte ending the string if no '/' has been found.
- */
- static inline const char* find_next_slash(const char* path) {
- while (*path && *path != '/') {
- path++;
- }
- return path;
- }
- /*
- * Finds previous '/' in `path` (starting from `offset` - 1).
- * If the last character is '/', then it is skipped (as a token can end with '/').
- *
- * Returns whether '/' was found.
- * Updates `*offset` to the index of the found '/' (or 0 if none was found).
- */
- static inline bool find_prev_slash_offset(const char* path, size_t* offset) {
- size_t off = *offset;
- if (!off) {
- return false;
- }
- off--; // get offset to last character
- /* Skip trailing '/' if there is one */
- if (off && path[off] == '/') {
- off--;
- }
- while (off && path[off] != '/') {
- off--;
- }
- *offset = off;
- return path[off] == '/';
- }
- /*
- * Before calling this function *size_ptr should hold the size of buf.
- * After returning it holds number of bytes actually written to it (excluding the ending '\0').
- */
- int get_norm_path(const char* path, char* buf, size_t* size_ptr) {
- if (!path || !buf || !size_ptr) {
- return -PAL_ERROR_INVAL;
- }
- size_t size = *size_ptr;
- if (!size) {
- return -PAL_ERROR_INVAL;
- }
- /* reserve 1 byte for ending '\0' */
- size--;
- size_t offset = 0, ret_size = 0; /* accounts for undiscardable bytes written to `buf`
- * i.e. `buf - ret_size` points to original `buf` */
- bool need_slash = false; // is '/' needed before next token
- bool is_absolute_path = *path == '/';
- /* handle an absolute path */
- if (is_absolute_path) {
- if (size < 1) {
- return -PAL_ERROR_TOOLONG;
- }
- *buf++ = '/';
- size--;
- ret_size++;
- path++;
- }
- while (1) {
- /* handle next token */
- const char* end = find_next_slash(path);
- if (end - path == 2 && path[0] == '.' && path[1] == '.') {
- /* ".." */
- if (offset) {
- /* eat up previously written token */
- need_slash = find_prev_slash_offset(buf, &offset);
- } else if (!is_absolute_path) {
- /* append undiscardable ".." since there is no previous token
- * but only if the path is not absolute */
- if (need_slash + 2u > size) {
- return -PAL_ERROR_TOOLONG;
- }
- if (need_slash) {
- *buf++ = '/';
- }
- *buf++ = '.';
- *buf++ = '.';
- size -= need_slash + 2u;
- ret_size += need_slash + 2u;
- need_slash = true;
- } else {
- /* remaining case: offset == 0, path is absolute and ".." was just seen,
- * i.e. "/..", which is collapsed to "/", hence nothing needs to be done
- */
- }
- } else if ((end == path) || (end - path == 1 && path[0] == '.')) {
- /* ignore "//" and "." */
- } else {
- size_t len = (size_t)(end - path);
- if (need_slash + len > size - offset) {
- return -PAL_ERROR_TOOLONG;
- }
- if (need_slash) {
- buf[offset++] = '/';
- }
- memcpy(buf + offset, path, len);
- offset += len;
- need_slash = true;
- }
- if (!*end) {
- break;
- }
- path = end + 1;
- }
- buf[offset] = '\0';
- *size_ptr = ret_size + offset;
- return 0;
- }
- /*
- * Returns the part after the last '/' (so `path` should probably be normalized).
- * Before calling this function *size should hold the size of buf.
- * After returning it holds number of bytes actually written to it (excluding the trailing '\0').
- */
- int get_base_name(const char* path, char* buf, size_t* size) {
- if (!path || !buf || !size) {
- return -PAL_ERROR_INVAL;
- }
- const char* end;
- while (*(end = find_next_slash(path))) {
- path = end + 1;
- }
- size_t result = (size_t)(end - path);
- if (result + 1 > *size) {
- return -PAL_ERROR_TOOLONG;
- }
- memcpy(buf, path, result);
- buf[result] = '\0';
- *size = result;
- return 0;
- }
|