]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_subr/magic.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.git] / contrib / subversion / subversion / libsvn_subr / magic.c
1 /*
2  * magic.c:  wrappers around libmagic
3  *
4  * ====================================================================
5  *    Licensed to the Apache Software Foundation (ASF) under one
6  *    or more contributor license agreements.  See the NOTICE file
7  *    distributed with this work for additional information
8  *    regarding copyright ownership.  The ASF licenses this file
9  *    to you under the Apache License, Version 2.0 (the
10  *    "License"); you may not use this file except in compliance
11  *    with the License.  You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  *    Unless required by applicable law or agreed to in writing,
16  *    software distributed under the License is distributed on an
17  *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18  *    KIND, either express or implied.  See the License for the
19  *    specific language governing permissions and limitations
20  *    under the License.
21  * ====================================================================
22  */
23
24 /* ==================================================================== */
25
26 \f
27 /*** Includes. ***/
28
29 #include <apr_lib.h>
30 #include <apr_file_info.h>
31
32 #include "svn_io.h"
33 #include "svn_types.h"
34 #include "svn_pools.h"
35 #include "svn_error.h"
36 #include "svn_config.h"
37 #include "svn_hash.h"
38
39 #include "svn_private_config.h"
40
41 #include "private/svn_magic.h"
42
43 #ifdef SVN_HAVE_LIBMAGIC
44 #include <magic.h>
45 #endif
46
47 struct svn_magic__cookie_t {
48 #ifdef SVN_HAVE_LIBMAGIC
49   magic_t magic;
50 #else
51   char dummy;
52 #endif
53 };
54
55 #ifdef SVN_HAVE_LIBMAGIC
56 /* Close the magic database. */
57 static apr_status_t
58 close_magic_cookie(void *baton)
59 {
60   svn_magic__cookie_t *mc = (svn_magic__cookie_t*)baton;
61   magic_close(mc->magic);
62   return APR_SUCCESS;
63 }
64 #endif
65
66 svn_error_t *
67 svn_magic__init(svn_magic__cookie_t **magic_cookie,
68                 apr_hash_t *config,
69                 apr_pool_t *result_pool)
70 {
71   svn_magic__cookie_t *mc = NULL;
72
73 #ifdef SVN_HAVE_LIBMAGIC
74   if (config)
75     {
76       svn_boolean_t enable;
77       svn_config_t *cfg = svn_hash_gets(config, SVN_CONFIG_CATEGORY_CONFIG);
78
79       SVN_ERR(svn_config_get_bool(cfg, &enable,
80                                   SVN_CONFIG_SECTION_MISCELLANY,
81                                   SVN_CONFIG_OPTION_ENABLE_MAGIC_FILE,
82                                   TRUE));
83       if (!enable)
84         {
85           *magic_cookie = NULL;
86           return SVN_NO_ERROR;
87         }
88     }
89
90   mc = apr_palloc(result_pool, sizeof(*mc));
91
92   /* Initialise libmagic. */
93 #ifndef MAGIC_MIME_TYPE
94   /* Some old versions of libmagic don't support MAGIC_MIME_TYPE.
95    * We can use MAGIC_MIME instead. It returns more than we need
96    * but we can work around that (see below). */
97   mc->magic = magic_open(MAGIC_MIME | MAGIC_ERROR);
98 #else
99   mc->magic = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR);
100 #endif
101   if (mc->magic)
102     {
103       /* This loads the default magic database.
104        * Point the MAGIC environment variable at your favourite .mgc
105        * file to load a non-default database. */
106       if (magic_load(mc->magic, NULL) == -1)
107         {
108           magic_close(mc->magic);
109           mc = NULL;
110         }
111       else
112         apr_pool_cleanup_register(result_pool, mc, close_magic_cookie,
113                                   apr_pool_cleanup_null);
114     }
115 #endif
116
117   *magic_cookie = mc;
118
119   return SVN_NO_ERROR;
120 }
121
122 svn_error_t *
123 svn_magic__detect_binary_mimetype(const char **mimetype,
124                                   const char *local_abspath,
125                                   svn_magic__cookie_t *magic_cookie,
126                                   apr_pool_t *result_pool,
127                                   apr_pool_t *scratch_pool)
128 {
129   const char *magic_mimetype = NULL;
130 #ifdef SVN_HAVE_LIBMAGIC
131   apr_finfo_t finfo;
132
133   /* Do not ask libmagic for the mime-types of empty files.
134    * This prevents mime-types like "application/x-empty" from making
135    * Subversion treat empty files as binary. */
136   SVN_ERR(svn_io_stat(&finfo, local_abspath, APR_FINFO_SIZE, scratch_pool));
137   if (finfo.size > 0)
138     {
139       magic_mimetype = magic_file(magic_cookie->magic, local_abspath);
140       if (magic_mimetype)
141         {
142           /* Only return binary mime-types. */
143           if (strncmp(magic_mimetype, "text/", 5) == 0)
144             magic_mimetype = NULL;
145           else
146             {
147               svn_error_t *err;
148 #ifndef MAGIC_MIME_TYPE
149               char *p;
150
151               /* Strip off trailing stuff like " charset=ascii". */
152               p = strchr(magic_mimetype, ' ');
153               if (p)
154                 *p = '\0';
155 #endif
156               /* Make sure we got a valid mime type. */
157               err = svn_mime_type_validate(magic_mimetype, scratch_pool);
158               if (err)
159                 {
160                   if (err->apr_err == SVN_ERR_BAD_MIME_TYPE)
161                     {
162                       svn_error_clear(err);
163                       magic_mimetype = NULL;
164                     }
165                   else
166                     return svn_error_trace(err);
167                 }
168               else
169                 {
170                   /* The string is allocated from memory managed by libmagic
171                    * so we must copy it to the result pool. */
172                   magic_mimetype = apr_pstrdup(result_pool, magic_mimetype);
173                 }
174             }
175         }
176     }
177 #endif
178
179   *mimetype = magic_mimetype;
180   return SVN_NO_ERROR;
181 }