page.c: Use open(2) fdopen(3) and fstat(2)

Now, the same file descriptor can be reused for all of the operations
above, instead of calling stat(2) and fopen(3) separately.
This commit is contained in:
Xavier Del Campo Romero 2024-02-19 23:20:25 +01:00
parent 78c8c4dabb
commit 6c3bfa270b
Signed by: xavi
GPG Key ID: 84FF3612A9BF43F2
1 changed files with 79 additions and 25 deletions

104
page.c
View File

@ -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;
}