cleanname from inferno
authorRonald G. Minnich <rminnich@google.com>
Fri, 17 Jan 2014 19:44:33 +0000 (11:44 -0800)
committerRonald G. Minnich <rminnich@google.com>
Fri, 17 Jan 2014 19:44:33 +0000 (11:44 -0800)
Signed-off-by: Ronald G. Minnich <rminnich@google.com>
kern/src/ns/Kbuild
kern/src/ns/cleanname.c [new file with mode: 0644]

index 7fbf190..7616cc5 100644 (file)
@@ -1,6 +1,7 @@
 obj-y                                          += allocb.o
 obj-y                                          += cache.o
 obj-y                                          += chan.o
+obj-y                                          += cleanname.o
 obj-y                                          += convD2M.o
 obj-y                                          += convM2D.o
 obj-y                                          += convM2S.o
diff --git a/kern/src/ns/cleanname.c b/kern/src/ns/cleanname.c
new file mode 100644 (file)
index 0000000..c34bca1
--- /dev/null
@@ -0,0 +1,75 @@
+// INFERNO
+#include <vfs.h>
+#include <kfs.h>
+#include <slab.h>
+#include <kmalloc.h>
+#include <kref.h>
+#include <string.h>
+#include <stdio.h>
+#include <assert.h>
+#include <error.h>
+#include <cpio.h>
+#include <pmap.h>
+#include <smp.h>
+#include <ip.h>
+
+/*
+ * In place, rewrite name to compress multiple /, eliminate ., and process ..
+ */
+#define SEP(x) ((x)=='/' || (x) == 0)
+char*
+cleanname(char *name)
+{
+       char *p, *q, *dotdot;
+       int rooted, erasedprefix;
+
+       rooted = name[0] == '/';
+       erasedprefix = 0;
+
+       /*
+        * invariants:
+        *      p points at beginning of path element we're considering.
+        *      q points just past the last path element we wrote (no slash).
+        *      dotdot points just past the point where .. cannot backtrack
+        *              any further (no slash).
+        */
+       p = q = dotdot = name+rooted;
+       while(*p) {
+               if(p[0] == '/') /* null element */
+                       p++;
+               else if(p[0] == '.' && SEP(p[1])) {
+                       if(p == name)
+                               erasedprefix = 1;
+                       p += 1; /* don't count the separator in case it is nul */
+               } else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
+                       p += 2;
+                       if(q > dotdot) {        /* can backtrack */
+                               while(--q > dotdot && *q != '/')
+                                       ;
+                       } else if(!rooted) {    /* /.. is / but ./../ is .. */
+                               if(q != name)
+                                       *q++ = '/';
+                               *q++ = '.';
+                               *q++ = '.';
+                               dotdot = q;
+                       }
+                       if(q == name)
+                               erasedprefix = 1;       /* erased entire path via dotdot */
+               } else {        /* real path element */
+                       if(q != name+rooted)
+                               *q++ = '/';
+                       while((*q = *p) != '/' && *q != 0)
+                               p++, q++;
+               }
+       }
+       if(q == name)   /* empty string is really ``.'' */
+               *q++ = '.';
+       *q = '\0';
+       if(erasedprefix && name[0] == '#'){     
+               /* this was not a #x device path originally - make it not one now */
+               memmove(name+2, name, strlen(name)+1);
+               name[0] = '.';
+               name[1] = '/';
+       }
+       return name;
+}