rdiff-backup-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Rdiff-backup-commits] rdiff-backup CHANGELOG rdiff_backup/FilenameMap..


From: Josh Nisly
Subject: [Rdiff-backup-commits] rdiff-backup CHANGELOG rdiff_backup/FilenameMap...
Date: Thu, 09 Apr 2009 13:59:20 +0000

CVSROOT:        /sources/rdiff-backup
Module name:    rdiff-backup
Changes by:     Josh Nisly <joshn>      09/04/09 13:59:19

Modified files:
        .              : CHANGELOG 
        rdiff_backup   : FilenameMapping.py eas_acls.py log.py 
                         metadata.py rpath.py statistics.py win_acls.py 

Log message:
        Use Unicode for paths internally to add support for Unicode on Windows.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/CHANGELOG?cvsroot=rdiff-backup&r1=1.370&r2=1.371
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/rdiff_backup/FilenameMapping.py?cvsroot=rdiff-backup&r1=1.19&r2=1.20
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/rdiff_backup/eas_acls.py?cvsroot=rdiff-backup&r1=1.43&r2=1.44
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/rdiff_backup/log.py?cvsroot=rdiff-backup&r1=1.25&r2=1.26
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/rdiff_backup/metadata.py?cvsroot=rdiff-backup&r1=1.32&r2=1.33
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/rdiff_backup/rpath.py?cvsroot=rdiff-backup&r1=1.138&r2=1.139
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/rdiff_backup/statistics.py?cvsroot=rdiff-backup&r1=1.23&r2=1.24
http://cvs.savannah.gnu.org/viewcvs/rdiff-backup/rdiff_backup/win_acls.py?cvsroot=rdiff-backup&r1=1.4&r2=1.5

Patches:
Index: CHANGELOG
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/CHANGELOG,v
retrieving revision 1.370
retrieving revision 1.371
diff -u -b -r1.370 -r1.371
--- CHANGELOG   31 Mar 2009 17:43:08 -0000      1.370
+++ CHANGELOG   9 Apr 2009 13:59:17 -0000       1.371
@@ -1,6 +1,9 @@
 New in v1.3.4 (????/??/??)
 ---------------------------
 
+Start using Unicode internally for filenames. This fixes Unicode support
+on Windows (Josh Nisly)
+
 Don't print "Fatal Error" if --check-destination-dir completed successfully.
 Thanks to Serge Zub for the suggestion. (Andrew Ferguson)
 

