Changeset 9bb85f3 in mainline


Ignore:
Timestamp:
2008-03-01T17:02:17Z (16 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d6084ef
Parents:
1e50f81
Message:

Add canonify() for file system path canonization.
Not yet used by VFS.

Location:
uspace
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/libfs/libfs.c

    r1e50f81 r9bb85f3  
    124124
    125125/** Lookup VFS triplet by name in the file system name space.
     126 *
     127 * The path passed in the PLB must be in the canonical file system path format
     128 * as returned by the canonify() function.
    126129 *
    127130 * @param ops           libfs operations structure with function pointers to
  • uspace/srv/vfs/vfs_lookup.c

    r1e50f81 r9bb85f3  
    4040#include <errno.h>
    4141#include <string.h>
     42#include <stdlib.h>
    4243#include <bool.h>
    4344#include <futex.h>
     
    4748
    4849#define min(a, b)       ((a) < (b) ? (a) : (b))
     50
     51/* Forward static declarations. */
     52static char *canonify(char *path);
    4953
    5054atomic_t plb_futex = FUTEX_INITIALIZER;
     
    175179}
    176180
     181/** Token types used for tokenization of path. */
     182typedef enum {
     183        TK_INVALID,
     184        TK_SLASH,
     185        TK_DOT,
     186        TK_DOTDOT,
     187        TK_COMP,
     188        TK_NUL
     189} tokval_t;
     190
     191typedef struct {
     192        tokval_t kind;
     193        char *start;
     194        char *stop;
     195} token_t;
     196
     197/** Fake up the TK_SLASH token. */
     198static token_t slash_token(char *start)
     199{
     200        token_t ret;
     201        ret.kind = TK_SLASH;
     202        ret.start = start;
     203        ret.stop = start;
     204        return ret;
     205}
     206
     207/** Given a token, return the next token. */
     208static token_t next_token(token_t *cur)
     209{
     210        token_t ret;
     211
     212        if (cur->stop[1] == '\0') {
     213                ret.kind = TK_NUL;
     214                ret.start = cur->stop + 1;
     215                ret.stop = ret.start;
     216                return ret;
     217        }
     218        if (cur->stop[1] == '/') {
     219                ret.kind = TK_SLASH;
     220                ret.start = cur->stop + 1;
     221                ret.stop = ret.start;
     222                return ret;
     223        }
     224        if (cur->stop[1] == '.' && (!cur->stop[2] || cur->stop[2] == '/')) {
     225                ret.kind = TK_DOT;
     226                ret.start = cur->stop + 1;
     227                ret.stop = ret.start;
     228                return ret;
     229        }
     230        if (cur->stop[1] == '.' && cur->stop[2] == '.' &&
     231            (!cur->stop[3] || cur->stop[3] == '/')) {
     232                ret.kind = TK_DOTDOT;
     233                ret.start = cur->stop + 1;
     234                ret.stop = cur->stop + 2;
     235                return ret;
     236        }
     237        unsigned i;
     238        for (i = 1; cur->stop[i] && cur->stop[i] != '/'; i++)
     239                ;
     240        ret.kind = TK_COMP;
     241        ret.start = &cur->stop[1];
     242        ret.stop = &cur->stop[i - 1];
     243        return ret;
     244}
     245
     246/** States used by canonify(). */
     247typedef enum {
     248        S_INI,
     249        S_A,
     250        S_B,
     251        S_C,
     252        S_ACCEPT,
     253        S_RESTART,
     254        S_REJECT
     255} state_t;
     256
     257typedef struct {
     258        state_t s;
     259        void (* f)(token_t *, token_t *, token_t *);
     260} change_state_t;
     261
     262/*
     263 * Actions that can be performed when transitioning from one
     264 * state of canonify() to another.
     265 */
     266static void set_first_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
     267{
     268        *tfsl = *t;
     269}
     270static void save_component(token_t *t, token_t *tfsl, token_t *tlcomp)
     271{
     272        *tlcomp = *t;
     273}
     274static void terminate_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
     275{
     276        tfsl->stop[1] = '\0';
     277}
     278static void remove_trailing_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
     279{
     280        t->start[-1] = '\0';
     281}
     282/** Eat the extra '/'..
     283 *
     284 * @param t             The current TK_SLASH token.
     285 */
     286static void shift_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
     287{
     288        char *p = t->start;
     289        char *q = t->stop + 1;
     290        while ((*p++ = *q++))
     291                ;
     292}
     293/** Eat the extra '.'.
     294 *
     295 * @param t             The current TK_DOT token.
     296 */
     297static void shift_dot(token_t *t, token_t *tfsl, token_t *tlcomp)
     298{
     299        char *p = t->start;
     300        char *q = t->stop + 1;
     301        while ((*p++ = *q++))
     302                ;
     303}
     304/** Collapse the TK_COMP TK_SLASH TK_DOTDOT pattern.
     305 *
     306 * @param t             The current TK_DOTDOT token.
     307 * @param tlcomp        The last TK_COMP token.
     308 */
     309static void shift_dotdot(token_t *t, token_t *tfsl, token_t *tlcomp)
     310{
     311        char *p = tlcomp->start;
     312        char *q = t->stop + 1;
     313        while ((*p++ = *q++))
     314                ;
     315}
     316
     317/** Transition function for canonify(). */
     318static change_state_t trans[4][6] = {
     319        [S_INI] = {
     320                [TK_SLASH] = {
     321                        .s = S_A,
     322                        .f = set_first_slash,
     323                },
     324                [TK_DOT] = {
     325                        .s = S_REJECT,
     326                        .f = NULL,
     327                },
     328                [TK_DOTDOT] = {
     329                        .s = S_REJECT,
     330                        .f = NULL,
     331                },
     332                [TK_COMP] = {
     333                        .s = S_REJECT,
     334                        .f = NULL,
     335                },
     336                [TK_NUL] = {
     337                        .s = S_REJECT,
     338                        .f = NULL,
     339                },
     340                [TK_INVALID] = {
     341                        .s = S_REJECT,
     342                        .f = NULL,
     343                },
     344        },
     345        [S_A] = {
     346                [TK_SLASH] = {
     347                        .s = S_A,
     348                        .f = set_first_slash,
     349                },
     350                [TK_DOT] = {
     351                        .s = S_A,
     352                        .f = NULL,
     353                },
     354                [TK_DOTDOT] = {
     355                        .s = S_A,
     356                        .f = NULL,
     357                },
     358                [TK_COMP] = {
     359                        .s = S_B,
     360                        .f = save_component,
     361                },
     362                [TK_NUL] = {
     363                        .s = S_ACCEPT,
     364                        .f = terminate_slash,
     365                },
     366                [TK_INVALID] = {
     367                        .s = S_REJECT,
     368                        .f = NULL,
     369                },
     370        },
     371        [S_B] = {
     372                [TK_SLASH] = {
     373                        .s = S_C,
     374                        .f = NULL,
     375                },
     376                [TK_DOT] = {
     377                        .s = S_REJECT,
     378                        .f = NULL,
     379                },
     380                [TK_DOTDOT] = {
     381                        .s = S_REJECT,
     382                        .f = NULL,
     383                },
     384                [TK_COMP] = {
     385                        .s = S_REJECT,
     386                        .f = NULL,
     387                },
     388                [TK_NUL] = {
     389                        .s = S_ACCEPT,
     390                        .f = NULL,
     391                },
     392                [TK_INVALID] = {
     393                        .s = S_REJECT,
     394                        .f = NULL,
     395                },
     396        },
     397        [S_C] = {
     398                [TK_SLASH] = {
     399                        .s = S_RESTART,
     400                        .f = shift_slash,
     401                },
     402                [TK_DOT] = {
     403                        .s = S_RESTART,
     404                        .f = shift_dot,
     405                },
     406                [TK_DOTDOT] = {
     407                        .s = S_RESTART,
     408                        .f = shift_dotdot,
     409                },
     410                [TK_COMP] = {
     411                        .s = S_B,
     412                        .f = save_component,
     413                },
     414                [TK_NUL] = {
     415                        .s = S_ACCEPT,
     416                        .f = remove_trailing_slash,
     417                },
     418                [TK_INVALID] = {
     419                        .s = S_REJECT,
     420                        .f = NULL,
     421                },
     422        }
     423};
     424
     425/** Canonify a file system path.
     426 *
     427 * A file system path is canonical, if the following holds:
     428 * 1) the path is absolute (i.e. a/b/c is not canonical)
     429 * 2) there is no trailing slash in the path (i.e. /a/b/c is not canonical)
     430 * 3) there is no extra slash in the path (i.e. /a//b/c is not canonical)
     431 * 4) there is no '.' component in the path (i.e. /a/./b/c is not canonical)
     432 * 5) there is no '..' component in the path (i.e. /a/b/../c is not canonical)
     433 *
     434 * This function makes a potentially non-canonical file system path canonical.
     435 * It works in-place and requires a NULL-terminated input string.
     436 *
     437 * @param               Path to be canonified.
     438 *
     439 * @return              Canonified path or NULL on failure.
     440 */
     441char *canonify(char *path)
     442{
     443        state_t state;
     444        token_t t;
     445        token_t tfsl;           /* first slash */
     446        token_t tlcomp;         /* last component */
     447        if (*path != '/')
     448                return NULL;
     449        tfsl = slash_token(path);
     450restart:
     451        state = S_INI;
     452        t = tfsl;
     453        while (state != S_ACCEPT && state != S_RESTART && state != S_REJECT) {
     454                if (trans[state][t.kind].f)
     455                        trans[state][t.kind].f(&t, &tfsl, &tlcomp);
     456                state = trans[state][t.kind].s;
     457                t = next_token(&t);
     458        }
     459       
     460        switch (state) {
     461        case S_RESTART:
     462                goto restart;
     463        case S_REJECT:
     464                return NULL;
     465        case S_ACCEPT:
     466                return tfsl.start;
     467        default:
     468                abort();
     469        }
     470}
     471
    177472/**
    178473 * @}
    179  */ 
     474 */
Note: See TracChangeset for help on using the changeset viewer.