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);
}