You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2013/10/23 10:58:44 UTC

svn commit: r1534960 - /subversion/trunk/subversion/libsvn_subr/io.c

Author: brane
Date: Wed Oct 23 08:58:44 2013
New Revision: 1534960

URL: http://svn.apache.org/r1534960
Log:
Use the new UTF conversion functions in the last file that still
includes a private APR header. This is the almost final step towards
elimintaing those headers altogether.

* subversion/libsvn_subr/io.c: Include svn_utf_private.h
  (io_utf8_to_unicode_path, io_unicode_to_utf8_path): Reimplement, using
   the private Windoes-specific UTF conversion functions, and return
   an svn_error_t* instead of an apr_status_t.
  (io_win_file_attrs_set): Return an svn_error_t* and adjust for the
   changed signature of io_utf8_to_unicode_path.
  (io_win_read_link): Adjust for the changed signature of
   io_unicode_to_utf8_path.
  (svn_io_set_file_read_write_carefully): Adjust for the changed
   return type of io_win_file_attrs_set.

Modified:
    subversion/trunk/subversion/libsvn_subr/io.c

Modified: subversion/trunk/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=1534960&r1=1534959&r2=1534960&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/io.c (original)
+++ subversion/trunk/subversion/libsvn_subr/io.c Wed Oct 23 08:58:44 2013
@@ -70,6 +70,7 @@
 
 #include "private/svn_atomic.h"
 #include "private/svn_io_private.h"
+#include "private/svn_utf_private.h"
 
 #define SVN_SLEEP_ENV_VAR "SVN_I_LOVE_CORRUPTED_WORKING_COPIES_SO_DISABLE_SLEEP_FOR_TIMESTAMPS"
 
