xref: /PHP-5.3/ext/fileinfo/libmagic/fsmagic.c (revision 12cf930a)
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.64 2011/08/14 09:03:12 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 
57 #ifndef HAVE_MAJOR
58 # define major(dev)  (((dev) >> 8) & 0xff)
59 # define minor(dev)  ((dev) & 0xff)
60 #endif
61 #undef HAVE_MAJOR
62 
63 #ifdef PHP_WIN32
64 
65 # undef S_IFIFO
66 #endif
67 
68 
69 #ifndef S_ISDIR
70 #define S_ISDIR(mode) ((mode) & _S_IFDIR)
71 #endif
72 
73 #ifndef S_ISREG
74 #define S_ISREG(mode) ((mode) & _S_IFREG)
75 #endif
76 
77 private int
handle_mime(struct magic_set * ms,int mime,const char * str)78 handle_mime(struct magic_set *ms, int mime, const char *str)
79 {
80 	if ((mime & MAGIC_MIME_TYPE)) {
81 		if (file_printf(ms, "inode/%s", str) == -1)
82 			return -1;
83 		if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms,
84 		    "; charset=") == -1)
85 			return -1;
86 	}
87 	if ((mime & MAGIC_MIME_ENCODING) && file_printf(ms, "binary") == -1)
88 		return -1;
89 	return 0;
90 }
91 
92 protected int
file_fsmagic(struct magic_set * ms,const char * fn,struct stat * sb,php_stream * stream)93 file_fsmagic(struct magic_set *ms, const char *fn, struct stat *sb, php_stream *stream)
94 {
95 	int mime = ms->flags & MAGIC_MIME;
96 	TSRMLS_FETCH();
97 
98 	if (ms->flags & MAGIC_APPLE)
99 		return 0;
100 
101 	if (!fn && !stream) {
102 		return 0;
103 	}
104 
105 	if (stream) {
106 		php_stream_statbuf ssb;
107 		if (php_stream_stat(stream, &ssb) < 0) {
108 			if (ms->flags & MAGIC_ERROR) {
109 				file_error(ms, errno, "cannot stat `%s'", fn);
110 				return -1;
111 			}
112 			return 1;
113 		}
114 		memcpy(sb, &ssb.sb, sizeof(struct stat));
115 	} else {
116 		if (php_sys_stat(fn, sb) != 0) {
117 			if (ms->flags & MAGIC_ERROR) {
118 				file_error(ms, errno, "cannot stat `%s'", fn);
119 				return -1;
120 			}
121 			return 1;
122 		}
123 	}
124 
125 	if (!mime) {
126 #ifdef S_ISUID
127 		if (sb->st_mode & S_ISUID)
128 			if (file_printf(ms, "setuid ") == -1)
129 				return -1;
130 #endif
131 #ifdef S_ISGID
132 		if (sb->st_mode & S_ISGID)
133 			if (file_printf(ms, "setgid ") == -1)
134 				return -1;
135 #endif
136 #ifdef S_ISVTX
137 		if (sb->st_mode & S_ISVTX)
138 			if (file_printf(ms, "sticky ") == -1)
139 				return -1;
140 #endif
141 	}
142 
143 	switch (sb->st_mode & S_IFMT) {
144 #ifndef PHP_WIN32
145 # ifdef S_IFCHR
146 		case S_IFCHR:
147 			/*
148 			 * If -s has been specified, treat character special files
149 			 * like ordinary files.  Otherwise, just report that they
150 			 * are block special files and go on to the next file.
151 			 */
152 			if ((ms->flags & MAGIC_DEVICES) != 0) {
153 				break;
154 			}
155 			if (mime) {
156 				if (handle_mime(ms, mime, "x-character-device") == -1)
157 					return -1;
158 			} else {
159 #  ifdef HAVE_STAT_ST_RDEV
160 #   ifdef dv_unit
161 				if (file_printf(ms, "character special (%d/%d/%d)",
162 				    major(sb->st_rdev), dv_unit(sb->st_rdev),
163 						dv_subunit(sb->st_rdev)) == -1)
164 					return -1;
165 #   else
166 				if (file_printf(ms, "character special (%ld/%ld)",
167 				    (long)major(sb->st_rdev), (long)minor(sb->st_rdev))
168 				    == -1)
169 					return -1;
170 #   endif
171 #  else
172 				if (file_printf(ms, "character special") == -1)
173 					return -1;
174 #  endif
175 			}
176 			return 1;
177 # endif
178 #endif
179 
180 #ifdef	S_IFIFO
181 	case S_IFIFO:
182 		if((ms->flags & MAGIC_DEVICES) != 0)
183 			break;
184 		if (mime) {
185 			if (handle_mime(ms, mime, "fifo") == -1)
186 				return -1;
187 		} else if (file_printf(ms, "fifo (named pipe)") == -1)
188 			return -1;
189 		return 1;
190 #endif
191 #ifdef	S_IFDOOR
192 	case S_IFDOOR:
193 		if (mime) {
194 			if (handle_mime(ms, mime, "door") == -1)
195 				return -1;
196 		} else if (file_printf(ms, "door") == -1)
197 			return -1;
198 		return 1;
199 #endif
200 #ifdef	S_IFLNK
201 	case S_IFLNK:
202 		/* stat is used, if it made here then the link is broken */
203 			if (ms->flags & MAGIC_ERROR) {
204 			    file_error(ms, errno, "unreadable symlink `%s'", fn);
205 			    return -1;
206 			}
207 	return 1;
208 #endif
209 
210 #ifdef	S_IFSOCK
211 #ifndef __COHERENT__
212 	case S_IFSOCK:
213 		if (mime) {
214 			if (handle_mime(ms, mime, "socket") == -1)
215 				return -1;
216 		} else if (file_printf(ms, "socket") == -1)
217 			return -1;
218 		return 1;
219 #endif
220 #endif
221 
222 		case S_IFREG:
223 			break;
224 
225 		default:
226 			file_error(ms, 0, "invalid mode 0%o", sb->st_mode);
227 			return -1;
228 			/*NOTREACHED*/
229 	}
230 
231 	/*
232 	 * regular file, check next possibility
233 	 *
234 	 * If stat() tells us the file has zero length, report here that
235 	 * the file is empty, so we can skip all the work of opening and
236 	 * reading the file.
237 	 * But if the -s option has been given, we skip this optimization,
238 	 * since on some systems, stat() reports zero size for raw disk
239 	 * partitions.  (If the block special device really has zero length,
240 	 * the fact that it is empty will be detected and reported correctly
241 	 * when we read the file.)
242 	 */
243 	if ((ms->flags & MAGIC_DEVICES) == 0 && sb->st_size == 0) {
244 		if (mime) {
245 			if (handle_mime(ms, mime, "x-empty") == -1)
246 				return -1;
247 		} else if (file_printf(ms, "empty") == -1)
248 			return -1;
249 		return 1;
250 	}
251 	return 0;
252 }
253