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:
parent
78c8c4dabb
commit
6c3bfa270b
104
page.c
104
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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue