]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/subversion/subversion/libsvn_subr/magic.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.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
37 #include "svn_private_config.h"
38
39 #include "private/svn_magic.h"
40
41 #ifdef SVN_HAVE_LIBMAGIC
42 #include <magic.h>
43 #endif
44
45 struct svn_magic__cookie_t {
46 #ifdef SVN_HAVE_LIBMAGIC
47   magic_t magic;
48 #else
49   char dummy;
50 #endif
51 };
52
53 #ifdef SVN_HAVE_LIBMAGIC
54 /* Close the magic database. */
55 static apr_status_t
56 close_magic_cookie(void *baton)
57 {
58   svn_magic__cookie_t *mc = (svn_magic__cookie_t*)baton;
59   magic_close(mc->magic);
60   return APR_SUCCESS;
61 }
62 #endif
63
64 void
65 svn_magic__init(svn_magic__cookie_t **magic_cookie,
66                 apr_pool_t *result_pool)
67 {
68
69   svn_magic__cookie_t *mc = NULL;
70
71 #ifdef SVN_HAVE_LIBMAGIC
72   mc = apr_palloc(result_pool, sizeof(*mc));
73
74   /* Initialise libmagic. */
75 #ifndef MAGIC_MIME_TYPE
76   /* Some old versions of libmagic don't support MAGIC_MIME_TYPE.
77    * We can use MAGIC_MIME instead. It returns more than we need
78    * but we can work around that (see below). */
79   mc->magic = magic_open(MAGIC_MIME | MAGIC_ERROR);
80 #else
81   mc->magic = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR);
82 #endif
83   if (mc->magic)
84     {
85       /* This loads the default magic database.
86        * Point the MAGIC environment variable at your favourite .mgc
87        * file to load a non-default database. */
88       if (magic_load(mc->magic, NULL) == -1)
89         {
90           magic_close(mc->magic);
91           mc = NULL;
92         }
93       else
94         apr_pool_cleanup_register(result_pool, mc, close_magic_cookie,
95                                   apr_pool_cleanup_null);
96     }
97 #endif
98
99   *magic_cookie = mc;
100 }
101
102 svn_error_t *
103 svn_magic__detect_binary_mimetype(const char **mimetype,
104                                   const char *local_abspath,
105                                   svn_magic__cookie_t *magic_cookie,
106                                   apr_pool_t *result_pool,
107                                   apr_pool_t *scratch_pool)
108 {
109   const char *magic_mimetype = NULL;
110 #ifdef SVN_HAVE_LIBMAGIC
111   apr_finfo_t finfo;
112
113   /* Do not ask libmagic for the mime-types of empty files.
114    * This prevents mime-types like "application/x-empty" from making
115    * Subversion treat empty files as binary. */
116   SVN_ERR(svn_io_stat(&finfo, local_abspath, APR_FINFO_SIZE, scratch_pool));
117   if (finfo.size > 0)
118     {
119       magic_mimetype = magic_file(magic_cookie->magic, local_abspath);
120       if (magic_mimetype)
121         {
122           /* Only return binary mime-types. */
123           if (strncmp(magic_mimetype, "text/", 5) == 0)
124             magic_mimetype = NULL;
125           else
126             {
127               svn_error_t *err;
128 #ifndef MAGIC_MIME_TYPE
129               char *p;
130
131               /* Strip off trailing stuff like " charset=ascii". */
132               p = strchr(magic_mimetype, ' ');
133               if (p)
134                 *p = '\0';
135 #endif
136               /* Make sure we got a valid mime type. */
137               err = svn_mime_type_validate(magic_mimetype, scratch_pool);
138               if (err)
139                 {
140                   if (err->apr_err == SVN_ERR_BAD_MIME_TYPE)
141                     {
142                       svn_error_clear(err);
143                       magic_mimetype = NULL;
144                     }
145                   else
146                     return svn_error_trace(err);
147                 }
148               else
149                 {
150                   /* The string is allocated from memory managed by libmagic
151                    * so we must copy it to the result pool. */
152                   magic_mimetype = apr_pstrdup(result_pool, magic_mimetype);
153                 }
154             }
155         }
156     }
157 #endif
158
159   *mimetype = magic_mimetype;
160   return SVN_NO_ERROR;
161 }