[File] [PATCH] reuse fstat() result instead of calling fstat() again
Denys Vlasenko
dvlasenk at redhat.com
Mon May 6 08:30:23 UTC 2019
This is what happens when
magic_file(ms, "some_elf_file")
is called:
openat(AT_FDCWD, "some_elf_file", O_RDONLY|O_NONBLOCK) = 6
fstat(6, {st_mode=S_IFREG|0755, st_size=29560, ...}) = 0
^^^^^^^^^^^ fstat #1
read(6, "\177ELF\2\1\1\0\0\0\...
fstat(6, {st_mode=S_IFREG|0755, st_size=29560, ...}) = 0
^^^^^^^^^^^ fstat #2
lseek(6, 0, SEEK_SET) = 0
fstat(6, {st_mode=S_IFREG|0755, st_size=29560, ...}) = 0
^^^^^^^^^^^ fstat #3
pread64(6, "\6\0\0\0...", 56, 120) = 56
...
This is not necessary. Propagate fstat result deeper into callees.
Signed-off-by: Denys Vlasenko <dvlasenk at redhat.com>
---
src/ascmagic.c | 2 +-
src/buffer.c | 7 +++++--
src/compress.c | 4 ++--
src/file.h | 7 ++++---
src/funcs.c | 5 +++--
src/magic.c | 11 +++++++----
src/readelf.c | 22 ++++++++++++++++++----
src/softmagic.c | 4 ++--
8 files changed, 42 insertions(+), 20 deletions(-)
diff --git a/src/ascmagic.c b/src/ascmagic.c
index bcebeab7..8f372976 100644
--- a/src/ascmagic.c
+++ b/src/ascmagic.c
@@ -150,7 +150,7 @@ file_ascmagic_with_encoding(struct magic_set *ms,
if ((utf8_end = encode_utf8(utf8_buf, mlen, ubuf, ulen))
== NULL)
goto done;
- buffer_init(&bb, b->fd, utf8_buf,
+ buffer_init(&bb, b->fd, &b->st, utf8_buf,
CAST(size_t, utf8_end - utf8_buf));
if ((rv = file_softmagic(ms, &bb, NULL, NULL,
diff --git a/src/buffer.c b/src/buffer.c
index fd40416a..0abee776 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -37,10 +37,13 @@ FILE_RCSID("@(#)$File: buffer.c,v 1.5 2019/02/20 02:35:27 christos Exp $")
#include <sys/stat.h>
void
-buffer_init(struct buffer *b, int fd, const void *data, size_t len)
+buffer_init(struct buffer *b, int fd, const struct stat *st, const void *data,
+ size_t len)
{
b->fd = fd;
- if (b->fd == -1 || fstat(b->fd, &b->st) == -1)
+ if (st)
+ memcpy(&b->st, st, sizeof(b->st));
+ else if (b->fd == -1 || fstat(b->fd, &b->st) == -1)
memset(&b->st, 0, sizeof(b->st));
b->fbuf = data;
b->flen = len;
diff --git a/src/compress.c b/src/compress.c
index cd67edaa..102d17cd 100644
--- a/src/compress.c
+++ b/src/compress.c
@@ -272,7 +272,7 @@ file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
if (urv == ERRDATA)
prv = format_decompression_error(ms, i, newbuf);
else
- prv = file_buffer(ms, -1, name, newbuf, nsz);
+ prv = file_buffer(ms, -1, NULL, name, newbuf, nsz);
if (prv == -1)
goto error;
rv = 1;
@@ -289,7 +289,7 @@ file_zmagic(struct magic_set *ms, const struct buffer *b, const char *name)
* XXX: If file_buffer fails here, we overwrite
* the compressed text. FIXME.
*/
- if (file_buffer(ms, -1, NULL, buf, nbytes) == -1) {
+ if (file_buffer(ms, -1, NULL, NULL, buf, nbytes) == -1) {
if (file_pop_buffer(ms, pb) != NULL)
abort();
goto error;
diff --git a/src/file.h b/src/file.h
index 2b372714..51bde279 100644
--- a/src/file.h
+++ b/src/file.h
@@ -454,8 +454,8 @@ protected const char *file_fmttime(uint64_t, int, char *);
protected struct magic_set *file_ms_alloc(int);
protected void file_ms_free(struct magic_set *);
protected int file_default(struct magic_set *, size_t);
-protected int file_buffer(struct magic_set *, int, const char *, const void *,
- size_t);
+protected int file_buffer(struct magic_set *, int, struct stat *, const char *,
+ const void *, size_t);
protected int file_fsmagic(struct magic_set *, const char *, struct stat *);
protected int file_pipe2file(struct magic_set *, int, const void *, size_t);
protected int file_vprintf(struct magic_set *, const char *, va_list)
@@ -512,7 +512,8 @@ protected int file_os2_apptype(struct magic_set *, const char *, const void *,
size_t);
#endif /* __EMX__ */
-protected void buffer_init(struct buffer *, int, const void *, size_t);
+protected void buffer_init(struct buffer *, int, const struct stat *,
+ const void *, size_t);
protected void buffer_fini(struct buffer *);
protected int buffer_fill(const struct buffer *);
diff --git a/src/funcs.c b/src/funcs.c
index eca99ad7..513224d7 100644
--- a/src/funcs.c
+++ b/src/funcs.c
@@ -201,7 +201,8 @@ file_default(struct magic_set *ms, size_t nb)
*/
/*ARGSUSED*/
protected int
-file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__unused__)),
+file_buffer(struct magic_set *ms, int fd, struct stat *st,
+ const char *inname __attribute__ ((__unused__)),
const void *buf, size_t nb)
{
int m = 0, rv = 0, looks_text = 0;
@@ -212,7 +213,7 @@ file_buffer(struct magic_set *ms, int fd, const char *inname __attribute__ ((__u
char *rbuf = NULL;
struct buffer b;
- buffer_init(&b, fd, buf, nb);
+ buffer_init(&b, fd, st, buf, nb);
ms->mode = b.st.st_mode;
if (nb == 0) {
diff --git a/src/magic.c b/src/magic.c
index 0796a753..0ac6b625 100644
--- a/src/magic.c
+++ b/src/magic.c
@@ -406,6 +406,7 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
struct stat sb;
ssize_t nbytes = 0; /* number of bytes read from a datafile */
int ispipe = 0;
+ int okstat = 0;
off_t pos = CAST(off_t, -1);
if (file_reset(ms, 1) == -1)
@@ -438,7 +439,7 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
int flags = O_RDONLY|O_BINARY|O_NONBLOCK;
errno = 0;
if ((fd = open(inname, flags)) < 0) {
- int okstat = stat(inname, &sb) == 0;
+ okstat = stat(inname, &sb) == 0;
if (okstat && S_ISFIFO(sb.st_mode))
ispipe = 1;
#ifdef WIN32
@@ -462,7 +463,9 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
}
if (fd != -1) {
- if (fstat(fd, &sb) == 0 && S_ISFIFO(sb.st_mode))
+ if (!okstat)
+ okstat = fstat(fd, &sb) == 0;
+ if (okstat && S_ISFIFO(sb.st_mode))
ispipe = 1;
if (inname == NULL)
pos = lseek(fd, CAST(off_t, 0), SEEK_CUR);
@@ -508,7 +511,7 @@ file_or_fd(struct magic_set *ms, const char *inname, int fd)
}
(void)memset(buf + nbytes, 0, SLOP); /* NUL terminate */
- if (file_buffer(ms, fd, inname, buf, CAST(size_t, nbytes)) == -1)
+ if (file_buffer(ms, fd, okstat ? &sb : NULL, inname, buf, CAST(size_t, nbytes)) == -1)
goto done;
rv = 0;
done:
@@ -534,7 +537,7 @@ magic_buffer(struct magic_set *ms, const void *buf, size_t nb)
* The main work is done here!
* We have the file name and/or the data buffer to be identified.
*/
- if (file_buffer(ms, -1, NULL, buf, nb) == -1) {
+ if (file_buffer(ms, -1, NULL, NULL, buf, nb) == -1) {
return NULL;
}
return file_getbuffer(ms);
diff --git a/src/readelf.c b/src/readelf.c
index 5d97dd02..394036e5 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -1734,6 +1734,7 @@ file_tryelf(struct magic_set *ms, const struct buffer *b)
int clazz;
int swap;
struct stat st;
+ const struct stat *stp;
off_t fsize;
int flags = 0;
Elf32_Ehdr elf32hdr;
@@ -1762,12 +1763,25 @@ file_tryelf(struct magic_set *ms, const struct buffer *b)
&& (errno == ESPIPE))
fd = file_pipe2file(ms, fd, buf, nbytes);
- if (fd == -1 || fstat(fd, &st) == -1) {
- file_badread(ms);
+ if (fd == -1) {
+ file_badread(ms);
return -1;
}
- if (S_ISREG(st.st_mode) || st.st_size != 0)
- fsize = st.st_size;
+
+ stp = &b->st;
+ /*
+ * b->st.st_size != 0 if previous fstat() succeeded,
+ * which is likely, we can avoid extra stat() call.
+ */
+ if (b->st.st_size == 0) {
+ stp = &st;
+ if (fstat(fd, &st) == -1) {
+ file_badread(ms);
+ return -1;
+ }
+ }
+ if (S_ISREG(stp->st_mode) || stp->st_size != 0)
+ fsize = stp->st_size;
else
fsize = SIZE_UNKNOWN;
diff --git a/src/softmagic.c b/src/softmagic.c
index 7a1c818a..bb186516 100644
--- a/src/softmagic.c
+++ b/src/softmagic.c
@@ -1487,13 +1487,13 @@ msetoffset(struct magic_set *ms, struct magic *m, struct buffer *bb,
}
if (CAST(size_t, -m->offset) > b->elen)
return -1;
- buffer_init(bb, -1, b->ebuf, b->elen);
+ buffer_init(bb, -1, NULL, b->ebuf, b->elen);
ms->eoffset = ms->offset = CAST(int32_t, b->elen + m->offset);
} else {
if (cont_level == 0) {
normal:
// XXX: Pass real fd, then who frees bb?
- buffer_init(bb, -1, b->fbuf, b->flen);
+ buffer_init(bb, -1, NULL, b->fbuf, b->flen);
ms->offset = m->offset;
ms->eoffset = 0;
} else {
--
2.21.0
More information about the File
mailing list