file/src/fsmagic.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) Ian F. Darwin 1986-1995.
00003  * Software written by Ian F. Darwin and others;
00004  * maintained 1995-present by Christos Zoulas and others.
00005  * 
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice immediately at the beginning of the file, without modification,
00011  *    this list of conditions, and the following disclaimer.
00012  * 2. Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in the
00014  *    documentation and/or other materials provided with the distribution.
00015  *  
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
00017  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00018  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00019  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
00020  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00021  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00022  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00023  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00024  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00025  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00026  * SUCH DAMAGE.
00027  */
00028 /*
00029  * fsmagic - magic based on filesystem info - directory, special files, etc.
00030  */
00031 
00032 #include "file.h"
00033 #include "magic.h"
00034 #include <string.h>
00035 #ifdef HAVE_UNISTD_H
00036 #include <unistd.h>
00037 #endif
00038 #include <stdlib.h>
00039 #include <sys/stat.h>
00040 /* Since major is a function on SVR4, we cannot use `ifndef major'.  */
00041 #ifdef MAJOR_IN_MKDEV
00042 # include <sys/mkdev.h>
00043 # define HAVE_MAJOR
00044 #endif
00045 #ifdef MAJOR_IN_SYSMACROS
00046 # include <sys/sysmacros.h>
00047 # define HAVE_MAJOR
00048 #endif
00049 #ifdef major                    /* Might be defined in sys/types.h.  */
00050 # define HAVE_MAJOR
00051 #endif
00052   
00053 #ifndef HAVE_MAJOR
00054 # define major(dev)  (((dev) >> 8) & 0xff)
00055 # define minor(dev)  ((dev) & 0xff)
00056 #endif
00057 #undef HAVE_MAJOR
00058 
00059 #ifndef lint
00060 FILE_RCSID("@(#)$Id: fsmagic.c,v 1.46 2005/06/25 15:52:14 christos Exp $")
00061 #endif  /* lint */
00062 
00063 protected int
00064 file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
00065 {
00066         int ret = 0;
00067 #ifdef  S_IFLNK
00068         char buf[BUFSIZ+4];
00069         int nch;
00070         struct stat tstatbuf;
00071 #endif
00072 
00073         if (fn == NULL)
00074                 return 0;
00075 
00076         /*
00077          * Fstat is cheaper but fails for files you don't have read perms on.
00078          * On 4.2BSD and similar systems, use lstat() to identify symlinks.
00079          */
00080 #ifdef  S_IFLNK
00081         if ((ms->flags & MAGIC_SYMLINK) == 0)
00082                 ret = lstat(fn, sb);
00083         else
00084 #endif
00085         ret = stat(fn, sb);     /* don't merge into if; see "ret =" above */
00086 
00087         if (ret) {
00088                 if (ms->flags & MAGIC_ERROR) {
00089                         file_error(ms, errno, "cannot stat `%s'", fn);
00090                         return -1;
00091                 }
00092                 if (file_printf(ms, "cannot open `%s' (%s)",
00093                     fn, strerror(errno)) == -1)
00094                         return -1;
00095                 ms->haderr++;
00096                 return -1;
00097         }
00098 
00099         if ((ms->flags & MAGIC_MIME) != 0) {
00100                 if ((sb->st_mode & S_IFMT) != S_IFREG) {
00101                         if (file_printf(ms, "application/x-not-regular-file")
00102                             == -1)
00103                                 return -1;
00104                         return 1;
00105                 }
00106         }
00107         else {
00108 #ifdef S_ISUID
00109                 if (sb->st_mode & S_ISUID) 
00110                         if (file_printf(ms, "setuid ") == -1)
00111                                 return -1;
00112 #endif
00113 #ifdef S_ISGID
00114                 if (sb->st_mode & S_ISGID) 
00115                         if (file_printf(ms, "setgid ") == -1)
00116                                 return -1;
00117 #endif
00118 #ifdef S_ISVTX
00119                 if (sb->st_mode & S_ISVTX) 
00120                         if (file_printf(ms, "sticky ") == -1)
00121                                 return -1;
00122 #endif
00123         }
00124         
00125         switch (sb->st_mode & S_IFMT) {
00126         case S_IFDIR:
00127                 if (file_printf(ms, "directory") == -1)
00128                         return -1;
00129                 return 1;
00130 #ifdef S_IFCHR
00131         case S_IFCHR:
00132                 /* 
00133                  * If -s has been specified, treat character special files
00134                  * like ordinary files.  Otherwise, just report that they
00135                  * are block special files and go on to the next file.
00136                  */
00137                 if ((ms->flags & MAGIC_DEVICES) != 0)
00138                         break;
00139 #ifdef HAVE_ST_RDEV
00140 # ifdef dv_unit
00141                 if (file_printf(ms, "character special (%d/%d/%d)",
00142                     major(sb->st_rdev), dv_unit(sb->st_rdev),
00143                     dv_subunit(sb->st_rdev)) == -1)
00144                         return -1;
00145 # else
00146                 if (file_printf(ms, "character special (%ld/%ld)",
00147                     (long) major(sb->st_rdev), (long) minor(sb->st_rdev)) == -1)
00148                         return -1;
00149 # endif
00150 #else
00151                 if (file_printf(ms, "character special") == -1)
00152                         return -1;
00153 #endif
00154                 return 1;
00155 #endif
00156 #ifdef S_IFBLK
00157         case S_IFBLK:
00158                 /* 
00159                  * If -s has been specified, treat block special files
00160                  * like ordinary files.  Otherwise, just report that they
00161                  * are block special files and go on to the next file.
00162                  */
00163                 if ((ms->flags & MAGIC_DEVICES) != 0)
00164                         break;
00165 #ifdef HAVE_ST_RDEV
00166 # ifdef dv_unit
00167                 if (file_printf(ms, "block special (%d/%d/%d)",
00168                     major(sb->st_rdev), dv_unit(sb->st_rdev),
00169                     dv_subunit(sb->st_rdev)) == -1)
00170                         return -1;
00171 # else
00172                 if (file_printf(ms, "block special (%ld/%ld)",
00173                     (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1)
00174                         return -1;
00175 # endif
00176 #else
00177                 if (file_printf(ms, "block special") == -1)
00178                         return -1;
00179 #endif
00180                 return 1;
00181 #endif
00182         /* TODO add code to handle V7 MUX and Blit MUX files */
00183 #ifdef  S_IFIFO
00184         case S_IFIFO:
00185                 if((ms->flags & MAGIC_DEVICES) != 0)
00186                         break;
00187                 if (file_printf(ms, "fifo (named pipe)") == -1)
00188                         return -1;
00189                 return 1;
00190 #endif
00191 #ifdef  S_IFDOOR
00192         case S_IFDOOR:
00193                 if (file_printf(ms, "door") == -1)
00194                         return -1;
00195                 return 1;
00196 #endif
00197 #ifdef  S_IFLNK
00198         case S_IFLNK:
00199                 if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
00200                         if (ms->flags & MAGIC_ERROR) {
00201                             file_error(ms, errno, "unreadable symlink `%s'",
00202                                 fn);
00203                             return -1;
00204                         }
00205                         if (file_printf(ms,
00206                             "unreadable symlink `%s' (%s)", fn,
00207                             strerror(errno)) == -1)
00208                                 return -1;
00209                         return 1;
00210                 }
00211                 buf[nch] = '\0';        /* readlink(2) forgets this */
00212 
00213                 /* If broken symlink, say so and quit early. */
00214                 if (*buf == '/') {
00215                     if (stat(buf, &tstatbuf) < 0) {
00216                             if (ms->flags & MAGIC_ERROR) {
00217                                     file_error(ms, errno, 
00218                                         "broken symbolic link to `%s'", buf);
00219                                     return -1;
00220                             } 
00221                             if (file_printf(ms, "broken symbolic link to `%s'",
00222                                 buf) == -1)
00223                                     return -1;
00224                             return 1;
00225                     }
00226                 }
00227                 else {
00228                         char *tmp;
00229                         char buf2[BUFSIZ+BUFSIZ+4];
00230 
00231                         if ((tmp = strrchr(fn,  '/')) == NULL) {
00232                                 tmp = buf; /* in current directory anyway */
00233                         } else {
00234                                 if (tmp - fn + 1 > BUFSIZ) {
00235                                         if (ms->flags & MAGIC_ERROR) {
00236                                                 file_error(ms, 0, 
00237                                                     "path too long: `%s'", buf);
00238                                                 return -1;
00239                                         }
00240                                         if (file_printf(ms,
00241                                             "path too long: `%s'", fn) == -1)
00242                                                 return -1;
00243                                         return 1;
00244                                 }
00245                                 (void)strcpy(buf2, fn);  /* take dir part */
00246                                 buf2[tmp - fn + 1] = '\0';
00247                                 (void)strcat(buf2, buf); /* plus (rel) link */
00248                                 tmp = buf2;
00249                         }
00250                         if (stat(tmp, &tstatbuf) < 0) {
00251                                 if (ms->flags & MAGIC_ERROR) {
00252                                         file_error(ms, errno, 
00253                                             "broken symbolic link to `%s'",
00254                                             buf);
00255                                         return -1;
00256                                 }
00257                                 if (file_printf(ms,
00258                                     "broken symbolic link to `%s'", buf) == -1)
00259                                         return -1;
00260                                 return 1;
00261                         }
00262                 }
00263 
00264                 /* Otherwise, handle it. */
00265                 if ((ms->flags & MAGIC_SYMLINK) != 0) {
00266                         const char *p;
00267                         ms->flags &= MAGIC_SYMLINK;
00268                         p = magic_file(ms, buf);
00269                         ms->flags |= MAGIC_SYMLINK;
00270                         return p != NULL ? 1 : -1;
00271                 } else { /* just print what it points to */
00272                         if (file_printf(ms, "symbolic link to `%s'",
00273                             buf) == -1)
00274                                 return -1;
00275                 }
00276         return 1;
00277 #endif
00278 #ifdef  S_IFSOCK
00279 #ifndef __COHERENT__
00280         case S_IFSOCK:
00281                 if (file_printf(ms, "socket") == -1)
00282                         return -1;
00283                 return 1;
00284 #endif
00285 #endif
00286         case S_IFREG:
00287                 break;
00288         default:
00289                 file_error(ms, 0, "invalid mode 0%o", sb->st_mode);
00290                 return -1;
00291                 /*@notreached@*/ break;
00292         }
00293 
00294         /*
00295          * regular file, check next possibility
00296          *
00297          * If stat() tells us the file has zero length, report here that
00298          * the file is empty, so we can skip all the work of opening and 
00299          * reading the file.
00300          * But if the -s option has been given, we skip this optimization,
00301          * since on some systems, stat() reports zero size for raw disk
00302          * partitions.  (If the block special device really has zero length,
00303          * the fact that it is empty will be detected and reported correctly
00304          * when we read the file.)
00305          */
00306         if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) {
00307                 if (file_printf(ms, (ms->flags & MAGIC_MIME) ?
00308                     "application/x-empty" : "empty") == -1)
00309                         return -1;
00310                 return 1;
00311         }
00312         return 0;
00313 }

Generated on Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2