Index: rdiff_backup/FilenameMapping.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/FilenameMapping.py,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -b -r1.19 -r1.20
--- rdiff_backup/FilenameMapping.py     3 Jan 2009 21:32:40 -0000       1.19
+++ rdiff_backup/FilenameMapping.py     9 Apr 2009 13:59:18 -0000       1.20
@@ -158,7 +158,10 @@
                correctly and append()ed to the currect QuotedRPath.
 
                """
-               return map(unquote, self.conn.os.listdir(self.path))
+               path = self.path
+               if type(path) != unicode:
+                       path = unicode(path, 'utf-8')
+               return map(unquote, self.conn.os.listdir(path))
 
        def __str__(self):
                return "QuotedPath: %s\nIndex: %s\nData: %s" % \

Index: rdiff_backup/eas_acls.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/eas_acls.py,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -b -r1.43 -r1.44
--- rdiff_backup/eas_acls.py    2 Mar 2009 18:02:58 -0000       1.43
+++ rdiff_backup/eas_acls.py    9 Apr 2009 13:59:18 -0000       1.44
@@ -57,7 +57,8 @@
        def read_from_rp(self, rp):
                """Set the extended attributes from an rpath"""
                try:
-                       attr_list = rp.conn.xattr.listxattr(rp.path, rp.issym())
+                       attr_list = 
rp.conn.xattr.listxattr(rp.path.encode('utf-8'),
+                                                                               
                rp.issym())
                except IOError, exc:
                        if exc[0] in (errno.EOPNOTSUPP, errno.EPERM, 
errno.ETXTBSY):
                                return # if not supported, consider empty
@@ -74,7 +75,8 @@
                                continue
                        try:
                                self.attr_dict[attr] = \
-                                       rp.conn.xattr.getxattr(rp.path, attr, 
rp.issym())
+                                       
rp.conn.xattr.getxattr(rp.path.encode('utf-8'),
+                                                                               
        attr, rp.issym())
                        except IOError, exc:
                                # File probably modified while reading, just 
continue
                                if exc[0] == errno.ENODATA: continue
@@ -86,9 +88,11 @@
        def clear_rp(self, rp):
                """Delete all the extended attributes in rpath"""
                try:
-                       for name in rp.conn.xattr.listxattr(rp.path, 
rp.issym()):
+                       for name in 
rp.conn.xattr.listxattr(rp.path.encode('utf-8'),
+                                                                               
                rp.issym()):
                                try:
-                                       rp.conn.xattr.removexattr(rp.path, 
name, rp.issym())
+                                       
rp.conn.xattr.removexattr(rp.path.encode('utf-8'),
+                                                                               
        name, rp.issym())
                                except IOError, exc:
                                        # SELinux attributes cannot be removed, 
and we don't want
                                        # to bail out or be too noisy at low 
log levels.
@@ -111,7 +115,8 @@
                self.clear_rp(rp)
                for (name, value) in self.attr_dict.iteritems():
                        try:
-                               rp.conn.xattr.setxattr(rp.path, name, value, 0, 
rp.issym())
+                               rp.conn.xattr.setxattr(rp.path.encode('utf-8'), 
name,
+                                                                               
value, 0, rp.issym())
                        except IOError, exc:
                                # Mac and Linux attributes have different 
namespaces, so
                                # fail gracefully if can't call setxattr
@@ -149,13 +154,14 @@
 
 def EA2Record(ea):
        """Convert ExtendedAttributes object to text record"""
-       str_list = ['# file: %s' % C.acl_quote(ea.get_indexpath())]
+       str_list = ['# file: %s' % 
C.acl_quote(ea.get_indexpath().encode('utf-8'))]
        for (name, val) in ea.attr_dict.iteritems():
                if not val: str_list.append(name)
                else:
                        encoded_val = base64.encodestring(val).replace('\n', '')
                        try:
-                               str_list.append('%s=0s%s' % (C.acl_quote(name), 
encoded_val))
+                               str_list.append('%s=0s%s' % 
(C.acl_quote(name.encode('utf-8')),
+                                                                               
        encoded_val))
                        except UnicodeEncodeError:
                                log.Log("Warning: unable to store Unicode 
extended attribute %s"
                                                        % repr(name), 3)
@@ -169,7 +175,8 @@
                raise metadata.ParsingError("Bad record beginning: " + 
first[:8])
        filename = first[8:]
        if filename == '.': index = ()
-       else: index = tuple(C.acl_unquote(filename).split('/'))
+       else: index = tuple(unicode(C.acl_unquote(filename.encode('utf-8')),
+                                                                               
        'utf-8').split('/'))
        ea = ExtendedAttributes(index)
 
        for line in lines:
@@ -194,7 +201,7 @@
        def filename_to_index(self, filename):
                """Convert possibly quoted filename to index tuple"""
                if filename == '.': return ()
-               else: return tuple(C.acl_unquote(filename).split('/'))
+               else: return 
tuple(C.acl_unquote(filename.encode('utf-8')).split('/'))
 
 class ExtendedAttributesFile(metadata.FlatFile):
        """Store/retrieve EAs from extended_attributes file"""
@@ -379,7 +386,7 @@
        else: acl = posix1e.ACL()
 
        try:
-               acl.applyto(rp.path)
+               acl.applyto(rp.path.encode('utf-8'))
        except IOError, exc:
                if exc[0] == errno.EOPNOTSUPP:
                        log.Log("Warning: unable to set ACL on %s: %s" % 
@@ -391,12 +398,12 @@
                if default_entry_list:
                        def_acl = list_to_acl(default_entry_list, map_names)
                else: def_acl = posix1e.ACL()
-               def_acl.applyto(rp.path, posix1e.ACL_TYPE_DEFAULT)
+               def_acl.applyto(rp.path.encode('utf-8'), 
posix1e.ACL_TYPE_DEFAULT)
 
 def get_acl_lists_from_rp(rp):
        """Returns (acl_list, def_acl_list) from an rpath.  Call locally"""
        assert rp.conn is Globals.local_connection
-       try: acl = posix1e.ACL(file=rp.path)
+       try: acl = posix1e.ACL(file=rp.path.encode('utf-8'))
        except IOError, exc:
                if exc[0] == errno.EOPNOTSUPP:
                        acl = None
@@ -406,7 +413,7 @@
                        acl = None
                else: raise
        if rp.isdir():
-               try: def_acl = posix1e.ACL(filedef=rp.path)
+               try: def_acl = posix1e.ACL(filedef=rp.path.encode('utf-8'))
                except IOError, exc:
                        if exc[0] == errno.EOPNOTSUPP:
                                def_acl = None
@@ -533,7 +540,8 @@
 
 def ACL2Record(acl):
        """Convert an AccessControlLists object into a text record"""
-       return '# file: %s\n%s\n' % (C.acl_quote(acl.get_indexpath()), str(acl))
+       return '# file: %s\n%s\n' % \
+               (C.acl_quote(acl.get_indexpath().encode('utf-8')), str(acl))
 
 def Record2ACL(record):
        """Convert text record to an AccessControlLists object"""
@@ -543,7 +551,8 @@
                raise metadata.ParsingError("Bad record beginning: "+ 
first_line)
        filename = first_line[8:]
        if filename == '.': index = ()
-       else: index = tuple(C.acl_unquote(filename).split('/'))
+       else: index = tuple(unicode(C.acl_unquote(filename.encode('utf-8')),
+                                               'utf-8').split('/'))
        return AccessControlLists(index, record[newline_pos:])
 
 class ACLExtractor(EAExtractor):

Index: rdiff_backup/log.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/log.py,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -b -r1.25 -r1.26
--- rdiff_backup/log.py 14 Aug 2007 02:58:20 -0000      1.25
+++ rdiff_backup/log.py 9 Apr 2009 13:59:19 -0000       1.26
@@ -125,7 +125,11 @@
                """Write the message to the log file, if possible"""
                if self.log_file_open:
                        if self.log_file_local:
-                               self.logfp.write(self.format(message, 
self.verbosity))
+                               str = self.format(message, self.verbosity)
+                               if type(str) != unicode:
+                                       str = unicode(str, 'utf-8')
+                               str = str.encode('utf-8')
+                               self.logfp.write(str)
                                self.logfp.flush()
                        else: self.log_file_conn.log.Log.log_to_file(message)
 
@@ -133,7 +137,14 @@
                """Write message to stdout/stderr"""
                if verbosity <= 2 or Globals.server: termfp = sys.stderr
                else: termfp = sys.stdout
-               termfp.write(self.format(message, self.term_verbosity))
+               str = self.format(message, self.term_verbosity)
+               if type(str) != unicode:
+                       str = unicode(str, 'utf-8')
+               try:
+                       # Try to log as unicode, but fall back to ascii (for 
Windows)
+                       termfp.write(str.encode('utf-8'))
+               except UnicodeDecodeError:
+                       termfp.write(str.encode('ascii', 'replace'))
 
        def conn(self, direction, result, req_num):
                """Log some data on the connection
