fsmagic.c revision 169962
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#include "magic.h" 34#include <string.h> 35#ifdef HAVE_UNISTD_H 36#include <unistd.h> 37#endif 38#include <stdlib.h> 39#include <sys/stat.h> 40/* Since major is a function on SVR4, we cannot use `ifndef major'. */ 41#ifdef MAJOR_IN_MKDEV 42# include <sys/mkdev.h> 43# define HAVE_MAJOR 44#endif 45#ifdef MAJOR_IN_SYSMACROS 46# include <sys/sysmacros.h> 47# define HAVE_MAJOR 48#endif 49#ifdef major /* Might be defined in sys/types.h. */ 50# define HAVE_MAJOR 51#endif 52 53#ifndef HAVE_MAJOR 54# define major(dev) (((dev) >> 8) & 0xff) 55# define minor(dev) ((dev) & 0xff) 56#endif 57#undef HAVE_MAJOR 58 59#ifndef lint 60FILE_RCSID("@(#)$File: fsmagic.c,v 1.47 2007/01/12 17:38:28 christos Exp $") 61#endif /* lint */ 62 63protected int 64file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb) 65{ 66 int ret = 0; 67#ifdef S_IFLNK 68 char buf[BUFSIZ+4]; 69 int nch; 70 struct stat tstatbuf; 71#endif 72 73 if (fn == NULL) 74 return 0; 75 76 /* 77 * Fstat is cheaper but fails for files you don't have read perms on. 78 * On 4.2BSD and similar systems, use lstat() to identify symlinks. 79 */ 80#ifdef S_IFLNK 81 if ((ms->flags & MAGIC_SYMLINK) == 0) 82 ret = lstat(fn, sb); 83 else 84#endif 85 ret = stat(fn, sb); /* don't merge into if; see "ret =" above */ 86 87 if (ret) { 88 if (ms->flags & MAGIC_ERROR) { 89 file_error(ms, errno, "cannot stat `%s'", fn); 90 return -1; 91 } 92 if (file_printf(ms, "cannot open `%s' (%s)", 93 fn, strerror(errno)) == -1) 94 return -1; 95 return 1; 96 } 97 98 if ((ms->flags & MAGIC_MIME) != 0) { 99 if ((sb->st_mode & S_IFMT) != S_IFREG) { 100 if (file_printf(ms, "application/x-not-regular-file") 101 == -1) 102 return -1; 103 return 1; 104 } 105 } 106 else { 107#ifdef S_ISUID 108 if (sb->st_mode & S_ISUID) 109 if (file_printf(ms, "setuid ") == -1) 110 return -1; 111#endif 112#ifdef S_ISGID 113 if (sb->st_mode & S_ISGID) 114 if (file_printf(ms, "setgid ") == -1) 115 return -1; 116#endif 117#ifdef S_ISVTX 118 if (sb->st_mode & S_ISVTX) 119 if (file_printf(ms, "sticky ") == -1) 120 return -1; 121#endif 122 } 123 124 switch (sb->st_mode & S_IFMT) { 125 case S_IFDIR: 126 if (file_printf(ms, "directory") == -1) 127 return -1; 128 return 1; 129#ifdef S_IFCHR 130 case S_IFCHR: 131 /* 132 * If -s has been specified, treat character special files 133 * like ordinary files. Otherwise, just report that they 134 * are block special files and go on to the next file. 135 */ 136 if ((ms->flags & MAGIC_DEVICES) != 0) 137 break; 138#ifdef HAVE_ST_RDEV 139# ifdef dv_unit 140 if (file_printf(ms, "character special (%d/%d/%d)", 141 major(sb->st_rdev), dv_unit(sb->st_rdev), 142 dv_subunit(sb->st_rdev)) == -1) 143 return -1; 144# else 145 if (file_printf(ms, "character special (%ld/%ld)", 146 (long) major(sb->st_rdev), (long) minor(sb->st_rdev)) == -1) 147 return -1; 148# endif 149#else 150 if (file_printf(ms, "character special") == -1) 151 return -1; 152#endif 153 return 1; 154#endif 155#ifdef S_IFBLK 156 case S_IFBLK: 157 /* 158 * If -s has been specified, treat block special files 159 * like ordinary files. Otherwise, just report that they 160 * are block special files and go on to the next file. 161 */ 162 if ((ms->flags & MAGIC_DEVICES) != 0) 163 break; 164#ifdef HAVE_ST_RDEV 165# ifdef dv_unit 166 if (file_printf(ms, "block special (%d/%d/%d)", 167 major(sb->st_rdev), dv_unit(sb->st_rdev), 168 dv_subunit(sb->st_rdev)) == -1) 169 return -1; 170# else 171 if (file_printf(ms, "block special (%ld/%ld)", 172 (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1) 173 return -1; 174# endif 175#else 176 if (file_printf(ms, "block special") == -1) 177 return -1; 178#endif 179 return 1; 180#endif 181 /* TODO add code to handle V7 MUX and Blit MUX files */ 182#ifdef S_IFIFO 183 case S_IFIFO: 184 if((ms->flags & MAGIC_DEVICES) != 0) 185 break; 186 if (file_printf(ms, "fifo (named pipe)") == -1) 187 return -1; 188 return 1; 189#endif 190#ifdef S_IFDOOR 191 case S_IFDOOR: 192 if (file_printf(ms, "door") == -1) 193 return -1; 194 return 1; 195#endif 196#ifdef S_IFLNK 197 case S_IFLNK: 198 if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) { 199 if (ms->flags & MAGIC_ERROR) { 200 file_error(ms, errno, "unreadable symlink `%s'", 201 fn); 202 return -1; 203 } 204 if (file_printf(ms, 205 "unreadable symlink `%s' (%s)", fn, 206 strerror(errno)) == -1) 207 return -1; 208 return 1; 209 } 210 buf[nch] = '\0'; /* readlink(2) forgets this */ 211 212 /* If broken symlink, say so and quit early. */ 213 if (*buf == '/') { 214 if (stat(buf, &tstatbuf) < 0) { 215 if (ms->flags & MAGIC_ERROR) { 216 file_error(ms, errno, 217 "broken symbolic link to `%s'", buf); 218 return -1; 219 } 220 if (file_printf(ms, "broken symbolic link to `%s'", 221 buf) == -1) 222 return -1; 223 return 1; 224 } 225 } 226 else { 227 char *tmp; 228 char buf2[BUFSIZ+BUFSIZ+4]; 229 230 if ((tmp = strrchr(fn, '/')) == NULL) { 231 tmp = buf; /* in current directory anyway */ 232 } else { 233 if (tmp - fn + 1 > BUFSIZ) { 234 if (ms->flags & MAGIC_ERROR) { 235 file_error(ms, 0, 236 "path too long: `%s'", buf); 237 return -1; 238 } 239 if (file_printf(ms, 240 "path too long: `%s'", fn) == -1) 241 return -1; 242 return 1; 243 } 244 (void)strcpy(buf2, fn); /* take dir part */ 245 buf2[tmp - fn + 1] = '\0'; 246 (void)strcat(buf2, buf); /* plus (rel) link */ 247 tmp = buf2; 248 } 249 if (stat(tmp, &tstatbuf) < 0) { 250 if (ms->flags & MAGIC_ERROR) { 251 file_error(ms, errno, 252 "broken symbolic link to `%s'", 253 buf); 254 return -1; 255 } 256 if (file_printf(ms, 257 "broken symbolic link to `%s'", buf) == -1) 258 return -1; 259 return 1; 260 } 261 } 262 263 /* Otherwise, handle it. */ 264 if ((ms->flags & MAGIC_SYMLINK) != 0) { 265 const char *p; 266 ms->flags &= MAGIC_SYMLINK; 267 p = magic_file(ms, buf); 268 ms->flags |= MAGIC_SYMLINK; 269 return p != NULL ? 1 : -1; 270 } else { /* just print what it points to */ 271 if (file_printf(ms, "symbolic link to `%s'", 272 buf) == -1) 273 return -1; 274 } 275 return 1; 276#endif 277#ifdef S_IFSOCK 278#ifndef __COHERENT__ 279 case S_IFSOCK: 280 if (file_printf(ms, "socket") == -1) 281 return -1; 282 return 1; 283#endif 284#endif 285 case S_IFREG: 286 break; 287 default: 288 file_error(ms, 0, "invalid mode 0%o", sb->st_mode); 289 return -1; 290 /*NOTREACHED*/ 291 } 292 293 /* 294 * regular file, check next possibility 295 * 296 * If stat() tells us the file has zero length, report here that 297 * the file is empty, so we can skip all the work of opening and 298 * reading the file. 299 * But if the -s option has been given, we skip this optimization, 300 * since on some systems, stat() reports zero size for raw disk 301 * partitions. (If the block special device really has zero length, 302 * the fact that it is empty will be detected and reported correctly 303 * when we read the file.) 304 */ 305 if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) { 306 if (file_printf(ms, (ms->flags & MAGIC_MIME) ? 307 "application/x-empty" : "empty") == -1) 308 return -1; 309 return 1; 310 } 311 return 0; 312} 313