]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/file/fsmagic.c
This commit was generated by cvs2svn to compensate for changes in r138298,
[FreeBSD/FreeBSD.git] / contrib / file / fsmagic.c
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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *    This product includes software developed by Ian F. Darwin and others.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *  
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
25  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 /*
34  * fsmagic - magic based on filesystem info - directory, special files, etc.
35  */
36
37 #include "file.h"
38 #include "magic.h"
39 #include <string.h>
40 #ifdef HAVE_UNISTD_H
41 #include <unistd.h>
42 #endif
43 #include <stdlib.h>
44 #include <sys/stat.h>
45 /* Since major is a function on SVR4, we cannot use `ifndef major'.  */
46 #ifdef MAJOR_IN_MKDEV
47 # include <sys/mkdev.h>
48 # define HAVE_MAJOR
49 #endif
50 #ifdef MAJOR_IN_SYSMACROS
51 # include <sys/sysmacros.h>
52 # define HAVE_MAJOR
53 #endif
54 #ifdef major                    /* Might be defined in sys/types.h.  */
55 # define HAVE_MAJOR
56 #endif
57   
58 #ifndef HAVE_MAJOR
59 # define major(dev)  (((dev) >> 8) & 0xff)
60 # define minor(dev)  ((dev) & 0xff)
61 #endif
62 #undef HAVE_MAJOR
63
64 #ifndef lint
65 FILE_RCSID("@(#)$Id: fsmagic.c,v 1.43 2003/10/14 19:29:55 christos Exp $")
66 #endif  /* lint */
67
68 protected int
69 file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb)
70 {
71         int ret = 0;
72 #ifdef  S_IFLNK
73         char buf[BUFSIZ+4];
74         int nch;
75         struct stat tstatbuf;
76 #endif
77
78         if (fn == NULL)
79                 return 0;
80
81         /*
82          * Fstat is cheaper but fails for files you don't have read perms on.
83          * On 4.2BSD and similar systems, use lstat() to identify symlinks.
84          */
85 #ifdef  S_IFLNK
86         if ((ms->flags & MAGIC_SYMLINK) == 0)
87                 ret = lstat(fn, sb);
88         else
89 #endif
90         ret = stat(fn, sb);     /* don't merge into if; see "ret =" above */
91
92         if (ret) {
93                 if (ms->flags & MAGIC_ERROR) {
94                         file_error(ms, errno, "cannot stat `%s'", fn);
95                         return -1;
96                 }
97                 if (file_printf(ms, "cannot open (%s)",
98                     fn, strerror(errno)) == -1)
99                         return -1;
100                 return 1;
101         }
102
103         if ((ms->flags & MAGIC_MIME) != 0) {
104                 if ((sb->st_mode & S_IFMT) != S_IFREG) {
105                         if (file_printf(ms, "application/x-not-regular-file")
106                             == -1)
107                                 return -1;
108                         return 1;
109                 }
110         }
111         else {
112 #ifdef S_ISUID
113                 if (sb->st_mode & S_ISUID) 
114                         if (file_printf(ms, "setuid ") == -1)
115                                 return -1;
116 #endif
117 #ifdef S_ISGID
118                 if (sb->st_mode & S_ISGID) 
119                         if (file_printf(ms, "setgid ") == -1)
120                                 return -1;
121 #endif
122 #ifdef S_ISVTX
123                 if (sb->st_mode & S_ISVTX) 
124                         if (file_printf(ms, "sticky ") == -1)
125                                 return -1;
126 #endif
127         }
128         
129         switch (sb->st_mode & S_IFMT) {
130         case S_IFDIR:
131                 if (file_printf(ms, "directory") == -1)
132                         return -1;
133                 return 1;
134 #ifdef S_IFCHR
135         case S_IFCHR:
136                 /* 
137                  * If -s has been specified, treat character special files
138                  * like ordinary files.  Otherwise, just report that they
139                  * are block special files and go on to the next file.
140                  */
141                 if ((ms->flags & MAGIC_DEVICES) != 0)
142                         break;
143 #ifdef HAVE_ST_RDEV
144 # ifdef dv_unit
145                 if (file_printf(ms, "character special (%d/%d/%d)",
146                     major(sb->st_rdev), dv_unit(sb->st_rdev),
147                     dv_subunit(sb->st_rdev)) == -1)
148                         return -1;
149 # else
150                 if (file_printf(ms, "character special (%ld/%ld)",
151                     (long) major(sb->st_rdev), (long) minor(sb->st_rdev)) == -1)
152                         return -1;
153 # endif
154 #else
155                 if (file_printf(ms, "character special") == -1)
156                         return -1;
157 #endif
158                 return 1;
159 #endif
160 #ifdef S_IFBLK
161         case S_IFBLK:
162                 /* 
163                  * If -s has been specified, treat block special files
164                  * like ordinary files.  Otherwise, just report that they
165                  * are block special files and go on to the next file.
166                  */
167                 if ((ms->flags & MAGIC_DEVICES) != 0)
168                         break;
169 #ifdef HAVE_ST_RDEV
170 # ifdef dv_unit
171                 if (file_printf(ms, "block special (%d/%d/%d)",
172                     major(sb->st_rdev), dv_unit(sb->st_rdev),
173                     dv_subunit(sb->st_rdev)) == -1)
174                         return -1;
175 # else
176                 if (file_printf(ms, "block special (%ld/%ld)",
177                     (long)major(sb->st_rdev), (long)minor(sb->st_rdev)) == -1)
178                         return -1;
179 # endif
180 #else
181                 if (file_printf(ms, "block special") == -1)
182                         return -1;
183 #endif
184                 return 1;
185 #endif
186         /* TODO add code to handle V7 MUX and Blit MUX files */
187 #ifdef  S_IFIFO
188         case S_IFIFO:
189                 if (file_printf(ms, "fifo (named pipe)") == -1)
190                         return -1;
191                 return 1;
192 #endif
193 #ifdef  S_IFDOOR
194         case S_IFDOOR:
195                 if (file_printf(ms, "door") == -1)
196                         return -1;
197                 return 1;
198 #endif
199 #ifdef  S_IFLNK
200         case S_IFLNK:
201                 if ((nch = readlink(fn, buf, BUFSIZ-1)) <= 0) {
202                         if (ms->flags & MAGIC_ERROR) {
203                             file_error(ms, errno, "unreadable symlink `%s'",
204                                 fn);
205                             return -1;
206                         }
207                         if (file_printf(ms,
208                             "unreadable symlink `%s' (%s)", fn,
209                             strerror(errno)) == -1)
210                                 return -1;
211                         return 1;
212                 }
213                 buf[nch] = '\0';        /* readlink(2) forgets this */
214
215                 /* If broken symlink, say so and quit early. */
216                 if (*buf == '/') {
217                     if (stat(buf, &tstatbuf) < 0) {
218                             if (ms->flags & MAGIC_ERROR) {
219                                     file_error(ms, errno, 
220                                         "broken symbolic link to `%s'", buf);
221                                     return -1;
222                             } 
223                             if (file_printf(ms, "broken symbolic link to `%s'",
224                                 buf) == -1)
225                                     return -1;
226                             return 1;
227                     }
228                 }
229                 else {
230                         char *tmp;
231                         char buf2[BUFSIZ+BUFSIZ+4];
232
233                         if ((tmp = strrchr(fn,  '/')) == NULL) {
234                                 tmp = buf; /* in current directory anyway */
235                         } else {
236                                 if (tmp - fn + 1 > BUFSIZ) {
237                                         if (ms->flags & MAGIC_ERROR) {
238                                                 file_error(ms, 0, 
239                                                     "path too long: `%s'", buf);
240                                                 return -1;
241                                         }
242                                         if (file_printf(ms,
243                                             "path too long: `%s'", fn) == -1)
244                                                 return -1;
245                                         return 1;
246                                 }
247                                 (void)strcpy(buf2, fn);  /* take dir part */
248                                 buf2[tmp - fn + 1] = '\0';
249                                 (void)strcat(buf2, buf); /* plus (rel) link */
250                                 tmp = buf2;
251                         }
252                         if (stat(tmp, &tstatbuf) < 0) {
253                                 if (ms->flags & MAGIC_ERROR) {
254                                         file_error(ms, errno, 
255                                             "broken symbolic link to `%s'",
256                                             buf);
257                                         return -1;
258                                 }
259                                 if (file_printf(ms,
260                                     "broken symbolic link to `%s'", buf) == -1)
261                                         return -1;
262                                 return 1;
263                         }
264                 }
265
266                 /* Otherwise, handle it. */
267                 if ((ms->flags & MAGIC_SYMLINK) != 0) {
268                         const char *p;
269                         ms->flags &= MAGIC_SYMLINK;
270                         p = magic_file(ms, buf);
271                         ms->flags |= MAGIC_SYMLINK;
272                         return p != NULL ? 1 : -1;
273                 } else { /* just print what it points to */
274                         if (file_printf(ms, "symbolic link to `%s'",
275                             buf) == -1)
276                                 return -1;
277                 }
278         return 1;
279 #endif
280 #ifdef  S_IFSOCK
281 #ifndef __COHERENT__
282         case S_IFSOCK:
283                 if (file_printf(ms, "socket") == -1)
284                         return -1;
285                 return 1;
286 #endif
287 #endif
288         case S_IFREG:
289                 break;
290         default:
291                 file_error(ms, 0, "invalid mode 0%o", sb->st_mode);
292                 return -1;
293                 /*NOTREACHED*/
294         }
295
296         /*
297          * regular file, check next possibility
298          *
299          * If stat() tells us the file has zero length, report here that
300          * the file is empty, so we can skip all the work of opening and 
301          * reading the file.
302          * But if the -s option has been given, we skip this optimization,
303          * since on some systems, stat() reports zero size for raw disk
304          * partitions.  (If the block special device really has zero length,
305          * the fact that it is empty will be detected and reported correctly
306          * when we read the file.)
307          */
308         if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) {
309                 if (file_printf(ms, (ms->flags & MAGIC_MIME) ?
310                     "application/x-empty" : "empty") == -1)
311                         return -1;
312                 return 1;
313         }
314         return 0;
315 }