@@ -165,10 +176,17 @@
        def exception_to_string(self, arglist = []):
                """Return string version of current exception plus what's in 
arglist"""
                type, value, tb = sys.exc_info()
-               s = ("Exception '%s' raised of class '%s':\n%s" %
-                        (value, type, "".join(traceback.format_tb(tb))))
+               s = (u"Exception '%s' raised of class '%s':\n%s" %
+                        (value, type, u"".join(traceback.format_tb(tb))))
+               s = s.encode('ascii', 'replace')
                if arglist:
-                       s += "__Arguments:\n" + "\n".join(map(str, arglist))
+                       s += "__Arguments:"
+                       for arg in arglist:
+                               s += "\n"
+                               try:
+                                       s += str(arg)
+                               except UnicodeError:
+                                       s += unicode(arg).encode('ascii', 
'replace')
                return s
 
        def exception(self, only_terminal = 0, verbosity = 5):
@@ -259,7 +277,8 @@
                """Return log string to put in error log"""
                assert (error_type == "ListError" or error_type == 
"UpdateError" or
                                error_type == "SpecialFileError"), "Unknown 
type "+error_type
-               return "%s %s %s" % (error_type, cls.get_indexpath(rp), 
str(exc))
+               str = u"%s %s %s" % (error_type, cls.get_indexpath(rp), 
unicode(exc))
+               return str.encode('utf-8')
 
        def close(cls):
                """Close the error log file"""

