]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/file/funcs.c
This commit was generated by cvs2svn to compensate for changes in r167974,
[FreeBSD/FreeBSD.git] / contrib / file / funcs.c
1 /*
2  * Copyright (c) Christos Zoulas 2003.
3  * All Rights Reserved.
4  * 
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice immediately at the beginning of the file, without modification,
10  *    this list of conditions, and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *  
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 #include "file.h"
28 #include "magic.h"
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <ctype.h>
33 #if defined(HAVE_WCHAR_H)
34 #include <wchar.h>
35 #endif
36
37 #ifndef lint
38 FILE_RCSID("@(#)$Id: funcs.c,v 1.19 2006/03/02 22:10:26 christos Exp $")
39 #endif  /* lint */
40
41 #ifndef HAVE_VSNPRINTF
42 int vsnprintf(char *, size_t, const char *, va_list);
43 #endif
44
45 /*
46  * Like printf, only we print to a buffer and advance it.
47  */
48 protected int
49 file_printf(struct magic_set *ms, const char *fmt, ...)
50 {
51         va_list ap;
52         size_t len;
53         char *buf;
54
55         va_start(ap, fmt);
56
57         if ((len = vsnprintf(ms->o.ptr, ms->o.len, fmt, ap)) >= ms->o.len) {
58                 va_end(ap);
59                 if ((buf = realloc(ms->o.buf, len + 1024)) == NULL) {
60                         file_oomem(ms);
61                         return -1;
62                 }
63                 ms->o.ptr = buf + (ms->o.ptr - ms->o.buf);
64                 ms->o.buf = buf;
65                 ms->o.len = ms->o.size - (ms->o.ptr - ms->o.buf);
66                 ms->o.size = len + 1024;
67
68                 va_start(ap, fmt);
69                 len = vsnprintf(ms->o.ptr, ms->o.len, fmt, ap);
70         }
71         ms->o.ptr += len;
72         ms->o.len -= len;
73         va_end(ap);
74         return 0;
75 }
76
77 /*
78  * error - print best error message possible
79  */
80 /*VARARGS*/
81 protected void
82 file_error(struct magic_set *ms, int error, const char *f, ...)
83 {
84         va_list va;
85         /* Only the first error is ok */
86         if (ms->haderr)
87                 return;
88         va_start(va, f);
89         (void)vsnprintf(ms->o.buf, ms->o.size, f, va);
90         va_end(va);
91         if (error > 0) {
92                 size_t len = strlen(ms->o.buf);
93                 (void)snprintf(ms->o.buf + len, ms->o.size - len, " (%s)",
94                     strerror(error));
95         }
96         ms->haderr++;
97         ms->error = error;
98 }
99
100
101 protected void
102 file_oomem(struct magic_set *ms)
103 {
104         file_error(ms, errno, "cannot allocate memory");
105 }
106
107 protected void
108 file_badseek(struct magic_set *ms)
109 {
110         file_error(ms, errno, "error seeking");
111 }
112
113 protected void
114 file_badread(struct magic_set *ms)
115 {
116         file_error(ms, errno, "error reading");
117 }
118
119 #ifndef COMPILE_ONLY
120 protected int
121 file_buffer(struct magic_set *ms, int fd, const void *buf, size_t nb)
122 {
123     int m;
124     /* try compression stuff */
125     if ((m = file_zmagic(ms, fd, buf, nb)) == 0) {
126         /* Check if we have a tar file */
127         if ((m = file_is_tar(ms, buf, nb)) == 0) {
128             /* try tests in /etc/magic (or surrogate magic file) */
129             if ((m = file_softmagic(ms, buf, nb)) == 0) {
130                 /* try known keywords, check whether it is ASCII */
131                 if ((m = file_ascmagic(ms, buf, nb)) == 0) {
132                     /* abandon hope, all ye who remain here */
133                     if (file_printf(ms, ms->flags & MAGIC_MIME ?
134                         (nb ? "application/octet-stream" :
135                             "application/empty") :
136                         (nb ? "data" :
137                             "empty")) == -1)
138                             return -1;
139                     m = 1;
140                 }
141             }
142         }
143     }
144     return m;
145 }
146 #endif
147
148 protected int
149 file_reset(struct magic_set *ms)
150 {
151         if (ms->mlist == NULL) {
152                 file_error(ms, 0, "no magic files loaded");
153                 return -1;
154         }
155         ms->o.ptr = ms->o.buf;
156         ms->haderr = 0;
157         ms->error = -1;
158         return 0;
159 }
160
161 #define OCTALIFY(n, o)  \
162         *(n)++ = '\\', \
163         *(n)++ = (((uint32_t)*(o) >> 6) & 3) + '0', \
164         *(n)++ = (((uint32_t)*(o) >> 3) & 7) + '0', \
165         *(n)++ = (((uint32_t)*(o) >> 0) & 7) + '0', \
166         (o)++
167
168 protected const char *
169 file_getbuffer(struct magic_set *ms)
170 {
171         char *nbuf, *op, *np;
172         size_t nsize;
173
174         if (ms->haderr)
175                 return NULL;
176
177         if (ms->flags & MAGIC_RAW)
178                 return ms->o.buf;
179
180         nsize = ms->o.len * 4 + 1;
181         if (ms->o.psize < nsize) {
182                 if ((nbuf = realloc(ms->o.pbuf, nsize)) == NULL) {
183                         file_oomem(ms);
184                         return NULL;
185                 }
186                 ms->o.psize = nsize;
187                 ms->o.pbuf = nbuf;
188         }
189
190 #if defined(HAVE_WCHAR_H) && defined(HAVE_MBRTOWC) && defined(HAVE_WCWIDTH)
191         {
192                 mbstate_t state;
193                 wchar_t nextchar;
194                 int mb_conv = 1;
195                 size_t bytesconsumed;
196                 char *eop;
197                 (void)memset(&state, 0, sizeof(mbstate_t));
198
199                 np = ms->o.pbuf;
200                 op = ms->o.buf;
201                 eop = op + strlen(ms->o.buf);
202
203                 while (op < eop) {
204                         bytesconsumed = mbrtowc(&nextchar, op, eop - op,
205                             &state);
206                         if (bytesconsumed == (size_t)(-1) ||
207                             bytesconsumed == (size_t)(-2)) {
208                                 mb_conv = 0;
209                                 break;
210                         }
211
212                         if (iswprint(nextchar) ) {
213                                 (void)memcpy(np, op, bytesconsumed);
214                                 op += bytesconsumed;
215                                 np += bytesconsumed;
216                         } else {
217                                 while (bytesconsumed-- > 0)
218                                         OCTALIFY(np, op);
219                         }
220                 }
221                 *np = '\0';
222
223                 /* Parsing succeeded as a multi-byte sequence */
224                 if (mb_conv != 0)
225                         return ms->o.pbuf;
226         }
227 #endif
228
229         for (np = ms->o.pbuf, op = ms->o.buf; *op; op++) {
230                 if (isprint((unsigned char)*op)) {
231                         *np++ = *op;    
232                 } else {
233                         OCTALIFY(np, op);
234                 }
235         }
236         *np = '\0';
237         return ms->o.pbuf;
238 }
239
240 /*
241  * Yes these suffer from buffer overflows, but if your OS does not have
242  * these functions, then maybe you should consider replacing your OS?
243  */
244 #ifndef HAVE_VSNPRINTF
245 int
246 vsnprintf(char *buf, size_t len, const char *fmt, va_list ap)
247 {
248         return vsprintf(buf, fmt, ap);
249 }
250 #endif
251
252 #ifndef HAVE_SNPRINTF
253 /*ARGSUSED*/
254 int
255 snprintf(char *buf, size_t len, const char *fmt, ...)
256 {
257         int rv;
258         va_list ap;
259         va_start(ap, fmt);
260         rv = vsprintf(buf, fmt, ap);
261         va_end(ap);
262         return rv;
263 }
264 #endif