aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorXavier Del Campo Romero <xavi.dcr@tutanota.com>2024-02-19 23:20:25 +0100
committerXavier Del Campo Romero <xavi.dcr@tutanota.com>2024-02-19 23:35:09 +0100
commit6c3bfa270b1de6cdea0da8e351f92ec65e90c4f0 (patch)
tree3aec762e2bc802962afbb2fd6dcace45da7c62ce
parent78c8c4dabb62a6669cfd4eca231e39fd7fd4567a (diff)
page.c: Use open(2) fdopen(3) and fstat(2)v0.2.1-rc1
Now, the same file descriptor can be reused for all of the operations above, instead of calling stat(2) and fopen(3) separately.
-rw-r--r--page.c104
1 files changed, 79 insertions, 25 deletions
diff --git a/page.c b/page.c
index 80a9675..f6e3a88 100644
--- a/page.c
+++ b/page.c
@@ -1294,22 +1294,18 @@ end:
}
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;
- FILE *const f = fopen(res, "rb");
+ FILE *f = NULL;
struct dynstr b, d;
char *bn;
dynstr_init(&b);
dynstr_init(&d);
- if (!f)
- {
- fprintf(stderr, "%s: fopen(3): %s\n", __func__, strerror(errno));
- goto end;
- }
- else if (dynstr_append(&b, "%s", res))
+ if (dynstr_append(&b, "%s", res))
{
fprintf(stderr, "%s: dynstr_append res failed\n", __func__);
goto end;
@@ -1333,6 +1329,14 @@ static int serve_file(struct http_response *const r,
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)
{
.status = HTTP_STATUS_OK,
@@ -1402,28 +1406,63 @@ static bool preview(const struct page_resource *const pr)
int page_resource(const struct page_resource *const pr)
{
+ int ret = -1;
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)
- return page_not_found(pr->r);
+ ret = page_not_found(pr->r);
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;
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))
- 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);
- return -1;
+ ret = 0;
+
+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)
@@ -1466,18 +1505,26 @@ static char *resolve_link(const char *const res)
int page_public(struct http_response *const r, const char *const res)
{
int ret = -1;
+ const int fd = open(res, O_RDONLY);
struct stat sb;
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)
- return page_not_found(r);
+ ret = page_not_found(r);
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;
@@ -1492,7 +1539,7 @@ int page_public(struct http_response *const r, const char *const res)
fprintf(stderr, "%s: resolve_link failed\n", __func__);
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__);
goto end;
@@ -1501,6 +1548,13 @@ int page_public(struct http_response *const r, const char *const res)
ret = 0;
end:
+ if (!fdopened && fd >= 0 && close(fd))
+ {
+ fprintf(stderr, "%s: close(2) %s: %s\n",
+ __func__, res, strerror(errno));
+ ret = -1;
+ }
+
free(path);
return ret;
}