Index: rdiff_backup/metadata.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/metadata.py,v
retrieving revision 1.32
retrieving revision 1.33
diff -u -b -r1.32 -r1.33
--- rdiff_backup/metadata.py    27 Sep 2008 00:17:24 -0000      1.32
+++ rdiff_backup/metadata.py    9 Apr 2009 13:59:19 -0000       1.33
@@ -55,7 +55,7 @@
 """
 
 from __future__ import generators
-import re, gzip, os, binascii
+import re, gzip, os, binascii, codecs
 import log, Globals, rpath, Time, robust, increment, static, rorpiter
 
 class ParsingError(Exception):
@@ -376,16 +376,18 @@
                        compress = 1
                if mode == 'r':
                        self.rp = rp_base
-                       self.fileobj = self.rp.open("rb", compress)
+                       self.fileobj = rpath.UnicodeFile(self.rp.open("rb", 
compress))
                else:
                        assert mode == 'w'
                        if compress and check_path and not 
rp_base.isinccompressed():
                                def callback(rp): self.rp = rp
-                               self.fileobj = rpath.MaybeGzip(rp_base, 
callback)
+                               self.fileobj = 
rpath.UnicodeFile(rpath.MaybeGzip(rp_base,
+                                                                               
                callback))
                        else:
                                self.rp = rp_base
                                assert not self.rp.lstat(), self.rp
-                               self.fileobj = self.rp.open("wb", compress = 
compress)
+                               self.fileobj = 
rpath.UnicodeFile(self.rp.open("wb", 
+                                                                               
                compress = compress))
 
        def write_record(self, record):
                """Write a (text) record into the file"""

Index: rdiff_backup/rpath.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/rpath.py,v
retrieving revision 1.138
retrieving revision 1.139
diff -u -b -r1.138 -r1.139
--- rdiff_backup/rpath.py       8 Mar 2009 17:20:16 -0000       1.138
+++ rdiff_backup/rpath.py       9 Apr 2009 13:59:19 -0000       1.139
@@ -35,7 +35,7 @@
 
 """
 
-import os, stat, re, sys, shutil, gzip, socket, time, errno
+import os, stat, re, sys, shutil, gzip, socket, time, errno, codecs
 import Globals, Time, static, log, user_group, C
 
 try:
@@ -284,6 +284,8 @@
        """
        if os.name != 'nt':
                try:
+                       if type(filename) == unicode:
+                               filename = filename.encode('utf-8')
                        return C.make_file_dict(filename)
                except OSError, error:
                        # Unicode filenames should be process by the Python 
version 
@@ -333,7 +335,7 @@
        data['nlink'] = statblock[stat.ST_NLINK]
 
        if os.name == 'nt':
-               attribs = win32file.GetFileAttributes(filename)
+               attribs = win32file.GetFileAttributesW(filename)
                if attribs & winnt.FILE_ATTRIBUTE_REPARSE_POINT:
                        data['type'] = 'sym'
                        data['linkname'] = None
@@ -995,7 +997,12 @@
 
        def listdir(self):
                """Return list of string paths returned by os.listdir"""
-               return self.conn.os.listdir(self.path)
+               path = self.path
+               # Use pass in unicode to os.listdir, so that the returned
+               # entries are in unicode.
+               if type(path) != unicode:
+                       path = unicode(path, 'utf-8')
+               return self.conn.os.listdir(path)
 
        def symlink(self, linktext):
                """Make symlink at self.path pointing to linktext"""
@@ -1406,6 +1413,23 @@
                write_win_acl(self, acl)
                self.data['win_acl'] = acl
 
+class UnicodeFile:
+       """ Wraps a RPath and reads/writes unicode. """
+
+       def __init__(self, fileobj):
+               self.fileobj = fileobj
+
+       def read(self, length = -1):
+               return unicode(self.fileobj.read(length), 'utf-8')
+
+       def write(self, buf):
+               if type(buf) != unicode:
+                       buf = unicode(buf, 'utf-8')
+               return self.fileobj.write(buf.encode('utf-8'))
+
+       def close(self):
+               return self.fileobj.close()
+
 class RPathFileHook:
        """Look like a file, but add closing hook"""
        def __init__(self, file, closing_thunk):
@@ -1429,6 +1453,18 @@
        messages.  Use this class instead to clean those up.
 
        """
+       def __init__(self, filename=None, mode=None):
+               """ This is needed because we need to write an
+               encoded filename to the file, but use normal
+               unicode with the filename."""
+               if mode and 'b' not in mode:
+                       mode += 'b'
+               if type(filename) != unicode:
+                       filename = unicode(filename, 'utf-8')
+               fileobj = open(filename, mode or 'rb')
+               gzip.GzipFile.__init__(self, filename.encode('utf-8'),
+                                                       mode=mode, 
fileobj=fileobj)
+
        def __del__(self): pass
        def __getattr__(self, name):
                if name == 'fileno': return self.fileobj.fileno

Index: rdiff_backup/statistics.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/statistics.py,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -b -r1.23 -r1.24
--- rdiff_backup/statistics.py  3 Jan 2009 21:35:59 -0000       1.23
+++ rdiff_backup/statistics.py  9 Apr 2009 13:59:19 -0000       1.24
@@ -20,7 +20,7 @@
 """Generate and process aggregated backup information"""
 
 import re, os, time
-import Globals, Time, increment, log, static, metadata
+import Globals, Time, increment, log, static, metadata, rpath
 
 class StatsException(Exception): pass
 
@@ -219,13 +219,13 @@
 
        def write_stats_to_rp(self, rp):
                """Write statistics string to given rpath"""
-               fp = rp.open("wb")
+               fp = rpath.UnicodeFile(rp.open("wb"))
                fp.write(self.get_stats_string())
                assert not fp.close()
 
        def read_stats_from_rp(self, rp):
                """Set statistics from rpath, return self for convenience"""
-               fp = rp.open("r")
+               fp = rpath.UnicodeFile(rp.open("r"))
                self.set_stats_from_string(fp.read())
                fp.close()
                return self
@@ -364,7 +364,8 @@
                suffix = Globals.compression and 'data.gz' or 'data'
                cls._rp = increment.get_inc(rpbase, suffix, Time.curtime)
                assert not cls._rp.lstat()
-               cls._fileobj = cls._rp.open("wb", compress = 
Globals.compression)
+               cls._fileobj = rpath.UnicodeFile(cls._rp.open("wb", 
+                                                       compress = 
Globals.compression))
 
                cls._line_sep = Globals.null_separator and '\0' or '\n'
                cls.write_docstring()

Index: rdiff_backup/win_acls.py
===================================================================
RCS file: /sources/rdiff-backup/rdiff-backup/rdiff_backup/win_acls.py,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5
--- rdiff_backup/win_acls.py    24 Nov 2008 22:07:32 -0000      1.4
+++ rdiff_backup/win_acls.py    9 Apr 2009 13:59:19 -0000       1.5
@@ -181,7 +181,7 @@
 
        def __str__(self):
                return '# file: %s\n%s\n' % \
-                               (C.acl_quote(self.get_indexpath()), 
unicode(self.__acl))
+                                       (self.get_indexpath(), 
unicode(self.__acl))
 
        def from_string(self, acl_str):
                lines = acl_str.splitlines()
@@ -189,7 +189,7 @@
                        raise metadata.ParsingError("Bad record beginning: " + 
lines[0][:8])
                filename = lines[0][8:]
                if filename == '.': self.index = ()
-               else: self.index = tuple(C.acl_unquote(filename).split('/'))
+               else: self.index = tuple(filename.split('/'))
                self.__acl = lines[1]
 
 def Record2WACL(record):




reply via email to

[Prev in Thread] Current Thread [Next in Thread]