canonify.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Jakub Jermar
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  *
00009  * - Redistributions of source code must retain the above copyright
00010  *   notice, this list of conditions and the following disclaimer.
00011  * - Redistributions in binary form must reproduce the above copyright
00012  *   notice, this list of conditions and the following disclaimer in the
00013  *   documentation and/or other materials provided with the distribution.
00014  * - The name of the author may not be used to endorse or promote products
00015  *   derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  */
00028 
00038 #include <stdlib.h>
00039 #include <vfs/canonify.h>
00040 
00042 typedef enum {
00043         TK_INVALID,
00044         TK_SLASH,
00045         TK_DOT,
00046         TK_DOTDOT,
00047         TK_COMP,
00048         TK_NUL
00049 } tokval_t;
00050 
00051 typedef struct {
00052         tokval_t kind;
00053         char *start;
00054         char *stop;
00055 } token_t;
00056 
00058 static token_t slash_token(char *start)
00059 {
00060         token_t ret;
00061         ret.kind = TK_SLASH;
00062         ret.start = start;
00063         ret.stop = start;
00064         return ret;
00065 }
00066 
00068 static token_t next_token(token_t *cur)
00069 {
00070         token_t ret;
00071 
00072         if (cur->stop[1] == '\0') {
00073                 ret.kind = TK_NUL;
00074                 ret.start = cur->stop + 1;
00075                 ret.stop = ret.start;
00076                 return ret;
00077         }
00078         if (cur->stop[1] == '/') {
00079                 ret.kind = TK_SLASH;
00080                 ret.start = cur->stop + 1;
00081                 ret.stop = ret.start;
00082                 return ret;
00083         }
00084         if (cur->stop[1] == '.' && (!cur->stop[2] || cur->stop[2] == '/')) {
00085                 ret.kind = TK_DOT;
00086                 ret.start = cur->stop + 1;
00087                 ret.stop = ret.start;
00088                 return ret;
00089         }
00090         if (cur->stop[1] == '.' && cur->stop[2] == '.' &&
00091             (!cur->stop[3] || cur->stop[3] == '/')) {
00092                 ret.kind = TK_DOTDOT;
00093                 ret.start = cur->stop + 1;
00094                 ret.stop = cur->stop + 2;
00095                 return ret;
00096         }
00097         unsigned i;
00098         for (i = 1; cur->stop[i] && cur->stop[i] != '/'; i++)
00099                 ;
00100         ret.kind = TK_COMP;
00101         ret.start = &cur->stop[1];
00102         ret.stop = &cur->stop[i - 1];
00103         return ret;
00104 }
00105 
00107 typedef enum {
00108         S_INI,
00109         S_A,
00110         S_B,
00111         S_C,
00112         S_ACCEPT,
00113         S_RESTART,
00114         S_REJECT
00115 } state_t;
00116 
00117 typedef struct {
00118         state_t s;
00119         void (* f)(token_t *, token_t *, token_t *);
00120 } change_state_t;
00121 
00122 /*
00123  * Actions that can be performed when transitioning from one
00124  * state of canonify() to another.
00125  */
00126 static void set_first_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
00127 {
00128         *tfsl = *t;
00129         *tlcomp = *t;
00130 }
00131 static void save_component(token_t *t, token_t *tfsl, token_t *tlcomp)
00132 {
00133         *tlcomp = *t;
00134 }
00135 static void terminate_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
00136 {
00137         if (tfsl->stop[1])      /* avoid writing to a well-formatted path */
00138                 tfsl->stop[1] = '\0';
00139 }
00140 static void remove_trailing_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
00141 {
00142         t->start[-1] = '\0';
00143 }
00148 static void shift_slash(token_t *t, token_t *tfsl, token_t *tlcomp)
00149 {
00150         char *p = t->start;
00151         char *q = t->stop + 1;
00152         while ((*p++ = *q++))
00153                 ;
00154 }
00159 static void shift_dot(token_t *t, token_t *tfsl, token_t *tlcomp)
00160 {
00161         char *p = t->start;
00162         char *q = t->stop + 1;
00163         while ((*p++ = *q++))
00164                 ;
00165 }
00171 static void shift_dotdot(token_t *t, token_t *tfsl, token_t *tlcomp)
00172 {
00173         char *p = tlcomp->start;
00174         char *q = t->stop + 1;
00175         while ((*p++ = *q++))
00176                 ;
00177 }
00178 
00180 static change_state_t trans[4][6] = {
00181         [S_INI] = {
00182                 [TK_SLASH] = {
00183                         .s = S_A,
00184                         .f = set_first_slash,
00185                 },
00186                 [TK_DOT] = {
00187                         .s = S_REJECT,
00188                         .f = NULL,
00189                 },
00190                 [TK_DOTDOT] = {
00191                         .s = S_REJECT,
00192                         .f = NULL,
00193                 },
00194                 [TK_COMP] = {
00195                         .s = S_REJECT,
00196                         .f = NULL,
00197                 },
00198                 [TK_NUL] = {
00199                         .s = S_REJECT,
00200                         .f = NULL,
00201                 },
00202                 [TK_INVALID] = {
00203                         .s = S_REJECT,
00204                         .f = NULL,
00205                 },
00206         },
00207         [S_A] = {
00208                 [TK_SLASH] = {
00209                         .s = S_A,
00210                         .f = set_first_slash,
00211                 },
00212                 [TK_DOT] = {
00213                         .s = S_A,
00214                         .f = NULL,
00215                 },
00216                 [TK_DOTDOT] = {
00217                         .s = S_A,
00218                         .f = NULL,
00219                 },
00220                 [TK_COMP] = {
00221                         .s = S_B,
00222                         .f = save_component,
00223                 },
00224                 [TK_NUL] = {
00225                         .s = S_ACCEPT,
00226                         .f = terminate_slash,
00227                 },
00228                 [TK_INVALID] = {
00229                         .s = S_REJECT,
00230                         .f = NULL,
00231                 },
00232         },
00233         [S_B] = {
00234                 [TK_SLASH] = {
00235                         .s = S_C,
00236                         .f = NULL,
00237                 },
00238                 [TK_DOT] = {
00239                         .s = S_REJECT,
00240                         .f = NULL,
00241                 },
00242                 [TK_DOTDOT] = {
00243                         .s = S_REJECT,
00244                         .f = NULL,
00245                 },
00246                 [TK_COMP] = {
00247                         .s = S_REJECT,
00248                         .f = NULL,
00249                 },
00250                 [TK_NUL] = {
00251                         .s = S_ACCEPT,
00252                         .f = NULL,
00253                 },
00254                 [TK_INVALID] = {
00255                         .s = S_REJECT,
00256                         .f = NULL,
00257                 },
00258         },
00259         [S_C] = {
00260                 [TK_SLASH] = {
00261                         .s = S_RESTART,
00262                         .f = shift_slash,
00263                 },
00264                 [TK_DOT] = {
00265                         .s = S_RESTART,
00266                         .f = shift_dot,
00267                 },
00268                 [TK_DOTDOT] = {
00269                         .s = S_RESTART,
00270                         .f = shift_dotdot,
00271                 },
00272                 [TK_COMP] = {
00273                         .s = S_B,
00274                         .f = save_component,
00275                 },
00276                 [TK_NUL] = {
00277                         .s = S_ACCEPT,
00278                         .f = remove_trailing_slash,
00279                 },
00280                 [TK_INVALID] = {
00281                         .s = S_REJECT,
00282                         .f = NULL,
00283                 },
00284         }
00285 };
00286 
00311 char *canonify(char *path, size_t *lenp)
00312 {
00313         state_t state;
00314         token_t t;
00315         token_t tfsl;           /* first slash */
00316         token_t tlcomp;         /* last component */
00317         if (*path != '/')
00318                 return NULL;
00319         tfsl = slash_token(path);
00320 restart:
00321         state = S_INI;
00322         t = tfsl;
00323         tlcomp = tfsl;
00324         while (state != S_ACCEPT && state != S_RESTART && state != S_REJECT) {
00325                 if (trans[state][t.kind].f)
00326                         trans[state][t.kind].f(&t, &tfsl, &tlcomp);
00327                 state = trans[state][t.kind].s;
00328                 t = next_token(&t);
00329         }
00330         
00331         switch (state) {
00332         case S_RESTART:
00333                 goto restart;
00334         case S_REJECT:
00335                 return NULL;
00336         case S_ACCEPT:
00337                 if (lenp)
00338                         *lenp = (size_t)((tlcomp.stop - tfsl.start) + 1);
00339                 return tfsl.start; 
00340         default:
00341                 abort();
00342         }
00343 }
00344 

Generated on Thu Jun 2 07:45:46 2011 for HelenOS/USB by  doxygen 1.4.7