Fix up sys*stat
[akaros.git] / kern / src / ns / cleanname.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 /*
17  * In place, rewrite name to compress multiple /, eliminate ., and process ..
18  */
19 #define SEP(x)  ((x)=='/' || (x) == 0)
20 char *cleanname(char *name)
21 {
22         char *p, *q, *dotdot;
23         int rooted, erasedprefix;
24
25         rooted = name[0] == '/';
26         erasedprefix = 0;
27
28         /*
29          * invariants:
30          *  p points at beginning of path element we're considering.
31          *  q points just past the last path element we wrote (no slash).
32          *  dotdot points just past the point where .. cannot backtrack
33          *      any further (no slash).
34          */
35         p = q = dotdot = name + rooted;
36         while (*p) {
37                 if (p[0] == '/')        /* null element */
38                         p++;
39                 else if (p[0] == '.' && SEP(p[1])) {
40                         if (p == name)
41                                 erasedprefix = 1;
42                         p += 1; /* don't count the separator in case it is nul */
43                 } else if (p[0] == '.' && p[1] == '.' && SEP(p[2])) {
44                         p += 2;
45                         if (q > dotdot) {       /* can backtrack */
46                                 while (--q > dotdot && *q != '/') ;
47                         } else if (!rooted) {   /* /.. is / but ./../ is .. */
48                                 if (q != name)
49                                         *q++ = '/';
50                                 *q++ = '.';
51                                 *q++ = '.';
52                                 dotdot = q;
53                         }
54                         if (q == name)
55                                 erasedprefix = 1;       /* erased entire path via dotdot */
56                 } else {        /* real path element */
57                         if (q != name + rooted)
58                                 *q++ = '/';
59                         while ((*q = *p) != '/' && *q != 0)
60                                 p++, q++;
61                 }
62         }
63         if (q == name)  /* empty string is really ``.'' */
64                 *q++ = '.';
65         *q = '\0';
66         if (erasedprefix && name[0] == '#') {
67                 /* this was not a #x device path originally - make it not one now */
68                 memmove(name + 2, name, strlen(name) + 1);
69                 name[0] = '.';
70                 name[1] = '/';
71         }
72         return name;
73 }