"Fossies" - the Fresh Open Source Software Archive

Member "file-5.35/src/fsmagic.c" (2 Oct 2018, 11039 Bytes) of package /linux/misc/file-5.35.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "fsmagic.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.34_vs_5.35.

    1 /*
    2  * Copyright (c) Ian F. Darwin 1986-1995.
    3  * Software written by Ian F. Darwin and others;
    4  * maintained 1995-present by Christos Zoulas and others.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice immediately at the beginning of the file, without modification,
   11  *    this list of conditions, and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 /*
   29  * fsmagic - magic based on filesystem info - directory, special files, etc.
   30  */
   31 
   32 #include "file.h"
   33 
   34 #ifndef lint
   35 FILE_RCSID("@(#)$File: fsmagic.c,v 1.79 2018/10/02 00:38:33 christos Exp $")
   36 #endif  /* lint */
   37 
   38 #include "magic.h"
   39 #include <string.h>
   40 #ifdef HAVE_UNISTD_H
   41 #include <unistd.h>
   42 #endif
   43 #include <stdlib.h>
   44 /* Since major is a function on SVR4, we cannot use `ifndef major'.  */
   45 #ifdef MAJOR_IN_MKDEV
   46 # include <sys/mkdev.h>
   47 # define HAVE_MAJOR
   48 #endif
   49 #ifdef MAJOR_IN_SYSMACROS
   50 # include <sys/sysmacros.h>
   51 # define HAVE_MAJOR
   52 #endif
   53 #ifdef major            /* Might be defined in sys/types.h.  */
   54 # define HAVE_MAJOR
   55 #endif
   56 #ifdef WIN32
   57 # define WIN32_LEAN_AND_MEAN
   58 # include <windows.h>
   59 #endif
   60 
   61 #ifndef HAVE_MAJOR
   62 # define major(dev)  (((dev) >> 8) & 0xff)
   63 # define minor(dev)  ((dev) & 0xff)
   64 #endif
   65 #undef HAVE_MAJOR
   66 #ifdef  S_IFLNK
   67 private int
   68 bad_link(struct magic_set *ms, int err, char *buf)
   69 {
   70     int mime = ms->flags & MAGIC_MIME;
   71     if ((mime & MAGIC_MIME_TYPE) &&
   72         file_printf(ms, "inode/symlink")
   73         == -1)
   74         return -1;
   75     else if (!mime) {
   76         if (ms->flags & MAGIC_ERROR) {
   77             file_error(ms, err,
   78                    "broken symbolic link to %s", buf);
   79             return -1;
   80         }
   81         if (file_printf(ms, "broken symbolic link to %s", buf) == -1)
   82             return -1;
   83     }
   84     return 1;
   85 }
   86 #endif
   87 private int
   88 handle_mime(struct magic_set *ms, int mime, const char *str)
   89 {
   90     if ((mime & MAGIC_MIME_TYPE)) {
   91         if (file_printf(ms, "inode/%s", str) == -1)
   92             return -1;
   93         if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms,
   94             "; charset=") == -1)
   95             return -1;
   96     }
   97     if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms, "binary") == -1)
   98         return -1;
   99     return 0;
  100 }
  101 
  102 protected int
  103 file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
  104 {
  105     int ret, did = 0;
  106     int mime = ms->flags & MAGIC_MIME;
  107     int silent = ms->flags & (MAGIC_APPLE|MAGIC_EXTENSION);
  108 #ifdef  S_IFLNK
  109     char buf[BUFSIZ+4];
  110     ssize_t nch;
  111     struct stat tstatbuf;
  112 #endif
  113 
  114     if (fn == NULL)
  115         return 0;
  116 
  117 #define COMMA   (did++ ? ", " : "")
  118     /*
  119      * Fstat is cheaper but fails for files you don't have read perms on.
  120      * On 4.2BSD and similar systems, use lstat() to identify symlinks.
  121      */
  122 #ifdef  S_IFLNK
  123     if ((ms->flags & MAGIC_SYMLINK) == 0)
  124         ret = lstat(fn, sb);
  125     else
  126 #endif
  127     ret = stat(fn, sb); /* don't merge into if; see "ret =" above */
  128 
  129 #ifdef WIN32
  130     {
  131         HANDLE hFile = CreateFile((LPCSTR)fn, 0, FILE_SHARE_DELETE |
  132             FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0,
  133             NULL);
  134         if (hFile != INVALID_HANDLE_VALUE) {
  135             /*
  136              * Stat failed, but we can still open it - assume it's
  137              * a block device, if nothing else.
  138              */
  139             if (ret) {
  140                 sb->st_mode = S_IFBLK;
  141                 ret = 0;
  142             }
  143             switch (GetFileType(hFile)) {
  144             case FILE_TYPE_CHAR:
  145                 sb->st_mode |= S_IFCHR;
  146                 sb->st_mode &= ~S_IFREG;
  147                 break;
  148             case FILE_TYPE_PIPE:
  149                 sb->st_mode |= S_IFIFO;
  150                 sb->st_mode &= ~S_IFREG;
  151                 break;
  152             }
  153             CloseHandle(hFile);
  154         }
  155     }
  156 #endif
  157 
  158     if (ret) {
  159         if (ms->flags & MAGIC_ERROR) {
  160             file_error(ms, errno, "cannot stat `%s'", fn);
  161             return -1;
  162         }
  163         if (file_printf(ms, "cannot open `%s' (%s)",
  164             fn, strerror(errno)) == -1)
  165             return -1;
  166         return 0;
  167     }
  168 
  169     ret = 1;
  170     if (!mime && !silent) {
  171 #ifdef S_ISUID
  172         if (sb->st_mode & S_ISUID)
  173             if (file_printf(ms, "%ssetuid", COMMA) == -1)
  174                 return -1;
  175 #endif
  176 #ifdef S_ISGID
  177         if (sb->st_mode & S_ISGID)
  178             if (file_printf(ms, "%ssetgid", COMMA) == -1)
  179                 return -1;
  180 #endif
  181 #ifdef S_ISVTX
  182         if (sb->st_mode & S_ISVTX)
  183             if (file_printf(ms, "%ssticky", COMMA) == -1)
  184                 return -1;
  185 #endif
  186     }
  187 
  188     switch (sb->st_mode & S_IFMT) {
  189     case S_IFDIR:
  190         if (mime) {
  191             if (handle_mime(ms, mime, "directory") == -1)
  192                 return -1;
  193         } else if (silent) {
  194         } else if (file_printf(ms, "%sdirectory", COMMA) == -1)
  195             return -1;
  196         break;
  197 #ifdef S_IFCHR
  198     case S_IFCHR:
  199         /*
  200          * If -s has been specified, treat character special files
  201          * like ordinary files.  Otherwise, just report that they
  202          * are block special files and go on to the next file.
  203          */
  204         if ((ms->flags & MAGIC_DEVICES) != 0) {
  205             ret = 0;
  206             break;
  207         }
  208         if (mime) {
  209             if (handle_mime(ms, mime, "chardevice") == -1)
  210                 return -1;
  211         } else if (silent) {
  212         } else {
  213 #ifdef HAVE_STRUCT_STAT_ST_RDEV
  214 # ifdef dv_unit
  215             if (file_printf(ms, "%scharacter special (%d/%d/%d)",
  216                 COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev),
  217                     dv_subunit(sb->st_rdev)) == -1)
  218                 return -1;
  219 # else
  220             if (file_printf(ms, "%scharacter special (%ld/%ld)",
  221                 COMMA, (long)major(sb->st_rdev),
  222                 (long)minor(sb->st_rdev)) == -1)
  223                 return -1;
  224 # endif
  225 #else
  226             if (file_printf(ms, "%scharacter special", COMMA) == -1)
  227                 return -1;
  228 #endif
  229         }
  230         break;
  231 #endif
  232 #ifdef S_IFBLK
  233     case S_IFBLK:
  234         /*
  235          * If -s has been specified, treat block special files
  236          * like ordinary files.  Otherwise, just report that they
  237          * are block special files and go on to the next file.
  238          */
  239         if ((ms->flags & MAGIC_DEVICES) != 0) {
  240             ret = 0;
  241             break;
  242         }
  243         if (mime) {
  244             if (handle_mime(ms, mime, "blockdevice") == -1)
  245                 return -1;
  246         } else if (silent) {
  247         } else {
  248 #ifdef HAVE_STRUCT_STAT_ST_RDEV
  249 # ifdef dv_unit
  250             if (file_printf(ms, "%sblock special (%d/%d/%d)",
  251                 COMMA, major(sb->st_rdev), dv_unit(sb->st_rdev),
  252                 dv_subunit(sb->st_rdev)) == -1)
  253                 return -1;
  254 # else
  255             if (file_printf(ms, "%sblock special (%ld/%ld)",
  256                 COMMA, (long)major(sb->st_rdev),
  257                 (long)minor(sb->st_rdev)) == -1)
  258                 return -1;
  259 # endif
  260 #else
  261             if (file_printf(ms, "%sblock special", COMMA) == -1)
  262                 return -1;
  263 #endif
  264         }
  265         break;
  266 #endif
  267     /* TODO add code to handle V7 MUX and Blit MUX files */
  268 #ifdef  S_IFIFO
  269     case S_IFIFO:
  270         if((ms->flags & MAGIC_DEVICES) != 0)
  271             break;
  272         if (mime) {
  273             if (handle_mime(ms, mime, "fifo") == -1)
  274                 return -1;
  275         } else if (silent) {
  276         } else if (file_printf(ms, "%sfifo (named pipe)", COMMA) == -1)
  277             return -1;
  278         break;
  279 #endif
  280 #ifdef  S_IFDOOR
  281     case S_IFDOOR:
  282         if (mime) {
  283             if (handle_mime(ms, mime, "door") == -1)
  284                 return -1;
  285         } else if (silent) {
  286         } else if (file_printf(ms, "%sdoor", COMMA) == -1)
  287             return -1;
  288         break;
  289 #endif
  290 #ifdef  S_IFLNK
  291     case S_IFLNK:
  292         if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
  293             if (ms->flags & MAGIC_ERROR) {
  294                 file_error(ms, errno, "unreadable symlink `%s'",
  295                 fn);
  296                 return -1;
  297             }
  298             if (mime) {
  299                 if (handle_mime(ms, mime, "symlink") == -1)
  300                     return -1;
  301             } else if (silent) {
  302             } else if (file_printf(ms,
  303                 "%sunreadable symlink `%s' (%s)", COMMA, fn,
  304                 strerror(errno)) == -1)
  305                 return -1;
  306             break;
  307         }
  308         buf[nch] = '\0';    /* readlink(2) does not do this */
  309 
  310         /* If broken symlink, say so and quit early. */
  311 #ifdef __linux__
  312         /*
  313          * linux procfs/devfs makes symlinks like pipe:[3515864880]
  314          * that we can't stat their readlink output, so stat the
  315          * original filename instead.
  316          */
  317         if (stat(fn, &tstatbuf) < 0)
  318             return bad_link(ms, errno, buf);
  319 #else
  320         if (*buf == '/') {
  321             if (stat(buf, &tstatbuf) < 0)
  322                 return bad_link(ms, errno, buf);
  323         } else {
  324             char *tmp;
  325             char buf2[BUFSIZ+BUFSIZ+4];
  326 
  327             if ((tmp = strrchr(fn,  '/')) == NULL) {
  328                 tmp = buf; /* in current directory anyway */
  329             } else {
  330                 if (tmp - fn + 1 > BUFSIZ) {
  331                     if (ms->flags & MAGIC_ERROR) {
  332                         file_error(ms, 0,
  333                             "path too long: `%s'", buf);
  334                         return -1;
  335                     }
  336                     if (mime) {
  337                         if (handle_mime(ms, mime,
  338                             "x-path-too-long") == -1)
  339                             return -1;
  340                     } else if (silent) {
  341                     } else if (file_printf(ms,
  342                         "%spath too long: `%s'", COMMA,
  343                         fn) == -1)
  344                         return -1;
  345                     break;
  346                 }
  347                 /* take dir part */
  348                 (void)strlcpy(buf2, fn, sizeof buf2);
  349                 buf2[tmp - fn + 1] = '\0';
  350                 /* plus (rel) link */
  351                 (void)strlcat(buf2, buf, sizeof buf2);
  352                 tmp = buf2;
  353             }
  354             if (stat(tmp, &tstatbuf) < 0)
  355                 return bad_link(ms, errno, buf);
  356         }
  357 #endif
  358 
  359         /* Otherwise, handle it. */
  360         if ((ms->flags & MAGIC_SYMLINK) != 0) {
  361             const char *p;
  362             ms->flags &= MAGIC_SYMLINK;
  363             p = magic_file(ms, buf);
  364             ms->flags |= MAGIC_SYMLINK;
  365             if (p == NULL)
  366                 return -1;
  367         } else { /* just print what it points to */
  368             if (mime) {
  369                 if (handle_mime(ms, mime, "symlink") == -1)
  370                     return -1;
  371             } else if (silent) {
  372             } else if (file_printf(ms, "%ssymbolic link to %s",
  373                 COMMA, buf) == -1)
  374                 return -1;
  375         }
  376         break;
  377 #endif
  378 #ifdef  S_IFSOCK
  379 #ifndef __COHERENT__
  380     case S_IFSOCK:
  381         if (mime) {
  382             if (handle_mime(ms, mime, "socket") == -1)
  383                 return -1;
  384         } else if (silent) {
  385         } else if (file_printf(ms, "%ssocket", COMMA) == -1)
  386             return -1;
  387         break;
  388 #endif
  389 #endif
  390     case S_IFREG:
  391         /*
  392          * regular file, check next possibility
  393          *
  394          * If stat() tells us the file has zero length, report here that
  395          * the file is empty, so we can skip all the work of opening and
  396          * reading the file.
  397          * But if the -s option has been given, we skip this
  398          * optimization, since on some systems, stat() reports zero
  399          * size for raw disk partitions. (If the block special device
  400          * really has zero length, the fact that it is empty will be
  401          * detected and reported correctly when we read the file.)
  402          */
  403         if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) {
  404             if (mime) {
  405                 if (handle_mime(ms, mime, "x-empty") == -1)
  406                     return -1;
  407             } else if (silent) {
  408             } else if (file_printf(ms, "%sempty", COMMA) == -1)
  409                 return -1;
  410             break;
  411         }
  412         ret = 0;
  413         break;
  414 
  415     default:
  416         file_error(ms, 0, "invalid mode 0%o", sb->st_mode);
  417         return -1;
  418         /*NOTREACHED*/
  419     }
  420 
  421     if (!silent && !mime && did && ret == 0) {
  422         if (file_printf(ms, " ") == -1)
  423             return -1;
  424     }
  425     return ret;
  426 }