io_dir.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*
  2. * Copyright (c) 2004-2005 Sergey Lyubka <valenok@gmail.com>
  3. * All rights reserved
  4. *
  5. * "THE BEER-WARE LICENSE" (Revision 42):
  6. * Sergey Lyubka wrote this file. As long as you retain this notice you
  7. * can do whatever you want with this stuff. If we meet some day, and you think
  8. * this stuff is worth it, you can buy me a beer in return.
  9. */
  10. #include "defs.h"
  11. /*
  12. * For a given PUT path, create all intermediate subdirectories
  13. * for given path. Return 0 if the path itself is a directory,
  14. * or -1 on error, 1 if OK.
  15. */
  16. int
  17. _shttpd_put_dir(const char *path)
  18. {
  19. char buf[FILENAME_MAX];
  20. const char *s, *p;
  21. struct stat st;
  22. size_t len;
  23. for (s = p = path + 2; (p = strchr(s, '/')) != NULL; s = ++p) {
  24. len = p - path;
  25. assert(len < sizeof(buf));
  26. (void) memcpy(buf, path, len);
  27. buf[len] = '\0';
  28. /* Try to create intermediate directory */
  29. if (_shttpd_stat(buf, &st) == -1 &&
  30. _shttpd_mkdir(buf, 0755) != 0)
  31. return (-1);
  32. /* Is path itself a directory ? */
  33. if (p[1] == '\0')
  34. return (0);
  35. }
  36. return (1);
  37. }
  38. static int
  39. read_dir(struct stream *stream, void *buf, size_t len)
  40. {
  41. static const char footer[] = "</table></body></html>\n";
  42. struct dirent *dp = NULL;
  43. char file[FILENAME_MAX], line[FILENAME_MAX + 512],
  44. size[64], mod[64];
  45. struct stat st;
  46. struct conn *c = stream->conn;
  47. int n, nwritten = 0;
  48. const char *slash = "";
  49. assert(stream->chan.dir.dirp != NULL);
  50. assert(stream->conn->uri[0] != '\0');
  51. do {
  52. if (len < sizeof(line))
  53. break;
  54. if ((dp = readdir(stream->chan.dir.dirp)) == NULL)
  55. break;
  56. DBG(("read_dir: %s", dp->d_name));
  57. /* Do not show current dir and passwords file */
  58. if (strcmp(dp->d_name, ".") == 0 ||
  59. strcmp(dp->d_name, HTPASSWD) == 0)
  60. continue;
  61. (void) _shttpd_snprintf(file, sizeof(file),
  62. "%s%s%s", stream->chan.dir.path, slash, dp->d_name);
  63. (void) _shttpd_stat(file, &st);
  64. if (S_ISDIR(st.st_mode)) {
  65. _shttpd_snprintf(size,sizeof(size),"%s","&lt;DIR&gt;");
  66. } else {
  67. if (st.st_size < 1024)
  68. (void) _shttpd_snprintf(size, sizeof(size),
  69. "%lu", (unsigned long) st.st_size);
  70. else if (st.st_size < 1024 * 1024)
  71. (void) _shttpd_snprintf(size,
  72. sizeof(size), "%luk",
  73. (unsigned long) (st.st_size >> 10) + 1);
  74. else
  75. (void) _shttpd_snprintf(size, sizeof(size),
  76. "%.1fM", (float) st.st_size / 1048576);
  77. }
  78. (void) strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M",
  79. localtime(&st.st_mtime));
  80. n = _shttpd_snprintf(line, sizeof(line),
  81. "<tr><td><a href=\"%s%s%s\">%s%s</a></td>"
  82. "<td>&nbsp;%s</td><td>&nbsp;&nbsp;%s</td></tr>\n",
  83. c->uri, slash, dp->d_name, dp->d_name,
  84. S_ISDIR(st.st_mode) ? "/" : "", mod, size);
  85. (void) memcpy(buf, line, n);
  86. buf = (char *) buf + n;
  87. nwritten += n;
  88. len -= n;
  89. } while (dp != NULL);
  90. /* Append proper HTML footer for the page */
  91. if (dp == NULL && len >= sizeof(footer)) {
  92. (void) memcpy(buf, footer, sizeof(footer));
  93. nwritten += sizeof(footer);
  94. stream->flags |= FLAG_CLOSED;
  95. }
  96. return (nwritten);
  97. }
  98. static void
  99. close_dir(struct stream *stream)
  100. {
  101. assert(stream->chan.dir.dirp != NULL);
  102. assert(stream->chan.dir.path != NULL);
  103. (void) closedir(stream->chan.dir.dirp);
  104. free(stream->chan.dir.path);
  105. }
  106. void
  107. _shttpd_get_dir(struct conn *c)
  108. {
  109. if ((c->loc.chan.dir.dirp = opendir(c->loc.chan.dir.path)) == NULL) {
  110. (void) free(c->loc.chan.dir.path);
  111. _shttpd_send_server_error(c, 500, "Cannot open directory");
  112. } else {
  113. c->loc.io.head = _shttpd_snprintf(c->loc.io.buf, c->loc.io.size,
  114. "HTTP/1.1 200 OK\r\n"
  115. "Connection: close\r\n"
  116. "Content-Type: text/html; charset=utf-8\r\n\r\n"
  117. "<html><head><title>Index of %s</title>"
  118. "<style>th {text-align: left;}</style></head>"
  119. "<body><h1>Index of %s</h1><pre><table cellpadding=\"0\">"
  120. "<tr><th>Name</th><th>Modified</th><th>Size</th></tr>"
  121. "<tr><td colspan=\"3\"><hr></td></tr>",
  122. c->uri, c->uri);
  123. io_clear(&c->rem.io);
  124. c->status = 200;
  125. c->loc.io_class = &_shttpd_io_dir;
  126. c->loc.flags |= FLAG_R | FLAG_ALWAYS_READY;
  127. }
  128. }
  129. const struct io_class _shttpd_io_dir = {
  130. "dir",
  131. read_dir,
  132. NULL,
  133. close_dir
  134. };