/* * magic.c: wrappers around libmagic * * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== */ /* ==================================================================== */ /*** Includes. ***/ #include #include #include "svn_io.h" #include "svn_types.h" #include "svn_pools.h" #include "svn_error.h" #include "svn_private_config.h" #include "private/svn_magic.h" #ifdef SVN_HAVE_LIBMAGIC #include #endif struct svn_magic__cookie_t { #ifdef SVN_HAVE_LIBMAGIC magic_t magic; #else char dummy; #endif }; #ifdef SVN_HAVE_LIBMAGIC /* Close the magic database. */ static apr_status_t close_magic_cookie(void *baton) { svn_magic__cookie_t *mc = (svn_magic__cookie_t*)baton; magic_close(mc->magic); return APR_SUCCESS; } #endif void svn_magic__init(svn_magic__cookie_t **magic_cookie, apr_pool_t *result_pool) { svn_magic__cookie_t *mc = NULL; #ifdef SVN_HAVE_LIBMAGIC mc = apr_palloc(result_pool, sizeof(*mc)); /* Initialise libmagic. */ #ifndef MAGIC_MIME_TYPE /* Some old versions of libmagic don't support MAGIC_MIME_TYPE. * We can use MAGIC_MIME instead. It returns more than we need * but we can work around that (see below). */ mc->magic = magic_open(MAGIC_MIME | MAGIC_ERROR); #else mc->magic = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR); #endif if (mc->magic) { /* This loads the default magic database. * Point the MAGIC environment variable at your favourite .mgc * file to load a non-default database. */ if (magic_load(mc->magic, NULL) == -1) { magic_close(mc->magic); mc = NULL; } else apr_pool_cleanup_register(result_pool, mc, close_magic_cookie, apr_pool_cleanup_null); } #endif *magic_cookie = mc; } svn_error_t * svn_magic__detect_binary_mimetype(const char **mimetype, const char *local_abspath, svn_magic__cookie_t *magic_cookie, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *magic_mimetype = NULL; #ifdef SVN_HAVE_LIBMAGIC apr_finfo_t finfo; /* Do not ask libmagic for the mime-types of empty files. * This prevents mime-types like "application/x-empty" from making * Subversion treat empty files as binary. */ SVN_ERR(svn_io_stat(&finfo, local_abspath, APR_FINFO_SIZE, scratch_pool)); if (finfo.size > 0) { magic_mimetype = magic_file(magic_cookie->magic, local_abspath); if (magic_mimetype) { /* Only return binary mime-types. */ if (strncmp(magic_mimetype, "text/", 5) == 0) magic_mimetype = NULL; else { svn_error_t *err; #ifndef MAGIC_MIME_TYPE char *p; /* Strip off trailing stuff like " charset=ascii". */ p = strchr(magic_mimetype, ' '); if (p) *p = '\0'; #endif /* Make sure we got a valid mime type. */ err = svn_mime_type_validate(magic_mimetype, scratch_pool); if (err) { if (err->apr_err == SVN_ERR_BAD_MIME_TYPE) { svn_error_clear(err); magic_mimetype = NULL; } else return svn_error_trace(err); } else { /* The string is allocated from memory managed by libmagic * so we must copy it to the result pool. */ magic_mimetype = apr_pstrdup(result_pool, magic_mimetype); } } } } #endif *mimetype = magic_mimetype; return SVN_NO_ERROR; }