@@ -1694,26 +1695,13 @@ io_set_file_perms(const char *path,
 
 #ifdef WIN32
 #if APR_HAS_UNICODE_FS
-/* copy of the apr function utf8_to_unicode_path since apr doesn't export this one */
-static apr_status_t io_utf8_to_unicode_path(apr_wchar_t* retstr, apr_size_t retlen,
-                                            const char* srcstr)
-{
-    /* TODO: The computations could preconvert the string to determine
-     * the true size of the retstr, but that's a memory over speed
-     * tradeoff that isn't appropriate this early in development.
-     *
-     * Allocate the maximum string length based on leading 4
-     * characters of \\?\ (allowing nearly unlimited path lengths)
-     * plus the trailing null, then transform /'s into \\'s since
-     * the \\?\ form doesn't allow '/' path separators.
-     *
-     * Note that the \\?\ form only works for local drive paths, and
-     * \\?\UNC\ is needed UNC paths.
-     */
-    apr_size_t srcremains = strlen(srcstr) + 1;
-    apr_wchar_t *t = retstr;
-    apr_status_t rv;
-
+/* This is semantically the same as the APR utf8_to_unicode_path
+   function, but reimplemented here because APR does not export it. */
+static svn_error_t*
+io_utf8_to_unicode_path(const WCHAR **result,
+                        const char *source,
+                        apr_pool_t *result_pool)
+{
     /* This is correct, we don't twist the filename if it will
      * definitely be shorter than 248 characters.  It merits some
      * performance testing to see if this has any effect, but there
@@ -1728,99 +1716,110 @@ static apr_status_t io_utf8_to_unicode_p
      * Note that a utf-8 name can never result in more wide chars
      * than the original number of utf-8 narrow chars.
      */
-    if (srcremains > 248) {
-        if (srcstr[1] == ':' && (srcstr[2] == '/' || srcstr[2] == '\\')) {
-            wcscpy (retstr, L"\\\\?\\");
-            retlen -= 4;
-            t += 4;
-        }
-        else if ((srcstr[0] == '/' || srcstr[0] == '\\')
-              && (srcstr[1] == '/' || srcstr[1] == '\\')
-              && (srcstr[2] != '?')) {
-            /* Skip the slashes */
-            srcstr += 2;
-            srcremains -= 2;
-            wcscpy (retstr, L"\\\\?\\UNC\\");
-            retlen -= 8;
-            t += 8;
+    const WCHAR *prefix = NULL;
+    const int srclen = strlen(source);
+    WCHAR *buffer;
+
+    if (srclen > 248)
+    {
+        if (svn_ctype_isalpha(source[0]) && source[1] == ':'
+            && (source[2] == '/' || source[2] == '\\'))
+        {
+            /* This is an ordinary absolute path. */
+            prefix = L"\\\\?\\";
+        }
+        else if ((source[0] == '/' || source[0] == '\\')
+                 && (source[1] == '/' || source[1] == '\\')
+                 && source[2] != '?')
+        {
+            /* This is a UNC path */
+            source += 2;        /* Skip the leading slashes */
+            prefix = L"\\\\?\\UNC\\";
         }
     }
 
-    if (rv = apr_conv_utf8_to_ucs2(srcstr, &srcremains, t, &retlen)) {
-        return (rv == APR_INCOMPLETE) ? APR_EINVAL : rv;
-    }
-    if (srcremains) {
-        return APR_ENAMETOOLONG;
-    }
-    for (; *t; ++t)
-        if (*t == L'/')
-            *t = L'\\';
-    return APR_SUCCESS;
-}
-
-/* copy of the apr function unicode_to_utf8_path since apr doesn't export this
- * one */
-static apr_status_t io_unicode_to_utf8_path(char* retstr, apr_size_t retlen,
-                                            const apr_wchar_t* srcstr)
-{
+    SVN_ERR(svn_utf__win32_utf8_to_utf16(&(const WCHAR*)buffer, source,
+                                         prefix, result_pool));
+
+    /* Convert slashes to backslashes because the \\?\ path format
+       does not allow backslashes as path separators. */
+    *result = buffer;
+    for (; *buffer; ++buffer)
+    {
+        if (*buffer == '/')
+            *buffer = '\\';
+    }
+    return SVN_NO_ERROR;
+}
+
+/* This is semantically the same as the APR unicode_to_utf8_path
+   function, but reimplemented here because APR does not export it. */
+static svn_error_t *
+io_unicode_to_utf8_path(const char **result,
+                        const apr_wchar_t *source,
+                        apr_pool_t *result_pool)
+{
+    const char *utf8_buffer;
+    char *buffer;
+
+    SVN_ERR(svn_utf__win32_utf16_to_utf8(&utf8_buffer, source,
+                                         NULL, result_pool));
+    if (!*utf8_buffer)
+      {
+        *result = utf8_buffer;
+        return SVN_NO_ERROR;
+      }
+
+    /* We know that the non-empty buffer returned from the UTF-16 to
+       UTF-8 conversion function is in fact writable. */
+    buffer = (char*)utf8_buffer;
+
     /* Skip the leading 4 characters if the path begins \\?\, or substitute
      * // for the \\?\UNC\ path prefix, allocating the maximum string
      * length based on the remaining string, plus the trailing null.
      * then transform \\'s back into /'s since the \\?\ form never
      * allows '/' path seperators, and APR always uses '/'s.
      */
-    apr_size_t srcremains = wcslen(srcstr) + 1;
-    apr_status_t rv;
-    char *t = retstr;
-    if (srcstr[0] == L'\\' && srcstr[1] == L'\\' && 
-        srcstr[2] == L'?'  && srcstr[3] == L'\\') {
-        if (srcstr[4] == L'U' && srcstr[5] == L'N' && 
-            srcstr[6] == L'C' && srcstr[7] == L'\\') {
-            srcremains -= 8;
-            srcstr += 8;
-            retstr[0] = '\\';
-            retstr[1] = '\\';
-            retlen -= 2;
-            t += 2;
-        }
-        else {
-            srcremains -= 4;
-            srcstr += 4;
-        }
-    }
-        
-    if ((rv = apr_conv_ucs2_to_utf8(srcstr, &srcremains, t, &retlen))) {
-        return rv;
-    }
-    if (srcremains) {
-        return APR_ENAMETOOLONG;
-    }
-    return APR_SUCCESS;
+    if (0 == strncmp(buffer, "\\\\?\\", 4))
+    {
+        buffer += 4;
+        if (0 == strncmp(buffer, "UNC\\", 4))
+        {
+            buffer += 2;
+            *buffer = '/';
+        }
+    }
+
+    *result = buffer;
+    for (; *buffer; ++buffer)
+    {
+        if (*buffer == '\\')
+            *buffer = '/';
+    }
+    return SVN_NO_ERROR;
 }
-#endif
+#endif /* APR_HAS_UNICODE_FS */
 
-static apr_status_t io_win_file_attrs_set(const char *fname,
-                                          DWORD attributes,
-                                          DWORD attr_mask,
-                                          apr_pool_t *pool)
+static svn_error_t *
+io_win_file_attrs_set(const char *fname,
+                      DWORD attributes,
+                      DWORD attr_mask,
+                      apr_pool_t *pool)
 {
     /* this is an implementation of apr_file_attrs_set() but one
        that uses the proper Windows attributes instead of the apr
        attributes. This way, we can apply any Windows file and
        folder attributes even if apr doesn't implement them */
     DWORD flags;
-    apr_status_t rv;
+    BOOL rc;
 #if APR_HAS_UNICODE_FS
-    apr_wchar_t wfname[APR_PATH_MAX];
+    const WCHAR *wfname;
 #endif
 
 #if APR_HAS_UNICODE_FS
     IF_WIN_OS_IS_UNICODE
     {
-        if (rv = io_utf8_to_unicode_path(wfname,
-                                         sizeof(wfname) / sizeof(wfname[0]),
-                                         fname))
-            return rv;
+        SVN_ERR(io_utf8_to_unicode_path(&wfname, fname, pool));
         flags = GetFileAttributesW(wfname);
     }
 #endif
@@ -1832,7 +1831,9 @@ static apr_status_t io_win_file_attrs_se
 #endif
 
     if (flags == 0xFFFFFFFF)
-        return apr_get_os_error();
+        return svn_error_wrap_apr(apr_get_os_error(),
+                                  _("Can't get attributes of file '%s'"),
+                                  svn_dirent_local_style(fname, pool));
 
     flags &= ~attr_mask;
     flags |= (attributes & attr_mask);
@@ -1840,20 +1841,22 @@ static apr_status_t io_win_file_attrs_se
 #if APR_HAS_UNICODE_FS
     IF_WIN_OS_IS_UNICODE
     {
-        rv = SetFileAttributesW(wfname, flags);
+        rc = SetFileAttributesW(wfname, flags);
     }
 #endif
 #if APR_HAS_ANSI_FS
     ELSE_WIN_OS_IS_ANSI
     {
-        rv = SetFileAttributesA(fname, flags);
+        rc = SetFileAttributesA(fname, flags);
     }
 #endif
 
-    if (rv == 0)
-        return apr_get_os_error();
+    if (!rc)
+        return svn_error_wrap_apr(apr_get_os_error(),
+                                  _("Can't set attributes of file '%s'"),
+                                  svn_dirent_local_style(fname, pool));
 
-    return APR_SUCCESS;
+    return SVN_NO_ERROR;;
 }
 
 static svn_error_t *win_init_dynamic_imports(void *baton, apr_pool_t *pool)
@@ -1880,7 +1883,7 @@ static svn_error_t * io_win_read_link(sv
         apr_file_t *file;
         apr_os_file_t filehand;
         apr_wchar_t wdest[APR_PATH_MAX];
-        char buf[APR_PATH_MAX];
+        const char *data;
 
         /* reserve one char for terminating zero. */
         DWORD wdest_len = sizeof(wdest)/sizeof(wdest[0]) - 1;
@@ -1914,18 +1917,21 @@ static svn_error_t * io_win_read_link(sv
 
         /* GetFinaPathNameByHandleW doesn't add terminating NUL. */
         wdest[rv] = 0;
+        SVN_ERR(io_unicode_to_utf8_path(&data, wdest, pool));
 
-        status = io_unicode_to_utf8_path(buf, sizeof(buf), wdest);
-        if (status)
-          return svn_error_wrap_apr(status,
-                                    _("Can't read contents of link"));
-
-        *dest = svn_string_create(buf, pool);
+        /* The result is already in the correct pool, so avoid copying
+           it to create the string. */
+        *dest = svn_string_create_empty(pool);
+        if (*data)
+          {
+            (*dest)->data = data;
+            (*dest)->len = strlen(data);
+          }
 
         return SVN_NO_ERROR;
       }
     else
-#endif
+#endif /* APR_HAS_UNICODE_FS */
       {
         return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                                 _("Symbolic links are not supported on this "
@@ -1933,7 +1939,7 @@ static svn_error_t * io_win_read_link(sv
       }
 }
 
-#endif
+#endif /* WIN32 */
 
 svn_error_t *
 svn_io_set_file_read_write_carefully(const char *path,
@@ -4081,22 +4087,26 @@ dir_make(const char *path, apr_fileperms
                                   APR_FILE_ATTR_HIDDEN,
                                   APR_FILE_ATTR_HIDDEN,
                                   pool);
-#else
-    /* on Windows, use our wrapper so we can also set the
-       FILE_ATTRIBUTE_NOT_CONTENT_INDEXED attribute */
-    status = io_win_file_attrs_set(path_apr,
-                                   FILE_ATTRIBUTE_HIDDEN |
-                                   FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
-                                   FILE_ATTRIBUTE_HIDDEN |
-                                   FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
-                                   pool);
-
-#endif
       if (status)
         return svn_error_wrap_apr(status, _("Can't hide directory '%s'"),
                                   svn_dirent_local_style(path, pool));
+#else
+    /* on Windows, use our wrapper so we can also set the
+       FILE_ATTRIBUTE_NOT_CONTENT_INDEXED attribute */
+      svn_error_t *err =
+          io_win_file_attrs_set(path_apr,
+                                FILE_ATTRIBUTE_HIDDEN |
+                                FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
+                                FILE_ATTRIBUTE_HIDDEN |
+                                FILE_ATTRIBUTE_NOT_CONTENT_INDEXED,
+                                pool);
+      if (err)
+        return svn_error_createf(err->apr_err, err,
+                                 _("Can't hide directory '%s'"),
+                                 svn_dirent_local_style(path, pool));
+#endif /* WIN32 */
     }
-#endif
+#endif /* APR_FILE_ATTR_HIDDEN */
 
 /* Windows does not implement sgid. Skip here because retrieving
    the file permissions via APR_FINFO_PROT | APR_FINFO_OWNER is documented