subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From s...@apache.org
Subject svn commit: r1131383 - in /subversion/trunk/subversion: include/private/svn_magic.h libsvn_client/add.c libsvn_client/client.h libsvn_client/commit.c libsvn_subr/io.c libsvn_subr/magic.c
Date Sat, 04 Jun 2011 12:32:28 GMT
Author: stsp
Date: Sat Jun  4 12:32:27 2011
New Revision: 1131383

URL: http://svn.apache.org/viewvc?rev=1131383&view=rev
Log:
Wrap libmagic support in a private API and use this API from libsvn_client.

This moves all the #ifdef HAVE_LIBMAGIC spaghetti into a single file.
It also makes Subversion's use of libmagic more efficient for recursive
operations because the magic database is only loaded once per invocation
of svn_client_add() and svn_client_import(), not per every invocation of
svn_io_detect_mimetype().

Inspired by: hwright

* subversion/include/private/svn_magic.h: New.

* subversion/libsvn_subr/magic.c: New.

* subversion/libsvn_subr/io.c
  (svn_io_detect_mimetype2): Drop libmagic support from this function.

* subversion/libsvn_client/add.c
  (svn_client__get_auto_props): Add a MAGIC_COOKIE parameter for use with
   the new svn_magic API. Let mime-types obtained from libmagic override
   the mimetypes map if the map returned "application/octet-stream" (but
   do not override "application/octet-stream" configured via auto-props).
  (add_file, add_dir_recursive): Add MAGIC_COOKIE parameter.
  (add): Initialise libmagic and pass the magic cookie on to other functions.

* subversion/libsvn_client/commit.c
  (import_ctx): Add a MAGIC_COOKIE here, too.
  (import_file): Pass CTX->MAGIC_COOKIE to svn_client__get_auto_props().
  (import): Initialise libmagic and store the cookie in the import context.

* subversion/libsvn_client/client.h
  (svn_client__get_auto_props): Update declaration.

Added:
    subversion/trunk/subversion/include/private/svn_magic.h
    subversion/trunk/subversion/libsvn_subr/magic.c
Modified:
    subversion/trunk/subversion/libsvn_client/add.c
    subversion/trunk/subversion/libsvn_client/client.h
    subversion/trunk/subversion/libsvn_client/commit.c
    subversion/trunk/subversion/libsvn_subr/io.c

Added: subversion/trunk/subversion/include/private/svn_magic.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_magic.h?rev=1131383&view=auto
==============================================================================
--- subversion/trunk/subversion/include/private/svn_magic.h (added)
+++ subversion/trunk/subversion/include/private/svn_magic.h Sat Jun  4 12:32:27 2011
@@ -0,0 +1,55 @@
+/**
+ * @copyright
+ * ====================================================================
+ *    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.
+ * ====================================================================
+ * @endcopyright
+ *
+ * @file svn_magic.h
+ * @brief Subversion interface to libmagic.
+ */
+
+#ifndef SVN_MAGIC_H
+#define SVN_MAGIC_H
+
+/* An opaque struct that wraps a libmagic cookie. */
+typedef struct svn_magic__cookie_t svn_magic__cookie_t;
+
+/* This routine initialises libmagic.
+ * Upon success new *MAGIC_COOKIE is allocated in RESULT_POOL.
+ * On failure *MAGIC_COOKIE is set to NULL.
+ * All resources used by libmagic are freed by a cleanup handler
+ * installed on RESULT_POOL, i.e. *MAGIC_COOKIE becomes invalid when
+ * the pool is cleared! */
+void
+svn_magic__init(svn_magic__cookie_t **magic_cookie,
+                apr_pool_t *result_pool);
+
+/* Detect the mime-type of the file at LOCAL_ABSPATH using MAGIC_COOKIE.
+ * If the mime-type is binary return the result in *MIMETYPE.
+ * If the file is not a binary file or if its mime-type cannot be determined
+ * set *MIMETYPE to NULL. Allocate *MIMETYPE in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations. */
+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);
+
+#endif /* SVN_MAGIC_H */

