00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
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
00124
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])
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;
00316 token_t tlcomp;
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