do the output buffering ourselves; this improves performance a lot
[cwebfiles.git] / listdir.c
index 9f1afda..6d58431 100644 (file)
--- a/listdir.c
+++ b/listdir.c
 #include <errno.h>
 #include <sys/stat.h>
 #include <fmt.h>
+#include <sys/prctl.h>
+
+// 64k RAM aren't really that much, and it should speed things up significantly
+#define OBULEN (64*1024)
+static char outbuf[OBULEN] = "Status: 200 here's your listing"
+                            "\nX-Frame-Options: DENY"
+                            "\nContent-Type: text/plain;charset=utf8"
+                            "\n\n";
 
 int main() {
-  FASTOUTPUT
+  //FASTOUTPUT
+  prctl(PR_SET_DUMPABLE, 1); // FIXME XXX potential security problem; disable later!
+  if (chdir("/")) senderr("chdir / failed", MYFAULT);
   
   char *encpath = getenv("QUERY_STRING");
   login_and_setup(); // will clear the environment
@@ -40,29 +50,35 @@ int main() {
     senderr(errstr, NOTMYFAULT);
   }
   
+  // ok, let's do fast output!
   // The directory was opened successfully - send our success header.
-  puts("Status: 200 here's your listing");
-  puts("X-Frame-Options: DENY");
-  puts("Content-Type: text/plain;charset=utf8");
-  puts("");
+  char *p = outbuf+strlen(outbuf);
   
   // send one line per file
+  #define LINE_LENGTH_LIMIT (NAME_MAX*2+1+FMT_ULONG+1+FMT_ULONG+1)
   struct dirent *dent;
-  char linedata[NAME_MAX*2+1+FMT_ULONG+1+FMT_ULONG+1];
   while ((dent = readdir(dir)) != NULL) {
+    if (p+LINE_LENGTH_LIMIT >= outbuf+OBULEN) {
+      // Whoah, that's a big directory!
+      // Flush the pipe.
+      write(1, outbuf, p-outbuf);
+      // And reuse the buffer.
+      p = outbuf;
+    }
     struct stat st;
     // if we can't really see the file anyway, skip it
     if (lstat(dent->d_name, &st)) continue;
     //printf("%s %lu %u\n", encfilename, (unsigned long)st.st_size, (unsigned int)st.st_mode);
     size_t name_len = strlen(dent->d_name);
-    hex(linedata, (unsigned char *)dent->d_name, name_len);
-    char *p = linedata+name_len*2;
+    hex(p, (unsigned char *)dent->d_name, name_len);
+    p += name_len*2;
     *(p++) = ' ';
     p += fmt_ulong(p, (unsigned long)st.st_size);
     *(p++) = ' ';
     p += fmt_ulong(p, (unsigned int)st.st_mode);
     *(p++) = '\n';
-    *p = 0;
-    fputs(linedata, stdout);
   }
+  
+  // final pipe flush
+  write(1, outbuf, p-outbuf);
 }