Compare commits
14 Commits
Author | SHA1 | Date |
---|---|---|
Xavier Del Campo Romero | 32af8ddd3d | |
Xavier Del Campo Romero | b4572c6217 | |
Xavier Del Campo Romero | fb8896bccd | |
Xavier Del Campo Romero | dd29f9096a | |
Xavier Del Campo Romero | 8bcf0bf855 | |
Xavier Del Campo Romero | afc5cf0dfc | |
Xavier Del Campo Romero | b7f232366c | |
Xavier Del Campo Romero | 6c3bfa270b | |
Xavier Del Campo Romero | 78c8c4dabb | |
Xavier Del Campo Romero | 55008f2f64 | |
Xavier Del Campo Romero | 1f8aa578a4 | |
Xavier Del Campo Romero | a578ad6537 | |
Xavier Del Campo Romero | f6b84b765d | |
Xavier Del Campo Romero | 0f889b409e |
|
@ -13,7 +13,7 @@ add_executable(${PROJECT_NAME}
|
||||||
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
target_compile_options(${PROJECT_NAME} PRIVATE -Wall)
|
||||||
target_compile_definitions(${PROJECT_NAME} PRIVATE _FILE_OFFSET_BITS=64)
|
target_compile_definitions(${PROJECT_NAME} PRIVATE _FILE_OFFSET_BITS=64)
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/cmake)
|
||||||
find_package(web 0.2.0)
|
find_package(web 0.3.0)
|
||||||
|
|
||||||
if(WEB_FOUND)
|
if(WEB_FOUND)
|
||||||
find_package(dynstr 0.1.0)
|
find_package(dynstr 0.1.0)
|
||||||
|
|
|
@ -59,13 +59,13 @@ to `slcl`. If required, encryption should be done before uploading e.g.: using
|
||||||
#### Mandatory packages
|
#### Mandatory packages
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install build-essential libcjson-dev libssl-dev
|
sudo apt install build-essential libcjson-dev libssl-dev m4 jq
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Optional packages
|
#### Optional packages
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
sudo apt install cmake xxd jq
|
sudo apt install cmake
|
||||||
```
|
```
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
@ -90,9 +90,8 @@ $ make
|
||||||
#### CMake
|
#### CMake
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
$ mkdir build/
|
$ cmake -B build
|
||||||
$ cmake ..
|
$ cmake --build build/
|
||||||
$ cmake --build .
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Setting up
|
### Setting up
|
||||||
|
|
2
libweb
2
libweb
|
@ -1 +1 @@
|
||||||
Subproject commit 6ceae16a20175edb77fb2ffab0d3d6648d011221
|
Subproject commit b4930f72bb9026c5a0871f4fa4cabe20cb0e6a9f
|
115
main.c
115
main.c
|
@ -393,14 +393,24 @@ end:
|
||||||
|
|
||||||
static bool path_isrel(const char *const path)
|
static bool path_isrel(const char *const path)
|
||||||
{
|
{
|
||||||
if (!strcmp(path, "..") || !strcmp(path, ".") || strstr(path, "/../"))
|
if (!strcmp(path, "..")
|
||||||
|
|| !strcmp(path, ".")
|
||||||
|
|| !strncmp(path, "./", strlen("./"))
|
||||||
|
|| !strncmp(path, "../", strlen("../"))
|
||||||
|
|| strstr(path, "/./")
|
||||||
|
|| strstr(path, "/../"))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
static const char suffix[] = "/..";
|
static const char *const suffixes[] = {"/.", "/.."};
|
||||||
const size_t n = strlen(path), sn = strlen(suffix);
|
|
||||||
|
|
||||||
if (n >= sn && !strcmp(path + n - sn, suffix))
|
for (size_t i = 0; i < sizeof suffixes / sizeof *suffixes; i++)
|
||||||
return true;
|
{
|
||||||
|
const char *const suffix = suffixes[i];
|
||||||
|
const size_t n = strlen(path), sn = strlen(suffix);
|
||||||
|
|
||||||
|
if (n >= sn && !strcmp(path + n - sn, suffix))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -425,7 +435,8 @@ static int getpublic(const struct http_payload *const p,
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
struct auth *const a = user;
|
struct auth *const a = user;
|
||||||
const char *const adir = auth_dir(a);
|
const char *const adir = auth_dir(a),
|
||||||
|
*const file = p->resource + strlen("/public/");
|
||||||
struct dynstr d;
|
struct dynstr d;
|
||||||
|
|
||||||
dynstr_init(&d);
|
dynstr_init(&d);
|
||||||
|
@ -435,6 +446,13 @@ static int getpublic(const struct http_payload *const p,
|
||||||
fprintf(stderr, "%s: auth_dir failed\n", __func__);
|
fprintf(stderr, "%s: auth_dir failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
else if (!*file || filename_invalid(file))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: invalid filename %s\n",
|
||||||
|
__func__, p->resource);
|
||||||
|
ret = page_forbidden(r);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
else if (path_invalid(p->resource))
|
else if (path_invalid(p->resource))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: illegal relative path %s\n",
|
fprintf(stderr, "%s: illegal relative path %s\n",
|
||||||
|
@ -893,7 +911,16 @@ static int check_length(const unsigned long long len,
|
||||||
bool has_quota;
|
bool has_quota;
|
||||||
unsigned long long quota;
|
unsigned long long quota;
|
||||||
|
|
||||||
if (auth_quota(a, username, &has_quota, "a))
|
if (auth_cookie(a, c))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: auth_cookie failed\n", __func__);
|
||||||
|
|
||||||
|
if (page_forbidden(r))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (auth_quota(a, username, &has_quota, "a))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: auth_quota failed\n", __func__);
|
fprintf(stderr, "%s: auth_quota failed\n", __func__);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1053,23 +1080,23 @@ end:
|
||||||
static int move_file(const char *const old, const char *const new)
|
static int move_file(const char *const old, const char *const new)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
FILE *const f = fopen(old, "rb");
|
const int fd_old = open(old, O_RDONLY),
|
||||||
const int fd = open(new, O_WRONLY | O_CREAT, 0600);
|
fd_new = open(new, O_WRONLY | O_CREAT, 0600);
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
if (!f)
|
if (fd_old < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: fopen(3): %s\n", __func__, strerror(errno));
|
fprintf(stderr, "%s: open(2) fd_old: %s\n", __func__, strerror(errno));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (fd < 0)
|
else if (fd_new < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: open(2): %s\n", __func__, strerror(errno));
|
fprintf(stderr, "%s: open(2): %s\n", __func__, strerror(errno));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (stat(old, &sb))
|
else if (fstat(fd_old, &sb))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: stat(2): %s\n", __func__, strerror(errno));
|
fprintf(stderr, "%s: fstat(2): %s\n", __func__, strerror(errno));
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1078,24 +1105,30 @@ static int move_file(const char *const old, const char *const new)
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
const off_t left = sb.st_size - i;
|
const off_t left = sb.st_size - i;
|
||||||
const size_t rem = left > sizeof buf ? sizeof buf : left;
|
const size_t rem = left > sizeof buf ? sizeof buf : left;
|
||||||
ssize_t w;
|
const ssize_t r = read(fd_old, buf, rem);
|
||||||
|
|
||||||
if (!fread(buf, rem, 1, f))
|
if (r < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: fread(3) failed, feof=%d, ferror=%d\n",
|
fprintf(stderr, "%s: read(2): %s\n", __func__, strerror(errno));
|
||||||
__func__, feof(f), ferror(f));
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if ((w = write(fd, buf, rem)) < 0)
|
|
||||||
|
size_t wrem = r;
|
||||||
|
const void *p = buf;
|
||||||
|
|
||||||
|
while (wrem)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: write(2): %s\n", __func__, strerror(errno));
|
const ssize_t w = write(fd_new, p, wrem);
|
||||||
goto end;
|
|
||||||
}
|
if (w < 0)
|
||||||
else if (w != rem)
|
{
|
||||||
{
|
fprintf(stderr, "%s: write(2): %s\n",
|
||||||
fprintf(stderr, "%s: write(2): expected to write %zu bytes, "
|
__func__, strerror(errno));
|
||||||
"only %ju written\n", __func__, rem, (intmax_t)w);
|
goto end;
|
||||||
goto end;
|
}
|
||||||
|
|
||||||
|
p = (const char *)p + w;
|
||||||
|
wrem -= w;
|
||||||
}
|
}
|
||||||
|
|
||||||
i += rem;
|
i += rem;
|
||||||
|
@ -1104,15 +1137,15 @@ static int move_file(const char *const old, const char *const new)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
if (fd >= 0 && close(fd))
|
if (fd_old >= 0 && close(fd_old))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: close(2): %s\n", __func__, strerror(errno));
|
fprintf(stderr, "%s: close(2) fd_old: %s\n", __func__, strerror(errno));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f && fclose(f))
|
if (fd_new >= 0 && close(fd_new))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: fclose(3): %s\n", __func__, strerror(errno));
|
fprintf(stderr, "%s: close(2) fd_new: %s\n", __func__, strerror(errno));
|
||||||
ret = -1;
|
ret = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1346,6 +1379,7 @@ static int createdir(const struct http_payload *const p,
|
||||||
struct dynstr d, userd;
|
struct dynstr d, userd;
|
||||||
struct form *forms = NULL;
|
struct form *forms = NULL;
|
||||||
size_t n = 0;
|
size_t n = 0;
|
||||||
|
char *encurl = NULL;
|
||||||
|
|
||||||
dynstr_init(&d);
|
dynstr_init(&d);
|
||||||
dynstr_init(&userd);
|
dynstr_init(&userd);
|
||||||
|
@ -1372,7 +1406,7 @@ static int createdir(const struct http_payload *const p,
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
char *name = NULL, *dir = NULL;
|
const char *name = NULL, *dir = NULL;
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
{
|
{
|
||||||
|
@ -1459,7 +1493,12 @@ static int createdir(const struct http_payload *const p,
|
||||||
.status = HTTP_STATUS_SEE_OTHER
|
.status = HTTP_STATUS_SEE_OTHER
|
||||||
};
|
};
|
||||||
|
|
||||||
if (http_response_add_header(r, "Location", userd.str))
|
if (!(encurl = http_encode_url(userd.str)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: http_encode_url failed\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
else if (http_response_add_header(r, "Location", encurl))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
|
fprintf(stderr, "%s: http_response_add_header failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -1472,6 +1511,7 @@ end:
|
||||||
forms_free(forms, n);
|
forms_free(forms, n);
|
||||||
dynstr_free(&userd);
|
dynstr_free(&userd);
|
||||||
dynstr_free(&d);
|
dynstr_free(&d);
|
||||||
|
free(encurl);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2086,7 +2126,14 @@ int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
.length = check_length,
|
.length = check_length,
|
||||||
.tmpdir = tmpdir,
|
.tmpdir = tmpdir,
|
||||||
.user = a
|
.user = a,
|
||||||
|
.post =
|
||||||
|
{
|
||||||
|
/* Arbitrary limit. */
|
||||||
|
.max_files = 10000,
|
||||||
|
/* File upload only requires one pair. */
|
||||||
|
.max_pairs = 1
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned short outport;
|
unsigned short outport;
|
||||||
|
|
142
page.c
142
page.c
|
@ -108,6 +108,7 @@ static int prepare_name(struct html_node *const n, struct stat *const sb,
|
||||||
struct html_node *a;
|
struct html_node *a;
|
||||||
struct dynstr d, dname;
|
struct dynstr d, dname;
|
||||||
const char *const sep = S_ISDIR(sb->st_mode) ? "/" : "";
|
const char *const sep = S_ISDIR(sb->st_mode) ? "/" : "";
|
||||||
|
char *encurl = NULL;
|
||||||
|
|
||||||
dynstr_init(&d);
|
dynstr_init(&d);
|
||||||
dynstr_init(&dname);
|
dynstr_init(&dname);
|
||||||
|
@ -122,7 +123,12 @@ static int prepare_name(struct html_node *const n, struct stat *const sb,
|
||||||
fprintf(stderr, "%s: html_node_add_child failed\n", __func__);
|
fprintf(stderr, "%s: html_node_add_child failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (html_node_add_attr(a, "href", d.str))
|
else if (!(encurl = http_encode_url(d.str)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: http_encode_url failed\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
else if (html_node_add_attr(a, "href", encurl))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: html_node_add_attr href failed\n", __func__);
|
fprintf(stderr, "%s: html_node_add_attr href failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -143,6 +149,7 @@ static int prepare_name(struct html_node *const n, struct stat *const sb,
|
||||||
end:
|
end:
|
||||||
dynstr_free(&d);
|
dynstr_free(&d);
|
||||||
dynstr_free(&dname);
|
dynstr_free(&dname);
|
||||||
|
free(encurl);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,6 +310,7 @@ static int prepare_preview(struct html_node *const n,
|
||||||
const struct stat *const sb, const char *const dir, const char *const name)
|
const struct stat *const sb, const char *const dir, const char *const name)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
char *encurl = NULL;
|
||||||
struct html_node *a;
|
struct html_node *a;
|
||||||
struct dynstr d;
|
struct dynstr d;
|
||||||
|
|
||||||
|
@ -315,9 +323,22 @@ static int prepare_preview(struct html_node *const n,
|
||||||
fprintf(stderr, "%s: html_node_add_child form failed\n", __func__);
|
fprintf(stderr, "%s: html_node_add_child form failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (dynstr_append(&d, "%s%s?preview=1", dir, name))
|
else if (dynstr_append(&d, "%s%s", dir, name))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: dynstr_append failed\n", __func__);
|
fprintf(stderr, "%s: dynstr_append d failed\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
else if (!(encurl = http_encode_url(d.str)))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: http_encode_url failed\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
dynstr_free(&d);
|
||||||
|
|
||||||
|
if (dynstr_append(&d, "%s?preview=1", encurl))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: dynstr_append encd failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (html_node_add_attr(a, "href", d.str))
|
else if (html_node_add_attr(a, "href", d.str))
|
||||||
|
@ -335,6 +356,7 @@ static int prepare_preview(struct html_node *const n,
|
||||||
|
|
||||||
end:
|
end:
|
||||||
dynstr_free(&d);
|
dynstr_free(&d);
|
||||||
|
free(encurl);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1272,20 +1294,24 @@ end:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int serve_file(struct http_response *const r,
|
static int serve_file(struct http_response *const r,
|
||||||
const struct stat *const sb, const char *const res, const bool preview)
|
const struct stat *const sb, const char *const res, const bool preview,
|
||||||
|
const int fd, bool *const fdopened)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
FILE *const f = fopen(res, "rb");
|
FILE *f = NULL;
|
||||||
struct dynstr b, d;
|
struct dynstr b, d;
|
||||||
char *bn;
|
char *bn;
|
||||||
|
|
||||||
dynstr_init(&b);
|
dynstr_init(&b);
|
||||||
dynstr_init(&d);
|
dynstr_init(&d);
|
||||||
|
|
||||||
if (!f)
|
if (preview)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: fopen(3): %s\n", __func__, strerror(errno));
|
if (dynstr_append(&d, "inline"))
|
||||||
goto end;
|
{
|
||||||
|
fprintf(stderr, "%s: dynstr_append inline failed\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (dynstr_append(&b, "%s", res))
|
else if (dynstr_append(&b, "%s", res))
|
||||||
{
|
{
|
||||||
|
@ -1297,20 +1323,20 @@ static int serve_file(struct http_response *const r,
|
||||||
fprintf(stderr, "%s: basename(3) failed\n", __func__);
|
fprintf(stderr, "%s: basename(3) failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (preview)
|
|
||||||
{
|
|
||||||
if (dynstr_append(&d, "inline"))
|
|
||||||
{
|
|
||||||
fprintf(stderr, "%s: dynstr_append inline failed\n", __func__);
|
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (dynstr_append(&d, "attachment; filename=\"%s\"", bn))
|
else if (dynstr_append(&d, "attachment; filename=\"%s\"", bn))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: dynstr_append attachment failed\n", __func__);
|
fprintf(stderr, "%s: dynstr_append attachment failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(f = fdopen(fd, "rb")))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: fdopen(3): %s\n", __func__, strerror(errno));
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fdopened = true;
|
||||||
|
|
||||||
*r = (const struct http_response)
|
*r = (const struct http_response)
|
||||||
{
|
{
|
||||||
.status = HTTP_STATUS_OK,
|
.status = HTTP_STATUS_OK,
|
||||||
|
@ -1380,28 +1406,63 @@ static bool preview(const struct page_resource *const pr)
|
||||||
|
|
||||||
int page_resource(const struct page_resource *const pr)
|
int page_resource(const struct page_resource *const pr)
|
||||||
{
|
{
|
||||||
|
int ret = -1;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
const int fd = open(pr->res, O_RDONLY);
|
||||||
|
bool fdopened = false;
|
||||||
|
|
||||||
if (stat(pr->res, &sb))
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: stat(2) %s: %s\n",
|
|
||||||
__func__, pr->res, strerror(errno));
|
|
||||||
|
|
||||||
if (errno == ENOENT || errno == ENOTDIR)
|
if (errno == ENOENT || errno == ENOTDIR)
|
||||||
return page_not_found(pr->r);
|
ret = page_not_found(pr->r);
|
||||||
else
|
else
|
||||||
return -1;
|
fprintf(stderr, "%s: open(2) %s: %s\n",
|
||||||
|
__func__, pr->res, strerror(errno));
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
else if (fstat(fd, &sb))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: fstat(2) %s: %s\n",
|
||||||
|
__func__, pr->res, strerror(errno));
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mode_t m = sb.st_mode;
|
const mode_t m = sb.st_mode;
|
||||||
|
|
||||||
if (S_ISDIR(m))
|
if (S_ISDIR(m))
|
||||||
return list_dir(pr);
|
{
|
||||||
|
if (list_dir(pr))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: list_dir failed\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
else if (S_ISREG(m))
|
else if (S_ISREG(m))
|
||||||
return serve_file(pr->r, &sb, pr->res, preview(pr));
|
{
|
||||||
|
if (serve_file(pr->r, &sb, pr->res, preview(pr), fd, &fdopened))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: serve_file failed\n", __func__);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: unexpected st_mode %jo\n", __func__, (intmax_t)m);
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s: unexpected st_mode %jd\n", __func__, (intmax_t)m);
|
ret = 0;
|
||||||
return -1;
|
|
||||||
|
end:
|
||||||
|
if (!fdopened && fd >= 0 && close(fd))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: close(2) %s: %s\n",
|
||||||
|
__func__, pr->res, strerror(errno));
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *resolve_link(const char *const res)
|
static char *resolve_link(const char *const res)
|
||||||
|
@ -1444,18 +1505,26 @@ static char *resolve_link(const char *const res)
|
||||||
int page_public(struct http_response *const r, const char *const res)
|
int page_public(struct http_response *const r, const char *const res)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
|
const int fd = open(res, O_RDONLY);
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
char *path = NULL;
|
char *path = NULL;
|
||||||
|
bool fdopened = false;
|
||||||
|
|
||||||
if (stat(res, &sb))
|
if (fd < 0)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: stat(2) %s: %s\n",
|
|
||||||
__func__, res, strerror(errno));
|
|
||||||
|
|
||||||
if (errno == ENOENT)
|
if (errno == ENOENT)
|
||||||
return page_not_found(r);
|
ret = page_not_found(r);
|
||||||
else
|
else
|
||||||
goto end;
|
fprintf(stderr, "%s: stat(2) %s: %s\n",
|
||||||
|
__func__, res, strerror(errno));
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
else if (fstat(fd, &sb))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: fstat(2) %s: %s\n",
|
||||||
|
__func__, res, strerror(errno));
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mode_t m = sb.st_mode;
|
const mode_t m = sb.st_mode;
|
||||||
|
@ -1470,7 +1539,7 @@ int page_public(struct http_response *const r, const char *const res)
|
||||||
fprintf(stderr, "%s: resolve_link failed\n", __func__);
|
fprintf(stderr, "%s: resolve_link failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
else if (serve_file(r, &sb, path, false))
|
else if (serve_file(r, &sb, path, false, fd, &fdopened))
|
||||||
{
|
{
|
||||||
fprintf(stderr, "%s: serve_file failed\n", __func__);
|
fprintf(stderr, "%s: serve_file failed\n", __func__);
|
||||||
goto end;
|
goto end;
|
||||||
|
@ -1479,6 +1548,13 @@ int page_public(struct http_response *const r, const char *const res)
|
||||||
ret = 0;
|
ret = 0;
|
||||||
|
|
||||||
end:
|
end:
|
||||||
|
if (!fdopened && fd >= 0 && close(fd))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "%s: close(2) %s: %s\n",
|
||||||
|
__func__, res, strerror(errno));
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
|
||||||
free(path);
|
free(path);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue