simplefiles

A lightweight C CGI web application for managing files.
git clone https://scm.kuandu.systems/git-raw/simplefiles.git
Log | Files | Refs | README | LICENSE

list.c (4410B)


      1 #include <sys/stat.h>
      2 #include <dirent.h>
      3 #include <errno.h>
      4 #include <limits.h>
      5 #include <stdio.h>
      6 #include <stdlib.h>
      7 #include <string.h>
      8 #include <time.h>
      9 #include <unistd.h>
     10 
     11 #include "config.h"
     12 #include "common.h"
     13 #include "url.h"
     14 #include "html.h"
     15 #include "http.h"
     16 
     17 static int list_files(const char *repository_path, struct html_row ** rows, size_t * nrows);
     18 static void format_size(char *buf, size_t len, off_t size);
     19 static void free_rows(struct html_row *rows, size_t nrows);
     20 
     21 int
     22 main(void)
     23 {
     24 	char path[PATH_MAX];
     25 	char template[PATH_MAX];
     26 	struct html_row *rows;
     27 	size_t nrows;
     28 	struct html_block blocks[1];
     29 	const char *template_name;
     30 
     31 	if (!config_access_allowed()) {
     32 		reply("403 Forbidden", "Forbidden");
     33 		return 0;
     34 	}
     35 
     36 	if (build_repository_path(path,
     37 		sizeof(path),
     38 		storage_root(),
     39 		repository()) == -1) {
     40 		reply("500 Internal Server Error",
     41 		    "Path too long");
     42 		return 0;
     43 	}
     44 	if (list_files(path, &rows, &nrows) == -1) {
     45 		reply("500 Internal Server Error",
     46 		    "Unable to list files");
     47 		return 0;
     48 	}
     49 
     50 	blocks[0].name = "FILES";
     51 	blocks[0].rows = rows;
     52 	blocks[0].nrows = nrows;
     53 
     54 
     55 	if (!config_write_allowed())
     56 		template_name = LIST_READONLY_TEMPLATE_NAME;
     57 	else
     58 		template_name = LIST_TEMPLATE_NAME;
     59 
     60 	if (snprintf(template, sizeof(template),
     61 	    "%s/%s",
     62 	    simplefiles_root(),
     63 	    template_name) >= (int) sizeof(template)) {
     64 		reply("500 Internal Server Error",
     65 		    "Template path too long");
     66 		free_rows(rows, nrows);
     67 		return 0;
     68 	}
     69 
     70 	if (render_template_response(template,
     71         	NULL, 0,
     72         	blocks, 1) == -1) {
     73 		free_rows(rows, nrows);
     74 		reply("500 Internal Server Error", "Unable to render template");
     75 		return 0;
     76 	}
     77 	free_rows(rows, nrows);
     78 	return 0;
     79 }
     80 
     81 static void
     82 format_size(char *buf, size_t len, off_t size)
     83 {
     84 	if (size >= 1073741824LL)
     85 		snprintf(buf, len, "%.1f GB", size / 1073741824.0);
     86 	else if (size >= 1048576LL)
     87 		snprintf(buf, len, "%.1f MB", size / 1048576.0);
     88 	else if (size >= 1024LL)
     89 		snprintf(buf, len, "%.1f KB", size / 1024.0);
     90 	else
     91 		snprintf(buf, len, "%lld B", (long long) size);
     92 }
     93 
     94 static int
     95 list_files(const char *repository_path,
     96     struct html_row ** rows, size_t * nrows)
     97 {
     98 	DIR *dir;
     99 	struct dirent *de;
    100 	struct stat st;
    101 	char path[PATH_MAX];
    102 	char timebuf[32];
    103 	struct tm *tm;
    104 	char sizebuf[32];
    105 	char *encoded;
    106 	struct html_row *new_rows;
    107 	struct html_var *vars;
    108 	size_t count = 0;
    109 
    110 	*rows = NULL;
    111 	*nrows = 0;
    112 
    113 	dir = opendir(repository_path);
    114 	if (dir == NULL)
    115 		return 0;
    116 
    117 	while ((de = readdir(dir)) != NULL) {
    118 		if (strcmp(de->d_name, ".") == 0 ||
    119 		    strcmp(de->d_name, "..") == 0)
    120 			continue;
    121 
    122 		if (strcmp(de->d_name, CONFIG_FILENAME) == 0)
    123 			continue;
    124 
    125 		if (snprintf(path, sizeof(path),
    126 			"%s/%s",
    127 			repository_path,
    128 			de->d_name) >= (int) sizeof(path))
    129 			continue;
    130 
    131 		if (stat(path, &st) == -1)
    132 			continue;
    133 
    134 		if (!S_ISREG(st.st_mode))
    135 			continue;
    136 
    137 		tm = localtime(&st.st_mtime);
    138 		if (tm == NULL)
    139 			continue;
    140 
    141 		if (strftime(timebuf, sizeof(timebuf),
    142 			"%Y-%m-%d %H:%M", tm) == 0)
    143 			continue;
    144 
    145 		encoded = url_encode(de->d_name);
    146 		if (encoded == NULL)
    147 			continue;
    148 
    149 
    150 		new_rows = realloc(*rows, (count + 1) * sizeof(**rows));
    151 		if (new_rows == NULL) {
    152 			free_rows(*rows, count);
    153 			free(encoded);
    154 			closedir(dir);
    155 			return -1;
    156 		}
    157 		*rows = new_rows;
    158 
    159 		vars = malloc(4 * sizeof(*vars));
    160 		if (vars == NULL) {
    161 			free_rows(*rows, count);
    162 			free(encoded);
    163 			closedir(dir);
    164 			return -1;
    165 		}
    166 		vars[0].name = "NAME";
    167 		vars[0].value = strdup(de->d_name);
    168 
    169 		vars[1].name = "URL";
    170 		vars[1].value = encoded;
    171 
    172 		format_size(sizebuf, sizeof(sizebuf), st.st_size);
    173 		vars[2].name = "SIZE";
    174 		vars[2].value = strdup(sizebuf);
    175 
    176 		vars[3].name = "MODIFIED";
    177 		vars[3].value = strdup(timebuf);
    178 
    179 		if (vars[0].value == NULL ||
    180 		    vars[2].value == NULL ||
    181 		    vars[3].value == NULL) {
    182 			free((char *) vars[0].value);
    183 			free((char *) vars[1].value);
    184 			free((char *) vars[2].value);
    185 			free((char *) vars[3].value);
    186 			free(vars);
    187 			free_rows(*rows, count);
    188 			*rows = NULL;
    189 			closedir(dir);
    190 			return -1;
    191 		}
    192 		(*rows)[count].vars = vars;
    193 		(*rows)[count].nvars = 4;
    194 		count++;
    195 	}
    196 
    197 	closedir(dir);
    198 
    199 	*nrows = count;
    200 	return 0;
    201 }
    202 
    203 static void
    204 free_rows(struct html_row *rows, size_t nrows)
    205 {
    206 	size_t i;
    207 	size_t j;
    208 
    209 	for (i = 0; i < nrows; i++) {
    210 		for (j = 0; j < rows[i].nvars; j++)
    211 			free((char *) rows[i].vars[j].value);
    212 
    213 		free((struct html_var *) rows[i].vars);
    214 	}
    215 
    216 	free(rows);
    217 }