Main Page   Modules   Data Structures   File List   Data Fields   Globals   Related Pages  

file/fsmagic.c

Go to the documentation of this file.
00001 /*
00002  * fsmagic - magic based on filesystem info - directory, special files, etc.
00003  *
00004  * Copyright (c) Ian F. Darwin, 1987.
00005  * Written by Ian F. Darwin.
00006  *
00007  * This software is not subject to any license of the American Telephone
00008  * and Telegraph Company or of the Regents of the University of California.
00009  *
00010  * Permission is granted to anyone to use this software for any purpose on
00011  * any computer system, and to alter it and redistribute it freely, subject
00012  * to the following restrictions:
00013  *
00014  * 1. The author is not responsible for the consequences of use of this
00015  *    software, no matter how awful, even if they arise from flaws in it.
00016  *
00017  * 2. The origin of this software must not be misrepresented, either by
00018  *    explicit claim or by omission.  Since few users ever read sources,
00019  *    credits must appear in the documentation.
00020  *
00021  * 3. Altered versions must be plainly marked as such, and must not be
00022  *    misrepresented as being the original software.  Since few users
00023  *    ever read sources, credits must appear in the documentation.
00024  *
00025  * 4. This notice may not be removed or altered.
00026  */
00027 
00028 #include "system.h"
00029 #include "file.h"
00030 #include "debug.h"
00031 
00032 FILE_RCSID("@(#)Id: fsmagic.c,v 1.36 2002/07/03 19:00:41 christos Exp ")
00033 
00034 /*@access fmagic @*/
00035 
00036 /*@-bounds@*/
00037 int
00038 fmagicD(fmagic fm)
00039 {
00040         const char * fn = fm->fn;
00041         struct stat * st = &fm->sb;
00042         int ret = 0;
00043         int xx;
00044 
00045         /*
00046          * Fstat is cheaper but fails for files you don't have read perms on.
00047          * On 4.2BSD and similar systems, use lstat() to identify symlinks.
00048          */
00049 #if defined(S_IFLNK) || defined(__LCLINT__)
00050         if (!(fm->flags & FMAGIC_FLAGS_FOLLOW))
00051                 ret = lstat(fn, st);
00052         else
00053 #endif
00054         ret = stat(fn, st);     /* don't merge into if; see "ret =" above */
00055 
00056         if (ret) {
00057                 /* Yes, I do mean stdout. */
00058                 /* No \n, caller will provide. */
00059                 fmagicPrintf(fm, "can't stat `%s' (%s).", fn, strerror(errno));
00060                 return 1;
00061         }
00062 
00063         if ((fm->flags & FMAGIC_FLAGS_MIME)) {
00064                 if ((st->st_mode & S_IFMT) != S_IFREG) {
00065                         fmagicPrintf(fm, "application/x-not-regular-file");
00066                         return 1;
00067                 }
00068         }
00069         else {
00070 #if defined(S_ISUID) || defined(__LCLINT__)
00071                 if (st->st_mode & S_ISUID) fmagicPrintf(fm, "setuid ");
00072 #endif
00073 #if defined(S_ISGID) || defined(__LCLINT__)
00074                 if (st->st_mode & S_ISGID) fmagicPrintf(fm, "setgid ");
00075 #endif
00076 #if defined(S_ISVTX) || defined(__LCLINT__)
00077                 if (st->st_mode & S_ISVTX) fmagicPrintf(fm, "sticky ");
00078 #endif
00079         }
00080         
00081         switch (st->st_mode & S_IFMT) {
00082         case S_IFDIR:
00083                 fmagicPrintf(fm, "directory");
00084                 return 1;
00085 #if defined(S_IFCHR) || defined(__LCLINT__)
00086         case S_IFCHR:
00087                 /* 
00088                  * If -s has been specified, treat character special files
00089                  * like ordinary files.  Otherwise, just report that they
00090                  * are block special files and go on to the next file.
00091                  */
00092                 if ((fm->flags & FMAGIC_FLAGS_SPECIAL))
00093                         break;
00094 #ifdef HAVE_STRUCT_STAT_ST_RDEV
00095 # ifdef dv_unit
00096                 fmagicPrintf(fm, "character special (%d/%d/%d)",
00097                         major(st->st_rdev),
00098                         dv_unit(st->st_rdev),
00099                         dv_subunit(st->st_rdev));
00100 # else
00101 /*@-shiftimplementation@*/
00102                 fmagicPrintf(fm, "character special (%ld/%ld)",
00103                         (long) major(st->st_rdev), (long) minor(st->st_rdev));
00104 /*@=shiftimplementation@*/
00105 # endif
00106 #else
00107                 fmagicPrintf(fm, "character special");
00108 #endif
00109                 return 1;
00110 #endif
00111 #if defined(S_IFBLK) || defined(__LCLINT__)
00112         case S_IFBLK:
00113                 /* 
00114                  * If -s has been specified, treat block special files
00115                  * like ordinary files.  Otherwise, just report that they
00116                  * are block special files and go on to the next file.
00117                  */
00118                 if ((fm->flags & FMAGIC_FLAGS_SPECIAL))
00119                         break;
00120 #ifdef HAVE_STRUCT_STAT_ST_RDEV
00121 # ifdef dv_unit
00122                 fmagicPrintf(fm, "block special (%d/%d/%d)",
00123                         major(st->st_rdev),
00124                         dv_unit(st->st_rdev),
00125                         dv_subunit(st->st_rdev));
00126 # else
00127 /*@-shiftimplementation@*/
00128                 fmagicPrintf(fm, "block special (%ld/%ld)",
00129                         (long) major(st->st_rdev), (long) minor(st->st_rdev));
00130 /*@=shiftimplementation@*/
00131 # endif
00132 #else
00133                 fmagicPrintf(fm, "block special");
00134 #endif
00135                 return 1;
00136 #endif
00137         /* TODO add code to handle V7 MUX and Blit MUX files */
00138 #if defined(S_IFIFO) || defined(__LCLINT__)
00139         case S_IFIFO:
00140                 fmagicPrintf(fm, "fifo (named pipe)");
00141                 return 1;
00142 #endif
00143 #if defined(S_IFDOOR)
00144         case S_IFDOOR:
00145                 fmagicPrintf(fm, "door");
00146                 return 1;
00147 #endif
00148 #if defined(S_IFLNK) || defined(__LCLINT__)
00149         case S_IFLNK:
00150                 {
00151                         char buf[BUFSIZ+4];
00152                         int nch;
00153                         struct stat tstatbuf;
00154 
00155                         buf[0] = '\0';
00156                         if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
00157                                 fmagicPrintf(fm, "unreadable symlink (%s).", strerror(errno));
00158                                 return 1;
00159                         }
00160                         buf[nch] = '\0';        /* readlink(2) needs this */
00161 
00162                         /* If broken symlink, say so and quit early. */
00163 /*@-branchstate@*/
00164                         if (*buf == '/') {
00165                             if (stat(buf, &tstatbuf) < 0) {
00166                                 fmagicPrintf(fm, "broken symbolic link to %s", buf);
00167                                 return 1;
00168                             }
00169                         }
00170                         else {
00171                             char *tmp;
00172                             char buf2[BUFSIZ+BUFSIZ+4];
00173 
00174                             if ((tmp = strrchr(fn,  '/')) == NULL) {
00175                                 tmp = buf; /* in current directory anyway */
00176                             }
00177                             else {
00178                                 strcpy (buf2, fn);  /* take directory part */
00179                                 buf2[tmp-fn+1] = '\0';
00180                                 strcat (buf2, buf); /* plus (relative) symlink */
00181                                 tmp = buf2;
00182                             }
00183                             if (stat(tmp, &tstatbuf) < 0) {
00184                                 fmagicPrintf(fm, "broken symbolic link to %s", buf);
00185                                 return 1;
00186                             }
00187                         }
00188 /*@=branchstate@*/
00189 
00190                         /* Otherwise, handle it. */
00191                         if ((fm->flags & FMAGIC_FLAGS_FOLLOW)) {
00192                                 fmagicPrintf(fm, "\n");
00193                                 xx = fmagicProcess(fm, buf, strlen(buf));
00194                                 return 1;
00195                         } else { /* just print what it points to */
00196                                 fmagicPrintf(fm, "symbolic link to %s", buf);
00197                         }
00198                 }
00199                 return 1;
00200 #endif
00201 #if defined(S_IFSOCK)
00202 #ifndef __COHERENT__
00203         case S_IFSOCK:
00204                 fmagicPrintf(fm, "socket");
00205                 return 1;
00206 #endif
00207 #endif
00208         case S_IFREG:
00209                 break;
00210         default:
00211                 error(EXIT_FAILURE, 0, "invalid mode 0%o.\n", st->st_mode);
00212                 /*@notreached@*/
00213         }
00214 
00215         /*
00216          * regular file, check next possibility
00217          *
00218          * If stat() tells us the file has zero length, report here that
00219          * the file is empty, so we can skip all the work of opening and 
00220          * reading the file.
00221          * But if the -s option has been given, we skip this optimization,
00222          * since on some systems, stat() reports zero size for raw disk
00223          * partitions.  (If the block special device really has zero length,
00224          * the fact that it is empty will be detected and reported correctly
00225          * when we read the file.)
00226          */
00227         if (!(fm->flags & FMAGIC_FLAGS_SPECIAL) && st->st_size == 0) {
00228                 fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
00229                         ? "application/x-empty" : "empty"));
00230                 return 1;
00231         }
00232         return 0;
00233 }
00234 /*@=bounds@*/
00235 
00236 int
00237 fmagicF(fmagic fm, int zfl)
00238 {
00239         /*
00240          * The main work is done here!
00241          * We have the file name and/or the data buffer to be identified. 
00242          */
00243 
00244 #ifdef __EMX__
00245         /*
00246          * Ok, here's the right place to add a call to some os-specific
00247          * routine, e.g.
00248          */
00249         if (os2_apptype(fn, buf, nb) == 1)
00250                return 'o';
00251 #endif
00252         /* try compression stuff */
00253         if (zfl && fmagicZ(fm))
00254                 return 'z';
00255 
00256         /* try tests in /etc/magic (or surrogate magic file) */
00257         if (fmagicS(fm))
00258                 return 's';
00259 
00260         /* try known keywords, check whether it is ASCII */
00261         if (fmagicA(fm))
00262                 return 'a';
00263 
00264         /* abandon hope, all ye who remain here */
00265         fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
00266                 ? "application/octet-stream" : "data"));
00267         return '\0';
00268 }
00269 
00270 /*
00271  * fmagicProcess - process input file
00272  */
00273 /*@-bounds@*/
00274 int
00275 fmagicProcess(fmagic fm, const char *fn, int wid)
00276 {
00277         static const char stdname[] = "standard input";
00278         char match = '\0';
00279         int ret = 0;
00280 
00281 /*@-assignexpose -temptrans @*/
00282         fm->fn = fn;
00283 /*@=assignexpose =temptrans @*/
00284         fm->buf = xmalloc(HOWMANY+1);
00285         fm->buf[0] = '\0';
00286         fm->nb = 0;
00287 
00288 /*@-branchstate@*/
00289         if (strcmp("-", fn) == 0) {
00290                 if (fstat(0, &fm->sb)<0) {
00291                         error(EXIT_FAILURE, 0, "cannot fstat `%s' (%s).\n", stdname,
00292                               strerror(errno));
00293                         /*@notreached@*/
00294                 }
00295                 fm->fn = stdname;
00296         }
00297 /*@=branchstate@*/
00298 
00299         if (wid > 0 && !(fm->flags & FMAGIC_FLAGS_BRIEF))
00300              fmagicPrintf(fm, "%s:%*s ", fm->fn, 
00301                            (int) (wid - strlen(fm->fn)), "");
00302 
00303         if (fm->fn != stdname) {
00304                 /*
00305                  * first try judging the file based on its filesystem status
00306                  */
00307                 if (fmagicD(fm) != 0)
00308                         goto exit;
00309 
00310                 if ((fm->fd = open(fm->fn, O_RDONLY)) < 0) {
00311                         /* We can't open it, but we were able to stat it. */
00312                         if (fm->sb.st_mode & 0002)
00313                                 fmagicPrintf(fm, "writeable, ");
00314                         if (fm->sb.st_mode & 0111)
00315                                 fmagicPrintf(fm, "executable, ");
00316                         fmagicPrintf(fm, "can't read `%s' (%s).", fm->fn, strerror(errno));
00317                         goto exit;
00318                 }
00319         }
00320 
00321 
00322         /*
00323          * try looking at the first HOWMANY bytes
00324          */
00325         if ((fm->nb = read(fm->fd, (char *)fm->buf, HOWMANY)) == -1) {
00326                 error(EXIT_FAILURE, 0, "read failed (%s).\n", strerror(errno));
00327                 /*@notreached@*/
00328         }
00329 
00330         if (fm->nb == 0)
00331                 fmagicPrintf(fm, ((fm->flags & FMAGIC_FLAGS_MIME)
00332                         ? "application/x-empty" : "empty"), fm);
00333         else {
00334                 fm->buf[fm->nb++] = '\0';       /* null-terminate data buffer */
00335                 match = fmagicF(fm, (fm->flags & FMAGIC_FLAGS_UNCOMPRESS));
00336         }
00337 
00338 #ifdef BUILTIN_ELF
00339         if (match == 's' && fm->nb > 5) {
00340                 /*
00341                  * We matched something in the file, so this *might*
00342                  * be an ELF file, and the file is at least 5 bytes long,
00343                  * so if it's an ELF file it has at least one byte
00344                  * past the ELF magic number - try extracting information
00345                  * from the ELF headers that can't easily be extracted
00346                  * with rules in the magic file.
00347                  */
00348                 fmagicE(fm);
00349         }
00350 #endif
00351 
00352         if (fm->fn != stdname) {
00353 #ifdef RESTORE_TIME
00354                 /*
00355                  * Try to restore access, modification times if read it.
00356                  * This is really *bad* because it will modify the status
00357                  * time of the file... And of course this will affect
00358                  * backup programs
00359                  */
00360 # ifdef USE_UTIMES
00361                 struct timeval  utsbuf[2];
00362                 utsbuf[0].tv_sec = fm->sb.st_atime;
00363                 utsbuf[1].tv_sec = fm->sb.st_mtime;
00364 
00365                 (void) utimes(fm->fn, utsbuf); /* don't care if loses */
00366 # else
00367                 struct utimbuf  utbuf;
00368 
00369                 utbuf.actime = fm->sb.st_atime;
00370                 utbuf.modtime = fm->sb.st_mtime;
00371                 (void) utime(fm->fn, &utbuf); /* don't care if loses */
00372 # endif
00373 #endif
00374                 (void) close(fm->fd);
00375                 fm->fd = -1;
00376         }
00377 
00378 exit:
00379         if (fm->buf != NULL)
00380                 free(fm->buf);
00381         fm->buf = NULL;
00382         fm->nb = 0;
00383         return ret;
00384 }
00385 /*@=bounds@*/

Generated on Sun Oct 26 13:01:58 2003 for rpm by doxygen1.2.18