2 * rs-serve - (c) 2013 Niklas E. Cathor
4 * This program is distributed in the hope that it will be useful,
5 * but WITHOUT ANY WARRANTY; without even the implied warranty of
6 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
7 * GNU Affero General Public License for more details.
9 * You should have received a copy of the GNU Affero General Public License
10 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 * Gets parsed requests and performs the requested actions / sends the requested
22 * These functions are only called from storage processes.
25 static char *escape_name(const char *name) {
26 int max_len = strlen(name) * 2, i = 0;
27 char *escaped = malloc(max_len + 1);
29 perror("malloc() failed");
33 for(name_p = name; *name_p != 0; name_p++) {
34 if(*name_p == '"' || *name_p == '\\') {
37 escaped[i++] = *name_p;
40 escaped = realloc(escaped, i);
44 static int serve_directory(struct rs_request *request) {
45 struct evbuffer *buf = evbuffer_new();
47 log_error("evbuffer_new() failed: %s", strerror(errno));
50 DIR *dir = opendir(request->path);
52 log_error("opendir() failed: %s", strerror(errno));
55 struct dirent *entryp = malloc(offsetof(struct dirent, d_name) +
56 pathconf(request->path, _PC_NAME_MAX) + 1);
57 struct dirent *resultp = NULL;
59 log_error("malloc() failed while creating directory pointer: %s",
63 struct stat file_stat_buf;
67 readdir_r(dir, entryp, &resultp);
71 if(strcmp(entryp->d_name, ".") == 0 ||
72 strcmp(entryp->d_name, "..") == 0) {
77 evbuffer_add(buf, "{", 1);
80 evbuffer_add(buf, ",", 1);
82 entry_len = strlen(entryp->d_name);
83 char full_path[request->path_len + entry_len + 1];
84 sprintf(full_path, "%s%s", request->path, entryp->d_name);
85 stat(full_path, &file_stat_buf);
87 char *escaped_name = escape_name(entryp->d_name);
89 // failed to allocate name
94 evbuffer_add_printf(buf, "\"%s%s\":%lld", escaped_name,
95 S_ISDIR(file_stat_buf.st_mode) ? "/" : "",
96 ((long long)file_stat_buf.st_mtime) * 1000);
101 evbuffer_add(buf, "{", 1);
103 evbuffer_add(buf, "}", 1);
104 struct rs_header header = {
105 .key = "Content-Type",
106 .value = "application/json",
109 send_response_head(request, 200, &header);
110 send_response_body(request, buf);
116 int serve_file(struct rs_request *request) {
120 int storage_handle_head(struct rs_request *request) {
124 int storage_handle_get(struct rs_request *request) {
126 struct stat stat_buf;
127 if(stat(request->path, &stat_buf) != 0) {
128 if(errno != ENOENT) {
129 log_error("stat() failed for path \"%s\": %s", request->path, strerror(errno));
135 // check for directory
136 if(request->path[request->path_len - 1] == '/') {
137 // directory requested
138 if(! S_ISDIR(stat_buf.st_mode)) {
143 return serve_directory(request);
146 if(S_ISDIR(stat_buf.st_mode)) {
147 // found, but is a directory
151 return serve_file(request);
155 int storage_handle_put(struct rs_request *request) {
159 int storage_handle_delete(struct rs_request *request) {