magic.c revision 251886
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 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 45struct 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. */ 55static apr_status_t 56close_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 64void 65svn_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 102svn_error_t * 103svn_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} 162