diff options
Diffstat (limited to 'file/src/fsmagic.c')
-rw-r--r-- | file/src/fsmagic.c | 494 |
1 files changed, 212 insertions, 282 deletions
diff --git a/file/src/fsmagic.c b/file/src/fsmagic.c index c3654e883..18bdd60e3 100644 --- a/file/src/fsmagic.c +++ b/file/src/fsmagic.c @@ -1,215 +1,296 @@ /* + * Copyright (c) Ian F. Darwin 1986-1995. + * Software written by Ian F. Darwin and others; + * maintained 1995-present by Christos Zoulas and others. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice immediately at the beginning of the file, without modification, + * this list of conditions, and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Ian F. Darwin and others. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +/* * fsmagic - magic based on filesystem info - directory, special files, etc. - * - * Copyright (c) Ian F. Darwin, 1987. - * Written by Ian F. Darwin. - * - * This software is not subject to any license of the American Telephone - * and Telegraph Company or of the Regents of the University of California. - * - * Permission is granted to anyone to use this software for any purpose on - * any computer system, and to alter it and redistribute it freely, subject - * to the following restrictions: - * - * 1. The author is not responsible for the consequences of use of this - * software, no matter how awful, even if they arise from flaws in it. - * - * 2. The origin of this software must not be misrepresented, either by - * explicit claim or by omission. Since few users ever read sources, - * credits must appear in the documentation. - * - * 3. Altered versions must be plainly marked as such, and must not be - * misrepresented as being the original software. Since few users - * ever read sources, credits must appear in the documentation. - * - * 4. This notice may not be removed or altered. */ -#include "system.h" #include "file.h" -#include "debug.h" - -FILE_RCSID("@(#)Id: fsmagic.c,v 1.36 2002/07/03 19:00:41 christos Exp ") +#include "magic.h" +#include <string.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> +#include <sys/stat.h> +/* Since major is a function on SVR4, we cannot use `ifndef major'. */ +#ifdef MAJOR_IN_MKDEV +# include <sys/mkdev.h> +# define HAVE_MAJOR +#endif +#ifdef MAJOR_IN_SYSMACROS +# include <sys/sysmacros.h> +# define HAVE_MAJOR +#endif +#ifdef major /* Might be defined in sys/types.h. */ +# define HAVE_MAJOR +#endif + +#ifndef HAVE_MAJOR +# define major(dev) (((dev) >> 8) & 0xff) +# define minor(dev) ((dev) & 0xff) +#endif +#undef HAVE_MAJOR -/*@access fmagic @*/ +#ifndef lint +FILE_RCSID("@(#)$Id: fsmagic.c,v 1.43 2003/10/14 19:29:55 christos Exp $") +#endif /* lint */ -/*@-bounds@*/ -int -fmagicD(fmagic fm) +protected int +file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) { - const char * fn = fm->fn; - struct stat * st = &fm->sb; int ret = 0; - int xx; +#ifdef S_IFLNK + char buf[BUFSIZ+4]; + int nch; + struct stat tstatbuf; +#endif + + if (fn == NULL) + return 0; /* * Fstat is cheaper but fails for files you don't have read perms on. * On 4.2BSD and similar systems, use lstat() to identify symlinks. */ -#if defined(S_IFLNK) || defined(__LCLINT__) - if (!(fm->flags & FMAGIC_FLAGS_FOLLOW)) - ret = lstat(fn, st); +#ifdef S_IFLNK + if ((ms->flags & MAGIC_SYMLINK) == 0) + ret = lstat(fn, sb); else #endif - ret = stat(fn, st); /* don't merge into if; see "ret =" above */ + ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ if (ret) { - /* Yes, I do mean stdout. */ - /* No \n, caller will provide. */ - file_printf(fm, "can't stat `%s' (%s).", fn, strerror(errno)); + if (ms->flags & MAGIC_ERROR) { + file_error(ms, errno, "cannot stat `%s'", fn); + return -1; + } + if (file_printf(ms, "cannot open (%s)", + fn, strerror(errno)) == -1) + return -1; return 1; } - if ((fm->flags & FMAGIC_FLAGS_MIME)) { - if ((st->st_mode & S_IFMT) != S_IFREG) { - file_printf(fm, "application/x-not-regular-file"); + if ((ms->flags & MAGIC_MIME) != 0) { + if ((sb->st_mode & S_IFMT) != S_IFREG) { + if (file_printf(ms, "application/x-not-regular-file") + == -1) + return -1; return 1; } } else { -#if defined(S_ISUID) || defined(__LCLINT__) - if (st->st_mode & S_ISUID) file_printf(fm, "setuid "); +#ifdef S_ISUID + if (sb->st_mode & S_ISUID) + if (file_printf(ms, "setuid ") == -1) + return -1; #endif -#if defined(S_ISGID) || defined(__LCLINT__) - if (st->st_mode & S_ISGID) file_printf(fm, "setgid "); +#ifdef S_ISGID + if (sb->st_mode & S_ISGID) + if (file_printf(ms, "setgid ") == -1) + return -1; #endif -#if defined(S_ISVTX) || defined(__LCLINT__) - if (st->st_mode & S_ISVTX) file_printf(fm, "sticky "); +#ifdef S_ISVTX + if (sb->st_mode & S_ISVTX) + if (file_printf(ms, "sticky ") == -1) + return -1; #endif } - switch (st->st_mode & S_IFMT) { + switch (sb->st_mode & S_IFMT) { case S_IFDIR: - file_printf(fm, "directory"); + if (file_printf(ms, "directory") == -1) + return -1; return 1; -#if defined(S_IFCHR) || defined(__LCLINT__) +#ifdef S_IFCHR case S_IFCHR: /* * If -s has been specified, treat character special files * like ordinary files. Otherwise, just report that they * are block special files and go on to the next file. */ - if ((fm->flags & FMAGIC_FLAGS_SPECIAL)) + if ((ms->flags & MAGIC_DEVICES) != 0) break; -#ifdef HAVE_STRUCT_STAT_ST_RDEV +#ifdef HAVE_ST_RDEV # ifdef dv_unit - file_printf(fm, "character special (%d/%d/%d)", - major(st->st_rdev), - dv_unit(st->st_rdev), - dv_subunit(st->st_rdev)); + if (file_printf(ms, "character special (%d/%d/%d)", + major(sb->st_rdev), dv_unit(sb->st_rdev), + dv_subunit(sb->st_rdev)) == -1) + return -1; # else -/*@-shiftimplementation@*/ - file_printf(fm, "character special (%ld/%ld)", - (long) major(st->st_rdev), (long) minor(st->st_rdev)); -/*@=shiftimplementation@*/ + if (file_printf(ms, "character special (%ld/%ld)", + (long) major(sb->st_rdev), (long) minor(sb->st_rdev)) == -1) + return -1; # endif #else - file_printf(fm, "character special"); + if (file_printf(ms, "character special") == -1) + return -1; #endif return 1; #endif -#if defined(S_IFBLK) || defined(__LCLINT__) +#ifdef S_IFBLK case S_IFBLK: /* * If -s has been specified, treat block special files * like ordinary files. Otherwise, just report that they * are block special files and go on to the next file. */ - if ((fm->flags & FMAGIC_FLAGS_SPECIAL)) + if ((ms->flags & MAGIC_DEVICES) != 0) break; -#ifdef HAVE_STRUCT_STAT_ST_RDEV +#ifdef HAVE_ST_RDEV # ifdef dv_unit - file_printf(fm, "block special (%d/%d/%d)", - major(st->st_rdev), - dv_unit(st->st_rdev), - dv_subunit(st->st_rdev)); + if (file_printf(ms, "block special (%d/%d/%d)", + major(sb->st_rdev), dv_unit(sb->st_rdev), + dv_subunit(sb->st_rdev)) == -1) + return -1; # else -/*@-shiftimplementation@*/ - file_printf(fm, "block special (%ld/%ld)", - (long) major(st->st_rdev), (long) minor(st->st_rdev)); -/*@=shiftimplementation@*/ + if (file_printf(ms, "block special (%ld/%ld)", + (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1) + return -1; # endif #else - file_printf(fm, "block special"); + if (file_printf(ms, "block special") == -1) + return -1; #endif return 1; #endif /* TODO add code to handle V7 MUX and Blit MUX files */ -#if defined(S_IFIFO) || defined(__LCLINT__) +#ifdef S_IFIFO case S_IFIFO: - file_printf(fm, "fifo (named pipe)"); + if (file_printf(ms, "fifo (named pipe)") == -1) + return -1; return 1; #endif -#if defined(S_IFDOOR) +#ifdef S_IFDOOR case S_IFDOOR: - file_printf(fm, "door"); + if (file_printf(ms, "door") == -1) + return -1; return 1; #endif -#if defined(S_IFLNK) || defined(__LCLINT__) +#ifdef S_IFLNK case S_IFLNK: - { - char buf[BUFSIZ+4]; - int nch; - struct stat tstatbuf; - - buf[0] = '\0'; - if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { - file_printf(fm, "unreadable symlink (%s).", strerror(errno)); - return 1; + if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { + if (ms->flags & MAGIC_ERROR) { + file_error(ms, errno, "unreadable symlink `%s'", + fn); + return -1; } - buf[nch] = '\0'; /* readlink(2) needs this */ + if (file_printf(ms, + "unreadable symlink `%s' (%s)", fn, + strerror(errno)) == -1) + return -1; + return 1; + } + buf[nch] = '\0'; /* readlink(2) forgets this */ - /* If broken symlink, say so and quit early. */ -/*@-branchstate@*/ - if (*buf == '/') { - if (stat(buf, &tstatbuf) < 0) { - file_printf(fm, "broken symbolic link to %s", buf); - return 1; - } - } - else { - char *tmp; - char buf2[BUFSIZ+BUFSIZ+4]; + /* If broken symlink, say so and quit early. */ + if (*buf == '/') { + if (stat(buf, &tstatbuf) < 0) { + if (ms->flags & MAGIC_ERROR) { + file_error(ms, errno, + "broken symbolic link to `%s'", buf); + return -1; + } + if (file_printf(ms, "broken symbolic link to `%s'", + buf) == -1) + return -1; + return 1; + } + } + else { + char *tmp; + char buf2[BUFSIZ+BUFSIZ+4]; - if ((tmp = strrchr(fn, '/')) == NULL) { + if ((tmp = strrchr(fn, '/')) == NULL) { tmp = buf; /* in current directory anyway */ - } - else { - strcpy (buf2, fn); /* take directory part */ - buf2[tmp-fn+1] = '\0'; - strcat (buf2, buf); /* plus (relative) symlink */ + } else { + if (tmp - fn + 1 > BUFSIZ) { + if (ms->flags & MAGIC_ERROR) { + file_error(ms, 0, + "path too long: `%s'", buf); + return -1; + } + if (file_printf(ms, + "path too long: `%s'", fn) == -1) + return -1; + return 1; + } + (void)strcpy(buf2, fn); /* take dir part */ + buf2[tmp - fn + 1] = '\0'; + (void)strcat(buf2, buf); /* plus (rel) link */ tmp = buf2; - } - if (stat(tmp, &tstatbuf) < 0) { - file_printf(fm, "broken symbolic link to %s", buf); - return 1; - } - } -/*@=branchstate@*/ - - /* Otherwise, handle it. */ - if ((fm->flags & FMAGIC_FLAGS_FOLLOW)) { - file_printf(fm, "\n"); - xx = fmagicProcess(fm, buf, strlen(buf)); + } + if (stat(tmp, &tstatbuf) < 0) { + if (ms->flags & MAGIC_ERROR) { + file_error(ms, errno, + "broken symbolic link to `%s'", + buf); + return -1; + } + if (file_printf(ms, + "broken symbolic link to `%s'", buf) == -1) + return -1; return 1; - } else { /* just print what it points to */ - file_printf(fm, "symbolic link to %s", buf); } } - return 1; + + /* Otherwise, handle it. */ + if ((ms->flags & MAGIC_SYMLINK) != 0) { + const char *p; + ms->flags &= MAGIC_SYMLINK; + p = magic_file(ms, buf); + ms->flags |= MAGIC_SYMLINK; + return p != NULL ? 1 : -1; + } else { /* just print what it points to */ + if (file_printf(ms, "symbolic link to `%s'", + buf) == -1) + return -1; + } + return 1; #endif -#if defined(S_IFSOCK) +#ifdef S_IFSOCK #ifndef __COHERENT__ case S_IFSOCK: - file_printf(fm, "socket"); + if (file_printf(ms, "socket") == -1) + return -1; return 1; #endif #endif case S_IFREG: break; default: - error(EXIT_FAILURE, 0, "invalid mode 0%o.\n", st->st_mode); - /*@notreached@*/ + file_error(ms, 0, "invalid mode 0%o", sb->st_mode); + return -1; + /*NOTREACHED*/ } /* @@ -224,162 +305,11 @@ fmagicD(fmagic fm) * the fact that it is empty will be detected and reported correctly * when we read the file.) */ - if (!(fm->flags & FMAGIC_FLAGS_SPECIAL) && st->st_size == 0) { - file_printf(fm, ((fm->flags & FMAGIC_FLAGS_MIME) - ? "application/x-empty" : "empty")); + if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) { + if (file_printf(ms, (ms->flags & MAGIC_MIME) ? + "application/x-empty" : "empty") == -1) + return -1; return 1; } return 0; } -/*@=bounds@*/ - -int -fmagicF(fmagic fm, int zfl) -{ - /* - * The main work is done here! - * We have the file name and/or the data buffer to be identified. - */ - -#ifdef __EMX__ - /* - * Ok, here's the right place to add a call to some os-specific - * routine, e.g. - */ - if (os2_apptype(fn, buf, nb) == 1) - return 'o'; -#endif - /* try compression stuff */ - if (zfl && fmagicZ(fm)) - return 'z'; - - /* try tests in /etc/magic (or surrogate magic file) */ - if (fmagicS(fm)) - return 's'; - - /* try known keywords, check whether it is ASCII */ - if (fmagicA(fm)) - return 'a'; - - /* abandon hope, all ye who remain here */ - file_printf(fm, ((fm->flags & FMAGIC_FLAGS_MIME) - ? "application/octet-stream" : "data")); - return '\0'; -} - -/* - * fmagicProcess - process input file - */ -/*@-bounds@*/ -int -fmagicProcess(fmagic fm, const char *fn, int wid) -{ - static const char stdname[] = "standard input"; - char match = '\0'; - int ret = 0; - -/*@-assignexpose -temptrans @*/ - fm->fn = fn; -/*@=assignexpose =temptrans @*/ - fm->buf = xmalloc(HOWMANY+1); - fm->buf[0] = '\0'; - fm->nb = 0; - -/*@-branchstate@*/ - if (strcmp("-", fn) == 0) { - if (fstat(0, &fm->sb)<0) { - error(EXIT_FAILURE, 0, "cannot fstat `%s' (%s).\n", stdname, - strerror(errno)); - /*@notreached@*/ - } - fm->fn = stdname; - } -/*@=branchstate@*/ - - if (wid > 0 && !(fm->flags & FMAGIC_FLAGS_BRIEF)) - file_printf(fm, "%s%s%*s ", fm->fn, fm->separator, - (int) ((fm->flags & FMAGIC_FLAGS_NOPAD) ? 0 : (wid - strlen(fm->fn))), ""); - - if (fm->fn != stdname) { - /* - * first try judging the file based on its filesystem status - */ - if (fmagicD(fm) != 0) - goto exit; - - if ((fm->fd = open(fm->fn, O_RDONLY)) < 0) { - /* We can't open it, but we were able to stat it. */ - if (fm->sb.st_mode & 0002) - file_printf(fm, "writeable, "); - if (fm->sb.st_mode & 0111) - file_printf(fm, "executable, "); - file_printf(fm, "can't read `%s' (%s).", fm->fn, strerror(errno)); - goto exit; - } - } - - - /* - * try looking at the first HOWMANY bytes - */ - if ((fm->nb = read(fm->fd, (char *)fm->buf, HOWMANY)) == -1) { - error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno)); - /*@notreached@*/ - } - - if (fm->nb == 0) - file_printf(fm, ((fm->flags & FMAGIC_FLAGS_MIME) - ? "application/x-empty" : "empty"), fm); - else { - fm->buf[fm->nb++] = '\0'; /* null-terminate data buffer */ - match = fmagicF(fm, (fm->flags & FMAGIC_FLAGS_UNCOMPRESS)); - } - -#ifdef BUILTIN_ELF - if (match == 's' && fm->nb > 5) { - /* - * We matched something in the file, so this *might* - * be an ELF file, and the file is at least 5 bytes long, - * so if it's an ELF file it has at least one byte - * past the ELF magic number - try extracting information - * from the ELF headers that can't easily be extracted - * with rules in the magic file. - */ - fmagicE(fm); - } -#endif - - if (fm->fn != stdname) { -#ifdef RESTORE_TIME - /* - * Try to restore access, modification times if read it. - * This is really *bad* because it will modify the status - * time of the file... And of course this will affect - * backup programs - */ -# ifdef USE_UTIMES - struct timeval utsbuf[2]; - utsbuf[0].tv_sec = fm->sb.st_atime; - utsbuf[1].tv_sec = fm->sb.st_mtime; - - (void) utimes(fm->fn, utsbuf); /* don't care if loses */ -# else - struct utimbuf utbuf; - - utbuf.actime = fm->sb.st_atime; - utbuf.modtime = fm->sb.st_mtime; - (void) utime(fm->fn, &utbuf); /* don't care if loses */ -# endif -#endif - (void) close(fm->fd); - fm->fd = -1; - } - -exit: - if (fm->buf != NULL) - free(fm->buf); - fm->buf = NULL; - fm->nb = 0; - return ret; -} -/*@=bounds@*/ |