[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