From 190362ab37c6b6c2bdb331df430aea23a3734591 Mon Sep 17 00:00:00 2001 From: Christos Zoulas Date: Tue, 7 May 2019 02:27:11 +0000 Subject: [PATCH] From: Denys Vlasenko Reduce amount of stat(2) calls when processing elf files; propagate fstat result deeper into callees. --- src/ascmagic.c | 4 ++-- src/buffer.c | 9 ++++++--- src/compress.c | 6 +++--- src/file.h | 9 +++++---- src/funcs.c | 7 ++++--- src/magic.c | 13 ++++++++----- src/readelf.c | 24 +++++++++++++++++++----- src/softmagic.c | 6 +++--- 8 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/ascmagic.c b/src/ascmagic.c index ea69f784..624ac90b 100644 --- a/src/ascmagic.c +++ b/src/ascmagic.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: ascmagic.c,v 1.103 2019/05/06 21:23:38 christos Exp $") +FILE_RCSID("@(#)$File: ascmagic.c,v 1.104 2019/05/07 02:27:11 christos Exp $") #endif /* lint */ #include "magic.h" @@ -151,7 +151,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..6d8967d2 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: buffer.c,v 1.5 2019/02/20 02:35:27 christos Exp $") +FILE_RCSID("@(#)$File: buffer.c,v 1.6 2019/05/07 02:27:11 christos Exp $") #endif /* lint */ #include "magic.h" @@ -37,10 +37,13 @@ FILE_RCSID("@(#)$File: buffer.c,v 1.5 2019/02/20 02:35:27 christos Exp $") #include 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 6ae0c59d..95e42a24 100644 --- a/src/compress.c +++ b/src/compress.c @@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: compress.c,v 1.120 2019/05/07 02:20:27 christos Exp $") +FILE_RCSID("@(#)$File: compress.c,v 1.121 2019/05/07 02:27:11 christos Exp $") #endif #include "magic.h" @@ -267,7 +267,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; @@ -284,7 +284,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 d96be4f9..69a586ab 100644 --- a/src/file.h +++ b/src/file.h @@ -27,7 +27,7 @@ */ /* * file.h - definitions for file(1) program - * @(#)$File: file.h,v 1.205 2019/05/06 21:22:13 christos Exp $ + * @(#)$File: file.h,v 1.206 2019/05/07 02:27:11 christos Exp $ */ #ifndef __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) @@ -513,7 +513,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 0fc53ad7..23e7f32e 100644 --- a/src/funcs.c +++ b/src/funcs.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: funcs.c,v 1.103 2019/05/06 21:22:13 christos Exp $") +FILE_RCSID("@(#)$File: funcs.c,v 1.104 2019/05/07 02:27:11 christos Exp $") #endif /* lint */ #include "magic.h" @@ -207,7 +207,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; @@ -218,7 +219,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..da5baf10 100644 --- a/src/magic.c +++ b/src/magic.c @@ -33,7 +33,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: magic.c,v 1.110 2019/04/15 16:49:29 christos Exp $") +FILE_RCSID("@(#)$File: magic.c,v 1.111 2019/05/07 02:27:11 christos Exp $") #endif /* lint */ #include "magic.h" @@ -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..ef61d4cd 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -27,7 +27,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: readelf.c,v 1.164 2019/04/15 16:49:53 christos Exp $") +FILE_RCSID("@(#)$File: readelf.c,v 1.165 2019/05/07 02:27:11 christos Exp $") #endif #ifdef BUILTIN_ELF @@ -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 542f6c5a..e1495a4a 100644 --- a/src/softmagic.c +++ b/src/softmagic.c @@ -32,7 +32,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: softmagic.c,v 1.283 2019/05/06 21:22:40 christos Exp $") +FILE_RCSID("@(#)$File: softmagic.c,v 1.284 2019/05/07 02:27:11 christos Exp $") #endif /* lint */ #include "magic.h" @@ -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.40.0