On 06.02.2011 11:43, Bert Huijben wrote:

Note that this patch is not really what you want: It doesn't handle UTF-8,
nor long path names (which apr's version would do for us). We need to
support both when we don't want to introduce a regression.

In 1.7 we usually only have one .svn directory per workingcopy so there
won't be any performance difference on our operations.

Attached is a patch that would address the issue. I implemented it in make_dir when the 'hidden' attribute is set: I just set the 'no index' attribute as well.


Stefan

--
       ___
  oo  // \\      "De Chelonian Mobile"
 (_,\/ \_/ \     TortoiseSVN
   \ \_/_\_/>    The coolest Interface to (Sub)Version Control
   /_/   \_\     http://tortoisesvn.net
[[[
Set the 'don't index' attribute on Windows on .svn the folders to prevent
its content from being indexed by the Windows search service.

* subversion/libsvn_subr/io.c
  (svn_utf8_to_unicode_path): new function, copy of utf8_to_unicode_path in
                              the apr library since it's not exported.
  (apr_win_file_attrs_set): new function to set Windows file attributes.
  (dir_make): when setting the 'hidden' attribute also set the 'no index'
              attribute.
]]]
Index: subversion/libsvn_subr/io.c
===================================================================
--- subversion/libsvn_subr/io.c (Revision 1066924)
+++ subversion/libsvn_subr/io.c (Arbeitskopie)
@@ -47,6 +47,10 @@
 #include <apr_portable.h>
 #include <apr_md5.h>
 
+#ifdef WIN32
+#include <arch/win32/apr_arch_file_io.h>
+#endif
+
 #include "svn_types.h"
 #include "svn_dirent_uri.h"
 #include "svn_path.h"
@@ -1539,7 +1543,132 @@
 }
 #endif /* !WIN32 && !__OS2__ */
 
+#ifdef WIN32
+#if APR_HAS_UNICODE_FS
+/* copy of the apr function utf8_to_unicode_path since apr doesn't export this 
one */
+apr_status_t svn_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 seperators.
+     *
+     * 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 correct, we don't twist the filename if it is will
+     * definately be shorter than 248 characters.  It merits some 
+     * performance testing to see if this has any effect, but there
+     * seem to be applications that get confused by the resulting
+     * Unicode \\?\ style file names, especially if they use argv[0]
+     * or call the Win32 API functions such as GetModuleName, etc.
+     * Not every application is prepared to handle such names.
+     * 
+     * Note also this is shorter than MAX_PATH, as directory paths 
+     * are actually limited to 248 characters. 
+     *
+     * 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;
+        }
+    }
+
+    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;
+}
+#endif
+
+apr_status_t apr_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;
+#if APR_HAS_UNICODE_FS
+    apr_wchar_t wfname[APR_PATH_MAX];
+#endif
+
+#if APR_HAS_UNICODE_FS
+    IF_WIN_OS_IS_UNICODE
+    {
+        if (rv = svn_utf8_to_unicode_path(wfname,
+                                          sizeof(wfname) / sizeof(wfname[0]),
+                                          fname))
+            return rv;
+        flags = GetFileAttributesW(wfname);
+    }
+#endif
+#if APR_HAS_ANSI_FS
+    ELSE_WIN_OS_IS_ANSI
+    {
+        flags = GetFileAttributesA(fname);
+    }
+#endif
+
+    if (flags == 0xFFFFFFFF)
+        return apr_get_os_error();
+
+    flags |= (attributes & attr_mask);
+    flags &= ~attr_mask;
+
+#if APR_HAS_UNICODE_FS
+    IF_WIN_OS_IS_UNICODE
+    {
+        rv = SetFileAttributesW(wfname, flags);
+    }
+#endif
+#if APR_HAS_ANSI_FS
+    ELSE_WIN_OS_IS_ANSI
+    {
+        rv = SetFileAttributesA(fname, flags);
+    }
+#endif
+
+    if (rv == 0)
+        return apr_get_os_error();
+
+    return APR_SUCCESS;
+}
+
+#endif
+
 svn_error_t *
 svn_io_set_file_read_write_carefully(const char *path,
                                      svn_boolean_t enable_write,
@@ -3197,10 +3326,22 @@
 #ifdef APR_FILE_ATTR_HIDDEN
   if (hidden)
     {
+#ifndef WIN32
       status = apr_file_attrs_set(path_apr,
                                   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 = apr_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));

Reply via email to