static void ls_child()

in netutils/thttpd/libhttpd.c [1587:1847]


static void ls_child(int argc, char **argv)
{
  FAR httpd_conn *hc = (FAR httpd_conn *)strtoul(argv[1], NULL, 16);
  DIR *dirp;
  struct dirent *de;
  int namlen;
  static int maxnames = 0;
  int oldmax;
  int nnames;
  static char *names;
  static char **nameptrs;
  static char *name;
  static size_t maxname = 0;
  static char *rname;
  static size_t maxrname = 0;
  static char *encrname;
  static size_t maxencrname = 0;
  FILE *fp;
  struct stat sb;
  char modestr[20];
  char *linkprefix;
#if 0
  char link[PATH_MAX + 1];
#else
  char link[1];
#endif
  char *fileclass;
  time_t now;
  char *timestr;
  int i;

  httpd_unlisten(hc->hs);
  send_mime(hc, 200, ok200title, "", "", "text/html; charset=%s",
            (off_t) - 1, hc->sb.st_mtime);
  httpd_write_response(hc);

  /* Open a stdio stream so that we can use fprintf, which is more
   * efficient than a bunch of separate write()s.  We don't have to
   * worry about double closes or file descriptor leaks cause we're
   * in a sub-task.
   */

  fp = fdopen(hc->conn_fd, "w");
  if (fp == NULL)
    {
      nerr("ERROR: fdopen: %d\n", errno);
      INTERNALERROR("fdopen");
      httpd_send_err(hc, 500, err500title, "", err500form, hc->encodedurl);
      httpd_write_response(hc);
      closedir(dirp);
      exit(1);
    }

  fputs(html_html, fp);
  fputs(html_hdtitle, fp);
  fprintf(fp, "Index of %s", hc->encodedurl, hc->encodedurl);
  fputs(html_titlehd, fp);
  fputs(html_body, fp);
  fputs(html_hdr2, fp);
  fprintf(fp, "Index of %s", hc->encodedurl, hc->encodedurl);
  fputs(html_endhdr2, fp);
  fputs(html_crlf, fp);
  fputs("<PRE>\r\nmode  links  bytes  last-changed  name\r\n<HR>", fp);

  /* Read in names. */

  nnames = 0;
  while ((de = readdir(dirp)) != 0)     /* dirent or direct */
    {
      if (nnames >= maxnames)
        {
          if (maxnames == 0)
            {
              maxnames = 100;
              names    = NEW(char, maxnames * PATH_MAX);
              nameptrs = NEW(char *, maxnames);
            }
          else
            {
              oldmax    = maxnames;
              maxnames *= 2;
              names     = RENEW(names, char, oldmax * PATH_MAX,
                                maxnames * PATH_MAX);
              nameptrs  = RENEW(nameptrs, char *, oldmax, maxnames);
            }

          if (!names || !nameptrs)
            {
              nerr("ERROR: out of memory reallocating directory names\n");
              exit(1);
            }

          for (i = 0; i < maxnames; ++i)
            {
              nameptrs[i] = &names[i * PATH_MAX];
            }
        }

      strlcpy(nameptrs[nnames], de->d_name, PATH_MAX);
      ++nnames;
    }

  closedir(dirp);

  /* Sort the names. */

  qsort(nameptrs, nnames, sizeof(*nameptrs), name_compare);

  /* Generate output. */

  for (i = 0; i < nnames; ++i)
    {
      httpd_realloc_str(&name, &maxname,
                        strlen(hc->expnfilename) + 1 +
                        strlen(nameptrs[i]));
      httpd_realloc_str(&rname, &maxrname,
                        strlen(hc->origfilename) + 1 +
                        strlen(nameptrs[i]));

      if (hc->expnfilename[0] == '\0' || strcmp(hc->expnfilename, ".") == 0)
        {
          strlcpy(name, nameptrs[i], maxname + 1);
          strlcpy(rname, nameptrs[i], maxrname + 1);
        }
      else
        {
          snprintf(name, maxname, "%s/%s", hc->expnfilename, nameptrs[i]);
          if (strcmp(hc->origfilename, ".") == 0)
            {
              snprintf(rname, maxrname, "%s", nameptrs[i]);
            }
          else
            {
              snprintf(rname, maxrname, "%s%s",
                       hc->origfilename, nameptrs[i]);
            }
        }

      httpd_realloc_str(&encrname, &maxencrname, 3 * strlen(rname) + 1);
      httpd_strencode(encrname, maxencrname, rname);

      if (stat(name, &sb) < 0)
        {
          continue;
        }

      linkprefix = "";
      link[0] = '\0';

      /* Break down mode word.  First the file type. */

      switch (sb.st_mode & S_IFMT)
        {
        case S_IFIFO:
          modestr[0] = 'p';
          break;

        case S_IFCHR:
          modestr[0] = 'c';
          break;

        case S_IFDIR:
          modestr[0] = 'd';
          break;

        case S_IFBLK:
          modestr[0] = 'b';
          break;

        case S_IFREG:
          modestr[0] = '-';
          break;

        case S_IFSOCK:
          modestr[0] = 's';
          break;

        case S_IFLNK:
        default:
          modestr[0] = '?';
          break;
        }

      /* Now the world permissions.  Owner and group permissions are
       * not of interest to web clients.
       */

      modestr[1] = (sb.st_mode & S_IROTH) ? 'r' : '-';
      modestr[2] = (sb.st_mode & S_IWOTH) ? 'w' : '-';
      modestr[3] = (sb.st_mode & S_IXOTH) ? 'x' : '-';
      modestr[4] = '\0';

      /* We also leave out the owner and group name */

      /* Get time string. */

      now = time(NULL);
      timestr = ctime(&sb.st_mtime);
      timestr[0] = timestr[4];
      timestr[1] = timestr[5];
      timestr[2] = timestr[6];
      timestr[3] = ' ';
      timestr[4] = timestr[8];
      timestr[5] = timestr[9];
      timestr[6] = ' ';

      if (now - sb.st_mtime > 60 * 60 * 24 * 182)      /* 1/2 year */
        {
          timestr[7] = ' ';
          timestr[8] = timestr[20];
          timestr[9] = timestr[21];
          timestr[10] = timestr[22];
          timestr[11] = timestr[23];
        }
      else
        {
          timestr[7] = timestr[11];
          timestr[8] = timestr[12];
          timestr[9] = ':';
          timestr[10] = timestr[14];
          timestr[11] = timestr[15];
        }

      timestr[12] = '\0';

      /* The ls -F file class. */

      switch (sb.st_mode & S_IFMT)
        {
        case S_IFDIR:
          fileclass = "/";
          break;

        case S_IFSOCK:
          fileclass = "=";
          break;

        case S_IFLNK:
          fileclass = "@";
          break;

        default:
          fileclass = (sb.st_mode & S_IXOTH) ? "*" : "";
          break;
        }

      /* And print. */

      fprintf(fp,
              "%s %3ld  %10lld  %s  <A HREF=\"/%.500s%s\">%s</A>%s%s%s\n",
              modestr, 0, (int16_t)sb.st_size, timestr, encrname,
              S_ISDIR(sb.st_mode) ? "/" : "", nameptrs[i], linkprefix,
              link, fileclass);
    }

  fputs("</PRE>", fp);
  fputs(html_endbody, fp);
  fputs(html_endhtml, fp);
  fclose(fp);
  exit(0);
}