Modified: subversion/trunk/subversion/libsvn_client/add.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/add.c?rev=1131383&r1=1131382&r2=1131383&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/add.c (original)
+++ subversion/trunk/subversion/libsvn_client/add.c Sat Jun  4 12:32:27 2011
@@ -47,6 +47,7 @@
 
 #include "private/svn_client_private.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_magic.h"
 
 #include "svn_private_config.h"
 
@@ -220,6 +221,7 @@ svn_error_t *
 svn_client__get_auto_props(apr_hash_t **properties,
                            const char **mimetype,
                            const char *path,
+                           svn_magic__cookie_t *magic_cookie,
                            svn_client_ctx_t *ctx,
                            apr_pool_t *pool)
 {
@@ -254,38 +256,20 @@ svn_client__get_auto_props(apr_hash_t **
       SVN_ERR(svn_io_detect_mimetype2(&autoprops.mimetype, path,
                                       ctx->mimetypes_map, pool));
 
-#ifdef HAVE_LIBMAGIC
-      /* We want to set an svn:mime-type property by default only on binary
-       * files. So don't set an svn:mime-type property on text files unless
-       * their mime-type appears in the map. This preserves behaviour
-       * of Subversion releases that did not include libmagic support.
-       * In those releases svn_io_detect_mimetype2() returned
-       * "application/octet-stream" or NULL unless the type was in the map. */
-      if (autoprops.mimetype && strncmp(autoprops.mimetype, "text/", 5) == 0)
-        {
-          if (ctx->mimetypes_map)
-            {
-              svn_boolean_t type_is_in_map = FALSE;
-              apr_hash_index_t *hi;
-
-              for (hi = apr_hash_first(pool, ctx->mimetypes_map);
-                   hi;
-                   hi = apr_hash_next(hi))
-                {
-                  const char *type_from_map = svn__apr_hash_index_val(hi);
-                  if (strcmp(type_from_map, autoprops.mimetype) == 0)
-                    {
-                      type_is_in_map = TRUE;
-                      break;
-                    }
-                }
-              if (!type_is_in_map)
-                autoprops.mimetype = NULL;
-            }
-          else
-            autoprops.mimetype = NULL;
+      /* If we got no mime-type, or if it is "application/octet-stream",
+       * try to get the mime-type from libmagic. */
+      if (magic_cookie &&
+          (!autoprops.mimetype ||
+           strcmp(autoprops.mimetype, "application/octet-stream") == 0))
+        {
+          const char *magic_mimetype;
+
+          SVN_ERR(svn_magic__detect_binary_mimetype(&magic_mimetype,
+                                                    path, magic_cookie,
+                                                    pool, pool));
+          if (magic_mimetype)
+            autoprops.mimetype = magic_mimetype;
         }
-#endif
 
       if (autoprops.mimetype)
         apr_hash_set(autoprops.properties, SVN_PROP_MIME_TYPE,
@@ -311,6 +295,7 @@ svn_client__get_auto_props(apr_hash_t **
 /* Only call this if the on-disk node kind is a file. */
 static svn_error_t *
 add_file(const char *local_abspath,
+         svn_magic__cookie_t *magic_cookie,
          svn_client_ctx_t *ctx,
          apr_pool_t *pool)
 {
@@ -331,7 +316,7 @@ add_file(const char *local_abspath,
        we open them to estimate file type.
        That's why we postpone the add until after this step. */
     SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, local_abspath,
-                                       ctx, pool));
+                                       magic_cookie, ctx, pool));
 
   /* Add the file */
   SVN_ERR(svn_wc_add_from_disk(ctx->wc_ctx, local_abspath,
@@ -402,6 +387,9 @@ add_file(const char *local_abspath,
  * Files and directories that match ignore patterns will not be added unless
  * NO_IGNORE is TRUE.
  *
+ * Use MAGIC_COOKIE (which may be NULL) to detect the mime-type of files
+ * if necessary.
+ *
  * If CTX->CANCEL_FUNC is non-null, call it with CTX->CANCEL_BATON to allow
  * the user to cancel the operation
  */
@@ -410,6 +398,7 @@ add_dir_recursive(const char *dir_abspat
                   svn_depth_t depth,
                   svn_boolean_t force,
                   svn_boolean_t no_ignore,
+                  svn_magic__cookie_t *magic_cookie,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *scratch_pool)
 {
@@ -476,12 +465,13 @@ add_dir_recursive(const char *dir_abspat
             depth_below_here = svn_depth_empty;
 
           SVN_ERR(add_dir_recursive(abspath, depth_below_here,
-                                    force, no_ignore, ctx, iterpool));
+                                    force, no_ignore, magic_cookie,
+                                    ctx, iterpool));
         }
       else if ((dirent->kind == svn_node_file || dirent->special)
                && depth >= svn_depth_files)
         {
-          err = add_file(abspath, ctx, iterpool);
+          err = add_file(abspath, magic_cookie, ctx, iterpool);
           if (err && err->apr_err == SVN_ERR_ENTRY_EXISTS && force)
             svn_error_clear(err);
           else
@@ -516,6 +506,9 @@ add(void *baton, apr_pool_t *result_pool
   svn_node_kind_t kind;
   svn_error_t *err;
   struct add_with_write_lock_baton *b = baton;
+  svn_magic__cookie_t *magic_cookie;
+
+  svn_magic__init(&magic_cookie, scratch_pool);
 
   if (b->existing_parent_abspath)
     {
@@ -565,11 +558,11 @@ add(void *baton, apr_pool_t *result_pool
          and pass depth along no matter what it is, so that the
          target's depth will be set correctly. */
       err = add_dir_recursive(b->local_abspath, b->depth,
-                              b->force, b->no_ignore, b->ctx,
+                              b->force, b->no_ignore, magic_cookie, b->ctx,
                               scratch_pool);
     }
   else if (kind == svn_node_file)
-    err = add_file(b->local_abspath, b->ctx, scratch_pool);
+    err = add_file(b->local_abspath, magic_cookie, b->ctx, scratch_pool);
   else if (kind == svn_node_none)
     {
       svn_boolean_t tree_conflicted;

Modified: subversion/trunk/subversion/libsvn_client/client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/client.h?rev=1131383&r1=1131382&r2=1131383&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/client.h (original)
+++ subversion/trunk/subversion/libsvn_client/client.h Sat Jun  4 12:32:27 2011
@@ -35,6 +35,8 @@
 #include "svn_ra.h"
 #include "svn_client.h"
 
+#include "private/svn_magic.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
@@ -348,10 +350,13 @@ svn_error_t * svn_client__can_delete(con
    (const char * keys mapping to svn_string_t * values), or if
    auto-props are disabled, set *PROPERTIES to NULL.
    Set *MIMETYPE to the mimetype, if any, or to NULL.
+   If MAGIC_COOKIE is not NULL and no mime-type can be determined
+   via CTX->config try to detect the mime-type with libmagic.
    Allocate the hash table, keys, values, and mimetype in POOL. */
 svn_error_t *svn_client__get_auto_props(apr_hash_t **properties,
                                         const char **mimetype,
                                         const char *path,
+                                        svn_magic__cookie_t *magic_cookie,
                                         svn_client_ctx_t *ctx,
                                         apr_pool_t *pool);
 

Modified: subversion/trunk/subversion/libsvn_client/commit.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/commit.c?rev=1131383&r1=1131382&r2=1131383&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/commit.c (original)
+++ subversion/trunk/subversion/libsvn_client/commit.c Sat Jun  4 12:32:27 2011
@@ -49,6 +49,7 @@
 
 #include "client.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_magic.h"
 
 #include "svn_private_config.h"
 
@@ -70,6 +71,8 @@ typedef struct import_ctx_t
   /* Whether any changes were made to the repository */
   svn_boolean_t repos_changed;
 
+  /* A magic cookie for mime-type detection. */
+  svn_magic__cookie_t *magic_cookie;
 } import_ctx_t;
 
 
@@ -211,8 +214,9 @@ import_file(const svn_delta_editor_t *ed
   if (! is_special)
     {
       /* add automatic properties */
-      SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, path, ctx,
-                                         pool));
+      SVN_ERR(svn_client__get_auto_props(&properties, &mimetype, path,
+                                         import_ctx->magic_cookie,
+                                         ctx, pool));
     }
   else
     properties = apr_hash_make(pool);
@@ -495,6 +499,8 @@ import(const char *path,
   const char *edit_path = "";
   import_ctx_t *import_ctx = apr_pcalloc(pool, sizeof(*import_ctx));
 
+  svn_magic__init(&import_ctx->magic_cookie, pool);
+
   /* Get a root dir baton.  We pass an invalid revnum to open_root
      to mean "base this on the youngest revision".  Should we have an
      SVN_YOUNGEST_REVNUM defined for these purposes? */

Modified: subversion/trunk/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=1131383&r1=1131382&r2=1131383&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/io.c (original)
+++ subversion/trunk/subversion/libsvn_subr/io.c Sat Jun  4 12:32:27 2011
@@ -66,10 +66,6 @@
 #include "private/svn_atomic.h"
 #include "private/svn_io_private.h"
 
-#ifdef HAVE_LIBMAGIC
-#include <magic.h>
-#endif
-
 #define SVN_SLEEP_ENV_VAR "SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_SLEEP_FOR_TIMESTAMPS"
 
 /*
@@ -2910,10 +2906,6 @@ svn_io_detect_mimetype2(const char **mim
   svn_error_t *err;
   unsigned char block[1024];
   apr_size_t amt_read = sizeof(block);
-  apr_finfo_t finfo;
-#ifdef HAVE_LIBMAGIC
-  magic_t magic;
-#endif
 
   /* Default return value is NULL. */
   *mimetype = NULL;
@@ -2941,40 +2933,6 @@ svn_io_detect_mimetype2(const char **mim
                              _("Can't detect MIME type of non-file '%s'"),
                              svn_dirent_local_style(file, pool));
 
-
-  /* Check if the file is empty and do not set a mime-type if it is.
-   * This also avoids spurious mime-types like "application/x-empty"
-   * from libmagic.
-   * ### merge this with the kind check above to save a stat() call */
-  SVN_ERR(svn_io_stat(&finfo, file, APR_FINFO_SIZE, pool));
-  if (finfo.size == 0)
-    return SVN_NO_ERROR;
-
-#ifdef HAVE_LIBMAGIC
-  /* Try to determine the mime-type with libmagic. */
-  magic = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR);
-  if (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(magic, NULL) != -1)
-        {
-          const char *magic_mime_type;
-
-          magic_mime_type = magic_file(magic, file);
-          if (magic_mime_type != NULL)
-            *mimetype = apr_pstrdup(pool, magic_mime_type);
-        }
-
-      /* This deallocates memory pointed to by magic_mime_type. */
-      magic_close(magic);
-
-      if (*mimetype)
-        return SVN_NO_ERROR;
-    }
-#endif
-
   SVN_ERR(svn_io_file_open(&fh, file, APR_READ, 0, pool));
 
   /* Read a block of data from FILE. */

Added: subversion/trunk/subversion/libsvn_subr/magic.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/magic.c?rev=1131383&view=auto
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/magic.c (added)
+++ subversion/trunk/subversion/libsvn_subr/magic.c Sat Jun  4 12:32:27 2011
@@ -0,0 +1,128 @@
+/*
+ * 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 <apr_lib.h>
+#include <apr_file_info.h>
+
+#include "svn_io.h"
+#include "svn_pools.h"
+#include "svn_error.h"
+
+#include "svn_private_config.h"
+
+#include "private/svn_magic.h"
+
+#ifdef HAVE_LIBMAGIC
+#include <magic.h>
+#endif
+
+struct svn_magic__cookie_t {
+#ifdef HAVE_LIBMAGIC
+  magic_t magic;
+#endif
+  char dummy;
+};
+
+#ifdef 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 HAVE_LIBMAGIC
+  mc = apr_palloc(result_pool, sizeof(*mc));
+
+  /* Initialise libmagic. */
+  mc->magic = magic_open(MAGIC_MIME_TYPE | MAGIC_ERROR);
+  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 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
+           {
+             /* 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;
+}



Mime
View raw message